eudora-mac/wazoo.c

1 line
67 KiB
C
Executable File

/* Copyright (c) 2017, Computer History Museum
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted (subject to
the limitations in the disclaimer below) provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of Computer History Museum nor the names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE. */
#include "wazoo.h"
#define FILE_NUM 92
/* Copyright (c) 1997 by QUALCOMM Incorporated */
#pragma segment Wazoo
/*
* constants
*/
#define kEmbedderId 'Embr'
#define kTabsId 'Tabs'
#define kMaxTabs 16
// Tab drawing specs
#define kTabLeftMargin 3 // Start first tab here from left
#define kTabCtlTop (GetRLong(WAZOO_TOPMARGIN)-GetRLong(WAZOO_TABHEIGHT)-INSET)
// Constants used in saving contents of a MyWindow structure minus the WindowRecord
enum { kSaveDataOffset = 0, kSaveDataSize = sizeof(MyWindow) };
//enum { kSaveDataOffset = sizeof(DialogRecord), kSaveDataSize = sizeof(MyWindow)-kSaveDataOffset };
/*
* globals
*/
// List of wazooable windows, menu items, functions that open them
typedef struct
{
short kind; // window kind
short windRsrc; // resource ID of WIND resource
void (*openFunction)(void); // function to open this window
FeatureType dependentFeature; // feature this wazoo depends on (if any)
short temp; // used to remember which window are currently open when restoring wazoos
} WazooableItem;
static WazooableItem gWazooKinds[] =
{
#ifdef TASK_PROGRESS_ON
TASKS_WIN,TASKS_WIND,OpenTasksWin,featureNone,0,
#endif
MB_WIN,MBWIN_WIND,OpenMBWin,featureNone,0,
PH_WIN,PH_WIND,nil,featureNone,0, // The open function needs a parameter
ALIAS_WIN,ALIAS_WIND,OpenABWin,featureNone,0,
FILT_WIN,FILT_WIND,nil,featureNone,0,
PERS_WIN,PERSONALITIES_WIND,OpenPersonalitiesWin,featureMultiplePersonalities,0,
STA_WIN,STATIONERY_WIND,OpenStationeryWin,featureStationery,0,
SIG_WIN,SIGNATURES_WIND,OpenSignaturesWin,featureNone,0,
LINK_WIN,LINK_WIND,OpenLinkWin,featureLink,0,
STAT_WIN,STAT_WIND,OpenStatWin,featureNone,0
};
typedef struct
{
long winRefCon;
ControlHandle ctlEmbedder;
Byte winData[kSaveDataSize];
} SaveWazooData, *SaveWazooPtr, **SaveWazooHandle;
// Info saved in resource for each item in a wazoo
typedef struct
{
short kind;
SaveWazooHandle hSaveInfo;
Point minSize;
Str32 name;
} WazooItem;
// Wazoo list stored in resource of type kWazooListResType
typedef struct
{
short count; // Number of windows in list
Boolean zoomed;
Rect position;
WazooItem kindList[]; // List of window types in wazoo
} WazooRes, *WazooResPtr, **WazooResHandle;
// Wazoo list
typedef struct WazooDataStruct *WazooDataPtr, **WazooDataHandle;
enum { kIconsAndNames,kCondensedNames,kIconsOnly };
typedef struct WazooDataStruct
{
short current; // Which one is currently active? (0 - N-1)
WazooDataHandle next;
MyWindowPtr win;
WazooResHandle list; // Wazoo list resource
ControlHandle hTabCtrl;
ControlHandle hTabColorCtrl;
short tabDisplayMode; // Show names, condensed, tabs only
Rect tabRect[kMaxTabs+1]; // Rect of each tab
} WazooData;
// In debug builds, we check this somewhere else
#ifndef DEBUG
static
#endif
WazooDataHandle gWazooListHead;
// Info for dragging a wazoo tab
typedef struct
{
MyWindowPtr winSrc,winDest;
short tabIdx;
WazooItem tabData;
} DragData;
typedef enum { kDragInWazoo, kDragOutsideWazoo, kDragDone, kDragHid } DragDrawMode;
typedef struct
{
long a5;
RgnHandle rgnWindow;
Point lastMouse;
DragDrawMode mode,lastDrawMode;
RgnHandle tempRgn,saveClip;
} DragOutlineInfo;
static DragData gDragData;
static Boolean gDontDragHilite;
static Boolean gForceNewWazoo; // Make the next new window a wazoo?
static short gForceHPos, gForceVPos;
static DragOutlineInfo *gpDragOutline;
/*
* prototypes
*/
static void CheckTabResize(MyWindowPtr win,WazooDataHandle hWazooData,WazooResHandle hWazooRes,short tabDisplayMode);
static Boolean CloseAWazoo(MyWindowPtr win,WazooDataHandle hWazooData,WazooResHandle hWazooRes, short index);
static Boolean CloseAllButCurrent(MyWindowPtr win,WazooDataHandle hWazooData,WazooResHandle hWazooRes);
static void DisposeDragRgn(RgnHandle rgn);
static void DisposeWazoo(WazooDataHandle hWazooData,WazooResHandle hWazooRes);
static void DoDragHilite(MyWindowPtr win, DragReference drag, Rect *rHilite, Boolean fShow);
static void DragWazoo(MyWindowPtr win,Rect *rTab,Boolean *dontActivate,short tab);
static Boolean GetWazooData(MyWindowPtr win,WazooDataHandle *hWazooData,WazooResHandle *hWazooRes);
static Boolean IsKindWazooable(short thisKind);
static RgnHandle MakeDragRegion(Rect *rTab,short tab,WazooDataHandle hWazooData);
static void OpenWazoo(short kind);
static short PtInTab(MyWindowPtr win,Point pt);
static void RemoveTab(MyWindowPtr win,short tabIdx);
static Boolean RestoreWazooWindow(MyWindowPtr win, WazooDataHandle hWazooData, short idx,Boolean quietly);
static Boolean SaveCurrentWazoo(MyWindowPtr win, WazooDataHandle hWazooData, WazooResHandle hWazooRes, Boolean switching);
static void SelectWazoo(MyWindowPtr win,short idx);
static void SetWinFields(MyWindowPtr win, Ptr winData);
static WazooDataHandle FindWazoo(short windowKind,short *idx);
static ControlHandle EmbedTheControls(MyWindowPtr win,ControlHandle ctlEmbedder);
static void CalcWazooMinSize(MyWindowPtr win);
static void SetWazooMinSize(short kind,short h,short v);
static void CheckMinWinSize(MyWindowPtr win, Point minSize);
static Boolean MustSaveWazoo(MyWindowPtr win);
static void SetupTabs(WazooDataHandle hWazooData,WazooResHandle hWazooRes,Boolean draw);
static void SetCurrentTab(ControlHandle ctl, short tab);
static ControlHandle GetEmbedder(WazooDataHandle hWazooData, short idx, Boolean create);
static void SetupCustomTabs(MyWindowPtr win,WazooDataHandle hWazooData,WazooResHandle hWazooRes);
static RgnHandle GetTabRgn(Rect *r);
static void CalcTabRects(WazooDataHandle hWazooData,WazooResHandle hWazooRes);
#define SelectWazooWithUpdate(aMyWindowPtr,i) do{UpdateMyWindow(GetMyWindowWindowPtr(aMyWindowPtr));SelectWazoo(aMyWindowPtr,i);}while(0)
static pascal OSErr DrawDrag(DragRegionMessage message,
RgnHandle showRegion, Point showOrigin, RgnHandle hideRegion,
Point hideOrigin, void *dragDrawingRefCon, DragReference drag);
static pascal void SetupTabBackground(ControlHandle control, ControlBackgroundPtr info);
/*
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//
// Translucent dragging stuff
//
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
enum
{
_DragDispatch = 0xABED
};
enum
{
gestaltDragMgrHasImageSupport = 3
};
typedef unsigned long DragImageFlags;
enum
{
dragStandardImage = 0x00000000,
dragDarkImage = 0x00000001,
dragDarkerImage = 0x00000002,
dragOpaqueImage = 0x00000003,
dragRegionAndImage = 0x00000010
};
pascal OSErr SetDragImage ( DragReference theDragRef,
PixMapHandle imagePixMap,
RgnHandle imageRgn,
Point imageOffsetPt,
DragImageFlags theImageFlags );
*/
/************************************************************************
* GetNewWazoo - a new window is being opened, is it a wazoo?
************************************************************************/
MyWindowPtr GetNewWazoo(short windowKind,Boolean *fIsWazoo)
{
MyWindowPtr win = nil;
short idx;
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
Str32 title;
if (hWazooData = FindWazoo(windowKind,&idx))
{
// It's a wazoo
*fIsWazoo = true;
hWazooRes = (*hWazooData)->list;
if (win = (*hWazooData)->win)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
// Wazoo window is already open, just switch
if (SaveCurrentWazoo(win,hWazooData,(*hWazooData)->list,true))
{
SetMyWindowPrivateData (win, 0);
win->pteList = nil;
PeteFocus(win,nil,true);
// Init everything to zero
SetWinFields(win, nil);
// Window has a new name
PCopy(title,(*hWazooRes)->kindList[idx].name);
SetWTitle(winWP, title);
UserSelectWindow(winWP);
// Don't let drawing take place until we're ready
// to display it
SetEmptyClipRgn(GetWindowPort(winWP));
win->noUpdates = true;
}
}
(*hWazooData)->current = idx;
}
else if (IsKindWazooable(windowKind))
*fIsWazoo = gForceNewWazoo; // Make this new window a wazoo?
else
*fIsWazoo = false;
return win;
}
/************************************************************************
* PositionWazoo - position the wazoo window
************************************************************************/
void PositionWazoo(MyWindowPtr win)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
Rect rPosition;
if (gForceNewWazoo && IsWazoo(winWP))
{
// Move to specified location
if (win->position)
{
(*win->position)(False,win);
MoveWindow(winWP, gForceHPos, gForceVPos, false);
MyWindowDidResize(win,nil);
}
}
else if (GetWazooData(win,&hWazooData,&hWazooRes))
{
rPosition = (*hWazooRes)->position;
utl_RestoreWindowPos(winWP,&rPosition,(*hWazooRes)->zoomed,1,TitleBarHeight(winWP),LeftRimWidth(winWP),(void*)FigureZoom,(void*)DefPosition);
MyWindowDidResize(win,nil);
}
}
/************************************************************************
* SelectOpenWazoo - see if we can switch to a previous-opened wazoo
************************************************************************/
Boolean SelectOpenWazoo(short windowKind)
{
MyWindowPtr win;
short idx;
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if ((hWazooData = FindWazoo(windowKind,&idx)) &&
(win = (*hWazooData)->win) &&
(hWazooRes = (*hWazooData)->list) &&
(idx == (*hWazooData)->current || (*hWazooRes)->kindList[idx].hSaveInfo))
{
SelectWazooWithUpdate(win,idx);
UserSelectWindow(GetMyWindowWindowPtr(win));
return true;
}
return false;
}
/************************************************************************
* FindOpenWazoo - return window ptr of wazoo based on window kind
************************************************************************/
MyWindowPtr FindOpenWazoo(short windowKind)
{
short idx;
WazooDataHandle hWazooData = FindWazoo(windowKind,&idx);
return hWazooData ? (*hWazooData)->win : nil;
}
/************************************************************************
* CloseWazoo - close wazoo window
************************************************************************/
Boolean CloseWazoo(MyWindowPtr win)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes))
{
short current;
Rect rWindow;
Boolean zoomed;
// Close the other ones first
current = (*hWazooData)->current;
if (!CloseAllButCurrent(win,hWazooData,hWazooRes))
return false;
// Now close the current one
if (!CloseAWazoo(win,hWazooData,hWazooRes,current)) return false;
utl_SaveWindowPos(GetMyWindowWindowPtr(win),&rWindow,&zoomed);
if (!EqualRect(&rWindow, &(*hWazooRes)->position) || zoomed != (*hWazooRes)->zoomed)
{
(*hWazooRes)->position = rWindow;
(*hWazooRes)->zoomed = zoomed;
ChangedResource((Handle)hWazooRes);
}
(*hWazooData)->win = nil;
}
return true;
}
/************************************************************************
* PromoteToWazoo - convert a normal window to a wazoo window
************************************************************************/
void PromoteToWazoo(MyWindowPtr win)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
Str255 sTitle;
Rect r;
Boolean zoomed;
OSErr err;
ControlHandle ctl,ctlColor;
short windowKind;
ResType resType = IsFreeMode()?kFreeWazooListResType:kWazooListResType;;
windowKind = GetWindowKind(winWP);
// Verify that this window kind is wazooable. Shouldn't get here if it isn't (but
// apparently it has happened).
if (!IsWazooable(winWP))
return;
if (!(hWazooData = FindWazoo(windowKind,nil)))
{
// New wazoo
if (!(hWazooData=NuHandleClear(sizeof(WazooData))))
return; // Err
if (!(hWazooRes=NuHandleClear(sizeof(WazooRes)+sizeof(WazooItem))))
return; // Err
// Do wazoo list resource
(*hWazooRes)->count = 1;
(*hWazooRes)->kindList[0].kind = windowKind;
MyGetOriginalWTitle(win, sTitle);
if (*sTitle > 31) *sTitle = 31; // Make sure name isn't too long
PCopy((*hWazooRes)->kindList[0].name,sTitle);
(*hWazooRes)->kindList[0].minSize = win->minSize;
win->minSize.v += GetRLong(WAZOO_TOPMARGIN);
// Get window position
utl_SaveWindowPos(winWP,&r,&zoomed);
(*hWazooRes)->position = r;
(*hWazooRes)->zoomed = zoomed;
AddResource_(hWazooRes,resType,Unique1ID(resType),"");
// Do wazoo data for win
LL_Push(gWazooListHead,hWazooData);
(*hWazooData)->list = hWazooRes;
}
SetTopMargin(win,GetRLong(WAZOO_TOPMARGIN));
// Do win stuff
(*hWazooData)->win = win;
win->wazooData = (Handle)hWazooData;
CalcWazooMinSize(win);
// Set up a tab control
GetPortBounds(GetWindowPort(winWP),&r);
r.bottom = GetRLong(WAZOO_TOPMARGIN);
r.top = kTabCtlTop; r.left--; r.right++;
ctl = NewControl(winWP,&r,"",false,0,0,0,kControlTabLargeNorthProc,kTabsId);
if (ctl)
{
err = EmbedControl(ctl,win->topMarginCntl);
// ASSERT(!err);
(*hWazooData)->hTabCtrl = ctl;
SetupTabs(hWazooData,(*hWazooData)->list,false);
SetControlVisibility(ctl,true,false);
// Embed a control within the tab control so we can get it's background color
SetRect(&r,10,GetRLong(WAZOO_TABHEIGHT)+10,15,GetRLong(WAZOO_TABHEIGHT)+15);
if (ctlColor = NewControl(winWP,&r,"",false,0,0,0,kControlUserPaneProc,0))
{
err = EmbedControl(ctlColor,ctl);
ASSERT(!err);
(*hWazooData)->hTabColorCtrl = ctlColor;
}
}
// Make sure window isn't too small with the tabs
CheckMinWinSize(win,win->minSize);
MyWindowDidResize(win,nil);
}
/************************************************************************
* DemoteWazoo - demote a wazoo to a normal window
************************************************************************/
void DemoteWazoo(MyWindowPtr win)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes))
{
Point minSize;
short i;
minSize = (*hWazooRes)->kindList[(*hWazooData)->current].minSize;
if (!CloseAllButCurrent(win,hWazooData,hWazooRes)) return;
DisposeControl((*hWazooData)->hTabCtrl);
DisposeControl((*hWazooData)->hTabColorCtrl);
// dispose of saved data for each window in wazoo
for(i=0;i<(*hWazooRes)->count;i++)
{
SaveWazooHandle hSaveInfo;
if (hSaveInfo = (*hWazooRes)->kindList[i].hSaveInfo)
{
ControlHandle ctlEmbedder;
if (ctlEmbedder = (*hSaveInfo)->ctlEmbedder)
{
// Un-embed all controls before disposing of embedder control
UInt16 count;
ControlHandle ctl,ctlRoot;
WindowPtr winWP = GetMyWindowWindowPtr(win);
GetRootControl(winWP, &ctlRoot);
if (!CountSubControls (ctlEmbedder, &count))
for (;count;count--)
if (!GetIndexedSubControl(ctlEmbedder,count,&ctl))
EmbedControl(ctl,ctlRoot);
DisposeControl(ctlEmbedder);
}
ZapHandle(hSaveInfo);
(*hWazooRes)->kindList[i].hSaveInfo = nil;
}
}
DisposeWazoo(hWazooData,hWazooRes);
SetTopMargin(win,0);
win->wazooData = nil;
win->minSize = minSize;
MyWindowDidResize(win,nil);
}
}
/************************************************************************
* WazooPreUpdate - going to update a window. Handle tab control updates
************************************************************************/
void WazooPreUpdate(MyWindowPtr win)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
CGrafPtr winPort = GetWindowPort(winWP);
WazooDataHandle hWazooData;
Rect rTab;
if (IsWindowVisible(winWP) && GetWazooData(win,&hWazooData,nil))
{
// Draw tab control first so it's in the background.
// Need to temporarily resize embedder control so entire
// tab control will draw
ControlHandle hTabCtrl = (*hWazooData)->hTabCtrl;
RgnHandle clipRgn;
// draw the top margin control first to clean up old tabs
Draw1Control(win->topMarginCntl);
if (GetWindowKind(GetMyWindowWindowPtr(win))!=STAT_WIN)
{
// if statistics window, only redraw top part of tabs to avoid flicker
Rect rPort,rCtl;
GetPortBounds(winPort,&rPort);
GetControlBounds(hTabCtrl,&rCtl);
rCtl.bottom = rPort.bottom+1;
SetControlBounds(hTabCtrl,&rCtl);
}
// Don't draw in the dontGreyOnMe area
clipRgn = SavePortClipRegion(winPort);
RgnMumbleRect(clipRgn,&win->dontGreyOnMe,false);
RestorePortClipRegion(winPort,clipRgn);
GetControlBounds(hTabCtrl,&rTab);
rTab.top = kTabCtlTop;
SetControlBounds(hTabCtrl,&rTab);
Draw1Control(hTabCtrl);
InfiniteClip(winPort); // Restore clipping region
rTab.bottom = GetRLong(WAZOO_TOPMARGIN);
SetControlBounds(hTabCtrl,&rTab);
SetTabBackColor(win);
// SetControlVisibility((*hWazooData)->hTabCtrl,false,false); // Don't want tab control to draw again
// Don't need to draw tabs anymore on this update event
ValidWindowRect(winWP,&rTab);
// Make sure controls are embedded
GetEmbedder(hWazooData,-1,true);
}
}
/************************************************************************
* SetupTabBackground - setup background color for tab control
************************************************************************/
static pascal void SetupTabBackground(ControlHandle control, ControlBackgroundPtr info)
{
SetTabBackColor(GetWindowMyWindowPtr(GetControlOwner(control)));
}
/************************************************************************
* IsKindWazooable - is this window kind wazooable?
************************************************************************/
static Boolean IsKindWazooable(short thisKind)
{
short kind;
for (kind=0;kind<sizeof(gWazooKinds)/sizeof(WazooableItem);kind++)
{
if (thisKind==gWazooKinds[kind].kind)
if (gWazooKinds[kind].dependentFeature && !HasFeature (gWazooKinds[kind].dependentFeature))
continue;
else
return true;
}
return false;
}
/************************************************************************
* IsWazooable - is this window wazooable?
************************************************************************/
Boolean IsWazooable(WindowPtr winWP)
{
if (winWP)
return IsKindWazooable(GetWindowKind(winWP));
return false;
}
/************************************************************************
* IsWazoo - is this window a wazoo?
************************************************************************/
Boolean IsWazoo(WindowPtr winWP)
{
if (IsMyWindow(winWP)) {
MyWindowPtr win = GetWindowMyWindowPtr(winWP);
return (win->wazooData != 0);
}
return (false);
}
/************************************************************************
* IsLonelyWazoo - is this window in a wazoo, all by itself?
************************************************************************/
Boolean IsLonelyWazoo(WindowPtr winWP)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (IsWazoo(winWP))
if (GetWazooData (GetWindowMyWindowPtr (winWP), &hWazooData, &hWazooRes))
return ((*hWazooRes)->count == 1);
return (false);
}
/************************************************************************
* IsKindWazoo - is this kind in a wazoo?
************************************************************************/
Boolean IsKindWazoo(short windowKind)
{
WazooDataHandle hWazooData;
short idx;
hWazooData = FindWazoo(windowKind,&idx);
return (hWazooData!=nil);
}
/************************************************************************
* ClickWazoo - check for and process clicks in a wazoo
************************************************************************/
Boolean ClickWazoo(MyWindowPtr win,EventRecord *event,Point pt,Boolean *dontActivate)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
short tab;
if (dontActivate) *dontActivate = False;
/*
if (event->modifiers & controlKey && IsWazooable(win) && !PrefIsSet(PREF_CONTROL_DRAG))
{
// Pop up contextual menu for window
Point globalPt = pt;
short menuItem;
MenuHandle mh = GetMHandle(WIND_PROP_HIER_MENU);
SetWindowPropMenu(win,true,False,diamondChar,event->modifiers);
SetWindowPropMenu(win,false,False,diamondChar,event->modifiers);
LocalToGlobal(&globalPt);
menuItem = AFPopUpMenuSelect(mh,globalPt.v,globalPt.h,-1);
DoWindowPropMenu(win,menuItem,event->modifiers);
return true;
}
*/
if ((tab = PtInTab(win,pt))>=0)
{
WazooDataHandle hWazooData;
Boolean moved;
Rect rTab;
if (!win->isActive)
{
SelectWindow_(winWP);
ActivateMyWindow(winWP,true);
}
GetWazooData(win,&hWazooData,nil);
rTab = (*hWazooData)->tabRect[tab];
if (tab != (*hWazooData)->current)
{
SetCurrentTab((*hWazooData)->hTabCtrl,tab);
SelectWazoo(win,tab);
}
moved = MyWaitMouseMoved(event->where,false);
if (moved)
{
// Started a drag
DragWazoo(win,&rTab,dontActivate,tab);
}
return true;
}
return false;
}
/************************************************************************
* DidResizeWazoo - wazoo was resized
************************************************************************/
void DidResizeWazoo(MyWindowPtr win,Rect *oldCont)
{
#pragma unused(oldCont)
// If tab width has changed, redraw the tabs
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes))
{
Rect r;
GetPortBounds(GetMyWindowCGrafPtr(win),&r);
r.bottom = GetRLong(WAZOO_TOPMARGIN);
r.top = kTabCtlTop; r.left--; r.right++;
// Don't draw tab control when resizing
SetControlVisibility((*hWazooData)->hTabCtrl,false,false);
SizeControl((*hWazooData)->hTabCtrl,RectWi(r),RectHi(r));
SetControlVisibility((*hWazooData)->hTabCtrl,true,true);
SetupTabs(hWazooData,hWazooRes,false);
CheckTabResize(win,hWazooData,hWazooRes,(*hWazooData)->tabDisplayMode);
}
CalcWazooMinSize(win);
}
/************************************************************************
* KillWazoos - get rid of the list of wazoos
************************************************************************/
void KillWazoos(void)
{
WazooDataHandle hWazooData;
if (hWazooData = gWazooListHead)
{
// Dispose of current wazoo list. Probably switching settings files
while (hWazooData)
{
WazooDataHandle hNextWazooData;
hNextWazooData = (*hWazooData)->next;
ZapHandle(hWazooData);
hWazooData = hNextWazooData;
}
gWazooListHead = nil;
}
}
/************************************************************************
* WazooHelp - display wazoo help balloon
************************************************************************/
Boolean WazooHelp(MyWindowPtr win,Point mouse)
{
Boolean result = false;
short tab;
Str255 sHelp;
Str32 title;
if ((tab = PtInTab(win,mouse))>=0)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
Rect rTab;
GetWazooData(win,&hWazooData,&hWazooRes);
rTab = (*hWazooData)->tabRect[tab];
PCopy(title,(*hWazooRes)->kindList[tab].name);
ComposeRString(sHelp,WAZOO_TAB_HELP,title,title);
MyBalloon(&rTab,100,0,0,0,sHelp);
result = true;
}
return result;
}
/************************************************************************
* InitWazoos - set up list of wazoos
************************************************************************/
void InitWazoos(void)
{
short saveFile = CurResFile();
short count,idx;
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
ResType resType = IsFreeMode()?kFreeWazooListResType:kWazooListResType;;
KillWazoos(); // just in case...
UseResFile(SettingsRefN);
count = Count1Resources(resType);
for(idx=1;idx<=count;idx++)
{
if (hWazooRes=(WazooResHandle)Get1IndResource(resType,idx))
{
short i;
WazooResPtr pWazooRes;
// Zero out hSaveInfo handle which may have been saved with the resource
pWazooRes = *hWazooRes;
for(i=0;i<pWazooRes->count;i++)
pWazooRes->kindList[i].hSaveInfo = nil;
if (hWazooData = NuHandleClear(sizeof(WazooData)))
{
(*hWazooData)->list = hWazooRes;
LL_Push(gWazooListHead,hWazooData);
}
}
}
UseResFile(saveFile);
}
/**********************************************************************
* SetupDefaultWazoos - revert to default wazoos
**********************************************************************/
void SetupDefaultWazoos(void)
{
short i;
WindowPtr win,next;
ResType resType = IsFreeMode()?kFreeWazooListResType:kWazooListResType;
Boolean abort = false;
// Clear out temp field for each wazoo type
for (i=0;i<sizeof(gWazooKinds)/sizeof(WazooableItem);i++)
gWazooKinds[i].temp = false;
// Close every wazoo that is open and remember what was open
for (win=FrontWindow();win;win=next)
{
next = GetNextWindow(win); // We might close this window
if (IsWindowVisible(win) && IsWazooable(win))
{
for (i=0;i<sizeof(gWazooKinds)/sizeof(WazooableItem);i++)
if (gWazooKinds[i].kind == GetWindowKind(win))
{
if (!CloseMyWindow(win))
{
// couldn't close window. abort
abort = true;
next = nil;
}
gWazooKinds[i].temp = true;
break;
}
}
}
if (!abort)
{
// Get rid of all wazoo resources and copy over default ones
UseResFile(SettingsRefN);
for(i=Count1Resources(resType);i;i--)
{
Handle resH;
SetResLoad(false);
resH=Get1IndResource(resType,i);
SetResLoad(true);
if (resH)
{
RemoveResource(resH);
ZapHandle(resH);
}
}
ResourceCpy(SettingsRefN,AppResFile,resType,kWazooRes1);
ResourceCpy(SettingsRefN,AppResFile,resType,kWazooRes2);
InitWazoos();
}
// Reopen wazoo windows that were previously open
for (i=0;i<sizeof(gWazooKinds)/sizeof(WazooableItem);i++)
if (gWazooKinds[i].temp)
{
gWazooKinds[i].temp = false;
OpenWazoo(gWazooKinds[i].kind);
}
}
/************************************************************************
* DisposeWazoo - dispose of wazoo info for window
************************************************************************/
static void DisposeWazoo(WazooDataHandle hWazooData,WazooResHandle hWazooRes)
{
SaveWazooHandle hSaveInfo;
short current = (*hWazooData)->current;
LL_Remove(gWazooListHead,hWazooData,(WazooDataHandle));
RemoveResource((Handle)hWazooRes);
if (current >= 0)
if (hSaveInfo = (*hWazooRes)->kindList[current].hSaveInfo)
ZapHandle(hSaveInfo);
ZapHandle(hWazooRes);
ZapHandle(hWazooData);
}
/************************************************************************
* SetTabBackColor - get tab background color
************************************************************************/
void SetTabBackColor(MyWindowPtr win)
{
WazooDataHandle hWazooData;
if (GetWazooData(win,&hWazooData,nil) && (*hWazooData)->hTabColorCtrl)
SetUpControlBackground((*hWazooData)->hTabColorCtrl,RectDepth(&win->contR),ThereIsColor);
}
/************************************************************************
* FindWazoo - search wazoo lists for the indicated type
************************************************************************/
static WazooDataHandle FindWazoo(short windowKind,short *idx)
{
WazooDataHandle hWazooData = gWazooListHead;
while (hWazooData)
{
WazooResPtr pWazooRes = *(*hWazooData)->list;
short i;
for(i=0;i<pWazooRes->count;i++)
{
if (pWazooRes->kindList[i].kind == windowKind)
{
if (idx)
*idx = i;
return hWazooData; // Found it!
}
}
hWazooData = (*hWazooData)->next;
}
return nil; // Not found
}
/************************************************************************
* SetWazooMinSize - set min size for this window and update wazoo's min size
************************************************************************/
static void SetWazooMinSize(short kind,short h,short v)
{
WazooDataHandle hWazooData;
short idx;
if (hWazooData = FindWazoo(kind,&idx))
{
// Make sure minimum size is set up correctly
Point minSize;
WazooResHandle hWazooRes;
MyWindowPtr win;
hWazooRes = (*hWazooData)->list;
if (win = (*hWazooData)->win)
{
Point newSize;
minSize = (*hWazooRes)->kindList[idx].minSize;
if (h && v)
{
newSize.h = h;
newSize.v = v;
}
else
{
// Need to get initial window size from WIND resource if we don't already have it
short kind;
if (minSize.h || minSize.v)
{
// Already have size
newSize = minSize;
}
else
{
newSize = minSize;
for (kind=0;kind<sizeof(gWazooKinds)/sizeof(WazooableItem);kind++)
if (GetWindowKind(GetMyWindowWindowPtr(win))==gWazooKinds[kind].kind)
{
Handle hWIND;
if (hWIND = GetResource('WIND',gWazooKinds[kind].windRsrc))
{
Rect r = **(Rect**)hWIND;
newSize.h = r.right-r.left;
newSize.v = r.bottom-r.top;
break;
}
}
}
}
if (minSize.h != newSize.h || minSize.v != newSize.v)
{
(*hWazooRes)->kindList[idx].minSize = newSize;
ChangedResource((Handle)hWazooRes);
}
CalcWazooMinSize(win);
}
}
}
/************************************************************************
* OpenWindow - open a window based on the windowKind
************************************************************************/
static void OpenWazoo(short kind)
{
if (kind==PH_WIN)
OpenPh(nil); // Special case, requires a parameter
else if (kind==FILT_WIN)
OpenFiltersWindow(); // Special case, returns a value
else
{
short i;
for (i=0;i<sizeof(gWazooKinds)/sizeof(WazooableItem);i++)
{
// (jp) 12-16-99 Check to see if the kind is wazooable, just in case we're
// attempting to wazoo a window that isn't available in Light
if (kind==gWazooKinds[i].kind && IsKindWazooable(kind))
{
// Open the window
(*gWazooKinds[i].openFunction)();
break;
}
}
}
SetWazooMinSize(kind,0,0);
}
/************************************************************************
* GetWazooData - get wazoo data
************************************************************************/
static Boolean GetWazooData(MyWindowPtr win,WazooDataHandle *hWazooData,WazooResHandle *hWazooRes)
{
if (win && (*hWazooData = (WazooDataHandle)win->wazooData))
{
if (hWazooRes)
*hWazooRes = (**hWazooData)->list;
return true;
}
return false;
}
/************************************************************************
* SelectWazoo - select the window
************************************************************************/
static void SelectWazoo(MyWindowPtr win,short idx)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes) && idx != (*hWazooData)->current)
{
if (MustSaveWazoo(win) && GetRLong(AUTOSAVE_INTERVAL))
// Auto save this wazoo window before switching out
DoMenu2(winWP,FILE_MENU,FILE_SAVE_ITEM,0);
if (SaveCurrentWazoo(win,hWazooData,hWazooRes,true))
{
if (!RestoreWazooWindow(win,hWazooData,idx,false))
{
// First time in this window. Open it.
// Set clip rgn to nil so the window doesn't
// get any garbage drawn to it while the window
// is being set up. Most of the window initialization
// is done with the assumption that the window is invisible.
SetEmptyClipRgn(GetWindowPort(winWP));
win->noUpdates = true;
OpenWazoo((*hWazooRes)->kindList[idx].kind);
win->noUpdates = false;
InfiniteClip(GetWindowPort(winWP)); // Restore clipping region
}
InvalContent(win);
InvalTopMargin(win);
CheckMinWinSize(win,win->minSize);
}
}
}
/************************************************************************
* PtInTab - see if point is in a tab (returns 0-based index), -1 if not found
************************************************************************/
static short PtInTab(MyWindowPtr win,Point pt)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
short tab;
if (GetWazooData(win,&hWazooData,&hWazooRes))
for(tab=0;tab<(*hWazooRes)->count;tab++)
{
Rect rTab = (*hWazooData)->tabRect[tab];
if (PtInRect(pt,&rTab))
return tab;
}
return -1;
}
/************************************************************************
* EmbedTheControls - make sure every non-embedder control in the window is embedded within an embedder
************************************************************************/
static ControlHandle EmbedTheControls(MyWindowPtr win,ControlHandle ctlEmbedder)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
ControlHandle ctlRoot;
ControlHandle ctlTabs = nil;
ControlHandle ctlTemp,ctl;
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes))
ctlTabs = (*hWazooData)->hTabCtrl;
if (!ctlEmbedder)
{
// Create an embedder control
Rect r;
DECLARE_UPP(SetupTabBackground,ControlUserPaneBackground);
INIT_UPP(SetupTabBackground,ControlUserPaneBackground);
SetRect(&r,-REAL_BIG/2,-REAL_BIG/2,REAL_BIG/2,REAL_BIG/2);
ctlEmbedder = NewControl(winWP, &r, "", true, kControlSupportsEmbedding+kControlWantsActivate+kControlHasSpecialBackground, 0, 0, kControlUserPaneProc, kEmbedderId);
SetControlData(ctlEmbedder,0,kControlUserPaneBackgroundProcTag,sizeof(SetupTabBackgroundUPP),(Ptr)&SetupTabBackgroundUPP);
}
// Make sure every non-embedder control in the window is embedded within this embedder
if (ctlEmbedder)
{
GetRootControl(winWP, &ctlRoot);
// Need to inspect every control embedded in the root control.
// Unfortunately, CountSubControls and GetIndexedSubControl don't appear
// to work correctly with the root control under Appearance Manager 1.0.
// We will therefore walk thru the control list checking for the root control
// as the super control
for(ctl=GetControlList(winWP);ctl;ctl=GetNextControl(ctl))
{
if (!GetSuperControl(ctl, &ctlTemp) && // Get super control
ctlTemp==ctlRoot && // Only want controls embedded within root control
GetControlReference(ctl)!=kEmbedderId && // Ignore embedders
ctl != win->topMarginCntl && // Ignore top margin control
ctl != ctlTabs) // Ignore tabs control
// Embed it in the embedder.
EmbedControl(ctl, ctlEmbedder);
}
}
return ctlEmbedder;
}
/************************************************************************
* SaveCurrentWazoo - save the current wazoo window data
************************************************************************/
static Boolean SaveCurrentWazoo(MyWindowPtr win, WazooDataHandle hWazooData, WazooResHandle hWazooRes,Boolean switching)
{
SaveWazooHandle hSave;
short current;
ControlHandle embedder;
current = (*hWazooData)->current;
if (current < 0) return true; // Nothing to save
hSave = (*hWazooRes)->kindList[current].hSaveInfo;
if (!hSave)
{
hSave = NuHandleClear(sizeof(SaveWazooData));
(*hWazooRes)->kindList[current].hSaveInfo = hSave;
}
if (hSave)
{
// Make sure every non-embedder control in the window is embedded within an embedder
EmbedTheControls(win,embedder = GetEmbedder(hWazooData,current,true));
if (switching) {
// Switching out, hide controls
SetControlVisibility (embedder,false,false);
if (win->wazooSwitch) (*win->wazooSwitch)(win,false);
}
(*hSave)->winRefCon = GetMyWindowPrivateData(win);
BMD(((Ptr)win)+kSaveDataOffset,(*hSave)->winData,kSaveDataSize);
}
return hSave!=nil;
}
/************************************************************************
* RestoreWazooWindow - restore the wazoo window data
************************************************************************/
static Boolean RestoreWazooWindow(MyWindowPtr win,WazooDataHandle hWazooData,short idx,Boolean quietly)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
SaveWazooHandle hSave;
Str32 title;
WazooResHandle hWazooRes = (*hWazooData)->list;
ControlHandle embedder;
short current;
if (win->pte)
// Deactivate any Pete text
PeteActivate(win->pte,false,false);
// Hide former controls
current = (*hWazooData)->current;
if (current >= 0)
if ((hSave = (*hWazooRes)->kindList[current].hSaveInfo) &&
(embedder = GetEmbedder(hWazooData,-1,true))) {
SetControlVisibility (embedder,false,false);
if (win->wazooSwitch) (*win->wazooSwitch)(win,false);
}
if (hSave = (*hWazooRes)->kindList[idx].hSaveInfo)
{
SaveWazooPtr pSave = *hSave;
Boolean wasActive = win->isActive;
SetMyWindowPrivateData (win,pSave->winRefCon);
SetWindowKind(winWP,(*hWazooRes)->kindList[idx].kind);
SetWinFields(win, pSave->winData);
(*hWazooData)->current = idx;
if (embedder = GetEmbedder(hWazooData,idx,true)) {
// Make these controls visible
SetControlVisibility (embedder,true,false);
if (win->wazooSwitch) (*win->wazooSwitch)(win,true);
}
if (!quietly)
{
PCopy(title,(*hWazooRes)->kindList[idx].name);
SetWTitle(winWP, title);
if (win->pte)
// Reactivate any Pete text
PeteActivate(win->pte,true,true);
SetEmptyClipRgn(GetWindowPort(winWP));
MyWindowDidResize(win,nil);
if (wasActive != win->isActive)
// Make sure wazoo is activated/deactivated
ActivateMyWindow(winWP,wasActive);
InfiniteClip(GetWindowPort(winWP)); // Restore clipping region
}
return true;
}
else
return false;
}
/************************************************************************
* CloseAllButCurrent - close all wazoo windows except one
************************************************************************/
static Boolean CloseAllButCurrent(MyWindowPtr win,WazooDataHandle hWazooData,WazooResHandle hWazooRes)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
short i,current;
Boolean fSelect = false;
current = (*hWazooData)->current;
SaveCurrentWazoo(win, hWazooData, hWazooRes,false);
for(i=0;i<(*hWazooRes)->count;i++)
{
if (i != current)
{
if (RestoreWazooWindow(win,hWazooData,i,true))
{
if (MustSaveWazoo(win))
{
// These windows will put up a WannaSave dialog.
// Need to switch to them
RestoreWazooWindow(win,hWazooData,i,false);
UpdateMyWindow(winWP);
fSelect = true;
}
if (!CloseAWazoo(win,hWazooData,hWazooRes,i))
return false;
}
}
}
// Need to go back to the current
RestoreWazooWindow(win,hWazooData,current,!fSelect);
if (fSelect)
UpdateMyWindow(winWP);
return true;
}
/************************************************************************
* CloseAWazoo - close a wazoo window
************************************************************************/
static Boolean CloseAWazoo(MyWindowPtr win,WazooDataHandle hWazooData,WazooResHandle hWazooRes, short index)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
SaveWazooHandle hSaveInfo;
PETEHandle pte, nextPTE;
ControlHandle embedder;
SetEmptyClipRgn(GetWindowPort(winWP));
if (win->close && !(*win->close)(win)) return(false);
for (pte=win->pteList;pte;pte=nextPTE)
{
nextPTE = PeteNext(pte);
PeteDispose(win,pte);
}
hSaveInfo = (*hWazooRes)->kindList[index].hSaveInfo;
if (embedder = GetEmbedder(hWazooData,-1,false))
DisposeControl(embedder);
if (hSaveInfo)
{
ZapHandle(hSaveInfo);
(*hWazooRes)->kindList[index].hSaveInfo = nil;
}
(*hWazooData)->current = -1;
InfiniteClip(GetWindowPort(winWP)); // Restore clipping region
return true;
}
/************************************************************************
* MakeDragRegion - make drag region for wazoo tab
************************************************************************/
static RgnHandle MakeDragRegion(Rect *rTab,short tab,WazooDataHandle hWazooData)
{
RgnHandle dragRgn;
if (dragRgn = NewRgn())
{
GetControlRegion((*hWazooData)->hTabCtrl,tab+1,dragRgn);
GlobalizeRgn(dragRgn);
OutlineRgn(dragRgn,1);
}
return dragRgn;
}
/************************************************************************
* DragWazoo - drag a wazoo tab to: same wazoo, different wazoo, new wazoo
************************************************************************/
static void DragWazoo(MyWindowPtr win,Rect *rTab,Boolean *dontActivate,short tab)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
RgnHandle dragRgn;
DragReference drag;
Str255 sTitle;
// OSErr err;
// PromiseHFSFlavor promise;
SetMyCursor(arrowCursor); SFWTC = True;
if (!MyNewDrag(win,&drag))
{
if (!FinderDragVoodoo(drag)) // pacify the evil gods in finder-land
if (!(AddDragItemFlavor(drag,1,kWazooDragType,nil,0,flavorSenderOnly|flavorNotSaved)))
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes) &&
SaveCurrentWazoo(win,hWazooData,hWazooRes,false))
{
Rect rWind,rPosition;
Boolean zoomed;
DECLARE_UPP(DrawDrag,DragDrawing);
DragOutlineInfo dragOutline;
INIT_UPP(DrawDrag,DragDrawing);
gDragData.winSrc = win;
gDragData.winDest = nil;
gDragData.tabIdx = (*hWazooData)->current;
gDragData.tabData = (*hWazooRes)->kindList[gDragData.tabIdx];
gDragData.tabData.hSaveInfo = nil; // Don't want saved wazoo info to transfer to another window
// Set up a drawing proc for drawing the drag outline
dragRgn = MakeDragRegion(rTab,tab,hWazooData);
gpDragOutline = &dragOutline;
dragOutline.a5 = SetCurrentA5();
// Get outline of window region
dragOutline.rgnWindow = NewRgn();
GetStructureRgnBounds(winWP,&rWind);
GetWTitle(winWP, sTitle);
if (RestorePosPrefs(sTitle,&rPosition,&zoomed))
{
rWind.right = rWind.left + (rPosition.right-rPosition.left);
rWind.bottom = rWind.top + (rPosition.bottom-rPosition.top);
}
RectRgn(dragOutline.rgnWindow, &rWind);
OutlineRgn(dragOutline.rgnWindow,1);
GetMouse(&dragOutline.lastMouse);
LocalToGlobal(&dragOutline.lastMouse);
OffsetRgn(dragOutline.rgnWindow,rTab->left-kTabLeftMargin,0); // Normalize region so tab appears in 1st position
dragOutline.mode = kDragInWazoo;
if (!HaveOSX())
// Apple engineering: "Drag drawing proc is not supported on X."
SetDragDrawingProc(drag, DrawDragUPP, (void*)&dragOutline);
// Do drag
gDontDragHilite = true;
MyTrackDrag(drag,&MainEvent,dragRgn);
gDontDragHilite = false;
DisposeRgn(dragOutline.rgnWindow);
if (gDragData.winDest != gDragData.winSrc)
{
short fromIdx = (*hWazooData)->current;
if (dontActivate) *dontActivate = True;
// Moved from original window
if (gDragData.winDest)
{
// Drag to a different window
// Do a soft close in old window
if (!CloseAWazoo(win,hWazooData,hWazooRes,fromIdx))
{
// The window won't close. Leave the tab in the source
// and remove it from the destination
WazooDataHandle hWazooDataDest;
WazooResHandle hWazooResDest;
RemoveTab(gDragData.winDest,gDragData.tabIdx);
GetWazooData(gDragData.winDest,&hWazooDataDest,&hWazooResDest);
SetupTabs(hWazooDataDest,hWazooResDest,true);
}
else
{
// Remove from old window
if ((*hWazooRes)->count<2)
{
// No tabs left in window. Get rid of the window
DisposeWazoo(hWazooData,hWazooRes);
win->close = nil; // Don't call close proc
win->position = nil;
win->wazooData = nil;
CloseMyWindow(winWP);
}
else
{
SelectWazoo(win,fromIdx ? 0 : 1); // Select first tab in source window
RemoveTab(win,fromIdx);
SetupTabs(hWazooData,hWazooRes,true);
UpdateMyWindow(winWP);
}
// Select tab in new window
SelectWazooWithUpdate(gDragData.winDest,gDragData.tabIdx);
}
CheckMinWinSize(gDragData.winDest, gDragData.tabData.minSize);
}
else
{
Point mouse;
Rect rMenuBar;
// Drag to nowhere.
GetDragMouse(drag, &mouse, nil);
// Don't move if drag to menu bar
rMenuBar = (*GetMainDevice())->gdRect;
rMenuBar.bottom = rMenuBar.top + GetMBarHeight();
if (!PtInRect(mouse,&rMenuBar))
{
gForceHPos = mouse.h - 24; // Position new window
gForceVPos = mouse.v - 14;
if ((*hWazooRes)->count > 1)
{
// Still got at least one left.
// Drag out to new window
// Need to soft close first
short kind;
kind = (*hWazooRes)->kindList[fromIdx].kind;
if (CloseAWazoo(win,hWazooData,hWazooRes,fromIdx))
{
SelectWazoo(win,fromIdx ? 0 : 1); // Select first tab in source window
RemoveTab(win,fromIdx); // Remove tab from source window
SetupTabs(hWazooData,hWazooRes,true);
UpdateMyWindow(winWP);
// Create new window
gForceNewWazoo = true;
OpenWazoo(kind);
gForceNewWazoo = false;
}
}
else
{
// Drag single tab out of any window. Just move this window
Rect oldContR = win->contR;
Rect r;
long sysVers;
GetPortBounds(GetWindowPort(winWP),&r);
r.right = r.right-r.left+gForceHPos;
r.bottom = r.bottom-r.top+gForceVPos;
r.left = gForceHPos;
r.top = gForceVPos;
if ((!Gestalt(gestaltSystemVersion, &sysVers) && sysVers<0x0850) ||
// utl_CouldDrag doesn't work correctly with visible windows with OS < 8.5
utl_CouldDrag(winWP,&r,4,TitleBarHeight(winWP),LeftRimWidth(winWP)))
MoveWindow(winWP,r.left,r.top,False);
}
}
}
}
gDragData.winSrc = nil;
DisposeDragRgn(dragRgn);
}
}
}
if (drag)
DisposeDrag(drag);
}
/************************************************************************
* RemoveTab - remove a tab from a window
************************************************************************/
static void RemoveTab(MyWindowPtr win,short tabIdx)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes))
{
WazooItem *pKindList;
long len;
short count;
Boolean tabDisplayMode = (*hWazooData)->tabDisplayMode;
pKindList = (*hWazooRes)->kindList;
count = (*hWazooRes)->count-1;
if (len = sizeof(WazooItem)*(count - tabIdx))
// Move items after it
BMD(&pKindList[tabIdx+1],&pKindList[tabIdx],len);
SetHandleSize((Handle)hWazooRes,sizeof(WazooRes)+sizeof(WazooItem)*count);
(*hWazooRes)->count = count;
ChangedResource((Handle)hWazooRes);
if (len)
{
if (tabIdx <= (*hWazooData)->current)
(*hWazooData)->current--;
}
CheckTabResize(win,hWazooData,hWazooRes,tabDisplayMode);
CalcWazooMinSize(win);
// Redraw
Draw1Control((*hWazooData)->hTabCtrl);
}
}
/************************************************************************
* DraggingWazoo - drag/receive handler if we are dragging a wazoo
************************************************************************/
Boolean DraggingWazoo(MyWindowPtr win,DragTrackingMessage message,DragReference drag,OSErr *err)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
Boolean result=false;
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
Boolean isWazooWindow;
Point pt;
short tab,lastTab;
*err = dragNotAcceptedErr;
isWazooWindow = GetWazooData(win,&hWazooData,&hWazooRes);
if (!gDragData.winSrc)
{
// Not dragging a wazoo tab
if (isWazooWindow)
{
// If we are over a wazoo tab, do a wazoo switch
SetPort_(GetWindowPort(winWP));
GetMouse(&pt);
if ((tab = PtInTab(win,pt))>=0 && tab != (*hWazooData)->current)
{
unsigned long waitTicks = TickCount()+GetRLong(DRAG_EXPAND_TICKS);
// Highlight tab then wait here a while
SetCurrentTab((*hWazooData)->hTabCtrl,tab);
lastTab = tab;
while(WaitMouseUp() && tab == lastTab && waitTicks > TickCount())
{
GetMouse(&pt);
lastTab = PtInTab(win,pt);
}
if (tab == lastTab)
{
SetupTabs(hWazooData,hWazooRes,true);
SelectWazoo(win,tab);
UpdateMyWindow(winWP);
}
}
}
}
else
{
// Dragging a wazoo tab
if (isWazooWindow)
{
// Dragging a wazoo tab within a wazoo window
Rect rHilite;
WazooItem *pKindList;
short count;
GrafPtr savePort;
Boolean tabDisplayMode = (*hWazooData)->tabDisplayMode;
SetPort_(GetWindowPort(winWP));
switch (message)
{
case kDragTrackingEnterWindow:
rHilite = win->contR;
rHilite.top = 0;
if (!gDontDragHilite)
DoDragHilite(win, drag, &rHilite, true);
if (win == gDragData.winSrc)
{
// Going back into original window
gDragData.tabIdx = (*hWazooData)->current;
}
else
{
// Add the tab to the end if not original window
count = (*hWazooRes)->count+1;
SetHandleSize((Handle)hWazooRes,sizeof(WazooRes)+sizeof(WazooItem)*(count));
if (!MemError())
{
(*hWazooRes)->count = count;
gDragData.tabIdx = count-1;
(*hWazooRes)->kindList[gDragData.tabIdx] = gDragData.tabData;
ChangedResource((Handle)hWazooRes);
CalcWazooMinSize(win);
GetPort(&savePort);
SetPort_(GetWindowPort(winWP));
CheckTabResize(win,hWazooData,hWazooRes,tabDisplayMode);
SetupTabs(hWazooData,hWazooRes,true);
SetPort(savePort);
}
}
gpDragOutline->mode = kDragInWazoo;
break;
case kDragTrackingLeaveWindow:
if (!gDontDragHilite)
if (win) DoDragHilite(win, drag, nil, false);
else
gDontDragHilite = false; // Make sure we hilite next time coming into this window
// Remove the tab if not the original window
// Check for destination window since the drag manager does
// a dragTrackingLeaveWindow on the drop also
if (win && win != gDragData.winSrc && !gDragData.winDest)
{
RemoveTab(win,gDragData.tabIdx);
SetupTabs(hWazooData,hWazooRes,true);
}
gpDragOutline->mode = kDragOutsideWazoo;
break;
case kDragTrackingInWindow:
GetDragMouse(drag, &pt, nil);
GlobalToLocal(&pt);
if ((tab = PtInTab(win,pt))>=0)
{
if (tab != gDragData.tabIdx)
{
// Make sure that we are far enough into the other tab that after
// we switch, we won't immediately switch back
Rect rFrom,rTo;
short wdTo;
rFrom = (*hWazooData)->tabRect[gDragData.tabIdx];
rTo = (*hWazooData)->tabRect[tab];
wdTo = rTo.right - rTo.left;
if (gDragData.tabIdx < tab)
rFrom.right = rFrom.left + wdTo;
else
rFrom.left = rFrom.right - wdTo;
if (!PtInRect(pt, &rFrom))
{
// Reposition item in tabs
WazooItem tempWazooItem;
pKindList = (*hWazooRes)->kindList;
tempWazooItem = pKindList[gDragData.tabIdx];
pKindList[gDragData.tabIdx] = pKindList[tab];
pKindList[tab] = tempWazooItem;
if (gDragData.winSrc == win)
(*hWazooData)->current = tab;
else
{
// Make sure current tab stays the same
if (tab == (*hWazooData)->current)
(*hWazooData)->current = gDragData.tabIdx;
}
SetupTabs(hWazooData,hWazooRes,true);
ChangedResource((Handle)hWazooRes);
gDragData.tabIdx = tab;
}
}
}
break;
case 0xfff:
// Drop
gDragData.winDest = win;
break;
}
}
result = true;
*err = noErr;
}
return result;
}
/************************************************************************
* DoDragHilite - show/hide drag hilite
************************************************************************/
// Need to change the background color of the window to match the
// color that is displayed
static void DoDragHilite(MyWindowPtr win, DragReference drag, Rect *rHilite, Boolean fShow)
{
RGBColor saveColor;
GetBackColor(&saveColor);
SetTabBackColor(win);
if (fShow)
ShowDragRectHilite(drag, rHilite, true);
else
HideDragHilite(drag);
RGBBackColor(&saveColor);
}
/************************************************************************
* CheckTabResize - see if the tabs need to be redrawn because of size change
************************************************************************/
static void CheckTabResize(MyWindowPtr win,WazooDataHandle hWazooData,WazooResHandle hWazooRes,short tabDisplayMode)
{
if (tabDisplayMode != (*hWazooData)->tabDisplayMode)
{
// Tab drawing mode has changed. Redraw.
Draw1Control((*hWazooData)->hTabCtrl);
}
}
/************************************************************************
* SetWinFields - change or initialize window fields
************************************************************************/
static void SetWinFields(MyWindowPtr win, Ptr winData)
{
struct MyWindowStruct oldWin;
// Save fields
oldWin = *win;
if (winData)
BMD(winData,((Ptr)win)+kSaveDataOffset,kSaveDataSize);
else
// Init everything to zero
WriteZero(((Ptr)win)+kSaveDataOffset,kSaveDataSize);
//Restore a few fields
win->theWindow = oldWin.theWindow;
win->privateData = oldWin.privateData;
win->dialogRefcon = oldWin.dialogRefcon;
win->windowType = oldWin.windowType;
win->wazooData = oldWin.wazooData;
win->noUpdates = oldWin.noUpdates;
win->topMarginCntl = oldWin.topMarginCntl;
win->topMargin = oldWin.topMargin;
win->windex = oldWin.windex;
win->uselessHi = oldWin.uselessHi;
win->uselessWi = oldWin.uselessWi;
win->titleBarHi = oldWin.titleBarHi;
win->leftRimWi = oldWin.leftRimWi;
win->minSize = oldWin.minSize;
// win->isActive = oldWin.isActive;
}
/**********************************************************************
* DisposeDragRgn - dispose of drag region
**********************************************************************/
static void DisposeDragRgn(RgnHandle rgn)
{
if (rgn)
DisposeRgn(rgn);
#if 0
if (gworld)
DisposeGWorld(gworld);
if (hDrawRgn)
DisposeRgn(hDrawRgn);
#endif
}
/**********************************************************************
* DrawDrag - drag drag region proc
**********************************************************************/
static pascal OSErr DrawDrag(DragRegionMessage message,
RgnHandle showRegion, Point showOrigin, RgnHandle hideRegion,
Point hideOrigin, void *dragDrawingRefCon, DragReference drag)
{
#pragma unused (showOrigin, hideOrigin)
Rect rClip;
DragOutlineInfo *pInfo;
RgnHandle paintRgn,tempRgn;
OSErr err = noErr;
Pattern gray;
pInfo = dragDrawingRefCon;
tempRgn = pInfo->tempRgn;
switch (message)
{
case kDragRegionBegin:
pInfo->tempRgn = NewRgn();
if (pInfo->saveClip = NewRgn())
GetClip(pInfo->saveClip); // Save wmgr clip region
pInfo->lastDrawMode = kDragInWazoo;
break;
case kDragRegionEnd:
DisposeRgn(tempRgn);
if (pInfo->saveClip)
{
SetClip(pInfo->saveClip);
DisposeRgn(pInfo->saveClip);
}
break;
case kDragRegionDraw:
case kDragRegionHide:
if (!tempRgn)
break;
SetRect(&rClip,-REAL_BIG,-REAL_BIG,REAL_BIG,REAL_BIG);
ClipRect(&rClip);
PenPat(GetQDGlobalsDarkGray(&gray)); // Need our gray pattern for XOR'ing
PenMode(notPatXor);
paintRgn = nil;
if (message==kDragRegionDraw)
{
if (pInfo->lastDrawMode == kDragOutsideWazoo)
{
// Hide window region
CopyRgn(pInfo->rgnWindow,tempRgn);
hideRegion = tempRgn;
}
if (pInfo->mode == kDragOutsideWazoo)
{
// Show window region
Point mouse;
GetDragMouse(drag, &mouse, nil);
OffsetRgn(pInfo->rgnWindow,mouse.h-pInfo->lastMouse.h,mouse.v-pInfo->lastMouse.v);
showRegion = pInfo->rgnWindow;
pInfo->lastMouse = mouse;
}
if (pInfo->lastDrawMode == kDragHid)
paintRgn = showRegion; // Nothing to hide
else
{
XorRgn(showRegion, hideRegion, tempRgn);
paintRgn = tempRgn;
}
pInfo->lastDrawMode = pInfo->mode;
}
else
{
// Hide region
if (pInfo->lastDrawMode == kDragInWazoo)
{
paintRgn = hideRegion;
}
else if (pInfo->lastDrawMode == kDragOutsideWazoo)
{
paintRgn = pInfo->rgnWindow;
pInfo->lastDrawMode = kDragHid;
}
}
if (paintRgn) PaintRgn(paintRgn);
PenNormal();
break;
}
return err;
}
/************************************************************************
* SafeWazooControl - make sure this control will be properly hidden in a wazoo
************************************************************************/
void SafeWazooControl(MyWindowPtr win,ControlHandle ctl,short windowKind)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWindowKind(GetMyWindowWindowPtr(win)) == windowKind)
return; // This window is the current wazoo window. It's already safe.
if (GetWazooData(win,&hWazooData,&hWazooRes))
{
short idx;
FindWazoo(windowKind,&idx);
// Embed the control in the embedder control
EmbedControl(ctl,GetEmbedder(hWazooData,idx,true));
}
}
/************************************************************************
* DirtyWazoo - make this wazooable window dirty
************************************************************************/
void DirtyWazoo(MyWindowPtr win,short windowKind)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
struct MyWindowStruct tempWin;
if (GetWindowKind(GetMyWindowWindowPtr(win)) == windowKind)
win->isDirty = true; // This window is the current wazoo window. It's easy
else if (GetWazooData(win,&hWazooData,&hWazooRes))
{
// Need to change isDirty flag in saved wazoo data
short idx;
SaveWazooHandle hSave;
FindWazoo(windowKind,&idx);
if (hSave = (*hWazooRes)->kindList[idx].hSaveInfo)
{
// get saved window data
BMD((*hSave)->winData,((Ptr)&tempWin)+kSaveDataOffset,kSaveDataSize);
tempWin.isDirty = true;
// put save window data back
BMD(((Ptr)&tempWin)+kSaveDataOffset,(*hSave)->winData,kSaveDataSize);
}
}
}
/************************************************************************
* CalcWazooMinSize - set wazoo minimum size
************************************************************************/
static void CalcWazooMinSize(MyWindowPtr win)
{
short count;
Point minSize;
WazooItem *pItem;
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
if (GetWazooData(win,&hWazooData,&hWazooRes))
{
minSize.h = minSize.v = 0;
pItem = (*hWazooRes)->kindList;
for(count=(*hWazooRes)->count;count--;)
{
// Get maximum minimum size
if (minSize.h < pItem->minSize.h) minSize.h = pItem->minSize.h;
if (minSize.v < pItem->minSize.v+GetRLong(WAZOO_TOPMARGIN)) minSize.v = pItem->minSize.v+GetRLong(WAZOO_TOPMARGIN);
pItem++;
}
win->minSize = minSize;
}
}
/************************************************************************
* SetWinMinSize - set window minimum size
************************************************************************/
void SetWinMinSize(MyWindowPtr win,short h,short v)
{
WindowPtr winWP = GetMyWindowWindowPtr(win);
Boolean initialSize = h<=0 || v<=0;
if (IsWazoo(winWP))
{
if (initialSize)
h = v = 0;
// Set min size for this window and update wazoo's min size
SetWazooMinSize(GetWindowKind(winWP),h,v);
}
else
{
// Not a wazoo
if (initialSize)
{
// Use current window size
Rect r;
GetPortBounds(GetWindowPort(winWP),&r);
h = r.right-r.left;
v = r.bottom-r.top;
}
win->minSize.h = h;
win->minSize.v = v;
}
}
/************************************************************************
* CheckMinWinSize - make sure the window isn't too small
************************************************************************/
static void CheckMinWinSize(MyWindowPtr win, Point minSize)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
Rect rWinSize;
Point winSize,origSize;
GetPortBounds(GetWindowPort(winWP),&rWinSize);
winSize.h = rWinSize.right-rWinSize.left;
winSize.v = rWinSize.bottom-rWinSize.top;
origSize = winSize;
if (minSize.h > winSize.h) winSize.h = minSize.h;
if (minSize.v > winSize.v) winSize.v = minSize.v;
if (winSize.h != origSize.h || winSize.v != origSize.v)
{
Rect oldContR;
oldContR = win->contR;
SizeWindow(winWP,winSize.h,winSize.v,TRUE);
MyWindowDidResize(win,&oldContR);
UpdateMyWindow(winWP);
win->saveSize = True;
}
}
/************************************************************************
* MustSaveWazoo - does this window need to be saved?
************************************************************************/
static Boolean MustSaveWazoo(MyWindowPtr win)
{
WindowPtr winWP = GetMyWindowWindowPtr (win);
return ((win->isDirty && GetWindowKind(winWP)==FILT_WIN) || (ABDirty (win) && GetWindowKind(winWP)==ALIAS_WIN));
}
/************************************************************************
* IsWazooEmbedderCntl - is this control a wazoo embedder?
************************************************************************/
Boolean IsWazooEmbedderCntl(ControlHandle cntl)
{
return GetControlReference(cntl)==kEmbedderId;
}
/************************************************************************
* IsWazooTabCntl - is this control the tab control?
************************************************************************/
Boolean IsWazooTabCntl(ControlHandle cntl)
{
return GetControlReference(cntl)==kTabsId;
}
/************************************************************************
* SetCurrentTab - set current tab in control
************************************************************************/
static void SetCurrentTab(ControlHandle ctl, short tab)
{
if (GetControlValue(ctl) != tab+1)
{
RgnHandle rgn = NewRgn();
if (rgn)
{
Rect r;
short saveBottom;
GetClip(rgn);
GetControlBounds(ctl,&r);
ClipRect(&r);
saveBottom = r.bottom;
r.bottom = 1000; // Avoid drawing line at bottom of tab
SetControlBounds(ctl,&r);
SetControlValue(ctl,tab+1);
r.bottom = saveBottom;
SetControlBounds(ctl,&r);
SetClip(rgn);
DisposeRgn(rgn);
}
}
}
/************************************************************************
* SetupTabs - setup tab icons and names
************************************************************************/
static void SetupTabs(WazooDataHandle hWazooData,WazooResHandle hWazooRes,Boolean drawIt)
{
ControlHandle ctl = (*hWazooData)->hTabCtrl;
ControlTabInfoRec tabInfo;
short tabIdx;
ControlFontStyleRec fontStyle;
Rect rCtl;
CGrafPtr port = GetMyWindowCGrafPtr((*hWazooData)->win);
RgnHandle clipRgn = SavePortClipRegion(port);
Rect rPort;
GetControlBounds(ctl,&rCtl);
SetPort(port);
ClipRect(&rCtl); // Don't want to redraw the whole window
// SetControlMaximum(ctl,(*hWazooRes)->count>1?(*hWazooRes)->count:2);
SetControlMaximum(ctl,(*hWazooRes)->count);
RestorePortClipRegion(port,clipRgn);
tabInfo.version = 0;
fontStyle.flags = kControlUseFontMask+kControlUseSizeMask+kControlUseFaceMask;
fontStyle.font = SmallSysFontID();
fontStyle.size = SmallSysFontSize();
fontStyle.style = bold;
SetControlData(ctl,0,kControlFontStyleTag,sizeof(fontStyle),(Ptr)&fontStyle);
// Put names on tabs
for(tabIdx=0;tabIdx<(*hWazooRes)->count;tabIdx++)
{
PCopy(tabInfo.name,(*hWazooRes)->kindList[tabIdx].name);
tabInfo.iconSuiteID = Names2Icon(tabInfo.name,"\p");
SetControlData(ctl,tabIdx+1,kControlTabInfoTag,sizeof(ControlTabInfoRec),(Ptr)&tabInfo);
}
// Determine which tab mode fits in the window
CalcTabRects(hWazooData,hWazooRes);
(*hWazooData)->tabDisplayMode = kIconsAndNames;
GetPortBounds(port,&rPort);
// Too wide?
if ((*hWazooData)->tabRect[(*hWazooRes)->count-1].right > rPort.right)
{
// Try condensed style
fontStyle.style = condense;
SetControlData(ctl,0,kControlFontStyleTag,sizeof(fontStyle),(Ptr)&fontStyle);
(*hWazooData)->tabDisplayMode = kCondensedNames;
CalcTabRects(hWazooData,hWazooRes);
// Still too wide?
if ((*hWazooData)->tabRect[(*hWazooRes)->count-1].right > rPort.right)
{
// Take off names
for(tabIdx=0;tabIdx<(*hWazooRes)->count;tabIdx++)
{
PCopy(tabInfo.name,(*hWazooRes)->kindList[tabIdx].name);
tabInfo.iconSuiteID = Names2Icon(tabInfo.name,"\p");
*tabInfo.name = 0;
SetControlData(ctl,tabIdx+1,kControlTabInfoTag,sizeof(ControlTabInfoRec),(Ptr)&tabInfo);
}
(*hWazooData)->tabDisplayMode = kIconsOnly;
CalcTabRects(hWazooData,hWazooRes);
}
}
SetCurrentTab(ctl,(*hWazooData)->current);
if (HaveTheDiseaseCalledOSX())
{
// bugs in the Jaguar control manager, if you ask me...
(*hWazooData)->win->topMargin += 20;
InvalTopMargin((*hWazooData)->win);
(*hWazooData)->win->topMargin -= 20;
}
else if (drawIt)
{
Draw1Control((*hWazooData)->win->topMarginCntl);
Draw1Control((*hWazooData)->hTabCtrl);
}
else
{
Rect r;
GetControlBounds((*hWazooData)->hTabCtrl,&r);
InvalWindowRect(GetMyWindowWindowPtr((*hWazooData)->win),&r);
}
}
/************************************************************************
* CalcTabRects - get bounds of each tab
************************************************************************/
static void CalcTabRects(WazooDataHandle hWazooData,WazooResHandle hWazooRes)
{
RgnHandle rgn;
short tab;
Rect rTab;
rgn = NewRgn();
for(tab=0;tab<(*hWazooRes)->count;tab++)
{
GetControlRegion((*hWazooData)->hTabCtrl,tab+1,rgn);
GetRegionBounds(rgn,&rTab);
(*hWazooData)->tabRect[tab] = rTab;
}
DisposeRgn(rgn);
}
/************************************************************************
* GetEmbedder - get embedder control for a wazoo
************************************************************************/
static ControlHandle GetEmbedder(WazooDataHandle hWazooData, short idx, Boolean create)
{
ControlHandle ctlEmbedder = nil;
WazooResHandle hWazooRes;
SaveWazooHandle hSaveInfo;
if (idx<0) idx = (*hWazooData)->current;
hWazooRes = (*hWazooData)->list;
if (hSaveInfo = (*hWazooRes)->kindList[idx].hSaveInfo)
ctlEmbedder = (*hSaveInfo)->ctlEmbedder;
if (!ctlEmbedder && create)
{
ctlEmbedder = EmbedTheControls((*hWazooData)->win,nil);
if (!hSaveInfo)
{
hSaveInfo = NuHandleClear(sizeof(SaveWazooData));
(*hWazooRes)->kindList[idx].hSaveInfo = hSaveInfo;
}
if (hSaveInfo)
(*hSaveInfo)->ctlEmbedder = ctlEmbedder;
}
return ctlEmbedder;
}
/************************************************************************
* EmbedInWazoo - embed control in wazoo embedder.
* Need to do this for OS X, otherwise may not be able to click
* on control
************************************************************************/
void EmbedInWazoo(ControlRef cntl,WindowPtr winWP)
{
WazooDataHandle hWazooData;
WazooResHandle hWazooRes;
SaveWazooHandle hSaveInfo;
ControlHandle ctlEmbedder;
MyWindowPtr win;
if (win=GetWindowMyWindowPtr(winWP))
if (GetWazooData(win,&hWazooData,&hWazooRes))
if (hSaveInfo = (*hWazooRes)->kindList[(*hWazooData)->current].hSaveInfo)
if (ctlEmbedder = (*hSaveInfo)->ctlEmbedder)
EmbedControl(cntl,ctlEmbedder);
}