
// // Copyright (c) 2008, Brian Frank and Andy Frank // Licensed under the Academic Free License version 3.0 // // History: // 22 Jul 08 Brian Frank Creation // ** ** Command packages up the diplay name, icon, execution, ** and undo support for a user command. You can create a ** command two ways: ** 1. use a closure (or any function) for `onInvoke` ** 2. subclass Command and override `invoke` ** ** If the command supports undo, then you must create a ** a subclass and override `undo`. ** ** Commands are often used to centralize control of multiple ** widgets. For example if a Command is associated with ** both a menu item and a toolbar button, then disabling the ** command will disable both the menu item and toolbar button. ** class Command { ////////////////////////////////////////////////////////////////////////// // Fields ////////////////////////////////////////////////////////////////////////// ** ** Name of the command. ** Str name ** ** Icon of the command or null. Typically a 16x16. ** Image icon ** ** The function to invoke when the command is executed. If ** null, then `invoke` must be overridden. ** |Event event| onInvoke ////////////////////////////////////////////////////////////////////////// // Constructor ////////////////////////////////////////////////////////////////////////// ** ** Construct a command with the specified onInvoke function. ** If onInvoke is not specified, then the `invoke` method ** must be overridden to execute the command. ** new make(Str name := null, Image icon := null, |Event event| onInvoke := null) { this.name = name this.icon = icon this.onInvoke = onInvoke } ////////////////////////////////////////////////////////////////////////// // Enabled ////////////////////////////////////////////////////////////////////////// ** ** The enable state of the command automatically controls ** the enabled state of all the registered widgets. ** Bool enabled := true { set { if (@enabled == val) return @enabled = val registry.each |Widget w| { w.enabled = val } } } ** ** Get the associated widgets with this command. Widgets are ** automatically associated with their command field is set. ** Widget[] widgets() { return registry.ro } ** ** Register a widget with this command. This is done ** automatically by the widget. You only need to call ** this method if you are developing a custom widget. ** Void register(Widget w) { registry.add(w) } ** ** Unregister a widget with this command. This is done ** automatically by the widget. You only need to call ** this method if you are developing a custom widget. ** Void unregister(Widget w) { registry.removeSame(w) } private Widget[] registry := Widget[,] ////////////////////////////////////////////////////////////////////////// // Invoke ////////////////////////////////////////////////////////////////////////// ** ** Invoke the command. If the user event is known ** then is passed, otherwise it might be null. ** virtual Void invoke(Event event) { if (onInvoke == null) throw UnsupportedErr("Must set onInvoke or override invoke: $name") onInvoke.call1(event) } ////////////////////////////////////////////////////////////////////////// // Undo ////////////////////////////////////////////////////////////////////////// ** ** Return if the command can be undone. Default implementation ** returns true is the `undo` method has been overridden. ** virtual Bool undoable() { return type.method("undo").parent != Command# } ** ** This method is invoked when the command invoked as ** a redo. It is not called on the first invocation. ** Default calls `invoke` with a null event. ** virtual Void redo() { invoke(null) } ** ** This method is invoked to undo the command. This ** method is only used if `undoable` returns true. ** virtual Void undo() { throw UnsupportedErr("Command not undoable $name") } }