📄 gui.c
字号:
} /* In the mahjonging state, if our hand is not declared, and the pending flag is not set, and if either we are the winner or the winner's hand is declared popup the scoring dialog, otherwise down */ if ( !auto_declaring_hand && the_game->active && !the_game->paused && the_game->state == MahJonging && !the_game->mjpending && !pflag(our_player,HandDeclared) && (the_game->player == our_seat || pflag(the_game->players[the_game->player],HandDeclared) ) ) { /* if we don't have a tile selected and we're the winner, select the first */ if ( selected_button < 0 && the_game->player == our_seat ) conc_callback(pdisps[0].conc[0],(gpointer)(0 | 128)); scoring_dialog_popup(); } else { gtk_widget_hide(scoring_dialog); } /* If the game is not active, or active but paused, pop up the continue dialog */ if ( (!the_game->active) || the_game->paused ) continue_dialog_popup(); else gtk_widget_hide(continue_dialog); /* make sure the discard dialog (or turn) is down */ if ( the_game->state == HandComplete ) { gtk_widget_hide(discard_dialog->widget); gtk_widget_hide(turn_dialog); }}static void stdin_input_callback(gpointer data UNUSED, gint source, GdkInputCondition condition UNUSED) { char *l; l = get_line(source); if ( l ) { put_line(the_game->fd,l); /* we're bypassing the client routines, so we must update the sequence number ourselves */ the_game->cseqno++; }}/* given an already allocated PlayerDisp* and an orientation, initialize a player display. The player widget is NOT shown, but everything else (appropriate) is */static void playerdisp_init(PlayerDisp *pd, int ori) { /* here is the widget hierarchy we want: w -- the parent widget concealed -- the concealed row csets[MAX_TILESETS] -- five boxes which will have tiles packed in them conc -- the concealed & special tile subbox, with... conc[14] -- 14 tile buttons extras[8] -- more spaces for specials if we run out. pdispwidth-14 are initially set, to get the spacing. exposed -- the exposed row esets[MAX_TILESETS] -- with sets, each of which has tile buttons as appropriate. specbox -- spec[8] -- places for specials (Not all of these can always be used; so we may need to balance dynamically between this and extras.) tongbox -- the tong box pixmap widget */ GtkWidget *concealed, *exposed, *conc, *c, *b, *pm, *w,*specbox; int i; int tb,br,bl; int eori; /* orientation of exposed tiles, if different */ /* pd->player = NULL; */ /* don't do this: playerdisp_init is also called when rebuilding the display, in which case we shouldn't null the player. The player field should be nulled when the PlayerDisp is created */ pd->orientation = ori; eori = flipori(ori); /* sometimes it's enough to know whether the player is top/bottom, or the left/right */ tb = ! (ori%2); /* and sometimes the bottom and right players are similar (they are to the increasing x/y of their tiles */ br = (ori < 2); /* and sometimes the bottom and left are similar (their right is at the positive and of the box */ bl = (ori == 0 || ori == 3); /* homogeneous to force exposed row to right height */ if ( tb ) w = gtk_vbox_new(1,tile_spacing); else w = gtk_hbox_new(1,tile_spacing); gtk_widget_set_style(w,tablestyle); pd->widget = w; gtk_container_set_border_width(GTK_CONTAINER(w),player_border_width); if ( tb ) concealed = gtk_hbox_new(0,tile_spacing); else concealed = gtk_vbox_new(0,tile_spacing); gtk_widget_set_style(concealed,tablestyle); gtk_widget_show(concealed); /* the concealed box is towards the player */ /* This box needs to stay expanded to the width of the surrounding, which should be fixed at start up.*/ if ( br ) gtk_box_pack_end(GTK_BOX(w),concealed,1,1,0); else gtk_box_pack_start(GTK_BOX(w),concealed,1,1,0); /* players put closed (nonkong) tilesets in to the left of their concealed tiles */ for ( i=0; i < MAX_TILESETS; i++) { if ( tb ) c = gtk_hbox_new(0,0); else c = gtk_vbox_new(0,0); if ( bl ) gtk_box_pack_start(GTK_BOX(concealed),c,0,0,0); else gtk_box_pack_end(GTK_BOX(concealed),c,0,0,0); pd->csets[i].widget = c; tilesetbox_init(&pd->csets[i],ori,NULL,0); } if ( tb ) conc = gtk_hbox_new(0,0); else conc = gtk_vbox_new(0,0); gtk_widget_set_style(conc,tablestyle); gtk_widget_show(conc); /* the concealed tiles are to the right of the concealed sets */ /* This also needs to stay expanded */ if ( bl ) gtk_box_pack_start(GTK_BOX(concealed),conc,1,1,0); else gtk_box_pack_end(GTK_BOX(concealed),conc,1,1,0); for ( i=0; i < 14; i++ ) { /* normally, just buttons, but for us toggle buttons */ if ( ori == 0 ) b = gtk_toggle_button_new(); else b = gtk_button_new(); /* we don't want any of the buttons taking the focus */ GTK_WIDGET_UNSET_FLAGS(b,GTK_CAN_FOCUS); gtk_widget_show(b); pm = gtk_pixmap_new(tilepixmaps[ori][HiddenTile],NULL); gtk_widget_show(pm); gtk_container_add(GTK_CONTAINER(b),pm); /* the concealed tiles are placed from the player's left */ if ( bl ) gtk_box_pack_start(GTK_BOX(conc),b,0,0,0); else gtk_box_pack_end(GTK_BOX(conc),b,0,0,0); pd->conc[i] = b; /* if this is our player (ori = 0), attach a callback */ if ( ori == 0 ) { gtk_signal_connect(GTK_OBJECT(b),"toggled", GTK_SIGNAL_FUNC(conc_callback),(gpointer)i); gtk_signal_connect(GTK_OBJECT(b),"button_press_event", GTK_SIGNAL_FUNC(doubleclicked),0); } } /* to the right of the concealed tiles, we will place up to 8 other tiles. These will be used for flowers and seasons when we run out of room in the exposed row. By setting pdispwidth-14 (default 5) of them initially, it also serves the purpose of fixing the row to be the desired 19 (currently) tiles wide */ for ( i=0; i < 8; i++ ) { b = gtk_button_new(); /* we don't want any of the buttons taking the focus */ GTK_WIDGET_UNSET_FLAGS(b,GTK_CAN_FOCUS); if ( i < pdispwidth-14 ) gtk_widget_show(b); pm = gtk_pixmap_new(tilepixmaps[ori][HiddenTile],NULL); gtk_widget_show(pm); gtk_container_add(GTK_CONTAINER(b),pm); /* these extra tiles are placed from the player's right */ if ( bl ) gtk_box_pack_end(GTK_BOX(conc),b,0,0,0); else gtk_box_pack_start(GTK_BOX(conc),b,0,0,0); pd->extras[i] = b; } if ( tb ) exposed = gtk_hbox_new(0,tile_spacing); else exposed = gtk_vbox_new(0,tile_spacing); gtk_widget_set_style(exposed,tablestyle); gtk_widget_show(exposed); /* the exposed box is away from the player */ if ( br ) gtk_box_pack_start(GTK_BOX(w),exposed,0,0,0); else gtk_box_pack_end(GTK_BOX(w),exposed,0,0,0); /* the exposed tiles will be in front of the player, from the left */ for ( i=0; i < MAX_TILESETS; i++ ) { if ( tb ) c = gtk_hbox_new(0,0); else c = gtk_vbox_new(0,0); gtk_widget_set_style(c,tablestyle); gtk_widget_show(c); if ( bl ) gtk_box_pack_start(GTK_BOX(exposed),c,0,0,0); else gtk_box_pack_end(GTK_BOX(exposed),c,0,0,0); pd->esets[i].widget = c; tilesetbox_init(&pd->esets[i],eori,NULL,0); } /* the special tiles are at the right of the exposed row */ if ( tb ) specbox = gtk_hbox_new(0,0); else specbox = gtk_vbox_new(0,0); gtk_widget_set_style(specbox,tablestyle); gtk_widget_show(specbox); if ( bl ) gtk_box_pack_end(GTK_BOX(exposed),specbox,0,0,0); else gtk_box_pack_start(GTK_BOX(exposed),specbox,0,0,0); /* at the right of the spec box, we place a tongbox pixmap. This is not initially shown */ pd->tongbox = gtk_pixmap_new(tongpixmaps[ori][east],tongmask); if ( bl ) gtk_box_pack_end(GTK_BOX(specbox),pd->tongbox,0,0,0); else gtk_box_pack_start(GTK_BOX(specbox),pd->tongbox,0,0,0); for ( i=0 ; i < 8; i++ ) { b = gtk_button_new(); /* we don't want any of the buttons taking the focus */ GTK_WIDGET_UNSET_FLAGS(b,GTK_CAN_FOCUS); pm = gtk_pixmap_new(tilepixmaps[eori][HiddenTile],NULL); gtk_widget_show(pm); gtk_container_add(GTK_CONTAINER(b),pm); if ( bl ) gtk_box_pack_end(GTK_BOX(specbox),b,0,0,0); else gtk_box_pack_start(GTK_BOX(specbox),b,0,0,0); pd->spec[i] = b; } /* the player's discard buttons are created as required, so just zero them */ for ( i=0; i<32; i++ ) pd->discards[i] = NULL; pd->num_discards = 0; /* also initialize the info kept by the discard routine */ pd->x = pd->y = 0; pd->row = 0; pd->plane = 0; for (i=0;i<5;i++) { pd->xmin[i] = 10000; pd->xmax[i] = 0; } pd->claimw = NULL; /* the claim window is initialized on first popup, because it needs to have all the rest of the board set out to get the size right */}/* event callback used below. The widget is a tile button, and the callback data is its tiletip window. For use below, a NULL event means always pop it up */static gint maybe_popup_tiletip(GtkWidget *w, GdkEvent *ev, gpointer data){ GtkWidget *tiletip = (GtkWidget *)data; /* popup if this is an enternotify with the right button already down, or if this is a button press with the right button */ if ( ev == NULL || ( ev->type == GDK_ENTER_NOTIFY && ( (((GdkEventCrossing *)ev)->state & GDK_BUTTON3_MASK) || tiletips ) ) || ( ev->type == GDK_BUTTON_PRESS && ((GdkEventButton *)ev)->button == 3 ) ) { /* pop it up just above, right, left, below the tile */ int ori = 0; gint x, y; gint ttx = 0, tty = 0; GtkRequisition r; get_relative_posn(boardfixed,w,&x,&y); gtk_widget_size_request(tiletip,&r); ori = (int)gtk_object_get_data(GTK_OBJECT(w),"ori"); switch ( ori ) { case 0: ttx = x; tty = y-r.height; break; case 1: ttx = x - r.width; tty = y; break; case 2: ttx = x; tty = y + tile_height; break; case 3: ttx = x + tile_height; tty = y; break; default: warn("impossible ori in maybe_popup_tiletip"); } vlazy_fixed_move(VLAZY_FIXED(boardfixed),tiletip,ttx,tty); gtk_widget_show(tiletip); } /* if it's a leavenotify, and the tile is not selected, pop down, unless the tile is a selected button */ if ( ev && ev->type == GDK_LEAVE_NOTIFY ) { if ( tiletips && GTK_WIDGET_VISIBLE(w) && GTK_IS_TOGGLE_BUTTON(w) && GTK_TOGGLE_BUTTON(w)->active ) { ; // leave it up } else { gtk_widget_hide(tiletip); } } return 1;}/* signal callback used to popup tiletips on selecting a tile */static gint maybe_popup_tiletip_when_selected(GtkWidget *w, gpointer data){ GtkWidget *tiletip = (GtkWidget *)data; if ( tiletips && GTK_IS_TOGGLE_BUTTON(w) && GTK_TOGGLE_BUTTON(w)->active && GTK_WIDGET_VISIBLE(w) ) { maybe_popup_tiletip(w,NULL,data); } else { gtk_widget_hide(tiletip); } return 1;}/* given a button, tile, and orientation, set the pixmap (and tooltip when we have them. Stash the tile in the user_data field. Stash the ori as ori. Last arg is true if a tiletip should be installed */static void button_set_tile_aux(GtkWidget *b, Tile t, int ori,int use_tiletip) { gint32 ti; GtkWidget *tiletip, *lab; gtk_pixmap_set(GTK_PIXMAP(GTK_BIN(b)->child), tilepixmaps[ori][t],NULL); ti = t; gtk_object_set_user_data(GTK_OBJECT(b),(gpointer)ti); gtk_object_set_data(GTK_OBJECT(b),"ori",(gpointer)ori); if ( use_tiletip ) { /* update, create or delete the tiletip */ tiletip = (GtkWidget *)gtk_object_get_data(GTK_OBJECT(b),"tiletip"); if ( t == HiddenTile ) { if ( tiletip ) gtk_widget_destroy(tiletip); gtk_object_set_data(GTK_OBJECT(b),"tiletip",0); } else { if ( tiletip ) { /* update label */ gtk_label_set_text(GTK_LABEL(GTK_BIN(tiletip)->child), tile_name(t)); } else { /* create tiletip */ tiletip = gtk_event_box_new(); /* it will be a child of board fixed, but its window will be moved around, and its widget position ignored */ vlazy_fixed_put(VLAZY_FIXED(boardfixed),tiletip,0,0); gtk_object_set_data(GTK_OBJECT(b),"tiletip",tiletip); lab = gtk_label_new(tile_name(t)); gtk_widget_show(lab); gtk_container_add(GTK_CONTAINER(tiletip),lab); /* install callbacks on the button, which will die when the popup is killed */ /* callback on enter */ gtk_signal_connect_while_alive(GTK_OBJECT(b),"enter_notify_event", (GtkSignalFunc)maybe_popup_tiletip, tiletip, GTK_OBJECT(tiletip)); /* callback on button press */ gtk_signal_connect_while_alive(GTK_OBJECT(b),"button_press_event", (GtkSignalFunc)maybe_popup_tiletip, tiletip, GTK_OBJECT(tiletip)); /* leaving may pop down the window */ gtk_signal_connect_while_alive(GTK_OBJECT(b),"leave_notify_event", (GtkSignalFunc)maybe_popup_tiletip, tiletip, GTK_OBJECT(tiletip)); /* toggling may require tile tips */ if ( GTK_IS_TOGGLE_BUTTON(b) ) { gtk_signal_connect_while_alive(GTK_OBJECT(b),"toggled", (GtkSignalFunc)maybe_popup_tiletip_when_selected, tiletip, GTK_OBJECT(tiletip)); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -