XEmacs 21.2.7
[chise/xemacs-chise.git.1] / src / glyphs-widget.c
1 /* Widget-specific glyph objects.
2    Copyright (C) 1998 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 #include <config.h>
24 #include "lisp.h"
25 #include "lstream.h"
26 #include "console.h"
27 #include "device.h"
28 #include "faces.h"
29 #include "glyphs.h"
30 #include "objects.h"
31
32 #include "window.h"
33 #include "buffer.h"
34 #include "frame.h"
35 #include "insdel.h"
36 #include "opaque.h"
37
38 DEFINE_IMAGE_INSTANTIATOR_FORMAT (button);
39 DEFINE_IMAGE_INSTANTIATOR_FORMAT (combo);
40 Lisp_Object Qcombo;
41 DEFINE_IMAGE_INSTANTIATOR_FORMAT (edit);
42 Lisp_Object Qedit;
43 DEFINE_IMAGE_INSTANTIATOR_FORMAT (scrollbar);
44 Lisp_Object Qscrollbar;
45 DEFINE_IMAGE_INSTANTIATOR_FORMAT (widget);
46 #if 0
47 DEFINE_IMAGE_INSTANTIATOR_FORMAT (group);
48 Lisp_Object Qgroup;
49 #endif
50 DEFINE_IMAGE_INSTANTIATOR_FORMAT (label);
51 Lisp_Object Qlabel;
52
53 Lisp_Object Q_descriptor, Q_height, Q_width, Q_properties, Q_items;
54
55 #define WIDGET_BORDER_HEIGHT 2
56 #define WIDGET_BORDER_WIDTH 4
57
58 /* TODO:
59    - more complex controls.
60    - tooltips for controls.
61    - images in controls.
62  */
63
64 /* In windows normal windows work in pixels, dialog boxes work in
65    dialog box units. Why? sigh. We could reuse the metrics for dialogs
66    if this were not the case. As it is we have to position things
67    pixel wise. I'm not even sure that X has this problem at least for
68    buttons in groups. */
69 Lisp_Object
70 widget_face_font_info (Lisp_Object domain, Lisp_Object face,
71                        int *height, int *width)
72 {
73   Lisp_Object font_instance = FACE_FONT (face, domain, Vcharset_ascii);
74
75   if (height)
76     *height = XFONT_INSTANCE (font_instance)->height;
77   if (width)
78     *width = XFONT_INSTANCE (font_instance)->width;
79   
80   return font_instance;
81 }
82
83 void
84 widget_text_to_pixel_conversion (Lisp_Object domain, Lisp_Object face,
85                                  int th, int tw,
86                                  int* height, int* width)
87 {
88   int ch=0, cw=0;
89   widget_face_font_info (domain, face, &ch, &cw);
90   if (height)
91     *height = th * (ch + 2 * WIDGET_BORDER_HEIGHT);
92   if (width)
93     *width = tw * cw + 2 * WIDGET_BORDER_WIDTH;
94 }
95
96 static int
97 widget_possible_dest_types (void)
98 {
99   return IMAGE_WIDGET_MASK;
100 }
101
102 #if 0 /* currently unused */
103 static void
104 check_valid_glyph (Lisp_Object data)
105 {
106   if (SYMBOLP (data))
107     CHECK_BUFFER_GLYPH (XSYMBOL (data)->value);
108   else
109     CHECK_BUFFER_GLYPH (data);
110 }
111 #endif /* currently unused */
112
113 static void
114 check_valid_item_list (Lisp_Object data)
115 {
116   Lisp_Object rest;
117   Lisp_Object items;
118   Fcheck_valid_plist (data);
119   
120   items = Fplist_get (data, Q_items, Qnil);
121
122   CHECK_LIST (items);
123   EXTERNAL_LIST_LOOP (rest, items)
124     {
125       CHECK_STRING (XCAR (rest));
126     }
127 }
128
129 /* wire widget property invocations to specific widgets ...  The
130  problem we are solving here is that when instantiators get converted
131  to instances they lose some type information (they just become
132  subwindows or widgets for example). For widgets we need to preserve
133  this type information so that we can do widget specific operations on
134  the instances. This is encoded in the widget type
135  field. widget_property gets invoked by decoding the primary type
136  (Qwidget), widget property then invokes based on the secondary type
137  (Qedit for example). It is debatable that we should wire things in this
138  generalised way rather than treating widgets specially in
139  image_instance_property. */
140 static Lisp_Object 
141 widget_property (Lisp_Object image_instance, Lisp_Object prop)
142 {
143   struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
144   struct image_instantiator_methods* meths;
145
146   /* first see if its a general property ... */
147   if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop)))
148     return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil);
149
150   /* .. then try device specific methods ... */
151   meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii), 
152                                    IMAGE_INSTANCE_WIDGET_TYPE (ii), 
153                                    ERROR_ME_NOT);
154   if (meths && HAS_IIFORMAT_METH_P (meths, property))
155     return IIFORMAT_METH (meths, property, (image_instance, prop));
156   /* ... then format specific methods ... */
157   meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), 
158                                    ERROR_ME_NOT);
159   if (meths && HAS_IIFORMAT_METH_P (meths, property))
160     return IIFORMAT_METH (meths, property, (image_instance, prop));
161   /* ... then fail */
162   return Qunbound;
163 }
164
165 static Lisp_Object 
166 widget_set_property (Lisp_Object image_instance, Lisp_Object prop, Lisp_Object val)
167 {
168   struct Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance);
169   struct image_instantiator_methods* meths;
170   Lisp_Object ret;
171
172   /* try device specific methods first ... */
173   meths = decode_device_ii_format (IMAGE_INSTANCE_DEVICE (ii), 
174                                    IMAGE_INSTANCE_WIDGET_TYPE (ii), 
175                                    ERROR_ME_NOT);
176   if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
177       &&
178       !UNBOUNDP (ret = 
179                  IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
180     {
181       return ret;
182     }
183   /* ... then format specific methods ... */
184   meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), 
185                                    ERROR_ME_NOT);
186   if (meths && HAS_IIFORMAT_METH_P (meths, set_property)
187       &&
188       !UNBOUNDP (ret = 
189                  IIFORMAT_METH (meths, set_property, (image_instance, prop, val))))
190     {
191       return ret;
192     }
193   /* we didn't do any device specific properties, so shove the property in our plist */
194   IMAGE_INSTANCE_WIDGET_PROPS (ii)
195     = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val);
196   return val;
197 }
198
199 static void
200 widget_validate (Lisp_Object instantiator)
201 {
202   Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
203   struct gui_item gui;
204   if (NILP (desc))
205     signal_simple_error ("Must supply :descriptor", instantiator);
206
207   gui_parse_item_keywords (desc, &gui);
208
209   if (!NILP (find_keyword_in_vector (instantiator, Q_width))
210              && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width)))
211     signal_simple_error ("Must supply only one of :width and :pixel-width", instantiator);
212
213   if (!NILP (find_keyword_in_vector (instantiator, Q_height))
214              && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height)))
215     signal_simple_error ("Must supply only one of :height and :pixel-height", instantiator);
216 }
217
218 static void
219 combo_validate (Lisp_Object instantiator)
220 {
221   widget_validate (instantiator);
222   if (NILP (find_keyword_in_vector (instantiator, Q_properties)))
223     signal_simple_error ("Must supply item list", instantiator);
224 }
225
226 static void
227 initialize_widget_image_instance (struct Lisp_Image_Instance *ii, Lisp_Object type)
228 {
229   /*  initialize_subwindow_image_instance (ii);*/
230   IMAGE_INSTANCE_WIDGET_TYPE (ii) = type;
231   IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil;
232   IMAGE_INSTANCE_WIDGET_FACE (ii) = Vwidget_face;
233   gui_item_init (&IMAGE_INSTANCE_WIDGET_ITEM (ii));
234 }
235
236 /* Instantiate a button widget. Unfortunately instantiated widgets are
237    particular to a frame since they need to have a parent. It's not
238    like images where you just select the image into the context you
239    want to display it in and BitBlt it. So images instances can have a
240    many-to-one relationship with things you see, whereas widgets can
241    only be one-to-one (i.e. per frame) */
242 static void
243 widget_instantiate_1 (Lisp_Object image_instance, Lisp_Object instantiator,
244                       Lisp_Object pointer_fg, Lisp_Object pointer_bg,
245                       int dest_mask, Lisp_Object domain, int default_textheight,
246                       int default_pixheight)
247 {
248   struct Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance);
249   struct gui_item* pgui = &IMAGE_INSTANCE_WIDGET_ITEM (ii);
250   Lisp_Object face = find_keyword_in_vector (instantiator, Q_face);
251   Lisp_Object height = find_keyword_in_vector (instantiator, Q_height);
252   Lisp_Object width = find_keyword_in_vector (instantiator, Q_width);
253   Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width);
254   Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height);
255   Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor);
256   int pw=0, ph=0, tw=0, th=0;
257   
258   /* this just does pixel type sizing */
259   subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg,
260                          dest_mask, domain);
261
262   if (!(dest_mask & IMAGE_WIDGET_MASK))
263     incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK);
264
265   initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]);
266
267   /* retrieve the fg and bg colors */
268   if (!NILP (face))
269     IMAGE_INSTANCE_WIDGET_FACE (ii) = Fget_face (face);
270   
271   /* data items for some widgets */
272   IMAGE_INSTANCE_WIDGET_PROPS (ii) = 
273     find_keyword_in_vector (instantiator, Q_properties);
274
275   /* retrieve the gui item information */
276   if (STRINGP (desc) || NILP (desc))
277     IMAGE_INSTANCE_WIDGET_TEXT (ii) = desc;
278   else
279     gui_parse_item_keywords (find_keyword_in_vector (instantiator, Q_descriptor),
280                              pgui);
281
282   /* normalize size information */
283   if (!NILP (width))
284     tw = XINT (width);
285   if (!NILP (height))
286     th = XINT (height);
287   if (!NILP (pixwidth))
288     pw = XINT (pixwidth);
289   if (!NILP (pixheight))
290     ph = XINT (pixheight);
291
292   if (!tw && !pw && !NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
293     tw = XSTRING_LENGTH (IMAGE_INSTANCE_WIDGET_TEXT (ii));
294   if (!th && !ph)
295     {
296       if (default_textheight)
297         th = default_textheight;
298       else if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)))
299         th = 1;
300       else
301         ph = default_pixheight;
302     }
303
304   if (tw !=0 || th !=0)
305     widget_text_to_pixel_conversion (domain,
306                                      IMAGE_INSTANCE_WIDGET_FACE (ii),
307                                      th, tw, th ? &ph : 0, tw ? &pw : 0);
308
309   IMAGE_INSTANCE_SUBWINDOW_WIDTH (ii) = pw;
310   IMAGE_INSTANCE_SUBWINDOW_HEIGHT (ii) = ph;
311 }
312
313 static void
314 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
315                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
316                     int dest_mask, Lisp_Object domain)
317 {
318   widget_instantiate_1 (image_instance, instantiator, pointer_fg,
319                                pointer_bg, dest_mask, domain, 1, 0);
320 }
321
322 static void
323 combo_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
324                    Lisp_Object pointer_fg, Lisp_Object pointer_bg,
325                    int dest_mask, Lisp_Object domain)
326 {
327   Lisp_Object data = Fplist_get (find_keyword_in_vector (instantiator, Q_properties),
328                                  Q_items, Qnil);
329   int len;
330   GET_LIST_LENGTH (data, len);
331   widget_instantiate_1 (image_instance, instantiator, pointer_fg,
332                         pointer_bg, dest_mask, domain, len + 1, 0);
333 }
334
335 /* Instantiate a static control */
336 static void
337 static_instantiate (Lisp_Object image_instance, Lisp_Object instantiator,
338                     Lisp_Object pointer_fg, Lisp_Object pointer_bg,
339                     int dest_mask, Lisp_Object domain)
340 {
341   widget_instantiate_1 (image_instance, instantiator, pointer_fg,
342                         pointer_bg, dest_mask, domain, 0, 4);
343 }
344
345 \f
346 /************************************************************************/
347 /*                            initialization                            */
348 /************************************************************************/
349
350 void
351 syms_of_glyphs_widget (void)
352 {
353   defkeyword (&Q_descriptor, ":descriptor");
354   defkeyword (&Q_height, ":height");
355   defkeyword (&Q_width, ":width");
356   defkeyword (&Q_properties, ":properties");
357   defkeyword (&Q_items, ":items");
358 }
359
360 void
361 image_instantiator_format_create_glyphs_widget (void)
362 {
363   /* we only do this for properties */
364   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget");
365   IIFORMAT_HAS_METHOD (widget, property);
366   IIFORMAT_HAS_METHOD (widget, set_property);
367
368   /* widget image-instantiator types - buttons */
369   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button");
370   IIFORMAT_HAS_SHARED_METHOD (button, validate, widget);
371   IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget);
372   IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget);
373
374   IIFORMAT_VALID_KEYWORD (button, Q_width, check_valid_int);
375   IIFORMAT_VALID_KEYWORD (button, Q_height, check_valid_int);
376   IIFORMAT_VALID_KEYWORD (button, Q_pixel_width, check_valid_int);
377   IIFORMAT_VALID_KEYWORD (button, Q_pixel_height, check_valid_int);
378   IIFORMAT_VALID_KEYWORD (button, Q_face, check_valid_face);
379   IIFORMAT_VALID_KEYWORD (button, Q_descriptor, check_valid_vector);
380   /* edit fields */
381   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit, "edit");
382   IIFORMAT_HAS_SHARED_METHOD (edit, validate, widget);
383   IIFORMAT_HAS_SHARED_METHOD (edit, possible_dest_types, widget);
384   IIFORMAT_HAS_SHARED_METHOD (edit, instantiate, widget);
385
386   IIFORMAT_VALID_KEYWORD (edit, Q_width, check_valid_int);
387   IIFORMAT_VALID_KEYWORD (edit, Q_height, check_valid_int);
388   IIFORMAT_VALID_KEYWORD (edit, Q_pixel_width, check_valid_int);
389   IIFORMAT_VALID_KEYWORD (edit, Q_pixel_height, check_valid_int);
390   IIFORMAT_VALID_KEYWORD (edit, Q_face, check_valid_face);
391   IIFORMAT_VALID_KEYWORD (edit, Q_descriptor, check_valid_vector);
392   /* combo box */
393   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo, "combo");
394   IIFORMAT_HAS_METHOD (combo, validate);
395   IIFORMAT_HAS_SHARED_METHOD (combo, possible_dest_types, widget);
396   IIFORMAT_HAS_METHOD (combo, instantiate);
397
398   IIFORMAT_VALID_KEYWORD (combo, Q_width, check_valid_int);
399   IIFORMAT_VALID_KEYWORD (combo, Q_height, check_valid_int);
400   IIFORMAT_VALID_KEYWORD (combo, Q_pixel_width, check_valid_int);
401   IIFORMAT_VALID_KEYWORD (combo, Q_face, check_valid_face);
402   IIFORMAT_VALID_KEYWORD (combo, Q_descriptor, check_valid_vector);
403   IIFORMAT_VALID_KEYWORD (combo, Q_properties, check_valid_item_list);
404   /* scrollbar */
405   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar");
406   IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget);
407   IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget);
408   IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget);
409
410   IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, check_valid_int);
411   IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, check_valid_int);
412   IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face);
413   IIFORMAT_VALID_KEYWORD (scrollbar, Q_descriptor, check_valid_vector);
414   /* labels */
415   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label");
416   IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget);
417   IIFORMAT_HAS_SHARED_METHOD (label, instantiate, static);
418
419   IIFORMAT_VALID_KEYWORD (label, Q_pixel_width, check_valid_int);
420   IIFORMAT_VALID_KEYWORD (label, Q_pixel_height, check_valid_int);
421   IIFORMAT_VALID_KEYWORD (label, Q_width, check_valid_int);
422   IIFORMAT_VALID_KEYWORD (label, Q_height, check_valid_int);
423   IIFORMAT_VALID_KEYWORD (label, Q_face, check_valid_face);
424   IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string);
425 #if 0
426   /* group */
427   INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (group, "group");
428   IIFORMAT_HAS_SHARED_METHOD (group, possible_dest_types, widget);
429   IIFORMAT_HAS_METHOD (group, instantiate);
430
431   IIFORMAT_VALID_KEYWORD (group, Q_width, check_valid_int);
432   IIFORMAT_VALID_KEYWORD (group, Q_height, check_valid_int);
433   IIFORMAT_VALID_KEYWORD (group, Q_pixel_width, check_valid_int);
434   IIFORMAT_VALID_KEYWORD (group, Q_pixel_height, check_valid_int);
435   IIFORMAT_VALID_KEYWORD (group, Q_face, check_valid_face);
436   IIFORMAT_VALID_KEYWORD (group, Q_background, check_valid_string);
437   IIFORMAT_VALID_KEYWORD (group, Q_descriptor, check_valid_string);
438 #endif
439 }
440
441 void
442 vars_of_glyphs_widget (void)
443 {
444 }