diff --git a/data/strings/en.ini b/data/strings/en.ini index 94f3567f4..b11f9d482 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -545,6 +545,8 @@ go_up_button_tooltip = Up to parent folder new_folder_button_tooltip = New folder file_name = File name: file_type = File type: +pinned_folders = Pinned Folders +recent_folders = Recent Folders [filters] selected_cels = Selected diff --git a/laf b/laf index 3355825d6..75f29b27c 160000 --- a/laf +++ b/laf @@ -1 +1 @@ -Subproject commit 3355825d61b8d0d92ffdea970fd9e1434bd4ecca +Subproject commit 75f29b27c661e66e1549dc6e6a172f284cd9326b diff --git a/src/app/app_menus.cpp b/src/app/app_menus.cpp index 0c00f97ae..bc9276e68 100644 --- a/src/app/app_menus.cpp +++ b/src/app/app_menus.cpp @@ -474,17 +474,20 @@ bool AppMenus::rebuildRecentList() submenu = new Menu(); list_menuitem->setSubmenu(submenu); - auto it = App::instance()->recentFiles()->files_begin(); - auto end = App::instance()->recentFiles()->files_end(); - if (it != end) { + auto recent = App::instance()->recentFiles(); + base::paths files; + files.insert(files.end(), + recent->pinnedFiles().begin(), + recent->pinnedFiles().end()); + files.insert(files.end(), + recent->recentFiles().begin(), + recent->recentFiles().end()); + if (!files.empty()) { Params params; - - for (; it != end; ++it) { - const char* filename = it->c_str(); - params.set("filename", filename); - + for (const auto& fn : files) { + params.set("filename", fn.c_str()); menuitem = new AppMenuItem( - base::get_file_name(filename).c_str(), + base::get_file_name(fn).c_str(), cmd_open_file, params); submenu->addChild(menuitem); diff --git a/src/app/ini_file.cpp b/src/app/ini_file.cpp index 0e2de1afd..3acacefa5 100644 --- a/src/app/ini_file.cpp +++ b/src/app/ini_file.cpp @@ -274,4 +274,11 @@ void del_config_value(const char* section, const char* name) g_configs.back()->deleteValue(section, name); } +base::paths enum_config_keys(const char* section) +{ + base::paths keys; + g_configs.back()->getAllKeys(section, keys); + return keys; +} + } // namespace app diff --git a/src/app/ini_file.h b/src/app/ini_file.h index e1e37e890..8c595cea2 100644 --- a/src/app/ini_file.h +++ b/src/app/ini_file.h @@ -10,6 +10,7 @@ #pragma once #include "app/color.h" +#include "base/paths.h" #include "gfx/point.h" #include "gfx/rect.h" #include "gfx/size.h" @@ -58,6 +59,8 @@ namespace app { void del_config_value(const char* section, const char* name); + base::paths enum_config_keys(const char* section); + // Generic get/set_config_value functions inline const char* get_config_value(const char* section, const char* name, const char* value) { diff --git a/src/app/recent_files.cpp b/src/app/recent_files.cpp index 4a1b0a8e1..bde0e3cad 100644 --- a/src/app/recent_files.cpp +++ b/src/app/recent_files.cpp @@ -12,8 +12,8 @@ #include "app/recent_files.h" #include "app/ini_file.h" +#include "base/convert_to.h" #include "base/fs.h" -#include "fmt/format.h" #include #include @@ -21,8 +21,10 @@ namespace { -const char* kRecentFilesSection = "RecentFiles"; -const char* kRecentFoldersSection = "RecentPaths"; +const char* kSectionName[] = { "PinnedFiles", + "RecentFiles", + "PinnedPaths", + "RecentPaths" }; struct compare_path { std::string a; @@ -32,81 +34,40 @@ struct compare_path { } }; -std::string format_filename_var(const int i) { - return fmt::format("Filename{0:02d}", i); -} - -std::string format_folder_var(const int i) { - return fmt::format("Path{0:02d}", i); -} - } namespace app { RecentFiles::RecentFiles(const int limit) - : m_files(limit) - , m_paths(limit) + : m_limit(limit) { - for (int c=m_files.limit()-1; c>=0; c--) { - const char* filename = get_config_string(kRecentFilesSection, - format_filename_var(c).c_str(), - nullptr); - if (filename && *filename && base::is_file(filename)) { - std::string fn = normalizePath(filename); - m_files.addItem(fn, compare_path(fn)); - } - } - - for (int c=m_paths.limit()-1; c>=0; c--) { - const char* path = get_config_string(kRecentFoldersSection, - format_folder_var(c).c_str(), - nullptr); - if (path && *path) { - std::string p = normalizePath(path); - m_paths.addItem(p, compare_path(p)); - } - } + load(); } RecentFiles::~RecentFiles() { - // Save recent files - - int c = 0; - for (auto const& filename : m_files) { - set_config_string(kRecentFilesSection, - format_filename_var(c).c_str(), - filename.c_str()); - ++c; - } - for (; c= 0); + for (auto& list : m_paths) { + if (newLimit < list.size()) { + auto it = list.begin(); + std::advance(it, newLimit); + list.erase(it, list.end()); + } + } + + m_limit = newLimit; Changed(); } void RecentFiles::clear() { - m_files.clear(); - m_paths.clear(); + // Clear only recent items (not pinned items) + m_paths[kRecentFiles].clear(); + m_paths[kRecentFolders].clear(); Changed(); } -void RecentFiles::setFiles(base::paths paths) +void RecentFiles::setFiles(const base::paths& pinnedFiles, + const base::paths& recentFiles) { - m_files.clear(); - for (auto it=paths.rbegin(), end=paths.rend(); it!=end; ++it) { - const auto& p = *it; - m_files.addItem(p, compare_path(p)); - } + m_paths[kPinnedFiles] = pinnedFiles; + m_paths[kRecentFiles] = recentFiles; } -void RecentFiles::setFolders(base::paths paths) +void RecentFiles::setFolders(const base::paths& pinnedFolders, + const base::paths& recentFolders) { - m_paths.clear(); - for (auto it=paths.rbegin(), end=paths.rend(); it!=end; ++it) { - const auto& p = *it; - m_paths.addItem(p, compare_path(p)); - } + m_paths[kPinnedFolders] = pinnedFolders; + m_paths[kRecentFolders] = recentFolders; } std::string RecentFiles::normalizePath(const std::string& filename) @@ -170,4 +136,60 @@ std::string RecentFiles::normalizePath(const std::string& filename) return base::normalize_path(filename); } +void RecentFiles::addItem(base::paths& list, const std::string& fn) +{ + auto it = std::find_if(list.begin(), list.end(), compare_path(fn)); + + // If the item already exist in the list... + if (it != list.end()) { + // Move it to the first position + list.erase(it); + list.insert(list.begin(), fn); + return; + } + + if (m_limit > 0) + list.insert(list.begin(), fn); + + while (list.size() > m_limit) + list.erase(--list.end()); +} + +void RecentFiles::removeItem(base::paths& list, const std::string& fn) +{ + auto it = std::find_if(list.begin(), list.end(), compare_path(fn)); + if (it != list.end()) + list.erase(it); +} + +void RecentFiles::load() +{ + for (int i=0; i= 2 && base::is_directory(fn)))) { + std::string normalFn = normalizePath(fn); + m_paths[i].push_back(normalFn); + } + } + } +} + +void RecentFiles::save() +{ + for (int i=0; i(j).c_str(), + m_paths[i][j].c_str()); + } + } +} + } // namespace app diff --git a/src/app/recent_files.h b/src/app/recent_files.h index d5d54719f..86875ef8e 100644 --- a/src/app/recent_files.h +++ b/src/app/recent_files.h @@ -10,7 +10,6 @@ #pragma once #include "base/paths.h" -#include "base/recent_items.h" #include "obs/signal.h" #include @@ -18,18 +17,16 @@ namespace app { class RecentFiles { + enum { kPinnedFiles, + kRecentFiles, + kPinnedFolders, + kRecentFolders, + kCollections }; public: - typedef base::RecentItems List; - typedef List::iterator iterator; - typedef List::const_iterator const_iterator; - - // Iterate through recent files. - const_iterator files_begin() { return m_files.begin(); } - const_iterator files_end() { return m_files.end(); } - - // Iterate through recent paths. - const_iterator paths_begin() { return m_paths.begin(); } - const_iterator paths_end() { return m_paths.end(); } + const base::paths& pinnedFiles() { return m_paths[kPinnedFiles]; } + const base::paths& recentFiles() { return m_paths[kRecentFiles]; } + const base::paths& pinnedFolders() { return m_paths[kPinnedFolders]; } + const base::paths& recentFolders() { return m_paths[kRecentFolders]; } RecentFiles(const int limit); ~RecentFiles(); @@ -37,19 +34,25 @@ namespace app { void addRecentFile(const std::string& filename); void removeRecentFile(const std::string& filename); void removeRecentFolder(const std::string& dir); - void setLimit(const int n); + void setLimit(const int newLimit); void clear(); - void setFiles(base::paths paths); - void setFolders(base::paths paths); + void setFiles(const base::paths& pinnedFiles, + const base::paths& recentFiles); + void setFolders(const base::paths& pinnedFolders, + const base::paths& recentFolders); obs::signal Changed; private: std::string normalizePath(const std::string& filename); + void addItem(base::paths& list, const std::string& filename); + void removeItem(base::paths& list, const std::string& filename); + void load(); + void save(); - List m_files; - List m_paths; + base::paths m_paths[kCollections]; + int m_limit; }; } // namespace app diff --git a/src/app/ui/file_selector.cpp b/src/app/ui/file_selector.cpp index ad604c88e..7d471d050 100644 --- a/src/app/ui/file_selector.cpp +++ b/src/app/ui/file_selector.cpp @@ -20,6 +20,7 @@ #include "app/recent_files.h" #include "app/ui/file_list.h" #include "app/ui/file_list_view.h" +#include "app/ui/separator_in_view.h" #include "app/ui/skin/skin_theme.h" #include "app/widget_loader.h" #include "base/bind.h" @@ -36,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -675,14 +677,20 @@ void FileSelector::updateLocation() } // Add paths from recent files list - { - location()->addItem(""); - location()->addItem("-------- Recent Paths --------"); - - auto it = App::instance()->recentFiles()->paths_begin(); - auto end = App::instance()->recentFiles()->paths_end(); - for (; it != end; ++it) - location()->addItem(new CustomFolderNameItem(it->c_str())); + auto recent = App::instance()->recentFiles(); + if (!recent->pinnedFolders().empty()) { + auto sep = new SeparatorInView(Strings::file_selector_pinned_folders(), HORIZONTAL); + sep->setMinSize(gfx::Size(0, sep->sizeHint().h*2)); + location()->addItem(sep); + for (const auto& fn : recent->pinnedFolders()) + location()->addItem(new CustomFolderNameItem(fn.c_str())); + } + if (!recent->recentFolders().empty()) { + auto sep = new SeparatorInView(Strings::file_selector_recent_folders(), HORIZONTAL); + sep->setMinSize(gfx::Size(0, sep->sizeHint().h*2)); + location()->addItem(sep); + for (const auto& fn : recent->recentFolders()) + location()->addItem(new CustomFolderNameItem(fn.c_str())); } // Select the location diff --git a/src/app/ui/recent_listbox.cpp b/src/app/ui/recent_listbox.cpp index 0b76ca59d..777cb75b8 100644 --- a/src/app/ui/recent_listbox.cpp +++ b/src/app/ui/recent_listbox.cpp @@ -43,11 +43,13 @@ using namespace skin; class RecentFileItem : public DraggableWidget { public: - RecentFileItem(const std::string& file) + RecentFileItem(const std::string& file, + const bool pinned) : DraggableWidget("") , m_fullpath(file) , m_name(base::get_file_name(file)) - , m_path(base::get_file_path(file)) { + , m_path(base::get_file_path(file)) + , m_pinned(pinned) { initTheme(); } @@ -121,6 +123,7 @@ protected: parent->moveChildTo(this, moveTo); parent->layout(); } + saveConfig(); return true; } break; @@ -188,7 +191,7 @@ protected: } } - static_cast(parent())->updateRecentListFromUIItems(); + saveConfig(); } private: @@ -204,10 +207,14 @@ private: pinSize.w, pinSize.h); } + void saveConfig() { + static_cast(parent())->updateRecentListFromUIItems(); + } + std::string m_fullpath; std::string m_name; std::string m_path; - bool m_pinned = false; + bool m_pinned; }; ////////////////////////////////////////////////////////////////////// @@ -243,10 +250,17 @@ void RecentListBox::rebuildList() void RecentListBox::updateRecentListFromUIItems() { - base::paths paths; - for (auto item : children()) - paths.push_back(static_cast(item)->fullpath()); - onUpdateRecentListFromUIItems(paths); + base::paths pinnedPaths; + base::paths recentPaths; + for (auto item : children()) { + auto fi = static_cast(item); + if (fi->pinned()) + pinnedPaths.push_back(fi->fullpath()); + else + recentPaths.push_back(fi->fullpath()); + } + onUpdateRecentListFromUIItems(pinnedPaths, + recentPaths); } void RecentListBox::onScrollRegion(ui::ScrollRegionEvent& ev) @@ -266,10 +280,10 @@ RecentFilesListBox::RecentFilesListBox() void RecentFilesListBox::onRebuildList() { auto recent = App::instance()->recentFiles(); - auto it = recent->files_begin(); - auto end = recent->files_end(); - for (; it != end; ++it) - addChild(new RecentFileItem(it->c_str())); + for (const auto& fn : recent->pinnedFiles()) + addChild(new RecentFileItem(fn, true)); + for (const auto& fn : recent->recentFiles()) + addChild(new RecentFileItem(fn, false)); } void RecentFilesListBox::onClick(const std::string& path) @@ -286,9 +300,11 @@ void RecentFilesListBox::onClick(const std::string& path) UIContext::instance()->executeCommand(command, params); } -void RecentFilesListBox::onUpdateRecentListFromUIItems(const base::paths& paths) +void RecentFilesListBox::onUpdateRecentListFromUIItems(const base::paths& pinnedPaths, + const base::paths& recentPaths) { - App::instance()->recentFiles()->setFiles(paths); + App::instance()->recentFiles()->setFiles(pinnedPaths, + recentPaths); } ////////////////////////////////////////////////////////////////////// @@ -302,10 +318,10 @@ RecentFoldersListBox::RecentFoldersListBox() void RecentFoldersListBox::onRebuildList() { auto recent = App::instance()->recentFiles(); - auto it = recent->paths_begin(); - auto end = recent->paths_end(); - for (; it != end; ++it) - addChild(new RecentFileItem(*it)); + for (const auto& fn : recent->pinnedFolders()) + addChild(new RecentFileItem(fn, true)); + for (const auto& fn : recent->recentFolders()) + addChild(new RecentFileItem(fn, false)); } void RecentFoldersListBox::onClick(const std::string& path) @@ -322,9 +338,11 @@ void RecentFoldersListBox::onClick(const std::string& path) UIContext::instance()->executeCommand(command, params); } -void RecentFoldersListBox::onUpdateRecentListFromUIItems(const base::paths& paths) +void RecentFoldersListBox::onUpdateRecentListFromUIItems(const base::paths& pinnedPaths, + const base::paths& recentPaths) { - App::instance()->recentFiles()->setFolders(paths); + App::instance()->recentFiles()->setFolders(pinnedPaths, + recentPaths); } } // namespace app diff --git a/src/app/ui/recent_listbox.h b/src/app/ui/recent_listbox.h index 003f6568c..798d1f563 100644 --- a/src/app/ui/recent_listbox.h +++ b/src/app/ui/recent_listbox.h @@ -32,7 +32,8 @@ namespace app { virtual void onRebuildList() = 0; virtual void onClick(const std::string& path) = 0; - virtual void onUpdateRecentListFromUIItems(const base::paths& paths) = 0; + virtual void onUpdateRecentListFromUIItems(const base::paths& pinnedPaths, + const base::paths& recentPaths) = 0; private: void rebuildList(); @@ -48,7 +49,8 @@ namespace app { private: void onRebuildList() override; void onClick(const std::string& path) override; - void onUpdateRecentListFromUIItems(const base::paths& paths) override; + void onUpdateRecentListFromUIItems(const base::paths& pinnedPaths, + const base::paths& recentPaths) override; }; class RecentFoldersListBox : public RecentListBox { @@ -58,7 +60,8 @@ namespace app { private: void onRebuildList() override; void onClick(const std::string& path) override; - void onUpdateRecentListFromUIItems(const base::paths& paths) override; + void onUpdateRecentListFromUIItems(const base::paths& pinnedPaths, + const base::paths& recentPaths) override; }; } // namespace app