Module: duim-gadgets-internals Synopsis: DUIM gadgets Author: Scott McKay, Andy Armstrong Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Generic gadget protocols // By the time we instantiate a gadget, it will be a as well... define open abstract class () end; // "Primary" gadget classes should inherit from // "Mixin" gadget classes should inherit from define protocol-class gadget () /* virtual slot gadget-enabled? :: ; virtual slot gadget-label; virtual slot gadget-value; virtual slot gadget-id; virtual slot gadget-client; virtual slot gadget-documentation; */ end protocol-class gadget; //--- If you change this method, change the one in sheets/frame-managers define method make (pane-class :: subclass(), #rest pane-options, #key port, frame-manager: framem, #all-keys) => (pane :: ) dynamic-extent(pane-options); let framem = framem | *current-frame-manager* | port-default-frame-manager(port | default-port()) | error("Can't find a frame manager to use with 'make-pane'"); let (concrete-class, concrete-options) = apply(class-for-make-pane, framem, pane-class, pane-options); // If there's a mapping from the abstract pane class to a concrete pane // class, then use it. Otherwise just try to create a class named by the // abstract pane class. if (concrete-class == pane-class) apply(next-method, pane-class, frame-manager: framem, pane-options) else //---*** Unfortunately, this recursive call to make will call //---*** 'class-for-make-pane' again. How to speed this up? apply(make, concrete-class, frame-manager: framem, concrete-options | pane-options) end end method make; define constant = one-of(#"horizontal", #"vertical", #"none"); define constant = one-of(#"none", #"single", #"multiple"); // Currently just for Windows "push-button-like" buttons... define constant = one-of(#f, #"push-button"); define constant = type-union(, ); define open abstract class () end class ; define protocol <> () getter gadget-enabled? (gadget :: ) => (enabled? :: ); setter gadget-enabled?-setter (enabled? :: , gadget :: ) => (enabled? :: ); function note-gadget-disabled (client, gadget :: ) => (); function note-gadget-enabled (client, gadget :: ) => (); getter gadget-id (gadget :: ) => (id); setter gadget-id-setter (id, gadget :: ) => (id); getter gadget-client (gadget :: ) => (client); function gadget-client-setter (client, gadget :: ) => (client); getter gadget-documentation (gadget :: ) => (documentation); setter gadget-documentation-setter (documentation, gadget :: ) => (documentation); getter gadget-selection-mode (gadget :: ) => (selection-mode :: ); getter gadget-default? (gadget :: ) => (default? :: ); getter gadget-default?-setter (default? :: , gadget :: ) => (default? :: ); getter gadget-read-only? (gadget :: ) => (read-only? :: ); getter gadget-slug-size (gadget :: ) => (slug-size :: ); getter gadget-slug-size-setter (slug-size :: , gadget :: ) => (slug-size :: ); function note-gadget-slug-size-changed (gadget :: ) => (); // Orientation and labels getter gadget-orientation (gadget :: ) => (orientation :: ); getter gadget-label (gadget :: ) => (label); setter gadget-label-setter (label, gadget :: ) => (label); function note-gadget-label-changed (gadget :: ) => (); function gadget-label-size (gadget :: , #key do-newlines?, do-tabs?) => (width :: , height :: ); function draw-gadget-label (gadget :: , medium :: , x, y, #key align-x, align-y, state, do-tabs?, brush, underline?) => (); // Accelerators and mnemonics getter gadget-accelerator (gadget :: ) => (accelerator); setter gadget-accelerator-setter (accelerator, gadget :: ) => (accelerator); getter defaulted-gadget-accelerator (framem :: , gadget :: ) => (accelerator :: false-or()); getter gadget-mnemonic (gadget :: ) => (mnemonic); setter gadget-mnemonic-setter (mnemonic, gadget :: ) => (mnemonic); getter defaulted-gadget-mnemonic (framem :: , gadget :: ) => (mnemonic :: false-or()); function compute-mnemonic-from-label (sheet :: type-union(, ), label, #key remove-ampersand?) => (label, mnemonic :: false-or(), index :: false-or()); getter gadget-scrolling? (gadget :: ) => (horizontally? :: , vertically? :: ); getter gadget-scrolling-horizontally? (gadget :: ) => (horizontally? :: ); getter gadget-scrolling-vertically? (gadget :: ) => (vertically? :: ); getter gadget-lines (gadget :: ) => (lines :: false-or()); getter gadget-columns (gadget :: ) => (columns :: false-or()); getter gadget-state (gadget :: ) => (state :: false-or()); setter gadget-state-setter (state :: , gadget :: ) => (state :: ); end protocol <>; /// Basic gadget definition // Note that only the concrete gadget classes have a , // which will typically come when gets included in the CPL define open abstract class () sealed slot gadget-id = #f, init-keyword: id:; sealed slot gadget-client = #f, init-keyword: client:; slot gadget-documentation :: false-or() = #f, init-keyword: documentation:, setter: %documentation-setter; // This stores mostly "static" properties that get used at mirroring time sealed slot gadget-flags :: = $initial-gadget-flags; end class ; // Bits 0..5 are some basic boolean flags define constant %gadget_enabled :: = #o01; define constant %gadget_read_only :: = #o02; define constant %default_button :: = #o04; define constant %show_value :: = #o10; define constant %tear_off_menu :: = #o20; define constant %help_menu :: = #o40; // Reuse this bit, since you can't be both a label and a menu define constant %multi_line_label :: = %tear_off_menu; // Bits 6..8 is the x-alignment field define constant %x_alignment_shift :: = 6; define constant %x_alignment_mask :: = #o700; define constant %x_alignment_left :: = #o000; define constant %x_alignment_right :: = #o100; define constant %x_alignment_center :: = #o200; // Bits 9..11 is the y-alignment field define constant %y_alignment_shift :: = 9; define constant %y_alignment_mask :: = #o7000; define constant %y_alignment_top :: = #o0000; define constant %y_alignment_bottom :: = #o1000; define constant %y_alignment_center :: = #o2000; define constant %y_alignment_baseline :: = #o3000; // Bits 12..14 is the scroll bar field define constant %scroll_bar_shift :: = 12; define constant %scroll_bar_mask :: = #o70000; define constant %scroll_bar_false :: = #o00000; define constant %scroll_bar_none :: = #o10000; define constant %scroll_bar_horizontal :: = #o20000; define constant %scroll_bar_vertical :: = #o30000; define constant %scroll_bar_both :: = #o40000; define constant %scroll_bar_dynamic :: = #o50000; // Bits 15..17 is the orientation field // define constant %orientation_shift :: = 15; define constant %orientation_mask :: = #o700000; define constant %orientation_none :: = #o000000; define constant %orientation_horizontal :: = #o100000; define constant %orientation_vertical :: = #o200000; // Bits 18..20 are some text field flags define constant %text_case_shift :: = 18; define constant %text_case_mask :: = #o3000000; define constant %text_case_false :: = #o0000000; define constant %text_case_lower :: = #o1000000; define constant %text_case_upper :: = #o2000000; define constant %auto_scroll :: = #o4000000; // Bits 21..23 are for gadgets that do their own borders define constant %border_shift :: = 21; define constant %border_mask :: = #o70000000; define constant %border_default :: = #o00000000; define constant %border_none :: = #o10000000; define constant %border_sunken :: = #o20000000; define constant %border_raised :: = #o30000000; define constant %border_ridge :: = #o40000000; define constant %border_groove :: = #o50000000; define constant %border_input :: = #o60000000; define constant %border_output :: = #o70000000; // Bit 24 is for "push-button-like" gadgets in tool bars define constant %push_button_like :: = #o100000000; // Bit 25 tells the gadget to ensure that the selection is visible define constant %keep_selection_visible :: = #o200000000; define constant $initial-gadget-flags :: = logior(%gadget_enabled, %show_value, %x_alignment_center, %y_alignment_top, %scroll_bar_both, %orientation_horizontal, %border_default, %keep_selection_visible); define method initialize (gadget :: , #key enabled? = #t, read-only? = #f, button-style :: = #f) next-method(); let bits = logior(if (enabled?) %gadget_enabled else 0 end, if (read-only?) %gadget_read_only else 0 end, if (button-style == #"push-button") %push_button_like else 0 end); gadget-flags(gadget) := logior(logand(gadget-flags(gadget), lognot(logior(%gadget_enabled, %gadget_read_only, %push_button_like))), bits) end method initialize; define method gadget-state (gadget :: ) => (state :: false-or()) #f end method gadget-state; define method gadget-state-setter (state :: , gadget :: ) => (state :: ) state end method gadget-state-setter; /// Basic gadget methods // Make gadgets have no label by default define method gadget-label (gadget :: ) => (label) #f end method gadget-label; define method gadget-documentation-setter (documentation, gadget :: ) => (documentation :: false-or()) gadget.%documentation := documentation end method gadget-documentation-setter; define sealed inline method gadget-read-only? (gadget :: ) => (read-only? :: ) logand(gadget-flags(gadget), %gadget_read_only) = %gadget_read_only end method gadget-read-only?; define sealed inline method push-button-like? (gadget :: ) => (push-button-like? :: ) logand(gadget-flags(gadget), %push_button_like) = %push_button_like end method push-button-like?; define method update-gadget (gadget :: ) => () #f end method update-gadget; /// Callbacks // Could be 'false-or(, , , )', but it's not worth it define constant = ; define constant = type-union(, ); define open generic execute-callback (client :: , callback :: , #rest args) => (); define method execute-callback (client :: , function :: , #rest args) => () dynamic-extent(args); apply(function, args) end method execute-callback; // A little bit of Lisp for you... define method execute-callback (client :: , function :: , #rest args) => () dynamic-extent(args); apply(head(function), concatenate(args, tail(function))) end method execute-callback; /// Command callbacks define method callback-for-command (command :: ) => (callback :: , command) values(method (sheet) command(sheet-frame(sheet)) end method, command) end method callback-for-command; define method callback-for-command (command :: ) => (callback :: , command) values(method (sheet) //--- This could copy the command and plug in the new server and client... execute-command(command) end method, command) end method callback-for-command; define method callback-for-command (command-type :: subclass()) => (callback :: , command) values(method (sheet) execute-command-type(command-type, server: sheet-frame(sheet), client: sheet) end method, command-type) end method callback-for-command; define method callback-for-command (command-type :: ) => (callback :: , command) values(method (sheet) execute-command-type(command-type, server: sheet-frame(sheet), client: sheet) end method, head(command-type)) end method callback-for-command; /// Enabling and disabling of gadgets define sealed inline method gadget-enabled? (gadget :: ) => (enabled? :: ) logand(gadget-flags(gadget), %gadget_enabled) = %gadget_enabled end method gadget-enabled?; define sealed method gadget-enabled?-setter (enabled? :: , gadget :: ) => (enabled? :: ) let bit = if (enabled?) %gadget_enabled else 0 end; when (logand(gadget-flags(gadget), %gadget_enabled) ~= bit) gadget-flags(gadget) := logior(logand(gadget-flags(gadget), lognot(%gadget_enabled)), bit); if (enabled?) note-gadget-enabled(gadget-client(gadget), gadget) else note-gadget-disabled(gadget-client(gadget), gadget) end end; enabled? end method gadget-enabled?-setter; define method note-gadget-enabled (client, gadget :: ) => () ignore(client); #f end method note-gadget-enabled; define method note-gadget-disabled (client, gadget :: ) => () ignore(client); #f end method note-gadget-disabled; /// Value gadgets define open abstract class () end class ; define open abstract class () end class ; define protocol <> (<>) getter gadget-value (gadget :: ) => (value); setter gadget-value-setter (value, gadget :: , #key do-callback?) => (value); function do-gadget-value-setter (gadget :: , normalized-value) => (); getter gadget-value-type (gadget :: ) => (type :: ); getter gadget-label-key (gadget :: ) => (label-key :: ); getter gadget-value-key (gadget :: ) => (value-key :: ); function normalize-gadget-value (gadget :: , value) => (value); function note-gadget-value-changed (gadget :: ) => (); function execute-value-changed-callback (gadget :: , client, id) => (); function do-execute-value-changed-callback (gadget :: , client, id) => (); getter gadget-value-changed-callback (gadget :: ) => (callback :: ); setter gadget-value-changed-callback-setter (callback :: , gadget :: ) => (callback :: ); getter gadget-value-range (gadget :: ) => (value-range :: ); getter gadget-value-range-setter (value-range :: , gadget :: ) => (value-range :: ); function note-gadget-value-range-changed (gadget :: ) => (); getter gadget-start-value (gadget :: ) => (start-value :: ); getter gadget-end-value (gadget :: ) => (start-value :: ); getter gadget-value-increment (gadget :: ) => (increment :: ); // This one is a little odd, but it is exported... getter button-gadget-value (button ::