mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 01:29:20 +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.
3481 lines
114 KiB
OpenEdge ABL
3481 lines
114 KiB
OpenEdge ABL
{__________________________________________________________________________________________________
|
|
File: BalloonPACK.p
|
|
|
|
Contains: Pascal support routines for _Pack14 (HelpMgr)
|
|
|
|
Written by: Randy Carr
|
|
|
|
Copyright: © 1989-1992 by Apple Computer, Inc., all rights reserved.
|
|
|
|
Change History (most recent first):
|
|
|
|
<SM3> 2/17/93 kc Allocate pictures in the System Heap because they persist longer
|
|
than the application heap.
|
|
<81> 6/2/92 KST #1030643 <JH>: We have only 1 default message for the floating
|
|
window instead of two (floating windows are all active).
|
|
<80> 5/14/92 KST #1027497 <JH>: #1025797,#1027497: In '__HMGetWindowPartCode',
|
|
defined 2 new window parts when mouse is over a floating window.
|
|
Provided default message so that Balloon help can work when
|
|
mouse is over a floating window.
|
|
<79> 4/23/92 JH #1027497,<YK>: CubeE adds a IMlayer for use by floating windows
|
|
that input windows need. Unfortunately, the Help mgr doesn't
|
|
know anything about this new layer. So I'm changing
|
|
__HMGetWindowPartCode to call the TSM call FindServiceWindow
|
|
before calling FindWindow. If FindServiceWindow returns a part
|
|
code in a real window we use GetParent to find IMlayer. Swap
|
|
that layer in, let the help mgr do its thing, and then swap the
|
|
old layer back.
|
|
<78> 4/4/92 csd #1017165,<BBM>: In HMShowWindowPartBalloon, set the port to the
|
|
BalloonWindow before calling ReplaceText since ReplaceText uses
|
|
the current portÕs font and script information.
|
|
<77> 3/23/92 JSM OSEvents.p is obsolete, use Events.p.
|
|
<76> 11/21/91 csd #83334: Used a single string with ReplaceText instead a two
|
|
strings with Concat to build "This window belongs to the
|
|
application ÒxxxÓ. To make this window active, click in it."
|
|
<75> 11/3/91 KSM In theFuture, we should not arbitrarily limit the size of
|
|
balloons (per Randy).
|
|
<74> 4/1/91 RLC vl, #85955- FIx bug that wasn't respecting current process when
|
|
tracking dialogs that contain a help item in the DITL handle.
|
|
<73> 3/19/91 RLC ksm,#BH-TCA-0083 - FIx bug that wasn't passing window method
|
|
parameter to HMShowBalloon() for 'hdlg' & 'hrct' resources.
|
|
<72> 3/13/91 RLC ksm,#84586 - Change reset of help msgs using a text edit handle
|
|
that are passed to HMShowBalloon to force the text edit handle
|
|
to the help mgr font.
|
|
<71> 2/20/91 RLC ksm,#BBSLostItsMind - Add a bracket back in that somehow got
|
|
left out of a comment in the HMSelectBestVariant routine.
|
|
<70> 2/20/91 RLC ksm,#82854 - Add a check in HMScanTemplateItems that makes sure
|
|
that the window we're examining is a dialog if the type if
|
|
kHMDialogResType. The call to FindDItem in HMSameItemState can
|
|
otherwise be made on a non-Dialog window (i.e. Crash!).
|
|
<69> 2/19/91 RLC ksm,#81544 Fix balloon positioner to make sure all variants are
|
|
tried when initial variant does not fit. This fixes the clipped
|
|
balloon for Empty Trash and KeyCaps. GO5 approved.
|
|
<68> 2/8/91 RLC <ksm> #82161 Add a call to strip the null character from the
|
|
processes that are desk accessories. This causes text edit to
|
|
word break the process name leaving beginning and ending quotes
|
|
on different lines of the balloon. <BHTCA0080> = force grayed
|
|
controls to get the HMDisabled state in all cases.
|
|
<67> 1/24/91 RLC <gbm> #81591 Change __HMFillInDialogMessage() calls to pass the
|
|
resource file refnum from HMScanTemplateItems(). Those routines
|
|
will call GetResource() for file refnum<>-1 otherwise call
|
|
Get1Resource() [which means specifically search a resource file
|
|
for a help resource]. Also changed occurrances of hmmPic to
|
|
hmmPict as per Scott Boyd's changes to Balloons.p.
|
|
<66> 1/22/91 RLC <dc> #81592 Fix bug that leaves a balloon up if the mouse
|
|
moves from a system tracked balloon to the menubar and remove
|
|
the extraneous tip parameter from HMShowTitleBalloon() routine.
|
|
<65> 1/10/91 RLC <stb> Change the code for HMTrackModalItems and
|
|
HMScanTemplateItems to not set the hmgLastItem and
|
|
hmgLastItemState when the 'hdlg' resource that we're tracking
|
|
returns a hmSkippedBalloon for an item's message. This makes
|
|
sure that the 'hdlg' resource indicated by the HMSetDialogResID
|
|
setting gets checked in case the resource comes later in the
|
|
resource map.
|
|
<64> 1/10/91 RLC <ksm> Fix __HMPinTipAndAltRect routine to do the right thing if
|
|
tip is outside screenbounds and after correction is still
|
|
outside altRect.
|
|
<63> 12/17/90 RLC <ksm> Change HMSetBalloons to always remove the balloon before
|
|
disposing of the layer when balloon help is turned off else we
|
|
risk orphaning the balloon window in a non-existent layer.
|
|
<62> 12/14/90 RLC <ngk> Add check to __HMShowWindowPartBalloon so that unhilited
|
|
windows that are behind a movable modal get the right balloon.
|
|
(i.e. you can switch to another layer, but you cannot bring an
|
|
inactive window to the front) Remove HMNewBestWorld conditional
|
|
and the older positioning code that was excluded by it. Change
|
|
giant case statement into table driven HMVarCodeToBias() asm
|
|
routine (saves 238 bytes). Changed kHMFinderOnly to
|
|
kHMActiveApplOther to support menu items in Process menu that
|
|
are marked. Make HMCountDITLHelpItems external so that Standard
|
|
file can call it from the private interface.
|
|
<61> 12/14/90 dba <JDR> get rid of LongIntPtr, now in Types.p
|
|
<60> 12/3/90 RLC <ksm> Add check to __HMShowWindowPartBalloon so that unhilited
|
|
windows that are behind a movable modal get the right balloon.
|
|
(i.e. you can switch to another layer, but you cannot bring an
|
|
inactive window to the front.
|
|
<59> 11/16/90 RLC <ksm> Always call HMFillInMenuMessage when a modal dialog is up
|
|
so that the disabled AppleMenu items get the right help string.
|
|
Fix bug that would not clear the pic VAR if HMCalculateBalloon
|
|
was called too frequently and not enough time elapsed. Roll in
|
|
new HMBestWorld calculation to fix all those agonizing balloons
|
|
that hang offscreen bugs. The new routine is simpler, smaller,
|
|
and tries more ways to get the balloon to fit.
|
|
<58> 10/4/90 RLC <ksm> Fix mem leak that wasn't always disposing of the picture
|
|
handles. The bug was that if the mouse was moving quickly
|
|
enough to cause HMCalculateBalloon to abort its calculation,
|
|
HMCalculateBalloon would return hmBalloonAborted, but with a
|
|
valid picHandle. In this case, the caller must dispose of
|
|
the picture by calling KillPicture. Remove references to
|
|
hmgContentWindow and hmgOurBalloon variables as these were
|
|
internal to the .a code of which is now calling the external
|
|
routine HMScanTemplateItems. Fixed bug in HMScanTemplate that
|
|
wasn't obeying the hmAbsoluteCoords option in the resource.
|
|
Change code that handles picture resources or picHandles when
|
|
showing a balloon: we don't copy the picture data, we just use
|
|
the pic as is and stuff it in the windowPic field. Call
|
|
DisposeWindow instead of CloseWindow for custom balloon winds.
|
|
<57> 9/30/90 RLC Change hits in the 'inGrow' message of a window to be
|
|
'inContent'. Reduce more redundant code in TrackModalHelp
|
|
routines by consolidating some code into:__HMSameItemState (this
|
|
saved >370 bytes).
|
|
<56> 9/26/90 RLC Make a change to the automatically generated window part
|
|
balloons to allow non-front windows that are hilighted to get
|
|
'front window' balloons. (This will allow windoids and other
|
|
palette windows that respect the window record's hilited boolean
|
|
to work correctly).
|
|
<55> 9/25/90 RLC Consolidate by having HMExtractHelpMsg call HMGetIndHelpMsg
|
|
instead of having separate (duplicate) code (saves >370 bytes).
|
|
Change HMShowMenuBalloon call to only call HMRemoveBalloon if a
|
|
new balloon is about to be displayed and add a call to
|
|
HMRemoveBalloon if HMSavedBitsÉ is called.
|
|
<54> 9/21/90 RLC Add code to the HMGetBalloons toggle to create both help window
|
|
and layer when the flag goes true and tear down the window &
|
|
layer for false. This means that the help layer won't be
|
|
burdening the window list hierarchy unless balloon help is on.
|
|
<53> 9/16/90 RLC (KSM also) Utilize itemReserved longword in HMShowMenuBalloon
|
|
routine to draw that string instead of fetching a help message
|
|
from the 'hmnu' resource.
|
|
<52> 9/15/90 RLC Repair positioner code in HMBestWorld that was calculating
|
|
balloon tip position incorrectly for balloons that failed to fit
|
|
on screen after 2 re-fits.
|
|
<51> 9/13/90 RLC Change references to our global handle (HMGlobalHandle) into
|
|
references to a global ptr (HMGlobalPtr), rename all routines
|
|
in this package to have __HM in front so that Balloons.p can
|
|
be part of uses statement, remove all multiple derefs to use
|
|
a single with as we don't have to worry about relocation of
|
|
handle's ptr.
|
|
<50> 8/31/90 RLC Remove duplicate and extraneous equates.
|
|
<49> 8/20/90 RLC Fix offscreen balloons bug that allows a balloon to hang off the
|
|
edge.
|
|
<48> 8/20/90 RLC Repair Philip's merge of the old file.
|
|
<46> 7/17/90 RLC Fix HMExtract calling conventions & styled text edit balloon
|
|
bugs.
|
|
<45> 7/16/90 RLC Change format of Styled-Text edit.
|
|
<44> 7/13/90 RLC Just about every interface routine got changed. Improved speed
|
|
of WDEF calc routines. Shortened code for everything. Made
|
|
multiple helpItems in dialogs work, fixed offset as well.
|
|
<43> 7/6/90 RLC Repair skip items in modal dialog to really be skipped instead
|
|
of always removing balloons.
|
|
<42> 7/5/90 RLC Fix multiple 'hdlg' occurrances.
|
|
<41> 7/2/90 RLC Some short changes
|
|
<40> 6/19/90 RLC More correction in variant central.
|
|
<39> 6/18/90 RLC Repair pinning algo again & add variant sensitivity/
|
|
<38> 6/14/90 RLC Include BalloonDefs.p for HMGlobalRecord.
|
|
<37> 6/8/90 KSM Update for new IsFrontWindowModal.
|
|
<36> 6/7/90 RLC Optimize a bit, fix misc positioning bugs.
|
|
<35> 6/5/90 RLC Fix HMSetDialogResID & system menu title balloon tip.
|
|
<34> 6/1/90 RLC Update global record
|
|
<33> 5/31/90 RLC Fix possible address error for 68K machines in HMShowBalloon.
|
|
<32> 5/29/90 RLC Add support routines for new HMGetHelpMenu selector.
|
|
<31> 5/4/90 RLC Patches CONST changes.
|
|
<30> 5/3/90 RLC Fix bugs in modal dialog balloons, launching, etc.
|
|
<29> 4/19/90 RLC Add scriptmgr help font & size to HMSet & HMGet font calls.
|
|
<28> 4/17/90 RLC Add reference to new utility routine: HMFillCitationString.
|
|
<27> 4/10/90 KSM New constants for system menu patch.
|
|
<26> 4/5/90 RLC Add support for the 'hovr' resource.
|
|
<25> 4/3/90 RLC Fix Modal Dialog tracking
|
|
<24> 4/2/90 RLC Reconnect HMSetDialogResID & HMSetMenuResID.
|
|
<23> 3/30/90 RLC Make sure MF rect is in line with MultiFinder.
|
|
<23> 3/28/90 RLC Add support for appends to the help menu.
|
|
<21> 3/26/90 RLC Fix global lasts for menus AND saveBits options.
|
|
<20> 3/22/90 RLC Remove hardcoded strings except for testing.
|
|
<19> 3/19/90 RLC Bug Fixes galore (58881 thru 62272).
|
|
<18> 3/15/90 RLC Fix all error return codes, abort remove if point is in our help
|
|
balloon.
|
|
<17> 3/7/90 RLC Fix the pt not in current layer stuff.
|
|
<16> 2/23/90 RLC Repair HMSetMenuResID for Pascal3.1 & add other layer support.
|
|
<15> 2/22/90 dnf Per RLC's instructions: Comment out code in HMSetMenuResID
|
|
Function
|
|
<14> 2/8/90 RLC Fix scanning of window parts to always return the correct
|
|
windowpart balloon.
|
|
<13> 2/7/90 RLC Add in change to respect tip & hotRect parameters in 'hdlg'
|
|
resources.
|
|
<12> 2/5/90 RLC Add support for delay in balloon drawing.
|
|
<11> 1/31/90 RLC Revise HMGlobalRecord again.
|
|
<10> 1/26/90 RLC Increase Performance.
|
|
<9> 1/26/90 RLC Update hmgGlobalRecord and support for a modal condition
|
|
(again).
|
|
<8> 1/25/90 RLC Change shape of Balloon look.
|
|
<7> 1/19/90 RLC Update selectors and error codes.
|
|
<6> 1/11/90 RLC Change mechanism for controlling how system balloons appear.
|
|
<5> 1/9/90 RLC Add support for new resource format.
|
|
<4> 1/3/90 RLC Fix to remove balloons in a modal dialog case where the mouse
|
|
leaves the dialog.
|
|
<3> 1/3/90 RC Change hdlgSaveBits option to only save bits if on.
|
|
<2> 12/20/89 RC Add change to support Menu title balloons better.
|
|
<4.1> 12/15/89 RLC Added TipProc, theProc, & variant support.
|
|
<4.0> 12/6/89 RLC Tweak tip when horizontal balloon crosses hotRect.
|
|
<3.9> 12/1/89 RLC Fix HMScanTemplate routine check to see if dialog is a modal
|
|
dialog before setting flag.
|
|
<3.8> 11/30/89 RLC Fixed bug in HMTrackTemplate code that couldn't handle HMSkip
|
|
types & updated HMGlobalsRecord
|
|
<3.7> 11/21/89 RLC Temp fix for bug in _DrawPicture & remember to TEDispose the
|
|
TENew.
|
|
<3.6> 11/20/89 RLC Update routines that find the helpItem parameter in a 'DITL'
|
|
template handle.
|
|
<3.5> 11/16/89 RLC Change parameter interface to HMTrackTemplateHelpItems.
|
|
<3.4> 11/15/89 RLC Change 'hdlg' support to correctly handle local offsets.
|
|
<3.3> 11/13/89 RLC Changed dialog tracking routines, window parts tracker.
|
|
<3.2> 11/9/89 RLC Fix bug in window part balloons for grow box.
|
|
<3.1> 11/7/89 RLC Add support for window parts tracking.
|
|
<3.0> 11/2/89 RLC Removed all non-PACK14 routines.
|
|
<2.9> 10/27/89 RLC Fix bug when displaying khmmPict and PicHandle types that didn't
|
|
set origin correctly.
|
|
<2.8> 10/1/89 RLC Added new routine HMGetStyledTE & Updated HMBalloonRect for
|
|
HelpMsg types: StyledTE & STR.
|
|
<2.7> 9/28/89 RLC Fixed bug that didn't correct the Balloon tip if on GDevice
|
|
monitors.
|
|
<2.6> 9/27/89 RLC Fixed positioner for Balloons in ModalDialogs.
|
|
<2.5> 9/25/89 RLC Added more support for MultiFinder appl icon.
|
|
<2.4> 9/22/89 RLC Fixed bug in HMGetGDevice & potential dangling pointer bug in
|
|
HMSaveBalloonBits
|
|
<2.3> 9/21/89 RLC Changed Balloon WDEF ID to 126.
|
|
<2.2> 9/21/89 RLC Added better error checking on message passing to HMBalloonRect
|
|
& HMCalcBalloon routines.
|
|
<2.1> 9/20/89 RLC Bug Fixes, change hmnu scanning routines to make sure
|
|
HMSkipItems never display balloons.
|
|
<2.0> 9/19/89 RLC Bug Fix in ShowMenuTitle.
|
|
<1.9> 9/19/89 RLC Added support for Multifinder Balloons.
|
|
<1.8> 9/18/89 RLC Dialog Template scan routines changed.
|
|
<1.7> 9/15/89 RLC Changed Modal Dialog Tracking to use PopupMenu instead of ICON.'
|
|
<1.6> 9/15/89 RLC Changed Debuggers to Assert calls.
|
|
<1.5> 9/13/89 RLC Repaired Balloon Calculation routines, made MenuTitle Balloons
|
|
better.
|
|
<1.4> 8/29/89 RLC Changed HMCalc & Changed all Balloon routines to use new calling
|
|
convention.
|
|
8/22/89 RCarr Rewrite nearly every interface!
|
|
<1.3> 8/10/89 RLC Added code for autocontents & added patch to _InitWindows
|
|
8/8/89 RCarr Optimize by preallocating Help Layer @ _InitWindows time, fix
|
|
bug that was calling _KillPicture twice when calling
|
|
_DisposeWindow.
|
|
7/31/89 RCarr Added support for autocontents patches for help mgr.
|
|
<1.2> 7/20/89 RLC Added patchcode to support help menu & move HMBalloonRect from C
|
|
to Pascal.
|
|
7/20/89 RCarr Added tons of support stuff & Help Menu
|
|
<1.1> 7/13/89 RLC Add HMBalloonRect to pack
|
|
<1.0> 6/29/89 RLC Created Today.
|
|
5/22/89 RCarr New Today!
|
|
__________________________________________________________________________________________________}
|
|
|
|
|
|
{$ifc UNDEFINED HelpMgrTesting}
|
|
{$setc HelpMgrTesting = false}
|
|
{$endc}
|
|
|
|
|
|
{$setc AllowCloseViewChanges = false}
|
|
|
|
{$ifc HelpMgrTesting}
|
|
{$D+}
|
|
{$INIT+}
|
|
{$elsec}
|
|
{$D-}
|
|
{$INIT-}
|
|
{$endc}
|
|
|
|
UNIT BalloonPack;
|
|
|
|
INTERFACE
|
|
|
|
USES
|
|
Types, QuickDraw, ToolUtils, Fonts, Events, Controls,
|
|
Windows, Dialogs, Files, Menus, Desk, Traps, OSUtils, GestaltEqu,
|
|
Resources, Memory, Packages, FixMath, Errors, Layers, Processes, MFPrivate, MenuMgrPriv, DialogsPriv, Balloons,
|
|
TextServices; {<79>}
|
|
|
|
CONST
|
|
{ Start of internal CONST }
|
|
|
|
hmGetNextHelpItem = -873;
|
|
hmWasAppleMenu = -874;
|
|
|
|
{System STR# resource indexes}
|
|
kHMMenuTitleIndex = 1;
|
|
kHMAboutHelpIndex = 2;
|
|
kHMAboutHelpDisabled = 3;
|
|
kHMReserved = 4;
|
|
kHMWhatIsHide = 5;
|
|
kHMInDragIndex = 6;
|
|
kHMInGrowIndex = 7;
|
|
kHMInGoAwayIndex = 8;
|
|
kHMInZoomIndex = 9;
|
|
kHMMultiFinderIndex = 10;
|
|
kHMInScrollBar = 11;
|
|
kHMInDisabledScrollBar = 12;
|
|
kHMInOtherWindow = 13;
|
|
kHMInLayerPreamble = 14;
|
|
kHMInLayerBody = 15;
|
|
kHMOutsideModalWindow = 16;
|
|
kHMAppleMenuTitle = 17;
|
|
kHMShowHideEnabled = 18;
|
|
kHMHideOthersEnabled = 19;
|
|
kHMShowAllEnabled = 20;
|
|
kHMShowHideDisabled = 21;
|
|
kHMHideOthersDisabled = 22;
|
|
kHMShowAllDisabled = 23;
|
|
kHMEasy1Access = 24;
|
|
kHMEasy2Access = 25;
|
|
kHMEasy3Access = 26;
|
|
kHMActiveApplEnabled = 27;
|
|
kHMActiveApplDisabled = 28;
|
|
kHMActiveApplChecked = 29;
|
|
kHMActiveApplOther = 30;
|
|
kHMActiveApplDisabledTitle = 31;
|
|
kHMActiveApplDisabledItem = 32;
|
|
kHMInFrontFloatingWindow = 33; { for IM, mouse is over a floating window }
|
|
|
|
|
|
|
|
kHMDelayTix = 5;
|
|
|
|
{Dialog item template type}
|
|
kHelpItem = 1;
|
|
|
|
{Dialog item template offsets}
|
|
kHelpItemType = 1; {new, allows the helpItem to contain more than just a resID}
|
|
kHelpItemData = 3; {offset in HelpItem array item in DITL to read ResID}
|
|
kHelpItemOffset = 5; {offset to reach overriding append offset for hdlg}
|
|
|
|
{helpItem type constants}
|
|
kScanhdlg = 1;
|
|
kScanhrct = 2;
|
|
kScanAppendhdlg = 8; { <58> for some reason, this was a 3 in previous, sync up w/ Types.r }
|
|
|
|
|
|
{ internal balloon creation consts (Tweak these values until we die) }
|
|
DicksOffsetPixels = 9; {was 9+3 for Dick's design}
|
|
HMMenuOffsetPixels = 8;
|
|
kHMFrameThickness = 6;
|
|
|
|
kHMVertContentMargin = 13;
|
|
kHMHorizContentMargin = 13;
|
|
kHMScreenBorder = 20;
|
|
kHMCornerDiameter = 16;
|
|
kHMPointerSize = 18;
|
|
kHMBottomMargin = 50;
|
|
|
|
kHMShadowThickness = 2;
|
|
|
|
kHMVertFrameMargin = (kHMPointerSize + (kHMShadowThickness * 4));
|
|
kHMHorizFrameMargin = (kHMPointerSize + (kHMShadowThickness * 4));
|
|
|
|
kHMMiscMargin = 5;
|
|
|
|
maxTETextArea = 50 * 340; {50 lines @ 340 pixels/line}
|
|
MBarHeight = $BAA;
|
|
UnImplementedTrap = $9F;
|
|
|
|
wasWindow = 0;
|
|
wasMenu = 1;
|
|
|
|
kTitleType = 1;
|
|
kDialogType = 2;
|
|
kMenuType = 3;
|
|
kRectType = 4;
|
|
kEAType = 5;
|
|
kWindPartType = 6;
|
|
|
|
{hmgMenuID flag values}
|
|
kwasMultiFinder = -2;
|
|
kwasWindowPart = -3;
|
|
kwasMenuTitle = -4;
|
|
kwasCleared = -5;
|
|
kwasEasyAccess = -6;
|
|
|
|
kGetFont = 0;
|
|
kSetFont = 1;
|
|
|
|
kVariantToRBS = true;
|
|
kRBSToVariant = false;
|
|
|
|
kShiftBit = 0;
|
|
kBottomBit = 1;
|
|
kRightBit = 2;
|
|
|
|
TYPE
|
|
EventRecPtr = ^EventRecord;
|
|
|
|
RBSRecord = Packed RECORD { this is it boys! }
|
|
CASE INTEGER OF
|
|
0: (
|
|
Filler1 : 0..8191;
|
|
rightValue : 0..1; { if 1 then balloon is hanging right }
|
|
bottomValue : 0..1; { if 1 then balloon is hanging down }
|
|
shiftValue : 0..1; { if 1 then balloon has vertical tip }
|
|
);
|
|
1: (
|
|
Whole : INTEGER;
|
|
);
|
|
END;
|
|
|
|
biasRecord = Packed RECORD
|
|
hShift : INTEGER;
|
|
vShift : INTEGER;
|
|
hCornerVector : INTEGER;
|
|
vCornerVector : INTEGER;
|
|
hBaseVector : INTEGER;
|
|
vBaseVector : INTEGER;
|
|
END;
|
|
|
|
|
|
{$I BalloonDefs.p}
|
|
|
|
|
|
FUNCTION __HMShowBalloon(aHelpMsg: HMMessageRecord;
|
|
tip: Point;
|
|
alternateRect: RectPtr;
|
|
tipProc: Ptr;
|
|
theProc,variant: INTEGER;
|
|
method: INTEGER): OsErr;
|
|
FUNCTION __HMRemoveBalloon: OsErr;
|
|
FUNCTION __HMGetBalloons: BOOLEAN;
|
|
FUNCTION __HMSetBalloons(flag: BOOLEAN): OsErr;
|
|
FUNCTION __HMShowMenuBalloon(itemNum,itemMenuID: INTEGER;
|
|
itemFlags,itemReserved: LongInt;
|
|
tip: Point; alternateRect: RectPtr; tipProc: Ptr;
|
|
theProc,variant: INTEGER): OsErr;
|
|
FUNCTION __HMIsBalloon: BOOLEAN;
|
|
FUNCTION __HMSetFont(font: INTEGER): OsErr;
|
|
FUNCTION __HMSetFontSize(fontSize: INTEGER): OsErr;
|
|
FUNCTION __HMGetFont(VAR font: INTEGER): OsErr;
|
|
FUNCTION __HMGetFontSize(VAR fontSize: INTEGER): OsErr;
|
|
FUNCTION __HMSetDialogResID(theResID: INTEGER): OsErr;
|
|
FUNCTION __HMGetDialogResID(VAR theResID: INTEGER): OsErr;
|
|
FUNCTION __HMSetMenuResID(theMenuID,theResID: INTEGER): OsErr;
|
|
FUNCTION __HMGetMenuResID(theMenuID: INTEGER; VAR theResID: INTEGER): OsErr;
|
|
FUNCTION __HMBalloonRect(aHelpMsg: HMMessageRecord; VAR coolRect: Rect): OsErr;
|
|
FUNCTION __HMBalloonPict(aHelpMsg: HMMessageRecord; VAR coolPict: PicHandle): OsErr;
|
|
FUNCTION __HMScanTemplateItems(whichID,whichResFile: INTEGER; whichType: ResType): OsErr;
|
|
FUNCTION __HMGetBalloonWindow(VAR window: WindowPtr): OsErr;
|
|
|
|
{private calls}
|
|
FUNCTION __HMCountDITLHelpItems(d: DialogPtr): INTEGER;
|
|
FUNCTION __HMModalDialogMenuSetup(ModalDialogComingUp: BOOLEAN): OsErr;
|
|
FUNCTION __HMTrackModalHelpItems: OsErr; { tracks items in modal dialogs and alerts }
|
|
|
|
FUNCTION __HMDrawBalloonFrame(rgn: RgnHandle): OsErr;
|
|
FUNCTION __HMSetupBalloonRgns( varCode: INTEGER;
|
|
VAR structRgn: RgnHandle;
|
|
VAR contentRgn: RgnHandle;
|
|
VAR bounds: Rect): OsErr;
|
|
|
|
PROCEDURE __HMShowEasyAccessBalloon;
|
|
PROCEDURE __HMShowTitleBalloon(menuID: INTEGER; flags: LongInt);
|
|
FUNCTION __HMShowContentBalloon(tip: Point; alternateRect: Rect;
|
|
theProc,variant: INTEGER;
|
|
aHelpMsg: HMMessageRecord; options: LongInt): OsErr;
|
|
|
|
FUNCTION __HMGetWindowPartCode(VAR window: WindowPtr): INTEGER;
|
|
FUNCTION __HMShowWindowPartBalloon(window: WindowPtr; windowCode: INTEGER): BOOLEAN;
|
|
FUNCTION __HMFillFrontProcessString(s: StringPtr): OsErr;
|
|
FUNCTION __HMExtractHelpMsg(whichType: ResType;
|
|
whichResID, whichMsg, whichState: INTEGER;
|
|
VAR aHelpMsg: HMMessageRecord): OsErr;
|
|
|
|
|
|
IMPLEMENTATION
|
|
|
|
|
|
FUNCTION __HMGetScreenGDevice(pt: Point): GDHandle; FORWARD;
|
|
FUNCTION __HMSaveBalloonBits(aHelpMsg: HMMessageRecord;
|
|
tip: Point;
|
|
alternateRect: RectPtr;
|
|
tipProc: Ptr;
|
|
variant: INTEGER;
|
|
balloonType: INTEGER): OsErr; FORWARD;
|
|
FUNCTION __HMCalculateBalloon( aHelpMsg: HMMessageRecord;
|
|
tip: Point;
|
|
alternateRect: RectPtr;
|
|
VAR varCode: INTEGER;
|
|
VAR bounds: Rect; VAR pic: PicHandle;
|
|
balloonType: INTEGER;
|
|
abortable: BOOLEAN): OsErr; FORWARD;
|
|
|
|
PROCEDURE __HMTwitchVarCode(isVariantToRBS: BOOLEAN;
|
|
FromValue: INTEGER; VAR ToValue: INTEGER); EXTERNAL;
|
|
PROCEDURE __HMVarCodeToBiasRecord(varCode: INTEGER; VAR bias: biasRecord); EXTERNAL;
|
|
FUNCTION __HMSlopMouse(tip: Point): BOOLEAN; EXTERNAL;
|
|
FUNCTION __HMCallTipProc(tipProc: Ptr;
|
|
tip: Point;
|
|
structure: RgnHandle;
|
|
VAR bounds: Rect;
|
|
VAR varCode: INTEGER): OsErr; EXTERNAL;
|
|
PROCEDURE __HMSetGetFontSizeGlobal(setit: INTEGER; VAR fontsize: LongInt); EXTERNAL;
|
|
FUNCTION __HMSaveBitsInRect(theRect: Rect): PixMapHandle; EXTERNAL;
|
|
PROCEDURE __HMRestoreBitsToRect(thePM: PixMapHandle); EXTERNAL;
|
|
FUNCTION __HMFillCitationString(origString,stuffString: StringPtr;
|
|
key: Char) : OsErr; EXTERNAL;
|
|
FUNCTION __HMCallCustomWDEFCalc(v: INTEGER; w: WindowPtr): INTEGER; EXTERNAL;
|
|
|
|
FUNCTION __HMGetIndHelpMsg(whichType: ResType;
|
|
whichResID, whichMsg, whichState: INTEGER;
|
|
VAR options: LongInt;
|
|
VAR tip: Point;
|
|
altRect: RectPtr;
|
|
VAR theProc: INTEGER; VAR variant: INTEGER;
|
|
VAR aHelpMsg: HMMessageRecord;
|
|
VAR count: INTEGER): OsErr; EXTERNAL;
|
|
FUNCTION __HMBalloonBulk: OsErr; EXTERNAL;
|
|
FUNCTION __HMFillInMenuMessage(menuID,item,resID: INTEGER; flags: LongInt;
|
|
VAR variant: INTEGER;
|
|
VAR aHelpMsg: HMMessageRecord): OsErr; EXTERNAL;
|
|
|
|
FUNCTION __HMFillInDialogMessage( resID,item,whichHelpItem,
|
|
totalHelpItems,state,offset: INTEGER;
|
|
resFile: INTEGER;
|
|
VAR options: LongInt;
|
|
VAR tip: Point; altRect: RectPtr;
|
|
VAR theProc: INTEGER; VAR variant: INTEGER;
|
|
VAR aHelpMsg: HMMessageRecord): OsErr; EXTERNAL;
|
|
|
|
FUNCTION __HMScanHRCTResource(whichWindow: WindowPtr; whichResID: INTEGER; whichPt: Point;
|
|
VAR whichMsg: INTEGER): OsErr; EXTERNAL;
|
|
|
|
FUNCTION __HMGetMenuItemStatus(mh: MenuHandle; flags: LongInt;
|
|
item: INTEGER): INTEGER; EXTERNAL;
|
|
|
|
FUNCTION __HMGetHelpGlobal: HMGlobalPtr; EXTERNAL;
|
|
FUNCTION __HMGetRealWindowHitResult(p: Point; w: WindowPtr): INTEGER; EXTERNAL;
|
|
FUNCTION __HMGetGlobalMouse: Point; EXTERNAL;
|
|
PROCEDURE __HMGetTextFontStuff(VAR theFont: INTEGER; VAR theSize: INTEGER); EXTERNAL;
|
|
FUNCTION __HMShiftKey: BOOLEAN; EXTERNAL;
|
|
PROCEDURE __HMStuffWindowInfo(window: WindowPtr; varCode: INTEGER; bounds: Rect); EXTERNAL;
|
|
PROCEDURE __HMStripNullFromProcessName(s: StringPtr); EXTERNAL;
|
|
|
|
|
|
|
|
{$ifc HelpMgrTesting}
|
|
PROCEDURE Assert(b: BOOLEAN; s: STR255);
|
|
BEGIN
|
|
if b then DebugStr(s);
|
|
END;
|
|
{$endc}
|
|
|
|
PROCEDURE __HMDisposeRgn(r: RgnHandle);
|
|
BEGIN
|
|
if r<>NIL then
|
|
DisposeRgn(r);
|
|
END;
|
|
|
|
FUNCTION __HMCanPictureBeKilled(kind: INTEGER): BOOLEAN; { <59> Code saver }
|
|
BEGIN
|
|
__HMCanPictureBeKilled := (kind <> khmmPict) and (kind <> khmmPictHandle);
|
|
END;
|
|
|
|
FUNCTION __HMIsThisAModalDialog: BOOLEAN;
|
|
VAR class : INTEGER;
|
|
BEGIN
|
|
__HMIsThisAModalDialog := false;
|
|
if GetFrontWindowModalClass(class) = noErr then
|
|
__HMIsThisAModalDialog := (class = dBoxProc);
|
|
END;
|
|
|
|
FUNCTION __HMFillFrontProcessString(s: StringPtr): OsErr;
|
|
VAR PSN : ProcessSerialNumber;
|
|
info : ProcessInfoRec;
|
|
result : OsErr;
|
|
BEGIN
|
|
result := GetFrontProcess(PSN);
|
|
|
|
if result=noErr then
|
|
begin
|
|
with info do
|
|
begin
|
|
processInfoLength := Sizeof(ProcessInfoRec);
|
|
processName := s;
|
|
processAppSpec := NIL;
|
|
end;
|
|
result := GetProcessInformation(PSN,info);
|
|
end;
|
|
|
|
__HMFillFrontProcessString := result;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMGetStyledHandleResource( textRect: Rect;
|
|
textResType: ResType;
|
|
textID: INTEGER): TEHandle;
|
|
VAR hTE : TEHandle;
|
|
hStyl : Handle;
|
|
hText : Handle;
|
|
BEGIN
|
|
__HMGetStyledHandleResource := NIL; { assume that we didn't get it }
|
|
if LongInt(textResType) = LongInt(kHMTETextResType) then
|
|
begin
|
|
hTE := TEStylNew(textRect,textRect);
|
|
if hTE<>NIL then
|
|
begin
|
|
hText := GetResource(kHMTETextResType,textID); { we hope this is purgeable! }
|
|
|
|
if hText<>NIL then { set up the TEHandle w the char data }
|
|
begin
|
|
hStyl := GetResource(kHMTEStyleResType,textID);
|
|
|
|
HLock(hText);
|
|
TESetText(Ptr(hText^),GetHandleSize(hText),hTE);
|
|
HUnlock(hText);
|
|
|
|
if hStyl<>NIL then
|
|
SetStylScrap(0,$7FF,stScrpHandle(hStyl),false,hTE);
|
|
end else
|
|
begin
|
|
if hTE<>NIL then
|
|
TEDispose(hTE);
|
|
hTE := NIL;
|
|
end;
|
|
end;
|
|
__HMGetStyledHandleResource := hTE;
|
|
end;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMBalloonPict(aHelpMsg: HMMessageRecord; VAR coolPict: PicHandle): OsErr;
|
|
VAR tip : Point;
|
|
bounds : Rect;
|
|
varCode : INTEGER;
|
|
BEGIN
|
|
LongInt(tip) := 0;
|
|
varCode := 0;
|
|
__HMBalloonPict := __HMCalculateBalloon(aHelpMsg,tip,NIL,
|
|
varCode,bounds,coolPict,wasWindow,false {can't abort balloon if mouse is moving});
|
|
END;
|
|
|
|
|
|
FUNCTION __HMBalloonRect(aHelpMsg: HMMessageRecord; VAR coolRect: Rect): OsErr;
|
|
VAR aTE : TEHandle;
|
|
fInfo : FontInfo;
|
|
lineHeight : LongInt;
|
|
ph : PicHandle;
|
|
textH : Handle;
|
|
textArea : LongInt;
|
|
ht,wd : LongInt;
|
|
numLines : LongInt;
|
|
r,rp : LongInt;
|
|
tempstr : STR255;
|
|
tempRect : Rect;
|
|
result : INTEGER;
|
|
resizeAble : BOOLEAN;
|
|
tempFont : INTEGER;
|
|
tempSize : INTEGER;
|
|
|
|
|
|
FUNCTION FastSQRT(val: LongInt): LongInt;
|
|
BEGIN
|
|
FastSQRT := BSR(FracSqrt(Fract(val)),15);
|
|
|
|
{ in C: FastSQRT = (long) FracSqrt((Fract)val) >> 15;}
|
|
END;
|
|
|
|
PROCEDURE ResizeTE(teh: TEHandle; width, height: INTEGER);
|
|
VAR ter : Rect;
|
|
BEGIN
|
|
with teh^^ do
|
|
begin
|
|
ter := destRect;
|
|
with ter do
|
|
begin
|
|
bottom := top + height;
|
|
right := left + width;
|
|
end;
|
|
destRect := ter;
|
|
viewRect := ter;
|
|
end;
|
|
TECalText(teh);
|
|
END;
|
|
|
|
|
|
BEGIN
|
|
GetFontInfo(fInfo);
|
|
with fInfo do
|
|
lineHeight := ascent + descent + leading;
|
|
|
|
__HMBalloonRect := noErr;
|
|
|
|
wd := 0;
|
|
ht := 0;
|
|
|
|
aTE := NIL;
|
|
result := noErr;
|
|
resizeAble := false;
|
|
|
|
SetRect(tempRect,5,5,100,100); { Start with this rect initially }
|
|
|
|
case aHelpMsg.hmmHelpType of
|
|
|
|
khmmString,khmmStringRes,khmmSTRRes:
|
|
begin
|
|
with aHelpMsg do
|
|
begin
|
|
tempstr := ''; { zero for failures }
|
|
|
|
if hmmHelpType = khmmString then
|
|
tempstr := hmmString
|
|
|
|
else if hmmHelpType = khmmSTRRes then
|
|
begin
|
|
textH := Handle(GetString(hmmSTRRes));
|
|
if textH<>NIL then
|
|
tempstr := StringHandle(textH)^^;
|
|
end else
|
|
GetIndString(tempstr,hmmStringRes.hmmResID,
|
|
hmmStringRes.hmmIndex);
|
|
|
|
if length(tempstr) > 0 then
|
|
begin
|
|
aTE := TENew(tempRect,tempRect);
|
|
|
|
{$ifc HelpMgrTesting}
|
|
Assert(aTE=NIL,'HMBalloonRect[X]: a te handle was NIL');
|
|
{$endc}
|
|
|
|
if aTE<>NIL then
|
|
begin
|
|
TESetText(pointer(ord(@tempstr)+1),
|
|
length(tempstr),aTE);
|
|
textArea := lineHeight * StringWidth(tempstr);
|
|
|
|
end else result := memFullErr;
|
|
|
|
end else result := paramErr;
|
|
end;
|
|
end;
|
|
|
|
khmmPict,khmmPictHandle:
|
|
begin
|
|
if aHelpMsg.hmmHelpType = khmmPict then
|
|
ph := PicHandle(GetResource('PICT',aHelpMsg.hmmPict))
|
|
else ph := aHelpMsg.hmmPictHandle;
|
|
|
|
if ph<>NIL then
|
|
begin
|
|
with ph^^.picFrame do
|
|
begin
|
|
wd := right-left;
|
|
ht := bottom-top;
|
|
end;
|
|
|
|
end else
|
|
if aHelpMsg.hmmHelpType = khmmPict then
|
|
result := resNotFound
|
|
else result := paramErr;
|
|
|
|
{$ifc HelpMgrTesting}
|
|
Assert(ph=NIL,'HMBalloonRect[2]: a pic handle was NIL');
|
|
{$endc}
|
|
end;
|
|
|
|
khmmTEHandle,khmmTERes:
|
|
begin
|
|
if (aHelpMsg.hmmHelpType = khmmTERes) then
|
|
aTE := __HMGetStyledHandleResource(tempRect,kHMTETextResType,aHelpMsg.hmmTERes)
|
|
else aTE := aHelpMsg.hmmTEHandle;
|
|
|
|
if aTE<>NIL then
|
|
begin
|
|
resizeAble := (aTE^^.txSize<>-1);
|
|
|
|
textH := aTE^^.hText;
|
|
HLock(textH);
|
|
|
|
if resizeAble then
|
|
with aTE^^ do
|
|
begin
|
|
{ <72> don't need these anymore
|
|
tempFont := txFont;
|
|
tempSize := txSize;
|
|
}
|
|
__HMGetTextFontStuff(txFont,txSize);
|
|
{ *** how do we reset the old TEHandle's font & size helpmgr font here? }
|
|
|
|
GetFontInfo(fInfo);
|
|
with fInfo do
|
|
lineHeight := ascent + descent + leading;
|
|
|
|
end else
|
|
lineHeight := TEGetHeight(0,$7FF,aTE) div aTE^^.nLines;
|
|
|
|
textArea := lineHeight * TextWidth(textH^, 0, aTE^^.teLength);
|
|
HUnlock(textH);
|
|
{$IFC NOT theFuture} {<75>}
|
|
if textArea > maxTETextArea then
|
|
result := paramErr;
|
|
{$ENDC}
|
|
end else result := paramErr;
|
|
end;
|
|
|
|
otherwise
|
|
begin
|
|
{$ifc HelpMgrTesting}
|
|
NumToString(aHelpMsg.hmmHelpType,tempstr);
|
|
DebugStr(concat('Bad HelpType (',tempstr,') passed to HMBalloonRect'));
|
|
{$endc}
|
|
|
|
__HMBalloonRect := hmUnknownHelpType;
|
|
Exit(__HMBalloonRect);
|
|
end;
|
|
end;
|
|
|
|
if result<>noErr then
|
|
begin
|
|
__HMBalloonRect := result;
|
|
Exit(__HMBalloonRect);
|
|
end;
|
|
|
|
if aTE<>NIL then { for khmmPict or khmmPictHandle case, don't do resizing}
|
|
begin
|
|
|
|
if textArea=0 then
|
|
r := 0 else
|
|
r := FastSQRT(textArea);
|
|
|
|
ht := (r * 1000) div 1272; {(1272/1000)**2 approx golden ratio}
|
|
|
|
{ make height a multiple of line height }
|
|
rp := ht mod lineHeight;
|
|
if (rp <> 0) then
|
|
ht := ht + lineHeight - rp;
|
|
|
|
numLines := ht div lineHeight;
|
|
|
|
wd := textArea div ht;
|
|
|
|
{ *** make sure longest word fits, someday! }
|
|
|
|
ResizeTE(aTE, wd, ht);
|
|
|
|
while (TEGetHeight(0,$7FF,aTE)>ht) do {loop until the # of lines fits in bounds}
|
|
begin
|
|
if (TEGetHeight(0,$7FF,aTE)>ht) then
|
|
begin
|
|
wd := (ht * 3236) div 2000;
|
|
ResizeTE(aTE, wd, ht);
|
|
end;
|
|
|
|
if (TEGetHeight(0,$7FF,aTE)>ht) then
|
|
begin
|
|
wd := ((ht + lineHeight) * 3236) div 2000;
|
|
ResizeTE(aTE, wd, ht);
|
|
end;
|
|
|
|
if (TEGetHeight(0,$7FF,aTE)>ht) then
|
|
begin
|
|
wd := (ht * 3236) div 2000;
|
|
ht := ht + lineHeight;
|
|
ResizeTE(aTE, wd, ht);
|
|
end;
|
|
end;
|
|
|
|
if (TEGetHeight(0,$7FF,aTE)<ht) then
|
|
begin
|
|
ht := TEGetHeight(0,$7FF,aTE);
|
|
ResizeTE(aTE, wd, ht); {resize again so HMCalc won't have to also}
|
|
end;
|
|
|
|
{ <72> don't reset the font and size of the text edit handle passed, as we've just calculated
|
|
the balloon for this text edit handle using the help mgr font
|
|
if resizeAble then
|
|
begin
|
|
with aTE^^ do
|
|
begin
|
|
txFont := tempFont;
|
|
txSize := tempSize;
|
|
end;
|
|
end;
|
|
}
|
|
|
|
with __HMGetHelpGlobal^ do
|
|
if hmgKeepTEHandle then
|
|
hmgTEHandle := aTE else
|
|
if aHelpMsg.hmmHelpType <> khmmTEHandle then {don't toss the supplied handle in khmmTEHandle case}
|
|
TEDispose(aTE);
|
|
end;
|
|
|
|
SetRect(coolRect,0,0,wd,ht);
|
|
END;
|
|
|
|
|
|
FUNCTION __HMGetBalloons: BOOLEAN;
|
|
|
|
BEGIN
|
|
|
|
__HMGetBalloons := __HMGetHelpGlobal^.hmgWhatIs;
|
|
END;
|
|
|
|
{$ifc AllowCloseViewChanges}
|
|
FUNCTION __HMIsCloseViewActive: BOOLEAN;
|
|
VAR result : LongInt;
|
|
BEGIN
|
|
__HMIsCloseViewActive := true;
|
|
(*
|
|
__HMIsCloseViewActive := false;
|
|
if Gestalt('BSDa',result) = noErr then
|
|
__HMIsCloseViewActive := (result <> 0);
|
|
*)
|
|
END;
|
|
{$endc}
|
|
|
|
FUNCTION __HMRemoveBalloon: OsErr;
|
|
VAR window : WindowPtr;
|
|
windowPic : PicHandle;
|
|
oldPort : GrafPtr;
|
|
wPort : GrafPtr;
|
|
oldLayer : LayerPtr;
|
|
floatLayer : LayerPtr;
|
|
bounds : Rect;
|
|
refcon : LongInt;
|
|
balloonDown : BOOLEAN;
|
|
pt : Point;
|
|
windowCode : INTEGER;
|
|
floatwindowCode : INTEGER;
|
|
ignoreErr : OSErr;
|
|
BEGIN
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
{$ifc AllowCloseViewChanges}
|
|
if __HMIsBalloon then
|
|
if __HMIsCloseViewActive then
|
|
if __HMShiftKey then
|
|
begin
|
|
hmgCloseViewCount := 1 {means remove current balloon when the shift key goes up};
|
|
|
|
__HMRemoveBalloon := hmCloseViewActive;
|
|
exit(__HMRemoveBalloon);
|
|
end;
|
|
{$endc}
|
|
|
|
|
|
|
|
if not hmgWhatIs then
|
|
__HMRemoveBalloon := hmHelpDisabled;
|
|
|
|
window := hmgWindow;
|
|
balloonDown := false; { assume that a balloon wasn't removed }
|
|
|
|
|
|
if (window<>NIL) then
|
|
begin
|
|
if hmgLayer<>NIL then
|
|
oldLayer := SwapCurLayer(hmgLayer);
|
|
|
|
windowPic := GetWindowPic(window); { <59> call toolbox instead of WindowPeeking record }
|
|
refcon := GetWRefCon(window); { <59> call toolbox instead of WindowPeeking record }
|
|
|
|
if windowPic<>NIL then { <58> make sure picture was actually there! }
|
|
if __HMCanPictureBeKilled(refcon) then { <59> don't 'kill' a resource! }
|
|
KillPicture(windowPic); { <54> but be sure to kill the picture }
|
|
|
|
SetWindowPic(window,NIL); { <59> call toolbox instead of WindowPeeking record }
|
|
|
|
if window = hmgHelpWindow then { we don't toss our window <54> }
|
|
begin
|
|
SetWRefCon(window,0); { <59> call toolbox instead of WindowPeeking record }
|
|
HideWindow(window); { just hide it <54> }
|
|
end else
|
|
DisposeWindow(window); { this does a KillPicture(windowPic) automagically! }
|
|
|
|
if hmgLayer<>NIL then
|
|
SetCurLayer(oldLayer);
|
|
|
|
hmgWindow := NIL;
|
|
hmgTitleBalloon := 0; { clear the flag that says that a menu title balloon is up }
|
|
hmgItemNum := -1;
|
|
|
|
balloonDown := true;
|
|
end;
|
|
|
|
if hmgSavedBitsHandle<>NIL then { <57> we don't need to set wmgrport anymore }
|
|
begin
|
|
__HMRestoreBitsToRect(hmgSavedBitsHandle);
|
|
|
|
hmgSavedBitsHandle := NIL; { zero the handle [flag] }
|
|
hmgItemNum := -1; { force new balloon to get shown }
|
|
balloonDown := true;
|
|
end;
|
|
|
|
with hmgSlopRect do
|
|
begin
|
|
LongInt(topLeft) := 0;
|
|
LongInt(botRight):= 0;
|
|
end;
|
|
|
|
with hmgItemRect do
|
|
begin
|
|
LongInt(topLeft) := 0;
|
|
LongInt(botRight):= 0;
|
|
end;
|
|
|
|
hmgLastPartCode := 0;
|
|
hmgLastWindowPtr := NIL;
|
|
|
|
hmgLastMenuID := -1;
|
|
hmgLastEnabled := 0;
|
|
hmgLastItem := 0;
|
|
|
|
hmgState := -1;
|
|
hmgMenuID := kwasCleared;
|
|
|
|
{$ifc AllowCloseViewChanges}
|
|
if balloonDown then
|
|
hmgCloseViewCount := 0;
|
|
{$endc}
|
|
|
|
end; { with __HMGetHelpGlobal^ }
|
|
|
|
{ do this nonsense 'cuz the WindowMgr clips the WmgrPort to menubar,
|
|
the result is that the pulldown menus get drawn w/o being erased first! }
|
|
SetRect(bounds,-32768, -32768, 32767,32767);
|
|
GetPort(oldPort);
|
|
GetWMgrPort(wPort);
|
|
SetPort(wPort);
|
|
ClipRect(bounds);
|
|
SetPort(oldport);
|
|
|
|
if balloonDown then
|
|
__HMRemoveBalloon := noErr
|
|
else __HMRemoveBalloon := hmNoBalloonUp;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMIsBalloon: BOOLEAN;
|
|
BEGIN
|
|
with __HMGetHelpGlobal^ do
|
|
__HMIsBalloon := (hmgWindow<>NIL) | (hmgSavedBitsHandle<>NIL);
|
|
END;
|
|
|
|
|
|
FUNCTION __HMSetBalloons(flag: BOOLEAN): OsErr; { the entire routine was rewritten <54> RLC }
|
|
VAR aLayer : LayerPtr;
|
|
fontAndSize : HMFontRecord;
|
|
gp : HMGlobalPtr;
|
|
oldLayer : LayerPtr;
|
|
oldZone : THz;
|
|
bounds : Rect;
|
|
chain : WindowPeek;
|
|
aMenu : MenuHandle;
|
|
result : OsErr;
|
|
BEGIN
|
|
__HMSetBalloons := noErr; { in case we're exiting early }
|
|
|
|
gp := __HMGetHelpGlobal;
|
|
if gp<>NIL then
|
|
with gp^ do
|
|
begin
|
|
if hmgWhatIs = flag then exit(__HMSetBalloons); { the state is already setup so exit now }
|
|
|
|
{ reset the script info again }
|
|
LongInt(fontAndSize) := GetScript(INTEGER(GetEnvirons(smSysScript)), smScriptHelpFondSize);
|
|
LongInt(hmgFontAndSize) := LongInt(fontAndSize); { all this LongInt stuff is a code saver }
|
|
|
|
if flag then { let's create the layer and window now! }
|
|
begin
|
|
chain := LayerPeek(GetRootLayer)^.subWindows; { get the first children of root }
|
|
if chain<>NIL then { there is a child }
|
|
begin
|
|
{ *** Assert if the child is our help layer then everything is set already (how could this happen?) }
|
|
{$ifc HelpMgrTesting}
|
|
Assert(chain = WindowPeek(hmgLayer),'HMSetBalloons: Help layer was not deallocated!');
|
|
|
|
{walk the children of the root, looking for our help layer}
|
|
repeat
|
|
chain := chain^.nextWindow;
|
|
until (chain = NIL) | (chain = WindowPeek(hmgLayer));
|
|
|
|
Assert(chain<>NIL,'HMSetBalloons: Help layer was still in layer chain!');
|
|
{$endc}
|
|
|
|
{ get and set the rootlayer }
|
|
oldLayer := SwapCurLayer(GetRootLayer);
|
|
|
|
oldZone := GetZone; { get the current heap zone }
|
|
SetZone(SystemZone); { point at the system heap }
|
|
|
|
aLayer := NIL;
|
|
|
|
{ create the help layer, having its rgns in sys heap }
|
|
result := NewLayer(aLayer,true{visible},true{neveractive},
|
|
pointer(-1){infront},LongInt($BADFACE){refcon});
|
|
|
|
if result<>noErr then
|
|
begin
|
|
{$ifc HelpMgrTesting}
|
|
DebugStr('HMSetBalloons: Unable to create a help layer');
|
|
{$endc}
|
|
|
|
aLayer := NIL; { this seems to be garbage sometimes when there isn't the memory }
|
|
end else
|
|
begin
|
|
SetCurLayer(aLayer);
|
|
|
|
SetRect(bounds,0,0,100,100);
|
|
hmgHelpWindow := NewWindow(@hmgHelpWRecord,bounds,'Balloon',
|
|
false,(16 * kBalloonWDEFID) + 0 {default varCode},pointer(-1),false,0);
|
|
end;
|
|
|
|
SetZone(oldZone); { restore the heap zone }
|
|
hmgLayer := aLayer; { make our globals have that layer }
|
|
SetCurLayer(oldLayer); { restore the current layer }
|
|
|
|
end; { else there wasn't any root layer (how can this happen?) }
|
|
end else
|
|
begin { tear down the layer and window }
|
|
{$ifc HelpMgrTesting}
|
|
if hmgHelpWindow = NIL then
|
|
begin
|
|
DebugStr('HMSetBalloons: we tried to deallocate the help window twice!');
|
|
exit(__HMSetBalloons);
|
|
end;
|
|
|
|
if hmgLayer = NIL then
|
|
begin
|
|
DebugStr('HMSetBalloons: we tried to deallocate the help layer twice!');
|
|
exit(__HMSetBalloons);
|
|
end;
|
|
{$endc}
|
|
|
|
if __HMRemoveBalloon=noErr then; { <63> always hide the balloons if help is turned off }
|
|
|
|
oldLayer := SwapCurLayer(hmgLayer);
|
|
|
|
CloseWindow(hmgHelpWindow); { close the window because we've got our own storage for the wRecord }
|
|
hmgHelpWindow := NIL;
|
|
DisposeWindow(hmgLayer); { dispose window because we allocated it in the System heap via NIL }
|
|
hmgLayer := NIL;
|
|
|
|
SetCurLayer(oldLayer); { restore the current layer }
|
|
end;
|
|
|
|
hmgWhatIs := flag; { Set the HMGetBalloons global flag }
|
|
end;
|
|
|
|
__HMSetBalloons := noErr;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMShowBalloon(aHelpMsg: HMMessageRecord;
|
|
tip: Point;
|
|
alternateRect: RectPtr;
|
|
tipProc: Ptr;
|
|
theProc,variant: INTEGER;
|
|
method: INTEGER): OsErr;
|
|
|
|
VAR oldPort : GrafPtr;
|
|
oldZone : THz;
|
|
bounds : Rect;
|
|
wBounds : Rect;
|
|
temprect : Rect;
|
|
gp : HMGlobalPtr;
|
|
pic : PicHandle;
|
|
window : WindowPtr;
|
|
oldLayer : LayerPtr;
|
|
initialWindowPtr: WindowPtr;
|
|
initialPartCode : INTEGER;
|
|
procID : INTEGER;
|
|
varCode : INTEGER;
|
|
wVarCode : INTEGER;
|
|
result : OsErr;
|
|
oldState : SignedByte;
|
|
|
|
PROCEDURE __HMSetLastGlobals;
|
|
BEGIN
|
|
with gp^ do
|
|
begin
|
|
if alternateRect<>NIL then
|
|
hmgSlopRect := alternateRect^ else
|
|
SetRect(hmgSlopRect,0,0,0,0);
|
|
|
|
hmgLastPartCode := initialPartCode;
|
|
hmgLastWindowPtr := initialWindowPtr;
|
|
|
|
if hmgLastWindowPtr<>NIL then
|
|
begin
|
|
if BAnd($C000,CGrafPtr(hmgLastWindowPtr)^.portVersion)<>0 then
|
|
temprect := CGrafPtr(hmgLastWindowPtr)^.portPixMap^^.bounds
|
|
else temprect := hmgLastWindowPtr^.portBits.bounds;
|
|
|
|
with hmgLastWindowPtr^.portRect do
|
|
begin
|
|
hmgLastWidth := (right-left);
|
|
hmgLastHeight := (bottom-top);
|
|
hmgLastLeft := temprect.left - left;
|
|
hmgLastTop := temprect.top - top;
|
|
end;
|
|
end else
|
|
begin
|
|
hmgLastWidth := 0;
|
|
hmgLastHeight := 0;
|
|
hmgLastLeft := 0;
|
|
hmgLastTop := 0;
|
|
end;
|
|
|
|
|
|
end;
|
|
END;
|
|
BEGIN
|
|
gp := __HMGetHelpGlobal;
|
|
|
|
if __HMGetBalloons
|
|
{$ifc AllowCloseViewChanges}
|
|
& (gp^.hmgCloseViewCount = 0) {CloseView is active, shift key was down, & balloon was up}
|
|
{$endc} then
|
|
begin
|
|
__HMShowBalloon := hmBalloonAborted;
|
|
|
|
|
|
|
|
if __HMRemoveBalloon=noErr then;
|
|
|
|
initialPartCode := __HMGetWindowPartCode(initialWindowPtr);
|
|
|
|
method := BAnd($0007,method); { strip off hi bits of method }
|
|
|
|
{ *** we currently support only:
|
|
kHMRegularWindow = 0; Create a regular window floating above all windows
|
|
kHMSaveBitsNoWindow = 1; Just save the bits and draw (for MDEF calls
|
|
kHMSaveBitsWindow = 2; Regular window, save bits behind, AND generate update event
|
|
}
|
|
|
|
if method = kHMSaveBitsNoWindow then
|
|
begin
|
|
if theProc<>0 then {only support proc 0 when saving bits}
|
|
__HMShowBalloon := hmOperationUnsupported else
|
|
begin
|
|
result := __HMSaveBalloonBits(aHelpMsg,tip,alternateRect,
|
|
tipProc,variant,wasWindow);
|
|
|
|
if result=noErr then
|
|
__HMSetLastGlobals;
|
|
|
|
__HMShowBalloon := result;
|
|
end;
|
|
end else
|
|
begin { it must have been a kHMRegularWindow or kHMSaveBitsWindow method }
|
|
GetPort(oldPort);
|
|
|
|
with gp^ do
|
|
if hmgLayer<>NIL then
|
|
oldLayer := SwapCurLayer(hmgLayer);
|
|
|
|
varCode := variant;
|
|
result := __HMCalculateBalloon(aHelpMsg,tip,alternateRect,
|
|
varCode,bounds,pic,wasWindow,true { will abort balloon if mouse moves });
|
|
if result = noErr then
|
|
begin
|
|
if theProc<>0 then
|
|
begin
|
|
procID := theProc;
|
|
varCode := variant; { override just calculated varCode in __HMCalculateBalloon
|
|
as we have our own defProc whose variant could be different }
|
|
|
|
if GetResource('WDEF',theProc)=NIL then { we couldn't load the custom 'WDEF' }
|
|
result := resNotFound;
|
|
end else
|
|
procID := kBalloonWDEFID; { use our balloon 'WDEF' }
|
|
|
|
if result = noErr then
|
|
with gp^ do
|
|
begin
|
|
if theProc<>0 then
|
|
begin
|
|
oldZone := GetZone; { get the current heap zone }
|
|
SetZone(SystemZone); { point at the system heap }
|
|
|
|
{ only call new window if theProc isn't our balloon definition <54> }
|
|
window := NewWindow(NIL,bounds,'appBalloon',false,(16 * procID) + varCode,
|
|
pointer(-1),false,0);
|
|
|
|
SetZone(oldZone);
|
|
end else
|
|
begin
|
|
{ change our balloon window's defproc variant to be the new one <54> }
|
|
__HMStuffWindowInfo(hmgHelpWindow,varCode,bounds);
|
|
|
|
{ make the showwindow call recalculate the window's regions <54> }
|
|
with WindowPeek(hmgHelpWindow)^ do
|
|
begin
|
|
SetEmptyRgn(strucRgn);
|
|
SetEmptyRgn(contRgn);
|
|
end;
|
|
|
|
{ make the current balloon our window <54> }
|
|
window := hmgHelpWindow;
|
|
end;
|
|
|
|
if window<>NIL then
|
|
begin
|
|
SetPort(window);
|
|
|
|
if (method = kHMSaveBitsWindow) | (tipProc<>NIL) then { <58> check tip procedure too }
|
|
begin
|
|
if __HMCallCustomWDEFCalc(wCalcRgns,window)=noErr then;
|
|
|
|
if tipProc<>NIL then { <58> give the caller a chance to abort }
|
|
begin
|
|
with WindowPeek(window)^ do { <58> using the balloon window informationÉ }
|
|
begin
|
|
wBounds := bounds;
|
|
wVarCode := varCode;
|
|
|
|
result := __HMCallTipProc(tipProc,tip,strucRgn,wBounds,wVarCode); { <58> see if caller doesn't like balloon }
|
|
|
|
if result = noErr then { <58> balloon might have changed a bit, so update info }
|
|
if (wVarCode<>varCode) |
|
|
(LongInt(wBounds.topLeft)<>LongInt(bounds.topLeft)) |
|
|
(LongInt(wBounds.botRight)<>LongInt(bounds.botRight)) then
|
|
begin
|
|
bounds := wBounds;
|
|
varCode := wVarCode;
|
|
|
|
__HMStuffWindowInfo(window,varCode,bounds); { <58> restuff the window info }
|
|
|
|
SetEmptyRgn(strucRgn); { <58> will cause window to recalc when visible }
|
|
SetEmptyRgn(contRgn);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if result = noErr then { <58> either there wasn't a tip proc or caller didn't abort }
|
|
if (method = kHMSaveBitsWindow) then
|
|
with WindowPeek(window)^ do
|
|
begin
|
|
wBounds := strucRgn^^.rgnBBox;
|
|
hmgSavedBitsHandle := __HMSaveBitsInRect(wBounds); { save bits behind window b4 putting up window }
|
|
|
|
{ make the ShowWindow() call recalculate the window's regions }
|
|
SetEmptyRgn(strucRgn);
|
|
SetEmptyRgn(contRgn);
|
|
end;
|
|
end;
|
|
|
|
if result = noErr then
|
|
begin
|
|
SetWindowPic(window,pic); { <59> Call toolbox instead of WindowPeeking record }
|
|
SetWRefCon(window,aHelpMsg.hmmHelpType); { <59> Call toolbox instead of WindowPeeking record }
|
|
ShowWindow(window);
|
|
|
|
{ The code below makes the balloon contents appear immediately
|
|
instead of waiting for the window manager to draw the picture }
|
|
|
|
BeginUpdate(window);
|
|
|
|
if pic^ = NIL then { <58> the pic was really a resource that was purged }
|
|
LoadResource(Handle(pic));
|
|
|
|
if pic^ <> NIL then { <58> the pic was successfully reloaded (if purged) }
|
|
begin
|
|
oldState := HGetState(Handle(pic)); { <58> remember pic handle's state }
|
|
HNoPurge(Handle(pic)); { <58> keep it around (if resource) }
|
|
|
|
with pic^^.picFrame do
|
|
SetRect(bounds,0,0,right-left,bottom-top); { <58> force picture to window coords }
|
|
|
|
DrawPicture(pic,bounds);
|
|
HSetState(Handle(pic),oldState);
|
|
end;
|
|
|
|
EndUpdate(window);
|
|
|
|
hmgWindow := window;
|
|
|
|
end else { there was an abort returned from calling tip proc, so toss the window }
|
|
begin
|
|
if window <> hmgHelpWindow then
|
|
begin
|
|
DisposeWindow(window); { <58> Dispose the wind if the window was custom }
|
|
pic := NIL; { *** } { <59> NIL picHandle, DisposeWindow() kills the pic automatically }
|
|
end;
|
|
|
|
if (hmgSavedBitsHandle <> NIL) then
|
|
begin
|
|
if DiscardBits(LongInt(hmgSavedBitsHandle))=noErr then;
|
|
hmgSavedBitsHandle := NIL; { <58> NIL this in case someone calls HMRemoveBalloon() }
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
if result <> noErr then { some sort of error or abort occurred, so toss the picture (if any) }
|
|
if pic <> NIL then
|
|
if __HMCanPictureBeKilled(aHelpMsg.hmmHelpType) then { <59> KillPicture if type wasn't resource based }
|
|
KillPicture(pic);
|
|
|
|
__HMShowBalloon := result;
|
|
|
|
with gp^ do
|
|
if (hmgLayer<>NIL) then
|
|
SetCurLayer(oldLayer);
|
|
|
|
SetPort(oldPort);
|
|
|
|
__HMSetLastGlobals;
|
|
end;
|
|
|
|
end else __HMShowBalloon := hmHelpDisabled;
|
|
END;
|
|
|
|
|
|
|
|
|
|
PROCEDURE __HMShowTitleBalloon(menuID: INTEGER; flags: LongInt);
|
|
VAR aHelpMsg : HMMessageRecord;
|
|
altRect : Rect;
|
|
pt : Point;
|
|
width : INTEGER;
|
|
variant : INTEGER;
|
|
resID : INTEGER;
|
|
result : OsErr;
|
|
gp : HMGlobalPtr;
|
|
BEGIN
|
|
gp := __HMGetHelpGlobal;
|
|
|
|
with gp^ do
|
|
if (hmgItemNum = 0) then if (menuID = hmgMenuID) then
|
|
Exit(__HMShowTitleBalloon);
|
|
|
|
if __HMGetMenuResID(menuID,resID)<>noErr then
|
|
resID := -1;
|
|
|
|
variant := 0; { default in the case of the Apple Menu }
|
|
|
|
if __HMFillInMenuMessage(menuID,0,resID,flags,variant,aHelpMsg)<>noErr then
|
|
Exit(__HMShowTitleBalloon);
|
|
|
|
if GetMenuTitleRect(menuID,altRect)=noErr then;
|
|
with altRect do
|
|
begin
|
|
width := right-left;
|
|
pt.h := left + BSR(width,1);
|
|
pt.v := IntegerPtr(MBarHeight)^;
|
|
|
|
top := top - 1;
|
|
bottom := top + pt.v;
|
|
end;
|
|
|
|
result := __HMShowBalloon(aHelpMsg,pt,@altRect,NIL,0,variant,2);
|
|
|
|
if result=noErr then
|
|
with gp^ do
|
|
begin
|
|
hmgLastMenuID := menuID;
|
|
hmgLastEnabled := flags;
|
|
hmgLastItem := 0;
|
|
|
|
hmgItemNum := 0;
|
|
hmgMenuID := menuID;
|
|
hmgTitleBalloon := 1; { when this is non-zero, the show hide patch won't toss this balloon }
|
|
end;
|
|
END;
|
|
|
|
|
|
|
|
|
|
|
|
FUNCTION __HMShowMenuBalloon(itemNum,itemMenuID: INTEGER;
|
|
itemFlags,itemReserved: LongInt;
|
|
tip: Point; alternateRect: RectPtr; tipProc: Ptr;
|
|
theProc,variant: INTEGER): OsErr;
|
|
VAR aHelpMsg : HMMessageRecord;
|
|
menuBarRect : Rect;
|
|
menuHeight : INTEGER;
|
|
overVariant : INTEGER;
|
|
gp : HMGlobalPtr;
|
|
pt : Point;
|
|
result : OsErr;
|
|
resID : INTEGER;
|
|
BEGIN
|
|
gp := __HMGetHelpGlobal;
|
|
|
|
__HMShowMenuBalloon := hmSameAsLastBalloon; {assume that it's already displayed}
|
|
|
|
if __HMGetBalloons
|
|
|
|
{$ifc AllowCloseViewChanges}
|
|
& (gp^.hmgCloseViewCount = 0) {CloseView is active, shift key was down, & balloon was up}
|
|
{$endc}
|
|
then
|
|
with gp^ do
|
|
begin
|
|
if (hmgLastItem = itemNum) then
|
|
if (hmgLastMenuID = itemMenuID) then
|
|
if (hmgLastEnabled = itemFlags) then EXIT(__HMShowMenuBalloon);
|
|
|
|
if itemNum <= 0 then { if 0 then mouse was in a title, if -1 then it was a dash }
|
|
begin
|
|
if __HMRemoveBalloon=noErr then; { toss any existing Balloons, if 0 or -1 }
|
|
Exit(__HMShowMenuBalloon);
|
|
end;
|
|
|
|
if __HMGetMenuResID(itemMenuID,resID)<>noErr then
|
|
resID := -1;
|
|
|
|
if alternateRect<>NIL then
|
|
hmgItemRect := alternateRect^;
|
|
|
|
hmgItemNum := itemNum;
|
|
hmgMenuID := itemMenuID;
|
|
|
|
overVariant := variant;
|
|
|
|
{ <59> Ignore itemReserved parameter menu or item is disabled }
|
|
if (itemReserved <> 0) then
|
|
begin
|
|
IF not BTST(itemFlags,0) THEN { The whole menu is disabled }
|
|
itemReserved := 0
|
|
ELSE IF (itemNum <= 31) THEN { The item has a flag bit }
|
|
IF NOT BTST(itemFlags,itemNum) THEN { That item is disabled }
|
|
itemReserved := 0;
|
|
end;
|
|
|
|
if (itemReserved = 0) or (ODD(itemReserved)) then { we need to fetch the msg out of the 'hmnu' resource }
|
|
begin
|
|
result := __HMFillInMenuMessage(itemMenuID,itemNum,resID,itemFlags,overVariant,aHelpMsg);
|
|
|
|
if result<>noErr then { we didn't find anything in the 'hmnu' or the 'hmnu' was missing }
|
|
begin
|
|
__HMShowMenuBalloon := result;
|
|
exit(__HMShowMenuBalloon);
|
|
end;
|
|
|
|
end else { let's assume that itemReserved is a StringHandle to the message string }
|
|
with aHelpMsg do
|
|
begin
|
|
hmmHelpType := khmmString;
|
|
hmmString := StringHandle(itemReserved)^^; { copy the string data }
|
|
result := noErr;
|
|
end;
|
|
|
|
with aHelpMsg do
|
|
if hmmHelpType = khmmString then
|
|
if length(hmmString)=0 then
|
|
begin
|
|
__HMShowMenuBalloon := paramErr;
|
|
exit(__HMShowMenuBalloon);
|
|
end;
|
|
|
|
if overVariant<>0 then
|
|
variant := overVariant;
|
|
|
|
result := __HMSaveBalloonBits(aHelpMsg,tip,alternateRect,tipProc,variant,wasMenu);
|
|
|
|
if result=noErr then
|
|
begin
|
|
if alternateRect<>NIL then
|
|
hmgSlopRect := alternateRect^
|
|
else SetRect(hmgSlopRect,0,0,0,0);
|
|
|
|
hmgLastItem := itemNum;
|
|
hmgLastMenuID := itemMenuID;
|
|
hmgLastEnabled := itemFlags;
|
|
end;
|
|
|
|
end else
|
|
result := hmHelpDisabled;
|
|
|
|
__HMShowMenuBalloon := result;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMSetFont(font: INTEGER): OsErr;
|
|
VAR fontlong : LongInt;
|
|
BEGIN
|
|
__HMSetGetFontSizeGlobal(kGetFont,fontlong);
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
hmgFontAndSize.hmgFont := font;
|
|
__HMSetGetFontSizeGlobal(kSetFont,LongInt(hmgFontAndSize));
|
|
end;
|
|
__HMSetFont := noErr;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMSetFontSize(fontSize: INTEGER): OsErr;
|
|
VAR fontlong : LongInt;
|
|
BEGIN
|
|
__HMSetGetFontSizeGlobal(kGetFont,fontlong);
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
hmgFontAndSize.hmgFontSize := fontSize;
|
|
__HMSetGetFontSizeGlobal(kSetFont,LongInt(hmgFontAndSize));
|
|
end;
|
|
__HMSetFontSize := noErr;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMGetFont(VAR font: INTEGER): OsErr;
|
|
BEGIN
|
|
font := __HMGetHelpGlobal^.hmgFontAndSize.hmgFont;
|
|
__HMGetFont := noErr;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMGetFontSize(VAR fontSize: INTEGER): OsErr;
|
|
BEGIN
|
|
fontSize := __HMGetHelpGlobal^.hmgFontAndSize.hmgFontSize;
|
|
__HMGetFontSize := noErr;
|
|
END;
|
|
|
|
|
|
{ <58> HMFind now will find BOTH menu & dialog PSN driven indices in open apps }
|
|
FUNCTION __HMFind(queue: HHMHelpQueueRecord; theMenuID: INTEGER;
|
|
VAR index: INTEGER; PSN: ProcessSerialNumber): INTEGER;
|
|
VAR i : INTEGER;
|
|
count : INTEGER;
|
|
BEGIN
|
|
__HMFind := -1; { say we didn't find it in the array }
|
|
|
|
if queue<>NIL then
|
|
begin
|
|
count := queue^^.queueCount;
|
|
for i := 1 to count do
|
|
with queue^^.queueRecords[i] do
|
|
begin
|
|
if (theMenuID = slotID) then { theMenuID will always be equal when searching the dialog queue }
|
|
if (PSN.lowLongOfPSN = slotPID.lowLongOfPSN) then
|
|
if (PSN.highLongOfPSN = slotPID.highLongOfPSN) then
|
|
begin
|
|
__HMFind := slotResID;
|
|
index := i;
|
|
leave;
|
|
end;
|
|
end;
|
|
end;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMSetDialogResID(theResID: INTEGER): OsErr; { <58> rewritten to work with the current PSN instead of just one index }
|
|
VAR i : INTEGER;
|
|
result : OsErr;
|
|
offset : LongInt;
|
|
p : LongInt;
|
|
queue : HHMHelpQueueRecord;
|
|
PSN : ProcessSerialNumber;
|
|
BEGIN
|
|
result := GetCurrentProcess(PSN); { <58> make this work for the current process who is assigning the res ID }
|
|
|
|
if result=noErr then { <58> only use Process IDs that are good }
|
|
begin
|
|
queue := __HMGetHelpGlobal^.hmgDialogQueue; { <58> use the dialog queue }
|
|
|
|
if __HMFind(queue,0 {allow only 1 entry in dialogs},i,PSN)<>-1 then { <58> we found a setup index, just replace the record's data }
|
|
begin
|
|
if theResID = -1 then { <58> remove this record from our queue }
|
|
begin
|
|
{believe it or not, the calculation below IS 32 bit clean}
|
|
|
|
p := ord4(@queue^^.queueRecords[i]); { <58> }
|
|
offset := p - ord4(queue^); { <58> }
|
|
|
|
{ <58> this does a SetHandleSize smaller so it should always (gulp!) succeed }
|
|
if Munger(Handle(queue),offset,NIL,SIZEOF(HMHelpSlot),Ptr(-1),0)=0 then; { <58> }
|
|
|
|
with queue^^ do
|
|
queueCount := queueCount - 1; { <58> }
|
|
|
|
{ *** <58> do we need to hide any currently displayed balloon here? }
|
|
|
|
end else
|
|
queue^^.queueRecords[i].slotResID := theResID; { <58> }
|
|
|
|
end else { <58> the ID returned from HMFind was -1 which means add a new element to the queue }
|
|
begin
|
|
SetHandleSize(Handle(queue), GetHandleSize(Handle(queue)) + SIZEOF(HMHelpSlot)); { <58> }
|
|
|
|
result := memError; { <58> }
|
|
|
|
if result=noErr then { <58> }
|
|
begin
|
|
with queue^^ do { <58> }
|
|
begin
|
|
queueCount := queueCount + 1;
|
|
with queueRecords[queueCount] do { <58> }
|
|
begin
|
|
{queueRecords[queueCount].}slotPID := PSN; { <58> }
|
|
{queueRecords[queueCount].}slotResID := theResID; { <58> }
|
|
{queueRecords[queueCount].}slotID := 0; { <58> }
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
__HMSetDialogResID := result; { <58> }
|
|
END;
|
|
|
|
|
|
FUNCTION __HMGetDialogResID(VAR theResID: INTEGER): OsErr;
|
|
VAR i : INTEGER;
|
|
PSN : ProcessSerialNumber;
|
|
BEGIN
|
|
__HMGetDialogResID := resNotFound; { <58> assume that we didn't find any dialog res id assignment }
|
|
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
if hmgDialogQueue^^.queueCount > 0 then { <58> quick check to see if anybody has ever overridden any dialog res ID }
|
|
if GetCurrentProcess(PSN)=noErr then { <58> only use Process IDs that are good }
|
|
begin
|
|
theResID := __HMFind(hmgDialogQueue,0,i,PSN); { <58> returns assigned res id for the PSN's dialog override }
|
|
if theResID<>-1 then
|
|
__HMGetDialogResID := noErr; { <58> return noErr if we found an assignment }
|
|
end;
|
|
end;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMSetMenuResID(theMenuID,theResID: INTEGER): OsErr; { <58> now can return ProcessMgr error by calling GetCurrentProcess }
|
|
VAR i : INTEGER;
|
|
result : OsErr;
|
|
offset : LongInt;
|
|
p : LongInt;
|
|
queue : HHMHelpQueueRecord;
|
|
PSN : ProcessSerialNumber;
|
|
BEGIN
|
|
result := GetCurrentProcess(PSN);
|
|
if result=noErr then { only use Process IDs that are good }
|
|
begin
|
|
__HMSetMenuResID := noErr;
|
|
|
|
queue := __HMGetHelpGlobal^.hmgMenuQueue;
|
|
|
|
if __HMFind(queue,theMenuID,i,PSN)<>-1 then { we found this theMenuID in the list already, returns found index in i for array }
|
|
begin
|
|
if theResID = -1 then { remove this record }
|
|
begin
|
|
{believe it or not, the calculation below IS 32 bit clean}
|
|
p := ord4(@queue^^.queueRecords[i]); {ord(Handle(queue^^.queueRecords[i])^);}
|
|
offset := p - ord4(queue^);
|
|
|
|
{ the following routine will remove the data at the given offset:
|
|
offset := p - ord(queue^);
|
|
count to remove := SIZEOF(record); (size of our record HMHelpSlot)
|
|
|
|
the trick to munger in this case below is that the last parameter must be zero
|
|
as we're not replacing anything & munger calls SetHandleSize for us!
|
|
and since this is a delete (SetHandleSize smaller), it will always (gulp!) succeedÉ }
|
|
|
|
if Munger(Handle(queue),offset,NIL,SIZEOF(HMHelpSlot),Ptr(-1),0)=0 then;
|
|
|
|
with queue^^ do
|
|
queueCount := queueCount - 1;
|
|
|
|
end else
|
|
queue^^.queueRecords[i].slotResID := theResID;
|
|
|
|
end else { the ID was -1 which means add a new record }
|
|
begin
|
|
SetHandleSize(Handle(queue), GetHandleSize(Handle(queue)) + SIZEOF(HMHelpSlot));
|
|
|
|
result := memError;
|
|
|
|
if result=noErr then
|
|
begin
|
|
with queue^^ do
|
|
begin
|
|
queueCount := queueCount + 1;
|
|
with queueRecords[queueCount] do
|
|
begin
|
|
{queueRecords[queueCount].}slotPID := PSN;
|
|
{queueRecords[queueCount].}slotResID := theResID;
|
|
{queueRecords[queueCount].}slotID := theMenuID;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
__HMSetMenuResID := result;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMGetMenuResID(theMenuID: INTEGER; VAR theResID: INTEGER): OsErr;
|
|
VAR i : INTEGER;
|
|
PSN : ProcessSerialNumber;
|
|
BEGIN
|
|
__HMGetMenuResID := resNotFound; { assume that we didn't find any resource }
|
|
|
|
{ <58> note: don't bother with quick check that HMGetDialogResID does by checking the queueCount field
|
|
in the menu queue. Finder always overrides the hmnu res id's when it is launched, so, there
|
|
is always something in the queue }
|
|
|
|
if GetCurrentProcess(PSN)=noErr then { only use Process IDs that are good }
|
|
begin
|
|
theResID := __HMFind(__HMGetHelpGlobal^.hmgMenuQueue,theMenuID,i,PSN); { <58> pass the queue now }
|
|
if theResID<>-1 then
|
|
__HMGetMenuResID := noErr;
|
|
end;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMModalDialogMenuSetup(ModalDialogComingUp: BOOLEAN): OsErr;
|
|
VAR mh : MenuHandle;
|
|
i : INTEGER;
|
|
BEGIN
|
|
__HMModalDialogMenuSetup := noErr;
|
|
mh := GetMHandle(kHMHelpMenuID);
|
|
if (mh<>NIL) then
|
|
begin
|
|
for i := 1 to CountMItems(mh) do
|
|
begin
|
|
if (i<>kHMShowBalloonsItem) then
|
|
if (ModalDialogComingUp) then
|
|
DisableItem(mh,i) else
|
|
EnableItem(mh,i);
|
|
end;
|
|
end else
|
|
__HMModalDialogMenuSetup := hmHelpManagerNotInited;
|
|
END;
|
|
|
|
FUNCTION __HMGetScreenGDevice(pt: Point): GDHandle;
|
|
VAR gh : GDHandle;
|
|
BEGIN
|
|
gh := GetDeviceList;
|
|
while gh<>NIL do
|
|
begin
|
|
if TestDeviceAttribute(gh,screenDevice) then
|
|
if TestDeviceAttribute(gh,screenActive) then
|
|
if PtInRect(pt,gh^^.gdRect) then
|
|
leave;
|
|
gh := GetNextDevice(gh); { *** faster if we use: gh^^.gdNextGD }
|
|
end;
|
|
__HMGetScreenGDevice := gh;
|
|
END;
|
|
|
|
|
|
|
|
PROCEDURE __HMGetVariantRect(rbs: RBSRecord; VAR fullRect: Rect); { Returns the rect that can encompass the balloon }
|
|
VAR theword : IntegerPtr;
|
|
BEGIN
|
|
with fullRect do
|
|
begin
|
|
theword := @right;
|
|
if BTST(rbs.whole, kShiftBit) then
|
|
theword := @bottom;
|
|
end;
|
|
theword^ := theword^ + kHMPointerSize;
|
|
END;
|
|
|
|
|
|
|
|
|
|
|
|
PROCEDURE __HMSelectProperVariant( balloonBounds: Rect; { bounds of balloon w/o tip }
|
|
altRect: Rect; { alternate rectangle }
|
|
screenRect: Rect; { bounds of monitor we're about to display on }
|
|
VAR rbs: RBSRecord; { balloon's variant word, right, bottom, shift values }
|
|
VAR tip: Point { balloon's initial tip position }
|
|
);
|
|
|
|
CONST
|
|
horizontal = 0;
|
|
vertical = 1;
|
|
|
|
VAR dL : INTEGER;
|
|
dR : INTEGER;
|
|
dT : INTEGER;
|
|
dB : INTEGER;
|
|
retries : INTEGER;
|
|
|
|
width : INTEGER;
|
|
height : INTEGER;
|
|
border : INTEGER;
|
|
|
|
deltaH : INTEGER;
|
|
deltaV : INTEGER;
|
|
|
|
whichAxis : INTEGER;
|
|
axisCount : INTEGER;
|
|
|
|
hangRight : INTEGER; { 1 if balloon hangs right }
|
|
hangDown : INTEGER; { 1 if balloon hangs down }
|
|
hangShift : INTEGER; { 1 if balloon has a vertical tip }
|
|
|
|
bestRight : INTEGER;
|
|
bestDown : INTEGER;
|
|
bestShift : INTEGER;
|
|
bestTip : Point;
|
|
|
|
bestArea : LongInt;
|
|
|
|
area : LongInt;
|
|
areaH : LongInt;
|
|
areaV : LongInt;
|
|
|
|
destRect : Rect;
|
|
areaRect : Rect;
|
|
|
|
{ ¥ First: See if tip's position delegates having a vertical (shift = 1) tip.
|
|
|
|
¥ Second: Try the horizontal position of the balloon to see if it fits with the
|
|
original tip and variant. The routine below is written to calculate balloons
|
|
in a specific order. Instead of just computing a balloon that fits, we walk
|
|
thru choices of variants to produce what appears better rather than what is
|
|
just mathematically appropriate.
|
|
|
|
Every second time that a variant is changed, the balloon
|
|
shift (whether or not a vertical tip is used) is toggled. This ensures that
|
|
every variant is tried in order to get the balloon to fit without clipping.
|
|
|
|
¥ Third: Try the vertical position.
|
|
|
|
¥ Fourth: If all variants have been tried then use the best balloon that we had calculated
|
|
along the way. The best balloon is the one with the most area.
|
|
|
|
}
|
|
|
|
BEGIN
|
|
border := IntegerPtr(MBarHeight)^ + 2; { compute the menubar's height plus room for the line & 1 pix }
|
|
|
|
hangRight := rbs.rightValue; { get right hang direction in local (if hangRight = 1 then the balloon hangs right) }
|
|
hangDown := rbs.bottomValue; { get downward hang direction in local (if hangDown = 1 then the balloon hangs down) }
|
|
hangShift := rbs.shiftValue; { get shift value in local (if hangShift = 1 then the balloon has a vertical tip) }
|
|
|
|
if hangShift = 0 then
|
|
with screenRect do
|
|
if (tip.v < top + border) or
|
|
(tip.v > bottom - border) then { the balloon tip is in menubar area or near very bottom of screen bounds }
|
|
begin
|
|
hangShift := 1; { force a vertical tip as we're near the top or bottom of screen }
|
|
end;
|
|
|
|
whichAxis := horizontal; { start with the horizontal axis first }
|
|
axisCount := 0; { reset the counter for keeping track of how many times we've tried either horizontal or vertically }
|
|
bestArea := -1; { initialize the bestArea local that keeps track of the balloon with the greatest area }
|
|
|
|
for retries := 1 to 8 do { keep computing until we tried 8 times }
|
|
begin
|
|
destRect := balloonBounds; { reset destination rect to be the balloon bounds EACH time thru the loop }
|
|
with destRect do { recalculate the dimensions of the balloon }
|
|
begin
|
|
if hangShift = 0 then
|
|
right := right + kHMPointerSize
|
|
else bottom := bottom + kHMPointerSize; { include space for tip dimensions }
|
|
|
|
width := right - left + kHMHorizFrameMargin; { include balloon horizontal margin }
|
|
height := bottom - top + kHMVertFrameMargin; { include balloon vertical margin }
|
|
end;
|
|
|
|
with screenRect do
|
|
begin
|
|
dR := (right - tip.h); { compute the space between the tip and the right edge of the screen bounds }
|
|
dL := (tip.h - left); { compute the space between the tip and the left edge of the screen bounds }
|
|
|
|
dB := (bottom - tip.v); { compute the space between the tip and the bottom edge of the screen bounds }
|
|
dT := (tip.v - (top + border)); { compute the space between the tip and the top edge of the screen bounds (minus border) }
|
|
end;
|
|
|
|
deltaH := dR; { Assume balloon hangs right so use deltaH for right }
|
|
if hangRight = 0 then { T => Nope, it hangs left, so use left deltaH }
|
|
deltaH := dL;
|
|
areaH := width; { remember this balloon's width so that if no balloons fit, we }
|
|
if width > deltaH then { can use the 'best' balloon as a last resortÉ }
|
|
areaH := deltaH;
|
|
|
|
deltaV := dB; { Assume balloon hangs down so use deltaV for bottom }
|
|
if hangDown = 0 then { T => Nope, it hangs up, so use top deltaV }
|
|
deltaV := dT;
|
|
areaV := height; { remember this balloon's height so that if no balloons fit, we }
|
|
if height > deltaV then { can use the 'best' balloon as a last resortÉ }
|
|
areaV := deltaV;
|
|
|
|
area := areaV * areaH; { compute this balloons area in case all balloons fail to fit }
|
|
if area > bestArea then { this balloon's area was larger than the last, so copy the balloon's params }
|
|
begin
|
|
bestRight := hangRight;
|
|
bestDown := hangDown;
|
|
bestShift := hangShift;
|
|
bestTip := tip;
|
|
bestArea := area; { and save the bestArea for the next go 'round }
|
|
end;
|
|
|
|
|
|
case whichAxis of
|
|
horizontal:
|
|
begin
|
|
if (width > deltaH) then { the balloon was too wide to fit, try tweeking the tip &/or variant }
|
|
begin
|
|
axisCount := axisCount + 1; { increment the counter for walking thru the balloon variants }
|
|
|
|
if axisCount <> 4 then { don't move the tip the 4th time we've checked the horiz size }
|
|
begin
|
|
tip.h := altRect.left + (altRect.right - tip.h); { move tip to the opposite side of the altRect }
|
|
end else
|
|
hangShift := 1 - hangShift; { change from a vertical tip to a horizontal one or horiz to vertical }
|
|
|
|
hangRight := 1 - hangRight; { change the balloon hanging right to hanging left or left to right }
|
|
end else
|
|
begin { we successfully fit horizontally }
|
|
whichAxis := vertical; { so now try the vertical }
|
|
axisCount := 0; { reset the counter }
|
|
cycle; { to the next for retries }
|
|
end;
|
|
end;
|
|
|
|
vertical:
|
|
begin
|
|
if (height > deltaV) then { the balloon was too tall to fit, try tweeking the tip &/or variant }
|
|
begin
|
|
axisCount := axisCount + 1; { increment the counter for walking thru the balloon variants }
|
|
|
|
if axisCount <> 4 then { don't move the tip the 4th time we've checked the vertical size }
|
|
begin
|
|
tip.v := altRect.top + (altRect.bottom - tip.v); { move tip to the opposite side of the altRect }
|
|
end else
|
|
hangShift := 1 - hangShift; { change from a vertical tip to a horizontal one or horiz to vertical }
|
|
|
|
hangDown := 1 - hangDown; { change the balloon hanging down to hanging up or down to up }
|
|
end else
|
|
begin
|
|
leave; { both the horizontal and vertical fit so exit now }
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if retries >= 8 then { balloon didn't fit, use the which one was best }
|
|
begin
|
|
hangRight := bestRight;
|
|
hangDown := bestDown;
|
|
hangShift := bestShift;
|
|
tip := bestTip;
|
|
|
|
leave;
|
|
end
|
|
else if (axisCount mod 2) = 0 then { every second try, change the shift factor }
|
|
begin
|
|
hangShift := 1 - hangShift; { change from a vertical tip to a horizontal one or horiz to vertical }
|
|
end;
|
|
end;
|
|
|
|
rbs.rightValue := hangRight; { reset the rbs value to use the just tweaked (possibly) hanging values }
|
|
rbs.bottomValue := hangDown;
|
|
rbs.shiftValue := hangShift;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMPinTipAndAltRect(screenBounds: Rect; VAR tip: Point; VAR altRect: Rect): BOOLEAN; { Returns false if no intersection }
|
|
VAR deltaLeft : LongInt;
|
|
deltaTop : LongInt;
|
|
width,height : LongInt;
|
|
newAltRect : Rect;
|
|
insideScreenBounds : BOOLEAN;
|
|
BEGIN
|
|
{ see if the altRect is really in the screen bounds (and clip it to the screen bounds at the same time) }
|
|
insideScreenBounds := SectRect(screenBounds,altRect,newAltRect);
|
|
|
|
if insideScreenBounds then { at least part of the altRect is visible }
|
|
begin
|
|
if not EqualRect(altRect,newAltRect) then { if part of the altRect is clipped, then use the ratio for the tip inside the altRect }
|
|
begin
|
|
{ use the original altRect to determine the tip deltas between the right & left, top & bottom with respect to the tip }
|
|
with altRect do
|
|
begin
|
|
deltaLeft := (tip.h - left); { this is the space between the right edge of the altRect and the horizontal part of the tip }
|
|
deltaTop := (tip.v - top);
|
|
|
|
width := right - left; { get old altRect width and height }
|
|
height := bottom - top;
|
|
|
|
end;
|
|
|
|
if width = 0 then width := 1; { make sure were not zero }
|
|
if height = 0 then height := 1;
|
|
|
|
with newAltRect do
|
|
begin
|
|
tip.h := left + (ORD4((right - left) * deltaLeft) div width); { compute ratio of tip within rect }
|
|
tip.v := top + (ORD4((bottom - top) * deltaTop) div height);
|
|
end;
|
|
|
|
altRect := newAltRect;
|
|
LongInt(tip) := PinRect(altRect,tip); { always repin the tip to the new altRect }
|
|
end;
|
|
end;
|
|
|
|
__HMPinTipAndAltRect := insideScreenBounds;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMBestWorld(worldBounds: Rect; tip: Point; areaRect: Rect; balloonType: INTEGER;
|
|
VAR balloonBounds: Rect; VAR variant: INTEGER): OsErr;
|
|
VAR rbs : RBSRecord;
|
|
i,j : INTEGER;
|
|
deltaL : INTEGER;
|
|
deltaR : INTEGER;
|
|
deltaT : INTEGER;
|
|
deltaB : INTEGER;
|
|
result : INTEGER;
|
|
boundsWidth : INTEGER;
|
|
boundsHeight : INTEGER;
|
|
tweek : INTEGER;
|
|
moveValue : Point;
|
|
destRect : Rect;
|
|
offset : Point;
|
|
rbsOK : BOOLEAN;
|
|
oldPort : GrafPtr;
|
|
|
|
BEGIN
|
|
rbsOK := false;
|
|
|
|
__HMTwitchVarCode(kVariantToRBS,variant,rbs.whole);
|
|
|
|
{ Compute the 'best' rbs that will fit the balloon in the worldBounds }
|
|
__HMSelectProperVariant(balloonBounds, areaRect, worldBounds, rbs, tip);
|
|
|
|
destRect := balloonBounds; { start with the balloon bounds }
|
|
__HMGetVariantRect(rbs,destRect); { tweak the bounds to take in account the tip placement }
|
|
|
|
with balloonBounds do
|
|
begin
|
|
boundsWidth := right - left;
|
|
boundsHeight := bottom - top;
|
|
|
|
left := tip.h - ((1-rbs.rightValue) * (destRect.right - destRect.left));
|
|
top := tip.v - ((1-rbs.bottomValue) * (destRect.bottom - destRect.top));
|
|
right := left + boundsWidth;
|
|
bottom := top + boundsHeight;
|
|
end;
|
|
|
|
LongInt(offset) := 0;
|
|
|
|
if BTST(rbs.whole,kShiftBit) then
|
|
offset.v := kHMPointerSize * rbs.bottomValue
|
|
else
|
|
offset.h := kHMPointerSize * rbs.rightValue;
|
|
|
|
offset.h := offset.h + (rbs.rightValue * kHMFrameThickness) - ((1-rbs.rightValue) * kHMPointerSize);
|
|
offset.v := offset.v + (rbs.bottomValue * kHMFrameThickness) - ((1-rbs.bottomValue) * kHMPointerSize);
|
|
|
|
OffsetRect(balloonBounds,offset.h,offset.v);
|
|
|
|
__HMTwitchVarCode(kRBSToVariant,INTEGER(rbs),variant);
|
|
|
|
__HMBestWorld := noErr;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMCalculateBalloon( aHelpMsg: HMMessageRecord;
|
|
tip: Point;
|
|
alternateRect: RectPtr;
|
|
VAR varCode: INTEGER;
|
|
VAR bounds: Rect; VAR pic: PicHandle;
|
|
balloonType: INTEGER;
|
|
abortable: BOOLEAN): OsErr;
|
|
|
|
VAR gp : HMGlobalPtr;
|
|
screenBounds : Rect;
|
|
areaRect : Rect;
|
|
visibleRect : Rect;
|
|
gh : GDHandle;
|
|
oldDevice : GDHandle;
|
|
oldPort : GrafPtr;
|
|
tPort : GrafPtr;
|
|
picPort : GrafPort;
|
|
err : INTEGER;
|
|
pt : Point;
|
|
slopTip : Point;
|
|
aTE : TEHandle;
|
|
tix : LongInt;
|
|
sloppy : BOOLEAN;
|
|
hasColorQD : BOOLEAN;
|
|
oldZone : THz; { <SM2> }
|
|
|
|
BEGIN
|
|
__HMCalculateBalloon := hmBalloonAborted; { make default case aborted }
|
|
gp := __HMGetHelpGlobal;
|
|
pic := NIL; { <59> make sure pic is NIL in case we exit early }
|
|
|
|
if abortable then
|
|
begin
|
|
tix := Tickcount;
|
|
with gp^ do
|
|
begin
|
|
if (hmgDelay - (tix - hmgTix)) > 0 then
|
|
exit(__HMCalculateBalloon); { exit if not enough time has elapsed }
|
|
hmgTix := tix;
|
|
end;
|
|
end;
|
|
|
|
oldDevice := NIL;
|
|
sloppy := false;
|
|
slopTip := __HMGetGlobalMouse;
|
|
hasColorQD := gp^.hmgHasColorQD;
|
|
|
|
if hasColorQD then
|
|
begin
|
|
{ *** do we want to use the tip's GDevice or the mouse point's ? }
|
|
gh := __HMGetScreenGDevice(slopTip); { use the mouse's GDevice }
|
|
if gh<>NIL then
|
|
begin
|
|
screenBounds := gh^^.gdRect;
|
|
oldDevice := GetGDevice;
|
|
SetGDevice(gh);
|
|
end else
|
|
exit(__HMCalculateBalloon); { how could the mouse be offscreen? }
|
|
end else
|
|
begin
|
|
screenBounds := GetGrayRgn^^.rgnBBox;
|
|
screenBounds.top := 0;
|
|
end;
|
|
|
|
if alternateRect<>NIL then
|
|
begin
|
|
areaRect := alternateRect^;
|
|
if not __HMPinTipAndAltRect(screenBounds,tip,areaRect) then
|
|
begin
|
|
if oldDevice<>NIL then { =NIL for non-color ports }
|
|
SetGDevice(oldDevice);
|
|
|
|
exit(__HMCalculateBalloon);
|
|
end;
|
|
end else
|
|
begin
|
|
LongInt(tip) := PinRect(screenBounds,tip);
|
|
with areaRect do
|
|
begin
|
|
topLeft := tip;
|
|
bottom := tip.v + 1;
|
|
right := tip.h + 1;
|
|
end;
|
|
end;
|
|
|
|
|
|
{$ifc HelpMgrTesting}
|
|
Assert(EmptyRect(areaRect),'HMCalculateBalloon: Empty area Rect!');
|
|
{$endc}
|
|
|
|
GetPort(oldPort);
|
|
|
|
{if hasColorQD then
|
|
OpenCPort(@picPort)
|
|
else }OpenPort(@picPort);
|
|
|
|
SetPort(@picPort);
|
|
|
|
with gp^ do
|
|
begin
|
|
TextFont(hmgFontAndSize.hmgFont);
|
|
TextSize(hmgFontAndSize.hmgFontSize);
|
|
|
|
hmgKeepTEHandle := true; {we don't want the __HMBalloonRect() call to toss the TEHandle (if any)}
|
|
hmgTEHandle := NIL; {in case __HMBalloonRect fails}
|
|
end;
|
|
|
|
SetRect(bounds,0,0,0,0);
|
|
err := __HMBalloonRect(aHelpMsg,bounds);
|
|
|
|
__HMCalculateBalloon := err;
|
|
|
|
if err=noErr then
|
|
begin
|
|
err := __HMBestWorld(screenBounds,tip,areaRect,balloonType,bounds,varCode);
|
|
|
|
{$ifc HelpMgrTesting}
|
|
if err<>noErr then
|
|
DebugStr('Unable to fit balloon on screenÉ');
|
|
{$endc}
|
|
end;
|
|
|
|
if err<>noErr then
|
|
begin
|
|
{if hasColorQD then
|
|
CloseCPort(@picPort)
|
|
else} ClosePort(@picPort);
|
|
|
|
SetPort(oldPort);
|
|
|
|
if oldDevice<>NIL then { always NIL for non-color ports }
|
|
SetGDevice(oldDevice);
|
|
exit(__HMCalculateBalloon);
|
|
end;
|
|
|
|
with bounds do
|
|
begin
|
|
SetRect(visibleRect,0,0,right-left,bottom-top);
|
|
|
|
right := right + kHMHorizContentMargin;
|
|
bottom := bottom + kHMVertContentMargin;
|
|
end;
|
|
|
|
aTE := gp^.hmgTEHandle;
|
|
|
|
if not __HMSlopMouse(slopTip) or not abortable then
|
|
begin
|
|
with aHelpMsg do
|
|
case hmmHelpType of
|
|
khmmPict,khmmPictHandle:
|
|
if hmmHelpType = khmmPict then
|
|
pic := PicHandle(GetResource('PICT',hmmPict))
|
|
else pic := hmmPictHandle;
|
|
|
|
khmmTEHandle:
|
|
begin
|
|
aTE := hmmTEHandle;
|
|
if aTE<>NIL then
|
|
begin
|
|
with aTE^^ do
|
|
begin
|
|
tPort := inPort;
|
|
inPort := @picPort;
|
|
end;
|
|
|
|
oldZone := GetZone; { get the current heap zone } { <SM2> }
|
|
SetZone(SystemZone); { point at the system heap } { <SM2> }
|
|
{ <SM2> }
|
|
pic := OpenPicture(visibleRect);
|
|
TEUpdate(visibleRect,aTE);
|
|
ClosePicture;
|
|
|
|
SetZone(oldZone); { <SM2> }
|
|
{ <SM2> }
|
|
with aTE^^ do
|
|
inPort := tPort;
|
|
end;
|
|
end;
|
|
|
|
otherwise
|
|
if aTE<>NIL then
|
|
begin
|
|
oldZone := GetZone; { get the current heap zone } { <SM2> }
|
|
SetZone(SystemZone); { point at the system heap } { <SM2> }
|
|
{ <SM2> }
|
|
pic := OpenPicture(visibleRect);
|
|
TEUpdate(visibleRect,aTE);
|
|
ClosePicture;
|
|
{ <SM2> }
|
|
SetZone(oldZone); { <SM2> }
|
|
{ <SM2> }
|
|
end;
|
|
end;
|
|
|
|
end else Sloppy := true;
|
|
|
|
if aHelpMsg.hmmHelpType<>khmmTEHandle then
|
|
if aTE<>NIL then
|
|
TEDispose(aTE);
|
|
|
|
with gp^ do
|
|
begin
|
|
hmgTEHandle := NIL;
|
|
hmgKeepTEHandle := false;
|
|
end;
|
|
|
|
{if hasColorQD then
|
|
CloseCPort(@picPort)
|
|
else} ClosePort(@picPort);
|
|
|
|
SetPort(oldPort);
|
|
|
|
if oldDevice<>NIL then {=NIL for non-color ports}
|
|
SetGDevice(oldDevice);
|
|
|
|
if Sloppy | (pic = NIL) then
|
|
begin
|
|
gp^.hmgItemNum := -1;
|
|
|
|
__HMCalculateBalloon := memFullErr;
|
|
|
|
if pic<>NIL then
|
|
begin
|
|
if __HMCanPictureBeKilled(aHelpMsg.hmmHelpType) then { <59> Kill picture if it wasn't resource based }
|
|
KillPicture(pic);
|
|
pic := NIL;
|
|
end;
|
|
|
|
if Sloppy then
|
|
__HMCalculateBalloon := hmBalloonAborted;
|
|
|
|
exit(__HMCalculateBalloon);
|
|
end;
|
|
|
|
{ <58> the third call to HMSlopMouse below means that HMCalculate can return w/ an error
|
|
but still return (in VAR pic) a valid picture handle, the calling code must call
|
|
KillPicture() to dispose of it in this case!! Memory leak bug in 7.0b1 }
|
|
|
|
if (abortable and __HMSlopMouse(slopTip)) or EmptyRect(bounds) then { <58> add abortable }
|
|
__HMCalculateBalloon := hmBalloonAborted;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMSetupBalloonRgns( varCode: INTEGER;
|
|
VAR structRgn: RgnHandle;
|
|
VAR contentRgn: RgnHandle;
|
|
VAR bounds: Rect): OsErr;
|
|
|
|
{ Balloon Tip Variants
|
|
|
|
The diagram below relates the varcode parameter value to the bubble
|
|
tip position and orientation. The table below shows the Unit
|
|
Vectors which are used to draw the tip.
|
|
|
|
1 2
|
|
|
|
* *
|
|
|\ /|
|
|
| \ / | NOTES
|
|
0 *---------------------* 3
|
|
\ | | / a. The 8 asterisks indicate the 8
|
|
\| |/ bubble tips.
|
|
| Bubble |
|
|
| Structure | b. The digits are the varcode values for each
|
|
| Rectangle | bubble tip.
|
|
/| |\
|
|
/ | | \
|
|
7 *---------------------* 4 c. The hCorner,vCorner columns below are a unit vector from
|
|
| / \ | the corner to the bubble tip.
|
|
|/ \|
|
|
* * d. The hBase,vBase columns are a unit vector from the
|
|
bubble tip to the base of the diagonal.
|
|
6 5
|
|
|
|
Pointing
|
|
varcode Hotspot Location Direction hCorner vCorner hBase vBase
|
|
------- ---------------- --------- ------ ------- ------- -------
|
|
0 Top, Left Left -1 0 1 1
|
|
1 Top, Left Up 0 -1 1 1
|
|
2 Top, Right Up 0 -1 -1 1
|
|
3 Top, Right Right 1 0 -1 1
|
|
4 Bottom, Right Right 1 0 -1 -1
|
|
5 Bottom, Right Down 0 1 -1 -1
|
|
6 Bottom, Left Down 0 1 1 -1
|
|
7 Bottom, Left Left -1 0 1 -1
|
|
}
|
|
|
|
VAR frame : Rect;
|
|
originalFrame : Rect;
|
|
tempRgn : RgnHandle;
|
|
bias : biasRecord;
|
|
BEGIN
|
|
RectRgn(contentRgn, bounds);
|
|
|
|
frame := bounds;
|
|
InsetRect(frame,-kHMFrameThickness,-kHMFrameThickness);
|
|
|
|
originalFrame := frame;
|
|
|
|
varCode := BAnd($0007,varCode); { strip off hi bits of varCode, in case the varCode is out of range }
|
|
|
|
with frame.topleft do
|
|
begin
|
|
if varCode >= 4 then
|
|
v := frame.bottom;
|
|
|
|
if (varCode >= 2) then if (varCode <= 5) then
|
|
h := frame.right;
|
|
|
|
__HMVarCodeToBiasRecord(varCode,bias);
|
|
|
|
with bias do
|
|
begin
|
|
h := h + (kHMPointerSize * hCornerVector);
|
|
v := v + (kHMPointerSize * vCornerVector);
|
|
|
|
OpenRgn;
|
|
FrameRoundRect(originalFrame, kHMCornerDiameter, kHMCornerDiameter);
|
|
|
|
MoveTo(h,v);
|
|
Line(hBaseVector * kHMPointerSize,VBaseVector * kHMPointerSize);
|
|
Line(DicksOffsetPixels * hShift, DicksOffsetPixels * vShift);
|
|
LineTo(h,v);
|
|
CloseRgn(structRgn);
|
|
end;
|
|
end;
|
|
|
|
tempRgn := GetGrayRgn;
|
|
SectRgn(tempRgn, structRgn, structRgn);
|
|
SectRgn(tempRgn, contentRgn, contentRgn);
|
|
|
|
__HMSetupBalloonRgns := noErr;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMDrawBalloonFrame(rgn: RgnHandle): OsErr;
|
|
VAR oldClip : RgnHandle;
|
|
BEGIN
|
|
oldClip := NewRgn;
|
|
|
|
{$ifc HelpMgrTesting}
|
|
Assert(oldClip=NIL,'HMDrawBalloonFrame[1]: NIL Region for NewRgn call');
|
|
{$endc}
|
|
|
|
GetClip(oldClip);
|
|
|
|
EraseRgn(rgn);
|
|
FrameRgn(rgn);
|
|
SetClip(rgn);
|
|
OffsetRgn(rgn, -1, -1);
|
|
FrameRgn(rgn);
|
|
OffsetRgn(rgn, 1, 1);
|
|
|
|
SetClip(oldClip);
|
|
__HMDisposeRgn(oldClip);
|
|
|
|
__HMDrawBalloonFrame := noErr;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMSaveBalloonBits(aHelpMsg: HMMessageRecord;
|
|
tip: Point;
|
|
alternateRect: RectPtr;
|
|
tipProc: Ptr;
|
|
variant: INTEGER;
|
|
balloonType: INTEGER): OsErr;
|
|
VAR bounds : Rect;
|
|
bitsbounds : Rect;
|
|
oldBounds : Rect;
|
|
pic : PicHandle;
|
|
result : OsErr;
|
|
varCode : INTEGER;
|
|
wVarCode : INTEGER;
|
|
wBounds : Rect;
|
|
oldPort : GrafPtr;
|
|
wPort : GrafPtr;
|
|
oldClipRgn : RgnHandle;
|
|
wideOpenRgn : RgnHandle;
|
|
aStructRgn : RgnHandle;
|
|
aContentRgn : RgnHandle;
|
|
oldState : SignedByte;
|
|
BEGIN
|
|
GetPort(oldPort);
|
|
GetWMgrPort(wPort);
|
|
SetPort(wPort);
|
|
|
|
oldClipRgn := NewRgn;
|
|
|
|
if oldClipRgn<>NIL then
|
|
begin
|
|
GetClip(oldClipRgn);
|
|
|
|
wideOpenRgn := NewRgn;
|
|
|
|
if wideOpenRgn<>NIL then
|
|
begin
|
|
SetRectRgn(wideOpenRgn,-32768,-32768,32767,32767);
|
|
SetClip(wideOpenRgn);
|
|
__HMDisposeRgn(wideOpenRgn);
|
|
end;
|
|
|
|
varCode := variant;
|
|
|
|
result := __HMCalculateBalloon(aHelpMsg,tip,alternateRect,varCode,bounds,pic,balloonType,true{can be aborted});
|
|
if result = noErr then { we can display a balloon }
|
|
begin
|
|
if __HMRemoveBalloon=noErr then; { toss any existing Balloons, if we get this far }
|
|
|
|
aStructRgn := NewRgn;
|
|
aContentRgn := NewRgn;
|
|
|
|
result := __HMSetupBalloonRgns(varCode,aStructRgn,aContentRgn,bounds);
|
|
|
|
if tipProc<>NIL then
|
|
begin
|
|
wBounds := bounds;
|
|
wVarCode := varCode;
|
|
|
|
result := __HMCallTipProc(tipProc,tip,aStructRgn,wBounds,wVarCode); { <58> give the caller a chance to abort }
|
|
|
|
if result = noErr then { <58> balloon might have changed a bit, so update info }
|
|
if (wVarCode<>varCode) |
|
|
(LongInt(wBounds.topLeft)<>LongInt(bounds.topLeft)) |
|
|
(LongInt(wBounds.botRight)<>LongInt(bounds.botRight)) then
|
|
begin
|
|
bounds := wBounds;
|
|
varCode := wVarCode;
|
|
|
|
if __HMSetupBalloonRgns(varCode,aStructRgn,aContentRgn,bounds)=noErr then; { <58> recalculate the balloon's regions }
|
|
end;
|
|
|
|
end else
|
|
result := noErr;
|
|
|
|
if result = noErr then
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
bitsbounds := aStructRgn^^.rgnBBox;
|
|
hmgSavedBitsHandle := __HMSaveBitsInRect(bitsbounds);
|
|
|
|
if hmgSavedBitsHandle<>NIL then
|
|
begin
|
|
if __HMDrawBalloonFrame(aStructRgn)=noErr then;
|
|
|
|
if pic<>NIL then
|
|
begin
|
|
SetClip(aContentRgn);
|
|
|
|
if pic^ = NIL then { <58> the pic was really a resource that was purged }
|
|
LoadResource(Handle(pic));
|
|
|
|
if pic^ <> NIL then { <58> the pic was successfully reloaded (if purged) }
|
|
begin
|
|
oldState := HGetState(Handle(pic)); { <58> remember pic handle's state }
|
|
HNoPurge(Handle(pic)); { <58> keep it around (if resource) }
|
|
|
|
oldBounds := pic^^.picFrame; { <58> keep old picture bounds as we're offsetting the frame }
|
|
|
|
with pic^^.picFrame do
|
|
begin
|
|
bounds.right := bounds.left + (right-left);
|
|
bounds.bottom := bounds.top + (bottom-top);
|
|
end;
|
|
|
|
DrawPicture(pic,bounds);
|
|
pic^^.picFrame := oldBounds; { <58> restore old picture bounds }
|
|
|
|
HSetState(Handle(pic),oldState); { <58> restore picture handle state }
|
|
end;
|
|
end;
|
|
end else
|
|
result := memFullErr;
|
|
end;
|
|
|
|
__HMDisposeRgn(aStructRgn);
|
|
__HMDisposeRgn(aContentRgn);
|
|
end;
|
|
|
|
if (pic<>NIL) then
|
|
if __HMCanPictureBeKilled(aHelpMsg.hmmHelpType) then { <59> Kill picture if it wasn't resource based }
|
|
KillPicture(pic); { bug before <58> [used to be before DisposeRgn(aStructRgn) above] }
|
|
|
|
SetClip(oldClipRgn);
|
|
DisposeRgn(oldClipRgn); { we don't need to NIL check handle here }
|
|
|
|
end else
|
|
result := memFullErr;
|
|
|
|
SetPort(oldPort);
|
|
|
|
__HMSaveBalloonBits := result;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMGetHelpItemResID(d: DialogPtr; whichOne: INTEGER; VAR kind: INTEGER; VAR offset: INTEGER): INTEGER;
|
|
VAR numItems : INTEGER;
|
|
dataSize : INTEGER;
|
|
i : INTEGER;
|
|
hItems : hItemList;
|
|
pItem : pDITLItem;
|
|
USB : SByteArray;
|
|
count : INTEGER;
|
|
BEGIN
|
|
__HMGetHelpItemResID := -1;
|
|
|
|
count := 1;
|
|
hItems := hItemList(DialogPeek(d)^.items);
|
|
numItems := hItems^^.dlgMaxIndex + 1;
|
|
pItem := @hItems^^.DITLItems;
|
|
|
|
for i := 1 to numItems do { code below is handle safe! }
|
|
begin
|
|
USB.Int := 0;
|
|
USB.SBArray[1] := pItem^.itmData[0];
|
|
|
|
with pItem^ do
|
|
if BAnd(itmType,$7F)=kHelpItem then
|
|
if count = whichOne then
|
|
begin
|
|
kind := IntegerPtr(@itmdata[kHelpItemType])^;
|
|
|
|
{ always check the ranges we know in case in the future we use HelpItem for something else }
|
|
if (kind = kScanhdlg) or (kind = kScanhrct) or (kind = kScanAppendhdlg) then
|
|
begin
|
|
__HMGetHelpItemResID := IntegerPtr(@itmdata[kHelpItemData])^;
|
|
offset := 0;
|
|
|
|
if kind = kScanAppendhdlg then
|
|
offset := IntegerPtr(@itmdata[kHelpItemOffset])^;
|
|
end;
|
|
leave;
|
|
end else
|
|
count := count + 1;
|
|
|
|
dataSize := BAnd(USB.Int + 1, $FFFE);
|
|
pItem := pDITLItem(ptr(ord4(@pItem^) + datasize + sizeof(DITLItem)));
|
|
end;
|
|
END;
|
|
|
|
FUNCTION __HMCountDITLHelpItems(d: DialogPtr): INTEGER;
|
|
VAR numItems : INTEGER;
|
|
i : INTEGER;
|
|
itemType : INTEGER;
|
|
itemHandle : Handle;
|
|
itemRect : Rect;
|
|
count : INTEGER;
|
|
BEGIN
|
|
count := 0;
|
|
numItems := hItemList(DialogPeek(d)^.items)^^.dlgMaxIndex + 1;
|
|
for i := 1 to numItems do
|
|
begin
|
|
GetDItem(d,i,itemType,itemHandle,itemRect);
|
|
|
|
if BAnd(itemType,$7F)=kHelpItem then
|
|
count := count + 1;
|
|
end;
|
|
__HMCountDITLHelpItems := count;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMSameItemState(theDialog: DialogPtr; thePoint: Point;
|
|
VAR item: INTEGER; VAR state: INTEGER; VAR itemRect: Rect): BOOLEAN;
|
|
{ Finds an item in theDialog at thePoint and returns true if the item & state were the same, therefore,
|
|
no balloon needs to be redrawn. It returns the item & state as VAR params.
|
|
}
|
|
VAR value : INTEGER;
|
|
itemType : INTEGER;
|
|
itemHandle : Handle;
|
|
BEGIN
|
|
__HMSameItemState := false; { say that we need to redraw the balloon }
|
|
item := FindDItem(theDialog,thePoint);
|
|
|
|
if item >= 0 then
|
|
begin
|
|
item := item + 1; { convert to GetDItem offset (always 1 based) }
|
|
|
|
GetDItem(theDialog,item,itemType,itemHandle,itemRect); { get the item's info }
|
|
|
|
if BAnd(itemType,$80)<>0 then { item was disabled }
|
|
state := kHMDisabledItem else
|
|
state := kHMEnabledItem; { otherwise it was enabled }
|
|
|
|
value := BAnd(itemType,$7F); { toss item's disabled bit }
|
|
|
|
if (value >= ctrlItem + btnCtrl) then
|
|
if (value <= ctrlItem + resCtrl) then { if item is a button, checkbox, or 'CNTL' thenÉ }
|
|
with ControlHandle(itemHandle)^^ do { convert it's state to it's value }
|
|
begin
|
|
if contrlHilite = 255 then { the item's control was gray, make it a disabled item }
|
|
state := kHMDisabledItem;
|
|
|
|
if value = ctrlItem + btnCtrl then
|
|
begin
|
|
if GetCtlMax(ControlHandle(itemHandle))>1 then
|
|
if state = kHMEnabledItem then
|
|
state := kHMCheckedItem
|
|
else state := kHMOtherItem;
|
|
end else
|
|
if state = kHMEnabledItem then { <68> BHTCA0080, check for 'checked' or 'other' only if enabled }
|
|
begin
|
|
if contrlValue = 1 then { the item's control value was 1, make it a checked item }
|
|
state := kHMCheckedItem
|
|
else if contrlValue > 1 then { the item's control value was >1, make it an 'other' item }
|
|
state := kHMOtherItem;
|
|
end;
|
|
end;
|
|
|
|
with __HMGetHelpGlobal^ do { return true if item & state were the same as last time }
|
|
__HMSameItemState := (hmgState = state) and (hmgItemNum = item);
|
|
end;
|
|
END;
|
|
|
|
FUNCTION __HMTrackModalHelpItems: OsErr;
|
|
VAR d : DialogPtr;
|
|
result : OsErr;
|
|
itemRect : Rect;
|
|
helpTemplateID : INTEGER;
|
|
founditem : INTEGER;
|
|
eachHelpItem : INTEGER;
|
|
state : INTEGER;
|
|
theProc : INTEGER;
|
|
variant : INTEGER;
|
|
index : INTEGER;
|
|
altRect : Rect;
|
|
pt : Point;
|
|
err : OsErr;
|
|
i : INTEGER;
|
|
aHelpMsg : HMMessageRecord;
|
|
gp : HMGlobalPtr;
|
|
oldPort : GrafPtr;
|
|
options : LongInt;
|
|
helpItemCount : INTEGER;
|
|
kind : INTEGER;
|
|
offset : INTEGER;
|
|
count : INTEGER;
|
|
method : LongInt;
|
|
currentPSN : ProcessSerialNumber;
|
|
frontPSN : ProcessSerialNumber;
|
|
sameResult : BOOLEAN;
|
|
|
|
BEGIN
|
|
if __HMGetHelpGlobal^.hmgOurDialog then { if our dialog is in front then call bulk once to kick menuselect }
|
|
if __HMBalloonBulk=noErr then;
|
|
|
|
__HMTrackModalHelpItems := noErr;
|
|
|
|
{ we already checked to see if Balloon Help mode was on }
|
|
d := FrontWindow;
|
|
|
|
if d=NIL then exit(__HMTrackModalHelpItems);
|
|
|
|
{ quik check to see if the front window is truely a dialog }
|
|
if WindowPeek(d)^.windowKind<>DialogKind then exit(__HMTrackModalHelpItems);
|
|
|
|
{ <74> now make sure that we're being executed from the frontmost process, otherwise exit }
|
|
err := GetCurrentProcess(currentPSN); { <74> }
|
|
if err = noErr then { <74> }
|
|
begin { <74> }
|
|
err := GetFrontProcess(frontPSN); { <74> }
|
|
if err = noErr then { <74> }
|
|
err := SameProcess(currentPSN,frontPSN,sameResult); { <74> }
|
|
end; { <74> }
|
|
if not sameResult or (err <> noErr) then { <74> }
|
|
exit(__HMTrackModalHelpItems); { <74> }
|
|
|
|
helpItemCount := __HMCountDITLHelpItems(d); { returns how many help items are in the dialog's item list }
|
|
|
|
if helpItemCount>0 then { there weren't any help items in the dialog so scram! }
|
|
begin
|
|
GetPort(oldPort);
|
|
SetPort(d);
|
|
GetMouse(pt);
|
|
|
|
if PtInRect(pt,d^.portrect) then { make sure local mouse is in window portrect }
|
|
begin
|
|
result := -1;
|
|
gp := __HMGetHelpGlobal;
|
|
|
|
if __HMSameItemState(d,pt,foundItem,state,itemRect) then
|
|
begin
|
|
SetPort(oldPort);
|
|
Exit(__HMTrackModalHelpItems);
|
|
end;
|
|
|
|
for eachHelpItem := 1 to helpItemCount do { check each help item present in the dialog item list }
|
|
begin
|
|
helpTemplateID := __HMGetHelpItemResID(d,eachHelpItem,kind,offset);
|
|
if helpTemplateID <> -1 then
|
|
begin
|
|
if (kind = kScanhrct) then
|
|
begin
|
|
result := __HMScanHRCTResource(WindowPtr(d),helpTemplateID,pt,index);
|
|
if result = noErr then
|
|
begin
|
|
with gp^ do { check to see if these were the same as last time, if so, exit! }
|
|
if (helpTemplateID = hmgState) then if (index = hmgItemNum) then
|
|
begin
|
|
SetPort(oldPort);
|
|
Exit(__HMTrackModalHelpItems);
|
|
end;
|
|
|
|
result := __HMGetIndHelpMsg(kHMRectListResType,helpTemplateID,
|
|
index,kHMEnabledItem,options,pt,@itemRect,
|
|
theProc,variant,aHelpMsg,count);
|
|
|
|
if result = noErr then
|
|
begin
|
|
state := helpTemplateID;
|
|
founditem := index;
|
|
end;
|
|
end;
|
|
end else
|
|
begin
|
|
if founditem >= 0 then
|
|
result := __HMFillInDialogMessage( helpTemplateID,founditem,
|
|
eachHelpItem,helpItemCount,
|
|
state,offset,-1{current resfile},options,pt,@altRect,
|
|
theProc,variant,aHelpMsg);
|
|
|
|
if result = noErr then
|
|
with itemRect do { correct the dialog item's hot rect [<59> always add in altRect params] }
|
|
begin
|
|
left := left + altRect.left;
|
|
top := top + altRect.top;
|
|
right := right + altRect.right;
|
|
bottom := bottom + altRect.bottom;
|
|
end;
|
|
end;
|
|
|
|
case result of
|
|
noErr,hmSkippedBalloon:
|
|
leave;
|
|
|
|
otherwise { including hmGetNextHelpItem }
|
|
cycle;
|
|
|
|
end; { case }
|
|
|
|
end else { end helpTemplateID=-1 }
|
|
{$ifc HelpMgrTesting}
|
|
DebugStr('HMGetHelpItemResID returned a -1 for a hdlg resource ID');
|
|
{$endc}
|
|
|
|
end; { end of for loop }
|
|
|
|
if result = noErr then { we hit something; either an hdlg driven item or hrct driven rect }
|
|
begin
|
|
altRect := itemRect;
|
|
|
|
with altRect do
|
|
begin
|
|
LocalToGlobal(topLeft); { note: the port is set already }
|
|
LocalToGlobal(botRight);
|
|
|
|
if LongInt(pt)=0 then
|
|
begin
|
|
pt := botRight;
|
|
pt.h := pt.h - 10;
|
|
pt.v := pt.v - 10;
|
|
end else { setup the tip as it wasn't the special 'EmptyPt' case }
|
|
if (kind <> kScanhrct) then
|
|
begin
|
|
pt.h := pt.h + left; { for 'hdlg's move the tip relative to the item's rect }
|
|
pt.v := pt.v + top;
|
|
end else
|
|
LocalToGlobal(pt); { for 'hrct's just convert the tip to global coords }
|
|
end;
|
|
|
|
method := BSR(BAnd(options,$0000000C),2);
|
|
result := __HMShowBalloon(aHelpMsg,pt,@altRect,
|
|
NIL,theProc,variant,method);
|
|
|
|
if result = noErr then
|
|
with gp^ do
|
|
begin
|
|
hmgLastWindowPtr := d;
|
|
hmgItemNum := founditem;
|
|
hmgState := state;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
SetPort(oldPort);
|
|
|
|
end; { helpItemCount>0 }
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMShowContentBalloon( tip: Point; alternateRect: Rect;
|
|
theProc,variant: INTEGER;
|
|
aHelpMsg: HMMessageRecord; options: LongInt): OsErr;
|
|
BEGIN
|
|
{Note: port is already set, and front window cannot be NIL!}
|
|
|
|
LocalToGlobal(tip); {yucko!}
|
|
LocalToGlobal(alternateRect.topLeft);
|
|
LocalToGlobal(alternateRect.botRight);
|
|
|
|
if BTst(options,kBTSTAbsoluteCoords) then
|
|
with FrontWindow^.portrect,tip do
|
|
begin
|
|
{tip.}h := {tip.}h + left;
|
|
{tip.}v := {tip.}v + top;
|
|
|
|
OffsetRect(alternateRect,left,top);
|
|
end;
|
|
|
|
__HMShowContentBalloon := __HMShowBalloon(aHelpMsg,tip,@alternateRect,NIL,theProc,variant,0);
|
|
|
|
{ hmgLastBalloon information is set in BalloonPack.a, when a balloon comes up }
|
|
END;
|
|
|
|
|
|
PROCEDURE __HMShowEasyAccessBalloon;
|
|
VAR aHelpMsg : HMMessageRecord;
|
|
altRect : Rect;
|
|
pt : Point;
|
|
result : LongInt;
|
|
BEGIN
|
|
if Gestalt(gestaltEasyAccessAttr,result) = noErr then { Easy Access is installed }
|
|
if GetMBARRect(altRect)=noErr then
|
|
begin
|
|
altRect.left := altRect.right-10;
|
|
|
|
if PtInRect(__HMGetGlobalMouse,altRect) then
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
result := BAnd($0007,result); { toss hi bits so that Don Brady can use the call for somethin' else }
|
|
|
|
if (hmgMenuID = kwasEasyAccess) then if (hmgItemNum = result) then
|
|
Exit(__HMShowEasyAccessBalloon);
|
|
|
|
if (result = 0) then
|
|
begin
|
|
if __HMIsBalloon then
|
|
if __HMRemoveBalloon=noErr then;
|
|
exit(__HMShowEasyAccessBalloon);
|
|
end;
|
|
|
|
with aHelpMsg do
|
|
begin
|
|
hmmHelpType := khmmString;
|
|
GetIndString(hmmString,kHMHelpID,kHMEasy1Access-1+result);
|
|
|
|
if length(hmmString)=0 then
|
|
exit(__HMShowEasyAccessBalloon);
|
|
end;
|
|
|
|
pt.h := altRect.left + 5;
|
|
pt.v := altRect.bottom;
|
|
|
|
if __HMShowBalloon(aHelpMsg,pt,@altRect,NIL,0,2,0)=noErr then
|
|
begin
|
|
hmgItemNum := result;
|
|
hmgMenuID := kwasEasyAccess;
|
|
hmgTitleBalloon := 1; { treat this balloon as if it was a menu title balloon }
|
|
end;
|
|
end;
|
|
end;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMGetWindowPartCode(VAR window: WindowPtr): INTEGER;
|
|
{ returns the typical FindWindow result codes:
|
|
inDesk = 0;
|
|
inMenuBar = 1;
|
|
inSysWindow = 2;
|
|
inContent = 3;
|
|
inDrag = 4;
|
|
inGrow = 5;
|
|
inGoAway = 6;
|
|
inZoomIn = 7;
|
|
inZoomOut = 8;
|
|
|
|
Note: Don't call this unless curLayer == applicationLayer
|
|
}
|
|
|
|
VAR layer : LayerPtr;
|
|
saveLayer : LayerPtr;
|
|
pt : Point;
|
|
windowCode : INTEGER;
|
|
variant : INTEGER;
|
|
err : OsErr;
|
|
PSN : ProcessSerialNumber;
|
|
info : ProcessInfoRec;
|
|
modalClass : INTEGER;
|
|
windowIsFloater : BOOLEAN;
|
|
gp : HMGlobalPtr;
|
|
|
|
BEGIN
|
|
pt := __HMGetGlobalMouse;
|
|
|
|
|
|
{
|
|
look in the IMlayer first, and explicitly set savelayer to NIL
|
|
}
|
|
saveLayer := NIL;
|
|
windowIsFloater := false;
|
|
windowCode := FindServiceWindow(pt,window);
|
|
|
|
if ( windowCode <> inDesk ) and ( windowCode <> inMenuBar ) then { appears that we have something in the IMlayer }
|
|
begin
|
|
saveLayer := SwapCurLayer(LayerPtr(GetParent(window)));
|
|
windowIsFloater := true;
|
|
end else
|
|
windowCode := FindWindow(pt,window);
|
|
|
|
if windowCode = inSysWindow then
|
|
windowCode := __HMGetRealWindowHitResult(pt,window);
|
|
|
|
case windowCode of
|
|
inGrow:
|
|
windowCode := inContent;
|
|
{ *** someday, figure out whether the grow box is really visible!
|
|
the code below doesn't work correctly as developers really
|
|
don't use the correct type of window for their applications!
|
|
begin
|
|
variant := GetWVariant(window);
|
|
if variant <> documentProc then
|
|
windowCode := inContent;
|
|
end;
|
|
}
|
|
|
|
inZoomOut:
|
|
windowCode := inZoomIn;
|
|
end;
|
|
|
|
if (windowCode = inDesk) and (window<>FrontWindow) then { we're in the desk or in another layer's window }
|
|
begin
|
|
saveLayer := SwapCurLayer(NIL); {set curLayer to RootLayer}
|
|
windowCode := FindWindow(pt,window);
|
|
SetCurLayer(saveLayer);
|
|
saveLayer := NIL; {<79> set this to NIL so we can test below}
|
|
|
|
if (GetFrontWindowModalClass(modalClass) = noErr) and (modalClass = dBoxProc) then { <60> don't put up a balloon for window areas outside a modal dialog }
|
|
windowCode := kHMOutsideModalWindow;
|
|
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
if (window=hmgLayer) or (window=hmgWindow) then
|
|
begin
|
|
windowCode := hmgLastPartCode;
|
|
window := hmgLastWindowPtr;
|
|
end else
|
|
if (windowCode <> inDesk) and (windowCode <> kHMOutsideModalWindow) then { <61> and if code isnt kHMOutsideModalWindow }
|
|
begin
|
|
if GetProcessFromLayer(PSN,window)=noErr then { works w/ WindowPtrs }
|
|
begin
|
|
with info do
|
|
begin
|
|
processInfoLength := Sizeof(ProcessInfoRec);
|
|
processName := @hmgProcessName;
|
|
processAppSpec := NIL;
|
|
end;
|
|
|
|
if GetProcessInformation(PSN,info)=noErr then
|
|
begin
|
|
windowCode := kHMInLayerPreamble;
|
|
__HMStripNullFromProcessName(@hmgProcessName);
|
|
end;
|
|
|
|
end else windowCode := kHMInOtherWindow;
|
|
end else
|
|
begin
|
|
{ *** the window code was inDesk (probably the Finder desktop), so lets do somethin' }
|
|
end;
|
|
end;
|
|
end else
|
|
begin
|
|
{ if (window<>NIL) then if (ORD(WindowPeek(window)^.hilited) = ORD(false)) and ( NOT windowIsFloater) then } { mouse isn't in a hilited window and it isn't a floater }
|
|
|
|
if (window<>NIL) then
|
|
if (ORD(WindowPeek(window)^.hilited) = ORD(false)) then { mouse isn't in a hilited window }
|
|
begin
|
|
if ( windowIsFloater ) then { it is a floater }
|
|
begin
|
|
if ( windowCode = inContent ) then { and the mouse is in content region }
|
|
windowCode := kHMInFrontFloatingWindow; { special Balloon for frontmost floater }
|
|
end
|
|
else { not a floater }
|
|
begin
|
|
windowCode := kHMInOtherWindow;
|
|
|
|
if (GetFrontWindowModalClass(modalClass) = noErr) then
|
|
if (modalClass = movableDBoxProc) or (modalClass = dBoxProc) then { <60> don't put up a balloon for window areas outside a modal dialog }
|
|
windowCode := kHMOutsideModalWindow;
|
|
end
|
|
end;
|
|
end;
|
|
|
|
__HMGetWindowPartCode := windowCode;
|
|
|
|
if saveLayer <> NIL then { <79> if we are in the IMlayer restore to the saved layer }
|
|
SetCurLayer(saveLayer);
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMShowWindowPartBalloon(window: WindowPtr; windowCode: INTEGER): BOOLEAN;
|
|
{ returns true if a Balloon was shown }
|
|
|
|
VAR aHelpMsg : HMMessageRecord;
|
|
w : WindowPtr;
|
|
pt : Point;
|
|
i : INTEGER;
|
|
thisFile : INTEGER;
|
|
count : INTEGER;
|
|
aID : INTEGER;
|
|
mapCode : INTEGER;
|
|
balloonProc : INTEGER;
|
|
balloonVariant : INTEGER;
|
|
aType : ResType;
|
|
overrideH : Handle;
|
|
tempstr : STR255;
|
|
overridden : BOOLEAN;
|
|
tempBaseStr : Handle; {<76>}
|
|
tempSubstituteStr : Handle; {<76>}
|
|
anErr : INTEGER; {<76>}
|
|
savedPort : GrafPtr; {<78>}
|
|
|
|
BEGIN
|
|
__HMShowWindowPartBalloon := false;
|
|
|
|
balloonProc := 0;
|
|
balloonVariant := 0;
|
|
|
|
overridden := false;
|
|
|
|
count := CountResources('hovr');
|
|
if count>0 then
|
|
begin
|
|
thisFile := CurResFile;
|
|
for i := 1 to count do
|
|
begin
|
|
overrideH := GetIndResource('hovr',i);
|
|
if HomeResFile(overrideH)=thisFile then
|
|
begin
|
|
GetResInfo(overrideH,aID,aType,tempstr);
|
|
|
|
with HMhfdrRecordHdl(overrideH)^^ do
|
|
begin
|
|
balloonProc := theProc;
|
|
balloonVariant := variant;
|
|
end;
|
|
|
|
{ Remember that FindWindow returns:
|
|
inDrag = 4;
|
|
inGrow = 5;
|
|
inGoAway = 6;
|
|
inZoomIn = 7;
|
|
inZoomOut = 8;
|
|
}
|
|
|
|
case windowCode of
|
|
inDrag..inZoomIn: mapCode := windowCode - 3; { convert to our indexes }
|
|
|
|
kHMInOtherWindow :
|
|
mapCode := 5;
|
|
kHMInLayerPreamble..kHMInLayerBody:
|
|
mapCode := 6;
|
|
kHMOutsideModalWindow:
|
|
mapCode := 7;
|
|
otherwise mapCode := windowCode;
|
|
end;
|
|
|
|
overridden := __HMExtractHelpMsg(aType,aID,mapCode,0,aHelpMsg)=noErr;
|
|
if overridden then
|
|
leave;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if not overridden then
|
|
with aHelpMsg do
|
|
begin
|
|
hmmHelpType := khmmString;
|
|
|
|
case windowCode of
|
|
kHMInOtherWindow..kHMOutsideModalWindow:
|
|
begin
|
|
GetIndString(hmmString,kHMHelpID,windowCode);
|
|
if windowCode=kHMInLayerPreamble then
|
|
begin
|
|
GetPort(savedPort); {<78>}
|
|
w := __HMGetHelpGlobal^.hmgHelpWindow; {<78>}
|
|
IF w <> NIL THEN {<78>}
|
|
SetPort(w); {<78>}
|
|
tempBaseStr := NewHandle(Length(hmmString)); {<76>}
|
|
tempSubstituteStr := NewHandle(Length(__HMGetHelpGlobal^.hmgProcessName)); {<76>}
|
|
IF (tempBaseStr <> NIL) AND (tempSubstituteStr <> NIL) THEN BEGIN {<76>}
|
|
BlockMove(@hmmString[1], tempBaseStr^, Length(hmmString)); {<76>}
|
|
with __HMGetHelpGlobal^ do {<76>}
|
|
BlockMove(@hmgProcessName[1], tempSubstituteStr^, Length(hmgProcessName)); {<76>}
|
|
anErr := ReplaceText(tempBaseStr, tempSubstituteStr, '^0'); {<76>}
|
|
hmmString[0] := Chr(GetHandleSize(tempBaseStr)); {<76>}
|
|
BlockMove(tempBaseStr^, @hmmString[1], Ord(hmmString[0])); {<76>}
|
|
END; {<76>}
|
|
DisposeHandle(tempBaseStr); {<76>}
|
|
DisposeHandle(tempSubstituteStr); {<76>}
|
|
SetPort(savedPort); {<78>}
|
|
end;
|
|
end;
|
|
|
|
kHMInFrontFloatingWindow: {<80>}
|
|
begin {<80>}
|
|
GetIndString(hmmString, kHMHelpID, windowCode); {<80>}
|
|
end; {<80>}
|
|
|
|
otherwise
|
|
GetIndString(hmmString,kHMHelpID,windowCode+(kHMInDragIndex-inDrag));
|
|
end;
|
|
|
|
if length(hmmString)=0 then { yikes! what happened to our string resource? }
|
|
{$ifc HelpMgrTesting}
|
|
hmmString := 'The window parts help resource was not foundÉ';
|
|
{$elsec}
|
|
Exit(__HMShowWindowPartBalloon);
|
|
{$endc}
|
|
end;
|
|
|
|
if __HMShowBalloon(aHelpMsg,__HMGetGlobalMouse,NIL,NIL,balloonProc,balloonVariant,0) = noErr then
|
|
with __HMGetHelpGlobal^ do
|
|
begin
|
|
hmgItemNum := windowCode;
|
|
hmgMenuID := kwasWindowPart;
|
|
|
|
__HMShowWindowPartBalloon := true;
|
|
end;
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION __HMGetBalloonWindow(VAR window: WindowPtr): OsErr;
|
|
BEGIN
|
|
window := __HMGetHelpGlobal^.hmgWindow;
|
|
__HMGetBalloonWindow := noErr;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMScanTemplateItems(whichID,whichResFile: INTEGER; whichType: ResType): OsErr;
|
|
VAR d : DialogPtr;
|
|
result : OsErr;
|
|
founditem : INTEGER;
|
|
state : INTEGER;
|
|
theProc : INTEGER;
|
|
variant : INTEGER;
|
|
oldResFile : INTEGER;
|
|
count : INTEGER;
|
|
index : INTEGER;
|
|
itemRect : Rect;
|
|
altRect : Rect;
|
|
pt : Point;
|
|
err : OsErr;
|
|
aHelpMsg : HMMessageRecord;
|
|
gp : HMGlobalPtr;
|
|
oldPort : GrafPtr;
|
|
options : LongInt;
|
|
|
|
BEGIN
|
|
__HMScanTemplateItems := paramErr;
|
|
|
|
d := FrontWindow;
|
|
if d=NIL then exit(__HMScanTemplateItems);
|
|
|
|
if (LongInt(whichType) = LongInt(kHMDialogResType)) or (LongInt(whichType) = LongInt(kHMRectListResType)) then
|
|
begin
|
|
__HMScanTemplateItems := hmSameAsLastBalloon; { assume that it's already displayed }
|
|
|
|
GetPort(oldPort);
|
|
SetPort(d);
|
|
GetMouse(pt);
|
|
|
|
if PtInRect(pt,d^.portrect) then { make sure local mouse is in window portrect }
|
|
begin
|
|
gp := __HMGetHelpGlobal;
|
|
|
|
if (LongInt(whichType) = LongInt(kHMDialogResType)) then { see if the mouse is in any of the dialog item rects }
|
|
begin
|
|
{ <67> the following check MUST be short circuit! }
|
|
if (WindowPeek(d)^.windowKind<>DialogKind) | (__HMSameItemState(d,pt,foundItem,state,itemRect)) then begin
|
|
SetPort(oldPort);
|
|
Exit(__HMScanTemplateItems);
|
|
end;
|
|
|
|
if whichResFile<>-1 then
|
|
begin
|
|
oldResFile := CurResFile;
|
|
UseResFile(whichResFile);
|
|
end;
|
|
|
|
result := __HMFillInDialogMessage(whichID,founditem,0,0,state,0{offset},whichResFile,options,
|
|
pt,@altRect,theProc,variant,aHelpMsg);
|
|
|
|
if result = noErr then
|
|
with itemRect do { correct the dialog item's ÒhotÓ rect [<59> always add in altRect params] }
|
|
begin
|
|
left := left + altRect.left;
|
|
top := top + altRect.top;
|
|
right := right + altRect.right;
|
|
bottom := bottom + altRect.bottom;
|
|
end;
|
|
|
|
end else { it must have been an hrct resource that we wanted to scan }
|
|
begin
|
|
if whichResFile<>-1 then
|
|
begin
|
|
oldResFile := CurResFile;
|
|
UseResFile(whichResFile);
|
|
end;
|
|
|
|
result := __HMScanHRCTResource(WindowPtr(d),whichID,pt,index);
|
|
if result = noErr then
|
|
begin
|
|
with gp^ do { check to see if these were the same as last time, if so, exit! }
|
|
if (hmgState = whichID) then if (hmgItemNum = index) then
|
|
begin
|
|
if whichResFile<>-1 then
|
|
UseResFile(oldResFile);
|
|
|
|
SetPort(oldPort);
|
|
Exit(__HMScanTemplateItems);
|
|
end;
|
|
|
|
result := __HMGetIndHelpMsg(kHMRectListResType,whichID,
|
|
index,kHMEnabledItem,options,pt,@itemRect,
|
|
theProc,variant,aHelpMsg,count);
|
|
|
|
if result = noErr then
|
|
begin
|
|
state := whichID;
|
|
founditem := index;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if result <> noErr then
|
|
begin
|
|
if whichResFile<>-1 then
|
|
UseResFile(oldResFile);
|
|
|
|
SetPort(oldPort);
|
|
|
|
__HMScanTemplateItems := result;
|
|
exit(__HMScanTemplateItems);
|
|
end;
|
|
|
|
altRect := itemRect;
|
|
with altRect do
|
|
begin
|
|
LocalToGlobal(topLeft); { watch the port! Make sure it is set! }
|
|
LocalToGlobal(botRight);
|
|
|
|
if LongInt(pt)=0 then
|
|
begin
|
|
pt := botRight;
|
|
pt.h := pt.h - 10;
|
|
pt.v := pt.v - 10;
|
|
end else { setup the tip as it wasn't the special 'EmptyPt' case }
|
|
if (LongInt(whichType) = LongInt(kHMDialogResType)) then
|
|
begin
|
|
pt.h := pt.h + left; { for 'hdlg's move the tip relative to the item's rect }
|
|
pt.v := pt.v + top;
|
|
end else
|
|
LocalToGlobal(pt); { for 'hrct's just convert the tip to global coords }
|
|
end;
|
|
|
|
if BTst(options,kBTSTAbsoluteCoords) then
|
|
with WindowPtr(d)^.portrect,pt do
|
|
begin
|
|
{pt.}h := {pt.}h + left;
|
|
{pt.}v := {pt.}v + top;
|
|
|
|
OffsetRect(altRect,left,top);
|
|
end;
|
|
|
|
result := __HMShowBalloon(aHelpMsg,pt,@altRect,
|
|
NIL,theProc,variant,BSR(BAnd(options,$0000000C),2) { convert hmSaveBitsNoWindow & hmSaveBitsWindow to method parameter });
|
|
|
|
if whichResFile<>-1 then
|
|
UseResFile(oldResFile);
|
|
|
|
if result = noErr then
|
|
with gp^ do
|
|
begin
|
|
hmgItemNum := founditem;
|
|
hmgState := state;
|
|
end;
|
|
|
|
__HMScanTemplateItems := result;
|
|
|
|
end else { mouse wasn't in window's port rect so return hmBalloonAborted }
|
|
__HMScanTemplateItems := hmBalloonAborted;
|
|
|
|
SetPort(oldPort);
|
|
end;
|
|
END;
|
|
|
|
|
|
FUNCTION __HMExtractHelpMsg( whichType: ResType;
|
|
whichResID, whichMsg, whichState: INTEGER;
|
|
VAR aHelpMsg: HMMessageRecord): OsErr;
|
|
VAR options : LongInt;
|
|
tip : Point;
|
|
altRect : Rect;
|
|
theProc : INTEGER;
|
|
variant : INTEGER;
|
|
count : INTEGER;
|
|
BEGIN
|
|
__HMExtractHelpMsg := __HMGetIndHelpMsg(whichType,whichResID,whichMsg,whichState,
|
|
options,tip,@altRect,theProc,variant,aHelpMsg,count);
|
|
END;
|
|
|
|
|
|
END.
|