Skip to content

Commit 2c693fe

Browse files
author
Evgeni Raikhel
committed
Polish MinZ editor UI and generalize the composite-option walkthrough
Editor UI: - Make the disabled-state dim more pronounced. - Disparity Shift/Threshold sliders gain a pencil-icon toggle between the slider and a centered, color-matched manual-entry text box (ImGui's native Ctrl+Click/double-click text-input proved unreliable here), plus Left/Right arrow-key nudging once the slider has focus. Both modes call touch() while active so the debounce timer freezes during manual edits instead of expiring mid-entry. - Add a "Reset to Default" button reusing the same debounced-commit pipeline as every other field edit, later hidden behind a small "..." marker in the box's bottom-right corner - revealed only on hover nearby, and drawn on the same line as the last field rather than reserving a row of its own, so it may partially overlap that field when revealed. - Fix: changing the Downscale Ratio radio buttons via arrow-key navigation didn't start the auto-commit debounce timer the way a mouse click did - a discrete edit's touch()+finalize() land in the same frame as the deadline-collapsing focus-loss shortcut, which couldn't yet tell a fresh discrete edit apart from focus genuinely leaving the group; suppressed for the one frame finalize() just ran on. - Keyboard-driven edits (arrow-key slider nudges, and radio-button changes via keyboard/gamepad nav) now schedule their auto-commit 0.1s out instead of the usual 1.7s, since they already land on a known, deliberate value one step at a time and don't need the same give-me-a-moment-to-change-my-mind pause a mouse edit gets. Mouse clicks/drags on the same controls are unaffected. Examples: - Generalize the composite-option walkthrough to sweep every embedded filter/id on the device rather than just Temporal Filter DPP, with dual raw-bytes + typed views and rectangular hex-grid wrapping for long buffers. - Add a pure-C99 demo of the same MinZ get/set walkthrough through the raw C API (no exceptions, templates, or RAII), verified end-to-end on both Windows and Linux.
1 parent 0cfbc97 commit 2c693fe

8 files changed

Lines changed: 966 additions & 309 deletions

File tree

common/composite-control-editor.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,23 @@ namespace rs2
107107
}
108108

109109
// Call once a field's edit is finalized (slider released, or immediately after a
110-
// checkbox/radio click). Schedules the real auto-commit commit_delay seconds out.
111-
void finalize() { _commit_deadline = ImGui::GetTime() + commit_delay; }
110+
// checkbox/radio click). Schedules the auto-commit out by commit_delay seconds, or by
111+
// the much shorter fast_commit_delay when use_fast_delay is set - the caller's own way
112+
// of saying "this particular edit came from a keyboard arrow-key nudge, not a mouse
113+
// click/drag," which should feel closer to immediate feedback than the deliberate,
114+
// give-me-a-moment-to-change-my-mind pause a mouse edit gets.
115+
void finalize( bool use_fast_delay = false )
116+
{
117+
_commit_deadline = ImGui::GetTime() + ( use_fast_delay ? fast_commit_delay : commit_delay );
118+
// A discrete edit (radio/checkbox click, keyboard arrow-key nudge) calls touch()+
119+
// finalize() together, synchronously, within the SAME frame as the
120+
// end_frame_and_maybe_commit() call below that just set this deadline - unlike a
121+
// mouse drag, which spans several frames with the widget genuinely active in
122+
// between, giving the focus-loss shortcut no chance to fire on that exact frame.
123+
// Suppress it for this one frame so it can't immediately collapse the deadline it
124+
// was never meant to see yet.
125+
_just_finalized = true;
126+
}
112127

113128
// Side-effect-free readout of the same progress end_frame_and_maybe_commit() animates
114129
// with: false if nothing is pending, true with `progress` in [0,1] (0 = just
@@ -185,9 +200,11 @@ namespace rs2
185200
// normal quiet gap between finishing one field and touching the next one in THIS
186201
// group, and must NOT cut the wait short). When that happens, don't make the user
187202
// wait out the rest of the countdown - finish it now, same as if it had lapsed
188-
// naturally.
189-
if( _dirty && ! any_field_active_this_frame && ImGui::IsAnyItemActive() )
203+
// naturally. Skipped on the one frame finalize() just ran on (see its comment) - a
204+
// discrete edit's own deadline must survive at least until the NEXT frame.
205+
if( _dirty && ! any_field_active_this_frame && ImGui::IsAnyItemActive() && ! _just_finalized )
190206
_commit_deadline = ImGui::GetTime();
207+
_just_finalized = false;
191208

