hostile-takeover/game/stylushandler.cpp
2014-07-06 17:47:28 -07:00

313 lines
7.9 KiB
C++

#include "game/ht.h"
namespace wi {
SimUIForm::StylusHandler::StylusHandler(SimUIForm *psui)
{
m_psui = psui;
m_fDragging = false;
}
bool SimUIForm::StylusHandler::OnPenEvent(Event *pevt, bool fScrollOnly)
{
// Can't scroll the playfield from this PenHandler
if (fScrollOnly) {
return true;
}
// Dragging mode captures all pen events except pen-hold for the duration of
// the drag to perform drag-scrolling, etc (shift-drag or graffiti-scroll)
if (m_fDragging && pevt->eType != penHoldEvent) {
OnPenDrag(pevt);
// Force draw to keep dragging as interactive as possible
// Raises redraw priority above next update
gevm.SetRedrawFlags(kfRedrawDirty | kfRedrawBeforeTimer);
return true;
}
switch (pevt->eType) {
case penHoldEvent:
// Popup Gob menu if pen held on one of them
OnPenHold(pevt);
break;
case penDownEvent:
// Handle the beginning of a drag selection operation or a tap on a
// unit/structure
OnPenDown(pevt);
break;
case penUpEvent:
// Handle the canceling of any in progress modes
OnPenUp(pevt);
break;
}
return true;
}
void SimUIForm::StylusHandler::OnPenDown(Event *pevt)
{
// Enter dragging mode; this'll cause OnPenDrag to be called until
// that mode exits.
m_fDragging = true;
// Calc a hit target in world coords
WCoord wxPen = WcFromPc(pevt->x);
WCoord wyPen = WcFromPc(pevt->y);
WCoord wxTarget, wyTarget;
gsim.GetViewPos(&wxTarget, &wyTarget);
wxTarget += wxPen;
wyTarget += wyPen;
// s_wptSelect1 & 2 are used to determine the transition from a
// tentative selection to a real one and must contain the beginning
// and current pen positions, respectively.
s_wptSelect1.wx = wxTarget;
s_wptSelect1.wy = wyTarget;
s_wptSelect2 = s_wptSelect1;
if (gfLassoSelection) {
s_awptSelection[0] = s_wptSelect1;
s_cwptSelection = 1;
} else {
gwrcSelection.Set(s_wptSelect1, s_wptSelect2);
gsim.SetSelection(&gwrcSelection);
}
// Only Select. Leave moving and attacking to the pen up handler.
m_psui->MoveOrAttackOrSelect(pevt->x, pevt->y, kfMasSelect);
}
void SimUIForm::StylusHandler::OnPenUp(Event *pevt)
{
CancelModes();
}
// TUNE:
#define kwcMinSelection WcFromTile16ths(8)
// The WI playfield finger UI:
//
// 1. One finger for selecting and rubber banding around troops
// 2. Two fingers for scrolling the map.
// 3. Two finger flick for momentum scrolls.
//
// Notes:
// - During a select operation, the second finger may come down. This cancels
// the selection and enters scroll mode. Units that were selected as part of
// entering the mode are unselected when entering scroll mode. Units that
// were selected before select mode was entered are left selected.
//
// - Once entered, scroll mode remains even if one of the fingers goes up
//
// - At the beginning of scroll mode, the first down is the reference
// point.
//
// - If in scroll mode, and one of the fingers goes up while the other remains
// down, the aggregate is still down, and the coordinate is based on the
// reference point so there is no map jumping.
void SimUIForm::StylusHandler::OnPenDrag(Event *pevt)
{
WCoord wxPen = WcFromPc(pevt->x);
WCoord wyPen = WcFromPc(pevt->y);
WCoord wxView, wyView;
gsim.GetViewPos(&wxView, &wyView);
switch (pevt->eType) {
case penUpEvent:
// If this is a forced up event, cancel our modes
if (pevt->dw == 1) {
CancelModes();
break;
}
// Real pen event. Leaving drag mode.
m_fDragging = false;
// If we're drag selecting complete the process. Otherwise handle this
// event as a tap on an enemy (attack it) or location (move to it)
if (gfDragSelecting) {
// Invalidate this area first so we get it to redraw
m_psui->InvalidateDragSelection();
// Turn off selection
gfDragSelecting = false;
if (gfLassoSelection && s_cwptSelection > 1) {
bool fGobsSelected = false;
Gob *pgobT;
for (pgobT = ggobm.GetFirstGob(); pgobT != NULL;
pgobT = ggobm.GetNextGob(pgobT)) {
dword ff = pgobT->GetFlags();
// If were in select mode then only Gobs inside the
// selection rectangle get to be selected.
bool fSelect = false;
if ((gfGodMode || pgobT->GetOwner() == gpplrLocal) &&
((ff & (kfGobActive | kfGobUnit)) ==
(kfGobActive | kfGobUnit))) {
WPoint wptGobCenter;
pgobT->GetCenter(&wptGobCenter);
if (PtInPolygon(s_awptSelection, s_cwptSelection,
wptGobCenter.wx, wptGobCenter.wy)) {
fSelect = true;
fGobsSelected = true;
}
}
if (ff & kfGobUnit) {
((UnitGob *)pgobT)->Select(fSelect);
}
}
s_cwptSelection = 0;
}
} else {
m_psui->MoveOrAttackOrSelect(pevt->x, pevt->y, kfMasMove | kfMasAttack | kfMasShowMenu);
}
break;
case penMoveEvent:
{
if (gfDragSelecting) {
// Inval old pos of selection rect
m_psui->InvalidateDragSelection();
}
// Update() code uses s_wptSelect2 to determine if edge scrolling
// is necessary
s_wptSelect2.wx = wxView + WcFromPc(pevt->x);
s_wptSelect2.wy = wyView + WcFromPc(pevt->y);
gwrcSelection.Set(s_wptSelect1, s_wptSelect2);
if (!gfDragSelecting) {
if (gwrcSelection.Width() >= kwcMinSelection ||
gwrcSelection.Height() >= kwcMinSelection) {
gfDragSelecting = true;
}
}
if (gfDragSelecting) {
// Inval new size of selection rect
m_psui->InvalidateDragSelection();
if (gfLassoSelection) {
AddPointToLassoSelection(s_wptSelect2);
}
gsim.SetSelection(&gwrcSelection);
}
}
break;
}
}
void SimUIForm::StylusHandler::OnPenHold(Event *pevt)
{
WCoord wxTarget, wyTarget;
gsim.GetViewPos(&wxTarget, &wyTarget);
wxTarget += WcFromPc(pevt->x);
wyTarget += WcFromPc(pevt->y);
Gob *pgobHit = NULL;
Enum enm;
if (!gsim.HitTest(&enm, wxTarget, wyTarget, kfGobActive | kfGobUnit,
&pgobHit)) {
return;
}
// Don't popup menu if the player doesn't own the Gob (unless in God mode)
// God mode is limited for multiplayer games.
if ((!gfGodMode || ggame.IsMultiplayer()) &&
pgobHit->GetSide() != gpplrLocal->GetSide()) {
return;
}
m_fDragging = false;
pgobHit->PopupMenu();
}
void SimUIForm::StylusHandler::CancelModes()
{
m_fDragging = false;
if (gfDragSelecting) {
// Invalidate this area first so we get it to redraw
m_psui->InvalidateDragSelection();
gfDragSelecting = false;
}
}
void SimUIForm::StylusHandler::CheckScroll()
{
// If the player is rectangle selecting and at the screen edge scroll the
// screen.
if (!gfDragSelecting) {
return;
}
Size sizPlayfield;
ggame.GetPlayfieldSize(&sizPlayfield);
WCoord wcxPlayfield = WcFromUpc(sizPlayfield.cx);
WCoord wcyPlayfield = WcFromUpc(sizPlayfield.cy);
WCoord wxView, wyView;
gsim.GetViewPos(&wxView, &wyView);
WCoord wxViewNew = wxView;
WCoord wyViewNew = wyView;
if (s_wptSelect2.wx < wxView + kwcScrollBorderSize) {
wxViewNew -= kwcScrollStepSize;
} else if (s_wptSelect2.wx > wxView + wcxPlayfield - kwcScrollBorderSize) {
wxViewNew += kwcScrollStepSize;
}
if (s_wptSelect2.wy < wyView + kwcScrollBorderSize) {
wyViewNew -= kwcScrollStepSize;
} else if (s_wptSelect2.wy > wyView + wcyPlayfield - kwcScrollBorderSize) {
wyViewNew += kwcScrollStepSize;
}
if (wxViewNew != wxView || wyViewNew != wyView) {
gsim.SetViewPos(wxViewNew, wyViewNew);
WCoord wxViewActual, wyViewActual;
gsim.GetViewPos(&wxViewActual, &wyViewActual);
s_wptSelect2.wx += wxViewActual - wxView;
s_wptSelect2.wy += wyViewActual - wyView;
gwrcSelection.Set(s_wptSelect1, s_wptSelect2);
if (gfLassoSelection)
AddPointToLassoSelection(s_wptSelect2);
gsim.SetSelection(&gwrcSelection);
}
}
} // namespace wi