1 /*
2  * src/editTool.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 <wms/str.h>
9 #include <wms/clp.h>
10 #include <but/but.h>
11 #include <abut/msg.h>
12 #include <but/text.h>
13 #include <abut/term.h>
14 #include <abut/fsel.h>
15 #include <abut/swin.h>
16 #include <but/radio.h>
17 #include <but/plain.h>
18 #include <but/canvas.h>
19 #include <but/ctext.h>
20 #include "cgoban.h"
21 #include "editTool.h"
22 #include "msg.h"
23 #include "sgfMap.h"
24 #include "sgf.h"
25 #include "help.h"
26 
27 
28 /**********************************************************************
29  * Forward declarations
30  **********************************************************************/
31 static ButOut  unmap(ButWin *win);
32 static ButOut  map(ButWin *win);
33 static ButOut  resize(ButWin *win);
34 static ButOut  iResize(ButWin *win);
35 static ButOut  mapResize(ButWin *win);
36 static ButOut  destroy(ButWin *win);
37 static ButOut  newTool(But *but, int val);
38 static ButOut  windowQuit(ButWin *win);
39 static ButOut  mapCallback(But *but, int newNodeNum);
40 static ButOut  cutPressed(But *but);
41 static ButOut  movePressed(But *but);
42 static void  updateTreeButtons(EditToolWin *etw);
43 
44 
45 /**********************************************************************
46  * Functions
47  **********************************************************************/
48 #define  editW(bw, fontH)  ((fontH*2 + bw*4) * editTool_max + bw * 4)
49 
50 
editToolWin_init(EditToolWin * etw,Cgoban * cg,Sgf * sgf,void (* quitRequested)(void * packet),ButOut (* newToolCallback)(void * packet),ButOut (* newActiveNode)(void * packet,int nodeNum),void * packet)51 void  editToolWin_init(EditToolWin *etw, Cgoban *cg, Sgf *sgf,
52 		       void (*quitRequested)(void *packet),
53 		       ButOut (*newToolCallback)(void *packet),
54 		       ButOut (*newActiveNode)(void *packet,
55 					       int nodeNum),
56 		       void *packet)  {
57   static const ButKey  shiftUpKeys[] = {{XK_Up, ShiftMask, ShiftMask},
58 					{0,0,0}};
59   static const ButKey  shiftDownKeys[] = {{XK_Down, ShiftMask, ShiftMask},
60 					  {0,0,0}};
61   int  w, h, minW, minH;
62   But  *b;
63   int  i, fontH;
64   bool  err;
65 
66   MAGIC_SET(etw);
67   etw->cg = cg;
68   etw->modified = FALSE;
69   fontH = butEnv_fontH(cg->env, 0);
70   minW = editW(butEnv_stdBw(cg->env), fontH);
71   minH = minW * 0.70710678 + 0.5;
72   w = (fontH * clp_getDouble(cg->clp, "edit.toolW") + 0.5);
73   h = (fontH * clp_getDouble(cg->clp, "edit.toolH") + 0.5);
74   if (w < minW)
75     w = minW;
76   if (h < minH)
77     h = minH;
78   etw->toolWin = butWin_iCreate(etw, cg->env, "Cgoban Tools", w, h,
79 				&etw->toolIWin, FALSE, 48, 48, unmap, map,
80 				resize, iResize, destroy);
81   i = clp_iGetInt(cg->clp, "edit.toolX", &err);
82   if (!err)
83     butWin_setX(etw->toolWin, i);
84   i = clp_iGetInt(cg->clp, "edit.toolY", &err);
85   if (!err)
86     butWin_setY(etw->toolWin, i);
87   butWin_setMinW(etw->toolWin, minW);
88   butWin_setMinH(etw->toolWin, minH);
89   butWin_setMaxW(etw->toolWin, 0);
90   butWin_setMaxH(etw->toolWin, 0);
91   butWin_setQuit(etw->toolWin, windowQuit);
92   butWin_activate(etw->toolWin);
93   etw->toolBg = butBoxFilled_create(etw->toolWin, 0, BUT_DRAWABLE);
94   butBoxFilled_setPixmaps(etw->toolBg, cg->bgLitPixmap, cg->bgShadPixmap,
95 			  cg->bgPixmap);
96   etw->toolIBg = butBoxFilled_create(etw->toolIWin, 0, BUT_DRAWABLE);
97   butBoxFilled_setPixmaps(etw->toolIBg, cg->bgLitPixmap, cg->bgShadPixmap,
98 			  cg->bgPixmap);
99   etw->toolIPic = toolPic_create(&cg->cgbuts, etw->toolIWin, 1, BUT_DRAWABLE);
100   etw->toolSel = butRadio_create(newTool, etw, etw->toolWin, 1,
101 				 BUT_PRESSABLE|BUT_DRAWABLE,
102 				 0, editTool_max);
103 
104   etw->selDesc[editTool_play] = b =
105     grid_create(&cg->cgbuts, NULL, NULL, etw->toolWin, 2,
106 		BUT_DRAWABLE|BUT_PRESSTHRU, 0);
107   grid_setStone(b, etw->lastColor = goStone_black, FALSE);
108   grid_setLineGroup(b, gridLines_none);
109   grid_setVersion(b, 0);
110 
111   etw->selDesc[editTool_changeBoard] =
112     stoneGroup_create(&cg->cgbuts, etw->toolWin,
113 		      2, BUT_DRAWABLE|BUT_PRESSTHRU);
114 
115   etw->selDesc[editTool_score] = b =
116     grid_create(&cg->cgbuts, NULL, NULL, etw->toolWin,
117 		2, BUT_DRAWABLE|BUT_PRESSTHRU, 0);
118   grid_setStone(b, goStone_black, FALSE);
119   grid_setLineGroup(b, gridLines_none);
120   grid_setVersion(b, CGBUTS_YINYANG(1));
121 
122   etw->selDesc[editTool_triangle] = b =
123     grid_create(&cg->cgbuts, NULL, NULL, etw->toolWin,
124 		2, BUT_DRAWABLE|BUT_PRESSTHRU, 0);
125   grid_setStone(b, goStone_black, FALSE);
126   grid_setLineGroup(b, gridLines_none);
127   grid_setMark(b, goMark_triangle, 0);
128 
129   etw->selDesc[editTool_square] = b =
130     grid_create(&cg->cgbuts, NULL, NULL, etw->toolWin,
131 		2, BUT_DRAWABLE|BUT_PRESSTHRU, 0);
132   grid_setStone(b, goStone_black, FALSE);
133   grid_setLineGroup(b, gridLines_none);
134   grid_setMark(b, goMark_square, 0);
135 
136   etw->selDesc[editTool_circle] = b =
137     grid_create(&cg->cgbuts, NULL, NULL, etw->toolWin,
138 		2, BUT_DRAWABLE|BUT_PRESSTHRU, 0);
139   grid_setStone(b, goStone_black, FALSE);
140   grid_setLineGroup(b, gridLines_none);
141   grid_setMark(b, goMark_circle, 0);
142 
143   etw->selDesc[editTool_letter] = b =
144     grid_create(&cg->cgbuts, NULL, NULL, etw->toolWin,
145 		2, BUT_DRAWABLE|BUT_PRESSTHRU, 0);
146   grid_setStone(b, goStone_black, FALSE);
147   grid_setLineGroup(b, gridLines_none);
148   grid_setMark(b, goMark_letter, 'A');
149   grid_setVersion(b, 1);
150 
151   etw->selDesc[editTool_number] = b =
152     grid_create(&cg->cgbuts, NULL, NULL, etw->toolWin,
153 		2, BUT_DRAWABLE|BUT_PRESSTHRU, 0);
154   grid_setStone(b, goStone_black, FALSE);
155   grid_setLineGroup(b, gridLines_none);
156   grid_setMark(b, goMark_number, 1);
157   grid_setVersion(b, 2);
158 
159   etw->mapWin = abutSwin_create(etw, etw->toolWin, 1,
160 				ABUTSWIN_LSLIDE|ABUTSWIN_BSLIDE,
161 				mapResize);
162   etw->mapBg = butPixmap_create(etw->mapWin->win, 0, BUT_DRAWABLE,
163 				cg->boardPixmap);
164   etw->sgfMap = sgfMap_create(&cg->cgbuts, mapCallback, etw,
165 			      etw->mapWin->win,
166 			      1, BUT_DRAWABLE|BUT_PRESSABLE, sgf);
167   etw->prevVar = butKeytrap_create(editToolWin_shiftUpPressed, etw,
168 				   etw->toolWin, BUT_DRAWABLE|BUT_PRESSABLE);
169   but_setKeys(etw->prevVar, shiftUpKeys);
170   etw->nextVar = butKeytrap_create(editToolWin_shiftDownPressed, etw,
171 				   etw->toolWin, BUT_DRAWABLE|BUT_PRESSABLE);
172   but_setKeys(etw->nextVar, shiftDownKeys);
173 
174   etw->sgf = sgf;
175 
176   etw->tool = editTool_play;
177 
178   etw->toolBox = butBoxFilled_create(etw->toolWin, 1, BUT_DRAWABLE);
179   etw->toolName = butText_create(etw->toolWin, 2, BUT_DRAWABLE,
180 				 msg_toolNames[etw->tool],
181 				 butText_center);
182   butText_setFont(etw->toolName, 2);
183   etw->toolDesc1 = butText_create(etw->toolWin, 2, BUT_DRAWABLE,
184 				  msg_toolDesc1[etw->tool],
185 				  butText_center);
186   etw->toolDesc2 = butText_create(etw->toolWin, 2, BUT_DRAWABLE,
187 				  msg_toolDesc2[etw->tool],
188 				  butText_center);
189   etw->help = butCt_create(cgoban_createHelpWindow, &help_editTool,
190 			   etw->toolWin, 1,
191 			   BUT_DRAWABLE | BUT_PRESSABLE, msg_help);
192   etw->killNode = butCt_create(cutPressed, etw, etw->toolWin, 1,
193 			       BUT_DRAWABLE | BUT_PRESSABLE,
194 			       msg_killNode);
195   etw->moveNode = butCt_create(movePressed, etw, etw->toolWin, 1,
196 			       BUT_DRAWABLE | BUT_PRESSABLE,
197 			       msg_moveNode);
198 
199   etw->quitRequested = quitRequested;
200   etw->newToolCallback = newToolCallback;
201   etw->mapCallback = newActiveNode;
202   etw->packet = packet;
203   updateTreeButtons(etw);
204 }
205 
206 
editToolWin_deinit(EditToolWin * etw)207 void  editToolWin_deinit(EditToolWin *etw)  {
208   int  fontH;
209 
210   assert(MAGIC(etw));
211   if (etw->toolWin != NULL)  {
212     fontH = butEnv_fontH(etw->cg->env, 0);
213     clp_setInt(etw->cg->clp, "edit.toolX", butWin_x(etw->toolWin));
214     clp_setInt(etw->cg->clp, "edit.toolY", butWin_y(etw->toolWin));
215     clp_setDouble(etw->cg->clp, "edit.toolW",
216 		  (double)butWin_w(etw->toolWin) / (double)fontH);
217     clp_setDouble(etw->cg->clp, "edit.toolH",
218 		  (double)butWin_h(etw->toolWin) / (double)fontH);
219     butWin_setPacket(etw->toolWin, NULL);
220     butWin_destroy(etw->toolWin);
221   }
222   MAGIC_UNSET(etw);
223 }
224 
225 
unmap(ButWin * win)226 static ButOut  unmap(ButWin *win)  {
227   return(0);
228 }
229 
230 
map(ButWin * win)231 static ButOut  map(ButWin *win)  {
232   return(0);
233 }
234 
235 
resize(ButWin * win)236 static ButOut  resize(ButWin *win)  {
237   EditToolWin  *etw = butWin_packet(win);
238   ButEnv  *env = butWin_env(win);
239   int  bw = butEnv_stdBw(env);
240   int  fontH = butEnv_fontH(env, 0), font2H = butEnv_fontH(env, 2);
241   int  butH;
242   int  w = butWin_w(win), h = butWin_h(win);
243   EditTool  tool;
244   int  x, x2, y, toolW;
245 
246   assert(MAGIC(etw));
247   butH = etw->cg->fontH * 2;
248   but_resize(etw->toolBg, 0, 0, w, h);
249   but_resize(etw->toolSel, bw * 2, bw * 2, w - bw * 4, fontH * 2 + bw * 4);
250   x2 = bw * 2;
251   toolW = fontH * 2;
252   for (tool = editTool_min;  tool < editTool_max;  ++tool)  {
253     x = x2;
254     x2 = bw * 2 + ((tool + 1) * (w - bw * 4)) / editTool_max;
255     but_resize(etw->selDesc[tool], (x + x2 - toolW) / 2, bw*4, toolW, toolW);
256   }
257   y = fontH * 2 + bw * 6;
258   but_resize(etw->toolBox, bw * 2, y, w - bw * 4, bw * 4 + font2H + fontH * 2);
259   but_resize(etw->toolName, bw * 4, y += bw * 2, w - bw * 8, font2H);
260   but_resize(etw->toolDesc1, bw * 4, y += font2H, w - bw * 8, fontH);
261   but_resize(etw->toolDesc2, bw * 4, y += fontH, w - bw * 8, fontH);
262   but_resize(etw->help, bw*2, y += fontH + bw * 3, (w - bw * 6 + 1) / 3, butH);
263   but_resize(etw->killNode, bw*3 + (w - bw * 6 + 1) / 3, y,
264 	     w - bw * 6 - 2*(w - bw * 6 + 1) / 3, butH);
265   but_resize(etw->moveNode, w - bw * 2 - (w - bw * 6 + 1) / 3, y,
266 	     (w - bw * 6 + 1) / 3, butH);
267 
268   y += butH + bw;
269   abutSwin_resize(etw->mapWin, bw * 2, y, w - bw * 4, h - bw * 2 - y,
270 		  (fontH * 3) / 2, fontH * 3);
271   sgfMap_resize(etw->sgfMap, 0, 0);
272   butCan_resizeWin(etw->mapWin->win, but_w(etw->sgfMap), but_h(etw->sgfMap),
273 		   TRUE);
274 
275   return(0);
276 }
277 
278 
iResize(ButWin * win)279 static ButOut  iResize(ButWin *win)  {
280   EditToolWin  *etw = butWin_packet(win);
281   int  bw = butEnv_stdBw(win->env);
282 
283   assert(MAGIC(etw));
284   but_resize(etw->toolIBg, 0, 0, butWin_w(win), butWin_h(win));
285   but_resize(etw->toolIPic, bw*2, bw*2, butWin_w(win) - bw*4,
286 	     butWin_h(win) - bw*4);
287   return(0);
288 }
289 
290 
mapResize(ButWin * win)291 static ButOut  mapResize(ButWin *win)  {
292   AbutSwin  *swin = butWin_packet(win);
293   EditToolWin  *etw;
294 
295   assert(MAGIC(swin));
296   etw = swin->packet;
297   assert(MAGIC(etw));
298   but_resize(etw->mapBg, 0, 0, butWin_w(win), butWin_h(win));
299   return(0);
300 }
301 
302 
destroy(ButWin * win)303 static ButOut  destroy(ButWin *win)  {
304   EditToolWin  *etw = butWin_packet(win);
305 
306   if (etw)  {
307     assert(MAGIC(etw));
308     clp_setInt(etw->cg->clp, "edit.toolX", butWin_x(win));
309     clp_setInt(etw->cg->clp, "edit.toolY", butWin_y(win));
310     etw->toolWin = NULL;
311     /* editToolWin_deinit(etw); */
312   }
313   return(0);
314 }
315 
316 
windowQuit(ButWin * win)317 static ButOut  windowQuit(ButWin *win)  {
318   EditToolWin  *etw = butWin_packet(win);
319 
320   assert(MAGIC(etw));
321   etw->quitRequested(etw->packet);
322   return(0);
323 }
324 
325 
newTool(But * but,int val)326 static ButOut  newTool(But *but, int val)  {
327   EditToolWin  *etw;
328 
329   etw = but_packet(but);
330   assert(MAGIC(etw));
331   if ((EditTool)val != etw->tool)  {
332     etw->tool = (EditTool)val;
333     butText_set(etw->toolName, msg_toolNames[val]);
334     butText_set(etw->toolDesc1, msg_toolDesc1[val]);
335     butText_set(etw->toolDesc2, msg_toolDesc2[val]);
336   }
337   return(etw->newToolCallback(etw->packet));
338 }
339 
340 
editToolWin_newColor(EditToolWin * etw,GoStone color)341 void  editToolWin_newColor(EditToolWin *etw, GoStone color)  {
342   if (color != etw->lastColor)  {
343     grid_setStone(etw->selDesc[editTool_play], etw->lastColor = color, FALSE);
344   }
345 }
346 
347 
editToolWin_newTool(EditToolWin * etw,EditTool tool,bool propagate)348 void  editToolWin_newTool(EditToolWin *etw, EditTool tool, bool propagate)  {
349   butRadio_set(etw->toolSel, tool, propagate);
350 }
351 
352 
mapCallback(But * but,int newNodeNum)353 static ButOut  mapCallback(But *but, int newNodeNum)  {
354   EditToolWin  *etw = but_packet(but);
355   ButOut  result;
356 
357   assert(MAGIC(etw));
358   result = etw->mapCallback(etw->packet, newNodeNum);
359   updateTreeButtons(etw);
360   return(result);
361 }
362 
363 
editToolWin_newActiveNode(EditToolWin * etw,SgfElem * newNode)364 void  editToolWin_newActiveNode(EditToolWin *etw, SgfElem *newNode)  {
365   int  w, h, loX, loY, hiX, hiY;
366   int  aX, aY;
367   int  slideX, slideY, newX, newY;
368 
369   sgfMap_newActive(etw->sgfMap, newNode);
370   w = butWin_viewW(etw->mapWin->win);
371   h = butWin_viewH(etw->mapWin->win);
372   newX = slideX = butCan_xOff(etw->mapWin->win);
373   newY = slideY = butCan_yOff(etw->mapWin->win);
374   loX = slideX + (w + 1) / 4;
375   loY = slideY + (h + 1) / 4;
376   hiX = slideX + (w * 3 + 1) / 4;
377   hiY = slideY + (h * 3 + 1) / 4;
378   aX = sgfMap_activeCtrX(etw->sgfMap);
379   aY = sgfMap_activeCtrY(etw->sgfMap);
380   if (aX < loX)  {
381     newX = aX - (w + 1) / 4;
382     if (newX < 0)
383       newX = 0;
384   } else if (aX > hiX)  {
385     newX = aX - (w * 3 + 1) / 4;
386     if (newX + w > butWin_w(etw->mapWin->win))
387       newX = butWin_w(etw->mapWin->win) - w;
388   }
389   if (aY < loY)  {
390     newY = aY - (h + 1) / 4;
391     if (newY < 0)
392       newY = 0;
393   } else if (aY > hiY)  {
394     newY = aY - (h * 3 + 1) / 4;
395     if (newY + h > butWin_h(etw->mapWin->win))
396       newY = butWin_h(etw->mapWin->win) - h;
397   }
398   if ((newX != slideX) || (newY != slideY))  {
399     butCan_slide(etw->mapWin->win, newX, newY, TRUE);
400   }
401   updateTreeButtons(etw);
402 }
403 
404 
cutPressed(But * but)405 static ButOut  cutPressed(But *but)  {
406   EditToolWin  *etw = but_packet(but);
407   SgfElem  *deadElem, *newActive;
408   ButOut  result;
409 
410   assert(MAGIC(etw));
411   etw->modified = TRUE;
412   deadElem = etw->sgf->active->activeChild;
413   if (deadElem == NULL)
414     return(BUTOUT_ERR);
415   newActive = deadElem->sibling;
416   if (newActive)  {
417     sgfMap_changeVar(etw->sgfMap, sgfMap_next);
418   } else  {
419     for (newActive = etw->sgf->active->childH;
420 	 newActive && (newActive->sibling != deadElem);
421 	 newActive = newActive->sibling);
422     if (newActive)
423       sgfMap_changeVar(etw->sgfMap, sgfMap_prev);
424   }
425   etw->sgf->active->activeChild = deadElem;
426   assert(newActive != etw->sgf->active->activeChild);
427   assert(MAGICNULL(newActive));
428   sgfElem_destroyActiveChild(etw->sgf->active);
429   assert(MAGICNULL(newActive));
430   etw->sgf->active->activeChild = newActive;
431   sgfMap_remap(etw->sgfMap, etw->sgf);
432   butCan_resizeWin(etw->mapWin->win, but_w(etw->sgfMap), but_h(etw->sgfMap),
433 		   TRUE);
434   result = etw->mapCallback(etw->packet, etw->sgf->active->mapX);
435   updateTreeButtons(etw);
436   return(result);
437 }
438 
439 
movePressed(But * but)440 static ButOut  movePressed(But *but)  {
441   EditToolWin  *etw = but_packet(but);
442   SgfElem  *active, *loSwap, *hiSwap, *prevChild;
443 
444   assert(MAGIC(etw));
445   etw->modified = TRUE;
446   active = etw->sgf->active;
447   assert(active->childH != active->childT);
448   assert(active->childH != NULL);
449   hiSwap = active->activeChild;
450   if (active->childH == hiSwap)  {
451     loSwap = hiSwap;
452     hiSwap = loSwap->sibling;
453   } else  {
454     for (loSwap = active->childH;
455 	 loSwap->sibling != hiSwap;
456 	 loSwap = loSwap->sibling)
457       assert(MAGIC(loSwap));
458   }
459   if (active->childH == loSwap)  {
460     active->childH = hiSwap;
461   } else  {
462     for (prevChild = active->childH;
463 	 prevChild->sibling != loSwap;
464 	 prevChild = prevChild->sibling);
465     prevChild->sibling = hiSwap;
466   }
467   loSwap->sibling = hiSwap->sibling;
468   hiSwap->sibling = loSwap;
469   if (active->childT == hiSwap)
470     active->childT = loSwap;
471   sgfMap_remap(etw->sgfMap, etw->sgf);
472   butCan_resizeWin(etw->mapWin->win, but_w(etw->sgfMap), but_h(etw->sgfMap),
473 		   TRUE);
474   return(0);
475 }
476 
477 
editToolWin_nodeAdded(EditToolWin * etw,SgfElem * newNode)478 void  editToolWin_nodeAdded(EditToolWin *etw, SgfElem *newNode)  {
479   bool  addSuccessful;
480 
481   addSuccessful = sgfMap_newNode(etw->sgfMap, newNode);
482   if (!addSuccessful)  {
483     sgfMap_remap(etw->sgfMap, etw->sgf);
484     butCan_resizeWin(etw->mapWin->win, but_w(etw->sgfMap), but_h(etw->sgfMap),
485 		     TRUE);
486   }
487   updateTreeButtons(etw);
488 }
489 
490 
editToolWin_shiftUpPressed(But * but,bool press)491 ButOut  editToolWin_shiftUpPressed(But *but, bool press)  {
492   EditToolWin  *etw = but_packet(but);
493 
494   assert(MAGIC(etw));
495   if (press)  {
496     if (sgfMap_changeVar(etw->sgfMap, sgfMap_prev))
497       return(0);
498     else
499       return(BUTOUT_ERR);
500   } else
501     return(0);
502 }
503 
504 
editToolWin_shiftDownPressed(But * but,bool press)505 ButOut  editToolWin_shiftDownPressed(But *but, bool press)  {
506   EditToolWin  *etw = but_packet(but);
507 
508   assert(MAGIC(etw));
509   if (press)  {
510     if (sgfMap_changeVar(etw->sgfMap, sgfMap_next))
511       return(0);
512     else
513       return(BUTOUT_ERR);
514   } else
515     return(0);
516 }
517 
518 
updateTreeButtons(EditToolWin * etw)519 static void  updateTreeButtons(EditToolWin *etw)  {
520   if (etw->sgf->active->childH)  {
521     but_setFlags(etw->killNode, BUT_PRESSABLE);
522     if (etw->sgf->active->childH == etw->sgf->active->childT)  {
523       but_setFlags(etw->moveNode, BUT_NOPRESS);
524     } else  {
525       but_setFlags(etw->moveNode, BUT_PRESSABLE);
526     }
527   } else  {
528     but_setFlags(etw->killNode, BUT_NOPRESS);
529     but_setFlags(etw->moveNode, BUT_NOPRESS);
530   }
531 }
532