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_int_or_function (Lisp_Object data)
154 if (!INTP (data) && !CONSP (data))
155 signal_simple_error ("must be an integer or expresssion", data);
159 check_valid_symbol (Lisp_Object data)
165 check_valid_string_or_vector (Lisp_Object data)
167 if (!STRINGP (data) && !VECTORP (data))
168 signal_simple_error (":descriptor must be a string or a vector", data);
172 check_valid_item_list_1 (Lisp_Object items)
177 EXTERNAL_LIST_LOOP (rest, items)
179 if (STRINGP (XCAR (rest)))
180 CHECK_STRING (XCAR (rest));
181 else if (VECTORP (XCAR (rest)))
182 gui_parse_item_keywords (XCAR (rest));
183 else if (LISTP (XCAR (rest)))
184 check_valid_item_list_1 (XCAR (rest));
186 signal_simple_error ("Items must be vectors, lists or strings", items);
191 check_valid_item_list (Lisp_Object data)
195 Fcheck_valid_plist (data);
196 items = Fplist_get (data, Q_items, Qnil);
198 check_valid_item_list_1 (items);
202 check_valid_glyph_or_instantiator_list (Lisp_Object data)
207 EXTERNAL_LIST_LOOP (rest, data)
209 check_valid_glyph_or_instantiator (XCAR (rest));
214 glyph_instantiator_to_glyph (Lisp_Object sym)
216 /* This function calls lisp. */
217 Lisp_Object glyph = sym;
221 /* if we have a symbol get at the actual data */
223 glyph = XSYMBOL (glyph)->value;
226 glyph = Feval (glyph);
228 /* Be really helpful to the user. */
231 glyph = call1 (intern ("make-glyph"), glyph);
234 /* substitute the new glyph */
235 RETURN_UNGCPRO (glyph);
239 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
242 /* substitute the new glyph */
243 for (i = 0; i < XVECTOR_LENGTH (inst); i++)
245 if (EQ (key, XVECTOR_DATA (inst)[i]))
247 XVECTOR_DATA (inst)[i+1] = val;
253 /* Wire widget property invocations to specific widgets. The problem
254 we are solving here is that when instantiators get converted to
255 instances they lose some type information (they just become
256 subwindows or widgets for example). For widgets we need to preserve
257 this type information so that we can do widget specific operations
258 on the instances. This is encoded in the widget type
259 field. widget_property gets invoked by decoding the primary type
260 (Qwidget), <widget>_property then invokes based on the secondary
261 type (Qedit_field for example). It is debatable whether we should
262 wire things in this generalised way rather than treating widgets
263 specially in image_instance_property. */
265 widget_property (Lisp_Object image_instance, Lisp_Object prop)
267 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
268 struct image_instantiator_methods* meths;
270 /* first see if its a general property ... */
271 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
272 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
274 /* .. then try device specific methods ... */
275 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
276 IMAGE_INSTANCE_WIDGET_TYPE (ii),
278 if (meths && HAS_IIFORMAT_METH_P (meths, property))
279 return IIFORMAT_METH (meths, property, (image_instance, prop));
280 /* ... then format specific methods ... */
281 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
283 if (meths && HAS_IIFORMAT_METH_P (meths, property))
284 return IIFORMAT_METH (meths, property, (image_instance, prop));
290 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val)
292 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
293 struct image_instantiator_methods* meths;
296 /* PIck up any generic properties that we might need to keep hold
298 if (EQ (prop, Q_text))
300 IMAGE_INSTANCE_WIDGET_TEXT (ii) = val;
301 IMAGE_INSTANCE_TEXT_CHANGED (ii) = 1;
304 /* Now try device specific methods first ... */
305 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
306 IMAGE_INSTANCE_WIDGET_TYPE (ii),
308 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
311 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
315 /* ... then format specific methods ... */
316 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
318 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
321 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
325 /* we didn't do any device specific properties, so shove the property in our plist */
326 IMAGE_INSTANCE_WIDGET_PROPS (ii)
327 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
331 /* Like the rest of redisplay, we want widget updates to occur
332 asynchronously. Thus toolkit specific methods for setting properties
333 must be called by redisplay instead of by *_set_property. Thus
334 *_set_property records the change and this function actually
335 implements it. We want to be slightly clever about this however by
336 supplying format specific functions for the updates instead of lumping
337 them all into this function. Note that there is no need for format
338 generic functions. */
340 update_widget (Lisp_Object widget)
342 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (widget);
343 struct image_instantiator_methods* meths;
345 if (IMAGE_INSTANCE_TYPE (ii) != IMAGE_WIDGET)
348 /* Device generic methods. We must update the widget's size as it
349 may have been changed by the the layout routines. We also do this
350 here so that explicit resizing from lisp does not result in
351 synchronous updates. */
352 MAYBE_DEVMETH (XDEVICE (ii->device), update_widget, (ii));
354 /* Device-format specific methods */
355 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
356 IMAGE_INSTANCE_WIDGET_TYPE (ii),
358 MAYBE_IIFORMAT_METH (meths, update, (widget));
361 /* Query for a widgets desired geometry. If no type specific method is
362 provided then use the widget text to calculate sizes. */
364 widget_query_geometry (Lisp_Object image_instance,
365 unsigned int* width, unsigned int* height,
366 enum image_instance_geometry disp, Lisp_Object domain)
368 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
369 struct image_instantiator_methods* meths;
370 Lisp_Object dynamic_width = Qnil;
371 Lisp_Object dynamic_height = Qnil;
373 /* First just set up what we already have. */
374 if (width) *width = IMAGE_INSTANCE_WIDTH (ii);
375 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii);
377 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)
379 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
381 /* .. then try device specific methods ... */
382 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
383 IMAGE_INSTANCE_WIDGET_TYPE (ii),
385 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
386 IIFORMAT_METH (meths, query_geometry, (image_instance,
391 /* ... then format specific methods ... */
392 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
394 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry))
395 IIFORMAT_METH (meths, query_geometry, (image_instance,
402 /* Then if we are allowed to resize the widget, make the
403 size the same as the text dimensions. */
404 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
405 IMAGE_INSTANCE_WIDGET_FACE (ii),
407 /* Adjust the size for borders. */
408 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii))
409 *width = w + 2 * WIDGET_BORDER_WIDTH;
410 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii))
411 *height = h + 2 * WIDGET_BORDER_HEIGHT;
414 /* Finish off with dynamic sizing. */
415 if (!NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)))
417 dynamic_width = Feval (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii));
418 if (INTP (dynamic_width))
419 *width = XINT (dynamic_width);
421 if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)))
423 dynamic_height = Feval (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii));
424 if (INTP (dynamic_height))
425 *height = XINT (dynamic_height);
431 widget_layout (Lisp_Object image_instance,
432 unsigned int width, unsigned int height, Lisp_Object domain)
434 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
435 struct image_instantiator_methods* meths;
437 /* .. then try device specific methods ... */
438 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
439 IMAGE_INSTANCE_WIDGET_TYPE (ii),
441 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
442 IIFORMAT_METH (meths, layout, (image_instance,
443 width, height, domain));
446 /* ... then format specific methods ... */
447 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
449 if (meths && HAS_IIFORMAT_METH_P (meths, layout))
450 IIFORMAT_METH (meths, layout, (image_instance,
451 width, height, domain));
456 widget_validate (Lisp_Object instantiator)
458 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
461 signal_simple_error ("Must supply :descriptor", instantiator);
464 gui_parse_item_keywords (desc);
466 if (!NILP (find_keyword_in_vector (instantiator, Q_width))
467 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
468 signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
470 if (!NILP (find_keyword_in_vector (instantiator, Q_height))
471 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
472 signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
476 combo_box_validate (Lisp_Object instantiator)
478 widget_validate (instantiator);
479 if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
480 signal_simple_error ("Must supply item list", instantiator);
483 /* we need to convert things like glyphs to images, eval expressions
486 widget_normalize (Lisp_Object inst, Lisp_Object console_type)
488 /* This function can call lisp */
489 Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
491 /* we need to eval glyph if its an expression, we do this for the
492 same reasons we normalize file to data. */
495 substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
502 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type)
504 /* initialize_subwindow_image_instance (ii);*/
505 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
506 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
507 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil);
508 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item ();
509 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil;
510 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = Qnil;
511 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = Qnil;
512 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 1;
513 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 1;
514 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 0;
515 IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii) = 0;
518 /* Instantiate a button widget. Unfortunately instantiated widgets are
519 particular to a frame since they need to have a parent. It's not
520 like images where you just select the image into the context you
521 want to display it in and BitBlt it. So image instances can have a
522 many-to-one relationship with things you see, whereas widgets can
523 only be one-to-one (i.e. per frame) */
525 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
526 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
527 int dest_mask, Lisp_Object domain)
529 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
530 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
531 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
532 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
533 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
534 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
535 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
536 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
537 Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties);
538 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
539 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
540 int pw=0, ph=0, tw=0, th=0;
542 /* this just does pixel type sizing */
543 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
546 if (!(dest_mask & (IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK)))
547 incompatible_image_types (instantiator, dest_mask,
548 IMAGE_WIDGET_MASK | IMAGE_LAYOUT_MASK);
550 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
552 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET;
553 IMAGE_INSTANCE_WIDGET_PROPS (ii) = props;
555 /* retrieve the fg and bg colors */
557 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face));
559 /* Do layout specific initialisation. This feels a bit tacky, but
560 the alternative is a myriad of different little functions. */
561 if (EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
563 Lisp_Object rest, children = Qnil;
564 Lisp_Object border = find_keyword_in_vector (instantiator, Q_border);
568 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL;
570 IMAGE_INSTANCE_TYPE (ii) = IMAGE_LAYOUT;
574 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in;
576 else if (GLYPHP (border))
578 /* We are going to be sneaky here and add the border text as
579 just another child, the layout and output routines don't know
580 this and will just display at the offsets we prescribe. */
581 Lisp_Object gii = glyph_image_instance (border, domain, ERROR_ME, 1);
582 /* make sure we are designated as the parent. */
583 XIMAGE_INSTANCE_PARENT (gii) = image_instance;
584 children = Fcons (gii, children);
585 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (0);
589 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border;
592 /* Pick up the sub-widgets. */
593 LIST_LOOP (rest, items)
595 /* make sure the image is instantiated */
596 Lisp_Object gii = glyph_image_instance (XCAR (rest), domain, ERROR_ME, 1);
597 /* make sure we are designated as the parent. */
598 XIMAGE_INSTANCE_PARENT (gii) = image_instance;
599 children = Fcons (gii, children);
600 /* Make sure elements in the layout are in the order the
602 children = Fnreverse (children);
604 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children;
606 /* retrieve the gui item information. This is easy if we have been
607 provided with a vector, more difficult if we have just been given
609 else if (STRINGP (desc) || NILP (desc))
611 /* big cheat - we rely on the fact that a gui item looks like an instantiator */
612 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
613 gui_parse_item_keywords_no_errors (instantiator);
614 IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
617 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
618 gui_parse_item_keywords_no_errors (desc);
620 /* Pick up the orientation before we do our first layout. */
621 if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical))
622 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = 1;
624 /* parse more gui items out of the properties */
626 && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout))
630 items = Fplist_get (props, Q_items, Qnil);
634 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
635 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
636 parse_gui_item_tree_children (items));
640 /* Normalize size information. We now only assign sizes if the user
641 gives us some explicitly, or there are some constraints that we
642 can't change later on. Otherwise we postpone sizing until query
643 geometry gets called. */
644 if (!NILP (pixwidth)) /* pixwidth takes precendent */
646 if (!INTP (pixwidth))
647 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = pixwidth;
650 pw = XINT (pixwidth);
651 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
654 else if (!NILP (width))
657 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
660 if (!NILP (pixheight))
662 if (!INTP (pixwidth))
663 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = pixheight;
666 ph = XINT (pixheight);
667 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
670 else if (!NILP (height) && XINT (height) > 1)
673 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
676 /* Taking the default face information when the user has specified
677 size in characters is probably as good as any since the widget
678 face is more likely to be proportional and thus give inadequate
679 results. Using character sizes can only ever be approximate
683 int charwidth, charheight;
684 default_face_font_info (domain, 0, 0, &charheight, &charwidth, 0);
688 ph = charheight * th;
691 /* for a widget with an image pick up the dimensions from that */
695 pw = glyph_width (glyph, domain) + 2 * WIDGET_BORDER_WIDTH;
697 ph = glyph_height (glyph, domain) + 2 * WIDGET_BORDER_HEIGHT;
698 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0;
699 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0;
702 /* When we create the widgets the window system expects a valid
703 size, so If we still don' t have sizes, call layout to pick them
704 up. If query_geometry or layout relies on the widget being in
705 existence then we are in catch 22. */
706 image_instance_layout (image_instance,
707 pw ? pw : IMAGE_UNSPECIFIED_GEOMETRY,
708 ph ? ph : IMAGE_UNSPECIFIED_GEOMETRY,
712 debug_widget_instances++;
713 stderr_out ("instantiated ");
714 debug_print (instantiator);
715 stderr_out ("%d widgets instantiated\n", debug_widget_instances);
719 /* tree-view geometry - get the height right */
721 tree_view_query_geometry (Lisp_Object image_instance,
722 unsigned int* width, unsigned int* height,
723 enum image_instance_geometry disp, Lisp_Object domain)
725 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
726 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii);
731 /* #### what should this be. reconsider when X has tree views. */
732 query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii),
733 IMAGE_INSTANCE_WIDGET_FACE (ii),
734 width, 0, 0, domain);
739 default_face_font_info (domain, 0, 0, &h, 0, 0);
740 GET_LIST_LENGTH (items, len);
745 /* Get the geometry of a tab control. This is based on the number of
746 items and text therin in the tab control. */
748 tab_control_query_geometry (Lisp_Object image_instance,
749 unsigned int* width, unsigned int* height,
750 enum image_instance_geometry disp, Lisp_Object domain)
752 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
753 Lisp_Object items = XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii));
755 unsigned int tw = 0, th = 0;
757 LIST_LOOP (rest, items)
761 query_string_geometry (XGUI_ITEM (XCAR (rest))->name,
762 IMAGE_INSTANCE_WIDGET_FACE (ii),
764 tw += 5 * WIDGET_BORDER_WIDTH; /* some bias */
766 th = max (th, h + 2 * WIDGET_BORDER_HEIGHT);
769 /* Fixup returned values depending on orientation. */
770 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii))
772 if (height) *height = tw;
773 if (width) *width = th;
777 if (height) *height = th;
778 if (width) *width = tw;
782 /* Get the geometry of a tab control. This is based on the number of
783 items and text therin in the tab control. */
785 tab_control_set_property (Lisp_Object image_instance,
789 /* Record new items for update. *_tab_control_update will do the
791 if (EQ (prop, Q_items))
793 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
795 check_valid_item_list_1 (val);
797 /* Don't set the actual items since we might decide not to use
798 the new ones (because nothing has really changed). If we did
799 set them and didn't use them then we would get into whole
800 heaps of trouble when the old items get GC'd. */
801 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) =
802 Fcons (XCAR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)),
803 parse_gui_item_tree_children (val));
804 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1;
811 /* set the properties of a progres guage */
813 progress_gauge_set_property (Lisp_Object image_instance,
817 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
819 if (EQ (prop, Q_percent))
822 IMAGE_INSTANCE_WIDGET_PROPS (ii)
823 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
824 IMAGE_INSTANCE_WIDGET_PERCENT_CHANGED (ii) = 1;
832 /*****************************************************************************
834 *****************************************************************************/
836 layout_possible_dest_types (void)
838 return IMAGE_LAYOUT_MASK;
841 /* we need to convert things like glyphs to images, eval expressions
844 layout_normalize (Lisp_Object inst, Lisp_Object console_type)
846 /* This function can call lisp */
847 Lisp_Object items = find_keyword_in_vector (inst, Q_items);
848 Lisp_Object border = find_keyword_in_vector (inst, Q_border);
849 /* we need to eval glyph if its an expression, we do this for the
850 same reasons we normalize file to data. */
854 LIST_LOOP (rest, items)
856 /* substitute the new glyph */
857 Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest)));
860 /* normalize the border spec. */
861 if (VECTORP (border) || CONSP (border))
863 substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border));
868 /* Layout widget. Sizing commentary: we have a number of problems that
869 we would like to address. Some consider some of these more
870 important than others. It used to be that size information was
871 determined at instantiation time and was then fixed forever
872 after. Generally this is not what we want. Users want size to be
873 "big enough" to accommodate whatever they are trying to show and
874 this is dependent on text length, lines, font metrics etc. Of
875 course these attributes can change dynamically and so the size
876 should changed dynamically also. Only in a few limited cases should
877 the size be fixed and remain fixed. Of course this actually means
878 that we don't really want to specifiy the size *at all* for most
879 widgets - we want it to be discovered dynamically. Thus we can
880 envisage the following scenarios:
882 1. A button is sized to accommodate its text, the text changes and the
883 button should change size also.
885 2. A button is given an explicit size. Its size should never change.
887 3. Layout is put inside an area. The size of the area changes, the
888 layout should change with it.
890 4. A button grows to accommodate additional text. The whitespace
891 around it should be modified to cope with the new layout
894 5. A button grows. The area surrounding it should grow also if
897 What metrics are important?
898 1. Actual width and height.
900 2. Whether the width and height are what the widget actually wants, or
901 whether it can grow or shrink.
903 Text glyphs are particularly troublesome since their metrics depend
904 on the context in which they are being viewed. For instance they
905 can appear differently depending on the window face, frame face or
906 glyph face. In order to simplify this text glyphs can now only have
907 a glyph-face or image-instance face. All other glyphs are
908 essentially fixed in appearance. Perhaps the problem is that text
909 glyphs are cached on a device basis like most other glyphs. Instead
910 they should be cached per-window and then the instance would be
911 fixed and we wouldn't have to mess around with font metrics and the
914 /* Query the geometry of a layout widget. We assume that we can only
915 get here if the size is not already fixed. */
917 layout_query_geometry (Lisp_Object image_instance, unsigned int* width,
918 unsigned int* height, enum image_instance_geometry disp,
921 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
922 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii), rest;
923 int maxph = 0, maxpw = 0, nitems = 0, ph_adjust = 0;
925 /* Flip through the items to work out how much stuff we have to display */
926 LIST_LOOP (rest, items)
928 Lisp_Object glyph = XCAR (rest);
929 unsigned int gheight, gwidth;
931 image_instance_query_geometry (glyph, &gwidth, &gheight, disp, domain);
933 /* Pick up the border text if we have one. */
934 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
935 && NILP (XCDR (rest)))
937 ph_adjust = gheight / 2;
943 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
944 == LAYOUT_HORIZONTAL)
946 maxph = max (maxph, gheight);
951 maxpw = max (maxpw, gwidth);
957 /* work out spacing between items and bounds of the layout. No user
958 provided width so we just do default spacing. */
959 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
960 == LAYOUT_HORIZONTAL)
961 *width = maxpw + (nitems + 1) * WIDGET_BORDER_WIDTH * 2;
963 *width = maxpw + 2 * WIDGET_BORDER_WIDTH * 2;
965 /* Work out vertical spacings. */
966 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
968 *height = maxph + (nitems + 1) * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
970 *height = maxph + 2 * WIDGET_BORDER_HEIGHT * 2 + ph_adjust;
975 layout_layout (Lisp_Object image_instance,
976 unsigned int width, unsigned int height, Lisp_Object domain)
978 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
980 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii);
981 int x, y, maxph = 0, maxpw = 0, nitems = 0,
982 horiz_spacing, vert_spacing, ph_adjust = 0;
983 unsigned int gheight, gwidth;
985 /* flip through the items to work out how much stuff we have to display */
986 LIST_LOOP (rest, items)
988 Lisp_Object glyph = XCAR (rest);
990 image_instance_query_geometry (glyph, &gwidth, &gheight,
991 IMAGE_DESIRED_GEOMETRY, domain);
993 /* Pick up the border text if we have one. */
994 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
995 && NILP (XCDR (rest)))
997 XIMAGE_INSTANCE_XOFFSET (glyph) = 10; /* Really, what should this be? */
998 XIMAGE_INSTANCE_YOFFSET (glyph) = 0;
999 ph_adjust = gheight / 2;
1000 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (ph_adjust);
1005 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1006 == LAYOUT_HORIZONTAL)
1008 maxph = max (maxph, gheight);
1013 maxpw = max (maxpw, gwidth);
1019 /* work out spacing between items and bounds of the layout */
1021 /* The user wants a smaller space than the largest item, so we
1022 just provide default spacing and will let the output routines
1024 horiz_spacing = WIDGET_BORDER_WIDTH * 2;
1025 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1026 == LAYOUT_HORIZONTAL)
1027 /* We have a larger area to display in so distribute the space
1029 horiz_spacing = (width - maxpw) / (nitems + 1);
1031 horiz_spacing = (width - maxpw) / 2;
1034 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
1035 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1037 vert_spacing = (height - (maxph + ph_adjust)) / (nitems + 1);
1039 vert_spacing = (height - (maxph + ph_adjust)) / 2;
1041 y = vert_spacing + ph_adjust;
1044 /* Now flip through putting items where we want them, paying
1045 attention to justification. Make sure we don't mess with the
1047 LIST_LOOP (rest, items)
1049 Lisp_Object glyph = XCAR (rest);
1051 image_instance_query_geometry (glyph, &gwidth, &gheight,
1052 IMAGE_DESIRED_GEOMETRY, domain);
1054 if (!INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))
1055 || !NILP (XCDR (rest)))
1057 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1058 == LAYOUT_HORIZONTAL)
1060 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1061 == LAYOUT_JUSTIFY_RIGHT)
1062 y = height - (gheight + vert_spacing);
1063 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1064 == LAYOUT_JUSTIFY_CENTER)
1065 y = (height - gheight) / 2;
1069 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1070 == LAYOUT_JUSTIFY_RIGHT)
1071 x = width - (gwidth + horiz_spacing);
1072 if (IMAGE_INSTANCE_SUBWINDOW_JUSTIFY (ii)
1073 == LAYOUT_JUSTIFY_CENTER)
1074 x = (width - gwidth) / 2;
1077 XIMAGE_INSTANCE_XOFFSET (glyph) = x;
1078 XIMAGE_INSTANCE_YOFFSET (glyph) = y;
1080 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)
1081 == LAYOUT_HORIZONTAL)
1083 x += (gwidth + horiz_spacing);
1087 y += (gheight + vert_spacing);
1091 /* Now layout subwidgets if they require it. */
1092 image_instance_layout (glyph, gwidth, gheight, domain);
1097 /************************************************************************/
1098 /* initialization */
1099 /************************************************************************/
1102 syms_of_glyphs_widget (void)
1104 defkeyword (&Q_descriptor, ":descriptor");
1105 defkeyword (&Q_height, ":height");
1106 defkeyword (&Q_width, ":width");
1107 defkeyword (&Q_properties, ":properties");
1108 defkeyword (&Q_items, ":items");
1109 defkeyword (&Q_image, ":image");
1110 defkeyword (&Q_percent, ":percent");
1111 defkeyword (&Q_text, ":text");
1112 defkeyword (&Q_orientation, ":orientation");
1113 defkeyword (&Q_justify, ":justify");
1114 defkeyword (&Q_border, ":border");
1116 defsymbol (&Qetched_in, "etched-in");
1117 defsymbol (&Qetched_out, "etched-out");
1118 defsymbol (&Qbevel_in, "bevel-in");
1119 defsymbol (&Qbevel_out, "bevel-out");
1122 #define VALID_GUI_KEYWORDS(type) do { \
1123 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything); \
1124 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \
1125 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \
1126 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \
1127 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything); \
1128 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \
1129 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \
1130 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \
1131 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \
1132 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \
1133 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \
1134 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback); \
1135 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor, check_valid_string_or_vector); \
1138 #define VALID_WIDGET_KEYWORDS(type) do { \
1139 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \
1140 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \
1141 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int_or_function);\
1142 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int_or_function);\
1143 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face); \
1147 static void image_instantiator_widget (void)
1148 { /* we only do this for properties */
1149 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
1150 IIFORMAT_HAS_METHOD (widget, property);
1151 IIFORMAT_HAS_METHOD (widget, set_property);
1152 IIFORMAT_HAS_METHOD (widget, query_geometry);
1153 IIFORMAT_HAS_METHOD (widget, layout);
1156 static void image_instantiator_buttons (void)
1158 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
1159 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
1160 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
1161 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
1162 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
1163 IIFORMAT_VALID_KEYWORD (button,
1164 Q_image, check_valid_glyph_or_instantiator);
1165 VALID_WIDGET_KEYWORDS (button);
1166 VALID_GUI_KEYWORDS (button);
1169 static void image_instantiator_edit_fields (void)
1171 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
1172 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
1173 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
1174 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
1175 VALID_WIDGET_KEYWORDS (edit_field);
1176 VALID_GUI_KEYWORDS (edit_field);
1179 static void image_instantiator_combo_box (void)
1181 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
1182 IIFORMAT_HAS_METHOD (combo_box, validate);
1183 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
1184 VALID_GUI_KEYWORDS (combo_box);
1186 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
1187 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
1188 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int_or_function);
1189 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
1190 IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list);
1193 static void image_instantiator_scrollbar (void)
1195 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
1196 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
1197 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
1198 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
1199 VALID_GUI_KEYWORDS (scrollbar);
1201 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int_or_function);
1202 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int_or_function);
1203 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
1206 static void image_instantiator_progress_guage (void)
1208 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
1209 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
1210 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
1211 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
1212 IIFORMAT_HAS_METHOD (progress_gauge, set_property);
1213 VALID_WIDGET_KEYWORDS (progress_gauge);
1214 VALID_GUI_KEYWORDS (progress_gauge);
1217 static void image_instantiator_tree_view (void)
1219 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
1220 IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
1221 IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
1222 IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget);
1223 IIFORMAT_HAS_METHOD (tree_view, query_geometry);
1224 VALID_WIDGET_KEYWORDS (tree_view);
1225 VALID_GUI_KEYWORDS (tree_view);
1226 IIFORMAT_VALID_KEYWORD (tree_view, Q_properties, check_valid_item_list);
1229 static void image_instantiator_tab_control (void)
1231 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
1232 IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
1233 IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
1234 IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget);
1235 IIFORMAT_HAS_METHOD (tab_control, query_geometry);
1236 IIFORMAT_HAS_METHOD (tab_control, set_property);
1237 VALID_WIDGET_KEYWORDS (tab_control);
1238 VALID_GUI_KEYWORDS (tab_control);
1239 IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation, check_valid_tab_orientation);
1240 IIFORMAT_VALID_KEYWORD (tab_control, Q_properties, check_valid_item_list);
1243 static void image_instantiator_labels (void)
1245 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
1246 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
1247 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget);
1248 VALID_WIDGET_KEYWORDS (label);
1249 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
1252 static void image_instantiator_layout (void)
1254 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
1255 IIFORMAT_HAS_METHOD (layout, possible_dest_types);
1256 IIFORMAT_HAS_SHARED_METHOD (layout, instantiate, widget);
1257 IIFORMAT_HAS_METHOD (layout, normalize);
1258 IIFORMAT_HAS_METHOD (layout, query_geometry);
1259 IIFORMAT_HAS_METHOD (layout, layout);
1260 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_width, check_valid_int_or_function);
1261 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_height, check_valid_int_or_function);
1262 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation);
1263 IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification);
1264 IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border);
1265 IIFORMAT_VALID_KEYWORD (layout, Q_items,
1266 check_valid_glyph_or_instantiator_list);
1270 image_instantiator_format_create_glyphs_widget (void)
1272 image_instantiator_widget();
1273 image_instantiator_buttons();
1274 image_instantiator_edit_fields();
1275 image_instantiator_combo_box();
1276 image_instantiator_scrollbar();
1277 image_instantiator_progress_guage();
1278 image_instantiator_tree_view();
1279 image_instantiator_tab_control();
1280 image_instantiator_labels();
1281 image_instantiator_layout();
1285 reinit_vars_of_glyphs_widget (void)
1287 #ifdef DEBUG_WIDGETS
1288 debug_widget_instances = 0;
1293 vars_of_glyphs_widget (void)
1295 reinit_vars_of_glyphs_widget ();