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