From 00591b6e4eb7ae61fdfb2a1b5d285fcbb1b40fcd Mon Sep 17 00:00:00 2001 From: Pixelplanet Date: Thu, 15 Oct 2026 08:19:06 +0200 Subject: [PATCH] Track/language selection as pick-lists (sub-menus) with greyed-out rows when there is nothing to choose --- src/app/app.cpp | 15 ++++-- src/gfx/vulkan_renderer.cpp | 15 ++++-- src/gfx/vulkan_renderer.hpp | 4 +- src/ui/settings_menu.cpp | 91 +++++++++++++++++++++++++++---------- src/ui/settings_menu.hpp | 11 +++-- 5 files changed, 99 insertions(+), 37 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index 6692b06..a814165 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -457,12 +457,17 @@ int App::run() { // Settings panel overlay if (settings_.isOpen()) { std::vector sRows; + std::vector sEnabled; sRows.reserve(settings_.rows().size()); + sEnabled.reserve(settings_.rows().size()); for (const auto& r : settings_.rows()) { - sRows.push_back(r.label + " : " + r.value); + sRows.push_back(r.value.empty() ? r.label + : (r.label + " : " + r.value)); + sEnabled.push_back(r.enabled ? 1 : 0); } renderer_.setSettings(true, settings_.title(), sRows, - settings_.selected(), settings_.status()); + settings_.selected(), settings_.status(), + sEnabled); settingsOpen = true; } else { renderer_.setSettings(false, "", {}, 0, ""); @@ -557,10 +562,10 @@ int App::run() { renderer_.adjustScreenDistance(settings_.screenDistance() - 3.0f); } #ifdef PIXELVR_HAVE_MEDIA - else if (act == SettingsMenu::Action::CycleVideoStream || - act == SettingsMenu::Action::CycleAudioStream) { + else if (act == SettingsMenu::Action::PickVideoStream || + act == SettingsMenu::Action::PickAudioStream) { switchTracks(false); - } else if (act == SettingsMenu::Action::CycleLanguage) { + } else if (act == SettingsMenu::Action::PickLanguage) { switchTracks(true); } #endif diff --git a/src/gfx/vulkan_renderer.cpp b/src/gfx/vulkan_renderer.cpp index 3534270..b91276d 100644 --- a/src/gfx/vulkan_renderer.cpp +++ b/src/gfx/vulkan_renderer.cpp @@ -838,12 +838,14 @@ void VulkanRenderer::scrollBrowser(int deltaRows) { void VulkanRenderer::setSettings(bool visible, const std::string& title, const std::vector& rows, int selected, - const std::string& status) { + const std::string& status, + const std::vector& enabled) { settingsVisible_ = visible; settingsTitle_ = title; settingsRows_ = rows; settingsSelected_ = selected; settingsStatus_ = status; + settingsEnabled_ = enabled; } void VulkanRenderer::setStats(bool visible, const std::vector& lines) { @@ -1624,7 +1626,10 @@ void VulkanRenderer::renderView(uint32_t viewIndex, uint32_t imageIndex, const int total = static_cast(settingsRows_.size()); for (int i = 0; i < total; ++i) { const float ry = panelTop - 0.2f - i * rowH; - const bool hovered = (i == settingsHovered_); + const bool en = settingsEnabled_.empty() || + (i < static_cast(settingsEnabled_.size()) && + settingsEnabled_[i] != 0); + const bool hovered = (i == settingsHovered_) && en; const bool selected = (i == settingsSelected_); if (hovered || selected) { const float* rowBg = hovered ? hlCol : selBg; @@ -1641,6 +1646,7 @@ void VulkanRenderer::renderView(uint32_t viewIndex, uint32_t imageIndex, const float white2[4] = {0.96f, 0.96f, 0.96f, 1.0f}; const float dim[4] = {0.55f, 0.7f, 0.9f, 1.0f}; const float cyan[4] = {0.35f, 0.75f, 1.0f, 1.0f}; + const float disabledCol[4] = {0.40f, 0.43f, 0.48f, 1.0f}; auto drawString = [&](float x, float baseline, float scale, const float col[4], const std::string& s) { float penX = x; @@ -1673,7 +1679,10 @@ void VulkanRenderer::renderView(uint32_t viewIndex, uint32_t imageIndex, settingsTitle_.substr(0, 42)); for (int i = 0; i < total; ++i) { const float ry = panelTop - 0.2f - i * rowH; - drawString(-panelW + 0.05f, ry, sc, white2, + const bool en = settingsEnabled_.empty() || + (i < static_cast(settingsEnabled_.size()) && + settingsEnabled_[i] != 0); + drawString(-panelW + 0.05f, ry, sc, en ? white2 : disabledCol, settingsRows_[static_cast(i)].substr(0, 46)); } if (!settingsStatus_.empty()) { diff --git a/src/gfx/vulkan_renderer.hpp b/src/gfx/vulkan_renderer.hpp index d75b7b3..8e896d3 100644 --- a/src/gfx/vulkan_renderer.hpp +++ b/src/gfx/vulkan_renderer.hpp @@ -165,7 +165,8 @@ public: // Settings overlay panel (re-uses panel & pointer interaction) void setSettings(bool visible, const std::string& title, const std::vector& rows, int selected, - const std::string& status); + const std::string& status, + const std::vector& enabled = {}); bool settingsVisible() const { return settingsVisible_; } int settingsRow() const { return settingsRow_; } int settingsHovered() const { return settingsHovered_; } @@ -279,6 +280,7 @@ private: std::string settingsTitle_; std::string settingsStatus_; std::vector settingsRows_; + std::vector settingsEnabled_; // per-row: 0 = greyed/disabled int settingsSelected_ = 0; int settingsHovered_ = -1; int settingsRow_ = -1; diff --git a/src/ui/settings_menu.cpp b/src/ui/settings_menu.cpp index 5e02c02..48f701c 100644 --- a/src/ui/settings_menu.cpp +++ b/src/ui/settings_menu.cpp @@ -109,27 +109,57 @@ void SettingsMenu::refresh() { Action::ToggleModels}); } else if (section_ == 2) { title_ = "Audio / Video Tracks"; - const std::string vLabel = - videoStreams_.empty() - ? "(none)" - : videoStreams_[std::min(videoSel_, - videoStreams_.size() - 1)] - .second; - const std::string aLabel = - audioStreams_.empty() - ? "(none)" - : audioStreams_[std::min(audioSel_, - audioStreams_.size() - 1)] - .second; - rows_.push_back({"Video Track", vLabel, Action::CycleVideoStream}); - rows_.push_back({"Audio Track", aLabel, Action::CycleAudioStream}); + Row v{"Video Track", + videoStreams_.empty() + ? "(none)" + : videoStreams_[std::min( + videoSel_, videoStreams_.size() - 1)].second, + Action::EnterVideoList}; + v.enabled = videoStreams_.size() > 1; // nothing to pick with 0/1 track + if (!v.enabled) v.action = Action::None; + rows_.push_back(v); + Row a{"Audio Track", + audioStreams_.empty() + ? "(none)" + : audioStreams_[std::min( + audioSel_, audioStreams_.size() - 1)].second, + Action::EnterAudioList}; + a.enabled = audioStreams_.size() > 1; + if (!a.enabled) a.action = Action::None; + rows_.push_back(a); rows_.push_back({"Preferred Audio Language", kLangNames[audioLangIdx_ % kLangCount], - Action::CycleLanguage}); - } else { + Action::EnterLangList}); + } else if (section_ == 3) { title_ = "System & Debug"; rows_.push_back({"Debug Statistics", showStats_ ? "On" : "Off", Action::ToggleStats}); + } else if (section_ == 10) { + title_ = "Select Video Track"; + for (std::size_t i = 0; i < videoStreams_.size(); ++i) { + Row r{videoStreams_[i].second, + static_cast(i) == videoSel_ ? "<" : "", + Action::PickVideoStream}; + r.data = static_cast(i); + rows_.push_back(r); + } + } else if (section_ == 11) { + title_ = "Select Audio Track"; + for (std::size_t i = 0; i < audioStreams_.size(); ++i) { + Row r{audioStreams_[i].second, + static_cast(i) == audioSel_ ? "<" : "", + Action::PickAudioStream}; + r.data = static_cast(i); + rows_.push_back(r); + } + } else { // section_ == 12: preferred-language list + title_ = "Preferred Audio Language"; + for (int i = 0; i < kLangCount; ++i) { + Row r{kLangNames[i], i == audioLangIdx_ ? "<" : "", + Action::PickLanguage}; + r.data = i; + rows_.push_back(r); + } } rows_.push_back({"< Back", "", Action::Back}); } @@ -144,7 +174,14 @@ SettingsMenu::Action SettingsMenu::activate() { case Action::EnterControls: section_ = 1; selected_ = 0; refresh(); break; case Action::EnterStreams: section_ = 2; selected_ = 0; refresh(); break; case Action::EnterSystem: section_ = 3; selected_ = 0; refresh(); break; - case Action::Back: section_ = -1; selected_ = 0; refresh(); break; + case Action::EnterVideoList: section_ = 10; selected_ = 0; refresh(); break; + case Action::EnterAudioList: section_ = 11; selected_ = 0; refresh(); break; + case Action::EnterLangList: section_ = 12; selected_ = 0; refresh(); break; + case Action::Back: + section_ = (section_ >= 10) ? 2 : -1; // list -> Tracks; else -> root + selected_ = 0; + refresh(); + break; case Action::CyclePlayBinding: bindPlayIdx_ = (bindPlayIdx_ + 1) % 4; saveConfig(); @@ -196,19 +233,23 @@ SettingsMenu::Action SettingsMenu::activate() { saveConfig(); refresh(); break; - case Action::CycleVideoStream: - if (!videoStreams_.empty()) - videoSel_ = (videoSel_ + 1) % static_cast(videoStreams_.size()); + case Action::PickVideoStream: + videoSel_ = rows_[selected_].data; + section_ = 2; + selected_ = 0; refresh(); break; - case Action::CycleAudioStream: - if (!audioStreams_.empty()) - audioSel_ = (audioSel_ + 1) % static_cast(audioStreams_.size()); + case Action::PickAudioStream: + audioSel_ = rows_[selected_].data; + section_ = 2; + selected_ = 0; refresh(); break; - case Action::CycleLanguage: - audioLangIdx_ = (audioLangIdx_ + 1) % kLangCount; + case Action::PickLanguage: + audioLangIdx_ = rows_[selected_].data; saveConfig(); + section_ = 2; + selected_ = 0; refresh(); break; case Action::RecenterScreen: diff --git a/src/ui/settings_menu.hpp b/src/ui/settings_menu.hpp index f7af42a..dfe905b 100644 --- a/src/ui/settings_menu.hpp +++ b/src/ui/settings_menu.hpp @@ -25,9 +25,12 @@ public: ToggleModels, ToggleStats, CycleDistance, - CycleVideoStream, - CycleAudioStream, - CycleLanguage, + EnterVideoList, + EnterAudioList, + EnterLangList, + PickVideoStream, + PickAudioStream, + PickLanguage, RecenterScreen, Close }; @@ -36,6 +39,8 @@ public: std::string label; std::string value; Action action = Action::None; + bool enabled = true; // disabled rows render greyed and do nothing + int data = -1; // payload: stream position or language index }; SettingsMenu();