Accounting Software
Small Business Software Estimating Software
Project Management SoftwareProject Estimating SoftwareProject Tracking SoftwareInventory Tracking SoftwareCustomer Tracking SoftwareCustomer Management SoftwareBusiness Management Software

Draggers (Source Code)

Link to: header | other interface directory

Copyright Turtle Creek Software 1996-2006. All Rights Reserved.

Comments

CTCS_Draggable.cp

This class manages generic draggers in the
Goldenseal small business accounting software,
project management software, construction accounting software
and construction software.

It's a mix in class for any object that can be dragged & dropped

SUPERCLASS = none

Constructor

/******************************************************************************
constructor v1.4, 11-14-95, 08-06-96
*******************************************************************************/
CTCS_Dragger::CTCS_Dragger(CTCS_Draggable *inSource, const SInt32 inDragID,
const TCS_Rect *inRect)
: mDragItems(sizeof(SDragItemInfo))
{
// Perform common initializations
InitDragger(inSource);
// Perform optional setups
SetDragID(inDragID);
if (inRect != nil)
mDragImage = *inRect;
}
/******************************************************************************
destructor v1.4, 11-14-95, 08-06-96
*******************************************************************************/
CTCS_Dragger::~CTCS_Dragger()
{
TCS_Forget(mImageBitMap);

if (mDragItems.GetCount() > 0) // TCS bugfix 1/30/03
{
CTCS_ArrayIterator itemIter(mDragItems);
SDragItemInfo itemInfo;
while (itemIter.Next(&itemInfo))
{
TCS_Forget(itemInfo.flavors);
}
}

#if TCS_FOR_OSX
#elif TCS_CANUSE_QUICKTIME
TCS_DisposeRoutine(mDragDrawProc);
#endif
}

Source Code

