diff --git a/applications/gui2/src/views/addsource.cpp b/applications/gui2/src/views/addsource.cpp index e698d2dcdf85170da60e670c820778f1e14e1c36..91b9041aec3f356ebe226873454b004f8c446725 100644 --- a/applications/gui2/src/views/addsource.cpp +++ b/applications/gui2/src/views/addsource.cpp @@ -34,12 +34,75 @@ AddSourceWindow::AddSourceWindow(nanogui::Widget* parent, AddCtrl *ctrl) : close->setBackgroundColor(theme()->mWindowHeaderGradientBot); close->setCallback([this](){ this->close();}); + auto *title = new Label(this, "Add Source", "sans-bold"); + title->setFontSize(28); + + tabs_ = new TabWidget(this); + + auto *recent_tab = tabs_->createTab("Recent"); + recent_tab->setLayout(new nanogui::BoxLayout + (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); + VScrollPanel *vscroll = new VScrollPanel(recent_tab); + vscroll->setFixedHeight(200); + Widget *recentscroll = new Widget(vscroll); + recentscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + + auto *group_tab = tabs_->createTab("Groups"); + group_tab->setLayout(new nanogui::BoxLayout + (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); + vscroll = new VScrollPanel(group_tab); + vscroll->setFixedHeight(200); + Widget *groupscroll = new Widget(vscroll); + groupscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + + auto *dev_tab = tabs_->createTab("Devices"); + dev_tab->setLayout(new nanogui::BoxLayout + (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); + vscroll = new VScrollPanel(dev_tab); + vscroll->setFixedHeight(200); + Widget *devscroll = new Widget(vscroll); + devscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + + auto *host_tab = tabs_->createTab("Hosts"); + host_tab->setLayout(new nanogui::BoxLayout + (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); + vscroll = new VScrollPanel(host_tab); + vscroll->setFixedHeight(200); + Widget *hostscroll = new Widget(vscroll); + hostscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + + auto *stream_tab = tabs_->createTab("Streams"); + stream_tab->setLayout(new nanogui::BoxLayout + (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); + vscroll = new VScrollPanel(stream_tab); + vscroll->setFixedHeight(200); + Widget *streamscroll = new Widget(vscroll); + streamscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + + auto *file_tab = tabs_->createTab("Files"); + file_tab->setLayout(new nanogui::BoxLayout + (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); + vscroll = new VScrollPanel(file_tab); + vscroll->setFixedHeight(200); + Widget *filescroll = new Widget(vscroll); + filescroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + + tab_items_.resize(6); + tab_items_[0] = recentscroll; + tab_items_[1] = groupscroll; + tab_items_[2] = devscroll; + tab_items_[3] = hostscroll; + tab_items_[4] = streamscroll; + tab_items_[5] = filescroll; + + uptodate_.test_and_set(); rebuild(); + tabs_->setActiveTab(0); new_source_handle_ = ctrl_->feed()->onNewSources([this](int a) { LOG(INFO) << "NEW SOURCES"; UNIQUE_LOCK(mutex_, lk); - do_rebuild_ = true; + uptodate_.clear(); return true; }); } @@ -83,65 +146,29 @@ nanogui::Button *AddSourceWindow::_addButton(const std::string &s, nanogui::Widg void AddSourceWindow::rebuild() { using namespace nanogui; - - auto *title = new Label(this, "Add Source", "sans-bold"); - title->setFontSize(28); - - auto *tabs = new TabWidget(this); - - auto *recent_tab = tabs->createTab("Recent"); - recent_tab->setLayout(new nanogui::BoxLayout - (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); - VScrollPanel *vscroll = new VScrollPanel(recent_tab); - vscroll->setFixedHeight(200); - Widget *recentscroll = new Widget(vscroll); - recentscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + for (auto *w : tab_items_) { + while (w->childCount() > 0) w->removeChild(w->childCount()-1); + } + Button *button; auto srcs = ctrl_->getRecent(); - for (auto &s : srcs) { - _addButton(s.uri, recentscroll); + _addButton(s.uri, tab_items_[0]); } - auto *group_tab = tabs->createTab("Groups"); - group_tab->setLayout(new nanogui::BoxLayout - (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); - vscroll = new VScrollPanel(group_tab); - vscroll->setFixedHeight(150); - Widget *groupscroll = new Widget(vscroll); - groupscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); - auto groups = ctrl_->getGroups(); - for (auto &s : groups) { - _addButton(s, groupscroll); + _addButton(s, tab_items_[1]); } - auto *dev_tab = tabs->createTab("Devices"); - dev_tab->setLayout(new nanogui::BoxLayout - (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); - vscroll = new VScrollPanel(dev_tab); - vscroll->setFixedHeight(150); - Widget *devscroll = new Widget(vscroll); - devscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); - auto devsrcs = ctrl_->getDeviceSources(); - for (auto &s : devsrcs) { - _addButton(s, devscroll); + _addButton(s, tab_items_[2]); } - auto *host_tab = tabs->createTab("Hosts"); - host_tab->setLayout(new nanogui::BoxLayout - (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); - vscroll = new VScrollPanel(host_tab); - vscroll->setFixedHeight(150); - Widget *hostscroll = new Widget(vscroll); - hostscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); - - button = new Button(hostscroll, "Add Host", ENTYPO_ICON_PLUS); + button = new Button(tab_items_[3], "Add Host", ENTYPO_ICON_PLUS); button->setIconPosition(Button::IconPosition::Left); button->setIconExtraScale(1.2); button->setFontSize(18); @@ -151,36 +178,19 @@ void AddSourceWindow::rebuild() { }); auto hostsrcs = ctrl_->getHosts(); - for (auto &s : hostsrcs) { - _addButton(s, hostscroll); + _addButton(s, tab_items_[3]); } - auto *stream_tab = tabs->createTab("Streams"); - stream_tab->setLayout(new nanogui::BoxLayout - (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); - vscroll = new VScrollPanel(stream_tab); - vscroll->setFixedHeight(150); - Widget *streamscroll = new Widget(vscroll); - streamscroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); - auto streamsrcs = ctrl_->getNetSources(); - for (auto &s : streamsrcs) { - _addButton(s, streamscroll); + _addButton(s, tab_items_[4]); } - auto *file_tab = tabs->createTab("Files"); - file_tab->setLayout(new nanogui::BoxLayout - (nanogui::Orientation::Vertical, nanogui::Alignment::Fill, 0, 0)); - vscroll = new VScrollPanel(file_tab); - vscroll->setFixedHeight(150); - Widget *filescroll = new Widget(vscroll); - filescroll->setLayout(new BoxLayout(Orientation::Vertical, Alignment::Fill, 10, 4)); + auto *file_menu = new Widget(tab_items_[5]); + file_menu->setLayout(new BoxLayout(nanogui::Orientation::Horizontal, nanogui::Alignment::Maximum, 5,4)); - button = new Button(filescroll, "Open", ENTYPO_ICON_PLUS); - button->setIconPosition(Button::IconPosition::Left); - button->setIconExtraScale(1.2); + button = new Button(file_menu, "Open", ENTYPO_ICON_PLUS); button->setFontSize(18); button->setTooltip("Open FTL File"); button->setCallback([this]() { @@ -205,64 +215,18 @@ void AddSourceWindow::rebuild() { close(); }); - auto filesrcs = ctrl_->getFileSources(); + button = new Button(file_menu, "Clear", ENTYPO_ICON_CYCLE); + button->setFontSize(18); + button->setTooltip("Clear file history"); + button->setCallback([this]() { + ctrl_->feed()->clearFileHistory(); + uptodate_.clear(); + }); + auto filesrcs = ctrl_->getFileSources(); for (auto &s : filesrcs) { - _addButton(s, filescroll); + _addButton(s, tab_items_[5]); } - - - tabs->setActiveTab(0); - - - /*button = new Button(devicebuttons, "Camera(s)"); - button->setCallback([this]() { ctrl_->add("device:camera"); close(); }); - button = new Button(devicebuttons, "Realsense"); - button->setCallback([this]() { ctrl_->add("device:realsense"); close(); }); - button = new Button(devicebuttons, "Screen"); - button->setCallback([this]() { ctrl_->add("device:screen"); close(); }); - button = new Button(devicebuttons, "3D Camera"); - button->setCallback([this]() { ctrl_->add("device:render"); close(); }); - button = new Button(devicebuttons, "OpenVR"); - button->setCallback([this]() { ctrl_->add("device:openvr"); close(); });*/ - - /*new Label(this, "Network Sources", "sans-bold"); - - auto *netbuttons = new Widget(this); - netbuttons->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 4)); - auto netsrcs = ctrl_->getNetSources(); - - for (auto &s : netsrcs) { - button = new Button(netbuttons, ctrl_->getSourceName(s)); - if (ctrl_->isSourceActive(s)) { - button->setBackgroundColor(Color(0, 255, 0, 25)); - } - - button->setCallback([this, s]() { - ctrl_->add(s); - close(); - }); - }*/ - - //new Label(this, "Files", "sans-bold"); - - //auto *filebuttons = new Widget(this); - //filebuttons->setLayout(new BoxLayout(Orientation::Horizontal, Alignment::Middle, 0, 4)); - - - /*auto filesrcs = ctrl_->getFileSources(); - - for (auto &s : filesrcs) { - button = new Button(filebuttons, ctrl_->getSourceName(s)); - if (ctrl_->isSourceActive(s)) { - button->setBackgroundColor(Color(0, 255, 0, 25)); - } - - button->setCallback([this, s]() { - ctrl_->add(s); - close(); - }); - }*/ } void AddSourceWindow::close() { @@ -274,10 +238,10 @@ void AddSourceWindow::close() { void AddSourceWindow::draw(NVGcontext *ctx) { { UNIQUE_LOCK(mutex_, lk); - if (do_rebuild_) { - do_rebuild_ = false; + if (!uptodate_.test_and_set()) { + tabs_->requestFocus(); // Note the 1, first widget is the title bar buttons - while(childCount() > 1) { removeChild(childCount()-1); } + //while(childCount() > 1) { removeChild(childCount()-1); } rebuild(); screen()->performLayout(); } diff --git a/applications/gui2/src/views/addsource.hpp b/applications/gui2/src/views/addsource.hpp index 938e1e3dde73d87b484814d8b98f731394045a0f..da075fbab3fc4ac93cc4aee96f70c3301b20c69a 100644 --- a/applications/gui2/src/views/addsource.hpp +++ b/applications/gui2/src/views/addsource.hpp @@ -29,7 +29,9 @@ private: ftl::Handle new_source_handle_; MUTEX mutex_; - std::atomic_bool do_rebuild_=false; + std::atomic_flag uptodate_; + std::vector<nanogui::Widget*> tab_items_; + nanogui::TabWidget *tabs_; public: // EIGEN_MAKE_ALIGNED_OPERATOR_NEW diff --git a/components/streams/include/ftl/streams/feed.hpp b/components/streams/include/ftl/streams/feed.hpp index c8565fcf209ab54148180d584a6d850f2f447303..5cfddc7071acd25c2795bebe0f8bf8a62d573640 100644 --- a/components/streams/include/ftl/streams/feed.hpp +++ b/components/streams/include/ftl/streams/feed.hpp @@ -111,6 +111,8 @@ public: bool sourceAvailable(const std::string &uri); bool sourceActive(const std::string &uri); + void clearFileHistory(); + /** * Perform a render tick for all render sources. Note that this must be * called from the GUI / OpenGL thread. diff --git a/components/streams/src/feed.cpp b/components/streams/src/feed.cpp index 0a6fb2da8b41d68cc719ac6581669de1372f97ab..6d149d13189b48a55d0868127154db9c713862da 100644 --- a/components/streams/src/feed.cpp +++ b/components/streams/src/feed.cpp @@ -568,6 +568,22 @@ std::vector<std::string> Feed::availableFileSources() { return files; } +void Feed::clearFileHistory() { + UNIQUE_LOCK(mtx_, lk); + auto &recent_files = getConfig()["recent_files"]; + recent_files.clear(); + + auto &recent = getConfig()["recent_sources"]; + for (auto i=recent.begin(); i != recent.end();) { + ftl::URI uri(i.key()); + if (uri.getScheme() == ftl::URI::SCHEME_FILE) { + i = recent.erase(i); + } else { + ++i; + } + } +} + std::vector<std::string> Feed::knownHosts() { std::vector<std::string> hosts; auto &known = getConfig()["known_hosts"]; @@ -680,7 +696,13 @@ std::string Feed::getName(const std::string &puri) { if (uri.getPathSegment(0) == "openvr") return "OpenVR"; return "Unknown Device"; } else if (uri.getScheme() == ftl::URI::SCHEME_FILE) { - return getConfig()["recent_files"][uri.getBaseURI()].value("name", "FTLFile"); + auto &recent_files = getConfig()["recent_files"]; + if (recent_files.is_structured() && recent_files.contains(uri.getBaseURI())) { + return recent_files[uri.getBaseURI()].value("name", uri.getPathSegment(-1)); + } else { + LOG(INFO) << "Missing file: " << puri; + return uri.getPathSegment(-1); + } } else if (uri.getScheme() == ftl::URI::SCHEME_TCP || uri.getScheme() == ftl::URI::SCHEME_WS) { return uri.getBaseURI(); } else if (uri.getScheme() == ftl::URI::SCHEME_GROUP) {