/* 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;kindwazooData != 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;icount;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;icurrent; 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;icount;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;kindkindList[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;iwazooData)) { 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); }