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