From a4294e4a94189dffb1fdf99c9a60d87d77272926 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 13 Jul 2024 10:52:24 -0700 Subject: Restructure project. --- src/input.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/input.c (limited to 'src/input.c') diff --git a/src/input.c b/src/input.c new file mode 100644 index 0000000..c4b1be7 --- /dev/null +++ b/src/input.c @@ -0,0 +1,178 @@ +#include + +#include "event.h" +#include "uiLibrary.h" +#include "widget/widget.h" + +#include + +#define Max(a, b) ((a) > (b) ? (a) : (b)) + +/// Return true if the rectangle contains the point. +static bool RectContains(uiRect rect, uiPoint point) { + return (rect.x <= point.x) && (point.x <= (rect.x + rect.width)) && + (rect.y <= point.y) && (point.y <= (rect.y + rect.height)); +} + +/// Get the bottom-most widget under the given mouse position. +static uiWidget* GetWidgetUnderMouse(uiWidget* parent, uiPoint mouse) { + assert(parent); + + // First check the children so that the selection is from "most specific" to + // "less specific" from the user's perspective. + list_foreach(parent->children, child, { + uiWidget* target = GetWidgetUnderMouse(child, mouse); + if (target != 0) { + return target; + } + }); + + if (RectContains(parent->rect, mouse)) { + return parent; + } + + return 0; +} + +/// Get the table row at the given pixel position. +static void GetTableRowColAtXy( + const uiTable* table, uiPoint p, int* out_row, int* out_col) { + assert(table); + assert(out_row); + assert(out_col); + + const uiWidget* widget = (uiWidget*)table; + + int col = -1; + int row = -1; + + if (RectContains(widget->rect, p)) { + int x = p.x - widget->rect.x; + for (col = 0; (col < table->cols) && (x > table->widths[col]); ++col) { + x -= table->widths[col]; + } + // 0 is the header and we want to map the first row to 0, so -1. + row = table->offset + + ((p.y - widget->rect.y) / g_ui.font->header.glyph_height) - 1; + // Out-of-bounds check. + if ((col >= table->cols) || (row >= table->rows)) { + col = row = -1; + } + } + + *out_col = col; + *out_row = row; +} + +/// Process a table click event. +static void ClickTable(uiTable* table, const uiMouseClickEvent* event) { + assert(table); + assert(event); + + int row, col; + GetTableRowColAtXy(table, event->mouse_position, &row, &col); + + if ((row != -1) && (col != -1)) { + PushWidgetEvent(&(uiWidgetEvent){ + .type = uiWidgetEventClick, + .widget = uiMakeTablePtr(table), + .table_click = (uiTableClickEvent){.row = row, .col = col} + }); + } +} + +/// Process a table scroll event. +static void ScrollTable(uiTable* table, const uiMouseScrollEvent* event) { + assert(table); + assert(event); + table->offset = Max(0, table->offset - event->scroll_offset); +} + +/// Process a scroll event. +static bool ProcessScrollEvent( + uiWidget* widget, const uiMouseScrollEvent* event) { + assert(widget); + assert(event); + + bool processed = false; + + switch (widget->type) { + case uiTypeTable: + ScrollTable((uiTable*)widget, event); + processed = true; + break; + default: + break; + } + + return processed; +} + +/// Process a click event. +static bool ProcessClickEvent( + uiWidget* widget, const uiMouseClickEvent* event) { + assert(widget); + assert(event); + + bool processed = false; + + switch (widget->type) { + case uiTypeTable: + ClickTable((uiTable*)widget, event); + processed = true; + break; + default: + break; + } + + return processed; +} + +bool uiSendEvent(uiFrame* frame, const uiInputEvent* event) { + assert(frame); + assert(event); + + uiWidget* widget = (uiWidget*)frame; + + bool processed = false; + + switch (event->type) { + case uiEventMouseButton: { + const uiMouseButtonEvent* ev = &event->mouse_button; + + uiMouseButtonState* prev_state = &g_ui.mouse_button_state[ev->button]; + + if ((*prev_state == uiMouseDown) && (ev->state == uiMouseUp)) { + // Click. + uiSendEvent( + frame, + &(uiInputEvent){ + .type = uiEventMouseClick, + .mouse_click = (uiMouseClickEvent){ + .button = ev->button, .mouse_position = ev->mouse_position} + }); + } + + *prev_state = ev->state; + break; + } + case uiEventMouseClick: { + const uiMouseClickEvent* ev = &event->mouse_click; + uiWidget* target = GetWidgetUnderMouse(widget, ev->mouse_position); + if (target) { + processed = ProcessClickEvent(target, ev); + } + break; + } + case uiEventMouseScroll: { + const uiMouseScrollEvent* ev = &event->mouse_scroll; + uiWidget* target = GetWidgetUnderMouse(widget, ev->mouse_position); + if (target) { + processed = ProcessScrollEvent(target, ev); + } + break; + } + } + + return processed; +} -- cgit v1.2.3