feat: spreadsheet cell resizing

This commit is contained in:
2026-03-06 16:46:15 +01:00
parent 3985188baa
commit 729c227b35
15 changed files with 194 additions and 5 deletions
+12
View File
@@ -149,6 +149,18 @@ void gui::desktop_compose(DesktopState* ds) {
}
}
// Check if focused external window requests a cursor style
if (cur_style == CURSOR_ARROW && ds->focused_window >= 0) {
Window* fwin = &ds->windows[ds->focused_window];
if (fwin->external && fwin->ext_cursor > 0) {
Rect cr = fwin->content_rect();
if (cr.contains(ds->mouse.x, ds->mouse.y)) {
if (fwin->ext_cursor == 1) cur_style = CURSOR_RESIZE_H;
else if (fwin->ext_cursor == 2) cur_style = CURSOR_RESIZE_V;
}
}
}
// Draw cursor last
draw_cursor(fb, ds->mouse.x, ds->mouse.y, cur_style);
}
+26
View File
@@ -434,6 +434,32 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
ds->ctx_menu_open = false;
}
// Forward continuous mouse events to focused window (hover, drag, release)
if (!left_pressed && ds->focused_window >= 0) {
Window* win = &ds->windows[ds->focused_window];
if (win->state != WIN_MINIMIZED && win->state != WIN_CLOSED) {
Rect cr = win->content_rect();
// Forward if mouse is over content (hover/move) or button is held/released (drag continuity)
if (cr.contains(mx, my) || left_held || left_released) {
if (win->external) {
Montauk::WinEvent wev;
montauk::memset(&wev, 0, sizeof(wev));
wev.type = 1; // mouse
wev.mouse.x = mx - cr.x;
wev.mouse.y = my - cr.y;
wev.mouse.scroll = 0;
wev.mouse.buttons = buttons;
wev.mouse.prev_buttons = prev;
montauk::win_sendevent(win->ext_win_id, &wev);
} else if (win->on_mouse) {
ev.x = mx;
ev.y = my;
win->on_mouse(win, ev);
}
}
}
}
// Handle scroll events on focused window
if (ev.scroll != 0 && ds->focused_window >= 0) {
Window* win = &ds->windows[ds->focused_window];
+2 -1
View File
@@ -114,10 +114,11 @@ void desktop_poll_external_windows(DesktopState* ds) {
for (int i = 0; i < ds->window_count; i++) {
if (ds->windows[i].external && ds->windows[i].ext_win_id == extId) {
found = true;
// Update dirty flag
// Update dirty flag and cursor
if (extWins[e].dirty) {
ds->windows[i].dirty = true;
}
ds->windows[i].ext_cursor = extWins[e].cursor;
// Re-map if external app resized its buffer
if (extWins[e].width != ds->windows[i].content_w ||
extWins[e].height != ds->windows[i].content_h) {
+58
View File
@@ -51,6 +51,11 @@ TrueTypeFont* g_font_bold = nullptr;
bool g_fmt_dropdown_open = false;
bool g_col_resizing = false;
int g_col_resize_idx = -1;
int g_col_resize_start_x = 0;
int g_col_resize_start_w = 0;
UndoEntry* g_undo[UNDO_MAX + 1];
int g_undo_count = 0;
int g_undo_pos = 0;
@@ -499,6 +504,58 @@ extern "C" void _start() {
uint8_t btns = ev.mouse.buttons;
uint8_t prev = ev.mouse.prev_buttons;
bool clicked = (btns & 1) && !(prev & 1);
bool left_held = (btns & 1);
bool left_released = !(btns & 1) && (prev & 1);
int pbh = g_pathbar_open ? PATHBAR_H : 0;
int header_y = TOOLBAR_H + pbh + FORMULA_BAR_H;
// Update cursor style: resize_h when hovering near column border in header
{
int cursor = 0; // arrow
if (g_col_resizing) {
cursor = 1; // resize_h while dragging
} else if (my >= header_y && my < header_y + COL_HEADER_H) {
for (int c = 0; c < MAX_COLS; c++) {
int cx = col_x(c) - g_scroll_x + g_col_widths[c] - 1;
if (mx >= cx - COL_RESIZE_GRAB && mx <= cx + COL_RESIZE_GRAB) {
cursor = 1; // resize_h
break;
}
}
}
montauk::win_setcursor(win_id, cursor);
}
// Column resize: drag in progress
if (g_col_resizing) {
if (left_held) {
int delta = mx - g_col_resize_start_x;
int new_w = g_col_resize_start_w + delta;
if (new_w < MIN_COL_W) new_w = MIN_COL_W;
g_col_widths[g_col_resize_idx] = new_w;
clamp_scroll();
redraw = true;
}
if (left_released) {
g_col_resizing = false;
}
goto done_mouse;
}
// Column resize: start drag (click near right edge of column header)
if (clicked && my >= header_y && my < header_y + COL_HEADER_H) {
for (int c = 0; c < MAX_COLS; c++) {
int cx = col_x(c) - g_scroll_x + g_col_widths[c] - 1;
if (mx >= cx - COL_RESIZE_GRAB && mx <= cx + COL_RESIZE_GRAB) {
g_col_resizing = true;
g_col_resize_idx = c;
g_col_resize_start_x = mx;
g_col_resize_start_w = g_col_widths[c];
goto done_mouse;
}
}
}
if (clicked) {
if (handle_fmt_dropdown_click(mx, my)) {
@@ -526,6 +583,7 @@ extern "C" void _start() {
redraw = true;
}
}
done_mouse:
if (redraw) {
render(pixels);
+11 -2
View File
@@ -249,8 +249,17 @@ void render(uint32_t* pixels) {
else
text_x = x + 6;
if (text_x >= ROW_HEADER_W - tw && text_x < g_win_w)
cf->draw_to_buffer(pixels, g_win_w, g_win_h, text_x, y + (ROW_H - FONT_SIZE) / 2, cell->display, col, FONT_SIZE);
{
// Clip text to cell boundaries
int cell_left = x < ROW_HEADER_W ? ROW_HEADER_W : x;
int cell_right = x + g_col_widths[c] - 1;
if (cell_right > g_win_w) cell_right = g_win_w;
if (text_x < g_win_w && cell_left < cell_right)
cf->draw_to_buffer_clipped(pixels, g_win_w, g_win_h,
text_x, y + (ROW_H - FONT_SIZE) / 2,
cell->display, col, FONT_SIZE,
cell_left, y, cell_right - cell_left, ROW_H);
}
}
// Cell right border
+7
View File
@@ -38,7 +38,9 @@ static constexpr int TB_BTN_RAD = 3;
static constexpr int MAX_COLS = 26; // A-Z
static constexpr int MAX_ROWS = 100;
static constexpr int DEF_COL_W = 100;
static constexpr int MIN_COL_W = 30;
static constexpr int ROW_H = 26;
static constexpr int COL_RESIZE_GRAB = 5; // pixels from border edge for grab zone
static constexpr int CELL_TEXT_MAX = 128;
static constexpr int FONT_SIZE = 18;
@@ -163,6 +165,11 @@ extern TrueTypeFont* g_font_bold;
extern bool g_fmt_dropdown_open;
extern bool g_col_resizing;
extern int g_col_resize_idx;
extern int g_col_resize_start_x;
extern int g_col_resize_start_w;
extern UndoEntry* g_undo[UNDO_MAX + 1];
extern int g_undo_count;
extern int g_undo_pos;