Update New Source panel for Media

Added list of recent files, recent recordings, and folders list of media files. All saved in settings. Connect list of recent recordings with recorder.
This commit is contained in:
Bruno Herbelin
2021-12-05 18:41:58 +01:00
parent 923d84f378
commit ffe05368e8
7 changed files with 335 additions and 75 deletions

View File

@@ -462,6 +462,8 @@ void VideoRecorder::terminate()
Log::Info("Video Recording : try a lower resolution / a lower framerate / a larger buffer size / a faster codec."); Log::Info("Video Recording : try a lower resolution / a lower framerate / a larger buffer size / a faster codec.");
} }
// remember and inform
Settings::application.recentRecordings.push(filename_);
Log::Notify("Video Recording %s is ready.", filename_.c_str()); Log::Notify("Video Recording %s is ready.", filename_.c_str());
} }

View File

@@ -12,11 +12,12 @@
class PNGRecorder : public FrameGrabber class PNGRecorder : public FrameGrabber
{ {
std::string filename_; std::string filename_;
public: public:
PNGRecorder(); PNGRecorder();
std::string filename() const { return filename_; }
protected: protected:
@@ -28,7 +29,7 @@ protected:
class VideoRecorder : public FrameGrabber class VideoRecorder : public FrameGrabber
{ {
std::string filename_; std::string filename_;
std::string init(GstCaps *caps) override; std::string init(GstCaps *caps) override;
void terminate() override; void terminate() override;
@@ -58,7 +59,7 @@ public:
VideoRecorder(); VideoRecorder();
std::string info() const override; std::string info() const override;
std::string filename() const { return filename_; }
}; };

View File

@@ -238,6 +238,29 @@ void Settings::Save(uint64_t runtime)
} }
recent->InsertEndChild(recentmedia); recent->InsertEndChild(recentmedia);
// recent import folders
XMLElement *recentimportfolder = xmlDoc.NewElement( "ImportFolder" );
recentmedia->SetAttribute("path", application.recentImportFolders.path.c_str());
for(auto it = application.recentImportFolders.filenames.cbegin();
it != application.recentImportFolders.filenames.cend(); ++it) {
XMLElement *pathNode = xmlDoc.NewElement("path");
XMLText *text = xmlDoc.NewText( (*it).c_str() );
pathNode->InsertEndChild( text );
recentimportfolder->InsertFirstChild(pathNode);
}
recent->InsertEndChild(recentimportfolder);
// recent recordings
XMLElement *recentrecord = xmlDoc.NewElement( "Record" );
for(auto it = application.recentRecordings.filenames.cbegin();
it != application.recentRecordings.filenames.cend(); ++it) {
XMLElement *pathNode = xmlDoc.NewElement("path");
XMLText *text = xmlDoc.NewText( (*it).c_str() );
pathNode->InsertEndChild( text );
recentrecord->InsertFirstChild(pathNode);
}
recent->InsertEndChild(recentrecord);
// recent dialog path // recent dialog path
XMLElement *recentdialogpath = xmlDoc.NewElement( "Dialog" ); XMLElement *recentdialogpath = xmlDoc.NewElement( "Dialog" );
for(auto it = application.dialogRecentFolder.cbegin(); for(auto it = application.dialogRecentFolder.cbegin();
@@ -517,6 +540,37 @@ void Settings::Load()
application.recentImport.push( std::string (p) ); application.recentImport.push( std::string (p) );
} }
} }
// recent import folders
XMLElement * pImportFolder = pElement->FirstChildElement("ImportFolder");
if (pImportFolder)
{
const char *path_ = pImportFolder->Attribute("path");
if (path_)
application.recentImportFolders.path = std::string(path_);
application.recentImportFolders.filenames.clear();
XMLElement* path = pImportFolder->FirstChildElement("path");
for( ; path ; path = path->NextSiblingElement())
{
const char *p = path->GetText();
if (p)
application.recentImportFolders.push( std::string (p) );
}
}
// recent recordings
XMLElement * pRecord = pElement->FirstChildElement("Record");
if (pRecord)
{
application.recentRecordings.filenames.clear();
XMLElement* path = pRecord->FirstChildElement("path");
for( ; path ; path = path->NextSiblingElement())
{
const char *p = path->GetText();
if (p)
application.recentRecordings.push( std::string (p) );
}
}
// recent dialog path // recent dialog path
XMLElement * pDialog = pElement->FirstChildElement("Dialog"); XMLElement * pDialog = pElement->FirstChildElement("Dialog");
if (pDialog) if (pDialog)
@@ -582,6 +636,37 @@ void Settings::History::validate()
} }
} }
// TODO unified history function saving
//void load_history(Settings::History &h, XMLElement *root)
//{
// XMLElement * pElement = root->FirstChildElement("Import");
// if (pElement)
// {
// h.filenames.clear();
// XMLElement* path = pElement->FirstChildElement("path");
// for( ; path ; path = path->NextSiblingElement())
// {
// const char *p = path->GetText();
// if (p)
// h.push( std::string (p) );
// }
// }
//}
//XMLElement *save_history(Settings::History &h, XMLDocument &xmlDoc)
//{
// XMLElement *pElement = xmlDoc.NewElement( "Import" );
// for(auto it = h.filenames.cbegin();
// it != h.filenames.cend(); ++it) {
// XMLElement *fileNode = xmlDoc.NewElement("path");
// XMLText *text = xmlDoc.NewText( (*it).c_str() );
// fileNode->InsertEndChild( text );
// pElement->InsertFirstChild(fileNode);
// }
// return pElement;
//}
void Settings::Lock() void Settings::Lock()
{ {

View File

@@ -243,6 +243,8 @@ struct Application
History recentSessions; History recentSessions;
History recentFolders; History recentFolders;
History recentImport; History recentImport;
History recentImportFolders;
History recentRecordings;
std::map< std::string, std::string > dialogRecentFolder; std::map< std::string, std::string > dialogRecentFolder;
// Metronome & stopwatch // Metronome & stopwatch

View File

@@ -111,8 +111,8 @@ std::string readable_date_time_string(std::string date){
// globals // globals
const std::chrono::milliseconds timeout = std::chrono::milliseconds(4); const std::chrono::milliseconds timeout = std::chrono::milliseconds(4);
std::vector< std::future<FrameGrabber *> > _video_recorders; std::vector< std::future<VideoRecorder *> > _video_recorders;
FrameGrabber *delayTrigger(FrameGrabber *g, std::chrono::milliseconds delay) { VideoRecorder *delayTrigger(VideoRecorder *g, std::chrono::milliseconds delay) {
std::this_thread::sleep_for (delay); std::this_thread::sleep_for (delay);
return g; return g;
} }
@@ -324,17 +324,20 @@ void UserInterface::handleKeyboard()
FrameGrabbing::manager().add(new PNGRecorder); FrameGrabbing::manager().add(new PNGRecorder);
} }
else { else {
// toggle recording // toggle recording stop / start
if (video_recorder_) { if (video_recorder_) {
// allow 'save & continue' for Ctrl+Alt+R if no timeout for recording // 'save & continue' for Ctrl+Alt+R if no timeout for recording
if (alt_modifier_active && Settings::application.record.timeout == RECORD_MAX_TIMEOUT) { if (alt_modifier_active && Settings::application.record.timeout == RECORD_MAX_TIMEOUT) {
VideoRecorder *rec = new VideoRecorder; VideoRecorder *rec = new VideoRecorder;
FrameGrabbing::manager().chain(video_recorder_, rec); FrameGrabbing::manager().chain(video_recorder_, rec);
video_recorder_ = rec; video_recorder_ = rec;
} }
// normal case: Ctrl+R stop recording // normal case: Ctrl+R stop recording
else else {
// prepare for next open new source panel to show the recording
navigator.setNewMedia(Navigator::MEDIA_RECORDING, video_recorder_->filename());
video_recorder_->stop(); video_recorder_->stop();
}
} }
else { else {
_video_recorders.emplace_back( std::async(std::launch::async, delayTrigger, new VideoRecorder, _video_recorders.emplace_back( std::async(std::launch::async, delayTrigger, new VideoRecorder,
@@ -795,7 +798,7 @@ void UserInterface::Render()
} }
} }
// verify the video recorder is valid (change to nullptr if invalid) // verify the video recorder is valid (change to nullptr if invalid)
FrameGrabbing::manager().verify(&video_recorder_); FrameGrabbing::manager().verify( (FrameGrabber**) &video_recorder_);
if (video_recorder_ // if there is an ongoing recorder if (video_recorder_ // if there is an ongoing recorder
&& Settings::application.record.timeout < RECORD_MAX_TIMEOUT // and if the timeout is valid && Settings::application.record.timeout < RECORD_MAX_TIMEOUT // and if the timeout is valid
&& video_recorder_->duration() > Settings::application.record.timeout ) // and the timeout is reached && video_recorder_->duration() > Settings::application.record.timeout ) // and the timeout is reached
@@ -1340,12 +1343,18 @@ void UserInterface::RenderPreview()
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_RECORD, 0.8f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(IMGUI_COLOR_RECORD, 0.8f));
if ( ImGui::MenuItem( ICON_FA_SQUARE " Stop Record", CTRL_MOD "R") ) { if ( ImGui::MenuItem( ICON_FA_SQUARE " Stop Record", CTRL_MOD "R") ) {
video_recorder_->stop(); video_recorder_->stop();
// prepare for next open new source panel to show the recording
navigator.setNewMedia(Navigator::MEDIA_RECORDING, video_recorder_->filename());
} }
// offer the 'save & continue' recording for undefined duration // offer the 'save & continue' recording for undefined duration
if (Settings::application.record.timeout == RECORD_MAX_TIMEOUT) { if (Settings::application.record.timeout == RECORD_MAX_TIMEOUT) {
if ( ImGui::MenuItem( ICON_FA_ARROW_ALT_CIRCLE_DOWN " Save & continue", CTRL_MOD "Alt+R") ) { if ( ImGui::MenuItem( ICON_FA_ARROW_ALT_CIRCLE_DOWN " Save & continue", CTRL_MOD "Alt+R") ) {
// prepare for next open new source panel to show the recording
navigator.setNewMedia(Navigator::MEDIA_RECORDING, video_recorder_->filename());
// create a new recorder chainned to the current one
VideoRecorder *rec = new VideoRecorder; VideoRecorder *rec = new VideoRecorder;
FrameGrabbing::manager().chain(video_recorder_, rec); FrameGrabbing::manager().chain(video_recorder_, rec);
// swap recorder
video_recorder_ = rec; video_recorder_ = rec;
} }
} }
@@ -3700,6 +3709,9 @@ Navigator::Navigator()
pannel_visible_ = false; pannel_visible_ = false;
view_pannel_visible = false; view_pannel_visible = false;
clearButtonSelection(); clearButtonSelection();
new_media_mode = MEDIA_RECENT;
new_media_mode_changed = true;
} }
void Navigator::applyButtonSelection(int index) void Navigator::applyButtonSelection(int index)
@@ -3724,7 +3736,8 @@ void Navigator::clearButtonSelection()
// clear new source pannel // clear new source pannel
new_source_preview_.setSource(); new_source_preview_.setSource();
pattern_type = -1; pattern_type = -1;
_selectedFiles.clear(); sourceSequenceFiles.clear();
setNewMedia(new_media_mode);
} }
void Navigator::showPannelSource(int index) void Navigator::showPannelSource(int index)
@@ -4037,6 +4050,43 @@ void Navigator::RenderSourcePannel(Source *s)
} }
} }
void Navigator::setNewMedia(MediaCreateMode mode, std::string path)
{
// switch new source to Media pannel
Settings::application.source.new_type = SOURCE_FILE;
// change mode
new_media_mode = mode;
new_media_mode_changed = true;
// mode dependent actions
switch (new_media_mode) {
case MEDIA_RECENT:
// set filename
sourceMediaFileCurrent = path;
// set combo to 'recent files'
Settings::application.recentImportFolders.path = IMGUI_LABEL_RECENT_FILES;
break;
case MEDIA_RECORDING:
// set filename
sourceMediaFileCurrent = path;
// set combo to 'recent recordings'
Settings::application.recentImportFolders.path = IMGUI_LABEL_RECENT_RECORDS;
break;
default:
case MEDIA_FOLDER:
// reset filename
sourceMediaFileCurrent.clear();
// set combo: a path was selected
if (!path.empty())
Settings::application.recentImportFolders.path.assign(path);
break;
}
// clear preview
new_source_preview_.setSource();
}
void Navigator::RenderNewPannel() void Navigator::RenderNewPannel()
{ {
// Next window is a side pannel // Next window is a side pannel
@@ -4058,7 +4108,7 @@ void Navigator::RenderNewPannel()
// //
// News Source selection pannel // News Source selection pannel
// //
static const char* origin_names[5] = { ICON_FA_PHOTO_VIDEO " File", static const char* origin_names[SOURCE_TYPES] = { ICON_FA_PHOTO_VIDEO " File",
ICON_FA_SORT_NUMERIC_DOWN " Sequence", ICON_FA_SORT_NUMERIC_DOWN " Sequence",
ICON_FA_PLUG " Connected", ICON_FA_PLUG " Connected",
ICON_FA_COG " Generated", ICON_FA_COG " Generated",
@@ -4071,66 +4121,157 @@ void Navigator::RenderNewPannel()
ImGui::SetCursorPosY(2.f * width_); ImGui::SetCursorPosY(2.f * width_);
// File Source creation // File Source creation
if (Settings::application.source.new_type == 0) { if (Settings::application.source.new_type == SOURCE_FILE) {
static DialogToolkit::OpenMediaDialog fileimportdialog("Open Media"); static DialogToolkit::OpenMediaDialog fileimportdialog("Open Media");
static DialogToolkit::OpenFolderDialog folderimportdialog("Select Folder");
// clic button to load file // clic button to load file
if ( ImGui::Button( ICON_FA_FILE_EXPORT " Open media", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) ) if ( ImGui::Button( ICON_FA_FILE_EXPORT " Open File", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) )
fileimportdialog.open(); fileimportdialog.open();
// Indication // Indication
ImGui::SameLine(); ImGui::SameLine();
ImGuiToolkit::HelpMarker("Create a source from a file:\n" ImGuiToolkit::HelpMarker("Create a source from a file:\n"
ICON_FA_CARET_RIGHT " Video (*.mpg, *mov, *.avi, etc.)\n" ICON_FA_CARET_RIGHT " Video (*.mpg, *mov, *.avi, etc.)\n"
ICON_FA_CARET_RIGHT " Image (*.jpg, *.png, etc.)\n" ICON_FA_CARET_RIGHT " Image (*.jpg, *.png, etc.)\n"
ICON_FA_CARET_RIGHT " Vector graphics (*.svg)\n" ICON_FA_CARET_RIGHT " Vector graphics (*.svg)\n"
ICON_FA_CARET_RIGHT " vimix session (*.mix)\n\n" ICON_FA_CARET_RIGHT " vimix session (*.mix)\n"
"(Equivalent to dropping the file in the workspace)"); "\nNB: Equivalent to dropping the file in the workspace");
// get media file if dialog finished // get media file if dialog finished
if (fileimportdialog.closed()){ if (fileimportdialog.closed()){
// get the filename from this file dialog // get the filename from this file dialog
std::string open_filename = fileimportdialog.path(); std::string importpath = fileimportdialog.path();
// create a source with this file // switch to recent files
if (open_filename.empty()) { setNewMedia(MEDIA_RECENT, importpath);
new_source_preview_.setSource(); // open file
Log::Notify("No file selected."); if (!importpath.empty()) {
} else { std::string label = BaseToolkit::transliterate( sourceMediaFileCurrent );
std::string label = BaseToolkit::transliterate( open_filename ); new_source_preview_.setSource( Mixer::manager().createSourceFile(sourceMediaFileCurrent), label);
label = BaseToolkit::trunc_string(label, 35);
new_source_preview_.setSource( Mixer::manager().createSourceFile(open_filename), label);
} }
} }
// combo of recent media filenames // combo to offer lists
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("##RecentImport", IMGUI_LABEL_RECENT_FILES)) if (ImGui::BeginCombo("##SelectionNewMedia", BaseToolkit::trunc_string(Settings::application.recentImportFolders.path, 25).c_str() ))
{ {
std::list<std::string> recent = Settings::application.recentImport.filenames; // Mode MEDIA_RECENT : recent files
for (std::list<std::string>::iterator path = recent.begin(); path != recent.end(); ++path ) if (ImGui::Selectable( ICON_FA_LIST_OL IMGUI_LABEL_RECENT_FILES) ) {
{ setNewMedia(MEDIA_RECENT);
std::string recentpath(*path); }
if ( SystemToolkit::file_exists(recentpath)) { // Mode MEDIA_RECORDING : recent recordings
std::string label = BaseToolkit::transliterate( recentpath ); if (ImGui::Selectable( ICON_FA_LIST_UL IMGUI_LABEL_RECENT_RECORDS) ) {
label = BaseToolkit::trunc_string(label, 35); setNewMedia(MEDIA_RECORDING);
if (ImGui::Selectable( label.c_str() )) { }
new_source_preview_.setSource( Mixer::manager().createSourceFile(recentpath.c_str()), label); // Mode MEDIA_FOLDER : known folders
} for(auto foldername = Settings::application.recentImportFolders.filenames.begin();
foldername != Settings::application.recentImportFolders.filenames.end(); foldername++) {
std::string f = std::string(ICON_FA_FOLDER) + " " + BaseToolkit::trunc_string( *foldername, 40);
if (ImGui::Selectable( f.c_str() )) {
setNewMedia(MEDIA_FOLDER, *foldername);
} }
} }
// Add a folder for MEDIA_FOLDER
if (ImGui::Selectable( ICON_FA_FOLDER_PLUS " Add Folder") ) {
folderimportdialog.open();
}
ImGui::EndCombo(); ImGui::EndCombo();
} }
// return from thread for folder openning
if (folderimportdialog.closed() && !folderimportdialog.path().empty()) {
Settings::application.recentImportFolders.push(folderimportdialog.path());
setNewMedia(MEDIA_FOLDER, folderimportdialog.path());
}
// icons to clear lists or discarc folder
ImVec2 pos_top = ImGui::GetCursorPos();
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
if ( new_media_mode == MEDIA_FOLDER ) {
if (ImGuiToolkit::IconButton( ICON_FA_FOLDER_MINUS, "Discard folder")) {
Settings::application.recentImportFolders.filenames.remove(Settings::application.recentImportFolders.path);
if (Settings::application.recentImportFolders.filenames.empty())
// revert mode RECENT
setNewMedia(MEDIA_RECENT);
else
setNewMedia(MEDIA_FOLDER, Settings::application.recentImportFolders.filenames.front());
}
}
else if ( new_media_mode == MEDIA_RECORDING ) {
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear list")) {
Settings::application.recentRecordings.filenames.clear();
Settings::application.recentRecordings.front_is_valid = false;
setNewMedia(MEDIA_RECORDING);
}
}
else if ( new_media_mode == MEDIA_RECENT ) {
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear list")) {
Settings::application.recentImport.filenames.clear();
Settings::application.recentImport.front_is_valid = false;
setNewMedia(MEDIA_RECENT);
}
}
ImGui::PopStyleVar();
ImGui::SetCursorPos(pos_top);
// change session list if changed
if (new_media_mode_changed || Settings::application.recentImport.changed || Settings::application.recentRecordings.changed) {
// MODE RECENT
if ( new_media_mode == MEDIA_RECENT) {
// show list of recent imports
Settings::application.recentImport.validate();
sourceMediaFiles = Settings::application.recentImport.filenames;
Settings::application.recentImport.changed = false;
}
// MODE RECORDINGS
else if ( new_media_mode == MEDIA_RECORDING) {
// show list of recent records
Settings::application.recentRecordings.validate();
sourceMediaFiles = Settings::application.recentRecordings.filenames;
Settings::application.recentRecordings.changed = false;
}
// MODE LIST FOLDER
else if ( new_media_mode == MEDIA_FOLDER) {
// show list of media files in folder
sourceMediaFiles = SystemToolkit::list_directory( Settings::application.recentImportFolders.path, { MEDIA_FILES_PATTERN });
}
// indicate the list changed (do not change at every frame)
new_media_mode_changed = false;
}
// different labels for each mode
static const char *listboxname[3] = { "##NewSourceMediaRecent", "##NewSourceMediaRecording", "##NewSourceMediafolder"};
// display the import-list and detect if one was selected
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::ListBoxHeader(listboxname[new_media_mode], sourceMediaFiles.size(), CLAMP(sourceMediaFiles.size(), 4, 6)) ) {
// loop over list of files
for(auto it = sourceMediaFiles.begin(); it != sourceMediaFiles.end(); ++it) {
// build displayed file name
std::string filename = BaseToolkit::transliterate(*it);
std::string label = BaseToolkit::trunc_string(SystemToolkit::filename(filename), 25);
// add selectable item to ListBox; open if clickec
if (ImGui::Selectable( label.c_str(), sourceMediaFileCurrent.compare(*it) == 0 )) {
// set new source preview
new_source_preview_.setSource( Mixer::manager().createSourceFile(*it), filename);
// remember current list item
sourceMediaFileCurrent = *it;
}
}
ImGui::ListBoxFooter();
}
} }
// Folder Source creator // Folder Source creator
else if (Settings::application.source.new_type == 1){ else if (Settings::application.source.new_type == SOURCE_SEQUENCE){
bool update_new_source = false; bool update_new_source = false;
static DialogToolkit::MultipleImagesDialog _selectImagesDialog("Select Images"); static DialogToolkit::MultipleImagesDialog _selectImagesDialog("Select Images");
// clic button to load file // clic button to load file
if ( ImGui::Button( ICON_FA_IMAGES " Open images", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) ) { if ( ImGui::Button( ICON_FA_IMAGES " Open images", ImVec2(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, 0)) ) {
_selectedFiles.clear(); sourceSequenceFiles.clear();
_selectImagesDialog.open(); _selectImagesDialog.open();
} }
@@ -4140,15 +4281,15 @@ void Navigator::RenderNewPannel()
// return from thread for folder openning // return from thread for folder openning
if (_selectImagesDialog.closed()) { if (_selectImagesDialog.closed()) {
_selectedFiles = _selectImagesDialog.images(); sourceSequenceFiles = _selectImagesDialog.images();
if (_selectedFiles.empty()) if (sourceSequenceFiles.empty())
Log::Notify("No file selected."); Log::Notify("No file selected.");
// ask to reload the preview // ask to reload the preview
update_new_source = true; update_new_source = true;
} }
// multiple files selected // multiple files selected
if (_selectedFiles.size() > 1) { if (sourceSequenceFiles.size() > 1) {
// set framerate // set framerate
static int _fps = 30; static int _fps = 30;
@@ -4164,27 +4305,27 @@ void Navigator::RenderNewPannel()
} }
if (update_new_source) { if (update_new_source) {
std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(_selectedFiles) ); std::string label = BaseToolkit::transliterate( BaseToolkit::common_pattern(sourceSequenceFiles) );
label = BaseToolkit::trunc_string(label, 35); label = BaseToolkit::trunc_string(label, 35);
new_source_preview_.setSource( Mixer::manager().createSourceMultifile(_selectedFiles, _fps), label); new_source_preview_.setSource( Mixer::manager().createSourceMultifile(sourceSequenceFiles, _fps), label);
} }
} }
// single file selected // single file selected
else if (_selectedFiles.size() > 0) { else if (sourceSequenceFiles.size() > 0) {
ImGui::Text("Single file selected"); ImGui::Text("Single file selected");
if (update_new_source) { if (update_new_source) {
std::string label = BaseToolkit::transliterate( _selectedFiles.front() ); std::string label = BaseToolkit::transliterate( sourceSequenceFiles.front() );
label = BaseToolkit::trunc_string(label, 35); label = BaseToolkit::trunc_string(label, 35);
new_source_preview_.setSource( Mixer::manager().createSourceFile(_selectedFiles.front()), label); new_source_preview_.setSource( Mixer::manager().createSourceFile(sourceSequenceFiles.front()), label);
} }
} }
} }
// Internal Source creator // Internal Source creator
else if (Settings::application.source.new_type == 4){ else if (Settings::application.source.new_type == SOURCE_INTERNAL){
// 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);
@@ -4213,7 +4354,7 @@ void Navigator::RenderNewPannel()
ICON_FA_CARET_RIGHT " Clone other sources"); ICON_FA_CARET_RIGHT " Clone other sources");
} }
// Generated Source creator // Generated Source creator
else if (Settings::application.source.new_type == 3){ else if (Settings::application.source.new_type == SOURCE_GENERATED){
bool update_new_source = false; bool update_new_source = false;
@@ -4255,7 +4396,7 @@ void Navigator::RenderNewPannel()
} }
} }
// External source creator // External source creator
else if (Settings::application.source.new_type == 2){ else if (Settings::application.source.new_type == SOURCE_CONNECTED){
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("##External", "Select device")) if (ImGui::BeginCombo("##External", "Select device"))
@@ -4290,7 +4431,7 @@ void Navigator::RenderNewPannel()
// if a new source was added // if a new source was added
if (new_source_preview_.filled()) { if (new_source_preview_.filled()) {
// show preview // show preview
new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN, Settings::application.source.new_type != 2); new_source_preview_.Render(ImGui::GetContentRegionAvail().x IMGUI_RIGHT_ALIGN);
// ask to import the source in the mixer // ask to import the source in the mixer
ImGui::NewLine(); ImGui::NewLine();
if (new_source_preview_.ready() && ImGui::Button( ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) { if (new_source_preview_.ready() && ImGui::Button( ICON_FA_CHECK " Create", ImVec2(pannel_width_ - padding_width_, 0)) ) {
@@ -4340,13 +4481,13 @@ void Navigator::RenderMainPannelVimix()
ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN);
if (ImGui::BeginCombo("##SelectionSession", BaseToolkit::trunc_string(Settings::application.recentFolders.path, 25).c_str() )) { if (ImGui::BeginCombo("##SelectionSession", BaseToolkit::trunc_string(Settings::application.recentFolders.path, 25).c_str() )) {
// Option 0 : recent files // Mode 0 : recent files
if (ImGui::Selectable( ICON_FA_CLOCK IMGUI_LABEL_RECENT_FILES) ) { if (ImGui::Selectable( ICON_FA_LIST_OL IMGUI_LABEL_RECENT_FILES) ) {
Settings::application.recentFolders.path = IMGUI_LABEL_RECENT_FILES; Settings::application.recentFolders.path = IMGUI_LABEL_RECENT_FILES;
selection_session_mode = 0; selection_session_mode = 0;
selection_session_mode_changed = true; selection_session_mode_changed = true;
} }
// Options 1 : known folders // Mode 1 : known folders
for(auto foldername = Settings::application.recentFolders.filenames.begin(); for(auto foldername = Settings::application.recentFolders.filenames.begin();
foldername != Settings::application.recentFolders.filenames.end(); foldername++) { foldername != Settings::application.recentFolders.filenames.end(); foldername++) {
std::string f = std::string(ICON_FA_FOLDER) + " " + BaseToolkit::trunc_string( *foldername, 40); std::string f = std::string(ICON_FA_FOLDER) + " " + BaseToolkit::trunc_string( *foldername, 40);
@@ -4358,7 +4499,7 @@ void Navigator::RenderMainPannelVimix()
selection_session_mode_changed = true; selection_session_mode_changed = true;
} }
} }
// Option 2 : add a folder // Add a folder
if (ImGui::Selectable( ICON_FA_FOLDER_PLUS " Add Folder") ) if (ImGui::Selectable( ICON_FA_FOLDER_PLUS " Add Folder") )
customFolder.open(); customFolder.open();
ImGui::EndCombo(); ImGui::EndCombo();
@@ -4390,7 +4531,7 @@ void Navigator::RenderMainPannelVimix()
} }
} }
else { else {
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear history")) { if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear list")) {
Settings::application.recentSessions.filenames.clear(); Settings::application.recentSessions.filenames.clear();
Settings::application.recentSessions.front_is_valid = false; Settings::application.recentSessions.front_is_valid = false;
// reload the list next time // reload the list next time
@@ -4690,7 +4831,7 @@ void Navigator::RenderMainPannelVimix()
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.7);
if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear undo")) { if (ImGuiToolkit::IconButton( ICON_FA_BACKSPACE, "Clear history")) {
Action::manager().init(); Action::manager().init();
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@@ -5226,7 +5367,7 @@ void SourcePreview::setSource(Source *s, const string &label)
delete source_; delete source_;
source_ = s; source_ = s;
label_ = label; label_ = BaseToolkit::trunc_string(label, 35);
reset_ = true; reset_ = true;
} }
@@ -5237,7 +5378,7 @@ Source * SourcePreview::getSource()
return s; return s;
} }
void SourcePreview::Render(float width, bool controlbutton) void SourcePreview::Render(float width)
{ {
if(source_) { if(source_) {
// cancel if failed // cancel if failed
@@ -5270,15 +5411,21 @@ void SourcePreview::Render(float width, bool controlbutton)
FrameBuffer *frame = source_->frame(); FrameBuffer *frame = source_->frame();
ImVec2 preview_size(width, width / frame->aspectRatio()); ImVec2 preview_size(width, width / frame->aspectRatio());
ImGui::Image((void*)(uintptr_t) frame->texture(), preview_size); ImGui::Image((void*)(uintptr_t) frame->texture(), preview_size);
// if the source is playable and once its ready
if (controlbutton && source_->ready()) { if (source_->playable() && source_->ready()) {
ImVec2 pos = ImGui::GetCursorPos(); // activate the source on mouse over
ImGui::SameLine(); bool activate = ImGui::IsItemHovered();
bool active = source_->active(); if (source_->active() != activate)
if (ImGuiToolkit::IconToggle(12,7,1,8, &active)) source_->setActive(activate);
source_->setActive(active); // show icon '>' to indicate if we can activate it
ImGui::SetCursorPos(pos); if (!activate) {
ImVec2 pos = ImGui::GetCursorPos();
ImGui::SetCursorPos(pos + preview_size * ImVec2(0.5f, -0.6f));
ImGuiToolkit::Icon(12,7);
ImGui::SetCursorPos(pos);
}
} }
// information text
ImGuiToolkit::Icon(source_->icon().x, source_->icon().y); ImGuiToolkit::Icon(source_->icon().x, source_->icon().y);
ImGui::SameLine(0, 10); ImGui::SameLine(0, 10);
ImGui::Text("%s", label_.c_str()); ImGui::Text("%s", label_.c_str());

View File

@@ -20,6 +20,7 @@ struct ImVec2;
class MediaPlayer; class MediaPlayer;
class FrameBufferImage; class FrameBufferImage;
class FrameGrabber; class FrameGrabber;
class VideoRecorder;
class SourcePreview { class SourcePreview {
@@ -33,7 +34,7 @@ public:
void setSource(Source *s = nullptr, const std::string &label = ""); void setSource(Source *s = nullptr, const std::string &label = "");
Source *getSource(); Source *getSource();
void Render(float width, bool controlbutton = false); void Render(float width);
bool ready() const; bool ready() const;
inline bool filled() const { return source_ != nullptr; } inline bool filled() const { return source_ != nullptr; }
}; };
@@ -67,7 +68,6 @@ class Navigator
bool view_pannel_visible; bool view_pannel_visible;
bool selected_button[NAV_COUNT]; bool selected_button[NAV_COUNT];
int pattern_type; int pattern_type;
std::list<std::string> _selectedFiles;
void clearButtonSelection(); void clearButtonSelection();
void applyButtonSelection(int index); void applyButtonSelection(int index);
@@ -80,8 +80,6 @@ class Navigator
void RenderNewPannel(); void RenderNewPannel();
void RenderViewPannel(ImVec2 draw_pos, ImVec2 draw_size); void RenderViewPannel(ImVec2 draw_pos, ImVec2 draw_size);
SourcePreview new_source_preview_;
public: public:
Navigator(); Navigator();
@@ -92,7 +90,31 @@ public:
void togglePannelNew(); void togglePannelNew();
void showConfig(); void showConfig();
typedef enum {
MEDIA_RECENT = 0,
MEDIA_RECORDING,
MEDIA_FOLDER
} MediaCreateMode;
void setNewMedia(MediaCreateMode mode, std::string path = std::string());
void Render(); void Render();
private:
// for new source panel
typedef enum {
SOURCE_FILE = 0,
SOURCE_SEQUENCE,
SOURCE_CONNECTED,
SOURCE_GENERATED,
SOURCE_INTERNAL,
SOURCE_TYPES
} NewSourceType;
SourcePreview new_source_preview_;
std::list<std::string> sourceSequenceFiles;
std::list<std::string> sourceMediaFiles;
std::string sourceMediaFileCurrent;
MediaCreateMode new_media_mode;
bool new_media_mode_changed;
}; };
class ToolBox class ToolBox
@@ -199,7 +221,7 @@ class UserInterface
unsigned int screenshot_step; unsigned int screenshot_step;
// frame grabbers // frame grabbers
FrameGrabber *video_recorder_; VideoRecorder *video_recorder_;
#if defined(LINUX) #if defined(LINUX)
FrameGrabber *webcam_emulator_; FrameGrabber *webcam_emulator_;

View File

@@ -72,6 +72,7 @@
#define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput" #define IMGUI_TITLE_PREVIEW ICON_FA_DESKTOP " Ouput"
#define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?" #define IMGUI_TITLE_DELETE ICON_FA_BROOM " Delete?"
#define IMGUI_LABEL_RECENT_FILES " Recent files" #define IMGUI_LABEL_RECENT_FILES " Recent files"
#define IMGUI_LABEL_RECENT_RECORDS " Recent recordings"
#define IMGUI_RIGHT_ALIGN -3.5f * ImGui::GetTextLineHeightWithSpacing() #define IMGUI_RIGHT_ALIGN -3.5f * ImGui::GetTextLineHeightWithSpacing()
#define IMGUI_TOP_ALIGN 10 #define IMGUI_TOP_ALIGN 10
#define IMGUI_COLOR_OVERLAY IM_COL32(5, 5, 5, 150) #define IMGUI_COLOR_OVERLAY IM_COL32(5, 5, 5, 150)