1 /*
2 * src/xio/sgfMap.c, part of Complete Goban (game program)
3 * Copyright (C) 1995 William Shubert.
4 * See "configure.h.in" for more copyright information.
5 */
6
7 #include <wms.h>
8 #include <but/but.h>
9 #include <but/net.h>
10 #include <wms/rnd.h>
11 #include <wms/str.h>
12 #include <but/box.h>
13 #include "cgbuts.h"
14 #include "sgfMap.h"
15
16
17 /**********************************************************************
18 * Forward declarations
19 **********************************************************************/
20 static ButOut mmove(But *but, int x, int y);
21 static ButOut mleave(But *but);
22 static ButOut mpress(But *but, int butNum, int x, int y);
23 static ButOut mrelease(But *but, int butNum, int x, int y);
24 static void draw(But *but, int x, int y, int w, int h);
25 static ButOut destroy(But *but);
26 static void relocate(But *but, SgfElem *elem, int x, int y, int numDiag,
27 int moveNum, bool mainLine);
28 static void resizeGraph(SgfMap *map, int newX, int newY);
29 static int findSubtreeY(SgfMap *map, SgfElem *tree, int x0, int y0,
30 int *numDiagOut);
31 static void drawConn(But *but, uint flags, int x, int y, int fontH);
32 static void newFlags(But *but, uint flags);
33 static void redrawEl(But *but, int x, int y);
34 static void newMain(But *but, SgfMap *map, int x, int y);
35
36
37 /**********************************************************************
38 * Functions
39 **********************************************************************/
sgfMap_create(Cgbuts * b,ButOut (* callback)(But * but,int newNodeNum),void * packet,ButWin * win,int layer,int flags,Sgf * sgf)40 But *sgfMap_create(Cgbuts *b, ButOut (*callback)(But *but, int newNodeNum),
41 void *packet, ButWin *win, int layer, int flags,
42 Sgf *sgf) {
43 static const ButAction action = {
44 mmove, mleave, mpress, mrelease,
45 NULL, NULL, draw, destroy, newFlags, NULL};
46 SgfMap *map;
47 But *but;
48
49 map = wms_malloc(sizeof(SgfMap));
50 MAGIC_SET(map);
51 but = but_create(win, map, &action);
52 but->uPacket = packet;
53 but->layer = layer;
54 but->flags = flags;
55
56 map->cgbuts = b;
57 map->callback = callback;
58 map->mapW = map->mapH = 0;
59 map->maxW = map->maxH = 1;
60 map->activeX = map->activeY = 0;
61 map->activeCtrX = map->activeCtrY = -1;
62 map->els = wms_malloc(sizeof(SgfMapElem));
63 map->els[0].flags = 0;
64
65 but_init(but);
66 relocate(but, sgf->top.activeChild, 0, 0, 0, 0, TRUE);
67 map->els[0].flags &= ~SGFMAPFLAGS_CONNL;
68
69 return(but);
70 }
71
72
sgfMap_destroy(But * but)73 void sgfMap_destroy(But *but) {
74 SgfMap *map = but->iPacket;
75
76 assert(MAGIC(map));
77 wms_free(map);
78 }
79
80
sgfMap_resize(But * but,int x,int y)81 void sgfMap_resize(But *but, int x, int y) {
82 SgfMap *map;
83 int fontH;
84
85 map = but->iPacket;
86 assert(MAGIC(map));
87 fontH = butEnv_fontH(but->win->env, 0);
88 but_resize(but, x, y, map->mapW * 3 * fontH + fontH,
89 map->mapH * 3 * fontH + fontH);
90 }
91
92
mmove(But * but,int x,int y)93 static ButOut mmove(But *but, int x, int y) {
94 SgfMap *map = but->iPacket;
95 ButEnv *env = but->win->env;
96 int gx, gy;
97 int gridSpc = butEnv_fontH(env, 0);
98 int gridW = gridSpc * 3;
99 uint newFlags = but->flags;
100 ButOut result = BUTOUT_CAUGHT;
101 bool overBut = TRUE;
102
103 gx = (x - but->x - gridSpc / 2) / gridW;
104 gy = (y - but->y - gridSpc / 2) / gridW;
105 if ((gx < 0) || (gy < 0) || (gx >= map->mapW) || (gy >= map->mapH))
106 overBut = FALSE;
107 else if (map->els[gx + gy * map->maxW].node == NULL)
108 overBut = FALSE;
109 else if ((but->flags & BUT_PRESSED) &&
110 ((gx != map->pressX) || (gy != map->pressY)))
111 overBut = FALSE;
112 if (overBut)
113 newFlags |= BUT_TWITCHED;
114 else {
115 newFlags &= ~BUT_TWITCHED;
116 if (!(newFlags & BUT_LOCKED))
117 result &= ~BUTOUT_CAUGHT;
118 }
119 if (!(but->flags & BUT_TWITCHED) && (newFlags & BUT_TWITCHED))
120 butEnv_setCursor(env, but, butCur_twitch);
121 else if ((but->flags & BUT_TWITCHED) && !(newFlags & BUT_TWITCHED))
122 butEnv_setCursor(env, but, butCur_idle);
123 if (newFlags != but->flags) {
124 but_newFlags(but, newFlags);
125 }
126 return(result);
127 }
128
129
mleave(But * but)130 static ButOut mleave(But *but) {
131 int newflags = but->flags;
132
133 newflags &= ~BUT_TWITCHED;
134 if ((but->flags & BUT_TWITCHED) && !(newflags & BUT_TWITCHED))
135 butEnv_setCursor(but->win->env, but, butCur_idle);
136 if (newflags != but->flags) {
137 but_newFlags(but, newflags);
138 }
139 return(BUTOUT_CAUGHT);
140 }
141
142
mpress(But * but,int butNum,int x,int y)143 static ButOut mpress(But *but, int butNum, int x, int y) {
144 SgfMap *map = but->iPacket;
145 ButOut result = BUTOUT_CAUGHT;
146 ButEnv *env = but->win->env;
147 int gx, gy;
148 int gridSpc = butEnv_fontH(env, 0);
149 int gridW = gridSpc * 3;
150 uint newFlags = but->flags;
151
152 gx = (x - but->x - gridSpc / 2) / gridW;
153 gy = (y - but->y - gridSpc / 2) / gridW;
154 if (!(newFlags & BUT_TWITCHED))
155 result &= ~BUTOUT_CAUGHT;
156 else {
157 assert(gx >= 0);
158 assert(gy >= 0);
159 assert(gx < map->mapW);
160 assert(gy < map->mapH);
161 assert(map->els[gx + gy * map->maxW].node != NULL);
162 if (butNum == 1) {
163 map->pressX = gx;
164 map->pressY = gy;
165 newFlags |= BUT_PRESSED | BUT_LOCKED;
166 } else
167 return(BUTOUT_CAUGHT | BUTOUT_ERR);
168 }
169 if (newFlags != but->flags)
170 but_newFlags(but, newFlags);
171 return(result);
172 }
173
174
mrelease(But * but,int butNum,int x,int y)175 static ButOut mrelease(But *but, int butNum, int x, int y) {
176 ButOut result = BUTOUT_CAUGHT;
177 bool makeCallback = FALSE;
178 uint newFlags = but->flags;
179 SgfMap *map = but->iPacket;
180
181 if (butNum != 1) {
182 if (but->flags & BUT_TWITCHED)
183 return(BUTOUT_CAUGHT);
184 else
185 return(0);
186 }
187 if (!(but->flags & BUT_PRESSED))
188 return(0);
189 if (but->flags & BUT_TWITCHED) {
190 makeCallback = TRUE;
191 } else {
192 result |= BUTOUT_ERR;
193 }
194 newFlags &= ~(BUT_PRESSED|BUT_LOCKED);
195 if (newFlags != but->flags)
196 but_newFlags(but, newFlags);
197 if (makeCallback && map->callback) {
198 if (!(map->els[map->pressX + map->pressY * map->maxW].flags &
199 SGFMAPFLAGS_MAIN)) {
200 newMain(but, map, map->pressX, map->pressY);
201 }
202 result |= map->callback(but, map->pressX);
203 }
204 return(0);
205 }
206
207
draw(But * but,int dx,int dy,int dw,int dh)208 static void draw(But *but, int dx, int dy, int dw, int dh) {
209 ButWin *win = but->win;
210 ButEnv *env = win->env;
211 SgfMap *map = but->iPacket;
212 SgfMapElem *el;
213 int gridW, gridSize, gridSep, bw;
214 int startY, endY, startX, endX;
215 int x, y, locX0, stoneX, stoneY;
216 GoStone stone = goStone_empty;
217 bool mark = TRUE, grey;
218
219 assert(MAGIC(env));
220 gridSep = butEnv_fontH(env, 0);
221 gridSize = butEnv_fontH(env, 0) * 2;
222 gridW = gridSep + gridSize;
223 bw = butEnv_stdBw(env);
224
225 startX = (dx - but->x - gridSep) / gridW;
226 if (startX < 0)
227 startX = 0;
228 if (startX >= map->mapW)
229 return;
230
231 startY = (dy - but->y - gridSep) / gridW;
232 if (startY < 0)
233 startY = 0;
234 if (startY >= map->mapH)
235 return;
236
237 endX = (dx + dw + gridSize - but->x) / gridW;
238 if (endX < 1)
239 return;
240 if (endX > map->mapW)
241 endX = map->mapW;
242
243 endY = (dy + dh + gridSize - but->y) / gridW;
244 if (endY < 1)
245 return;
246 if (endY > map->mapH)
247 endY = map->mapH;
248
249 if ((map->activeX >= startX) && (map->activeX < endX) &&
250 (map->activeY >= startY) && (map->activeY < endY)) {
251 stoneX = map->activeX * gridW + gridSep + but->x;
252 stoneY = map->activeY * gridW + gridSep + but->y;
253 butEnv_setXFg(env, BUT_CHOICE);
254 XFillRectangle(env->dpy, win->win, env->gc,
255 stoneX - gridSep/2 + bw - win->xOff,
256 stoneY - gridSep/2 + bw - win->yOff,
257 gridW - bw*2, gridW - bw*2);
258 but_drawBox(win, stoneX - gridSep/2, stoneY - gridSep/2,
259 gridW, gridW, 0, bw,
260 BUT_SRIGHT|BUT_SLEFT, BUT_LIT, BUT_SHAD, None, None);
261 }
262 if ((but->flags & BUT_PRESSED) && (but->flags & BUT_TWITCHED) &&
263 (map->pressX >= startX) && (map->pressX < endX) &&
264 (map->pressY >= startY) && (map->pressY < endY)) {
265 stoneX = map->pressX * gridW + gridSep + but->x;
266 stoneY = map->pressY * gridW + gridSep + but->y;
267 butEnv_setXFg(env, BUT_PBG);
268 XFillRectangle(env->dpy, win->win, env->gc,
269 stoneX - gridSep/2 + bw - win->xOff,
270 stoneY - gridSep/2 + bw - win->yOff,
271 gridW - bw*2, gridW - bw*2);
272 but_drawBox(win, stoneX - gridSep/2, stoneY - gridSep/2,
273 gridW, gridW, 0, bw,
274 BUT_SRIGHT|BUT_SLEFT, BUT_SHAD, BUT_LIT, None, None);
275 }
276 for (y = startY; y < endY; ++y) {
277 locX0 = y * map->maxW;
278 for (x = startX; x < endX; ++x) {
279 stoneX = x * gridW + gridSep + but->x;
280 stoneY = y * gridW + gridSep + but->y;
281 el = &map->els[locX0 + x];
282 if (el->flags & SGFMAPFLAGS_CONN)
283 drawConn(but, el->flags, stoneX, stoneY, gridSep);
284 if (el->node == NULL)
285 continue;
286 switch(el->type) {
287 case sgfMap_white:
288 case sgfMap_wPass:
289 mark = TRUE;
290 stone = goStone_white;
291 break;
292 case sgfMap_black:
293 case sgfMap_bPass:
294 mark = TRUE;
295 stone = goStone_black;
296 break;
297 case sgfMap_edit:
298 mark = FALSE;
299 break;
300 case sgfMap_none:
301 mark = TRUE;
302 stone = goStone_empty;
303 break;
304 }
305 grey = !(el->flags & SGFMAPFLAGS_MAIN);
306 if (mark) {
307 if (stone != goStone_empty) {
308 cgbuts_drawp(map->cgbuts, win, stone, grey,
309 stoneX, stoneY, gridSize,
310 x % CGBUTS_NUMWHITE, dx, dy, dw, dh);
311 } if (el->flags & SGFMAPFLAGS_MARKED)
312 cgbuts_markPiece(map->cgbuts, win, stone, goMark_triangle, 0,
313 stoneX, stoneY, gridSize, 1, dx, dy, dw, dh);
314 else if (stone != goStone_empty)
315 cgbuts_markPiece(map->cgbuts, win, stone, goMark_number, el->moveNum,
316 stoneX, stoneY, gridSize, 1, dx, dy, dw, dh);
317 } else {
318 cgbuts_drawp(map->cgbuts, win, goStone_black, grey,
319 stoneX, stoneY, gridSep,
320 1, dx, dy, dw, dh);
321 cgbuts_drawp(map->cgbuts, win, goStone_white, grey,
322 stoneX + gridSep, stoneY, gridSep,
323 2, dx, dy, dw, dh);
324 cgbuts_drawp(map->cgbuts, win, goStone_white, grey,
325 stoneX, stoneY + gridSep, gridSep,
326 3, dx, dy, dw, dh);
327 cgbuts_drawp(map->cgbuts, win, goStone_black, grey,
328 stoneX + gridSep, stoneY + gridSep, gridSep,
329 4, dx, dy, dw, dh);
330 }
331 }
332 }
333 }
334
335
drawConn(But * but,uint flags,int x,int y,int fontH)336 static void drawConn(But *but, uint flags, int x, int y, int fontH) {
337 ButWin *win = but->win;
338 ButEnv *env = win->env;
339 int lineStart, lineEnd;
340 int lineW;
341
342 lineW = (fontH + 3) / 8;
343 if (lineW < 1)
344 lineW = 1;
345 XSetLineAttributes(env->dpy, env->gc, lineW, LineSolid, CapButt, JoinMiter);
346 butEnv_setXFg(but->win->env, BUT_BLACK);
347 lineStart = lineEnd = y + fontH;
348 if (flags & SGFMAPFLAGS_CONNU)
349 lineStart = y;
350 if (flags & SGFMAPFLAGS_CONND)
351 lineEnd += fontH * 2;
352 if (lineStart != lineEnd)
353 XDrawLine(env->dpy, win->win, env->gc,
354 x + fontH - win->xOff, lineStart - win->yOff,
355 x + fontH - win->xOff, lineEnd - win->yOff);
356
357 lineStart = lineEnd = x + fontH;
358 if (flags & SGFMAPFLAGS_CONNL)
359 lineStart = x;
360 if (flags & SGFMAPFLAGS_CONNR)
361 lineEnd += fontH * 2;
362 if (lineStart != lineEnd)
363 XDrawLine(env->dpy, win->win, env->gc,
364 lineStart - win->xOff, y + fontH - win->yOff,
365 lineEnd - win->xOff, y + fontH - win->yOff);
366
367 lineStart = lineEnd = fontH;
368 if (flags & SGFMAPFLAGS_CONNUL)
369 lineStart = 0;
370 if (flags & SGFMAPFLAGS_CONNDR)
371 lineEnd += fontH * 2;
372 if (lineStart != lineEnd)
373 XDrawLine(env->dpy, win->win, env->gc,
374 x + lineStart - win->xOff, y + lineStart - win->yOff,
375 x + lineEnd - win->xOff, y + lineEnd - win->yOff);
376 }
377
378
destroy(But * but)379 static ButOut destroy(But *but) {
380 return(0);
381 }
382
383
relocate(But * but,SgfElem * elem,int x,int y,int numDiag,int moveNum,bool mainLine)384 static void relocate(But *but, SgfElem *elem, int x, int y, int numDiag,
385 int moveNum, bool mainLine) {
386 SgfMap *map = but->iPacket;
387 SgfMapElem *me;
388 SgfElem *child;
389 int connLoc;
390
391 assert(MAGIC(map));
392 if (elem == NULL)
393 return;
394 resizeGraph(map, x, y);
395 me = &map->els[x + y * map->maxW];
396 if (numDiag) {
397 me->flags |= SGFMAPFLAGS_CONNUL;
398 --numDiag;
399 } else {
400 me->flags |= SGFMAPFLAGS_CONNL;
401 }
402 if (mainLine)
403 me->flags |= SGFMAPFLAGS_MAIN;
404 me->type = sgfMap_none;
405 while (elem->childH && (elem->childH->type != sgfType_node)) {
406 elem->mapX = x;
407 elem->mapY = y;
408 assert(elem->childH == elem->childT);
409 elem = elem->childH;
410 switch(elem->type) {
411 case sgfType_move:
412 if (elem->gVal == goStone_white)
413 me->type = sgfMap_white;
414 else {
415 assert(elem->gVal == goStone_black);
416 me->type = sgfMap_black;
417 }
418 me->moveNum = ++moveNum;
419 break;
420 case sgfType_pass:
421 if (elem->gVal == goStone_white)
422 me->type = sgfMap_wPass;
423 else {
424 assert(elem->gVal == goStone_black);
425 me->type = sgfMap_bPass;
426 }
427 me->moveNum = ++moveNum;
428 break;
429 case sgfType_triangle:
430 case sgfType_comment:
431 case sgfType_square:
432 case sgfType_circle:
433 case sgfType_label:
434 me->flags |= SGFMAPFLAGS_MARKED;
435 break;
436 case sgfType_setBoard:
437 me->type = sgfMap_edit;
438 break;
439 default:
440 break;
441 }
442 }
443 elem->mapX = x;
444 elem->mapY = y;
445 me->node = elem;
446 if (elem->childH) {
447 if (numDiag) {
448 me->flags |= SGFMAPFLAGS_CONNDR;
449 relocate(but, elem->childH, x + 1, y + 1, numDiag, moveNum,
450 mainLine && (elem->childH == elem->activeChild));
451 } else {
452 me->flags |= SGFMAPFLAGS_CONNR;
453 relocate(but, elem->childH, x + 1, y, 0, moveNum,
454 mainLine && (elem->childH == elem->activeChild));
455 }
456 for (child = elem->childH->sibling; child; child = child->sibling) {
457 connLoc = y;
458 y = findSubtreeY(map, child, x, y, &numDiag);
459 assert(numDiag > 0);
460 while (connLoc < y) {
461 map->els[x + connLoc * map->maxW].flags |= SGFMAPFLAGS_CONND;
462 map->els[x + ++connLoc * map->maxW].flags |= SGFMAPFLAGS_CONNU;
463 }
464 map->els[x + y * map->maxW].flags |= SGFMAPFLAGS_CONNDR;
465 relocate(but, child, x + 1, y + 1, numDiag, moveNum,
466 mainLine && (child == elem->activeChild));
467 }
468 }
469 }
470
471
resizeGraph(SgfMap * map,int newX,int newY)472 static void resizeGraph(SgfMap *map, int newX, int newY) {
473 SgfMapElem *newEls;
474 int newMaxW, newMaxH;
475 int x, y, oldX0, newX0;
476
477 if ((newX >= map->maxW) || (newY >= map->maxH)) {
478 newMaxW = (newX + 1) * 2;
479 if (newMaxW < map->maxW)
480 newMaxW = map->maxW;
481 newMaxH = (newY + 1) * 2;
482 if (newMaxH < map->maxH)
483 newMaxH = map->maxH;
484 newEls = wms_malloc(newMaxW * newMaxH * sizeof(SgfMapElem));
485 for (y = 0; y < map->maxH; ++y) {
486 oldX0 = y * map->maxW;
487 newX0 = y * newMaxW;
488 for (x = 0; x < map->maxW; ++x) {
489 newEls[newX0 + x] = map->els[oldX0 + x];
490 }
491 for (x = map->maxW; x < newMaxW; ++x) {
492 newEls[newX0 + x].node = NULL;
493 newEls[newX0 + x].flags = 0;
494 }
495 }
496 for (y = map->maxH; y < newMaxH; ++y) {
497 newX0 = y * newMaxW;
498 for (x = 0; x < newMaxW; ++x) {
499 newEls[newX0 + x].node = NULL;
500 newEls[newX0 + x].flags = 0;
501 }
502 }
503 if (map->els != NULL)
504 wms_free(map->els);
505 map->els = newEls;
506 map->maxW = newMaxW;
507 map->maxH = newMaxH;
508 }
509 if (newX >= map->mapW)
510 map->mapW = newX + 1;
511 if (newY >= map->mapH)
512 map->mapH = newY + 1;
513 }
514
515
findSubtreeY(SgfMap * map,SgfElem * tree,int x0,int y0,int * numDiagOut)516 static int findSubtreeY(SgfMap *map, SgfElem *tree, int x0, int y0,
517 int *numDiagOut) {
518 int x, y, numDiag;
519
520 x = x0;
521 y = y0 + 1;
522 numDiag = 1;
523 while (tree) {
524 ++x;
525 resizeGraph(map, x, y);
526 while (map->els[y * map->maxW + x].node ||
527 map->els[y * map->maxW + x].flags) {
528 ++y;
529 ++numDiag;
530 resizeGraph(map, x, y);
531 }
532 if (numDiag > x - x0) {
533 numDiag = x - x0;
534 }
535 do {
536 tree = tree->childH;
537 } while (tree && (tree->type != sgfType_node));
538 }
539 *numDiagOut = numDiag;
540 return(y - numDiag);
541 }
542
543
sgfMap_newActive(But * but,SgfElem * new)544 void sgfMap_newActive(But *but, SgfElem *new) {
545 SgfMap *map = but->iPacket;
546 ButWin *win = but->win;
547 int butSpc = butEnv_fontH(win->env, 0);
548
549 assert(MAGIC(map));
550 assert(new->mapX >= 0);
551 assert(new->mapY >= 0);
552 assert(new->mapX < map->mapW);
553 assert(new->mapY < map->mapH);
554 if (map->activeX >= 0) {
555 redrawEl(but, map->activeX, map->activeY);
556 }
557 map->activeX = new->mapX;
558 map->activeY = new->mapY;
559 if (map->activeX >= 0) {
560 map->activeCtrX = but->x + butSpc * 3 * map->activeX + butSpc * 2;
561 map->activeCtrY = but->y + butSpc * 3 * map->activeY + butSpc * 2;
562 redrawEl(but, map->activeX, map->activeY);
563 }
564 }
565
566
newFlags(But * but,uint flags)567 static void newFlags(But *but, uint flags) {
568 SgfMap *map = but->iPacket;
569 uint ofl = but->flags;
570
571 but->flags = flags;
572 if (((flags & BUT_PRESSED) != (ofl & BUT_PRESSED)) ||
573 (((flags & BUT_TWITCHED) != (ofl & BUT_TWITCHED)) &&
574 (flags & BUT_PRESSED))) {
575 redrawEl(but, map->pressX, map->pressY);
576 }
577 }
578
579
redrawEl(But * but,int x,int y)580 static void redrawEl(But *but, int x, int y) {
581 int elSpc = butEnv_fontH(but->win->env, 0);
582
583 butWin_redraw(but->win, but->x + x * elSpc * 3,
584 but->y + y * elSpc * 3, elSpc * 4, elSpc * 4);
585 }
586
587
newMain(But * but,SgfMap * map,int x,int y)588 static void newMain(But *but, SgfMap *map, int x, int y) {
589 SgfElem *node, *prevNode, *oldMain;
590 int prevX, prevY;
591 SgfMapElem *el;
592
593 el = &map->els[x + y * map->maxW];
594 assert(MAGIC(el->node));
595 /*
596 * First, go _down_ from the current active node, coloring all
597 * links as "main".
598 */
599 prevX = prevY = -1;
600 for (node = el->node; node; node = node->activeChild) {
601 if ((prevX != node->mapX) || (prevY != node->mapY)) {
602 prevX = node->mapX;
603 prevY = node->mapY;
604 map->els[prevX + prevY * map->maxW].flags |= SGFMAPFLAGS_MAIN;
605 redrawEl(but, prevX, prevY);
606 }
607 }
608 /*
609 * Now, go _up_ from the current active node, coloring all links as
610 * "main".
611 */
612 prevX = x;
613 prevY = y;
614 prevNode = el->node;
615 for (node = prevNode->parent; ; node = node->parent) {
616 oldMain = node->activeChild;
617 node->activeChild = prevNode;
618 assert(node == prevNode->parent);
619 assert((node->childH != node->childT) ||
620 (node->activeChild == node->childH));
621 prevNode = node;
622 if ((prevX != node->mapX) || (prevY != node->mapY)) {
623 prevX = node->mapX;
624 prevY = node->mapY;
625 if (map->els[prevX + prevY * map->maxW].flags & SGFMAPFLAGS_MAIN)
626 break;
627 else {
628 map->els[prevX + prevY * map->maxW].flags |= SGFMAPFLAGS_MAIN;
629 redrawEl(but, prevX, prevY);
630 }
631 }
632 }
633 assert(oldMain != node->activeChild);
634 /*
635 * Now, make all the stuff that _used_ to be main as "non-main".
636 */
637 for (; oldMain; oldMain = oldMain->activeChild) {
638 if ((prevX != oldMain->mapX) || (prevY != oldMain->mapY)) {
639 prevX = oldMain->mapX;
640 prevY = oldMain->mapY;
641 map->els[prevX + prevY * map->maxW].flags &= ~SGFMAPFLAGS_MAIN;
642 redrawEl(but, prevX, prevY);
643 }
644 }
645 }
646
647
sgfMap_changeVar(But * but,SgfMapDirection dir)648 bool sgfMap_changeVar(But *but, SgfMapDirection dir) {
649 SgfMap *map = but->iPacket;
650 SgfElem *active, *curChild, *newChild;
651
652 assert(MAGIC(map));
653 active = map->els[map->activeX + map->activeY * map->maxW].node;
654 assert(MAGIC(active));
655 while ((active->childH != NULL) &&
656 (active->childH->type != sgfType_node)) {
657 active = active->childH;
658 assert(MAGIC(active));
659 }
660 if ((active->childH == NULL) ||
661 (active->childH == active->childT))
662 return(FALSE);
663 curChild = active->activeChild;
664 assert(MAGIC(curChild));
665 if (dir == sgfMap_next) {
666 newChild = curChild->sibling;
667 if (!newChild)
668 newChild = active->childH;
669 } else {
670 assert(dir == sgfMap_prev);
671 if (curChild == active->childH)
672 newChild = active->childT;
673 else {
674 for (newChild = active->childH;
675 newChild->sibling != curChild;
676 newChild = newChild->sibling);
677 }
678 }
679 newMain(but, map, newChild->mapX, newChild->mapY);
680 return(TRUE);
681 }
682
683
sgfMap_remap(But * but,Sgf * sgf)684 void sgfMap_remap(But *but, Sgf *sgf) {
685 SgfMap *map = but->iPacket;
686 int i, fontH = butEnv_fontH(but->win->env, 0);
687
688 assert(MAGIC(map));
689 for (i = 0; i < map->maxW * map->maxH; ++i) {
690 map->els[i].node = NULL;
691 map->els[i].flags = 0;
692 map->els[i].type = sgfMap_none;
693 }
694 map->mapW = map->mapH = 0;
695 relocate(but, sgf->top.activeChild, 0, 0, 0, 0, TRUE);
696 map->els[0].flags &= ~SGFMAPFLAGS_CONNL;
697 but_resize(but, but->x, but->y, map->mapW * 3 * fontH + fontH,
698 map->mapH * 3 * fontH + fontH);
699 but_draw(but);
700 }
701
702
sgfMap_newNode(But * but,SgfElem * new)703 bool sgfMap_newNode(But *but, SgfElem *new) {
704 SgfMap *map = but->iPacket;
705 int newX, newY;
706 SgfMapElem *el;
707
708 assert(MAGIC(map));
709 newX = new->mapX;
710 newY = new->mapY;
711 assert(newX < map->maxW);
712 if (newX + 1 == map->mapW)
713 return(FALSE);
714 if (map->els[newX + newY * map->maxW].flags &
715 (SGFMAPFLAGS_CONND | SGFMAPFLAGS_CONNDR | SGFMAPFLAGS_CONNR))
716 return(FALSE);
717 if (map->els[newX + 1 + newY * map->maxW].flags)
718 return(FALSE);
719 map->els[newX + newY * map->maxW].flags |=
720 SGFMAPFLAGS_CONNR | SGFMAPFLAGS_MAIN;
721 el = &map->els[newX + 1 + newY * map->maxW];
722 ++newX;
723 el->flags |= SGFMAPFLAGS_CONNL | SGFMAPFLAGS_MAIN;
724 redrawEl(but, newX, newY);
725 new->mapX = newX;
726 new->mapY = newY;
727 el->node = new;
728 el->type = sgfMap_none;
729 return(TRUE);
730 }
731
732
sgfMap_changeNode(But * but,SgfElem * changed)733 void sgfMap_changeNode(But *but, SgfElem *changed) {
734 SgfMap *map = but->iPacket;
735 SgfMapElem *me;
736 int moveAdd = 0;
737
738 assert(MAGIC(map));
739 assert(changed != NULL);
740 me = &map->els[changed->mapX + changed->mapY * map->maxW];
741 me->type = sgfMap_none;
742 while (changed->parent && (changed->type != sgfType_node)) {
743 switch(changed->type) {
744 case sgfType_move:
745 if (changed->gVal == goStone_white)
746 me->type = sgfMap_white;
747 else {
748 assert(changed->gVal == goStone_black);
749 me->type = sgfMap_black;
750 }
751 moveAdd = 1;
752 break;
753 case sgfType_pass:
754 if (changed->gVal == goStone_white)
755 me->type = sgfMap_wPass;
756 else {
757 assert(changed->gVal == goStone_black);
758 me->type = sgfMap_bPass;
759 }
760 moveAdd = 1;
761 break;
762 case sgfType_triangle:
763 case sgfType_comment:
764 case sgfType_square:
765 case sgfType_circle:
766 case sgfType_label:
767 me->flags |= SGFMAPFLAGS_MARKED;
768 break;
769 case sgfType_setBoard:
770 me->type = sgfMap_edit;
771 break;
772 default:
773 break;
774 }
775 changed = changed->parent;
776 assert(changed != NULL);
777 }
778 if (changed->parent) {
779 changed = changed->parent;
780 assert(changed != NULL);
781 me->moveNum = map->els[changed->mapX + changed->mapY * map->maxW].moveNum +
782 moveAdd;
783 } else
784 me->moveNum = moveAdd;
785 assert(changed != NULL);
786 redrawEl(but, changed->mapX, changed->mapY);
787 }
788
789
790 /*
791 * Sometimes, in our frenzy of adding and deleting SgfElems, we could kill
792 * the one that the map points to. So every time we change active nodes,
793 * we first reset the map to point to the old active node.
794 */
sgfMap_setMapPointer(But * but,SgfElem * activeElem)795 void sgfMap_setMapPointer(But *but, SgfElem *activeElem) {
796 SgfMap *map = but->iPacket;
797 int x, y;
798
799 assert(MAGIC(map));
800 x = activeElem->mapX;
801 y = activeElem->mapY;
802 assert((x >= 0) && (x < map->mapW) && (y >= 0) && (y < map->mapH));
803 assert(map->els[x + y * map->maxW].node);
804 map->els[x + y * map->maxW].node = activeElem;
805 }
806