netscape-revival
lib/mac/VText/V_PowerPlant_Mods/LDataDragEventHandler.cp
// ===========================================================================
// LDataDragEventHandler.cp ©1994 Metrowerks Inc. All rights reserved.
// ===========================================================================
#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif
#include "LDataDragEventHandler.h"
#include <LSelection.h>
#include <LSelectableItem.h>
#include <LAEAction.h>
#include <UAppleEventsMgr.h>
#include <UDrawingState.h>
#include <UMemoryMgr.h>
#include <LDragTube.h>
#include <URegions.h>
#include <LSelectHandlerView.h>
#include <LStream.h>
#include <StClasses.h>
#include <UCursor.h>
#ifndef __ERRORS__
#include <Errors.h>
#endif
#pragma warn_unusedarg off
#define ZOOMSTEPS 12
#define DragTask LDataDragTask::sActiveTask
// ===========================================================================
// Maintenance
DragSendDataUPP LDataDragEventHandler::sDragSendDataUPP
= NewDragSendDataProc(LDropArea::HandleDragSendData);
Boolean LDataDragEventHandler::sPreScrollWasHilited;
LDataDragEventHandler *LDataDragEventHandler::sReceiveHandler = NULL;
LDataDragEventHandler::LDataDragEventHandler()
: LDropArea(UQDGlobals::GetCurrentPort())
{
mReceiver = NULL;
mPossibleReceiver = NULL;
mStartsDataDrags = true;
mReceivesDataDrags = true;
}
LDataDragEventHandler::~LDataDragEventHandler()
{
ReplaceSharable(mReceiver, (LSelectableItem *)NULL, this);
ReplaceSharable(mPossibleReceiver, (LSelectableItem *)NULL, this);
}
#ifndef PP_No_ObjectStreaming
void LDataDragEventHandler::WriteObject(LStream &inStream) const
{
inStream << mStartsDataDrags;
inStream << mReceivesDataDrags;
LEventHandler::WriteObject(inStream);
}
void LDataDragEventHandler::ReadObject(LStream &inStream)
{
inStream >> mStartsDataDrags;
inStream >> mReceivesDataDrags;
LEventHandler::ReadObject(inStream);
}
#endif
void LDataDragEventHandler::Reset(void)
{
OSErr err = noErr;
inheritEventHandler::Reset();
ReplaceSharable(mReceiver, (LSelectableItem *)NULL, this);
ReplaceSharable(mPossibleReceiver, (LSelectableItem *)NULL, this);
Try_ {
delete DragTask;
DragTask = NULL;
} Catch_(err) {
DragTask = NULL;
} EndCatch_;
}
Boolean LDataDragEventHandler::GetStartsDataDrags(void)
{
return mStartsDataDrags;
}
void LDataDragEventHandler::SetStartsDataDrags(Boolean inStartsDataDrags)
{
mStartsDataDrags = inStartsDataDrags;
}
Boolean LDataDragEventHandler::GetReceivesDataDrags(void)
{
return mReceivesDataDrags;
}
void LDataDragEventHandler::SetReceivesDataDrags(Boolean inReceivesDataDrags)
{
mReceivesDataDrags = inReceivesDataDrags;
}
LDataDragTask * LDataDragEventHandler::MakeDragTask(
LDataDragEventHandler *inHandler,
Boolean inHandlerIsSource)
{
return new LDataDragTask(inHandler, inHandlerIsSource);
}
// ===========================================================================
// Drag actions:
DataDragT LDataDragEventHandler::FindDragSemantic(void)
{
OSErr err;
DragAttributes attributes;
DataDragT rval;
short modifiers,
downModifiers,
upModifiers;
err = GetDragAttributes(DragTask->mDragRef, &attributes);
ThrowIfOSErr_(err);
/*-
if (!(attributes & dragInsideSenderApplication))
Throw_(paramErr); // Can't be here because sender does the drag.
*/
if ((attributes & dragInsideSenderWindow) && DragTask->mSourceHandler &&
(DragTask->mSourceHandler == DragTask->GetReceiveHandler())
) {
rval = dataDrag_Move;
} else {
rval = dataDrag_Copy;
}
err = GetDragModifiers(DragTask->mDragRef, &modifiers, &downModifiers, &upModifiers);
ThrowIfOSErr_(err);
if ((upModifiers & optionKey) || (downModifiers & optionKey) || (modifiers & optionKey))
rval = dataDrag_Copy;
// dataDrag_OSpec & Link could be determined through overriding and examing
// modifiers.
return rval;
}
// ===========================================================================
// New features -- data dragging:
void LDataDragEventHandler::DataDragDo(void)
{
OSErr err;
StRegion dragRgn;
Point origin = {0,0};
Boolean dragDone = false;
Assert_(mReceiver == NULL);
Assert_(mPossibleReceiver == NULL);
Assert_(mSelection);
Assert_(sDragSendDataUPP);
Try_ {
// Make the drag... task & tube
{
DragTask = MakeDragTask(this, true);
Assert_(DragTask->mDragTube == NULL);
DragTask->mDragTube = new LDragTube(DragTask->mDragRef, mSelection);
// Use send data callback
err = SetDragSendProc(DragTask->mDragRef, sDragSendDataUPP, (LDropArea *)this);
ThrowIfOSErr_(err);
}
// Reconstruct mouseDown event...
EventRecord event = mEvtRecord;
event.where = mEvtLastButtonWhere;
LocalToGlobal(&event.where);
event.what = mouseDown;
// Drag outline...
// Assert_(member(mHandlerView, LSelectHandlerView));
((LSelectHandlerView *)mHandlerView)->GetPresentHiliteRgn(false, dragRgn, event.where.h, event.where.v);
/*
It is merely a matter of convention but...
the "origin less" drag outlines made by inheritEventHandler
need to be converted to the global origin regions
used by the OS Drag Manager.
*/
LocalToGlobal(&origin);
origin.h += event.where.h;
origin.v += event.where.v;
URegions::Translate(dragRgn, origin);
Try_ {
// Do the drag tracking and maybe the actual transfer...
err = TrackDrag(DragTask->mDragRef, &event, dragRgn);
LView::OutOfFocus(NULL); // who knows what got focused.
FocusDropArea();
// If transfer was delayed, make sure it is now done.
if (err == noErr) {
DragTask->DoTransfer();
dragDone = true;
}
LView::OutOfFocus(NULL); // who knows what got focused.
FocusDropArea();
} Catch_(err) {
// Rejection zoom
Point startPt,
endPt,
zoomVector;
OSErr newErr;
OffsetRgn(dragRgn, -origin.h, -origin.v);
newErr = GetDragMouse(DragTask->mDragRef, &startPt, &endPt);
Assert_(newErr == noErr);
endPt = mEvtRecord.where;
zoomVector.h = endPt.h - startPt.h;
zoomVector.v = endPt.v - startPt.v;
origin.h = origin.v = 0;
LocalToGlobal(&origin);
origin.h += startPt.h;
origin.v += startPt.v;
URegions::Translate(dragRgn, origin);
newErr = ZoomRegion(dragRgn, zoomVector, ZOOMSTEPS, zoomDecelerate);
Assert_(newErr == noErr);
LView::OutOfFocus(NULL); // who knows what got focused.
FocusDropArea();
if (err != userCanceledErr)
Throw_(err);
} EndCatch_;
// Accepting zoom
// ???
// Clean up...
Reset();
mMaybeDragDragged = true; // oh yes it did!
} Catch_(inErr) {
Reset();
LView::OutOfFocus(NULL); // who knows what got focused.
FocusDropArea();
Throw_(inErr);
} EndCatch_;
}
// ---------------------------------------------------------------------------
// Receive Handlers
void LDataDragEventHandler::DataDragMoveIn(void)
{
if (DragTask->mSourceHandler != this) {
mPreDragState = GetEvtState();
SetEvtState(evs_Drag);
mDragType = dragType_Data;
}
if (mReceiver)
mReceiver->UnDrawSelfReceiver();
ReplaceSharable(mReceiver, (LSelectableItem *)NULL, this);
ReplaceSharable(mPossibleReceiver, (LSelectableItem *)NULL, this);
DragTask->NoteReceiveHandler(this);
}
void LDataDragEventHandler::DataDragMoveOut(void)
{
DragTask->NoteReceiveHandler(NULL); // will be ignored if it has been "notified"
if (mReceiver)
mReceiver->UnDrawSelfReceiver();
ReplaceSharable(mReceiver, (LSelectableItem *)NULL, this);
ReplaceSharable(mPossibleReceiver, (LSelectableItem *)NULL, this);
if (DragTask->mSourceHandler != this) {
SetEvtState(mPreDragState);
}
if (DragTask->mSourceHandler == NULL) {
delete DragTask;
DragTask = NULL;
}
}
void LDataDragEventHandler::DataDragTrackMove(void)
{
Point mouse,
temp;
OSErr err;
LSelectableItem *itemFound,
*newReceiver;
err = GetDragMouse(DragTask->mDragRef, &mouse, &temp);
ThrowIfOSErr_(err);
temp = mouse;
GlobalToLocal(&mouse);
mEvtMouse = mouse;
CheckBoundaryDrag();
mouse = temp;
GlobalToLocal(&mouse);
itemFound = OverReceiver(mouse);
ReplaceSharable(mPossibleReceiver, itemFound, this);
newReceiver = mPossibleReceiver;
// Filter out if receiver is the selection & in the sender drop area
if ( newReceiver &&
mSelection &&
DragTask->mSourceHandler &&
(DragTask->mSourceHandler->mSelection == mSelection)
) {
if (FindDragSemantic() == dataDrag_Move) {
if ( !mSelection->IndependentFrom(newReceiver) ||
mSelection->AdjacentWith(newReceiver)
) {
// Can't "move" a selection to inside or adjacent with itself
newReceiver = NULL;
}
} else {
if (mSelection->ListEquivalentItem(newReceiver)) {
// It doesn't make sense to "copy" the selection to itself.
newReceiver = NULL;
}
}
}
// Filter out if receiver can't receive the drop
if (newReceiver) {
Assert_(DragTask->mDragTube != NULL);
if (newReceiver->PickFlavorFrom(DragTask->mDragTube) == typeNull)
newReceiver = NULL;
}
if (mReceiver != newReceiver) {
if (mReceiver)
mReceiver->UnDrawSelfReceiver();
ReplaceSharable(mReceiver, newReceiver, this);
if (mReceiver)
mReceiver->DrawSelfReceiver();
}
if (mReceiver)
mReceiver->DrawSelfReceiverTick();
}
void LDataDragEventHandler::PreScroll(Point inVector)
{
inheritEventHandler::PreScroll(inVector);
if (mReceiver)
mReceiver->UnDrawSelfReceiver();
if (mIsHilited) {
sPreScrollWasHilited = true;
// DragPreScroll(mDragRef, -inVector.h, -inVector.v);
HideDragHilite(DragTask->mDragRef); // Above would be better but exact scroll amounts are needed.
mIsHilited = false;
} else {
sPreScrollWasHilited = false;
}
}
void LDataDragEventHandler::PostScroll(Point inVector)
{
inheritEventHandler::PostScroll(inVector);
if (sPreScrollWasHilited) {
// DragPostScroll(mDragRef);
HiliteDropArea(DragTask->mDragRef); // Above would be better but exact scroll amounts are needed.
mIsHilited = true;
}
if (mReceiver)
mReceiver->DrawSelfReceiver();
}
Boolean LDataDragEventHandler::PtInBoundaryArea(Point inWhere)
{
Boolean rval;
if (mDragType == dragType_Data)
rval = !PtInRect(inWhere, &mBDArea) && PtInRect(inWhere, &mBDAreaOutside);
else
rval = inheritEventHandler::PtInBoundaryArea(inWhere);
return rval;
}
// ===========================================================================
// Implementation:
void LDataDragEventHandler::CheckDragRef(DragReference inDragRef)
{
if (DragTask) {
if (DragTask->mDragRef != inDragRef)
Throw_(paramErr);
} else {
DragTask = MakeDragTask(this);
DragTask->mDragRef = inDragRef;
DragTask->CheckTube();
}
}
Boolean LDataDragEventHandler::PointInDropArea(Point inGlobalPt)
{
Point localPt = inGlobalPt;
mHandlerView->GlobalToPortPoint(localPt);
mHandlerView->PortToLocalPoint(localPt);
return PtInRect(localPt, &mMouseBounds);
}
void LDataDragEventHandler::SetMouseBounds(const Rect &inBounds)
{
inheritEventHandler::SetMouseBounds(inBounds);
}
DragTypeT LDataDragEventHandler::GetDragType(void)
{
DragTypeT rval = LEventHandler::GetDragType();
if (mEvtThing) {
if ((mEvtThing->ItemType() == kSelection) && mSelectionCanMove && GetStartsDataDrags())
rval = dragType_Data;
}
return rval;
}
Boolean LDataDragEventHandler::DoCondition(EventConditionT inCondition)
{
Boolean rval = false;
switch (inCondition) {
case eva_DStart:
{
mDragType = GetDragType();
if (mDragType == dragType_Data) {
DataDragDo();
} else {
rval = inheritEventHandler::DoCondition(inCondition);
}
break;
}
default:
rval = inheritEventHandler::DoCondition(inCondition);
break;
}
return rval;
}
void LDataDragEventHandler::NoteOverNewThingSelf(LManipulator *inThing)
{
if (GetStartsDataDrags() && inThing && (inThing->ItemType() == kSelection))
UCursor::Tick(cu_Hand);
else
inheritEventHandler::NoteOverNewThingSelf(inThing);
}
LSelectableItem * LDataDragEventHandler::OverReceiverSelf(Point inWhere)
{
LSelectableItem *rval = inheritEventHandler::OverReceiverSelf(inWhere);
if (rval)
return rval;
if (mReceiver)
if (mReceiver->PointInRepresentation(inWhere))
return mReceiver;
if (mPossibleReceiver)
if (mPossibleReceiver->PointInRepresentation(inWhere))
return mPossibleReceiver;
return NULL;
}
// ===========================================================================
// Implementation -- DropArea:
void LDataDragEventHandler::EnterDropArea(
DragReference inDragRef,
Boolean inDragHasLeftSender)
{
CheckDragRef(inDragRef);
Try_ {
LDropArea::EnterDropArea(inDragRef, inDragHasLeftSender);
mBDHasEntered = false; // Ugly fix -- should be somewhere else.
DataDragMoveIn();
} Catch_(inErr) {
ReplaceSharable(mReceiver, (LSelectableItem *)NULL, this);
ReplaceSharable(mPossibleReceiver, (LSelectableItem *)NULL, this);
Throw_(inErr);
} EndCatch_;
}
void LDataDragEventHandler::LeaveDropArea(
DragReference inDragRef)
{
CheckDragRef(inDragRef);
Try_ {
DataDragMoveOut();
LDropArea::LeaveDropArea(inDragRef);
} Catch_(inErr) {
ReplaceSharable(mReceiver, (LSelectableItem *)NULL, this);
ReplaceSharable(mPossibleReceiver, (LSelectableItem *)NULL, this);
Throw_(inErr);
} EndCatch_;
}
void LDataDragEventHandler::InsideDropArea(
DragReference inDragRef)
{
CheckDragRef(inDragRef);
Try_ {
LDropArea::InsideDropArea(inDragRef);
DataDragTrackMove();
} Catch_(inErr) {
ReplaceSharable(mReceiver, (LSelectableItem *)NULL, this);
ReplaceSharable(mPossibleReceiver, (LSelectableItem *)NULL, this);
Throw_(inErr);
} EndCatch_;
}
void LDataDragEventHandler::DoDragReceive(DragReference inDragRef)
{
CheckDragRef(inDragRef);
DragTask->NoteReceiveHandler(this);
DragTask->SetReceiver(mReceiver);
DragTask->NoteTransfer();
}
void LDataDragEventHandler::DoDragSendData(
FlavorType inFlavor,
ItemReference inItemRef,
DragReference inDragRef)
{
CheckDragRef(inDragRef);
DragTask->NoteTransfer();
Assert_(DragTask->mDragTube);
DragTask->mDragTube->SendFlavorData(inItemRef, inFlavor);
}
Boolean LDataDragEventHandler::DragIsAcceptable(
DragReference inDragRef)
{
if (!GetReceivesDataDrags())
return false;
return true; // Assume receivability -- mReceiver will make
// the final decision.
}
void LDataDragEventHandler::FocusDropArea(void)
{
Assert_(mHandlerView);
mHandlerView->FocusDraw();
}
void LDataDragEventHandler::HiliteDropArea(
DragReference inDragRef)
{
Rect dropRect;
Assert_(mHandlerView);
mHandlerView->CalcLocalFrameRect(dropRect);
RgnHandle dropRgn = ::NewRgn();
::RectRgn(dropRgn, &dropRect);
::ShowDragHilite(inDragRef, dropRgn, true);
::DisposeRgn(dropRgn);
}