📄 gui-dial.c
字号:
/* accelerators for discard dialog actions */ discard_accel = gtk_accel_group_new(); but = gtk_button_new_with_label("No claim"); gtk_widget_show(but); gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked", disc_callback,(gpointer)NoClaim); dd->noclaim = but; gtk_accel_group_add(discard_accel,GDK_n,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); but = gtk_button_new_with_label("Eyes"); GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS); /* not shown in normal state */ gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked" ,disc_callback,(gpointer)PairClaim); dd->eyes = but; gtk_accel_group_add(discard_accel,GDK_e,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); but = gtk_button_new_with_label("Chow"); GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS); gtk_widget_show(but); gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked" ,disc_callback,(gpointer)ChowClaim); dd->chow = but; gtk_accel_group_add(discard_accel,GDK_c,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); but = gtk_button_new_with_label("Pung"); GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS); gtk_widget_show(but); gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked", disc_callback,(gpointer)PungClaim); dd->pung = but; gtk_accel_group_add(discard_accel,GDK_p,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); but = gtk_button_new_with_label("Special Hand"); GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS); /* gtk_widget_show(but); */ /* don't show this; uses other space */ gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked", disc_callback,(gpointer)SpecialSetClaim); dd->special = but; gtk_accel_group_add(discard_accel,GDK_s,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); but = gtk_button_new_with_label("Kong"); GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS); gtk_widget_show(but); gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked", disc_callback,(gpointer)KongClaim); dd->kong = but; gtk_accel_group_add(discard_accel,GDK_k,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); but = gtk_button_new_with_label("Mah Jong"); GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS); gtk_widget_show(but); gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked", disc_callback,(gpointer)MahJongClaim); dd->mahjong = but; gtk_accel_group_add(discard_accel,GDK_m,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); but = gtk_button_new_with_label("Rob the Kong - Mah Jong!"); GTK_WIDGET_UNSET_FLAGS(but,GTK_CAN_FOCUS); /* gtk_widget_show(but); */ /* don't show this; it uses the space of others */ gtk_box_pack_start(GTK_BOX(butbox),but,1,1,0); gtk_signal_connect(GTK_OBJECT(but),"clicked", disc_callback,(gpointer)MahJongClaim); dd->robkong = but; gtk_accel_group_add(discard_accel,GDK_r,0,0,GTK_OBJECT(but),"clicked"); gtk_label_set_pattern(GTK_LABEL(GTK_BIN(but)->child),"_"); pbar = gtk_progress_bar_new(); gtk_widget_show(pbar); /* These are packed in reverse order so they float to the bottom */ gtk_box_pack_end(GTK_BOX(box),butbox,0,0,0); gtk_box_pack_end(GTK_BOX(box),lbl,0,0,0); gtk_box_pack_end(GTK_BOX(box),pbar,0,0,0); gtk_box_pack_end(GTK_BOX(box),tilebox,0,0,0); /* OK, now ask its size: store the result, and keep it this size for ever more */ gtk_widget_size_request(dd->widget,&discard_req); gtk_widget_set_usize(dd->widget,discard_req.width,discard_req.height); /* we have to ensure that the accelerators are only available when the widget is popped up */ gtk_signal_connect(GTK_OBJECT(discard_dialog->widget),"hide", add_or_remove_discard_accels,(gpointer)0); gtk_signal_connect(GTK_OBJECT(discard_dialog->widget),"show", add_or_remove_discard_accels,(gpointer)1);}static GtkWidget *turn_dialog_discard_button;static GtkWidget *turn_dialog_calling_button;void turn_dialog_popup(void) { /* only original call is allowed, so hide the calling button after first discard */ if ( pflag(our_player,NoDiscard) ) gtk_widget_show(turn_dialog_calling_button); else gtk_widget_hide(turn_dialog_calling_button); /* if not showing wall, put tiles left in label */ if ( ! showwall ) { char buf[128]; sprintf(buf,"(%d tiles left) Select tile and:", the_game->wall.live_end-the_game->wall.live_used); gtk_label_set_text(GTK_LABEL(turn_dialog_label),buf); } else { gtk_label_set_text(GTK_LABEL(turn_dialog_label),"Select tile and:"); } dialog_popup(turn_dialog,DPOnDiscardOnce); grab_focus_if_appropriate(turn_dialog_discard_button);}/* callback when we toggle one of our tiles. data is our index number. If data also has bit 7 set, force the tile active. If called with NULL widget, clear selection */void conc_callback(GtkWidget *w, gpointer data) { int active; int i; int force=0, index=-1; static GtkWidget *selected = NULL; /* for radiogroup functionality */ active = (w && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))); if ( active ) index = ((int)data)& 127; force = (w && (((int)data) & 128)); if ( w && just_doubleclicked == w) force = 1; /* make sure all other tiles are unselected, if we're active, or if we're called to clear: we don't just rely on the selected variable, since under some circumstances we can end up with two tiles active, by accident as it were */ /* FIXME: this relies on induced callbacks being executed synchronously */ if ( active || w == NULL) { for ( i = 0; i<14; i++ ) { if ( pdisps[0].conc[i] && pdisps[0].conc[i] != w) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pdisps[0].conc[i]), FALSE); } } } selected_button = index; selected = NULL; if ( active ) selected = w; if ( w == NULL ) return; if ( force ) { /* if it's not active, set it active: we'll then be invoked normally, so we just return now. */ if ( ! active ) { gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w),TRUE); return; } } /* if we were double clicked, invoke the turn callback directly */ if ( w && just_doubleclicked == w) { just_doubleclicked = 0; turn_callback(w,(gpointer)PMsgDiscard); }}/* This detects doubleclicks on the concealed buttons */gint doubleclicked(GtkWidget *w, GdkEventButton *eb,gpointer data UNUSED) { if ( eb->type != GDK_2BUTTON_PRESS ) return FALSE; /* This is disgusting. We set a global doubleclicked flag, which is noticed by the toggle callback */ just_doubleclicked = w; return FALSE;}/* callback attached to the buttons of the discarding dialog. They pass PMsgDiscard, PMsgDeclareClosedKong, PMsgAddToPung, or PMsgMahJong. Passed PMsgDiscard + 1000000 to declare calling. Also invoked by the declaring special callback: with DeclareSpecial to declare a special, Kong if appropriate, and NoClaim to indicate the end of declaration. Also invoked by scoring dialog with appropriate values */static void turn_callback(GtkWidget *w UNUSED, gpointer data) { PMsgUnion m; Tile selected_tile; /* it is possible for this to be invoked when it shouldn't be, for example double-clicking on a tile (or hitting space on a tile?) when no dialog is up. So let's check that one of possible dialogs is up */ if ( ! (GTK_WIDGET_VISIBLE(turn_dialog) || GTK_WIDGET_VISIBLE(ds_dialog) || GTK_WIDGET_VISIBLE(scoring_dialog) ) ) return; m.type = (PlayerMsgType)data; if ( m.type == PMsgMahJong ) { // set the discard to 0 for cleanliness. m.mahjong.discard = 0; send_packet(&m); return; } if ( m.type == PMsgShowTiles || m.type == PMsgFormClosedSpecialSet ) { send_packet(&m); return; } if ( the_game->state == DeclaringSpecials && m.type == PMsgNoClaim ) { m.type = PMsgDeclareSpecial; conc_callback(NULL,NULL); /* clear the selection */ } selected_tile = (selected_button < 0) ? HiddenTile : our_player->concealed[selected_button]; /* in declaring specials, use this to finish */ if ( selected_tile == HiddenTile ) { if ( the_game->state == DeclaringSpecials ) m.type = PMsgDeclareSpecial; else { error_dialog_popup("No tile selected!"); return; } } if ( is_special(selected_tile) ) m.type = PMsgDeclareSpecial; switch ( m.type ) { case PMsgDeclareSpecial: m.declarespecial.tile = selected_tile; break; case PMsgDiscard: m.discard.tile = selected_tile; m.discard.calling = 0; break; case PMsgDiscard+1000000: m.type = PMsgDiscard; m.discard.tile = selected_tile; m.discard.calling = 1; break; case PMsgDeclareClosedKong: m.declareclosedkong.tile = selected_tile; break; case PMsgAddToPung: m.addtopung.tile = selected_tile; break; case PMsgFormClosedPair: m.formclosedpair.tile = selected_tile; break; case PMsgFormClosedChow: m.formclosedchow.tile = selected_tile; break; case PMsgFormClosedPung: m.formclosedpung.tile = selected_tile; break; default: warn("bad type in turn_callback"); return; } send_packet(&m);} /* callback when one of the discard dialog buttons is clicked */void disc_callback(GtkWidget *w UNUSED, gpointer data) { PMsgUnion m; switch ( (gint32) data) { case NoClaim: m.type = PMsgNoClaim; m.noclaim.discard = the_game->serial; break; case ChowClaim: m.type = PMsgChow; m.chow.discard = the_game->serial; m.chow.cpos = AnyPos; /* worry about it later */ break; case PairClaim: m.type = PMsgPair; break; case SpecialSetClaim: m.type = PMsgSpecialSet; break; case PungClaim: m.type = PMsgPung; m.pung.discard = the_game->serial; break; case KongClaim: m.type = PMsgKong; m.kong.discard = the_game->serial; break; case MahJongClaim: m.type = PMsgMahJong; m.mahjong.discard = the_game->serial; break; default: warn("disc callback called with unexpected data"); return; } /* If the server has a protocol version before 1050, we mustn't send an AnyPos while mahjonging, as it doesn't know how to handle it; so pop up the chow dialog directly */ if ( server_pversion < 1050 && the_game->state == MahJonging && m.type == PMsgChow ) { do_chow(NULL,(gpointer)AnyPos); } else { send_packet(&m); }}static GtkAccelGroup *chow_accel;static void add_or_remove_chow_accels(GtkWidget *w UNUSED, gpointer data){ if ( chow_accel == NULL ) return; if ( data ) { gtk_window_add_accel_group(GTK_WINDOW(topwindow),chow_accel); } else { gtk_window_remove_accel_group(GTK_WINDOW(topwindow),chow_accel); }} /* Now create the Chow dialog box: Structure: three boxes, each containing a tileset showing a possible chow. Below that, a label "which chow?". Below that, three buttons to select. */void chow_dialog_init(void) { GtkWidget *box,*u,*v; int i; if ( chow_dialog ) { gtk_widget_destroy(chow_dialog); chow_dialog = NULL; } switch ( dialogs_position ) { case DialogsCentral: case DialogsUnspecified: chow_dialog = gtk_event_box_new(); gtk_fixed_put(GTK_FIXED(discard_area),chow_dialog,0,0); break; case DialogsPopup: case DialogsBelow: chow_dialog = gtk_window_new(GTK_WINDOW_DIALOG); gtk_signal_connect (GTK_OBJECT (chow_dialog), "delete_event", GTK_SIGNAL_FUNC (gtk_widget_hide), NULL); /* This one is allowed to shrink, and should */ gtk_window_set_policy(GTK_WINDOW(chow_dialog),1,1,1); } box = gtk_vbox_new(0,dialog_vert_spacing); gtk_container_set_border_width(GTK_CONTAINER(box), dialog_border_width); gtk_widget_show(box); gtk_container_add(GTK_CONTAINER(chow_dialog),box); u = gtk_hbox_new(0,dialog_button_spacing); gtk_widget_show(u); gtk_box_pack_start(GTK_BOX(box),u,0,0,0); for (i=0;i<3;i++) { v = gtk_hbox_new(0,0); gtk_widget_show(v); gtk_box_pack_start(GTK_BOX(u),v,0,0,0); chowtsbs[i].widget = v; tilesetbox_init(&chowtsbs[i],0,do_chow,(gpointer)i); } u = gtk_label_new("Which chow?"); gtk_widget_show(u); gtk_box_pack_start(GTK_BOX(box),u,0,0,0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -