Unified GUI behavior for source creation. cleanup of history of recent

files after loading error.
This commit is contained in:
brunoherbelin
2020-09-20 11:28:09 +02:00
parent 59db2cf57c
commit 519baf7a3b
9 changed files with 139 additions and 96 deletions

View File

@@ -348,9 +348,8 @@ void ImGuiVisitor::visit (CloneSource& s)
{ {
ImGuiToolkit::Icon(9,2); ImGuiToolkit::Icon(9,2);
ImGui::SameLine(0, 10); ImGui::SameLine(0, 10);
ImGui::Text("Clone of %s", s.origin()->name().c_str()); ImGui::Text("Clone");
std::string label = "Select " + s.origin()->name(); if ( ImGui::Button(s.origin()->name().c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
if ( ImGui::Button(label.c_str(), ImVec2(IMGUI_RIGHT_ALIGN, 0)) )
Mixer::manager().setCurrentSource(s.origin()); Mixer::manager().setCurrentSource(s.origin());
} }
@@ -358,13 +357,17 @@ void ImGuiVisitor::visit (PatternSource& s)
{ {
ImGuiToolkit::Icon(13,5); ImGuiToolkit::Icon(13,5);
ImGui::SameLine(0, 10); ImGui::SameLine(0, 10);
ImGui::Text("Pattern %s", Pattern::pattern_names[s.pattern()]); ImGui::Text("Pattern");
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
int p = s.pattern(); if (ImGui::BeginCombo("##Pattern", Pattern::pattern_types[s.pattern()->type()].c_str()) )
if ( ImGui::Combo("Pattern", &p, Pattern::pattern_names, IM_ARRAYSIZE(Pattern::pattern_names) ) )
{ {
for (int p = 0; p < Pattern::pattern_types.size(); ++p){
if (ImGui::Selectable( Pattern::pattern_types[p].c_str() )) {
s.setPattern(p); s.setPattern(p);
} }
}
ImGui::EndCombo();
}
} }

View File

@@ -110,7 +110,7 @@ Mixer::Mixer() : session_(nullptr), back_session_(nullptr), current_view_(nullpt
// auto load if Settings ask to // auto load if Settings ask to
if ( Settings::application.recentSessions.load_at_start && if ( Settings::application.recentSessions.load_at_start &&
Settings::application.recentSessions.valid_file && Settings::application.recentSessions.front_is_valid &&
Settings::application.recentSessions.filenames.size() > 0 ) Settings::application.recentSessions.filenames.size() > 0 )
load( Settings::application.recentSessions.filenames.front() ); load( Settings::application.recentSessions.filenames.front() );
else else
@@ -187,8 +187,14 @@ void Mixer::update()
session_->update(dt_); session_->update(dt_);
// delete sources which failed update (one by one) // delete sources which failed update (one by one)
if (session()->failedSource() != nullptr) Source *failure = session()->failedSource();
deleteSource(session()->failedSource()); if (failure != nullptr) {
MediaSource *failedFile = dynamic_cast<MediaSource *>(failure);
if (failedFile != nullptr) {
Settings::application.recentImport.remove( failedFile->path() );
}
deleteSource(failure);
}
// update views // update views
mixing_.update(dt_); mixing_.update(dt_);
@@ -240,8 +246,10 @@ Source * Mixer::createSourceFile(const std::string &path)
renameSource(s, SystemToolkit::base_filename(path)); renameSource(s, SystemToolkit::base_filename(path));
} }
else else {
Settings::application.recentImport.remove(path);
Log::Notify("File %s does not exist.", path.c_str()); Log::Notify("File %s does not exist.", path.c_str());
}
return s; return s;
} }
@@ -264,7 +272,7 @@ Source * Mixer::createSourcePattern(int pattern, glm::ivec2 res)
s->setPattern(pattern); s->setPattern(pattern);
// propose a new name based on pattern name // propose a new name based on pattern name
renameSource(s, Pattern::pattern_names[pattern]); renameSource(s, Pattern::pattern_types[pattern]);
return s; return s;
} }

View File

