Here, we add the action that we want to be executed when the menu item is chosen. UserInterface instances already understand the #close method, so we don't have to do anything else to get this menu item to work. If you have been following along, you'll note that if you pressed Alt-F4, the close already worked. This is because by default, all windows have Alt-F4 set to close. However, the menu option, when selected by the mouse, up until now, didn't do anything. Now it does what we expect.
Next we'll do the &Open On Selected Class menu item:
Here, we add an action named #openOnClass. We'll add code to be executed when that is selected:
openOnClass
self classTree selectionDo: [:each | self class openWith: each]
If we open our ClassHierarchyBrowser right now, and select a class, and then select that menu item, we'll get a "Does Not Understand" on #openWith:... which is as it should be. We need a couple of things to do this. First, we need to add an #openWith: to the class side of our ClassHierarchyBrowser, and then we need to do some work so that it opens on something other than Object all the time. First, the class openWith: method:
openWith: aClass
(self new setInitialClass: aClass) open.
That code implies we need a #setInitialClass: method on the instance side... But first, let's add an instance variable to our definition to hold this new value, and then the new method, as well as an accessor method for the new instance variable:
Now we just need to change how we hookup the user interface to use "self initialClass" instead of Object by default:
createInterface
...
pane id: #ClassTree.
self addComponent: pane.
pane tree: (Pollock.Tree
on: self initialClass
childrenBlock: [:each | each subclasses]
hasChildrenBlock: [:each | each subclasses notEmpty]).
pane expandRootFully.
There we go. If we open our ClassHierarchyBrowser, and select a class, it opens a new browser on the selected class. If nothing is selected, then nothing happens. However, to me, that isn't very satisfying. I would prefer if the menu item was disabled when there are no classes selected. We'll do that by adding another UserInterface framework method which in this case is called after the #getMainMenu method is called... which is named #hookupMainMenu:
Now the menu item is only enabled when an item is selected in the Class tree pane. You notice that we give it a block for the enabled value. All dynamic menu item values, such as enablement and hidden-ness, can use either a Block, an ObservedValue or a Symbol as the value you give them to act on. If it is a Block or an ObservedValue, it gets the value by sending evaluate to the value. If it is a Symbol, then it asks the UserInterface to perform the method by that name, and then uses the result answered by that execution.
So far, we've done the E-Z menu items. Now for the tougher ones. We'll start with the Look Changing menu items. We'll start with giving the same action to each of these menu items, and that action will be #changeLookTo::
That's pretty straight forward. Notice, unlike our "Exit" menu item, here we're giving a keyword selector. When a menu item comes across an action that takes one argument, it sends itself along as the argument. That leads us to our #changeLookTo: method:
A little behind the scenes look here, as we see how simple it is in Pollock to change a look. Simply take a look and send #installLookPreferences to it. The other part is that the Screen default has a method that answers the current Widget policy. Now, it would have been cooler if we had added our own #changeToKey: method to UILookPolicy, and had it do the work for us. I'll leave that as an exercise for the reader if they wish.
This all works fine, mechanically speaking... but our goal was to have an indicator next to the menu items so that it will show us which look is active. To do this, we give each menu item that acts as a mutual exclusive indicator a shared value, which will be an ObservedValue, that has as its underlying value a Symbol. We'll name this value lookObservedValue, and add it as an instance variable:
Here's how a mutual exclusive (or group indication) menu item knows if it is the "on" value. The value of the observed value that it shares with other items will tell an item that is the "on" value if that value is equal to its nameKey. Let's start off with an accessing method for our key value:
currentLookKey
Screen default defaultWidgetPolicy class == Win98WidgetPolicy ifTrue: [^#microsoftLook].
Screen default defaultWidgetPolicy class == MotifWidgetPolicy ifTrue: [^#motifLook].
Screen default defaultWidgetPolicy class == Pollock.MacOSXWidgetPolicy ifTrue: [^#macLook].
^#none
Then we'll add an #initialize method to our ClassHierarchyBrowser to set up our new #lookObservedValue:
initialize
super initialize.
lookObservedValue := self currentLookKey asObservedValue.
Don't be a goof like I was and forget the "super initialize" method the first time I wrote this. Bad things can happen when you forget to call super on initialize, and in Pollock, it will happen if you forget.
Back to the menu. All we need to do now is tell all of our look changing menu items that they share this new value we have set up... we'll extend the #hookupMainMenu method to do this:
hookupMainMenu
(self menuBar menu atNameKey: #openOnClass) enabled: [self classTree selections notEmpty].
(self menuBar menu atNameKey: #microsoftLook) indication: lookObservedValue.
(self menuBar menu atNameKey: #motifLook) indication: lookObservedValue.
(self menuBar menu atNameKey: #macLook) indication: lookObservedValue.
Now, depending on which look you're using, when you change looks, then reopen the menu, the appropriate item has an Dot (Windows), Box (Motif) or a Check mark (MacOSX).
Finally, we want to have the "Console Text" menu item to toggle between "Normal" text, and "White On Black" text. Like the grouped items, we also set the indication for the menu item, however, instead of having a symbol, toggle menu items want a boolean value to say if they are on or off. We'll create another instance variable to hold on to that for us, and we'll name it textColorValue:
Done! Our ClassHierarchyBrowser now as a nice, if simple, menu bar. We've demonstrated how to set up a menu so that it dynamically changes an item's enablement, as well as group and toggle indications. Lots of behavior, not much code.
The above is published as version 1.20 in the Package named "PollockBlog" on the Cincom public repository.
Next time, we'll add our the openOnClass behavior to the Class tree's popup menu as a way of demonstrating how popup menus work.