netscape-revival
lib/mac/VText/V_PowerPlant_Mods/LEventMachine.cp
// ===========================================================================
// LEventMachine.cp ©1994-5 Metrowerks Inc. All rights reserved.
// ===========================================================================
#ifdef PowerPlant_PCH
#include PowerPlant_PCH
#endif
#include "LEventMachine.h"
#include <LHandlerView.h>
#include <LManipulator.h>
#include <UCursor.h>
#include <UEventUtils.h>
#include <LCommander.h>
#include <LAction.h>
#include <LStream.h>
#ifndef __WINDOWS__
#include <Windows.h>
#endif
#pragma warn_unusedarg off
// ===========================================================================
/*
NOTICE !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
If you try to understand this code make certain you read the separate
documentation. The documentation includes a state diagram for the state
machine implemented by this event handler. Knowledge of that state
diagram makes this code much more understandable.
*/
// ===========================================================================
LEventMachine *LEventMachine::sActiveDragger = NULL;
// ===========================================================================
// Maintenance
LEventMachine::LEventMachine()
{
mCommander = NULL;
mHandlerView = NULL;
mEvtState = mLastEvtState = evs_Cold;
mMaybeDragDragged = false;
mMultiClickDistance = 4;
mAllowSingleGestureDrag = false;
mMouseBounds.top = mMouseBounds.left = mMouseBounds.right =
mMouseBounds.bottom = 0;
mBDArea = mBDAreaOutside = mMouseBounds;
mBDArea.top += ScrollBar_Size / 2;
mBDArea.left += ScrollBar_Size / 2;
mBDArea.right -= ScrollBar_Size / 2;
mBDArea.bottom -= ScrollBar_Size / 2;
mBDDelay = 2;
mBDInitialDelay = 10;
SetStateTable();
SetConditionTable();
SetActionTable();
SetNoteTable();
SetFallbackTable();
}
LEventMachine::~LEventMachine()
{
}
#ifndef PP_No_ObjectStreaming
void LEventMachine::WriteObject(LStream &inStream) const
{
inStream << mMouseBounds;
inStream << mAllowSingleGestureDrag;
inStream << mMultiClickDistance;
inStream << mBDDelay;
inStream << mBDInitialDelay;
inStream << mBDArea;
inStream << mBDAreaOutside;
inStream.WriteVP(GetCommander());
}
void LEventMachine::ReadObject(LStream &inStream)
{
inStream >> mMouseBounds;
inStream >> mAllowSingleGestureDrag;
inStream >> mMultiClickDistance;
inStream >> mBDDelay;
inStream >> mBDInitialDelay;
inStream >> mBDArea;
inStream >> mBDAreaOutside;
SetCommander(ReadVoidPtr<LCommander *>()(inStream));
}
#endif
// ===========================================================================
// Options / setup
void LEventMachine::SetMouseBounds(const Rect &inBounds)
{
Int32 delta;
delta = mBDAreaOutside.top - mMouseBounds.top;
mBDAreaOutside.top = inBounds.top + delta;
delta = mBDArea.top - mMouseBounds.top;
mBDArea.top = inBounds.top + delta;
delta = mBDAreaOutside.left - mMouseBounds.left;
mBDAreaOutside.left = inBounds.left + delta;
delta = mBDArea.left - mMouseBounds.left;
mBDArea.left = inBounds.left + delta;
delta = mBDAreaOutside.right - mMouseBounds.right;
mBDAreaOutside.right = inBounds.right + delta;
delta = mBDArea.right - mMouseBounds.right;
mBDArea.right = inBounds.right + delta;
delta = mBDAreaOutside.bottom - mMouseBounds.bottom;
mBDAreaOutside.bottom = inBounds.bottom + delta;
delta = mBDArea.bottom - mMouseBounds.bottom;
mBDArea.bottom = inBounds.bottom + delta;
mMouseBounds = inBounds;
}
void LEventMachine::GetMouseBounds(Rect *outBounds)
{
*outBounds = mMouseBounds;
}
void LEventMachine::SetBoundaryRects(const Rect &inInside, const Rect &inOutside)
{
mBDAreaOutside = inOutside;
mBDArea = inInside;
}
LHandlerView * LEventMachine::GetHandlerView(void)
{
return mHandlerView;
}
void LEventMachine::SetHandlerView(LHandlerView *inHandlerView)
{
mHandlerView = inHandlerView;
}
LCommander * LEventMachine::GetCommander(void) const
{
return mCommander;
}
void LEventMachine::SetCommander(LCommander *inCommander)
{
mCommander = inCommander;
}
// ===========================================================================
// Table accessors:
EventConditionT * LEventMachine::GetConditionTable(void)
{
return mConditions;
}
void LEventMachine::SetConditionTable(EventConditionT *inTable)
{
if (!inTable)
inTable = sConditions;
mConditions = inTable;
}
EventStateT * LEventMachine::GetStateTable(void)
{
return mNextState;
}
void LEventMachine::SetStateTable(EventStateT *inTable)
{
if (!inTable)
inTable = sNextState;
mNextState = inTable;
}
EventConditionT * LEventMachine::GetActionTable(void)
{
return mActions;
}
void LEventMachine::SetActionTable(EventConditionT *inTable)
{
if (!inTable)
inTable = sActions;
mActions = inTable;
}
EventConditionT * LEventMachine::GetNoteTable(void)
{
return mNotes;
}
void LEventMachine::SetNoteTable(EventConditionT *inTable)
{
if (!inTable)
inTable = sNotes;
mNotes = inTable;
}
EventConditionT * LEventMachine::GetFallbackTable(void)
{
return mFallbacks;
}
void LEventMachine::SetFallbackTable(EventConditionT *inTable)
{
if (!inTable)
inTable = sFallbacks;
mFallbacks = inTable;
}
EventConditionT LEventMachine::FindCondition(EventStateT inState, EventVerbT inVerb)
{
ThrowIfNULL_(mConditions);
return *(mConditions + (inState * evv_EventMachine_Count) + inVerb);
}
EventStateT LEventMachine::FindNextState(EventStateT inState, EventVerbT inVerb)
{
ThrowIfNULL_(mNextState);
return *(mNextState + (inState * evv_EventMachine_Count) + inVerb);
}
EventConditionT LEventMachine::FindAction(EventStateT inState, EventVerbT inVerb)
{
ThrowIfNULL_(mActions);
return *(mActions + (inState * evv_EventMachine_Count) + inVerb);
}
EventConditionT LEventMachine::FindNote(EventStateT inState, EventVerbT inVerb)
{
ThrowIfNULL_(mNotes);
return *(mNotes + (inState * evv_EventMachine_Count) + inVerb);
}
EventConditionT LEventMachine::FindFallback(EventStateT inState, EventVerbT inVerb)
{
ThrowIfNULL_(mNotes);
return *(mFallbacks + (inState * evv_EventMachine_Count) + inVerb);
}
Boolean LEventMachine::GetAllowSingleGestureDrag(void)
{
return mAllowSingleGestureDrag;
}
void LEventMachine::SetAllowSingleGestureDrag(Boolean inValue)
{
mAllowSingleGestureDrag = inValue;
}
// ===========================================================================
// Required incoming hooks
void LEventMachine::Activate(void)
{
mActive = true;
}
void LEventMachine::Deactivate(void)
{
mActive = false;
}
// ===========================================================================
// Query
EventRecord & LEventMachine::GetEvtRecord(void)
{
return mEvtRecord;
}
Point & LEventMachine::GetEvtMouse(void)
{
return mEvtMouse;
}
Int16 LEventMachine::GetClickCount(void)
{
return mEvtClickCount;
}
Boolean LEventMachine::IsTardy(void) const
{
return (mEvtRecord.when - mEvtLastButtonTime) > GetDblTime();
}
#ifndef abs
#define abs(a) ((a) > 0 ? (a) : -(a))
#endif
Boolean LEventMachine::PointIsClose(
Point oldPt,
Point newPt)
{
Int16 dx = newPt.h - oldPt.h,
dy = newPt.v - oldPt.v,
d = mMultiClickDistance >> 1;
dx = abs(dx);
dy = abs(dy);
return ( (dx <= d) && (dy <= d) );
}
Boolean LEventMachine::PointInHandlerRgn(Point inWhere)
/*
Returns true if the mouse is over the mMouseBounds rectangle AND
there is not a different (floating) window under the mouse location.
*/
{
if (PtInRect(inWhere, &mMouseBounds)) {
WindowPtr handlerWindow,
windowOver;
handlerWindow = (WindowPtr)mHandlerView->GetMacPort();
LocalToGlobal(&inWhere);
FindWindow(inWhere, &windowOver);
if (windowOver == handlerWindow)
return true;
}
return false;
}
Boolean LEventMachine::LastMaybeDragDragged(void)
{
return mMaybeDragDragged;
}
// ===========================================================================
// Overrides
void LEventMachine::OutOfBounds(Point inWhere)
/*
Returns whether "NoteOutOfBounds" handled event.
Seldom will client code need to override this.
*/
{
Assert_(mInBounds);
mInBounds = false;
UCursor::Reset();
}
void LEventMachine::InBounds(Point inWhere)
/*
Returns whether "NoteInBounds" handled event.
Seldom will client code need to override this.
*/
{
Assert_(!mInBounds);
mInBounds = true;
UCursor::Reset();
}
void LEventMachine::BoundaryDrag(Point inWhere)
/*
Default behavior is for autoscrolling
*/
{
Point vector = {0, 0};
if (inWhere.h <= mBDArea.left)
vector.h = inWhere.h - mBDArea.left;
else if (mBDArea.right <= inWhere.h)
vector.h = inWhere.h - mBDArea.right;
if (inWhere.v <= mBDArea.top)
vector.v = inWhere.v - mBDArea.top;
else if (mBDArea.bottom <= inWhere.v)
vector.v = inWhere.v - mBDArea.bottom;
AutoScrollVector(vector);
}
void LEventMachine::AutoScrollVector(Point inVector)
/*
Default method calls AutoScrollImage of owning view.
Note: This default method defeats the "ramping" nature of inVector.
*/
{
Point simulatedWhere;
if (inVector.h < 0)
simulatedWhere.h = mMouseBounds.left + inVector.h;
if (inVector.h == 0)
simulatedWhere.h = mMouseBounds.left;
if (inVector.h > 0)
simulatedWhere.h = mMouseBounds.right + inVector.h;
if (inVector.v < 0)
simulatedWhere.v = mMouseBounds.top + inVector.v;
if (inVector.v == 0)
simulatedWhere.v = mMouseBounds.top;
if (inVector.v > 0)
simulatedWhere.v = mMouseBounds.bottom + inVector.v;
if (mHandlerView && ((inVector.h != 0) || (inVector.v != 0))) {
PreScroll(inVector);
mHandlerView->AutoScrollImage(simulatedWhere);
PostScroll(inVector);
}
}
void LEventMachine::PostAction(LAction *inAction)
/*
To which class should this really belong?
*/
{
if (mCommander) {
mCommander->PostAction(inAction);
} else {
LCommander::PostAnAction(inAction);
}
}
void LEventMachine::PreScroll(Point inVector)
{
FocusDraw();
}
void LEventMachine::PostScroll(Point inVector)
{
FocusDraw();
}
Boolean LEventMachine::CheckCursor(void)
{
return false;
}
Boolean LEventMachine::CheckThings(void)
{
return false;
}
// ===========================================================================
// Implementation
Boolean LEventMachine::IsActive(void)
{
return mActive;
}
void LEventMachine::UpdateLastEvt(EventRecord &inEvent, Point inLocalMouse)
{
// A new event for the handler
mLastEvtRecord = mEvtRecord;
mLastEvtMouse = mEvtMouse;
mLastEvtState = mEvtState;
mEvtMouse = inLocalMouse;
mEvtRecord = inEvent;
// SetEvtState(?); // Determined by subsequent action and state info
}
void LEventMachine::FocusDraw(void)
{
if (mHandlerView)
mHandlerView->FocusDraw();
}
Boolean LEventMachine::PtInBoundaryArea(Point inWhere)
{
return !PtInRect(inWhere, &mBDArea);
}
void LEventMachine::CheckBoundaryDrag(void)
{
switch (GetEvtState()) {
case evs_Drag:
// IsActive() test required to prevent views in non
// front-most windows from auto scrolling. Allowing such
// would me a Mac HI violation.
if (mHandlerView && PtInBoundaryArea(mEvtMouse) && mHandlerView->IsActive()) {
Int32 tc = TickCount();
Boolean doNotify = false;
if (!mBDHasEntered) {
mBDHasEntered = true;
mBDFirstTime = PtInRect(mEvtMouse, &mBDAreaOutside);
mLastBDTime = tc;
} else {
if (!PtInRect(mEvtMouse, &mBDAreaOutside))
mBDFirstTime = false;
}
if (mBDFirstTime) {
doNotify = (tc - mLastBDTime) > mBDInitialDelay;
} else {
doNotify = (tc - mLastBDTime) > mBDDelay;
}
if (doNotify) {
BoundaryDrag(mEvtMouse);
mBDFirstTime = false;
mLastBDTime = tc;
}
} else {
mBDHasEntered = false;
}
break;
}
}