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;
296 /* Now try device specific methods first ... */
297 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
298 IMAGE_INSTANCE_WIDGET_TYPE (ii),
300 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
303 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
307 /* ... then format specific methods ... */
308 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
310 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
313 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
317 /* we didn't do any device specific properties, so shove the property in our plist */
318 IMAGE_INSTANCE_WIDGET_PROPS (ii)
319 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
323 /* Query for a widgets desired geometry. If no type specific method is
324 provided then use the widget text to calculate sizes. */
326 widget_query_geometry (Lisp_Object image_instance,
327 unsigned int* width, unsigned int* height,
328 enum image_instance_geometry disp, Lisp_Object domain)
330 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
331 struct image_instantiator_methods* meths;
333 /* First just set up what we already have. */
334 if (width) *width = IMAGE_INSTANCE_WIDTH (ii);
335 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii);
337 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
339 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
341 /* .. then try device specific methods ... */
342 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
343 IMAGE_INSTANCE_WIDGET_TYPE (ii),
345 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
346 IIFORMAT_METH (meths, query_geometry, (image_instance,
351 /* ... then format specific methods ... */
352 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
354 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
355 IIFORMAT_METH (meths, query_geometry, (image_instance,
362 /* Then if we are allowed to resize the widget, make the
363 size the same as the text dimensions. */
364 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
365 IMAGE_INSTANCE_WIDGET_FACE (ii),
367 /* Adjust the size for borders. */
368 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
369 *width = w + 2 * WIDGET_BORDER_WIDTH;
370 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
371 *height = h + 2 * WIDGET_BORDER_HEIGHT;
378 widget_layout (Lisp_Object image_instance,
379 unsigned int width, unsigned int height, Lisp_Object domain)
381 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
382 struct image_instantiator_methods* meths;
384 /* .. then try device specific methods ... */
385 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
386 IMAGE_INSTANCE_WIDGET_TYPE (ii),
388 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
389 IIFORMAT_METH (meths, layout, (image_instance,
390 width, height, domain));
393 /* ... then format specific methods ... */
394 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
396 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
397 IIFORMAT_METH (meths, layout, (image_instance,
398 width, height, domain));
403 widget_validate (Lisp_Object instantiator)
405 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
408 signal_simple_error ("Must supply :descriptor", instantiator);
411 gui_parse_item_keywords (desc);
413 if (!NILP (find_keyword_in_vector (instantiator, Q_width))
414 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
415 signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
417 if (!NILP (find_keyword_in_vector (instantiator, Q_height))
418 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
419 signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
423 combo_box_validate (Lisp_Object instantiator)
425 widget_validate (instantiator);
426 if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
427 signal_simple_error ("Must supply item list", instantiator);
430 /* we need to convert things like glyphs to images, eval expressions
433 widget_normalize (Lisp_Object inst, Lisp_Object console_type)
435 /* This function can call lisp */
436 Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
438 /* we need to eval glyph if its an expression, we do this for the
439 same reasons we normalize file to data. */
442 substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
449 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type)
451 /* initialize_subwindow_image_instance (ii);*/
452 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
453 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
454 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil);
455 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item ();
456 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 1;
457 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 1;
458 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 0;
459 IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) = 0;
462 /* Instantiate a button widget. Unfortunately instantiated widgets are
463 particular to a frame since they need to have a parent. It's not
464 like images where you just select the image into the context you
465 want to display it in and BitBlt it. So image instances can have a
466 many-to-one relationship with things you see, whereas widgets can
467 only be one-to-one (i.e. per frame) */
469 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
470 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
471 int dest_mask, Lisp_Object domain)
473 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
474 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
475 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
476 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
477 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
478 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
479 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
480 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
481 Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties);
482 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
483 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
484 int pw=0, ph=0, tw=0, th=0;
486 /* this just does pixel type sizing */
487 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
490 if (!(dest_mask & (IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK)))
491 incompatible_image_types (instantiator, dest_mask,
492 IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK);
494 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
496 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
497 IMAGE_INSTANCE_WIDGET_PROPS (ii) = props;
499 /* retrieve the fg and bg colors */
501 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
503 /* Do layout specific initialisation. This feels a bit tacky, but
504 the alternative is a myriad of different little functions. */
505 if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
507 Lisp_Object rest, children = Qnil;
508 Lisp_Object border = find_keyword_in_vector (instantiator, Q_border);
512 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
514 IMAGE_INSTANCE_TYPE (ii) = IMAGE_LAYOUT;
518 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in;
520 else if (GLYPHP (border))
522 /* We are going to be sneaky here and add the border text as
523 just another child, the layout and output routines don't know
524 this and will just display at the offsets we prescribe. */
525 children = Fcons (glyph_image_instance (border, domain, ERROR_ME, 1),
527 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (0);
531 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border;
534 /* Pick up the sub-widgets. */
535 LIST_LOOP (rest, items)
537 /* make sure the image is instantiated */
538 Lisp_Object gii = glyph_image_instance (XCAR (rest), domain, ERROR_ME, 1);
539 children = Fcons (gii, children);
540 /* Make sure elements in the layout are in the order the
542 children = Fnreverse (children);
544 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children;
546 /* retrieve the gui item information. This is easy if we have been
547 provided with a vector, more difficult if we have just been given
549 else if (STRINGP (desc) || NILP (desc))
551 /* big cheat - we rely on the fact that a gui item looks like an instantiator */
552 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
553 gui_parse_item_keywords_no_errors (instantiator);
554 IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
557 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
558 gui_parse_item_keywords_no_errors (desc);
560 /* Pick up the orientation before we do our first layout. */
561 if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical))
562 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 1;
564 /* parse more gui items out of the properties */
566 && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
570 items = Fplist_get (props, Q_items, Qnil);
574 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
575 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
576 parse_gui_item_tree_children (items));
580 /* Normalize size information. We now only assign sizes if the user
581 gives us some explicitly, or there are some constraints that we
582 can't change later on. Otherwise we postpone sizing until query
583 geometry gets called. */
584 if (!NILP (pixwidth)) /* pixwidth takes precendent */
586 pw = XINT (pixwidth);
587 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
589 else if (!NILP (width))
592 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
595 if (!NILP (pixheight))
597 ph = XINT (pixheight);
598 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
600 else if (!NILP (height) && XINT (height) > 1)
603 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
606 /* Taking the default face information when the user has specified
607 size in characters is probably as good as any since the widget
608 face is more likely to be proportional and thus give inadequate
609 results. Using character sizes can only ever be approximate
613 int charwidth, charheight;
614 default_face_font_info (domain, 0, 0, &charheight, &charwidth, 0);
618 ph = charheight * th;
621 /* for a widget with an image pick up the dimensions from that */
625 pw = glyph_width (glyph, domain) + 2 * WIDGET_BORDER_WIDTH;
627 ph = glyph_height (glyph, domain) + 2 * WIDGET_BORDER_HEIGHT;
628 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
629 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
632 /* When we create the widgets the window system expects a valid
633 size, so If we still don' t have sizes, call layout to pick them
634 up. If query_geometry or layout relies on the widget being in
635 existence then we are in catch 22. */
636 image_instance_layout (image_instance,
637 pw ? pw : IMAGE_UNSPECIFIED_GEOMETRY,
638 ph ? ph : IMAGE_UNSPECIFIED_GEOMETRY,
640 /* Layout has already been done so we don't need to re-layout. */
641 IMAGE_INSTANCE_DIRTYP (ii) = 0;
644 debug_widget_instances++;
645 stderr_out ("instantiated ");
646 debug_print (instantiator);
647 stderr_out ("%d widgets instantiated\n", debug_widget_instances);
651 /* tree-view geometry - get the height right */
653 tree_view_query_geometry (Lisp_Object image_instance,
654 unsigned int* width, unsigned int* height,
655 enum image_instance_geometry disp, Lisp_Object domain)
657 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
658 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
663 /* #### what should this be. reconsider when X has tree views. */
664 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
665 IMAGE_INSTANCE_WIDGET_FACE (ii),
666 width, 0, 0, domain);
671 default_face_font_info (domain, 0, 0, &h, 0, 0);
672 GET_LIST_LENGTH (items, len);
677 /* Get the geometry of a tab control. This is based on the number of
678 items and text therin in the tab control. */
680 tab_control_query_geometry (Lisp_Object image_instance,
681 unsigned int* width, unsigned int* height,
682 enum image_instance_geometry disp, Lisp_Object domain)
684 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
685 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
687 unsigned int tw = 0, th = 0;
689 LIST_LOOP (rest, items)
693 query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
694 IMAGE_INSTANCE_WIDGET_FACE (ii),
696 tw += 2 * WIDGET_BORDER_WIDTH; /* some bias */
698 th = max (th, h + 2 * WIDGET_BORDER_HEIGHT);
701 /* Fixup returned values depending on orientation. */
702 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
704 if (height) *height = tw;
705 if (width) *width = th;
709 if (height) *height = th;
710 if (width) *width = tw;
715 /*****************************************************************************
717 *****************************************************************************/
719 layout_possible_dest_types (void)
721 return IMAGE_LAYOUT_MASK;
724 /* we need to convert things like glyphs to images, eval expressions
727 layout_normalize (Lisp_Object inst, Lisp_Object console_type)
729 /* This function can call lisp */
730 Lisp_Object items = find_keyword_in_vector (inst, Q_items);
731 Lisp_Object border = find_keyword_in_vector (inst, Q_border);
732 /* we need to eval glyph if its an expression, we do this for the
733 same reasons we normalize file to data. */
737 LIST_LOOP (rest, items)
739 /* substitute the new glyph */
740 Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest)));
743 /* normalize the border spec. */
744 if (VECTORP (border) || CONSP (border))
746 substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border));
751 /* Layout widget. Sizing commentary: we have a number of problems that
752 we would like to address. Some consider some of these more
753 important than others. It used to be that size information was
754 determined at instantiation time and was then fixed forever
755 after. Generally this is not what we want. Users want size to be
756 "big enough" to accommodate whatever they are trying to show and
757 this is dependent on text length, lines, font metrics etc. Of
758 course these attributes can change dynamically and so the size
759 should changed dynamically also. Only in a few limited cases should
760 the size be fixed and remain fixed. Of course this actually means
761 that we don't really want to specifiy the size *at all* for most
762 widgets - we want it to be discovered dynamically. Thus we can
763 envisage the following scenarios:
765 1. A button is sized to accommodate its text, the text changes and the
766 button should change size also.
768 2. A button is given an explicit size. Its size should never change.
770 3. Layout is put inside an area. The size of the area changes, the
771 layout should change with it.
773 4. A button grows to accommodate additional text. The whitespace
774 around it should be modified to cope with the new layout
777 5. A button grows. The area surrounding it should grow also if
780 What metrics are important?
781 1. Actual width and height.
783 2. Whether the width and height are what the widget actually wants, or
784 whether it can grow or shrink.
786 Text glyphs are particularly troublesome since their metrics depend
787 on the context in which they are being viewed. For instance they
788 can appear differently depending on the window face, frame face or
789 glyph face. In order to simplify this text glyphs can now only have
790 a glyph-face or image-instance face. All other glyphs are
791 essentially fixed in appearance. Perhaps the problem is that text
792 glyphs are cached on a device basis like most other glyphs. Instead
793 they should be cached per-window and then the instance would be
794 fixed and we wouldn't have to mess around with font metrics and the
797 /* Query the geometry of a layout widget. We assume that we can only
798 get here if the size is not already fixed. */
800 layout_query_geometry (Lisp_Object image_instance, unsigned int* width,
801 unsigned int* height, enum image_instance_geometry disp,
804 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
805 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii), rest;
806 int maxph = 0, maxpw = 0, nitems = 0, ph_adjust = 0;
808 /* Flip through the items to work out how much stuff we have to display */
809 LIST_LOOP (rest, items)
811 Lisp_Object glyph = XCAR (rest);
812 unsigned int gheight, gwidth;
814 image_instance_query_geometry (glyph, &gwidth, &gheight, disp, domain);
816 /* Pick up the border text if we have one. */
817 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
818 && NILP (XCDR (rest)))
820 ph_adjust = gheight / 2;
826 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
827 == LAYOUT_HORIZONTAL)
829 maxph = max (maxph, gheight);
834 maxpw = max (maxpw, gwidth);
840 /* work out spacing between items and bounds of the layout. No user
841 provided width so we just do default spacing. */
842 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
843 == LAYOUT_HORIZONTAL)
844 *width = maxpw + (nitems + 1) * WIDGET_BORDER_WIDTH * 2;
846 *width = maxpw + 2 * WIDGET_BORDER_WIDTH * 2;
848 /* Work out vertical spacings. */
849 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
851 *height = maxph + (nitems + 1) * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
853 *height = maxph + 2 * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
858 layout_layout (Lisp_Object image_instance,
859 unsigned int width, unsigned int height, Lisp_Object domain)
861 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
863 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
864 int x, y, maxph = 0, maxpw = 0, nitems = 0,
865 horiz_spacing, vert_spacing, ph_adjust = 0;
866 unsigned int gheight, gwidth;
868 /* flip through the items to work out how much stuff we have to display */
869 LIST_LOOP (rest, items)
871 Lisp_Object glyph = XCAR (rest);
873 image_instance_query_geometry (glyph, &gwidth, &gheight,
874 IMAGE_DESIRED_GEOMETRY, domain);
876 /* Pick up the border text if we have one. */
877 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
878 && NILP (XCDR (rest)))
880 XIMAGE_INSTANCE_XOFFSET (glyph) = 10; /* Really, what should this be? */
881 XIMAGE_INSTANCE_YOFFSET (glyph) = 0;
882 ph_adjust = gheight / 2;
883 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (ph_adjust);
889 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
890 == LAYOUT_HORIZONTAL)
892 maxph = max (maxph, gheight);
897 maxpw = max (maxpw, gwidth);
903 /* work out spacing between items and bounds of the layout */
905 /* The user wants a smaller space than the largest item, so we
906 just provide default spacing and will let the output routines
908 horiz_spacing = WIDGET_BORDER_WIDTH * 2;
909 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
910 == LAYOUT_HORIZONTAL)
911 /* We have a larger area to display in so distribute the space
913 horiz_spacing = (width - maxpw) / (nitems + 1);
915 horiz_spacing = (width - maxpw) / 2;
918 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
919 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
921 vert_spacing = (height - (maxph + ph_adjust)) / (nitems + 1);
923 vert_spacing = (height - (maxph + ph_adjust)) / 2;
925 y = vert_spacing + ph_adjust;
928 /* Now flip through putting items where we want them, paying
929 attention to justification. Make sure we don't mess with the
931 LIST_LOOP (rest, items)
933 Lisp_Object glyph = XCAR (rest);
935 image_instance_query_geometry (glyph, &gwidth, &gheight,
936 IMAGE_DESIRED_GEOMETRY, domain);
938 if (!INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
939 || !NILP (XCDR (rest)))
941 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
942 == LAYOUT_HORIZONTAL)
944 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
945 == LAYOUT_JUSTIFY_RIGHT)
946 y = height - (gheight + vert_spacing);
947 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
948 == LAYOUT_JUSTIFY_CENTER)
949 y = (height - gheight) / 2;
953 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
954 == LAYOUT_JUSTIFY_RIGHT)
955 x = width - (gwidth + horiz_spacing);
956 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
957 == LAYOUT_JUSTIFY_CENTER)
958 x = (width - gwidth) / 2;
961 XIMAGE_INSTANCE_XOFFSET (glyph) = x;
962 XIMAGE_INSTANCE_YOFFSET (glyph) = y;
964 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
965 == LAYOUT_HORIZONTAL)
967 x += (gwidth + horiz_spacing);
971 y += (gheight + vert_spacing);
975 /* Now layout subwidgets if they require it. */
976 image_instance_layout (glyph, gwidth, gheight, domain);
979 IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = width;
980 IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = height;
984 /************************************************************************/
986 /************************************************************************/
989 syms_of_glyphs_widget (void)
991 defkeyword (&Q_descriptor, ":descriptor");
992 defkeyword (&Q_height, ":height");
993 defkeyword (&Q_width, ":width");
994 defkeyword (&Q_properties, ":properties");
995 defkeyword (&Q_items, ":items");
996 defkeyword (&Q_image, ":image");
997 defkeyword (&Q_percent, ":percent");
998 defkeyword (&Q_text, ":text");
999 defkeyword (&Q_orientation, ":orientation");
1000 defkeyword (&Q_justify, ":justify");
1001 defkeyword (&Q_border, ":border");
1003 defsymbol (&Qetched_in, "etched-in");
1004 defsymbol (&Qetched_out, "etched-out");
1005 defsymbol (&Qbevel_in, "bevel-in");
1006 defsymbol (&Qbevel_out, "bevel-out");
1009 #define VALID_GUI_KEYWORDS(type) do { \
1010 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything); \
1011 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \
1012 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \
1013 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \
1014 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything); \
1015 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \
1016 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \
1017 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \
1018 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \
1019 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \
1020 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \
1021 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback); \
1022 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor, check_valid_string_or_vector); \
1025 #define VALID_WIDGET_KEYWORDS(type) do { \
1026 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \
1027 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \
1028 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int); \
1029 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int); \
1030 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face); \
1034 static void image_instantiator_widget (void)
1035 { /* we only do this for properties */
1036 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
1037 IIFORMAT_HAS_METHOD (widget, property);
1038 IIFORMAT_HAS_METHOD (widget, set_property);
1039 IIFORMAT_HAS_METHOD (widget, query_geometry);
1040 IIFORMAT_HAS_METHOD (widget, layout);
1043 static void image_instantiator_buttons (void)
1045 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
1046 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
1047 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
1048 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
1049 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
1050 IIFORMAT_VALID_KEYWORD (button,
1051 Q_image, check_valid_glyph_or_instantiator);
1052 VALID_WIDGET_KEYWORDS (button);
1053 VALID_GUI_KEYWORDS (button);
1056 static void image_instantiator_edit_fields (void)
1058 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
1059 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
1060 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
1061 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
1062 VALID_WIDGET_KEYWORDS (edit_field);
1063 VALID_GUI_KEYWORDS (edit_field);
1066 static void image_instantiator_combo_box (void)
1068 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
1069 IIFORMAT_HAS_METHOD (combo_box, validate);
1070 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
1071 VALID_GUI_KEYWORDS (combo_box);
1073 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
1074 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
1075 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int);
1076 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
1077 IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list);
1080 static void image_instantiator_scrollbar (void)
1082 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
1083 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
1084 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
1085 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
1086 VALID_GUI_KEYWORDS (scrollbar);
1088 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int);
1089 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int);
1090 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
1093 static void image_instantiator_progress_guage (void)
1095 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
1096 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
1097 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
1098 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
1099 VALID_WIDGET_KEYWORDS (progress_gauge);
1100 VALID_GUI_KEYWORDS (progress_gauge);
1103 static void image_instantiator_tree_view (void)
1105 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
1106 IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
1107 IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
1108 IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget);
1109 IIFORMAT_HAS_METHOD (tree_view, query_geometry);
1110 VALID_WIDGET_KEYWORDS (tree_view);
1111 VALID_GUI_KEYWORDS (tree_view);
1112 IIFORMAT_VALID_KEYWORD (tree_view, Q_properties, check_valid_item_list);
1115 static void image_instantiator_tab_control (void)
1117 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
1118 IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
1119 IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
1120 IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget);
1121 IIFORMAT_HAS_METHOD (tab_control, query_geometry);
1122 VALID_WIDGET_KEYWORDS (tab_control);
1123 VALID_GUI_KEYWORDS (tab_control);
1124 IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation, check_valid_tab_orientation);
1125 IIFORMAT_VALID_KEYWORD (tab_control, Q_properties, check_valid_item_list);
1128 static void image_instantiator_labels (void)
1130 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
1131 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
1132 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
1133 VALID_WIDGET_KEYWORDS (label);
1134 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
1137 static void image_instantiator_layout (void)
1139 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
1140 IIFORMAT_HAS_METHOD (layout, possible_dest_types);
1141 IIFORMAT_HAS_SHARED_METHOD (layout, instantiate, widget);
1142 IIFORMAT_HAS_METHOD (layout, normalize);
1143 IIFORMAT_HAS_METHOD (layout, query_geometry);
1144 IIFORMAT_HAS_METHOD (layout, layout);
1145 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_width, check_valid_int);
1146 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_height, check_valid_int);
1147 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation);
1148 IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification);
1149 IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border);
1150 IIFORMAT_VALID_KEYWORD (layout, Q_items,
1151 check_valid_glyph_or_instantiator_list);
1155 image_instantiator_format_create_glyphs_widget (void)
1157 image_instantiator_widget();
1158 image_instantiator_buttons();
1159 image_instantiator_edit_fields();
1160 image_instantiator_combo_box();
1161 image_instantiator_scrollbar();
1162 image_instantiator_progress_guage();
1163 image_instantiator_tree_view();
1164 image_instantiator_tab_control();
1165 image_instantiator_labels();
1166 image_instantiator_layout();
1170 reinit_vars_of_glyphs_widget (void)
1172 #ifdef DEBUG_WIDGETS
1173 debug_widget_instances = 0;
1178 vars_of_glyphs_widget (void)
1180 reinit_vars_of_glyphs_widget ();