Skip to content

Commit

Permalink
API for multi touch.
Browse files Browse the repository at this point in the history
Opt-in support for multi touch. Widgets will still only respond to
pointer/first touch events, but new API makes it possible to implement
multi touch widgets (such as action buttons, pan/zoom containers etc).
  • Loading branch information
fruxo committed Nov 26, 2016
1 parent 898cc72 commit ee05368
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 7 deletions.
10 changes: 7 additions & 3 deletions integration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ Turbo Badger will handle input capture, focus, etc. automatically.

List of input triggers (root is your root TBWidget):

root->InvokePointer[Down/Up/Move] - Mouse or touch input.
root->InvokeWheel - Mouse wheel input
root->InvokeKey - Keyboard input
root->InvokePointer[Down/Up/Move/Cancel] - Mouse or touch input
root->InvokeTouch[Down/Up/Move/Cancel] - Touch input (touch indices > 0).
root->InvokeWheel - Mouse wheel input
root->InvokeKey - Keyboard input

Additionally, there's common event types that can be invoked by root->InvokeEvent
like f.ex: EVENT_TYPE_SHORTCUT, EVENT_TYPE_CONTEXT_MENU, EVENT_TYPE_FILE_DROP...

Animations, Layout and Painting
-------------------------------
Expand Down
4 changes: 4 additions & 0 deletions src/tb/tb_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ class DebugSettingsWindow : public TBWindow, public TBWidgetListener
case EVENT_TYPE_POINTER_DOWN: return "POINTER_DOWN";
case EVENT_TYPE_POINTER_UP: return "POINTER_UP";
case EVENT_TYPE_POINTER_MOVE: return "POINTER_MOVE";
case EVENT_TYPE_TOUCH_DOWN: return "TOUCH_DOWN";
case EVENT_TYPE_TOUCH_UP: return "TOUCH_UP";
case EVENT_TYPE_TOUCH_MOVE: return "TOUCH_MOVE";
case EVENT_TYPE_TOUCH_CANCEL: return "TOUCH_CANCEL";
case EVENT_TYPE_WHEEL: return "WHEEL";
case EVENT_TYPE_CHANGED: return "CHANGED";
case EVENT_TYPE_KEY_DOWN: return "KEY_DOWN";
Expand Down
125 changes: 124 additions & 1 deletion src/tb/tb_widgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@ bool TBWidget::update_widget_states = true;
bool TBWidget::update_skin_states = true;
bool TBWidget::show_focus_state = false;

static TBHashTableAutoDeleteOf<TBWidget::TOUCH_INFO> s_touch_info;

TBWidget::TOUCH_INFO *TBWidget::GetTouchInfo(uint32 id)
{
return s_touch_info.Get(id);
}

static TBWidget::TOUCH_INFO *NewTouchInfo(uint32 id)
{
assert(!s_touch_info.Get(id));
TBWidget::TOUCH_INFO *ti = new TBWidget::TOUCH_INFO;
memset(ti, 0, sizeof(TBWidget::TOUCH_INFO));
s_touch_info.Add(id, ti);
return ti;
}

static void DeleteTouchInfo(uint32 id)
{
s_touch_info.Delete(id);
}

// == TBLongClickTimer ==================================================================

/** One shot timer for long click event */
Expand Down Expand Up @@ -84,13 +105,24 @@ TBWidget::~TBWidget()
assert(!m_parent); ///< A widget must be removed from parent before deleted
m_packed.is_dying = true;

// Unreference from pointer capture
if (this == hovered_widget)
hovered_widget = nullptr;
if (this == captured_widget)
captured_widget = nullptr;
if (this == focused_widget)
focused_widget = nullptr;

// Unreference from touch info
TBHashTableIteratorOf<TOUCH_INFO> it(&s_touch_info);
while (TOUCH_INFO *ti = it.GetNextContent())
{
if (this == ti->hovered_widget)
ti->hovered_widget = nullptr;
if (this == ti->captured_widget)
ti->captured_widget = nullptr;
}

TBWidgetListener::InvokeWidgetDelete(this);
DeleteAllChildren();

