A new function in Common Graphics in Allegro CL 8.1, pop-up-menus-for-many-sorted-choices, supports displaying a cascade of menus allowing a user to choose efficiently among many possibilities without being overwhelmed by too many choices presented at any instant. The only requirement is that the choices be in alphabetical order (numbers are allowed along with alphabetic characters, but they must be ordered as if by string-less-than).
This function is available in Allegro CL 8.1.
Here is a complete example that uses an owner window so that keyboard shortcuts will work (see the documentation -- in short if an owner window is not used, you cannot easily dismiss the menu). The user's most recent choice is displayed in the window. Methods are defined on a window subclass so that the initial menu may be shown either by right-clicking the window or by pressing the spacebar when the window is selected. The mouse or keyboard may then be used to select choices.
The short list of choices is (:apple :blueberry :cherry :chocolate :cranberry). Admittedly this is a short list, but we want to demonstrate the function as simply as possible. The point is that it also works on very long lists.
There is only one choice that begins with "a", so "apple" appears on the initial menu and may be chosen immediately. Likewise with "blueberry" for "b". But there are multiple choices beginning with "c", and so the third menu item will show "c ...", and choosing that item will show a second menu of all choices that being with "c". If "c" is chosen, then the second menu will show "ch ..." for the two remaining choices that begin with "ch", followed by "cranberry" since it is the only remaining choice that begins with "cr".
When using the keyboard to select choices most quickly, :apple could be selected by pressing the spacebar to show the first menu, and then pressing the "a" key. :cranberry can be selected by typing space, c, r, while :chocolate requires space, c, h, o.
Here is the code:
(defclass menu-test-window (frame-window) ((current-food :accessor current-food :initform nil))) (defun select-a-food (window cursor-position) (let* ((choice (pop-up-menus-for-many-sorted-choices '(:apple :blueberry :cherry :chocolate :cranberry) :stream window :position cursor-position))) (when choice (setf (current-food window) choice) (invalidate window)))) (defmethod redisplay-window ((window menu-test-window) &optional box) (declare (ignore box)) (clear-page window) (let* ((food (current-food window))) (when food (with-font (window (make-font-ex nil "Arial" 24 '(:bold))) (draw-string-in-box window (princ-to-string food) nil nil (visible-box window) :center :center))))) (defmethod mouse-right-down ((window menu-test-window) mouse-buttons cursor-position ) (declare (ignore mouse-buttons)) (select-a-food window cursor-position)) (defmethod virtual-key-down ((window menu-test-window) mouse-buttons key-code) (declare (ignore mouse-buttons)) (case key-code (#.vk-space (select-a-food window #.(make-position 0 0))) (t (call-next-method)))) (make-window :menu-sequence-test :class 'menu-test-window :title "Right-Click or Space" :exterior (make-box-relative 200 200 300 200))
When we run it, a window with title "Right-Click or Space" is displayed (from the make-window form at the bottom of the code):
We right click in the window and this menu appears:
If we chose apple or blueberry, they would be returned, but we choose c... and this menu appears:
If we chose cranberry, it would be returned, but we choose ch... and this menu appears:
Now we are down to cherry and chocolate and whichever we choose is returned. We choose chocolate, and it is displayed in the window, as called for in the code:
The same kind of cascade of menus appears when there are many more choices, but never more than 36 entries (26 letters and 10 numbers).
|Copyright © 2018 Franz Inc., All Rights Reserved | Privacy Statement|