+/*****************************************************************************
+ * 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;
+}
+
+\f