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