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