ogl_beamforming

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

Commit: eb014c46e97668b22c5e1da156ec9159ec6b9831
Parent: 33cccf68deeb58ed448aff2e0edea781d3c16950
Author: Randy Palamar
Date:   Thu, 20 Mar 2025 07:29:51 -0600

ui: add scrolling to clipped parameter view

Diffstat:
Mui.c | 64+++++++++++++++++++++++++++++++++++++++++++++++-----------------
1 file changed, 47 insertions(+), 17 deletions(-)

diff --git a/ui.c b/ui.c @@ -13,7 +13,11 @@ #define RULER_TICK_LENGTH 20.0f #define UI_SPLIT_HANDLE_THICK 8.0f -#define UI_REGION_PAD 16.0f +/* TODO(rnp): y_padding seems to not match x_padding */ +#define UI_REGION_PAD 32.0f + +/* TODO(rnp) smooth scroll */ +#define UI_SCROLL_SPEED 12.0f typedef struct { u8 buf[64]; @@ -79,6 +83,7 @@ typedef enum { VT_COMPUTE_STATS_VIEW, VT_COMPUTE_LATEST_STATS_VIEW, VT_SCALE_BAR, + VT_UI_LIST, VT_UI_REGION_SPLIT, } VariableType; @@ -98,13 +103,21 @@ typedef struct { VariableGroupType type; } VariableGroup; +typedef struct { + /* NOTE(rnp): superset of group, group must come first */ + VariableGroup group; + f32 needed_height; + f32 offset; +} UIList; + struct Variable { s8 name; union { void *generic; - VariableGroup group; - RegionSplit region_split; ComputeStatsView compute_stats_view; + RegionSplit region_split; + UIList list; + VariableGroup group; b32 b32; i32 i32; f32 f32; @@ -283,7 +296,7 @@ add_variable(Variable *group, Arena *arena, s8 name, u32 flags, VariableType typ result->parent = group; result->name_width = measure_text(font, name).x; - if (group && group->type == VT_GROUP) { + if (group && (group->type == VT_GROUP || group->type == VT_UI_LIST)) { if (group->u.group.last) group->u.group.last = group->u.group.last->next = result; else group->u.group.last = group->u.group.first = result; @@ -354,7 +367,8 @@ add_beamformer_parameters_view(Variable *parent, BeamformerCtx *ctx) v2 v2_inf = {.x = -F32_INFINITY, .y = F32_INFINITY}; - Variable *result = add_variable_group(parent, &ui->arena, s8("Parameters List"), VG_LIST, ui->font); + Variable *result = add_variable(parent, &ui->arena, s8("Parameters"), 0, VT_UI_LIST, ui->font); + result->u.list.group.type = VG_LIST; add_beamformer_variable_f32(result, &ui->arena, s8("Sampling Frequency:"), s8("[MHz]"), &bp->sampling_frequency, (v2){0}, 1e-6, 0, 0, ui->font); @@ -725,8 +739,6 @@ draw_beamformer_frame_view(BeamformerUI *ui, Arena a, BeamformerFrameView *view, v2 txt_s = measure_text(ui->small_font, s8("-288.8 mm")); - display_rect = shrink_rect_centered(display_rect, (v2){.x = 2 * UI_REGION_PAD, .y = UI_REGION_PAD}); - f32 pad = 1.2 * txt_s.x + RULER_TICK_LENGTH; Rect vr = display_rect; vr.pos.x += 0.5 * ui->small_font.baseSize; @@ -900,15 +912,26 @@ draw_beamformer_variable(BeamformerUI *ui, Arena arena, Variable *var, v2 at, v2 #define LISTING_LINE_PAD 6.0f static void -draw_variable_list(BeamformerUI *ui, Variable *group, Rect r, v2 mouse) +draw_ui_list(BeamformerUI *ui, Variable *ui_list, Rect r, v2 mouse) { - /* TODO(rnp): limit the width of each element so that elements don't overlap */ - ASSERT(group->type == VT_GROUP); + ASSERT(ui_list->type == VT_UI_LIST); + UIList *list = &ui_list->u.list; + + /* TODO(rnp): this should get moved up to draw_variable */ + if (hover_rect(mouse, r, &ui_list->hover_t)) + ui->interaction.hot = ui_list; + + if (list->needed_height - r.size.h < list->offset) + list->offset = list->needed_height - r.size.h; - r = shrink_rect_centered(r, (v2){.x = 2 * UI_REGION_PAD, .y = UI_REGION_PAD}); + if (list->needed_height - r.size.h < 0) + list->offset = 0; - Variable *var = group->u.group.first; - f32 x_off = group->u.group.max_name_width; + r.pos.y -= list->offset; + + f32 start_height = r.size.h; + Variable *var = list->group.first; + f32 x_off = list->group.max_name_width; while (var) { s8 suffix = {0}; v2 at = r.pos; @@ -994,6 +1017,7 @@ draw_variable_list(BeamformerUI *ui, Variable *group, Rect r, v2 mouse) r.pos.y += advance + LISTING_LINE_PAD; r.size.y -= advance + LISTING_LINE_PAD; } + list->needed_height = start_height - r.size.h; } static void @@ -1009,7 +1033,6 @@ draw_compute_stats(BeamformerCtx *ctx, ComputeShaderStats *stats, Arena arena, R Stream buf = stream_alloc(&arena, 64); - r = shrink_rect_centered(r, (v2){.x = 2 * UI_REGION_PAD, .y = UI_REGION_PAD}); v2 pos = r.pos; pos.y += r.size.h; @@ -1124,8 +1147,8 @@ draw_variable(BeamformerUI *ui, Variable *var, Rect draw_rect, v2 mouse) BeginScissorMode(draw_rect.pos.x, draw_rect.pos.y, draw_rect.size.w, draw_rect.size.h); switch (var->type) { - case VT_GROUP: { - draw_variable_list(ui, var, draw_rect, mouse); + case VT_UI_LIST: { + draw_ui_list(ui, var, draw_rect, mouse); } break; case VT_BEAMFORMER_FRAME_VIEW: { BeamformerFrameView *view = var->u.generic; @@ -1273,6 +1296,10 @@ scroll_interaction(Variable *var, f32 delta) scroll_interaction_base(bv->subtype, var->u.generic, delta * bv->params.scroll_scale); ui_store_variable(var, var->u.generic); } break; + case VT_UI_LIST: { + scroll_interaction_base(VT_F32, &var->u.list.offset, UI_SCROLL_SPEED * delta); + var->u.list.offset = MAX(0, var->u.list.offset); + } break; default: scroll_interaction_base(var->type, &var->u, delta); break; } } @@ -1478,6 +1505,9 @@ ui_begin_interact(BeamformerUI *ui, BeamformerInput *input, b32 scroll, b32 mous case VT_B32: is->type = IT_SET; break; case VT_GROUP: is->type = IT_SET; break; case VT_UI_REGION_SPLIT: is->type = IT_DRAG; break; + case VT_UI_LIST: { + if (scroll) is->type = IT_SCROLL; + } break; case VT_BEAMFORMER_VARIABLE: { BeamformerVariable *bv = (BeamformerVariable *)is->hot; if (bv->subtype == VT_B32) { @@ -1637,7 +1667,7 @@ ui_init(BeamformerCtx *ctx, Arena store) ui->scratch_variable = ui->scratch_variables + 0; - Variable *split = ui->regions = add_ui_split(0, &ui->arena, s8("UI Root"), 0.35, + Variable *split = ui->regions = add_ui_split(0, &ui->arena, s8("UI Root"), 0.4, RSD_HORIZONTAL, ui->font); split->u.region_split.left = add_ui_split(split, &ui->arena, s8(""), 0.8, RSD_VERTICAL, ui->font);