Last updated at 2:04 am UTC on 25 August 2021
In the Japanese language, "Ma" refers to "the space between". This is where Maui focuses, to provide a medium for observing and sending messages to objects.
Maui is a user-interface framework built on three primary widgets; Object, Message, and Input. Inspired by Morphic Wrappers, Maui can generate an operable user-interface for any object based on a subset of its message selectors. This is customizable, of course. When the Message widgets of the object are clicked, a Maui object representing the result of the message is produced which can, itself, be dragged as an input to yet another keyword message, which would then produce its own result as a properly-configured Object widget.
Maui can be loaded from the SqueakMap Catalog available from the App menu of the world's Docking Bar.
A good description of Maui, with lots of screen-shots.
Terrible video. Spur of the moment. No planning. One take. No editing.
What follows below here are the older, terse documentation.
Three kinds of widgets
The Object Widget
The object widget is merely a rectangle that represents a single object. It contains message widgets which themselves contain parameter-holder widgets.
For any object, there are several default views available: "default", "iconic" and "small".
Any object widget is customizable via pointing-and-clicking. Standard things provided by the underlying UI framework (Morphic) such as color, layout, size, etc. are available but, equally importantly, which messages
does the user drop into it and what are each of their configurations (discussed shortly).
Once the power-user has a configuration they like, it may be remembered
by a particular name. Then, all kinds of this object (including subclasses) can assume this view. The view of any on-screen object may be changed at any time.
The Message Widget
The message widget is pretty much just another object widget for a MessageSend. Also, it is allowed to contain the object widget as the result of its invocation. It's most powerful feature is customizability of its "InvocationStrategy". This lets the designer specify when they want the message invoked (on-clicked, repeating, one-time immediate, or on-mouse-over), where the result should pop out ('self' embedded in the message, 'hand', 'world', 'balloon' or 'none') and, finally, which view they want the result to take, either one of the three default views or any previous one they've previously defined saved.
In my brief experiments, these few combinations provide surprisingly good usability as naked-objects interfaces go. For example, by specifying "self" (embedded) as the resultHolderTarget, you can end up with a UI that appears to be for more than one object.
The Parameter-Holder widget
Obviously, this is used to invoke messages that require parameters. It is currently represented by a small black "hole" next to each keyword in the message in which the user may drop any other naked object widget. The message is invoked when all of its parameters are populated, and will do so according to the selected invocation-strategy. Strings and Numbers are also representable as object widgets but, most of the time, simple text / number entry is easier to do by merely typing, so the parameter holders may also be typed directly into, if desired (and this uses the auto-expanding text widget I alluded to yesterday).
User-interfaces built in Maui are a composition of Morphs. The outermost Morph of the composition is a MauiMorph. Inside this you can drop regular (non-Maui) Morphs, messages from system browsers or another MauiMorph for the same identical object, allowing for table-layout in both horizontal and vertical directions.
Any object may have multiple representations on the screen simultaneously. When hovering over any object, all occurrences of that instance on the screen are highlighted. If the Connectors framework is loaded, lines will be drawn to all identical objects on the screen.
Object widgets may actually contain not just other message widgets but another object widget for the same object only. Why? For more-advanced layout. When you create two views of an object and embed one into the other, it becomes a "pane" that can have its own layout (horizontal, vertical, etc.).
In Smalltalk everything is an object including messages and parameter-holders. This is indicated visually in two ways. First, the border of the object under the hand (mouse pointer) is highlighted, along with the border of any other views of that identical object. Second, if Connectors is installed, lines will be drawn to all other views of that identical object on the screen.
If you drop a binary or keyword message onto a MauiMorph, it will show a black-hole where, to invoke the message, you must drop another MauiMorph. Once all parameters have MauiMorphs dropped in them, the message invokes and offers the result as another MauiMorph.
The invocation of messages can be customized in several ways by using the "Tools" context menu.
The context menu
The context menu appears by clicking the yellow button (right mouse button in Windows). The menu presents options for whatever was highlighted, either an object, a message or a parameter-holder.
By holding Shift when you activate the menu, you can jump to the "Tools" menu, which is the menu used for user-interface refinement.
Remembering customized views
Maui is a prototype-based system. Once you've dragged some messages, changed some colors, layout, preferences, or anything else, you can ask Maui to remember a prototype of your work by invoking "manage views..." from the "tools" context menu. A Maui "dialog" appears where you give the prototype a name and specify the level of inheritance.
You can then recall this named view from the objects or any similar objects context menu.
Maui offers extensive keyboard support. Unlike many systems, it is not necessary to hold down the Command modifier key. Also, the object which is highlighted is the one that receives keyboard events. To highlight an object, simply point the mouse on it. For example, to remove an object from the screen, simply point the mouse on it and press "x".
Keyboard help is provided in the context menus, the letter of the key is in parenthesis.
Multiple Simultaneous Views
Early in the design of Maui, I wanted to have only one view of any particular object on
the screen so that the identity concept would be reinforced to the user. But that created problems for dropping them into parameter-holders. I found myself building a fourth kind of widget which, at the time, I called a "token" which was a compact view the user could use to drop into parameters. It turned out to be a bad idea. Multiple views solves the problem so much more cleanly. The "small" or "iconic" view is perfect for dropping into parameter-holders, and Connectors provided a fantastic solution to the identity conundrum. Identical views of the same object are connected with a line when you hover over them.
I've already mentioned that Maui widgets may be created by dragging messages directly out of browsers onto the desktop. Widgets may be also created programmatically for any object by sending #maui to it:
You should see a little box appear on the hand. Drop it anywhere. Hover the mouse pointer over it and press 'b' on the keyboard. No Alt, just b (this function is also buried in its context menu).
A hierarchy browser on Association pops up. Drag the value message out of the browser onto the object. Notice the object and the message widgets highlight individually; they each have their own context menus (for users) and Shifted context menus (for power-users and developers). Now click it and it should say 'world'.
To see the dialog that adjusts its invocation-strategy, Shift+Right
click the message and select "edit invoke strategy...". Here you can see the dialog for adjusting other Maui views is, itself, a Maui view for the UI object.
Now back to the #value message. Shift+Right click the message and select "be a getter/setter". This builds the message in a way that would otherwise require quite a bit of clicking to do manually; so its a useful shortcut, and the 90% case for simple getter/setter attributes in your domain model. Now you should see the setter message (value:) and 'world'. The getter (value) is actually embedded and hidden in the setter message and its result target is actually the parameter holder!
To change the value from 'world' you may either type directly in there (a Smalltalk expression please) or drag a new object in there (myObject maui) and it will update. To see the changes in an inspector simultaneously, just press "i" while hovering over the object.
Balloons as result targets
One innovative feature of Maui is the ability to specify a dynamic balloon as the result of invocation. Maui uses this in its own UI's for the progress message. In this way, the progress of a background process doesn't take up real-estate all the time, but is quickly and easily available by simply hovering over it.
To see it, Shift+right click on the object widget (so you have to click outside the message morph) then "messages" | "domain" | "find message...".
A special code-built UI pops up.. Notice the two indented "panes". Hover over the #progress message to see the UI in the balloon.
A rudimentary file-manager in five minutes
Let's build the beginnings of a rudimentary "File Manager" in under five minutes. Open up FileDirectory and drag its class-side #default message onto the desktop. Then click on it. The little square that apperas the instance of FileDirectory.
Now drag the instance-side #entries message onto this (before dropping, make sure it shows the green outline rectangle of where it will drop). Click on this message; a collection of entries appears in their "iconic" form. Change any ONE of them to the "Small" view ("beSmall" on the context menu) so that we may drag some messages into it.
While still hovered over the one you just made small, press "b" to browse its hierarchy. DirectoryEntry pops up. Drag #name and #fileSize to the one you made small. Now Shift+click for its tool menu and select "as list entry". Finally, right-click on the actual Collection object, carefully getting outside that black border (its ScrollPane or something) but still on the Collection and select "elements view | list entry". Its is tricky to click in the right place, but the results are worth it.
You can now remember this view by Shift+right click and select "manage
views...". A dialog pops up letting you name this view.
Obviously, with this sort of an interface, your domain must have proper validation; even type validation since they can drag any object into the parameter holders. In a preliminary "checkbook manager application" which I have started building with this, when an error message is signaled, it is able to contain actual embedded object widgets as "words" in the message. For example:
(The words in brackets are simply squares, Maui "object" widgets.. update this to show a screenshot instead..)
[aMoneyTransaction] cannot be added to [anAccount] because they do not
share the same AccountsBook.
When the user hovers over the [aMoneyTransaction] object widget, a line is drawn to elsewhere on the screen so that they may see which object that word refers to.
MauiPage - mini text processor