From fb3ee2aa8c6e1a889b0c541f10a1fdb9a392c8ac Mon Sep 17 00:00:00 2001 From: Bruno Herbelin Date: Sun, 3 Sep 2023 00:08:30 +0200 Subject: [PATCH] New button to reorder the list of sessions and of media files In navigator panel, the list of sessions can be reordered either alphabetically or by file modification date. Same for list of media files for creating a new media source. --- rsc/images/icons.dds | Bin 1638528 -> 1638528 bytes src/Settings.h | 4 ++ src/SystemToolkit.cpp | 68 +++++++++++++++++++++++++- src/SystemToolkit.h | 20 ++++++-- src/UserInterfaceManager.cpp | 90 ++++++++++++++++++----------------- src/UserInterfaceManager.h | 3 ++ 6 files changed, 136 insertions(+), 49 deletions(-) diff --git a/rsc/images/icons.dds b/rsc/images/icons.dds index 270174cabeed5fd30e8a226efa2bdb38b907a7ff..a69be9d07f1bd14e0e6716b06c692659a80f4723 100644 GIT binary patch delta 2299 zcmcguTWk$M82vhoe3XWG7UhLF}D?(unLKr26!k|Mr#Ecq+A8t`|4PtLbPGcxTnC#T*hx-eiMQ|#hC~mM8(WE3FyYV2 zzm(Vlz2JbFHkqhkxH?T{d>Dpd0r=W*J~&ugYy2~8!vNHR;S-^WL!>P}gsT2W5>6fo zRD*WRC3~12C!dY@bCd)_Y4!3Y=Wc3`Pg&s92y|!X@%~jV{wSbaLeU?u-{!A^Ekkq? zOa7BhQ~VjKf}x&|HqYPY@1j3MsCqOpK7uYeqg;|D$ujUlb%jxFL0!jF6H|&OawHnuu)<^V_hP1+N zl@oG8?kt5HGUe&=bQX`QTpk|JfQKhYt|a5wv5Vxew{fy0*$U2CEHj`=LC4wmoWBrI zzLK~8{ISBGKSs-c@W+o?66v#m$JpxR^02$6`_hZ?U1@l$c;`#P5_d?MN$Df9OMXkT zBymgKkXyhPtD!Yg{q2DZN~B8`s(ih4$$kMn7npK&{QMf>5`Hwu|8C>tyJU)V$r3eh zjdaO6pNAWjE?K1V^@3+6;8_G-s65>BLg9Q##KtjLa)7i7mki+tU4Ea1@x7zqc1jH$ z6gNEOV=f;ASaKXae@@M3<3X|%4?BgkHqJMA`UgDZkrnXB=Q#&#bbFA8cb9R~rF-e_?r5Z$cHSm8lgBr+ z?qdDCN&BLaCVFFreu2eIZA}>e3weE_ty0HkU^B6mV2ffa#Wn?78EdPY%3u5d7{Bu! delta 1466 zcmaJ=Ye-Z<6h3!#UDwU#-d(lC9;-o7Xsu9!MWqB~PkL$5i|m0BMMgh@)^ay*8It79 zYN|h*6a^94_TWN4Qu8e%DP;F|aYFD#VhdN5lR!83@)%gW7JVZ9GvjJ=N4>M?2Z;5IMSnbz)MwLXtDPuo&n1yR+|fHYLTQV%fd)&6 zPd@F5-NrDF8#&{&quSxhL8LLUbXdZCJcXh5s&#Yp%hO4dvj9K@;UToZiqDe{pWK9rm!6n#gZZvWjf1Jn;Sx^j(Nn)M^WD_68VT>k< zcmE^vRO$GCxA0~+R)Nj5(BtJ{3pBg2pX4c;0K_KX)`a8^T^*h*O#X4qTSO-?IJhRj19pv z*dJp|M$Z~No1sfWFOMdgxE^|skC?vk)`MH<`U~k(b?r2%|1IkTPu$&X(qbbvo~SZ? z%~wi0ipeRdf=U~StN3akC?W-aK0l-+OA6WcfF-3w&6lemyGk0In!lQU-02_=SSX3j z3F3QM+se$PLfwC#seeKR+Smn!jjfJ!|$M0esE7rD4D#eB6W~9o@+< z2OxuYoS`Z0E+z-5?WjF_+>S4%>_dTA0QqEtUmGh&*IsZ@DzBwiPL`t(G4pjoCsQ|M z6<`>KFhnZibk`JnIhUtxhH*EhY;T_x7Ny=+JP->+*%S<#uR_1{o~6^;O3Plc4>d(L zd@zFTeNZT{UlB(d!qTwtd5^NLNuI7v=FESxucY!ZlCIw!BCXD{ZSVnt;1T<4q);Bd zFr|=VwK#~T6pc^9Otjm5rS+Ius( diff --git a/src/Settings.h b/src/Settings.h index 0b80f1f..87aefc9 100644 --- a/src/Settings.h +++ b/src/Settings.h @@ -321,10 +321,12 @@ struct Application std::vector windows; // recent files histories + int orderingSessions; History recentSessions; History recentFolders; History recentImport; History recentImportFolders; + int orderingImportFolder; History recentRecordings; std::map< std::string, std::string > dialogRecentFolder; @@ -361,6 +363,8 @@ struct Application windows = std::vector(1+MAX_OUTPUT_WINDOW); windows[0].w = 1600; windows[0].h = 900; + orderingSessions = 3; + orderingImportFolder = 3; } }; diff --git a/src/SystemToolkit.cpp b/src/SystemToolkit.cpp index ab35ff8..c97935e 100644 --- a/src/SystemToolkit.cpp +++ b/src/SystemToolkit.cpp @@ -280,6 +280,70 @@ string SystemToolkit::full_filename(const std::string& path, const string &filen return fullfilename; } +unsigned long SystemToolkit::file_modification_time(const std::string& path) +{ + if (file_exists(path)) { + struct stat statsfile; + // fill statistics of given file path + if( stat( path.c_str(), &statsfile) > -1 ) { + // return modification time + return (unsigned long) statsfile.st_mtime; + } + } + + return 0; +} + +std::string SystemToolkit::file_modification_time_string(const std::string& path) +{ + ostringstream oss; + + if (file_exists(path)) { + struct stat statsfile; + // fill statistics of given file path + if( stat( path.c_str(), &statsfile) > -1 ) { + // read modification time + tm *datetime = localtime(&statsfile.st_mtime); + ostringstream oss; + oss << setw(4) << setfill('0') << to_string(datetime->tm_year + 1900); + oss << setw(2) << setfill('0') << to_string(datetime->tm_mon + 1); + oss << setw(2) << setfill('0') << to_string(datetime->tm_mday ); + oss << setw(2) << setfill('0') << to_string(datetime->tm_hour ); + oss << setw(2) << setfill('0') << to_string(datetime->tm_min ); + oss << setw(2) << setfill('0') << to_string(datetime->tm_sec ); + } + + } + + return oss.str(); +} + + +void SystemToolkit::reorder_file_list(std::list &filelist, Ordering m) +{ + if ( m >= DATE ) { + auto dateComparator = [](const std::string &a, const std::string &b) { + return SystemToolkit::file_modification_time(a) < SystemToolkit::file_modification_time(b); + }; + filelist.sort( dateComparator ); + if ( m == DATE_INVERSE ) + filelist.reverse(); + } + else { + auto alphaComparator = [](const std::string &a, const std::string &b) { + std::string _a = a; + std::string _b = b; + std::transform(_a.begin(), _a.end(), _a.begin(), ::tolower); + std::transform(_b.begin(), _b.end(), _b.begin(), ::tolower); + return _a < _b; + }; + filelist.sort( alphaComparator ); + if ( m == ALPHA_INVERSE ) + filelist.reverse(); + } +} + + bool SystemToolkit::file_exists(const string& path) { if (path.empty()) @@ -307,7 +371,7 @@ string SystemToolkit::path_directory(const string& path) return directorypath; } -list SystemToolkit::list_directory(const string& path, const list& patterns) +list SystemToolkit::list_directory(const string& path, const list& patterns, Ordering m) { list ls; @@ -329,7 +393,7 @@ list SystemToolkit::list_directory(const string& path, const list list_directory(const std::string& path, const std::list &patterns); - // builds a path relative to 'relativeTo' to reach file at 'absolutePath' (e.g. /a/b/c/d rel to /a/b/e -> ../c/d) std::string path_relative_to_path(const std::string& absolutePath, const std::string& relativeTo); @@ -64,6 +61,23 @@ namespace SystemToolkit // generates a filename at given path, with basename and date prefix std::string filename_dateprefix(const std::string& path, const std::string& base, const std::string& extension); + // Get modification time of file, as string YYYYMMDDHHmmss + unsigned long file_modification_time(const std::string& path); + std::string file_modification_time_string(const std::string& path); + + + typedef enum { + ALPHA = 0, + ALPHA_INVERSE = 1, + DATE = 2, + DATE_INVERSE = 3 + } Ordering; + // + void reorder_file_list(std::list &filelist, Ordering m); + + // list all files of a directory mathing the given filter extension (if any) + std::list list_directory(const std::string& path, const std::list &patterns, Ordering m = ALPHA); + // true of file exists bool file_exists(const std::string& path); diff --git a/src/UserInterfaceManager.cpp b/src/UserInterfaceManager.cpp index a856812..9619054 100644 --- a/src/UserInterfaceManager.cpp +++ b/src/UserInterfaceManager.cpp @@ -2649,6 +2649,11 @@ void UserInterface::RenderHelp() /// /// NAVIGATOR /// +/// + +std::vector< std::pair > Navigator::icons_ordering_files = { {2,12}, {3,12}, {4,12}, {5,12} }; +std::vector< std::string > Navigator::tooltips_ordering_files = { "Alphabetical", "Invert alphabetical", "Older files first", "Recent files first" }; + Navigator::Navigator() { // default geometry @@ -3480,7 +3485,8 @@ void Navigator::RenderNewPannel() // 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 }); + sourceMediaFiles = SystemToolkit::list_directory( Settings::application.recentImportFolders.path, { MEDIA_FILES_PATTERN }, + (SystemToolkit::Ordering) Settings::application.orderingImportFolder); } // indicate the list changed (do not change at every frame) new_media_mode_changed = false; @@ -3524,9 +3530,10 @@ void Navigator::RenderNewPannel() ImGui::ListBoxFooter(); } + // Supplementary icons to manage the list + ImVec2 pos_bot = ImGui::GetCursorPos(); + // Bottom Right side of the list: helper and options of Recent Recordings if (new_media_mode == MEDIA_RECORDING) { - // Bottom Right side of the list: helper and options - ImVec2 pos_bot = ImGui::GetCursorPos(); ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - 2.f * ImGui::GetFrameHeightWithSpacing())); ImGuiToolkit::HelpToolTip("Recently recorded videos (lastest on top). Clic on a filename to open.\n\n" ICON_FA_CHEVRON_CIRCLE_RIGHT " Auto-preload prepares this panel with the " @@ -3541,9 +3548,18 @@ void Navigator::RenderNewPannel() new_source_preview_.setSource( Mixer::manager().createSourceFile(sourceMediaFileCurrent), label); } } - // come back... - ImGui::SetCursorPos(pos_bot); } + // Top right of Media folder list + else if (new_media_mode == MEDIA_FOLDER) { + // ordering list + ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y) ); + ImGui::PushID("##new_media_mode_changed"); + if ( ImGuiToolkit::IconMultistate(icons_ordering_files, &Settings::application.orderingImportFolder, tooltips_ordering_files) ) + new_media_mode_changed = true; + ImGui::PopID(); + } + // come back... + ImGui::SetCursorPos(pos_bot); } // Sequence Source creator @@ -4103,14 +4119,18 @@ void Navigator::RenderMainPannelVimix() // show list of recent sessions Settings::application.recentSessions.validate(); sessions_list = Settings::application.recentSessions.filenames; - Settings::application.recentSessions.changed = false; + SystemToolkit::reorder_file_list( sessions_list, (SystemToolkit::Ordering) Settings::application.orderingSessions); } // selection MODE 1 : LIST FOLDER else if ( selection_session_mode == 1) { // show list of vimix files in folder - sessions_list = SystemToolkit::list_directory( Settings::application.recentFolders.path, { VIMIX_FILE_PATTERN }); + sessions_list = SystemToolkit::list_directory( Settings::application.recentFolders.path, { VIMIX_FILE_PATTERN }, + (SystemToolkit::Ordering) Settings::application.orderingSessions); } + // indicate the list changed (do not change at every frame) + Settings::application.recentSessions.changed = false; + Settings::application.recentFolders.changed = false; selection_session_mode_changed = false; _file_over = sessions_list.end(); _displayed_over = sessions_list.end(); @@ -4219,8 +4239,16 @@ void Navigator::RenderMainPannelVimix() if (ImGui::IsItemHovered()) ImGuiToolkit::ToolTip("New session", SHORTCUT_NEW_FILE); + // ordering list + ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_top.y + ImGui::GetFrameHeightWithSpacing()) ); + ImGui::PushID("##selection_session_mode_changed"); + if ( ImGuiToolkit::IconMultistate(icons_ordering_files, &Settings::application.orderingSessions, tooltips_ordering_files) ) + selection_session_mode_changed = true; + ImGui::PopID(); + + // help indicator ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - 2.f * ImGui::GetFrameHeightWithSpacing())); - ImGuiToolkit::HelpToolTip("Here are listed either all recent files or all the sessions files inside a selected folder (*.mix) .\n\n" + ImGuiToolkit::HelpToolTip("Here are listed either the recent files or all the sessions files (*.mix) in a selected folder.\n\n" "Double-clic on a filename to open the session.\n\n" ICON_FA_ARROW_CIRCLE_RIGHT " Smooth transition " "performs cross fading to the opened session."); @@ -4262,35 +4290,6 @@ void Navigator::RenderMainPannelVimix() ImGui::InputText("##Info", (char *)info.c_str(), info.size(), ImGuiInputTextFlags_ReadOnly); ImGui::PopStyleColor(1); - // Kept for later? Larger info box with more details on the session file... - // ImGuiTextBuffer info; - // if (!sessionfilename.empty()) - // info.appendf("%s\n", SystemToolkit::filename(sessionfilename).c_str()); - // else - // info.append("\n"); - // info.appendf("%dx%dpx", output->width(), output->height()); - // if (p.x > -1) - // info.appendf(", %s", FrameBuffer::aspect_ratio_name[p.x]); - // // content info - // const uint N = Mixer::manager().session()->numSource(); - // if (N > 1) - // info.appendf("\n%d sources", N); - // else if (N > 0) - // info.append("\n1 source"); - // const size_t M = MediaPlayer::registered().size(); - // if (M > 0) { - // info.appendf("\n%d media files:", M); - // for (auto mit = MediaPlayer::begin(); mit != MediaPlayer::end(); ++mit) - // info.appendf("\n- %s", SystemToolkit::filename((*mit)->filename()).c_str()); - // } - // // Show info text bloc (multi line, dark background) - // ImGuiToolkit::PushFont( ImGuiToolkit::FONT_MONO ); - // ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.14f, 0.14f, 0.14f, 0.9f)); - // ImGui::SetNextItemWidth(IMGUI_RIGHT_ALIGN); - // ImGui::InputTextMultiline("##Info", (char *)info.c_str(), info.size(), ImVec2(IMGUI_RIGHT_ALIGN, 2*ImGui::GetTextLineHeightWithSpacing()), ImGuiInputTextFlags_ReadOnly); - // ImGui::PopStyleColor(1); - // ImGui::PopFont(); - // change resolution (height only) // get parameters to edit resolution glm::ivec2 preset = RenderView::presetFromResolution(output->resolution()); @@ -4375,7 +4374,7 @@ void Navigator::RenderMainPannelVimix() // Thumbnail static Thumbnail _file_thumbnail; static FrameBufferImage *thumbnail = nullptr; - if ( ImGui::Button( ICON_FA_TAG " New thumbnail", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) { + if ( ImGui::Button( ICON_FA_TAG " Create thumbnail", ImVec2(IMGUI_RIGHT_ALIGN, 0)) ) { Mixer::manager().session()->setThumbnail(); thumbnail = nullptr; } @@ -4647,8 +4646,8 @@ void Navigator::RenderMainPannelVimix() ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - 2.f * ImGui::GetFrameHeightWithSpacing())); ImGuiToolkit::HelpToolTip("Previous versions of the session (latest on top). " "Double-clic on a version to restore it.\n\n" - ICON_FA_CODE_BRANCH " Iterative saving automatically " - "keeps a version each time a session is saved."); + ICON_FA_CODE_BRANCH " With iterative saving on, a new version " + "is kept each time the session is saved."); // toggle button for versioning ImGui::SetCursorPos( ImVec2( pannel_width_ IMGUI_RIGHT_ALIGN, pos_bot.y - ImGui::GetFrameHeightWithSpacing()) ); ImGuiToolkit::ButtonToggle(" " ICON_FA_CODE_BRANCH " ", &Settings::application.save_version_snapshot,"Iterative saving"); @@ -4803,8 +4802,8 @@ void Navigator::RenderMousePointerSelector(const ImVec2 &size) ImGui::SameLine(0, IMGUI_SAME_LINE * 3); ImGuiToolkit::ButtonToggle(Settings::application.mouse_pointer_lock ? ICON_FA_LOCK ALT_LOCK : ICON_FA_UNLOCK ALT_LOCK, &Settings::application.mouse_pointer_lock, - "Activate the selected snap mouse pointer by pressing the [" ALT_MOD "] key.\n\n" - ICON_FA_LOCK ALT_LOCK " keeps the snap mouse pointer active."); + "Activate the selected Snap mouse cursor by pressing the [" ALT_MOD "] key.\n\n" + ICON_FA_LOCK ALT_LOCK " keeps the Snap mouse cursor active."); // slider to adjust strength of the mouse pointer ImGui::SetNextItemWidth( IMGUI_RIGHT_ALIGN ); @@ -4821,12 +4820,15 @@ void Navigator::RenderMousePointerSelector(const ImVec2 &size) } // special case of GRID else { - static const char* grid_names[Grid::UNIT_ONE+1] = { "Precise (0.05)", "Small (0.1)", "Default (0.2)", "Large (0.5)", "Huge (1.0)"}; + static const char* grid_names[Grid::UNIT_ONE+1] = { "Precise", "Small", "Default", "Large", "Huge"}; int grid_current = (Grid::Units) round( *val * 4.f) ; const char* grid_current_name = (grid_current >= 0 && grid_current <= Grid::UNIT_ONE) ? grid_names[grid_current] : "Unknown"; - if (ImGui::SliderInt("##slidergrid", &grid_current, 0, Grid::UNIT_ONE, grid_current_name) ) { + if (ImGui::SliderInt("##slidergrid", &grid_current, 0, Grid::UNIT_ONE, grid_current_name) ) *val = (float) grid_current * 0.25f; + if (ImGui::IsItemHovered() && g.IO.MouseWheel != 0.f ){ + *val += 0.25f * g.IO.MouseWheel; + *val = CLAMP( *val, 0.f, 1.f); } } ImGui::SameLine(0, IMGUI_SAME_LINE); diff --git a/src/UserInterfaceManager.h b/src/UserInterfaceManager.h index 644c870..9f18fc9 100644 --- a/src/UserInterfaceManager.h +++ b/src/UserInterfaceManager.h @@ -110,6 +110,9 @@ private: MediaCreateMode new_media_mode; bool new_media_mode_changed; Source *source_to_replace; + + static std::vector< std::pair > icons_ordering_files; + static std::vector< std::string > tooltips_ordering_files; }; class ToolBox