@@ -64,8 +64,7 @@ const char* pattern_internal_[25] = { "videotestsrc pattern=black",
"videotestsrc pattern=black ! clockoverlay halignment=center valignment=center font-desc=\"Sans, 72\" " "videotestsrc pattern=black ! clockoverlay halignment=center valignment=center font-desc=\"Sans, 72\" "
}; };
std::vector<std::string> Pattern::pattern_types = { "100% Black",
const char* Pattern::pattern_names[25] = { "100% Black",
"100% White", "100% White",
"Gray bars", "Gray bars",
"Gradient", "Gradient",
@@ -99,16 +98,22 @@ Pattern::Pattern(glm::ivec2 res) : Stream()
height_ = res.y; height_ = res.y;
} }
glm::ivec2 Pattern::resolution()
{
return glm::ivec2( width_, height_);
}
void Pattern::open( uint pattern ) void Pattern::open( uint pattern )
{ {
std::string gstreamer_pattern = pattern_internal_[pattern]; type_ = CLAMP(pattern, 0, 25);
std::string gstreamer_pattern = pattern_internal_[type_];
// always some special cases... // always some special cases...
switch(pattern) switch(type_)
{ {
case 16: case 18:
case 17: case 19:
{ {
std::ostringstream oss; std::ostringstream oss;
oss << " kx2=" << (int)(aspectRatio() * 10.f) << " ky2=10 kt=4"; oss << " kx2=" << (int)(aspectRatio() * 10.f) << " ky2=10 kt=4";
@@ -121,7 +126,7 @@ void Pattern::open( uint pattern )
} }
// all patterns before index are single frames (not animated) // all patterns before index are single frames (not animated)
single_frame_ = pattern < 13; single_frame_ = type_ < 15;
// (private) open stream // (private) open stream
open(gstreamer_pattern); open(gstreamer_pattern);
@@ -149,11 +154,6 @@ PatternSource::PatternSource(glm::ivec2 resolution) : Source()
patternsurface_ = new Surface(renderingshader_); patternsurface_ = new Surface(renderingshader_);
} }
glm::ivec2 PatternSource::resolution()
{
return glm::ivec2( stream_->width(), stream_->height());
}
PatternSource::~PatternSource() PatternSource::~PatternSource()
{ {
// delete media surface & stream // delete media surface & stream
@@ -178,12 +178,10 @@ void PatternSource::replaceRenderingShader()
void PatternSource::setPattern(int id) void PatternSource::setPattern(int id)
{ {
pattern_ = CLAMP(id, 0, 25); stream_->open(id);
stream_->open(pattern_);
stream_->play(true); stream_->play(true);
Log::Notify("Creating pattern %s", Pattern::pattern_names[pattern_]); Log::Notify("Creating pattern %s", Pattern::pattern_types[id].c_str());
} }

View File

@@ -1,21 +1,25 @@
#ifndef PATTERNSOURCE_H #ifndef PATTERNSOURCE_H
#define PATTERNSOURCE_H #define PATTERNSOURCE_H
#include <vector>
#include "Source.h"
#include "Stream.h" #include "Stream.h"
#include "Source.h"
class Pattern : public Stream class Pattern : public Stream
{ {
public: public:
static const char* pattern_names[25]; static std::vector<std::string> pattern_types;
Pattern(glm::ivec2 res); Pattern(glm::ivec2 res);
void open( uint pattern ); void open( uint pattern );
glm::ivec2 resolution();
inline uint type() const { return type_; }
private: private:
void open( std::string description ) override; void open( std::string description ) override;
uint type_;
}; };
class PatternSource : public Source class PatternSource : public Source
@@ -33,11 +37,9 @@ public:
void accept (Visitor& v) override; void accept (Visitor& v) override;
// Pattern specific interface // Pattern specific interface
inline uint pattern() const { return pattern_; } inline Pattern *pattern() const { return stream_; }
void setPattern(int id); void setPattern(int id);
glm::ivec2 resolution();
protected: protected:
void init() override; void init() override;
@@ -46,7 +48,6 @@ protected:
Surface *patternsurface_; Surface *patternsurface_;
Pattern *stream_; Pattern *stream_;
uint pattern_;
}; };
#endif // PATTERNSOURCE_H #endif // PATTERNSOURCE_H

View File

@@ -384,9 +384,9 @@ void SessionVisitor::visit (CloneSource& s)
void SessionVisitor::visit (PatternSource& s) void SessionVisitor::visit (PatternSource& s)
{ {
xmlCurrent_->SetAttribute("type", "PatternSource"); xmlCurrent_->SetAttribute("type", "PatternSource");
xmlCurrent_->SetAttribute("pattern", s.pattern() ); xmlCurrent_->SetAttribute("pattern", s.pattern()->type() );
XMLElement *resolution = xmlDoc_->NewElement("resolution"); XMLElement *resolution = xmlDoc_->NewElement("resolution");
resolution->InsertEndChild( XMLElementFromGLM(xmlDoc_, s.resolution() ) ); resolution->InsertEndChild( XMLElementFromGLM(xmlDoc_, s.pattern()->resolution() ) );
xmlCurrent_->InsertEndChild(resolution); xmlCurrent_->InsertEndChild(resolution);
} }

View File

@@ -99,7 +99,6 @@ void Settings::Save()
// Source // Source
XMLElement *SourceConfNode = xmlDoc.NewElement( "Source" ); XMLElement *SourceConfNode = xmlDoc.NewElement( "Source" );
SourceConfNode->SetAttribute("new_type", application.source.new_type); SourceConfNode->SetAttribute("new_type", application.source.new_type);
SourceConfNode->SetAttribute("pattern_type", application.source.pattern_type);
SourceConfNode->SetAttribute("ratio", application.source.ratio); SourceConfNode->SetAttribute("ratio", application.source.ratio);
SourceConfNode->SetAttribute("res", application.source.res); SourceConfNode->SetAttribute("res", application.source.res);
pRoot->InsertEndChild(SourceConfNode); pRoot->InsertEndChild(SourceConfNode);
@@ -141,7 +140,7 @@ void Settings::Save()
recentsession->SetAttribute("path", application.recentSessions.path.c_str()); recentsession->SetAttribute("path", application.recentSessions.path.c_str());
recentsession->SetAttribute("autoload", application.recentSessions.load_at_start); recentsession->SetAttribute("autoload", application.recentSessions.load_at_start);
recentsession->SetAttribute("autosave", application.recentSessions.save_on_exit); recentsession->SetAttribute("autosave", application.recentSessions.save_on_exit);
recentsession->SetAttribute("valid", application.recentSessions.valid_file); recentsession->SetAttribute("valid", application.recentSessions.front_is_valid);
for(auto it = application.recentSessions.filenames.begin(); for(auto it = application.recentSessions.filenames.begin();
it != application.recentSessions.filenames.end(); it++) { it != application.recentSessions.filenames.end(); it++) {
XMLElement *fileNode = xmlDoc.NewElement("path"); XMLElement *fileNode = xmlDoc.NewElement("path");
@@ -253,7 +252,6 @@ void Settings::Load()
XMLElement * sourceconfnode = pRoot->FirstChildElement("Source"); XMLElement * sourceconfnode = pRoot->FirstChildElement("Source");
if (sourceconfnode != nullptr) { if (sourceconfnode != nullptr) {
sourceconfnode->QueryIntAttribute("new_type", &application.source.new_type); sourceconfnode->QueryIntAttribute("new_type", &application.source.new_type);
sourceconfnode->QueryIntAttribute("pattern_type", &application.source.pattern_type);
sourceconfnode->QueryIntAttribute("ratio", &application.source.ratio); sourceconfnode->QueryIntAttribute("ratio", &application.source.ratio);
sourceconfnode->QueryIntAttribute("res", &application.source.res); sourceconfnode->QueryIntAttribute("res", &application.source.res);
} }
@@ -344,7 +342,7 @@ void Settings::Load()
} }
pSession->QueryBoolAttribute("autoload", &application.recentSessions.load_at_start); pSession->QueryBoolAttribute("autoload", &application.recentSessions.load_at_start);
pSession->QueryBoolAttribute("autosave", &application.recentSessions.save_on_exit); pSession->QueryBoolAttribute("autosave", &application.recentSessions.save_on_exit);
pSession->QueryBoolAttribute("valid", &application.recentSessions.valid_file); pSession->QueryBoolAttribute("valid", &application.recentSessions.front_is_valid);
} }
// recent session filenames // recent session filenames
XMLElement * pFolder = pElement->FirstChildElement("Folder"); XMLElement * pFolder = pElement->FirstChildElement("Folder");

