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