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