Object Shell 2
Volume Number: 6
Issue Number: 9
Column Tag: MacOOPs!
Related Info: Window Manager QuickDraw TextEdit
Object Shell, Part II
By Dr. Christian Stratowa, Vienna, Austria
Part 2: Application-specific Units
Let me start the second part of my article once again with a statement, this time
with the first sentence of the TMLetter: “Apple is giving notice to Macintosh
developers that object-oriented programming (OOP) will become the only way to
write Mac software.” I really hope this statement does not mean that in the future
Apple will force programmers to use MacApp. Although I don’t have MacApp yet, from
what I have seen in the different articles published in MacTutor, I have the feeling that
I won’t like it. Once upon a time...Apple has started the computer revolution by giving
people the freedom of personal computing. Now that Apple seems more and more to
adopt IBM-like behaviour let me say: “Freedom to the programmers to adopt their own
programming style and to use the language of their choice!” Programming is still an
esthetic art and having a uniform user interface (which is surely of great benefit to
the users) does not necessarily mean to have to adopt a uniform programming style.
Last time I have presented the general part of our shell program, which needs not
be changed when you want to use ObjectShell for your own purposes. So let’s now talk
about the units specific to our demo application.
Adding your own menus
Unit MyMenus allows us to attach all menus specific to our application. Here we
make use of Apple’s new “Hierarchical Menus” feature, where any menu item can be
defined as submenu. So we define an object TSubMenu, whose method Create inserts a
submenu (see IM V-236). In our program we make use of this feature not only in
menu “Text” where Font, Size, Style and Justification are arranged as submenus, and
in “Color” with submenus TForeCMenu and TBackCMenu, but we do also define item
“New” of our standard “File” menu as submenu to be able to create “NewText” or
“NewPict” documents. We can do this by creating submenu TNewMenu without having
to change any code in our unit StdMenus. Every submenu item can itself be another
submenu, although Apple states that only one level of hierarchical menus should be
used. In our demo program we create another submenu level by defining TNewPictMenu
and TNewTextMenu to let the user choose the window type. Normally you would delete
this level.
We can open windows containing either TEXT or PICT documents which use
different menus. For this we want to change the appearance of the menubar depending
on the type of window becoming Front window. Therefore procedure SetMyMenuBar,
which is called from DoActivate every time a window will be activated, does change the
whole MenuBar by calling SwitchMenus. When no window is in front, all but the three
standard menus will be deleted from the menubar. In the case Frontwindow is a desk
acessory I decided for demonstration purposes to disable the application-specific
menus only although we could have also deleted them in this case. (I have put the
necessary call to SwitchMenus in parenthesis.) Procedure SwitchMenus does insert or
delete the necessary menus by calling DoInsertMenu. This procedure requires
parameter vMenuHdl besides vRsrcID, because it is not possible to call
GetMenuHandle(vRsrcID), when a menu is not installed in the menulist.
When a userwindow becomes activated, we want the current menu settings to be
marked, e.g. for text the current Font, Size, Style and Align menu items should be
indicated with a checkmark. This is pretty straight foreward. For text procedure
SwitchMenus calls CheckFontMenu, CheckSizeMenu etc. Procedure CheckFontMenu does
for example get the current font from the GrafPort (thePort^.txFont) and does call
SetCheckMark if vFontName equals vCurrentFont. It has also to call OutlineFontSize for
every RealFont in the System. Procedure CheckStyleMenu is a little more tricky,
because Apple has decided to define Style as set of type StyleItem [see IM I-152].
Together with style “Plain” there exist eight style items, therefore I have decided to
use the bits of one byte for the style setting. For this purpose I defined a field variable
fMyHdl of type Handle in TDocument. All procedure CheckStyleMenu has to do is to set
the corresponding bits. (Because a Handle is defined as ^^SignedByte the initial setting
“Plain” is: fMyHdl^^:= -128.) Similarly, when we select or unselect a style item,
TStyleMenu.Choose sets or clears the corresponding bit.
For graphics we have only to call SetCheckMark every time a graphics window
becomes activated or the user selects an item from the “Graphics” menu or one of the
“Color” submenus. (To save some space in this article, I have decided not to colorize
the “Color” submenu items. With new ResEdit 1.3 (one.three!) it is much too easy to
do, anyway.)
Documents - What the Mac is Made for
So far we have learned how to deal with Mac specific stuff, but every computer is
built for one purpose only - to process our documents.
As mentioned earlier, our program can handle text and graphics. In unit
MyDocuments we define subclasses TTextDocument and TPictDocument. The document
type itself is then set in TWindow.DoNew in the already known manner. However,
creating a new document this way does have its disadvantages, too: We have to place
every field, which has to be set from outside the object, in ancestor class TDocument.
Let us take textedit record’s handle fTextHdl as an example. This is clearly a field
variable, which does only belong to subclass TTextDocument. But if we define it there
the compiler will generate an error message in method Choose of our submenus, where
we have set e.g. fTextHdl^^.txFont. Isn’t this a limitation of the ObjectPascal compiler?
(You will probably say objects should be encapsulated and fields not changed from
outside directly.)
Since we are already talking about text let’s have a closer look.
Typewriter’s Mac
Before creating a new fTextHdl for our textedit record in DoNew we have to define
its view rectangle fViewRect and destination rectangle fDocRect. These two rectangles
have also to be set in our Update routine, otherwise you will be in trouble when for