/******************************************************************************
constructor v1.4, 11-14-95, 08-06-96
*******************************************************************************/
CTCS_Dragger::CTCS_Dragger(CTCS_Draggable *inSource, const SInt32 inDragID,
const TCS_Rect *inRect)
: mDragItems(sizeof(SDragItemInfo))
{
// Perform common initializations
InitDragger(inSource);
// Perform optional setups
SetDragID(inDragID);
if (inRect != nil)
mDragImage = *inRect;
}
/******************************************************************************
destructor v1.4, 11-14-95, 08-06-96
*******************************************************************************/
CTCS_Dragger::~CTCS_Dragger()
{
TCS_Forget(mImageBitMap);

if (mDragItems.GetCount() > 0) // TCS bugfix 1/30/03
{
CTCS_ArrayIterator itemIter(mDragItems);
SDragItemInfo itemInfo;
while (itemIter.Next(&itemInfo))
{
TCS_Forget(itemInfo.flavors);
}
}

#if TCS_FOR_OSX
#elif TCS_CANUSE_QUICKTIME
TCS_DisposeRoutine(mDragDrawProc);
#endif
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

InitDragger v1.0, 10-30-96 rev TCS 1/10/04

Common initializations

*******************************************************************************/
void CTCS_Dragger::InitDragger(CTCS_Draggable *inSource)
{
mImageLayer = -1; // rev TCS 1/10/04
mDragID = 0;
mNextItemRef = 1;
// Initialize drag & clip areas
mCurrPort = TCS_GetPort();
mDragArea = TCS_GetPortRect(mCurrPort); // rev TCS 12/26/03
mClipArea = mDragArea;
mDragImage = mDragArea;
mHiliteRgn = nil;

mHiliteBackColor = CTCS_RGBColor::GetWhiteColor();

mLocation.h = 0;
mLocation.v = 0;

mDragRef = nil;
mSendDataProc = nil;
mDragDrawProc = nil;
mImageBitMap = nil;
mDragData = nil;
// Record shift-key states at drag start
SaveModifierState();

// Set up static refs to source & target
sSource = inSource;
TCS_FailNILMsg(sSource, TCS_GetErrString(errID_BadObject));
sTarget = nil;
// TCS removed some non-QT windows code 12/26/03
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

SaveModifierState v1.1, 07-31-96, 09-22-97

Saves the state of the modifier keys, based on the mouse event.
Pass nil to get current keyboard states directly from the keyboard.

*******************************************************************************/
void CTCS_Dragger::SaveModifierState(const SMouseDownEvent *inMouseDown)
{
if (inMouseDown != nil)
{
mKeyStates.shiftDown = TCS_ShiftIsDown(inMouseDown->macEvent);
mKeyStates.controlDown = TCS_ControlIsDown(inMouseDown->macEvent);
mKeyStates.optionDown = TCS_OptionIsDown(inMouseDown->macEvent);
mKeyStates.commandDown = TCS_CommandIsDown(inMouseDown->macEvent);
}
else
{
mKeyStates.shiftDown = TCS_ShiftDown();
mKeyStates.controlDown = TCS_ControlDown();
mKeyStates.optionDown = TCS_OptionDown();
mKeyStates.commandDown = TCS_CommandDown();
}
}
/******************************************************************************

ConstrainToDragArea v1.31, 11-27-95, 08-06-96

Constrains the point to the Drag area,

*******************************************************************************/
void CTCS_Dragger::ConstrainToDragArea(TCS_Point & thePoint)
{
TCS_Rect dragRect;
mDragArea.GetEnclRect(&dragRect);
TCS_PinInRect(&thePoint, dragRect);
}
/******************************************************************************

TrackDrag v3.02, ??-??-95, 09-19-96

Sets up to track the drag,
Calls the appropriate tracker based on which Drag Manager is present

*******************************************************************************/
void CTCS_Dragger::TrackDrag(const SMouseDownEvent & inMouseDown)
{
// Set static ptr to this drag
sCurrentDrag = this;
// We need to update the key states from the mousedown info
//SaveModifierState(&inMouseDown); // disabled TCS 5/31/98
// Set ourselves up to actually drag
SetDragRef();
InstallDragItems();
InstallSenderProc();
InstallDrawProc();
// Offset the region to global coordinates
TCS_Point local = inMouseDown.wherePort,
global = TCS_GetEventLocation(inMouseDown.macEvent);
mDragImage.Offset(global.h - local.h, global.v - local.v);
// Now that we're all set up we can finally track the drag
ReallyTrackDrag(inMouseDown.macEvent);
DisposeDrag();

// If there is a target we let it know the drag is completed
if (sTarget != nil)
sTarget->RespondToDrag(*this, eDragCompleted);
// Clear static drag ptr
sCurrentDrag = nil;
}
/******************************************************************************

ReallyTrackDrag v2.0, 07-31-96, 09-22-97

Tracks the mouse until mouse-up

*******************************************************************************/
void CTCS_Dragger::ReallyTrackDrag(const TCS_EventRecord & inDragEvent)
{
// Sanity Check!
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
// If the Mac Drag Manager is present we just let it do the tracking
// Otherwise, we have to do it ourselves
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
::TrackDrag(mDragRef, &inDragEvent, mDragImage.GetRgnHandle());
#elif TCS_FOR_WINDOWS
TCS_NYI("CTCS_Dragger::ReallyTrackDrag")
// No equivalent under Windows, so this branch should never execute
#endif
}
else
{
#if TCS_CANUSE_QUICKTIME
ManualTrackMacDrag(inDragEvent);
#elif TCS_FOR_WINDOWS
ManualTrackWinDrag(inDragEvent);
#endif
}
}
/******************************************************************************

ManualTrackMacDrag v1.0, 09-22-97

Brute force tracking of mac drag,
Called only when Mac Drag & Drop is NOT installed

*******************************************************************************/
#if TCS_CANUSE_QUICKTIME
void CTCS_Dragger::ManualTrackMacDrag(const TCS_EventRecord & inDragEvent)
{
#if TCS_FOR_OSX // TCS 12/26/03
// We can definitely count on drag & drop in OS X
NeoUsed(inDragEvent);
#else
// Set up a port that covers the entire desktop
TCS_GrafPtr windMgrPort,
desktopPort = NEW GrafPort;
LView::OutOfFocus(nil); // We won't restore focus

mCurrPort = UQDGlobals::GetCurrentPort();
::GetWMgrPort(&windMgrPort);
::OpenPort(desktopPort);
#if TCS_FOR_MAC // mfs_sa 5jul2k2, Closed for windows
desktopPort->portBits = windMgrPort->portBits;
desktopPort->portRect = windMgrPort->portRect;
#endif
TCS_ClipToRegion(GetGrayRgn());
mDragArea = GetGrayRgn();
// Set up drawing proc if one hasn't been set already.
DragDrawingUPP drawProc = NewDragDrawingProc(DrawBMPProc);
if (mDragDrawProc == nil)
SetDragDrawProc(drawProc);
// Make sure the mouse is still down
if (TCS_MouseStillDown())
{
TCS_Point pinnedMouse;
TCS_WindowPtr theWind,
lastWind = nil;
// Set our initial location & draw the image
mLocation = inDragEvent.where;
CallDragDrawingProc(mDragDrawProc, kDragRegionBegin, nil,
mLocation, nil, mLocation, mImageBitMap, mDragRef);
Show();
// Loop until mouseup occurs
while (TCS_WaitMouseUp())
{
// Get the new mouse location & move the image
// We need to reset the port first
TCS_SetPort(desktopPort);
GetDragMouse(nil, &pinnedMouse);
if (pinnedMouse != mLocation)
{
MoveTo(pinnedMouse);
// Figure out which window is under the mouse & set the port
// accordingly. We set the port for compatibility with
// the Mac Drag Manager
TCS_FindWindow(pinnedMouse, &theWind);
Hide();
TCS_SetPort(theWind);
// Check if we are in a different window than last time
if (theWind != lastWind)
{
// If the last window is not nil, inform its
// trackers that the drag has left the window
if (lastWind != nil)
CallWindowTrackers(kDragTrackingLeaveWindow, lastWind);
// Tell the new window's trackers the drag is entering
if (theWind != nil)
CallWindowTrackers(kDragTrackingEnterWindow, theWind);
// Update last window pointer
lastWind = theWind;
}
// If the current window is not nil,
// tell its trackers to do their thing
if (theWind != nil)
CallWindowTrackers(kDragTrackingInWindow, theWind);
TCS_SetPort(desktopPort);
Show();
}
}
// Hide the image
Hide();
// If the current window is not nil we tell its trackers the
// drag has left the window. We do this for compatability with
// the Mac Drag Manager
if (theWind != nil)
{
// Call the receive handler
DragReceiveHandlerUPP receiver = NewDragReceiveHandlerProc(DefaultReceiver);
CallDragReceiveHandlerProc(receiver, theWind, nil, mDragRef);
TCS_DisposeRoutine(receiver); // rev TCS 12/6/00
CallWindowTrackers(kDragTrackingLeaveWindow, theWind);
}
}
// Restore the port
::ClosePort(desktopPort);
TCS_SetPort(mCurrPort);
TCS_DisposeRoutine(drawProc); // rev TCS 12/6/00
TCS_Forget(desktopPort); // TCS rev 11/5/00
#endif
}
#endif
/******************************************************************************

ManualTrackWinDrag

Brute force tracking of Windows drag, v1.0
Since Windows does not have a drag manager this is always called

*******************************************************************************/
#if TCS_FOR_WINDOWS && !TCS_CANUSE_QUICKTIME
void CTCS_Dragger::ManualTrackWinDrag(const TCS_EventRecord & inDragEvent)
{
#pragma unused(inDragEvent)
SIGNAL_Debug("Not Yet Implemented!");
}
#endif
/******************************************************************************

CallWindowTrackers v1.01, 08-06-96, 08-07-96

Call all trackers associated with the window,

*******************************************************************************/
void CTCS_Dragger::CallWindowTrackers(const TCS_DragDrawMessage inMessage,
const TCS_WindowPtr inWind)
{
CTCS_ArrayIterator iterator(sTrackerList);
STrackerInfo info;
// Iterate through all trackers
while (iterator.Next(&info))
{
// We call the tracker if either it belongs to this
// window specifically, or if it is global(nil window)
if ((info.window == inWind) || (info.window == nil))
{
#if TCS_FOR_OSX // TCS 1/3/04
::InvokeDragTrackingHandlerUPP(inMessage, inWind,
info.refCon, mDragRef, info.tracker);
#else
CallDragTrackingHandlerProc(info.tracker, inMessage,
inWind, info.refCon, mDragRef);
#endif
}
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

MoveTo

Moves the drag outline, v3.01, 11-20-95, 08-06-96
The caller is responsible for ensuring the new location is valid

*******************************************************************************/
void CTCS_Dragger::MoveTo(TCS_Point newLoc)
{
if (newLoc != mLocation)
{
CTCS_Region oldRgn = mDragImage;
mDragImage.Offset(newLoc.h - mLocation.h, newLoc.v - mLocation.v);
#if TCS_FOR_OSX // TCS 1/3/04 rev 3/22/04
::InvokeDragDrawingUPP(drawMessage_Draw,
oldRgn.GetRgnHandle(), mLocation,
mDragImage.GetRgnHandle(), newLoc,
mImageBitMap, mDragRef, nil);
#else
CallDragDrawingProc(mDragDrawProc, drawMessage_Draw,
oldRgn.GetRgnHandle(), mLocation,
mDragImage.GetRgnHandle(), newLoc,
mImageBitMap, mDragRef);
#endif
mLocation = newLoc;
}
}

/******************************************************************************

Show v2.1, 11-27-95, 07-31-96

Brings image up one layer,
If image ends up on layer zero, it is shown

*******************************************************************************/
void CTCS_Dragger::Show()
{
// Sanity Check!
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
mImageLayer++;
if (mImageLayer == 0)
{
TCS_RgnHandle hideRgn = TCS_NewRgn();
TCS_Point showPt,
hidePt = {0,0};
GetDragMouse(nil, &showPt);
#if TCS_FOR_OSX // TCS 1/3/04 rev 3/22/04
::InvokeDragDrawingUPP(drawMessage_Draw,
mDragImage.GetRgnHandle(), showPt,
hideRgn, hidePt, mImageBitMap, mDragRef,
nil);
#else
CallDragDrawingProc(mDragDrawProc, drawMessage_Draw,
mDragImage.GetRgnHandle(), showPt,
hideRgn, hidePt, mImageBitMap, mDragRef);
#endif
}
}
/******************************************************************************

Hide v2.1, 11-27-95, 07-31-96

Pushes image down one layer,
If image was on layer zero, it is hidden

*******************************************************************************/
void CTCS_Dragger::Hide()
{
// Sanity Check!
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
mImageLayer--;
if (mImageLayer == -1)
{
TCS_Point showPt = {0,0},
hidePt;
GetDragMouse(nil, &hidePt);
#if TCS_FOR_OSX // TCS 1/3/04 rev 3/22/04
::InvokeDragDrawingUPP(drawMessage_Hide, nil, showPt,
mDragImage.GetRgnHandle(),
hidePt, mImageBitMap, mDragRef, nil);
#else
CallDragDrawingProc(mDragDrawProc, drawMessage_Hide, nil, showPt,
mDragImage.GetRgnHandle(),
hidePt, mImageBitMap, mDragRef);
#endif
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

SetDragImageRgn v2.0, 12-29-95, 05-08-96

Sets the region that is dragged,
Renamed from SetDragImage(), 04-04-96

*******************************************************************************/
void CTCS_Dragger::SetDragImageRgn(const CTCS_Region & aRgn)
{
mDragImage = aRgn;
}
/******************************************************************************

SetDragImageBitmap v1.01, 04-04-96, 04-05-96

Defines a bitmap to drag,

*******************************************************************************/
void CTCS_Dragger::SetDragImageBitmap(TCS_BitMap *aBitMap)
{
TCS_FailNILMsg(aBitMap, TCS_GetErrString(errID_BadObject));
mImageBitMap = aBitMap;
// Install a reference to the default bitmap drawing proc
#if TCS_FOR_OSX // TCS 1/3/04
TCS_DragDrawProc drawProc = ::NewDragDrawingUPP(DrawBMPProc);
SetDragDrawProc(drawProc);
#else
TCS_DragDrawProc drawProc = NewDragDrawingProc(DrawBMPProc);
SetDragDrawProc(drawProc);
#endif
}
/******************************************************************************

SetDragImageIcon v1.2, 04-04-96, 08-01-96

Creates a bitmap to drag from an icon,
Callers should specify inCenterPt in local coordinates

*******************************************************************************/
void CTCS_Dragger::SetDragImageIcon(const ResIDT anIconID,
const TCS_Point inCenterPt)
{
TCS_IconSuiteH suiteH;
TCS_IconHandle icon;
TCS_RgnHandle iconRgn = TCS_NewRgn();
TCS_BitMap *bitMap = NEW TCS_BitMap;
TCS_FailNILMsg(bitMap, TCS_GetErrString(errID_BadGraphic));
TCS_FailOSErr(TCS_GetIconSuite(&suiteH, anIconID, iconSelector_Large1Bit));
TCS_FailOSErr(TCS_GetIconFromSuite(&icon, suiteH, cIconBandWResType));
TCS_FailNILMsg(icon, TCS_GetErrString(errID_BadIcon));
TStHandleLocker lock(icon);
#if TCS_CANUSE_QUICKTIME
bitMap->baseAddr = *icon; // Set up the bitmap
#elif TCS_FOR_WINDOWS
bitMap->baseAddr = (char *) icon; // Set up the bitmap
#endif
bitMap->rowBytes = 4;
TCS_SetRect(& (bitMap->bounds), inCenterPt.h - (cIconSize >> 1),
inCenterPt.v - (cIconSize >> 1), inCenterPt.h + (cIconSize >> 1),
inCenterPt.v + (cIconSize >> 1));
SetDragImageBitmap(bitMap);

// fetch the icon outline TCS removed mac-specific code 8/1/00
#if TCS_FOR_MAC
TCS_FailOSErr(TCS_GetIconRegion(anIconID, iconRgn, bitMap->bounds));
#elif TCS_FOR_WINDOWS
// mfs_sa 5jul2k2
// IconIDToRegion is not available on Windows, but luckily
// we have BitMapToRegion available, so use that instead
TCS_FailOSErr(::BitMapToRegion(iconRgn, bitMap));
#endif
SetDragImageRgn(CTCS_Region(iconRgn));
}
/******************************************************************************

InstallHandlersInWindow v1.1, 05-06-96, 08-06-96

Install the standard handlers in a window,

*******************************************************************************/
void CTCS_Dragger::InstallHandlersInWindow(TCS_WindowPtr wind, void *refCon)
{
TCS_TRY
{
// Install the defualt tracking handler
#if TCS_FOR_OSX
InstallTracker(::NewDragTrackingHandlerUPP(DefaultTracker), wind, refCon);

DragReceiveHandlerUPP receiver =
::NewDragReceiveHandlerUPP(DefaultReceiver);
// It's ok if the handlers are already installed for the
// window, so we just swallow the error if that ocurrs
OSErr err = InstallReceiveHandler(receiver, wind, refCon);
if ((err != noErr) && (err != duplicateHandlerErr))
TCS_FailOSErr(err);
#else
InstallTracker(NewDragTrackingHandlerProc(DefaultTracker), wind, refCon);
// Install the default receiver only when the Mac Drag Mgr is present
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
DragReceiveHandlerUPP receiver =
NewDragReceiveHandlerProc(DefaultReceiver);
// It's ok if the handlers are already installed for the
// window, so we just swallow the error if that ocurrs
OSErr err = ::InstallReceiveHandler(receiver, wind, refCon);
if ((err != noErr) && (err != duplicateHandlerErr))
TCS_FailOSErr(err);
#else
// This branch should never execute under Windows
SIGNAL_Debug("Illegal branch?");
#endif
} // if no Drag Manager, do nothing
#endif
}
TCS_CATCH
{
}
}
/******************************************************************************

InstallTracker v1.11, 12-29-95, 08-07-96

Installs a tracking handler in a window,
if (aWindow == nil) the tracker is installed globally for all app windows

*******************************************************************************/
Boolean CTCS_Dragger::InstallTracker(TCS_DragTrackProc aTracker,
TCS_WindowPtr aWindow, void *aRefCon)
{
Boolean installed = false;
STrackerInfo trackInfo;
TCS_TRY
{
// Set up the tracker info
trackInfo.tracker = aTracker;
trackInfo.window = aWindow;
trackInfo.refCon = aRefCon;
// Only add it to the list if not already present for this window
if (sTrackerList.FetchIndexOf(&trackInfo) == CTCS_Array::index_Bad)
{
sTrackerList.Append(&trackInfo);
// If the Mac Drag Mgr is present we also add tracker there
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
// It's ok if the handler is already installed for the
// window, so we just swallow the error if that ocurrs
OSErr err = InstallTrackingHandler(aTracker, aWindow, aRefCon);
// if ((err != noErr) && (err != duplicateHandlerErr))
TCS_FailOSErr(err);
installed = true;
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
}
}
TCS_CATCH
{
sTrackerList.Remove(&trackInfo);
}
return installed;
}
/******************************************************************************

GetDragMouse v1.1, 01-18-96, 07-31-96

Returns the position/pinned position of the mouse,
// THe returned points are in GLOBAL coordinates

*******************************************************************************/
void CTCS_Dragger::GetDragMouse(TCS_Point *mouse, TCS_Point *pinnedMouse)
{
// Sanity Check!
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
// If the Mac Drag Manager is present we get the info from it
// Otherwise we collect it manually
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
TCS_FailOSErr(::GetDragMouse(mDragRef, mouse, pinnedMouse));
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
else
{
TCS_Point tmpMouse;
// Get the current mouse location & convert to global coordinates
// We need global coords since that's what Mac Drag Manager uses
TCS_GetMouse(&tmpMouse);
TCS_LocalToGlobal(&tmpMouse);
if (mouse != nil)
*mouse = tmpMouse;
if (pinnedMouse != nil)
{
ConstrainToDragArea(tmpMouse);
*pinnedMouse = tmpMouse;
}
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

ItemHasFlavor v1.0, 10-31-96

Gets the data for an item

*******************************************************************************/
Boolean CTCS_Dragger::ItemHasFlavor(const TCS_DragItemRef inItemRef,
const TCS_FlavorType inFlavor)
{
TCS_FlavorFlags flags;
// Fastest way to find out is to just try to get the flags
return (GetItemFlavorFlags(&flags, inItemRef, inFlavor) == noErr);
}
/******************************************************************************

GetItemFlavorFlags v1.0, 10-31-96

Gets the data for an item

*******************************************************************************/
OSErr CTCS_Dragger::GetItemFlavorFlags(TCS_FlavorFlags *outFlags,
const TCS_DragItemRef inItemRef,
const TCS_FlavorType inFlavor)
{
TCS_TRY
{
// Sanity check
TCS_ASSERTMsg(mDragRef, TCS_GetErrString(errID_BadGraphic));
TCS_FailNILMsg(outFlags, TCS_GetErrString(errID_BadGraphic));
// Get the flags
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
return ::GetFlavorFlags(mDragRef, inItemRef, inFlavor, outFlags);
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
return -1;
#endif
}
else
{
SFlavorInfo info;
// Try to get the flavor info
if (!GetFlavorInfo(inItemRef, inFlavor, &info))
{
return err_BadDragFlavor;
}
else
{
*outFlags = info.flags;
return noErr;
}
}
}
TCS_CATCH {}

return err_BadDragRef;
}
/******************************************************************************

GetDragItemData v1.0, 10-31-96

Gets the data for an item

*******************************************************************************/
OSErr CTCS_Dragger::GetDragItemData(void *outData, SInt32 *ioSize,
const TCS_DragItemRef inItemRef,
const TCS_FlavorType inFlavor,
UInt32 inOffset)
{
TCS_FailNILMsg(outData, TCS_GetErrString(errID_BadPointer)); // TCS 9/19/02
TCS_FailNILMsg(ioSize, TCS_GetErrString(errID_BadPointer));

TCS_TRY
{
TCS_ASSERTMsg(mDragRef, TCS_GetErrString(errID_BadAction));
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_CANUSE_QUICKTIME
return ::GetFlavorData(mDragRef, inItemRef, inFlavor,
outData, ioSize, inOffset);
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
return -1;
#endif
}
else
{
SFlavorInfo info;
// Try to get the flavor info
if (!GetFlavorInfo(inItemRef, inFlavor, &info))
{
return err_BadDragFlavor;
}
else
{
// return the data
if (*ioSize >(info.size - inOffset))
*ioSize = (info.size - inOffset);
TCS_BlockMove(& (((char *) info.data) [inOffset]), outData, *ioSize);
return noErr;
}
}
}
TCS_CATCH {}

return err_BadDragRef;
}
/******************************************************************************

SetDragItemData v1.0, 10-31-96

Sets the data to be sent for an item's flavor

*******************************************************************************/
void CTCS_Dragger::SetDragItemData(const void *inDataPtr, const UInt32 inDataSize,
const TCS_DragItemRef inItemRef,
const TCS_FlavorType inFlavor,
const UInt32 inOffset)
{
// Sanity check!
TCS_ASSERTMsg(mDragRef, TCS_GetErrString(errID_BadAction));
// Set the flavor data
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_CANUSE_QUICKTIME
OSErr err = ::SetDragItemFlavorData(mDragRef, inItemRef, inFlavor,
inDataPtr, inDataSize, inOffset);
TCS_FailOSErr(err);
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
else
{
SFlavorInfo info;
// Try to get the flavor info
if (GetFlavorInfo(inItemRef, inFlavor, &info))
{
// Set the data
TCS_BlockMove(inDataPtr, & (((char *) info.data) [inOffset]), inDataSize);
info.size += inDataSize;
}
}
}
/******************************************************************************

GetItemFlavorData v1.0, 08-07-96

Gets the data for an item's flavor

*******************************************************************************/
OSErr CTCS_Dragger::GetItemFlavorData(TCS_DragItemRef inItemRef,
TCS_FlavorType inFlavor, void *outData,
SInt32 *ioSize, UInt32 inOffset)
{
TCS_FailNILMsg(outData, TCS_GetErrString(errID_BadPointer)); // TCS 9/19/02
TCS_FailNILMsg(ioSize, TCS_GetErrString(errID_BadPointer));

TCS_TRY
{
TCS_ASSERTMsg(mDragRef, TCS_GetErrString(errID_BadAction));
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_CANUSE_QUICKTIME
return ::GetFlavorData(mDragRef, inItemRef, inFlavor,
outData, ioSize, inOffset);
#else
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
return -1;
#endif
}
else
{
SFlavorInfo info;
// Try to get the flavor info
if (!GetFlavorInfo(inItemRef, inFlavor, &info))
{
return err_BadDragFlavor;
}
else
{
// return the data
if (*ioSize >(info.size - inOffset))
*ioSize = (info.size - inOffset);
TCS_BlockMove(& (((char *) info.data) [inOffset]), outData, *ioSize);
return noErr;
}
}
}
TCS_CATCH {}

return err_BadDragRef;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

AddDragItem v2.0, 07-31-96, 10-31-96

Adds an item to the list to be dragged,
Return value is the item reference
Clients may pass zero to have an item reference assigned

*******************************************************************************/
TCS_DragItemRef CTCS_Dragger::AddDragItem(const TCS_DragItemRef inItem,
const TCS_FlavorType inFlavor,
void *inData, const SInt32 inSize,
const TCS_FlavorFlags inFlags)
{
SDragItemInfo itemInfo;
SFlavorInfo flavorInfo;
// Set the item reference
if (inItem == 0)
{
// Assign a default reference
itemInfo.item = mNextItemRef++;
}
else
{
// Assign the passed item & update the default item ref
itemInfo.item = inItem;
if (inItem >= mNextItemRef)
mNextItemRef = inItem + 1;
}
// Fill in the flavor info struct
flavorInfo.flavor = inFlavor;
flavorInfo.flags = inFlags;
flavorInfo.data = inData;
flavorInfo.size = inSize;
// See if the item reference already exists
if (!GetItemInfo(inItem, &itemInfo))
{
// It's a new item, so we need to create the flavor array
itemInfo.flavors = NEW CTCS_Array(sizeof(SFlavorInfo));
}
// Append the info to the arrays & return the item reference
TCS_FailNILMsg(itemInfo.flavors, TCS_GetErrString(errID_BadObject));
itemInfo.flavors->Append(&flavorInfo);
mDragItems.Append(&itemInfo);
return itemInfo.item;
}
/******************************************************************************

SetDragRef v1.0, 07-31-96 renamed TCS 1/10/04
Installs all drag items into the current drag

*******************************************************************************/
void CTCS_Dragger::SetDragRef()
{
// Sanity Check! We shouldn't have a drag ref yet.
// If this throws an exception, we don't want to catch it here
TCS_ASSERTMsg(mDragRef == 0, TCS_GetErrString(errID_BadAction));
TCS_TRY
{
// If the Mac Drag Manager is present we get the ref from it
// Otherwise we just use 'this'
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
TCS_FailOSErr(::NewDrag(&mDragRef));
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
else
{
mDragRef = (TCS_DragRef) this;
}
}
TCS_CATCH
{
// Set the drag reference to zero and rethrow
mDragRef = 0;
throw;
}
}
/******************************************************************************

DisposeDrag v1.0, 07-31-96

Disposes the drag,

*******************************************************************************/
void CTCS_Dragger::DisposeDrag()
{
TCS_TRY
{
// Sanity Check!
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
// If the Mac Drag Manager is present we must let it dispose
// Otherwise we just set the ref to zero
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
TCS_FailOSErr(::DisposeDrag(mDragRef));
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
else
{
mDragRef = 0;
}
}
TCS_CATCH
{
// Set the drag reference to zero and rethrow
mDragRef = 0;
throw;
}
}
/******************************************************************************

GetFlavorInfo v1.0, 10-31-96

Returns a flavor info struct for an item,
Return value indicates whether the flavor was found
if the flavor info is not found outInfo will be the same as at entry

*******************************************************************************/
Boolean CTCS_Dragger::GetFlavorInfo(const TCS_DragItemRef inItemRef,
const TCS_FlavorType inFlavor,
SFlavorInfo *outInfo)
{
SDragItemInfo itemInfo;
SFlavorInfo flavorInfo;
Boolean success = false;
TCS_TRY
{
// Try to get the item info
if (GetItemInfo(inItemRef, &itemInfo))
{
// Make sure everything's sane!
TCS_FailNILMsg(itemInfo.flavors, TCS_GetErrString(errID_BadValue));
TCS_FailNILMsg(outInfo, TCS_GetErrString(errID_BadValue));
CTCS_ArrayIterator iterator(*(itemInfo.flavors));
// Search for the flavor info
while (iterator.Next(&flavorInfo))
{
if (flavorInfo.flavor == inFlavor)
{
*outInfo = flavorInfo;
success = true;
break;
}
}
}
}
TCS_CATCH
{
// Something happened, so we didn't succeed
success = false;
}
return success;
}
/******************************************************************************

GetItemInfo v1.0, 10-31-96

Gets the info struct for an item
Return value indicates whether the item was found
if the item info is not found outInfo will be the same as at entry

*******************************************************************************/
Boolean CTCS_Dragger::GetItemInfo(const TCS_DragItemRef inItemRef,
SDragItemInfo *outInfo)
{
CTCS_ArrayIterator iterator(mDragItems);
SDragItemInfo info;
Boolean success = false;
TCS_TRY
{
// Search for the item in question
TCS_FailNILMsg(outInfo, TCS_GetErrString(errID_BadValue));
while (iterator.Next(&info))
{
if (info.item == inItemRef)
{
*outInfo = info;
success = true;
break;
}
}
}
TCS_CATCH
{
success = false;
}
return success;
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

InstallDragItems v2.0, 07-31-96, 10-31-96

Installs all drag items into the current drag

*******************************************************************************/
void CTCS_Dragger::InstallDragItems()
{
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
// We only need to do this if the Mac Drag Manager is present
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
CTCS_ArrayIterator itemIter(mDragItems);
SDragItemInfo itemInfo;
SFlavorInfo flavorInfo;
while (itemIter.Next(&itemInfo))
{
TCS_FailNILMsg(itemInfo.flavors, TCS_GetErrString(errID_BadValue));
CTCS_ArrayIterator flavorIter(*(itemInfo.flavors));
while (flavorIter.Next(&flavorInfo))
{
TCS_FailOSErr(::AddDragItemFlavor(mDragRef, itemInfo.item,
flavorInfo.flavor, flavorInfo.data, flavorInfo.size,
flavorInfo.flags));
}
}
#else
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
}
/******************************************************************************

InstallSenderProc

Installs the drag data sender proc

*******************************************************************************/
void CTCS_Dragger::InstallSenderProc()
{
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
// We only need to do this if the Mac Drag Manager is present
if ((mSendDataProc != nil) && CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
TCS_FailOSErr(::SetDragSendProc(mDragRef, mSendDataProc, nil));
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
}
/******************************************************************************

InstallDrawProc v1.0, 07-31-96
Installs the drawing proc

*******************************************************************************/
void CTCS_Dragger::InstallDrawProc()
{
TCS_ASSERTMsg(mDragRef != 0, TCS_GetErrString(errID_BadAction));
// We only need to do this if the Mac Drag Manager is present
if ((mDragDrawProc != nil) && CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_OSX
// do nothing in OS X TCS 3/22/04
#elif TCS_FOR_MAC
TCS_FailOSErr(::SetDragDrawingProc(mDragRef, mDragDrawProc, mImageBitMap));
#elif TCS_FOR_WINDOWS
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

ShowHilite v1.02, 09-24-96, 12-19-96

Shows the drag hilite

*******************************************************************************/
void CTCS_Dragger::ShowHilite(const CTCS_Region & inRegion, Boolean inside,
const CTCS_RGBColor & inBackColor)
{
TCS_TRY
{
TStColorPenState penState;
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
// Set the background color & hilite
mHiliteBackColor = inBackColor;
TCS_SetBackgroundColor(mHiliteBackColor);
::ShowDragHilite(mDragRef, inRegion.GetRgnHandle(), inside);
#elif TCS_FOR_WINDOWS
#pragma unused(inBackColor)
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
else
{
// Set up pen
penState.Normalize();
TCS_PenSize(cHilitePenSize, cHilitePenSize);
TCS_PenMode(penMode_Xor);

// Erase the previous hilite if it exists, or allocate memory
if (mHiliteRgn != nil)
{
UDrawingUtils::SetHiliteModeOn();
mHiliteRgn->Frame();
}
else
{
mHiliteRgn = NEW CTCS_Region;
}
// Set the new hilite region & show it
*mHiliteRgn = inRegion;
if (!inside)
mHiliteRgn->Inset(-2, -2);
UDrawingUtils::SetHiliteModeOn();
mHiliteRgn->Frame();
}
}
TCS_CATCH
{
}
}
/******************************************************************************

HideHilite v1.02, 09-24-96, 12-19-96

Hides the drag hilite

*******************************************************************************/
void CTCS_Dragger::HideHilite()
{
TStColorPenState penState;
if (CTCS_Environment::HasMacDragManager())
{
#if TCS_FOR_MAC
// Set the background color & remove the hilite
TCS_SetBackgroundColor(mHiliteBackColor);
::HideDragHilite(mDragRef);
#else
// Branch should not be executed under Windows
SIGNAL_Debug("Illegal branch?");
#endif
}
else
{
// Sanity Check!
if (mHiliteRgn == nil)
return;
// Set up pen
penState.Normalize();
TCS_PenSize(cHilitePenSize, cHilitePenSize);
TCS_PenMode(penMode_Xor);

// Erase the previous hilite & trash the memory
#if TCS_CANUSE_QUICKTIME
UDrawingUtils::SetHiliteModeOn();
#endif
mHiliteRgn->Frame();
TCS_Forget(mHiliteRgn);
}
}
#if CAN_USE_MARK
#pragma mark -
#endif
/******************************************************************************

DrawMBagProc v1.11, 04-05-96, 08-02-96

Draws a bitmap, Custom callback for drag drawing

*******************************************************************************/
#if TCS_FOR_WINDOWS // mfs_sa 2jul2k2, ADDED, see comment in header
DEFINE_API(OSErr)
#elif TCS_FOR_MAC
pascal OSErr
#endif
CTCS_Dragger::DrawBMPProc (TCS_DragDrawMessage message,
TCS_RgnHandle showRegion,
TCS_Point showOrigin,
TCS_RgnHandle hideRegion,
TCS_Point hideOrigin,
void *dragDrawingRefCon,
TCS_DragRef /*theDragRef*/)
{
#if TCS_CANUSE_QUICKTIME
const SInt32 cHalfIconSize = cIconSize / 2;
TCS_GrafPtr dragPort;
TCS_BitMap *bitMap = (TCS_BitMap *) dragDrawingRefCon;
// Check parameters
if (dragDrawingRefCon == nil)
return paramErr;
// Get the port
TCS_GetPort(&dragPort);
// Check the message
switch (message)
{
case kDragRegionBegin :
// Set up the port
TCS_ForeColor(blackColor);
TCS_BackColor(whiteColor);
TCS_PenMode(patXor);
TCS_BlackPenPat();
break;
case kDragRegionDraw :
{
TCS_Rect showRect = { showOrigin.v - cHalfIconSize,
showOrigin.h - cHalfIconSize,
showOrigin.v + cHalfIconSize,
showOrigin.h + cHalfIconSize },
hideRect = { hideOrigin.v - cHalfIconSize,
hideOrigin.h - cHalfIconSize,
hideOrigin.v + cHalfIconSize,
hideOrigin.h + cHalfIconSize };
TCS_PaintRgn(hideRegion);
TCS_PaintRgn(showRegion);
break;
}
case kDragRegionHide :
{
TCS_Rect hideRect = { hideOrigin.v - cHalfIconSize,
hideOrigin.h - cHalfIconSize,
hideOrigin.v + cHalfIconSize,
hideOrigin.h + cHalfIconSize };
#if TCS_FOR_MAC
LMSetHiliteMode(LMGetHiliteMode() | (1 << hiliteBit));
#endif
TCS_PaintRgn(hideRegion);
break;
}
}
return noErr;
#elif TCS_FOR_WINDOWS
#pragma unused(message, showRegion, showOrigin, hideRegion)
#pragma unused(hideOrigin, dragDrawingRefCon)
TCS_NYI("CTCS_Dragger::DrawBMPProc!");
return noErr;
#endif
}
/******************************************************************************

DefaultTracker v1.13, 05-06-96, 09-19-96

Drag Tracking handler

*******************************************************************************/
#if TCS_FOR_WINDOWS // mfs_sa 2jul2k2, ADDED, see comment in header
DEFINE_API(OSErr)
#elif TCS_FOR_MAC
pascal OSErr
#endif
CTCS_Dragger::DefaultTracker(TCS_DragTrackMessage message,
TCS_WindowPtr theWindow,
void */*handlerRefCon*/,
TCS_DragRef /*theDragRef*/)
{
TCS_Point pinnedPoint;
CTCS_DragAware *paneHit = nil;
switch (message)
{
case kDragTrackingInWindow :
{
// Origin needs to be(0, 0) so Global To Local conversions work right
LView::OutOfFocus(nil);
TCS_SetOrigin(0, 0);
// Get the mouse position and find out if a drag-aware pane was hit
// We iterate from the end of the drop-panes list because the most
// deeply nested panes are usually added last. By iterating backwards
// through the list we should find the topmost pane that is hit
if (sCurrentDrag == nil)
return err_Params;
sCurrentDrag->GetDragMouse(nil, &pinnedPoint);
TCS_GlobalToLocal(&pinnedPoint);

TDropPaneInfoArrayIterator iter(CTCS_DragAware::sDropPanes, iter_from_end);
SDropPaneInfo info; // TCS rewrite 12/13/03
CTCS_DragAware *thePane = nil;

while (iter.Previous(info))
{
if (info.window == theWindow)
{
thePane = info.pane;
if (thePane)
{
LPane *testPane = thePane->GetDragPane();

if (testPane && testPane->IsHitBy(pinnedPoint.h, pinnedPoint.v))
{
paneHit = TCS_SAFE_CAST(thePane, CTCS_DragAware);
break;
}
}
}
}

/*CTCS_DragAware::sDropPanes.DoForEachUntil((ArrayItemTestFunc) PaneHitBy_Func,
iter_from_end,
&pinnedPoint, theWindow,
&paneHit);*/
// Update the drag ticks variable
sDragTicks = TCS_TickCount();
// Now we check if this is the same pane we were in last time
if (paneHit == sTarget)
{
// Drag is in the same pane as last time(could be no pane)
// If we're actually in a pane, we tell it to do something
if (paneHit != nil)
paneHit->RespondToDrag(*sCurrentDrag, eDragWithinPane);
}
else
{
// Tell the previous drag pane we've left
if (sTarget != nil)
sTarget->RespondToDrag(*sCurrentDrag, eDragLeavingPane);
// If we are in a drag pane now, we reset the action tick
// and tell the pane the drag has entered it
sTarget = paneHit;
if (paneHit != nil)
{
paneHit->ResetActionTick();
paneHit->RespondToDrag(*sCurrentDrag, eDragEnteringPane);
}

}
}
break;
case kDragTrackingLeaveWindow :

// Purge any cached focus
LView::OutOfFocus(nil);
// If we were in a pane before, we tell it the drag has left it
if (sTarget != nil)
sTarget->RespondToDrag(*sCurrentDrag, eDragLeavingPane);
sTarget = nil;
break;

default:
break;
}
return noErr;
}
/******************************************************************************

DefaultReceiver v1.11, 05-06-96, 09-19-96

Generic drag receiver

*******************************************************************************/
#if TCS_FOR_WINDOWS // mfs_sa 2jul2k2, ADDED, see comment in header
DEFINE_API(OSErr)
#elif TCS_FOR_MAC
pascal OSErr
#endif
CTCS_Dragger::DefaultReceiver(TCS_WindowPtr /*theWindow*/,
void */*handlerRefCon*/,
TCS_DragRef /*theDragRef*/)
{
// If there is no target, the user must want to cancel
if (sTarget == nil)
return err_UserCanceled;
// Find out if the target can accept the drag and process
TCS_FailNILMsg(sCurrentDrag, TCS_GetErrString(errID_BadGraphic));

if (sTarget->CanAcceptDrag(*sCurrentDrag))
{
LView::OutOfFocus(nil);
sTarget->FinishDrag(*sCurrentDrag, sSource);
return noErr;
}
else
return err_DragNotAccepted;
}