Commit: 4af608e8bdcc929907c6bd60abf3bdb434bf50b5
Parent: 5329fd7e405d7030cd24466b5d2368b12414ea19
Author: Randy Palamar
Date: Wed, 6 Nov 2024 21:30:26 -0700
move mouse input to the platform layer
Diffstat:
M | debug.c | | | 22 | ++++++++-------------- |
M | debug.h | | | 6 | ++---- |
M | platform_linux_x11.c | | | 52 | +++++++++++++++++++++++++++++++++++++++++++++++++++- |
M | util.c | | | 2 | +- |
M | vtgl.c | | | 85 | +++++++++++++++++++++++++++++++++++-------------------------------------------- |
M | vtgl.h | | | 19 | +++++++++++++++++++ |
6 files changed, 119 insertions(+), 67 deletions(-)
diff --git a/debug.c b/debug.c
@@ -186,7 +186,8 @@ refresh_collation(DebugState *ds)
}
static void
-draw_debug_bar_chart(Term *t, DebugState *ds, RenderCtx *rc, v2 bar_chart_top_left, f32 bar_chart_magnitude)
+draw_debug_bar_chart(Term *t, DebugState *ds, TerminalInput *input, RenderCtx *rc,
+ v2 bar_chart_top_left, f32 bar_chart_magnitude)
{
BEGIN_TIMED_BLOCK();
@@ -199,11 +200,6 @@ draw_debug_bar_chart(Term *t, DebugState *ds, RenderCtx *rc, v2 bar_chart_top_le
f32 target_time = 1 / target_fps;
f32 secs_scale = bar_chart_magnitude * target_fps;
- /* TODO: store the mouse somewhere */
- f64 xpos, ypos;
- glfwGetCursorPos(t->gl.window, &xpos, &ypos);
- v2 mouse = {.x = xpos, .y = t->gl.window_size.h - ypos};
-
/* TODO */
v4 fg = normalize_colour((Colour){.rgba = 0x1e9e33ff});
v4 colours[] = {
@@ -238,7 +234,7 @@ draw_debug_bar_chart(Term *t, DebugState *ds, RenderCtx *rc, v2 bar_chart_top_le
Rect r = {.pos = pos, .size = {.h = bar_thick, .w = time}};
if (r.size.w > 1.0f) {
push_rect(rc, r, colours[dr->colour_index % ARRAY_COUNT(colours)]);
- if (point_in_rect(mouse, r)) {
+ if (point_in_rect(input->mouse, r)) {
hot_region = dr;
hot_region_secs = cycs * cycs_to_secs;
}
@@ -280,23 +276,21 @@ draw_debug_bar_chart(Term *t, DebugState *ds, RenderCtx *rc, v2 bar_chart_top_le
stream_push_s8(&txt, c_str_to_s8(txt_meta->file_name));
stream_push_byte(&txt, ':');
stream_push_u64(&txt, txt_meta->line_number);
- push_s8(rc, mouse, fg, g_ui_debug_font_id, stream_to_s8(&txt));
+ push_s8(rc, input->mouse, fg, g_ui_debug_font_id, stream_to_s8(&txt));
}
- /* TODO: this should be stored so that we can properly mask */
- b32 pressed = glfwGetMouseButton(t->gl.window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
- if (pressed && pressed != ds->mouse_pressed_last_frame) {
+ ButtonState *mouse_left = input->mouse_buttons + MOUSE_LEFT;
+ if (mouse_left->ended_down && mouse_left->transitions > 0) {
if (hot_region) ds->selected_metadata = hot_region->meta;
else ds->selected_metadata = 0;
refresh_collation(ds);
}
- ds->mouse_pressed_last_frame = pressed;
END_TIMED_BLOCK();
}
static void
-draw_debug_overlay(TerminalMemory *term_memory, RenderCtx *rc)
+draw_debug_overlay(TerminalMemory *term_memory, TerminalInput *input, RenderCtx *rc)
{
Term *t = term_memory->memory;
DebugState *ds = term_memory->debug_memory;
@@ -308,7 +302,7 @@ draw_debug_overlay(TerminalMemory *term_memory, RenderCtx *rc)
v2 bar_chart_top_left = v2_from_iv2(t->gl.window_size);
bar_chart_top_left.x *= 0.5;
- draw_debug_bar_chart(t, ds, rc, bar_chart_top_left, 0.25 * t->gl.window_size.w);
+ draw_debug_bar_chart(t, ds, input, rc, bar_chart_top_left, 0.25 * t->gl.window_size.w);
Arena memory = *ds->temp_memory.arena;
diff --git a/debug.h b/debug.h
@@ -61,7 +61,6 @@ typedef struct {
u32 frame_draw_count;
DebugMetadata *selected_metadata;
- b32 mouse_pressed_last_frame;
u32 record_count;
u32 record_working_index;
@@ -157,10 +156,9 @@ static DebugTable g_debug_table;
RECORD_DEBUG_META_COMMON(__counter_##name, #name)
#define END_NAMED_BLOCK(name) RECORD_DEBUG_EVENT(__counter_##name, DE_END)
-
-typedef struct TerminalMemory TerminalMemory;
+typedef struct TerminalInput TerminalInput;
typedef struct Term Term;
typedef struct RenderCtx RenderCtx;
static void dump_lines_to_file(Term *t);
-static void draw_debug_overlay(TerminalMemory *memory, RenderCtx *rc);
+static void draw_debug_overlay(TerminalMemory *memory, TerminalInput *input, RenderCtx *rc);
#endif
diff --git a/platform_linux_x11.c b/platform_linux_x11.c
@@ -3,7 +3,6 @@
#include <GLFW/glfw3.h>
#include "util.h"
-
#include "vtgl.h"
#ifndef VERSION
@@ -79,6 +78,14 @@ do_debug(TerminalMemory *t, Stream *err)
#endif /* _DEBUG */
static void
+button_action(ButtonState *button, b32 pressed)
+{
+ if (pressed != button->ended_down)
+ button->transitions++;
+ button->ended_down = pressed;
+}
+
+static void
glfw_error_callback(int code, const char *desc)
{
u8 buf[256];
@@ -100,6 +107,31 @@ fb_callback(GLFWwindow *win, i32 w, i32 h)
ctx->input->window_size = (iv2){.w = w, .h = h};
}
+static void
+mouse_button_callback(GLFWwindow *win, i32 button, i32 action, i32 modifiers)
+{
+ tmp_user_ctx *ctx = glfwGetWindowUserPointer(win);
+ TerminalInput *input = ctx->input;
+
+ switch (button) {
+ case GLFW_MOUSE_BUTTON_LEFT:
+ button_action(input->mouse_buttons + MOUSE_LEFT, action == GLFW_PRESS);
+ break;
+ case GLFW_MOUSE_BUTTON_RIGHT:
+ button_action(input->mouse_buttons + MOUSE_RIGHT, action == GLFW_PRESS);
+ break;
+ case GLFW_MOUSE_BUTTON_MIDDLE:
+ button_action(input->mouse_buttons + MOUSE_MIDDLE, action == GLFW_PRESS);
+ break;
+ case GLFW_MOUSE_BUTTON_4:
+ button_action(input->mouse_buttons + MOUSE_EXTENDED_0, action == GLFW_PRESS);
+ break;
+ case GLFW_MOUSE_BUTTON_5:
+ button_action(input->mouse_buttons + MOUSE_EXTENDED_1, action == GLFW_PRESS);
+ break;
+ }
+}
+
static GLFWwindow *
init_window(tmp_user_ctx *ctx, iv2 window_size)
{
@@ -125,6 +157,7 @@ init_window(tmp_user_ctx *ctx, iv2 window_size)
glfwSwapInterval(1);
glfwSetFramebufferSizeCallback(window, fb_callback);
+ glfwSetMouseButtonCallback(window, mouse_button_callback);
return window;
}
@@ -238,6 +271,21 @@ check_shaders(GLCtx *gl, Arena a, Stream *err)
}
static void
+update_input(GLFWwindow *win, TerminalInput *input)
+{
+ /* NOTE: mouse */
+ input->mouse_scroll = (v2){0};
+
+ f64 mouse_x, mouse_y;
+ glfwGetCursorPos(win, &mouse_x, &mouse_y);
+ input->mouse.x = mouse_x;
+ input->mouse.y = input->window_size.h - mouse_y;
+
+ for (u32 i = 0; i < ARRAY_COUNT(input->mouse_buttons); i++)
+ input->mouse_buttons[i].transitions = 0;
+}
+
+static void
usage(char *argv0, Stream *err)
{
stream_push_s8(err, s8("usage: "));
@@ -362,6 +410,8 @@ main(i32 argc, char *argv[], char *envp[])
f64 last_time = os_get_time();
while (!glfwWindowShouldClose(window)) {
+ update_input(window, &input);
+
do_debug(&term_memory, &error_stream);
/* TODO: cpu time excluding waiting for the vblank */
diff --git a/util.c b/util.c
@@ -55,7 +55,7 @@ static Range
normalize_range(Range r)
{
Range result;
- if (r.start.y < r.end.y) {
+ if (!is_valid_range(r) || r.start.y < r.end.y) {
result = r;
} else if (r.end.y < r.start.y) {
result = (Range){.start = r.end, .end = r.start};
diff --git a/vtgl.c b/vtgl.c
@@ -64,11 +64,11 @@ get_occupied_size(Term *t)
}
static v2
-get_terminal_bot_left(Term *t)
+get_terminal_top_left(Term *t)
{
v2 os = get_occupied_size(t);
v2 delta = {.x = t->gl.window_size.w - os.w, .y = t->gl.window_size.h - os.h};
- v2 result = {.x = delta.x / 2, .y = delta.y / 2};
+ v2 result = {.x = delta.x / 2, .y = t->gl.window_size.h - delta.y / 2};
return result;
}
@@ -443,10 +443,10 @@ mouse_to_cell_space(Term *t, v2 mouse)
{
iv2 result = {0};
v2 cell_size = get_cell_size(&t->fa);
- v2 bot_left = get_terminal_bot_left(t);
+ v2 top_left = get_terminal_top_left(t);
- result.x = (i32)((mouse.x - bot_left.x) / cell_size.w);
- result.y = (i32)((mouse.y - bot_left.y) / cell_size.h);
+ result.x = (i32)((mouse.x - top_left.x) / cell_size.w);
+ result.y = (i32)((top_left.y - mouse.y) / cell_size.h);
CLAMP(result.x, 0, t->size.w - 1);
CLAMP(result.y, 0, t->size.h - 1);
@@ -493,25 +493,43 @@ stream_push_selection(Stream *s, TermView *tv, Range sel, u32 term_width)
}
static void
-update_selection(Term *t)
+update_selection(Term *t, v2 mouse, ButtonState *mouse_left)
{
Selection *sel = &t->selection;
- b32 held = glfwGetMouseButton(t->gl.window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS;
+
+ if (mouse_left->transitions && mouse_left->ended_down) {
+ if (is_valid_range(sel->range))
+ t->gl.flags |= UPDATE_RENDER_BUFFER;
+
+ sel->range.end = INVALID_RANGE_END;
+ sel->last_mouse = mouse;
+ sel->click_param = DOUBLE_CLICK_TIME;
+
+ if (sel->state != SS_WORDS)
+ sel->state++;
+
+ iv2 cell = mouse_to_cell_space(t, sel->last_mouse);
+ if (t->views[t->view_idx].fb.rows[cell.y][cell.x].bg & ATTR_WDUMMY) {
+ ASSERT(t->views[t->view_idx].fb.rows[cell.y][cell.x - 1].bg & ATTR_WIDE);
+ cell.x--;
+ }
+
+ if (sel->state == SS_WORDS) sel->anchor = get_word_around_cell(t, cell);
+ else sel->anchor = (Range){.start = cell, .end = cell};
+
+ return;
+ }
sel->click_param -= dt_for_frame;
if (sel->click_param < 0) {
sel->click_param = 0;
- if (!held)
+ if (!mouse_left->ended_down)
sel->state = SS_NONE;
}
- if (!held)
+ if (!mouse_left->ended_down)
return;
- f64 xpos, ypos;
- glfwGetCursorPos(t->gl.window, &xpos, &ypos);
- v2 mouse = {.x = xpos, .y = ypos};
-
if (sel->state != SS_WORDS && (mouse.x == sel->last_mouse.x && mouse.y == sel->last_mouse.y))
return;
sel->last_mouse = mouse;
@@ -711,38 +729,10 @@ key_callback(GLFWwindow *win, i32 key, i32 sc, i32 act, i32 mods)
}
static void
-mouse_button_callback(GLFWwindow *win, i32 btn, i32 act, i32 mod)
+handle_keybindings(Term *t, TerminalInput *input)
{
- tmp_user_ctx *ctx = glfwGetWindowUserPointer(win);
- Term *t = ctx->memory->memory;
/* TODO: map other mouse buttons */
- if (btn != GLFW_MOUSE_BUTTON_LEFT)
- return;
-
- if (act == GLFW_RELEASE)
- return;
-
- f64 xpos, ypos;
- glfwGetCursorPos(win, &xpos, &ypos);
- t->selection.range.end = (iv2){.x = -1, .y = -1};
- t->selection.last_mouse = (v2){.x = xpos, .y = ypos};
- t->selection.click_param = DOUBLE_CLICK_TIME;
-
- if (t->selection.state != SS_WORDS)
- t->selection.state++;
-
- iv2 cell = mouse_to_cell_space(t, t->selection.last_mouse);
- if (t->views[t->view_idx].fb.rows[cell.y][cell.x].bg & ATTR_WDUMMY) {
- ASSERT(t->views[t->view_idx].fb.rows[cell.y][cell.x - 1].bg & ATTR_WIDE);
- cell.x--;
- }
-
- if (t->selection.state == SS_WORDS) {
- t->selection.anchor = get_word_around_cell(t, cell);
- } else {
- t->selection.anchor = (Range){.start = cell, .end = cell};
- t->selection.range.end = INVALID_RANGE_END;
- }
+ update_selection(t, input->mouse, input->mouse_buttons + MOUSE_LEFT);
}
static void
@@ -824,7 +814,6 @@ reset_terminal(TerminalMemory *memory)
Term *t = memory->memory;
glfwSetCharCallback(t->gl.window, char_callback);
glfwSetKeyCallback(t->gl.window, key_callback);
- glfwSetMouseButtonCallback(t->gl.window, mouse_button_callback);
//glfwSetWindowRefreshCallback(t->gl.window, refresh_callback);
glfwSetScrollCallback(t->gl.window, scroll_callback);
}
@@ -977,13 +966,15 @@ DEBUG_EXPORT VTGL_FRAME_STEP_FN(vtgl_frame_step)
END_NAMED_BLOCK(input_from_child);
+ BEGIN_NAMED_BLOCK(mouse_and_keyboard_input);
+ handle_keybindings(t, input, &memory->platform_api);
+ END_NAMED_BLOCK(mouse_and_keyboard_input);
+
if (t->gl.flags & (NEEDS_REFILL|NEEDS_FULL_REFILL)) {
blit_lines(t, t->arena_for_frame, 0);
t->gl.flags |= UPDATE_RENDER_BUFFER;
}
- update_selection(t);
-
set_projection_matrix(&t->gl);
BEGIN_NAMED_BLOCK(update_render);
@@ -1043,7 +1034,7 @@ DEBUG_EXPORT VTGL_FRAME_STEP_FN(vtgl_frame_step)
* processing/effects shader */
BEGIN_NAMED_BLOCK(debug_overlay);
glUseProgram(t->gl.programs[SHADER_RECTS]);
- draw_debug_overlay(memory, &rc);
+ draw_debug_overlay(memory, input, &rc);
flush_render_push_buffer(&rc);
END_NAMED_BLOCK(debug_overlay);
diff --git a/vtgl.h b/vtgl.h
@@ -17,11 +17,30 @@ typedef struct {
platform_write_fn *write;
} PlatformAPI;
+enum mouse_buttons {
+ MOUSE_LEFT,
+ MOUSE_RIGHT,
+ MOUSE_MIDDLE,
+ MOUSE_EXTENDED_0,
+ MOUSE_EXTENDED_1,
+ MOUSE_BUTTON_COUNT,
+};
+
typedef struct {
+ /* TODO: is this even supported or does GLFW only call you once per poll? */
+ i32 transitions;
+ b32 ended_down;
+} ButtonState;
+
+typedef struct TerminalInput {
b32 data_available;
b32 executable_reloaded;
iv2 window_size;
+ v2 mouse;
+ v2 mouse_scroll;
+ ButtonState mouse_buttons[MOUSE_BUTTON_COUNT];
+
f32 dt;
} TerminalInput;