192209
// Fires once the countdown elapses quietly - checked every frame, so any fresh
193210
// touch() (which re-parks the deadline at +infinity) naturally defers this for as
@@ -212,8 +229,10 @@ namespace rs2
212229
private:
213230
bool _dirty = false;
214231
double _commit_deadline = std::numeric_limits< double >::max();
232+
bool _just_finalized = false;
215233

216234
static constexpr double commit_delay = 1.7; // seconds of quiet before auto-sending
235+
static constexpr double fast_commit_delay = 0.1; // ditto, for keyboard arrow-key nudges
217236
static constexpr float border_start_scale = 4.0f; // 400% of normal width, right after an edit
218237
static constexpr float border_end_scale = 2.5f; // 250% of normal width, right before commit
219238
};

common/embedded-filter-model.cpp

Lines changed: 257 additions & 20 deletions
Large diffs are not rendered by default.

common/embedded-filter-model.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,5 +99,14 @@ namespace rs2
9999
// other multi-param composite option can get the same touch/fade/reset/commit behavior
100100
// by holding its own composite_control_editor<its-struct-type> the same way.
101101
composite_control_editor< rs2_minz_control > _minz_editor;
102+
103+
// Per-field manual-entry toggle state for the Disparity Shift / Threshold sliders (see
104+
// draw_minz_control_editor()) - mirrors option_model's own edit_mode/edit_value pattern
105+
// (common/option-model.cpp) rather than relying on ImGui's native SliderInt Ctrl+Click/
106+
// double-click text-input, which turned out not to be reliably discoverable/usable here.
107+
bool _minz_shift_edit_mode = false;
108+
std::string _minz_shift_edit_buf;
109+
bool _minz_threshold_edit_mode = false;
110+
std::string _minz_threshold_edit_buf;
102111
};
103112
}

examples/composite-option-walkthrough/CMakeLists.txt

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@ cmake_minimum_required(VERSION 3.10)
55
project(RealsenseExamplesCompositeOptionWalkthrough)
66

