comparison 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
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
1 /* Widget-specific glyph objects.
2 Copyright (C) 1998, 1999 Andy Piper.
3
4 This file is part of XEmacs.
5
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
9 later version.
10
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
14 for more details.
15
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. */
20
21 /* Synched up with: Not in FSF. */
22
23 /* written by Andy Piper <andy@xemacs.org> */
24
25 #include <config.h>
26 #include "lisp.h"
27 #include "lstream.h"
28 #include "console.h"
29 #include "device.h"
30 #include "faces.h"
31 #include "glyphs.h"
32 #include "objects.h"
33 #include "bytecode.h"
34 #include "window.h"
35 #include "buffer.h"
36 #include "frame.h"
37 #include "insdel.h"
38 #include "opaque.h"
39
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);
49 Lisp_Object Qlabel;
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);
57 Lisp_Object Qlayout;
58
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;
62
63 #define WIDGET_BORDER_HEIGHT 4
64 #define WIDGET_BORDER_WIDTH 4
65
66 #ifdef DEBUG_WIDGETS
67 int debug_widget_instances;
68 #endif
69
70 /* TODO:
71 - more complex controls.
72 - tooltips for controls.
73 */
74
75 /* In windows normal windows work in pixels, dialog boxes work in
76 dialog box units. Why? sigh. We could reuse the metrics for dialogs
77 if this were not the case. As it is we have to position things
78 pixel wise. I'm not even sure that X has this problem at least for
79 buttons in groups. */
80 Lisp_Object
81 widget_face_font_info (Lisp_Object domain, Lisp_Object face,
82 int *height, int *width)
83 {
84 Lisp_Object font_instance = FACE_FONT (face, domain, Vcharset_ascii);
85
86 if (height)
87 *height = XFONT_INSTANCE (font_instance)->height;
88 if (width)
89 *width = XFONT_INSTANCE (font_instance)->width;
90
91 return font_instance;
92 }
93
94 void
95 widget_text_to_pixel_conversion (Lisp_Object domain, Lisp_Object face,
96 int th, int tw,
97 int* height, int* width)
98 {
99 int ch=0, cw=0;
100 widget_face_font_info (domain, face, &ch, &cw);
101 if (height)
102 *height = th * ch + 2 * WIDGET_BORDER_HEIGHT;
103 if (width)
104 *width = tw * cw + 2 * WIDGET_BORDER_WIDTH;
105 }
106
107 static int
108 widget_possible_dest_types (void)
109 {
110 return IMAGE_WIDGET_MASK;
111 }
112
113 static void
114 check_valid_glyph_or_instantiator (Lisp_Object data)
115 {
116 Lisp_Object glyph = data;
117 if (SYMBOLP (data))
118 glyph = XSYMBOL (data)->value;
119
120 if (IMAGE_INSTANCEP (glyph))
121 CHECK_IMAGE_INSTANCE (glyph);
122 else if (!CONSP (glyph) && !VECTORP (glyph))
123 CHECK_BUFFER_GLYPH (glyph);
124 }
125
126 static void
127 check_valid_orientation (Lisp_Object data)
128 {
129 if (!EQ (data, Qhorizontal)
130 &&
131 !EQ (data, Qvertical))
132 signal_simple_error ("unknown orientation for layout", data);
133 }
134
135 static void
136 check_valid_justification (Lisp_Object data)
137 {
138 if (!EQ (data, Qleft) && !EQ (data, Qright) && !EQ (data, Qcenter))
139 signal_simple_error ("unknown justification for layout", data);
140 }
141
142 static void
143 check_valid_border (Lisp_Object data)
144 {
145 if (!EQ (data, Qt) && !EQ (data, Qetched_in) && !EQ (data, Qetched_out)
146 && !EQ (data, Qbevel_in) && !EQ (data, Qbevel_out)
147 && !GLYPHP (data) && !VECTORP (data))
148 signal_simple_error ("unknown border style for layout", data);
149 }
150
151 static void
152 check_valid_anything (Lisp_Object data)
153 {
154 }
155
156 static void
157 check_valid_callback (Lisp_Object data)
158 {
159 if (!SYMBOLP (data)
160 && !COMPILED_FUNCTIONP (data)
161 && !CONSP (data))
162 {
163 signal_simple_error (":callback must be a function or expression", data);
164 }
165 }
166
167 static void
168 check_valid_symbol (Lisp_Object data)
169 {
170 CHECK_SYMBOL (data);
171 }
172
173 static void
174 check_valid_string_or_vector (Lisp_Object data)
175 {
176 if (!STRINGP (data) && !VECTORP (data))
177 signal_simple_error (":descriptor must be a string or a vector", data);
178 }
179
180 void
181 check_valid_item_list_1 (Lisp_Object items)
182 {
183 Lisp_Object rest;
184
185 CHECK_LIST (items);
186 EXTERNAL_LIST_LOOP (rest, items)
187 {
188 if (STRINGP (XCAR (rest)))
189 CHECK_STRING (XCAR (rest));
190 else if (VECTORP (XCAR (rest)))
191 gui_parse_item_keywords (XCAR (rest));
192 else if (LISTP (XCAR (rest)))
193 check_valid_item_list_1 (XCAR (rest));
194 else
195 signal_simple_error ("Items must be vectors, lists or strings", items);
196 }
197 }
198
199 static void
200 check_valid_item_list (Lisp_Object data)
201 {
202 Lisp_Object items;
203
204 Fcheck_valid_plist (data);
205 items = Fplist_get (data, Q_items, Qnil);
206
207 check_valid_item_list_1 (items);
208 }
209
210 static void
211 check_valid_glyph_or_instantiator_list (Lisp_Object data)
212 {
213 Lisp_Object rest;
214
215 CHECK_LIST (data);
216 EXTERNAL_LIST_LOOP (rest, data)
217 {
218 check_valid_glyph_or_instantiator (XCAR (rest));
219 }
220 }
221
222 static Lisp_Object
223 glyph_instantiator_to_glyph (Lisp_Object sym)
224 {
225 /* This function calls lisp. */
226 Lisp_Object glyph = sym;
227 struct gcpro gcpro1;
228
229 GCPRO1 (glyph);
230 /* if we have a symbol get at the actual data */
231 if (SYMBOLP (glyph))
232 glyph = XSYMBOL (glyph)->value;
233
234 if (CONSP (glyph))
235 glyph = Feval (glyph);
236
237 /* Be really helpful to the user. */
238 if (VECTORP (glyph))
239 {
240 glyph = call1 (intern ("make-glyph"), glyph);
241 }
242
243 /* substitute the new glyph */
244 RETURN_UNGCPRO (glyph);
245 }
246
247 static void
248 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val)
249 {
250 int i;
251 /* substitute the new glyph */
252 for (i = 0; i < XVECTOR_LENGTH (inst); i++)
253 {
254 if (EQ (key, XVECTOR_DATA (inst)[i]))
255 {
256 XVECTOR_DATA (inst)[i+1] = val;
257 break;
258 }
259 }
260 }
261
262 /* wire widget property invocations to specific widgets ... The
263 problem we are solving here is that when instantiators get converted
264 to instances they lose some type information (they just become
265 subwindows or widgets for example). For widgets we need to preserve
266 this type information so that we can do widget specific operations on
267 the instances. This is encoded in the widget type
268 field. widget_property gets invoked by decoding the primary type
269 (Qwidget), widget property then invokes based on the secondary type
270 (Qedit_field for example). It is debatable that we should wire things in this
271 generalised way rather than treating widgets specially in
272 image_instance_property. */
273 static Lisp_Object
274 widget_property (Lisp_Object image_instance, Lisp_Object prop)
275 {
276 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
277 struct image_instantiator_methods* meths;
278
279 /* first see if its a general property ... */
280 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
281 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
282
283 /* .. then try device specific methods ... */
284 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
285 IMAGE_INSTANCE_WIDGET_TYPE (ii),
286 ERROR_ME_NOT);
287 if (meths && HAS_IIFORMAT_METH_P (meths, property))
288 return IIFORMAT_METH (meths, property, (image_instance, prop));
289 /* ... then format specific methods ... */
290 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
291 ERROR_ME_NOT);
292 if (meths && HAS_IIFORMAT_METH_P (meths, property))
293 return IIFORMAT_METH (meths, property, (image_instance, prop));
294 /* ... then fail */
295 return Qunbound;
296 }
297
298 static Lisp_Object
299 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val)
300 {
301 struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
302 struct image_instantiator_methods* meths;
303 Lisp_Object ret;
304
305 /* try device specific methods first ... */
306 meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii),
307 IMAGE_INSTANCE_WIDGET_TYPE (ii),
308 ERROR_ME_NOT);
309 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
310 &&
311 !UNBOUNDP (ret =
312 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
313 {
314 return ret;
315 }
316 /* ... then format specific methods ... */
317 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii),
318 ERROR_ME_NOT);
319 if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
320 &&
321 !UNBOUNDP (ret =
322 IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
323 {
324 return ret;
325 }
326 /* we didn't do any device specific properties, so shove the property in our plist */
327 IMAGE_INSTANCE_WIDGET_PROPS (ii)
328 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
329 return val;
330 }
331
332 static void
333 widget_validate (Lisp_Object instantiator)
334 {
335 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
336
337 if (NILP (desc))
338 signal_simple_error ("Must supply :descriptor", instantiator);
339
340 if (VECTORP (desc))
341 gui_parse_item_keywords (desc);
342
343 if (!NILP (find_keyword_in_vector (instantiator, Q_width))
344 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
345 signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
346
347 if (!NILP (find_keyword_in_vector (instantiator, Q_height))
348 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
349 signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
350 }
351
352 static void
353 combo_box_validate (Lisp_Object instantiator)
354 {
355 widget_validate (instantiator);
356 if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
357 signal_simple_error ("Must supply item list", instantiator);
358 }
359
360 /* we need to convert things like glyphs to images, eval expressions
361 etc.*/
362 static Lisp_Object
363 widget_normalize (Lisp_Object inst, Lisp_Object console_type)
364 {
365 /* This function can call lisp */
366 Lisp_Object glyph = find_keyword_in_vector (inst, Q_image);
367
368 /* we need to eval glyph if its an expression, we do this for the
369 same reasons we normalize file to data. */
370 if (!NILP (glyph))
371 {
372 substitute_keyword_value (inst, Q_image, glyph_instantiator_to_glyph (glyph));
373 }
374
375 return inst;
376 }
377
378 static void
379 initialize_widget_image_instance (struct Lisp_Image_Instance *ii, Lisp_Object type)
380 {
381 /* initialize_subwindow_image_instance (ii);*/
382 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
383 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
384 IMAGE_INSTANCE_WIDGET_FACE (ii) = Vwidget_face;
385 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item ();
386 }
387
388 /* Instantiate a button widget. Unfortunately instantiated widgets are
389 particular to a frame since they need to have a parent. It's not
390 like images where you just select the image into the context you
391 want to display it in and BitBlt it. So image instances can have a
392 many-to-one relationship with things you see, whereas widgets can
393 only be one-to-one (i.e. per frame) */
394 void
395 widget_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator,
396 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
397 int dest_mask, Lisp_Object domain, int default_textheight,
398 int default_pixheight, int default_textwidth)
399 {
400 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
401 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
402 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
403 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
404 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
405 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
406 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
407 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image);
408 Lisp_Object props = find_keyword_in_vector (instantiator, Q_properties);
409 int pw=0, ph=0, tw=0, th=0;
410
411 /* this just does pixel type sizing */
412 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
413 dest_mask, domain);
414
415 if (!(dest_mask & IMAGE_WIDGET_MASK))
416 incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK);
417
418 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
419
420 /* retrieve the fg and bg colors */
421 if (!NILP (face))
422 IMAGE_INSTANCE_WIDGET_FACE (ii) = Fget_face (face);
423
424 /* data items for some widgets */
425 IMAGE_INSTANCE_WIDGET_PROPS (ii) = props;
426
427 /* retrieve the gui item information. This is easy if we have been
428 provided with a vector, more difficult if we have just been given
429 keywords */
430 if (STRINGP (desc) || NILP (desc))
431 {
432 /* big cheat - we rely on the fact that a gui item looks like an instantiator */
433 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
434 gui_parse_item_keywords_no_errors (instantiator);
435 IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
436 }
437 else
438 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
439 gui_parse_item_keywords_no_errors (desc);
440
441 /* parse more gui items out of the properties */
442 if (!NILP (props))
443 {
444 Lisp_Object items = Fplist_get (props, Q_items, Qnil);
445 if (!NILP (items))
446 IMAGE_INSTANCE_WIDGET_ITEMS (ii) =
447 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii),
448 parse_gui_item_tree_children (items));
449 }
450
451 /* normalize size information */
452 if (!NILP (width))
453 tw = XINT (width);
454 if (!NILP (height))
455 th = XINT (height);
456 if (!NILP (pixwidth))
457 pw = XINT (pixwidth);
458 if (!NILP (pixheight))
459 ph = XINT (pixheight);
460
461 /* for a widget with an image pick up the dimensions from that */
462 if (!NILP (glyph))
463 {
464 if (!pw && !tw)
465 pw = glyph_width (glyph, Qnil, DEFAULT_INDEX, domain)
466 + 2 * WIDGET_BORDER_WIDTH;
467 if (!ph && !th)
468 ph = glyph_height (glyph, Qnil, DEFAULT_INDEX, domain)
469 + 2 * WIDGET_BORDER_HEIGHT;
470 }
471
472 /* if we still don' t have sizes, guess from text size */
473 if (!tw && !pw)
474 {
475 if (default_textwidth)
476 tw = default_textwidth;
477 else if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
478 tw = XSTRING_LENGTH (IMAGE_INSTANCE_WIDGET_TEXT (ii));
479 }
480
481 if (!th && !ph)
482 {
483 if (default_textheight)
484 th = default_textheight;
485 else if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
486 th = 1;
487 else
488 ph = default_pixheight;
489 }
490
491 if (tw !=0 || th !=0)
492 widget_text_to_pixel_conversion (domain,
493 IMAGE_INSTANCE_WIDGET_FACE (ii),
494 th, tw, th ? &ph : 0, tw ? &pw : 0);
495
496 IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = pw;
497 IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = ph;
498 #ifdef DEBUG_WIDGETS
499 debug_widget_instances++;
500 stderr_out ("instantiated ");
501 debug_print (instantiator);
502 stderr_out ("%d widgets instantiated\n", debug_widget_instances);
503 #endif
504 }
505
506 static void
507 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
508 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
509 int dest_mask, Lisp_Object domain)
510 {
511 widget_instantiate_1 (image_instance, instantiator, pointer_fg,
512 pointer_bg, dest_mask, domain, 1, 0, 0);
513 }
514
515 /* tree-view generic instantiation - get the height right */
516 static void
517 tree_view_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
518 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
519 int dest_mask, Lisp_Object domain)
520 {
521 Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties),
522 Q_items, Qnil);
523 int len;
524 GET_LIST_LENGTH (data, len);
525 widget_instantiate_1 (image_instance, instantiator, pointer_fg,
526 pointer_bg, dest_mask, domain, len + 1, 0, 0);
527 }
528
529 static void
530 tab_control_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
531 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
532 int dest_mask, Lisp_Object domain)
533 {
534 Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties),
535 Q_items, Qnil);
536 Lisp_Object rest;
537 int len = 0;
538
539 LIST_LOOP (rest, data)
540 {
541 len += 3; /* some bias */
542 if (STRINGP (XCAR (rest)))
543 len += XSTRING_LENGTH (XCAR (rest));
544 else if (VECTORP (XCAR (rest)))
545 {
546 Lisp_Object gui = gui_parse_item_keywords (XCAR (rest));
547 len += XSTRING_LENGTH (XGUI_ITEM (gui)->name);
548 }
549 }
550
551 widget_instantiate_1 (image_instance, instantiator, pointer_fg,
552 pointer_bg, dest_mask, domain, 0, 0, len);
553 }
554
555 /* Instantiate a static control */
556 static void
557 static_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
558 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
559 int dest_mask, Lisp_Object domain)
560 {
561 widget_instantiate_1 (image_instance, instantiator, pointer_fg,
562 pointer_bg, dest_mask, domain, 0, 4, 0);
563 }
564
565
566 /*****************************************************************************
567 * widget layout *
568 *****************************************************************************/
569 static int
570 layout_possible_dest_types (void)
571 {
572 return IMAGE_LAYOUT_MASK;
573 }
574
575 /* we need to convert things like glyphs to images, eval expressions
576 etc.*/
577 static Lisp_Object
578 layout_normalize (Lisp_Object inst, Lisp_Object console_type)
579 {
580 /* This function can call lisp */
581 Lisp_Object items = find_keyword_in_vector (inst, Q_items);
582 Lisp_Object border = find_keyword_in_vector (inst, Q_border);
583 /* we need to eval glyph if its an expression, we do this for the
584 same reasons we normalize file to data. */
585 if (!NILP (items))
586 {
587 Lisp_Object rest;
588 LIST_LOOP (rest, items)
589 {
590 /* substitute the new glyph */
591 Fsetcar (rest, glyph_instantiator_to_glyph (XCAR (rest)));
592 }
593 }
594 /* normalize the border spec. */
595 if (VECTORP (border) || CONSP (border))
596 {
597 substitute_keyword_value (inst, Q_border, glyph_instantiator_to_glyph (border));
598 }
599 return inst;
600 }
601
602 /* Instantiate a layout widget. */
603 static void
604 layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
605 Lisp_Object pointer_fg, Lisp_Object pointer_bg,
606 int dest_mask, Lisp_Object domain)
607 {
608 struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
609 Lisp_Object rest, device = IMAGE_INSTANCE_DEVICE (ii);
610 Lisp_Object frame = FW_FRAME (domain);
611 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items);
612 Lisp_Object width = find_keyword_in_vector (instantiator, Q_pixel_width);
613 Lisp_Object height = find_keyword_in_vector (instantiator, Q_pixel_height);
614 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation);
615 Lisp_Object justify = find_keyword_in_vector (instantiator, Q_justify);
616 Lisp_Object border = find_keyword_in_vector (instantiator, Q_border);
617 Lisp_Object children = Qnil;
618 int pw = 0, ph = 0, x, y, maxph = 0, maxpw = 0, nitems = 0,
619 horiz_spacing, vert_spacing, ph_adjust = 0;
620
621 if (NILP (frame))
622 signal_simple_error ("No selected frame", device);
623
624 if (!(dest_mask & IMAGE_LAYOUT_MASK))
625 incompatible_image_types (instantiator, dest_mask, IMAGE_LAYOUT_MASK);
626
627 if (NILP (orient))
628 orient = Qvertical;
629
630 if (EQ (border, Qt))
631 border = Qetched_in;
632
633 ii->data = 0;
634 IMAGE_INSTANCE_TYPE (ii) = IMAGE_LAYOUT;
635 IMAGE_INSTANCE_SUBWINDOW_ID (ii) = 0;
636 IMAGE_INSTANCE_SUBWINDOW_DISPLAYEDP (ii) = 0;
637 IMAGE_INSTANCE_SUBWINDOW_FRAME (ii) = frame;
638 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border;
639
640 /* normalize size information */
641 if (!NILP (width))
642 pw = XINT (width);
643 if (!NILP (height))
644 ph = XINT (height);
645
646 /* flip through the items to work out how much stuff we have to display */
647 LIST_LOOP (rest, items)
648 {
649 Lisp_Object glyph = XCAR (rest);
650 int gheight = glyph_height (glyph, Qnil, DEFAULT_INDEX, domain);
651 int gwidth = glyph_width (glyph, Qnil, DEFAULT_INDEX, domain);
652 nitems ++;
653 if (EQ (orient, Qhorizontal))
654 {
655 maxph = max (maxph, gheight);
656 maxpw += gwidth;
657 }
658 else if (EQ (orient, Qvertical))
659 {
660 maxpw = max (maxpw, gwidth);
661 maxph += gheight;
662 }
663 }
664
665 /* work out spacing between items and bounds of the layout */
666 if (!pw)
667 {
668 /* No user provided width so we just do default spacing. */
669 horiz_spacing = WIDGET_BORDER_WIDTH * 2;
670 if (EQ (orient, Qhorizontal))
671 pw = maxpw + (nitems + 1) * horiz_spacing;
672 else
673 pw = maxpw + 2 * horiz_spacing;
674 }
675 else if (pw < maxpw)
676 /* The user wants a smaller space than the largest item, so we
677 just provide default spacing and will let the output routines
678 clip.. */
679 horiz_spacing = WIDGET_BORDER_WIDTH * 2;
680 else if (EQ (orient, Qhorizontal))
681 /* We have a larger area to display in so distribute the space
682 evenly. */
683 horiz_spacing = (pw - maxpw) / (nitems + 1);
684 else
685 horiz_spacing = (pw - maxpw) / 2;
686
687 /* Do the border now so that we can adjust the layout. */
688 if (GLYPHP (border))
689 {
690 /* We are going to be sneaky here and add the border text as
691 just another child, the layout and output routines don't know
692 this and will just display at the offsets we prescribe. */
693 Lisp_Object bglyph = glyph_image_instance (border, domain, ERROR_ME, 1);
694
695 children = Fcons (bglyph, children);
696 XIMAGE_INSTANCE_XOFFSET (bglyph) = 10; /* Really, what should this be? */
697 XIMAGE_INSTANCE_YOFFSET (bglyph) = 0;
698
699 ph_adjust = (glyph_height (border, Qnil, DEFAULT_INDEX, domain) / 2);
700 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (ph_adjust);
701 }
702
703 /* Work out vertical spacings. */
704 if (!ph)
705 {
706 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
707 if (EQ (orient, Qvertical))
708 ph = maxph + (nitems + 1) * vert_spacing + ph_adjust;
709 else
710 ph = maxph + 2 * vert_spacing + ph_adjust;
711 }
712 else if (ph < maxph)
713 vert_spacing = WIDGET_BORDER_HEIGHT * 2;
714 else if (EQ (orient, Qvertical))
715 vert_spacing = (ph - (maxph + ph_adjust)) / (nitems + 1);
716 else
717 vert_spacing = (ph - (maxph + ph_adjust)) / 2;
718
719 y = vert_spacing + ph_adjust;
720 x = horiz_spacing;
721
722 /* Now flip through putting items where we want them, paying
723 attention to justification. */
724 LIST_LOOP (rest, items)
725 {
726 /* make sure the image is instantiated */
727 Lisp_Object glyph = XCAR (rest);
728 Lisp_Object gii = glyph_image_instance (glyph, domain, ERROR_ME, 1);
729 int gwidth = glyph_width (glyph, Qnil, DEFAULT_INDEX, domain);
730 int gheight = glyph_height (glyph, Qnil, DEFAULT_INDEX, domain);
731
732 children = Fcons (gii, children);
733
734 if (EQ (orient, Qhorizontal))
735 {
736 if (EQ (justify, Qright))
737 y = ph - (gheight + vert_spacing);
738 else if (EQ (justify, Qcenter))
739 y = (ph - gheight) / 2;
740 }
741 else if (EQ (orient, Qvertical))
742 {
743 if (EQ (justify, Qright))
744 x = pw - (gwidth + horiz_spacing);
745 else if (EQ (justify, Qcenter))
746 x = (pw - gwidth) / 2;
747 }
748
749 XIMAGE_INSTANCE_XOFFSET (gii) = x;
750 XIMAGE_INSTANCE_YOFFSET (gii) = y;
751
752 if (EQ (orient, Qhorizontal))
753 {
754 x += (gwidth + horiz_spacing);
755 }
756 else if (EQ (orient, Qvertical))
757 {
758 y += (gheight + vert_spacing);
759 }
760 }
761
762 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = children;
763 assert (pw && ph);
764 IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = pw;
765 IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = ph;
766 }
767
768
769 /************************************************************************/
770 /* initialization */
771 /************************************************************************/
772
773 void
774 syms_of_glyphs_widget (void)
775 {
776 defkeyword (&Q_descriptor, ":descriptor");
777 defkeyword (&Q_height, ":height");
778 defkeyword (&Q_width, ":width");
779 defkeyword (&Q_properties, ":properties");
780 defkeyword (&Q_items, ":items");
781 defkeyword (&Q_image, ":image");
782 defkeyword (&Q_percent, ":percent");
783 defkeyword (&Q_text, ":text");
784 defkeyword (&Q_orientation, ":orientation");
785 defkeyword (&Q_justify, ":justify");
786 defkeyword (&Q_border, ":border");
787
788 defsymbol (&Qetched_in, "etched-in");
789 defsymbol (&Qetched_out, "etched-out");
790 defsymbol (&Qbevel_in, "bevel-in");
791 defsymbol (&Qbevel_out, "bevel-out");
792 }
793
794 void
795 image_instantiator_format_create_glyphs_widget (void)
796 {
797 #define VALID_GUI_KEYWORDS(type) \
798 IIFORMAT_VALID_KEYWORD (type, Q_active, check_valid_anything); \
799 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \
800 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \
801 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \
802 IIFORMAT_VALID_KEYWORD (type, Q_selected, check_valid_anything); \
803 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \
804 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \
805 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \
806 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \
807 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \
808 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \
809 IIFORMAT_VALID_KEYWORD (type, Q_callback, check_valid_callback); \
810 IIFORMAT_VALID_KEYWORD (type, Q_descriptor, check_valid_string_or_vector)
811
812 #define VALID_WIDGET_KEYWORDS(type) \
813 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \
814 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \
815 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int); \
816 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int); \
817 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face)
818
819 /* we only do this for properties */
820 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
821 IIFORMAT_HAS_METHOD (widget, property);
822 IIFORMAT_HAS_METHOD (widget, set_property);
823
824 /* widget image-instantiator types - buttons */
825 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
826 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
827 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
828 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
829 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget);
830 IIFORMAT_VALID_KEYWORD (button,
831 Q_image, check_valid_glyph_or_instantiator);
832 VALID_WIDGET_KEYWORDS (button);
833 VALID_GUI_KEYWORDS (button);
834
835 /* edit fields */
836 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field");
837 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget);
838 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget);
839 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget);
840 VALID_WIDGET_KEYWORDS (edit_field);
841 VALID_GUI_KEYWORDS (edit_field);
842
843 /* combo box */
844 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box");
845 IIFORMAT_HAS_METHOD (combo_box, validate);
846 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget);
847 VALID_GUI_KEYWORDS (combo_box);
848
849 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int);
850 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int);
851 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, check_valid_int);
852 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face);
853 IIFORMAT_VALID_KEYWORD (combo_box, Q_properties, check_valid_item_list);
854
855 /* scrollbar */
856 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
857 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
858 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
859 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
860 VALID_GUI_KEYWORDS (scrollbar);
861
862 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int);
863 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int);
864 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
865
866 /* progress guage */
867 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge");
868 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget);
869 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget);
870 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget);
871 VALID_WIDGET_KEYWORDS (progress_gauge);
872 VALID_GUI_KEYWORDS (progress_gauge);
873
874 /* tree view */
875 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view");
876 IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box);
877 IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget);
878 IIFORMAT_HAS_METHOD (tree_view, instantiate);
879 VALID_WIDGET_KEYWORDS (tree_view);
880 VALID_GUI_KEYWORDS (tree_view);
881 IIFORMAT_VALID_KEYWORD (tree_view, Q_properties, check_valid_item_list);
882
883 /* tab control */
884 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control");
885 IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box);
886 IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget);
887 IIFORMAT_HAS_METHOD (tab_control, instantiate);
888 VALID_WIDGET_KEYWORDS (tab_control);
889 VALID_GUI_KEYWORDS (tab_control);
890 IIFORMAT_VALID_KEYWORD (tab_control, Q_properties, check_valid_item_list);
891
892 /* labels */
893 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
894 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
895 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, static);
896 VALID_WIDGET_KEYWORDS (label);
897 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
898
899 /* layout */
900 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout");
901 IIFORMAT_HAS_METHOD (layout, possible_dest_types);
902 IIFORMAT_HAS_METHOD (layout, instantiate);
903 IIFORMAT_HAS_METHOD (layout, normalize);
904 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_width, check_valid_int);
905 IIFORMAT_VALID_KEYWORD (layout, Q_pixel_height, check_valid_int);
906 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation);
907 IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification);
908 IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border);
909 IIFORMAT_VALID_KEYWORD (layout, Q_items,
910 check_valid_glyph_or_instantiator_list);
911 }
912
913 void
914 reinit_vars_of_glyphs_widget (void)
915 {
916 #ifdef DEBUG_WIDGETS
917 debug_widget_instances = 0;
918 #endif
919 }
920
921 void
922 vars_of_glyphs_widget (void)
923 {
924 reinit_vars_of_glyphs_widget ();
925 }