151 lines
4.7 KiB
C++
151 lines
4.7 KiB
C++
/*
|
|
* table.hpp
|
|
* Montauk Toolkit table/list helpers
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "gui/canvas.hpp"
|
|
#include "gui/mtk/theme.hpp"
|
|
|
|
namespace gui::mtk {
|
|
|
|
struct TableColumn {
|
|
const char* label;
|
|
int x;
|
|
int w;
|
|
};
|
|
|
|
struct TableLayout {
|
|
Rect header;
|
|
Rect body;
|
|
int row_h;
|
|
};
|
|
|
|
struct TableStyle {
|
|
Color header_bg;
|
|
Color header_border;
|
|
Color header_text;
|
|
Color row_selected_bg;
|
|
Color row_hover_bg;
|
|
};
|
|
|
|
inline TableStyle make_table_style(const Theme& theme) {
|
|
return {
|
|
theme.surface_alt,
|
|
theme.border,
|
|
theme.text_subtle,
|
|
theme.accent_soft,
|
|
colors::TRANSPARENT,
|
|
};
|
|
}
|
|
|
|
inline int table_visible_rows(const TableLayout& layout) {
|
|
if (layout.row_h <= 0 || layout.body.h <= 0) return 0;
|
|
return layout.body.h / layout.row_h;
|
|
}
|
|
|
|
inline int table_max_scroll(const TableLayout& layout, int row_count) {
|
|
int visible = table_visible_rows(layout);
|
|
if (row_count > visible && visible > 0) return row_count - visible;
|
|
return 0;
|
|
}
|
|
|
|
inline void clamp_table_scroll(int* scroll, const TableLayout& layout, int row_count) {
|
|
if (!scroll) return;
|
|
*scroll = gui_clamp(*scroll, 0, table_max_scroll(layout, row_count));
|
|
}
|
|
|
|
inline void ensure_table_row_visible(int* scroll,
|
|
const TableLayout& layout,
|
|
int row_count,
|
|
int selected) {
|
|
if (!scroll || selected < 0) return;
|
|
int visible = table_visible_rows(layout);
|
|
if (visible <= 0) return;
|
|
if (selected < *scroll) {
|
|
*scroll = selected;
|
|
} else if (selected >= *scroll + visible) {
|
|
*scroll = selected - visible + 1;
|
|
}
|
|
clamp_table_scroll(scroll, layout, row_count);
|
|
}
|
|
|
|
inline Rect table_row_rect(const TableLayout& layout, int scroll, int row_index) {
|
|
return {
|
|
layout.body.x,
|
|
layout.body.y + (row_index - scroll) * layout.row_h,
|
|
layout.body.w,
|
|
layout.row_h
|
|
};
|
|
}
|
|
|
|
inline Rect table_cell_rect(const Rect& row_rect, const TableColumn& col) {
|
|
return {row_rect.x + col.x, row_rect.y, col.w, row_rect.h};
|
|
}
|
|
|
|
inline int table_hit_row(const TableLayout& layout,
|
|
int scroll,
|
|
int row_count,
|
|
int mx,
|
|
int my) {
|
|
if (!layout.body.contains(mx, my) || layout.row_h <= 0) return -1;
|
|
int row = (my - layout.body.y) / layout.row_h;
|
|
int index = scroll + row;
|
|
if (index < 0 || index >= row_count) return -1;
|
|
return index;
|
|
}
|
|
|
|
using TableRowRenderer = void (*)(Canvas& c,
|
|
void* userdata,
|
|
int row_index,
|
|
const Rect& row_rect,
|
|
int text_y,
|
|
const TableColumn* cols,
|
|
int col_count,
|
|
const Theme& theme,
|
|
const TableStyle& style);
|
|
|
|
inline void draw_table(Canvas& c,
|
|
const TableLayout& layout,
|
|
const TableColumn* cols,
|
|
int col_count,
|
|
int row_count,
|
|
int scroll,
|
|
int selected,
|
|
int hovered,
|
|
const Theme& theme,
|
|
const TableStyle& style,
|
|
TableRowRenderer draw_row,
|
|
void* userdata) {
|
|
c.fill_rect(layout.header.x, layout.header.y, layout.header.w, layout.header.h, style.header_bg);
|
|
c.hline(layout.header.x, layout.header.y + layout.header.h - 1, layout.header.w, style.header_border);
|
|
|
|
int fh = system_font_height();
|
|
int header_text_y = layout.header.y + (layout.header.h - fh) / 2;
|
|
for (int i = 0; i < col_count; i++) {
|
|
c.text(layout.header.x + cols[i].x, header_text_y, cols[i].label, style.header_text);
|
|
}
|
|
|
|
int visible = table_visible_rows(layout);
|
|
for (int row = 0; row < visible; row++) {
|
|
int index = scroll + row;
|
|
if (index >= row_count) break;
|
|
|
|
Rect row_rect = table_row_rect(layout, scroll, index);
|
|
if (index == selected) {
|
|
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, style.row_selected_bg);
|
|
} else if (index == hovered && style.row_hover_bg.a > 0) {
|
|
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, style.row_hover_bg);
|
|
}
|
|
|
|
if (draw_row) {
|
|
int text_y = row_rect.y + (layout.row_h - fh) / 2;
|
|
draw_row(c, userdata, index, row_rect, text_y, cols, col_count, theme, style);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace gui::mtk
|