| 1 | ;; menu-uitls.lisp
|
|---|
| 2 |
|
|---|
| 3 | #|
|
|---|
| 4 | The MIT license.
|
|---|
| 5 |
|
|---|
| 6 | Copyright (c) 2010 Paul L. Krueger
|
|---|
| 7 |
|
|---|
| 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|---|
| 9 | and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|---|
| 10 | including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|---|
| 11 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
|---|
| 12 | furnished to do so, subject to the following conditions:
|
|---|
| 13 |
|
|---|
| 14 | The above copyright notice and this permission notice shall be included in all copies or substantial
|
|---|
| 15 | portions of the Software.
|
|---|
| 16 |
|
|---|
| 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|---|
| 18 | LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|---|
| 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|---|
| 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|---|
| 21 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|---|
| 22 |
|
|---|
| 23 | |#
|
|---|
| 24 |
|
|---|
| 25 | (eval-when (:compile-toplevel :load-toplevel :execute)
|
|---|
| 26 | (require :selector-utils))
|
|---|
| 27 |
|
|---|
| 28 | (defpackage :interface-utilities
|
|---|
| 29 | (:nicknames :iu)
|
|---|
| 30 | (:export make-and-install-menu make-and-install-menuitems-after
|
|---|
| 31 | test-menu test2-menu))
|
|---|
| 32 |
|
|---|
| 33 | (in-package :iu)
|
|---|
| 34 |
|
|---|
| 35 | ;; Utility functions that allow lisp programs to add menus to the existing menubar
|
|---|
| 36 |
|
|---|
| 37 | #|
|
|---|
| 38 | (defun make-menu-item (title-str action-str &key (key-equiv ""))
|
|---|
| 39 | (let* ((ns-title (ccl::%make-nsstring name-str))
|
|---|
| 40 | (action-selector (get-selector action-str))
|
|---|
| 41 | (ns-key (ccl::%make-nsstring key-equiv))
|
|---|
| 42 | (mi (#/initWithTitle:action:keyEquivalent:
|
|---|
| 43 | (#/alloc ns:ns-menu-item)
|
|---|
| 44 | ns-title
|
|---|
| 45 | action-selector
|
|---|
| 46 | ns-key)))
|
|---|
| 47 | (#/autorelease ns-title)
|
|---|
| 48 | (#/autorelease ns-key)
|
|---|
| 49 | (#/autorelease mi)
|
|---|
| 50 | mi))
|
|---|
| 51 |
|
|---|
| 52 | |#
|
|---|
| 53 |
|
|---|
| 54 | ;; For the following function menu-item-specs should be a list where each
|
|---|
| 55 | ;; element of the list is itself a list of the form:
|
|---|
| 56 | ;; (menu-item-name menu-item-action menu-item-key-equivalent menu-item-target)
|
|---|
| 57 | ;; where each of these except the menu-item-target must be acceptable as an
|
|---|
| 58 | ;; argument to the function "string". Menu-item-target must be an Ojbective-C object,
|
|---|
| 59 | ;; but can be nil to signify no target (the default)
|
|---|
| 60 | ;; Used "menumadness" sample code from Apple Developer website to know what to do ...
|
|---|
| 61 | ;; NSMenu *newMenu;
|
|---|
| 62 | ;; NSMenuItem *newItem;
|
|---|
| 63 | ;;
|
|---|
| 64 | ;; // Add the submenu
|
|---|
| 65 | ;; newItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:@"Flashy" action:NULL keyEquivalent:@""];
|
|---|
| 66 | ;; newMenu = [[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:@"Flashy"];
|
|---|
| 67 | ;; [newItem setSubmenu:newMenu];
|
|---|
| 68 | ;; [newMenu release];
|
|---|
| 69 | ;; [[NSApp mainMenu] addItem:newItem];
|
|---|
| 70 | ;; [newItem release];
|
|---|
| 71 | ;; Basically you need to create both a menuitem and a menu for any menu displayed in the menubar
|
|---|
| 72 | ;; and link them together. Then add the menuitem to the main menu (i.e. menubar)
|
|---|
| 73 |
|
|---|
| 74 | (defun make-and-install-menu (menu-name &rest menu-item-specs)
|
|---|
| 75 | (let* ((ns-menu-name (ccl::%make-nsstring menu-name))
|
|---|
| 76 | (menuitem (#/initWithTitle:action:keyEquivalent:
|
|---|
| 77 | (#/allocWithZone: ns:ns-menu-item
|
|---|
| 78 | (#/menuZone ns:ns-menu))
|
|---|
| 79 | ns-menu-name
|
|---|
| 80 | (%null-ptr)
|
|---|
| 81 | #@""))
|
|---|
| 82 | (menu (#/initWithTitle: (#/allocWithZone:
|
|---|
| 83 | ns:ns-menu (#/menuZone ns:ns-menu))
|
|---|
| 84 | ns-menu-name))
|
|---|
| 85 | (main-menu (#/mainMenu #&NSApp)))
|
|---|
| 86 | (dolist (mi menu-item-specs)
|
|---|
| 87 | (destructuring-bind (mi-title mi-selector &optional (mi-key "") mi-target) mi
|
|---|
| 88 | (let* ((ns-title (ccl::%make-nsstring (string mi-title)))
|
|---|
| 89 | (action-selector (get-selector (string mi-selector)))
|
|---|
| 90 | (ns-key (ccl::%make-nsstring (string mi-key)))
|
|---|
| 91 | (men-item (#/addItemWithTitle:action:keyEquivalent: menu
|
|---|
| 92 | ns-title
|
|---|
| 93 | action-selector
|
|---|
| 94 | ns-key)))
|
|---|
| 95 | (when mi-target
|
|---|
| 96 | (#/setTarget: men-item mi-target))
|
|---|
| 97 | (#/release ns-title)
|
|---|
| 98 | (#/release ns-key))))
|
|---|
| 99 | ;; Link up the new menuitem and new menu
|
|---|
| 100 | (#/setSubmenu: menuitem menu)
|
|---|
| 101 | (#/release menu)
|
|---|
| 102 | ;; Now tell the main menu to make this a sub-menu
|
|---|
| 103 | (#/addItem: main-menu menuitem)
|
|---|
| 104 | (#/release ns-menu-name)
|
|---|
| 105 | (#/release menuitem)
|
|---|
| 106 | menu))
|
|---|
| 107 |
|
|---|
| 108 | ;; The following function inserts one or more new menu-items immediately
|
|---|
| 109 | ;; following a specified menu-item.
|
|---|
| 110 | ;; If the menu-item-name is "" the insertion will be after the first divider
|
|---|
| 111 | ;; (which has a blank name). If the menu-item-name does not exist in the menu,
|
|---|
| 112 | ;; the items will be placed at the beginning of the menu.
|
|---|
| 113 | ;; menu-item-specs are as defined above for the make-and-install-menu function.
|
|---|
| 114 | ;; menu-name and menu-item-name arguments must be acceptable as argument to the
|
|---|
| 115 | ;; "string" function.
|
|---|
| 116 | (defun make-and-install-menuitems-after (menu-name menu-item-name &rest menu-item-specs)
|
|---|
| 117 | (let* ((ns-menu-name (ccl::%make-nsstring menu-name))
|
|---|
| 118 | (main-menu (#/mainMenu #&NSApp))
|
|---|
| 119 | (menuitem (or (#/itemWithTitle: main-menu ns-menu-name)
|
|---|
| 120 | (error "~s is not a valid menu title" menu-name)))
|
|---|
| 121 | (sub-menu (#/submenu menuitem))
|
|---|
| 122 | (ns-menu-item-name (ccl::%make-nsstring menu-item-name))
|
|---|
| 123 | (insert-index (#/indexOfItemWithTitle: sub-menu ns-menu-item-name)))
|
|---|
| 124 | (dolist (mi menu-item-specs)
|
|---|
| 125 | (destructuring-bind (mi-title mi-selector &optional (mi-key "") mi-target) mi
|
|---|
| 126 | (let* ((ns-title (ccl::%make-nsstring (string mi-title)))
|
|---|
| 127 | (action-selector (get-selector (string mi-selector)))
|
|---|
| 128 | (ns-key (ccl::%make-nsstring (string mi-key)))
|
|---|
| 129 | (men-item (#/insertItemWithTitle:action:keyEquivalent:atIndex:
|
|---|
| 130 | sub-menu
|
|---|
| 131 | ns-title
|
|---|
| 132 | action-selector
|
|---|
| 133 | ns-key
|
|---|
| 134 | (incf insert-index))))
|
|---|
| 135 | (when mi-target
|
|---|
| 136 | (#/setTarget: men-item mi-target))
|
|---|
| 137 | (#/release ns-title)
|
|---|
| 138 | (#/release ns-key))))
|
|---|
| 139 | (#/release ns-menu-item-name)
|
|---|
| 140 | (#/release ns-menu-name)))
|
|---|
| 141 |
|
|---|
| 142 | (defun menu-item-action-selector (menu-name menu-item-name)
|
|---|
| 143 | (let* ((ns-menu-name (ccl::%make-nsstring menu-name))
|
|---|
| 144 | (main-menu (#/mainMenu #&NSApp))
|
|---|
| 145 | (menuitem (or (#/itemWithTitle: main-menu ns-menu-name)
|
|---|
| 146 | (error "~s is not a valid menu title" menu-name)))
|
|---|
| 147 | (sub-menu (#/submenu menuitem))
|
|---|
| 148 | (ns-menu-item-name (ccl::%make-nsstring menu-item-name))
|
|---|
| 149 | (target-mi (#/itemWithTitle: sub-menu ns-menu-item-name)))
|
|---|
| 150 | (#/release ns-menu-item-name)
|
|---|
| 151 | (#/release ns-menu-name)
|
|---|
| 152 | (#/action target-mi)))
|
|---|
| 153 |
|
|---|
| 154 |
|
|---|
| 155 | (defun test-menu ()
|
|---|
| 156 | (make-and-install-menu "New App Menu"
|
|---|
| 157 | '("Menu Item1" "doFirstThing")
|
|---|
| 158 | '("Menu Item2" "doSecondThing")))
|
|---|
| 159 |
|
|---|
| 160 | (defun test2-menu ()
|
|---|
| 161 | (make-and-install-menuitems-after "File" "New"
|
|---|
| 162 | '("New myDoc" "newMyDoc")))
|
|---|
| 163 |
|
|---|
| 164 |
|
|---|
| 165 | (provide :menu-utils)
|
|---|