Mercurial > hg > xemacs-beta
annotate src/glyphs-widget.c @ 5127:a9c41067dd88 ben-lisp-object
more cleanups, terminology clarification, lots of doc work
-------------------- ChangeLog entries follow: --------------------
man/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* internals/internals.texi (Introduction to Allocation):
* internals/internals.texi (Integers and Characters):
* internals/internals.texi (Allocation from Frob Blocks):
* internals/internals.texi (lrecords):
* internals/internals.texi (Low-level allocation):
Rewrite section on allocation of Lisp objects to reflect the new
reality. Remove references to nonexistent XSETINT and XSETCHAR.
modules/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* postgresql/postgresql.c (allocate_pgconn):
* postgresql/postgresql.c (allocate_pgresult):
* postgresql/postgresql.h (struct Lisp_PGconn):
* postgresql/postgresql.h (struct Lisp_PGresult):
* ldap/eldap.c (allocate_ldap):
* ldap/eldap.h (struct Lisp_LDAP):
Same changes as in src/ dir. See large log there in ChangeLog,
but basically:
ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT
LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER
../hlo/src/ChangeLog addition:
2010-03-05 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (old_alloc_sized_lcrecord):
* alloc.c (very_old_free_lcrecord):
* alloc.c (copy_lisp_object):
* alloc.c (zero_sized_lisp_object):
* alloc.c (zero_nonsized_lisp_object):
* alloc.c (lisp_object_storage_size):
* alloc.c (free_normal_lisp_object):
* alloc.c (FREE_FIXED_TYPE_WHEN_NOT_IN_GC):
* alloc.c (ALLOC_FROB_BLOCK_LISP_OBJECT):
* alloc.c (Fcons):
* alloc.c (noseeum_cons):
* alloc.c (make_float):
* alloc.c (make_bignum):
* alloc.c (make_bignum_bg):
* alloc.c (make_ratio):
* alloc.c (make_ratio_bg):
* alloc.c (make_ratio_rt):
* alloc.c (make_bigfloat):
* alloc.c (make_bigfloat_bf):
* alloc.c (size_vector):
* alloc.c (make_compiled_function):
* alloc.c (Fmake_symbol):
* alloc.c (allocate_extent):
* alloc.c (allocate_event):
* alloc.c (make_key_data):
* alloc.c (make_button_data):
* alloc.c (make_motion_data):
* alloc.c (make_process_data):
* alloc.c (make_timeout_data):
* alloc.c (make_magic_data):
* alloc.c (make_magic_eval_data):
* alloc.c (make_eval_data):
* alloc.c (make_misc_user_data):
* alloc.c (Fmake_marker):
* alloc.c (noseeum_make_marker):
* alloc.c (size_string_direct_data):
* alloc.c (make_uninit_string):
* alloc.c (make_string_nocopy):
* alloc.c (mark_lcrecord_list):
* alloc.c (alloc_managed_lcrecord):
* alloc.c (free_managed_lcrecord):
* alloc.c (sweep_lcrecords_1):
* alloc.c (malloced_storage_size):
* buffer.c (allocate_buffer):
* buffer.c (compute_buffer_usage):
* buffer.c (DEFVAR_BUFFER_LOCAL_1):
* buffer.c (nuke_all_buffer_slots):
* buffer.c (common_init_complex_vars_of_buffer):
* buffer.h (struct buffer_text):
* buffer.h (struct buffer):
* bytecode.c:
* bytecode.c (make_compiled_function_args):
* bytecode.c (size_compiled_function_args):
* bytecode.h (struct compiled_function_args):
* casetab.c (allocate_case_table):
* casetab.h (struct Lisp_Case_Table):
* charset.h (struct Lisp_Charset):
* chartab.c (fill_char_table):
* chartab.c (Fmake_char_table):
* chartab.c (make_char_table_entry):
* chartab.c (copy_char_table_entry):
* chartab.c (Fcopy_char_table):
* chartab.c (put_char_table):
* chartab.h (struct Lisp_Char_Table_Entry):
* chartab.h (struct Lisp_Char_Table):
* console-gtk-impl.h (struct gtk_device):
* console-gtk-impl.h (struct gtk_frame):
* console-impl.h (struct console):
* console-msw-impl.h (struct Lisp_Devmode):
* console-msw-impl.h (struct mswindows_device):
* console-msw-impl.h (struct msprinter_device):
* console-msw-impl.h (struct mswindows_frame):
* console-msw-impl.h (struct mswindows_dialog_id):
* console-stream-impl.h (struct stream_console):
* console-stream.c (stream_init_console):
* console-tty-impl.h (struct tty_console):
* console-tty-impl.h (struct tty_device):
* console-tty.c (allocate_tty_console_struct):
* console-x-impl.h (struct x_device):
* console-x-impl.h (struct x_frame):
* console.c (allocate_console):
* console.c (nuke_all_console_slots):
* console.c (DEFVAR_CONSOLE_LOCAL_1):
* console.c (common_init_complex_vars_of_console):
* data.c (make_weak_list):
* data.c (make_weak_box):
* data.c (make_ephemeron):
* database.c:
* database.c (struct Lisp_Database):
* database.c (allocate_database):
* database.c (finalize_database):
* device-gtk.c (allocate_gtk_device_struct):
* device-impl.h (struct device):
* device-msw.c:
* device-msw.c (mswindows_init_device):
* device-msw.c (msprinter_init_device):
* device-msw.c (finalize_devmode):
* device-msw.c (allocate_devmode):
* device-tty.c (allocate_tty_device_struct):
* device-x.c (allocate_x_device_struct):
* device.c:
* device.c (nuke_all_device_slots):
* device.c (allocate_device):
* dialog-msw.c (handle_question_dialog_box):
* elhash.c:
* elhash.c (struct Lisp_Hash_Table):
* elhash.c (finalize_hash_table):
* elhash.c (make_general_lisp_hash_table):
* elhash.c (Fcopy_hash_table):
* elhash.h (htentry):
* emacs.c (main_1):
* eval.c:
* eval.c (size_multiple_value):
* event-stream.c (finalize_command_builder):
* event-stream.c (allocate_command_builder):
* event-stream.c (free_command_builder):
* event-stream.c (event_stream_generate_wakeup):
* event-stream.c (event_stream_resignal_wakeup):
* event-stream.c (event_stream_disable_wakeup):
* event-stream.c (event_stream_wakeup_pending_p):
* events.h (struct Lisp_Timeout):
* events.h (struct command_builder):
* extents-impl.h:
* extents-impl.h (struct extent_auxiliary):
* extents-impl.h (struct extent_info):
* extents-impl.h (set_extent_no_chase_aux_field):
* extents-impl.h (set_extent_no_chase_normal_field):
* extents.c:
* extents.c (gap_array_marker):
* extents.c (gap_array):
* extents.c (extent_list_marker):
* extents.c (extent_list):
* extents.c (stack_of_extents):
* extents.c (gap_array_make_marker):
* extents.c (extent_list_make_marker):
* extents.c (allocate_extent_list):
* extents.c (SLOT):
* extents.c (mark_extent_auxiliary):
* extents.c (allocate_extent_auxiliary):
* extents.c (attach_extent_auxiliary):
* extents.c (size_gap_array):
* extents.c (finalize_extent_info):
* extents.c (allocate_extent_info):
* extents.c (uninit_buffer_extents):
* extents.c (allocate_soe):
* extents.c (copy_extent):
* extents.c (vars_of_extents):
* extents.h:
* faces.c (allocate_face):
* faces.h (struct Lisp_Face):
* faces.h (struct face_cachel):
* file-coding.c:
* file-coding.c (finalize_coding_system):
* file-coding.c (sizeof_coding_system):
* file-coding.c (Fcopy_coding_system):
* file-coding.h (struct Lisp_Coding_System):
* file-coding.h (MARKED_SLOT):
* fns.c (size_bit_vector):
* font-mgr.c:
* font-mgr.c (finalize_fc_pattern):
* font-mgr.c (print_fc_pattern):
* font-mgr.c (Ffc_pattern_p):
* font-mgr.c (Ffc_pattern_create):
* font-mgr.c (Ffc_name_parse):
* font-mgr.c (Ffc_name_unparse):
* font-mgr.c (Ffc_pattern_duplicate):
* font-mgr.c (Ffc_pattern_add):
* font-mgr.c (Ffc_pattern_del):
* font-mgr.c (Ffc_pattern_get):
* font-mgr.c (fc_config_create_using):
* font-mgr.c (fc_strlist_to_lisp_using):
* font-mgr.c (fontset_to_list):
* font-mgr.c (Ffc_config_p):
* font-mgr.c (Ffc_config_up_to_date):
* font-mgr.c (Ffc_config_build_fonts):
* font-mgr.c (Ffc_config_get_cache):
* font-mgr.c (Ffc_config_get_fonts):
* font-mgr.c (Ffc_config_set_current):
* font-mgr.c (Ffc_config_get_blanks):
* font-mgr.c (Ffc_config_get_rescan_interval):
* font-mgr.c (Ffc_config_set_rescan_interval):
* font-mgr.c (Ffc_config_app_font_add_file):
* font-mgr.c (Ffc_config_app_font_add_dir):
* font-mgr.c (Ffc_config_app_font_clear):
* font-mgr.c (size):
* font-mgr.c (Ffc_config_substitute):
* font-mgr.c (Ffc_font_render_prepare):
* font-mgr.c (Ffc_font_match):
* font-mgr.c (Ffc_font_sort):
* font-mgr.c (finalize_fc_config):
* font-mgr.c (print_fc_config):
* font-mgr.h:
* font-mgr.h (struct fc_pattern):
* font-mgr.h (XFC_PATTERN):
* font-mgr.h (struct fc_config):
* font-mgr.h (XFC_CONFIG):
* frame-gtk.c (allocate_gtk_frame_struct):
* frame-impl.h (struct frame):
* frame-msw.c (mswindows_init_frame_1):
* frame-x.c (allocate_x_frame_struct):
* frame.c (nuke_all_frame_slots):
* frame.c (allocate_frame_core):
* gc.c:
* gc.c (GC_CHECK_NOT_FREE):
* glyphs.c (finalize_image_instance):
* glyphs.c (allocate_image_instance):
* glyphs.c (Fcolorize_image_instance):
* glyphs.c (allocate_glyph):
* glyphs.c (unmap_subwindow_instance_cache_mapper):
* glyphs.c (register_ignored_expose):
* glyphs.h (struct Lisp_Image_Instance):
* glyphs.h (struct Lisp_Glyph):
* glyphs.h (struct glyph_cachel):
* glyphs.h (struct expose_ignore):
* gui.c (allocate_gui_item):
* gui.h (struct Lisp_Gui_Item):
* keymap.c (struct Lisp_Keymap):
* keymap.c (make_keymap):
* lisp.h:
* lisp.h (struct Lisp_String_Direct_Data):
* lisp.h (struct Lisp_String_Indirect_Data):
* lisp.h (struct Lisp_Vector):
* lisp.h (struct Lisp_Bit_Vector):
* lisp.h (DECLARE_INLINE_LISP_BIT_VECTOR):
* lisp.h (struct weak_box):
* lisp.h (struct ephemeron):
* lisp.h (struct weak_list):
* lrecord.h:
* lrecord.h (struct lrecord_implementation):
* lrecord.h (MC_ALLOC_CALL_FINALIZER):
* lrecord.h (struct lcrecord_list):
* lstream.c (finalize_lstream):
* lstream.c (sizeof_lstream):
* lstream.c (Lstream_new):
* lstream.c (Lstream_delete):
* lstream.h (struct lstream):
* marker.c:
* marker.c (finalize_marker):
* marker.c (compute_buffer_marker_usage):
* mule-charset.c:
* mule-charset.c (make_charset):
* mule-charset.c (compute_charset_usage):
* objects-impl.h (struct Lisp_Color_Instance):
* objects-impl.h (struct Lisp_Font_Instance):
* objects-tty-impl.h (struct tty_color_instance_data):
* objects-tty-impl.h (struct tty_font_instance_data):
* objects-tty.c (tty_initialize_color_instance):
* objects-tty.c (tty_initialize_font_instance):
* objects.c (finalize_color_instance):
* objects.c (Fmake_color_instance):
* objects.c (finalize_font_instance):
* objects.c (Fmake_font_instance):
* objects.c (reinit_vars_of_objects):
* opaque.c:
* opaque.c (sizeof_opaque):
* opaque.c (make_opaque_ptr):
* opaque.c (free_opaque_ptr):
* opaque.h:
* opaque.h (Lisp_Opaque):
* opaque.h (Lisp_Opaque_Ptr):
* print.c (printing_unreadable_lcrecord):
* print.c (external_object_printer):
* print.c (debug_p4):
* process.c (finalize_process):
* process.c (make_process_internal):
* procimpl.h (struct Lisp_Process):
* rangetab.c (Fmake_range_table):
* rangetab.c (Fcopy_range_table):
* rangetab.h (struct Lisp_Range_Table):
* scrollbar.c:
* scrollbar.c (create_scrollbar_instance):
* scrollbar.c (compute_scrollbar_instance_usage):
* scrollbar.h (struct scrollbar_instance):
* specifier.c (finalize_specifier):
* specifier.c (sizeof_specifier):
* specifier.c (set_specifier_caching):
* specifier.h (struct Lisp_Specifier):
* specifier.h (struct specifier_caching):
* symeval.h:
* symeval.h (SYMBOL_VALUE_MAGIC_P):
* symeval.h (DEFVAR_SYMVAL_FWD):
* symsinit.h:
* syntax.c (init_buffer_syntax_cache):
* syntax.h (struct syntax_cache):
* toolbar.c:
* toolbar.c (allocate_toolbar_button):
* toolbar.c (update_toolbar_button):
* toolbar.h (struct toolbar_button):
* tooltalk.c (struct Lisp_Tooltalk_Message):
* tooltalk.c (make_tooltalk_message):
* tooltalk.c (struct Lisp_Tooltalk_Pattern):
* tooltalk.c (make_tooltalk_pattern):
* ui-gtk.c:
* ui-gtk.c (allocate_ffi_data):
* ui-gtk.c (emacs_gtk_object_finalizer):
* ui-gtk.c (allocate_emacs_gtk_object_data):
* ui-gtk.c (allocate_emacs_gtk_boxed_data):
* ui-gtk.h:
* window-impl.h (struct window):
* window-impl.h (struct window_mirror):
* window.c (finalize_window):
* window.c (allocate_window):
* window.c (new_window_mirror):
* window.c (mark_window_as_deleted):
* window.c (make_dummy_parent):
* window.c (compute_window_mirror_usage):
* window.c (compute_window_usage):
Overall point of this change and previous ones in this repository:
(1) Introduce new, clearer terminology: everything other than int
or char is a "record" object, which comes in two types: "normal
objects" and "frob-block objects". Fix up all places that
referred to frob-block objects as "simple", "basic", etc.
(2) Provide an advertised interface for doing operations on Lisp
objects, including creating new types, that is clean and
consistent in its naming, uses the above-referenced terms and
avoids referencing "lrecords", "old lcrecords", etc., which should
hide under the surface.
(3) Make the size_in_bytes and finalizer methods take a
Lisp_Object rather than a void * for consistency with other methods.
(4) Separate finalizer method into finalizer and disksaver, so
that normal finalize methods don't have to worry about disksaving.
Other specifics:
(1) Renaming:
LISP_OBJECT_HEADER -> NORMAL_LISP_OBJECT_HEADER
ALLOC_LISP_OBJECT -> ALLOC_NORMAL_LISP_OBJECT
implementation->basic_p -> implementation->frob_block_p
ALLOCATE_FIXED_TYPE_AND_SET_IMPL -> ALLOC_FROB_BLOCK_LISP_OBJECT
*FCCONFIG*, wrap_fcconfig -> *FC_CONFIG*, wrap_fc_config
*FCPATTERN*, wrap_fcpattern -> *FC_PATTERN*, wrap_fc_pattern
(the last two changes make the naming of these macros consistent
with the naming of all other macros, since the objects are named
fc-config and fc-pattern with a hyphen)
(2) Lots of documentation fixes in lrecord.h.
(3) Eliminate macros for copying, freeing, zeroing objects, getting
their storage size. Instead, new functions:
zero_sized_lisp_object()
zero_nonsized_lisp_object()
lisp_object_storage_size()
free_normal_lisp_object()
(copy_lisp_object() already exists)
LISP_OBJECT_FROB_BLOCK_P() (actually a macro)
Eliminated:
free_lrecord()
zero_lrecord()
copy_lrecord()
copy_sized_lrecord()
old_copy_lcrecord()
old_copy_sized_lcrecord()
old_zero_lcrecord()
old_zero_sized_lcrecord()
LISP_OBJECT_STORAGE_SIZE()
COPY_SIZED_LISP_OBJECT()
COPY_SIZED_LCRECORD()
COPY_LISP_OBJECT()
ZERO_LISP_OBJECT()
FREE_LISP_OBJECT()
(4) Catch the remaining places where lrecord stuff was used directly
and use the advertised interface, e.g. alloc_sized_lrecord() ->
ALLOC_SIZED_LISP_OBJECT().
(5) Make certain statically-declared pseudo-objects
(buffer_local_flags, console_local_flags) have their lheader
initialized correctly, so things like copy_lisp_object() can work
on them. Make extent_auxiliary_defaults a proper heap object
Vextent_auxiliary_defaults, and make extent auxiliaries dumpable
so that this object can be dumped. allocate_extent_auxiliary()
now just creates the object, and attach_extent_auxiliary()
creates an extent auxiliary and attaches to an extent, like the
old allocate_extent_auxiliary().
(6) Create EXTENT_AUXILIARY_SLOTS macro, similar to the foo-slots.h
files but in a macro instead of a file. The purpose is to avoid
duplication when iterating over all the slots in an extent auxiliary.
Use it.
(7) In lstream.c, don't zero out object after allocation because
allocation routines take care of this.
(8) In marker.c, fix a mistake in computing marker overhead.
(9) In print.c, clean up printing_unreadable_lcrecord(),
external_object_printer() to avoid lots of ifdef NEW_GC's.
(10) Separate toolbar-button allocation into a separate
allocate_toolbar_button() function for use in the example code
in lrecord.h.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Fri, 05 Mar 2010 04:08:17 -0600 |
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 } |