Open Save in the project folder and offer the last name with a number counted on
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -672,4 +672,22 @@ Project loadProject(const std::string& path) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string nextExportPath(const std::string& previous) {
|
||||
const std::filesystem::path path(previous);
|
||||
std::string stem = path.stem().string();
|
||||
long count = 0;
|
||||
const auto dash = stem.rfind('-');
|
||||
if (dash != std::string::npos && dash + 1 < stem.size() && stem.size() - dash <= 10 &&
|
||||
stem.find_first_not_of("0123456789", dash + 1) == std::string::npos) {
|
||||
count = std::strtol(stem.c_str() + dash + 1, nullptr, 10);
|
||||
stem.resize(dash);
|
||||
}
|
||||
std::filesystem::path next;
|
||||
std::error_code error;
|
||||
do {
|
||||
next = path.parent_path() / (stem + "-" + std::to_string(++count) + path.extension().string());
|
||||
} while (std::filesystem::exists(next, error));
|
||||
return next.string();
|
||||
}
|
||||
|
||||
} // namespace effector
|
||||
|
||||
@@ -54,4 +54,9 @@ Project projectFromJson(const std::string& text, const std::string& directory =
|
||||
void saveProject(const std::string& path, const Project& project);
|
||||
Project loadProject(const std::string& path);
|
||||
|
||||
// The name to offer for the next export after `previous`: its stem with the
|
||||
// trailing `-N` counted on (`city.png` → `city-1.png`, `city-4.png` →
|
||||
// `city-5.png`), skipping any that already exist in its folder.
|
||||
std::string nextExportPath(const std::string& previous);
|
||||
|
||||
} // namespace effector
|
||||
|
||||
+24
-2
@@ -2476,6 +2476,7 @@ void EffectorWindow::applyProject(const Project& project, const std::string& pat
|
||||
seedEntry_.set_text(std::to_string(seed_));
|
||||
|
||||
projectPath_ = path;
|
||||
lastExport_.clear();
|
||||
updateTitle();
|
||||
clearError();
|
||||
suspendRender_ = false;
|
||||
@@ -2801,8 +2802,27 @@ void EffectorWindow::onSave() {
|
||||
|
||||
auto dialog = Gtk::FileDialog::create();
|
||||
dialog->set_title(video ? "Save video" : "Save image");
|
||||
dialog->set_initial_name("effector-" + chainSlug(stages_, video) + "-" + std::to_string(seed_) +
|
||||
(video ? ".mp4" : ".png"));
|
||||
// The project's own folder when it has one, else where the last save went.
|
||||
std::filesystem::path folder;
|
||||
if (!projectPath_.empty()) {
|
||||
folder = std::filesystem::path(projectPath_).parent_path();
|
||||
} else if (!lastExport_.empty()) {
|
||||
folder = std::filesystem::path(lastExport_).parent_path();
|
||||
}
|
||||
if (!folder.empty()) dialog->set_initial_folder(Gio::File::create_for_path(folder.string()));
|
||||
// The last save's name counted on, so saving again never offers to
|
||||
// overwrite it; its extension only when it is the same kind of file.
|
||||
std::string name;
|
||||
if (lastExport_.empty()) {
|
||||
name = "effector-" + chainSlug(stages_, video) + "-" + std::to_string(seed_) +
|
||||
(video ? ".mp4" : ".png");
|
||||
} else {
|
||||
std::filesystem::path last(lastExport_);
|
||||
if (isVideoPath(last.string()) != video) last.replace_extension(video ? ".mp4" : ".png");
|
||||
if (!folder.empty()) last = folder / last.filename();
|
||||
name = std::filesystem::path(nextExportPath(last.string())).filename().string();
|
||||
}
|
||||
dialog->set_initial_name(name);
|
||||
dialog->save(*this, [this, dialog](const Glib::RefPtr<Gio::AsyncResult>& result) {
|
||||
onSaveChosen(result, dialog);
|
||||
});
|
||||
@@ -2838,6 +2858,7 @@ void EffectorWindow::onSaveChosen(const Glib::RefPtr<Gio::AsyncResult>& result,
|
||||
return;
|
||||
}
|
||||
clearError();
|
||||
lastExport_ = path.string();
|
||||
status_.set_text("Saved " + path.string());
|
||||
status_.set_tooltip_text("Saved " + path.string());
|
||||
}
|
||||
@@ -2956,6 +2977,7 @@ void EffectorWindow::onExportFinished() {
|
||||
return;
|
||||
}
|
||||
clearError();
|
||||
lastExport_ = exportPath_;
|
||||
status_.set_text("Saved " + exportPath_);
|
||||
status_.set_tooltip_text("Saved " + exportPath_);
|
||||
}
|
||||
|
||||
@@ -206,6 +206,9 @@ private:
|
||||
Image result_;
|
||||
std::uint64_t seed_ = 0;
|
||||
std::string projectPath_; // empty until the project has been saved once
|
||||
// The last image or video saved from this project, which the next Save
|
||||
// offers again with its number counted on; empty until one is saved.
|
||||
std::string lastExport_;
|
||||
Glib::RefPtr<Gio::Menu> recentMenu_;
|
||||
sigc::connection recentChanged_; // the recent list outlives the window
|
||||
bool suspendRender_ = true;
|
||||
|
||||
Reference in New Issue
Block a user