From 09dbc5c84e5070848feb52ae1633aa30a53f7784 Mon Sep 17 00:00:00 2001 From: Bruno Herbelin Date: Sat, 12 Aug 2023 20:47:26 +0200 Subject: [PATCH] Improve UX List of New source type to insert New icons for inserted source panel. Merged loopback into connected list. Removed 'internal' new source. --- rsc/images/icons.dds | Bin 1638528 -> 1638528 bytes src/ImGuiToolkit.cpp | 22 +++++++----- src/ImGuiToolkit.h | 2 +- src/ImGuiVisitor.cpp | 2 +- src/RenderSource.cpp | 2 +- src/UserInterfaceManager.cpp | 64 ++++++++--------------------------- src/UserInterfaceManager.h | 1 - 7 files changed, 31 insertions(+), 62 deletions(-) diff --git a/rsc/images/icons.dds b/rsc/images/icons.dds index 3d4d75e7c1ecf55c0b5e39f4aef3f1a311e58a69..0e1bedc6d8ce3603a60a3e6fffeeb1525253d287 100644 GIT binary patch delta 5141 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 diff --git a/src/ImGuiToolkit.cpp b/src/ImGuiToolkit.cpp index 9c88edf..a95cb87 100644 --- a/src/ImGuiToolkit.cpp +++ b/src/ImGuiToolkit.cpp @@ -541,9 +541,9 @@ bool ImGuiToolkit::ComboIcon (const char* label, int* current_item, std::vector< if ( ImGui::BeginCombo( label, text_buf, ImGuiComboFlags_None) ) { for (int p = 0; p < (int) items.size(); ++p){ ImGui::PushID((void*)(intptr_t)p); - if (ImGuiToolkit::SelectableIcon( "", - std::get<0>( items.at(p) ), + if (ImGuiToolkit::SelectableIcon( std::get<0>( items.at(p) ), std::get<1>( items.at(p) ), + "", p == *current_item) ) { *current_item = p; ret = true; @@ -560,9 +560,9 @@ bool ImGuiToolkit::ComboIcon (const char* label, int* current_item, std::vector< if ( ImGui::BeginCombo( label, text_buf, ImGuiComboFlags_None) ) { for (int p = 0; p < (int) items.size(); ++p){ ImGui::PushID((void*)(intptr_t)p); - if (ImGuiToolkit::SelectableIcon( std::get<2>( items.at(p) ).c_str(), - std::get<0>( items.at(p) ), + if (ImGuiToolkit::SelectableIcon( std::get<0>( items.at(p) ), std::get<1>( items.at(p) ), + std::get<2>( items.at(p) ).c_str(), p == *current_item) ) { *current_item = p; ret = true; @@ -579,7 +579,7 @@ bool ImGuiToolkit::ComboIcon (const char* label, int* current_item, std::vector< return ret; } -bool ImGuiToolkit::SelectableIcon(const char* label, int i, int j, bool selected) +bool ImGuiToolkit::SelectableIcon(int i, int j, const char* label, bool selected, const ImVec2 &size_arg) { ImGuiContext& g = *GImGui; ImVec2 draw_pos = ImGui::GetCursorScreenPos() - g.Style.FramePadding * 0.5; @@ -588,15 +588,19 @@ bool ImGuiToolkit::SelectableIcon(const char* label, int i, int j, bool selected char space_buf[] = " "; const ImVec2 space_size = ImGui::CalcTextSize(" ", NULL); const int space_num = static_cast( ceil(g.FontSize / space_size.x) ); - space_buf[space_num]='\0'; + space_buf[space_num+1]='\0'; char text_buf[256]; - ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%s %s", space_buf, label); + ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%s%s", space_buf, label); // draw menu item - bool ret = ImGui::Selectable(text_buf, selected); + bool ret = ImGui::Selectable(text_buf, selected, ImGuiSelectableFlags_None, size_arg); - // overlay of icon on top of first item + // center icon vertically + draw_pos.y += size_arg.y > 0 ? (size_arg.y - space_size.y) * 0.5 : 0.0; + draw_pos.x += size_arg.x > 0 ? (size_arg.x - g.FontSize) * 0.5 : 0.0; + + // overlay of icon on top of first item _drawIcon(draw_pos, i, j); return ret; diff --git a/src/ImGuiToolkit.h b/src/ImGuiToolkit.h index 4670c56..7332881 100644 --- a/src/ImGuiToolkit.h +++ b/src/ImGuiToolkit.h @@ -28,7 +28,7 @@ namespace ImGuiToolkit bool ButtonIconToggle (int i, int j, int i_toggle, int j_toggle, bool* toggle, const char *tooltip = nullptr); bool ButtonIconMultistate (std::vector > icons, int* state, std::vector tooltips); bool MenuItemIcon (int i, int j, const char* label, const char* shortcut = nullptr, bool selected = false, bool enabled = true); - bool SelectableIcon(const char* label, int i, int j, bool selected = false); + bool SelectableIcon(int i, int j, const char* label, bool selected, const ImVec2& size_arg = ImVec2(0,0)); bool ComboIcon (const char* label, int* current_item, std::vector > items, bool tooltiptext = false); // buttons diff --git a/src/ImGuiVisitor.cpp b/src/ImGuiVisitor.cpp index 22e6f65..927e454 100644 --- a/src/ImGuiVisitor.cpp +++ b/src/ImGuiVisitor.cpp @@ -923,7 +923,7 @@ void ImGuiVisitor::visit (RenderSource& s) } // icon to open output view ImGui::SetCursorPos(top); - if (ImGuiToolkit::IconButton(ICON_FA_LAPTOP, "Show Output")) + if (ImGuiToolkit::IconButton(ICON_FA_LAPTOP, "Open Display")) Settings::application.widget.preview = true; } else diff --git a/src/RenderSource.cpp b/src/RenderSource.cpp index 2edc4de..f3fd649 100644 --- a/src/RenderSource.cpp +++ b/src/RenderSource.cpp @@ -175,5 +175,5 @@ glm::ivec2 RenderSource::icon() const std::string RenderSource::info() const { - return "Rendering Output"; + return "Display loopback"; } diff --git a/src/UserInterfaceManager.cpp b/src/UserInterfaceManager.cpp index f9e69ea..4f77b0c 100644 --- a/src/UserInterfaceManager.cpp +++ b/src/UserInterfaceManager.cpp @@ -68,7 +68,6 @@ #include "Mixer.h" #include "Recorder.h" #include "SourceCallback.h" -#include "CloneSource.h" #include "MediaSource.h" #include "PatternSource.h" #include "DeviceSource.h" @@ -3103,14 +3102,11 @@ void Navigator::RenderSourcePannel(Source *s) // prepare panel for new source of same type MediaSource *file = dynamic_cast(s); MultiFileSource *sequence = dynamic_cast(s); - CloneSource *internal = dynamic_cast(s); PatternSource *generated = dynamic_cast(s); if (file != nullptr) Settings::application.source.new_type = SOURCE_FILE; else if (sequence != nullptr) Settings::application.source.new_type = SOURCE_SEQUENCE; - else if (internal != nullptr) - Settings::application.source.new_type = SOURCE_INTERNAL; else if (generated != nullptr) Settings::application.source.new_type = SOURCE_GENERATED; else @@ -3199,30 +3195,27 @@ void Navigator::RenderNewPannel() ImGui::Columns(5, NULL, false); bool selected_type[5] = {0}; selected_type[Settings::application.source.new_type] = true; - if (ImGui::Selectable( ICON_FA_PHOTO_VIDEO, &selected_type[SOURCE_FILE], 0, iconsize)) { + if (ImGuiToolkit::SelectableIcon( 2, 5, "##SOURCE_FILE", selected_type[SOURCE_FILE], iconsize)) { Settings::application.source.new_type = SOURCE_FILE; clearNewPannel(); } ImGui::NextColumn(); - if (ImGui::Selectable( ICON_FA_IMAGES, &selected_type[SOURCE_SEQUENCE], 0, iconsize)) { + if (ImGuiToolkit::SelectableIcon( 3, 9, "##SOURCE_SEQUENCE", selected_type[SOURCE_SEQUENCE], iconsize)) { Settings::application.source.new_type = SOURCE_SEQUENCE; clearNewPannel(); } ImGui::NextColumn(); - if (ImGui::Selectable( ICON_FA_PLUG, &selected_type[SOURCE_CONNECTED], 0, iconsize)) { + if (ImGuiToolkit::SelectableIcon( 10, 9, "##SOURCE_CONNECTED", selected_type[SOURCE_CONNECTED], iconsize)) { Settings::application.source.new_type = SOURCE_CONNECTED; clearNewPannel(); } ImGui::NextColumn(); - if (ImGui::Selectable( ICON_FA_COGS, &selected_type[SOURCE_GENERATED], 0, iconsize)) { + if (ImGuiToolkit::SelectableIcon( 11, 5, "##SOURCE_GENERATED", selected_type[SOURCE_GENERATED], iconsize)) { Settings::application.source.new_type = SOURCE_GENERATED; clearNewPannel(); } ImGui::NextColumn(); - if (ImGui::Selectable( ICON_FA_RETWEET, &selected_type[SOURCE_INTERNAL], 0, iconsize)) { - Settings::application.source.new_type = SOURCE_INTERNAL; - clearNewPannel(); - } + ImGui::Columns(1); ImGui::PopStyleVar(); @@ -3437,7 +3430,7 @@ void Navigator::RenderNewPannel() static MultiFileRecorder _video_recorder; static int _fps = 25; - ImGui::Text("Create image sequence:"); + ImGui::Text("Load image sequence:"); // clic button to load file if ( ImGui::Button( ICON_FA_FOLDER_OPEN " Open multiple", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) ) { @@ -3570,55 +3563,23 @@ void Navigator::RenderNewPannel() } - // Internal Source creator - else if (Settings::application.source.new_type == SOURCE_INTERNAL){ - - ImGui::Text("Loopback object:"); - - // fill new_source_preview with a new source - ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - if (ImGui::BeginCombo("##Source", "Select")) - { - std::string label = "Rendering Loopback"; - if (ImGui::Selectable( label.c_str() )) { - new_source_preview_.setSource( Mixer::manager().createSourceRender(), label); - } - SourceList::iterator iter; - for (iter = Mixer::manager().session()->begin(); iter != Mixer::manager().session()->end(); ++iter) - { - label = std::string("Source ") + (*iter)->initials() + " - " + (*iter)->name(); - if (ImGui::Selectable( label.c_str() )) { - label = std::string("Clone of ") + label; - new_source_preview_.setSource( Mixer::manager().createSourceClone((*iter)->name(), false),label); - } - } - ImGui::EndCombo(); - } - - // Indication - ImGui::SameLine(); - ImGuiToolkit::HelpToolTip("Create a source replicating internal vimix objects.\n" - ICON_FA_CARET_RIGHT " Loopback from output\n" - ICON_FA_CARET_RIGHT " Clone other sources"); - } - // Generated Source creator else if (Settings::application.source.new_type == SOURCE_GENERATED){ bool update_new_source = false; - ImGui::Text("Generate graphics:"); + ImGui::Text("Generate graphic patterns:"); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); if (ImGui::BeginCombo("##Pattern", "Select", ImGuiComboFlags_HeightLarge)) { - if ( ImGui::Selectable("Custom " ICON_FA_CARET_RIGHT) ) { + if ( ImGui::Selectable("Custom " ICON_FA_PLAY_CIRCLE) ) { update_new_source = true; custom_pipeline = true; pattern_type = -1; } for (int p = 0; p < (int) Pattern::count(); ++p){ pattern_descriptor pattern = Pattern::get(p); - std::string label = pattern.label + (pattern.animated ? " " ICON_FA_CARET_RIGHT : " "); + std::string label = pattern.label + (pattern.animated ? " " ICON_FA_PLAY_CIRCLE : " "); if (pattern.available && ImGui::Selectable( label.c_str(), p == pattern_type )) { update_new_source = true; custom_pipeline = false; @@ -3715,6 +3676,10 @@ void Navigator::RenderNewPannel() } } + if ( ImGui::Selectable("Display Loopback") ) { + new_source_preview_.setSource( Mixer::manager().createSourceRender(), "Display Loopback"); + } + if ( ImGui::Selectable("SRT Broadcaster") ) { new_source_preview_.setSource(); custom_connected = true; @@ -3732,7 +3697,8 @@ void Navigator::RenderNewPannel() ImGuiToolkit::HelpToolTip("Create a source capturing video streams from connected devices or machines;\n" ICON_FA_CARET_RIGHT " webcams or frame grabbers\n" ICON_FA_CARET_RIGHT " screen capture\n" - ICON_FA_CARET_RIGHT " shared by vimix on local network\n" + ICON_FA_CARET_RIGHT " vimix display loopback\n" + ICON_FA_CARET_RIGHT " vimix Peer-to-peer in local network\n" ICON_FA_CARET_RIGHT " broadcasted with SRT over network."); if (custom_connected) { diff --git a/src/UserInterfaceManager.h b/src/UserInterfaceManager.h index f73d8b7..b5489dd 100644 --- a/src/UserInterfaceManager.h +++ b/src/UserInterfaceManager.h @@ -77,7 +77,6 @@ public: SOURCE_SEQUENCE, SOURCE_CONNECTED, SOURCE_GENERATED, - SOURCE_INTERNAL, SOURCE_TYPES } NewSourceType;