diff --git a/ActionManager.cpp b/ActionManager.cpp index c13969e..7ff6a4d 100644 --- a/ActionManager.cpp +++ b/ActionManager.cpp @@ -185,10 +185,12 @@ void Action::restore(uint target) void Action::snapshot(const std::string &label) { - // ignore if locked or if no label is given - if (locked_ || label.empty()) + // ignore if locked + if (locked_) return; + std::string snap_label = BaseToolkit::uniqueName(label, labels()); + // create snapshot id u_int64_t id = BaseToolkit::uniqueId(); @@ -197,10 +199,10 @@ void Action::snapshot(const std::string &label) se->snapshots()->keys_.push_back(id); // threaded capture state of current session - std::thread(captureMixerSession, se->snapshots()->xmlDoc_, SNAPSHOT_NODE(id), label).detach(); + std::thread(captureMixerSession, se->snapshots()->xmlDoc_, SNAPSHOT_NODE(id), snap_label).detach(); #ifdef ACTION_DEBUG - Log::Info("Snapshot stored %d '%s'", id, label.c_str()); + Log::Info("Snapshot stored %d '%s'", id, snap_label.c_str()); #endif } @@ -252,6 +254,17 @@ std::list Action::snapshots() const return Mixer::manager().session()->snapshots()->keys_; } +std::list Action::labels() const +{ + std::list names; + + tinyxml2::XMLDocument *doc = Mixer::manager().session()->snapshots()->xmlDoc_; + for ( XMLElement *snap = doc->FirstChildElement(); snap ; snap = snap->NextSiblingElement() ) + names.push_back( snap->Attribute("label")); + + return names; +} + std::string Action::label(uint64_t snapshotid) const { std::string label = ""; diff --git a/ActionManager.h b/ActionManager.h index a00612e..b8c65b9 100644 --- a/ActionManager.h +++ b/ActionManager.h @@ -38,7 +38,7 @@ public: FrameBufferImage *thumbnail (uint s) const; // Snapshots - void snapshot (const std::string &label); + void snapshot (const std::string &label = ""); std::list snapshots () const; uint64_t currentSnapshot () const { return snapshot_id_; } @@ -49,6 +49,7 @@ public: void remove (uint64_t snapshotid = 0); std::string label (uint64_t snapshotid) const; + std::list labels () const; void setLabel (uint64_t snapshotid, const std::string &label); FrameBufferImage *thumbnail (uint64_t snapshotid) const; diff --git a/BaseToolkit.cpp b/BaseToolkit.cpp index 910cfb2..6b00a34 100644 --- a/BaseToolkit.cpp +++ b/BaseToolkit.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -18,6 +19,33 @@ uint64_t BaseToolkit::uniqueId() } + +std::string BaseToolkit::uniqueName(const std::string &basename, std::list existingnames) +{ + std::string tentativename = basename; + int count = 1; + int max = 100; + + // while tentativename can be found in the list of existingnames + while ( std::find( existingnames.begin(), existingnames.end(), tentativename ) != existingnames.end() ) + { + for( auto it = existingnames.cbegin(); it != existingnames.cend(); ++it) { + if ( it->find(tentativename) != std::string::npos) + ++count; + } + + if (count > 1) + tentativename = basename + "_" + std::to_string( count ); + else + tentativename += "_"; + + if ( --max < 0 ) // for safety only, should never be needed + break; + } + + return tentativename; +} + // Using ICU transliteration : // https://unicode-org.github.io/icu/userguide/transforms/general/#icu-transliterators diff --git a/BaseToolkit.h b/BaseToolkit.h index 29562dc..ecef3b0 100644 --- a/BaseToolkit.h +++ b/BaseToolkit.h @@ -1,6 +1,7 @@ #ifndef BASETOOLKIT_H #define BASETOOLKIT_H +#include #include namespace BaseToolkit @@ -9,6 +10,9 @@ namespace BaseToolkit // get integer with unique id uint64_t uniqueId(); +// proposes a name that is not already in the list +std::string uniqueName(const std::string &basename, std::list existingnames); + // get a transliteration to Latin of any string std::string transliterate(std::string input); @@ -18,6 +22,7 @@ std::string byte_to_string(long b); // get a string to display bit size with unit Kbit, MBit, Gbit, Tbit std::string bits_to_string(long b); + } diff --git a/Mixer.cpp b/Mixer.cpp index 4e20dbd..a82b4a2 100644 --- a/Mixer.cpp +++ b/Mixer.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "View.h" #include "ImageShader.h" +#include "BaseToolkit.h" #include "SystemToolkit.h" #include "SessionCreator.h" #include "SessionVisitor.h" @@ -251,7 +252,10 @@ Source * Mixer::createSourceRender() s->setSession(session_); // propose a new name based on session name - s->setName(SystemToolkit::base_filename(session_->filename())); + if ( !session_->filename().empty() ) + s->setName(SystemToolkit::base_filename(session_->filename())); + else + s->setName("Output"); return s; } @@ -263,8 +267,7 @@ Source * Mixer::createSourceStream(const std::string &gstreamerpipeline) s->setDescription(gstreamerpipeline); // propose a new name based on pattern name - std::string name = gstreamerpipeline.substr(0, gstreamerpipeline.find(" ")); - s->setName(name); + s->setName( gstreamerpipeline.substr(0, gstreamerpipeline.find(" ")) ); return s; } @@ -289,8 +292,7 @@ Source * Mixer::createSourceDevice(const std::string &namedevice) Source *s = Device::manager().createSource(namedevice); // propose a new name based on pattern name - std::string name = namedevice.substr(0, namedevice.find(" ")); - s->setName(name); + s->setName( namedevice.substr(0, namedevice.find(" ")) ); return s; } @@ -333,23 +335,17 @@ Source * Mixer::createSourceClone(const std::string &namesource) origin = current_source_; // have an origin, can clone it - if (origin != session_->end()) { - + if (origin != session_->end()) // create a source s = (*origin)->clone(); - // propose new name (this automatically increments name) - s->setName((*origin)->name()); - } - return s; } void Mixer::addSource(Source *s) { - if (s != nullptr) { + if (s != nullptr) candidate_sources_.push_back(s); - } } void Mixer::insertSource(Source *s, View::Mode m) @@ -656,16 +652,7 @@ void Mixer::renameSource(Source *s, const std::string &newname) if ( !newname.empty() ) tentativename = newname; - // search for a source of the name 'tentativename' - std::string basename = tentativename; - int count = 1; - for( auto it = session_->begin(); it != session_->end(); it++){ - if ( s->id() != (*it)->id() && (*it)->name() == tentativename ) - tentativename = basename + std::to_string( ++count ); - } - -// std::list names = session_->getNameList(); - + tentativename = BaseToolkit::uniqueName(tentativename, session_->getNameList()); // ok to rename s->setName(tentativename); diff --git a/Source.cpp b/Source.cpp index 4bd4193..e794527 100644 --- a/Source.cpp +++ b/Source.cpp @@ -316,7 +316,8 @@ Source::~Source() void Source::setName (const std::string &name) { - name_ = BaseToolkit::transliterate(name); + if (!name.empty()) + name_ = BaseToolkit::transliterate(name); initials_[0] = std::toupper( name_.front(), std::locale("C") ); initials_[1] = std::toupper( name_.back(), std::locale("C") ); @@ -817,6 +818,7 @@ CloneSource *Source::clone(uint64_t id) CloneSource::CloneSource(Source *origin, uint64_t id) : Source(id), origin_(origin) { + name_ = origin->name(); // set symbol symbol_ = new Symbol(Symbol::CLONE, glm::vec3(0.75f, 0.75f, 0.01f)); symbol_->scale_.y = 1.5f; diff --git a/UserInterfaceManager.cpp b/UserInterfaceManager.cpp index bfd0be8..9440983 100644 --- a/UserInterfaceManager.cpp +++ b/UserInterfaceManager.cpp @@ -259,7 +259,7 @@ void UserInterface::handleKeyboard() } } else if (ImGui::IsKeyPressed( GLFW_KEY_Y )) { - Action::manager().snapshot( SystemToolkit::date_time_string() ); + Action::manager().snapshot( "Snap" ); } else if (ImGui::IsKeyPressed( GLFW_KEY_Z )) { if (shift_modifier_active) @@ -807,7 +807,7 @@ void UserInterface::showMenuEdit() if ( ImGui::MenuItem( ICON_FA_REDO " Redo", CTRL_MOD "Shift+Z") ) Action::manager().redo(); if ( ImGui::MenuItem( ICON_FA_STAR "+ Snapshot", CTRL_MOD "Y") ) - Action::manager().snapshot( SystemToolkit::date_time_string() ); + Action::manager().snapshot( "Snap" ); } void UserInterface::showMenuFile() @@ -3236,7 +3236,7 @@ void Navigator::RenderMainPannelVimix() // right buttons ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y )); if ( ImGuiToolkit::IconButton( ICON_FA_STAR "+")) - Action::manager().snapshot( SystemToolkit::date_time_string() ); + Action::manager().snapshot( "Snap" ); if (ImGui::IsItemHovered()) ImGuiToolkit::ToolTip("Take Snapshot ", CTRL_MOD "Y");