(in-package :ccl) (require 'cocoa) (defun make-menu-item (item) (make-objc-instance 'ns-menu-item :with-title (nth 0 item) :action (nth 1 item) :key-equivalent (if (> (length item) 3) (nth 3 item) #@""))) (defun make-menu (items) (let ((menu (make-objc-instance 'ns-menu))) (loop for item in items do (let ((menu-item (make-menu-item item))) (send menu :add-item menu-item) (send menu-item :set-target (nth 2 item)))) menu)) (defun add-menu (parent menu title) (let ((item (send parent :item-with-title title))) (send parent :set-submenu menu :for-item item) (send parent :item-changed item))) (defun add-application-menu (menu title) (let ((parent (send *NSApp* 'main-menu))) (send parent :add-item-with-title title :action (%null-ptr) :key-equivalent #@"") (add-menu parent menu title))) ; Note this doesn't quite work yet... (defun insert-item-at-index (menu-name item index) (let* ((main-menu (send *NSApp* 'main-menu)) (main-item (send main-menu :item-with-title menu-name)) (menu (send main-item 'submenu))) (send item :set-enabled T) (send menu :insert-item item :at-index index))) #| Sample Code... |# (def-objc-class menu-handler ns-object ()) (define-objc-method ((:void first) menu-handler) (#_NSRunInformationalAlertPanel #@"Selection" #@"First item selected" #@"Ok" (%null-ptr) (%null-ptr))) (define-objc-method ((:void second) menu-handler) (#_NSRunInformationalAlertPanel #@"Selection" #@"Second item selected" #@"Ok" (%null-ptr) (%null-ptr))) (define-objc-method ((:void third) menu-handler) (#_NSRunInformationalAlertPanel #@"Selection" #@"Third item selected" #@"Ok" (%null-ptr) (%null-ptr))) (define-objc-method ((:void load) menu-handler) (print "tbd")) (setf *handler* (make-objc-instance 'menu-handler)) (add-application-menu (make-menu (list (list #@"Test Item" (@selector "first") *handler*) (list #@"Second Item" (@selector "second") *handler*) (list #@"Third Item" (@selector "third") *handler*))) #@"Test") (insert-item-at-index #@"File" (make-menu-item (list #@"Load" (@selector "load") *handler*)) 5)