mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-27 10:29:32 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
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);
|
|
} |