Module: duim-deuce-internals Synopsis: DUIM back-end for Deuce Author: Scott McKay 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 /// DUIM back-end for choosing from a menu define sealed method deuce/choose-from-menu (window :: , items :: , #key title, value, label-key, value-key, width, height, multiple-sets? = #f) => (value :: false-or(), success? :: ) let (value, success? :: ) = choose-from-menu(items, title: title, label-key: label-key, value-key: value-key, value: value, owner: sheet-frame(window), width: width, height: height, multiple-sets?: multiple-sets?); values(success? & value, success?) end method deuce/choose-from-menu; define sealed method deuce/choose-from-dialog (window :: , items :: , #key title, value, label-key, value-key, width, height, selection-mode = #"single") => (value :: false-or(), success? :: , width :: false-or(), height :: false-or()) let (value, success? :: , width, height) = choose-from-dialog(items, title: title, label-key: label-key, value-key: value-key, value: value, owner: sheet-frame(window), width: width, height: height, selection-mode: selection-mode); values(success? & value, success?, width, height) end method deuce/choose-from-dialog; /// DUIM back-end for various dialogs define sealed method information-dialog (window :: , format-string :: , #rest format-args) => () let frame = sheet-frame(window); notify-user(apply(format-to-string, format-string, format-args), owner: frame, style: #"information") end method information-dialog; define sealed method warning-dialog (window :: , format-string :: , #rest format-args) => () let frame = sheet-frame(window); notify-user(apply(format-to-string, format-string, format-args), owner: frame, style: #"warning") end method warning-dialog; define sealed method yes-or-no-dialog (window :: , format-string :: , #rest format-args) => (result :: ) let frame = sheet-frame(window); let (value, exit-type) = notify-user(apply(format-to-string, format-string, format-args), owner: frame, style: #"question", exit-style: #"yes-no"); ignore(value); select (exit-type) #"yes" => #t; #"no" => #f; end end method yes-or-no-dialog; define sealed method yes-no-or-cancel-dialog (window :: , format-string :: , #rest format-args) => (result :: type-union(, singleton(#"cancel"))) let frame = sheet-frame(window); let (value, exit-type) = notify-user(apply(format-to-string, format-string, format-args), owner: frame, style: #"question", exit-style: #"yes-no-cancel"); ignore(value); select (exit-type) #"yes" => #t; #"no" => #f; #"cancel" => #"cancel"; end end method yes-no-or-cancel-dialog; define sealed method open-file-dialog (window :: , #key default, default-type) => (pathname :: false-or()) let frame = sheet-frame(window); choose-file(owner: frame, direction: #"input", if-does-not-exist: #"ask", default: default & as(, default), default-type: default-type) end method open-file-dialog; define sealed method new-file-dialog (window :: , #key default, default-type) => (pathname :: false-or()) let frame = sheet-frame(window); choose-file(owner: frame, direction: #"output", if-exists: #"overwrite", // Deuce will take care of this default: default & as(, default), default-type: default-type) end method new-file-dialog; // These can be tweaked by the user... define variable $buffer-box-width :: = 250; define variable $buffer-box-height :: = 100; define sealed method save-buffers-dialog (window :: , #key exit-label :: false-or(), reason :: false-or(), buffers :: false-or(), default-buffers :: false-or()) => (buffers :: type-union(, singleton(#f), singleton(#"cancel")), no-buffers? :: ) // Note that sheet-frame ~= window-frame for let frame = sheet-frame(window); let editor = frame-editor(window-frame(window)); do-save-buffers-dialog(frame, editor, exit-label: exit-label, reason: reason, buffers: buffers, default-buffers: default-buffers) end method save-buffers-dialog; define sealed method do-save-buffers-dialog (frame :: , editor :: , #key exit-label :: false-or(), reason :: false-or(), buffers :: false-or(), default-buffers :: false-or()) => (buffers :: type-union(, singleton(#f), singleton(#"cancel")), no-buffers? :: ) // List all buffers but initially select only modified or non-file buffers. // Only show the dialog if there are files needing to be saved. //--- It would be nice to inform the user if either (1) an unmodified file //--- was deleted from the file system and offer to re-save it, or (2) an //--- unmodified file was changed on the file system // Keep the set of buffers sorted... editor-buffers(editor) := sort!(editor-buffers(editor), test: method (b1, b2) string-less?(buffer-name(b1), buffer-name(b2)) end); // Use buffers passed in (if any), else all modified non-anonymous buffers let all-buffers = buffers | choose(method (b) ~buffer-anonymous?(b) end, editor-buffers(editor)); let default-buffers = default-buffers | choose(method (b) buffer-modified?(b) & ~special-purpose-buffer?(b) end, all-buffers); if (empty?(default-buffers)) values(#f, #t) else let framem = frame-manager(frame); let save-label = "&Save"; let all-label = "Save &All"; let cancel-label = "Cancel"; with-frame-manager (framem) let result = default-buffers; let reason-labels = reason & string-to-labels(reason); let reason-layout = reason-labels & ~empty?(reason-labels) & make(, children: reason-labels); let buffers-box = make(, items: all-buffers, value: default-buffers, label-key: buffer-name, width: $buffer-box-width, height: $buffer-box-height, selection-mode: #"multiple", activate-callback: method (b) result := gadget-value(b); exit-dialog(b) end method); let reason-and-buffers = if (reason-layout) make(, y-spacing: 2, children: vector(reason-layout, buffers-box)); else buffers-box end; let save-button = make(, label: save-label, activate-callback: method (b) result := gadget-value(buffers-box); exit-dialog(b) end method); let all-button = make(, label: all-label, activate-callback: method (b) // OK, so it doesn't really save them all, // it just saves all of the modified buffers result := default-buffers; exit-dialog(b) end method); let exit-button = make(, label: exit-label, activate-callback: method (b) result := #f; exit-dialog(b) end method); let cancel-button = make(, label: cancel-label, activate-callback: method (b) result := #"cancel"; exit-dialog(b) end method); let layout = make(, y-spacing: 2, x-alignment: #"right", children: vector(reason-and-buffers, make(, x-alignment: #"right", x-spacing: 2, equalize-widths?: #t, children: if (exit-label) vector(save-button, all-button, exit-button, cancel-button) else vector(save-button, all-button, cancel-button) end))); let dialog = make(, title: "Save Files", layout: layout, input-focus: buffers-box, exit-buttons?: #f, // we'll do our own exit buttons exit-button: exit-button, cancel-button: cancel-button, mode: #"modal", owner: frame, // Be consistent with 'choose-buffer-dialog' width: max($buffer-box-width, 300)); frame-default-button(dialog) := save-button; let exit-status = start-dialog(dialog); when (exit-status) let (width, height) = sheet-size(buffers-box); $buffer-box-width := width; $buffer-box-height := height end; values(exit-status & result, #f) end end end method do-save-buffers-dialog; // Return a sequence of