Dispatch layer operations through app core
This commit is contained in:
@@ -88,6 +88,25 @@ public:
|
||||
virtual void show_merge_animated_not_supported() = 0;
|
||||
};
|
||||
|
||||
class DocumentLayerOperationServices {
|
||||
public:
|
||||
virtual ~DocumentLayerOperationServices() = default;
|
||||
|
||||
virtual void add_layer(std::string_view name, int insert_index) = 0;
|
||||
virtual void duplicate_layer(int source_index, int insert_index) = 0;
|
||||
virtual void select_layer(int index) = 0;
|
||||
virtual void reorder_layer(int from_index, int to_index) = 0;
|
||||
virtual void remove_layer(int index) = 0;
|
||||
virtual void set_layer_opacity(int index, float opacity) = 0;
|
||||
virtual void set_layer_visibility(int index, bool visible) = 0;
|
||||
virtual void set_layer_alpha_lock(int index, bool locked) = 0;
|
||||
virtual void set_layer_blend_mode(int index, int blend_mode) = 0;
|
||||
virtual void set_layer_highlight(int index, bool highlighted) = 0;
|
||||
virtual void mark_unsaved() = 0;
|
||||
virtual void reload_animation_layers() = 0;
|
||||
virtual void update_title() = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status validate_layer_index(
|
||||
int layer_count,
|
||||
int index) noexcept
|
||||
@@ -420,6 +439,81 @@ public:
|
||||
return pp::foundation::Result<DocumentLayerMenuPlan>::success(std::move(plan));
|
||||
}
|
||||
|
||||
inline void execute_document_layer_operation_side_effects(
|
||||
const DocumentLayerOperationPlan& plan,
|
||||
DocumentLayerOperationServices& services)
|
||||
{
|
||||
if (plan.marks_unsaved)
|
||||
services.mark_unsaved();
|
||||
if (plan.reloads_animation_layers)
|
||||
services.reload_animation_layers();
|
||||
if (plan.updates_title)
|
||||
services.update_title();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_document_layer_operation_plan(
|
||||
const DocumentLayerOperationPlan& plan,
|
||||
DocumentLayerOperationServices& services)
|
||||
{
|
||||
switch (plan.operation) {
|
||||
case DocumentLayerOperation::add:
|
||||
if (!plan.mutates_document || plan.name.empty()) {
|
||||
return pp::foundation::Status::invalid_argument("layer add plan must mutate with a name");
|
||||
}
|
||||
services.add_layer(plan.name, plan.insert_index);
|
||||
break;
|
||||
case DocumentLayerOperation::duplicate:
|
||||
if (!plan.mutates_document) {
|
||||
return pp::foundation::Status::invalid_argument("layer duplicate plan must mutate the document");
|
||||
}
|
||||
services.duplicate_layer(plan.source_index, plan.insert_index);
|
||||
break;
|
||||
case DocumentLayerOperation::select:
|
||||
services.select_layer(plan.index);
|
||||
break;
|
||||
case DocumentLayerOperation::reorder:
|
||||
if (plan.mutates_document)
|
||||
services.reorder_layer(plan.from_index, plan.to_index);
|
||||
break;
|
||||
case DocumentLayerOperation::remove:
|
||||
if (!plan.mutates_document) {
|
||||
return pp::foundation::Status::invalid_argument("layer remove plan must mutate the document");
|
||||
}
|
||||
services.remove_layer(plan.index);
|
||||
break;
|
||||
case DocumentLayerOperation::set_opacity:
|
||||
if (!plan.mutates_document) {
|
||||
return pp::foundation::Status::invalid_argument("layer opacity plan must mutate the document");
|
||||
}
|
||||
services.set_layer_opacity(plan.index, plan.opacity);
|
||||
break;
|
||||
case DocumentLayerOperation::set_visibility:
|
||||
if (!plan.mutates_document) {
|
||||
return pp::foundation::Status::invalid_argument("layer visibility plan must mutate the document");
|
||||
}
|
||||
services.set_layer_visibility(plan.index, plan.flag);
|
||||
break;
|
||||
case DocumentLayerOperation::set_alpha_lock:
|
||||
if (!plan.mutates_document) {
|
||||
return pp::foundation::Status::invalid_argument("layer alpha-lock plan must mutate the document");
|
||||
}
|
||||
services.set_layer_alpha_lock(plan.index, plan.flag);
|
||||
break;
|
||||
case DocumentLayerOperation::set_blend_mode:
|
||||
if (!plan.mutates_document) {
|
||||
return pp::foundation::Status::invalid_argument("layer blend-mode plan must mutate the document");
|
||||
}
|
||||
services.set_layer_blend_mode(plan.index, plan.blend_mode);
|
||||
break;
|
||||
case DocumentLayerOperation::set_highlight:
|
||||
services.set_layer_highlight(plan.index, plan.flag);
|
||||
break;
|
||||
}
|
||||
|
||||
execute_document_layer_operation_side_effects(plan, services);
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] inline pp::foundation::Status execute_document_layer_menu_plan(
|
||||
const DocumentLayerMenuPlan& plan,
|
||||
DocumentLayerMenuServices& services)
|
||||
|
||||
@@ -605,6 +605,142 @@ private:
|
||||
App& app_;
|
||||
};
|
||||
|
||||
class LegacyDocumentLayerOperationServices final : public pp::app::DocumentLayerOperationServices {
|
||||
public:
|
||||
LegacyDocumentLayerOperationServices(
|
||||
App& app,
|
||||
const std::shared_ptr<class Layer>& 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<class Layer> pending_layer_;
|
||||
};
|
||||
|
||||
void execute_main_toolbar_plan(App& app, const pp::app::MainToolbarPlan& plan)
|
||||
{
|
||||
LegacyMainToolbarServices services(app);
|
||||
@@ -637,6 +773,17 @@ void execute_document_layer_menu_plan(App& app, const pp::app::DocumentLayerMenu
|
||||
LOG("Layer menu action failed: %s", status.message);
|
||||
}
|
||||
|
||||
void execute_document_layer_operation_plan(
|
||||
App& app,
|
||||
const pp::app::DocumentLayerOperationPlan& plan,
|
||||
const std::shared_ptr<class Layer>& pending_layer = nullptr)
|
||||
{
|
||||
LegacyDocumentLayerOperationServices services(app, pending_layer);
|
||||
const auto status = pp::app::execute_document_layer_operation_plan(plan, services);
|
||||
if (!status.ok())
|
||||
LOG("Layer operation failed: %s", status.message);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void App::title_update()
|
||||
@@ -833,13 +980,7 @@ void App::init_sidebar()
|
||||
layers->m_layers.back()->m_label_text);
|
||||
if (!plan)
|
||||
return;
|
||||
Canvas::I->layer_add(plan.value().name, layer, plan.value().insert_index);
|
||||
Canvas::I->m_unsaved = plan.value().marks_unsaved;
|
||||
Canvas::I->anim_update();
|
||||
if (plan.value().reloads_animation_layers)
|
||||
animation->load_layers();
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value(), layer);
|
||||
};
|
||||
|
||||
layers->on_layer_duplicate = [this](Node*, int source_index) {
|
||||
@@ -848,49 +989,16 @@ void App::init_sidebar()
|
||||
source_index);
|
||||
if (!plan)
|
||||
return;
|
||||
Canvas::I->layer_add(layers->m_layers.back()->m_label_text.c_str(), nullptr, plan.value().insert_index);
|
||||
auto& dst = Canvas::I->m_layers[plan.value().insert_index];
|
||||
auto& src = Canvas::I->m_layers[plan.value().source_index];
|
||||
for (int i = 1; i < src->frames_count(); i++)
|
||||
dst->add_frame();
|
||||
Canvas::I->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;
|
||||
Canvas::I->m_unsaved = plan.value().marks_unsaved;
|
||||
if (plan.value().reloads_animation_layers)
|
||||
animation->load_layers();
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_change = [this](Node*, int old_idx, int new_idx) {
|
||||
layers->on_layer_change = [this](Node*, int, int new_idx) {
|
||||
const auto plan = pp::app::plan_document_layer_select(
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
new_idx);
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->m_current_layer_idx = plan.value().index;
|
||||
if (plan.value().reloads_animation_layers)
|
||||
animation->load_layers();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_order = [this](Node*, int old_idx, int new_idx) {
|
||||
@@ -898,14 +1006,9 @@ void App::init_sidebar()
|
||||
static_cast<int>(canvas->m_canvas->m_layers.size()),
|
||||
old_idx,
|
||||
new_idx);
|
||||
if (!plan || !plan.value().mutates_document)
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->layer_order(plan.value().from_index, plan.value().to_index);
|
||||
canvas->m_canvas->m_unsaved = plan.value().marks_unsaved;
|
||||
if (plan.value().reloads_animation_layers)
|
||||
animation->load_layers();
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_delete = [this](Node*, int idx) {
|
||||
@@ -914,12 +1017,7 @@ void App::init_sidebar()
|
||||
idx);
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->layer_remove(plan.value().index);
|
||||
canvas->m_canvas->m_unsaved = plan.value().marks_unsaved;
|
||||
if (plan.value().reloads_animation_layers)
|
||||
animation->load_layers();
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_opacity_changed = [this](Node*, int idx, float value) {
|
||||
@@ -929,10 +1027,7 @@ void App::init_sidebar()
|
||||
value);
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->m_layers[plan.value().index]->m_opacity = plan.value().opacity;
|
||||
canvas->m_canvas->m_unsaved = plan.value().marks_unsaved;
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) {
|
||||
@@ -942,12 +1037,7 @@ void App::init_sidebar()
|
||||
visible);
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->m_layers[plan.value().index]->m_visible = plan.value().flag;
|
||||
canvas->m_canvas->m_unsaved = plan.value().marks_unsaved;
|
||||
if (plan.value().reloads_animation_layers)
|
||||
animation->load_layers();
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) {
|
||||
@@ -957,10 +1047,7 @@ void App::init_sidebar()
|
||||
locked);
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->m_layers[plan.value().index]->m_alpha_locked = plan.value().flag;
|
||||
canvas->m_canvas->m_unsaved = plan.value().marks_unsaved;
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) {
|
||||
@@ -970,10 +1057,7 @@ void App::init_sidebar()
|
||||
mode);
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->m_layers[plan.value().index]->m_blend_mode = plan.value().blend_mode;
|
||||
canvas->m_canvas->m_unsaved = plan.value().marks_unsaved;
|
||||
if (plan.value().updates_title)
|
||||
title_update();
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
|
||||
layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) {
|
||||
@@ -983,7 +1067,7 @@ void App::init_sidebar()
|
||||
highlight);
|
||||
if (!plan)
|
||||
return;
|
||||
canvas->m_canvas->m_layers[plan.value().index]->m_hightlight = plan.value().flag;
|
||||
execute_document_layer_operation_plan(*this, plan.value());
|
||||
};
|
||||
if (auto* button = layout[main_id]->find<NodeButtonCustom>("btn-stroke"))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user