1 /*
2 * src/msg.c, part of wmslib library
3 * Copyright (C) 1994-1995 William Shubert.
4 * See "configure.h.in" for more copyright information.
5 */
6
7 #include <math.h>
8 #include <wms.h>
9 #include <but/but.h>
10 #include <but/text.h>
11 #include <but/ctext.h>
12 #include <but/box.h>
13 #include <but/tblock.h>
14 #include <but/plain.h>
15 #include <but/textin.h>
16 #include <abut/msg.h>
17
18
19 static ButOut unmap(ButWin *win);
20 static ButOut wDestroy(ButWin *win);
21 static ButOut resize(ButWin *win);
22 static ButOut ok_pressed(But *but);
23 static void checkNewSize(AbutMsg *mwin, ButWin *win);
24 static void calcDims(Abut *abut, int fontNum, const char *text,
25 int *w, int *h, int *textH, int numTins);
26 static ButOut msg_resize(ButWin *win, AbutMsg *mwin);
27 static void fillboxDead(But *but);
28
29
30 /*
31 * UseMsg is never accessed. We just need a void * guaranteed to be
32 * different from any the user could pass us.
33 */
34 static int useMsg = 0;
35
36
abutMsg_inCreate(Abut * a,ButWin * win,int layer,const char * text,void * packet,int numTins,const AbutMsgTin * tinList)37 AbutMsg *abutMsg_inCreate(Abut *a, ButWin *win, int layer, const char *text,
38 void *packet,
39 int numTins, const AbutMsgTin *tinList) {
40 static AbutMsgOpt ok[1];
41 static ButKey ka_ok[] = {{XK_Return, 0, ShiftMask},
42 {XK_KP_Enter, 0, ShiftMask}, {0,0,0}};
43
44 ok[0].name = a->ok;
45 ok[0].callback = ok_pressed;
46 ok[0].keyEq = ka_ok;
47 ok[0].packet = &useMsg;
48 return(abutMsg_optInCreate(a, win, layer, text, NULL, NULL, 1, ok,
49 numTins, tinList));
50 }
51
52
abutMsg_optInCreate(Abut * a,ButWin * win,int layer,const char * text,ButOut (* destroy)(void * packet),void * packet,int numButs,const AbutMsgOpt * optList,int numTins,const AbutMsgTin * tinList)53 AbutMsg *abutMsg_optInCreate(Abut *a, ButWin *win, int layer,
54 const char *text,
55 ButOut (*destroy)(void *packet), void *packet,
56 int numButs, const AbutMsgOpt *optList,
57 int numTins, const AbutMsgTin *tinList) {
58 ButEnv *env;
59 AbutMsg *mwin;
60 int winW, winH;
61 int i;
62 void *butPacket;
63
64 assert(MAGIC(a));
65 assert(a->env == butWin_env(win));
66 env = a->env;
67 mwin = wms_malloc(sizeof(AbutMsg));
68 MAGIC_SET(mwin);
69 mwin->abut = a;
70 mwin->win = win;
71 mwin->numButs = numButs;
72 mwin->buts = wms_malloc(numButs * sizeof(But *));
73 mwin->numTins = numTins;
74 mwin->tins = wms_malloc(numTins * sizeof(But *));
75 mwin->tinTitles = wms_malloc(numTins * sizeof(But *));
76 mwin->butDesc = optList;
77 mwin->destroy = destroy;
78 mwin->packet = packet;
79 mwin->layer = layer;
80
81 calcDims(a, 0, text, &winW, &winH, &mwin->textH, numTins);
82 mwin->w = winW;
83 mwin->h = winH;
84 mwin->box = butBoxFilled_create(win, layer, BUT_DRAWABLE);
85 but_setPacket(mwin->box, mwin);
86 but_setDestroyCallback(mwin->box, fillboxDead);
87 butBoxFilled_setColors(mwin->box, a->ulColor, a->lrColor, a->bgColor);
88 butBoxFilled_setPixmaps(mwin->box, a->ulPixmap, a->lrPixmap, a->bgPixmap);
89 mwin->text = butTblock_create(win, layer+1, BUT_DRAWABLE,
90 text, butText_just);
91 for (i = 0; i < numButs; ++i) {
92 butPacket = optList[i].packet;
93 if (butPacket == &useMsg)
94 butPacket = mwin;
95 mwin->buts[i] = butCt_create(optList[i].callback, butPacket,
96 win, layer+1, BUT_DRAWABLE|BUT_PRESSABLE,
97 optList[i].name);
98 if (optList[i].keyEq)
99 but_setKeys(mwin->buts[i], optList[i].keyEq);
100 }
101 for (i = 0; i < numTins; ++i) {
102 if (tinList[i].name)
103 mwin->tinTitles[i] = butText_create(win, layer+1, BUT_DRAWABLE,
104 tinList[i].name, butText_left);
105 else
106 mwin->tinTitles[i] = NULL;
107 mwin->tins[i] = butTextin_create(tinList[i].callback, packet,
108 win, layer+1, BUT_DRAWABLE|BUT_PRESSABLE,
109 tinList[i].def, 500);
110 }
111 if (butWin_w(win))
112 msg_resize(win, mwin);
113 return(mwin);
114 }
115
116
abutMsg_winInCreate(Abut * a,const char * title,const char * text,void * packet,int numTins,const AbutMsgTin * tinList)117 AbutMsg *abutMsg_winInCreate(Abut *a, const char *title, const char *text,
118 void *packet,
119 int numTins, const AbutMsgTin *tinList) {
120 static AbutMsgOpt ok[1];
121 static ButKey ka_ok[] = {{XK_Return, 0, ShiftMask|ControlMask},
122 {XK_KP_Enter, 0, ShiftMask|ControlMask},
123 {0, 0, 0}};
124
125 ok[0].name = a->ok;
126 ok[0].callback = ok_pressed;
127 ok[0].keyEq = ka_ok;
128 ok[0].packet = &useMsg;
129 return(abutMsg_winOptInCreate(a, title, text, NULL, NULL, 1, ok,
130 numTins, tinList));
131 }
132
133
abutMsg_winOptInCreate(Abut * a,const char * title,const char * text,ButOut (* destroy)(void * packet),void * packet,int numButs,const AbutMsgOpt * optList,int numTins,const AbutMsgTin * tinList)134 AbutMsg *abutMsg_winOptInCreate(Abut *a, const char *title, const char *text,
135 ButOut (*destroy)(void *packet), void *packet,
136 int numButs, const AbutMsgOpt *optList,
137 int numTins, const AbutMsgTin *tinList) {
138 ButEnv *env;
139 AbutMsg *mwin;
140 ButWin *win;
141 int winW, winH;
142 int i;
143 void *butPacket;
144
145 assert(MAGIC(a));
146 env = a->env;
147 mwin = wms_malloc(sizeof(AbutMsg));
148 MAGIC_SET(mwin);
149 mwin->abut = a;
150 mwin->numButs = numButs;
151 mwin->buts = wms_malloc(numButs * sizeof(But *));
152 mwin->numTins = numTins;
153 mwin->tins = wms_malloc(numTins * sizeof(But *));
154 mwin->tinTitles = wms_malloc(numTins * sizeof(But *));
155 mwin->butDesc = optList;
156 mwin->destroy = destroy;
157 mwin->packet = packet;
158 mwin->layer = 0;
159
160 calcDims(a, 0, text, &winW, &winH, &mwin->textH, numTins);
161 mwin->w = winW;
162 mwin->h = winH;
163 mwin->win = win = butWin_create(mwin, env, title, winW, winH,
164 unmap, NULL, resize, wDestroy);
165 butWin_activate(win);
166 mwin->box = butBoxFilled_create(win, 0, BUT_DRAWABLE);
167 butBoxFilled_setColors(mwin->box, a->ulColor, a->lrColor, a->bgColor);
168 butBoxFilled_setPixmaps(mwin->box, a->ulPixmap, a->lrPixmap, a->bgPixmap);
169 mwin->text = butTblock_create(win, 1, BUT_DRAWABLE,
170 text, butText_just);
171 for (i = 0; i < numButs; ++i) {
172 butPacket = optList[i].packet;
173 if (butPacket == &useMsg)
174 butPacket = mwin;
175 mwin->buts[i] = butCt_create(optList[i].callback, butPacket,
176 win, 1, BUT_DRAWABLE|BUT_PRESSABLE,
177 optList[i].name);
178 if (optList[i].keyEq)
179 but_setKeys(mwin->buts[i], optList[i].keyEq);
180 }
181 for (i = 0; i < numTins; ++i) {
182 mwin->tinTitles[i] = butText_create(win, 1, BUT_DRAWABLE,
183 tinList[i].name, butText_left);
184 mwin->tins[i] = butTextin_create(tinList[i].callback, packet, win,
185 1, BUT_DRAWABLE|BUT_PRESSABLE,
186 tinList[i].def, 150);
187 if (tinList[i].flags & abutMsgTinFlags_secret) {
188 butTextin_setHidden(mwin->tins[i], TRUE);
189 }
190 }
191 if (butWin_w(win))
192 msg_resize(win, mwin);
193 return(mwin);
194 }
195
196
unmap(ButWin * win)197 static ButOut unmap(ButWin *win) {
198 butWin_destroy(win);
199 return(0);
200 }
201
202
wDestroy(ButWin * win)203 static ButOut wDestroy(ButWin *win) {
204 AbutMsg *mwin = butWin_packet(win);
205 ButOut result = 0;
206
207 assert(MAGIC(mwin));
208 mwin->win = NULL;
209 if (mwin->buts) {
210 wms_free(mwin->buts);
211 mwin->buts = NULL;
212 }
213 if (mwin->tins) {
214 wms_free(mwin->tins);
215 wms_free(mwin->tinTitles);
216 mwin->tins = NULL;
217 mwin->tinTitles = NULL;
218 }
219 if (mwin->destroy)
220 result = mwin->destroy(mwin->packet);
221 MAGIC_UNSET(mwin);
222 wms_free(mwin);
223 return(result);
224 }
225
226
resize(ButWin * win)227 static ButOut resize(ButWin *win) {
228 return(msg_resize(win, butWin_packet(win)));
229 }
230
231
msg_resize(ButWin * win,AbutMsg * mwin)232 static ButOut msg_resize(ButWin *win, AbutMsg *mwin) {
233 int x, y, w, h, buth;
234 ButEnv *env = butWin_env(win);
235 int bw = butEnv_stdBw(env);
236 int butX, butW, i;
237 int maxTinNameLen = 0, newLen;
238
239 assert(MAGIC(mwin));
240 checkNewSize(mwin, win);
241 x = (butWin_w(win) - mwin->w) / 2;
242 y = (butWin_h(win) - mwin->h) / 2;
243 w = mwin->w;
244 h = mwin->h;
245 buth = mwin->abut->butH;
246 but_resize(mwin->box, x,y, w,h);
247 butTblock_resize(mwin->text, x+bw*2, y+bw*2, w - bw*4);
248 for (butX = bw*2, i = 0; i < mwin->numButs; ++i) {
249 butW = (w-bw-butX + (mwin->numButs - i) / 2) / (mwin->numButs - i) - bw;
250 but_resize(mwin->buts[i], x+butX, y+h-bw*2-buth, butW, buth);
251 butX += butW + bw;
252 }
253 for (i = 0; i < mwin->numTins; ++i) {
254 if (mwin->tinTitles[i]) {
255 newLen = butText_resize(mwin->tinTitles[i], x + bw*2,
256 y + h - (buth + bw)*(mwin->numTins - i + 1) -
257 bw*2, buth) + bw;
258 if (newLen > maxTinNameLen)
259 maxTinNameLen = newLen;
260 }
261 }
262 for (i = 0; i < mwin->numTins; ++i) {
263 but_resize(mwin->tins[i], x + bw*2 + maxTinNameLen,
264 y + h - (buth + bw)*(mwin->numTins - i + 1) - bw*2,
265 w - bw*4 - maxTinNameLen, buth);
266 }
267 return(0);
268 }
269
270
checkNewSize(AbutMsg * mwin,ButWin * win)271 static void checkNewSize(AbutMsg *mwin, ButWin *win) {
272 ButEnv *env = butWin_env(win);
273 int textH, butH;
274
275 textH = butEnv_fontH(env, 0);
276 butH = mwin->abut->butH;
277 if (textH != mwin->textH) {
278 calcDims(mwin->abut, 0, butTblock_getText(mwin->text),
279 &mwin->w, &mwin->h, &mwin->textH, mwin->numTins);
280 if (mwin->layer == 0)
281 butWin_resize(win, mwin->w, mwin->h);
282 }
283 }
284
285
ok_pressed(But * but)286 static ButOut ok_pressed(But *but) {
287 AbutMsg *msg;
288
289 msg = but_packet(but);
290 assert(MAGIC(msg));
291 if (msg->layer == 0)
292 butWin_destroy(msg->win);
293 else
294 abutMsg_destroy(but_packet(but), TRUE);
295 return(0);
296 }
297
298
abutMsg_destroy(AbutMsg * msg,bool propagate)299 void abutMsg_destroy(AbutMsg *msg, bool propagate) {
300 int i;
301 int x = 0, y = 0, w = 0, h = 0;
302
303 assert(MAGIC(msg));
304 if (propagate == FALSE) {
305 msg->destroy = NULL;
306 }
307 if (msg->box) {
308 x = but_x(msg->box);
309 y = but_y(msg->box);
310 w = but_w(msg->box);
311 h = but_h(msg->box);
312 }
313 if (msg->buts) {
314 but_setPacket(msg->box, NULL);
315 but_destroy(msg->box);
316 but_destroy(msg->text);
317 for (i = 0; i < msg->numButs; ++i)
318 but_destroy(msg->buts[i]);
319 for (i = 0; i < msg->numTins; ++i) {
320 but_destroy(msg->tins[i]);
321 but_destroy(msg->tinTitles[i]);
322 }
323 }
324 if ((msg->layer == 0) && msg->win)
325 butWin_destroy(msg->win);
326 else {
327 butWin_redraw(msg->win, x, y, w, h);
328 MAGIC_UNSET(msg);
329 wms_free(msg);
330 }
331 }
332
333
calcDims(Abut * abut,int fontNum,const char * text,int * w,int * h,int * textHOut,int numTins)334 static void calcDims(Abut *abut, int fontNum, const char *text,
335 int *w, int *h, int *textHOut, int numTins) {
336 ButEnv *env = abut->env;
337 int textW, textH, butH, butSpc;
338 int winW, winH, actualH, bw;
339 double b, c;
340
341 textW = butEnv_textWidth(env, text, fontNum);
342 *textHOut = textH = butEnv_fontH(env, fontNum);
343 butH = abut->butH;
344 bw = butEnv_stdBw(env);
345 butSpc = butH + bw;
346
347 /*
348 * This is based on the calculations:
349 * winW = 2*winH
350 * (winW - 4*bw) * (winH - (4*bw + butSpc*(numTins + 1))) = textW*textH
351 * Solve for winW...
352 * (winW - 4*bw) * (0.5*winW - 4*bw - butSpc*numTins - butSpc) =
353 * textW*textH
354 * 0.5*winW^2 - winW*(-4*bw-butSpc*numTins-butSpc-2*bw) +
355 * 16*bw*bw+4*bw*butSpc*numTins+4*bw*butSpc - textW*textH = 0
356 * winW^2 - winW*(-12*bw-2*butSpc*numTins-2*butSpc) +
357 * 32*bw*bw+8*bw*butSpc*numTins+8*bw*butSpc - 2*textW*textH = 0
358 * Using the quadratic equation, notice a is 1.0, and solve
359 * winW = (-b+sqrt(b*b-4*a*c))/2*a
360 */
361 b = (double)(-12 * bw - 2 * butSpc * numTins - 2 * butSpc);
362 c = (double)(32*bw*bw + 8*bw*butSpc*numTins + 8*bw*butSpc - 2 * textW*textH);
363 winW = (int)((-b + sqrt(b*b-4*c)) * 0.5 + 0.5);
364 winH = winW / 2;
365 if (winH < 2*textH + butSpc*(numTins + 1) + 4*butEnv_stdBw(env))
366 winH = 2*textH + butSpc*(numTins + 1) + 4*butEnv_stdBw(env);
367 winW = winH * 2;
368 actualH = butTblock_guessH(env, text, winW - 4*butEnv_stdBw(env), fontNum) +
369 butSpc*(numTins + 1) + 4*butEnv_stdBw(env);
370 if (actualH > winH) {
371 winH = actualH;
372 winW = 2*winH;
373 }
374 *w = winW;
375 *h = winH;
376 }
377
378
fillboxDead(But * but)379 static void fillboxDead(But *but) {
380 AbutMsg *mwin;
381
382 assert(MAGIC(but));
383 mwin = but_packet(but);
384 if (mwin) {
385 assert(MAGIC(mwin));
386 if (mwin->buts) {
387 wms_free(mwin->buts);
388 mwin->buts = NULL;
389 }
390 if (mwin->tins) {
391 wms_free(mwin->tins);
392 wms_free(mwin->tinTitles);
393 mwin->tins = NULL;
394 mwin->tinTitles = NULL;
395 }
396 mwin->box = mwin->text = NULL;
397 mwin->win = NULL;
398 }
399 }
400