From 5063346544715010b8c7cbbcbb1cea2e0764bec6 Mon Sep 17 00:00:00 2001 From: Pia Baltazar Date: Mon, 13 Jul 2026 06:54:23 -0400 Subject: [PATCH] avnd ui: resolve file-path templates before syncing them to custom items File-chooser port values are stored in the document as path templates (:..., :..., or document-relative). Score's own file widgets resolve them via score::locateFilePath, but the avnd layout builder pushed the raw template string into custom ui items' `value`, so an add-on widget bound to a soundfile/file/folder port received a path it could not use (e.g. a waveform widget that decodes the file in edit mode could never find it after the document moved or used project-relative paths). Resolve through score::locateFilePath in setupControl, both for the initial sync and in the valueChanged connections, whenever the inlet is a FileChooserBase or FolderChooser and the value is a non-empty string. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01AvD2PFHZtW6pfsh3gGhayg --- .../score-plugin-avnd/Crousti/Layer.hpp | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/plugins/score-plugin-avnd/Crousti/Layer.hpp b/src/plugins/score-plugin-avnd/Crousti/Layer.hpp index 9313a5b905..0ec4b9063c 100644 --- a/src/plugins/score-plugin-avnd/Crousti/Layer.hpp +++ b/src/plugins/score-plugin-avnd/Crousti/Layer.hpp @@ -7,11 +7,14 @@ #include #include +#include + #include #include #include #include #include +#include #include #include @@ -140,6 +143,22 @@ struct LayoutBuilder final : Process::LayoutBuilderBase const Process::ControlLayout& lay, Item& item) = delete; // TODO + // File paths are stored in the document as templates (:..., + // :..., or document-relative); resolve them so the ui items + // always receive a usable absolute path, like the score-side file + // widgets do. + static ossia::value resolveFilePath( + const ossia::value& v, Process::ControlInlet* inl, + const score::DocumentContext& ctx) noexcept + { + if(qobject_cast(inl) + || qobject_cast(inl)) + if(auto str = v.target(); str && !str->empty()) + return score::locateFilePath(QString::fromStdString(*str), ctx) + .toStdString(); + return v; + } + template void setupControl( QGraphicsItem* parent, Process::ControlInlet* inl, @@ -149,14 +168,16 @@ struct LayoutBuilder final : Process::LayoutBuilderBase { using avnd_port_type = pmf_member_type_t; avnd_port_type p; - oscr::from_ossia_value(p, inl->value(), item.value); + oscr::from_ossia_value(p, resolveFilePath(inl->value(), inl, doc), item.value); if constexpr(requires { rootUi->on_control_update(); }) { QObject::connect( inl, &Process::ControlInlet::valueChanged, &context, - [rui = rootUi, layout = this->layout, &item](const ossia::value& v) { + [rui = rootUi, layout = this->layout, &item, inl, + &ctx = static_cast(this->doc)]( + const ossia::value& v) { avnd_port_type p; - oscr::from_ossia_value(p, v, item.value); + oscr::from_ossia_value(p, resolveFilePath(v, inl, ctx), item.value); rui->on_control_update(); layout->update(); @@ -166,9 +187,11 @@ struct LayoutBuilder final : Process::LayoutBuilderBase { QObject::connect( inl, &Process::ControlInlet::valueChanged, &context, - [layout = this->layout, &item](const ossia::value& v) { + [layout = this->layout, &item, inl, + &ctx = static_cast(this->doc)]( + const ossia::value& v) { avnd_port_type p; - oscr::from_ossia_value(p, v, item.value); + oscr::from_ossia_value(p, resolveFilePath(v, inl, ctx), item.value); layout->update(); }); }