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 - more complex controls.
69 - tooltips for controls, especially buttons.
72 /* In MS-Windows normal windows work in pixels, dialog boxes work in
73 dialog box units. Why? sigh. We could reuse the metrics for dialogs
74 if this were not the case. As it is we have to position things
75 pixel wise. I'm not even sure that X has this problem at least for
78 widget_possible_dest_types (void)
80 return IMAGE_WIDGET_MASK;
84 check_valid_glyph_or_instantiator (Lisp_Object data)
86 Lisp_Object glyph = data;
88 glyph = XSYMBOL (data)->value;
90 if (IMAGE_INSTANCEP (glyph))
91 CHECK_IMAGE_INSTANCE (glyph);
92 else if (!CONSP (glyph) && !VECTORP (glyph))
93 CHECK_BUFFER_GLYPH (glyph);
97 check_valid_orientation (Lisp_Object data)
99 if (!EQ (data, Qhorizontal)
101 !EQ (data, Qvertical))
102 signal_simple_error ("unknown orientation for layout", data);
106 check_valid_tab_orientation (Lisp_Object data)
115 signal_simple_error ("unknown orientation for tab control", data);
119 check_valid_justification (Lisp_Object data)
121 if (!EQ (data, Qleft) && !EQ (data, Qright) && !EQ (data, Qcenter))
122 signal_simple_error ("unknown justification for layout", data);
126 check_valid_border (Lisp_Object data)
128 if (!EQ (data, Qt) && !EQ (data, Qetched_in) && !EQ (data, Qetched_out)
129 && !EQ (data, Qbevel_in) && !EQ (data, Qbevel_out)
130 && !GLYPHP (data) && !VECTORP (data))
131 signal_simple_error ("unknown border style for layout", data);
135 check_valid_anything (Lisp_Object data)
140 check_valid_callback (Lisp_Object data)
143 && !COMPILED_FUNCTIONP (data)
146 signal_simple_error (":callback must be a function or expression", data);
151 check_valid_symbol (Lisp_Object data)
157 check_valid_string_or_vector (Lisp_Object data)
159 if (!STRINGP (data) && !VECTORP (data))
160 signal_simple_error (":descriptor must be a string or a vector", data);
164 check_valid_item_list_1 (Lisp_Object items)
169 EXTERNAL_LIST_LOOP (rest, items)
171 if (STRINGP (XCAR (rest)))
172 CHECK_STRING (XCAR (rest));
173 else if (VECTORP (XCAR (rest)))
174 gui_parse_item_keywords (XCAR (rest));
175 else if (LISTP (XCAR (rest)))
176 check_valid_item_list_1 (XCAR (rest));
178 signal_simple_error ("Items must be vectors, lists or strings", items);
183 check_valid_item_list (Lisp_Object data)
187 Fcheck_valid_plist (data);
188 items = Fplist_get (data, Q_items, Qnil);
190 check_valid_item_list_1 (items);
194 check_valid_glyph_or_instantiator_list (Lisp_Object data)
199 EXTERNAL_LIST_LOOP (rest, data)
201 check_valid_glyph_or_instantiator (XCAR (rest));
206 glyph_instantiator_to_glyph (Lisp_Object sym)
208 /* This function calls lisp. */
209 Lisp_Object glyph = sym;
213 /* if we have a symbol get at the actual data */
215 glyph = XSYMBOL (glyph)->value;
218 glyph = Feval (glyph);
220 /* Be really helpful to the user. */
223 glyph = call1 (intern ("make-glyph"), glyph);
226 /* substitute the new glyph */
227 RETURN_UNGCPRO (glyph);
231 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
234 /* substitute the new glyph */
235 for (i = 0; i < XVECTOR_LENGTH (inst); i++)
237 if (EQ (key, XVECTOR_DATA (inst)[i]))
239 XVECTOR_DATA (inst)[i+1] = val;
245 /* Wire widget property invocations to specific widgets. The problem
246 we are solving here is that when instantiators get converted to
247 instances they lose some type information (they just become
248 subwindows or widgets for example). For widgets we need to preserve
249 this type information so that we can do widget specific operations
250 on the instances. This is encoded in the widget type
251 field. widget_property gets invoked by decoding the primary type
252 (Qwidget), <widget>_property then invokes based on the secondary
253 type (Qedit_field for example). It is debatable whether we should
254 wire things in this generalised way rather than treating widgets
255 specially in image_instance_property. */
257 widget_property (Lisp_Object image_instance, Lisp_Object prop)
259 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
260 struct image_instantiator_methods* meths;
262 /* first see if its a general property ... */
263 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
264 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
266 /* .. then try device specific methods ... */
267 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
268 IMAGE_INSTANCE_WIDGET_TYPE (ii),
270 if (meths && HAS_IIFORMAT_METH_P (meths, property))
271 return IIFORMAT_METH (meths, property, (image_instance, prop));
272 /* ... then format specific methods ... */
273 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
275 if (meths && HAS_IIFORMAT_METH_P (meths, property))
276 return IIFORMAT_METH (meths, property, (image_instance, prop));
282 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val)
284 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
285 struct image_instantiator_methods* meths;
288 /* PIck up any generic properties that we might need to keep hold
290 if (EQ (prop, Q_text))
292 IMAGE_INSTANCE_WIDGET_TEXT (ii) = val;
295 /* Now try device specific methods first ... */
296 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
297 IMAGE_INSTANCE_WIDGET_TYPE (ii),
299 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
302 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
306 /* ... then format specific methods ... */
307 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
309 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
312 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
316 /* we didn't do any device specific properties, so shove the property in our plist */
317 IMAGE_INSTANCE_WIDGET_PROPS (ii)
318 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
322 /* Query for a widgets desired geometry. If no type specific method is
323 provided then use the widget text to calculate sizes. */
325 widget_query_geometry (Lisp_Object image_instance,
326 unsigned int* width, unsigned int* height,
327 enum image_instance_geometry disp, Lisp_Object domain)
329 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
330 struct image_instantiator_methods* meths;
332 /* First just set up what we already have. */
333 if (width) *width = IMAGE_INSTANCE_WIDTH (ii);
334 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii);
336 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
338 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
340 /* .. then try device specific methods ... */
341 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
342 IMAGE_INSTANCE_WIDGET_TYPE (ii),
344 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
345 IIFORMAT_METH (meths, query_geometry, (image_instance,
350 /* ... then format specific methods ... */
351 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
353 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
354 IIFORMAT_METH (meths, query_geometry, (image_instance,
361 /* Then if we are allowed to resize the widget, make the
362 size the same as the text dimensions. */
363 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
364 IMAGE_INSTANCE_WIDGET_FACE (ii),
366 /* Adjust the size for borders. */
367 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
368 *width = w + 2 * WIDGET_BORDER_WIDTH;
369 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
370 *height = h + 2 * WIDGET_BORDER_HEIGHT;
377 widget_layout (Lisp_Object image_instance,
378 unsigned int width, unsigned int height, Lisp_Object domain)
380 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
381 struct image_instantiator_methods* meths;
383 /* .. then try device specific methods ... */
384 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
385 IMAGE_INSTANCE_WIDGET_TYPE (ii),
387 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
388 IIFORMAT_METH (meths, layout, (image_instance,
389 width, height, domain));
392 /* ... then format specific methods ... */
393 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
395 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
396 IIFORMAT_METH (meths, layout, (image_instance,
397 width, height, domain));
402 widget_validate (Lisp_Object instantiator)
404 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
407 signal_simple_error ("Must supply :descriptor", instantiator);
410 gui_parse_item_keywords (desc);
412 if (!NILP (find_keyword_in_vector (instantiator, Q_width))
413 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
414 signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
416 if (!NILP (find_keyword_in_vector (instantiator, Q_height))
417 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
418 signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
422 combo_box_validate (Lisp_Object instantiator)
424 widget_validate (instantiator);
425 if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
426 signal_simple_error ("Must supply item list", instantiator);
429 /* we need to convert things like glyphs to images, eval expressions
432 widget_normalize (Lisp_Object inst, Lisp_Object console_type)
434 /* This function can call lisp */
435 Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
437 /* we need to eval glyph if its an expression, we do this for the
438 same reasons we normalize file to data. */
441 substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
448 initialize_widget_image_instance (struct Lisp_Image_Instance *ii, Lisp_Object type)
450 /* initialize_subwindow_image_instance (ii);*/
451 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
452 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
453 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil);
454 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item ();
455 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 1;
456 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 1;
457 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 0;
458 IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) = 0;
461 /* Instantiate a button widget. Unfortunately instantiated widgets are
462 particular to a frame since they need to have a parent. It's not
463 like images where you just select the image into the context you
464 want to display it in and BitBlt it. So image instances can have a
465 many-to-one relationship with things you see, whereas widgets can
466 only be one-to-one (i.e. per frame) */
468 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
469 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
470 int dest_mask, Lisp_Object domain)
472 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
473 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
474 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
475 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
476 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
477 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
478 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
479 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
480 Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties);
481 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
482 int pw=0, ph=0, tw=0, th=0;
484 /* this just does pixel type sizing */
485 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
488 if (!(dest_mask & IMAGE_WIDGET_MASK))
489 incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK);
491 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
493 /* retrieve the fg and bg colors */
495 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
497 /* data items for some widgets */
498 IMAGE_INSTANCE_WIDGET_PROPS (ii) = props;
500 /* Pick up the orientation before we do our first layout. */
501 if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical))
502 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 1;
504 /* retrieve the gui item information. This is easy if we have been
505 provided with a vector, more difficult if we have just been given
507 if (STRINGP (desc) || NILP (desc))
509 /* big cheat - we rely on the fact that a gui item looks like an instantiator */
510 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
511 gui_parse_item_keywords_no_errors (instantiator);
512 IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
515 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
516 gui_parse_item_keywords_no_errors (desc);
518 /* parse more gui items out of the properties */
521 Lisp_Object items = Fplist_get (props, Q_items, Qnil);
523 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
524 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
525 parse_gui_item_tree_children (items));
528 /* Normalize size information. We now only assign sizes if the user
529 gives us some explicitly, or there are some constraints that we
530 can't change later on. Otherwise we postpone sizing until query
531 geometry gets called. */
532 if (!NILP (pixwidth)) /* pixwidth takes precendent */
534 pw = XINT (pixwidth);
535 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
537 else if (!NILP (width))
540 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
543 if (!NILP (pixheight))
545 ph = XINT (pixheight);
546 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
548 else if (!NILP (height) && XINT (height) > 1)
551 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
554 /* Taking the default face information when the user has specified
555 size in characters is probably as good as any since the widget
556 face is more likely to be proportional and thus give inadequate
557 results. Using character sizes can only ever be approximate
561 int charwidth, charheight;
562 default_face_font_info (domain, 0, 0, &charheight, &charwidth, 0);
566 ph = charheight * th;
569 /* for a widget with an image pick up the dimensions from that */
573 pw = glyph_width (glyph, domain) + 2 * WIDGET_BORDER_WIDTH;
575 ph = glyph_height (glyph, domain) + 2 * WIDGET_BORDER_HEIGHT;
576 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
577 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
580 /* have to set the type this late in case there is no device
581 instantiation for a widget */
582 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
584 /* When we create the widgets the window system expects a valid
585 size, so If we still don' t have sizes, call layout to pick them
586 up. If query_geometry or layout relies on the widget being in
587 existence then we are in catch 22. */
588 image_instance_layout (image_instance,
589 pw ? pw : IMAGE_UNSPECIFIED_GEOMETRY,
590 ph ? ph : IMAGE_UNSPECIFIED_GEOMETRY,
592 /* Layout has already been done so we don't need to re-layout. */
593 IMAGE_INSTANCE_DIRTYP (ii) = 0;
596 debug_widget_instances++;
597 stderr_out ("instantiated ");
598 debug_print (instantiator);
599 stderr_out ("%d widgets instantiated\n", debug_widget_instances);
603 /* tree-view geometry - get the height right */
605 tree_view_query_geometry (Lisp_Object image_instance,
606 unsigned int* width, unsigned int* height,
607 enum image_instance_geometry disp, Lisp_Object domain)
609 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
610 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
615 /* #### what should this be. reconsider when X has tree views. */
616 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
617 IMAGE_INSTANCE_WIDGET_FACE (ii),
618 width, 0, 0, domain);
623 default_face_font_info (domain, 0, 0, &h, 0, 0);
624 GET_LIST_LENGTH (items, len);
629 /* Get the geometry of a tab control. This is based on the number of
630 items and text therin in the tab control. */
632 tab_control_query_geometry (Lisp_Object image_instance,
633 unsigned int* width, unsigned int* height,
634 enum image_instance_geometry disp, Lisp_Object domain)
636 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
637 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
639 unsigned int tw = 0, th = 0;
641 LIST_LOOP (rest, items)
645 query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
646 IMAGE_INSTANCE_WIDGET_FACE (ii),
648 tw += 2 * WIDGET_BORDER_WIDTH; /* some bias */
650 th = max (th, h + 2 * WIDGET_BORDER_HEIGHT);
653 /* Fixup returned values depending on orientation. */
654 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
656 if (height) *height = tw;
657 if (width) *width = th;
661 if (height) *height = th;
662 if (width) *width = tw;
667 /*****************************************************************************
669 *****************************************************************************/
671 layout_possible_dest_types (void)
673 return IMAGE_LAYOUT_MASK;
676 /* we need to convert things like glyphs to images, eval expressions
679 layout_normalize (Lisp_Object inst, Lisp_Object console_type)
681 /* This function can call lisp */
682 Lisp_Object items = find_keyword_in_vector (inst, Q_items);
683 Lisp_Object border = find_keyword_in_vector (inst, Q_border);
684 /* we need to eval glyph if its an expression, we do this for the
685 same reasons we normalize file to data. */
689 LIST_LOOP (rest, items)
691 /* substitute the new glyph */
692 Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest)));
695 /* normalize the border spec. */
696 if (VECTORP (border) || CONSP (border))
698 substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border));
703 /* Instantiate a layout widget. Sizing commentary: we have a number of
704 problems that we would like to address. Some consider some of these
705 more important than others. Currently size information is
706 determined at instantiation time and is then fixed forever
707 after. Generally this is not what we want. Users want size to be
708 "big enough" to accommodate whatever they are trying to show and
709 this is dependent on text length, lines, font metrics etc. Of
710 course these attributes can change dynamically and so the size
711 should changed dynamically also. Only in a few limited cases should
712 the size be fixed and remain fixed. Of course this actually means
713 that we don't really want to specifiy the size *at all* for most
714 widgets - we want it to be discovered dynamically. Thus we can
715 envisage the following scenarios:
717 1. A button is sized to accommodate its text, the text changes and the
718 button should change size also.
720 2. A button is given an explicit size. Its size should never change.
722 3. Layout is put inside an area. The size of the area changes, the
723 layout should change with it.
725 4. A button grows to accommodate additional text. The whitespace
726 around it should be modified to cope with the new layout
729 5. A button grows. The area surrounding it should grow also if
732 What metrics are important?
733 1. Actual width and height.
735 2. Whether the width and height are what the widget actually wants, or
736 whether it can grow or shrink.
738 Text glyphs are particularly troublesome since their metrics depend
739 on the context in which they are being viewed. For instance they
740 can appear differently depending on the window face, frame face or
741 glyph face. All other glyphs are essentially fixed in
742 appearance. Perhaps the problem is that text glyphs are cached on a
743 device basis like most other glyphs. Instead they should be cached
744 per-window and then the instance would be fixed and we wouldn't
745 have to mess around with font metrics and the rest. */
747 layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
748 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
749 int dest_mask, Lisp_Object domain)
751 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
752 Lisp_Object rest, device = IMAGE_INSTANCE_DEVICE (ii);
753 Lisp_Object frame = FW_FRAME (domain);
754 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
755 Lisp_Object width = find_keyword_in_vector (instantiator, Q_pixel_width);
756 Lisp_Object height = find_keyword_in_vector (instantiator, Q_pixel_height);
757 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
758 Lisp_Object justify = find_keyword_in_vector (instantiator, Q_justify);
759 Lisp_Object border = find_keyword_in_vector (instantiator, Q_border);
760 Lisp_Object children = Qnil;
761 int pw = 0, ph = 0, x, y, maxph = 0, maxpw = 0, nitems = 0,
762 horiz_spacing, vert_spacing, ph_adjust = 0;
765 signal_simple_error ("No selected frame", device);
767 if (!(dest_mask & IMAGE_LAYOUT_MASK))
768 incompatible_image_types (instantiator, dest_mask, IMAGE_LAYOUT_MASK);
777 IMAGE_INSTANCE_TYPE (ii) = IMAGE_LAYOUT;
778 IMAGE_INSTANCE_SUBWINDOW_ID (ii) = 0;
779 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 0;
780 IMAGE_INSTANCE_SUBWINDOW_FRAME (ii) = frame;
781 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border;
783 /* normalize size information */
789 /* flip through the items to work out how much stuff we have to display */
790 LIST_LOOP (rest, items)
792 Lisp_Object glyph = XCAR (rest);
793 int gheight = glyph_height (glyph, domain);
794 int gwidth = glyph_width (glyph, domain);
796 if (EQ (orient, Qhorizontal))
798 maxph = max (maxph, gheight);
801 else if (EQ (orient, Qvertical))
803 maxpw = max (maxpw, gwidth);
808 /* work out spacing between items and bounds of the layout */
811 /* No user provided width so we just do default spacing. */
812 horiz_spacing = WIDGET_BORDER_WIDTH * 2;
813 if (EQ (orient, Qhorizontal))
814 pw = maxpw + (nitems + 1) * horiz_spacing;
816 pw = maxpw + 2 * horiz_spacing;
819 /* The user wants a smaller space than the largest item, so we
820 just provide default spacing and will let the output routines
822 horiz_spacing = WIDGET_BORDER_WIDTH * 2;
823 else if (EQ (orient, Qhorizontal))
824 /* We have a larger area to display in so distribute the space
826 horiz_spacing = (pw - maxpw) / (nitems + 1);
828 horiz_spacing = (pw - maxpw) / 2;
830 /* Do the border now so that we can adjust the layout. */
833 /* We are going to be sneaky here and add the border text as
834 just another child, the layout and output routines don't know
835 this and will just display at the offsets we prescribe. */
836 Lisp_Object bglyph = glyph_image_instance (border, domain, ERROR_ME, 1);
838 children = Fcons (bglyph, children);
839 XIMAGE_INSTANCE_XOFFSET (bglyph) = 10; /* Really, what should this be? */
840 XIMAGE_INSTANCE_YOFFSET (bglyph) = 0;
842 ph_adjust = (glyph_height (border, domain) / 2);
843 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (ph_adjust);
846 /* Work out vertical spacings. */
849 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
850 if (EQ (orient, Qvertical))
851 ph = maxph + (nitems + 1) * vert_spacing + ph_adjust;
853 ph = maxph + 2 * vert_spacing + ph_adjust;
856 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
857 else if (EQ (orient, Qvertical))
858 vert_spacing = (ph - (maxph + ph_adjust)) / (nitems + 1);
860 vert_spacing = (ph - (maxph + ph_adjust)) / 2;
862 y = vert_spacing + ph_adjust;
865 /* Now flip through putting items where we want them, paying
866 attention to justification. */
867 LIST_LOOP (rest, items)
869 /* make sure the image is instantiated */
870 Lisp_Object glyph = XCAR (rest);
871 Lisp_Object gii = glyph_image_instance (glyph, domain, ERROR_ME, 1);
872 int gwidth = glyph_width (glyph, domain);
873 int gheight = glyph_height (glyph, domain);
875 children = Fcons (gii, children);
877 if (EQ (orient, Qhorizontal))
879 if (EQ (justify, Qright))
880 y = ph - (gheight + vert_spacing);
881 else if (EQ (justify, Qcenter))
882 y = (ph - gheight) / 2;
884 else if (EQ (orient, Qvertical))
886 if (EQ (justify, Qright))
887 x = pw - (gwidth + horiz_spacing);
888 else if (EQ (justify, Qcenter))
889 x = (pw - gwidth) / 2;
892 XIMAGE_INSTANCE_XOFFSET (gii) = x;
893 XIMAGE_INSTANCE_YOFFSET (gii) = y;
895 if (EQ (orient, Qhorizontal))
897 x += (gwidth + horiz_spacing);
899 else if (EQ (orient, Qvertical))
901 y += (gheight + vert_spacing);
905 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children;
907 IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = pw;
908 IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = ph;
912 /************************************************************************/
914 /************************************************************************/
917 syms_of_glyphs_widget (void)
919 defkeyword (&Q_descriptor, ":descriptor");
920 defkeyword (&Q_height, ":height");
921 defkeyword (&Q_width, ":width");
922 defkeyword (&Q_properties, ":properties");
923 defkeyword (&Q_items, ":items");
924 defkeyword (&Q_image, ":image");
925 defkeyword (&Q_percent, ":percent");
926 defkeyword (&Q_text, ":text");
927 defkeyword (&Q_orientation, ":orientation");
928 defkeyword (&Q_justify, ":justify");
929 defkeyword (&Q_border, ":border");
931 defsymbol (&Qetched_in, "etched-in");
932 defsymbol (&Qetched_out, "etched-out");
933 defsymbol (&Qbevel_in, "bevel-in");
934 defsymbol (&Qbevel_out, "bevel-out");
938 image_instantiator_format_create_glyphs_widget (void)
940 #define VALID_GUI_KEYWORDS(type) \
941 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything); \
942 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \
943 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \
944 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \
945 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything); \
946 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \
947 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \
948 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \
949 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \
950 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \
951 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \
952 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback); \
953 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor, check_valid_string_or_vector)
955 #define VALID_WIDGET_KEYWORDS(type) \
956 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \
957 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \
958 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int); \
959 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int); \
960 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face)
962 /* we only do this for properties */
963 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
964 IIFORMAT_HAS_METHOD (widget, property);
965 IIFORMAT_HAS_METHOD (widget, set_property);
966 IIFORMAT_HAS_METHOD (widget, query_geometry);
967 IIFORMAT_HAS_METHOD (widget, layout);
969 /* widget image-instantiator types - buttons */
970 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
971 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
972 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
973 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
974 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
975 IIFORMAT_VALID_KEYWORD (button,
976 Q_image, check_valid_glyph_or_instantiator);
977 VALID_WIDGET_KEYWORDS (button);
978 VALID_GUI_KEYWORDS (button);
981 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
982 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
983 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
984 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
985 VALID_WIDGET_KEYWORDS (edit_field);
986 VALID_GUI_KEYWORDS (edit_field);
989 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
990 IIFORMAT_HAS_METHOD (combo_box, validate);
991 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
992 VALID_GUI_KEYWORDS (combo_box);
994 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
995 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
996 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int);
997 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
998 IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list);
1001 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
1002 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
1003 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
1004 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
1005 VALID_GUI_KEYWORDS (scrollbar);
1007 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int);
1008 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int);
1009 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
1011 /* progress guage */
1012 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
1013 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
1014 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
1015 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
1016 VALID_WIDGET_KEYWORDS (progress_gauge);
1017 VALID_GUI_KEYWORDS (progress_gauge);
1020 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
1021 IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
1022 IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
1023 IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget);
1024 IIFORMAT_HAS_METHOD (tree_view, query_geometry);
1025 VALID_WIDGET_KEYWORDS (tree_view);
1026 VALID_GUI_KEYWORDS (tree_view);
1027 IIFORMAT_VALID_KEYWORD (tree_view, Q_properties, check_valid_item_list);
1030 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
1031 IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
1032 IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
1033 IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget);
1034 IIFORMAT_HAS_METHOD (tab_control, query_geometry);
1035 VALID_WIDGET_KEYWORDS (tab_control);
1036 VALID_GUI_KEYWORDS (tab_control);
1037 IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation, check_valid_tab_orientation);
1038 IIFORMAT_VALID_KEYWORD (tab_control, Q_properties, check_valid_item_list);
1041 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
1042 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
1043 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
1044 VALID_WIDGET_KEYWORDS (label);
1045 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
1048 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
1049 IIFORMAT_HAS_METHOD (layout, possible_dest_types);
1050 IIFORMAT_HAS_METHOD (layout, instantiate);
1051 IIFORMAT_HAS_METHOD (layout, normalize);
1052 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_width, check_valid_int);
1053 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_height, check_valid_int);
1054 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation);
1055 IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification);
1056 IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border);
1057 IIFORMAT_VALID_KEYWORD (layout, Q_items,
1058 check_valid_glyph_or_instantiator_list);
1062 reinit_vars_of_glyphs_widget (void)
1064 #ifdef DEBUG_WIDGETS
1065 debug_widget_instances = 0;
1070 vars_of_glyphs_widget (void)
1072 reinit_vars_of_glyphs_widget ();