|
@@ -12,7 +12,6 @@
|
|
|
namespace fs = std::filesystem;
|
|
namespace fs = std::filesystem;
|
|
|
|
|
|
|
|
// --- Natural Sort Helper ---
|
|
// --- Natural Sort Helper ---
|
|
|
-// Sorts strings like humans do: "img1.jpg", "img2.jpg", "img10.jpg"
|
|
|
|
|
struct NaturalSort {
|
|
struct NaturalSort {
|
|
|
bool operator()(const fs::path& a, const fs::path& b) const {
|
|
bool operator()(const fs::path& a, const fs::path& b) const {
|
|
|
std::string s1 = a.filename().string();
|
|
std::string s1 = a.filename().string();
|
|
@@ -51,7 +50,6 @@ public:
|
|
|
set_title("Visual Renamer Pro");
|
|
set_title("Visual Renamer Pro");
|
|
|
set_default_size(1200, 800);
|
|
set_default_size(1200, 800);
|
|
|
|
|
|
|
|
- // Connect the background thread signal to the UI thread
|
|
|
|
|
m_Dispatcher.connect(sigc::mem_fun(*this, &RenamerWindow::on_worker_notification));
|
|
m_Dispatcher.connect(sigc::mem_fun(*this, &RenamerWindow::on_worker_notification));
|
|
|
|
|
|
|
|
// --- Layout ---
|
|
// --- Layout ---
|
|
@@ -65,7 +63,6 @@ public:
|
|
|
|
|
|
|
|
// Open Button
|
|
// Open Button
|
|
|
Gtk::Image* icon_open = Gtk::manage(new Gtk::Image);
|
|
Gtk::Image* icon_open = Gtk::manage(new Gtk::Image);
|
|
|
- // "folder-open" is a standard icon name in almost all Linux themes
|
|
|
|
|
icon_open->set_from_icon_name("folder-open", Gtk::ICON_SIZE_BUTTON);
|
|
icon_open->set_from_icon_name("folder-open", Gtk::ICON_SIZE_BUTTON);
|
|
|
m_BtnOpen.set_image(*icon_open);
|
|
m_BtnOpen.set_image(*icon_open);
|
|
|
m_BtnOpen.set_label("Open Folder");
|
|
m_BtnOpen.set_label("Open Folder");
|
|
@@ -86,10 +83,9 @@ public:
|
|
|
m_ComboSize.append("Small (100px)");
|
|
m_ComboSize.append("Small (100px)");
|
|
|
m_ComboSize.append("Medium (250px)");
|
|
m_ComboSize.append("Medium (250px)");
|
|
|
m_ComboSize.append("Large (500px)");
|
|
m_ComboSize.append("Large (500px)");
|
|
|
- m_ComboSize.set_active(1); // Default to Medium (Index 1)
|
|
|
|
|
|
|
+ m_ComboSize.set_active(1);
|
|
|
m_ComboSize.signal_changed().connect(sigc::mem_fun(*this, &RenamerWindow::on_size_changed));
|
|
m_ComboSize.signal_changed().connect(sigc::mem_fun(*this, &RenamerWindow::on_size_changed));
|
|
|
m_Toolbar.pack_start(m_ComboSize, Gtk::PACK_SHRINK, 5);
|
|
m_Toolbar.pack_start(m_ComboSize, Gtk::PACK_SHRINK, 5);
|
|
|
- // ---------------------
|
|
|
|
|
|
|
|
|
|
// Rename Button
|
|
// Rename Button
|
|
|
m_BtnRename.set_label("Rename Files");
|
|
m_BtnRename.set_label("Rename Files");
|
|
@@ -115,7 +111,6 @@ public:
|
|
|
m_IconView.set_column_spacing(10);
|
|
m_IconView.set_column_spacing(10);
|
|
|
m_IconView.set_row_spacing(10);
|
|
m_IconView.set_row_spacing(10);
|
|
|
|
|
|
|
|
- // Use .index() to prevent compile error (int expected)
|
|
|
|
|
m_IconView.set_tooltip_column(m_Columns.m_col_orig_name.index());
|
|
m_IconView.set_tooltip_column(m_Columns.m_col_orig_name.index());
|
|
|
|
|
|
|
|
m_IconView.signal_button_press_event().connect(sigc::mem_fun(*this, &RenamerWindow::on_iconview_button_press), false);
|
|
m_IconView.signal_button_press_event().connect(sigc::mem_fun(*this, &RenamerWindow::on_iconview_button_press), false);
|
|
@@ -127,7 +122,7 @@ public:
|
|
|
m_Statusbar.push("Ready.");
|
|
m_Statusbar.push("Ready.");
|
|
|
m_VBox.pack_end(m_Statusbar, Gtk::PACK_SHRINK);
|
|
m_VBox.pack_end(m_Statusbar, Gtk::PACK_SHRINK);
|
|
|
|
|
|
|
|
- // --- Drag and Drop (System -> Window) ---
|
|
|
|
|
|
|
+ // --- Drag and Drop ---
|
|
|
std::vector<Gtk::TargetEntry> listTargets;
|
|
std::vector<Gtk::TargetEntry> listTargets;
|
|
|
listTargets.push_back(Gtk::TargetEntry("text/uri-list"));
|
|
listTargets.push_back(Gtk::TargetEntry("text/uri-list"));
|
|
|
drag_dest_set(listTargets, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_COPY);
|
|
drag_dest_set(listTargets, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_COPY);
|
|
@@ -148,7 +143,6 @@ public:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
protected:
|
|
|
- // Widgets
|
|
|
|
|
Gtk::Box m_VBox, m_Toolbar;
|
|
Gtk::Box m_VBox, m_Toolbar;
|
|
|
Gtk::Button m_BtnOpen, m_BtnRename;
|
|
Gtk::Button m_BtnOpen, m_BtnRename;
|
|
|
Gtk::Label m_LblPattern, m_LblSize;
|
|
Gtk::Label m_LblPattern, m_LblSize;
|
|
@@ -159,7 +153,6 @@ protected:
|
|
|
Gtk::Statusbar m_Statusbar;
|
|
Gtk::Statusbar m_Statusbar;
|
|
|
Gtk::Menu m_ContextMenu;
|
|
Gtk::Menu m_ContextMenu;
|
|
|
|
|
|
|
|
- // Model
|
|
|
|
|
class ModelColumns : public Gtk::TreeModel::ColumnRecord {
|
|
class ModelColumns : public Gtk::TreeModel::ColumnRecord {
|
|
|
public:
|
|
public:
|
|
|
ModelColumns() { add(m_col_path); add(m_col_name); add(m_col_pixbuf); add(m_col_orig_name); }
|
|
ModelColumns() { add(m_col_path); add(m_col_name); add(m_col_pixbuf); add(m_col_orig_name); }
|
|
@@ -171,7 +164,8 @@ protected:
|
|
|
ModelColumns m_Columns;
|
|
ModelColumns m_Columns;
|
|
|
Glib::RefPtr<Gtk::ListStore> m_RefListStore;
|
|
Glib::RefPtr<Gtk::ListStore> m_RefListStore;
|
|
|
|
|
|
|
|
- // Threading
|
|
|
|
|
|
|
+ // State
|
|
|
|
|
+ std::string m_current_path; // <--- Tracks current folder for reloading
|
|
|
std::thread m_WorkerThread;
|
|
std::thread m_WorkerThread;
|
|
|
std::atomic<bool> m_stop_flag{false};
|
|
std::atomic<bool> m_stop_flag{false};
|
|
|
Glib::Dispatcher m_Dispatcher;
|
|
Glib::Dispatcher m_Dispatcher;
|
|
@@ -187,11 +181,9 @@ protected:
|
|
|
return 250;
|
|
return 250;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Called when Dropdown Changes
|
|
|
|
|
void on_size_changed() {
|
|
void on_size_changed() {
|
|
|
int new_size = get_current_size();
|
|
int new_size = get_current_size();
|
|
|
|
|
|
|
|
- // 1. Collect current files (preserve order)
|
|
|
|
|
std::vector<fs::path> current_files;
|
|
std::vector<fs::path> current_files;
|
|
|
auto children = m_RefListStore->children();
|
|
auto children = m_RefListStore->children();
|
|
|
for(auto iter = children.begin(); iter != children.end(); ++iter) {
|
|
for(auto iter = children.begin(); iter != children.end(); ++iter) {
|
|
@@ -200,11 +192,9 @@ protected:
|
|
|
|
|
|
|
|
if (current_files.empty()) return;
|
|
if (current_files.empty()) return;
|
|
|
|
|
|
|
|
- // 2. Stop Thread
|
|
|
|
|
m_stop_flag = true;
|
|
m_stop_flag = true;
|
|
|
if (m_WorkerThread.joinable()) m_WorkerThread.join();
|
|
if (m_WorkerThread.joinable()) m_WorkerThread.join();
|
|
|
|
|
|
|
|
- // 3. Clear UI & Restart Thread
|
|
|
|
|
m_RefListStore->clear();
|
|
m_RefListStore->clear();
|
|
|
m_IconView.set_item_width(new_size);
|
|
m_IconView.set_item_width(new_size);
|
|
|
m_Statusbar.push("Resizing...");
|
|
m_Statusbar.push("Resizing...");
|
|
@@ -214,6 +204,7 @@ protected:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void start_loading_folder(std::string path) {
|
|
void start_loading_folder(std::string path) {
|
|
|
|
|
+ m_current_path = path; // <--- Store path
|
|
|
m_stop_flag = true;
|
|
m_stop_flag = true;
|
|
|
if (m_WorkerThread.joinable()) m_WorkerThread.join();
|
|
if (m_WorkerThread.joinable()) m_WorkerThread.join();
|
|
|
|
|
|
|
@@ -246,7 +237,6 @@ protected:
|
|
|
start_loading_folder(filename);
|
|
start_loading_folder(filename);
|
|
|
context->drag_finish(true, false, time);
|
|
context->drag_finish(true, false, time);
|
|
|
} else {
|
|
} else {
|
|
|
- // Load parent folder if a single file is dropped
|
|
|
|
|
start_loading_folder(fs::path(filename).parent_path().string());
|
|
start_loading_folder(fs::path(filename).parent_path().string());
|
|
|
context->drag_finish(true, false, time);
|
|
context->drag_finish(true, false, time);
|
|
|
}
|
|
}
|
|
@@ -254,9 +244,7 @@ protected:
|
|
|
|
|
|
|
|
bool on_iconview_button_press(GdkEventButton* event) {
|
|
bool on_iconview_button_press(GdkEventButton* event) {
|
|
|
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
|
|
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
|
|
|
- // Fix: Cast coordinates to int for get_path_at_pos
|
|
|
|
|
Gtk::TreeModel::Path path = m_IconView.get_path_at_pos((int)event->x, (int)event->y);
|
|
Gtk::TreeModel::Path path = m_IconView.get_path_at_pos((int)event->x, (int)event->y);
|
|
|
-
|
|
|
|
|
if (path) {
|
|
if (path) {
|
|
|
if (!m_IconView.path_is_selected(path)) {
|
|
if (!m_IconView.path_is_selected(path)) {
|
|
|
m_IconView.unselect_all();
|
|
m_IconView.unselect_all();
|
|
@@ -335,7 +323,6 @@ protected:
|
|
|
int dest_w = (ratio > 1) ? size : size * ratio;
|
|
int dest_w = (ratio > 1) ? size : size * ratio;
|
|
|
int dest_h = (ratio > 1) ? size / ratio : size;
|
|
int dest_h = (ratio > 1) ? size / ratio : size;
|
|
|
|
|
|
|
|
- // Scale in background thread
|
|
|
|
|
item.pixbuf = pixbuf->scale_simple(dest_w, dest_h, Gdk::INTERP_BILINEAR);
|
|
item.pixbuf = pixbuf->scale_simple(dest_w, dest_h, Gdk::INTERP_BILINEAR);
|
|
|
|
|
|
|
|
{
|
|
{
|
|
@@ -343,7 +330,6 @@ protected:
|
|
|
m_ResultQueue.push_back(item);
|
|
m_ResultQueue.push_back(item);
|
|
|
}
|
|
}
|
|
|
m_Dispatcher.emit();
|
|
m_Dispatcher.emit();
|
|
|
- // Brief sleep to yield CPU, keeping UI responsive
|
|
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(500));
|
|
std::this_thread::sleep_for(std::chrono::microseconds(500));
|
|
|
} catch (...) {}
|
|
} catch (...) {}
|
|
|
}
|
|
}
|
|
@@ -400,7 +386,6 @@ protected:
|
|
|
std::string new_name;
|
|
std::string new_name;
|
|
|
if (pad_width > 0) {
|
|
if (pad_width > 0) {
|
|
|
std::string num = std::to_string(index);
|
|
std::string num = std::to_string(index);
|
|
|
- // Fix: cast to size_t to solve sign warning
|
|
|
|
|
while (num.length() < (size_t)pad_width) num = "0" + num;
|
|
while (num.length() < (size_t)pad_width) num = "0" + num;
|
|
|
std::string pat = pattern;
|
|
std::string pat = pattern;
|
|
|
pat.replace(hash_pos, pad_width, num);
|
|
pat.replace(hash_pos, pad_width, num);
|
|
@@ -412,8 +397,9 @@ protected:
|
|
|
index++;
|
|
index++;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- m_RefListStore->clear();
|
|
|
|
|
- m_Statusbar.push("Rename Complete.");
|
|
|
|
|
|
|
+ // --- RELOAD LOGIC ---
|
|
|
|
|
+ m_Statusbar.push("Rename Complete. Reloading...");
|
|
|
|
|
+ start_loading_folder(m_current_path); // Automatically refresh directory
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|