📄 gui.c
字号:
/* also want to make sure tip goes away on being hidden. */ gtk_signal_connect_object_while_alive(GTK_OBJECT(b),"hide", (GtkSignalFunc)gtk_widget_hide,GTK_OBJECT(tiletip)); /* and if the tile is destroyed, the tip had better be */ gtk_signal_connect_object_while_alive(GTK_OBJECT(b),"destroy", (GtkSignalFunc)gtk_widget_destroy,GTK_OBJECT(tiletip)); } } }}void button_set_tile(GtkWidget *b, Tile t, int ori){ button_set_tile_aux(b,t,ori,1);}void button_set_tile_without_tiletip(GtkWidget *b, Tile t, int ori){ button_set_tile_aux(b,t,ori,0);}/* given a pointer to a TileSetBox, and an orientation, and a callback function and data initialize the box by creating the widgets and attaching the signal function.*/void tilesetbox_init(TileSetBox *tb, int ori, GtkSignalFunc func,gpointer func_data) { int i; GtkWidget *b, *pm; for (i=0; i<4; i++) { /* make a button */ b = gtk_button_new(); tb->tiles[i] = b; if ( func ) gtk_signal_connect(GTK_OBJECT(b),"clicked", func,func_data); /* we don't want any of the tiles taking the focus */ GTK_WIDGET_UNSET_FLAGS(b,GTK_CAN_FOCUS); pm = gtk_pixmap_new(tilepixmaps[ori][HiddenTile],NULL); gtk_widget_show(pm); gtk_container_add(GTK_CONTAINER(b),pm); /* we want chows to grow from top and left for left and bottom */ if ( ori == 0 || ori == 3 ) gtk_box_pack_start(GTK_BOX(tb->widget),b,0,0,0); else gtk_box_pack_end(GTK_BOX(tb->widget),b,0,0,0); } tb->set.type = Empty;}/* given a pointer to a TileSetBox, and a pointer to a TileSet, and an orientation, make the box display the tileset.*/void tilesetbox_set(TileSetBox *tb, const TileSet *ts, int ori) { int n, i, ck, millingkong; Tile t[4]; if (tb->set.type == ts->type && tb->set.tile == ts->tile) { /* nothing to do, except show for safety */ if ( ts->type == Empty ) gtk_widget_hide(tb->widget); else gtk_widget_show(tb->widget); return; } tb->set = *ts; n = 2; /* for pairs etc */ ck = 0; /* closed kong */ millingkong = 0; /* playing Millington's rules, and the kong is claimed rather than annexed */ switch (ts->type) { case ClosedKong: ck = 1; case Kong: n++; if ( !ck && ! ts->annexed && the_game && game_get_option_value(the_game,GOKongHas3Types,NULL) ) millingkong = 1; case Pung: case ClosedPung: n++; case Pair: case ClosedPair: for ( i=0 ; i < n ; i++ ) { t[i] = ts->tile; if ( ck && ( i == 0 || i == 3 ) ) t[i] = HiddenTile; if ( millingkong && i == 3 ) t[i] = HiddenTile; } break; case Chow: case ClosedChow: n = 3; for (i=0; i<n; i++) { t[i] = ts->tile+i; } break; case Empty: n = 0; } for (i=0; i<n; i++) { button_set_tile(tb->tiles[i],t[i],ori); gtk_widget_show(tb->tiles[i]); } for ( ; i < 4; i++ ) if ( tb->tiles[i] ) gtk_widget_hide(tb->tiles[i]); if ( ts->type == Empty ) gtk_widget_hide(tb->widget); else gtk_widget_show(tb->widget);}/* utility used by the chow functions. Given a TileSetBox, highlight the nth tile by setting the others insensitive. (n counts from zero). */void tilesetbox_highlight_nth(TileSetBox *tb,int n) { int i; for (i=0; i<4; i++) if ( tb->tiles[i] ) gtk_widget_set_sensitive(tb->tiles[i],i==n);}/* two routines used internally *//* update the concealed tiles of the playerdisp. Returns the *index* of the last tile matching the third argument.*/static int playerdisp_update_concealed(PlayerDisp *pd,Tile t) { PlayerP p = pd->player; int tindex = -1; int i; int cori,eori; cori = pd->orientation; eori = flipori(cori); if ( p && pflag(p,HandDeclared) ) cori = eori; for ( i=0 ; p && i < p->num_concealed ; i++ ) { button_set_tile(pd->conc[i],p->concealed[i],cori); gtk_widget_show(pd->conc[i]); if ( p->concealed[i] == t ) tindex = i; } for ( ; i < MAX_CONCEALED ; i++ ) { gtk_widget_hide(pd->conc[i]); } return tindex;}/* update the exposed tiles of the playerdisp. Returns the _button widget_ of the last tile that matched the second argument. The third argument causes special treatment: an exposed pung matching the tile is displayed as a kong.*/static GtkWidget *playerdisp_update_exposed(PlayerDisp *pd,Tile t,int robbingkong){ int i,scount,excount,ccount,ecount,qtiles; GtkWidget *w; TileSet emptyset; PlayerP p = pd->player; int cori, eori; /* orientations of concealed and exposed tiles */ cori = pd->orientation; eori = flipori(cori); emptyset.type = Empty; if ( p && pflag(p,HandDeclared) ) cori = eori; w = NULL; /* destination widget */ /* We need to count the space taken up by the exposed tilesets, in order to know where to put the specials */ qtiles = 0; /* number of quarter tile widths */ ccount = ecount = 0; for ( i=0; p && i < MAX_TILESETS; i++) { switch (p->tilesets[i].type) { case ClosedPair: case ClosedChow: /* in the concealed row, so no space */ /* NB, these are declared, they are oriented as exposed sets, despite the name */ tilesetbox_set(&pd->csets[ccount++],&p->tilesets[i],eori); break; case ClosedPung: /* in the special case that we are in the middle of robbing a kong (13 wonders), and this is the robbed set, we keep it in the exposed row displayed as a kong */ if ( robbingkong && t == p->tilesets[i].tile) { TileSet ts = p->tilesets[i]; ts.type = ClosedKong; tilesetbox_set(&pd->esets[ecount],&ts,eori); w = pd->esets[ecount].tiles[3]; qtiles += 16; /* four tiles */ ecount++; } else { tilesetbox_set(&pd->csets[ccount++],&p->tilesets[i],eori); } break; case ClosedKong: case Kong: tilesetbox_set(&pd->esets[ecount],&p->tilesets[i],eori); if ( t == p->tilesets[i].tile ) w = pd->esets[ecount].tiles[3]; qtiles += 16; /* four tiles */ ecount++; break; case Pung: if ( robbingkong && t == p->tilesets[i].tile) { TileSet ts = p->tilesets[i]; ts.type = Kong; tilesetbox_set(&pd->esets[ecount],&ts,eori); w = pd->esets[ecount].tiles[3]; qtiles += 16; /* four tiles */ } else { tilesetbox_set(&pd->esets[ecount],&p->tilesets[i],eori); if ( t == p->tilesets[i].tile ) w = pd->esets[ecount].tiles[2]; qtiles += 12; } ecount++; break; case Chow: tilesetbox_set(&pd->esets[ecount],&p->tilesets[i],eori); if ( t >= p->tilesets[i].tile && t <= p->tilesets[i].tile+2 ) w = pd->esets[ecount].tiles[t-p->tilesets[i].tile]; qtiles += 12; ecount++; break; case Pair: tilesetbox_set(&pd->esets[ecount],&p->tilesets[i],eori); if ( t == p->tilesets[i].tile ) w = pd->esets[ecount].tiles[1]; qtiles += 9; /* for the two tiles and space */ ecount++; break; case Empty: ; } } for ( ; ccount < MAX_TILESETS; ) tilesetbox_set(&pd->csets[ccount++],&emptyset,eori); for ( ; ecount < MAX_TILESETS; ) tilesetbox_set(&pd->esets[ecount++],&emptyset,eori); /* if we are the dealer, the tongbox takes up about 1.5 tiles */ if ( p && p->wind == EastWind ) { gtk_pixmap_set(GTK_PIXMAP(pd->tongbox),tongpixmaps[cori][the_game->round-1], tongmask); gtk_widget_show(pd->tongbox); qtiles += 6; } else { gtk_widget_hide(pd->tongbox); } /* for the special tiles, we put as many as possible in the exposed row (specs), and then overflow into the concealed row */ qtiles = (qtiles+3)/4; /* turn quarter tiles into tiles */ scount = excount = 0; for ( i = 0; p && i < p->num_specials && i <= pdispwidth - qtiles ; i++ ) { button_set_tile(pd->spec[i],p->specials[i],eori); gtk_widget_show(pd->spec[i]); if ( t == p->specials[i] ) w = pd->spec[i]; scount++; } for ( ; p && i < p->num_specials ; i++ ) { button_set_tile(pd->extras[i-scount],p->specials[i],eori); gtk_widget_show(pd->extras[i-scount]); if ( t == p->specials[i] ) w = pd->extras[i-scount]; excount++; } for ( ; scount < 8; scount ++ ) gtk_widget_hide(pd->spec[scount]); for ( ; excount < 8; excount ++ ) gtk_widget_hide(pd->extras[excount]); return w;}/* given a playerdisp, update the hand. The second argument gives the message prompting this. Animation is handled entirely in here.*/static void playerdisp_update(PlayerDisp *pd, CMsgUnion *m) { int i; Tile t; int tindex; static AnimInfo srcs[4], dests[4]; TileSet emptyset; int numanims = 0; static GtkWidget *robbedfromkong; /* yech */ PlayerP p = pd->player; int deftile = -1; /* default tile to be discarded */ int cori, eori; /* orientations of concealed and exposed tiles */ int updated = 0; /* flag to say we've done our stuff */ cori = pd->orientation; eori = flipori(cori); emptyset.type = Empty; if ( p && pflag(p,HandDeclared) ) cori = eori; if ( m == NULL ) { /* just update */ playerdisp_update_concealed(pd,HiddenTile); playerdisp_update_exposed(pd,HiddenTile,0); return; } if ( m->type == CMsgNewHand && p) { playerdisp_clear_discards(pd); playerdisp_update_concealed(pd,HiddenTile); playerdisp_update_exposed(pd,HiddenTile,0); return; } if ( m->type == CMsgPlayerDraws || m->type == CMsgPlayerDrawsLoose) { updated = 1; t = (m->type == CMsgPlayerDraws) ? m->playerdraws.tile : m->playerdrawsloose.tile; tindex = playerdisp_update_concealed(pd,t); assert(tindex >= 0); /* do we want to select a tile? Usually, but in declaring specials state, we want to select the rightmost tile if it's a special and otherwise none */ if ( p == our_player ) { if ( the_game->state == DeclaringSpecials ) { if ( is_special(p->concealed[p->num_concealed-1]) ) { deftile = p->num_concealed-1; conc_callback(pd->conc[deftile],(gpointer)(deftile | 128)); } else { conc_callback(NULL,NULL); } } else { deftile = tindex; conc_callback(pd->conc[deftile],(gpointer)(deftile | 128)); } } dests[numanims].target = pd->conc[tindex]; dests[numanims].t = t; get_relative_posn(boardframe,dests[numanims].target,&dests[numanims].x,&dests[numanims].y); /* that was the destination, now the source */ if ( showwall ) { if ( m->type == CMsgPlayerDraws ) { int i; /* wall has already been updated, so it's -1 */ i = wall_game_to_board(the_game->wall.live_used-1); srcs[numanims].target = NULL; srcs[numanims].t = m->playerdraws.tile; /* we may as well see our tile now */ srcs[numanims].ori = wall_ori(i); get_relative_posn(boardframe,wall[i],&srcs[numanims].x,&srcs[numanims].y); gtk_widget_destroy(wall[i]); wall[i] = NULL; } else { /* draws loose */ srcs[numanims] = *adjust_wall_loose(the_game->wall.dead_end); /* in fact, we may as well see the tile if we're drawing */ srcs[numanims].t = t; } } else { /* if we're animating, we'll just have the tile spring up from nowhere! */ srcs[numanims].target = NULL; srcs[numanims].t = t; /* we may as well see our tile now */ srcs[numanims].ori = cori; /* these should be corrected for orientation */ srcs[numanims].x = boardframe->allocation.width/2 - tile_width/2; srcs[numanims].y = boardframe->allocation.height/2 - tile_height/2; } numanims++; } /* end of Draws and DrawsLoose */ if ( m->type == CMsgPlayerDiscards ) { updated = 1; /* update the concealed tiles */ for ( i=0 ; i < p->num_concealed ; i++ ) { button_set_tile(pd->conc[i],p->concealed[i],cori); gtk_widget_show(pd->conc[i]); } for ( ; i < MAX_CONCEALED ; i++ ) { gtk_widget_hide(pd->conc[i]); } /* the source for animation is the previous rightmost tile for other players, or the selected tile, for us. Note that selected button may not be set, if we're replaying history. In that case, we won't bother to set the animation position, in the knowledge that it won't actually be animated. This is far too
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -