From 38a5abae0730c67c24ea787d745b81f9aad0971d Mon Sep 17 00:00:00 2001 From: Pia Baltazar Date: Sun, 12 Jul 2026 19:12:43 -0400 Subject: [PATCH 1/3] Add dynamic_combobox: a combobox with a runtime-populated item list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A combobox port whose choices are discovered by the processor at run time (e.g. the files in a folder, OSC addresses, dataset ids) rather than being fixed at compile time. The port carries an update_items callback that supporting bindings inject and that the object invokes — from any thread — whenever its list changes. Bindings without support leave the callback empty and render a plain combobox from the static fallback range(), so the feature is fully backwards-compatible: no API, ABI or behaviour change for existing objects. avnd::dynamic_items_parameter lets a binding detect such ports. Co-authored-by: Pia Baltazar --- include/avnd/concepts/dynamic_items.hpp | 20 +++++++++++ include/halp/dynamic_combobox.hpp | 46 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 include/avnd/concepts/dynamic_items.hpp create mode 100644 include/halp/dynamic_combobox.hpp diff --git a/include/avnd/concepts/dynamic_items.hpp b/include/avnd/concepts/dynamic_items.hpp new file mode 100644 index 00000000..8f4708be --- /dev/null +++ b/include/avnd/concepts/dynamic_items.hpp @@ -0,0 +1,20 @@ +#pragma once + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include + +#include +#include +#include + +namespace avnd +{ +// enum-ish parameter carrying an update_items callback for runtime item lists. +template +concept dynamic_items_parameter = enum_ish_parameter && requires(T t) { + { + t.update_items + } -> std::convertible_to)>>; +}; +} diff --git a/include/halp/dynamic_combobox.hpp b/include/halp/dynamic_combobox.hpp new file mode 100644 index 00000000..a412b0e1 --- /dev/null +++ b/include/halp/dynamic_combobox.hpp @@ -0,0 +1,46 @@ +#pragma once + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include + +#include +#include +#include +#include +#include + +namespace halp +{ +// Combobox whose items are set at runtime via update_items. Bindings without +// support leave update_items empty and use the static range() fallback. +template +struct dynamic_combobox +{ + enum widget + { + combobox + }; + + struct range + { + std::array values{"-"}; + int init{0}; + }; + + static clang_buggy_consteval auto name() { return std::string_view{lit.value}; } + + int value{0}; + + std::function)> update_items; + + operator int&() noexcept { return value; } + operator const int&() const noexcept { return value; } + auto& operator=(int t) noexcept + { + value = t; + return *this; + } +}; +} From 0a890e9bc75725053ac87028c3049dc50af8c48f Mon Sep 17 00:00:00 2001 From: Pia Baltazar Date: Mon, 13 Jul 2026 13:38:13 -0400 Subject: [PATCH 2/3] Add folder_combobox: a combobox populated from a sibling folder port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A combobox whose items are the files of a sibling folder/path port, listed by the host at edit time and refreshed when the folder changes — populated at document load, without execution. Complements dynamic_combobox (which is pushed by the running object); this pulls from a folder in the UI, matching how file pickers actually need to behave in an editor. Co-authored-by: Pia Baltazar --- include/avnd/concepts/folder_items.hpp | 19 +++++++++++ include/halp/folder_combobox.hpp | 46 ++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 include/avnd/concepts/folder_items.hpp create mode 100644 include/halp/folder_combobox.hpp diff --git a/include/avnd/concepts/folder_items.hpp b/include/avnd/concepts/folder_items.hpp new file mode 100644 index 00000000..51fdf83e --- /dev/null +++ b/include/avnd/concepts/folder_items.hpp @@ -0,0 +1,19 @@ +#pragma once + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include + +#include + +namespace avnd +{ +// A combobox whose items are the files of a sibling folder port, populated by +// the host at edit time. The port exposes folder_port() (the sibling port's +// name) and extensions() (accepted suffixes). +template +concept folder_items_parameter = enum_ish_parameter && requires { + { T::folder_port() } -> std::convertible_to; + { T::extensions() } -> std::convertible_to; +}; +} diff --git a/include/halp/folder_combobox.hpp b/include/halp/folder_combobox.hpp new file mode 100644 index 00000000..11839517 --- /dev/null +++ b/include/halp/folder_combobox.hpp @@ -0,0 +1,46 @@ +#pragma once + +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include +#include + +#include +#include +#include + +namespace halp +{ +// Combobox whose items are the files of a sibling folder port, listed by the +// host at edit time (and refreshed when the folder changes) — no execution +// needed. `folder_port` names the sibling path/folder port; `extensions` is a +// space-separated list of accepted suffixes (empty = all files). +template +struct folder_combobox +{ + enum widget + { + combobox + }; + + struct range + { + std::array values{"-"}; + int init{0}; + }; + + static clang_buggy_consteval auto name() { return std::string_view{lit.value}; } + static clang_buggy_consteval auto folder_port() { return std::string_view{folder.value}; } + static clang_buggy_consteval auto extensions() { return std::string_view{exts.value}; } + + int value{0}; + + operator int&() noexcept { return value; } + operator const int&() const noexcept { return value; } + auto& operator=(int t) noexcept + { + value = t; + return *this; + } +}; +} From 1a7afc677a58cbc7358b7362f07de12a0c9c7409 Mon Sep 17 00:00:00 2001 From: Pia Baltazar Date: Tue, 14 Jul 2026 00:42:54 -0400 Subject: [PATCH 3/3] folder_combobox: add an init file-name template parameter Chains of processes that write then read conventionally-named files rely on default values; keep the initially selected file name as a parameter so it stays selected even while the file does not exist yet. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01DDQaHG5FbEyH9D8VsjEyXe --- include/halp/folder_combobox.hpp | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/include/halp/folder_combobox.hpp b/include/halp/folder_combobox.hpp index 11839517..0dfd7827 100644 --- a/include/halp/folder_combobox.hpp +++ b/include/halp/folder_combobox.hpp @@ -13,9 +13,15 @@ namespace halp { // Combobox whose items are the files of a sibling folder port, listed by the // host at edit time (and refreshed when the folder changes) — no execution -// needed. `folder_port` names the sibling path/folder port; `extensions` is a -// space-separated list of accepted suffixes (empty = all files). -template +// needed. The VALUE is the selected file name (a string), so an object can use +// it directly as a file name. `folder_port` names the sibling path/folder +// port; `extensions` is a space-separated list of accepted suffixes (empty = +// all files); `init` is the initially selected file name — it stays selected +// even while the file does not exist yet, so chains of processes that write +// then read conventionally-named files keep working with default values. +template < + static_string lit, static_string folder = "Folder", static_string exts = "", + static_string init_value = "-"> struct folder_combobox { enum widget @@ -25,21 +31,21 @@ struct folder_combobox struct range { - std::array values{"-"}; - int init{0}; + std::array values{init_value.value}; + std::string_view init{init_value.value}; }; static clang_buggy_consteval auto name() { return std::string_view{lit.value}; } static clang_buggy_consteval auto folder_port() { return std::string_view{folder.value}; } static clang_buggy_consteval auto extensions() { return std::string_view{exts.value}; } - int value{0}; + std::string value{}; - operator int&() noexcept { return value; } - operator const int&() const noexcept { return value; } - auto& operator=(int t) noexcept + operator std::string&() noexcept { return value; } + operator const std::string&() const noexcept { return value; } + auto& operator=(std::string t) noexcept { - value = t; + value = std::move(t); return *this; } };