Expand Down Expand Up @@ -1374,8 +1406,8 @@ void TBWidget::MaybeInvokeLongClickOrContextMenu(bool touch)
void TBWidget::InvokePointerMove(int x, int y, MODIFIER_KEYS modifierkeys, bool touch)
{
SetHoveredWidget(GetWidgetAt(x, y, true), touch);
TBWidget *target = captured_widget ? captured_widget : hovered_widget;

TBWidget *target = captured_widget ? captured_widget : hovered_widget;
if (target)
{
target->ConvertFromRoot(x, y);
Expand Down Expand Up @@ -1446,6 +1478,97 @@ void TBWidget::HandlePanningOnMove(int x, int y)
}
}

void TBWidget::InvokePointerCancel()
{
if (captured_widget)
captured_widget->ReleaseCapture();
}

bool TBWidget::InvokeTouchDown(int x, int y, uint32 id, int click_count, MODIFIER_KEYS modifierkeys)
{
if (id == 0)
return InvokePointerDown(x, y, click_count, modifierkeys, true);

TOUCH_INFO *ti = NewTouchInfo(id);
if (!ti)
return false;

if (!ti->captured_widget)
ti->captured_widget = GetWidgetAt(x, y, true);
if (ti->captured_widget && !ti->captured_widget->GetState(WIDGET_STATE_DISABLED))
ti->hovered_widget = ti->captured_widget;

if (ti->captured_widget)
{
ti->captured_widget->ConvertFromRoot(x, y);
ti->move_widget_x = ti->down_widget_x = x;
ti->move_widget_y = ti->down_widget_y = y;
TBWidgetEvent ev(EVENT_TYPE_TOUCH_DOWN, x, y, true, modifierkeys);
ev.count = click_count;
ev.ref_id = id;
ti->captured_widget->InvokeEvent(ev);
return true;
}
return false;
}

bool TBWidget::InvokeTouchUp(int x, int y, uint32 id, MODIFIER_KEYS modifierkeys)
{
if (id == 0)
return InvokePointerUp(x, y, modifierkeys, true);
TOUCH_INFO *ti = GetTouchInfo(id);
if (ti && ti->captured_widget)
{
ti->captured_widget->ConvertFromRoot(x, y);
TBWidgetEvent ev(EVENT_TYPE_TOUCH_UP, x, y, true, modifierkeys);
ev.ref_id = id;
ti->captured_widget->InvokeEvent(ev);
DeleteTouchInfo(id);
return true;
}
return false;
}

void TBWidget::InvokeTouchMove(int x, int y, uint32 id, MODIFIER_KEYS modifierkeys)
{
if (id == 0)
return InvokePointerMove(x, y, modifierkeys, true);

TOUCH_INFO *ti = GetTouchInfo(id);
if (!ti)
return;

ti->hovered_widget = GetWidgetAt(x, y, true);
if (ti->captured_widget)
{
ti->captured_widget->ConvertFromRoot(x, y);
ti->move_widget_x = x;
ti->move_widget_y = y;
TBWidgetEvent ev(EVENT_TYPE_TOUCH_MOVE, x, y, true, modifierkeys);
ev.ref_id = id;
if (ti->captured_widget->InvokeEvent(ev))
return;
}
}

void TBWidget::InvokeTouchCancel(uint32 id)
{
if (id == 0)
return InvokePointerCancel();

TOUCH_INFO *ti = GetTouchInfo(id);
if (ti)
{
if (ti->captured_widget)
{
TBWidgetEvent ev(EVENT_TYPE_TOUCH_CANCEL, 0, 0, true);
ev.ref_id = id;
ti->captured_widget->InvokeEvent(ev);
}
DeleteTouchInfo(id);
}
}

