ogl_beamforming

Ultrasound Beamforming Implemented with OpenGL
git clone anongit@rnpnr.xyz:ogl_beamforming.git
Log | Files | Refs | Feed | Submodules | LICENSE

Commit: 7e9306137a8a1c0be8021a9bc6d608365e9c8e3f
Parent: be868315b5189efb3884bd9592c2952e8fe5a1f8
Author: Randy Palamar
Date:   Sat, 26 Apr 2025 15:55:08 -0600

ui: sub tables for parameter group listings

Diffstat:
Mui.c | 105+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
1 file changed, 65 insertions(+), 40 deletions(-)

diff --git a/ui.c b/ui.c @@ -4,6 +4,7 @@ * [ ]: refactor: ui shouldn't fully destroy itself on hot reload * [ ]: refactor: remove all the excessive measure_texts (cell drawing, hover_var in params table) * [ ]: refactor: move remaining fragment shader stuff into ui + * [ ]: refactor: scale table to rect * [ ]: refactor: re-add next_hot variable. this will simplify the code and number of checks * being performed inline. example: * if (hovering) @@ -391,7 +392,7 @@ typedef struct { TableRowKind kind; } TableRow; -typedef struct { +typedef struct Table { TableRow *data; iz count; iz capacity; @@ -407,6 +408,8 @@ typedef struct { /* NOTE(rnp): row count including nested tables */ i32 rows; i32 columns; + + struct Table *parent; } Table; typedef struct { @@ -514,14 +517,15 @@ stream_append_variable(Stream *s, Variable *var) } } -function Table +function Table * table_new(Arena *a, i32 initial_capacity, i32 columns, TextAlignment *alignment) { - Table result = {.columns = columns}; - da_reserve(a, &result, initial_capacity); - result.alignment = alloc(a, TextAlignment, columns); - result.widths = alloc(a, f32, columns); - mem_copy(result.alignment, alignment, sizeof(*alignment) * columns); + Table *result = push_struct(a, Table); + da_reserve(a, result, initial_capacity); + result->columns = columns; + result->alignment = alloc(a, TextAlignment, columns); + result->widths = alloc(a, f32, columns); + mem_copy(result->alignment, alignment, sizeof(*alignment) * columns); return result; } @@ -574,7 +578,7 @@ table_iterator_next(TableIterator *it, Arena *a) it->row = result; it->column = 0; it->cell_rect.pos.x = it->start_x; - it->cell_rect.pos.y += it->cell_rect.size.h; + it->cell_rect.pos.y += it->cell_rect.size.h + it->frame.table->row_border_thick; } if (it->row && it->kind == TIK_CELLS) { @@ -625,11 +629,7 @@ table_extent(Table *t, Arena arena, Font *font) row_width += (columns - 1) * it->frame.table->column_border_thick; max_row_width = MAX(row_width, max_row_width); } - - v2 result; - result.x = max_row_width; - result.y = t->rows * (font->baseSize + TABLE_CELL_PAD_HEIGHT) - + (t->rows - 1) * t->row_border_thick; + v2 result = {.x = max_row_width, .y = it->cell_rect.pos.y}; return result; } @@ -666,12 +666,12 @@ function TableRow * table_push_row(Table *t, Arena *a, TableRowKind kind) { TableRow *result = da_push(a, t); - if (kind == TRK_TABLE) { - result->data = push_struct(a, Table); - } else { + if (kind == TRK_CELLS) { result->data = alloc(a, TableCell, t->columns); + /* NOTE(rnp): do not increase rows for an empty subtable */ t->rows++; } + result->kind = kind; return result; } @@ -689,6 +689,22 @@ table_push_parameter_row(Table *t, Arena *a, s8 label, Variable *var, s8 suffix) return result; } +function Table * +table_begin_subtable(Table *table, Arena *a, i32 columns, TextAlignment *alignment) +{ + TableRow *row = table_push_row(table, a, TRK_TABLE); + Table *result = row->data = table_new(a, 0, columns, alignment); + result->parent = table; + return result; +} + +function Table * +table_end_subtable(Table *table) +{ + Table *result = table->parent ? table->parent : table; + return result; +} + function void resize_frame_view(BeamformerFrameView *view, uv2 dim) { @@ -1675,7 +1691,7 @@ draw_table_cell(BeamformerUI *ui, TableCell *cell, Rect cell_rect, TextAlignment v4 base_colour = ts.colour; if (cell->kind == TCK_VARIABLE && cell->var->flags & V_INPUT) { - Rect hover = {.pos = cell_rect.pos, .size = {.w = cell->width, .h = cell_rect.size.h}}; + Rect hover = {.pos = cell_at, .size = {.w = cell->width, .h = cell_rect.size.h}}; if (hover_var(ui, mouse, hover, cell->var) && (cell->var->flags & V_TEXT)) ui->interaction.hot_font = ts.font; ts.colour = lerp_v4(ts.colour, HOVERED_COLOUR, cell->var->hover_t); @@ -1903,20 +1919,20 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, Variable *var, Rect displa draw_text(stream_to_s8(&buf), txt_p, &text_spec); } - Table table = table_new(&a, 3, 3, (TextAlignment []){TA_LEFT, TA_LEFT, TA_LEFT}); - table_push_parameter_row(&table, &a, view->gamma.name, &view->gamma, s8("")); - table_push_parameter_row(&table, &a, view->threshold.name, &view->threshold, s8("")); - table_push_parameter_row(&table, &a, view->dynamic_range.name, &view->dynamic_range, s8("[dB]")); + Table *table = table_new(&a, 3, 3, (TextAlignment []){TA_LEFT, TA_LEFT, TA_LEFT}); + table_push_parameter_row(table, &a, view->gamma.name, &view->gamma, s8("")); + table_push_parameter_row(table, &a, view->threshold.name, &view->threshold, s8("")); + table_push_parameter_row(table, &a, view->dynamic_range.name, &view->dynamic_range, s8("[dB]")); Rect table_rect = vr; - f32 height = table_extent(&table, a, text_spec.font).y; + f32 height = table_extent(table, a, text_spec.font).y; height = MIN(height, vr.size.h); table_rect.pos.w += 8; table_rect.pos.y += vr.size.h - height - 8; table_rect.size.h = height; table_rect.size.w = draw_table_width - 16; - draw_table(ui, a, &table, table_rect, text_spec, mouse); + draw_table(ui, a, table, table_rect, text_spec, mouse); } static v2 @@ -1955,35 +1971,38 @@ draw_compute_stats_view(BeamformerCtx *ctx, Arena arena, ComputeShaderStats *sta u32 stages = ctx->shared_memory->compute_stages_count; TextSpec text_spec = {.font = &ui->font, .colour = FG_COLOUR, .flags = TF_LIMITED}; - Stream sb = stream_alloc(&arena, 256); - Table table = table_new(&arena, stages + 1, 3, (TextAlignment []){TA_LEFT, TA_LEFT, TA_LEFT}); + Stream sb = stream_alloc(&arena, 256); + Table *table = table_new(&arena, stages + 1, 3, (TextAlignment []){TA_LEFT, TA_LEFT, TA_LEFT}); for (u32 i = 0; i < stages; i++) { u32 index = ctx->shared_memory->compute_stages[i]; compute_time_sum += stats->times[index]; stream_append_f64_e(&sb, stats->times[index]); - TableCell *cells = table_push_row(&table, &arena, TRK_CELLS)->data; + TableCell *cells = table_push_row(table, &arena, TRK_CELLS)->data; cells[0].text = labels[index]; cells[1].text = stream_chop_head(&sb); cells[2].text = s8("[s]"); } stream_append_f64_e(&sb, compute_time_sum); - TableCell *cells = table_push_row(&table, &arena, TRK_CELLS)->data; + TableCell *cells = table_push_row(table, &arena, TRK_CELLS)->data; cells[0].text = s8("Compute Total:"); cells[1].text = stream_chop_head(&sb); cells[2].text = s8("[s]"); - table_extent(&table, arena, text_spec.font); - return draw_table(ui, arena, &table, r, text_spec, (v2){0}); + table_extent(table, arena, text_spec.font); + return draw_table(ui, arena, table, r, text_spec, (v2){0}); } function v2 draw_ui_view_listing(BeamformerUI *ui, Variable *group, Arena arena, Rect r, v2 mouse, TextSpec text_spec) { ASSERT(group->type == VT_GROUP); - Table table = table_new(&arena, 0, 3, (TextAlignment []){TA_LEFT, TA_LEFT, TA_RIGHT}); + Table *table = table_new(&arena, 0, 3, (TextAlignment []){TA_LEFT, TA_LEFT, TA_RIGHT}); + /* NOTE(rnp): minimum width for middle column */ + table->widths[1] = 150; + Variable *var = group->u.group.first; while (var) { switch (var->type) { @@ -1992,23 +2011,27 @@ draw_ui_view_listing(BeamformerUI *ui, Variable *group, Arena arena, Rect r, v2 s8 suffix = s8(""); if (var->type == VT_BEAMFORMER_VARIABLE) suffix = var->u.beamformer_variable.suffix; - table_push_parameter_row(&table, &arena, var->name, var, suffix); + table_push_parameter_row(table, &arena, var->name, var, suffix); while (var) { if (var->next) { var = var->next; break; } - var = var->parent; + var = var->parent; + table = table_end_subtable(table); } } break; case VT_GROUP: { VariableGroup *g = &var->u.group; - TableCell *cells = table_push_row(&table, &arena, TRK_CELLS)->data; + TableCell *cells = table_push_row(table, &arena, TRK_CELLS)->data; cells[0] = (TableCell){.text = var->name, .kind = TCK_VARIABLE, .var = var}; if (g->expanded) { var = g->first; + table = table_begin_subtable(table, &arena, table->columns, + (TextAlignment []){TA_LEFT, TA_CENTER, TA_RIGHT}); + table->widths[1] = 100; } else { Variable *v = g->first; @@ -2039,23 +2062,25 @@ draw_ui_view_listing(BeamformerUI *ui, Variable *group, Arena arena, Rect r, v2 var = var->next; } } break; - default: INVALID_CODE_PATH; + INVALID_DEFAULT_CASE; } } text_spec.flags |= TF_LIMITED; - /* NOTE(rnp): minimum width for middle column */ - table.widths[1] = 150; - v2 result = table_extent(&table, arena, text_spec.font); - TableIterator *it = table_iterator_new(&table, TIK_CELLS, &arena, 0, r.pos, text_spec.font); + v2 result = table_extent(table, arena, text_spec.font); + TableIterator *it = table_iterator_new(table, TIK_CELLS, &arena, 0, r.pos, text_spec.font); for (TableCell *cell = table_iterator_next(it, &arena); cell; cell = table_iterator_next(it, &arena)) { text_spec.limits.size.w = r.size.w - (it->cell_rect.pos.x - it->start_x); + /* TODO(rnp): ensure this doesn't exceed r.size */ + Rect rect; + rect.pos = add_v2(it->cell_rect.pos, scale_v2((v2){.x = text_spec.font->baseSize}, it->sub_table_depth)); + rect.size = it->cell_rect.size; if (cell->kind == TCK_VARIABLE_GROUP) { Variable *v = cell->var->u.group.first; - v2 at = table_cell_align(cell, it->alignment, it->cell_rect); + v2 at = table_cell_align(cell, it->alignment, rect); text_spec.limits.size.w = r.size.w - (at.x - it->start_x); f32 dw = draw_text(s8("{"), at, &text_spec).x; while (v) { @@ -2074,7 +2099,7 @@ draw_ui_view_listing(BeamformerUI *ui, Variable *group, Arena arena, Rect r, v2 text_spec.limits.size.w -= dw; draw_text(s8("}"), at, &text_spec); } else { - draw_table_cell(ui, cell, it->cell_rect, it->alignment, text_spec, mouse); + draw_table_cell(ui, cell, rect, it->alignment, text_spec, mouse); } }