1 /*
2  * src/editInfo.c, part of Complete Goban (game program)
3  * Copyright (C) 1996 William Shubert
4  * See "configure.h.in" for more copyright information.
5  */
6 
7 #include <wms.h>
8 #include "sgf.h"
9 #include "msg.h"
10 #include <but/box.h>
11 #include <but/textin.h>
12 #ifdef  _EDITINFO_H_
13   Levelization Error.
14 #endif
15 #include "editInfo.h"
16 
17 
18 /**********************************************************************
19  * Forward Declarations
20  **********************************************************************/
21 static ButOut  unmap(ButWin *win);
22 static ButOut  map(ButWin *win);
23 static ButOut  resize(ButWin *win);
24 static ButOut  destroy(ButWin *win);
25 static ButOut  newTitle(But *but, const char *newStr);
26 
27 
28 /**********************************************************************
29  * Globals
30  **********************************************************************/
31 static const struct  {
32   const char  *title;
33   SgfType  type;
34   GoStone  color;
35 } sgfVals[] = {
36   {msg_gameTitle,  sgfType_title,     goStone_empty},
37   {msg_copyrightC, sgfType_copyright, goStone_empty},
38   {msg_wStoneName, sgfType_playerName, goStone_white},
39   {msg_bStoneName, sgfType_playerName, goStone_black},
40   {msg_wRank, sgfType_playerRank, goStone_white},
41   {msg_bRank, sgfType_playerRank, goStone_black},
42   {msg_handicapC, sgfType_handicap, goStone_empty},
43   {msg_komiC, sgfType_komi, goStone_empty},
44   {msg_time, sgfType_time, goStone_empty},
45   {msg_result, sgfType_result, goStone_empty},
46   {msg_date, sgfType_date, goStone_empty},
47   {msg_place, sgfType_place, goStone_empty},
48   {msg_event, sgfType_event, goStone_empty},
49   {msg_source, sgfType_source, goStone_empty}};
50 
51 
52 /**********************************************************************
53  * Functions
54  **********************************************************************/
editInfo_create(Cgoban * cg,Goban * goban,Sgf * sgf,void (* dCallback)(EditInfo * info,void * packet),void * packet)55 EditInfo  *editInfo_create(Cgoban *cg, Goban *goban, Sgf *sgf,
56 			   void (*dCallback)(EditInfo *info, void *packet),
57 			   void *packet)  {
58   int  i, minW, minH, w, h, bw, fontH;
59   ButEnv  *env;
60   EditInfo  *info;
61   bool  err;
62   EditInfoVal  val;
63   Str  defValBuf;
64   const char  *defVal;
65   SgfElem  *elLookup;
66   ButOut  (*callback)(But *but, const char *newStr);
67 
68   info = wms_malloc(sizeof(EditInfo));
69   MAGIC_SET(info);
70   env = cg->env;
71   info->cg = cg;
72   info->goban = goban;
73   info->sgf = sgf;
74   info->destroy = dCallback;
75   info->packet = packet;
76 
77   fontH = cg->fontH;
78   bw = butEnv_stdBw(env);
79   minW = fontH * 24 + bw * 14;
80   minH = minW;
81   w = (double)minW * clp_getDouble(cg->clp, "edit.infoW") + 0.5;
82   h = (double)minH * clp_getDouble(cg->clp, "edit.infoH") + 0.5;
83   info->win = butWin_create(info, cg->env, "Cgoban Game Info", w, h,
84 			    unmap, map, resize, destroy);
85   i = clpEntry_iGetInt(clp_lookup(cg->clp, "edit.infoX"), &err);
86   if (!err)
87     butWin_setX(info->win, i);
88   i = clpEntry_iGetInt(clp_lookup(cg->clp, "edit.infoY"), &err);
89   if (!err)
90     butWin_setY(info->win, i);
91   butWin_setMinW(info->win, minW);
92   butWin_setMinH(info->win, minH);
93   butWin_setMaxW(info->win, 0);
94   butWin_setMaxH(info->win, 0);
95   butWin_activate(info->win);
96   info->bg = butBoxFilled_create(info->win, 0, BUT_DRAWABLE);
97   butBoxFilled_setPixmaps(info->bg, cg->bgLitPixmap, cg->bgShadPixmap,
98 			  cg->bgPixmap);
99 
100   info->winTitle = butText_create(info->win, 1, BUT_DRAWABLE,
101 				   msg_editInfoTitle,
102 				   butText_center);
103   butText_setFont(info->winTitle, 2);
104   str_init(&defValBuf);
105   editInfoVal_iter(val)  {
106     info->infos[val].name = butText_create(info->win, 1, BUT_DRAWABLE,
107 					   sgfVals[val].title,
108 					   butText_left);
109     defVal = "";
110     for (elLookup = &sgf->top;
111 	 (elLookup != NULL) && (elLookup->type != sgfType_node);
112 	 elLookup = elLookup->activeChild)  {
113       if ((elLookup->type == sgfVals[val].type) &&
114 	  ((sgfVals[val].color == goStone_empty) ||
115 	   (sgfVals[val].color == elLookup->gVal)))  {
116 	switch(elLookup->type)  {
117 	case sgfType_komi:
118 	  str_print(&defValBuf, "%g", (double)elLookup->iVal / 2.0);
119 	  defVal = str_chars(&defValBuf);
120 	  break;
121 	case sgfType_handicap:
122 	  str_print(&defValBuf, "%d", elLookup->iVal);
123 	  defVal = str_chars(&defValBuf);
124 	  break;
125 	default:
126 	  defVal = str_chars(elLookup->sVal);
127 	  break;
128 	}
129 	break;
130       }
131     }
132     if (val == editInfo_gameTitle)
133       callback = newTitle;
134     else
135       callback = NULL;
136     info->infos[val].in = butTextin_create(callback, info, info->win, 1,
137 					   BUT_DRAWABLE|BUT_PRESSABLE,
138 					   defVal, 1000);
139   }
140   str_deinit(&defValBuf);
141   info->gameComment = abutTerm_create(cg->abut, info->win, 1, TRUE);
142   for (elLookup = &sgf->top;
143        (elLookup != NULL) && (elLookup->type != sgfType_node);
144        elLookup = elLookup->activeChild)  {
145     if (elLookup->type == sgfType_gameComment)  {
146       abutTerm_set(info->gameComment, str_chars(elLookup->sVal));
147       break;
148     }
149   }
150 
151   return(info);
152 }
153 
154 
editInfo_destroy(EditInfo * info,bool propagate)155 void  editInfo_destroy(EditInfo *info, bool propagate)  {
156   Cgoban  *cg;
157 
158   assert(MAGIC(info));
159   if (propagate)  {
160     info->destroy(info, info->packet);
161     assert(MAGIC(info));
162   }
163   if (info->win)  {
164     cg = info->cg;
165     assert(MAGIC(cg));
166     clp_setDouble(cg->clp, "edit.infoW",
167 		  (double)butWin_w(info->win) /
168 		  (double)butWin_getMinW(info->win));
169     clp_setDouble(cg->clp, "edit.infoH",
170 		  (double)butWin_h(info->win) /
171 		  (double)butWin_getMinH(info->win));
172     clp_setInt(cg->clp, "edit.infoX", butWin_x(info->win));
173     clp_setInt(cg->clp, "edit.infoY", butWin_y(info->win));
174     butWin_setDestroy(info->win, NULL);
175     butWin_destroy(info->win);
176   }
177   MAGIC_UNSET(info);
178   wms_free(info);
179 }
180 
181 
unmap(ButWin * win)182 static ButOut  unmap(ButWin *win)  {
183   return(0);
184 }
185 
186 
map(ButWin * win)187 static ButOut  map(ButWin *win)  {
188   return(0);
189 }
190 
191 
resize(ButWin * win)192 static ButOut  resize(ButWin *win)  {
193   EditInfo  *info = butWin_packet(win);
194   int  fontH, bw, w, h;
195   int  y;
196   int  w2;
197   int  lw, rw;
198   EditInfoVal  val;
199   int  textW, maxTextW;
200 
201   assert(MAGIC(info));
202   w = butWin_w(info->win);
203   h = butWin_h(info->win);
204   fontH = info->cg->fontH;
205   bw = butEnv_stdBw(butWin_env(win));
206   but_resize(info->bg, 0, 0, w, h);
207   but_resize(info->winTitle, bw*2, y = bw*2, w - bw*4, fontH*2);
208 
209   maxTextW = 0;
210   editInfoVal_iter(val)  {
211     textW = butEnv_textWidth(info->cg->env, sgfVals[val].title, 0);
212     if (textW > maxTextW)
213       maxTextW = textW;
214   }
215   w2 = (w + bw) / 2;
216   lw = w2 - bw * 3;
217   rw = w - bw * 2 - w2;
218   editInfoVal_iter(val)  {
219     if (val <= editInfo_copyright)  {
220       but_resize(info->infos[val].name, bw*2, y += bw + fontH*2,
221 		 maxTextW, fontH*2);
222       but_resize(info->infos[val].in, bw*3 + maxTextW, y,
223 		 w - (bw*5 + maxTextW), fontH*2);
224     } else  {
225       but_resize(info->infos[val].name, bw*2, y += bw + fontH*2,
226 		 maxTextW, fontH*2);
227       but_resize(info->infos[val].in, bw*3 + maxTextW, y,
228 		 lw - (maxTextW + bw), fontH*2);
229       ++val;
230       but_resize(info->infos[val].name, w2, y, maxTextW, fontH*2);
231       but_resize(info->infos[val].in, w2 + maxTextW + bw, y,
232 		 rw - (maxTextW + bw), fontH*2);
233     }
234   }
235   y += bw + fontH * 2;
236   abutTerm_resize(info->gameComment, bw*2, y, w - bw*4, h - y - bw*2);
237 
238   return(0);
239 }
240 
241 
destroy(ButWin * win)242 static ButOut  destroy(ButWin *win)  {
243   EditInfo  *info = butWin_packet(win);
244   Cgoban  *cg;
245 
246   assert(MAGIC(info));
247   editInfo_updateSgf(info);
248   cg = info->cg;
249   assert(MAGIC(cg));
250   clp_setDouble(cg->clp, "edit.infoW",
251 		(double)butWin_w(win) / (double)butWin_getMinW(win));
252   clp_setDouble(cg->clp, "edit.infoH",
253 		(double)butWin_h(win) / (double)butWin_getMinH(win));
254   clp_setInt(cg->clp, "edit.infoX", butWin_x(win));
255   clp_setInt(cg->clp, "edit.infoY", butWin_y(win));
256   info->win = NULL;
257   editInfo_destroy(info, TRUE);
258   return(0);
259 }
260 
261 
newTitle(But * but,const char * newStr)262 static ButOut  newTitle(But *but, const char *newStr)  {
263   EditInfo  *info = but_packet(but);
264 
265   assert(MAGIC(info));
266   assert(but == info->infos[editInfo_gameTitle].in);
267   editInfo_updateSgf(info);
268   butText_set(info->goban->labelText, newStr);
269   return(0);
270 }
271 
272 
273 /*
274  * This function is really badly structured.  I should fix it up.
275  */
editInfo_updateSgf(EditInfo * info)276 void  editInfo_updateSgf(EditInfo *info)  {
277   EditInfoVal  val;
278   const char  *newVal;
279   SgfElem  *elLookup;
280   int  newIval;
281   bool  found, change, err;
282   SgfInsert  oldMode;
283 
284   newIval = 0;  /* To shut up the warning from gcc. */
285   change = FALSE;  /* To shut up the warning from gcc. */
286   assert(MAGIC(info));
287   editInfoVal_iter(val)  {
288     newVal = butTextin_get(info->infos[val].in);
289     found = FALSE;
290     for (elLookup = &info->sgf->top;
291 	 (elLookup != NULL) && (elLookup->type != sgfType_node);
292 	 elLookup = elLookup->activeChild)  {
293       if ((elLookup->type == sgfVals[val].type) &&
294 	  ((sgfVals[val].color == goStone_empty) ||
295 	   (sgfVals[val].color == elLookup->gVal)))  {
296 	found = TRUE;
297 	break;
298       }
299     }
300     err = FALSE;
301     if (val == editInfo_komi)  {
302       newIval = (int)(wms_atof(newVal, &err) * 2.0);
303     } else if (val == editInfo_handicap)  {
304       newIval = wms_atoi(newVal, &err);
305     }
306     if (!found)  {
307       if (newVal[0] != '\0')
308 	change = TRUE;
309     } else  {
310       if ((val == editInfo_komi) || (val == editInfo_handicap))  {
311 	change = (newIval != elLookup->iVal);
312       } else  {
313 	change = strcmp(newVal, str_chars(elLookup->sVal));
314       }
315     }
316     if (change)  {
317       if (found)  {
318 	if ((val == editInfo_komi) || (val == editInfo_handicap))  {
319 	  if (!err)
320 	    elLookup->iVal = newIval;
321 	} else  {
322 	  str_copyChars(elLookup->sVal, newVal);
323 	}
324       } else  {
325 	elLookup = info->sgf->active;
326 	info->sgf->active = info->sgf->top.activeChild;
327 	oldMode = info->sgf->mode;
328 	info->sgf->mode = sgfInsert_inline;
329 	if ((val == editInfo_komi) || (val == editInfo_handicap))  {
330 	  if (!err)
331 	    sgf_addCIElem(info->sgf, sgfVals[val].type,
332 			  sgfVals[val].color, newIval);
333 	} else  {
334 	  sgf_addCSElem(info->sgf, sgfVals[val].type,
335 			sgfVals[val].color, newVal);
336 	}
337 	info->sgf->mode = oldMode;
338 	info->sgf->active = elLookup;
339       }
340     }
341   }
342   newVal = butTbin_get(info->gameComment->tbin);
343   found = FALSE;
344   for (elLookup = &info->sgf->top;
345        (elLookup != NULL) && (elLookup->type != sgfType_node);
346        elLookup = elLookup->activeChild)  {
347     if (elLookup->type == sgfType_gameComment)  {
348       found = TRUE;
349       break;
350     }
351   }
352   if (found)  {
353     if (strcmp(newVal, str_chars(elLookup->sVal)))  {
354       str_copyChars(elLookup->sVal, newVal);
355     }
356   } else  {
357     if (newVal[0] != '\0')  {
358       elLookup = info->sgf->active;
359       info->sgf->active = info->sgf->top.activeChild;
360       oldMode = info->sgf->mode;
361       info->sgf->mode = sgfInsert_inline;
362       sgf_addCSElem(info->sgf, sgfType_gameComment, goStone_empty, newVal);
363       info->sgf->mode = oldMode;
364       info->sgf->active = elLookup;
365     }
366   }
367 }
368