Skip to content

Commit

Permalink
Widget: Add custom hit-testing support
Browse files Browse the repository at this point in the history
  • Loading branch information
past-due committed Mar 17, 2019
1 parent 6731c4c commit 405a594
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 1 deletion.
8 changes: 8 additions & 0 deletions lib/widget/widgbase.h
Expand Up @@ -66,6 +66,9 @@ typedef std::function<void (WIDGET *psWidget, unsigned int oldScreenWidth, unsig
/* The optional "onDelete" callback function */
typedef std::function<void (WIDGET *psWidget)> WIDGET_ONDELETE_FUNC;

/* The optional hit-testing function, used for custom hit-testing within the outer bounding rectangle */
typedef std::function<bool (WIDGET *psWidget, int x, int y)> WIDGET_HITTEST_FUNC;


/* The different base types of widget */
enum WIDGET_TYPE
Expand Down Expand Up @@ -129,6 +132,8 @@ class WIDGET
virtual void display(int, int) {}
virtual void geometryChanged() {}

virtual bool hitTest(int x, int y);

public:
virtual unsigned getState();
virtual void setState(unsigned state);
Expand Down Expand Up @@ -207,6 +212,8 @@ class WIDGET

void setOnDelete(const WIDGET_ONDELETE_FUNC& onDeleteFunc);

void setCustomHitTest(const WIDGET_HITTEST_FUNC& newCustomHitTestFunc);

UDWORD id; ///< The user set ID number for the widget. This is returned when e.g. a button is pressed.
WIDGET_TYPE type; ///< The widget type
UDWORD style; ///< The style of the widget
Expand All @@ -219,6 +226,7 @@ class WIDGET
private:
WIDGET_CALCLAYOUT_FUNC calcLayout; ///< Optional calc layout callback
WIDGET_ONDELETE_FUNC onDelete; ///< Optional callback called when the Widget is about to be deleted
WIDGET_HITTEST_FUNC customHitTest; ///< Optional hit-testing custom function
void setScreenPointer(W_SCREEN *screen); ///< Set screen pointer for us and all children.
public:
void processClickRecursive(W_CONTEXT *psContext, WIDGET_KEY key, bool wasPressed);
Expand Down
24 changes: 23 additions & 1 deletion lib/widget/widget.cpp
Expand Up @@ -111,6 +111,7 @@ W_INIT::W_INIT()
, UserData(0)
, calcLayout(nullptr)
, onDelete(nullptr)
, customHitTest(nullptr)
, initPUserDataFunc(nullptr)
{}

Expand All @@ -125,6 +126,7 @@ WIDGET::WIDGET(W_INIT const *init, WIDGET_TYPE type)
, screenPointer(nullptr)
, calcLayout(init->calcLayout)
, onDelete(init->onDelete)
, customHitTest(init->customHitTest)
, parentWidget(nullptr)
, dim(init->x, init->y, init->width, init->height)
, dirty(true)
Expand All @@ -151,6 +153,7 @@ WIDGET::WIDGET(WIDGET *parent, WIDGET_TYPE type)
, screenPointer(nullptr)
, calcLayout(nullptr)
, onDelete(nullptr)
, customHitTest(nullptr)
, parentWidget(nullptr)
, dim(0, 0, 1, 1)
, dirty(true)
Expand Down Expand Up @@ -237,6 +240,11 @@ void WIDGET::setOnDelete(const WIDGET_ONDELETE_FUNC& onDeleteFunc)
onDelete = onDeleteFunc;
}

void WIDGET::setCustomHitTest(const WIDGET_HITTEST_FUNC& newCustomHitTestFunc)
{
customHitTest = newCustomHitTestFunc;
}

void WIDGET::attach(WIDGET *widget)
{
ASSERT_OR_RETURN(, widget != nullptr && widget->parentWidget == nullptr, "Bad attach.");
Expand Down Expand Up @@ -739,6 +747,20 @@ void WIDGET::runRecursive(W_CONTEXT *psContext)
}
}

bool WIDGET::hitTest(int x, int y)
{
// default hit-testing bounding rect (based on the widget's x, y, width, height)
bool hitTestResult = dim.contains(x, y);

if(customHitTest)
{
// if the default bounding-rect hit-test succeeded, use the custom hit-testing func
hitTestResult = hitTestResult && customHitTest(this, x, y);
}

return hitTestResult;
}

void WIDGET::processClickRecursive(W_CONTEXT *psContext, WIDGET_KEY key, bool wasPressed)
{
W_CONTEXT shiftedContext;
Expand All @@ -752,7 +774,7 @@ void WIDGET::processClickRecursive(W_CONTEXT *psContext, WIDGET_KEY key, bool wa
{
WIDGET *psCurr = *i;

if (!psCurr->visible() || !psCurr->dim.contains(shiftedContext.mx, shiftedContext.my))
if (!psCurr->visible() || !psCurr->hitTest(shiftedContext.mx, shiftedContext.my))
{
continue; // Skip any hidden widgets, or widgets the click missed.
}
Expand Down
1 change: 1 addition & 0 deletions lib/widget/widget.h
Expand Up @@ -123,6 +123,7 @@ struct W_INIT
UDWORD UserData; ///< User data (if any)
WIDGET_CALCLAYOUT_FUNC calcLayout; ///< Optional calculate layout callback function
WIDGET_ONDELETE_FUNC onDelete; ///< Optional callback called when the Widget is about to be deleted
WIDGET_HITTEST_FUNC customHitTest; ///< Optional custom hit-testing function
WIDGET_INITIALIZE_PUSERDATA_FUNC initPUserDataFunc; ///< (Optional) Used to initialize the pUserData pointer per widget instance
};

Expand Down

0 comments on commit 405a594

Please sign in to comment.