comparison src/glyphs-widget.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents aabb7f5b1c81
children a86b2b5e0111
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
1 /* Widget-specific glyph objects. 1 /* Widget-specific glyph objects.
2 Copyright (C) 1998 Andy Piper 2 Copyright (C) 1998, 1999, 2000 Andy Piper.
3 3
4 This file is part of XEmacs. 4 This file is part of XEmacs.
5 5
6 XEmacs is free software; you can redistribute it and/or modify it 6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the 7 under the terms of the GNU General Public License as published by the
36 #include "frame.h" 36 #include "frame.h"
37 #include "insdel.h" 37 #include "insdel.h"
38 #include "opaque.h" 38 #include "opaque.h"
39 39
40 DEFINE_IMAGE_INSTANTIATOR_FORMAT (button); 40 DEFINE_IMAGE_INSTANTIATOR_FORMAT (button);
41 DEFINE_IMAGE_INSTANTIATOR_FORMAT (combo); 41 DEFINE_IMAGE_INSTANTIATOR_FORMAT (combo_box);
42 Lisp_Object Qcombo; 42 Lisp_Object Qcombo_box;
43 DEFINE_IMAGE_INSTANTIATOR_FORMAT (edit); 43 DEFINE_IMAGE_INSTANTIATOR_FORMAT (edit_field);
44 Lisp_Object Qedit; 44 Lisp_Object Qedit_field;
45 DEFINE_IMAGE_INSTANTIATOR_FORMAT (scrollbar); 45 DEFINE_IMAGE_INSTANTIATOR_FORMAT (scrollbar);
46 Lisp_Object Qscrollbar; 46 Lisp_Object Qscrollbar;
47 DEFINE_IMAGE_INSTANTIATOR_FORMAT (widget); 47 DEFINE_IMAGE_INSTANTIATOR_FORMAT (widget);
48 #if 0
49 DEFINE_IMAGE_INSTANTIATOR_FORMAT (group);
50 Lisp_Object Qgroup;
51 #endif
52 DEFINE_IMAGE_INSTANTIATOR_FORMAT (label); 48 DEFINE_IMAGE_INSTANTIATOR_FORMAT (label);
53 Lisp_Object Qlabel; 49 Lisp_Object Qlabel;
54 DEFINE_IMAGE_INSTANTIATOR_FORMAT (progress); 50 DEFINE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge);
55 Lisp_Object Qprogress; 51 Lisp_Object Qprogress_gauge;
52 DEFINE_IMAGE_INSTANTIATOR_FORMAT (tree_view);
53 Lisp_Object Qtree_view;
54 DEFINE_IMAGE_INSTANTIATOR_FORMAT (tab_control);
55 Lisp_Object Qtab_control;
56 DEFINE_IMAGE_INSTANTIATOR_FORMAT (layout);
57 Lisp_Object Qlayout;
56 58
57 Lisp_Object Q_descriptor, Q_height, Q_width, Q_properties, Q_items; 59 Lisp_Object Q_descriptor, Q_height, Q_width, Q_properties, Q_items;
58 Lisp_Object Q_image, Q_text, Q_percent; 60 Lisp_Object Q_image, Q_text, Q_percent, Q_orientation, Q_justify, Q_border;
59 61 Lisp_Object Qetched_in, Qetched_out, Qbevel_in, Qbevel_out;
60 #define WIDGET_BORDER_HEIGHT 2 62
61 #define WIDGET_BORDER_WIDTH 4 63 #ifdef DEBUG_WIDGETS
64 int debug_widget_instances;
65 #endif
62 66
63 /* TODO: 67 /* TODO:
64 - more complex controls. 68 - tooltips for controls, especially buttons.
65 - tooltips for controls. 69 - keyboard traversal.
70 - lisp configurable layout.
66 */ 71 */
67 72
68 /* In windows normal windows work in pixels, dialog boxes work in 73 /* In MS-Windows normal windows work in pixels, dialog boxes work in
69 dialog box units. Why? sigh. We could reuse the metrics for dialogs 74 dialog box units. Why? sigh. We could reuse the metrics for dialogs
70 if this were not the case. As it is we have to position things 75 if this were not the case. As it is we have to position things
71 pixel wise. I'm not even sure that X has this problem at least for 76 pixel wise. I'm not even sure that X has this problem at least for
72 buttons in groups. */ 77 buttons in groups. */
73 Lisp_Object
74 widget_face_font_info (Lisp_Object domain, Lisp_Object face,
75 int *height, int *width)
76 {
77 Lisp_Object font_instance = FACE_FONT (face, domain, Vcharset_ascii);
78
79 if (height)
80 *height = XFONT_INSTANCE (font_instance)->height;
81 if (width)
82 *width = XFONT_INSTANCE (font_instance)->width;
83
84 return font_instance;
85 }
86
87 void
88 widget_text_to_pixel_conversion (Lisp_Object domain, Lisp_Object face,
89 int th, int tw,
90 int* height, int* width)
91 {
92 int ch=0, cw=0;
93 widget_face_font_info (domain, face, &ch, &cw);
94 if (height)
95 *height = th * (ch + 2 * WIDGET_BORDER_HEIGHT);
96 if (width)
97 *width = tw * cw + 2 * WIDGET_BORDER_WIDTH;
98 }
99
100 static int 78 static int
101 widget_possible_dest_types (void) 79 widget_possible_dest_types (void)
102 { 80 {
103 return IMAGE_WIDGET_MASK; 81 return IMAGE_WIDGET_MASK;
104 } 82 }
105 83
106 static void 84 static void
107 check_valid_glyph_or_image (Lisp_Object data) 85 check_valid_glyph_or_instantiator (Lisp_Object data)
108 { 86 {
109 Lisp_Object glyph = data; 87 Lisp_Object glyph = data;
110 if (SYMBOLP (data)) 88 if (SYMBOLP (data))
111 glyph = XSYMBOL (data)->value; 89 glyph = XSYMBOL (data)->value;
112 90
113 if (IMAGE_INSTANCEP (glyph)) 91 if (IMAGE_INSTANCEP (glyph))
114 CHECK_IMAGE_INSTANCE (glyph); 92 CHECK_IMAGE_INSTANCE (glyph);
115 else if (!CONSP (glyph)) 93 else if (!CONSP (glyph) && !VECTORP (glyph))
116 CHECK_BUFFER_GLYPH (glyph); 94 CHECK_BUFFER_GLYPH (glyph);
95 }
96
97 static void
98 check_valid_orientation (Lisp_Object data)
99 {
100 if (!EQ (data, Qhorizontal)
101 &&
102 !EQ (data, Qvertical))
103 signal_simple_error ("unknown orientation for layout", data);
104 }
105
106 static void
107 check_valid_tab_orientation (Lisp_Object data)
108 {
109 if (!EQ (data, Qtop)
110 &&
111 !EQ (data, Qbottom)
112 &&
113 !EQ (data, Qleft)
114 &&
115 !EQ (data, Qright))
116 signal_simple_error ("unknown orientation for tab control", data);
117 }
118
119 static void
120 check_valid_justification (Lisp_Object data)
121 {
122 if (!EQ (data, Qleft) && !EQ (data, Qright) && !EQ (data, Qcenter))
123 signal_simple_error ("unknown justification for layout", data);
124 }
125
126 static void
127 check_valid_border (Lisp_Object data)
128 {
129 if (!EQ (data, Qt) && !EQ (data, Qetched_in) && !EQ (data, Qetched_out)
130 && !EQ (data, Qbevel_in) && !EQ (data, Qbevel_out)
131 && !GLYPHP (data) && !VECTORP (data))
132 signal_simple_error ("unknown border style for layout", data);
117 } 133 }
118 134
119 static void 135 static void
120 check_valid_anything (Lisp_Object data) 136 check_valid_anything (Lisp_Object data)
121 { 137 {
143 { 159 {
144 if (!STRINGP (data) && !VECTORP (data)) 160 if (!STRINGP (data) && !VECTORP (data))
145 signal_simple_error (":descriptor must be a string or a vector", data); 161 signal_simple_error (":descriptor must be a string or a vector", data);
146 } 162 }
147 163
148 static void 164 void
149 check_valid_item_list (Lisp_Object data) 165 check_valid_item_list_1 (Lisp_Object items)
150 { 166 {
151 Lisp_Object rest; 167 Lisp_Object rest;
152 Lisp_Object items;
153 Fcheck_valid_plist (data);
154
155 items = Fplist_get (data, Q_items, Qnil);
156 168
157 CHECK_LIST (items); 169 CHECK_LIST (items);
158 EXTERNAL_LIST_LOOP (rest, items) 170 EXTERNAL_LIST_LOOP (rest, items)
159 { 171 {
160 CHECK_STRING (XCAR (rest)); 172 if (STRINGP (XCAR (rest)))
161 } 173 CHECK_STRING (XCAR (rest));
162 } 174 else if (VECTORP (XCAR (rest)))
163 175 gui_parse_item_keywords (XCAR (rest));
164 /* wire widget property invocations to specific widgets ... The 176 else if (LISTP (XCAR (rest)))
165 problem we are solving here is that when instantiators get converted 177 check_valid_item_list_1 (XCAR (rest));
166 to instances they lose some type information (they just become 178 else
167 subwindows or widgets for example). For widgets we need to preserve 179 signal_simple_error ("Items must be vectors, lists or strings", items);
168 this type information so that we can do widget specific operations on 180 }
169 the instances. This is encoded in the widget type 181 }
170 field. widget_property gets invoked by decoding the primary type 182
171 (Qwidget), widget property then invokes based on the secondary type 183 static void
172 (Qedit for example). It is debatable that we should wire things in this 184 check_valid_item_list (Lisp_Object data)
173 generalised way rather than treating widgets specially in 185 {
174 image_instance_property. */ 186 Lisp_Object items;
187
188 Fcheck_valid_plist (data);
189 items = Fplist_get (data, Q_items, Qnil);
190
191 check_valid_item_list_1 (items);
192 }
193
194 static void
195 check_valid_glyph_or_instantiator_list (Lisp_Object data)
196 {
197 Lisp_Object rest;
198
199 CHECK_LIST (data);
200 EXTERNAL_LIST_LOOP (rest, data)
201 {
202 check_valid_glyph_or_instantiator (XCAR (rest));
203 }
204 }
205
206 static Lisp_Object
207 glyph_instantiator_to_glyph (Lisp_Object sym)
208 {
209 /* This function calls lisp. */
210 Lisp_Object glyph = sym;
211 struct gcpro gcpro1;
212
213 GCPRO1 (glyph);
214 /* if we have a symbol get at the actual data */
215 if (SYMBOLP (glyph))
216 glyph = XSYMBOL (glyph)->value;
217
218 if (CONSP (glyph))
219 glyph = Feval (glyph);
220
221 /* Be really helpful to the user. */
222 if (VECTORP (glyph))
223 {
224 glyph = call1 (intern ("make-glyph"), glyph);
225 }
226
227 /* substitute the new glyph */
228 RETURN_UNGCPRO (glyph);
229 }
230
231 static void
232 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
233 {
234 int i;
235 /* substitute the new glyph */
236 for (i = 0; i < XVECTOR_LENGTH (inst); i++)
237 {
238 if (EQ (key, XVECTOR_DATA (inst)[i]))
239 {
240 XVECTOR_DATA (inst)[i+1] = val;
241 break;
242 }
243 }
244 }
245
246 /* Wire widget property invocations to specific widgets. The problem
247 we are solving here is that when instantiators get converted to
248 instances they lose some type information (they just become
249 subwindows or widgets for example). For widgets we need to preserve
250 this type information so that we can do widget specific operations
251 on the instances. This is encoded in the widget type
252 field. widget_property gets invoked by decoding the primary type
253 (Qwidget), <widget>_property then invokes based on the secondary
254 type (Qedit_field for example). It is debatable whether we should
255 wire things in this generalised way rather than treating widgets
256 specially in image_instance_property. */
175 static Lisp_Object 257 static Lisp_Object
176 widget_property (Lisp_Object image_instance, Lisp_Object prop) 258 widget_property (Lisp_Object image_instance, Lisp_Object prop)
177 { 259 {
178 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); 260 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
179 struct image_instantiator_methods* meths; 261 struct image_instantiator_methods* meths;
180 262
181 /* first see if its a general property ... */ 263 /* first see if its a general property ... */
182 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop))) 264 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
183 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil); 265 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
198 } 280 }
199 281
200 static Lisp_Object 282 static Lisp_Object
201 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val) 283 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val)
202 { 284 {
203 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); 285 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
204 struct image_instantiator_methods* meths; 286 struct image_instantiator_methods* meths;
205 Lisp_Object ret; 287 Lisp_Object ret;
206 288
207 /* try device specific methods first ... */ 289 /* PIck up any generic properties that we might need to keep hold
290 of. */
291 if (EQ (prop, Q_text))
292 {
293 IMAGE_INSTANCE_WIDGET_TEXT (ii) = val;
294 IMAGE_INSTANCE_TEXT_CHANGED (ii) = 1;
295 }
296
297 /* Now try device specific methods first ... */
208 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii), 298 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
209 IMAGE_INSTANCE_WIDGET_TYPE (ii), 299 IMAGE_INSTANCE_WIDGET_TYPE (ii),
210 ERROR_ME_NOT); 300 ERROR_ME_NOT);
211 if (meths && HAS_IIFORMAT_METH_P (meths, set_property) 301 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
212 && 302 &&
229 IMAGE_INSTANCE_WIDGET_PROPS (ii) 319 IMAGE_INSTANCE_WIDGET_PROPS (ii)
230 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val); 320 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
231 return val; 321 return val;
232 } 322 }
233 323
324 /* Like the rest of redisplay, we want widget updates to occur
325 asynchronously. Thus toolkit specific methods for setting properties
326 must be called by redisplay instead of by *_set_property. Thus
327 *_set_property records the change and this function actually
328 implements it. We want to be slightly clever about this however by
329 supplying format specific functions for the updates instead of lumping
330 them all into this function. Note that there is no need for format
331 generic functions. */
332 void
333 update_widget (Lisp_Object widget)
334 {
335 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (widget);
336 struct image_instantiator_methods* meths;
337
338 if (!IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET)
339 return;
340
341 /* Device generic methods. We must update the widget's size as it
342 may have been changed by the the layout routines. We also do this
343 here so that explicit resizing from lisp does not result in
344 synchronous updates. */
345 MAYBE_DEVMETH (XDEVICE (ii->device), update_widget, (ii));
346
347 /* Device-format specific methods */
348 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
349 IMAGE_INSTANCE_WIDGET_TYPE (ii),
350 ERROR_ME_NOT);
351 MAYBE_IIFORMAT_METH (meths, update, (widget));
352 }
353
354 /* Query for a widgets desired geometry. If no type specific method is
355 provided then use the widget text to calculate sizes. */
356 static void
357 widget_query_geometry (Lisp_Object image_instance,
358 unsigned int* width, unsigned int* height,
359 enum image_instance_geometry disp, Lisp_Object domain)
360 {
361 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
362 struct image_instantiator_methods* meths;
363
364 /* First just set up what we already have. */
365 if (width) *width = IMAGE_INSTANCE_WIDTH (ii);
366 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii);
367
368 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
369 ||
370 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
371 {
372 /* .. then try device specific methods ... */
373 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
374 IMAGE_INSTANCE_WIDGET_TYPE (ii),
375 ERROR_ME_NOT);
376 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
377 IIFORMAT_METH (meths, query_geometry, (image_instance,
378 width, height, disp,
379 domain));
380 else
381 {
382 /* ... then format specific methods ... */
383 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
384 ERROR_ME_NOT);
385 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
386 IIFORMAT_METH (meths, query_geometry, (image_instance,
387 width, height, disp,
388 domain));
389 else
390 {
391 unsigned int w, h;
392
393 /* Then if we are allowed to resize the widget, make the
394 size the same as the text dimensions. */
395 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
396 IMAGE_INSTANCE_WIDGET_FACE (ii),
397 &w, &h, 0, domain);
398 /* Adjust the size for borders. */
399 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
400 *width = w + 2 * WIDGET_BORDER_WIDTH;
401 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
402 *height = h + 2 * WIDGET_BORDER_HEIGHT;
403 }
404 }
405 }
406 }
407
408 static void
409 widget_layout (Lisp_Object image_instance,
410 unsigned int width, unsigned int height, Lisp_Object domain)
411 {
412 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
413 struct image_instantiator_methods* meths;
414
415 /* .. then try device specific methods ... */
416 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
417 IMAGE_INSTANCE_WIDGET_TYPE (ii),
418 ERROR_ME_NOT);
419 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
420 IIFORMAT_METH (meths, layout, (image_instance,
421 width, height, domain));
422 else
423 {
424 /* ... then format specific methods ... */
425 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
426 ERROR_ME_NOT);
427 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
428 IIFORMAT_METH (meths, layout, (image_instance,
429 width, height, domain));
430 }
431 }
432
234 static void 433 static void
235 widget_validate (Lisp_Object instantiator) 434 widget_validate (Lisp_Object instantiator)
236 { 435 {
237 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); 436 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
238 struct gui_item gui; 437
239 if (NILP (desc)) 438 if (NILP (desc))
240 signal_simple_error ("Must supply :descriptor", instantiator); 439 signal_simple_error ("Must supply :descriptor", instantiator);
241 440
242 if (VECTORP (desc)) 441 if (VECTORP (desc))
243 gui_parse_item_keywords (desc, &gui); 442 gui_parse_item_keywords (desc);
244 443
245 if (!NILP (find_keyword_in_vector (instantiator, Q_width)) 444 if (!NILP (find_keyword_in_vector (instantiator, Q_width))
246 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width))) 445 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
247 signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator); 446 signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
248 447
249 if (!NILP (find_keyword_in_vector (instantiator, Q_height)) 448 if (!NILP (find_keyword_in_vector (instantiator, Q_height))
250 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height))) 449 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
251 signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator); 450 signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
252 } 451 }
253 452
254 static void 453 static void
255 combo_validate (Lisp_Object instantiator) 454 combo_box_validate (Lisp_Object instantiator)
256 { 455 {
257 widget_validate (instantiator); 456 widget_validate (instantiator);
258 if (NILP (find_keyword_in_vector (instantiator, Q_properties))) 457 if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
259 signal_simple_error ("Must supply item list", instantiator); 458 signal_simple_error ("Must supply item list", instantiator);
260 } 459 }
269 468
270 /* we need to eval glyph if its an expression, we do this for the 469 /* we need to eval glyph if its an expression, we do this for the
271 same reasons we normalize file to data. */ 470 same reasons we normalize file to data. */
272 if (!NILP (glyph)) 471 if (!NILP (glyph))
273 { 472 {
274 int i; 473 substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
275 struct gcpro gcpro1; 474 }
276 if (SYMBOLP (glyph)) 475
277 glyph = XSYMBOL (glyph)->value;
278 GCPRO1 (glyph);
279
280 if (CONSP (glyph))
281 glyph = Feval (glyph);
282 /* substitute the new glyph */
283 for (i = 0; i < XVECTOR_LENGTH (inst); i++)
284 {
285 if (EQ (Q_image, XVECTOR_DATA (inst)[i]))
286 {
287 XVECTOR_DATA (inst)[i+1] = glyph;
288 break;
289 }
290 }
291 UNGCPRO;
292 }
293 return inst; 476 return inst;
294 } 477 }
295 478
296 static void 479 static void
297 initialize_widget_image_instance (struct Lisp_Image_Instance *ii, Lisp_Object type) 480 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type)
298 { 481 {
299 /* initialize_subwindow_image_instance (ii);*/ 482 /* initialize_subwindow_image_instance (ii);*/
300 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type; 483 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
301 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil; 484 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
302 IMAGE_INSTANCE_WIDGET_FACE (ii) = Vwidget_face; 485 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil);
303 gui_item_init (&IMAGE_INSTANCE_WIDGET_ITEM (ii)); 486 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item ();
487 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 1;
488 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 1;
489 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 0;
490 IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) = 0;
304 } 491 }
305 492
306 /* Instantiate a button widget. Unfortunately instantiated widgets are 493 /* Instantiate a button widget. Unfortunately instantiated widgets are
307 particular to a frame since they need to have a parent. It's not 494 particular to a frame since they need to have a parent. It's not
308 like images where you just select the image into the context you 495 like images where you just select the image into the context you
309 want to display it in and BitBlt it. So images instances can have a 496 want to display it in and BitBlt it. So image instances can have a
310 many-to-one relationship with things you see, whereas widgets can 497 many-to-one relationship with things you see, whereas widgets can
311 only be one-to-one (i.e. per frame) */ 498 only be one-to-one (i.e. per frame) */
312 static void 499 void
313 widget_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator, 500 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
314 Lisp_Object pointer_fg, Lisp_Object pointer_bg, 501 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
315 int dest_mask, Lisp_Object domain, int default_textheight, 502 int dest_mask, Lisp_Object domain)
316 int default_pixheight) 503 {
317 { 504 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
318 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
319 struct gui_item* pgui = &IMAGE_INSTANCE_WIDGET_ITEM (ii);
320 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face); 505 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
321 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height); 506 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
322 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width); 507 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
323 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width); 508 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
324 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height); 509 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
325 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); 510 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
326 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image); 511 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
512 Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties);
513 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
514 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
327 int pw=0, ph=0, tw=0, th=0; 515 int pw=0, ph=0, tw=0, th=0;
328 516
329 /* this just does pixel type sizing */ 517 /* this just does pixel type sizing */
330 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg, 518 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
331 dest_mask, domain); 519 dest_mask, domain);
332 520
333 if (!(dest_mask & IMAGE_WIDGET_MASK)) 521 if (!(dest_mask & (IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK)))
334 incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK); 522 incompatible_image_types (instantiator, dest_mask,
523 IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK);
335 524
336 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]); 525 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
526
527 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
528 IMAGE_INSTANCE_WIDGET_PROPS (ii) = props;
337 529
338 /* retrieve the fg and bg colors */ 530 /* retrieve the fg and bg colors */
339 if (!NILP (face)) 531 if (!NILP (face))
340 IMAGE_INSTANCE_WIDGET_FACE (ii) = Fget_face (face); 532 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
341 533
342 /* data items for some widgets */ 534 /* Do layout specific initialisation. This feels a bit tacky, but
343 IMAGE_INSTANCE_WIDGET_PROPS (ii) = 535 the alternative is a myriad of different little functions. */
344 find_keyword_in_vector (instantiator, Q_properties); 536 if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
345 537 {
538 Lisp_Object rest, children = Qnil;
539 Lisp_Object border = find_keyword_in_vector (instantiator, Q_border);
540
541 if (NILP (orient))
542 {
543 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
544 }
545 IMAGE_INSTANCE_TYPE (ii) = IMAGE_LAYOUT;
546
547 if (EQ (border, Qt))
548 {
549 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in;
550 }
551 else if (GLYPHP (border))
552 {
553 /* We are going to be sneaky here and add the border text as
554 just another child, the layout and output routines don't know
555 this and will just display at the offsets we prescribe. */
556 Lisp_Object gii = glyph_image_instance (border, domain, ERROR_ME, 1);
557 /* make sure we are designated as the parent. */
558 XIMAGE_INSTANCE_PARENT (gii) = image_instance;
559 children = Fcons (gii, children);
560 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (0);
561 }
562 else
563 {
564 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border;
565 }
566
567 /* Pick up the sub-widgets. */
568 LIST_LOOP (rest, items)
569 {
570 /* make sure the image is instantiated */
571 Lisp_Object gii = glyph_image_instance (XCAR (rest), domain, ERROR_ME, 1);
572 /* make sure we are designated as the parent. */
573 XIMAGE_INSTANCE_PARENT (gii) = image_instance;
574 children = Fcons (gii, children);
575 /* Make sure elements in the layout are in the order the
576 user expected. */
577 children = Fnreverse (children);
578 }
579 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children;
580 }
346 /* retrieve the gui item information. This is easy if we have been 581 /* retrieve the gui item information. This is easy if we have been
347 provided with a vector, more difficult if we have just been given 582 provided with a vector, more difficult if we have just been given
348 keywords */ 583 keywords */
349 if (STRINGP (desc) || NILP (desc)) 584 else if (STRINGP (desc) || NILP (desc))
350 { 585 {
351 /* big cheat - we rely on the fact that a gui item looks like an instantiator */ 586 /* big cheat - we rely on the fact that a gui item looks like an instantiator */
352 gui_parse_item_keywords_no_errors (instantiator, pgui); 587 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
588 gui_parse_item_keywords_no_errors (instantiator);
353 IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc; 589 IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
354 } 590 }
355 else 591 else
356 gui_parse_item_keywords_no_errors (desc, pgui); 592 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
357 593 gui_parse_item_keywords_no_errors (desc);
358 /* normalize size information */ 594
359 if (!NILP (width)) 595 /* Pick up the orientation before we do our first layout. */
360 tw = XINT (width); 596 if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical))
361 if (!NILP (height)) 597 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 1;
362 th = XINT (height); 598
363 if (!NILP (pixwidth)) 599 /* parse more gui items out of the properties */
364 pw = XINT (pixwidth); 600 if (!NILP (props)
601 && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
602 {
603 if (NILP (items))
604 {
605 items = Fplist_get (props, Q_items, Qnil);
606 }
607 if (!NILP (items))
608 {
609 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
610 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
611 parse_gui_item_tree_children (items));
612 }
613 }
614
615 /* Normalize size information. We now only assign sizes if the user
616 gives us some explicitly, or there are some constraints that we
617 can't change later on. Otherwise we postpone sizing until query
618 geometry gets called. */
619 if (!NILP (pixwidth)) /* pixwidth takes precendent */
620 {
621 pw = XINT (pixwidth);
622 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
623 }
624 else if (!NILP (width))
625 {
626 tw = XINT (width);
627 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
628 }
629
365 if (!NILP (pixheight)) 630 if (!NILP (pixheight))
366 ph = XINT (pixheight); 631 {
632 ph = XINT (pixheight);
633 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
634 }
635 else if (!NILP (height) && XINT (height) > 1)
636 {
637 th = XINT (height);
638 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
639 }
640
641 /* Taking the default face information when the user has specified
642 size in characters is probably as good as any since the widget
643 face is more likely to be proportional and thus give inadequate
644 results. Using character sizes can only ever be approximate
645 anyway. */
646 if (tw || th)
647 {
648 int charwidth, charheight;
649 default_face_font_info (domain, 0, 0, &charheight, &charwidth, 0);
650 if (tw)
651 pw = charwidth * tw;
652 if (th)
653 ph = charheight * th;
654 }
367 655
368 /* for a widget with an image pick up the dimensions from that */ 656 /* for a widget with an image pick up the dimensions from that */
369 if (!NILP (glyph)) 657 if (!NILP (glyph))
370 { 658 {
371 if (!pw && !tw) 659 if (!pw)
372 pw = glyph_width (glyph, Qnil, DEFAULT_INDEX, domain) 660 pw = glyph_width (glyph, domain) + 2 * WIDGET_BORDER_WIDTH;
373 + 2 * WIDGET_BORDER_WIDTH; 661 if (!ph)
374 if (!ph && !th) 662 ph = glyph_height (glyph, domain) + 2 * WIDGET_BORDER_HEIGHT;
375 ph = glyph_height (glyph, Qnil, DEFAULT_INDEX, domain) 663 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
376 + 2 * WIDGET_BORDER_HEIGHT; 664 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
377 } 665 }
378 666
379 /* if we still don' t have sizes, guess from text size */ 667 /* When we create the widgets the window system expects a valid
380 if (!tw && !pw && !NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii))) 668 size, so If we still don' t have sizes, call layout to pick them
381 tw = XSTRING_LENGTH (IMAGE_INSTANCE_WIDGET_TEXT (ii)); 669 up. If query_geometry or layout relies on the widget being in
382 if (!th && !ph) 670 existence then we are in catch 22. */
383 { 671 image_instance_layout (image_instance,
384 if (default_textheight) 672 pw ? pw : IMAGE_UNSPECIFIED_GEOMETRY,
385 th = default_textheight; 673 ph ? ph : IMAGE_UNSPECIFIED_GEOMETRY,
386 else if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii))) 674 domain);
387 th = 1; 675
676 #ifdef DEBUG_WIDGETS
677 debug_widget_instances++;
678 stderr_out ("instantiated ");
679 debug_print (instantiator);
680 stderr_out ("%d widgets instantiated\n", debug_widget_instances);
681 #endif
682 }
683
684 /* tree-view geometry - get the height right */
685 static void
686 tree_view_query_geometry (Lisp_Object image_instance,
687 unsigned int* width, unsigned int* height,
688 enum image_instance_geometry disp, Lisp_Object domain)
689 {
690 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
691 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
692
693
694 if (*width)
695 {
696 /* #### what should this be. reconsider when X has tree views. */
697 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
698 IMAGE_INSTANCE_WIDGET_FACE (ii),
699 width, 0, 0, domain);
700 }
701 if (*height)
702 {
703 int len, h;
704 default_face_font_info (domain, 0, 0, &h, 0, 0);
705 GET_LIST_LENGTH (items, len);
706 *height = len * h;
707 }
708 }
709
710 /* Get the geometry of a tab control. This is based on the number of
711 items and text therin in the tab control. */
712 static void
713 tab_control_query_geometry (Lisp_Object image_instance,
714 unsigned int* width, unsigned int* height,
715 enum image_instance_geometry disp, Lisp_Object domain)
716 {
717 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
718 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
719 Lisp_Object rest;
720 unsigned int tw = 0, th = 0;
721
722 LIST_LOOP (rest, items)
723 {
724 unsigned int h, w;
725
726 query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
727 IMAGE_INSTANCE_WIDGET_FACE (ii),
728 &w, &h, 0, domain);
729 tw += 2 * WIDGET_BORDER_WIDTH; /* some bias */
730 tw += w;
731 th = max (th, h + 2 * WIDGET_BORDER_HEIGHT);
732 }
733
734 /* Fixup returned values depending on orientation. */
735 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
736 {
737 if (height) *height = tw;
738 if (width) *width = th;
739 }
740 else
741 {
742 if (height) *height = th;
743 if (width) *width = tw;
744 }
745 }
746
747 /* Get the geometry of a tab control. This is based on the number of
748 items and text therin in the tab control. */
749 static Lisp_Object
750 tab_control_set_property (Lisp_Object image_instance,
751 Lisp_Object prop,
752 Lisp_Object val)
753 {
754 /* Record new items for update. *_tab_control_update will do the
755 rest. */
756 if (EQ (prop, Q_items))
757 {
758 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
759 check_valid_item_list_1 (val);
760
761 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
762 Fcons (XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)),
763 parse_gui_item_tree_children (val));
764
765 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1;
766
767 return Qt;
768 }
769 return Qunbound;
770 }
771
772 /* set the properties of a progres guage */
773 static Lisp_Object
774 progress_gauge_set_property (Lisp_Object image_instance,
775 Lisp_Object prop,
776 Lisp_Object val)
777 {
778 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
779
780 if (EQ (prop, Q_percent))
781 {
782 CHECK_INT (val);
783 IMAGE_INSTANCE_WIDGET_PROPS (ii)
784 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
785 IMAGE_INSTANCE_WIDGET_PERCENT_CHANGED (ii) = 1;
786
787 return Qt;
788 }
789 return Qunbound;
790 }
791
792
793 /*****************************************************************************
794 * widget layout *
795 *****************************************************************************/
796 static int
797 layout_possible_dest_types (void)
798 {
799 return IMAGE_LAYOUT_MASK;
800 }
801
802 /* we need to convert things like glyphs to images, eval expressions
803 etc.*/
804 static Lisp_Object
805 layout_normalize (Lisp_Object inst, Lisp_Object console_type)
806 {
807 /* This function can call lisp */
808 Lisp_Object items = find_keyword_in_vector (inst, Q_items);
809 Lisp_Object border = find_keyword_in_vector (inst, Q_border);
810 /* we need to eval glyph if its an expression, we do this for the
811 same reasons we normalize file to data. */
812 if (!NILP (items))
813 {
814 Lisp_Object rest;
815 LIST_LOOP (rest, items)
816 {
817 /* substitute the new glyph */
818 Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest)));
819 }
820 }
821 /* normalize the border spec. */
822 if (VECTORP (border) || CONSP (border))
823 {
824 substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border));
825 }
826 return inst;
827 }
828
829 /* Layout widget. Sizing commentary: we have a number of problems that
830 we would like to address. Some consider some of these more
831 important than others. It used to be that size information was
832 determined at instantiation time and was then fixed forever
833 after. Generally this is not what we want. Users want size to be
834 "big enough" to accommodate whatever they are trying to show and
835 this is dependent on text length, lines, font metrics etc. Of
836 course these attributes can change dynamically and so the size
837 should changed dynamically also. Only in a few limited cases should
838 the size be fixed and remain fixed. Of course this actually means
839 that we don't really want to specifiy the size *at all* for most
840 widgets - we want it to be discovered dynamically. Thus we can
841 envisage the following scenarios:
842
843 1. A button is sized to accommodate its text, the text changes and the
844 button should change size also.
845
846 2. A button is given an explicit size. Its size should never change.
847
848 3. Layout is put inside an area. The size of the area changes, the
849 layout should change with it.
850
851 4. A button grows to accommodate additional text. The whitespace
852 around it should be modified to cope with the new layout
853 requirements.
854
855 5. A button grows. The area surrounding it should grow also if
856 possible.
857
858 What metrics are important?
859 1. Actual width and height.
860
861 2. Whether the width and height are what the widget actually wants, or
862 whether it can grow or shrink.
863
864 Text glyphs are particularly troublesome since their metrics depend
865 on the context in which they are being viewed. For instance they
866 can appear differently depending on the window face, frame face or
867 glyph face. In order to simplify this text glyphs can now only have
868 a glyph-face or image-instance face. All other glyphs are
869 essentially fixed in appearance. Perhaps the problem is that text
870 glyphs are cached on a device basis like most other glyphs. Instead
871 they should be cached per-window and then the instance would be
872 fixed and we wouldn't have to mess around with font metrics and the
873 rest. */
874
875 /* Query the geometry of a layout widget. We assume that we can only
876 get here if the size is not already fixed. */
877 static void
878 layout_query_geometry (Lisp_Object image_instance, unsigned int* width,
879 unsigned int* height, enum image_instance_geometry disp,
880 Lisp_Object domain)
881 {
882 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
883 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii), rest;
884 int maxph = 0, maxpw = 0, nitems = 0, ph_adjust = 0;
885
886 /* Flip through the items to work out how much stuff we have to display */
887 LIST_LOOP (rest, items)
888 {
889 Lisp_Object glyph = XCAR (rest);
890 unsigned int gheight, gwidth;
891
892 image_instance_query_geometry (glyph, &gwidth, &gheight, disp, domain);
893
894 /* Pick up the border text if we have one. */
895 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
896 && NILP (XCDR (rest)))
897 {
898 ph_adjust = gheight / 2;
899 }
388 else 900 else
389 ph = default_pixheight; 901 {
390 } 902
391 903 nitems ++;
392 if (tw !=0 || th !=0) 904 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
393 widget_text_to_pixel_conversion (domain, 905 == LAYOUT_HORIZONTAL)
394 IMAGE_INSTANCE_WIDGET_FACE (ii), 906 {
395 th, tw, th ? &ph : 0, tw ? &pw : 0); 907 maxph = max (maxph, gheight);
396 908 maxpw += gwidth;
397 IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = pw; 909 }
398 IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = ph; 910 else
399 } 911 {
400 912 maxpw = max (maxpw, gwidth);
401 static void 913 maxph += gheight;
402 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, 914 }
403 Lisp_Object pointer_fg, Lisp_Object pointer_bg, 915 }
404 int dest_mask, Lisp_Object domain) 916 }
405 { 917
406 widget_instantiate_1 (image_instance, instantiator, pointer_fg, 918 /* work out spacing between items and bounds of the layout. No user
407 pointer_bg, dest_mask, domain, 1, 0); 919 provided width so we just do default spacing. */
408 } 920 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
409 921 == LAYOUT_HORIZONTAL)
410 static void 922 *width = maxpw + (nitems + 1) * WIDGET_BORDER_WIDTH * 2;
411 combo_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, 923 else
412 Lisp_Object pointer_fg, Lisp_Object pointer_bg, 924 *width = maxpw + 2 * WIDGET_BORDER_WIDTH * 2;
413 int dest_mask, Lisp_Object domain) 925
414 { 926 /* Work out vertical spacings. */
415 Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties), 927 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
416 Q_items, Qnil); 928 == LAYOUT_VERTICAL)
417 int len; 929 *height = maxph + (nitems + 1) * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
418 GET_LIST_LENGTH (data, len); 930 else
419 widget_instantiate_1 (image_instance, instantiator, pointer_fg, 931 *height = maxph + 2 * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
420 pointer_bg, dest_mask, domain, len + 1, 0); 932 }
421 } 933
422 934
423 /* Instantiate a static control */ 935 static void
424 static void 936 layout_layout (Lisp_Object image_instance,
425 static_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, 937 unsigned int width, unsigned int height, Lisp_Object domain)
426 Lisp_Object pointer_fg, Lisp_Object pointer_bg, 938 {
427 int dest_mask, Lisp_Object domain) 939 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
428 { 940 Lisp_Object rest;
429 widget_instantiate_1 (image_instance, instantiator, pointer_fg, 941 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
430 pointer_bg, dest_mask, domain, 0, 4); 942 int x, y, maxph = 0, maxpw = 0, nitems = 0,
943 horiz_spacing, vert_spacing, ph_adjust = 0;
944 unsigned int gheight, gwidth;
945
946 /* flip through the items to work out how much stuff we have to display */
947 LIST_LOOP (rest, items)
948 {
949 Lisp_Object glyph = XCAR (rest);
950
951 image_instance_query_geometry (glyph, &gwidth, &gheight,
952 IMAGE_DESIRED_GEOMETRY, domain);
953
954 /* Pick up the border text if we have one. */
955 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
956 && NILP (XCDR (rest)))
957 {
958 XIMAGE_INSTANCE_XOFFSET (glyph) = 10; /* Really, what should this be? */
959 XIMAGE_INSTANCE_YOFFSET (glyph) = 0;
960 ph_adjust = gheight / 2;
961 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (ph_adjust);
962 }
963 else
964 {
965 nitems ++;
966 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
967 == LAYOUT_HORIZONTAL)
968 {
969 maxph = max (maxph, gheight);
970 maxpw += gwidth;
971 }
972 else
973 {
974 maxpw = max (maxpw, gwidth);
975 maxph += gheight;
976 }
977 }
978 }
979
980 /* work out spacing between items and bounds of the layout */
981 if (width < maxpw)
982 /* The user wants a smaller space than the largest item, so we
983 just provide default spacing and will let the output routines
984 clip.. */
985 horiz_spacing = WIDGET_BORDER_WIDTH * 2;
986 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
987 == LAYOUT_HORIZONTAL)
988 /* We have a larger area to display in so distribute the space
989 evenly. */
990 horiz_spacing = (width - maxpw) / (nitems + 1);
991 else
992 horiz_spacing = (width - maxpw) / 2;
993
994 if (height < maxph)
995 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
996 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
997 == LAYOUT_VERTICAL)
998 vert_spacing = (height - (maxph + ph_adjust)) / (nitems + 1);
999 else
1000 vert_spacing = (height - (maxph + ph_adjust)) / 2;
1001
1002 y = vert_spacing + ph_adjust;
1003 x = horiz_spacing;
1004
1005 /* Now flip through putting items where we want them, paying
1006 attention to justification. Make sure we don't mess with the
1007 border glyph. */
1008 LIST_LOOP (rest, items)
1009 {
1010 Lisp_Object glyph = XCAR (rest);
1011
1012 image_instance_query_geometry (glyph, &gwidth, &gheight,
1013 IMAGE_DESIRED_GEOMETRY, domain);
1014
1015 if (!INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
1016 || !NILP (XCDR (rest)))
1017 {
1018 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1019 == LAYOUT_HORIZONTAL)
1020 {
1021 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1022 == LAYOUT_JUSTIFY_RIGHT)
1023 y = height - (gheight + vert_spacing);
1024 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1025 == LAYOUT_JUSTIFY_CENTER)
1026 y = (height - gheight) / 2;
1027 }
1028 else
1029 {
1030 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1031 == LAYOUT_JUSTIFY_RIGHT)
1032 x = width - (gwidth + horiz_spacing);
1033 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1034 == LAYOUT_JUSTIFY_CENTER)
1035 x = (width - gwidth) / 2;
1036 }
1037
1038 XIMAGE_INSTANCE_XOFFSET (glyph) = x;
1039 XIMAGE_INSTANCE_YOFFSET (glyph) = y;
1040
1041 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1042 == LAYOUT_HORIZONTAL)
1043 {
1044 x += (gwidth + horiz_spacing);
1045 }
1046 else
1047 {
1048 y += (gheight + vert_spacing);
1049 }
1050 }
1051
1052 /* Now layout subwidgets if they require it. */
1053 image_instance_layout (glyph, gwidth, gheight, domain);
1054 }
431 } 1055 }
432 1056
433 1057
434 /************************************************************************/ 1058 /************************************************************************/
435 /* initialization */ 1059 /* initialization */
443 defkeyword (&Q_width, ":width"); 1067 defkeyword (&Q_width, ":width");
444 defkeyword (&Q_properties, ":properties"); 1068 defkeyword (&Q_properties, ":properties");
445 defkeyword (&Q_items, ":items"); 1069 defkeyword (&Q_items, ":items");
446 defkeyword (&Q_image, ":image"); 1070 defkeyword (&Q_image, ":image");
447 defkeyword (&Q_percent, ":percent"); 1071 defkeyword (&Q_percent, ":percent");
448 defkeyword (&Q_text, "text"); 1072 defkeyword (&Q_text, ":text");
449 } 1073 defkeyword (&Q_orientation, ":orientation");
450 1074 defkeyword (&Q_justify, ":justify");
451 void 1075 defkeyword (&Q_border, ":border");
452 image_instantiator_format_create_glyphs_widget (void) 1076
453 { 1077 defsymbol (&Qetched_in, "etched-in");
454 #define VALID_GUI_KEYWORDS(type) \ 1078 defsymbol (&Qetched_out, "etched-out");
455 IIFORMAT_VALID_KEYWORD (type, Q_active, check_valid_anything); \ 1079 defsymbol (&Qbevel_in, "bevel-in");
456 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \ 1080 defsymbol (&Qbevel_out, "bevel-out");
457 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \ 1081 }
458 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \ 1082
459 IIFORMAT_VALID_KEYWORD (type, Q_selected, check_valid_anything); \ 1083 #define VALID_GUI_KEYWORDS(type) do { \
460 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \ 1084 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything); \
461 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \ 1085 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \
462 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \ 1086 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \
463 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \ 1087 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \
464 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \ 1088 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything); \
465 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \ 1089 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \
466 IIFORMAT_VALID_KEYWORD (type, Q_callback, check_valid_callback); \ 1090 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \
467 IIFORMAT_VALID_KEYWORD (type, Q_descriptor, check_valid_string_or_vector) 1091 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \
468 1092 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \
469 #define VALID_WIDGET_KEYWORDS(type) \ 1093 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \
1094 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \
1095 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback); \
1096 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor, check_valid_string_or_vector); \
1097 } while (0)
1098
1099 #define VALID_WIDGET_KEYWORDS(type) do { \
470 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \ 1100 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \
471 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \ 1101 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \
472 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int); \ 1102 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int); \
473 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int); \ 1103 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int); \
474 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face) 1104 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face); \
475 1105 } while (0)
476 /* we only do this for properties */ 1106
1107
1108 static void image_instantiator_widget (void)
1109 { /* we only do this for properties */
477 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget"); 1110 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
478 IIFORMAT_HAS_METHOD (widget, property); 1111 IIFORMAT_HAS_METHOD (widget, property);
479 IIFORMAT_HAS_METHOD (widget, set_property); 1112 IIFORMAT_HAS_METHOD (widget, set_property);
480 1113 IIFORMAT_HAS_METHOD (widget, query_geometry);
481 /* widget image-instantiator types - buttons */ 1114 IIFORMAT_HAS_METHOD (widget, layout);
1115 }
1116
1117 static void image_instantiator_buttons (void)
1118 {
482 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button"); 1119 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
483 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget); 1120 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
484 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget); 1121 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
485 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget); 1122 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
486 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget); 1123 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
487 IIFORMAT_VALID_KEYWORD (button, Q_image, check_valid_glyph_or_image); 1124 IIFORMAT_VALID_KEYWORD (button,
1125 Q_image, check_valid_glyph_or_instantiator);
488 VALID_WIDGET_KEYWORDS (button); 1126 VALID_WIDGET_KEYWORDS (button);
489 VALID_GUI_KEYWORDS (button); 1127 VALID_GUI_KEYWORDS (button);
490 1128 }
491 /* edit fields */ 1129
492 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit, "edit"); 1130 static void image_instantiator_edit_fields (void)
493 IIFORMAT_HAS_SHARED_METHOD (edit, validate, widget); 1131 {
494 IIFORMAT_HAS_SHARED_METHOD (edit, possible_dest_types, widget); 1132 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
495 IIFORMAT_HAS_SHARED_METHOD (edit, instantiate, widget); 1133 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
496 VALID_WIDGET_KEYWORDS (edit); 1134 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
497 VALID_GUI_KEYWORDS (edit); 1135 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
498 1136 VALID_WIDGET_KEYWORDS (edit_field);
499 /* combo box */ 1137 VALID_GUI_KEYWORDS (edit_field);
500 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo, "combo"); 1138 }
501 IIFORMAT_HAS_METHOD (combo, validate); 1139
502 IIFORMAT_HAS_SHARED_METHOD (combo, possible_dest_types, widget); 1140 static void image_instantiator_combo_box (void)
503 IIFORMAT_HAS_METHOD (combo, instantiate); 1141 {
504 VALID_GUI_KEYWORDS (combo); 1142 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
505 1143 IIFORMAT_HAS_METHOD (combo_box, validate);
506 IIFORMAT_VALID_KEYWORD (combo, Q_width, check_valid_int); 1144 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
507 IIFORMAT_VALID_KEYWORD (combo, Q_height, check_valid_int); 1145 VALID_GUI_KEYWORDS (combo_box);
508 IIFORMAT_VALID_KEYWORD (combo, Q_pixel_width, check_valid_int); 1146
509 IIFORMAT_VALID_KEYWORD (combo, Q_face, check_valid_face); 1147 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
510 IIFORMAT_VALID_KEYWORD (combo, Q_properties, check_valid_item_list); 1148 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
511 1149 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int);
512 /* scrollbar */ 1150 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
1151 IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list);
1152 }
1153
1154 static void image_instantiator_scrollbar (void)
1155 {
513 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar"); 1156 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
514 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget); 1157 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
515 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget); 1158 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
516 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget); 1159 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
517 VALID_GUI_KEYWORDS (scrollbar); 1160 VALID_GUI_KEYWORDS (scrollbar);
518 1161
519 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int); 1162 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int);
520 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int); 1163 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int);
521 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face); 1164 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
522 1165 }
523 /* progress guage */ 1166
524 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress, "progress"); 1167 static void image_instantiator_progress_guage (void)
525 IIFORMAT_HAS_SHARED_METHOD (progress, validate, widget); 1168 {
526 IIFORMAT_HAS_SHARED_METHOD (progress, possible_dest_types, widget); 1169 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
527 IIFORMAT_HAS_SHARED_METHOD (progress, instantiate, widget); 1170 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
528 VALID_WIDGET_KEYWORDS (progress); 1171 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
529 VALID_GUI_KEYWORDS (progress); 1172 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
530 1173 IIFORMAT_HAS_METHOD (progress_gauge, set_property);
531 /* labels */ 1174 VALID_WIDGET_KEYWORDS (progress_gauge);
1175 VALID_GUI_KEYWORDS (progress_gauge);
1176 }
1177
1178 static void image_instantiator_tree_view (void)
1179 {
1180 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
1181 IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
1182 IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
1183 IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget);
1184 IIFORMAT_HAS_METHOD (tree_view, query_geometry);
1185 VALID_WIDGET_KEYWORDS (tree_view);
1186 VALID_GUI_KEYWORDS (tree_view);
1187 IIFORMAT_VALID_KEYWORD (tree_view, Q_properties, check_valid_item_list);
1188 }
1189
1190 static void image_instantiator_tab_control (void)
1191 {
1192 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
1193 IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
1194 IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
1195 IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget);
1196 IIFORMAT_HAS_METHOD (tab_control, query_geometry);
1197 IIFORMAT_HAS_METHOD (tab_control, set_property);
1198 VALID_WIDGET_KEYWORDS (tab_control);
1199 VALID_GUI_KEYWORDS (tab_control);
1200 IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation, check_valid_tab_orientation);
1201 IIFORMAT_VALID_KEYWORD (tab_control, Q_properties, check_valid_item_list);
1202 }
1203
1204 static void image_instantiator_labels (void)
1205 {
532 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label"); 1206 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
533 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget); 1207 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
534 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, static); 1208 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
535 VALID_WIDGET_KEYWORDS (label); 1209 VALID_WIDGET_KEYWORDS (label);
536 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string); 1210 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
537 1211 }
538 #if 0 1212
539 /* group */ 1213 static void image_instantiator_layout (void)
540 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (group, "group"); 1214 {
541 IIFORMAT_HAS_SHARED_METHOD (group, possible_dest_types, widget); 1215 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
542 IIFORMAT_HAS_METHOD (group, instantiate); 1216 IIFORMAT_HAS_METHOD (layout, possible_dest_types);
543 1217 IIFORMAT_HAS_SHARED_METHOD (layout, instantiate, widget);
544 IIFORMAT_VALID_KEYWORD (group, Q_width, check_valid_int); 1218 IIFORMAT_HAS_METHOD (layout, normalize);
545 IIFORMAT_VALID_KEYWORD (group, Q_height, check_valid_int); 1219 IIFORMAT_HAS_METHOD (layout, query_geometry);
546 IIFORMAT_VALID_KEYWORD (group, Q_pixel_width, check_valid_int); 1220 IIFORMAT_HAS_METHOD (layout, layout);
547 IIFORMAT_VALID_KEYWORD (group, Q_pixel_height, check_valid_int); 1221 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_width, check_valid_int);
548 IIFORMAT_VALID_KEYWORD (group, Q_face, check_valid_face); 1222 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_height, check_valid_int);
549 IIFORMAT_VALID_KEYWORD (group, Q_background, check_valid_string); 1223 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation);
550 IIFORMAT_VALID_KEYWORD (group, Q_descriptor, check_valid_string); 1224 IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification);
1225 IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border);
1226 IIFORMAT_VALID_KEYWORD (layout, Q_items,
1227 check_valid_glyph_or_instantiator_list);
1228 }
1229
1230 void
1231 image_instantiator_format_create_glyphs_widget (void)
1232 {
1233 image_instantiator_widget();
1234 image_instantiator_buttons();
1235 image_instantiator_edit_fields();
1236 image_instantiator_combo_box();
1237 image_instantiator_scrollbar();
1238 image_instantiator_progress_guage();
1239 image_instantiator_tree_view();
1240 image_instantiator_tab_control();
1241 image_instantiator_labels();
1242 image_instantiator_layout();
1243 }
1244
1245 void
1246 reinit_vars_of_glyphs_widget (void)
1247 {
1248 #ifdef DEBUG_WIDGETS
1249 debug_widget_instances = 0;
551 #endif 1250 #endif
552 } 1251 }
553 1252
554 void 1253 void
555 vars_of_glyphs_widget (void) 1254 vars_of_glyphs_widget (void)
556 { 1255 {
557 } 1256 reinit_vars_of_glyphs_widget ();
1257 }