mirror of
https://github.com/obsqrbtz/clrsync.git
synced 2026-04-08 20:19:04 +03:00
feat: allow to remove templates
This commit is contained in:
@@ -216,6 +216,32 @@ Result<void> config::update_template(const std::string &key,
|
|||||||
return m_file->save_file();
|
return m_file->save_file();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<void> config::remove_template(const std::string &key)
|
||||||
|
{
|
||||||
|
if (!m_file)
|
||||||
|
return Err<void>(error_code::config_missing, "Configuration not initialized");
|
||||||
|
|
||||||
|
auto it = m_themes.find(key);
|
||||||
|
if (it == m_themes.end())
|
||||||
|
return Err<void>(error_code::template_not_found, "Template not found", key);
|
||||||
|
|
||||||
|
std::filesystem::path template_file = it->second.template_path();
|
||||||
|
if (std::filesystem::exists(template_file))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
std::filesystem::remove(template_file);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
return Err<void>(error_code::file_write_failed, "Failed to delete template file", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_themes.erase(it);
|
||||||
|
|
||||||
|
m_file->remove_section("templates." + key);
|
||||||
|
|
||||||
|
return m_file->save_file();
|
||||||
|
}
|
||||||
|
|
||||||
const std::unordered_map<std::string, clrsync::core::theme_template> config::templates()
|
const std::unordered_map<std::string, clrsync::core::theme_template> config::templates()
|
||||||
{
|
{
|
||||||
if (m_themes.empty() && m_file)
|
if (m_themes.empty() && m_file)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class config
|
|||||||
|
|
||||||
Result<void> update_template(const std::string &key,
|
Result<void> update_template(const std::string &key,
|
||||||
const clrsync::core::theme_template &theme_template);
|
const clrsync::core::theme_template &theme_template);
|
||||||
|
Result<void> remove_template(const std::string &key);
|
||||||
static std::filesystem::path get_data_dir();
|
static std::filesystem::path get_data_dir();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class file
|
|||||||
}
|
}
|
||||||
virtual void insert_or_update_value(const std::string §ion, const std::string &key,
|
virtual void insert_or_update_value(const std::string §ion, const std::string &key,
|
||||||
const value_type &value) {};
|
const value_type &value) {};
|
||||||
|
virtual void remove_section(const std::string §ion) {};
|
||||||
virtual Result<void> save_file() { return Ok(); };
|
virtual Result<void> save_file() { return Ok(); };
|
||||||
};
|
};
|
||||||
} // namespace clrsync::core::io
|
} // namespace clrsync::core::io
|
||||||
|
|||||||
@@ -92,6 +92,25 @@ void toml_file::insert_or_update_value(const std::string §ion, const std::st
|
|||||||
std::visit([&](auto &&v) { tbl->insert_or_assign(key, v); }, value);
|
std::visit([&](auto &&v) { tbl->insert_or_assign(key, v); }, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toml_file::remove_section(const std::string §ion)
|
||||||
|
{
|
||||||
|
toml::table *tbl = m_file.as_table();
|
||||||
|
auto parts = split(section, '.');
|
||||||
|
|
||||||
|
if (parts.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < parts.size() - 1; ++i)
|
||||||
|
{
|
||||||
|
auto *sub = (*tbl)[parts[i]].as_table();
|
||||||
|
if (!sub)
|
||||||
|
return;
|
||||||
|
tbl = sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbl->erase(parts.back());
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> toml_file::save_file()
|
Result<void> toml_file::save_file()
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class toml_file : public file
|
|||||||
std::map<std::string, value_type> get_table(const std::string §ion_path) const override;
|
std::map<std::string, value_type> get_table(const std::string §ion_path) const override;
|
||||||
void insert_or_update_value(const std::string §ion, const std::string &key,
|
void insert_or_update_value(const std::string §ion, const std::string &key,
|
||||||
const value_type &value) override;
|
const value_type &value) override;
|
||||||
|
void remove_section(const std::string §ion) override;
|
||||||
Result<void> save_file() override;
|
Result<void> save_file() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -133,10 +133,14 @@ void color_scheme_editor::render_controls()
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.2f, 0.2f, 1.0f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.1f, 0.1f, 1.0f));
|
||||||
if (ImGui::Button("Delete"))
|
if (ImGui::Button("Delete"))
|
||||||
{
|
{
|
||||||
m_controller.delete_current_palette();
|
m_controller.delete_current_palette();
|
||||||
}
|
}
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Apply"))
|
if (ImGui::Button("Apply"))
|
||||||
|
|||||||
@@ -15,6 +15,15 @@ void template_controller::set_template_enabled(const std::string& key, bool enab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template_controller::set_template_input_path(const std::string& key, const std::string& path)
|
||||||
|
{
|
||||||
|
auto it = m_templates.find(key);
|
||||||
|
if (it != m_templates.end()) {
|
||||||
|
it->second.set_template_path(path);
|
||||||
|
(void)clrsync::core::config::instance().update_template(key, it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void template_controller::set_template_output_path(const std::string& key, const std::string& path)
|
void template_controller::set_template_output_path(const std::string& key, const std::string& path)
|
||||||
{
|
{
|
||||||
auto it = m_templates.find(key);
|
auto it = m_templates.find(key);
|
||||||
@@ -33,6 +42,16 @@ void template_controller::set_template_reload_command(const std::string& key, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool template_controller::remove_template(const std::string& key)
|
||||||
|
{
|
||||||
|
auto result = clrsync::core::config::instance().remove_template(key);
|
||||||
|
if (result) {
|
||||||
|
m_templates.erase(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void template_controller::refresh()
|
void template_controller::refresh()
|
||||||
{
|
{
|
||||||
m_templates = m_template_manager.templates();
|
m_templates = m_template_manager.templates();
|
||||||
|
|||||||
@@ -12,8 +12,10 @@ public:
|
|||||||
template_controller();
|
template_controller();
|
||||||
[[nodiscard]] const std::unordered_map<std::string, clrsync::core::theme_template>& templates() const { return m_templates; }
|
[[nodiscard]] const std::unordered_map<std::string, clrsync::core::theme_template>& templates() const { return m_templates; }
|
||||||
void set_template_enabled(const std::string& key, bool enabled);
|
void set_template_enabled(const std::string& key, bool enabled);
|
||||||
|
void set_template_input_path(const std::string& key, const std::string& path);
|
||||||
void set_template_output_path(const std::string& key, const std::string& path);
|
void set_template_output_path(const std::string& key, const std::string& path);
|
||||||
void set_template_reload_command(const std::string& key, const std::string& cmd);
|
void set_template_reload_command(const std::string& key, const std::string& cmd);
|
||||||
|
bool remove_template(const std::string& key);
|
||||||
void refresh();
|
void refresh();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -118,6 +118,40 @@ void template_editor::render()
|
|||||||
render_editor();
|
render_editor();
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
if (m_show_delete_confirmation)
|
||||||
|
{
|
||||||
|
ImGui::OpenPopup("Delete Template?");
|
||||||
|
m_show_delete_confirmation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupModal("Delete Template?", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
ImGui::Text("Are you sure you want to delete '%s'?", m_template_name.c_str());
|
||||||
|
ImGui::Text("This action cannot be undone.");
|
||||||
|
ImGui::Separator();
|
||||||
|
|
||||||
|
if (ImGui::Button("Delete", ImVec2(120, 0)))
|
||||||
|
{
|
||||||
|
bool success = m_template_controller.remove_template(m_template_name);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
new_template();
|
||||||
|
refresh_templates();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_validation_error = "Failed to delete template";
|
||||||
|
}
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
||||||
|
{
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,6 +174,19 @@ void template_editor::render_controls()
|
|||||||
save_template();
|
save_template();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_is_editing_existing)
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.8f, 0.2f, 0.2f, 1.0f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.6f, 0.1f, 0.1f, 1.0f));
|
||||||
|
if (ImGui::Button("Delete"))
|
||||||
|
{
|
||||||
|
delete_template();
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::Text("Template Name:");
|
ImGui::Text("Template Name:");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@@ -164,6 +211,24 @@ void template_editor::render_controls()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::Text("Input Path:");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||||
|
char input_path_buf[512] = {0};
|
||||||
|
snprintf(input_path_buf, sizeof(input_path_buf), "%s", m_input_path.c_str());
|
||||||
|
if (ImGui::InputText("##input_path", input_path_buf, sizeof(input_path_buf)))
|
||||||
|
{
|
||||||
|
m_input_path = input_path_buf;
|
||||||
|
if (!m_input_path.empty())
|
||||||
|
{
|
||||||
|
m_validation_error = "";
|
||||||
|
}
|
||||||
|
if (m_is_editing_existing)
|
||||||
|
{
|
||||||
|
m_template_controller.set_template_input_path(m_template_name, m_input_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Text("Output Path:");
|
ImGui::Text("Output Path:");
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||||
@@ -318,6 +383,10 @@ void template_editor::save_template()
|
|||||||
trimmed_name.erase(0, trimmed_name.find_first_not_of(" \t\n\r"));
|
trimmed_name.erase(0, trimmed_name.find_first_not_of(" \t\n\r"));
|
||||||
trimmed_name.erase(trimmed_name.find_last_not_of(" \t\n\r") + 1);
|
trimmed_name.erase(trimmed_name.find_last_not_of(" \t\n\r") + 1);
|
||||||
|
|
||||||
|
std::string trimmed_input_path = m_input_path;
|
||||||
|
trimmed_input_path.erase(0, trimmed_input_path.find_first_not_of(" \t\n\r"));
|
||||||
|
trimmed_input_path.erase(trimmed_input_path.find_last_not_of(" \t\n\r") + 1);
|
||||||
|
|
||||||
std::string trimmed_path = m_output_path;
|
std::string trimmed_path = m_output_path;
|
||||||
trimmed_path.erase(0, trimmed_path.find_first_not_of(" \t\n\r"));
|
trimmed_path.erase(0, trimmed_path.find_first_not_of(" \t\n\r"));
|
||||||
trimmed_path.erase(trimmed_path.find_last_not_of(" \t\n\r") + 1);
|
trimmed_path.erase(trimmed_path.find_last_not_of(" \t\n\r") + 1);
|
||||||
@@ -328,6 +397,12 @@ void template_editor::save_template()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (trimmed_input_path.empty())
|
||||||
|
{
|
||||||
|
m_validation_error = "Error: Input path cannot be empty!";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (trimmed_path.empty())
|
if (trimmed_path.empty())
|
||||||
{
|
{
|
||||||
m_validation_error = "Error: Output path cannot be empty!";
|
m_validation_error = "Error: Output path cannot be empty!";
|
||||||
@@ -344,29 +419,22 @@ void template_editor::save_template()
|
|||||||
m_validation_error = "";
|
m_validation_error = "";
|
||||||
|
|
||||||
auto &cfg = clrsync::core::config::instance();
|
auto &cfg = clrsync::core::config::instance();
|
||||||
std::string palettes_path = cfg.palettes_path();
|
|
||||||
std::filesystem::path templates_dir =
|
|
||||||
std::filesystem::path(palettes_path).parent_path() / "templates";
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(templates_dir))
|
std::filesystem::path template_file = trimmed_input_path;
|
||||||
|
|
||||||
|
// Ensure the parent directory exists
|
||||||
|
auto parent_dir = template_file.parent_path();
|
||||||
|
if (!parent_dir.empty() && !std::filesystem::exists(parent_dir))
|
||||||
{
|
{
|
||||||
std::filesystem::create_directories(templates_dir);
|
try
|
||||||
|
{
|
||||||
|
std::filesystem::create_directories(parent_dir);
|
||||||
}
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
std::filesystem::path template_file;
|
|
||||||
if (m_is_editing_existing)
|
|
||||||
{
|
{
|
||||||
auto existing_template_result = cfg.template_by_name(trimmed_name);
|
m_validation_error = "Error: Could not create directory for input path";
|
||||||
if (!existing_template_result)
|
|
||||||
{
|
|
||||||
m_validation_error = "Template not found: " + existing_template_result.error().description();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
template_file = existing_template_result.value()->template_path();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
template_file = templates_dir / trimmed_name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string template_content = m_editor.GetText();
|
std::string template_content = m_editor.GetText();
|
||||||
@@ -393,6 +461,7 @@ void template_editor::save_template()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_template_name = trimmed_name;
|
m_template_name = trimmed_name;
|
||||||
|
m_input_path = trimmed_input_path;
|
||||||
m_output_path = trimmed_path;
|
m_output_path = trimmed_path;
|
||||||
m_is_editing_existing = true;
|
m_is_editing_existing = true;
|
||||||
m_saved_content = m_editor.GetText();
|
m_saved_content = m_editor.GetText();
|
||||||
@@ -410,6 +479,7 @@ void template_editor::load_template(const std::string &name)
|
|||||||
{
|
{
|
||||||
const auto &tmpl = it->second;
|
const auto &tmpl = it->second;
|
||||||
m_template_name = name;
|
m_template_name = name;
|
||||||
|
m_input_path = tmpl.template_path();
|
||||||
m_output_path = tmpl.output_path();
|
m_output_path = tmpl.output_path();
|
||||||
m_reload_command = tmpl.reload_command();
|
m_reload_command = tmpl.reload_command();
|
||||||
m_enabled = tmpl.enabled();
|
m_enabled = tmpl.enabled();
|
||||||
@@ -446,6 +516,7 @@ void template_editor::new_template()
|
|||||||
"Examples: {color.hex}, {color.rgb}, {color.r}\n\n";
|
"Examples: {color.hex}, {color.rgb}, {color.r}\n\n";
|
||||||
m_editor.SetText(default_content);
|
m_editor.SetText(default_content);
|
||||||
m_saved_content = default_content;
|
m_saved_content = default_content;
|
||||||
|
m_input_path = "";
|
||||||
m_output_path = "";
|
m_output_path = "";
|
||||||
m_reload_command = "";
|
m_reload_command = "";
|
||||||
m_enabled = true;
|
m_enabled = true;
|
||||||
@@ -454,6 +525,14 @@ void template_editor::new_template()
|
|||||||
m_has_unsaved_changes = false;
|
m_has_unsaved_changes = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template_editor::delete_template()
|
||||||
|
{
|
||||||
|
if (!m_is_editing_existing || m_template_name.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_show_delete_confirmation = true;
|
||||||
|
}
|
||||||
|
|
||||||
void template_editor::refresh_templates()
|
void template_editor::refresh_templates()
|
||||||
{
|
{
|
||||||
m_template_controller.refresh();
|
m_template_controller.refresh();
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ private:
|
|||||||
void save_template();
|
void save_template();
|
||||||
void load_template(const std::string &name);
|
void load_template(const std::string &name);
|
||||||
void new_template();
|
void new_template();
|
||||||
|
void delete_template();
|
||||||
void refresh_templates();
|
void refresh_templates();
|
||||||
|
|
||||||
bool is_valid_path(const std::string &path);
|
bool is_valid_path(const std::string &path);
|
||||||
@@ -29,6 +30,7 @@ private:
|
|||||||
TextEditor m_editor;
|
TextEditor m_editor;
|
||||||
|
|
||||||
std::string m_template_name;
|
std::string m_template_name;
|
||||||
|
std::string m_input_path;
|
||||||
std::string m_output_path;
|
std::string m_output_path;
|
||||||
std::string m_reload_command;
|
std::string m_reload_command;
|
||||||
std::string m_validation_error;
|
std::string m_validation_error;
|
||||||
@@ -37,6 +39,7 @@ private:
|
|||||||
|
|
||||||
bool m_enabled{true};
|
bool m_enabled{true};
|
||||||
bool m_is_editing_existing{false};
|
bool m_is_editing_existing{false};
|
||||||
|
bool m_show_delete_confirmation{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CLRSYNC_GUI_TEMPLATE_EDITOR_HPP
|
#endif // CLRSYNC_GUI_TEMPLATE_EDITOR_HPP
|
||||||
Reference in New Issue
Block a user