77
# PROTOTYPE / DEMO reference sample: a "how do I use the composite-option API" walkthrough,
8-
# exercising the FULL surface (enumeration, set, get, get_range, metadata queries) against a fake
9-
# in-memory librealsense::composite_option_interface implementation standing in for real HKR/D555
10-
# hardware (librealsense::composite_xu_option, src/ds/composite-xu-option.h), which is not present
11-
# on this dev machine. See rs-hkr-temporal-filter-dpp-mock for the companion round-trip/atomicity
12-
# proof; this sample is meant to read as documentation for other engineers. Drives everything
13-
# through the REAL PUBLIC API (rs2::options::get_supported_composite_options()/
14-
# set_composite_option()/get_composite_option()/get_composite_option_range()/
15-
# supports_composite_option()/is_composite_option_read_only()/get_composite_option_description()),
8+
# exercising the FULL surface (enumeration, get, read-modify-write set, get_range, metadata
9+
# queries) against every composite option found on every embedded filter of every depth sensor of
10+
# every connected device - no fake/mock transport. Each composite option id found gets its own
11+
# try/catch, so a control that's registered but non-functional on this device/FW (e.g.
12+
# RS2_COMPOSITE_OPTION_HKR_TEMPORAL_FILTER_DPP's ctrl_id not being validated against real
13+
# firmware, see src/ds/d500/d500-factory.cpp's rs555_device comment) is reported per-id rather
14+
# than aborting the whole walkthrough - see rs-composite-option-walkthrough.cpp for the full
15+
# sequence and per-id dispatch. Drives everything through the REAL PUBLIC API
16+
# (rs2::options::get_supported_composite_options()/set_composite_option()/get_composite_option()/
17+
# get_composite_option_range()/is_composite_option_read_only()/get_composite_option_description()),
1618
# so it links against realsense2 like any other example.
1719
add_executable(rs-composite-option-walkthrough
1820
rs-composite-option-walkthrough.cpp
@@ -22,12 +24,24 @@ target_link_libraries(rs-composite-option-walkthrough PRIVATE ${LRS_TARGET})
2224
set_target_properties (rs-composite-option-walkthrough PROPERTIES FOLDER Examples)
2325
install(TARGETS rs-composite-option-walkthrough RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
2426

25-
# PROTOTYPE / DEMO: HKR MinZ Control, one call at a time, against a REAL connected device (no
26-
# fake transport) - see rs-minz-control-walkthrough.cpp.
27+
# PROTOTYPE / DEMO: sweeps every connected device's depth sensor(s), enumerates whichever
28+
# composite options each one supports, and prints the current value of each - against REAL
29+
# connected devices (no fake transport). See rs-minz-control-walkthrough.cpp.
2730
add_executable(rs-minz-control-walkthrough
2831
rs-minz-control-walkthrough.cpp
2932
)
3033
set_property(TARGET rs-minz-control-walkthrough PROPERTY CXX_STANDARD 14)
3134
target_link_libraries(rs-minz-control-walkthrough PRIVATE ${LRS_TARGET})
3235
set_target_properties (rs-minz-control-walkthrough PROPERTIES FOLDER Examples)
3336
install(TARGETS rs-minz-control-walkthrough RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
37+
38+
# PROTOTYPE / DEMO: same MinZ get/set walkthrough, through the raw C API instead of the C++
39+
# wrapper - no exceptions, no templates, manual struct casts and buffer frees. See
40+
# rs-composite-option-c99.c.
41+
add_executable(rs-composite-option-c99
42+
rs-composite-option-c99.c
43+
)
44+
set_property(TARGET rs-composite-option-c99 PROPERTY C_STANDARD 99)
45+
target_link_libraries(rs-composite-option-c99 PRIVATE ${LRS_TARGET})
46+
set_target_properties (rs-composite-option-c99 PROPERTIES FOLDER Examples)
47+
install(TARGETS rs-composite-option-c99 RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/* License: Apache 2.0. See LICENSE file in root directory. */
2+
/* Copyright(c) 2026 RealSense, Inc. All Rights Reserved. */
3+
4+
/* C99 version of the composite-option walkthrough - same MinZ get/set, through the raw C API:
5+
no exceptions (check rs2_error* after every call), no templates (manual struct/byte casts),
6+
no RAII (every list/device/sensor/filter/buffer freed by hand). Main success scenario only. */
7+
8+
#include <librealsense2/rs.h>
9+
#include <librealsense2/h/rs_hkr_minz_control.h>
10+
11+
#include <stdio.h>
12+
#include <stdlib.h>
13+
#include <string.h>
14+
15+
static void check_error( rs2_error * e )
16+
{
17+
if( e )
18+
{
19+
printf( "error: %s\n", rs2_get_error_message( e ) );
20+
rs2_free_error( e );
21+
exit( 1 );
22+
}
23+
}
24+
25+
int main( void )
26+
{
27+
rs2_error * e = NULL;
28+
29+
rs2_context * ctx = rs2_create_context( RS2_API_VERSION, &e );
30+
check_error( e );
31+
32+
rs2_device_list * devices = rs2_query_devices( ctx, &e );
33+
check_error( e );
34+
int device_count = rs2_get_device_count( devices, &e );
35+
check_error( e );
36+
printf( "Found %d device(s)\n", device_count );
37+
if( device_count == 0 )
38+
return 0;
39+
40+
rs2_device * dev = rs2_create_device( devices, 0, &e );
41+
check_error( e );
42+
43+
rs2_sensor_list * sensors = rs2_query_sensors( dev, &e );
44+
check_error( e );
45+
int sensor_count = rs2_get_sensors_count( sensors, &e );
46+
check_error( e );
47+
48+
for( int i = 0; i < sensor_count; ++i )
49+
{
50+
rs2_sensor * sensor = rs2_create_sensor( sensors, i, &e );
51+
check_error( e );
52+
53+
if( ! rs2_is_sensor_extendable_to( sensor, RS2_EXTENSION_DEPTH_SENSOR, &e ) )
54+
{
55+
check_error( e );
56+
rs2_delete_sensor( sensor );
57+
continue;
58+
}
59+
check_error( e );
60+
61+
rs2_embedded_filter_list * filters = rs2_query_embedded_filters( sensor, &e );
62+
check_error( e );
63+
int filter_count = rs2_get_embedded_filters_count( filters, &e );
64+
check_error( e );
65+
66+
for( int f = 0; f < filter_count; ++f )
67+
{
68+
rs2_embedded_filter * filter = rs2_create_embedded_filter( filters, f, &e );
69+
check_error( e );
70+
71+
/* rs2_embedded_filter is-a rs2_options in the underlying C++ implementation
72+
(see struct rs2_embedded_filter : public rs2_options in src/rs.cpp) - every
73+
composite-option C function takes an rs2_options*, so this cast is valid. */
74+
const rs2_options * opts = ( const rs2_options * )filter;
75+
76+
if( rs2_supports_composite_option( opts, RS2_COMPOSITE_OPTION_HKR_MINZ_CONTROL, &e ) )
77+
{
78+
check_error( e );
79+
80+
/* Get - raw bytes, application-side cast (no get_composite_option_as<T>() here). */
81+
const rs2_raw_data_buffer * raw = rs2_get_composite_option(
82+
opts, RS2_COMPOSITE_OPTION_HKR_MINZ_CONTROL, &e );
83+
check_error( e );
84+
int size = rs2_get_raw_data_size( raw, &e );
85+
check_error( e );
86+
if( (size_t)size != sizeof( rs2_minz_control ) )
87+
{
88+
printf( "unexpected payload size: %d\n", size );
89+
exit( 1 );
90+
}
91+
const unsigned char * bytes = rs2_get_raw_data( raw, &e );
92+
check_error( e );
93+
94+
rs2_minz_control current;
95+
memcpy( &current, bytes, sizeof( current ) );
96+
rs2_delete_raw_data( raw );
97+
98+
printf( "Get: enable=%d downscale_ratio=%d disparity_shift=%d threshold=%d threshold_mode=%d\n",
99+
current.enable, current.downscale_ratio, current.disparity_shift,
100+
current.threshold, current.threshold_mode );
101+
102+
/* Set - read-modify-write, toggle enable, whole struct sent atomically. */
103+
rs2_minz_control cfg = current;
104+
cfg.enable = ! cfg.enable;
105+
rs2_set_composite_option( opts, RS2_COMPOSITE_OPTION_HKR_MINZ_CONTROL, &cfg, sizeof( cfg ), &e );
106+
check_error( e );
107+
printf( "Set: enable=%d\n", cfg.enable );
108+
109+
/* Get again to confirm. */
110+
raw = rs2_get_composite_option( opts, RS2_COMPOSITE_OPTION_HKR_MINZ_CONTROL, &e );
111+
check_error( e );
112+
bytes = rs2_get_raw_data( raw, &e );
113+
check_error( e );
114+
rs2_minz_control after;
115+
memcpy( &after, bytes, sizeof( after ) );
116+
rs2_delete_raw_data( raw );
117+
118+
printf( "Get (after): enable=%d downscale_ratio=%d disparity_shift=%d threshold=%d threshold_mode=%d\n",
119+
after.enable, after.downscale_ratio, after.disparity_shift,
120+
after.threshold, after.threshold_mode );
121+
printf( "%s\n", after.enable == cfg.enable ? "matches what was sent" : "differs" );
122+
}
123+
124+
rs2_delete_embedded_filter( filter );
125+
}
126+
127+
rs2_delete_embedded_filter_list( filters );
128+
rs2_delete_sensor( sensor );
129+
}
130+
131+
rs2_delete_sensor_list( sensors );
132+
rs2_delete_device( dev );
133+
rs2_delete_device_list( devices );
134+
rs2_delete_context( ctx );
135+
return 0;
136+
}

0 commit comments

Comments
 (0)