3.1 aws_balloon
The aws_balloon is composed of a toplevel widget, with in it a
small label with text. One such toplevel is created per aws_balloon,
not for each bound widget, the label is adjusted for each widget when it
pops up.
The toplevel is immediately created together with the label and withdrawn from the screen, so it's 'there' al the time, because it's properties must be continuously available through the subLabel() and subFrame() methods.
Binding a widget to an aws_balloon simply means that the aws_balloon captures the widgets <Any-Enter> and <Any-Leave> events. If the mouse enters the widget, aws_balloons operator()() is called with the configured balloon message and status message. The status message is immediately displayed, and a timer is set for the balloonmessage (it's annoying if the balloon appears immediately). The Id of this timer is stored so it can be canceled if the mouse leaves the widget before the timer expires.
3.2 aws_combobox
The aws_combobox is composed of a frame containing an entry
and a button. A separate toplevel with listbox is, as with
the aws_balloon, created and immediately withdrawn from the screen.
The aws_combobox tries to handle the events (<Key-Return> in the entry and <1> in the listbox itself, simulating the standard combobox behaviour. However, if a handler is bound to the combobox, both events are passed to the handler (the ListSelected and the EntrySelected are sent to the handler, and the handler will have to simulate this behaviour itself (this may change in the future - A ListSelected event will be handled internally and result in a EntrySelected event).
Implementing this behaviour however, is trivial:
if(cbEvent == "EntrySelected")
{
string selection = cb->get();
// Add entry to listbox.
cb->insert(0, selection);
cout << "You selected " << selection << endl;
}
else if(cbEvent == "ListSelected")
// Insert in entry, move selection to top
{
string selection = cb->selection();
// Clear entry, insert selection
cb->del();
cb->insert(selection);
// Remove from listbox, move to top
cb->del(cb->curselection());
cb->insert(0, selection);
cout << "You selected " << selection << endl;
}
Handling both events may seem redundant but it allows more flexibility for the programmer. For example, the handler can check the text typed in the entry before inserting it in the listbox.
If the toplevel with the listbox is popped-up, the widget will do a global grab on the focus. This is tricy, becase another widget (i.e. an aws_dialog) might be holding the grab. This means that this grabinfo has to be stored first, and restored after a choice has been made.
3.3 aws_dialog
The aws_dialog is composed of:
The implementation of these components is fairly straight-forward - they're laid out in a standard dialog box manner. More interesting is the frame returned by the subWidgetFrame() method, which returns a frame in which the programmer can build his own widgets, makeing it possible to create dialogs containing checkboxes, entries, etc.
The programmer can add any number of buttons using the addButton() method. If no handler is specified, the button will be handled internally and the specified const char *arg will be returned by the getChoice() method (very usefull for OK and CANCEL buttons), else the handler will have to handle the button (usefull for adding a HELP button, or a button to update the widgetFrame contents.
The aws_dialog will do a global grab on the mousecursor when it pops up. Again, the previous grabstate will have to be stored and restored, as this dialog might, for example, be a help popup in another dialog window!
3.4 Problems
Most of the problems encountered when implementing these widgets occured
when trying to access Tk internals (and more standard funcitonality)
to which Hush did not provide access.
Fortunately, Hush provides a rather ugly but effective access to the Tk toolkits interpreter using
int kit::eval(char *cmd);
char *kit::evaluate(char *cmd);
(See [2] The Hush Kit Manualpage))
When implementing these AWS Widgets, I notices quite alot of missing funcitonality, which was sometimes almost trivial to implement.
For example, Hush provides hardly any access to the Tk wm command. The wm command (See [4]) usually works on toplevel windows, so it can be implemented perfectly as part of the toplevel widget.
For example, the aws_balloon uses a toplevel as windowtip. The windowtip is 'withdrawn' from the screen when it has to disappear (wm withdraw), and when it's created, it's made transient (wm transient, which weirdly enough *is* implemented), should be ignored by the windowmanager (wm overrideredirect), and deiconified ('unwithdrawn') when it should popup again (wm deiconify).
All of these command's are missing in Hush except for wm transient, for which toplevel::transient() *does* exist.
Another lacking feature is access to the Tk grab command which can grab the mousepointer locally or globally.
Global grabbing is required by the aws_combobox (to make sure the user chooses from the optionlist when it's pulled down before doing something else, which could seriously messup the widget) (*1)
The dialog also optionally ilocally grabs the cursor so the user clicks one of the 'Ok' or 'Cancel' buttons before doing something else with the application.
Finally, it's often usefull to query all sorts of information about a window using the Tk winfo command. For example, the aws_balloon queries the active widget's size and position to correctly position the windowtip (just below the widget exactly in the middle). Hush does not provide access to this command but it could very well be implemented in the widget baseclass.
See Appendix B. for a complete overview of used but missing commands.
3.5 Bugs
These bugs are currently known in the AWS implementation:
session::statistics()
are displayed, so this
might like a leak, but it isn't.