Tear-Off
Volume Number: 3
Issue Number: 12
Column Tag: Pascal Procedures
Tear-Off Menus Explained 
By Darryl Lovato, TML Systems, MacTutor Contributing Editor
Hello once again, this month I would like to show how to implement tear-off
menus. What is a tear-off menu? It is a menu which can be removed from the menu
bar and used as a window. I first saw a tear off menu in a pre-release version of
Hypercard by Bill Atkinson. Since I have had a lot of experience creating and using
Menu and Window Definition routines, I thought I would try to duplicate his
implementation of tear-offs so that MacTutor readers can see how it is done and use
them in their own programs.
I assume that you know how menu and window definition routines work. If you
are not familiar with them read my articles in the July, August, and October 1986
issues of MacTutor.
The Window Definition routine used in the example is fairly straight forward,
and, in fact, really isn’t needed. It’s sole purpose is to NOT look like a regular window.
To do this I made the window’s title bar small and solid black. The pattern drawing is
not a part of the definition routine. It is handled in a update event as any other
window’s contents. The window looks like the one in figure 1.
Figure 1
The Menu Definition routine used in the example is where the special tear-menu
code is. The tear-off menu in figure 2 looks very similar to the tear-off window. The
size and draw messages are just as you would expect. The choose message, however,
has some special coding to implement the tear-off. When we get the choose message,
and the mouse is outside of the menu rectangle we check to see how far outside it is. If
it is more than 10 pixels outide of the menu rectange, then we do not return from the
choose message routine. Instead, we drag a outline of the menu on the desktop region
until the mouse comes up, the user moves the mouse over another menu, or the mouse
is moved back onto the original menu. If the mouse comes up while we are tracking it,
we send a message back to the program telling it to move and re-display the torn
window at that point. We communicate this information by posting an event which is
unused by the application. I picked event #12, but you could choose any of the
application event numbers. We pass the top left coordinate of where to display the
pallete window in the Event.message paramter.
When the main event loop gets event 12, it must move the menu to the location
passed in the message and display the window.
Figure #2
There are a couple of things that need to be pointed out. First, drawing all the
patterns is real slow (even on a MacII!!!). This could be improved a great deal by
keeping a offscreen bitmap of the patterns and use copybits instead of drawing them.
Second. I know I have done a big no-no by not making the menu and window defs code
resources. Third, you should be able to edit the patterns by double clicking on them to
bring up a pattern editor window. Fourth, it would be great if the patterns could be in
color on a Mac II. I leave the above enhancements to you as an exersize.
The program I used to create the tear-off windows is given below. It was written
is TML Pascal, but the techniques shown should be usefull no matter what language
your using. Have fun!
Pascal Code Optimizations
I would like to share some secrets with MacTutor readers out there who strive
for the fastest, smallest Pascal code. My tricks will not improve your code 500%, as
re-designing a algorithm could, but they can help you get the most out of the code
generated by your compiler. These tricks are for TML Pascal, but should help you
generate better code in any Pascal.
1. Always use Inc(x) and Dec(x) procedures instead of x := x + 1 or x := x - 1. The
inc and dec procedures generate one assembler instruction as opposed to 3 for x
:= x + 1. This saves 6 bytes each time you use it. When inc and dec are used in
loops, this can save a lot of execution time. [Unfortuanately, these are not
available in other implementations. -Ed]
2. If you pass a structure larger than 4 bytes to a procedure or function, pass it as
a static paramter. When you use a static, instead of regular parameters, you
save 18 bytes per paramter in code size. This saves a lot of execution time, too.
The reason for this is that when you pass a large structure as a static parameter,
it is not copied local to the procedure. This is e specially usefull if you pass a lot
of strings to procedures and functions.
3. In certain if..then..else statements, you can save code by restructuring the
statement to eliminate the else, and 4 bytes!
4. For loops are code hogs! Because Pascal compilers check the bounds of ‘for’ loops
before entering them, they generate a lot of error checking. By recoding a ‘for’
loop as a repeat loop you can save 16 bytes. Here is an example:
Instead of this:
for x := 1 to 100 do
begin
end;
Do this:
x := 1;
repeat
inc(x);
until x = 100;
There are a lot of other optimizations that can be done to make faster, smaller
Pascal code, but these are the ones that can be used the most. Of course, re-writting
the code in assembler would make the biggest diffrence in code size and speed, but that
can take a long time and there are a lot of people who do not understand 680x0
assembler.
[The following code has been sanitized to work in both TML Pascal and LS Pascal
and has been tested in both. However, one of the functions that returns a rect as an
argument tripped up the Turbo Pascal syntax checker, so some modification may be
necessary to get the program compiled in Turbo. We are at a loss as to why Turbo
should be more picky than LS Pascal, which I thought was the most fussy of all! The