Module: duim-sheets-internals Synopsis: DUIM sheets 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 /// Frame Managers //--- Should these be added to the display instead of the port? define open abstract primary class () sealed slot port :: false-or() = #f, init-keyword: port:, setter: %port-setter; sealed slot frame-manager-frames :: = make(); sealed slot frame-manager-palette :: false-or() = #f, init-keyword: palette:; end class ; define sealed class () end class ; //---*** This is most likely wrong, since it forces a 1-to-1 mapping //---*** between ports and displays define method display (framem :: ) => (display :: false-or()) let displays = port-displays(port(framem)); ~empty?(displays) & displays[0] end method display; define method initialize (framem :: , #key) next-method(); unless (frame-manager-palette(framem)) frame-manager-palette(framem) := port-default-palette(port(framem)) end end method initialize; define method find-color (name, framem :: , #key error? = #t) => (color :: ) find-color(name, frame-manager-palette(framem), error?: error?) end method find-color; /// Frame manager creation define method find-frame-manager (#rest options, #key port: _port, server-path, class, palette, #all-keys) => (framem :: ) dynamic-extent(options); block (return) with-keywords-removed (new-options = options, #[port:, server-path:, palette:]) unless (_port) _port := default-port(server-path: server-path) end; unless (palette) palette := port-default-palette(_port) end; // Don't call 'port-default-frame-manager', because that can // get us into a loop... let default-framem = begin let framems = port-frame-managers(_port); case empty?(framems) => #f; ~class => framems[0]; otherwise => find-value(framems, method (f) object-class(f) == class end); end end; case // 'find-frame-manager' -> default one default-framem & empty?(options) => default-framem; // We specified a port, so make sure the default framem matches it default-framem & apply(frame-manager-matches-options?, default-framem, _port, new-options) => default-framem; // No default, look for one in the port, or create a new one; otherwise => for (framem in port-frame-managers(_port)) when (apply(frame-manager-matches-options?, framem, _port, palette: palette, new-options)) return(framem) end; end; let framem = apply(make-frame-manager, _port, palette: palette, new-options); add!(port-frame-managers(_port), framem); framem end end end end method find-frame-manager; define open generic make-frame-manager (port :: , #key class, palette, #all-keys) => (framem :: ); define method make-frame-manager (_port :: , #key palette, class = , #all-keys) => (framem :: ) make(class, port: _port, palette: palette) end method make-frame-manager; define sealed inline method make (class == , #rest initargs, #key port: _port, #all-keys) => (framem :: ) dynamic-extent(initargs); apply(make-frame-manager, _port, initargs) end method make; define method frame-manager-matches-options? (framem :: , _port, #key palette, class, #all-keys) => (true? :: ) ignore(palette); port(framem) == _port & (~class | object-class(framem) == class) end method frame-manager-matches-options?; define method destroy-frame-manager (framem :: ) => () while (~empty?(frame-manager-frames(framem))) destroy-frame(frame-manager-frames(framem)[0]) end; let _port = port(framem); remove!(port-frame-managers(_port), framem) end method destroy-frame-manager; /// Frame protocol //--- These are all forward references into 'duim-frames' // The current application frame in this thread define thread variable *current-frame* = #f; define inline function current-frame () *current-frame* end; define open generic destroy-frame (frame :: ) => (); define open generic frame-input-focus (frame :: ) => (sheet :: false-or()); define open generic frame-input-focus-setter (sheet :: false-or(), frame :: ) => (sheet :: false-or()); define open generic frame-cursor-override (frame :: ) => (cursor :: false-or()); define open generic frame-cursor-override-setter (cursor :: false-or(), frame :: ) => (cursor :: false-or()); define function do-frames (function :: , #key port: _port, frame-manager: framem, z-order :: = #f) => () dynamic-extent(function); local method do-port-frames (_port :: ) => () for (framem in port-frame-managers(_port)) frame-manager-do-frames(function, framem, z-order: z-order) end end method; case framem => // Frame manager specified, so map over all the frames for // just this frame manager frame-manager-do-frames(function, framem, z-order: z-order); _port => // Port specified, map over all of the frames for all of the // frame managers on the port do-port-frames(_port); otherwise => // Map over all of the port... for (_port in *ports*) do-port-frames(_port) end; end end function do-frames; define open generic frame-manager-do-frames (function :: , framem :: , #key z-order :: ) => (); define method frame-manager-do-frames (function :: , framem :: , #key z-order :: = #f) => () ignore(z-order); // Copy the sequence of frame manager's frames in case the function // modifies the sequence, e.g., 'do-frames(exit-frame, port: _port)' let frames = copy-sequence(frame-manager-frames(framem)); do(function, frames) end method frame-manager-do-frames; /// Pane creation // The current application frame in this thread define thread variable *current-frame-manager* :: false-or() = #f; define inline function current-frame-manager () *current-frame-manager* end; // Here for compatibility and self-documentation... define method make-pane (pane-class :: , #rest pane-options, #key, #all-keys) => (pane :: ) dynamic-extent(pane-options); apply(make, pane-class, pane-options) end method make-pane; //--- If you change this method, change the one in gadgets/gadget-mixins 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; // Platform-specific back-ends must supply methods for: // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // - // The DUIM gadgets library provides methods for: // -