GtkWidget *window;
grr_board_view_t *board_view;
- GtkWidget *command_entry;
+ GtkWidget *message_entry;
+ GtkWidget *bid_entry;
GtkTextBuffer *message_buffer;
GtkWidget *message_view;
int msg_id;
int last_move_msg_id;
- rr_robot_t last_move_robot;
+ rr_robot_t last_move_robot;
+
+ rr_gamestate_t state;
} grr_game_t;
+static void
+grr_game_pass (grr_game_t *game);
+
+static void
+grr_game_zap (grr_game_t *game);
+
+static void
+grr_game_next (grr_game_t *game);
+
static int
grr_game_printf (grr_game_t *game, const char *fmt, ...);
grr_game_print (grr_game_t *game, const char *msg);
static int
-grr_game_start_gui (grr_game_t *game);
+grr_game_start_gui (grr_game_t *game, const char *user);
static void
grr_game_read_notices (grr_game_t *game);
free (diagram);
}
- return grr_game_start_gui (&game);
+ return grr_game_start_gui (&game, args.user);
}
typedef struct _GrrNoticeSource {
else
fprintf (stderr, "Error during rr_client_next_notice: %s\n",
rr_status_str (status));
- gtk_exit (1);
+ gtk_main_quit ();
}
if (!notice) {
fprintf (stderr, "Missing notice\n");
gtk_widget_queue_draw (GTK_WIDGET (game->window));
break;
case RR_NOTICE_GAMESTATE:
+ game->state = notice->u.gamestate;
grr_game_printf (game, "\nGame state changed to: %s.",
rr_gamestate_str (notice->u.gamestate));
break;
case RR_NOTICE_TURN:
+ /* XXX: Setting game->state here is goofy. Cleaner would
+ be to make the server send a NOTICE GAMESTATE NEW
+ here. */
+ game->state = RR_GAMESTATE_NEW;
+
grr_game_print (game, "\nNew round!");
rr_board_set_goal_target (board, notice->u.target);
gtk_widget_queue_draw (GTK_WIDGET (game->window));
case RR_NOTICE_MOVE:
if (game->msg_id == game->last_move_msg_id
&& game->last_move_robot == notice->u.move.robot) {
- game->last_move_msg_id = grr_game_printf (game, " %s",
- rr_direction_str (notice->u.move.direction));
+ game->last_move_msg_id = grr_game_printf (game, ",%c",
+ rr_direction_char (notice->u.move.direction));
} else {
- game->last_move_msg_id = grr_game_printf (game, "\nMove #%d: %s %s",
+ game->last_move_msg_id = grr_game_printf (game, "\nMove #%d: %s %c",
notice->u.move.count,
rr_robot_str (notice->u.move.robot),
- rr_direction_str (notice->u.move.direction));
+ rr_direction_char (notice->u.move.direction));
game->last_move_robot = notice->u.move.robot;
}
break;
GdkEventKey *event,
grr_game_t *game)
{
- if (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (game->command_entry))) {
+ if (GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (game->message_entry))
+ || GTK_WIDGET_HAS_FOCUS (GTK_WIDGET (game->bid_entry))
+ ) {
if (event->keyval == GDK_Escape) {
- gtk_entry_set_text (GTK_ENTRY (game->command_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (game->message_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (game->bid_entry), "");
gtk_widget_grab_focus (GTK_WIDGET (game->message_view));
return TRUE;
}
switch (event->keyval) {
+ case GDK_N:
+ case GDK_n:
+ case GDK_T:
+ case GDK_t:
+ grr_game_next (game);
+ break;
+ case GDK_P:
+ case GDK_p:
+ grr_game_pass (game);
+ break;
+ case GDK_Z:
+ case GDK_z:
+ grr_game_zap (game);
+ break;
case GDK_B:
case GDK_b:
grr_board_view_set_active_robot (game->board_view, RR_ROBOT_BLUE);
case GDK_BackSpace:
grr_board_view_undo (game->board_view);
break;
+ case GDK_0:
+ case GDK_1:
+ case GDK_2:
+ case GDK_3:
+ case GDK_4:
+ case GDK_5:
+ case GDK_6:
+ case GDK_7:
+ case GDK_8:
+ case GDK_9:
+ {
+ int pos = -1;
+ const gchar *key = gdk_keyval_name (event->keyval);
+ gtk_widget_grab_focus (GTK_WIDGET (game->bid_entry));
+ gtk_editable_insert_text (GTK_EDITABLE (game->bid_entry),
+ key, strlen (key), &pos);
+ gtk_editable_set_position (GTK_EDITABLE (game->bid_entry), -1);
+ }
+ break;
case GDK_space:
case GDK_slash:
- gtk_widget_grab_focus (GTK_WIDGET (game->command_entry));
+ gtk_widget_grab_focus (GTK_WIDGET (game->message_entry));
if (event->keyval == GDK_slash) {
int pos = -1;
- gtk_editable_insert_text (GTK_EDITABLE (game->command_entry),
+ gtk_editable_insert_text (GTK_EDITABLE (game->message_entry),
"/", 1, &pos);
- gtk_editable_set_position (GTK_EDITABLE (game->command_entry), -1);
+ gtk_editable_set_position (GTK_EDITABLE (game->message_entry), -1);
}
break;
case GDK_Q:
case GDK_q:
if (event->state & GDK_CONTROL_MASK) {
- gtk_exit (0);
+ gtk_main_quit ();
}
break;
}
return TRUE;
}
+/* XXX: Messy, messy. I can't seem to make up my mind whether client
+ functions like such as these should be called here or in
+ grr_board_view. */
static void
-grr_game_entry_callback (GtkWidget *widget,
- grr_game_t *game)
+grr_game_pass (grr_game_t *game)
+{
+ if (game->client == NULL)
+ return;
+
+ if (game->state == RR_GAMESTATE_SHOW)
+ rr_client_pass (game->client);
+ else
+ rr_client_revoke (game->client);
+}
+
+static void
+grr_game_zap (grr_game_t *game)
+{
+ if (game->client == NULL)
+ return;
+
+ rr_client_nobid (game->client);
+}
+
+static void
+grr_game_next (grr_game_t *game)
+{
+ if (game->client == NULL)
+ return;
+
+ if (game->state == RR_GAMESTATE_DONE)
+ rr_client_turn (game->client);
+ else
+ rr_client_abandon (game->client);
+}
+
+static void
+grr_game_pass_callback (GtkWidget *widget,
+ grr_game_t *game)
+{
+ grr_game_pass (game);
+}
+
+static void
+grr_game_zap_callback (GtkWidget *widget,
+ grr_game_t *game)
+{
+ grr_game_zap (game);
+}
+
+static void
+grr_game_next_callback (GtkWidget *widget,
+ grr_game_t *game)
+{
+ grr_game_next (game);
+}
+
+static void
+grr_game_bid_entry_callback (GtkWidget *widget,
+ grr_game_t *game)
+{
+ const gchar *bid_text;
+ char *end;
+ long bid;
+
+ if (game->client == NULL)
+ return;
+
+ bid_text = gtk_entry_get_text (GTK_ENTRY (game->bid_entry));
+
+ if (bid_text && bid_text[0]) {
+ bid = strtol (bid_text, &end, 10);
+ if (*end != '\0' && ! isspace (*end)) {
+ grr_game_printf (game, "\nInvalid bid value: %s", bid_text);
+ } else {
+ if (bid == 0)
+ rr_client_revoke (game->client);
+ else
+ rr_client_bid (game->client, bid);
+ }
+ }
+
+ gtk_entry_set_text (GTK_ENTRY (game->bid_entry), "");
+ gtk_widget_grab_focus (GTK_WIDGET (game->message_view));
+}
+
+static void
+grr_game_message_entry_callback (GtkWidget *widget,
+ grr_game_t *game)
{
rr_status_t status;
const gchar *entry_text;
char **response;
int i;
- entry_text = gtk_entry_get_text (GTK_ENTRY (game->command_entry));
+ if (game->client == NULL)
+ return;
+
+ entry_text = gtk_entry_get_text (GTK_ENTRY (game->message_entry));
- if (entry_text && entry_text[0] && game->client) {
+ if (entry_text && entry_text[0]) {
if (entry_text[0] == '/') {
status = rr_client_request (game->client, entry_text + 1, &response);
if (status) {
}
}
- gtk_entry_set_text (GTK_ENTRY (game->command_entry), "");
+ gtk_entry_set_text (GTK_ENTRY (game->message_entry), "");
gtk_widget_grab_focus (GTK_WIDGET (game->message_view));
/* XXX: Huh? Why is this triggering valgrind?
}
static int
-grr_game_start_gui (grr_game_t *game)
+grr_game_start_gui (grr_game_t *game, const char *user)
{
GtkWidget *board_frame;
GtkWidget *vpaned;
GtkWidget *sw;
GtkWidget *vbox;
+ GtkWidget *hbox;
GtkWidget *window;
GtkWidget *message_view;
- GtkWidget *command_entry;
+ GtkWidget *message_entry;
+ GtkWidget *bid_entry;
+ GtkWidget *bid_button;
+ GtkWidget *pass_button;
+ GtkWidget *zap_button;
+ GtkWidget *next_button;
+ GtkWidget *user_label;
+
+ game->state = RR_GAMESTATE_NEW;
game->window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
window = game->window;
gtk_text_buffer_create_mark (game->message_buffer,
"end", &iter, FALSE);
game->message_view = gtk_text_view_new_with_buffer (game->message_buffer);
- game->command_entry = gtk_entry_new ();
vpaned = gtk_vpaned_new ();
gtk_container_set_border_width (GTK_CONTAINER (vpaned), 0);
}
gtk_widget_show (vpaned);
- command_entry = game->command_entry;
- gtk_box_pack_end (GTK_BOX (vbox), command_entry,
- FALSE, FALSE, 0);
- gtk_widget_show (command_entry);
- g_signal_connect (G_OBJECT (command_entry), "activate",
- G_CALLBACK (grr_game_entry_callback),
- (gpointer) game);
+ hbox = gtk_hbox_new (FALSE, 1);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ {
+ user_label = gtk_label_new (user);
+ gtk_box_pack_start (GTK_BOX (hbox), user_label,
+ FALSE, FALSE, 1);
+ gtk_widget_show (user_label);
+
+ game->message_entry = gtk_entry_new ();
+ message_entry = game->message_entry;
+ gtk_box_pack_start (GTK_BOX (hbox), message_entry,
+ TRUE, TRUE, 1);
+ gtk_widget_show (message_entry);
+ g_signal_connect (G_OBJECT (message_entry), "activate",
+ G_CALLBACK (grr_game_message_entry_callback),
+ (gpointer) game);
+ }
+ gtk_widget_show (hbox);
+
+ hbox = gtk_hbox_new (FALSE, 1);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+ {
+ bid_button = gtk_button_new_with_label ("Bid:");
+ gtk_box_pack_start (GTK_BOX (hbox), bid_button,
+ FALSE, FALSE, 1);
+ gtk_widget_show (bid_button);
+ g_signal_connect (G_OBJECT (bid_button), "clicked",
+ G_CALLBACK (grr_game_bid_entry_callback),
+ (gpointer) game);
+
+ game->bid_entry = gtk_entry_new ();
+ bid_entry = game->bid_entry;
+ gtk_entry_set_max_length (GTK_ENTRY (bid_entry), 3);
+ gtk_entry_set_width_chars (GTK_ENTRY (bid_entry), 4);
+ gtk_box_pack_start (GTK_BOX (hbox), bid_entry,
+ FALSE, FALSE, 0);
+ gtk_widget_show (bid_entry);
+ g_signal_connect (G_OBJECT (bid_entry), "activate",
+ G_CALLBACK (grr_game_bid_entry_callback),
+ (gpointer) game);
+
+ pass_button = gtk_button_new_with_label ("Pass");
+ gtk_box_pack_start (GTK_BOX (hbox), pass_button,
+ FALSE, FALSE, 1);
+ gtk_widget_show (pass_button);
+ g_signal_connect (G_OBJECT (pass_button), "clicked",
+ G_CALLBACK (grr_game_pass_callback),
+ (gpointer) game);
+
+ zap_button = gtk_button_new_with_label ("Zap timer");
+ gtk_box_pack_start (GTK_BOX (hbox), zap_button,
+ FALSE, FALSE, 1);
+ gtk_widget_show (zap_button);
+ g_signal_connect (G_OBJECT (zap_button), "clicked",
+ G_CALLBACK (grr_game_zap_callback),
+ (gpointer) game);
+
+ next_button = gtk_button_new_with_label ("Next turn");
+ gtk_box_pack_start (GTK_BOX (hbox), next_button,
+ FALSE, FALSE, 1);
+ gtk_widget_show (next_button);
+ g_signal_connect (G_OBJECT (next_button), "clicked",
+ G_CALLBACK (grr_game_next_callback),
+ (gpointer) game);
+ }
+ gtk_widget_show (hbox);
}
gtk_widget_show (vbox);