feat: extend Files app marquee selection and highlight to list view
This commit is contained in:
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 48
|
#define MONTAUK_BUILD_NUMBER 49
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
|||||||
|
|
||||||
if (clicked_idx >= 0 && clicked_idx < fm->entry_count) {
|
if (clicked_idx >= 0 && clicked_idx < fm->entry_count) {
|
||||||
uint64_t now = montauk::get_milliseconds();
|
uint64_t now = montauk::get_milliseconds();
|
||||||
|
filemanager_clear_multi_selection(fm);
|
||||||
|
|
||||||
// Double-click detection
|
// Double-click detection
|
||||||
if (fm->last_click_item == clicked_idx &&
|
if (fm->last_click_item == clicked_idx &&
|
||||||
@@ -166,15 +167,24 @@ void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
|||||||
fm->last_click_time = now;
|
fm->last_click_time = now;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Background click in list area: start marquee drag
|
||||||
fm->selected = -1;
|
fm->selected = -1;
|
||||||
|
filemanager_clear_multi_selection(fm);
|
||||||
|
fm->marquee_active = true;
|
||||||
|
fm->marquee_start_x = local_x;
|
||||||
|
fm->marquee_start_y = rel_y;
|
||||||
|
fm->marquee_cur_x = local_x;
|
||||||
|
fm->marquee_cur_y = rel_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Marquee drag in grid view ----
|
// ---- Marquee drag (grid or list view) ----
|
||||||
if (fm->marquee_active) {
|
if (fm->marquee_active) {
|
||||||
int list_y = FM_TOOLBAR_H + FM_PATHBAR_H;
|
int list_y = fm->grid_view
|
||||||
|
? FM_TOOLBAR_H + FM_PATHBAR_H
|
||||||
|
: FM_TOOLBAR_H + FM_PATHBAR_H + FM_HEADER_H;
|
||||||
int rel_y = local_y - list_y + fm->scrollbar.scroll_offset;
|
int rel_y = local_y - list_y + fm->scrollbar.scroll_offset;
|
||||||
int clamp_x = local_x;
|
int clamp_x = local_x;
|
||||||
if (clamp_x < 0) clamp_x = 0;
|
if (clamp_x < 0) clamp_x = 0;
|
||||||
@@ -187,17 +197,17 @@ void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
|||||||
fm->marquee_cur_y = rel_y;
|
fm->marquee_cur_y = rel_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recompute hit-set every frame so icons highlight live during the drag.
|
|
||||||
int cols = (cw - FM_SCROLLBAR_W) / FM_GRID_CELL_W;
|
|
||||||
if (cols < 1) cols = 1;
|
|
||||||
|
|
||||||
int rx0 = fm->marquee_start_x < fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
int rx0 = fm->marquee_start_x < fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
||||||
int ry0 = fm->marquee_start_y < fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
int ry0 = fm->marquee_start_y < fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
||||||
int rx1 = fm->marquee_start_x > fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
int rx1 = fm->marquee_start_x > fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
||||||
int ry1 = fm->marquee_start_y > fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
int ry1 = fm->marquee_start_y > fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
||||||
|
|
||||||
|
// Recompute hit-set every frame so entries highlight live during the drag.
|
||||||
filemanager_clear_multi_selection(fm);
|
filemanager_clear_multi_selection(fm);
|
||||||
int limit = fm->entry_count < 64 ? fm->entry_count : 64;
|
int limit = fm->entry_count < 64 ? fm->entry_count : 64;
|
||||||
|
if (fm->grid_view) {
|
||||||
|
int cols = (cw - FM_SCROLLBAR_W) / FM_GRID_CELL_W;
|
||||||
|
if (cols < 1) cols = 1;
|
||||||
for (int i = 0; i < limit; i++) {
|
for (int i = 0; i < limit; i++) {
|
||||||
int col = i % cols;
|
int col = i % cols;
|
||||||
int row = i / cols;
|
int row = i / cols;
|
||||||
@@ -213,6 +223,18 @@ void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
|||||||
fm->multi_selected[i] = true;
|
fm->multi_selected[i] = true;
|
||||||
fm->multi_count++;
|
fm->multi_count++;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// List rows span the full width, so select any row whose vertical
|
||||||
|
// extent overlaps the marquee box.
|
||||||
|
for (int i = 0; i < limit; i++) {
|
||||||
|
int cell_y = i * FM_ITEM_H;
|
||||||
|
int cy1 = cell_y + FM_ITEM_H;
|
||||||
|
if (ry1 < cell_y || ry0 >= cy1) continue;
|
||||||
|
|
||||||
|
fm->multi_selected[i] = true;
|
||||||
|
fm->multi_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
fm->selected = -1;
|
fm->selected = -1;
|
||||||
|
|
||||||
if (!ev.left_held()) {
|
if (!ev.left_held()) {
|
||||||
@@ -262,8 +284,16 @@ void filemanager_on_mouse(Window* win, MouseEvent& ev) {
|
|||||||
int idx = rel_y / FM_ITEM_H;
|
int idx = rel_y / FM_ITEM_H;
|
||||||
if (idx >= 0 && idx < fm->entry_count) {
|
if (idx >= 0 && idx < fm->entry_count) {
|
||||||
target_idx = idx;
|
target_idx = idx;
|
||||||
|
// Preserve multi-selection if right-clicking inside it,
|
||||||
|
// otherwise replace it with a single selection.
|
||||||
|
if (!(fm->multi_count > 0 && fm->multi_selected[idx])) {
|
||||||
|
filemanager_clear_multi_selection(fm);
|
||||||
fm->selected = idx;
|
fm->selected = idx;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
filemanager_clear_multi_selection(fm);
|
||||||
|
fm->selected = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,6 +105,34 @@ static void draw_centered_grid_label(Canvas& c, int cell_x, int y, const char* l
|
|||||||
c.text(tx, y, label, color);
|
c.text(tx, y, label, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Marquee overlay (translucent accent wash + darker outline). Marquee
|
||||||
|
// coordinates are stored in content space (y = rel_y, anchored to scroll), so
|
||||||
|
// list_y is the top of the scrollable area for the active view.
|
||||||
|
static void draw_marquee(Canvas& c, FileManagerState* fm, int list_y) {
|
||||||
|
if (!fm->marquee_active) return;
|
||||||
|
DesktopState* ds = fm->desktop;
|
||||||
|
|
||||||
|
int rx0 = fm->marquee_start_x < fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
||||||
|
int ry0 = fm->marquee_start_y < fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
||||||
|
int rx1 = fm->marquee_start_x > fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
||||||
|
int ry1 = fm->marquee_start_y > fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
||||||
|
|
||||||
|
int sy0 = list_y + ry0 - fm->scrollbar.scroll_offset;
|
||||||
|
int sy1 = list_y + ry1 - fm->scrollbar.scroll_offset;
|
||||||
|
int max_x = c.w - FM_SCROLLBAR_W;
|
||||||
|
if (rx1 > max_x) rx1 = max_x;
|
||||||
|
if (sy0 < list_y) sy0 = list_y;
|
||||||
|
if (sy1 > c.h) sy1 = c.h;
|
||||||
|
int mw = rx1 - rx0;
|
||||||
|
int mh = sy1 - sy0;
|
||||||
|
if (mw > 0 && mh > 0) {
|
||||||
|
Color accent = ds ? ds->settings.accent_color : colors::ACCENT;
|
||||||
|
Color wash = Color::from_rgba(accent.r, accent.g, accent.b, 80);
|
||||||
|
c.fill_rect_alpha(rx0, sy0, mw, mh, wash);
|
||||||
|
c.rect(rx0, sy0, mw, mh, gui::mtk::darken(accent, 48));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int filemanager_grid_row_height(FileManagerState* fm, int row, int cols) {
|
int filemanager_grid_row_height(FileManagerState* fm, int row, int cols) {
|
||||||
if (!fm || cols <= 0 || row < 0) return FM_GRID_CELL_H;
|
if (!fm || cols <= 0 || row < 0) return FM_GRID_CELL_H;
|
||||||
|
|
||||||
@@ -408,27 +436,7 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) {
|
|||||||
|
|
||||||
// Marquee drawn on top of cells: a translucent accent wash so icons
|
// Marquee drawn on top of cells: a translucent accent wash so icons
|
||||||
// and labels remain visible underneath, plus a darker outline.
|
// and labels remain visible underneath, plus a darker outline.
|
||||||
if (fm->marquee_active) {
|
draw_marquee(c, fm, list_y);
|
||||||
int rx0 = fm->marquee_start_x < fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
|
||||||
int ry0 = fm->marquee_start_y < fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
|
||||||
int rx1 = fm->marquee_start_x > fm->marquee_cur_x ? fm->marquee_start_x : fm->marquee_cur_x;
|
|
||||||
int ry1 = fm->marquee_start_y > fm->marquee_cur_y ? fm->marquee_start_y : fm->marquee_cur_y;
|
|
||||||
|
|
||||||
int sy0 = list_y + ry0 - fm->scrollbar.scroll_offset;
|
|
||||||
int sy1 = list_y + ry1 - fm->scrollbar.scroll_offset;
|
|
||||||
int max_x = c.w - FM_SCROLLBAR_W;
|
|
||||||
if (rx1 > max_x) rx1 = max_x;
|
|
||||||
if (sy0 < list_y) sy0 = list_y;
|
|
||||||
if (sy1 > c.h) sy1 = c.h;
|
|
||||||
int mw = rx1 - rx0;
|
|
||||||
int mh = sy1 - sy0;
|
|
||||||
if (mw > 0 && mh > 0) {
|
|
||||||
Color accent = ds ? ds->settings.accent_color : colors::ACCENT;
|
|
||||||
Color wash = Color::from_rgba(accent.r, accent.g, accent.b, 80);
|
|
||||||
c.fill_rect_alpha(rx0, sy0, mw, mh, wash);
|
|
||||||
c.rect(rx0, sy0, mw, mh, gui::mtk::darken(accent, 48));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// ---- List View ----
|
// ---- List View ----
|
||||||
|
|
||||||
@@ -471,8 +479,9 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) {
|
|||||||
int iy = list_y + (i - scroll_items) * FM_ITEM_H - (fm->scrollbar.scroll_offset % FM_ITEM_H);
|
int iy = list_y + (i - scroll_items) * FM_ITEM_H - (fm->scrollbar.scroll_offset % FM_ITEM_H);
|
||||||
if (iy + FM_ITEM_H <= list_y || iy >= c.h) continue;
|
if (iy + FM_ITEM_H <= list_y || iy >= c.h) continue;
|
||||||
|
|
||||||
// Highlight selected
|
// Highlight selected (single or marquee multi-selection)
|
||||||
if (i == fm->selected) {
|
bool row_selected = (i == fm->selected) || (i < 64 && fm->multi_selected[i]);
|
||||||
|
if (row_selected) {
|
||||||
int sy = gui_max(iy, list_y);
|
int sy = gui_max(iy, list_y);
|
||||||
int sh = gui_min(iy + FM_ITEM_H, c.h) - sy;
|
int sh = gui_min(iy + FM_ITEM_H, c.h) - sy;
|
||||||
if (sh > 0)
|
if (sh > 0)
|
||||||
@@ -592,6 +601,9 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) {
|
|||||||
c.text(type_col_x, ty, type_str, dim);
|
c.text(type_col_x, ty, type_str, dim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Marquee overlay drawn on top of the rows.
|
||||||
|
draw_marquee(c, fm, list_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- Scrollbar ----
|
// ---- Scrollbar ----
|
||||||
|
|||||||
Reference in New Issue
Block a user