ambassador at fourthworld.com
Wed Mar 4 03:03:10 EST 2009
> "doMenu", a command, is replaced by sending "menuPick", a message,
> to a button, an object, renamed in this special case a "menu"?
Not necessarily. You can also use "button" to refer to the object. I
believe the "menu" token was added mostly for HC compatibility, along
with a few other things like "menuItem".
There's a subtle difference between "menu" and "button" when addressing
menu buttons so they're not true synonyms, but in practice it seems
"button" is more commonly used.
> Well, OK, it works alright, but why not a simple command, oh, like,
> um, "doMenu"? Instead we have a procedure.
As a general-purpose way of triggering menu items I also prefer
HyperTalk's syntax to Transcript's, but the difference may be reflective
of a very different philosophy of what the menu bar is all about, and
why one would ever have a need to trigger a menu's script armed only
with the item name and no knowledge of the scripts it calls: it becomes
necessary when a menu is hard wired into the engine and has no script at
In HC the engine owned and controlled the menu bar, and allowed you to
modify its contents to some degree but every time you booted HC it
always started out with its own menus, requiring you to tear them down
and rebuild them on the fly with scripts.
And even that only came later. If memory serves, HC 1.0 provided little
if any control over the menu bar other than limiting choices by changing
HC started out by defining its world as one in which the engine provided
the environment and your stacks were more or less documents within that
environment, almost like web pages in a browser.
As it grew, and as SuperCard, Plus, and others came along and pushed the
xTalk envelope in new directions, HC expanded its vision to think of
stacks more like applications, allowing full modification of the menu
bar and eventually even deploying standalone applications.
In contrast, tools like SC and MC/Rev were built from the start as
systems for deploying standalone applications. As such, rather than
providing a set of menus at runtime those engines have none at all,
leaving the menu bar entirely up to the developer.
In a world where stacks are documents and the menu bar is provided by
the engine, it makes sense to provide a way to trigger those commands.
In fact, since HC menus had no scripts of their own, there was really no
other way to do it but to send messages from outside the menu.
But in a world where the developer is responsible for the menu bar and
everything in the menu bar has its own script, the approach used by SC
and MC turns this around: rather than prodding menus from the outside,
SC and MC work from the inside out, letting you call the shots from
within the menu's own scripts.
Whether one way may seem better than another depends on a lot of things,
not the least of which is one's own habits. :)
When I first signed on to the MetaCard list way back in the day I was a
rantfest, screaming up one side and down the other about how "wrong" MC
was in every way it differed from SC.
Over time I've come to appreciate the differences as largely borne of
multi-platform considerations, as may also be at least a contributing
factor with this:
> If the formal syntax for the invoking of menu commands was written
> send "menuPick" && "menuItem" to menu "menuName"
> then it would imply that Rev contains a native menu object, like HC.
> You can only send messages to objects, right?
HC did not have menu objects, at least not anything like its buttons and
fields. HC menus had no scripts of their own, no true properties
(though some clever syntax made menuItems almost feel like objects), and
most of all no persistence: whatever you built in the menu bar during a
session would disappear as soon as you quit, requiring that you rebuild
it again from scratch on startup or openStack, often with rather long
SC is one of the very few xTalks that has true menu and menuItem objects.
Rev goes halfway between the two, implementing menus as buttons. This
gives you the speed of being able to replace an entire menu's contents
in one move as with HC, but also the persistence and discrete script
space SC offers.
The rationale Scott Raney gave me for using the button class is that a
menu is in the generic sense a selector control, and so the differences
between a checkbox and an option menu are conceptually minor; indeed
even HyperCard implemented option controls, a form of popup menu, as
Remember that MC was born on Unix, where menus are part of the window.
While I appreciate why Apple has a detached menu bar and believe it's
measurably more efficient to use, I have to admit it's just not how the
other 90% live.
So in an environment where menus are a part of the window, and inspired
by HC which has option menus as buttons, it's just a short skip to
extend the button class to handle all of the menu types, even pulldowns.
Sure, Mac folks often find this confusing at first. I didn't much care
for it myself when I first started working with MC. But the more time I
spent working on Windows, Linux, Irix and Solaris (ah, the good ol'
days) the more I began to kinda like the flexibility that comes with
using buttons for other types of menus beyond option controls.
All that said, I appreciate that it can be useful to have something like
DoMenu, so below is a replacement handler I wrote for you that may help.
Because we can't have custom handlers overriding built-in commands (a
small price to pay for an order-of-magnitude speed bump by streamlining
the token table), this handler is named "MenuDo", which could also be
capitalized as "menudo" which is regarded in my neighborhood as a cure
for hangovers; maybe it'll help take the edge off of the nausea and
headaches that come with the unlearning process as well. :)
Along with MenuDo is a function named MenuItemsToText, which isn't very
interesting but is needed by MenuDo.
Use MenuDo just like DoMenu:
MenuDo "Open Stack..."
It's kinda tossed together, but should work for most menus.
Put these handlers in your library, and hopefully they'll make a
reasonable substitute for DoMenu as you continue to learn the wu wei of Rev.
Happy scripting -
Revolution training and consulting: http://www.fourthworld.com
Webzine for Rev developers: http://www.revjournal.com
-- Call this instead of "DoMenu", using the label of any
-- menu item as the param in pItem
on MenuDo pItem
put the menubar of this stack into tMbar
if tMbar is empty then put the defaultMenuBar into tMbar
if tMBar is empty then return "No menu bar active"
put empty into tMenuString
repeat with i = 1 to the number of btns of tMBar
put the long id of btn i of tMBar into tMenuObj
put MenuItemsToText(the text of tMenuObj) into tMenuItems
put lineoffset(cr& pItem &cr, cr&tMenuItems &cr) into tOS
if tOS > 1 then
put line tOS of tMenuItems into tMenuString
if tMenuString is not empty then exit repeat
send "menuPick "&tMenuString to tMenuObj
-- This function takes the contents of a menu object
-- and removes the metacharacter stuff to arrive at
-- a string which is hopefully like the one which
-- you'd get as a param to menuPick. It's called
-- by MenuDo to reformat menu object contents into
-- a form which can be used to send a menuPick
-- message. Needs some work, but handles most
-- basic cases okay:
function MenuItemsToText pItems
put "!r,!u,!c,!n" into tEntities
repeat for each item tEntity in tEntities
replace cr&tEntity with cr in pItems
replace tab&tEntity with tab in pItems
replace tEntity&tab with tab in pItems
replace "&" with empty in pItems
put empty into tList
set the itemdel to "/"
put empty into tLastSubMemu
repeat for each line tLine in pItems
put item 1 of tLine into tMenuItem
if char 1 of tMenuItem = tab then
put tLastSubMenu &"|" into char 1 of tMenuItem
put tMenuItem into tLastSubMenu
put tMenuItem &cr after tList
if char 1 of last item of tMenuItem = "(" then
delete char 1 of last item of tMenuItem
More information about the Use-livecode