1 /*
2  * $Source: /cvsroot/cgoban1/cgoban1/src/cgbuts.c,v $
3  * $Revision: 1.2 $
4  * $Author: wmshub $
5  * $Date: 2002/05/31 23:40:54 $
6  *
7  * src/cgbuts.c, part of Complete Goban (game program)
8  * Copyright (C) 1995-1996 William Shubert.
9  * See "configure.h.in" for more copyright information.
10  *
11  * This code extends the wmslib/but library to add special buttons needed
12  *   for cgoban.
13  *
14  * The globe data was extracted from the CIA World Data Bank II map database.
15  *   via XEarth.  See the main copyright for information about this.
16  */
17 
18 #include <math.h>
19 #include <wms.h>
20 #include <but/but.h>
21 #include <but/net.h>
22 #include <wms/rnd.h>
23 #include <wms/str.h>
24 #include "goBoard.h"
25 #include "drawStone.h"
26 #ifdef  _CGBUTS_H_
27   Levelization Error.
28 #endif
29 #include "cgbuts.h"
30 
31 
32 /**********************************************************************
33  * Forward Declarations
34  **********************************************************************/
35 static ButOut  grid_mmove(But *but, int x, int y);
36 static ButOut  grid_mleave(But *but);
37 static ButOut  grid_mpress(But *but, int butnum, int x, int y);
38 static ButOut  grid_mrelease(But *but, int butnum, int x, int y);
39 static void  grid_draw(But *but, int x,int y,int w,int h);
40 static ButOut  grid_destroy(But *but);
41 static void  grid_newflags(But *but, uint fl);
42 static ButOut  gridNetPress(But *but, void *buf, int bufLen);
43 static void  drawRewChar(void *packet, ButWin *win,
44 			 int x, int y, int w, int h);
45 static void  drawBackChar(void *packet, ButWin *win,
46 			  int x, int y, int w, int h);
47 static void  drawFwdChar(void *packet, ButWin *win,
48 			 int x, int y, int w, int h);
49 static void  drawFfChar(void *packet, ButWin *win,
50 			int x, int y, int w, int h);
51 static void  drawWStoneChar(void *packet, ButWin *win,
52 			    int x, int y, int w, int h);
53 static void  drawBStoneChar(void *packet, ButWin *win,
54 			    int x, int y, int w, int h);
55 static void  grid_morePixmaps(Cgbuts *b, int newNumPixmaps);
56 static void  gobanPic_draw(But *but, int x,int y, int w,int h);
57 static ButOut  gobanPic_destroy(But *but);
58 static void  stoneGroup_draw(But *but, int x,int y, int w,int h);
59 static ButOut  stoneGroup_destroy(But *but);
60 static void  computerPic_draw(But *but, int x,int y, int w,int h);
61 static ButOut  computerPic_destroy(But *but);
62 static void  toolPic_draw(But *but, int x,int y, int w,int h);
63 static ButOut  toolPic_destroy(But *but);
64 
65 
66 /**********************************************************************
67  * Global Variables
68  **********************************************************************/
69 const char  *cgbuts_stoneChar[2] = {CGBUTS_WSTONECHAR, CGBUTS_BSTONECHAR};
70 
71 static const ButAction  grid_action = {
72   grid_mmove, grid_mleave, grid_mpress, grid_mrelease,
73   NULL, NULL, grid_draw, grid_destroy, grid_newflags, gridNetPress};
74 
75 static const ButAction  gobanPic_action = {
76   NULL, NULL, NULL, NULL,
77   NULL, NULL, gobanPic_draw, gobanPic_destroy, but_flags, NULL};
78 
79 static const ButAction  stoneGroup_action = {
80   NULL, NULL, NULL, NULL,
81   NULL, NULL, stoneGroup_draw, stoneGroup_destroy, but_flags, NULL};
82 
83 static const ButAction  computerPic_action = {
84   NULL, NULL, NULL, NULL,
85   NULL, NULL, computerPic_draw, computerPic_destroy, but_flags, NULL};
86 
87 static const ButAction  toolPic_action = {
88   NULL, NULL, NULL, NULL,
89   NULL, NULL, toolPic_draw, toolPic_destroy, but_flags, NULL};
90 
91 
92 /**********************************************************************
93  * Functions
94  **********************************************************************/
cgbuts_init(Cgbuts * cgbuts,ButEnv * env,Rnd * rnd,int color,bool hold,bool hiContrast,int timeWarn)95 void  cgbuts_init(Cgbuts *cgbuts, ButEnv *env, Rnd *rnd, int color,
96 		  bool  hold, bool hiContrast, int timeWarn)  {
97   MAGIC_SET(cgbuts);
98 
99   cgbuts->env = env;
100   cgbuts->dpyDepth = DefaultDepth(butEnv_dpy(env),
101 				  DefaultScreen(butEnv_dpy(env)));
102   cgbuts->dpyRootWindow = RootWindow(butEnv_dpy(env),
103 				     DefaultScreen(butEnv_dpy(env)));
104   cgbuts->pics = NULL;
105   cgbuts->numPics = 0;
106   cgbuts->rnd = rnd;
107   cgbuts->color = color;
108   cgbuts->holdStart = 0;
109   cgbuts->hiContrast = hiContrast;
110   cgbuts->holdEnabled = hold;
111   cgbuts->timeWarn = timeWarn;
112 
113   butEnv_setChar(env, 1.0, CGBUTS_REWCHAR, drawRewChar, NULL);
114   butEnv_setChar(env, 0.5, CGBUTS_BACKCHAR, drawBackChar, NULL);
115   butEnv_setChar(env, 0.5, CGBUTS_FWDCHAR, drawFwdChar, NULL);
116   butEnv_setChar(env, 1.0, CGBUTS_FFCHAR, drawFfChar, NULL);
117   butEnv_setChar(env, 1.0, CGBUTS_WSTONECHAR, drawWStoneChar, cgbuts);
118   butEnv_setChar(env, 1.0, CGBUTS_BSTONECHAR, drawBStoneChar, cgbuts);
119 }
120 
121 
grid_create(Cgbuts * b,ButOut (* func)(But * but),void * packet,ButWin * win,int layer,int flags,int pos)122 But  *grid_create(Cgbuts *b, ButOut (*func)(But *but), void *packet,
123 		  ButWin *win, int layer, int flags, int pos)  {
124   Grid  *grid;
125   But  *but;
126 
127   grid = wms_malloc(sizeof(Grid));
128   MAGIC_SET(grid);
129   but = but_create(win, grid, &grid_action);
130   but->uPacket = packet;
131   but->layer = layer;
132   but->flags = flags;
133 
134   grid->b = b;
135   grid->callback = func;
136   grid->lineGroup = gridLines_center;
137   grid->starPoint = FALSE;
138   grid->pos = pos;
139   grid->pressColor = goStone_black;
140   grid->stoneVersion = rnd_int(b->rnd) % CGBUTS_NUMWHITE;
141   grid->ptype = goStone_empty;
142   grid->grey = FALSE;
143   grid->holdRequired = FALSE;
144   grid->markType = goMark_none;
145   grid->markAux = 0;
146   but_init(but);
147   return(but);
148 }
149 
150 
grid_setStone(But * but,GoStone piece,bool grey)151 void  grid_setStone(But *but, GoStone piece, bool grey)  {
152   Grid  *grid = but->iPacket;
153 
154   assert(but->action == &grid_action);
155   if ((piece != grid->ptype) || (grey != grid->grey))  {
156     grid->ptype = piece;
157     grid->grey = grey;
158     but_draw(but);
159   }
160 }
161 
162 
grid_setMark(But * but,GoMarkType mark,int aux)163 void  grid_setMark(But *but, GoMarkType mark, int aux)  {
164   Grid  *grid = but->iPacket;
165 
166   assert(but->action == &grid_action);
167   if ((grid->markType != mark) || (grid->markAux != aux))  {
168     grid->markType = mark;
169     grid->markAux = aux;
170     but_draw(but);
171   }
172 }
173 
174 
grid_destroy(But * but)175 static ButOut  grid_destroy(But *but)  {
176   Grid  *grid = but->iPacket;
177 
178   wms_free(grid);
179   return(0);
180 }
181 
182 
grid_newflags(But * but,uint fl)183 static void  grid_newflags(But *but, uint fl)  {
184   uint  ofl = but->flags;
185 
186   but->flags = fl;
187   if ((ofl & (BUT_TWITCHED|BUT_PRESSED|BUT_NETTWITCH|BUT_NETPRESS)) !=
188       (fl & (BUT_TWITCHED|BUT_PRESSED|BUT_NETTWITCH|BUT_NETPRESS)))  {
189     but_draw(but);
190   }
191 }
192 
193 
grid_mmove(But * but,int x,int y)194 static ButOut  grid_mmove(But *but, int x, int y)  {
195   uint  newflags = but->flags, retval = BUTOUT_CAUGHT;
196   Grid  *grid;
197 
198   if (!(but->flags & BUT_PRESSABLE))
199     return(BUTOUT_CAUGHT);
200   if ((x < but->x) || (y < but->y) ||
201       (x >= but->x + but->w) || (y >= but->y + but->h))  {
202     newflags &= ~BUT_TWITCHED;
203     if (newflags != but->flags)  {
204       butEnv_setCursor(but->win->env, but, butCur_idle);
205       but_newFlags(but, newflags);
206     }
207     if (!(newflags & BUT_LOCKED))
208       retval = 0;
209   } else  {
210     newflags |= BUT_TWITCHED;
211     if (newflags != but->flags)  {
212       grid = but->iPacket;
213       assert(MAGIC(grid));
214       grid->b->holdStart = butWin_env(but_win(but))->eventTime;
215       butEnv_setCursor(but->win->env, but, butCur_twitch);
216       but_newFlags(but, newflags);
217     }
218   }
219   return(retval);
220 }
221 
222 
grid_mleave(But * but)223 static ButOut  grid_mleave(But *but)  {
224   int  newflags = but->flags;
225 
226   newflags &= ~BUT_TWITCHED;
227   if (newflags != but->flags)  {
228     butEnv_setCursor(but->win->env, but, butCur_idle);
229     but_newFlags(but, newflags);
230   }
231   return(BUTOUT_CAUGHT);
232 }
233 
234 
grid_mpress(But * but,int butnum,int x,int y)235 static ButOut  grid_mpress(But *but, int butnum, int x, int y)  {
236   int  newflags = but->flags, retval = BUTOUT_CAUGHT;
237   Grid  *grid;
238 
239   if (butnum == 1)  {
240     grid = but->iPacket;
241     assert(MAGIC(grid));
242     /*
243      * Check to make sure that the user has been holding the mouse there
244      *   long enough.
245      * Holding the mouse is only necessare if all of these are true:
246      *   - Cgbuts.holdEnabled is TRUE.  This lets the user turn on and off
247      *     all holds globally.
248      *   - This particular button has hold enabled.  This lets cgoban turn
249      *     off hold when you are in a situation where an undo is no problem.
250      *   - No modifiers are pressed.  Same reason as the previous.
251      */
252     if (((but->win->env->keyModifiers & (ShiftMask | ControlMask)) == 0) &&
253 	grid->holdRequired && grid->b->holdEnabled &&
254 	(butWin_env(but_win(but))->eventTime - grid->b->holdStart <
255 	 CGBUTS_HOLDTIME))
256       retval |= BUTOUT_ERR;
257     else
258       newflags |= BUT_PRESSED|BUT_LOCKED;
259   } else
260     retval |= BUTOUT_ERR;
261   /*
262    * if (!(but->flags & BUT_PRESSED) && (newflags & BUT_PRESSED))
263    *   snd_play(&pe_move_snd);
264    */
265   if (newflags != but->flags)
266     but_newFlags(but, newflags);
267   return(retval);
268 }
269 
270 
grid_mrelease(But * but,int butnum,int x,int y)271 static ButOut  grid_mrelease(But *but, int butnum, int x, int y)  {
272   int  newflags = but->flags, retval = BUTOUT_CAUGHT;
273   Grid  *grid = but->iPacket;
274   bool  makeCallback = FALSE;
275 
276   if (butnum != 1)
277     return(retval);
278   if (but->flags & BUT_TWITCHED)  {
279     if (but->flags & BUT_PRESSED)  {
280       if (but->id)
281 	butRnet_butSpecSend(but, NULL, 0);
282       makeCallback = TRUE;
283     }
284   } else
285     retval |= BUTOUT_ERR;
286   newflags &= ~(BUT_PRESSED|BUT_LOCKED);
287   if (newflags != but->flags)
288     but_newFlags(but, newflags);
289   if (makeCallback)
290     retval |= grid->callback(but);
291   return(retval);
292 }
293 
294 
grid_draw(But * but,int x,int y,int w,int h)295 static void  grid_draw(But *but, int x,int y,int w,int h)  {
296   static const struct  {
297     int  numPoints, points[5];
298   } lineFormats[9] = {
299     {3, {4,2,3}},     /* ul */
300     {4, {1,3,2,4}},   /* top */
301     {3, {1,2,4}},     /* ur */
302     {4, {0,4,2,3}},   /* left */
303     {5, {1,3,2,0,4}}, /* center */
304     {4, {0,4,2,1}},   /* right */
305     {3, {0,2,3}},     /* ll */
306     {4, {1,3,2,0}},   /* bottom */
307     {3, {0,2,1}}};    /* lr */
308   Grid  *grid = but->iPacket;
309   int  i, lineWidth, starSize, flags = but->flags;
310   Display  *dpy;
311   XPoint  points[5], lines[5];
312   GC  gc = but->win->env->gc;
313   GoStone  markColor;
314   Cgbuts  *b = grid->b;
315 
316   assert(MAGIC(b));
317   dpy = but->win->env->dpy;
318   /* Points are:
319    *     0
320    *     |
321    * 1 - 2 - 3
322    *     |
323    *     4
324    */
325   if ((grid->markType != goMark_letter) && (grid->markType != goMark_number) &&
326       (grid->lineGroup != gridLines_none) &&
327       ((grid->ptype == goStone_empty) || grid->grey))  {
328     butEnv_setXFg(but->win->env, BUT_FG);
329     lineWidth = (but->w + 15) / 30;
330     if (lineWidth < 1)
331       lineWidth = 1;
332     XSetLineAttributes(dpy, gc, lineWidth, LineSolid, CapButt, JoinMiter);
333     points[0].x = points[2].x = points[4].x = but->x + but->w/2;
334     points[1].x = but->x;
335     points[3].x = but->x + but->w;
336     points[0].y = but->y;
337     points[1].y = points[2].y = points[3].y = but->y + but->h/2;
338     points[4].y = but->y + but->h;
339     for (i = 0;  i < lineFormats[grid->lineGroup].numPoints;  ++i)
340       lines[i] = points[lineFormats[grid->lineGroup].points[i]];
341     XDrawLines(dpy, but->win->win, gc, lines,
342 	       lineFormats[grid->lineGroup].numPoints, CoordModeOrigin);
343     if (grid->starPoint)  {
344       butEnv_setXFg(but->win->env, BUT_FG);
345       starSize = (((but->w + 6 - lineWidth*6) / 12) * 2) + lineWidth+1;
346       if (starSize > 1)  {
347 	XFillArc(dpy, but->win->win, gc, but->x+(but->w - starSize)/2,
348 		 but->y + (but->h-starSize)/2, starSize, starSize,
349 		 0, 360*64);
350       }
351     }
352   }
353   if ((grid->ptype == goStone_empty) &&
354       !(flags & (BUT_TWITCHED|BUT_NETTWITCH)) &&
355       (grid->markType == goMark_none))
356     return;
357   markColor = grid->ptype;
358   if (grid->ptype != goStone_empty)  {
359     if (flags & (BUT_PRESSED|BUT_NETPRESS))  {
360       /* Pressed.  Invert the greyness. */
361       cgbuts_drawp(b, but->win, grid->ptype, !grid->grey, but->x, but->y,
362 		   but->w, grid->stoneVersion, x,y,w,h);
363     } else  {
364       cgbuts_drawp(b, but->win, grid->ptype, grid->grey, but->x, but->y,
365 		   but->w, grid->stoneVersion, x,y,w,h);
366       if (flags & (BUT_TWITCHED|BUT_NETTWITCH))  {
367 	/* Twitched.  Draw a small stone in the middle of it. */
368 	if (grid->grey)  {
369 	  cgbuts_drawp(b, but->win, grid->ptype, FALSE,
370 		       but->x+(but->w+1)/4, but->y+(but->w+1)/4,
371 		       but->w/2, grid->stoneVersion, x,y,w,h);
372 	} else  {
373 	  cgbuts_drawp(b, but->win, goStone_opponent(grid->ptype), TRUE,
374 		       but->x+(but->w+1)/4, but->y+(but->w+1)/4,
375 		       but->w/2, grid->stoneVersion, x,y,w,h);
376 	}
377       }
378     }
379   } else  {
380     assert(grid->ptype == goStone_empty);
381     if (flags & (BUT_PRESSED|BUT_NETPRESS|BUT_TWITCHED|BUT_NETTWITCH))  {
382       markColor = grid->pressColor;
383       if (flags & (BUT_PRESSED |BUT_NETPRESS))  {
384 	cgbuts_drawp(b, but->win, grid->pressColor, FALSE,
385 		     but->x, but->y, but->w, grid->stoneVersion, x,y,w,h);
386       } else  {
387 	/* Grid is twitched only. */
388 	cgbuts_drawp(b, but->win, grid->pressColor, TRUE,
389 		     but->x, but->y, but->w, grid->stoneVersion, x,y,w,h);
390       }
391     }
392   }
393   if ((grid->markType != goMark_none) &&
394       (!(flags & (BUT_PRESSED|BUT_NETPRESS))))  {
395     cgbuts_markPiece(b, but->win, markColor, grid->markType, grid->markAux,
396 		     but->x, but->y, but->w, grid->stoneVersion, x,y,w,h);
397   }
398 }
399 
400 
gridNetPress(But * but,void * buf,int bufLen)401 static ButOut  gridNetPress(But *but, void *buf, int bufLen)  {
402   Grid  *grid = but->iPacket;
403 
404   assert(bufLen == 0);
405   /* snd_play(&pe_move_snd); */
406   return(grid->callback(but));
407 }
408 
409 
cgbuts_drawp(Cgbuts * b,ButWin * win,GoStone piece,bool grey,int x,int y,int size,int stoneVersion,int dx,int dy,int dw,int dh)410 void  cgbuts_drawp(Cgbuts *b, ButWin *win, GoStone piece, bool grey,
411 		   int x, int y, int size, int stoneVersion,
412 		   int dx,int dy, int dw,int dh)  {
413   ButEnv  *env = win->env;
414   Display  *dpy = env->dpy;
415   GC  gc = env->gc2;
416   int  copyStart;
417   int  worldNum = 0;
418 
419   if (size >= b->numPics)
420     grid_morePixmaps(b, size + 1);
421   if (b->pics[size].stonePixmaps == None)
422     drawStone_newPics(env, b->rnd, CGBUTS_GREY(0),
423 		      &b->pics[size].stonePixmaps,
424 		      &b->pics[size].maskBitmaps, size,
425 		      butEnv_isColor(env) && !b->hiContrast);
426   if (stoneVersion >= CGBUTS_NUMWHITE)  {
427     worldNum = 2 + stoneVersion / CGBUTS_NUMWHITE;
428     stoneVersion %= CGBUTS_NUMWHITE;
429   }
430 
431   if ((dx >= x+size) || (dy >= y+size) ||
432       (dx+dw <= x) || (dy+dh <= y))
433     return;
434   if (dx < x)  {
435     dw -= x - dx;
436     dx = x;
437   }
438   if (dy < y)  {
439     dh -= y - dy;
440     dy = y;
441   }
442   if (dx + dw > x + size)
443     dw = x + size - dx;
444   if (dy + dh > y + size)
445     dh = y + size - dy;
446   XSetClipMask(dpy, gc, b->pics[size].maskBitmaps);
447   if (grey)  {
448     if ((x & 1) == (y & 1))
449       XSetClipOrigin(dpy, gc, x - size - win->xOff, y - win->yOff);
450     else
451       XSetClipOrigin(dpy, gc, x - size * 2 - win->xOff, y - win->yOff);
452   } else  {
453     XSetClipOrigin(dpy, gc, x - win->xOff, y - win->yOff);
454   }
455   copyStart = 0;
456   if (piece == goStone_white)
457     copyStart = (stoneVersion + 1) * size;
458   XCopyArea(dpy, b->pics[size].stonePixmaps, win->win, gc,
459 	    copyStart+dx-x,dy-y, dw,dh, dx - win->xOff, dy - win->yOff);
460   if (worldNum)  {
461     copyStart = 0;
462     if (piece == goStone_black)
463       copyStart = (stoneVersion + 1) * size;
464     XSetClipOrigin(dpy, gc, x-size*worldNum - win->xOff, y - win->yOff);
465     XCopyArea(dpy, b->pics[size].stonePixmaps, win->win, gc,
466 	      copyStart+dx-x,dy-y, dw,dh, dx - win->xOff, dy - win->yOff);
467   }
468   XSetClipMask(dpy, gc, None);
469 }
470 
471 
cgbuts_markPiece(Cgbuts * b,ButWin * win,GoStone piece,GoMarkType markType,int markAux,int x,int y,int w,int stoneVersion,int dx,int dy,int dw,int dh)472 void  cgbuts_markPiece(Cgbuts *b, ButWin *win, GoStone piece,
473 		       GoMarkType markType, int markAux,
474 		       int x, int y, int w, int stoneVersion,
475 		       int dx,int dy, int dw,int dh)  {
476   ButEnv *env = win->env;
477   Display *dpy = env->dpy;
478   GC  gc = env->gc;
479   int  lw = 0;
480   XPoint  points[4];
481   int  off;
482   char  text[4];
483 
484   if ((markType >= goMark_lastMove) && (markType <= goMark_circle))  {
485     /* Must set up line attributes. */
486     lw = (w + 7) / 15;
487     if (lw < 1)
488       lw = 1;
489     XSetLineAttributes(dpy, gc, lw, LineSolid, CapButt, JoinMiter);
490   }
491   if (piece == goStone_black)
492     butEnv_setXFg(env, BUT_WHITE);
493   else
494     butEnv_setXFg(env, BUT_BLACK);
495   switch(markType)  {
496   case goMark_none:
497     break;
498   case goMark_triangle:
499     points[0].x = x+w/2 - win->xOff;
500     points[0].y = y+lw - win->yOff;
501     points[1].x = x+((w*0.9330127)-(lw*0.8660254)+0.5) - win->xOff;
502     points[1].y = y+((w*0.75)-(lw*0.5)+0.5) - win->yOff;
503     points[2].x = x+((w*0.0669873)+(lw*0.8660254)+0.5) - win->xOff;
504     points[2].y = points[1].y;
505     points[3] = points[0];
506     XDrawLines(dpy, win->win, gc, points, 4, CoordModeOrigin);
507     break;
508   case goMark_x:
509     off = (int)(w*0.14644661+lw*0.5+1.5);
510     XDrawLine(dpy, win->win, gc,
511 	      x + off - win->xOff, y + off - win->yOff,
512 	      x + w - off - win->xOff-(lw&1), y + w - off - win->yOff-(lw&1));
513     XDrawLine(dpy, win->win, gc,
514 	      x + off - win->xOff,  y + w - off  - win->yOff-(lw&1),
515 	      x + w - off - win->xOff-(lw&1), y + off - win->yOff);
516     break;
517   case goMark_ko:
518   case goMark_square:
519     off = (int)(w*0.14644661+lw*0.5+0.5);
520     XDrawRectangle(dpy, win->win, gc, x + off - win->xOff, y + off - win->yOff,
521 		   w-off*2-(lw&1),w-off*2-(lw&1));
522     break;
523   case goMark_lastMove:
524   case goMark_circle:
525     off = (w + 1) / 4;
526     XDrawArc(dpy, win->win, gc, x + off - win->xOff, y + off - win->yOff,
527 	     w-off*2-1,w-off*2-1, 0,360*64);
528     break;
529   case goMark_smBlack:
530   case goMark_smWhite:
531     if (markType == goMark_smBlack)
532       cgbuts_drawp(b, win, goStone_black, FALSE, x+(w+1)/4,y+(w+1)/4, w/2,
533 		   stoneVersion, dx,dy,dw,dh);
534     else
535       cgbuts_drawp(b, win, goStone_white, FALSE, x+(w+1)/4,y+(w+1)/4, w/2,
536 		   stoneVersion, dx,dy,dw,dh);
537     break;
538   case goMark_letter:
539     text[0] = markAux;
540     text[1] = '\0';
541     butWin_write(win, x + (w - butEnv_textWidth(env, text, 1)) / 2,
542 		 y + (w - butEnv_fontH(env, 1)) / 2, text, 1);
543     break;
544   case goMark_number:
545     assert(markAux >= 0);
546     if (markAux > 999)
547       markAux = 999;
548     if ((markAux > 99) && (w < butEnv_fontH(env, 0) * 2))
549       sprintf(text, "%02d", markAux % 100);
550     else
551       sprintf(text, "%d", markAux);
552     butWin_write(win, x + (w - butEnv_textWidth(env, text, 1)) / 2,
553 		 y + (w - butEnv_fontH(env, 1)) / 2, text, 1);
554     break;
555   }
556 }
557 
558 
grid_setPress(But * but,GoStone pressColor)559 void  grid_setPress(But *but, GoStone pressColor)  {
560   Grid  *grid;
561 
562   assert(but->action == &grid_action);
563   if (pressColor == goStone_empty)  {
564     if (but->flags & BUT_PRESSABLE)
565       but_setFlags(but, BUT_NOPRESS);
566   } else  {
567     if (!(but->flags & BUT_PRESSABLE))
568       but_setFlags(but, BUT_PRESSABLE);
569     grid = but->iPacket;
570     grid->pressColor = pressColor;
571   }
572   if (but->flags & BUT_TWITCHED)
573     but_draw(but);
574 }
575 
576 
drawRewChar(void * packet,ButWin * win,int x,int y,int w,int h)577 static void  drawRewChar(void *packet, ButWin *win,
578 			 int x, int y, int w, int h)  {
579   XPoint  points[8];
580   Display  *dpy = butEnv_dpy(butWin_env(win));
581   Window  xwin = butWin_xwin(win);
582   GC  gc = butEnv_gc(butWin_env(win));
583 
584   h &= ~1;
585   w &= ~1;
586   points[0].x = x;
587   points[0].y = y+h/2;
588   points[1].x = x+w/2;
589   points[1].y = y;
590   points[2].x = x+w/2;
591   points[2].y = y+h/2;
592   points[3].x = x+w;
593   points[3].y = y;
594   points[4].x = x+w;
595   points[4].y = y+h;
596   points[5] = points[2];
597   points[6].x = x+w/2;
598   points[6].y = y+h;
599   points[7] = points[0];
600   XFillPolygon(dpy, xwin, gc, points, 8, Nonconvex, CoordModeOrigin);
601 }
602 
603 
drawBackChar(void * packet,ButWin * win,int x,int y,int w,int h)604 static void  drawBackChar(void *packet, ButWin *win,
605 			  int x, int y, int w, int h)  {
606   XPoint  points[4];
607   Display  *dpy = butEnv_dpy(butWin_env(win));
608   Window  xwin = butWin_xwin(win);
609   GC  gc = butEnv_gc(butWin_env(win));
610 
611   h &= ~1;
612   points[0].x = x;
613   points[0].y = y+h/2;
614   points[1].x = x+w;
615   points[1].y = y;
616   points[2].x = x+w;
617   points[2].y = y+h;
618   points[3] = points[0];
619   XFillPolygon(dpy, xwin, gc, points, 4, Nonconvex, CoordModeOrigin);
620 }
621 
622 
drawFwdChar(void * packet,ButWin * win,int x,int y,int w,int h)623 static void  drawFwdChar(void *packet, ButWin *win,
624 			 int x, int y, int w, int h)  {
625   XPoint  points[4];
626   Display  *dpy = butEnv_dpy(butWin_env(win));
627   Window  xwin = butWin_xwin(win);
628   GC  gc = butEnv_gc(butWin_env(win));
629 
630   h &= ~1;
631   points[0].x = x;
632   points[0].y = y;
633   points[1].x = x+w;
634   points[1].y = y+h/2;
635   points[2].x = x;
636   points[2].y = y+h;
637   points[3] = points[0];
638   XFillPolygon(dpy, xwin, gc, points, 4, Nonconvex, CoordModeOrigin);
639 }
640 
641 
drawFfChar(void * packet,ButWin * win,int x,int y,int w,int h)642 static void  drawFfChar(void *packet, ButWin *win,
643 			int x, int y, int w, int h)  {
644   XPoint  points[8];
645   Display  *dpy = butEnv_dpy(butWin_env(win));
646   Window  xwin = butWin_xwin(win);
647   GC  gc = butEnv_gc(butWin_env(win));
648 
649   h &= ~1;
650   w &= ~1;
651   points[0].x = x;
652   points[0].y = y;
653   points[1].x = x+w/2;
654   points[1].y = y+h/2;
655   points[2].x = x+w/2;
656   points[2].y = y;
657   points[3].x = x+w;
658   points[3].y = y+h/2;
659   points[4].x = x+w/2;
660   points[4].y = y+h;
661   points[5] = points[1];
662   points[6].x = x;
663   points[6].y = y+h;
664   points[7] = points[0];
665   XFillPolygon(dpy, xwin, gc, points, 8, Nonconvex, CoordModeOrigin);
666 }
667 
668 
drawWStoneChar(void * packet,ButWin * win,int x,int y,int w,int h)669 static void  drawWStoneChar(void *packet, ButWin *win,
670 			    int x, int y, int w, int h)  {
671   Cgbuts  *b = packet;
672 
673   cgbuts_drawp(b, win, goStone_white, FALSE, x,y, w, 1, x,y,w,h);
674 }
675 
676 
drawBStoneChar(void * packet,ButWin * win,int x,int y,int w,int h)677 static void  drawBStoneChar(void *packet, ButWin *win,
678 			    int x, int y, int w, int h)  {
679   Cgbuts  *b = packet;
680 
681   cgbuts_drawp(b, win, goStone_black, FALSE, x,y, w, 1, x,y,w,h);
682 }
683 
684 
grid_morePixmaps(Cgbuts * b,int newNumPics)685 static void  grid_morePixmaps(Cgbuts *b, int newNumPics)  {
686   int  i;
687   CgbutsPic  *newPics;
688 
689   assert(MAGIC(b));
690   newPics = wms_malloc(newNumPics * sizeof(CgbutsPic));
691   for (i = 0;  i < b->numPics;  ++i)  {
692     newPics[i] = b->pics[i];
693   }
694   for (;  i < newNumPics;  ++i)  {
695     newPics[i].stonePixmaps = None;
696     newPics[i].maskBitmaps = None;
697   }
698   b->numPics = newNumPics;
699   if (b->pics)  {
700     wms_free(b->pics);
701   }
702   b->pics = newPics;
703 }
704 
705 
gobanPic_create(Cgbuts * b,ButWin * win,int layer,int flags)706 But  *gobanPic_create(Cgbuts *b, ButWin *win, int layer, int flags)  {
707   But  *but;
708 
709   but = but_create(win, b, &gobanPic_action);
710   but->uPacket = NULL;
711   but->layer = layer;
712   but->flags = flags;
713   return(but);
714 }
715 
716 
gobanPic_draw(But * but,int x,int y,int w,int h)717 static void  gobanPic_draw(But *but, int x,int y, int w,int h)  {
718   ButWin  *win = but->win;
719   ButEnv  *env = win->env;
720   int  w13 = (but->w+1)/3;
721   int  w16 = (but->w + 2) / 6;
722   int  stonew = but->w/3;
723   int  bw = butEnv_stdBw(env);
724   int  cgtop = but->y + (but->w - stonew - bw - (w13 + w16)) / 2;
725   int  bdtop = cgtop + stonew + bw;
726   XPoint  points[4];
727 
728   butEnv_setXFg(env, CGBUTS_COLORBOARD(0));
729   XFillRectangle(env->dpy, win->win, env->gc, but->x,bdtop+w13,
730 		 but->w,w16);
731   butEnv_setXFg(env, CGBUTS_COLORBOARD(225));
732   points[0].x = but->x;
733   points[0].y = bdtop+w13;
734   points[1].x = but->x + w16;
735   points[1].y = bdtop;
736   points[2].x = but->x + but->w - w16;
737   points[2].y = points[1].y;
738   points[3].x = but->x + but->w;
739   points[3].y = points[0].y;
740   XFillPolygon(env->dpy, win->win, env->gc, points, 4,
741 	       Convex, CoordModeOrigin);
742 }
743 
744 
gobanPic_destroy(But * but)745 static ButOut  gobanPic_destroy(But *but)  {
746   return(0);
747 }
748 
749 
stoneGroup_create(Cgbuts * b,ButWin * win,int layer,int flags)750 But  *stoneGroup_create(Cgbuts *b, ButWin *win, int layer, int flags)  {
751   But  *but;
752 
753   but = but_create(win, b, &stoneGroup_action);
754   but->uPacket = NULL;
755   but->layer = layer;
756   but->flags = flags;
757   return(but);
758 }
759 
760 
stoneGroup_draw(But * but,int x,int y,int w,int h)761 static void  stoneGroup_draw(But *but, int x,int y, int w,int h)  {
762   ButWin  *win = but->win;
763   int  stoneW;
764 
765   stoneW = but->w >> 1;
766   cgbuts_drawp(but->iPacket, win, goStone_black, FALSE,
767 	       but->x, but->y, stoneW, 0, x, y, w, h);
768   cgbuts_drawp(but->iPacket, win, goStone_white, FALSE,
769 	       but->x + stoneW, but->y, stoneW, 1, x, y, w, h);
770   cgbuts_drawp(but->iPacket, win, goStone_white, FALSE,
771 	       but->x, but->y + stoneW, stoneW, 2, x, y, w, h);
772   cgbuts_drawp(but->iPacket, win, goStone_black, FALSE,
773 	       but->x + stoneW, but->y + stoneW, stoneW, 3, x, y, w, h);
774 }
775 
776 
stoneGroup_destroy(But * but)777 static ButOut  stoneGroup_destroy(But *but)  {
778   return(0);
779 }
780 
781 
computerPic_create(Cgbuts * b,ButWin * win,int layer,int flags)782 But  *computerPic_create(Cgbuts *b, ButWin *win, int layer, int flags)  {
783   But  *but;
784 
785   but = but_create(win, b, &computerPic_action);
786   but->uPacket = NULL;
787   but->layer = layer;
788   but->flags = flags;
789   return(but);
790 }
791 
792 
computerPic_draw(But * but,int x,int y,int w,int h)793 static void  computerPic_draw(But *but, int x,int y, int w,int h)  {
794   XPoint  points[4];
795   ButWin  *win = but->win;
796   Display  *dpy = butEnv_dpy(butWin_env(win));
797   Window  xwin = butWin_xwin(win);
798   GC  gc = butEnv_gc(butWin_env(win));
799   int  h2 = but->h / 2, h3 = but->h / 3, h12 = but->h / 12;
800   int  w6 = but->w / 6, w9 = but->w / 9;
801 
802   x = but->x;
803   y = but->y;
804   w = but->w;
805   h = but->h;
806   y += (h - (h12 + h2 + h12 + h3)) / 2;
807   points[0].x = x;
808   points[0].y = y + h12 + h2 + h3;
809   points[1].x = x + w6;
810   points[1].y = y + h12 + h2 + h12;
811   points[2].x = x + w - w6;
812   points[2].y = y + h12 + h2 + h12;
813   points[3].x = x + w;
814   points[3].y = y + h12 + h2 + h3;
815   butEnv_setXFg(butWin_env(win), BUT_BLACK);
816   XFillPolygon(dpy, xwin, gc, points, 4, Nonconvex, CoordModeOrigin);
817   XFillRectangle(dpy, xwin, gc, x+w6,y+h12, w-2*w6,h2);
818   butEnv_setXFg(butWin_env(win), BUT_PBG);
819   XFillRectangle(dpy, xwin, gc, x+w6+w9,y+h12*2, w-2*w6-2*w9,h2-h12*2);
820 }
821 
822 
computerPic_destroy(But * but)823 static ButOut  computerPic_destroy(But *but)  {
824   return(0);
825 }
826 
827 
toolPic_create(Cgbuts * b,ButWin * win,int layer,int flags)828 But  *toolPic_create(Cgbuts *b, ButWin *win, int layer, int flags)  {
829   But  *but;
830 
831   but = but_create(win, b, &toolPic_action);
832   but->uPacket = NULL;
833   but->layer = layer;
834   but->flags = flags;
835   return(but);
836 }
837 
838 
toolPic_draw(But * but,int x,int y,int w,int h)839 static void  toolPic_draw(But *but, int x,int y, int w,int h)  {
840   XPoint  points[12];
841   ButWin  *win = but->win;
842   Display  *dpy = butEnv_dpy(butWin_env(win));
843   Window  xwin = butWin_xwin(win);
844   GC  gc = butEnv_gc(butWin_env(win));
845 
846   /* Size of hammer or screwdriver relative to whole picture. */
847   const float  subBoxSize = 0.75;
848   const float  bevel = 0.25;
849   const float  hr2 = 0.70710678;  /* Half of Root 2 */
850 
851   /* Hammer constants. */
852   const float  hHandleW = 0.1;
853   const float  hJointW = 0.2;
854   const float  hJointL = 0.2;
855   const float  hClawL = 0.4;
856   const float  hNeckW = 0.07;
857   const float  hHeadL = 0.1;
858 
859   /* Screwdriver constants. */
860   const float  sHandleW = 0.2;
861   const float  sHandleL = 0.5;
862   const float  sHEndW = 0.15;
863   const float  sBladeW = 0.04;
864 
865   float  th;
866   float  bx, by;
867 
868   x = but->x;
869   y = but->y;
870   h = but->h;
871   th = h * subBoxSize;
872   bx = x + h * (1.0 - subBoxSize);
873   by = y + h * (1.0 - subBoxSize);
874 
875   /* The hammer's handle. */
876   points[0].x = x;
877   points[0].y = y + th * (1.0 - hHandleW) + 0.5;
878   points[1].x = x + th * hHandleW + 0.5;
879   points[1].y = points[0].y + (points[1].x - points[0].x);
880   points[2].x = x + th * (1.0 - hJointL * hr2) + 0.5;
881   points[2].y = points[1].y - (points[2].x - points[1].x);
882   points[3].x = points[2].x - (points[1].x - points[0].x);
883   points[3].y = points[2].y - (points[1].x - points[0].x);
884 
885 
886   /* Add beveling to the handle. */
887   points[4] = points[0];
888   points[5].x = x + th * hHandleW * bevel + 0.5;
889   points[5].y = points[4].y + (points[5].x - points[4].x);
890   points[6].x = x + th * (1.0 - hJointL * hr2) + 0.5;
891   points[6].y = points[5].y - (points[6].x - points[5].x);
892   points[7] = points[3];
893 
894   points[9] = points[1];
895   points[10] = points[2];
896   points[8].x = points[9].x - th * hHandleW * bevel + 0.5;
897   points[8].y = points[9].y - (points[9].x - points[8].x);
898   points[11].x = points[10].x - (points[9].x - points[8].x);
899   points[11].y = points[10].y - (points[9].x - points[8].x);
900 
901   butEnv_setXFg(butWin_env(win), CGBUTS_COLORBOARD(200));
902   XFillPolygon(dpy, xwin, gc, points, 4, Nonconvex, CoordModeOrigin);
903   butEnv_setXFg(butWin_env(win), CGBUTS_COLORBOARD(0));
904   XFillPolygon(dpy, xwin, gc, points+4, 4, Nonconvex, CoordModeOrigin);
905   butEnv_setXFg(butWin_env(win), CGBUTS_COLORBOARD(255));
906   XFillPolygon(dpy, xwin, gc, points+8, 4, Nonconvex, CoordModeOrigin);
907 
908   /* The hammer's head. */
909   points[0].x = x + th + 0.5;
910   points[0].y = y + th * (hJointL * hr2) + 0.5;
911   points[1].x = points[0].x - (points[0].y - y);
912   points[1].y = y;
913   points[2].x = x + th * (1.0 - hJointL * hr2 - hClawL) + 0.5;
914   points[2].y = y;
915   points[3].x = x + th * (1.0 - (hJointL + hJointW) * hr2) + 0.5;
916   points[3].y = y + (points[1].x - points[3].x);
917   points[4].x = points[3].x + (points[0].x - points[1].x);
918   points[4].y = points[3].y + (points[4].x - points[3].x);
919   points[5].x = x + th * (1.0 - (hJointW + hNeckW) * hr2 * 0.5) + 0.5;
920   points[5].y = points[4].y - (points[5].x - points[4].x);
921   points[6].x = points[5].x;
922   points[6].y = points[4].y + (points[6].x - points[4].x);
923   points[7].x = x + th * (1.0 + (hHeadL * 2.0 - hJointW) * hr2) + 0.5;
924   points[7].y = points[6].y + (points[7].x - points[6].x);
925   points[8].x = points[7].x + (points[0].x - points[4].x);
926   points[8].y = points[7].y - (points[8].x - points[7].x);
927   points[9].x = points[8].x - (points[7].x - points[6].x);
928   points[9].y = points[8].y - (points[7].x - points[6].x);
929   points[10].x = points[0].x - (points[9].y - points[0].y);
930   points[10].y = points[9].y;
931 
932   butEnv_setXFg(butWin_env(win), BUT_BLACK);
933   XFillPolygon(dpy, xwin, gc, points, 11, Nonconvex, CoordModeOrigin);
934 
935   /* The screwdriver's blade. */
936   points[0].x = bx + th * (1.0 - sBladeW * hr2) + 0.5;
937   points[0].y = by + 0.5;
938   points[1].x = bx + th * sHandleW + 0.5;
939   points[1].y = points[0].y + (points[0].x - points[1].x);
940   points[3].x = bx + th + 0.5;
941   points[3].y = points[0].y + (points[3].x - points[0].x);
942   points[2].x = points[1].x + (points[3].x - points[0].x);
943   points[2].y = points[1].y + (points[3].x - points[0].x);
944 
945   butEnv_setXFg(butWin_env(win), CGBUTS_GREY(120));
946   XFillPolygon(dpy, xwin, gc, points, 4, Nonconvex, CoordModeOrigin);
947 
948   /* The screwdriver's handle. */
949   points[4].x = bx + 0.5;
950   points[4].y = by + th * (1.0 - sHandleW * hr2) + 0.5;
951   points[5].x = points[4].x;
952   points[5].y = by + th * (1.0 - sHEndW * hr2) + 0.5;
953   points[6].y = by + th + 0.5;
954   points[6].x = points[5].x + (points[6].y - points[5].y);
955   points[7].y = points[6].y;
956   points[7].x = points[6].x + (points[5].y - points[4].y);
957   points[8].x = bx + th * (sHandleL + sHandleW) * hr2 + 0.5;
958   points[8].y = points[7].y - (points[8].x - points[7].x);
959   points[3].x = points[4].x + (points[8].x - points[7].x);
960   points[3].y = points[4].y - (points[8].x - points[7].x);
961 
962   points[2].x = points[3].x + th * bevel * sHandleW * hr2 + 0.5;
963   points[2].y = points[3].y + (points[2].x - points[3].x);
964   points[9].x = points[8].x - (points[2].x - points[3].x);
965   points[9].y = points[8].y - (points[2].x - points[3].x);
966   points[1].x = points[4].x + (points[2].x - points[3].x);
967   points[1].y = points[4].y + (points[2].x - points[3].x);
968   points[10].x = points[7].x - (points[2].x - points[3].x);
969   points[10].y = points[7].y - (points[2].x - points[3].x);
970   points[0].x = points[5].x + th * bevel * sHEndW * hr2 + 0.5;
971   points[0].y = points[5].y + (points[0].x - points[5].x);
972   points[11].x = points[6].x - (points[0].x - points[5].x);
973   points[11].y = points[6].y - (points[0].x - points[5].x);
974 
975   butEnv_setXFg(butWin_env(win), CGBUTS_COLORBOARD(200));
976   XFillPolygon(dpy, xwin, gc, points+3, 6, Nonconvex, CoordModeOrigin);
977   butEnv_setXFg(butWin_env(win), CGBUTS_COLORBOARD(0));
978   XFillPolygon(dpy, xwin, gc, points, 6, Nonconvex, CoordModeOrigin);
979   butEnv_setXFg(butWin_env(win), CGBUTS_COLORBOARD(255));
980   XFillPolygon(dpy, xwin, gc, points+6, 6, Nonconvex, CoordModeOrigin);
981 }
982 
983 
toolPic_destroy(But * but)984 static ButOut  toolPic_destroy(But *but)  {
985   return(0);
986 }
987 
988 
cgbuts_redraw(Cgbuts * b)989 void  cgbuts_redraw(Cgbuts *b)  {
990   int  i;
991 
992   assert(MAGIC(b));
993   for (i = 0;  i < b->numPics;  ++i)  {
994     if (b->pics[i].stonePixmaps != None)  {
995       XFreePixmap(butEnv_dpy(b->env), b->pics[i].stonePixmaps);
996       XFreePixmap(butEnv_dpy(b->env), b->pics[i].maskBitmaps);
997     }
998   }
999   wms_free(b->pics);
1000   b->pics = NULL;
1001   b->numPics = 0;
1002   butEnv_drawAll(b->env);
1003 }
1004 
1005