Today we expands on our work from the last posting, adding some hot keys, an icon, and showing how to do toggle menu items and grouped menu items.
Design
File Menu: For the Browse menu item, we'll add the smalltalk balloon icon and add a hot key; Shift-Ctrl-B. For the Inspect menu item, we'll add the standard VisualWorks inspect hot hey: Ctrl-Q. For the Close menu item, we'll add the Alt-F4 hot key.
System Menu: We'll make the Toggle Me menu item a toggle
Other Menu: We'll make the Red, Green and Blue menu items act like radio buttons, making it so only one is toggled when the others are not.
File Menu
Here is where we left the File Menu:
To add hot keys, we create a Keystroke, configured with the information about the key combination we want to use, and then add it to the menu item:
hookupMainMenu
| menuBarMenu |
menuBarMenu := self menuBar menu.
(menuBarMenu someMenuItemWithID: #Close)
actionID: #closeMe;
keystroke: (Keystroke alt: #F4).
self addAction: (Action
id: #closeMe
action: [self close]).
(menuBarMenu someMenuItemWithID: #Inspect)
actionID: #inspect;
keystroke: (Keystroke ctrl: $Q).
self addAction: (Action
id: #inspect
action: [self inspect]).
(menuBarMenu someMenuItemWithID: #Browse)
actionID: #browse;
keystroke: (Keystroke key: $b modifiedBy: #(#shift #control)).
self addAction: (Action
id: #browse
action: [self browse])
The resulting menu when opened looks like this:
Pressing the hot keys specified and displayed in the menu automatically do the action associated with them. There is one small interesting side note to make here; while we have added the Alt-F4 as a hot key, windows in Widgetry already know that Alt-F4 is the hot key to close them, and adding it here simply adds the visible hot key text to our menu item. Even without that hot key on the menu, Alt-F4 always closes the window.
The Keystroke class has a bunch of nice protocol for adding simple keystrokes: alt: and #ctrl: and #shift:. For more complex keystrokes, we use the #key:modifiedBy: method, which takes a collection of modifier ids. Valid modifier ids are: #shift, #control, #alt, #meta and #command. Currently, #command isn't hooked up to anything, but is there for the future when we support the Command key on a Mac.
Now let's add our balloon icon to the Browse menu item:
hookupMainMenu
| menuBarMenu |
menuBarMenu := self menuBar menu.
(menuBarMenu someMenuItemWithID: #Close)
actionID: #closeMe;
keystroke: (Keystroke alt: #F4).
self addAction: (Action
id: #closeMe
action: [self close]).
(menuBarMenu someMenuItemWithID: #Inspect)
actionID: #inspect;
keystroke: (Keystroke ctrl: $Q).
self addAction: (Action
id: #inspect
action: [self inspect]).
(menuBarMenu someMenuItemWithID: #Browse)
actionID: #browse;
keystroke: (Keystroke key: $b modifiedBy: #(#shift #control));
image: (ToolbarIconLibrary visualFor: #systemBrowser).
self addAction: (Action
id: #browse
action: [self browse])
Now our menu looks like this:
System Menu
To specify that a menu item is a toggle, we use the #indication: method. The method can take either a Boolean outright, or it can take an ObservedValue on a Boolean. Here, we'll use an ObservedValue:
hookupMainMenu
| menuBarMenu toggle |
menuBarMenu := self menuBar menu.
(menuBarMenu someMenuItemWithID: #Close)
actionID: #closeMe;
keystroke: (Keystroke alt: #F4).
self addAction: (Action
id: #closeMe
action: [self close]).
(menuBarMenu someMenuItemWithID: #Inspect)
actionID: #inspect;
keystroke: (Keystroke ctrl: $Q).
self addAction: (Action
id: #inspect
action: [self inspect]).
(menuBarMenu someMenuItemWithID: #Browse)
actionID: #browse;
keystroke: (Keystroke key: $b modifiedBy: #(#shift #control));
image: (ToolbarIconLibrary visualFor: #systemBrowser).
self addAction: (Action
id: #browse
action: [self browse]).
toggle := false asObservedValue.
(menuBarMenu someMenuItemWithID: #ToggleMe)
indication: toggle.
This alone doesn't actually do anything. So, we'll add an action, and tell it to change the value of the toggle when menu item is clicked on:
hookupMainMenu
| menuBarMenu toggle |
menuBarMenu := self menuBar menu.
(menuBarMenu someMenuItemWithID: #Close)
actionID: #closeMe;
keystroke: (Keystroke alt: #F4).
self addAction: (Action
id: #closeMe
action: [self close]).
(menuBarMenu someMenuItemWithID: #Inspect)
actionID: #inspect;
keystroke: (Keystroke ctrl: $Q).
self addAction: (Action
id: #inspect
action: [self inspect]).
(menuBarMenu someMenuItemWithID: #Browse)
actionID: #browse;
keystroke: (Keystroke key: $b modifiedBy: #(#shift #control));
image: (ToolbarIconLibrary visualFor: #systemBrowser).
self addAction: (Action
id: #browse
action: [self browse]).
toggle := false asObservedValue.
(menuBarMenu someMenuItemWithID: #ToggleMe)
indication: toggle;
actionID: #toggleMe.
self addAction: (Action
id: #toggleMe
action: [toggle value: toggle value not]).
Now, when we click on that menu item, it will toggle a selection indicator. When you use this feature in your own system, you'll want to watch for the value changing in your toggle, and then perform some additional action according to if it is on or off. For us, just making it display is enough:
Other Menu
For our Other menu, we want to have the three color named menu items to be mutually exclusively selected. To do this, we also use the #indication: method.
Unlike for toggling, we use a Symbol in our ObservedValue. Then, just like we do with RadioButtons, we share that observed value between all three menu items in the group. When the value of that ObservedValue matches the ID of the MenuItem, that is when the target menu item will have the selection indicator. For our example, we'll start off with Red as the initially selected item:
hookupMainMenu
| menuBarMenu toggle indication |
menuBarMenu := self menuBar menu.
(menuBarMenu someMenuItemWithID: #Close)
actionID: #closeMe;
keystroke: (Keystroke alt: #F4).
self addAction: (Action
id: #closeMe
action: [self close]).
(menuBarMenu someMenuItemWithID: #Inspect)
actionID: #inspect;
keystroke: (Keystroke ctrl: $Q).
self addAction: (Action
id: #inspect
action: [self inspect]).
(menuBarMenu someMenuItemWithID: #Browse)
actionID: #browse;
keystroke: (Keystroke key: $b modifiedBy: #(#shift #control));
image: (ToolbarIconLibrary visualFor: #systemBrowser).
self addAction: (Action
id: #browse
action: [self browse]).
toggle := false asObservedValue.
(menuBarMenu someMenuItemWithID: #ToggleMe)
indication: toggle;
actionID: #toggleMe.
self addAction: (Action
id: #toggleMe
action: [toggle value: toggle value not]).
indication := #Red asObservedValue.
(menuBarMenu someMenuItemWithID: #Red)
indication: indication;
actionID: #makeRed.
self addAction: (Action
id: #makeRed
action: [indication value: #Red]).
(menuBarMenu someMenuItemWithID: #Green)
indication: indication;
actionID: #makeGreen.
self addAction: (Action
id: #makeGreen
action: [indication value: #Green]).
(menuBarMenu someMenuItemWithID: #Blue)
indication: indication;
actionID: #makeBlue.
self addAction: (Action
id: #makeBlue
action: [indication value: #Blue]).
Here is how it looks after each in turn is clicked on:
Again, as with our toggle example, you'll want to watch for the change, and actually do something when the value changes. But for this example, the sole purpose of this is so I can say:
Isn't that pretty?
And So It GoesSames