bool TBWidget::InvokeWheel(int x, int y, int delta_x, int delta_y, MODIFIER_KEYS modifierkeys)
{
SetHoveredWidget(GetWidgetAt(x, y, true), true);
Expand Down
35 changes: 32 additions & 3 deletions src/tb/tb_widgets.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ enum EVENT_TYPE {
EVENT_TYPE_POINTER_DOWN,
EVENT_TYPE_POINTER_UP,
EVENT_TYPE_POINTER_MOVE,
EVENT_TYPE_TOUCH_DOWN,
EVENT_TYPE_TOUCH_UP,
EVENT_TYPE_TOUCH_MOVE,
EVENT_TYPE_TOUCH_CANCEL,
EVENT_TYPE_WHEEL,

/** Invoked after changing text in a TBTextField, changing selected item
Expand Down Expand Up @@ -139,6 +143,10 @@ class TBWidgetEvent : public TBTypedObject
bool IsPointerEvent() const { return type == EVENT_TYPE_POINTER_DOWN ||
type == EVENT_TYPE_POINTER_UP ||
type == EVENT_TYPE_POINTER_MOVE; }
bool IsTouchEvent() const { return type == EVENT_TYPE_TOUCH_DOWN ||
type == EVENT_TYPE_TOUCH_UP ||
type == EVENT_TYPE_TOUCH_MOVE ||
type == EVENT_TYPE_TOUCH_CANCEL; }
bool IsKeyEvent() const { return type == EVENT_TYPE_KEY_DOWN ||
type == EVENT_TYPE_KEY_UP; }
};
Expand Down Expand Up @@ -929,6 +937,17 @@ class TBWidget : public TBTypedObject, public TBLinkOf<TBWidget>
bool InvokePointerDown(int x, int y, int click_count, MODIFIER_KEYS modifierkeys, bool touch);
bool InvokePointerUp(int x, int y, MODIFIER_KEYS modifierkeys, bool touch);
void InvokePointerMove(int x, int y, MODIFIER_KEYS modifierkeys, bool touch);
void InvokePointerCancel();

/** Invoke touch events with ref_id set as the given id.
Note: For id 0, it will invoke EVENT_TYPE_POINTER_DOWN (with touch flag set to true), and EVENT_TYPE_TOUCH_DOWN
for other id > 0. This results in normal interaction for first finger, and optional handling of other
simultaneous interaction. GetTouchInfo(id) can be used to get additional interaction info. */
bool InvokeTouchDown(int x, int y, uint32 id, int click_count, MODIFIER_KEYS modifierkeys);
bool InvokeTouchUp(int x, int y, uint32 id, MODIFIER_KEYS modifierkeys);
void InvokeTouchMove(int x, int y, uint32 id, MODIFIER_KEYS modifierkeys);
void InvokeTouchCancel(uint32 id);

bool InvokeWheel(int x, int y, int delta_x, int delta_y, MODIFIER_KEYS modifierkeys);

/** Invoke the EVENT_TYPE_KEY_DOWN and EVENT_TYPE_KEY_UP events on the currently focused widget.
Expand Down Expand Up @@ -1019,9 +1038,9 @@ class TBWidget : public TBTypedObject, public TBLinkOf<TBWidget>
#endif // TB_RUNTIME_DEBUG_INFO

// TBWidget related globals
static TBWidget *hovered_widget; ///< The currently hovered widget, or nullptr.
static TBWidget *captured_widget; ///< The currently captured widget, or nullptr.
static TBWidget *focused_widget; ///< The currently focused widget, or nullptr.
static TBWidget *hovered_widget; ///< The currently hovered widget, or nullptr.
static TBWidget *captured_widget; ///< The currently captured widget, or nullptr.
static TBWidget *focused_widget; ///< The currently focused widget, or nullptr.
static int pointer_down_widget_x; ///< Pointer x position on down event, relative to the captured widget.
static int pointer_down_widget_y; ///< Pointer y position on down event, relative to the captured widget.
static int pointer_move_widget_x; ///< Pointer x position on last pointer event, relative to the captured widget (if any) or hovered widget.
Expand All @@ -1030,6 +1049,16 @@ class TBWidget : public TBTypedObject, public TBLinkOf<TBWidget>
static bool update_widget_states; ///< true if something has called InvalidateStates() and it still hasn't been updated.
static bool update_skin_states; ///< true if something has called InvalidateStates() and skin still hasn't been updated.
static bool show_focus_state; ///< true if the focused state should be painted automatically.
struct TOUCH_INFO {
TBWidget *hovered_widget; ///< The currently hovered widget, or nullptr.
TBWidget *captured_widget; ///< The currently captured widget, or nullptr.
int down_widget_x; ///< Touch x position on down event, relative to the captured widget.
int down_widget_y; ///< Touch y position on down event, relative to the captured widget.
int move_widget_x; ///< Touch x position on last touch event, relative to the captured widget.
int move_widget_y; ///< Touch y position on last touch event, relative to the captured widget.
};
/** Return TOUCH_INFO for the given id, or nullptr if no touch is active for that id. */
static TOUCH_INFO *GetTouchInfo(uint32 id);
private:
/** Return this widget or the nearest parent that is scrollable
in the given axis, or nullptr if there is none. */
Expand Down

0 comments on commit ee05368

Please sign in to comment.