1 /*  Part of XPCE --- The SWI-Prolog GUI toolkit
2 
3     Author:        Jan Wielemaker and Anjo Anjewierden
4     E-mail:        jan@swi.psy.uva.nl
5     WWW:           http://www.swi.psy.uva.nl/projects/xpce/
6     Copyright (c)  1997-2011, University of Amsterdam
7     All rights reserved.
8 
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions
11     are met:
12 
13     1. Redistributions of source code must retain the above copyright
14        notice, this list of conditions and the following disclaimer.
15 
16     2. Redistributions in binary form must reproduce the above copyright
17        notice, this list of conditions and the following disclaimer in
18        the documentation and/or other materials provided with the
19        distribution.
20 
21     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25     COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32     POSSIBILITY OF SUCH DAMAGE.
33 */
34 
35 #include <h/kernel.h>
36 #include <h/dialog.h>
37 
38 static status	restoreLabelBox(LabelBox lb);
39 
40 		/********************************
41 		*             CREATE		*
42 		********************************/
43 
44 static status
initialiseLabelBox(LabelBox lb,Name name,Code msg)45 initialiseLabelBox(LabelBox lb, Name name, Code msg)
46 { assign(lb, label_width,  DEFAULT);
47 
48   initialiseDialogGroup((DialogGroup) lb, name, DEFAULT);
49 
50   if ( isDefault(msg) )
51     msg = NIL;
52 
53   assign(lb, pen, 		toInt(0));
54   assign(lb, border, 		newObject(ClassSize, EAV));
55   assign(lb, auto_label_align,	ON);
56   assign(lb, message,		msg);
57   assign(lb, modified,		OFF);
58 
59   succeed;
60 }
61 
62 		 /*******************************
63 		 *	      LABEL		*
64 		 *******************************/
65 
66 static void
compute_label(LabelBox lb,int * w,int * h,int * y)67 compute_label(LabelBox lb, int *w, int *h, int *y)
68 { compute_label_size_dialog_group((DialogGroup)lb, w, h);
69 
70   if ( *w > 0 )
71   { if ( instanceOfObject(lb->label_font, ClassFont) )
72       *w += valInt(getExFont(lb->label_font));
73     else
74       *w += 5;
75   }
76 
77   if ( notDefault(lb->label_width) && *w < valInt(lb->label_width) )
78     *w = valInt(lb->label_width);
79 
80   if ( y )
81   { *y = 0;
82 
83     if ( instanceOfObject(lb->label, ClassCharArray) )
84     { Graphical gr = getHeadChain(lb->graphicals);
85 
86       for( ; gr && notNil(gr); gr = get(gr, NAME_right, EAV))
87       { Point pt;
88 
89 	if ( (pt = get(gr, NAME_reference, EAV)) )
90 	{ int ry = valInt(pt->y);
91 	  int af = valInt(getAscentFont(lb->label_font));
92 
93 	  if ( ry > af )
94 	    *y = ry-af;
95 
96 	  break;
97 	}
98       }
99     }
100   }
101 }
102 
103 
104 static status
labelWidthLabelBox(LabelBox lb,Int w)105 labelWidthLabelBox(LabelBox lb, Int w)
106 { if ( lb->label_width != w )
107   { assign(lb, label_width, w);
108     return requestComputeDevice((Device)lb, DEFAULT);
109   }
110 
111   succeed;
112 }
113 
114 
115 static status
labelFormatLabelBox(LabelBox lb,Name fmt)116 labelFormatLabelBox(LabelBox lb, Name fmt)
117 { if ( lb->label_format != fmt )
118   { assign(lb, label_width, fmt);
119     return requestComputeDevice((Device)lb, DEFAULT);
120   }
121 
122   succeed;
123 }
124 
125 
126 static Int
getLabelWidthLabelBox(LabelBox lb)127 getLabelWidthLabelBox(LabelBox lb)
128 { int w, h;
129 
130   compute_label(lb, &w, &h, NULL);
131 
132   answer(toInt(w));
133 }
134 
135 
136 		 /*******************************
137 		 *	      COMPUTE		*
138 		 *******************************/
139 
140 static status
computeLabelBox(LabelBox lb)141 computeLabelBox(LabelBox lb)
142 { if ( notNil(lb->request_compute) )
143   { int x, y, w, h;
144     Area a = lb->area;
145     int lw, lh;
146     Size border;
147 
148     obtainClassVariablesObject(lb);
149     border = (isDefault(lb->border) ? lb->gap : lb->border);
150     compute_label(lb, &lw, &lh, NULL);
151     computeGraphicalsDevice((Device) lb);
152 
153     if ( isDefault(lb->size) )		/* implicit size */
154     { Cell cell;
155 
156       clearArea(a);
157       for_cell(cell, lb->graphicals)
158       { Graphical gr = cell->value;
159 
160 	unionNormalisedArea(a, gr->area);
161       }
162       relativeMoveArea(a, lb->offset);
163 
164       x = valInt(a->x) -     valInt(border->w);
165       y = valInt(a->y) -     valInt(border->h);
166       w = valInt(a->w) + 2 * valInt(border->w);
167       h = valInt(a->h) + 2 * valInt(border->h);
168 
169       w += lw;
170       x -= lw;
171     } else				/* explicit size */
172     { x = valInt(lb->offset->x);
173       y = valInt(lb->offset->y);
174       w = valInt(lb->size->w);
175       h = valInt(lb->size->h);
176       x -= lw;
177     }
178 
179     h = max(h, lh);
180     w = max(w, lw);
181 
182     CHANGING_GRAPHICAL(lb,
183 	assign(a, x, toInt(x));
184 	assign(a, y, toInt(y));
185 	assign(a, w, toInt(w));
186 	assign(a, h, toInt(h)));
187 
188     assign(lb, request_compute, NIL);
189   }
190 
191   succeed;
192 }
193 
194 		 /*******************************
195 		 *	       GEOMETRY		*
196 		 *******************************/
197 
198 static status
geometryLabelBox(LabelBox lb,Int x,Int y,Int w,Int h)199 geometryLabelBox(LabelBox lb, Int x, Int y, Int w, Int h)
200 { if ( notDefault(w) || notDefault(h) )
201   { Any size;
202     int lw, lh;
203 
204     compute_label(lb, &lw, &lh, NULL);
205 
206     if ( isDefault(w) )
207       w = getWidthGraphical((Graphical) lb);
208     if ( isDefault(h) )
209       h = getHeightGraphical((Graphical) lb);
210 
211     size = newObject(ClassSize, w, h, EAV);
212     qadSendv(lb, NAME_size, 1, &size);
213     doneObject(size);
214   }
215 
216   return geometryDevice((Device) lb, x, y, w, h);
217 }
218 
219 
220 static status
layoutDialogLabelBox(LabelBox lb)221 layoutDialogLabelBox(LabelBox lb)
222 { int lw, lh;
223 
224   obtainClassVariablesObject(lb);
225   compute_label(lb, &lw, &lh, NULL);
226 
227   if ( notDefault(lb->size) )
228     lb->size->w = toInt(valInt(lb->size->w) - lw);
229   layoutDialogDevice((Device)lb, lb->gap, lb->size, lb->border);
230   if ( notDefault(lb->size) )
231     lb->size->w = toInt(valInt(lb->size->w) + lw);
232 
233   succeed;
234 }
235 
236 
237 
238 		 /*******************************
239 		 *	       REDRAW		*
240 		 *******************************/
241 
242 static status
RedrawAreaLabelBox(LabelBox lb,Area a)243 RedrawAreaLabelBox(LabelBox lb, Area a)
244 { Device dev = (Device)lb;
245   device_draw_context ctx;
246 
247   if ( EnterRedrawAreaDevice(dev, a, &ctx) )
248   { Cell cell;
249     int lw, lh, ly, sx = 5;
250 
251     compute_label(lb, &lw, &lh, &ly);
252     if ( instanceOfObject(lb->label_font, ClassFont) )
253       sx = valInt(getExFont(lb->label_font));
254 
255     RedrawLabelDialogGroup((DialogGroup)lb, 0,
256 			   -lw, ly, lw-sx, lh,
257 			   lb->label_format, NAME_top, 0);
258 
259     for_cell(cell, dev->graphicals)
260     { Graphical gr = cell->value;
261 
262       if ( gr->displayed == ON && overlapArea(a, gr->area) )
263 	RedrawArea(gr, a);
264     }
265 
266     ExitRedrawAreaDevice(dev, a, &ctx);
267   }
268 
269   return RedrawAreaGraphical(dev, a);
270 }
271 
272 
273 static Point
getReferenceLabelBox(LabelBox lb)274 getReferenceLabelBox(LabelBox lb)
275 { Point pt;
276 
277   if ( (pt = getAttributeObject(lb, NAME_reference)) &&
278        instanceOfObject(pt, ClassPoint) )
279     answer(pt);
280 
281   obtainClassVariablesObject(lb);
282 
283   answer(answerObject(ClassPoint, ZERO, getAscentFont(lb->label_font), EAV));
284 }
285 
286 		 /*******************************
287 		 *	  MODIFIED/APPLY	*
288 		 *******************************/
289 
290 static status
modifiedLabelBox(LabelBox lb,BoolObj m)291 modifiedLabelBox(LabelBox lb, BoolObj m)
292 { assign(lb, modified, m);
293 
294   if ( m == ON && notNil(lb->device) )
295     send(lb->device, NAME_modifiedItem, lb, ON, EAV);
296 
297   succeed;
298 }
299 
300 
301 static status
modifiedItemLabelBox(LabelBox lb,Graphical item,BoolObj m)302 modifiedItemLabelBox(LabelBox lb, Graphical item, BoolObj m)
303 { if ( m == ON )
304     send(lb, NAME_modified, ON, EAV);
305 
306   succeed;
307 }
308 
309 
310 static status
defaultLabelBox(LabelBox lb,Any def)311 defaultLabelBox(LabelBox lb, Any def)
312 { if ( lb->default_value != def )
313   { assign(lb, default_value, def);
314 
315     return restoreLabelBox(lb);
316   }
317 
318   succeed;
319 }
320 
321 
322 static Any
getDefaultLabelBox(LabelBox lb)323 getDefaultLabelBox(LabelBox lb)
324 { answer(checkType(lb->default_value, TypeAny, lb));
325 }
326 
327 
328 static status
restoreLabelBox(LabelBox lb)329 restoreLabelBox(LabelBox lb)
330 { Any val;
331 
332   TRY(val = getDefaultLabelBox(lb));
333   return send(lb, NAME_selection, val, EAV);
334 }
335 
336 
337 static status
applyLabelBox(LabelBox lb,BoolObj always)338 applyLabelBox(LabelBox lb, BoolObj always)
339 { Any val;
340 
341   if ( instanceOfObject(lb->message, ClassCode) &&
342        (always == ON || lb->modified == ON) &&
343        (val = getv(lb, NAME_selection, 0, NULL)) )
344     return forwardReceiverCode(lb->message, lb, val, EAV);
345 
346   fail;
347 }
348 
349 		 /*******************************
350 		 *	 CLASS DECLARATION	*
351 		 *******************************/
352 
353 /* Type declaractions */
354 
355 static char *T_initialise[] =
356         { "name=[name]", "message=[code]*" };
357 static char *T_modifiedItem[] =
358         { "item=graphical", "modified=bool" };
359 static char *T_geometry[] =
360         { "x=[int]", "y=[int]", "width=[int]", "height=[int]" };
361 
362 /* Instance Variables */
363 
364 static vardecl var_label_box[] =
365 { SV(NAME_labelFormat, "{left,center,right}", IV_GET|IV_STORE|IV_REDEFINE,
366      labelFormatLabelBox,
367      NAME_layout, "Align label in its box"),
368   IV(NAME_labelWidth, "[int]", IV_NONE,
369      NAME_layout, "Width of the label"),
370   IV(NAME_autoLabelAlign, "bool", IV_BOTH,
371      NAME_layout, "Automatically align label"),
372   IV(NAME_message, "code*", IV_BOTH,
373      NAME_action, "Associated action"),
374   IV(NAME_default, "any|function", IV_NONE,
375      NAME_apply, "The default value"),
376   IV(NAME_modified, "bool", IV_GET,
377      NAME_apply, "Item has been modified")
378 };
379 
380 /* Send Methods */
381 
382 static senddecl send_label_box[] =
383 { SM(NAME_initialise, 2, T_initialise, initialiseLabelBox,
384      DEFAULT, "Create a label_box"),
385   SM(NAME_geometry, 4, T_geometry, geometryLabelBox,
386      DEFAULT, "Move/resize label box"),
387   SM(NAME_compute, 0, NULL, computeLabelBox,
388      NAME_update, "Recompute area"),
389   SM(NAME_labelWidth, 1, "[int]", labelWidthLabelBox,
390      NAME_layout, "Specify width of the label"),
391   SM(NAME_layoutDialog, 0, NULL, layoutDialogLabelBox,
392      NAME_layout, "(Re)compute layout of dialog_items"),
393   SM(NAME_modified, 1, "bool", modifiedLabelBox,
394      NAME_apply, "Forward to all <-graphicals"),
395   SM(NAME_default, 1, "any|function", defaultLabelBox,
396      NAME_apply, "Set variable -default and ->selection"),
397   SM(NAME_restore, 0, NULL, restoreLabelBox,
398      NAME_apply, "Set ->selection to <-default"),
399   SM(NAME_apply, 1, "[bool]", applyLabelBox,
400      NAME_apply, "->execute if <-modified or @on"),
401   SM(NAME_selection, 1, "any", failObject,
402      NAME_selection, "Virtual method"),
403   SM(NAME_modifiedItem, 2, T_modifiedItem, modifiedItemLabelBox,
404      NAME_apply, "Indicates item has changed state")
405 };
406 
407 /* Get Methods */
408 
409 static getdecl get_label_box[] =
410 { GM(NAME_reference, 0, "point", NULL, getReferenceLabelBox,
411      DEFAULT, "Left, baseline of label"),
412   GM(NAME_labelWidth, 0, "int", NULL, getLabelWidthLabelBox,
413      NAME_layout, "Current width of the label"),
414   GM(NAME_default, 0, "any", NULL, getDefaultLabelBox,
415      NAME_apply, "Current default value"),
416   GM(NAME_selection, 0, "any", NULL, getFailObject,
417      NAME_selection, "Virtual method")
418 };
419 
420 /* Resources */
421 
422 static classvardecl rc_label_box[] =
423 { RC(NAME_labelFormat, "{left,center,right}", "right",
424      "Alignment of the label in its box"),
425   RC(NAME_labelSuffix, "name", ":",
426      "Ensured suffix of label")
427 };
428 
429 /* Class Declaration */
430 
431 ClassDecl(label_box_decls,
432           var_label_box, send_label_box, get_label_box, rc_label_box,
433           ARGC_INHERIT, NULL,
434           "$Rev$");
435 
436 
437 status
makeClassLabelBox(Class class)438 makeClassLabelBox(Class class)
439 { declareClass(class, &label_box_decls);
440 
441   setRedrawFunctionClass(class, RedrawAreaLabelBox);
442 
443   succeed;
444 }
445 
446