home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Mac Game Programming Gurus
/
TricksOfTheMacGameProgrammingGurus.iso
/
Information
/
CSMP Digest
/
volume 1
/
csmp-v1-183.txt
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Text File
|
1994-12-08
|
43.6 KB
|
1,528 lines
|
[
TEXT/R*ch
]
C.S.M.P. Digest Thu, 15 Oct 92 Volume 1 : Issue 183
Today's Topics:
Repeated GetCIcon/PlotCIcon calls
Powerbook Battery Question
Quick TCL gDesktop question
Smooth Animation
Using PostHighLevelEvents to send low level (KeyPressed) events
Radio buttons
menubar in dialogs
The Comp.Sys.Mac.Programmer Digest is moderated by Michael A. Kelly.
The digest is a collection of article threads from the internet newsgroup
comp.sys.mac.programmer. It is designed for people who read c.s.m.p. semi-
regularly and want an archive of the discussions. If you don't know what a
newsgroup is, you probably don't have access to it. Ask your systems
administrator(s) for details. (This means you can't post questions to the
digest.)
Each issue of the digest contains one or more sets of articles (called
threads), with each set corresponding to a 'discussion' of a particular
subject. The articles are not edited; all articles included in this digest
are in their original posted form (as received by our news server at
cs.uoregon.edu). Article threads are not added to the digest until the last
article added to the thread is at least one month old (this is to ensure that
the thread is dead before adding it to the digest). Article threads that
consist of only one message are generally not included in the digest.
The entire digest is available for anonymous ftp from ftp.cs.uoregon.edu
[128.223.8.8] in the directory /pub/mac/csmp-digest. Be sure to read the
file /pub/mac/csmp-digest/README before downloading any files. The most
recent issues are available from sumex-aim.stanford.edu [36.44.0.6] in the
directory /info-mac/digest/csmp. If you don't have ftp capability, the sumex
archive has a mail server; send a message with the text '$MACarch help' (no
quotes) to LISTSERV@ricevm1.rice.edu for more information.
The digest is also available via email. Just send a note saying that you
want to be on the digest mailing list to mkelly@cs.uoregon.edu, and you will
automatically receive each new issue as it is created. Sorry, back issues
are not available through the mailing list.
Send administrative mail to mkelly@cs.uoregon.edu.
-------------------------------------------------------
From: bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan)
Subject: Repeated GetCIcon/PlotCIcon calls
Date: 14 Jul 92 22:48:21 GMT
Organization: Reed College, Portland, OR
I need to plot a fairly large number of color icons a very large number
of times in my application.
IMV says that you shouldn't call PlotCICon before each GetCIcon because
it overhead will build up in the resource map. Makes sense to me...that
seems to be happenening when my system crashes after plotting some number
of icons...
I don't know what I should be doing to dispose of the data when I'm done
plotting it. I've tried DisposCIcon & ReleaseResource, and both together,
but nothing seems to do much good...memory still gets filled up.
I just want to get rid of the things after I draw them...what do I do?
+++++++++++++++++++++++++++
From: mxmora@unix.SRI.COM (Matt Mora)
Date: 15 Jul 92 15:48:56 GMT
Organization: SRI International, Menlo Park, California
In article <m0m7vfN-000FO0C@bagpipe.reed.edu> bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan) writes:
>IMV says that you shouldn't call PlotCICon before each GetCIcon because
>it overhead will build up in the resource map. Makes sense to me...that
>seems to be happenening when my system crashes after plotting some number
>of icons...
>I don't know what I should be doing to dispose of the data when I'm done
>plotting it. I've tried DisposCIcon & ReleaseResource, and both together,
>but nothing seems to do much good...memory still gets filled up.
>I just want to get rid of the things after I draw them...what do I do?
You could mark them purgeable. But I don't think that really works. I think
there is a bug with cicns or something because I tried to get rid of the
memory but it would still fill up the heap. I'm using ploticonid now
(tech note #30x) and it works fine.
What you might want to do is create a gworld and plot all the icons at
once. Then blit them in via copybits as you need them. Depending on the
amount of icons and pixdepth this might not be posible in your case.
Matt
- --
___________________________________________________________
Matthew Mora | my Mac Matt_Mora@sri.com
SRI International | my unix mxmora@unix.sri.com
___________________________________________________________
+++++++++++++++++++++++++++
From: ozma@kuhub.cc.ukans.edu
Date: 16 Jul 92 23:41:46 CDT
Organization: University of Kansas Academic Computing Services
In article <36915@unix.SRI.COM>, mxmora@unix.SRI.COM (Matt Mora) writes:
> In article <m0m7vfN-000FO0C@bagpipe.reed.edu> bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan) writes:
>
>>IMV says that you shouldn't call PlotCICon before each GetCIcon because
>>it overhead will build up in the resource map. Makes sense to me...that
>>seems to be happenening when my system crashes after plotting some number
>>of icons...
> You could mark them purgeable. But I don't think that really works. I think
> there is a bug with cicns or something because I tried to get rid of the
> memory but it would still fill up the heap. I'm using ploticonid now
> (tech note #30x) and it works fine.
I believe ReleaseResource() after every PlotCIcon will do the trick.
john calhoun-
+++++++++++++++++++++++++++
From: gluttony@reed.edu!gluttony.reed.edu!pcalahan (Patrick John Calahan)
Date: 17 Jul 92 21:14:24 GMT
Organization: Reed College, Portland, OR
In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>
ozma@kuhub.cc.ukans.edu writes:
>
> I believe ReleaseResource() after every PlotCIcon will do the trick.
>
> john calhoun-
nope. like i said in the message, i had been using release resource but
it still wasn't working. i kludged my way around it by quitting the
application after plotting a lot of icons (i only needed to see them for a
while while the app is in development). a more elegant solution remains
a mystery to me
+++++++++++++++++++++++++++
From: ozma@kuhub.cc.ukans.edu
Date: 19 Jul 92 01:04:03 CDT
Organization: University of Kansas Academic Computing Services
In article <m0m8zd3-0006ChC@gluttony.reed.edu>, gluttony@reed.edu!gluttony.reed.edu!pcalahan (Patrick John Calahan) writes:
> In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>
> ozma@kuhub.cc.ukans.edu writes:
>> I believe ReleaseResource() after every PlotCIcon will do the trick.
>> john calhoun-
>
> nope. like i said in the message, i had been using release resource but
> it still wasn't working. i kludged my way around it by quitting the
> application after plotting a lot of icons (i only needed to see them for a
> while while the app is in development). a more elegant solution remains
> a mystery to me
Whoops, sorry. It's DisposCIcon() that you need. So, GetCIcon(), PlotCIcon(),
DisposCIcon().
john calhoun-
+++++++++++++++++++++++++++
From: nextweek@reed.edu!nextweek.Reed.Edu!pcalahan (Patrick John Calahan)
Date: 20 Jul 92 02:38:56 GMT
Organization: Reed College, Portland, OR
In article <1992Jul19.010403.41701@kuhub.cc.ukans.edu>
ozma@kuhub.cc.ukans.edu writes:
> In article <m0m8zd3-0006ChC@gluttony.reed.edu>,
gluttony@reed.edu!gluttony.reed.edu!pcalahan (Patrick John Calahan)
writes:
> > In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>
> > ozma@kuhub.cc.ukans.edu writes:
> >> I believe ReleaseResource() after every PlotCIcon will do the trick.
> >> john calhoun-
> >
> > nope. like i said in the message, i had been using release resource
but
> > it still wasn't working. i kludged my way around it by quitting the
> > application after plotting a lot of icons (i only needed to see them
for a
> > while while the app is in development). a more elegant solution
remains
> > a mystery to me
>
> Whoops, sorry. It's DisposCIcon() that you need. So, GetCIcon(),
PlotCIcon(),
> DisposCIcon().
>
> john calhoun-
>
been trying that to...no go :) no matter to me anymore, though
+++++++++++++++++++++++++++
From: absurd@applelink.apple.com (Tim Dierks, software saboteur)
Date: 29 Jul 92 00:09:18 GMT
Organization: MacDTS Misfits
In article <1992Jul16.234146.41639@kuhub.cc.ukans.edu>,
ozma@kuhub.cc.ukans.edu wrote:
>
> In article <36915@unix.SRI.COM>, mxmora@unix.SRI.COM (Matt Mora) writes:
> > In article <m0m7vfN-000FO0C@bagpipe.reed.edu> bagpipe@reed.edu!bagpipe.reed.edu!pcalahan (Patrick John Calahan) writes:
> >
> >>IMV says that you shouldn't call PlotCICon before each GetCIcon because
> >>it overhead will build up in the resource map. Makes sense to me...that
> >>seems to be happenening when my system crashes after plotting some number
> >>of icons...
>
> > You could mark them purgeable. But I don't think that really works. I think
> > there is a bug with cicns or something because I tried to get rid of the
> > memory but it would still fill up the heap. I'm using ploticonid now
> > (tech note #30x) and it works fine.
>
> I believe ReleaseResource() after every PlotCIcon will do the trick.
>
Actually, the appropriate call is DisposCIcon(), which will dispose of all
the various handles associated with a color icon. ReleaseResource() would
not release all the handles; in fact, I think it would be in error, because
I'm pretty sure that a CIconHandle in memory is not a resource handle; it's
constructed from one.
Tim Dierks
MacDTS, but I speak for the trees
---------------------------
From: mar@ocf.berkeley.edu (Michael A. Ramirez)
Subject: Powerbook Battery Question
Date: 21 Jul 92 22:17:25 GMT
Organization: U.C. Berkeley Open Computing Facility
I am wondering how I can get rid of the dialog boxes warning me that the
power is low on the Powerbooks. Are these dialog boxes in the ROM or
in the System file? Any help or comments would be appreciated.
Thanks.
Michael
- --
- -----------------------------------------------------------------------------
___ _ ___ ___ _ ____ ____ ____ mar@ocf.berkeley.edu
|__| |_| | | | | |___| |___ / When laws are outlawed then only
| \ | | | | | | | \ |___ /___ outlaws will obey the law- Mondo 2000
+++++++++++++++++++++++++++
From: stevec@Apple.COM (Steve Christensen)
Date: 25 Jul 92 02:30:12 GMT
Organization: Apple Computer Inc., Cupertino, CA
mar@ocf.berkeley.edu (Michael A. Ramirez) writes:
>I am wondering how I can get rid of the dialog boxes warning me that the
>power is low on the Powerbooks. Are these dialog boxes in the ROM or
>in the System file? Any help or comments would be appreciated.
I assume from your question that you don't mind if your PowerBook will
suddenly go to sleep without notice in order to preserve the state of
its memory (and thus your data)?
OK, if so, you can find the strings it uses to warn you in the System File.
If you remove them, you won't get any warnings, the PowerBook will just go
to sleep...
steve
- --
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Steve Christensen Never hit a man with glasses.
stevec@apple.com Hit him with a baseball bat.
---------------------------
From: rla20@duts.ccc.amdahl.com (Roger Allen)
Subject: Quick TCL gDesktop question
Date: 21 Jul 92 21:24:46 GMT
Organization: Amdahl Corporation, Sunnyvale CA
Quickie:
For multi-monitor systems, does gDesktop->bounds include the main device
only or some rect that bounds all of the screens.
In other words is gDesktop->bounds A or B. Where B is the main screen and
C is another screen and A is the rect that bounds them.
AAAAAAAAAAAAAAAAAAA
ABBBBBBBB A
AB B A
AB .. B A
AB \/ BCCCCCCCCCA
AB BC CA
ABBBBBBBBC CA
A C CA
A C CA
A C CA
A CCCCCCCCCA
AAAAAAAAAAAAAAAAAAA
Hope it takes less time to answer than it did to draw that.
Roger
- --
> Roger Allen | <
> Amdahl Computer Development | What are you looking here for? <
> rla20@cd.amdahl.com | <
+++++++++++++++++++++++++++
From: k044477@hobbes.kzoo.edu (Jamie R. McCarthy)
Date: 23 Jul 92 16:45:36 GMT
Organization: Kalamazoo College
rla20@DUTS.ccc.amdahl.com (Roger Allen) writes:
>Quickie:
>For multi-monitor systems, does gDesktop->bounds include the main device
>only or some rect that bounds all of the screens.
All the screens.
This is despite the comment in ThC's TCL 1.1's CDesktop::IDesktop:
/* Make the port rectangle coincide with the bounding box of */
/* the gray region (entire screen excluding the menu bar). ... */
grayRgn = GetGrayRgn();
bounds = (**grayRgn).rgnBBox;
The parenthetic should read "(all screens excluding the menu bar)".
>Hope it takes less time to answer than it did to draw that.
Probably... :-)
- --
Jamie McCarthy Internet: k044477@kzoo.edu AppleLink: j.mccarthy
I'm having a lot of trouble seeing how a request that you "shut up" can be
interpreted as "looking to other people for validation." - Tim Pierce
---------------------------
From: tj@kona.cs.ucla.edu (Tom Johnson)
Subject: Smooth Animation
Date: 23 Jul 92 19:59:03 GMT
Organization: UCLA Computer Science Department
FAQ Alert! FAQ Alert! FAQ Alert!
Could someone send me some sample code for doing smooth color
animation that's compatible with all the different machines and
accelerated/non-accelerated video cards out there?
Or some discussion/archived c.s.m.p posts?
I've seen so much of this in the past, but since my work never required
any sort of animated graphics, I didn't save anything. And now.....
Now I feel stupid for not saving them.
Thanks-
Tom
- --
Tom Johnson "They say Confucious does his crossword with a pen."
tj@cs.ucla.edu -Tori Amos
+++++++++++++++++++++++++++
From: tj@kona.cs.ucla.edu (Tom Johnson)
Organization: UCLA Computer Science Department
Date: Fri, 31 Jul 92 20:57:37 GMT
I'm thinking about writing a game, so I decided I'd play around a bit and
try to get some nice fast and smooth animation running just to see how to
do it. Nothing fancy, just a box bouncing around in a window on the screen.
I've got the drawing sync'd to a VBL task and everything works great in a
situation like this:
do {
DrawNextFrame();
} while (!Button());
of course. But when I put it into a real event loop:
do {
MainIdle();
gotEvent = WaitNextEvent(everyEvent, &theEvent, 0,nil);
if (gotEvent)
HandleEvent(&theEvent);
} while (gQuitApplication != true);
I get all sorts of little starts/stops/pauses in the animation, as the mac
gives time to background processes. And it's certainly not acceptable for
a fast arcade-style game.
How do other game authors handle it? Do you not give time to bkgnd processes?
Just let downloads timeout? Or is there some simple idea that's gone by
me completely?
Question 2: I've given up on getting enough speed from CopyBits and have
decided that I'm willing to take a few risks and write directly to the
screen. I found the sample code in the FAQ for setting pixels. Does anyone
have some utility routines they might be willing to share to handle other
tasks? (ie drawing Icl's, etc...).
This is just a little throw away freeware
game, so I'm trying to get as much done as I can as quickly as possible. Has
anyone ever written a sample arcade game and given away the source? Something
I could base mine upon?
Thanks-
Tom
- --
Tom Johnson "They say Confucious does his crossword with a pen."
tj@cs.ucla.edu -Tori Amos
+++++++++++++++++++++++++++
From: mspace@netcom.com (Brian Hall)
Date: Sat, 01 Aug 92 07:03:09 GMT
Organization: Netcom - Online Communication Services (408 241-9760 guest)
tj@kona.cs.ucla.edu (Tom Johnson) writes:
>I'm thinking about writing a game, so I decided I'd play around a bit and
>try to get some nice fast and smooth animation running just to see how to
>do it. Nothing fancy, just a box bouncing around in a window on the screen.
>I've got the drawing sync'd to a VBL task and everything works great in a
>situation like this:
> do {
> DrawNextFrame();
> } while (!Button());
>of course. But when I put it into a real event loop:
> do {
> MainIdle();
> gotEvent = WaitNextEvent(everyEvent, &theEvent, 0,nil);
> if (gotEvent)
> HandleEvent(&theEvent);
> } while (gQuitApplication != true);
>I get all sorts of little starts/stops/pauses in the animation, as the mac
>gives time to background processes. And it's certainly not acceptable for
>a fast arcade-style game.
Instead of calling WNE for each pass through the loop, why not try calling
it once every few ticks. Perhaps one call every 10 ticks. You could
vary the number depending on how friendly you want to be.
A friend of mine did this in a database program he was working on where
it called WNE during long processes, and found that by calling WNE once
every so often instead of once per pass, he was able to more than double
the time to sort the database.
- --
\ | / | Brian Hall mspace@netcom.com
- : - | Mark/Space Softworks Applelink: markspace
/|\ | America Online: MarkSpace
|-+-| |
/-\|/-\ | People don't kill people, toasters kill people.
---------------------------
From: mmigdol@ccwf.cc.utexas.edu (michael a migdol)
Subject: Using PostHighLevelEvents to send low level (KeyPressed) events
Date: 24 Jul 92 14:31:06 GMT
Organization: The University of Texas at Austin, Austin TX
According to IM VI, p. 5-18, "Your application can both send and receive high-
level events, but it generally only receives low-level events and should not
send them."
So, this implies that I *can* send KeyPressed events to other applications.
(Even though I "shouldn't", I want to. I really do! :) )
Anyways, Apple certainly doesn't seem to encourage this, and I'm about to try
this out myself, but am I supposed to use PostHighLevelEvents with theEvent.what
set to Keypressed (or whatever) to do this? Am I going to hit any problems
later on? Does the application I'm sending to have to "AcceptHighLevelEvents"
to receive low level events sent this way?
Thanks in advance, and smile - it's FRIDAY!
- -Michael
+++++++++++++++++++++++++++
From: smoke@well.sf.ca.us (Nicholas Jackiw)
Organization: Whole Earth 'Lectronic Link
Date: Fri, 24 Jul 1992 16:04:10 GMT
In article <76508@ut-emx.uucp> mmigdol@ccwf.cc.utexas.edu (michael a migdol) writes:
>According to IM VI, p. 5-18, "Your application can both send and receive high-
>level events, but it generally only receives low-level events and should not
>send them."
>
>So, this implies that I *can* send KeyPressed events to other applications.
>(Even though I "shouldn't", I want to. I really do! :) )
That's right; you can and "shouldn't." Remember, however, that it's *your*
Macintosh and you can do what you damn well like with it.
>
>Anyways, Apple certainly doesn't seem to encourage this, and I'm about to try
>this out myself, but am I supposed to use PostHighLevelEvents with theEvent.what
>set to Keypressed (or whatever) to do this? Am I going to hit any problems
>later on? Does the application I'm sending to have to "AcceptHighLevelEvents"
>to receive low level events sent this way?
No, PostHighLevelEvents won't work for this; all high-level events are of
the same low-level event type. Nor do you need AcceptHighLevelEvents; this
will simply add unnecessary launch-time overhead.
I believe that any low-level event gets sent to the event handler of the
foremost application. This means you'll need to have your receiver in
front. (See the Process Manager in System 7 for how to do this automatically,
otherwise just bring it to the front with the multifinder menu after
launching the sender.) Then, call PostEvent from your sender with
the appropriate keydowns.
[Actually, I think you should use PPostEvent, which will return to you
a pointer to the event that will be shipped the frontapp. You want this
pointer if you intend to do any preprocessing of the event record, such
as clearing its modifier keys or setting the "where" field to a mouse
location of your choice.]
- --
--- * ---
Nick Jackiw Smoke@well.sf.ca.us | Jackiw@cs.swarthmore.edu
Key Curriculum Press, Inc. Applelink:KEY.EDUSOFT | (510) 548-2304
--- * ---
+++++++++++++++++++++++++++
From: walkerj@math.scarolina.edu (Jim Walker)
Date: 24 Jul 92 17:35:37 GMT
Organization: USC Department of Computer Science
To post low-level events, use PPostEvent. It is documented in IM IV, but
was omitted from the index. I think it's in the chapter on the OS Event
Manager. The advantage of PPostEvent over PostEvent is that the former
allows you to set the modifiers, location, and time as well as the message.
- --
-- Jim Walker USC Dept. of Math. walkerj@math.scarolina.edu
---------------------------
From: fsmah1@acad3.alaska.edu (Mike Hageland)
Subject: Radio buttons
Date: 27 Jul 92 03:51:45 GMT
Organization: University of Alaska Fairbanks
I have a very simple little problem with what seems to be a complicated
solution. Look at this diagram and pretend the X represents where I
want a radio button.
X Title | Title X
X Title | Title X
X Title | Title X
Personally I think this looks kinda neat. I would like to do something
like this. Now this is no problem, I can simply draw the titles in and
then place in the radio buttons. However, then you can't simply click
onto the title like you can with most radio buttons. It seems that the
radio button will only put the title to the right of the radio button.
The way I can think of to do this is to create another simple button over the
titles on the right side and deal with changing the radio buttons around
when it is pressed.
Can anybody think of a cleaner way to do this? Is there a hiden way to
make a radio button have a title on the left?
+++++++++++++++++++++++++++
From: ericsc@microsoft.com (Eric Schlegel)
Date: 29 Jul 92 19:58:07 GMT
Organization: Microsoft Corporation
In article <1992Jul26.195145.1@acad3.alaska.edu> fsmah1@acad3.alaska.edu (Mike Hageland) writes:
>I have a very simple little problem with what seems to be a complicated
>solution. Look at this diagram and pretend the X represents where I
>want a radio button.
>
> X Title | Title X
> X Title | Title X
> X Title | Title X
>
>Personally I think this looks kinda neat. I would like to do something
>like this. Now this is no problem, I can simply draw the titles in and
>then place in the radio buttons. However, then you can't simply click
>onto the title like you can with most radio buttons. It seems that the
>radio button will only put the title to the right of the radio button.
>
>Is there a hidden way to make a radio button have a title on the left?
You need to set the system justification to teFlushRight (-1) before
drawing the right-hand column of radio buttons. You can do this with the
Script Manager trap _SetSysJust:
SetSysJust(teFlushRight);
Don't forget to save the previous justification using _GetSysJust before
changing it, and restore it afterwards.
If you're doing this in a window of your own creation, you can just
call _SetSysJust and then _Draw1Control to draw the right-hand radio buttons.
If your radio buttons are in a Dialog Manager dialog you may need to use
a filter proc that catches update events and does the updating itself,
using _SetSysJust and _Draw1Control as needed, instead of letting the Dialog
Manager draw the controls.
For more information, see Inside Mac vol. 5, pg. 301, "Writing Direction."
- -eric
- -------
My opinions, not Microsoft's.
---------------------------
From: kaas@cc.ruu.nl (Dick Kaas)
Subject: menubar in dialogs
Date: 28 Jul 92 13:27:28 GMT
Organization: -
I'm planning to write a TCL pane for a menu-bar.
Is there a simple way to implement a menubar into dialogs (like WP and
superboomerang) without having to write a complete menu package by
yourself?
I have looked at the low memory globals, such as MenuBarHook etc. None of
these seem useful.
Dick kaas.
+++++++++++++++++++++++++++
From: keith@taligent.com (Keith Rollin)
Date: 29 Jul 92 08:17:31 GMT
Organization: Taligent
In article <kaas-280792151810@jojo.cc.ruu.nl>, kaas@cc.ruu.nl (Dick Kaas)
writes:
>
> I'm planning to write a TCL pane for a menu-bar.
>
> Is there a simple way to implement a menubar into dialogs (like WP and
> superboomerang) without having to write a complete menu package by
> yourself?
>
> I have looked at the low memory globals, such as MenuBarHook etc. None of
> these seem useful.
>
I did one of these. I wouldn't consider the approach I took to be "simple."
Although I wrote the bulk of it in a couple of nights, they were long nights. I
had to re-implement and wrap up a lot of stuff. My first attempt that tried
setting the origin of the window manager port at strategic times didn't work
because of a bug in System 7.0's background saving and restoring routines.
I did it as a control to make it easy for others to use. It's included below.
How to use: create a control item in your DITL, and specify the CDEF shown
below. When the user clicks on the item, the dialog manager will call
TrackControl. If you are writing a TCL pane, then call TrackControl yourself.
The control will track the menus and leave the chosen item in contrlValue, so
all you have to do is call GetCtlValue to get the chosen menu item.
If you want to manipulate the menubar, use one of the macros starting with a "Z"
included below. Those macros will call the CDEF directly with a custom message
number. Please note that for the CallIt macro to work, the CDEF must be marked
as locked. If you don't want to lock your CDEF, then you'll need a more
elaborate way to call the CDEF than just dereferencing the handle and jumping.
As an example of what you might need, I've included a commented-out function at
the end of this posting that calls the standard MBDF directly.
A note: pay no attention to the UseGlobals and DoneWithGlobals stuff. That's for
an MPW package that allows globals in standalone code. If you are using THINK C,
don't worry about it. If you are using MPW, use the techniques shown in Technote
#256.
(BTW: as you'll see below, MenubarHook _was_ useful!)
As a final note, I found it useful to write a wrapper for the standard MDEF.
Because the below CDEF essentially works by using popup menus, you need to have
fine control over where the popup menus show up. The standard MBDF will try to
position popup menus so that as much of them will appear on the screen as
possible. However, we don't want that with our menubar CDEF; we want to the top
of the menu to be right below the menubar. Therefore, I wrap up the standard
MDEF with one of my own that first calls the standard MDEF, and then checks to
see if the message handled was mPopUpMsg. If so, the top of the menu is adjusted
by executing "menuRect->top = *itemID;".
Sorry for the lack of any comments in the source code...
- -------------
MenubarCDEF.h
- -------------
#ifndef THINK_C
#include <Controls.h>
#endif
#define kStayPutMDEF 90
#define clearMenuBar 128
#define deleteMenu 129 // param = ID of menu to remove
#define drawMenuBar 130
#define flashMenuBar 131 // param = ID of menu to flash
#define getMenuBar 132 // result = handle to custom data
#define getMHandle 133 // param = menu ID, result = menuHandle
#define hiliteMenu 134 // param = ID of menu to hilite
#define insertMenu 135 // param = menuHandle, varCode = before menu ID
#define menuKey 136 // param = char, result = same as MenuKey
#define menuSelect 137 // param = startPt, result = same as MenuSelect
#define setMenuBar 138 // param = result from getMenuBar
typedef pascal long (*CDEFProc)(short varCode, ControlHandle theControl,
short msg, long param);
#define CallIt(ctl) ((CDEFProc) *((**ctl).contrlDefProc))
#define ZClearMenuBar(ctl) CallIt(ctl)(0, ctl, clearMenuBar, 0)
#define ZDeleteMenu(ctl, menuID) CallIt(ctl)(0, ctl, deleteMenu, menuID)
#define ZDrawMenuBar(ctl) CallIt(ctl)(0, ctl, drawMenuBar, 0)
#define ZFlashMenuBar(ctl, menuID) CallIt(ctl)(0, ctl, flashMenuBar, menuID)
#define ZGetMenuBar(ctl) (Handle) CallIt(ctl)(0, ctl, getMenuBar, 0)
#define ZGetMHandle(ctl, menuID) (MenuHandle) CallIt(ctl)(0, ctl, getMHandle,
menuID)
#define ZHiliteMenu(ctl, menuID) CallIt(ctl)(0, ctl, hiliteMenu, 0)
#define ZInsertMenu(ctl, mh, id) CallIt(ctl)(id, ctl, insertMenu, mh)
#define ZMenuKey(ctl, key) CallIt(ctl)(0, ctl, menuKey, key)
#define ZMenuSelect(ctl, startPt) CallIt(ctl)(0, ctl, menuSelect, startPt)
#define ZSetMenuBar(ctl, mbar) CallIt(ctl)(0, ctl, setMenuBar, mbar)
- -------------
MenubarCDEF.c
- -------------
/*
To do:
% Support hierarchicals
% Support color
*/
#include "MetaGlobal.h"
#include "MenubarCDEF.h"
#ifdef THINK_C
#include <SetUpA4.h>
Ptr GetA0(void) = { 0x2008 };
#else
#include <Types.h>
#include <Memory.h>
#include <Menus.h>
#include <OSEvents.h> // For EvQPtr
#include <Resources.h> // For GetResource
#include <Script.h> // For GetMBarHeight
#include <ToolUtils.h> // For HiWord, LoWord
#include <Windows.h> // we return inMenubar as our part
#include "SAGlobals.h"
#define MenuHook (*(ProcPtr*) 0xA30)
#define MenuList (*(Handle*) 0xA1C)
#endif
#define NIL NULL
#define kTopMargin 1
#define kBottomMargin 1
#define kTextMargin 8
typedef struct {
MenuHandle menu;
short menuLeft;
} MenuRec, *MenuRecPtr;
typedef struct {
MenuHandle menu;
short reserved;
} HMenuRec, *HMenuRecPtr;
typedef struct {
short lastMenu;
short lastRight;
short mbResID;
MenuRec menus[1];
// short lastHMenu;
// PixMapHandle menuTitleSave;
// MenuRec hmenus[1];
} MenuBar, *MenuBarPtr, **MenuBarHdl;
ProcPtr gOldMenuHook;
ControlHandle gControl;
MenuBarHdl gMenuList;
short gTheMenu; // _Index_ of currently hilighted menu
short gNormalHeight;
FontInfo gFontInfo;
short gBaseline;
pascal long main(short varCode, ControlHandle theControl, short msg, long
param);
void DrawMyControl(short part);
short TestMyControl(Point location);
void InitMyControl(void);
void DisposeMyControl(void);
void DoClearMenuBar(void);
void DoDeleteMenu(short menuID);
void DoDrawMenuBar(void);
void DoFlashMenuBar(short menuID);
MenuBarHdl DoGetMenuBar(void);
MenuHandle DoGetMHandle(short menuID);
void DoHiliteMenu(short menuID);
void DoInsertMenu(MenuHandle menu, short before);
long DoMenuKey(char theKey);
long DoMenuSelect(Point startPt);
void DoSetMenuBar(MenuBarHdl menuBar);
void DrawMenuTitle(short menuIndex);
short FindHitMenu(Point location); // returns menuIndex (or -1)
short GetFreeHMenuID(void);
Rect GetHitRect(short menuIndex);
Rect GetInvertRect(short menuIndex);
short GetMenuCount(void);
MenuHandle GetNthMenu(short index);
Point GetTitleLocation(short menuIndex);
short IDToIndex(short);
short IndexToID(short);
void MyMenuHook(void);
void SwapMenuBars(void);
//--------------------------------------------------------------------------------
pascal long main(short varCode, ControlHandle theControl, short msg, long param)
{
long result;
Ptr oldA5;
char oldState;
Handle ourHandle;
Ptr ourPtr;
ourPtr = GetA0();
#ifdef THINK_C
RememberA0();
SetUpA4();
#else
oldA5 = UseGlobals();
#endif
ourHandle = RecoverHandle(ourPtr);
oldState = HGetState(ourHandle);
HLock(ourHandle);
result = 0;
gControl = theControl;
GetFontInfo(&gFontInfo);
gBaseline = kTopMargin + gFontInfo.leading + gFontInfo.ascent;
if (msg < 128) {
switch (msg) {
case drawCntl:
DrawMyControl((short) param);
break;
case testCntl:
result = TestMyControl(*(Point*) ¶m);
break;
case initCntl:
InitMyControl();
break;
case dispCntl:
DisposeMyControl();
break;
case calcCntlRgn:
case calcThumbRgn:
RectRgn((RgnHandle) param, &(**gControl).contrlRect);
result = 1;
break;
}
} else {
switch (msg) {
case clearMenuBar:
DoClearMenuBar();
break;
case deleteMenu:
DoDeleteMenu((short) param);
break;
case drawMenuBar:
DoDrawMenuBar();
break;
case flashMenuBar:
DoFlashMenuBar((short) param);
break;
case getMenuBar:
result = (long) DoGetMenuBar();
break;
case getMHandle:
result = (long) DoGetMHandle((short) param);
break;
case hiliteMenu:
DoHiliteMenu((short) param);
break;
case insertMenu:
DoInsertMenu((MenuHandle) param, varCode);
break;
case menuKey:
result = DoMenuKey((char) param);
break;
case menuSelect:
result = DoMenuSelect(*(Point*) ¶m);
break;
case setMenuBar:
DoSetMenuBar((MenuBarHdl) param);
break;
}
}
#ifdef THINK_C
RestoreA4();
#else
DoneWithGlobals(oldA5);
#endif
HSetState(ourHandle, oldState);
return result;
}
//--------------------------------------------------------------------------------
void DrawMyControl(short part)
{
#pragma unused (part)
if ((**gControl).contrlVis != false) {
DoDrawMenuBar();
}
}
//--------------------------------------------------------------------------------
short TestMyControl(Point location)
{
short hitPart;
hitPart = 0;
if (FindHitMenu(location) >= 0) {
hitPart = inMenuBar;
if (Button()) {
DoMenuSelect(location);
if ((**gControl).contrlValue == 0) {
hitPart = 0;
}
}
}
return hitPart;
}
//--------------------------------------------------------------------------------
void InitMyControl()
{
Handle menuBar;
gOldMenuHook = NIL;
gMenuList = NIL;
gTheMenu = -1;
gNormalHeight = GetMBarHeight();
(**gControl).contrlRect.bottom = (**gControl).contrlRect.top + gBaseline
+ gFontInfo.descent + gFontInfo.leading + kBottomMargin;
GetMBarHeight() = 0;
menuBar = GetNewMBar((**gControl).contrlMin);
if (menuBar != NIL) {
gMenuList = (MenuBarHdl) menuBar;
} else {
menuBar = GetMenuBar();
ClearMenuBar();
gMenuList = (MenuBarHdl) GetMenuBar();
SetMenuBar(menuBar);
DisposeHandle(menuBar);
}
GetMBarHeight() = gNormalHeight;
}
//--------------------------------------------------------------------------------
void DisposeMyControl()
{
DisposeHandle((Handle) gMenuList);
}
//--------------------------------------------------------------------------------
void DoClearMenuBar()
{
SwapMenuBars();
ClearMenuBar();
SwapMenuBars();
}
//--------------------------------------------------------------------------------
void DoDeleteMenu(short menuID)
{
if (IndexToID(gTheMenu) == menuID)
gTheMenu = -1;
SwapMenuBars();
DeleteMenu(menuID);
SwapMenuBars();
}
//--------------------------------------------------------------------------------
void DoDrawMenuBar()
{
Rect frame;
short loop;
PenNormal();
frame = (**gControl).contrlRect;
FrameRect(&frame);
gTheMenu = -1;
for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
DrawMenuTitle(loop);
}
}
//--------------------------------------------------------------------------------
void DoFlashMenuBar(short menuID)
{
Rect bounds;
if (menuID != 0)
DoHiliteMenu(menuID);
else {
bounds = (**gControl).contrlRect;
InsetRect(&bounds, 1, 1);
InvertRect(&bounds);
}
}
//--------------------------------------------------------------------------------
MenuBarHdl DoGetMenuBar()
{
return gMenuList;
}
//--------------------------------------------------------------------------------
MenuHandle DoGetMHandle(short menuID)
{
short menuIndex;
menuIndex = IDToIndex(menuID);
if (menuIndex >= 0)
return GetNthMenu(menuIndex);
else
return NIL;
}
//--------------------------------------------------------------------------------
void DoHiliteMenu(short menuID)
{
short menuIndex;
Rect invertRect;
menuIndex = IDToIndex(menuID);
if (menuIndex != gTheMenu) {
if (menuIndex >= 0) {
invertRect = GetInvertRect(menuIndex);
InvertRect(&invertRect);
}
gTheMenu = menuIndex;
}
}
//--------------------------------------------------------------------------------
void DoInsertMenu(MenuHandle menu, short before)
{
SwapMenuBars();
InsertMenu(menu, before);
SwapMenuBars();
}
//--------------------------------------------------------------------------------
long DoMenuKey(char theKey)
{
char upperKey[2];
short loop;
MenuHandle menu;
short mItems;
short menuItem;
short key;
upperKey[0] = 1;
upperKey[1] = theKey;
UprString((StringPtr) &upperKey, true);
for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
menu = GetNthMenu(loop);
mItems = CountMItems(menu);
for (menuItem = 1; menuItem <= mItems; menuItem++) {
if (menuItem > 31 || (((**menu).enableFlags & (1 << menuItem)) != 0)) {
GetItemCmd(menu, menuItem, &key);
if (key == upperKey[1]) {
return ((long) (**menu).menuID << 16) + menuItem;
}
}
}
}
return 0;
}
//--------------------------------------------------------------------------------
long DoMenuSelect(Point startPt)
{
#pragma unused (startPt)
Point currentLocation;
short oldMenuIndex;
short newMenuIndex;
Rect invertRect;
Point where;
MenuHandle menu;
long menuAndItem;
short oldMenuID;
Handle myMDEF;
menuAndItem = 0;
while (Button()) {
GetMouse(¤tLocation);
oldMenuIndex = gTheMenu;
newMenuIndex = FindHitMenu(currentLocation);
if (oldMenuIndex != newMenuIndex) {
gTheMenu = newMenuIndex;
DrawMenuTitle(oldMenuIndex);
if (newMenuIndex >= 0) {
DrawMenuTitle(newMenuIndex);
invertRect = GetInvertRect(newMenuIndex);
where.v = invertRect.bottom + 1;
where.h = invertRect.left + 1;
LocalToGlobal(&where);
gOldMenuHook = MenuHook;
MenuHook = (ProcPtr) MyMenuHook;
menu = GetNthMenu(newMenuIndex);
oldMenuID = (**menu).menuID;
(**menu).menuID = GetFreeHMenuID();
myMDEF = GetResource('MDEF', kStayPutMDEF);
if (myMDEF != NIL) {
(**(StdHeaderHdl) myMDEF).refCon = (long) (**menu).menuProc;
(**menu).menuProc = myMDEF;
}
InsertMenu(menu, hierMenu);
menuAndItem = PopUpMenuSelect(menu, where.v, where.h, 1);
DeleteMenu((**menu).menuID);
(**menu).menuID = oldMenuID;
if (myMDEF != NIL) {
(**menu).menuProc = (Handle) (**(StdHeaderHdl) myMDEF).refCon;
(**(StdHeaderHdl) myMDEF).refCon = (long) NIL;
}
MenuHook = gOldMenuHook;
if (HiWord(menuAndItem) != 0)
menuAndItem = ((long) oldMenuID << 16) + (short) menuAndItem;
(**gControl).contrlValue = HiWord(menuAndItem);
(**gControl).contrlMax = LoWord(menuAndItem);
}
}
}
if (gTheMenu != -1) {
oldMenuIndex = gTheMenu;
gTheMenu = -1;
DrawMenuTitle(oldMenuIndex);
}
return menuAndItem;
}
//--------------------------------------------------------------------------------
void DoSetMenuBar(MenuBarHdl menuBar)
{
DisposeHandle((Handle) gMenuList);
gMenuList = menuBar;
DoDrawMenuBar();
}
//--------------------------------------------------------------------------------
void DrawMenuTitle(short menuIndex)
{
Rect invertRect;
Point titleLocation;
MenuHandle menu;
if ((menuIndex >= 0) && (menuIndex < GetMenuCount())) {
invertRect = GetInvertRect(menuIndex);
EraseRect(&invertRect);
menu = GetNthMenu(menuIndex);
if ((((**menu).enableFlags & 1) == 0) || ((**gControl).contrlHilite == 255))
TextMode(grayishTextOr);
else
TextMode(srcOr);
titleLocation = GetTitleLocation(menuIndex);
MoveTo(titleLocation.h, titleLocation.v);
HLock((Handle) menu);
DrawString((**menu).menuData);
HUnlock((Handle) menu);
if (gTheMenu == menuIndex)
InvertRect(&invertRect);
}
}
//--------------------------------------------------------------------------------
short FindHitMenu(Point location)
{
short loop;
Rect hitRect;
for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
hitRect = GetHitRect(loop);
if (PtInRect(location, &hitRect)) {
break;
}
}
return loop; // returns -1 if no hit
}
//--------------------------------------------------------------------------------
short GetFreeHMenuID(void)
{
short index;
for (index = 235-20; index > 0; index--) {
if (GetMHandle(index) == NIL)
return index;
}
return -1;
}
//--------------------------------------------------------------------------------
Rect GetHitRect(short menuIndex)
{
Rect bounds;
RectPtr rectPtr;
MenuBarPtr menuBarPtr;
rectPtr = &(**gControl).contrlRect;
menuBarPtr = *gMenuList;
bounds.top = rectPtr->top + 1;
bounds.bottom = rectPtr->bottom - 1;
bounds.left = rectPtr->left + menuBarPtr->menus[menuIndex].menuLeft;
menuIndex++;
bounds.right = rectPtr->left + ((menuIndex < GetMenuCount())
? menuBarPtr->menus[menuIndex].menuLeft
: menuBarPtr->lastRight);
return bounds;
}
//--------------------------------------------------------------------------------
Rect GetInvertRect(short menuIndex)
{
Rect bounds;
bounds = GetHitRect(menuIndex);
bounds.left--;
bounds.right += 4;
return bounds;
}
//--------------------------------------------------------------------------------
short GetMenuCount()
{
return (**gMenuList).lastMenu / (short) sizeof(MenuRec);
}
//--------------------------------------------------------------------------------
MenuHandle GetNthMenu(short index)
{
return (**gMenuList).menus[index].menu;
}
//--------------------------------------------------------------------------------
Point GetTitleLocation(short menuIndex)
{
Point result;
result.h = (**gMenuList).menus[menuIndex].menuLeft + kTextMargin;
result.v = (**gControl).contrlRect.top + gBaseline;
return result;
}
//--------------------------------------------------------------------------------
short IDToIndex(short menuID)
{
short loop;
for (loop = GetMenuCount() - 1; loop >= 0; loop--) {
if ((**GetNthMenu(loop)).menuID == menuID)
break;
}
return loop;
}
//--------------------------------------------------------------------------------
short IndexToID(short menuIndex)
{
if ((menuIndex >= 0) && (menuIndex < GetMenuCount()))
return (**GetNthMenu(menuIndex)).menuID;
else
return 0;
}
//--------------------------------------------------------------------------------
void MyMenuHook()
{
typedef void (*MenuHookProc)(void);
GrafPtr oldPort;
Point mouseLocation;
short hitMenu;
Ptr oldA5;
#ifdef THINK_C
SetUpA4();
#else
oldA5 = UseGlobals();
#endif
if (gOldMenuHook != NIL)
((MenuHookProc) gOldMenuHook)();
GetPort(&oldPort);
SetPort((**gControl).contrlOwner);
GetMouse(&mouseLocation);
hitMenu = FindHitMenu(mouseLocation);
if ((hitMenu >= 0) && (hitMenu != gTheMenu)) {
PostEvent(mouseUp, 0);
}
SetPort(oldPort);
#ifdef THINK_C
RestoreA4();
#else
DoneWithGlobals(oldA5);
#endif
}
//--------------------------------------------------------------------------------
void SwapMenuBars()
{
MenuBarHdl oldMenuBar;
oldMenuBar = (MenuBarHdl) MenuList;
MenuList = (Handle) gMenuList;
gMenuList = oldMenuBar;
}
#if 0
void CalcMenuPositions(short index);
long CallMBDF(short message, short param1, long param2);
//--------------------------------------------------------------------------------
void CalcMenuPositions(short index)
{
SwapMenuBars();
CallMBDF(2, 0, (index+1) * 6);
SwapMenuBars();
}
//--------------------------------------------------------------------------------
long CallMBDF(short message, short param1, long param2)
{
typedef pascal long (*MBDFProc)(short selector, short message, short
parameter1,
long parameter2);
Handle mbdfHandle;
short mbResID;
short resID;
short mbVariant;
char oldState;
long result;
mbResID = (**gMenuList).mbResID;
resID = mbResID >> 3;
mbVariant = mbResID & 0x0007;
mbdfHandle = GetResource('MBDF', resID);
if (mbdfHandle != NIL) {
if (*mbdfHandle == NIL) {
LoadResource(mbdfHandle);
}
if (*mbdfHandle != NIL) {
oldState = HGetState(mbdfHandle);
HLock(mbdfHandle);
result = ((MBDFProc) *mbdfHandle)(mbVariant, message, param1, param2);
HSetState(mbdfHandle, oldState);
return result;
}
}
SysError(dsMBarNFnd);
}
#endif
- --
Keith Rollin
Phantom Programmer
Taligent, Inc.
---------------------------
End of C.S.M.P. Digest
**********************