Pin-up Menu
Volume Number: 6
Issue Number: 6
Column Tag: Pascal Procedures
"PinUpMenu" XCMD
By Steven Fuchs, Coram, NY
Interface the Music
The Problem with the Finder
Excessive Folderfication. How many readers suffer from this graphically
oriented computer malady? As our hard drives grow larger we are faced with a
delicate balance between maintaining enough folders to satisfy our need for
organization, and so many levels of folders that finding a document requires the
opening and closing of eight windows. Let’s not even mention a trip to the handy but
discouraging “Find File” DA. Don’t get me wrong, I love folders as much as the next
guy, but I believe many users would like to have the ability to reach through the
folders to ‘grab’ a specific document.
Hypercard “Open Command”
Within the Hypertalk programming environment there exists the “Open ”
command . The Open command when used with an application name as its parameter in
the form “Open AppName” will launch that application in a manner similar to the
Finder. In addition it can be passed a document name as a parameter in the form “Open
DocName with AppName” which will cause the application to open to the specified
document. This performance parallels the Finder and offers no distinct advantages.
The Hypercard advantage lies in its knack for remembering the full pathnames of all
documents and applications launched from within it in a “pathname memory”. When
launching an application or document from Hypercard only it’s name must be given.
Hypercard will search through its “pathname memory” until the correct path is
found. If the document is not found Hypercard displays a modal dialog requesting the
user’s aid in locating the file. If that search is successful then that pathname is added
to the “pathname memory”. This “pathname memory” can be examined by looking at
pages 2 through 4 of your Home stack. Here is stored the pathnames of stacks,
applications, and documents respectively. If you recognize any folder names that have
been changed or deleted, these can be safely removed to save time and disk space.
Introduce Pin-Up Menus
The XCMD to be described this month allows for quick selection from a set of
pre-chosen commands, and is accessible from anywhere within Hypercard. The name
of the XFCN is “PinUpMenu”, which can be altered by the Hypercard user for his or
her own utility. The instance I will use as an example I have dubbed “The Pop-Up
Finder”. Which is just what the doctor ordered for quickly launching applications and
their documents from within Hypercard.
Figure 1.
Cards-Eye View
Call it Up
Upon invocation, PinUpMenu displays a small window, and waits patiently for a
mousedown event (See Figure 1). If this mousedown occurs outside of the window , the
window disappears and PinUpMenu has run its course. If this mousedown occurs
within the window a pop-up menu (hierarchical if desired) appears and allows for the
selection of any desired item. The returned value can then be processed by the script
that called it. In the case of “The Pop-Up Finder” the selected application and
document will be launched using Hypercards “Open” command.
Necessary Scripts, Options
The PinUpMenu XFCN must be called with at least 2 parameters (See Figure 2).
The first parameter is a string which is drawn within the window. Use this
parameter to differentiate between your particular implementations of PinUpMenu.
Parameters 2 through 16 are used to build the menus, they accomplish this by
following a few simple rules. Each parameter should be a Hypercard container which
holds one or more items. An Hypercard item being a string delineated by commas. The
first item in the list will be the name of that line in the parent menu, while any
remaining items will be listed in order as the submenus of that line. If there is only
one item in the parameter then that item will be listed alone.
The Returns
PinUpMenu is an XFCN, therefore it must be used within an assignment and will
return a value to Hypercard. This value will consist of one or two items. If the
original click is made outside of the window or the mouse is released outside of the
menu, then “Cancel” is returned. If the mouse is released in the parent menu inside of
an item with no submenus then the selection name is returned in a one item string. If
the mouse is released in a submenu choice, the answer consists of a two item string,
the parent item followed by the submenu item separated by a comma so that your
script can process the return with little modification. Be warned, this type of
construction will not allow for the use of commas in a menu, as Hypercard will
interpret this as two different items.
Figure 2.
Amongst the Gears
Hierarchical Menus
Submenus and Pop-Up Menus themselves are very easy to create and call up.
They are created just as are other menus are, with a call to NewMenu. Although
GetNewMenu and a resource could have been used, I have decided to create all windows
and menus “on the fly”. I believe that XCMD’s should function this way whenever
possible, simplifying the resource fork of the users Home stack as well as avoiding
numbering conflicts between other external commands. To invoke a parent menu and
the associated set of submenus , all you must do is call up the parent menu. The Mac
toolbox handles the correct hiliting and displaying of the submenus. In order to alert
the toolbox as to what you consider to be the correct hilighting and display two things
must be done. First the command key field of the item you wish to give a submenu to
should be set to $1B. This is a character which Apple has reserved to represent
Hierarchical menus, it consists of the now familiar triangle pointing to the right.
Secondly, set the item mark field of that same item to the menu id of the submenu and
that’s it. The final step is to call InsertMenu(TheMenu,-1) for each of the submenus,
and for the main menu in our case since it is a pop-up menu. By specifying -1 as the
second parameter you tell the Mac not to put this menu in the Menubar, but to add it to
the menu list anyway. Then call PopUpMenuSelect or MenuSelect and it will take care
of the details from there. A very important consideration is that the menu id of a
submenu may not be greater than 255, since that value must be a character placed into
the item field. Passing a number larger will at the very least not work, and in the
worst case cause some major problems.
Stealing Events
While PinUpMenus (or any other external code) is in control, Hypercard is in a
semiconscious state so we will have to process events in its stead. This is no problem
while running under the Finder, since the Menu Manager refreshes the screen beneath
menus. However, if running under MultiFinder update events being generated through
application switching will not be handled. This results in white blotches in the
Hypercard window. The solution is very simple. By sending Hypercard the message ‘Go
to this card’ we can force Hypercard to update itself, without interrupting our goings
on (Thanks to Joe Zuffoletto and his article in Feb and March 1989 MacTutor for that
handy tip). This however does not update the message box or the tool/pattern windoids.
If this causes a problem the windoids can be restored by simply hiding and showing
them again once PinUpMenu has run its course. Since the PinUpMenu XFCN serves no
real purpose running in the background I plead guilty with explanation to not devising
a more graceful alternative.
Saying Goodbye
Cleaning up the stack before returning to Hypercard is very important for any
external code. I make sure all menu handles not used are set to nil. This helps to
determine which items have submenus, allowing us to avoid the unpleasant symptoms
of deleting a menu which is not there or not deleting a menu that is. When writing
external code it is important to dispose of all handles and pointers before returning.
The leaving of unneeded blocks of memory lying around the heap for Hypercard to skirt
is a very unMac-Like way of programming. In addition the window must be disposed
of, and last but certainly not least the GrafPort must be reset to its state before the
XFCN ran. If all of these have been done correctly then Hypercard should return
without difficulty.
Getting Fancy
Simplicity equals Power
The structure of the XFCN, while remaining simple may be confusing to some
developers not familiar with nesting procedures and functions. Under ordinary
circumstances this is not necessary, and not often used. When writing a XFCN (or any
other code resource) global variables are not allowed. By declaring the important
variables in MAIN and then nesting all of the other routines, these variables can be
treated as globals by the nested routines.
To sum up the actions of PinUpMenu in a nutshell besides creating a window it
merely deciphers Hypercard item lists and calls AppendMenu for each of these.
Simplicity yes but where is the power in that? Well, for those of you familiar with
AppendMenu’s inherent power the answer is one simple word. Metacharacters. By
passing these Metacharacters through Hypercard to PinUpMenus, all of the effects
which can be used to make menus more clear can be used.
Staying in Metacharacter
Within the structure of the Mac OS menus may have some different
characteristics. Each menu item may be drawn in a different style, may have an icon,
may be enabled or disabled, and can have a command key associated with it. These can
be added by a developer with little problem, by being specified in a resource file, or
added through the AppendMenu call with Metacharacters. A metacharacter is a
character which is not part of the actual text. Instead it allows for special distinctions
to be made for a menu item. To add an icon to a menu item use the “^” character
followed by the icons number less 256. To mark an item with a check mark or some
such character, place an exclamation point (!) followed by the character before your
item. The less than symbol (<) followed by either B,I,U,O,S sets the style of that item
to the corresponding standard style. A slash (/) will associate a command key with
that item, and a left parentheses (() will disable the item. If you don’t quite
understand this you should get Inside Macintosh Volume 1 (which you should have
anyway) and read page 352, where it is all explained very well.
K.I.S.S.
The most important aspect of menus is to add simplicity to your programs, or in
this case stacks, menus should serve, not confuse. This means keeping styles, icons,
item marks, and command keys to a minimum. By the way any command key
equivalents used in PinUpMenus won’t work from Hypercard, since they only exist
while the XFCN is running (i.e. while you are holding the mouse button down). If you
must use command key equivalents you will have to trap for them yourself from within
the scripts.
In Summation
Advantages and Other Uses
The Pop-Up Finder represents a speedy way to launch any desired application
and/or document. But this is not the only use for our versatile little XFCN. Since
PinUpMenu accepts its parameters as Hypercard item lists, scripts can use it to
process and display whatever information they desire. I have written a script which
determines the names of all objects in the present card and presents them in menu
format. The object which is selected then opens its script for editing. I have also used
it as a Pop-Up home stack, presenting the user with a variety of stack categories and
names, going to whichever one is selected. For those of you who have taken the time to
type this all in, or sent away for the source code, I believe the PinUpMenu represents
a very useful XFCN, it makes no great departure from the mandated user interface
standard yet allows for a customizable method of processing and choosing your
Hypercard data. Hope you like it.
Listing: XCMDUtil.PUM
unit XCMDUtils;
interface
uses
XCMDIntf;
Str31 = string[31];
function PasToZero (paramPtr: XCmdPtr;
str: Str255): Handle;
procedure ZeroToPas (paramPtr: XCmdPtr;
zeroStr: Ptr; var pasStr: Str255);
procedure SendCardMessage (paramPtr: XCmdPtr;
msg: Str255);
implementation
procedure DoJsr (addr: ProcPtr);
inline
$205F, $4E90;
procedure SendCardMessage;
begin
with paramPtr^ do
begin
inArgs[1] := ORD(@msg);
request := xreqSendCardMessage;
DoJsr(entryPoint);
end;
end;
function PasToZero;
begin
with paramPtr^ do
begin
inArgs[1] := ORD(@str);
request := xreqPasToZero;
DoJsr(entryPoint);
PasToZero := Handle(outArgs[1]);
end;
end;
procedure ZeroToPas;
begin
with paramPtr^ do
begin
inArgs[1] := ORD(zeroStr);
inArgs[2] := ORD(@pasStr);
request := xreqZeroToPas;
DoJsr(entryPoint);
end;
end;
end.
Listing: PinUpMenu.p