Mercurial > hg > xemacs-beta
annotate src/glyphs-widget.c @ 5159:cb303ff63e76
merge
| author | Ben Wing <ben@xemacs.org> |
|---|---|
| date | Fri, 19 Mar 2010 17:02:11 -0500 |
| parents | 07dcc7000bbf |
| children | 8b2f75cecb89 |
| rev | line source |
|---|---|
| 428 | 1 /* Widget-specific glyph objects. |
| 863 | 2 Copyright (C) 1998, 1999, 2000, 2002 Andy Piper. |
| 1318 | 3 Copyright (C) 2003 Ben Wing. |
| 428 | 4 |
| 5 This file is part of XEmacs. | |
| 6 | |
| 7 XEmacs is free software; you can redistribute it and/or modify it | |
| 8 under the terms of the GNU General Public License as published by the | |
| 9 Free Software Foundation; either version 2, or (at your option) any | |
| 10 later version. | |
| 11 | |
| 12 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
| 13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| 15 for more details. | |
| 16 | |
| 17 You should have received a copy of the GNU General Public License | |
| 18 along with XEmacs; see the file COPYING. If not, write to | |
| 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
| 20 Boston, MA 02111-1307, USA. */ | |
| 21 | |
| 22 /* Synched up with: Not in FSF. */ | |
| 23 | |
| 24 /* written by Andy Piper <andy@xemacs.org> */ | |
| 25 | |
| 26 #include <config.h> | |
| 27 #include "lisp.h" | |
| 800 | 28 |
| 29 #include "bytecode.h" | |
| 428 | 30 #include "console.h" |
| 872 | 31 #include "device-impl.h" |
| 428 | 32 #include "faces.h" |
| 800 | 33 #include "frame.h" |
| 428 | 34 #include "glyphs.h" |
| 800 | 35 #include "gui.h" |
| 36 #include "insdel.h" | |
| 37 #include "lstream.h" | |
| 428 | 38 #include "objects.h" |
| 800 | 39 #include "opaque.h" |
| 428 | 40 #include "window.h" |
| 41 | |
| 42 DEFINE_IMAGE_INSTANTIATOR_FORMAT (button); | |
| 43 DEFINE_IMAGE_INSTANTIATOR_FORMAT (combo_box); | |
| 44 Lisp_Object Qcombo_box; | |
| 45 DEFINE_IMAGE_INSTANTIATOR_FORMAT (edit_field); | |
| 46 Lisp_Object Qedit_field; | |
| 47 DEFINE_IMAGE_INSTANTIATOR_FORMAT (scrollbar); | |
| 48 Lisp_Object Qscrollbar; | |
| 49 DEFINE_IMAGE_INSTANTIATOR_FORMAT (widget); | |
| 50 DEFINE_IMAGE_INSTANTIATOR_FORMAT (label); | |
| 51 Lisp_Object Qlabel; | |
| 52 DEFINE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge); | |
| 53 Lisp_Object Qprogress_gauge; | |
| 54 DEFINE_IMAGE_INSTANTIATOR_FORMAT (tree_view); | |
| 55 Lisp_Object Qtree_view; | |
| 56 DEFINE_IMAGE_INSTANTIATOR_FORMAT (tab_control); | |
| 57 Lisp_Object Qtab_control; | |
| 58 DEFINE_IMAGE_INSTANTIATOR_FORMAT (layout); | |
| 59 Lisp_Object Qlayout; | |
| 442 | 60 DEFINE_IMAGE_INSTANTIATOR_FORMAT (native_layout); |
| 61 Lisp_Object Qnative_layout; | |
| 428 | 62 |
| 63 Lisp_Object Qetched_in, Qetched_out, Qbevel_in, Qbevel_out; | |
| 442 | 64 Lisp_Object Qmake_glyph; |
| 863 | 65 Lisp_Object Vwidget_border_width; |
| 66 | |
| 67 static int widget_border_width (Lisp_Object domain); | |
| 68 static int widget_spacing (Lisp_Object domain); | |
| 69 static void widget_query_string_geometry (Lisp_Object string, Lisp_Object face, | |
| 70 int *width, int *height, Lisp_Object domain); | |
| 428 | 71 |
| 1068 | 72 #define BORDER_FIDDLE_FACTOR 10 |
| 428 | 73 #ifdef DEBUG_WIDGETS |
| 74 int debug_widget_instances; | |
| 75 #endif | |
| 76 | |
| 77 /* TODO: | |
| 438 | 78 - tooltips for controls, especially buttons. |
| 440 | 79 - keyboard traversal. |
| 80 - lisp configurable layout. | |
| 428 | 81 */ |
| 82 | |
| 438 | 83 /* In MS-Windows normal windows work in pixels, dialog boxes work in |
| 428 | 84 dialog box units. Why? sigh. We could reuse the metrics for dialogs |
| 85 if this were not the case. As it is we have to position things | |
| 86 pixel wise. I'm not even sure that X has this problem at least for | |
| 87 buttons in groups. */ | |
| 88 static int | |
| 89 widget_possible_dest_types (void) | |
| 90 { | |
| 91 return IMAGE_WIDGET_MASK; | |
| 92 } | |
| 93 | |
| 94 static void | |
| 442 | 95 check_valid_instantiator (Lisp_Object data) |
| 428 | 96 { |
| 97 Lisp_Object glyph = data; | |
| 98 if (SYMBOLP (data)) | |
| 99 glyph = XSYMBOL (data)->value; | |
| 100 | |
| 442 | 101 if (!CONSP (glyph) && !VECTORP (glyph)) |
| 102 invalid_argument ("instantiator item must be a vector", data); | |
| 428 | 103 } |
| 104 | |
| 105 static void | |
| 106 check_valid_orientation (Lisp_Object data) | |
| 107 { | |
| 108 if (!EQ (data, Qhorizontal) | |
| 109 && | |
| 110 !EQ (data, Qvertical)) | |
| 563 | 111 invalid_constant ("unknown orientation for layout", data); |
| 428 | 112 } |
| 113 | |
| 114 static void | |
| 438 | 115 check_valid_tab_orientation (Lisp_Object data) |
| 116 { | |
| 117 if (!EQ (data, Qtop) | |
| 118 && | |
| 119 !EQ (data, Qbottom) | |
| 120 && | |
| 121 !EQ (data, Qleft) | |
| 122 && | |
| 123 !EQ (data, Qright)) | |
| 563 | 124 invalid_constant ("unknown orientation for tab control", data); |
| 438 | 125 } |
| 126 | |
| 127 static void | |
| 428 | 128 check_valid_justification (Lisp_Object data) |
| 129 { | |
| 863 | 130 if (!EQ (data, Qleft) |
| 131 && | |
| 132 !EQ (data, Qright) | |
| 133 && | |
| 134 !EQ (data, Qtop) | |
| 135 && | |
| 136 !EQ (data, Qbottom) | |
| 137 && | |
| 138 !EQ (data, Qcenter)) | |
| 563 | 139 invalid_constant ("unknown justification for layout", data); |
| 428 | 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)) | |
| 442 | 148 invalid_argument ("unknown border style for layout", data); |
| 428 | 149 } |
| 150 | |
| 151 static void | |
| 2286 | 152 check_valid_anything (Lisp_Object UNUSED (data)) |
| 428 | 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 { | |
| 442 | 163 invalid_argument (":callback must be a function or expression", data); |
| 428 | 164 } |
| 165 } | |
| 166 | |
| 167 static void | |
| 442 | 168 check_valid_int_or_function (Lisp_Object data) |
| 169 { | |
| 458 | 170 if (!INTP (data) && !CONSP (data) && !SYMBOLP (data)) |
| 442 | 171 invalid_argument ("must be an integer or expresssion", data); |
| 172 } | |
| 173 | |
| 174 static void | |
| 428 | 175 check_valid_symbol (Lisp_Object data) |
| 176 { | |
| 177 CHECK_SYMBOL (data); | |
| 178 } | |
| 179 | |
| 180 static void | |
| 181 check_valid_string_or_vector (Lisp_Object data) | |
| 182 { | |
| 183 if (!STRINGP (data) && !VECTORP (data)) | |
| 442 | 184 invalid_argument (":descriptor must be a string or a vector", data); |
| 428 | 185 } |
| 186 | |
| 793 | 187 static void |
| 442 | 188 check_valid_item_list (Lisp_Object items) |
| 428 | 189 { |
| 2367 | 190 EXTERNAL_LIST_LOOP_2 (elt, items) |
| 428 | 191 { |
| 2367 | 192 if (STRINGP (elt)) |
| 193 CHECK_STRING (elt); | |
| 194 else if (VECTORP (elt)) | |
| 195 gui_parse_item_keywords (elt); | |
| 196 else if (LISTP (elt)) | |
| 197 check_valid_item_list (elt); | |
| 428 | 198 else |
| 2367 | 199 invalid_argument ("Item must be vector, list or string", elt); |
| 428 | 200 } |
| 201 } | |
| 202 | |
| 203 static void | |
| 442 | 204 check_valid_instantiator_list (Lisp_Object data) |
| 428 | 205 { |
| 2367 | 206 EXTERNAL_LIST_LOOP_2 (elt, data) |
| 428 | 207 { |
| 2367 | 208 check_valid_instantiator (elt); |
| 428 | 209 } |
| 210 } | |
| 211 | |
| 212 static Lisp_Object | |
| 213 glyph_instantiator_to_glyph (Lisp_Object sym) | |
| 214 { | |
| 215 /* This function calls lisp. */ | |
| 216 Lisp_Object glyph = sym; | |
| 217 struct gcpro gcpro1; | |
| 442 | 218 |
| 428 | 219 GCPRO1 (glyph); |
| 220 /* if we have a symbol get at the actual data */ | |
| 221 if (SYMBOLP (glyph)) | |
| 222 glyph = XSYMBOL (glyph)->value; | |
| 442 | 223 |
| 428 | 224 if (CONSP (glyph)) |
|
4677
8f1ee2d15784
Support full Common Lisp multiple values in C.
Aidan Kehoe <kehoea@parhasard.net>
parents:
3466
diff
changeset
|
225 glyph = IGNORE_MULTIPLE_VALUES (Feval (glyph)); |
| 428 | 226 |
| 227 /* Be really helpful to the user. */ | |
| 228 if (VECTORP (glyph)) | |
| 229 { | |
| 442 | 230 glyph = call1 (Qmake_glyph, glyph); |
| 428 | 231 } |
| 232 | |
| 233 /* substitute the new glyph */ | |
| 234 RETURN_UNGCPRO (glyph); | |
| 235 } | |
| 236 | |
| 442 | 237 static void |
| 428 | 238 substitute_keyword_value (Lisp_Object inst, Lisp_Object key, Lisp_Object val) |
| 239 { | |
| 240 int i; | |
| 241 /* substitute the new glyph */ | |
| 242 for (i = 0; i < XVECTOR_LENGTH (inst); i++) | |
| 243 { | |
| 244 if (EQ (key, XVECTOR_DATA (inst)[i])) | |
| 245 { | |
| 246 XVECTOR_DATA (inst)[i+1] = val; | |
| 247 break; | |
| 248 } | |
| 249 } | |
| 250 } | |
| 251 | |
| 863 | 252 /* Determine the border with of the widget. */ |
| 253 static int | |
| 254 widget_border_width (Lisp_Object domain) | |
| 255 { | |
| 256 /* #### FIXME -- need to use specifiers (Vwidget_border_width) for | |
| 257 some portion of this. */ | |
| 258 if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), | |
| 259 widget_border_width)) | |
| 260 return DEVMETH (DOMAIN_XDEVICE (domain), widget_border_width, ()); | |
| 261 else | |
| 262 return DEFAULT_WIDGET_BORDER_WIDTH; | |
| 263 } | |
| 264 | |
| 265 static int | |
| 266 widget_instance_border_width (Lisp_Image_Instance* ii) | |
| 267 { | |
| 268 return widget_border_width (IMAGE_INSTANCE_DOMAIN (ii)); | |
| 269 } | |
| 270 | |
| 2297 | 271 /* #### It's not clear to me what the value of logical_unit_height should |
| 272 be, or whether it should even depend on the current image_instance. It | |
| 273 really should probably only depend on the default widget face and the | |
| 274 domain, however you can envisage users wanting different logical units | |
| 275 for nested layouts - so using the properties of the current layout is | |
| 276 probably not so dumb. */ | |
| 863 | 277 static int |
| 278 logical_unit_height (Lisp_Object text, Lisp_Object face, Lisp_Object domain) | |
| 279 { | |
| 280 int charheight = 0; | |
| 281 widget_query_string_geometry (text, face, | |
| 282 0, &charheight, domain); | |
| 283 /* For the returned value to be useful it needs to be big enough to | |
| 2297 | 284 accomodate the largest single-height widget. This is currently |
| 863 | 285 the edit-field. */ |
| 286 return charheight + 2 * widget_spacing (domain) | |
| 287 + 4 * widget_border_width (domain); | |
| 288 } | |
| 289 | |
| 290 static int | |
| 291 widget_logical_unit_height (Lisp_Image_Instance* ii) | |
| 292 { | |
| 293 return logical_unit_height (NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii)) ? | |
| 866 | 294 NILP (IMAGE_INSTANCE_NAME (ii)) ? |
| 295 Fsymbol_name (Qwidget) | |
| 296 : IMAGE_INSTANCE_NAME (ii) | |
| 863 | 297 : IMAGE_INSTANCE_WIDGET_TEXT (ii), |
| 298 IMAGE_INSTANCE_WIDGET_FACE (ii), | |
| 299 IMAGE_INSTANCE_DOMAIN (ii)); | |
| 300 } | |
| 301 | |
| 438 | 302 /* Wire widget property invocations to specific widgets. The problem |
| 303 we are solving here is that when instantiators get converted to | |
| 304 instances they lose some type information (they just become | |
| 305 subwindows or widgets for example). For widgets we need to preserve | |
| 306 this type information so that we can do widget specific operations | |
| 307 on the instances. This is encoded in the widget type | |
| 308 field. widget_property gets invoked by decoding the primary type | |
| 309 (Qwidget), <widget>_property then invokes based on the secondary | |
| 310 type (Qedit_field for example). It is debatable whether we should | |
| 311 wire things in this generalised way rather than treating widgets | |
| 312 specially in image_instance_property. */ | |
| 442 | 313 static Lisp_Object |
| 428 | 314 widget_property (Lisp_Object image_instance, Lisp_Object prop) |
| 315 { | |
| 440 | 316 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); |
| 428 | 317 struct image_instantiator_methods* meths; |
| 442 | 318 #if 0 /* The usefulness of this is dubious. */ |
| 428 | 319 /* first see if its a general property ... */ |
| 320 if (!NILP (Fplist_member (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop))) | |
| 321 return Fplist_get (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, Qnil); | |
| 442 | 322 #endif |
| 428 | 323 /* .. then try device specific methods ... */ |
| 442 | 324 meths = decode_device_ii_format (image_instance_device (image_instance), |
| 325 IMAGE_INSTANCE_WIDGET_TYPE (ii), | |
| 428 | 326 ERROR_ME_NOT); |
| 327 if (meths && HAS_IIFORMAT_METH_P (meths, property)) | |
| 328 return IIFORMAT_METH (meths, property, (image_instance, prop)); | |
| 329 /* ... then format specific methods ... */ | |
| 442 | 330 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), |
| 428 | 331 ERROR_ME_NOT); |
| 332 if (meths && HAS_IIFORMAT_METH_P (meths, property)) | |
| 333 return IIFORMAT_METH (meths, property, (image_instance, prop)); | |
| 334 /* ... then fail */ | |
| 335 return Qunbound; | |
| 336 } | |
| 337 | |
| 442 | 338 /* Update the displayed properties of a widget. |
| 339 | |
| 340 #### This has been adapted from the original set_property functions | |
| 341 and thus reuses the state management of that. A better solution is | |
| 342 to simply re-parse the instantiator when items need updating. This | |
| 343 make comparing differences much simpler and obviates the need for a | |
| 344 lot of the state variables. | |
| 345 | |
| 346 #### property is still a valid function since we have to be able to | |
| 347 extract information from the actual widget. | |
| 348 | |
| 3094 | 349 #### widget_update should probably be re-written to use the |
| 442 | 350 instantiator. We probably want to keep a record of the differences |
| 351 also to make this easy. We would also need a pending_instantiator | |
| 352 so that changes could be delayed. */ | |
| 353 static void | |
| 354 widget_update (Lisp_Object image_instance, Lisp_Object instantiator) | |
| 428 | 355 { |
| 440 | 356 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); |
| 428 | 357 struct image_instantiator_methods* meths; |
| 454 | 358 struct gcpro gcpro1; |
| 428 | 359 |
| 442 | 360 Lisp_Object text = find_keyword_in_vector (instantiator, Q_text); |
| 454 | 361 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); |
| 362 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items); | |
| 363 Lisp_Object descriptor_item = Qnil; | |
| 364 | |
| 365 GCPRO1 (descriptor_item); | |
| 366 | |
| 442 | 367 /* Pick up any generic properties that we might need to keep hold |
| 454 | 368 of. |
| 369 #### This is potentially bogus because it is changing the items | |
| 370 in place rather than in the pending items. */ | |
| 442 | 371 if (!NILP (text)) |
| 438 | 372 { |
| 442 | 373 IMAGE_INSTANCE_WIDGET_TEXT (ii) = text; |
| 374 IMAGE_INSTANCE_TEXT_CHANGED (ii) = 1; | |
| 438 | 375 } |
| 376 | |
| 454 | 377 /* Retrieve the gui item information. This is easy if we have been |
| 378 provided with a vector, more difficult if we have just been given | |
| 379 keywords. | |
| 380 | |
| 381 #### This is inconsistent with instantiation in that you have to | |
| 382 have the :descriptor keyword for updates in order to recognise | |
| 383 changes. */ | |
| 384 if (VECTORP (desc)) | |
| 385 { | |
| 386 descriptor_item = gui_parse_item_keywords_no_errors (desc); | |
| 387 } | |
| 388 else | |
| 389 { | |
| 390 /* Since we are updating the instantiator could be incomplete | |
| 391 and hence the gui item descriptor not well formed. We | |
| 392 therefore try updating and discard the results if nothing | |
| 393 changed. */ | |
| 394 descriptor_item = copy_gui_item (IMAGE_INSTANCE_WIDGET_ITEM (ii)); | |
| 395 if (!update_gui_item_keywords (descriptor_item, instantiator)) | |
| 396 descriptor_item = Qnil; | |
| 397 } | |
| 398 | |
| 399 /* Record new items for update. *_redisplay will do the | |
| 400 rest. */ | |
| 401 if (!EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout) | |
| 402 && | |
| 403 !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout)) | |
| 404 { | |
| 405 if (!NILP (items)) | |
| 406 { | |
| 407 if (NILP (descriptor_item)) | |
| 408 descriptor_item = IMAGE_INSTANCE_WIDGET_ITEM (ii); | |
| 409 | |
| 410 check_valid_item_list (items); | |
| 411 #ifdef DEBUG_WIDGET_OUTPUT | |
| 412 stderr_out ("items for widget %p updated\n", | |
| 413 IMAGE_INSTANCE_SUBWINDOW_ID (ii)); | |
| 414 #endif | |
| 415 /* Don't set the actual items since we might decide not to use | |
| 416 the new ones (because nothing has really changed). If we did | |
| 417 set them and didn't use them then we would get into whole | |
| 418 heaps of trouble when the old items get GC'd. */ | |
| 419 descriptor_item = Fcons (descriptor_item, parse_gui_item_tree_children (items)); | |
| 420 } | |
| 421 /* If the descriptor was updated but not the items we need to fill | |
| 422 in the `new' items. */ | |
| 423 else if (!NILP (descriptor_item) | |
| 424 && | |
| 425 CONSP (IMAGE_INSTANCE_WIDGET_ITEMS (ii))) | |
| 426 { | |
| 427 descriptor_item = Fcons | |
| 428 (descriptor_item, | |
| 429 copy_gui_item_tree (XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)))); | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 if (!NILP (descriptor_item)) | |
| 434 { | |
| 435 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = descriptor_item; | |
| 436 IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii) = 1; | |
| 437 } | |
| 438 | |
| 439 UNGCPRO; | |
| 440 | |
| 438 | 441 /* Now try device specific methods first ... */ |
| 442 | 442 meths = decode_device_ii_format (image_instance_device (image_instance), |
| 443 IMAGE_INSTANCE_WIDGET_TYPE (ii), | |
| 444 ERROR_ME_NOT); | |
| 445 MAYBE_IIFORMAT_METH (meths, update, (image_instance, instantiator)); | |
| 446 /* ... then format specific methods ... */ | |
| 447 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), | |
| 448 ERROR_ME_NOT); | |
| 449 MAYBE_IIFORMAT_METH (meths, update, (image_instance, instantiator)); | |
| 450 #if 0 /* The usefulness of this is dubious. */ | |
| 451 /* we didn't do any device specific properties, so shove the property in our plist. */ | |
| 452 IMAGE_INSTANCE_WIDGET_PROPS (ii) | |
| 453 = Fplist_put (IMAGE_INSTANCE_WIDGET_PROPS (ii), prop, val); | |
| 454 #endif | |
| 455 } | |
| 456 | |
| 457 /* Like the rest of redisplay, we want widget updates to occur | |
| 458 asynchronously. Thus toolkit specific methods for setting | |
| 459 properties must be called by redisplay instead of by *_update. Thus | |
| 460 *_update records the change and this function actually implements | |
| 461 it. We want to be slightly clever about this however by supplying | |
| 462 format specific functions for the updates instead of lumping them | |
| 463 all into this function. Note that there is no need for format | |
| 464 generic functions. This is not the same as widget_update! */ | |
| 465 void | |
| 466 redisplay_widget (Lisp_Object widget) | |
| 467 { | |
| 468 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (widget); | |
| 469 struct image_instantiator_methods* meths; | |
| 470 | |
| 471 if (!WIDGET_IMAGE_INSTANCEP (widget) | |
| 472 || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout) | |
| 473 || EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout)) | |
| 474 return; | |
| 475 | |
| 476 /* Device-format specific methods - e.g. x_tab_control_redisplay () */ | |
| 477 meths = decode_device_ii_format (image_instance_device (widget), | |
| 428 | 478 IMAGE_INSTANCE_WIDGET_TYPE (ii), |
| 479 ERROR_ME_NOT); | |
| 442 | 480 MAYBE_IIFORMAT_METH (meths, redisplay, (widget)); |
| 481 | |
| 482 /* Device generic methods - e.g. x_redisplay_widget (). We must | |
| 483 update the widget's size as it may have been changed by the the | |
| 484 layout routines. We also do this here so that explicit resizing | |
| 485 from lisp does not result in synchronous updates. Do this last so | |
| 486 that format-specific methods have an opportunity to prevent | |
| 487 wholesale changes - e.g. rebuilding tabs. */ | |
| 863 | 488 MAYBE_DEVMETH (DOMAIN_XDEVICE (IMAGE_INSTANCE_DOMAIN (ii)), |
| 489 redisplay_widget, (ii)); | |
| 442 | 490 |
| 491 /* Pick up the items we recorded earlier. */ | |
| 492 if (IMAGE_INSTANCE_WIDGET_ITEMS_CHANGED (ii)) | |
| 428 | 493 { |
| 442 | 494 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = |
| 495 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii); | |
| 496 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil; | |
| 428 | 497 } |
| 498 } | |
| 499 | |
| 771 | 500 static void |
| 501 widget_query_string_geometry (Lisp_Object string, Lisp_Object face, | |
| 502 int *width, int *height, Lisp_Object domain) | |
| 503 { | |
| 504 struct device *d = DOMAIN_XDEVICE (domain); | |
| 505 | |
| 506 if (HAS_DEVMETH_P (d, widget_query_string_geometry)) | |
| 507 DEVMETH (d, widget_query_string_geometry, | |
| 508 (string, face, width, height, domain)); | |
| 509 else | |
| 510 query_string_geometry (string, face, width, height, 0, domain); | |
| 511 | |
| 512 } | |
| 513 | |
| 863 | 514 /* Determine the spacing of the widget. */ |
| 515 static int | |
| 516 widget_spacing (Lisp_Object domain) | |
| 517 { | |
| 518 if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), widget_spacing)) | |
| 519 return DEVMETH (DOMAIN_XDEVICE (domain), | |
| 520 widget_spacing, (0)); | |
| 521 else | |
| 522 return DEFAULT_WIDGET_SPACING; | |
| 523 } | |
| 524 | |
| 438 | 525 /* Query for a widgets desired geometry. If no type specific method is |
| 526 provided then use the widget text to calculate sizes. */ | |
| 442 | 527 static void |
| 528 widget_query_geometry (Lisp_Object image_instance, | |
| 529 int* width, int* height, | |
| 438 | 530 enum image_instance_geometry disp, Lisp_Object domain) |
| 531 { | |
| 440 | 532 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); |
| 438 | 533 struct image_instantiator_methods* meths; |
| 442 | 534 Lisp_Object dynamic_width = Qnil; |
| 535 Lisp_Object dynamic_height = Qnil; | |
| 438 | 536 |
| 537 /* First just set up what we already have. */ | |
| 538 if (width) *width = IMAGE_INSTANCE_WIDTH (ii); | |
| 539 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii); | |
| 442 | 540 |
| 438 | 541 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) |
| 542 || | |
| 543 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) | |
| 544 { | |
| 545 /* .. then try device specific methods ... */ | |
| 442 | 546 meths = decode_device_ii_format (image_instance_device (image_instance), |
| 547 IMAGE_INSTANCE_WIDGET_TYPE (ii), | |
| 438 | 548 ERROR_ME_NOT); |
| 549 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry)) | |
| 442 | 550 IIFORMAT_METH (meths, query_geometry, (image_instance, |
| 438 | 551 width, height, disp, |
| 552 domain)); | |
| 553 else | |
| 554 { | |
| 555 /* ... then format specific methods ... */ | |
| 442 | 556 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), |
| 438 | 557 ERROR_ME_NOT); |
| 558 if (meths && HAS_IIFORMAT_METH_P (meths, query_geometry)) | |
| 442 | 559 IIFORMAT_METH (meths, query_geometry, (image_instance, |
| 438 | 560 width, height, disp, |
| 561 domain)); | |
| 442 | 562 else |
| 438 | 563 { |
| 442 | 564 int w, h; |
| 565 | |
| 438 | 566 /* Then if we are allowed to resize the widget, make the |
| 567 size the same as the text dimensions. */ | |
| 771 | 568 widget_query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii), |
| 569 IMAGE_INSTANCE_WIDGET_FACE (ii), | |
| 570 &w, &h, domain); | |
| 438 | 571 /* Adjust the size for borders. */ |
| 3466 | 572 if (width && IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) |
| 863 | 573 *width = w + 2 * widget_instance_border_width (ii); |
| 3466 | 574 if (height && IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)) |
| 863 | 575 *height = h + 2 * widget_instance_border_width (ii); |
| 438 | 576 } |
| 577 } | |
| 442 | 578 /* Finish off with dynamic sizing. */ |
| 3466 | 579 if (width && !NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii))) |
| 442 | 580 { |
| 853 | 581 dynamic_width = |
| 582 eval_within_redisplay (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)); | |
| 442 | 583 if (INTP (dynamic_width)) |
| 584 *width = XINT (dynamic_width); | |
| 585 } | |
| 3466 | 586 if (height && !NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii))) |
| 442 | 587 { |
| 853 | 588 dynamic_height = |
| 589 eval_within_redisplay (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)); | |
| 442 | 590 if (INTP (dynamic_height)) |
| 591 *height = XINT (dynamic_height); | |
| 592 } | |
| 438 | 593 } |
| 594 } | |
| 595 | |
| 442 | 596 static int |
| 597 widget_layout (Lisp_Object image_instance, | |
| 598 int width, int height, int xoffset, int yoffset, | |
| 599 Lisp_Object domain) | |
| 438 | 600 { |
| 440 | 601 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); |
| 438 | 602 struct image_instantiator_methods* meths; |
| 603 | |
| 604 /* .. then try device specific methods ... */ | |
| 442 | 605 meths = decode_device_ii_format (image_instance_device (image_instance), |
| 606 IMAGE_INSTANCE_WIDGET_TYPE (ii), | |
| 438 | 607 ERROR_ME_NOT); |
| 608 if (meths && HAS_IIFORMAT_METH_P (meths, layout)) | |
| 442 | 609 return IIFORMAT_METH (meths, layout, (image_instance, |
| 610 width, height, xoffset, yoffset, | |
| 611 domain)); | |
| 438 | 612 else |
| 613 { | |
| 614 /* ... then format specific methods ... */ | |
| 442 | 615 meths = decode_device_ii_format (Qnil, IMAGE_INSTANCE_WIDGET_TYPE (ii), |
| 438 | 616 ERROR_ME_NOT); |
| 617 if (meths && HAS_IIFORMAT_METH_P (meths, layout)) | |
| 442 | 618 return IIFORMAT_METH (meths, layout, (image_instance, |
| 619 width, height, xoffset, yoffset, | |
| 620 domain)); | |
| 438 | 621 } |
| 442 | 622 return 1; |
| 438 | 623 } |
| 624 | |
| 428 | 625 static void |
| 626 widget_validate (Lisp_Object instantiator) | |
| 627 { | |
| 628 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); | |
| 629 | |
| 630 if (NILP (desc)) | |
| 563 | 631 invalid_argument ("Must supply :descriptor", instantiator); |
| 428 | 632 |
| 633 if (VECTORP (desc)) | |
| 634 gui_parse_item_keywords (desc); | |
| 635 | |
| 636 if (!NILP (find_keyword_in_vector (instantiator, Q_width)) | |
| 637 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_width))) | |
| 563 | 638 invalid_argument ("Must supply only one of :width and :pixel-width", instantiator); |
| 428 | 639 |
| 640 if (!NILP (find_keyword_in_vector (instantiator, Q_height)) | |
| 641 && !NILP (find_keyword_in_vector (instantiator, Q_pixel_height))) | |
| 563 | 642 invalid_argument ("Must supply only one of :height and :pixel-height", instantiator); |
| 428 | 643 } |
| 644 | |
| 645 static void | |
| 646 combo_box_validate (Lisp_Object instantiator) | |
| 647 { | |
| 648 widget_validate (instantiator); | |
| 442 | 649 if (NILP (find_keyword_in_vector (instantiator, Q_items))) |
| 563 | 650 invalid_argument ("Must supply item list", instantiator); |
| 428 | 651 } |
| 652 | |
| 653 /* we need to convert things like glyphs to images, eval expressions | |
| 654 etc.*/ | |
| 655 static Lisp_Object | |
| 2286 | 656 widget_normalize (Lisp_Object inst, Lisp_Object UNUSED (console_type), |
| 657 Lisp_Object UNUSED (dest_mask)) | |
| 428 | 658 { |
| 659 /* This function can call lisp */ | |
| 660 Lisp_Object glyph = find_keyword_in_vector (inst, Q_image); | |
| 661 | |
| 662 /* we need to eval glyph if its an expression, we do this for the | |
| 442 | 663 same reasons we normalize file to data. |
| 664 | |
| 665 #### should just normalize the data. */ | |
| 428 | 666 if (!NILP (glyph)) |
| 667 { | |
| 1318 | 668 substitute_keyword_value (inst, Q_image, |
| 669 glyph_instantiator_to_glyph (glyph)); | |
| 428 | 670 } |
| 671 | |
| 672 return inst; | |
| 673 } | |
| 674 | |
| 675 static void | |
| 440 | 676 initialize_widget_image_instance (Lisp_Image_Instance *ii, Lisp_Object type) |
| 428 | 677 { |
| 678 /* initialize_subwindow_image_instance (ii);*/ | |
| 679 IMAGE_INSTANCE_WIDGET_TYPE (ii) = type; | |
| 680 IMAGE_INSTANCE_WIDGET_PROPS (ii) = Qnil; | |
| 438 | 681 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Qnil); |
| 428 | 682 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = allocate_gui_item (); |
| 442 | 683 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = Qnil; |
| 684 IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii) = Qnil; | |
| 685 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = Qnil; | |
| 686 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = Qnil; | |
| 438 | 687 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 1; |
| 688 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 1; | |
| 442 | 689 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_HORIZONTAL; |
| 863 | 690 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = 0; |
| 691 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = 0; | |
| 428 | 692 } |
| 693 | |
| 694 /* Instantiate a button widget. Unfortunately instantiated widgets are | |
| 695 particular to a frame since they need to have a parent. It's not | |
| 696 like images where you just select the image into the context you | |
| 697 want to display it in and BitBlt it. So image instances can have a | |
| 698 many-to-one relationship with things you see, whereas widgets can | |
| 699 only be one-to-one (i.e. per frame) */ | |
| 700 void | |
| 438 | 701 widget_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, |
| 702 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
| 703 int dest_mask, Lisp_Object domain) | |
| 428 | 704 { |
| 442 | 705 /* #### practically all of this should be moved to widget_update() |
| 706 so that users can dynamically change all possible widget | |
| 707 properties. */ | |
| 440 | 708 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
| 428 | 709 Lisp_Object face = find_keyword_in_vector (instantiator, Q_face); |
| 710 Lisp_Object height = find_keyword_in_vector (instantiator, Q_height); | |
| 711 Lisp_Object width = find_keyword_in_vector (instantiator, Q_width); | |
| 712 Lisp_Object pixwidth = find_keyword_in_vector (instantiator, Q_pixel_width); | |
| 713 Lisp_Object pixheight = find_keyword_in_vector (instantiator, Q_pixel_height); | |
| 714 Lisp_Object desc = find_keyword_in_vector (instantiator, Q_descriptor); | |
| 715 Lisp_Object glyph = find_keyword_in_vector (instantiator, Q_image); | |
| 440 | 716 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items); |
| 438 | 717 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation); |
| 442 | 718 Lisp_Object mwidth = find_keyword_in_vector (instantiator, Q_margin_width); |
| 719 Lisp_Object ifocus = find_keyword_in_vector (instantiator, Q_initial_focus); | |
| 428 | 720 int pw=0, ph=0, tw=0, th=0; |
| 442 | 721 |
| 428 | 722 /* this just does pixel type sizing */ |
| 723 subwindow_instantiate (image_instance, instantiator, pointer_fg, pointer_bg, | |
| 724 dest_mask, domain); | |
| 725 | |
| 442 | 726 if (!(dest_mask & IMAGE_WIDGET_MASK)) |
| 727 incompatible_image_types (instantiator, dest_mask, IMAGE_WIDGET_MASK); | |
| 428 | 728 |
| 729 initialize_widget_image_instance (ii, XVECTOR_DATA (instantiator)[0]); | |
| 730 | |
| 440 | 731 IMAGE_INSTANCE_TYPE (ii) = IMAGE_WIDGET; |
| 732 | |
| 428 | 733 /* retrieve the fg and bg colors */ |
| 734 if (!NILP (face)) | |
| 438 | 735 SET_IMAGE_INSTANCE_WIDGET_FACE (ii, Fget_face (face)); |
| 428 | 736 |
| 454 | 737 /* Retrieve the gui item information. This is easy if we have been |
| 428 | 738 provided with a vector, more difficult if we have just been given |
| 454 | 739 keywords. Note that standard gui descriptor shortcuts will not work |
| 740 because of keyword parsing. | |
| 741 | |
| 742 #### This is bogus in that descriptor and items share the same slot, | |
| 743 we should rationalize. */ | |
| 744 if (VECTORP (desc)) | |
| 745 { | |
| 746 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = | |
| 747 gui_parse_item_keywords_no_errors (desc); | |
| 748 } | |
| 749 else | |
| 428 | 750 { |
| 751 /* big cheat - we rely on the fact that a gui item looks like an instantiator */ | |
| 442 | 752 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = |
| 454 | 753 widget_gui_parse_item_keywords (instantiator); |
| 428 | 754 } |
| 755 | |
| 440 | 756 /* Pick up the orientation before we do our first layout. */ |
| 757 if (EQ (orient, Qleft) || EQ (orient, Qright) || EQ (orient, Qvertical)) | |
| 442 | 758 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL; |
| 440 | 759 |
| 428 | 760 /* parse more gui items out of the properties */ |
| 442 | 761 if (!NILP (items) && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qlayout) |
| 762 && !EQ (IMAGE_INSTANCE_WIDGET_TYPE (ii), Qnative_layout)) | |
| 428 | 763 { |
| 442 | 764 IMAGE_INSTANCE_WIDGET_ITEMS (ii) = |
| 765 Fcons (IMAGE_INSTANCE_WIDGET_ITEMS (ii), | |
| 766 parse_gui_item_tree_children (items)); | |
| 428 | 767 } |
| 768 | |
| 438 | 769 /* Normalize size information. We now only assign sizes if the user |
| 770 gives us some explicitly, or there are some constraints that we | |
| 771 can't change later on. Otherwise we postpone sizing until query | |
| 772 geometry gets called. */ | |
| 773 if (!NILP (pixwidth)) /* pixwidth takes precendent */ | |
| 774 { | |
| 442 | 775 if (!INTP (pixwidth)) |
| 776 IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii) = pixwidth; | |
| 777 else | |
| 778 { | |
| 779 pw = XINT (pixwidth); | |
| 780 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0; | |
| 781 } | |
| 438 | 782 } |
| 783 else if (!NILP (width)) | |
| 784 { | |
| 785 tw = XINT (width); | |
| 786 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0; | |
| 787 } | |
| 788 | |
| 428 | 789 if (!NILP (pixheight)) |
| 438 | 790 { |
| 442 | 791 if (!INTP (pixheight)) |
| 792 IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii) = pixheight; | |
| 793 else | |
| 794 { | |
| 795 ph = XINT (pixheight); | |
| 796 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0; | |
| 797 } | |
| 438 | 798 } |
| 799 else if (!NILP (height) && XINT (height) > 1) | |
| 800 { | |
| 801 th = XINT (height); | |
| 802 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0; | |
| 803 } | |
| 804 | |
| 805 /* Taking the default face information when the user has specified | |
| 806 size in characters is probably as good as any since the widget | |
| 807 face is more likely to be proportional and thus give inadequate | |
| 808 results. Using character sizes can only ever be approximate | |
| 863 | 809 anyway. :height is measured in logical characters which take into |
| 810 account the borders and spacing on widgets. */ | |
| 811 if (tw) | |
| 812 { | |
| 813 int charwidth; | |
|
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
4677
diff
changeset
|
814 default_face_font_info (domain, 0, 0, &charwidth, 0, 0); |
| 863 | 815 pw = ROUND_UP (charwidth * tw + 4 * widget_instance_border_width (ii), charwidth); |
| 816 } | |
| 817 | |
| 818 /* For heights the widget face is more appropriate. */ | |
| 819 if (th == 1) | |
| 438 | 820 { |
| 863 | 821 int charheight; |
| 822 if (!NILP (IMAGE_INSTANCE_WIDGET_TEXT (ii))) | |
| 823 { | |
| 824 widget_query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii), | |
| 825 IMAGE_INSTANCE_WIDGET_FACE (ii), | |
| 826 0, &charheight, domain); | |
| 827 } | |
| 828 else | |
| 829 { | |
|
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
4677
diff
changeset
|
830 default_face_font_info (domain, 0, 0, 0, &charheight, 0); |
| 863 | 831 } |
| 832 ph = (charheight + 2 * widget_instance_border_width (ii)) * th; | |
| 833 } | |
| 834 /* For heights > 1 use logical units. */ | |
| 835 else if (th > 1) | |
| 836 { | |
| 837 ph = widget_logical_unit_height (ii) * th; | |
| 438 | 838 } |
| 428 | 839 |
| 840 /* for a widget with an image pick up the dimensions from that */ | |
| 841 if (!NILP (glyph)) | |
| 842 { | |
| 438 | 843 if (!pw) |
| 863 | 844 pw = glyph_width (glyph, image_instance) + 2 * widget_instance_border_width (ii); |
| 438 | 845 if (!ph) |
| 863 | 846 ph = glyph_height (glyph, image_instance) + 2 * widget_instance_border_width (ii); |
| 438 | 847 IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) = 0; |
| 848 IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii) = 0; | |
| 428 | 849 } |
| 850 | |
| 442 | 851 /* Pick up the margin width. */ |
| 852 if (!NILP (mwidth)) | |
| 853 IMAGE_INSTANCE_MARGIN_WIDTH (ii) = XINT (mwidth); | |
| 854 | |
| 855 IMAGE_INSTANCE_WANTS_INITIAL_FOCUS (ii) = !NILP (ifocus); | |
| 438 | 856 |
| 442 | 857 /* Layout for the layout widget is premature at this point since the |
| 858 children will not have been instantiated. We can't instantiate | |
| 859 them until the device instantiation method for the layout has | |
| 860 been executed. We do however want to record any specified | |
| 861 dimensions. */ | |
| 862 if (pw) IMAGE_INSTANCE_WIDTH (ii) = pw; | |
| 863 if (ph) IMAGE_INSTANCE_HEIGHT (ii) = ph; | |
| 864 } | |
| 865 | |
| 866 static void | |
| 2286 | 867 widget_post_instantiate (Lisp_Object UNUSED (image_instance), |
| 868 #ifdef DEBUG_WIDGETS | |
| 869 Lisp_Object instantiator, | |
| 870 #else | |
| 871 Lisp_Object UNUSED (instantiator), | |
| 872 #endif | |
| 873 Lisp_Object UNUSED (domain)) | |
| 442 | 874 { |
| 428 | 875 #ifdef DEBUG_WIDGETS |
| 876 debug_widget_instances++; | |
| 877 stderr_out ("instantiated "); | |
| 878 debug_print (instantiator); | |
| 879 stderr_out ("%d widgets instantiated\n", debug_widget_instances); | |
| 880 #endif | |
| 881 } | |
| 882 | |
| 442 | 883 /* Get the geometry of a button control. We need to adjust the size |
| 884 depending on the type of button. */ | |
| 885 static void | |
| 886 button_query_geometry (Lisp_Object image_instance, | |
| 887 int* width, int* height, | |
| 2286 | 888 enum image_instance_geometry UNUSED (disp), |
| 889 Lisp_Object domain) | |
| 442 | 890 { |
| 891 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
| 892 int w, h; | |
| 771 | 893 widget_query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii), |
| 894 IMAGE_INSTANCE_WIDGET_FACE (ii), | |
| 895 &w, &h, domain); | |
| 442 | 896 /* Adjust the size for borders. */ |
| 897 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) | |
| 898 { | |
| 863 | 899 *width = w + 3 * widget_instance_border_width (ii); |
| 442 | 900 |
| 901 if (EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qradio) | |
| 902 || | |
| 903 EQ (XGUI_ITEM (IMAGE_INSTANCE_WIDGET_ITEM (ii))->style, Qtoggle)) | |
| 904 /* This is an approximation to the size of the actual button bit. */ | |
| 905 *width += 12; | |
| 906 } | |
| 907 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)) | |
| 863 | 908 *height = h + 3 * widget_instance_border_width (ii); |
| 909 } | |
| 910 | |
| 911 /* Get the geometry of an edit field. */ | |
| 912 static void | |
| 913 edit_field_query_geometry (Lisp_Object image_instance, | |
| 2286 | 914 int* width, int* height, |
| 915 enum image_instance_geometry UNUSED (disp), | |
| 916 Lisp_Object domain) | |
| 863 | 917 { |
| 918 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
| 919 int w, h; | |
| 920 widget_query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii), | |
| 921 IMAGE_INSTANCE_WIDGET_FACE (ii), | |
| 922 &w, &h, domain); | |
| 923 /* Adjust the size for borders. */ | |
| 924 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) | |
| 925 *width = w + 4 * widget_instance_border_width (ii); | |
| 926 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)) | |
| 927 *height = h + 4 * widget_instance_border_width (ii); | |
| 442 | 928 } |
| 929 | |
| 438 | 930 /* tree-view geometry - get the height right */ |
| 428 | 931 static void |
| 442 | 932 tree_view_query_geometry (Lisp_Object image_instance, |
| 933 int* width, int* height, | |
| 2286 | 934 enum image_instance_geometry UNUSED (disp), |
| 935 Lisp_Object domain) | |
| 428 | 936 { |
| 440 | 937 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
| 438 | 938 Lisp_Object items = IMAGE_INSTANCE_WIDGET_ITEMS (ii); |
| 939 | |
| 442 | 940 |
| 438 | 941 if (*width) |
| 942 { | |
| 943 /* #### what should this be. reconsider when X has tree views. */ | |
| 771 | 944 widget_query_string_geometry (IMAGE_INSTANCE_WIDGET_TEXT (ii), |
| 945 IMAGE_INSTANCE_WIDGET_FACE (ii), | |
| 946 width, 0, domain); | |
| 438 | 947 } |
| 948 if (*height) | |
| 949 { | |
| 950 int len, h; | |
| 863 | 951 /* #### widget face would be better here. */ |
|
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
4677
diff
changeset
|
952 default_face_font_info (domain, 0, 0, 0, &h, 0); |
| 438 | 953 GET_LIST_LENGTH (items, len); |
| 954 *height = len * h; | |
| 955 } | |
| 428 | 956 } |
| 957 | |
| 2297 | 958 /* Get the geometry of a tab control. This is based on the number of |
| 959 items and text therein in the tab control. */ | |
| 428 | 960 static void |
| 442 | 961 tab_control_query_geometry (Lisp_Object image_instance, |
| 962 int* width, int* height, | |
| 2286 | 963 enum image_instance_geometry UNUSED (disp), |
| 964 Lisp_Object domain) | |
| 428 | 965 { |
| 440 | 966 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
| 442 | 967 Lisp_Object items = XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii)); |
| 428 | 968 Lisp_Object rest; |
| 442 | 969 int tw = 0, th = 0; |
| 428 | 970 |
| 438 | 971 LIST_LOOP (rest, items) |
| 428 | 972 { |
| 442 | 973 int h, w; |
| 438 | 974 |
| 2297 | 975 /* #### Maybe we should allow items to be a list of strings? |
| 976 Ie, autoconvert "label" -> ["label" "label" :selected maybe-t]. | |
| 977 Maybe there's a better place (or several places) to do this? | |
| 978 If so, change image_instantiator_tab_control back to use | |
| 979 check_valid_item_list for checking Q_items. -- sjt */ | |
| 771 | 980 widget_query_string_geometry (XGUI_ITEM (XCAR (rest))->name, |
| 863 | 981 IMAGE_INSTANCE_WIDGET_FACE (ii), |
| 982 &w, &h, domain); | |
| 983 tw += 5 * widget_instance_border_width (ii); /* some bias */ | |
| 438 | 984 tw += w; |
| 863 | 985 th = max (th, h + 2 * widget_instance_border_width (ii)); |
| 428 | 986 } |
| 987 | |
| 438 | 988 /* Fixup returned values depending on orientation. */ |
| 989 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii)) | |
| 990 { | |
| 991 if (height) *height = tw; | |
| 992 if (width) *width = th; | |
| 993 } | |
| 994 else | |
| 995 { | |
| 996 if (height) *height = th; | |
| 997 if (width) *width = tw; | |
| 998 } | |
| 428 | 999 } |
| 1000 | |
| 442 | 1001 /* Determine whether only the order has changed for a tab. */ |
| 1318 | 1002 int |
| 1003 tab_control_order_only_changed (Lisp_Object image_instance) | |
| 442 | 1004 { |
| 1318 | 1005 /* Called within redisplay */ |
| 442 | 1006 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
| 1007 int found = 0, len, pending_len; | |
| 1008 Lisp_Object rest; | |
| 1009 | |
| 1010 /* Degenerate case. */ | |
| 1011 if (NILP (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))) | |
| 1012 return 1; | |
| 1013 | |
| 1014 /* See whether we just need a change in order. */ | |
| 1015 GET_LIST_LENGTH (IMAGE_INSTANCE_WIDGET_ITEMS (ii), len); | |
| 1016 GET_LIST_LENGTH (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii), | |
| 1017 pending_len); | |
| 1018 if (len == pending_len) | |
| 1019 { | |
| 1020 LIST_LOOP (rest, XCDR (IMAGE_INSTANCE_WIDGET_ITEMS (ii))) | |
| 1021 { | |
| 1022 Lisp_Object pending_rest; | |
| 1023 found = 0; | |
| 1024 LIST_LOOP (pending_rest, | |
| 1025 XCDR (IMAGE_INSTANCE_WIDGET_PENDING_ITEMS (ii))) | |
| 1026 { | |
| 1027 if (gui_item_equal_sans_selected (XCAR (rest), | |
| 1913 | 1028 XCAR (pending_rest), 0)) |
| 442 | 1029 { |
| 1030 found = 1; | |
| 1031 break; | |
| 1032 } | |
| 1033 } | |
| 1034 if (!found) | |
| 1035 break; | |
| 1036 } | |
| 1037 } | |
| 1038 return found; | |
| 1039 } | |
| 1040 | |
| 428 | 1041 |
| 1042 /***************************************************************************** | |
| 1043 * widget layout * | |
| 1044 *****************************************************************************/ | |
| 442 | 1045 /* We need to cascade normalization.*/ |
| 428 | 1046 static Lisp_Object |
| 442 | 1047 layout_normalize (Lisp_Object inst, Lisp_Object console_type, |
| 1048 Lisp_Object dest_mask) | |
| 428 | 1049 { |
| 1050 /* This function can call lisp */ | |
| 442 | 1051 struct gcpro gcpro1, gcpro2; |
| 1052 Lisp_Object alist = Qnil, new_items = Qnil, border; | |
| 1053 /* This function can call lisp */ | |
| 1054 Lisp_Object items; | |
| 1055 | |
| 1056 GCPRO2 (alist, new_items); | |
| 1057 alist = tagged_vector_to_alist (inst); | |
| 1058 items = assq_no_quit (Q_items, alist); | |
| 1059 | |
| 1060 /* We need to normalize sub-objects. */ | |
| 428 | 1061 if (!NILP (items)) |
| 1062 { | |
| 1063 Lisp_Object rest; | |
| 442 | 1064 LIST_LOOP (rest, XCDR (items)) |
| 428 | 1065 { |
| 442 | 1066 /* Substitute the new instantiator */ |
| 1067 new_items = Fcons (normalize_image_instantiator (XCAR (rest), | |
| 1068 console_type, dest_mask), | |
| 1069 new_items); | |
| 1070 } | |
| 1071 new_items = Fnreverse (new_items); | |
| 1072 Fsetcdr (items, new_items); | |
| 1073 } | |
| 1074 /* Normalize the border spec. */ | |
| 1075 border = assq_no_quit (Q_border, alist); | |
| 1076 if (!NILP (border) && VECTORP (XCDR (border))) | |
| 1077 { | |
| 1078 Fsetcdr (border, normalize_image_instantiator (XCDR (border), | |
| 1079 console_type, dest_mask)); | |
| 1080 } | |
| 1081 | |
| 1082 { | |
| 1083 Lisp_Object result = alist_to_tagged_vector (XVECTOR_DATA (inst)[0], | |
| 1084 alist); | |
| 1085 free_alist (alist); | |
| 1086 RETURN_UNGCPRO (result); | |
| 1087 } | |
| 1088 } | |
| 1089 | |
| 1090 /* Update the instances in the layout. */ | |
| 1091 static void | |
| 1092 layout_update (Lisp_Object image_instance, Lisp_Object instantiator) | |
| 1093 { | |
| 1094 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
| 1095 Lisp_Object items = find_keyword_in_vector (instantiator, Q_items); | |
| 1096 Lisp_Object border_inst = find_keyword_in_vector (instantiator, Q_border); | |
| 863 | 1097 Lisp_Object justify = find_keyword_in_vector (instantiator, Q_justify); |
| 1098 Lisp_Object hjustify = find_keyword_in_vector (instantiator, Q_horizontally_justify); | |
| 1099 Lisp_Object vjustify = find_keyword_in_vector (instantiator, Q_vertically_justify); | |
| 442 | 1100 Lisp_Object border = Qnil; |
| 1101 Lisp_Object children = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii); | |
| 1102 int structure_changed = 0; | |
| 1103 struct gcpro gcpro1; | |
| 1104 | |
| 863 | 1105 /* Pick up horizontal justification, left is the default.*/ |
| 1106 if (!NILP (hjustify)) | |
| 1107 { | |
| 1108 if (EQ (hjustify, Qright) || EQ (hjustify, Qbottom)) | |
| 1109 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_RIGHT; | |
| 1110 else if (EQ (hjustify, Qcenter)) | |
| 1111 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER; | |
| 1112 } | |
| 1113 /* If not set use general justification. */ | |
| 1114 else if (!NILP (justify)) | |
| 1115 { | |
| 1116 if (EQ (justify, Qright) || EQ (justify, Qbottom)) | |
| 1117 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_RIGHT; | |
| 1118 else if (EQ (justify, Qcenter)) | |
| 1119 IMAGE_INSTANCE_SUBWINDOW_H_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER; | |
| 1120 } | |
| 1121 | |
| 1122 /* Pick up vertical justification, top is the default. */ | |
| 1123 if (!NILP (vjustify)) | |
| 1124 { | |
| 1125 if (EQ (vjustify, Qright) || EQ (vjustify, Qbottom)) | |
| 1126 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_BOTTOM; | |
| 1127 else if (EQ (vjustify, Qcenter)) | |
| 1128 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER; | |
| 1129 } | |
| 1130 /* If not set use general justification. */ | |
| 1131 else if (!NILP (justify)) | |
| 1132 { | |
| 1133 if (EQ (justify, Qright) || EQ (justify, Qbottom)) | |
| 1134 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_BOTTOM; | |
| 1135 else if (EQ (justify, Qcenter)) | |
| 1136 IMAGE_INSTANCE_SUBWINDOW_V_JUSTIFY (ii) = LAYOUT_JUSTIFY_CENTER; | |
| 1137 } | |
| 1138 | |
| 442 | 1139 /* We want to avoid consing if we can. This is quite awkward because |
| 1140 we have to deal with the border as well as the items. */ | |
| 1141 GCPRO1 (border); | |
| 1142 | |
| 1143 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))) | |
| 1144 { | |
| 1145 border = XCAR (children); | |
| 1146 children = XCDR (children); | |
| 1147 } | |
| 1148 | |
| 1149 #ifdef DEBUG_WIDGET_OUTPUT | |
| 1150 stderr_out ("layout updated\n"); | |
| 1151 #endif | |
| 1152 /* Update the border. */ | |
| 1153 if (!NILP (border_inst)) | |
| 1154 { | |
| 1155 if (VECTORP (border_inst)) | |
| 1156 { | |
| 1157 /* We are going to be sneaky here and add the border text as | |
| 1158 just another child, the layout and output routines don't know | |
| 1159 this and will just display at the offsets we prescribe. */ | |
| 1160 if (!NILP (border)) | |
| 1161 call3 (Qset_glyph_image, border, border_inst, | |
| 1162 IMAGE_INSTANCE_DOMAIN (ii)); | |
| 1163 else | |
| 1164 { | |
| 1165 border = Fcons (call1 (Qmake_glyph, border_inst), Qnil); | |
| 1166 structure_changed = 1; | |
| 1167 } | |
| 1168 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (0); | |
| 1169 } | |
| 1170 else | |
| 1171 { | |
| 1172 if (!NILP (border)) | |
| 1173 { | |
| 1174 border = Qnil; | |
| 1175 structure_changed = 1; | |
| 1176 } | |
| 1177 if (EQ (border_inst, Qt)) | |
| 1178 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = Qetched_in; | |
| 1179 else | |
| 1180 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = border_inst; | |
| 428 | 1181 } |
| 1182 } | |
| 442 | 1183 |
| 1184 /* Pick up the sub-widgets. */ | |
| 1185 if (!NILP (items)) | |
| 428 | 1186 { |
| 442 | 1187 int len1, len2; |
| 1188 GET_LIST_LENGTH (items, len1); | |
| 1189 GET_LIST_LENGTH (children, len2); | |
| 1190 /* The structure hasn't changed so just update the images. */ | |
| 1191 if (!structure_changed && len1 == len2) | |
| 1192 { | |
| 1193 /* Pick up the sub-widgets. */ | |
| 1194 for (; !NILP (children); children = XCDR (children), items = XCDR (items)) | |
| 1195 { | |
| 1196 call3 (Qset_glyph_image, XCAR (children), XCAR (items), | |
| 1197 IMAGE_INSTANCE_DOMAIN (ii)); | |
| 1198 } | |
| 1199 } | |
| 1200 /* The structure has changed so start over. */ | |
| 1201 else | |
| 1202 { | |
| 1203 /* Instantiate any new glyphs. */ | |
| 1204 for (; !NILP (items); items = XCDR (items)) | |
| 1205 { | |
| 458 | 1206 /* #### We really want to use call_with_suspended_errors |
| 1207 here, but it won't allow us to call lisp. */ | |
| 442 | 1208 border = Fcons (call1 (Qmake_glyph, XCAR (items)), border); |
| 1209 } | |
| 1210 IMAGE_INSTANCE_LAYOUT_CHILDREN (ii) = Fnreverse (border); | |
| 1211 } | |
| 428 | 1212 } |
| 442 | 1213 UNGCPRO; |
| 1214 } | |
| 1215 | |
| 1216 static void | |
| 1217 layout_instantiate (Lisp_Object image_instance, Lisp_Object instantiator, | |
| 1218 Lisp_Object pointer_fg, Lisp_Object pointer_bg, | |
| 1219 int dest_mask, Lisp_Object domain) | |
| 1220 { | |
| 1221 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
| 1222 Lisp_Object orient = find_keyword_in_vector (instantiator, Q_orientation); | |
| 1223 | |
| 1224 #ifdef DEBUG_WIDGET_OUTPUT | |
| 1225 stderr_out ("layout instantiated\n"); | |
| 1226 #endif | |
| 1227 /* Do widget type instantiation first. */ | |
| 1228 widget_instantiate (image_instance, instantiator, pointer_fg, pointer_bg, | |
| 1229 dest_mask, domain); | |
| 1230 | |
| 1231 if (NILP (orient)) | |
| 1232 { | |
| 1233 IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) = LAYOUT_VERTICAL; | |
| 1234 } | |
| 1235 | |
| 1236 /* Get child glyphs and finish instantiation. We can't do image | |
| 1237 instance children yet as we might not have a containing | |
| 1238 window. */ | |
| 1239 layout_update (image_instance, instantiator); | |
| 1240 } | |
| 1241 | |
| 1242 static void | |
| 2286 | 1243 layout_post_instantiate (Lisp_Object UNUSED (image_instance), |
| 1244 Lisp_Object UNUSED (instantiator), | |
| 1245 Lisp_Object UNUSED (domain)) | |
| 442 | 1246 { |
| 428 | 1247 } |
| 1248 | |
| 440 | 1249 /* Layout widget. Sizing commentary: we have a number of problems that |
| 1250 we would like to address. Some consider some of these more | |
| 1251 important than others. It used to be that size information was | |
| 1252 determined at instantiation time and was then fixed forever | |
| 434 | 1253 after. Generally this is not what we want. Users want size to be |
| 1254 "big enough" to accommodate whatever they are trying to show and | |
| 1255 this is dependent on text length, lines, font metrics etc. Of | |
| 1256 course these attributes can change dynamically and so the size | |
| 1257 should changed dynamically also. Only in a few limited cases should | |
| 1258 the size be fixed and remain fixed. Of course this actually means | |
| 442 | 1259 that we don't really want to specify the size *at all* for most |
| 434 | 1260 widgets - we want it to be discovered dynamically. Thus we can |
| 1261 envisage the following scenarios: | |
| 442 | 1262 |
| 434 | 1263 1. A button is sized to accommodate its text, the text changes and the |
| 442 | 1264 button should change size also. |
| 434 | 1265 |
| 1266 2. A button is given an explicit size. Its size should never change. | |
| 1267 | |
| 1268 3. Layout is put inside an area. The size of the area changes, the | |
| 442 | 1269 layout should change with it. |
| 434 | 1270 |
| 1271 4. A button grows to accommodate additional text. The whitespace | |
| 1272 around it should be modified to cope with the new layout | |
| 442 | 1273 requirements. |
| 434 | 1274 |
| 1275 5. A button grows. The area surrounding it should grow also if | |
| 442 | 1276 possible. |
| 434 | 1277 |
| 1278 What metrics are important? | |
| 1279 1. Actual width and height. | |
| 442 | 1280 |
| 434 | 1281 2. Whether the width and height are what the widget actually wants, or |
| 442 | 1282 whether it can grow or shrink. |
| 434 | 1283 |
| 1284 Text glyphs are particularly troublesome since their metrics depend | |
| 1285 on the context in which they are being viewed. For instance they | |
| 1286 can appear differently depending on the window face, frame face or | |
| 440 | 1287 glyph face. In order to simplify this text glyphs can now only have |
| 1288 a glyph-face or image-instance face. All other glyphs are | |
| 1289 essentially fixed in appearance. Perhaps the problem is that text | |
| 1290 glyphs are cached on a device basis like most other glyphs. Instead | |
| 1291 they should be cached per-window and then the instance would be | |
| 1292 fixed and we wouldn't have to mess around with font metrics and the | |
| 863 | 1293 rest. |
| 1294 | |
| 1295 Another sizing problem is alignment. We provide layout widgets that | |
| 1296 allow users to stack widgets vertically or horizontally. These | |
| 1297 layouts also allow the widgets to be centered (space evenly | |
| 1298 distributed), left or right justified (fixed spacing widgets | |
| 3094 | 1299 stacked against the left, right, top or bottom edge). Unfortunately |
| 863 | 1300 this doesn't allow widgets in different layouts to be aligned. For |
| 1301 instance how should the search dialog be organized for alignment? | |
| 1302 The obvious choice of two vertical columns does not work since the | |
| 1303 size of individual widgets will affect where they get placed. The | |
| 1304 same is true for several rows of widgets. To solve this problem we | |
| 1305 introduce the notion of `logical_unit_height'. This is a size | |
| 1306 quantity that is designed to be big enough to accomodate the | |
| 1307 largest `single height unit'. The function | |
| 1308 widget_logical_unit_height() determines the value of this in | |
| 1309 pixels. It is dependent on the widget face and some combination of | |
| 1310 spacing and border-width. Thus if users specify left or right | |
| 1311 justification in a vertical layout they get something in logical | |
| 1312 units. To simplify this the functions | |
| 1313 `widget-logical-to-character-height' and | |
| 1314 `widget-logical-to-character-width' allow conversion between | |
| 1315 characters and logical units so that frames can be sized | |
| 1316 appropriately. */ | |
| 440 | 1317 |
| 1065 | 1318 /* Query the geometry of a layout widget. */ |
| 428 | 1319 static void |
| 442 | 1320 layout_query_geometry (Lisp_Object image_instance, int* width, |
| 1321 int* height, enum image_instance_geometry disp, | |
| 2286 | 1322 Lisp_Object UNUSED (domain)) |
| 428 | 1323 { |
| 440 | 1324 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); |
| 1325 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii), rest; | |
| 1326 int maxph = 0, maxpw = 0, nitems = 0, ph_adjust = 0; | |
| 863 | 1327 int gheight, gwidth, luh; |
| 442 | 1328 |
| 1329 /* If we are not initialized then we won't have any children. */ | |
| 1330 if (!IMAGE_INSTANCE_INITIALIZED (ii)) | |
| 1331 return; | |
| 1332 | |
| 1333 /* First just set up what we already have. */ | |
| 1334 if (width) *width = IMAGE_INSTANCE_WIDTH (ii); | |
| 1335 if (height) *height = IMAGE_INSTANCE_HEIGHT (ii); | |
| 1336 | |
| 1337 /* If we are not allowed to dynamically size then return. */ | |
| 1338 if (!IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii) | |
| 1339 && | |
| 1340 !IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) | |
| 1341 return; | |
| 1342 | |
| 863 | 1343 luh = widget_logical_unit_height (ii); |
| 1344 | |
| 442 | 1345 /* Pick up the border text if we have one. */ |
| 1346 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))) | |
| 1347 { | |
| 1348 glyph_query_geometry (XCAR (items), &gwidth, &gheight, disp, | |
| 1349 image_instance); | |
| 863 | 1350 ph_adjust = gheight; |
| 1068 | 1351 /* Include text width in vertical layouts. */ |
| 1352 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_VERTICAL) | |
| 1353 maxpw = gwidth + BORDER_FIDDLE_FACTOR; | |
| 442 | 1354 items = XCDR (items); |
| 1355 } | |
| 440 | 1356 |
| 1357 /* Flip through the items to work out how much stuff we have to display */ | |
| 1358 LIST_LOOP (rest, items) | |
| 1359 { | |
| 1360 Lisp_Object glyph = XCAR (rest); | |
| 442 | 1361 glyph_query_geometry (glyph, &gwidth, &gheight, disp, image_instance); |
| 440 | 1362 |
| 442 | 1363 nitems ++; |
| 863 | 1364 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL) |
| 440 | 1365 { |
| 442 | 1366 maxph = max (maxph, gheight); |
| 1367 maxpw += gwidth; | |
| 440 | 1368 } |
| 1369 else | |
| 1370 { | |
| 442 | 1371 maxpw = max (maxpw, gwidth); |
| 1372 maxph += gheight; | |
| 440 | 1373 } |
| 1374 } | |
| 428 | 1375 |
| 442 | 1376 /* Work out minimum space we need to fit all the items. This could |
| 1377 have been fixed by the user. */ | |
| 1318 | 1378 if (IMAGE_INSTANCE_SUBWINDOW_H_RESIZEP (ii)) |
| 1379 { | |
| 1065 | 1380 if (!NILP (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii))) |
| 1318 | 1381 { |
| 1065 | 1382 Lisp_Object dynamic_width = |
| 1318 | 1383 eval_within_redisplay (IMAGE_INSTANCE_WIDGET_WIDTH_SUBR (ii)); |
| 1065 | 1384 if (INTP (dynamic_width)) |
| 1318 | 1385 *width = XINT (dynamic_width); |
| 1386 } | |
| 1065 | 1387 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL) |
| 1318 | 1388 { |
| 1065 | 1389 *width = maxpw + ((nitems + 1) * widget_instance_border_width (ii) + |
| 1390 IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2; | |
| 1318 | 1391 } |
| 1065 | 1392 else |
| 1318 | 1393 { |
| 1065 | 1394 *width = maxpw + 2 * (widget_instance_border_width (ii) * 2 + |
| 1395 IMAGE_INSTANCE_MARGIN_WIDTH (ii)); | |
| 1318 | 1396 } |
| 1065 | 1397 } |
| 1398 | |
| 440 | 1399 /* Work out vertical spacings. */ |
| 1318 | 1400 if (IMAGE_INSTANCE_SUBWINDOW_V_RESIZEP (ii)) |
| 1401 { | |
| 1065 | 1402 if (!NILP (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii))) |
| 1318 | 1403 { |
| 1065 | 1404 Lisp_Object dynamic_height = |
| 1318 | 1405 eval_within_redisplay (IMAGE_INSTANCE_WIDGET_HEIGHT_SUBR (ii)); |
| 1065 | 1406 if (INTP (dynamic_height)) |
| 1318 | 1407 *height = XINT (dynamic_height); |
| 1408 } | |
| 1065 | 1409 else if (IMAGE_INSTANCE_SUBWINDOW_LOGICAL_LAYOUT (ii)) |
| 1318 | 1410 { |
| 1065 | 1411 *height = nitems * luh + ph_adjust; |
| 1318 | 1412 } |
| 1065 | 1413 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_VERTICAL) |
| 1318 | 1414 { |
| 1065 | 1415 *height = maxph + ((nitems + 1) * widget_instance_border_width (ii) + |
| 1416 IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust; | |
| 1318 | 1417 } |
| 1065 | 1418 else |
| 1318 | 1419 { |
| 1065 | 1420 *height = maxph + (2 * widget_instance_border_width (ii) + |
| 1421 IMAGE_INSTANCE_MARGIN_WIDTH (ii)) * 2 + ph_adjust; | |
| 1318 | 1422 } |
| 1065 | 1423 } |
| 863 | 1424 #ifdef DEBUG_WIDGET_OUTPUT |
| 1425 stderr_out ("layout wants %dx%d\n", *width, *height); | |
| 1426 #endif | |
| 440 | 1427 } |
| 1428 | |
| 442 | 1429 int |
| 1430 layout_layout (Lisp_Object image_instance, | |
| 2286 | 1431 int width, int height, int UNUSED (xoffset), int yoffset, |
| 1432 Lisp_Object UNUSED (domain)) | |
| 440 | 1433 { |
| 1434 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
| 1435 Lisp_Object rest; | |
| 1436 Lisp_Object items = IMAGE_INSTANCE_LAYOUT_CHILDREN (ii); | |
| 1437 int x, y, maxph = 0, maxpw = 0, nitems = 0, | |
| 1438 horiz_spacing, vert_spacing, ph_adjust = 0; | |
| 442 | 1439 int gheight, gwidth; |
| 863 | 1440 /* See comments in widget_logical_unit_height(). */ |
| 1441 int luh = widget_logical_unit_height (ii); | |
| 442 | 1442 |
| 1443 /* If we are not initialized then we won't have any children. */ | |
| 1444 if (!IMAGE_INSTANCE_INITIALIZED (ii)) | |
| 1445 return 0; | |
| 428 | 1446 |
| 863 | 1447 #ifdef DEBUG_WIDGET_OUTPUT |
| 1448 stderr_out ("layout output %dx%d\n", width, height); | |
| 1449 #endif | |
| 1450 | |
| 1451 /* Pick up the border text if we have one. A border can have the | |
| 1452 values Qetched_in, Qetched_out, Qbevel_in, Qbevel_out or an | |
| 1453 integer. The first four just affect the display properties of the | |
| 1454 border that is drawn. The last is an offset and implies that the | |
| 1455 first item in the list of subcontrols is a text control that | |
| 1456 should be displayed on the border. */ | |
| 442 | 1457 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii))) |
| 1458 { | |
| 1459 Lisp_Object border = XCAR (items); | |
| 1460 items = XCDR (items); | |
| 1461 glyph_query_geometry (border, &gwidth, &gheight, | |
| 1462 IMAGE_DESIRED_GEOMETRY, image_instance); | |
| 863 | 1463 /* The vertical offset for subsequent items is the full height |
| 1464 of the border glyph. */ | |
| 1465 ph_adjust = gheight; | |
| 1466 /* The offset for the border is half the glyph height. */ | |
| 1467 IMAGE_INSTANCE_LAYOUT_BORDER (ii) = make_int (gheight / 2); | |
| 442 | 1468 |
| 1469 /* #### Really, what should this be? */ | |
| 1068 | 1470 glyph_do_layout (border, gwidth, gheight, BORDER_FIDDLE_FACTOR, 0, |
| 442 | 1471 image_instance); |
| 1472 } | |
| 1473 | |
| 1474 /* Flip through the items to work out how much stuff we have to display. */ | |
| 428 | 1475 LIST_LOOP (rest, items) |
| 1476 { | |
| 1477 Lisp_Object glyph = XCAR (rest); | |
| 440 | 1478 |
| 442 | 1479 glyph_query_geometry (glyph, &gwidth, &gheight, |
| 1480 IMAGE_DESIRED_GEOMETRY, image_instance); | |
| 1481 nitems ++; | |
| 1482 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) | |
| 1483 == LAYOUT_HORIZONTAL) | |
| 428 | 1484 { |
| 442 | 1485 maxph = max (maxph, gheight); |
| 1486 maxpw += gwidth; | |
| 428 | 1487 } |
| 440 | 1488 else |
| 428 | 1489 { |
| 442 | 1490 maxpw = max (maxpw, gwidth); |
| 1491 maxph += gheight; | |
| 428 | 1492 } |
| 1493 } | |
| 1494 | |
| 1495 /* work out spacing between items and bounds of the layout */ | |
| 440 | 1496 if (width < maxpw) |
| 428 | 1497 /* The user wants a smaller space than the largest item, so we |
| 1498 just provide default spacing and will let the output routines | |
| 863 | 1499 clip. */ |
| 1500 horiz_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)); | |
| 442 | 1501 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) |
| 863 | 1502 == LAYOUT_HORIZONTAL) |
| 428 | 1503 /* We have a larger area to display in so distribute the space |
| 1504 evenly. */ | |
| 442 | 1505 horiz_spacing = (width - (maxpw + |
| 1506 IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2)) | |
| 1507 / (nitems + 1); | |
| 428 | 1508 else |
| 442 | 1509 horiz_spacing = (width - maxpw) / 2 |
| 1510 - IMAGE_INSTANCE_MARGIN_WIDTH (ii); | |
| 428 | 1511 |
| 863 | 1512 /* We are trying here to get widgets to line up when they are left |
| 1513 or right justified vertically. This means that we must position | |
| 1514 widgets on logical unit boundaries, even though their height may | |
| 1515 be greater or less than a logical unit. In order to avoid | |
| 1516 clipping we need to determine how big the widget wants to be and | |
| 1517 then allocate as many logical units as necessary in order to | |
| 1518 accommodate it. */ | |
| 440 | 1519 if (height < maxph) |
| 863 | 1520 vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2; |
| 442 | 1521 else if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) |
| 440 | 1522 == LAYOUT_VERTICAL) |
| 863 | 1523 { |
| 1524 if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii)) | |
| 1525 vert_spacing = widget_spacing (IMAGE_INSTANCE_DOMAIN (ii)) * 2; | |
| 1526 else | |
| 1527 vert_spacing = (height - (maxph + ph_adjust + | |
| 1528 IMAGE_INSTANCE_MARGIN_WIDTH (ii) * 2)) | |
| 1529 / (nitems + 1); | |
| 1530 } | |
| 428 | 1531 else |
| 442 | 1532 vert_spacing = (height - (maxph + ph_adjust)) / 2 |
| 1533 - IMAGE_INSTANCE_MARGIN_WIDTH (ii); | |
| 428 | 1534 |
| 863 | 1535 y = yoffset = vert_spacing + ph_adjust + IMAGE_INSTANCE_MARGIN_WIDTH (ii); |
| 442 | 1536 x = horiz_spacing + IMAGE_INSTANCE_MARGIN_WIDTH (ii); |
| 428 | 1537 |
| 1538 /* Now flip through putting items where we want them, paying | |
| 440 | 1539 attention to justification. Make sure we don't mess with the |
| 1540 border glyph. */ | |
| 428 | 1541 LIST_LOOP (rest, items) |
| 1542 { | |
| 1543 Lisp_Object glyph = XCAR (rest); | |
| 1544 | |
| 442 | 1545 glyph_query_geometry (glyph, &gwidth, &gheight, |
| 1546 IMAGE_DESIRED_GEOMETRY, image_instance); | |
| 1547 | |
| 863 | 1548 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL) |
| 442 | 1549 { |
| 863 | 1550 if (IMAGE_INSTANCE_SUBWINDOW_BOTTOM_JUSTIFIED (ii)) |
| 442 | 1551 y = height - (gheight + vert_spacing); |
| 863 | 1552 else if (IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii)) |
| 442 | 1553 y = (height - gheight) / 2; |
| 1554 } | |
| 1555 else | |
| 1556 { | |
| 863 | 1557 if (IMAGE_INSTANCE_SUBWINDOW_RIGHT_JUSTIFIED (ii)) |
| 442 | 1558 x = width - (gwidth + horiz_spacing); |
| 863 | 1559 else if (IMAGE_INSTANCE_SUBWINDOW_H_CENTERED (ii)) |
| 442 | 1560 x = (width - gwidth) / 2; |
| 1561 } | |
| 1562 | |
| 1563 /* Now layout subwidgets if they require it. */ | |
| 1564 glyph_do_layout (glyph, gwidth, gheight, x, y, image_instance); | |
| 1565 | |
| 863 | 1566 if (IMAGE_INSTANCE_SUBWINDOW_ORIENT (ii) == LAYOUT_HORIZONTAL) |
| 442 | 1567 { |
| 1568 x += (gwidth + horiz_spacing); | |
| 1569 } | |
| 1570 else | |
| 1571 { | |
| 1572 y += (gheight + vert_spacing); | |
| 863 | 1573 if (!IMAGE_INSTANCE_SUBWINDOW_V_CENTERED (ii)) |
| 1574 { | |
| 1575 /* justified, vertical layout, try and align on logical unit | |
| 1576 boundaries. */ | |
| 1577 y = ROUND_UP (y - yoffset, luh) + yoffset; | |
| 1578 } | |
| 442 | 1579 } |
| 1580 | |
| 1581 } | |
| 1582 return 1; | |
| 1583 } | |
| 1584 | |
| 1585 /* Get the glyphs that comprise a layout. These are created internally | |
| 1586 and so are otherwise inaccessible to lisp. We need some way of getting | |
| 1587 properties from the widgets that comprise a layout and this is the | |
| 1588 simplest way of doing it. | |
| 428 | 1589 |
| 442 | 1590 #### Eventually we should allow some more intelligent access to |
| 1591 sub-widgets. */ | |
| 1592 static Lisp_Object | |
| 1593 layout_property (Lisp_Object image_instance, Lisp_Object prop) | |
| 1594 { | |
| 1595 /* This function can GC. */ | |
| 1596 Lisp_Image_Instance *ii = XIMAGE_INSTANCE (image_instance); | |
| 1597 if (EQ (prop, Q_items)) | |
| 1598 { | |
| 1599 if (INTP (IMAGE_INSTANCE_LAYOUT_BORDER (ii)) && | |
| 1600 CONSP (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii))) | |
| 1601 return Fcopy_sequence (XCDR | |
| 1602 (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii))); | |
| 1603 else | |
| 1604 return Fcopy_sequence (IMAGE_INSTANCE_LAYOUT_CHILDREN (ii)); | |
| 428 | 1605 } |
| 442 | 1606 return Qunbound; |
| 1607 } | |
| 428 | 1608 |
| 442 | 1609 /* Layout subwindows if they are real subwindows. */ |
| 1610 static int | |
| 1611 native_layout_layout (Lisp_Object image_instance, | |
| 1612 int width, int height, int xoffset, int yoffset, | |
| 1613 Lisp_Object domain) | |
| 1614 { | |
| 1615 Lisp_Image_Instance* ii = XIMAGE_INSTANCE (image_instance); | |
| 1616 Lisp_Object rest; | |
| 1617 | |
| 1618 /* The first time this gets called, the layout will be only | |
| 1619 partially instantiated. The children get done in | |
| 1620 post_instantiate. */ | |
| 1621 if (!IMAGE_INSTANCE_INITIALIZED (ii)) | |
| 1622 return 0; | |
| 1623 | |
| 1624 /* Defining this overrides the default layout_layout so we first have to call that to get | |
| 1625 suitable instances and values set up. */ | |
| 1626 layout_layout (image_instance, width, height, xoffset, yoffset, domain); | |
| 1627 | |
| 1628 LIST_LOOP (rest, IMAGE_INSTANCE_LAYOUT_CHILDREN (ii)) | |
| 1629 { | |
| 1630 struct display_glyph_area dga; | |
| 1631 dga.xoffset = 0; | |
| 1632 dga.yoffset = 0; | |
| 1633 dga.width = IMAGE_INSTANCE_WIDTH (ii); | |
| 1634 dga.height = IMAGE_INSTANCE_HEIGHT (ii); | |
| 1635 | |
| 1636 map_subwindow (XCAR (rest), | |
| 1637 IMAGE_INSTANCE_XOFFSET (ii), | |
| 1638 IMAGE_INSTANCE_YOFFSET (ii), &dga); | |
| 1639 } | |
| 1640 return 1; | |
| 428 | 1641 } |
| 1642 | |
| 863 | 1643 DEFUN ("widget-logical-to-character-width", Fwidget_logical_to_character_width, 1, 3, 0, /* |
| 1644 Convert the width in logical widget units to characters. | |
| 3094 | 1645 Logical widget units do not take into account adjustments made for |
| 1646 layout borders, so this adjustment is approximated. | |
| 863 | 1647 */ |
| 2286 | 1648 (width, UNUSED (face), domain)) |
| 863 | 1649 { |
| 1650 int w, neww, charwidth; | |
| 1651 int border_width = DEFAULT_WIDGET_BORDER_WIDTH; | |
| 1652 | |
| 1653 if (NILP (domain)) | |
| 1654 domain = Fselected_frame (Qnil); | |
| 1655 | |
| 1656 CHECK_INT (width); | |
| 1657 w = XINT (width); | |
| 1658 | |
| 1659 if (HAS_DEVMETH_P (DOMAIN_XDEVICE (domain), widget_border_width)) | |
| 1660 border_width = DEVMETH (DOMAIN_XDEVICE (domain), widget_border_width, ()); | |
| 1661 | |
|
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
4677
diff
changeset
|
1662 default_face_font_info (domain, 0, 0, &charwidth, 0, 0); |
| 863 | 1663 neww = ROUND_UP (charwidth * w + 4 * border_width + 2 * widget_spacing (domain), |
| 1664 charwidth) / charwidth; | |
| 1665 | |
| 1666 return make_int (neww); | |
| 1667 } | |
| 1668 | |
| 1669 DEFUN ("widget-logical-to-character-height", Fwidget_logical_to_character_height, 1, 3, 0, /* | |
| 1670 Convert the height in logical widget units to characters. | |
| 3094 | 1671 Logical widget units do not take into account adjustments made for |
| 863 | 1672 layout borders, so this adjustment is approximated. |
| 1673 | |
| 1674 If the components of a widget layout are justified to the top or the | |
| 1675 bottom then they are aligned in terms of `logical units'. This is a | |
| 1676 size quantity that is designed to be big enough to accomodate the | |
| 1677 largest `single height' widget. It is dependent on the widget face and | |
| 1678 some combination of spacing and border-width. Thus if you specify top | |
| 1679 or bottom justification in a vertical layout the subcontrols are laid | |
| 1680 out one per logical unit. This allows adjoining layouts to have | |
| 1681 identical alignment for their subcontrols. | |
| 1682 | |
| 1683 Since frame sizes are measured in characters, this function allows you | |
| 1684 to do appropriate conversion between logical units and characters. | |
| 1685 */ | |
| 2286 | 1686 (height, UNUSED (face), domain)) |
| 863 | 1687 { |
| 1688 int h, newh, charheight; | |
| 1689 | |
| 1690 CHECK_INT (height); | |
| 1691 if (NILP (domain)) | |
| 1692 domain = Fselected_frame (Qnil); | |
| 1693 | |
| 1694 h = XINT (height); | |
| 1695 | |
|
5047
07dcc7000bbf
put width before height consistently, fix a real bug found in the process
Ben Wing <ben@xemacs.org>
parents:
4677
diff
changeset
|
1696 default_face_font_info (domain, 0, 0, 0, &charheight, 0); |
| 863 | 1697 newh = ROUND_UP (logical_unit_height (Fsymbol_name (Qwidget), |
| 1698 Vwidget_face, domain) * h, charheight) | |
| 1699 / charheight; | |
| 1700 | |
| 1701 return make_int (newh); | |
| 1702 } | |
| 1703 | |
| 428 | 1704 |
| 1705 /************************************************************************/ | |
| 1706 /* initialization */ | |
| 1707 /************************************************************************/ | |
| 1708 | |
| 1709 void | |
| 1710 syms_of_glyphs_widget (void) | |
| 1711 { | |
| 442 | 1712 DEFSYMBOL (Qetched_in); |
| 1713 DEFSYMBOL (Qetched_out); | |
| 1714 DEFSYMBOL (Qbevel_in); | |
| 1715 DEFSYMBOL (Qbevel_out); | |
| 1716 DEFSYMBOL (Qmake_glyph); | |
| 863 | 1717 |
| 1718 DEFSUBR (Fwidget_logical_to_character_height); | |
| 1719 DEFSUBR (Fwidget_logical_to_character_width); | |
| 428 | 1720 } |
| 1721 | |
| 442 | 1722 #define VALID_GUI_KEYWORDS(type) do { \ |
| 1723 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_active, check_valid_anything); \ | |
| 1724 IIFORMAT_VALID_KEYWORD (type, Q_suffix, check_valid_anything); \ | |
| 1725 IIFORMAT_VALID_KEYWORD (type, Q_keys, check_valid_string); \ | |
| 1726 IIFORMAT_VALID_KEYWORD (type, Q_style, check_valid_symbol); \ | |
| 1727 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_selected, check_valid_anything); \ | |
| 1728 IIFORMAT_VALID_KEYWORD (type, Q_filter, check_valid_anything); \ | |
| 1729 IIFORMAT_VALID_KEYWORD (type, Q_config, check_valid_symbol); \ | |
| 1730 IIFORMAT_VALID_KEYWORD (type, Q_included, check_valid_anything); \ | |
| 1731 IIFORMAT_VALID_KEYWORD (type, Q_initial_focus, check_valid_anything); \ | |
| 1732 IIFORMAT_VALID_KEYWORD (type, Q_key_sequence, check_valid_string); \ | |
| 1733 IIFORMAT_VALID_KEYWORD (type, Q_accelerator, check_valid_string); \ | |
| 1734 IIFORMAT_VALID_KEYWORD (type, Q_label, check_valid_anything); \ | |
| 1735 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback, check_valid_callback); \ | |
| 1736 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_callback_ex, check_valid_callback); \ | |
| 1737 IIFORMAT_VALID_NONCOPY_KEYWORD (type, Q_descriptor, \ | |
| 1738 check_valid_string_or_vector); \ | |
| 440 | 1739 } while (0) |
| 428 | 1740 |
| 442 | 1741 #define VALID_WIDGET_KEYWORDS(type) do { \ |
| 1742 IIFORMAT_VALID_KEYWORD (type, Q_width, check_valid_int); \ | |
| 1743 IIFORMAT_VALID_KEYWORD (type, Q_height, check_valid_int); \ | |
| 1744 IIFORMAT_VALID_KEYWORD (type, Q_pixel_width, check_valid_int_or_function); \ | |
| 1745 IIFORMAT_VALID_KEYWORD (type, Q_pixel_height, check_valid_int_or_function); \ | |
| 1746 IIFORMAT_VALID_KEYWORD (type, Q_face, check_valid_face); \ | |
| 440 | 1747 } while (0) |
| 428 | 1748 |
| 440 | 1749 |
| 1750 static void image_instantiator_widget (void) | |
| 1751 { /* we only do this for properties */ | |
| 428 | 1752 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT_NO_SYM (widget, "widget"); |
| 1753 IIFORMAT_HAS_METHOD (widget, property); | |
| 442 | 1754 IIFORMAT_HAS_METHOD (widget, update); |
| 438 | 1755 IIFORMAT_HAS_METHOD (widget, query_geometry); |
| 1756 IIFORMAT_HAS_METHOD (widget, layout); | |
| 440 | 1757 } |
| 428 | 1758 |
| 440 | 1759 static void image_instantiator_buttons (void) |
| 1760 { | |
| 428 | 1761 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (button, "button"); |
| 1762 IIFORMAT_HAS_SHARED_METHOD (button, validate, widget); | |
| 1763 IIFORMAT_HAS_SHARED_METHOD (button, possible_dest_types, widget); | |
| 1764 IIFORMAT_HAS_SHARED_METHOD (button, instantiate, widget); | |
| 442 | 1765 IIFORMAT_HAS_SHARED_METHOD (button, post_instantiate, widget); |
| 428 | 1766 IIFORMAT_HAS_SHARED_METHOD (button, normalize, widget); |
| 442 | 1767 IIFORMAT_HAS_SHARED_METHOD (button, governing_domain, subwindow); |
| 1768 IIFORMAT_HAS_METHOD (button, query_geometry); | |
| 440 | 1769 IIFORMAT_VALID_KEYWORD (button, |
| 442 | 1770 Q_image, check_valid_instantiator); |
| 428 | 1771 VALID_WIDGET_KEYWORDS (button); |
| 1772 VALID_GUI_KEYWORDS (button); | |
| 440 | 1773 } |
| 428 | 1774 |
| 440 | 1775 static void image_instantiator_edit_fields (void) |
| 1776 { | |
| 428 | 1777 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (edit_field, "edit-field"); |
| 1778 IIFORMAT_HAS_SHARED_METHOD (edit_field, validate, widget); | |
| 1779 IIFORMAT_HAS_SHARED_METHOD (edit_field, possible_dest_types, widget); | |
| 1780 IIFORMAT_HAS_SHARED_METHOD (edit_field, instantiate, widget); | |
| 442 | 1781 IIFORMAT_HAS_SHARED_METHOD (edit_field, post_instantiate, widget); |
| 1782 IIFORMAT_HAS_SHARED_METHOD (edit_field, governing_domain, subwindow); | |
| 863 | 1783 IIFORMAT_HAS_METHOD (edit_field, query_geometry); |
| 428 | 1784 VALID_WIDGET_KEYWORDS (edit_field); |
| 1785 VALID_GUI_KEYWORDS (edit_field); | |
| 440 | 1786 } |
| 428 | 1787 |
| 440 | 1788 static void image_instantiator_combo_box (void) |
| 1789 { | |
| 428 | 1790 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (combo_box, "combo-box"); |
| 1791 IIFORMAT_HAS_METHOD (combo_box, validate); | |
| 1792 IIFORMAT_HAS_SHARED_METHOD (combo_box, possible_dest_types, widget); | |
| 442 | 1793 IIFORMAT_HAS_SHARED_METHOD (combo_box, governing_domain, subwindow); |
| 1794 | |
| 428 | 1795 VALID_GUI_KEYWORDS (combo_box); |
| 1796 | |
| 1797 IIFORMAT_VALID_KEYWORD (combo_box, Q_width, check_valid_int); | |
| 1798 IIFORMAT_VALID_KEYWORD (combo_box, Q_height, check_valid_int); | |
| 442 | 1799 IIFORMAT_VALID_KEYWORD (combo_box, Q_pixel_width, |
| 1800 check_valid_int_or_function); | |
| 428 | 1801 IIFORMAT_VALID_KEYWORD (combo_box, Q_face, check_valid_face); |
| 442 | 1802 IIFORMAT_VALID_KEYWORD (combo_box, Q_items, check_valid_item_list); |
| 440 | 1803 } |
| 428 | 1804 |
| 440 | 1805 static void image_instantiator_scrollbar (void) |
| 1806 { | |
| 428 | 1807 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (scrollbar, "scrollbar"); |
| 1808 IIFORMAT_HAS_SHARED_METHOD (scrollbar, validate, widget); | |
| 1809 IIFORMAT_HAS_SHARED_METHOD (scrollbar, possible_dest_types, widget); | |
| 1810 IIFORMAT_HAS_SHARED_METHOD (scrollbar, instantiate, widget); | |
| 442 | 1811 IIFORMAT_HAS_SHARED_METHOD (scrollbar, post_instantiate, widget); |
| 1812 IIFORMAT_HAS_SHARED_METHOD (scrollbar, governing_domain, subwindow); | |
| 428 | 1813 VALID_GUI_KEYWORDS (scrollbar); |
| 1814 | |
| 442 | 1815 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_width, |
| 1816 check_valid_int_or_function); | |
| 1817 IIFORMAT_VALID_KEYWORD (scrollbar, Q_pixel_height, | |
| 1818 check_valid_int_or_function); | |
| 428 | 1819 IIFORMAT_VALID_KEYWORD (scrollbar, Q_face, check_valid_face); |
| 440 | 1820 } |
| 428 | 1821 |
| 3094 | 1822 static void image_instantiator_progress_gauge (void) |
| 440 | 1823 { |
| 428 | 1824 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (progress_gauge, "progress-gauge"); |
| 1825 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, validate, widget); | |
| 1826 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, possible_dest_types, widget); | |
| 1827 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, instantiate, widget); | |
| 442 | 1828 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, post_instantiate, widget); |
| 1829 IIFORMAT_HAS_SHARED_METHOD (progress_gauge, governing_domain, subwindow); | |
| 428 | 1830 VALID_WIDGET_KEYWORDS (progress_gauge); |
| 1831 VALID_GUI_KEYWORDS (progress_gauge); | |
| 442 | 1832 |
| 1833 IIFORMAT_VALID_KEYWORD (progress_gauge, Q_value, check_valid_int); | |
| 440 | 1834 } |
| 428 | 1835 |
| 440 | 1836 static void image_instantiator_tree_view (void) |
| 1837 { | |
| 428 | 1838 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tree_view, "tree-view"); |
| 1839 IIFORMAT_HAS_SHARED_METHOD (tree_view, validate, combo_box); | |
| 1840 IIFORMAT_HAS_SHARED_METHOD (tree_view, possible_dest_types, widget); | |
| 438 | 1841 IIFORMAT_HAS_SHARED_METHOD (tree_view, instantiate, widget); |
| 442 | 1842 IIFORMAT_HAS_SHARED_METHOD (tree_view, post_instantiate, widget); |
| 1843 IIFORMAT_HAS_SHARED_METHOD (tree_view, governing_domain, subwindow); | |
| 438 | 1844 IIFORMAT_HAS_METHOD (tree_view, query_geometry); |
| 428 | 1845 VALID_WIDGET_KEYWORDS (tree_view); |
| 1846 VALID_GUI_KEYWORDS (tree_view); | |
| 442 | 1847 IIFORMAT_VALID_KEYWORD (tree_view, Q_items, check_valid_item_list); |
| 440 | 1848 } |
| 428 | 1849 |
| 440 | 1850 static void image_instantiator_tab_control (void) |
| 1851 { | |
| 428 | 1852 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (tab_control, "tab-control"); |
| 1853 IIFORMAT_HAS_SHARED_METHOD (tab_control, validate, combo_box); | |
| 1854 IIFORMAT_HAS_SHARED_METHOD (tab_control, possible_dest_types, widget); | |
| 438 | 1855 IIFORMAT_HAS_SHARED_METHOD (tab_control, instantiate, widget); |
| 442 | 1856 IIFORMAT_HAS_SHARED_METHOD (tab_control, post_instantiate, widget); |
| 1857 IIFORMAT_HAS_SHARED_METHOD (tab_control, governing_domain, subwindow); | |
| 438 | 1858 IIFORMAT_HAS_METHOD (tab_control, query_geometry); |
| 428 | 1859 VALID_WIDGET_KEYWORDS (tab_control); |
| 1860 VALID_GUI_KEYWORDS (tab_control); | |
| 442 | 1861 IIFORMAT_VALID_KEYWORD (tab_control, Q_orientation, |
| 1862 check_valid_tab_orientation); | |
| 1863 IIFORMAT_VALID_KEYWORD (tab_control, Q_items, check_valid_item_list); | |
| 440 | 1864 } |
| 428 | 1865 |
| 440 | 1866 static void image_instantiator_labels (void) |
| 1867 { | |
| 428 | 1868 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (label, "label"); |
| 1869 IIFORMAT_HAS_SHARED_METHOD (label, possible_dest_types, widget); | |
| 438 | 1870 IIFORMAT_HAS_SHARED_METHOD (label, instantiate, widget); |
| 442 | 1871 IIFORMAT_HAS_SHARED_METHOD (label, post_instantiate, widget); |
| 1872 IIFORMAT_HAS_SHARED_METHOD (label, governing_domain, subwindow); | |
| 428 | 1873 VALID_WIDGET_KEYWORDS (label); |
| 1874 IIFORMAT_VALID_KEYWORD (label, Q_descriptor, check_valid_string); | |
| 440 | 1875 } |
| 428 | 1876 |
| 442 | 1877 #define VALID_LAYOUT_KEYWORDS(layout) \ |
| 1878 VALID_WIDGET_KEYWORDS (layout); \ | |
| 1879 IIFORMAT_VALID_KEYWORD (layout, Q_orientation, check_valid_orientation); \ | |
| 1880 IIFORMAT_VALID_KEYWORD (layout, Q_justify, check_valid_justification); \ | |
| 863 | 1881 IIFORMAT_VALID_KEYWORD (layout, Q_vertically_justify, check_valid_justification); \ |
| 1882 IIFORMAT_VALID_KEYWORD (layout, Q_horizontally_justify, check_valid_justification); \ | |
| 442 | 1883 IIFORMAT_VALID_KEYWORD (layout, Q_border, check_valid_border); \ |
| 1884 IIFORMAT_VALID_KEYWORD (layout, Q_margin_width, check_valid_int); \ | |
| 1885 IIFORMAT_VALID_KEYWORD (layout, Q_items, \ | |
| 1886 check_valid_instantiator_list) | |
| 1887 | |
| 440 | 1888 static void image_instantiator_layout (void) |
| 1889 { | |
| 428 | 1890 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (layout, "layout"); |
| 442 | 1891 IIFORMAT_HAS_SHARED_METHOD (layout, possible_dest_types, widget); |
| 1892 IIFORMAT_HAS_METHOD (layout, instantiate); | |
| 1893 IIFORMAT_HAS_METHOD (layout, post_instantiate); | |
| 1894 IIFORMAT_HAS_SHARED_METHOD (layout, governing_domain, subwindow); | |
| 428 | 1895 IIFORMAT_HAS_METHOD (layout, normalize); |
| 440 | 1896 IIFORMAT_HAS_METHOD (layout, query_geometry); |
| 1897 IIFORMAT_HAS_METHOD (layout, layout); | |
| 442 | 1898 IIFORMAT_HAS_METHOD (layout, update); |
| 1899 IIFORMAT_HAS_METHOD (layout, property); | |
| 1900 | |
| 1901 VALID_GUI_KEYWORDS (layout); | |
| 1902 VALID_LAYOUT_KEYWORDS (layout); | |
| 1903 } | |
| 1904 | |
| 1905 static void image_instantiator_native_layout (void) | |
| 1906 { | |
| 1907 INITIALIZE_IMAGE_INSTANTIATOR_FORMAT (native_layout, "native-layout"); | |
| 1908 IIFORMAT_HAS_SHARED_METHOD (native_layout, possible_dest_types, widget); | |
| 1909 IIFORMAT_HAS_SHARED_METHOD (native_layout, instantiate, layout); | |
| 1910 IIFORMAT_HAS_SHARED_METHOD (native_layout, post_instantiate, layout); | |
| 1911 IIFORMAT_HAS_METHOD (native_layout, layout); | |
| 1912 IIFORMAT_HAS_SHARED_METHOD (native_layout, governing_domain, subwindow); | |
| 1913 IIFORMAT_HAS_SHARED_METHOD (native_layout, normalize, layout); | |
| 1914 IIFORMAT_HAS_SHARED_METHOD (native_layout, query_geometry, layout); | |
| 1915 IIFORMAT_HAS_SHARED_METHOD (native_layout, layout, layout); | |
| 1916 IIFORMAT_HAS_SHARED_METHOD (native_layout, property, layout); | |
| 1917 | |
| 1918 VALID_GUI_KEYWORDS (native_layout); | |
| 1919 VALID_LAYOUT_KEYWORDS (native_layout); | |
| 428 | 1920 } |
| 1921 | |
| 1922 void | |
| 440 | 1923 image_instantiator_format_create_glyphs_widget (void) |
| 1924 { | |
| 1925 image_instantiator_widget(); | |
| 1926 image_instantiator_buttons(); | |
| 1927 image_instantiator_edit_fields(); | |
| 1928 image_instantiator_combo_box(); | |
| 1929 image_instantiator_scrollbar(); | |
| 3094 | 1930 image_instantiator_progress_gauge(); |
| 440 | 1931 image_instantiator_tree_view(); |
| 1932 image_instantiator_tab_control(); | |
| 1933 image_instantiator_labels(); | |
| 1934 image_instantiator_layout(); | |
| 442 | 1935 image_instantiator_native_layout(); |
| 440 | 1936 } |
| 1937 | |
| 1938 void | |
| 428 | 1939 reinit_vars_of_glyphs_widget (void) |
| 1940 { | |
| 1941 #ifdef DEBUG_WIDGETS | |
| 1942 debug_widget_instances = 0; | |
| 1943 #endif | |
| 1944 } | |
| 1945 | |
| 1946 void | |
| 1947 vars_of_glyphs_widget (void) | |
| 1948 { | |
| 1949 } | |
| 863 | 1950 |
| 1951 | |
| 1952 void | |
| 1953 specifier_vars_of_glyphs_widget (void) | |
| 1954 { | |
| 1955 DEFVAR_SPECIFIER ("widget-border-width", | |
| 1956 &Vwidget_border_width /* | |
| 1957 *Border width of widgets. | |
| 1958 This is a specifier; use `set-specifier' to change it. | |
| 1959 */ ); | |
| 1960 Vwidget_border_width = Fmake_specifier (Qnatnum); | |
| 1961 } |
