1 /* Widget-specific glyph objects.
2 Copyright (C) 1998, 1999, 2000 Andy Piper.
4 This file is part of XEmacs.
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
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
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. */
21 /* Synched up with: Not in FSF. */
23 /* written by Andy Piper <andy@xemacs.org> */
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);
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);
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;
64 int debug_widget_instances;
68 - tooltips for controls, especially buttons.
70 - lisp configurable layout.
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
79 widget_possible_dest_types (void)
81 return IMAGE_WIDGET_MASK;
85 check_valid_glyph_or_instantiator (Lisp_Object data)
87 Lisp_Object glyph = data;
89 glyph = XSYMBOL (data)->value;
91 if (IMAGE_INSTANCEP (glyph))
92 CHECK_IMAGE_INSTANCE (glyph);
93 else if (!CONSP (glyph) && !VECTORP (glyph))
94 CHECK_BUFFER_GLYPH (glyph);
98 check_valid_orientation (Lisp_Object data)
100 if (!EQ (data, Qhorizontal)
102 !EQ (data, Qvertical))
103 signal_simple_error ("unknown orientation for layout", data);
107 check_valid_tab_orientation (Lisp_Object data)
116 signal_simple_error ("unknown orientation for tab control", data);
120 check_valid_justification (Lisp_Object data)
122 if (!EQ (data, Qleft) && !EQ (data, Qright) && !EQ (data, Qcenter))
123 signal_simple_error ("unknown justification for layout", data);
127 check_valid_border (Lisp_Object data)
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);
136 check_valid_anything (Lisp_Object data)
141 check_valid_callback (Lisp_Object data)
144 && !COMPILED_FUNCTIONP (data)
147 signal_simple_error (":callback must be a function or expression", data);
152 check_valid_symbol (Lisp_Object data)
158 check_valid_string_or_vector (Lisp_Object data)
160 if (!STRINGP (data) && !VECTORP (data))
161 signal_simple_error (":descriptor must be a string or a vector", data);
165 check_valid_item_list_1 (Lisp_Object items)
170 EXTERNAL_LIST_LOOP (rest, items)
172 if (STRINGP (XCAR (rest)))
173 CHECK_STRING (XCAR (rest));
174 else if (VECTORP (XCAR (rest)))
175 gui_parse_item_keywords (XCAR (rest));
176 else if (LISTP (XCAR (rest)))
177 check_valid_item_list_1 (XCAR (rest));
179 signal_simple_error ("Items must be vectors, lists or strings", items);
184 check_valid_item_list (Lisp_Object data)
188 Fcheck_valid_plist (data);
189 items = Fplist_get (data, Q_items, Qnil);
191 check_valid_item_list_1 (items);
195 check_valid_glyph_or_instantiator_list (Lisp_Object data)
200 EXTERNAL_LIST_LOOP (rest, data)
202 check_valid_glyph_or_instantiator (XCAR (rest));
207 glyph_instantiator_to_glyph (Lisp_Object sym)
209 /* This function calls lisp. */
210 Lisp_Object glyph = sym;
214 /* if we have a symbol get at the actual data */
216 glyph = XSYMBOL (glyph)->value;
219 glyph = Feval (glyph);
221 /* Be really helpful to the user. */
224 glyph = call1 (intern ("make-glyph"), glyph);
227 /* substitute the new glyph */
228 RETURN_UNGCPRO (glyph);
232 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
235 /* substitute the new glyph */
236 for (i = 0; i < XVECTOR_LENGTH (inst); i++)
238 if (EQ (key, XVECTOR_DATA (inst)[i]))
240 XVECTOR_DATA (inst)[i+1] = val;
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. */
258 widget_property (Lisp_Object image_instance, Lisp_Object prop)
260 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
261 struct image_instantiator_methods* meths;
263 /* first see if its a general property ... */
264 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
265 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
267 /* .. then try device specific methods ... */
268 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
269 IMAGE_INSTANCE_WIDGET_TYPE (ii),
271 if (meths && HAS_IIFORMAT_METH_P (meths, property))
272 return IIFORMAT_METH (meths, property, (image_instance, prop));
273 /* ... then format specific methods ... */
274 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
276 if (meths && HAS_IIFORMAT_METH_P (meths, property))
277 return IIFORMAT_METH (meths, property, (image_instance, prop));
283 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val)
285 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
286 struct image_instantiator_methods* meths;
289 /* PIck up any generic properties that we might need to keep hold
291 if (EQ (prop, Q_text))
293 IMAGE_INSTANCE_WIDGET_TEXT (ii) = val;
294 IMAGE_INSTANCE_TEXT_CHANGED (ii) = 1;
297 /* Now try device specific methods first ... */
298 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
299 IMAGE_INSTANCE_WIDGET_TYPE (ii),
301 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
304 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
308 /* ... then format specific methods ... */
309 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
311 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
314 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
318 /* we didn't do any device specific properties, so shove the property in our plist */
319 IMAGE_INSTANCE_WIDGET_PROPS (ii)
320 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
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. */
333 update_widget (Lisp_Object widget)
335 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (widget);
336 struct image_instantiator_methods* meths;
338 if (!IMAGE_INSTANCE_TYPE (ii) == IMAGE_WIDGET)
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));
347 /* Device-format specific methods */
348 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
349 IMAGE_INSTANCE_WIDGET_TYPE (ii),
351 MAYBE_IIFORMAT_METH (meths, update, (widget));
354 /* Query for a widgets desired geometry. If no type specific method is
355 provided then use the widget text to calculate sizes. */
357 widget_query_geometry (Lisp_Object image_instance,
358 unsigned int* width, unsigned int* height,
359 enum image_instance_geometry disp, Lisp_Object domain)
361 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
362 struct image_instantiator_methods* meths;
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);
368 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
370 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
372 /* .. then try device specific methods ... */
373 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
374 IMAGE_INSTANCE_WIDGET_TYPE (ii),
376 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
377 IIFORMAT_METH (meths, query_geometry, (image_instance,
382 /* ... then format specific methods ... */
383 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
385 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
386 IIFORMAT_METH (meths, query_geometry, (image_instance,
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),
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;
409 widget_layout (Lisp_Object image_instance,
410 unsigned int width, unsigned int height, Lisp_Object domain)
412 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
413 struct image_instantiator_methods* meths;
415 /* .. then try device specific methods ... */
416 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
417 IMAGE_INSTANCE_WIDGET_TYPE (ii),
419 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
420 IIFORMAT_METH (meths, layout, (image_instance,
421 width, height, domain));
424 /* ... then format specific methods ... */
425 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
427 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
428 IIFORMAT_METH (meths, layout, (image_instance,
429 width, height, domain));
434 widget_validate (Lisp_Object instantiator)
436 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
439 signal_simple_error ("Must supply :descriptor", instantiator);
442 gui_parse_item_keywords (desc);
444 if (!NILP (find_keyword_in_vector (instantiator, Q_width))
445 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
446 signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
448 if (!NILP (find_keyword_in_vector (instantiator, Q_height))
449 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
450 signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
454 combo_box_validate (Lisp_Object instantiator)
456 widget_validate (instantiator);
457 if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
458 signal_simple_error ("Must supply item list", instantiator);
461 /* we need to convert things like glyphs to images, eval expressions
464 widget_normalize (Lisp_Object inst, Lisp_Object console_type)
466 /* This function can call lisp */
467 Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
469 /* we need to eval glyph if its an expression, we do this for the
470 same reasons we normalize file to data. */
473 substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
480 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type)
482 /* initialize_subwindow_image_instance (ii);*/
483 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
484 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
485 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil);
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;
493 /* Instantiate a button widget. Unfortunately instantiated widgets are
494 particular to a frame since they need to have a parent. It's not
495 like images where you just select the image into the context you
496 want to display it in and BitBlt it. So image instances can have a
497 many-to-one relationship with things you see, whereas widgets can
498 only be one-to-one (i.e. per frame) */
500 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
501 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
502 int dest_mask, Lisp_Object domain)
504 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
505 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
506 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
507 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
508 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
509 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
510 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
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);
515 int pw=0, ph=0, tw=0, th=0;
517 /* this just does pixel type sizing */
518 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
521 if (!(dest_mask & (IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK)))
522 incompatible_image_types (instantiator, dest_mask,
523 IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK);
525 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
527 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
528 IMAGE_INSTANCE_WIDGET_PROPS (ii) = props;
530 /* retrieve the fg and bg colors */
532 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
534 /* Do layout specific initialisation. This feels a bit tacky, but
535 the alternative is a myriad of different little functions. */
536 if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
538 Lisp_Object rest, children = Qnil;
539 Lisp_Object border = find_keyword_in_vector (instantiator, Q_border);
543 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
545 IMAGE_INSTANCE_TYPE (ii) = IMAGE_LAYOUT;
549 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in;
551 else if (GLYPHP (border))
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);
564 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border;
567 /* Pick up the sub-widgets. */
568 LIST_LOOP (rest, items)
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
577 children = Fnreverse (children);
579 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children;
581 /* retrieve the gui item information. This is easy if we have been
582 provided with a vector, more difficult if we have just been given
584 else if (STRINGP (desc) || NILP (desc))
586 /* big cheat - we rely on the fact that a gui item looks like an instantiator */
587 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
588 gui_parse_item_keywords_no_errors (instantiator);
589 IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
592 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
593 gui_parse_item_keywords_no_errors (desc);
595 /* Pick up the orientation before we do our first layout. */
596 if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical))
597 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 1;
599 /* parse more gui items out of the properties */
601 && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
605 items = Fplist_get (props, Q_items, Qnil);
609 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
610 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
611 parse_gui_item_tree_children (items));
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 */
621 pw = XINT (pixwidth);
622 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
624 else if (!NILP (width))
627 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
630 if (!NILP (pixheight))
632 ph = XINT (pixheight);
633 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
635 else if (!NILP (height) && XINT (height) > 1)
638 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
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
648 int charwidth, charheight;
649 default_face_font_info (domain, 0, 0, &charheight, &charwidth, 0);
653 ph = charheight * th;
656 /* for a widget with an image pick up the dimensions from that */
660 pw = glyph_width (glyph, domain) + 2 * WIDGET_BORDER_WIDTH;
662 ph = glyph_height (glyph, domain) + 2 * WIDGET_BORDER_HEIGHT;
663 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
664 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
667 /* When we create the widgets the window system expects a valid
668 size, so If we still don' t have sizes, call layout to pick them
669 up. If query_geometry or layout relies on the widget being in
670 existence then we are in catch 22. */
671 image_instance_layout (image_instance,
672 pw ? pw : IMAGE_UNSPECIFIED_GEOMETRY,
673 ph ? ph : IMAGE_UNSPECIFIED_GEOMETRY,
677 debug_widget_instances++;
678 stderr_out ("instantiated ");
679 debug_print (instantiator);
680 stderr_out ("%d widgets instantiated\n", debug_widget_instances);
684 /* tree-view geometry - get the height right */
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)
690 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
691 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
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);
704 default_face_font_info (domain, 0, 0, &h, 0, 0);
705 GET_LIST_LENGTH (items, len);
710 /* Get the geometry of a tab control. This is based on the number of
711 items and text therin in the tab control. */
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)
717 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
718 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
720 unsigned int tw = 0, th = 0;
722 LIST_LOOP (rest, items)
726 query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
727 IMAGE_INSTANCE_WIDGET_FACE (ii),
729 tw += 2 * WIDGET_BORDER_WIDTH; /* some bias */
731 th = max (th, h + 2 * WIDGET_BORDER_HEIGHT);
734 /* Fixup returned values depending on orientation. */
735 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
737 if (height) *height = tw;
738 if (width) *width = th;
742 if (height) *height = th;
743 if (width) *width = tw;
747 /* Get the geometry of a tab control. This is based on the number of
748 items and text therin in the tab control. */
750 tab_control_set_property (Lisp_Object image_instance,
754 /* Record new items for update. *_tab_control_update will do the
756 if (EQ (prop, Q_items))
758 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
759 check_valid_item_list_1 (val);
761 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
762 Fcons (XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)),
763 parse_gui_item_tree_children (val));
765 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1;
772 /* set the properties of a progres guage */
774 progress_gauge_set_property (Lisp_Object image_instance,
778 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
780 if (EQ (prop, Q_percent))
783 IMAGE_INSTANCE_WIDGET_PROPS (ii)
784 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
785 IMAGE_INSTANCE_WIDGET_PERCENT_CHANGED (ii) = 1;
793 /*****************************************************************************
795 *****************************************************************************/
797 layout_possible_dest_types (void)
799 return IMAGE_LAYOUT_MASK;
802 /* we need to convert things like glyphs to images, eval expressions
805 layout_normalize (Lisp_Object inst, Lisp_Object console_type)
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. */
815 LIST_LOOP (rest, items)
817 /* substitute the new glyph */
818 Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest)));
821 /* normalize the border spec. */
822 if (VECTORP (border) || CONSP (border))
824 substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border));
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:
843 1. A button is sized to accommodate its text, the text changes and the
844 button should change size also.
846 2. A button is given an explicit size. Its size should never change.
848 3. Layout is put inside an area. The size of the area changes, the
849 layout should change with it.
851 4. A button grows to accommodate additional text. The whitespace
852 around it should be modified to cope with the new layout
855 5. A button grows. The area surrounding it should grow also if
858 What metrics are important?
859 1. Actual width and height.
861 2. Whether the width and height are what the widget actually wants, or
862 whether it can grow or shrink.
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
875 /* Query the geometry of a layout widget. We assume that we can only
876 get here if the size is not already fixed. */
878 layout_query_geometry (Lisp_Object image_instance, unsigned int* width,
879 unsigned int* height, enum image_instance_geometry disp,
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;
886 /* Flip through the items to work out how much stuff we have to display */
887 LIST_LOOP (rest, items)
889 Lisp_Object glyph = XCAR (rest);
890 unsigned int gheight, gwidth;
892 image_instance_query_geometry (glyph, &gwidth, &gheight, disp, domain);
894 /* Pick up the border text if we have one. */
895 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
896 && NILP (XCDR (rest)))
898 ph_adjust = gheight / 2;
904 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
905 == LAYOUT_HORIZONTAL)
907 maxph = max (maxph, gheight);
912 maxpw = max (maxpw, gwidth);
918 /* work out spacing between items and bounds of the layout. No user
919 provided width so we just do default spacing. */
920 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
921 == LAYOUT_HORIZONTAL)
922 *width = maxpw + (nitems + 1) * WIDGET_BORDER_WIDTH * 2;
924 *width = maxpw + 2 * WIDGET_BORDER_WIDTH * 2;
926 /* Work out vertical spacings. */
927 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
929 *height = maxph + (nitems + 1) * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
931 *height = maxph + 2 * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
936 layout_layout (Lisp_Object image_instance,
937 unsigned int width, unsigned int height, Lisp_Object domain)
939 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
941 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
942 int x, y, maxph = 0, maxpw = 0, nitems = 0,
943 horiz_spacing, vert_spacing, ph_adjust = 0;
944 unsigned int gheight, gwidth;
946 /* flip through the items to work out how much stuff we have to display */
947 LIST_LOOP (rest, items)
949 Lisp_Object glyph = XCAR (rest);
951 image_instance_query_geometry (glyph, &gwidth, &gheight,
952 IMAGE_DESIRED_GEOMETRY, domain);
954 /* Pick up the border text if we have one. */
955 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
956 && NILP (XCDR (rest)))
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);
966 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
967 == LAYOUT_HORIZONTAL)
969 maxph = max (maxph, gheight);
974 maxpw = max (maxpw, gwidth);
980 /* work out spacing between items and bounds of the layout */
982 /* The user wants a smaller space than the largest item, so we
983 just provide default spacing and will let the output routines
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
990 horiz_spacing = (width - maxpw) / (nitems + 1);
992 horiz_spacing = (width - maxpw) / 2;
995 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
996 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
998 vert_spacing = (height - (maxph + ph_adjust)) / (nitems + 1);
1000 vert_spacing = (height - (maxph + ph_adjust)) / 2;
1002 y = vert_spacing + ph_adjust;
1005 /* Now flip through putting items where we want them, paying
1006 attention to justification. Make sure we don't mess with the
1008 LIST_LOOP (rest, items)
1010 Lisp_Object glyph = XCAR (rest);
1012 image_instance_query_geometry (glyph, &gwidth, &gheight,
1013 IMAGE_DESIRED_GEOMETRY, domain);
1015 if (!INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
1016 || !NILP (XCDR (rest)))
1018 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1019 == LAYOUT_HORIZONTAL)
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;
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;
1038 XIMAGE_INSTANCE_XOFFSET (glyph) = x;
1039 XIMAGE_INSTANCE_YOFFSET (glyph) = y;
1041 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1042 == LAYOUT_HORIZONTAL)
1044 x += (gwidth + horiz_spacing);
1048 y += (gheight + vert_spacing);
1052 /* Now layout subwidgets if they require it. */
1053 image_instance_layout (glyph, gwidth, gheight, domain);
1058 /************************************************************************/
1059 /* initialization */
1060 /************************************************************************/
1063 syms_of_glyphs_widget (void)
1065 defkeyword (&Q_descriptor, ":descriptor");
1066 defkeyword (&Q_height, ":height");
1067 defkeyword (&Q_width, ":width");
1068 defkeyword (&Q_properties, ":properties");
1069 defkeyword (&Q_items, ":items");
1070 defkeyword (&Q_image, ":image");
1071 defkeyword (&Q_percent, ":percent");
1072 defkeyword (&Q_text, ":text");
1073 defkeyword (&Q_orientation, ":orientation");
1074 defkeyword (&Q_justify, ":justify");
1075 defkeyword (&Q_border, ":border");
1077 defsymbol (&Qetched_in, "etched-in");
1078 defsymbol (&Qetched_out, "etched-out");
1079 defsymbol (&Qbevel_in, "bevel-in");
1080 defsymbol (&Qbevel_out, "bevel-out");
1083 #define VALID_GUI_KEYWORDS(type) do { \
1084 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything); \
1085 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \
1086 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \
1087 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \
1088 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything); \
1089 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \
1090 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \
1091 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \
1092 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \
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); \
1099 #define VALID_WIDGET_KEYWORDS(type) do { \
1100 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \
1101 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \
1102 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int); \
1103 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int); \
1104 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face); \
1108 static void image_instantiator_widget (void)
1109 { /* we only do this for properties */
1110 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
1111 IIFORMAT_HAS_METHOD (widget, property);
1112 IIFORMAT_HAS_METHOD (widget, set_property);
1113 IIFORMAT_HAS_METHOD (widget, query_geometry);
1114 IIFORMAT_HAS_METHOD (widget, layout);
1117 static void image_instantiator_buttons (void)
1119 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
1120 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
1121 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
1122 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
1123 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
1124 IIFORMAT_VALID_KEYWORD (button,
1125 Q_image, check_valid_glyph_or_instantiator);
1126 VALID_WIDGET_KEYWORDS (button);
1127 VALID_GUI_KEYWORDS (button);
1130 static void image_instantiator_edit_fields (void)
1132 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
1133 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
1134 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
1135 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
1136 VALID_WIDGET_KEYWORDS (edit_field);
1137 VALID_GUI_KEYWORDS (edit_field);
1140 static void image_instantiator_combo_box (void)
1142 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
1143 IIFORMAT_HAS_METHOD (combo_box, validate);
1144 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
1145 VALID_GUI_KEYWORDS (combo_box);
1147 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
1148 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
1149 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int);
1150 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
1151 IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list);
1154 static void image_instantiator_scrollbar (void)
1156 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
1157 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
1158 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
1159 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
1160 VALID_GUI_KEYWORDS (scrollbar);
1162 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int);
1163 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int);
1164 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
1167 static void image_instantiator_progress_guage (void)
1169 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
1170 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
1171 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
1172 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
1173 IIFORMAT_HAS_METHOD (progress_gauge, set_property);
1174 VALID_WIDGET_KEYWORDS (progress_gauge);
1175 VALID_GUI_KEYWORDS (progress_gauge);
1178 static void image_instantiator_tree_view (void)
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);
1190 static void image_instantiator_tab_control (void)
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);
1204 static void image_instantiator_labels (void)
1206 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
1207 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
1208 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
1209 VALID_WIDGET_KEYWORDS (label);
1210 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
1213 static void image_instantiator_layout (void)
1215 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
1216 IIFORMAT_HAS_METHOD (layout, possible_dest_types);
1217 IIFORMAT_HAS_SHARED_METHOD (layout, instantiate, widget);
1218 IIFORMAT_HAS_METHOD (layout, normalize);
1219 IIFORMAT_HAS_METHOD (layout, query_geometry);
1220 IIFORMAT_HAS_METHOD (layout, layout);
1221 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_width, check_valid_int);
1222 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_height, check_valid_int);
1223 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation);
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);
1231 image_instantiator_format_create_glyphs_widget (void)
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();
1246 reinit_vars_of_glyphs_widget (void)
1248 #ifdef DEBUG_WIDGETS
1249 debug_widget_instances = 0;
1254 vars_of_glyphs_widget (void)
1256 reinit_vars_of_glyphs_widget ();