#include "pch.h" #include "legacy_document_layer_services.h" #include "action.h" #include "app.h" #include "legacy_document_canvas_services.h" #include "legacy_ui_overlay_services.h" namespace pp::panopainter { namespace { struct LegacyActionLayerRename : public Action { std::string m_old_name; std::string m_new_name; Layer* m_layer = nullptr; std::shared_ptr m_layer_node; LegacyActionLayerRename( std::string old_name, std::string new_name, std::shared_ptr layer_node, Layer* layer) : m_old_name(std::move(old_name)) , m_new_name(std::move(new_name)) , m_layer(layer) , m_layer_node(std::move(layer_node)) { } void run() override { } size_t memory() override { return 0; } void undo() override { if (m_layer_node) m_layer_node->set_name(m_old_name.c_str()); if (m_layer) m_layer->m_name = m_old_name; } Action* get_redo() override { return new LegacyActionLayerRename(m_new_name, m_old_name, m_layer_node, m_layer); } }; class LegacyDocumentLayerRenameServices final : public pp::app::DocumentLayerRenameServices { public: LegacyDocumentLayerRenameServices(App& app, const std::shared_ptr& dialog) noexcept : app_(app) , dialog_(dialog) { } void record_layer_rename_undo(std::string_view old_name, std::string_view new_name) override { if (!app_.layers || !app_.layers->m_current_layer || !app_.canvas || !app_.canvas->m_canvas) return; auto layer_node = std::static_pointer_cast(app_.layers->m_current_layer->shared_from_this()); auto* layer = app_.canvas->m_canvas->m_layers[app_.canvas->m_canvas->m_current_layer_idx].get(); const std::string old_name_copy(old_name); const std::string new_name_copy(new_name); ActionManager::add(new LegacyActionLayerRename( old_name_copy, new_name_copy, layer_node, layer)); } void set_current_layer_name(std::string_view new_name) override { if (!app_.layers || !app_.layers->m_current_layer || !app_.canvas || !app_.canvas->m_canvas) return; auto layer_node = std::static_pointer_cast(app_.layers->m_current_layer->shared_from_this()); auto* layer = app_.canvas->m_canvas->m_layers[app_.canvas->m_canvas->m_current_layer_idx].get(); const std::string new_name_copy(new_name); layer_node->set_name(new_name_copy.c_str()); layer->m_name = new_name_copy; } void finish_layer_rename() override { if (dialog_) pp::panopainter::close_legacy_dialog_node(*dialog_); app_.hideKeyboard(); } private: App& app_; std::shared_ptr dialog_; }; class LegacyDocumentLayerMergeServices final : public pp::app::DocumentLayerMergeServices { public: explicit LegacyDocumentLayerMergeServices(App& app) noexcept : app_(app) { } void merge_layers(int from_index, int to_index, bool create_history) override { if (app_.layers) app_.layers->merge(from_index, to_index, create_history); } private: App& app_; }; class LegacyDocumentLayerMenuServices final : public pp::app::DocumentLayerMenuServices { public: explicit LegacyDocumentLayerMenuServices(App& app) noexcept : app_(app) { } void clear_current_layer() override { const auto plan = pp::app::plan_document_canvas_clear( app_.canvas && app_.canvas->m_canvas, 1.0F, 1.0F, 1.0F, 0.0F); if (!plan) return; const auto status = execute_legacy_document_canvas_clear_plan(app_, plan.value()); if (!status.ok()) LOG("Canvas clear failed: %s", status.message); } void show_rename_dialog() override { app_.dialog_layer_rename(); } void merge_with_lower_layer(int from_index, int to_index) override { const int layer_count = app_.canvas && app_.canvas->m_canvas ? static_cast(app_.canvas->m_canvas->m_layers.size()) : 0; const int animation_duration = Canvas::I ? Canvas::I->anim_duration() : 0; const auto plan = pp::app::plan_document_layer_merge( layer_count, from_index, to_index, animation_duration); if (!plan) return; const auto status = execute_legacy_document_layer_merge_plan(app_, plan.value()); if (!status.ok()) LOG("Layer merge failed: %s", status.message); } void show_merge_animated_not_supported() override { app_.message_box("Not supported", "Merging animated layers is not supported yet."); } private: App& app_; }; class LegacyDocumentLayerOperationServices final : public pp::app::DocumentLayerOperationServices { public: LegacyDocumentLayerOperationServices( App& app, const std::shared_ptr& pending_layer = nullptr) noexcept : app_(app) , pending_layer_(pending_layer) { } void add_layer(std::string_view name, int insert_index) override { auto* canvas = legacy_canvas(); if (!canvas) return; canvas->layer_add(std::string(name), pending_layer_, insert_index); canvas->anim_update(); } void duplicate_layer(int source_index, int insert_index) override { auto* canvas = legacy_canvas(); if (!canvas) return; std::string duplicated_name = "Layer"; if (app_.layers && !app_.layers->m_layers.empty()) duplicated_name = app_.layers->m_layers.back()->m_label_text; canvas->layer_add(duplicated_name, nullptr, insert_index); auto& dst = canvas->m_layers[insert_index]; auto& src = canvas->m_layers[source_index]; for (int i = 1; i < src->frames_count(); i++) dst->add_frame(); canvas->anim_update(); for (int frame = 0; frame < src->frames_count(); frame++) { for (int i = 0; i < 6; i++) { if (!src->face(i)) continue; bool loaded = src->frame(frame).gpu_load(); dst->frame(frame).gpu_load(); dst->rtt(i, frame).copy(src->rtt(i)); dst->face(i, frame) = src->face(i); dst->box(i, frame) = src->box(i); if (!loaded) { dst->frame(frame).gpu_unload(); src->frame(frame).gpu_unload(); } } } dst->m_opacity = src->m_opacity; dst->m_blend_mode = src->m_blend_mode; dst->m_alpha_locked = src->m_alpha_locked; } void select_layer(int index) override { if (auto* canvas = legacy_canvas()) canvas->m_current_layer_idx = index; } void reorder_layer(int from_index, int to_index) override { if (auto* canvas = legacy_canvas()) canvas->layer_order(from_index, to_index); } void remove_layer(int index) override { if (auto* canvas = legacy_canvas()) canvas->layer_remove(index); } void set_layer_opacity(int index, float opacity) override { if (auto* canvas = legacy_canvas()) canvas->m_layers[index]->m_opacity = opacity; } void set_layer_visibility(int index, bool visible) override { if (auto* canvas = legacy_canvas()) canvas->m_layers[index]->m_visible = visible; } void set_layer_alpha_lock(int index, bool locked) override { if (auto* canvas = legacy_canvas()) canvas->m_layers[index]->m_alpha_locked = locked; } void set_layer_blend_mode(int index, int blend_mode) override { if (auto* canvas = legacy_canvas()) canvas->m_layers[index]->m_blend_mode = blend_mode; } void set_layer_highlight(int index, bool highlighted) override { if (auto* canvas = legacy_canvas()) canvas->m_layers[index]->m_hightlight = highlighted; } void mark_unsaved() override { if (auto* canvas = legacy_canvas()) canvas->m_unsaved = true; } void reload_animation_layers() override { if (app_.animation) app_.animation->load_layers(); } void update_title() override { app_.title_update(); } private: [[nodiscard]] Canvas* legacy_canvas() const noexcept { if (app_.canvas && app_.canvas->m_canvas) return app_.canvas->m_canvas.get(); return Canvas::I; } App& app_; std::shared_ptr pending_layer_; }; } // namespace pp::foundation::Status execute_legacy_document_layer_rename_plan( App& app, const pp::app::DocumentLayerRenamePlan& plan, const std::shared_ptr& dialog) { LegacyDocumentLayerRenameServices services(app, dialog); return pp::app::execute_document_layer_rename_plan(plan, services); } pp::foundation::Status execute_legacy_document_layer_menu_plan( App& app, const pp::app::DocumentLayerMenuPlan& plan) { LegacyDocumentLayerMenuServices services(app); return pp::app::execute_document_layer_menu_plan(plan, services); } pp::foundation::Status execute_legacy_document_layer_merge_plan( App& app, const pp::app::DocumentLayerMergePlan& plan) { LegacyDocumentLayerMergeServices services(app); return pp::app::execute_document_layer_merge_plan(plan, services); } pp::foundation::Status execute_legacy_document_layer_operation_plan( App& app, const pp::app::DocumentLayerOperationPlan& plan, const std::shared_ptr& pending_layer) { LegacyDocumentLayerOperationServices services(app, pending_layer); return pp::app::execute_document_layer_operation_plan(plan, services); } } // namespace pp::panopainter