View File

@@ -77,26 +77,33 @@ struct History
{ {
std::string path; std::string path;
std::list<std::string> filenames; std::list<std::string> filenames;
bool valid_file; bool front_is_valid;
bool load_at_start; bool load_at_start;
bool save_on_exit; bool save_on_exit;
History() { History() {
path = IMGUI_LABEL_RECENT_FILES; path = IMGUI_LABEL_RECENT_FILES;
valid_file = false; front_is_valid = false;
load_at_start = false; load_at_start = false;
save_on_exit = false; save_on_exit = false;
} }
void push(std::string filename) { void push(const std::string &filename) {
if (filename.empty()) { if (filename.empty()) {
valid_file = false; front_is_valid = false;
return; return;
} }
filenames.remove(filename); filenames.remove(filename);
filenames.push_front(filename); filenames.push_front(filename);
if (filenames.size() > MAX_RECENT_HISTORY) if (filenames.size() > MAX_RECENT_HISTORY)
filenames.pop_back(); filenames.pop_back();
valid_file = true; front_is_valid = true;
}
void remove(const std::string &filename) {
if (filename.empty())
return;
if (filenames.front() == filename)
front_is_valid = false;
filenames.remove(filename);
} }
}; };
@@ -139,13 +146,11 @@ struct RenderConfig
struct SourceConfig struct SourceConfig
{ {
int new_type; int new_type;
int pattern_type;
int ratio; int ratio;
int res; int res;
SourceConfig() { SourceConfig() {
new_type = 0; new_type = 0;
pattern_type = 0;
ratio = 3; ratio = 3;
res = 1; res = 1;
} }

View File

@@ -984,6 +984,9 @@ void UserInterface::RenderPreview()
if ( ImGui::MenuItem( ICON_FA_WINDOW_RESTORE " Show output window") ) if ( ImGui::MenuItem( ICON_FA_WINDOW_RESTORE " Show output window") )
Rendering::manager().outputWindow().show(); Rendering::manager().outputWindow().show();
if ( ImGui::MenuItem( ICON_FA_SHARE_SQUARE " Create Source") )
Mixer::manager().addSource( Mixer::manager().createSourceRender() );
if ( ImGui::MenuItem( ICON_FA_TIMES " Close") ) if ( ImGui::MenuItem( ICON_FA_TIMES " Close") )
Settings::application.widget.preview = false; Settings::application.widget.preview = false;
@@ -1559,6 +1562,7 @@ void Navigator::clearButtonSelection()
// clear new source pannel // clear new source pannel
sprintf(file_browser_path_, " "); sprintf(file_browser_path_, " ");
new_source_preview_.setSource(); new_source_preview_.setSource();
pattern_type = -1;
} }
void Navigator::showPannelSource(int index) void Navigator::showPannelSource(int index)
@@ -1799,8 +1803,14 @@ void SourcePreview::Render(float width, bool controlbutton)
{ {
if(source_) { if(source_) {
// cancel if failed // cancel if failed
if (source_->failed()) if (source_->failed()) {
// remove from list of recent import files if relevant
MediaSource *failedFile = dynamic_cast<MediaSource *>(source_);
if (failedFile != nullptr) {
Settings::application.recentImport.remove( failedFile->path() );
}
setSource(); setSource();
}
else else
{ {
bool active = source_->active(); bool active = source_->active();
@@ -1842,7 +1852,9 @@ void Navigator::RenderNewPannel()
ImGui::SetCursorPosY(width_); ImGui::SetCursorPosY(width_);
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
static const char* origin_names[3] = { ICON_FA_FILE " File", ICON_FA_SITEMAP " Internal", ICON_FA_COG " Generated" }; static const char* origin_names[3] = { ICON_FA_FILE " File",
ICON_FA_SITEMAP " Internal",
ICON_FA_COG " Generated" };
// TODO IMPLEMENT EXTERNAL SOURCES static const char* origin_names[3] = { ICON_FA_FILE " File", ICON_FA_SITEMAP " Internal", ICON_FA_PLUG " External" }; // TODO IMPLEMENT EXTERNAL SOURCES static const char* origin_names[3] = { ICON_FA_FILE " File", ICON_FA_SITEMAP " Internal", ICON_FA_PLUG " External" };
if (ImGui::Combo("Origin", &Settings::application.source.new_type, origin_names, IM_ARRAYSIZE(origin_names)) ) if (ImGui::Combo("Origin", &Settings::application.source.new_type, origin_names, IM_ARRAYSIZE(origin_names)) )
new_source_preview_.setSource(); new_source_preview_.setSource();
@@ -1905,7 +1917,7 @@ void Navigator::RenderNewPannel()
// fill new_source_preview with a new source // fill new_source_preview with a new source
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("##Source", "Select input")) if (ImGui::BeginCombo("##Source", "Select object"))
{ {
std::string label = "Rendering output"; std::string label = "Rendering output";
if (ImGui::Selectable( label.c_str() )) { if (ImGui::Selectable( label.c_str() )) {
@@ -1914,8 +1926,9 @@ void Navigator::RenderNewPannel()
SourceList::iterator iter; SourceList::iterator iter;
for (iter = Mixer::manager().session()->begin(); iter != Mixer::manager().session()->end(); iter++) for (iter = Mixer::manager().session()->begin(); iter != Mixer::manager().session()->end(); iter++)
{ {
label = std::string("Clone of ") + (*iter)->name(); label = std::string("Source ") + (*iter)->name();
if (ImGui::Selectable( label.c_str() )) { if (ImGui::Selectable( label.c_str() )) {
label = std::string("Clone of ") + label;
new_source_preview_.setSource( Mixer::manager().createSourceClone((*iter)->name()),label); new_source_preview_.setSource( Mixer::manager().createSourceClone((*iter)->name()),label);
} }
} }
@@ -1934,7 +1947,25 @@ void Navigator::RenderNewPannel()
bool update_new_source = false; bool update_new_source = false;
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::Combo("Aspect Ratio", &Settings::application.source.ratio, if (ImGui::BeginCombo("##Pattern", "Select generator"))
{
for (int p = 0; p < Pattern::pattern_types.size(); ++p){
if (ImGui::Selectable( Pattern::pattern_types[p].c_str() )) {
pattern_type = p;
update_new_source = true;
}
}
ImGui::EndCombo();
}
// Indication
ImGui::SameLine();
ImGuiToolkit::HelpMarker("Create a source generated algorithmically.");
// resolution (if pattern selected
if (pattern_type > 0) {
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::Combo("Ratio", &Settings::application.source.ratio,
GlmToolkit::aspect_ratio_names, IM_ARRAYSIZE(GlmToolkit::aspect_ratio_names) ) ) GlmToolkit::aspect_ratio_names, IM_ARRAYSIZE(GlmToolkit::aspect_ratio_names) ) )
update_new_source = true; update_new_source = true;
@@ -1942,23 +1973,19 @@ void Navigator::RenderNewPannel()
if (ImGui::Combo("Height", &Settings::application.source.res, if (ImGui::Combo("Height", &Settings::application.source.res,
GlmToolkit::height_names, IM_ARRAYSIZE(GlmToolkit::height_names) ) ) GlmToolkit::height_names, IM_ARRAYSIZE(GlmToolkit::height_names) ) )
update_new_source = true; update_new_source = true;
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if ( ImGui::Combo("Pattern", &Settings::application.source.pattern_type,
Pattern::pattern_names, IM_ARRAYSIZE(Pattern::pattern_names) ) )
update_new_source = true;
if (update_new_source)
{
std::string label = Pattern::pattern_names[Settings::application.source.pattern_type];
glm::ivec2 res = GlmToolkit::resolutionFromDescription(Settings::application.source.ratio, Settings::application.source.res);
new_source_preview_.setSource( Mixer::manager().createSourcePattern(Settings::application.source.pattern_type, res), label);
} }
// Indication // create preview
ImGui::SameLine(); if (update_new_source)
ImGuiToolkit::HelpMarker("Create a source generated algorithmically."); {
std::ostringstream oss;
oss << Pattern::pattern_types[pattern_type];
glm::ivec2 res = GlmToolkit::resolutionFromDescription(Settings::application.source.ratio, Settings::application.source.res);
oss << " (" << res.x << " x " << res.y << " px)";
new_source_preview_.setSource( Mixer::manager().createSourcePattern(pattern_type, res), oss.str());
}
} }
// Hardware // Hardware
else { else {
@@ -1967,6 +1994,8 @@ void Navigator::RenderNewPannel()
ImGuiToolkit::HelpMarker("Create a source capturing images\nfrom external devices or network."); ImGuiToolkit::HelpMarker("Create a source capturing images\nfrom external devices or network.");
} }
ImGui::NewLine();
// if a new source was added // if a new source was added
if (new_source_preview_.ready()) { if (new_source_preview_.ready()) {
// show preview // show preview
@@ -2154,7 +2183,7 @@ void Navigator::RenderMainPannel()
const char *tooltip[2] = {"Clear history", "Clear history"}; const char *tooltip[2] = {"Clear history", "Clear history"};
if (ImGuiToolkit::IconToggle(12,14,11,14, &reset, tooltip)) { if (ImGuiToolkit::IconToggle(12,14,11,14, &reset, tooltip)) {
Settings::application.recentSessions.filenames.clear(); Settings::application.recentSessions.filenames.clear();
Settings::application.recentSessions.valid_file = false; Settings::application.recentSessions.front_is_valid = false;
// reload the list next time // reload the list next time
selection_session_mode_changed = true; selection_session_mode_changed = true;
} }

View File

@@ -41,6 +41,7 @@ class Navigator
// behavior pannel // behavior pannel
bool pannel_visible_; bool pannel_visible_;
bool selected_button[NAV_COUNT]; bool selected_button[NAV_COUNT];
int pattern_type;
void clearButtonSelection(); void clearButtonSelection();
void applyButtonSelection(int index); void applyButtonSelection(int index);