Mercurial > hg > xemacs-beta
diff src/glyphs-widget.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 9d177e8d4150 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/glyphs-widget.c Mon Aug 13 11:28:15 2007 +0200 @@ -0,0 +1,925 @@ +/* Widget-specific glyph objects. + Copyright (C) 1998, 1999 Andy Piper. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* written by Andy Piper <andy@xemacs.org> */ + +#include <config.h> +#include "lisp.h" +#include "lstream.h" +#include "console.h" +#include "device.h" +#include "faces.h" +#include "glyphs.h" +#include "objects.h" +#include "bytecode.h" +#include "window.h" +#include "buffer.h" +#include "frame.h" +#include "insdel.h" +#include "opaque.h" + +DEFINE_IMAGE_INSTANTIATOR_FORMAT (button); +DEFINE_IMAGE_INSTANTIATOR_FORMAT (combo_box); +Lisp_Object Qcombo_box; +DEFINE_IMAGE_INSTANTIATOR_FORMAT (edit_field); +Lisp_Object Qedit_field; +DEFINE_IMAGE_INSTANTIATOR_FORMAT (scrollbar); +Lisp_Object Qscrollbar; +DEFINE_IMAGE_INSTANTIATOR_FORMAT (widget); +DEFINE_IMAGE_INSTANTIATOR_FORMAT (label); +Lisp_Object Qlabel; +DEFINE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge); +Lisp_Object Qprogress_gauge; +DEFINE_IMAGE_INSTANTIATOR_FORMAT (tree_view); +Lisp_Object Qtree_view; +DEFINE_IMAGE_INSTANTIATOR_FORMAT (tab_control); +Lisp_Object Qtab_control; +DEFINE_IMAGE_INSTANTIATOR_FORMAT (layout); +Lisp_Object Qlayout; + +Lisp_Object Q_descriptor, Q_height, Q_width, Q_properties, Q_items; +Lisp_Object Q_image, Q_text, Q_percent, Q_orientation, Q_justify, Q_border; +Lisp_Object Qetched_in, Qetched_out, Qbevel_in, Qbevel_out; + +#define WIDGET_BORDER_HEIGHT 4 +#define WIDGET_BORDER_WIDTH 4 + +#ifdef DEBUG_WIDGETS +int debug_widget_instances; +#endif + +/* TODO: + - more complex controls. + - tooltips for controls. + */ + +/* In windows normal windows work in pixels, dialog boxes work in + dialog box units. Why? sigh. We could reuse the metrics for dialogs + if this were not the case. As it is we have to position things + pixel wise. I'm not even sure that X has this problem at least for + buttons in groups. */ +Lisp_Object +widget_face_font_info (Lisp_Object domain, Lisp_Object face, + int *height, int *width) +{ + Lisp_Object font_instance = FACE_FONT (face, domain, Vcharset_ascii); + + if (height) + *height = XFONT_INSTANCE (font_instance)->height; + if (width) + *width = XFONT_INSTANCE (font_instance)->width; + + return font_instance; +} + +void +widget_text_to_pixel_conversion (Lisp_Object domain, Lisp_Object face, + int th, int tw, + int* height, int* width) +{ + int ch=0, cw=0; + widget_face_font_info (domain, face, &ch, &cw); + if (height) + *height = th * ch + 2 * WIDGET_BORDER_HEIGHT; + if (width) + *width = tw * cw + 2 * WIDGET_BORDER_WIDTH; +} + +static int +widget_possible_dest_types (void) +{ + return IMAGE_WIDGET_MASK; +} + +static void +check_valid_glyph_or_instantiator (Lisp_Object data) +{ + Lisp_Object glyph = data; + if (SYMBOLP (data)) + glyph = XSYMBOL (data)->value; + + if (IMAGE_INSTANCEP (glyph)) + CHECK_IMAGE_INSTANCE (glyph); + else if (!CONSP (glyph) && !VECTORP (glyph)) + CHECK_BUFFER_GLYPH (glyph); +} + +static void +check_valid_orientation (Lisp_Object data) +{ + if (!EQ (data, Qhorizontal) + && + !EQ (data, Qvertical)) + signal_simple_error ("unknown orientation for layout", data); +} + +static void +check_valid_justification (Lisp_Object data) +{ + if (!EQ (data, Qleft) && !EQ (data, Qright) && !EQ (data, Qcenter)) + signal_simple_error ("unknown justification for layout", data); +} + +static void +check_valid_border (Lisp_Object data) +{ + if (!EQ (data, Qt) && !EQ (data, Qetched_in) && !EQ (data, Qetched_out) + && !EQ (data, Qbevel_in) && !EQ (data, Qbevel_out) + && !GLYPHP (data) && !VECTORP (data)) + signal_simple_error ("unknown border style for layout", data); +} + +static void +check_valid_anything (Lisp_Object data) +{ +} + +static void +check_valid_callback (Lisp_Object data) +{ + if (!SYMBOLP (data) + && !COMPILED_FUNCTIONP (data) + && !CONSP (data)) + { + signal_simple_error (":callback must be a function or expression", data); + } +} + +static void +check_valid_symbol (Lisp_Object data) +{ + CHECK_SYMBOL (data); +} + +static void +check_valid_string_or_vector (Lisp_Object data) +{ + if (!STRINGP (data) && !VECTORP (data)) + signal_simple_error (":descriptor must be a string or a vector", data); +} + +void +check_valid_item_list_1 (Lisp_Object items) +{ + Lisp_Object rest; + + CHECK_LIST (items); + EXTERNAL_LIST_LOOP (rest, items) + { + if (STRINGP (XCAR (rest))) + CHECK_STRING (XCAR (rest)); + else if (VECTORP (XCAR (rest))) + gui_parse_item_keywords (XCAR (rest)); + else if (LISTP (XCAR (rest))) + check_valid_item_list_1 (XCAR (rest)); + else + signal_simple_error ("Items must be vectors, lists or strings", items); + } +} + +static void +check_valid_item_list (Lisp_Object data) +{ + Lisp_Object items; + + Fcheck_valid_plist (data); + items = Fplist_get (data, Q_items, Qnil); + + check_valid_item_list_1 (items); +} + +static void +check_valid_glyph_or_instantiator_list (Lisp_Object data) +{ + Lisp_Object rest; + + CHECK_LIST (data); + EXTERNAL_LIST_LOOP (rest, data) + { + check_valid_glyph_or_instantiator (XCAR (rest)); + } +} + +static Lisp_Object +glyph_instantiator_to_glyph (Lisp_Object sym) +{ + /* This function calls lisp. */ + Lisp_Object glyph = sym; + struct gcpro gcpro1; + + GCPRO1 (glyph); + /* if we have a symbol get at the actual data */ + if (SYMBOLP (glyph)) + glyph = XSYMBOL (glyph)->value; + + if (CONSP (glyph)) + glyph = Feval (glyph); + + /* Be really helpful to the user. */ + if (VECTORP (glyph)) + { + glyph = call1 (intern ("make-glyph"), glyph); + } + + /* substitute the new glyph */ + RETURN_UNGCPRO (glyph); +} + +static void +substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val) +{ + int i; + /* substitute the new glyph */ + for (i = 0; i < XVECTOR_LENGTH (inst); i++) + { + if (EQ (key, XVECTOR_DATA (inst)[i])) + { + XVECTOR_DATA (inst)[i+1] = val; + break; + } + } +} + +/* wire widget property invocations to specific widgets ... The + problem we are solving here is that when instantiators get converted + to instances they lose some type information (they just become + subwindows or widgets for example). For widgets we need to preserve + this type information so that we can do widget specific operations on + the instances. This is encoded in the widget type + field. widget_property gets invoked by decoding the primary type + (Qwidget), widget property then invokes based on the secondary type + (Qedit_field for example). It is debatable that we should wire things in this + generalised way rather than treating widgets specially in + image_instance_property. */ +static Lisp_Object +widget_property (Lisp_Object image_instance, Lisp_Object prop) +{ + struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); + struct image_instantiator_methods* meths; + + /* first see if its a general property ... */ + if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop))) + return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil); + + /* .. then try device specific methods ... */ + meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii), + IMAGE_INSTANCE_WIDGET_TYPE (ii), + ERROR_ME_NOT); + if (meths && HAS_IIFORMAT_METH_P (meths, property)) + return IIFORMAT_METH (meths, property, (image_instance, prop)); + /* ... then format specific methods ... */ + meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), + ERROR_ME_NOT); + if (meths && HAS_IIFORMAT_METH_P (meths, property)) + return IIFORMAT_METH (meths, property, (image_instance, prop)); + /* ... then fail */ + return Qunbound; +} + +static Lisp_Object +widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val) +{ + struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); + struct image_instantiator_methods* meths; + Lisp_Object ret; + + /* try device specific methods first ... */ + meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii), + IMAGE_INSTANCE_WIDGET_TYPE (ii), + ERROR_ME_NOT); + if (meths && HAS_IIFORMAT_METH_P (meths, set_property) + && + !UNBOUNDP (ret = + IIFORMAT_METH (meths, set_property, (image_instance, prop, val)))) + { + return ret; + } + /* ... then format specific methods ... */ + meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), + ERROR_ME_NOT); + if (meths && HAS_IIFORMAT_METH_P (meths, set_property) + && + !UNBOUNDP (ret = + IIFORMAT_METH (meths, set_property, (image_instance, prop, val)))) + { + return ret; + } + /* we didn't do any device specific properties, so shove the property in our plist */ + IMAGE_INSTANCE_WIDGET_PROPS (ii) + = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val); + return val; +} + +static void +widget_validate (Lisp_Object instantiator) +{ + Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); + + if (NILP (desc)) + signal_simple_error ("Must supply :descriptor", instantiator); + + if (VECTORP (desc)) + gui_parse_item_keywords (desc); + + if (!NILP (find_keyword_in_vector (instantiator, Q_width)) + && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width))) + signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator); + + if (!NILP (find_keyword_in_vector (instantiator, Q_height)) + && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height))) + signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator); +} + +static void +combo_box_validate (Lisp_Object instantiator) +{ + widget_validate (instantiator); + if (NILP (find_keyword_in_vector (instantiator, Q_properties))) + signal_simple_error ("Must supply item list", instantiator); +} + +/* we need to convert things like glyphs to images, eval expressions + etc.*/ +static Lisp_Object +widget_normalize (Lisp_Object inst, Lisp_Object console_type) +{ + /* This function can call lisp */ + Lisp_Object glyph = find_keyword_in_vector (inst, Q_image); + + /* we need to eval glyph if its an expression, we do this for the + same reasons we normalize file to data. */ + if (!NILP (glyph)) + { + substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph)); + } + + return inst; +} + +static void +initialize_widget_image_instance (struct Lisp_Image_Instance *ii, Lisp_Object type) +{ + /* initialize_subwindow_image_instance (ii);*/ + IMAGE_INSTANCE_WIDGET_TYPE (ii) = type; + IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil; + IMAGE_INSTANCE_WIDGET_FACE (ii) = Vwidget_face; + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item (); +} + +/* Instantiate a button widget. Unfortunately instantiated widgets are + particular to a frame since they need to have a parent. It's not + like images where you just select the image into the context you + want to display it in and BitBlt it. So image instances can have a + many-to-one relationship with things you see, whereas widgets can + only be one-to-one (i.e. per frame) */ +void +widget_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator, + Lisp_Object pointer_fg, Lisp_Object pointer_bg, + int dest_mask, Lisp_Object domain, int default_textheight, + int default_pixheight, int default_textwidth) +{ + struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); + Lisp_Object face = find_keyword_in_vector (instantiator, Q_face); + Lisp_Object height = find_keyword_in_vector (instantiator, Q_height); + Lisp_Object width = find_keyword_in_vector (instantiator, Q_width); + Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width); + Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height); + Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); + Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image); + Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties); + int pw=0, ph=0, tw=0, th=0; + + /* this just does pixel type sizing */ + subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg, + dest_mask, domain); + + if (!(dest_mask & IMAGE_WIDGET_MASK)) + incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK); + + initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]); + + /* retrieve the fg and bg colors */ + if (!NILP (face)) + IMAGE_INSTANCE_WIDGET_FACE (ii) = Fget_face (face); + + /* data items for some widgets */ + IMAGE_INSTANCE_WIDGET_PROPS (ii) = props; + + /* retrieve the gui item information. This is easy if we have been + provided with a vector, more difficult if we have just been given + keywords */ + if (STRINGP (desc) || NILP (desc)) + { + /* big cheat - we rely on the fact that a gui item looks like an instantiator */ + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = + gui_parse_item_keywords_no_errors (instantiator); + IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc; + } + else + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = + gui_parse_item_keywords_no_errors (desc); + + /* parse more gui items out of the properties */ + if (!NILP (props)) + { + Lisp_Object items = Fplist_get (props, Q_items, Qnil); + if (!NILP (items)) + IMAGE_INSTANCE_WIDGET_ITEMS (ii) = + Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii), + parse_gui_item_tree_children (items)); + } + + /* normalize size information */ + if (!NILP (width)) + tw = XINT (width); + if (!NILP (height)) + th = XINT (height); + if (!NILP (pixwidth)) + pw = XINT (pixwidth); + if (!NILP (pixheight)) + ph = XINT (pixheight); + + /* for a widget with an image pick up the dimensions from that */ + if (!NILP (glyph)) + { + if (!pw && !tw) + pw = glyph_width (glyph, Qnil, DEFAULT_INDEX, domain) + + 2 * WIDGET_BORDER_WIDTH; + if (!ph && !th) + ph = glyph_height (glyph, Qnil, DEFAULT_INDEX, domain) + + 2 * WIDGET_BORDER_HEIGHT; + } + + /* if we still don' t have sizes, guess from text size */ + if (!tw && !pw) + { + if (default_textwidth) + tw = default_textwidth; + else if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii))) + tw = XSTRING_LENGTH (IMAGE_INSTANCE_WIDGET_TEXT (ii)); + } + + if (!th && !ph) + { + if (default_textheight) + th = default_textheight; + else if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii))) + th = 1; + else + ph = default_pixheight; + } + + if (tw !=0 || th !=0) + widget_text_to_pixel_conversion (domain, + IMAGE_INSTANCE_WIDGET_FACE (ii), + th, tw, th ? &ph : 0, tw ? &pw : 0); + + IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = pw; + IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = ph; +#ifdef DEBUG_WIDGETS + debug_widget_instances++; + stderr_out ("instantiated "); + debug_print (instantiator); + stderr_out ("%d widgets instantiated\n", debug_widget_instances); +#endif +} + +static void +widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, + Lisp_Object pointer_fg, Lisp_Object pointer_bg, + int dest_mask, Lisp_Object domain) +{ + widget_instantiate_1 (image_instance, instantiator, pointer_fg, + pointer_bg, dest_mask, domain, 1, 0, 0); +} + +/* tree-view generic instantiation - get the height right */ +static void +tree_view_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, + Lisp_Object pointer_fg, Lisp_Object pointer_bg, + int dest_mask, Lisp_Object domain) +{ + Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties), + Q_items, Qnil); + int len; + GET_LIST_LENGTH (data, len); + widget_instantiate_1 (image_instance, instantiator, pointer_fg, + pointer_bg, dest_mask, domain, len + 1, 0, 0); +} + +static void +tab_control_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, + Lisp_Object pointer_fg, Lisp_Object pointer_bg, + int dest_mask, Lisp_Object domain) +{ + Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties), + Q_items, Qnil); + Lisp_Object rest; + int len = 0; + + LIST_LOOP (rest, data) + { + len += 3; /* some bias */ + if (STRINGP (XCAR (rest))) + len += XSTRING_LENGTH (XCAR (rest)); + else if (VECTORP (XCAR (rest))) + { + Lisp_Object gui = gui_parse_item_keywords (XCAR (rest)); + len += XSTRING_LENGTH (XGUI_ITEM (gui)->name); + } + } + + widget_instantiate_1 (image_instance, instantiator, pointer_fg, + pointer_bg, dest_mask, domain, 0, 0, len); +} + +/* Instantiate a static control */ +static void +static_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, + Lisp_Object pointer_fg, Lisp_Object pointer_bg, + int dest_mask, Lisp_Object domain) +{ + widget_instantiate_1 (image_instance, instantiator, pointer_fg, + pointer_bg, dest_mask, domain, 0, 4, 0); +} + + +/***************************************************************************** + * widget layout * + *****************************************************************************/ +static int +layout_possible_dest_types (void) +{ + return IMAGE_LAYOUT_MASK; +} + +/* we need to convert things like glyphs to images, eval expressions + etc.*/ +static Lisp_Object +layout_normalize (Lisp_Object inst, Lisp_Object console_type) +{ + /* This function can call lisp */ + Lisp_Object items = find_keyword_in_vector (inst, Q_items); + Lisp_Object border = find_keyword_in_vector (inst, Q_border); + /* we need to eval glyph if its an expression, we do this for the + same reasons we normalize file to data. */ + if (!NILP (items)) + { + Lisp_Object rest; + LIST_LOOP (rest, items) + { + /* substitute the new glyph */ + Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest))); + } + } + /* normalize the border spec. */ + if (VECTORP (border) || CONSP (border)) + { + substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border)); + } + return inst; +} + +/* Instantiate a layout widget. */ +static void +layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, + Lisp_Object pointer_fg, Lisp_Object pointer_bg, + int dest_mask, Lisp_Object domain) +{ + struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); + Lisp_Object rest, device = IMAGE_INSTANCE_DEVICE (ii); + Lisp_Object frame = FW_FRAME (domain); + Lisp_Object items = find_keyword_in_vector (instantiator, Q_items); + Lisp_Object width = find_keyword_in_vector (instantiator, Q_pixel_width); + Lisp_Object height = find_keyword_in_vector (instantiator, Q_pixel_height); + Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation); + Lisp_Object justify = find_keyword_in_vector (instantiator, Q_justify); + Lisp_Object border = find_keyword_in_vector (instantiator, Q_border); + Lisp_Object children = Qnil; + int pw = 0, ph = 0, x, y, maxph = 0, maxpw = 0, nitems = 0, + horiz_spacing, vert_spacing, ph_adjust = 0; + + if (NILP (frame)) + signal_simple_error ("No selected frame", device); + + if (!(dest_mask & IMAGE_LAYOUT_MASK)) + incompatible_image_types (instantiator, dest_mask, IMAGE_LAYOUT_MASK); + + if (NILP (orient)) + orient = Qvertical; + + if (EQ (border, Qt)) + border = Qetched_in; + + ii->data = 0; + IMAGE_INSTANCE_TYPE (ii) = IMAGE_LAYOUT; + IMAGE_INSTANCE_SUBWINDOW_ID (ii) = 0; + IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 0; + IMAGE_INSTANCE_SUBWINDOW_FRAME (ii) = frame; + IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border; + + /* normalize size information */ + if (!NILP (width)) + pw = XINT (width); + if (!NILP (height)) + ph = XINT (height); + + /* flip through the items to work out how much stuff we have to display */ + LIST_LOOP (rest, items) + { + Lisp_Object glyph = XCAR (rest); + int gheight = glyph_height (glyph, Qnil, DEFAULT_INDEX, domain); + int gwidth = glyph_width (glyph, Qnil, DEFAULT_INDEX, domain); + nitems ++; + if (EQ (orient, Qhorizontal)) + { + maxph = max (maxph, gheight); + maxpw += gwidth; + } + else if (EQ (orient, Qvertical)) + { + maxpw = max (maxpw, gwidth); + maxph += gheight; + } + } + + /* work out spacing between items and bounds of the layout */ + if (!pw) + { + /* No user provided width so we just do default spacing. */ + horiz_spacing = WIDGET_BORDER_WIDTH * 2; + if (EQ (orient, Qhorizontal)) + pw = maxpw + (nitems + 1) * horiz_spacing; + else + pw = maxpw + 2 * horiz_spacing; + } + else if (pw < maxpw) + /* The user wants a smaller space than the largest item, so we + just provide default spacing and will let the output routines + clip.. */ + horiz_spacing = WIDGET_BORDER_WIDTH * 2; + else if (EQ (orient, Qhorizontal)) + /* We have a larger area to display in so distribute the space + evenly. */ + horiz_spacing = (pw - maxpw) / (nitems + 1); + else + horiz_spacing = (pw - maxpw) / 2; + + /* Do the border now so that we can adjust the layout. */ + if (GLYPHP (border)) + { + /* We are going to be sneaky here and add the border text as + just another child, the layout and output routines don't know + this and will just display at the offsets we prescribe. */ + Lisp_Object bglyph = glyph_image_instance (border, domain, ERROR_ME, 1); + + children = Fcons (bglyph, children); + XIMAGE_INSTANCE_XOFFSET (bglyph) = 10; /* Really, what should this be? */ + XIMAGE_INSTANCE_YOFFSET (bglyph) = 0; + + ph_adjust = (glyph_height (border, Qnil, DEFAULT_INDEX, domain) / 2); + IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (ph_adjust); + } + + /* Work out vertical spacings. */ + if (!ph) + { + vert_spacing = WIDGET_BORDER_HEIGHT * 2; + if (EQ (orient, Qvertical)) + ph = maxph + (nitems + 1) * vert_spacing + ph_adjust; + else + ph = maxph + 2 * vert_spacing + ph_adjust; + } + else if (ph < maxph) + vert_spacing = WIDGET_BORDER_HEIGHT * 2; + else if (EQ (orient, Qvertical)) + vert_spacing = (ph - (maxph + ph_adjust)) / (nitems + 1); + else + vert_spacing = (ph - (maxph + ph_adjust)) / 2; + + y = vert_spacing + ph_adjust; + x = horiz_spacing; + + /* Now flip through putting items where we want them, paying + attention to justification. */ + LIST_LOOP (rest, items) + { + /* make sure the image is instantiated */ + Lisp_Object glyph = XCAR (rest); + Lisp_Object gii = glyph_image_instance (glyph, domain, ERROR_ME, 1); + int gwidth = glyph_width (glyph, Qnil, DEFAULT_INDEX, domain); + int gheight = glyph_height (glyph, Qnil, DEFAULT_INDEX, domain); + + children = Fcons (gii, children); + + if (EQ (orient, Qhorizontal)) + { + if (EQ (justify, Qright)) + y = ph - (gheight + vert_spacing); + else if (EQ (justify, Qcenter)) + y = (ph - gheight) / 2; + } + else if (EQ (orient, Qvertical)) + { + if (EQ (justify, Qright)) + x = pw - (gwidth + horiz_spacing); + else if (EQ (justify, Qcenter)) + x = (pw - gwidth) / 2; + } + + XIMAGE_INSTANCE_XOFFSET (gii) = x; + XIMAGE_INSTANCE_YOFFSET (gii) = y; + + if (EQ (orient, Qhorizontal)) + { + x += (gwidth + horiz_spacing); + } + else if (EQ (orient, Qvertical)) + { + y += (gheight + vert_spacing); + } + } + + IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children; + assert (pw && ph); + IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = pw; + IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = ph; +} + + +/************************************************************************/ +/* initialization */ +/************************************************************************/ + +void +syms_of_glyphs_widget (void) +{ + defkeyword (&Q_descriptor, ":descriptor"); + defkeyword (&Q_height, ":height"); + defkeyword (&Q_width, ":width"); + defkeyword (&Q_properties, ":properties"); + defkeyword (&Q_items, ":items"); + defkeyword (&Q_image, ":image"); + defkeyword (&Q_percent, ":percent"); + defkeyword (&Q_text, ":text"); + defkeyword (&Q_orientation, ":orientation"); + defkeyword (&Q_justify, ":justify"); + defkeyword (&Q_border, ":border"); + + defsymbol (&Qetched_in, "etched-in"); + defsymbol (&Qetched_out, "etched-out"); + defsymbol (&Qbevel_in, "bevel-in"); + defsymbol (&Qbevel_out, "bevel-out"); +} + +void +image_instantiator_format_create_glyphs_widget (void) +{ +#define VALID_GUI_KEYWORDS(type) \ + IIFORMAT_VALID_KEYWORD (type, Q_active, check_valid_anything); \ + IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \ + IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \ + IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \ + IIFORMAT_VALID_KEYWORD (type, Q_selected, check_valid_anything); \ + IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \ + IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \ + IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \ + IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \ + IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \ + IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \ + IIFORMAT_VALID_KEYWORD (type, Q_callback, check_valid_callback); \ + IIFORMAT_VALID_KEYWORD (type, Q_descriptor, check_valid_string_or_vector) + +#define VALID_WIDGET_KEYWORDS(type) \ + IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \ + IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \ + IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int); \ + IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int); \ + IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face) + + /* we only do this for properties */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget"); + IIFORMAT_HAS_METHOD (widget, property); + IIFORMAT_HAS_METHOD (widget, set_property); + + /* widget image-instantiator types - buttons */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button"); + IIFORMAT_HAS_SHARED_METHOD (button, validate, widget); + IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget); + IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget); + IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget); + IIFORMAT_VALID_KEYWORD (button, + Q_image, check_valid_glyph_or_instantiator); + VALID_WIDGET_KEYWORDS (button); + VALID_GUI_KEYWORDS (button); + + /* edit fields */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field"); + IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget); + IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget); + IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget); + VALID_WIDGET_KEYWORDS (edit_field); + VALID_GUI_KEYWORDS (edit_field); + + /* combo box */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box"); + IIFORMAT_HAS_METHOD (combo_box, validate); + IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget); + VALID_GUI_KEYWORDS (combo_box); + + IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int); + IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int); + IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int); + IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face); + IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list); + + /* scrollbar */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar"); + IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget); + IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget); + IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget); + VALID_GUI_KEYWORDS (scrollbar); + + IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int); + IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int); + IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face); + + /* progress guage */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge"); + IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget); + IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget); + IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget); + VALID_WIDGET_KEYWORDS (progress_gauge); + VALID_GUI_KEYWORDS (progress_gauge); + + /* tree view */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view"); + IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box); + IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget); + IIFORMAT_HAS_METHOD (tree_view, instantiate); + VALID_WIDGET_KEYWORDS (tree_view); + VALID_GUI_KEYWORDS (tree_view); + IIFORMAT_VALID_KEYWORD (tree_view, Q_properties, check_valid_item_list); + + /* tab control */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control"); + IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box); + IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget); + IIFORMAT_HAS_METHOD (tab_control, instantiate); + VALID_WIDGET_KEYWORDS (tab_control); + VALID_GUI_KEYWORDS (tab_control); + IIFORMAT_VALID_KEYWORD (tab_control, Q_properties, check_valid_item_list); + + /* labels */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label"); + IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget); + IIFORMAT_HAS_SHARED_METHOD (label, instantiate, static); + VALID_WIDGET_KEYWORDS (label); + IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string); + + /* layout */ + INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout"); + IIFORMAT_HAS_METHOD (layout, possible_dest_types); + IIFORMAT_HAS_METHOD (layout, instantiate); + IIFORMAT_HAS_METHOD (layout, normalize); + IIFORMAT_VALID_KEYWORD (layout, Q_pixel_width, check_valid_int); + IIFORMAT_VALID_KEYWORD (layout, Q_pixel_height, check_valid_int); + IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation); + IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification); + IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border); + IIFORMAT_VALID_KEYWORD (layout, Q_items, + check_valid_glyph_or_instantiator_list); +} + +void +reinit_vars_of_glyphs_widget (void) +{ +#ifdef DEBUG_WIDGETS + debug_widget_instances = 0; +#endif +} + +void +vars_of_glyphs_widget (void) +{ + reinit_vars_of_glyphs_widget (); +}