mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-08-30 14:29:18 +00:00
1685 lines
54 KiB
C
1685 lines
54 KiB
C
/*
|
||
File: PopupCDEF.c
|
||
|
||
Contains: Source code for Popup Menu CDEF
|
||
|
||
Written by: Byron Han
|
||
|
||
Copyright: © 1987-1992 by Apple Computer, Inc., all rights reserved.
|
||
|
||
Change History (most recent first):
|
||
|
||
<SM4> 11/19/92 RB Set ROMMapInsert to mapTRue to look for resources in ROM first.
|
||
<43> 11/13/92 JDR Updated QuickDraw.h to not use the dangerous pattern type.
|
||
<42> 11/7/92 JDR Removed the PopupPrivateData record, which is now a public
|
||
structure. Change occurances of the usage too,
|
||
<41> 11/3/92 DTY Strip out unnecessary includes.
|
||
<40> 5/21/92 gbm #1030284,<dty>: Stop leaving the menu handle in the menu list
|
||
all the time. This causes conflicts if two popups have the same
|
||
ID.
|
||
<39> 5/10/92 BH some applications stuff the window manager and color window
|
||
manager ports with text size 12 (font is still set to 0).
|
||
normally, these values are 0 and 0 - this causes the menu
|
||
manager to barf since it tries to draw using the font and size
|
||
of the window mgr ports. if a non zero value is specified in
|
||
these ports, the appropriate values in sysFontFam and
|
||
sysFontSize are not used (which is where we stuff the
|
||
appropriate owning window's font and size information.
|
||
|
||
this is the infamous geneva 12 popup problem.
|
||
|
||
and I solved it. (Byronus Maximus)
|
||
|
||
we use the routines SaveAndResetWMPorts() and RestoreWMPorts()
|
||
[see mods in PopupCdef.h]
|
||
|
||
All under the TheFuture conditional
|
||
• REALPOPUP() when saving port state, also save and reset the
|
||
window manager port and color port font and size to 0, 0
|
||
• DoDraw() fix bug where triangles for items after the 31st in
|
||
the menu would be dimmed
|
||
• DoUseWFont() fix bug where if the owning window font was the
|
||
system font we would not set the size for the control properly.
|
||
• DoUseWFont() always invalidate the font manager cache (was
|
||
checking to see if it was 0, 0 but it may be different because
|
||
of window manager port/color port may have been set to 0, C
|
||
instead) [fontfam, fontsize]
|
||
• SaveAndResetWMPorts() added
|
||
• RestoreWMPorts() added
|
||
<38> 2/19/92 BH fixed comments for <37>
|
||
<37> 1/24/92 BH Fixed problem with triangles for items after item 31 were always
|
||
dimmed. Also fixed the infamous 12 point geneva popup (now
|
||
always invalidate font mgr cache when changing system font and
|
||
size)
|
||
<36> 8/22/91 KSM PKE,#85693-Bruges: Don't use hard-coded bullet char for menu.
|
||
Don't use sysFontFam=0, get smSysScript.
|
||
<35> 4/5/91 JDR dba, DTY, kaz, BRC#86187: If the menu has been disposed and then
|
||
re-added to the menu list, call GetMHandle to refresh the menu
|
||
handle in the control's data storage.
|
||
<34> 4/3/91 DTY ngk, kaz, #SIAC: The preflighting calls _HNoPurge on the menu
|
||
handle for all messages except for initCntlMsg. In low memory
|
||
conditions, the menu can get purged inside of CalcAndDrawMenu
|
||
which is called via ResizeControl which in turn is called during
|
||
the initCntlMsg. Add lines to _HNoPurge the menu for the
|
||
initCtlMsg case also.
|
||
<33> 3/27/91 kaz jng, AEK-038: Fix last fix — dispCntl will dispose what dataP
|
||
points to, so dataP->theMenu is an unknown. Instead we check the
|
||
menuList w/ _GetMHandle to see if the menu is still around &
|
||
then restore the state.
|
||
<32> 3/27/91 DFH JWM,WS#DFH-910320a: Fixed so that we don't try to HSetState the
|
||
menu handle if the menu has been disposed.
|
||
<31> 3/20/91 VL DFH, WS#DFH-910320a: theMenu is made non-purgeable during the
|
||
CDEF routines. This fixes many problems with PopupCDEF during
|
||
low-memory situations.
|
||
<30> 3/15/91 kaz jng, b6-ngk-002: Fixing bug in _TestControl — removing -2 fudge
|
||
factor from rectangle test
|
||
<29> 2/7/91 kaz BBH, #81082: ResizeControl() - if the popup gets too big and
|
||
only the triangle is showing (Views CDEV - size menu), we will
|
||
draw the frame at the contrlRect boundary.
|
||
<28> 2/4/91 kaz jng, #74915: DrawTriangle() will dim the triangle if the control
|
||
is dimmed, the whole menu is dimmed, or the menuItem is dimmed.
|
||
<27> 1/23/91 kaz <jng>,#81486,#81487: Fix ResEdit crash by exiting from the CDEF
|
||
if the MENU is really gone. If the menu is not preloaded, use
|
||
the contrlMin field as a 'MENU' resID and get the new menuID
|
||
after GetMenu(resID).
|
||
<26> 1/16/91 kaz Fixing Script Mgr bug: DoUseWFont() will not stuff SysFontFam if
|
||
txFont is systemFont or applFont.
|
||
<25> 1/14/91 kaz <jng> Fixing DrawTitle for B&W classic machines.
|
||
<24> 12/13/90 kaz Copying the pnVis field if we have to create a color port. <jng>
|
||
<23> 12/7/90 kaz Hierarchial Menu support: added popupResult field to private
|
||
record to save the last value of PopupMenuSelect. Won't check
|
||
hierarchial items, and draws the unpopped item without hier
|
||
arrow. Added FindHMenu() to return the parent if a hier menu
|
||
item is tracked; Fixed bug in right just of title: not sign
|
||
extending. <jng>
|
||
<22> 11/12/90 kaz Added StandardFile support: draws the box pinned to the
|
||
contrlRect if needed; Shrinks the box width to be the current
|
||
itemwidth. Smarter drawing: only redraws the control if heights
|
||
or widths have changed, the control has moved, etc. Some
|
||
cleanup. <jng>
|
||
<21> 10/30/90 kaz Triangle is now drawn using _FillPoly instead of _DrawPicture;
|
||
Will only dehilite the title if the user tracks the same value;
|
||
Removed PaintMyGrayRect(). <BBH>
|
||
<20> 9/22/90 gbm (with kaz) Changing DoDraw to properly dispose of PixPats (by
|
||
calling PenNormal!) instead of leaving them around in the app
|
||
heap
|
||
<19> 9/16/90 PWD Grays the title on classic machines properly. <kaz>
|
||
<18> 9/15/90 PWD Reimplemented AddResMenu variant; popupUseCQD is now reserved.
|
||
<kaz> <crz>
|
||
<17> 9/14/90 kaz Always tries to use CQD; Clips properly, even if we roll our own
|
||
color port; Erase control if the new menu item height < old (for
|
||
icons).
|
||
<16> 9/13/90 kaz DoDraw(): no longer calls _DisposPixPat after _PenPixPat (let QD
|
||
dispose it when we reset the PenState); calls _PenPixPat after
|
||
sending drawItemMsg in case MDEF has changed it.
|
||
<15> 9/11/90 kaz If the menu is cleared after InitMsg, we reload it and delete it
|
||
at the end.
|
||
<14> 9/5/90 kaz Properly bracketing calls for BeginGray/EndGray
|
||
<13> 9/4/90 kaz Changing gray text _PenMode to _TextMode.
|
||
<12> 8/5/90 kaz Added new graying algorithm; Spun out DrawTitle().
|
||
<11> 8/2/90 kaz Fixed shadow dimensions. Moved triangle in a little, and center
|
||
it for popups with not enough space. Only erases the old
|
||
location if the control has moved. Only redraws the title when
|
||
mouse hit. Fixed right justified bugs. Temporary gray algorithm.
|
||
More code shrinkage.
|
||
<10> 7/10/90 dba get rid of C warnings
|
||
<9> 6/12/90 kaz Mega changes to decrease code size. JustLeft is now the default.
|
||
Does not grow the contrlRect. Clips to conrtlRect. Draws the
|
||
popup nicely if the menu is empty. ItemMark will be a checkmark
|
||
if the useWFont is a SystemFont.
|
||
<8> 6/4/90 kaz Temporarily removed the min/max FixedWidth stuff as Finder uses
|
||
the refCon. Resort to old fixedWidth. Locks theData before
|
||
calling ResizeControl() from DoInit().
|
||
<7> 6/4/90 kaz Control is now vertically centered; Will not normally change the
|
||
control rectangle, except to grow it. Will center the control if
|
||
titleWidth == 0 and titleJust = center (for Standard File).
|
||
FixedWidth will calc a minimum width from the refCon, and
|
||
maxWidth from the controlRect. AddResMenu temporarily #ifdef'ed.
|
||
<6> 5/31/90 kaz popupFixedWidth expands the menu in DoTrack() if the menuWidth <
|
||
boxWidth.
|
||
<5> 5/29/90 kaz Title textFace is set to grafPort's for useWFont; Removed SKANKY
|
||
#ifdef; Tweaked traingle drawing.
|
||
<4> 3/20/90 EMT Changed CQDLives() function to HaveCQD() macro used by
|
||
Notification and Layer managers (to save code).
|
||
<3> 3/16/90 BBH removed code that checked if mdefproc bailed on the
|
||
mCalcItemMsg; also stopped diddling with the wmgrport and
|
||
wmgrcport's font and fontsize since we are already diddling with
|
||
sysFontFam and sysFontSize
|
||
<2> 3/5/90 BBH fix problem with drawing the popup label in right justification
|
||
mode
|
||
<1> 3/5/90 BBH first checked in to BBS
|
||
|
||
To Do:
|
||
• Add our own truncString for < System 7
|
||
|
||
*/
|
||
|
||
// Pre-BBS Modification History
|
||
// WHEN WHO WHAT
|
||
// 2/6/90 BBH Changed drawing of triangle via polygon to use a pict
|
||
// renamed hasColor to hasCQD in myData data structure
|
||
// renamed color to useCQD in myData data structure
|
||
//
|
||
// 12/7/89 BBH Fixed calculation of size for reduced icons
|
||
// Now tries to use mdef to calculate item size and
|
||
// standard message for drawing an item.
|
||
//
|
||
// 12/6/89 BBH Finished port to C
|
||
// Better accuray in redraw, smaller code
|
||
// 12/5/89 BBH Started
|
||
//////////Ported to C
|
||
/* old revision notes
|
||
12/4/89 BBH Use two custom MDEF's
|
||
One that calls the mdef and widens the width
|
||
Other really isn't an MDEF - just handles mDrawMsg
|
||
differently (draws item in whichItem in the
|
||
rectangle provided) - but handles icons,
|
||
sicns, and reduced icons
|
||
Added triangle support
|
||
Consolidation of calculation routines
|
||
11/30/89 BBH Trying to get it up
|
||
10/4/89 BBH Minimum safe title width is 1 pixel. We now check.
|
||
10/3/89 BBH If menu preexists in the menu list, we do not a GetMenu, InsertMenu
|
||
upon creation, and a DeleteMenu, DisposMenu upon disposal
|
||
(SAFEMENUS set to TRUE for this feature)
|
||
Fixed bug in TruncateString if space given is insufficient for even
|
||
an ellipsis caused infinite loop in truncation.
|
||
TruncateString routine has been modified to return empty string
|
||
if there is insuffient space for 1 character (can be multibyte)
|
||
plus the ellipsis.
|
||
7/25/89 BBH Always recalculate the height regardless of popupFixedWidth bit.
|
||
6/19/89 BBH Added checks for the popup menu trap and the script manager trap.
|
||
If the popup menu trap is NOT available, then draw
|
||
the control as if disabled and do not perform tracking.
|
||
If the script manager trap is NOT available, then truncate the
|
||
string one byte at a time (do not test for multibute chars)
|
||
6/18/89 BBH Instead of setting clip to the control rectangle, set to the intersection
|
||
of the existing clipRgn and the control rectangle.
|
||
Removed scripts field from private data structure. Was not being used.
|
||
Reformatted modification history. Added more generous comments.
|
||
Also use CTBUtils.p pascal interface file for the variant code
|
||
constants.
|
||
Removed some dead code. Did a personal review of the code.
|
||
6/16/89 BBH TruncateString is now script manager compatible - uses CharByte.
|
||
Also, when drawing the control, we clip to the control rectangle.
|
||
This prevents a problem with descenders in geneva 9pt, shadow being
|
||
drawing outside of the control rectangle.
|
||
6/14/89 BBH Added support for calcCntlRgn and calcThumbRgn messages for System 7.0
|
||
compatibility. See TN 212
|
||
6/8/89 BBH Fixed bug that Rich Hoiberg was having that if you have a control
|
||
attached to a dialog item list and after creating the dialog
|
||
(and hence creating the control) you change the dialog font and
|
||
dialog size, the height of the popup is not recalculated properly.
|
||
fixed by calling GetFontInfo in DoResize and manually adjusting
|
||
the control height if the variation code for fixed size is not being
|
||
used.
|
||
Removed info: FontInfo and height: INTEGER from myData data structure
|
||
6/7/89 BBH Changed EraseRect of the control rectangle to a EraseControl call
|
||
which will only erase the parts of the control that get drawn
|
||
which means if the window is filled with a pattern, no annoying
|
||
whitespace gets left behind.
|
||
6/4/89 BBH PreflightFont is called after resetting the window manager ports
|
||
in DoResize.
|
||
5/31/89 BBH popup value has the justification stored as a signed Byte
|
||
in the low byte and stores the popup title style in
|
||
the high byte if the high bit is clear
|
||
Defined new constants in CTBUtils.r, .p, and .h
|
||
If high bit of the popup value is set, ignore style (this is for
|
||
backwards compatibility with old CNTL templates which use -1 for
|
||
the popup title justification)
|
||
5/3/89 BBH Changed HLock and HUnlock of the control handle to HGetState,
|
||
HLock, HSetState
|
||
4/26/89 BBH Changed all BitAnd's to BANDs
|
||
Changed drawing to not subtract 3. This fixes shifting of quiescent and
|
||
active menu items with system 6.0.4
|
||
3/22/89 BBH use checkmark if using system font
|
||
use • if using window font instead of checkMark
|
||
we now call preflightFont to load in font info if using window font
|
||
prior to calling CalcMenuSize in the DoResize routine.
|
||
Also indentation when drawing popup box is using the max char width
|
||
of the font minus two.
|
||
3/21/89 kaz in DoTrack() check to see if variant is UseWFont
|
||
then save the old WMgrPort text info, set it to the
|
||
current window text info, then reset it. This
|
||
should paint the menus in the right font/size
|
||
Changed Pop-up to use a bullet mark • for the
|
||
checked menu item instead of a checkmark
|
||
3/14/89 BBH use System Font size 0.
|
||
also added support for variant codes.
|
||
moved refcon/AddResMenu stuff to variant code 4.
|
||
added color quickdraw stuff with support for mctb.
|
||
opens a CGrafPort is necessary.
|
||
added support for sys just of teJustRight to draw
|
||
title to the RIGHT of the pop up box.
|
||
12/23/88 BBH Drawing of the ow done with TextBox. Is using GetSysJust
|
||
Also, instead of using System Font size 12, we get font and
|
||
size information from window manager port.
|
||
The test routine will return 0 or myPartCode which is 1.
|
||
Caveats
|
||
The CDEF installs and deinstalls the menu from the menu list
|
||
when the control is created/destroyed.
|
||
If the menu does not exist, you are at your own risk.
|
||
12/22/88 BBH value is justification of the popup menu title. It is
|
||
reset to min after control creation
|
||
application must reset the value then.
|
||
|
||
9/88 BBH Second major rewrite to add AddResMenu capability
|
||
refCon is NIL - nothing
|
||
refCon is NOT nil - do a AddResMenu(ResType(refcon));
|
||
menuID is MIN
|
||
popuptitlewidth is MAX
|
||
7/88 BBH First major rewrite. Use refCon to specify menuID and popup title
|
||
width. Use flag bit in refCon to determine if application
|
||
is performing InsertMenu/DeleteMenu.
|
||
Refcon values
|
||
HiWord contains ID of menu
|
||
LoWord contains width of popup title
|
||
If the hi bit of the low word of the refcon is set, then the calling
|
||
applciation must install/deinstall the menu from the menu list.
|
||
Rect is rect.
|
||
11/2/87 BBH Second version
|
||
10/20/87 BBH First version
|
||
|
||
Things to be done:
|
||
TruncateString should be internationalized. Test it.
|
||
Why does TrackControl always return non zero even if we track out of the control?
|
||
|
||
Make popup return different part codes
|
||
*/
|
||
|
||
#include <Types.h>
|
||
#include <Controls.h>
|
||
#include <Fonts.h>
|
||
#include <Memory.h>
|
||
#include <Menus.h>
|
||
#include <QuickDraw.h>
|
||
#include <QuickDrawText.h>
|
||
#include <Resources.h>
|
||
#include <Script.h>
|
||
#include <SysEqu.h>
|
||
#include <TextEdit.h>
|
||
#include <ToolUtils.h>
|
||
|
||
#include "PopupCDEF.h"
|
||
|
||
#define HaveCQD() ((*(unsigned short *) ROM85) <= 0x3FFF)
|
||
|
||
|
||
/*************************************************************
|
||
REALPOPUP - DefProc control
|
||
|
||
hControl - the popup
|
||
theVar - CDEF variant
|
||
**************************************************************/
|
||
|
||
pascal long REALPOPUP(short theVar, ControlHandle hControl, short msg, long theParam)
|
||
{
|
||
PenState savedPen;
|
||
TextState savedText,
|
||
myText;
|
||
WMPortState savedWMPortState;
|
||
|
||
GrafPtr savedPort;
|
||
unsigned char savedState;
|
||
long rval = 0; // return value
|
||
GrafPtr owner;
|
||
myDataP dataP; // moved this declaration out from if-statement <31>
|
||
unsigned char menuSavedState; // state for theMenu <31>
|
||
|
||
GetPort(&savedPort); // set to the owner
|
||
owner = (**hControl).contrlOwner;
|
||
SetPort(owner);
|
||
|
||
savedState = HGetState((Handle) hControl);
|
||
HLock((Handle) hControl); // lock the control down
|
||
|
||
/* We need to lock theData 'cuz we use dangling ptrs to save space */
|
||
/* It's NIL at init time, but HLock doesn't care, so we don't either */
|
||
HLock((Handle) (**hControl).contrlData);
|
||
|
||
GetTextState(&savedText);
|
||
GetPenState(&savedPen);
|
||
SaveAndResetWMPorts(&savedWMPortState);
|
||
|
||
PenNormal();
|
||
if ( !(theVar & popupUseWFont) ) {
|
||
myText.theFont = systemFont;
|
||
myText.theSize = 0;
|
||
myText.theFace = 0;
|
||
myText.theMode = srcOr;
|
||
SetTextState(&myText);
|
||
}
|
||
|
||
dataP = *((myDataH) (**hControl).contrlData); // moved this from the if-statement below <31>
|
||
|
||
// if the menu's gone, reload it & mark it for deletion later
|
||
if (msg != initCntl) {
|
||
dataP->public.mHandle = GetMHandle(dataP->public.mID); // <35>
|
||
if (dataP->public.mHandle == nil) {
|
||
dataP->preinstalled = false; // delete at dispose time
|
||
dataP->public.mHandle = GetMenu(dataP->resID);
|
||
if (dataP->public.mHandle == nil)
|
||
goto restoreState; // if it doesn't work, get out
|
||
dataP->public.mID = (**dataP->public.mHandle).menuID;
|
||
InsertMenu(dataP->public.mHandle, hierMenu);
|
||
|
||
menuSavedState = HGetState((Handle) dataP->public.mHandle);
|
||
HNoPurge((Handle) dataP->public.mHandle);
|
||
} else
|
||
dataP->preinstalled = true;
|
||
|
||
// <31> The following segment of code is added to ensure that the menu is not purgeable
|
||
// during the course of PopupCDEF routines.
|
||
|
||
}
|
||
|
||
|
||
switch (msg) {
|
||
case drawCntl:
|
||
if ( (**hControl).contrlVis )
|
||
rval = DoDraw(hControl, theVar, (short) theParam);
|
||
break;
|
||
|
||
case testCntl:
|
||
rval = DoTest(hControl, theParam);
|
||
break;
|
||
|
||
case calcCRgns:
|
||
#ifdef calcCntlRgn
|
||
case calcCntlRgn:
|
||
#endif calcCntlRgn
|
||
#ifdef calcThumbRgn
|
||
case calcThumbRgn:
|
||
#endif calcThumbRgn
|
||
DoCalc(hControl, theVar, &theParam);
|
||
break;
|
||
|
||
case initCntl:
|
||
DoInit(hControl, theVar);
|
||
break;
|
||
|
||
case dispCntl:
|
||
DoDispose(hControl);
|
||
break;
|
||
|
||
case autoTrack:
|
||
rval = DoTrack(hControl, theVar);
|
||
break;
|
||
}
|
||
|
||
// <31> The following line is used to restore the state of public.mHandle so that public.mHandle can
|
||
// become purgeable again. (maybe)
|
||
// we inserted the menu in the list on entry, and now we’re taking it out again
|
||
if ((msg != initCntl) && (msg !=dispCntl)) {
|
||
if (!dataP->preinstalled) {
|
||
DeleteMenu( dataP->public.mID );
|
||
HSetState((Handle)dataP->public.mHandle, menuSavedState );
|
||
}
|
||
}
|
||
|
||
restoreState:
|
||
SetTextState(&savedText);
|
||
SetPenState(&savedPen); // restore control handle
|
||
RestoreWMPorts(&savedWMPortState);
|
||
|
||
HUnlock((Handle) (**hControl).contrlData);
|
||
HSetState((Handle) hControl, savedState);
|
||
|
||
SetPort(savedPort);
|
||
return(rval); // bye bye
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
/*************************************************************
|
||
DoInit - Gets the values from the control record,
|
||
and puts them in our private data struct
|
||
|
||
hControl - the popup
|
||
theVar - CDEF variant
|
||
**************************************************************/
|
||
|
||
void DoInit(ControlHandle hControl, short theVar)
|
||
{
|
||
myDataP dataP;
|
||
ControlPtr controlP;
|
||
myDataH theData;
|
||
MenuHandle hMenu;
|
||
unsigned char menuSavedState; // Save the state of the menu handle <34>
|
||
|
||
controlP = *hControl;
|
||
|
||
theData = (myDataH) NewHandleClear(sizeof(myData));
|
||
controlP->contrlData = (Handle) theData;
|
||
if (theData == nil)
|
||
goto error;
|
||
|
||
HLock((Handle) theData); // will be unlocked in REALPOPUP
|
||
|
||
dataP = *theData; // ptr for smaller code
|
||
|
||
// deal with environment
|
||
dataP->useColor = HaveCQD(); // always try to use CQD
|
||
if (dataP->useColor)
|
||
dataP->makeCPort = ((dataP->useColor) &&
|
||
(!(controlP->contrlOwner->portBits.rowBytes & cGrafSignature)));
|
||
|
||
// deal with creation parameters
|
||
dataP->resID = dataP->public.mID = controlP->contrlMin; // get the menu ID
|
||
|
||
if (controlP->contrlMax > 1)
|
||
dataP->titleWidth = controlP->contrlMax;
|
||
|
||
dataP->titleJust = (char) (controlP->contrlValue & popupTitleJustMask);
|
||
if (!(controlP->contrlValue & popupTitleNoStyle))
|
||
dataP->titleStyle = (Style) ((controlP->contrlValue & popupTitleStyleMask ) >> 8);
|
||
|
||
// Add the grafport's style if useWFont
|
||
if (theVar & popupUseWFont)
|
||
dataP->titleStyle |= controlP->contrlOwner->txFace;
|
||
|
||
// get the menu; if it isn't pre-installed, then we need to build it
|
||
hMenu = GetMHandle(dataP->public.mID);
|
||
dataP->preinstalled = (hMenu != nil);
|
||
if (! dataP->preinstalled) {
|
||
hMenu = GetMenu(dataP->resID);
|
||
if (hMenu == nil)
|
||
goto error;
|
||
menuSavedState = HGetState((Handle) hMenu); // Save the state <34>
|
||
HNoPurge((Handle) hMenu); // Make it non-purgeable <34>
|
||
dataP->public.mID = (**hMenu).menuID;
|
||
InsertMenu(hMenu, hierMenu); // stick it in
|
||
}
|
||
dataP->public.mHandle = hMenu;
|
||
|
||
// Use the refCon as the resource type to add
|
||
if ( (theVar & popupUseAddResMenu) )
|
||
AddResMenu(hMenu, (ResType) controlP->contrlRfCon);
|
||
|
||
// Get the widths for fixedWidth controls. Note that if the refCon = 0, this is
|
||
// the old fixedWidth control setting to maintain compatibility w/ 1.0
|
||
dataP->maxWidth = controlP->contrlRect.right - controlP->contrlRect.left;
|
||
|
||
if (theVar & popupFixedWidth)
|
||
dataP->minWidth = dataP->maxWidth;
|
||
|
||
// set up max/min/val
|
||
controlP->contrlMin = 1;
|
||
controlP->contrlMax = CountMItems(hMenu);
|
||
if (controlP->contrlMax == 0 )
|
||
controlP->contrlMin = 0; // nothing around
|
||
controlP->contrlValue = controlP->contrlMin;
|
||
|
||
dataP->popupResult = (dataP->public.mID << 16) + controlP->contrlValue;
|
||
|
||
dataP->oldContrlRect = controlP->contrlRect;
|
||
dataP->oldMax = controlP->contrlMax;
|
||
dataP->changedVal = true; // forces a draw of the control
|
||
|
||
ResizeControl(hControl, theVar); // calculate dynamic values
|
||
|
||
controlP->contrlAction = (ProcPtr) (-1); // handle own autotrack
|
||
if (!dataP->preinstalled) { // take this back out of the menu list when <gbm>
|
||
DeleteMenu(dataP->public.mID); // we’re done, but only if we put it in there <gbm>
|
||
HSetState((Handle) dataP->public.mHandle, menuSavedState); // Restore the state <34>
|
||
}
|
||
goto exit;
|
||
error: // clean up
|
||
DoDispose(hControl);
|
||
controlP->contrlData = nil; // nil it out please
|
||
|
||
exit:
|
||
;
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
DoDraw - Draws the entire popup control
|
||
|
||
hControl - the popup
|
||
theVar - CDEF variant
|
||
theParam - part code to draw:
|
||
0 => all parts
|
||
myPartCode => control hasn't moved
|
||
129 => control has moved
|
||
returns - 0
|
||
**************************************************************/
|
||
|
||
long DoDraw(ControlHandle hControl, short theVar, short theParam)
|
||
{
|
||
myDataP dataP;
|
||
ControlPtr controlP;
|
||
CGrafPtr myCPort = nil;
|
||
GrafPtr owner; // owner of control
|
||
Rect boxRect,
|
||
theRect;
|
||
RgnHandle savedClip,
|
||
newClip; // for setting clip to control frame
|
||
RGBColor oldCQDFore, // CQD variables
|
||
oldCQDBack;
|
||
Boolean dimmedOut;
|
||
Boolean useColor;
|
||
PixPatHandle myPixPat = nil;
|
||
long oldFlags;
|
||
Boolean majorClean = false;
|
||
short cmdChar = 0,
|
||
markChar = 0;
|
||
|
||
controlP = *hControl;
|
||
dataP = *((myDataH) controlP->contrlData);
|
||
|
||
useColor = dataP->useColor; // local vars for smaller code
|
||
owner = controlP->contrlOwner;
|
||
|
||
// We dim the control if the hilite is set, or the menu is empty
|
||
dimmedOut = ((controlP->contrlHilite == 255) ||
|
||
((**dataP->public.mHandle).menuWidth == 0));
|
||
|
||
// get new menu item height
|
||
SetRect(&theRect, 0, 0, 0, 0);
|
||
CalcAndDrawItem(hControl, theVar, mCalcItemMsg, &theRect); // theRect.top = 0 => ignore it
|
||
GetItemCmd(dataP->public.mHandle,controlP->contrlValue,&cmdChar);
|
||
GetItemMark(dataP->public.mHandle,controlP->contrlValue,&markChar);
|
||
|
||
majorClean = ((theParam == movedPartCode) ||
|
||
(controlP->contrlMax != dataP->oldMax) ||
|
||
(theRect.bottom != dataP->oldHeight) ||
|
||
(cmdChar == 0x001A) ||
|
||
(dataP->oldWidth != (**dataP->public.mHandle).menuWidth) ||
|
||
(! EqualRect(&dataP->oldContrlRect, &controlP->contrlRect)));
|
||
|
||
if (majorClean) {
|
||
dataP->oldMax = controlP->contrlMax;
|
||
dataP->oldHeight = theRect.bottom; // update flags
|
||
dataP->oldWidth = (**dataP->public.mHandle).menuWidth;
|
||
dataP->oldContrlRect = controlP->contrlRect;
|
||
|
||
EraseRect(&dataP->myCtlRect);
|
||
ResizeControl(hControl, theVar); // recalc & erase new loc
|
||
EraseRect(&dataP->myCtlRect);
|
||
}
|
||
|
||
// If the value has changed, we just need to dehilite the title
|
||
if (! dataP->changedVal)
|
||
if (! majorClean)
|
||
if (dataP->titleWidth <= 0)
|
||
goto done;
|
||
|
||
PortNClip:
|
||
if (dataP->makeCPort)
|
||
myCPort = MakeColorPort(owner);
|
||
// save off color quickdraw stuff
|
||
if (useColor) {
|
||
GetForeColor(&oldCQDFore);
|
||
GetBackColor(&oldCQDBack);
|
||
}
|
||
|
||
savedClip = NewRgn();
|
||
newClip = NewRgn();
|
||
GetClip(savedClip);
|
||
RectRgn(newClip, &controlP->contrlRect);
|
||
SectRgn(newClip, savedClip, newClip);
|
||
SetClip(newClip);
|
||
|
||
if (dataP->titleWidth > 0) {
|
||
DrawTitle(controlP, dataP);
|
||
|
||
if (! dataP->changedVal)
|
||
if (! majorClean)
|
||
goto cleanup;
|
||
}
|
||
|
||
// Don't need to redraw the following for hilited state as
|
||
// menu will popup on top and save bits behind
|
||
if ((controlP->contrlHilite == myPartCode) && (! majorClean))
|
||
goto cleanup;
|
||
|
||
// now erase the popup box if CQD to get colors right
|
||
CalcBoxArea(dataP, &boxRect);
|
||
if (useColor) {
|
||
SetColors(dataP->public.mID, controlP->contrlValue, false);
|
||
EraseRect(&boxRect);
|
||
}
|
||
|
||
// Draw the Menu Item
|
||
// If we're dimmed, we trick the Menu Mgr into dimming for us
|
||
// Also, we don't want any check marks, hier arrows drawn for us, so we zap 'em
|
||
CalcMenuArea(dataP, &theRect);
|
||
if (dimmedOut) {
|
||
oldFlags = (**dataP->public.mHandle).enableFlags;
|
||
if (controlP->contrlValue <= 31)
|
||
DisableItem(dataP->public.mHandle, controlP->contrlValue);
|
||
}
|
||
if (cmdChar == 0x001B)
|
||
SetItemCmd(dataP->public.mHandle,controlP->contrlValue,0);
|
||
SetItemMark(dataP->public.mHandle,controlP->contrlValue,0);
|
||
|
||
CalcAndDrawItem(hControl, theVar, mDrawItemMsg, &theRect);
|
||
|
||
// Now put everything back
|
||
SetItemCmd(dataP->public.mHandle,controlP->contrlValue,cmdChar);
|
||
SetItemMark(dataP->public.mHandle,controlP->contrlValue,markChar);
|
||
if (dimmedOut)
|
||
(**dataP->public.mHandle).enableFlags = oldFlags;
|
||
|
||
// Triangle will be dimmed if control is dimmed OR the menu OR current item is dimmed
|
||
// so we reuse oldFlags to see if the menu is dimmed, else if the item is dimmed
|
||
|
||
oldFlags = (**dataP->public.mHandle).enableFlags & 1; // bit 0 -- whole menu is dimmed
|
||
#if CubeE
|
||
if (oldFlags == 1)
|
||
oldFlags = (**dataP->public.mHandle).enableFlags & (1 << controlP->contrlValue);
|
||
#endif
|
||
#if TheFuture
|
||
if (oldFlags == 1) {
|
||
if (controlP->contrlValue <= 31) // <37>
|
||
oldFlags = (**dataP->public.mHandle).enableFlags & (1 << controlP->contrlValue);
|
||
}
|
||
#endif
|
||
DrawTriangle(dataP,(dimmedOut || (oldFlags == 0)));
|
||
|
||
if (useColor)
|
||
SetColors(dataP->public.mID, -1, false); // reset to default colors
|
||
|
||
// set it in case menu mgr changed it
|
||
if (dimmedOut)
|
||
myPixPat = BeginMyGray(dataP);
|
||
|
||
// Frame & Shadow
|
||
FrameRect(&boxRect);
|
||
CalcShadowArea(dataP, &boxRect);
|
||
MoveTo(--boxRect.right, boxRect.top); // move the pen INSIDE the rect
|
||
LineTo(boxRect.right, --boxRect.bottom);
|
||
LineTo(boxRect.left, boxRect.bottom);
|
||
|
||
// Graying over the triangle
|
||
if (dimmedOut)
|
||
if (myPixPat == nil) { // gray the title if no color avail.
|
||
CalcTitleArea(dataP, &theRect);
|
||
PenMode(patBic);
|
||
PaintRect(&theRect);
|
||
}
|
||
|
||
PenNormal();
|
||
if (myPixPat != nil)
|
||
DisposPixPat(myPixPat);
|
||
|
||
cleanup:
|
||
// _SetPenState will be reset it main
|
||
|
||
if (useColor) {
|
||
RGBForeColor(&oldCQDFore);
|
||
RGBBackColor(&oldCQDBack);
|
||
}
|
||
|
||
SetClip(savedClip);
|
||
DisposeRgn(savedClip);
|
||
DisposeRgn(newClip);
|
||
|
||
if (myCPort != nil) {
|
||
CloseCPort(myCPort);
|
||
DisposPtr((Ptr) myCPort);
|
||
SetPort(owner);
|
||
}
|
||
|
||
done:
|
||
dataP->changedVal = true;
|
||
return(0);
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
DoTest - Determines if a point is in my control
|
||
and returns which part.
|
||
|
||
hControl - the popup
|
||
theParam - point location
|
||
|
||
returns - control part code
|
||
**************************************************************/
|
||
|
||
long DoTest(ControlHandle hControl, long theParam)
|
||
{
|
||
myDataP dataP;
|
||
Point thePoint;
|
||
long rval = 0;
|
||
Rect theRect;
|
||
|
||
*((long *) &thePoint) = theParam;
|
||
|
||
dataP = *((myDataH) (**hControl).contrlData);
|
||
|
||
theRect = dataP->myCtlRect;
|
||
|
||
if (PtInRect(thePoint, &theRect))
|
||
if (((**hControl).contrlHilite != 255) &&
|
||
((**dataP->public.mHandle).menuWidth != 0))
|
||
rval = myPartCode;
|
||
|
||
return (rval);
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
DoDispose - Returns the control area as a region
|
||
for Control Mgr calculations
|
||
|
||
hControl - the popup
|
||
**************************************************************/
|
||
|
||
void DoDispose(ControlHandle hControl)
|
||
{
|
||
myDataH theData;
|
||
|
||
theData = (myDataH) (**hControl).contrlData;
|
||
if (theData != nil) {
|
||
if (!(**theData).preinstalled) {
|
||
DeleteMenu( (**theData).public.mID);
|
||
DisposeMenu( (**theData).public.mHandle );
|
||
(**theData).public.mHandle = nil;
|
||
}
|
||
|
||
DisposHandle((Handle) theData);
|
||
(**hControl).contrlData = 0;
|
||
}
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
DoCalc - Returns the control area as a region
|
||
for Control Mgr calculations
|
||
|
||
hControl - the popup
|
||
theVar - CDEF variant
|
||
theParam - a VAR RgnHandle to return
|
||
**************************************************************/
|
||
|
||
void DoCalc(ControlHandle hControl, short theVar, long* theParam)
|
||
{
|
||
ResizeControl(hControl, theVar);
|
||
RectRgn((RgnHandle) (*theParam), &((**((myDataH) (**hControl).contrlData)).myCtlRect));
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
DoTrack - Gets the SpandexMDEF if necessary, and
|
||
calls _PopUpMenuSelect.
|
||
|
||
hControl - the popup
|
||
theVar - CDEF variant
|
||
**************************************************************/
|
||
|
||
long DoTrack(ControlHandle hControl, short theVar)
|
||
{
|
||
myDataP dataP;
|
||
MenuHandle hMenu;
|
||
TextState savedInfo; // saved wmgr/cwmgr port font/size
|
||
SpandexH theHandle = nil;
|
||
Rect theRect;
|
||
Point thePoint;
|
||
Boolean useSpandex = true;
|
||
short growWidth;
|
||
short curWidth;
|
||
char myMark;
|
||
long rval = 0;
|
||
short cmdChar = 0;
|
||
short thisMenuID;
|
||
|
||
dataP = *((myDataH) (**hControl).contrlData);
|
||
|
||
hMenu = dataP->public.mHandle;
|
||
|
||
CalcBoxArea(dataP, &theRect);
|
||
thePoint.h = ++theRect.left;
|
||
thePoint.v = ++theRect.top;
|
||
LocalToGlobal(&thePoint);
|
||
|
||
if (theVar & popupUseWFont)
|
||
DoUseWFont(&savedInfo,(**hControl).contrlOwner,true);
|
||
|
||
/* We want to check the current item but won't for StdFile ($1A) or Hier ($1B) */
|
||
/* Also, use checkmark unless we're not using System Font */
|
||
GetItemCmd(hMenu,(**hControl).contrlValue,&cmdChar);
|
||
if ((cmdChar != 0x001A) && (cmdChar != 0x001B)) {
|
||
myMark = (char) checkMark;
|
||
if (theVar & popupUseWFont)
|
||
{
|
||
short sysFont = (*((short *) SysFontFam));
|
||
if (sysFont != GetScript(GetEnvirons(smSysScript), smScriptSysFond))
|
||
myMark = GetIntlTokenChar(tokenCenterDot, Font2Script(sysFont), BulletMark); // no checkmark available
|
||
}
|
||
SetItemMark(hMenu, (**hControl).contrlValue, myMark);
|
||
}
|
||
|
||
/* We want to grow the menu for non-fixed width and for */
|
||
/* fixed width where the menuWidth < controlWidth */
|
||
CalcBoxArea(dataP, &theRect);
|
||
// +1 for the shadow
|
||
growWidth = theRect.right - theRect.left - (**hMenu).menuWidth - popupSlop + 1;
|
||
useSpandex = (growWidth > 0);
|
||
|
||
if (useSpandex) { // invoke spandex MDEF
|
||
*(short*) RomMapInsert = mapTrue; // <SM4> rb
|
||
theHandle = (SpandexH) GetResource(SpandexResType, SpandexMDEF); // <SM4> rb
|
||
if (theHandle != nil) { // load in spandex MDEF
|
||
LoadResource( (Handle) theHandle ); // load in case of purged -- now unpurgeable so remove this
|
||
HLock( (Handle) theHandle );
|
||
if ( * (Handle) theHandle == nil) // was it loaded properly?
|
||
theHandle = nil; // nope
|
||
}
|
||
|
||
if (theHandle != nil) { // splice old mdef into spandex
|
||
(**theHandle).defProc = (**hMenu).menuProc; // store old mdefproc
|
||
|
||
/* If the menu is in a fixed state, then we expand to the max */
|
||
/* otherwise we just grow to the triangle size */
|
||
|
||
curWidth = dataP->myCtlRect.right - dataP->myCtlRect.left;
|
||
if (!((theVar & popupFixedWidth) &&
|
||
((curWidth == dataP->minWidth) ||
|
||
(curWidth == dataP->maxWidth))))
|
||
growWidth = dataP->info.widMax;
|
||
|
||
(**theHandle).dH = growWidth; // amount to widen by...
|
||
|
||
(**hMenu).menuProc = (Handle) theHandle; // splice it in
|
||
CalcMenuSize(hMenu); // recalculate the menu width
|
||
}
|
||
}
|
||
|
||
rval = PopUpMenuSelect(hMenu, thePoint.v, thePoint.h, (**hControl).contrlValue);
|
||
|
||
dataP->popupResult = rval; // track menuID & value for hier menus
|
||
|
||
if (useSpandex) // take off spandex
|
||
if (theHandle != nil) {
|
||
(**hMenu).menuProc = (**theHandle).defProc; // restore mdefproc
|
||
HUnlock( (Handle) theHandle );
|
||
}
|
||
|
||
if ((cmdChar != 0x001A) && (cmdChar != 0x001B))
|
||
CheckItem(hMenu, (**hControl).contrlValue, false); // uncheck the item
|
||
|
||
if ((theVar & popupUseWFont))
|
||
DoUseWFont(&savedInfo,nil,false);
|
||
|
||
dataP->changedVal = false;
|
||
|
||
/*
|
||
To determine the control value we normally check the low word of rval.
|
||
For hierarchial menus, the ctl value should be the parent item of the selected item.
|
||
We match the menuHandles instead of the menu IDs, 'cuz MacApp adds a menuHandle
|
||
from their 'cmnu' stuff
|
||
*/
|
||
|
||
thisMenuID = (rval & 0xFFFF0000) >> 16;
|
||
if (thisMenuID == 0)
|
||
rval = 0;
|
||
else {
|
||
if (GetMHandle(thisMenuID) != dataP->public.mHandle)
|
||
rval = FindHItem(dataP->public.mHandle,thisMenuID);
|
||
else
|
||
rval &= 0x0000FFFF;
|
||
// set the flag for changed val
|
||
dataP->changedVal = ((**hControl).contrlValue != rval);
|
||
(**hControl).contrlValue = rval;
|
||
|
||
rval = myPartCode; // useless as DoTrack is a void()
|
||
}
|
||
|
||
return(rval);
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
ResizeControl - Calculates the Rect to draw in.
|
||
Grows contrlRect if needed.
|
||
|
||
hControl - the popup
|
||
theVar - CDEF variant
|
||
**************************************************************/
|
||
|
||
void ResizeControl(hControl, theVar)
|
||
ControlHandle hControl;
|
||
short theVar;
|
||
{
|
||
myDataP dataP;
|
||
myDataH theData;
|
||
TextState savedInfo;
|
||
MenuHandle hMenu;
|
||
short height; // also used for menu width
|
||
Rect theRect;
|
||
short curWidth;
|
||
short lineHeight;
|
||
short cmdChar = 0; // for StdFile presence
|
||
short limit;
|
||
Rect controlRect,
|
||
mRect;
|
||
|
||
theData = (myDataH) (**hControl).contrlData;
|
||
|
||
dataP = *theData;
|
||
hMenu = dataP->public.mHandle;
|
||
|
||
// recalculate dynamic properties
|
||
dataP->sysJust = GetSysJust();
|
||
|
||
if ((theVar & popupUseWFont))
|
||
DoUseWFont(&savedInfo,(**hControl).contrlOwner,true);
|
||
|
||
CalcMenuSize(hMenu); // recalculate menusize
|
||
GetFontInfo(&dataP->info); // get font information
|
||
|
||
// Set my control area
|
||
controlRect = (**hControl).contrlRect;
|
||
dataP->myCtlRect = controlRect;
|
||
|
||
// calculate height of the control
|
||
SetRect(&theRect, 0, 0, 0, 0);
|
||
CalcAndDrawItem(hControl, theVar, mCalcItemMsg, &theRect);
|
||
dataP->oldHeight = theRect.bottom;
|
||
dataP->oldWidth = (**hMenu).menuWidth;
|
||
|
||
// If the menu is empty, get the height from the font info
|
||
lineHeight = theRect.bottom; // - top, but top == 0
|
||
if (lineHeight == 0)
|
||
lineHeight = dataP->info.ascent + dataP->info.descent + dataP->info.leading;
|
||
|
||
// We now center the control on the height
|
||
height = ((controlRect.bottom - controlRect.top) - lineHeight - popupSlopV) >> 1;
|
||
dataP->myCtlRect.top += height;
|
||
dataP->myCtlRect.bottom = dataP->myCtlRect.top + lineHeight + popupSlopV;
|
||
|
||
// If the box gets too tall, we shorten the popup to the controlRect for 2 cases:
|
||
// StandardFile and the case where only the triangle is displayed
|
||
|
||
GetItemCmd(hMenu,(**hControl).contrlValue,&cmdChar);
|
||
CalcMenuArea(dataP, &mRect);
|
||
// small menurect => no menuitem drawn
|
||
if ((cmdChar == 0x001A) || ((mRect.right - mRect.left) <= (popupSlop << 1))) {
|
||
limit = controlRect.top;
|
||
if (dataP->myCtlRect.top < limit)
|
||
dataP->myCtlRect.top = limit;
|
||
limit = controlRect.bottom;
|
||
if (dataP->myCtlRect.bottom > limit)
|
||
dataP->myCtlRect.bottom = limit;
|
||
}
|
||
|
||
// Calc the width of the control. If the menu's empty, we set to the max width
|
||
// If StandardFile, the width is the current item, otherwise use menuWidth
|
||
if ((**hMenu).menuWidth == 0)
|
||
height = dataP->maxWidth;
|
||
else {
|
||
height = dataP->info.widMax + dataP->titleWidth + popupSlop;
|
||
if (cmdChar == 0x001A)
|
||
height += theRect.right;
|
||
else
|
||
height += (**hMenu).menuWidth;
|
||
}
|
||
|
||
// Sanity check for new fixed width, both min & max
|
||
if (height > dataP->maxWidth)
|
||
height = dataP->maxWidth;
|
||
|
||
if (height < dataP->minWidth)
|
||
height = dataP->minWidth;
|
||
|
||
/* For popups w/ no title (i.e. StandardFile), we can center the control */
|
||
if ((dataP->titleWidth == 0) &&
|
||
(dataP->titleJust == popupTitleCenterJust)) {
|
||
curWidth = controlRect.right - controlRect.left;
|
||
dataP->myCtlRect.left -= (height - curWidth) >> 1;
|
||
dataP->myCtlRect.right = dataP->myCtlRect.left + height;
|
||
}
|
||
else if (dataP->sysJust == teJustRight)
|
||
dataP->myCtlRect.left = dataP->myCtlRect.right - height;
|
||
else
|
||
dataP->myCtlRect.right = dataP->myCtlRect.left + height;
|
||
|
||
// restore font information
|
||
if ((theVar & popupUseWFont))
|
||
DoUseWFont(&savedInfo,nil,false);
|
||
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////////
|
||
// Drawing Routines
|
||
///////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
/*************************************************************
|
||
DrawTriangle - Draws the popup triangle
|
||
|
||
dataP - control info
|
||
dimmed - gray the triangle using fore & back blend
|
||
**************************************************************/
|
||
|
||
void DrawTriangle(myDataP dataP, Boolean dimmed)
|
||
{
|
||
short tWidth; // width of triangle
|
||
short tHeight; // height of triangle
|
||
short sWidth; // width of rectangle
|
||
short sHeight; // height of tectangle
|
||
Rect trigRect,
|
||
boxRect;
|
||
short theWidth; // max width of the triangle
|
||
PolyHandle trigPoly;
|
||
PixPatHandle myPixPat = nil;
|
||
|
||
if (dimmed)
|
||
myPixPat = BeginMyGray(dataP);
|
||
|
||
CalcTriangleRect(dataP, &trigRect);
|
||
CalcBoxArea(dataP, &boxRect);
|
||
|
||
theWidth = dataP->info.widMax;
|
||
sWidth = boxRect.right - boxRect.left;
|
||
sHeight = trigRect.bottom - trigRect.top;
|
||
|
||
// We need a width that's 75% of original and even
|
||
tWidth = theWidth;
|
||
tWidth -= (tWidth >> 2);
|
||
if (tWidth & 0x0001)
|
||
tWidth++;
|
||
|
||
// Minimum size sanity checking
|
||
if (tWidth < 6) {
|
||
tWidth = 6;
|
||
if (tWidth > theWidth) {
|
||
if (theWidth < 4)
|
||
return;
|
||
tWidth = 4;
|
||
}
|
||
}
|
||
|
||
tHeight = tWidth >> 1;
|
||
|
||
/* Horizontally center the triangle if the control */
|
||
/* isn't wide enough for the menu item */
|
||
if (sWidth < (theWidth + (popupSlop << 1)))
|
||
trigRect.left = boxRect.left + ((sWidth - tWidth) >> 1);
|
||
else if (dataP->sysJust == teJustRight)
|
||
trigRect.left = trigRect.right - tWidth;
|
||
|
||
trigRect.right = trigRect.left + tWidth;
|
||
trigRect.top += ((sHeight - tHeight) >> 1); // move top by half of vertical whitespace
|
||
trigRect.bottom = trigRect.top + tHeight;
|
||
|
||
trigPoly = OpenPoly();
|
||
MoveTo(trigRect.left, trigRect.top);
|
||
LineTo(trigRect.right, trigRect.top);
|
||
LineTo((trigRect.right + trigRect.left) >> 1, trigRect.bottom);
|
||
LineTo(trigRect.left, trigRect.top);
|
||
ClosePoly();
|
||
|
||
PaintPoly(trigPoly);
|
||
KillPoly(trigPoly);
|
||
|
||
PenNormal();
|
||
if (myPixPat != nil)
|
||
DisposPixPat(myPixPat);
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
DrawTitle - Draws the popup title
|
||
|
||
controlP - control
|
||
dataP - control info
|
||
**************************************************************/
|
||
|
||
void DrawTitle(ControlPtr controlP, myDataP dataP)
|
||
{
|
||
Rect titleRect,
|
||
theRect;
|
||
Style oldStyle;
|
||
short oldMode;
|
||
Str255 theString;
|
||
short width;
|
||
|
||
CalcTitleArea(dataP, &titleRect);
|
||
InsetRect(&titleRect,0,1);
|
||
|
||
// Erase the title & swap colors for color inverse
|
||
if (dataP->useColor)
|
||
SetColors(dataP->public.mID, 0, (controlP->contrlHilite == myPartCode)); // use menu table
|
||
|
||
EraseRect(&titleRect);
|
||
|
||
oldStyle = (controlP->contrlOwner)->txFace;
|
||
oldMode = (controlP->contrlOwner)->txMode;
|
||
TextFace(dataP->titleStyle);
|
||
|
||
// We dim the control if the hilite is set, or the menu is empty
|
||
if ((controlP->contrlHilite == 255) ||
|
||
((**dataP->public.mHandle).menuWidth == 0))
|
||
TextMode(grayishTextOr);
|
||
|
||
BlockMove((Ptr) controlP->contrlTitle, (Ptr) theString,
|
||
Length(controlP->contrlTitle) + 1);
|
||
|
||
// textbox rect
|
||
theRect = titleRect;
|
||
InsetRect(&theRect, popupSlop, 0);
|
||
|
||
// turn on condensing if we can't fit
|
||
width = theRect.right - theRect.left - 1; // 1 is for indent
|
||
if (StringWidth(theString) > width) {
|
||
TextFace(dataP->titleStyle | condense);
|
||
TruncString(width, theString, smTruncEnd);
|
||
}
|
||
TextBox((Ptr) (theString + 1), Length(theString), &theRect, dataP->titleJust );
|
||
TextFace(oldStyle);
|
||
TextMode(oldMode);
|
||
|
||
// now hilite the title if necessary and if not CQD (CQD already done above)
|
||
if (controlP->contrlHilite == myPartCode)
|
||
if (! dataP->useColor)
|
||
InvertRect(&titleRect);
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
MakeColorPort - Returns a color grafport
|
||
|
||
owner - where this will reside
|
||
**************************************************************/
|
||
|
||
CGrafPtr MakeColorPort(GrafPtr owner)
|
||
{
|
||
Rect theRect;
|
||
Point tempPt;
|
||
TextState myText;
|
||
CGrafPtr myCPort;
|
||
|
||
myCPort = (CGrafPtr) NewPtr(sizeof(CGrafPort)); // create color graf port
|
||
if (myCPort != nil) {
|
||
theRect = owner->portRect;
|
||
|
||
tempPt.h = theRect.left;
|
||
tempPt.v = theRect.top;
|
||
|
||
LocalToGlobal(&tempPt);
|
||
OpenCPort(myCPort); // initialize the port (and set to it)
|
||
MovePortTo(tempPt.h, tempPt.v); // and size it properly
|
||
PortSize( theRect.right - theRect.left, theRect.bottom - theRect.top);
|
||
|
||
// now copy quickdraw stuff
|
||
myText.theFont = owner->txFont;
|
||
myText.theSize = owner->txSize;
|
||
myText.theFace = owner->txFace;
|
||
myText.theMode = owner->txMode;
|
||
SetTextState(&myText);
|
||
|
||
PenNormal(); // Isn't this done for us?
|
||
CopyRgn(owner->clipRgn, myCPort->clipRgn);
|
||
CopyRgn(owner->visRgn, myCPort->visRgn);
|
||
if (owner->pnVis < 0)
|
||
HidePen();
|
||
}
|
||
|
||
return(myCPort);
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
SetColors - Sets the RGB Fore & Back colors to
|
||
the appropriate values
|
||
|
||
menuID - for the menu color table entry
|
||
menuItem - > 0 --> item color table entry
|
||
= 0 --> use menu CT
|
||
= -1 --> set to default colors
|
||
isHilited - reverse the colors if we're hilited
|
||
**************************************************************/
|
||
|
||
void SetColors(short menuID, short menuItem, Boolean isHilited)
|
||
{
|
||
RGBColor newCQDFore, newCQDBack,
|
||
*foreCP, *backCP;
|
||
MCEntryPtr theMenuColor;
|
||
|
||
newCQDFore.red = // load up initial values
|
||
newCQDFore.green =
|
||
newCQDFore.blue = 0;
|
||
|
||
newCQDBack.red =
|
||
newCQDBack.green =
|
||
newCQDBack.blue = 0xFFFF;
|
||
|
||
/* We try to get the colors asked for. */
|
||
/* Failing that, we keep trying 'till default mctb */
|
||
|
||
if (menuItem == -1) // just set to default color
|
||
goto setColor;
|
||
|
||
if (menuItem == 0) // default item color
|
||
goto getMenuColor;
|
||
|
||
/* We have to make local copies of the menu colors, 'cuz the */
|
||
/* table is relocatable, and RGBForColor may move it */
|
||
|
||
// use mctb for menu/item
|
||
if ((theMenuColor = GetMCEntry(menuID,menuItem)) != nil) {
|
||
newCQDFore = theMenuColor->mctRGB2; // item color
|
||
newCQDBack = theMenuColor->mctRGB4; // item background color
|
||
goto setColor;
|
||
}
|
||
|
||
getMenuColor: // use mctb for menu
|
||
if ((theMenuColor = GetMCEntry(menuID,0)) != nil) {
|
||
newCQDFore = theMenuColor->mctRGB3; // default item color
|
||
newCQDBack = theMenuColor->mctRGB4; // default item background color
|
||
goto setColor;
|
||
}
|
||
|
||
getSystemColor: // use default mctb
|
||
if ((theMenuColor = GetMCEntry(0,0)) != nil) {
|
||
newCQDFore = theMenuColor->mctRGB3; // default title color
|
||
newCQDBack = theMenuColor->mctRGB2; // default menubar background color
|
||
}
|
||
|
||
setColor:
|
||
foreCP = &newCQDFore; // ptrs for easy swap & small size
|
||
backCP = &newCQDBack;
|
||
|
||
if (isHilited) {
|
||
foreCP = &newCQDBack; // swap values if we're highlighted
|
||
backCP = &newCQDFore;
|
||
}
|
||
|
||
RGBForeColor(foreCP);
|
||
RGBBackColor(backCP);
|
||
}
|
||
|
||
|
||
///////////////////////////////////////////////////////////////////////////////////////////
|
||
// Calculation Routines
|
||
///////////////////////////////////////////////////////////////////////////////////////////
|
||
|
||
/*************************************************************
|
||
CalcAndDrawItem - passes mCalcMsg or mDrawMsg to the
|
||
menu defProc
|
||
|
||
hControl - the popup
|
||
theVar - CDEF variant
|
||
theRect - what to return
|
||
**************************************************************/
|
||
|
||
void CalcAndDrawItem(ControlHandle hControl, short theVar, short theMsg, Rect* theRect)
|
||
{
|
||
myDataH theData;
|
||
MDEFHandle theHandle;
|
||
short whichItem;
|
||
TextState savedInfo;
|
||
unsigned char theState;
|
||
|
||
theData = (myDataH) (**hControl).contrlData;
|
||
|
||
theHandle = (MDEFHandle) (**((**theData).public.mHandle)).menuProc;
|
||
if (theHandle == nil)
|
||
return;
|
||
|
||
LoadResource((Handle) theHandle);
|
||
if (*((Handle) theHandle) == nil)
|
||
return;
|
||
|
||
// Set up the grafport info
|
||
if (theVar & popupUseWFont)
|
||
DoUseWFont(&savedInfo,(**hControl).contrlOwner,true);
|
||
|
||
whichItem = (**hControl).contrlValue;
|
||
|
||
// Is the lock really needed??
|
||
theState = HGetState( (Handle) theHandle);
|
||
HLock((Handle) theHandle);
|
||
(**theHandle) (theMsg, (**theData).public.mHandle, theRect, * (Point*) theRect, &whichItem);
|
||
HSetState((Handle) theHandle, theState);
|
||
|
||
// Reset the grafport info
|
||
if (theVar & popupUseWFont)
|
||
DoUseWFont(&savedInfo,nil,false);
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
CalcTriangleRect - Calcs triangle rect for pict
|
||
|
||
dataP - the popup
|
||
theRect - what to return
|
||
**************************************************************/
|
||
|
||
void CalcTriangleRect(myDataP dataP, Rect *theRect)
|
||
{
|
||
short tWidth;
|
||
|
||
CalcBoxArea(dataP, theRect);
|
||
|
||
tWidth = dataP->info.widMax + popupSlop;
|
||
|
||
InsetRect(theRect,1,1);
|
||
if (dataP->sysJust == teJustRight)
|
||
theRect->right = theRect->left + tWidth;
|
||
else
|
||
theRect->left = theRect->right - tWidth;
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
CalcTitleArea - Calcs enclosing title rect
|
||
|
||
dataP - the popup
|
||
theRect - what to return
|
||
**************************************************************/
|
||
|
||
void CalcTitleArea(myDataP dataP,Rect *theRect)
|
||
{
|
||
short tWidth;
|
||
|
||
*theRect = dataP->myCtlRect;
|
||
tWidth = dataP->titleWidth;
|
||
|
||
if (dataP->sysJust == teJustRight)
|
||
theRect->left = theRect->right - tWidth;
|
||
else
|
||
theRect->right = theRect->left + tWidth;
|
||
|
||
--theRect->bottom;
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
CalcBoxArea - Calcs popup box without shadow
|
||
|
||
dataP - the popup
|
||
theRect - what to return
|
||
**************************************************************/
|
||
void CalcBoxArea(myDataP dataP, Rect *theRect)
|
||
{
|
||
short tWidth;
|
||
|
||
*theRect = dataP->myCtlRect;
|
||
tWidth = dataP->titleWidth;
|
||
|
||
if (dataP->sysJust == teJustRight)
|
||
theRect->right -= tWidth;
|
||
else
|
||
theRect->left += tWidth;
|
||
|
||
--theRect->bottom;
|
||
--theRect->right;
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
CalcMenuArea - Calcs popup box without shadow, triangle
|
||
|
||
dataP - the popup
|
||
theRect - what to return
|
||
**************************************************************/
|
||
|
||
void CalcMenuArea(myDataP dataP, Rect *theRect)
|
||
{
|
||
short tWidth;
|
||
|
||
tWidth = dataP->info.widMax + popupSlop;
|
||
CalcBoxArea(dataP, theRect);
|
||
|
||
if (dataP->sysJust == teJustRight) {
|
||
theRect->left += tWidth;
|
||
--theRect->right;
|
||
}
|
||
else {
|
||
theRect->right -= tWidth;
|
||
++theRect->left;
|
||
}
|
||
|
||
++theRect->top;
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
CalcShadowArea - Calc rect for popup shadow
|
||
|
||
dataP - the popup
|
||
theRect - what to return
|
||
**************************************************************/
|
||
|
||
void CalcShadowArea(myDataP dataP, Rect *theRect)
|
||
{
|
||
CalcBoxArea(dataP, theRect);
|
||
theRect->left += shadowLeft;
|
||
theRect->top += shadowTop;
|
||
++theRect->right;
|
||
++theRect->bottom;
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
GetTextState - Loads the current grafport text info
|
||
|
||
txState - Like penState
|
||
**************************************************************/
|
||
|
||
void GetTextState(TextState *txState)
|
||
{
|
||
GrafPtr thePort;
|
||
|
||
GetPort(&thePort);
|
||
|
||
txState->theFont = thePort->txFont;
|
||
txState->theFace = thePort->txFace;
|
||
txState->theSize = thePort->txSize;
|
||
txState->theMode = thePort->txMode;
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
SetTextState - Sets the current grafport text info
|
||
|
||
txState - Like penState
|
||
**************************************************************/
|
||
|
||
void SetTextState(TextState *txState)
|
||
{
|
||
TextFont(txState->theFont);
|
||
TextSize(txState->theSize);
|
||
TextFace(txState->theFace);
|
||
TextMode(txState->theMode);
|
||
}
|
||
|
||
/*************************************************************
|
||
SaveAndResetWMPorts -
|
||
saves font and size for window manager
|
||
port and color window manager port
|
||
then sets them to zero
|
||
WMPortState - Like penState
|
||
**************************************************************/
|
||
|
||
void
|
||
SaveAndResetWMPorts(WMPortState *pWMPortState)
|
||
{
|
||
GrafPtr tempPort;
|
||
CGrafPtr tempCPort;
|
||
|
||
tempPort = * (GrafPtr *) WMgrPort;
|
||
pWMPortState->savedFont = tempPort->txFont;
|
||
pWMPortState->savedSize = tempPort->txSize;
|
||
tempPort->txFont = tempPort->txSize = 0;
|
||
|
||
if (HaveCQD()) {
|
||
tempCPort = * (CGrafPtr *) WMgrCPort;
|
||
pWMPortState->savedCFont = tempCPort->txFont;
|
||
pWMPortState->savedCSize = tempCPort->txSize;
|
||
tempCPort->txFont = tempCPort->txSize = 0;
|
||
}
|
||
}
|
||
|
||
/*************************************************************
|
||
RestoreWMPorts - sets the wmgr and color wmgr ports
|
||
WMPortState - Like penState
|
||
**************************************************************/
|
||
void
|
||
RestoreWMPorts(WMPortState *pWMPortState)
|
||
{
|
||
GrafPtr tempPort;
|
||
CGrafPtr tempCPort;
|
||
|
||
tempPort = * (GrafPtr *) WMgrPort;
|
||
tempPort->txFont = pWMPortState->savedFont;
|
||
tempPort->txSize = pWMPortState->savedSize;
|
||
|
||
if (HaveCQD()) {
|
||
tempCPort = * (CGrafPtr *) WMgrCPort;
|
||
tempCPort->txFont = pWMPortState->savedCFont;
|
||
tempCPort->txSize = pWMPortState->savedCSize;
|
||
}
|
||
}
|
||
|
||
/*************************************************************
|
||
DoUseWFont - Sets the font mgr low mem globals so
|
||
we can have Geneva 9 popups
|
||
|
||
savedInfo - Fills it in if saveIt = true, else
|
||
it sets the port to those values
|
||
owner - Where to get the original values
|
||
saveIt - true at the start of the
|
||
**************************************************************/
|
||
|
||
void DoUseWFont(TextState *savedInfo, WindowPtr owner, Boolean saveIt)
|
||
{
|
||
TextState myState,
|
||
*theState;
|
||
short aFont;
|
||
|
||
theState = savedInfo;
|
||
|
||
if (saveIt) {
|
||
savedInfo->theFont = *((short *) SysFontFam); // save low memory globals
|
||
savedInfo->theSize = *((short *) SysFontSize);
|
||
|
||
myState.theFont = owner->txFont;
|
||
myState.theSize = owner->txSize;
|
||
theState = &myState;
|
||
|
||
// if we stuff systemFont, it will screw up Script Mgr
|
||
if (owner->txFont == systemFont)
|
||
goto dosizestuff;
|
||
}
|
||
|
||
// if we stuff applFont, this will also screw up Script Mgr
|
||
// instead we get the actual font
|
||
|
||
aFont = theState->theFont;
|
||
if (saveIt)
|
||
if (owner->txFont == applFont)
|
||
aFont = *((short *) ApFontID);
|
||
*((short *) SysFontFam) = aFont; // set/restore low memory globals
|
||
|
||
dosizestuff:
|
||
*((short *) SysFontSize) = theState->theSize;
|
||
|
||
*((long *) CurFMInput) = 0xFFFFFFFF;
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************
|
||
BeginMyGray - Sets up the pen, etc for disabled
|
||
drawing
|
||
|
||
returns - A colorQD pattern
|
||
**************************************************************/
|
||
|
||
PixPatHandle BeginMyGray(myDataP dataP)
|
||
{
|
||
Pattern pat;
|
||
RGBColor oldFore, oldAft;
|
||
PixPatHandle myPixPat = nil;
|
||
|
||
if (dataP->useColor) {
|
||
// do color QD stuff here
|
||
GetForeColor(&oldFore);
|
||
GetBackColor(&oldAft);
|
||
|
||
// gimme average RGB. Why does MenuMgr do a ROXR instead of an ASR??
|
||
oldFore.red = (oldFore.red + oldAft.red) >> 1;
|
||
oldFore.green = (oldFore.green + oldAft.green) >> 1;
|
||
oldFore.blue = (oldFore.blue + oldAft.blue) >> 1;
|
||
|
||
myPixPat = NewPixPat();
|
||
|
||
if (myPixPat != nil) {
|
||
MakeRGBPat(myPixPat,&oldFore);
|
||
PenPixPat(myPixPat);
|
||
}
|
||
|
||
TextMode(grayishTextOr); //grayish text copy
|
||
}
|
||
|
||
if (myPixPat == nil) {
|
||
GetIndPattern(&pat,sysPatListID,grayPatternID);
|
||
PenPat(&pat);
|
||
}
|
||
|
||
return(myPixPat);
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
FindHItem - Tries to find a hierarchial item in the
|
||
menu with the given hier menu id
|
||
|
||
returns - The parent item number
|
||
**************************************************************/
|
||
|
||
short FindHItem(MenuHandle hMenu, short hMenuID)
|
||
{
|
||
short i;
|
||
short cmdChar = 0,
|
||
markChar = 0;
|
||
|
||
for (i = 1;i <= CountMItems(hMenu);i++) {
|
||
GetItemCmd(hMenu, i, &cmdChar);
|
||
if (cmdChar == 0x001B) {
|
||
GetItemMark(hMenu, i, &markChar);
|
||
if (markChar == hMenuID)
|
||
return(i);
|
||
}
|
||
}
|
||
|
||
return(1);
|
||
}
|
||
|
||
|
||
/*************************************************************
|
||
GetIntlTokenChar - Get the token for the given script
|
||
|
||
returns - The token or the default if error
|
||
**************************************************************/
|
||
|
||
char GetIntlTokenChar(short whichToken, short whichScript, char defaultChar)
|
||
{
|
||
Handle itl4H;
|
||
long offset, len;
|
||
|
||
// Look up the untoken table -- bail if we can’t get it
|
||
IUGetItlTable(whichScript, iuUnTokenTable, &itl4H, &offset, &len);
|
||
if (itl4H && (offset > 0) && (len >= 0))
|
||
{
|
||
char *sp = (*itl4H + offset); // Point to start of untoken table
|
||
if (whichToken <= ((short *)sp)[1]) // Check if token has valid index
|
||
{
|
||
sp += ((short *)sp)[2+whichToken]; // Add the string offset and voliá!
|
||
if (*sp == 1) defaultChar = sp[1]; // Might be 2-byte, so check length byte
|
||
}
|
||
}
|
||
return(defaultChar);
|
||
} |