diff --git a/cmake/PanoPainterSources.cmake b/cmake/PanoPainterSources.cmake index 0883436..6a0601f 100644 --- a/cmake/PanoPainterSources.cmake +++ b/cmake/PanoPainterSources.cmake @@ -86,6 +86,8 @@ set(PP_PANOPAINTER_APP_SOURCES ) set(PP_PANOPAINTER_UI_SOURCES + src/legacy_brush_ui_services.cpp + src/legacy_brush_ui_services.h src/node_about.cpp src/node_canvas.cpp src/node_changelog.cpp diff --git a/docs/modernization/build-inventory.md b/docs/modernization/build-inventory.md index e354628..05da024 100644 --- a/docs/modernization/build-inventory.md +++ b/docs/modernization/build-inventory.md @@ -173,6 +173,12 @@ Known local toolchain state: contracts while legacy `Canvas` mode state, transform actions, picking, touch-lock, save/UI/cursor calls, brush-size controls, and history execution remain tracked by `DEBT-0027`. +- `src/legacy_brush_ui_services.*` is the current UI-shell bridge for brush + color, texture, preset, stroke-refresh, brush texture-list, and stroke-control + execution. It keeps those live paths on the `pp_app_core` contracts while + legacy `Brush`, `Canvas::I`, image load/save, `NodePanelBrush`, + `NodePanelStroke`, quick/color refreshes, and the temporary + `NodePanelBrush` friend adapter remain tracked by `DEBT-0023`. - `pano_cli simulate-image-import` decodes an embedded tiny PNG through `pp_assets`, attaches it to `pp_document`, and is covered by `pano_cli_simulate_image_import_smoke`. diff --git a/docs/modernization/debt.md b/docs/modernization/debt.md index ebf6a88..ee1d794 100644 --- a/docs/modernization/debt.md +++ b/docs/modernization/debt.md @@ -40,7 +40,7 @@ agent or engineer to remove them without reconstructing context from chat. | DEBT-0020 | Open | Modernization | Document resize dialog state, selected-resolution planning, and execution dispatch now consume pure `pp_app_core` through `NodeDialogResize`, `App::dialog_resize`, `pano_cli plan-document-resize`, and the `DocumentResizeServices` boundary, and live resize shares `src/legacy_document_canvas_services.*` with canvas clear commands, but the shared live bridge still calls legacy `Canvas::resize`, updates the legacy app title, and clears legacy `ActionManager` history through the history bridge | Preserve existing layer/frame GPU resize behavior while the document model and canvas execution boundary are extracted incrementally | `pp_app_core_document_resize_tests`; `pano_cli plan-document-resize --current-resolution 2048 --selected-resolution-index 4`; `ctest --preset desktop-fast --build-config Debug` | Document resize execution is owned by injected document/app services with no legacy resize adapter, title shim, or direct `ActionManager` history clearing | | DEBT-0021 | Open | Modernization | Layer rename planning/execution dispatch and layer panel operation planning/execution dispatch now consume pure `pp_app_core` through `App::dialog_layer_rename`, `App::init_sidebar` layer callbacks, `pano_cli plan-layer-rename`, `pano_cli plan-layer-operation`, `DocumentLayerRenameServices`, and `DocumentLayerOperationServices`, and the live execution adapters are centralized in `src/legacy_document_layer_services.*`, but that shared bridge still mutates legacy `Canvas` layer state, `NodeLayer`/`NodePanelLayer`, and `ActionManager` undo entries | Preserve existing UI/canvas behavior while document layer commands and undo history are extracted incrementally | `pp_app_core_document_layer_tests`; `pano_cli plan-layer-rename --old-name Base --new-name Paint`; `pano_cli plan-layer-operation --kind add --layer-count 2 --index 1 --name Paint`; `ctest --preset desktop-fast --build-config Debug` | Layer command execution is owned by the document/app command boundary with legacy `Canvas`/UI nodes acting only as adapters or removed entirely | | DEBT-0022 | Open | Modernization | Animation panel frame command planning, panel action planning, panel-control/timeline execution dispatch, selected-frame click dispatch, playback tick stepping, and play-mode toggles now consume pure `pp_app_core` through `NodePanelAnimation`, `pano_cli plan-animation-operation`, `pano_cli plan-animation-panel-action`, and `DocumentAnimationServices`, and `pp_legacy_ui_core` temporarily links `pp_app_core`, but the live adapter still mutates or reads legacy `Canvas`/`Layer` frame state and canvas mode directly | Preserve existing animation panel behavior while timeline/frame commands move toward the document/app command boundary | `pp_app_core_document_animation_tests`; `pano_cli plan-animation-operation --kind add --frame-count 2 --current-frame 0`; `pano_cli plan-animation-operation --kind select --frame-count 3 --selected-frame 1 --layer-index 2 --layer-id 42`; `pano_cli plan-animation-operation --kind playback --total-duration 5 --current-frame 4 --offset 1`; `pano_cli plan-animation-operation --kind toggle-playback --playing`; `pano_cli plan-animation-panel-action --action next --total-duration 5 --current-frame 4`; `ctest --preset desktop-fast --build-config Debug` | Animation frame/timeline/playback execution is owned by injected document/app timeline services with no legacy `Canvas`/`Layer`/canvas-mode adapter and UI nodes acting only as adapters or removed entirely | -| DEBT-0023 | Open | Modernization | Brush/color/preset/stroke-settings UI planning, texture-list add/remove/reorder planning, stroke-panel slider/toggle/blend/reset planning, and execution dispatch now consume pure `pp_app_core` through `App::init_sidebar`, `NodePanelBrush`, `NodePanelStroke`, restored/docked floating-panel callbacks, `pano_cli plan-brush-operation`, `pano_cli plan-brush-texture-list`, `pano_cli plan-brush-stroke-control`, `BrushUiServices`, `BrushTextureListServices`, and `BrushStrokeControlServices`, but the live adapter still mutates legacy `Brush`/`Canvas::I`, loads/saves legacy brush texture images, and refreshes legacy quick/stroke/color widgets | Preserve existing brush UI behavior while brush commands move toward a brush/app/asset command boundary and asset-managed texture selection | `pp_app_core_brush_ui_tests`; `pano_cli plan-brush-operation --kind color --r 0.25 --g 0.5 --b 0.75 --a 1`; `pano_cli plan-brush-operation --kind pattern --path data/patterns/noise.png --thumb data/patterns/thumbs/noise.png`; `pano_cli plan-brush-texture-list --kind add --dir brushes --data-path data --source C:/Temp/soft.png`; `pano_cli plan-brush-stroke-control --kind float --setting tip-size --value 42.5`; `pano_cli plan-brush-stroke-control --kind blend --setting pattern --blend-mode 3`; `ctest --preset desktop-fast --build-config Debug` | Brush color/texture/preset/stroke-settings, texture-list, and stroke-control execution are owned by injected brush/app/asset/UI services with no legacy brush/canvas adapter | +| DEBT-0023 | Open | Modernization | Brush/color/preset/stroke-settings UI planning, texture-list add/remove/reorder planning, stroke-panel slider/toggle/blend/reset planning, and execution dispatch now consume pure `pp_app_core` through `App::init_sidebar`, `NodePanelBrush`, `NodePanelStroke`, restored/docked floating-panel callbacks, `pano_cli plan-brush-operation`, `pano_cli plan-brush-texture-list`, `pano_cli plan-brush-stroke-control`, `BrushUiServices`, `BrushTextureListServices`, and `BrushStrokeControlServices`, and live execution is centralized in `src/legacy_brush_ui_services.*`, but the bridge still mutates legacy `Brush`/`Canvas::I`, loads/saves legacy brush texture images, refreshes legacy quick/stroke/color widgets, and uses a temporary `NodePanelBrush` friend adapter to reach private list state | Preserve existing brush UI behavior while brush commands move toward a brush/app/asset command boundary and asset-managed texture selection | `pp_app_core_brush_ui_tests`; `pano_cli plan-brush-operation --kind color --r 0.25 --g 0.5 --b 0.75 --a 1`; `pano_cli plan-brush-operation --kind pattern --path data/patterns/noise.png --thumb data/patterns/thumbs/noise.png`; `pano_cli plan-brush-texture-list --kind add --dir brushes --data-path data --source C:/Temp/soft.png`; `pano_cli plan-brush-stroke-control --kind float --setting tip-size --value 42.5`; `pano_cli plan-brush-stroke-control --kind blend --setting pattern --blend-mode 3`; `ctest --preset desktop-fast --build-config Debug` | Brush color/texture/preset/stroke-settings, texture-list, and stroke-control execution are owned by injected brush/app/asset/UI services with no legacy brush/canvas adapter or `NodePanelBrush` friend access | | DEBT-0024 | Open | Modernization | Grid/heightmap/lightmap UI planning now consumes pure `pp_app_core` through `NodePanelGrid` and `pano_cli plan-grid-operation`, but live execution still performs legacy image loading, OpenGL texture updates, nanort lightmap baking, progress UI, and `Canvas::draw_objects` commit directly | Preserve grid/lightmap behavior while moving renderable grid commands toward app/renderer/document boundaries | `pp_app_core_grid_ui_tests`; `pano_cli plan-grid-operation --kind render --float32 --texture-resolution 1024 --samples 32`; `ctest --preset desktop-fast --build-config Debug` | Grid heightmap/lightmap execution is owned by app/renderer/document services with `NodePanelGrid` acting only as UI adapter | | DEBT-0025 | Open | Modernization | Quick brush/color slot and mini-state planning and execution dispatch now consume pure `pp_app_core` through `NodePanelQuick`, `pano_cli plan-quick-operation`, and the `QuickUiServices` boundary, but the live adapter still mutates legacy quick UI widgets, `Brush` previews, color picker popup state, and preset popup state | Preserve quick-panel behavior while quick brush/color commands move toward a brush/app command boundary with safer automation coverage | `pp_app_core_quick_ui_tests`; `pano_cli plan-quick-operation --kind brush --current-index 0 --slot-index 2`; `pano_cli plan-quick-operation --kind restore --brush-index 2 --color-index 1 --fire-event`; `ctest --preset desktop-fast --build-config Debug` | Quick-panel selection, popup, restore, reset, brush preview, and color execution are owned by injected app/brush/UI services with no legacy quick-panel adapter | | DEBT-0026 | Open | Modernization | Toolbar history command planning and canvas hotkey history dispatch now consume pure `pp_app_core` through `App::init_toolbar_main`, `NodeCanvas`, `pano_cli plan-history-operation`, and the `HistoryUiServices` boundary, and both live callers share `src/legacy_history_services.*` for saturated legacy history metrics and execution, but the shared live bridge still mutates legacy `ActionManager` stacks directly | Preserve undo/redo/clear behavior while moving action history toward document/app command services | `pp_app_core_history_ui_tests`; `pano_cli plan-history-operation --kind undo --undo-count 2`; `pano_cli plan-history-operation --kind clear --undo-count 2 --redo-count 1 --memory-bytes 4096`; `ctest --preset desktop-fast --build-config Debug` | Undo/redo/clear execution is owned by injected document/app history services with no legacy `ActionManager` adapter | diff --git a/docs/modernization/roadmap.md b/docs/modernization/roadmap.md index 094e38a..d5a3d2b 100644 --- a/docs/modernization/roadmap.md +++ b/docs/modernization/roadmap.md @@ -520,21 +520,22 @@ legacy `Canvas`/`Layer`/canvas-mode adapter continues. changes, tip/pattern/dual texture changes, preset brush replacement, and stroke settings refreshes used by the live brush, quick, color, and floating panel callbacks. Brush UI execution now dispatches through `BrushUiServices` before -the legacy `Brush`/panel adapter mutates brush state or loads brush resources. +the shared `src/legacy_brush_ui_services.*` bridge mutates legacy `Brush` and +panel state or loads brush resources. `pano_cli plan-brush-texture-list` exposes app-core planning for brush/pattern texture add, remove, and reorder actions, and `NodePanelBrush` now dispatches -those actions through `BrushTextureListServices` before the legacy image -load/save and UI-list adapter continues. +those actions through `BrushTextureListServices` in the shared brush bridge +before the legacy image load/save and UI-list adapter continues. `pano_cli plan-brush-stroke-control` exposes app-core planning for the live stroke panel's slider, checkbox, blend-mode, tip-aspect reset, and default brush reset commands. `NodePanelStroke` now dispatches those controls through -`BrushStrokeControlServices` before the legacy `Canvas::I`/`Brush`/stroke-panel -adapter continues. +`BrushStrokeControlServices` in the shared brush bridge before the legacy +`Canvas::I`/`Brush`/stroke-panel adapter continues. `pano_cli plan-canvas-tool` exposes app-core planning for draw/erase/line, camera, grid, copy, cut, fill, mask, flood-fill, pick, and touch-lock toolbar commands. Canvas tool execution now dispatches through `CanvasToolServices` -through `src/legacy_canvas_tool_services.*` before legacy toolbar selection, -`Canvas` mode, pen picking, touch-lock, and transform state adapters continue. +in `src/legacy_canvas_tool_services.*` before legacy toolbar selection, `Canvas` +mode, pen picking, touch-lock, and transform state adapters continue. `pano_cli plan-canvas-tool-state` exposes the matching toolbar active-state refresh used by `App::update` before legacy `Canvas` mode state remains the source of truth. `NodeCanvas` stylus eraser mode switching consumes the same diff --git a/src/app_layout.cpp b/src/app_layout.cpp index f30c344..94d687b 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -18,6 +18,7 @@ #include "app_core/main_toolbar.h" #include "app_core/tools_menu.h" #include "legacy_app_shell_services.h" +#include "legacy_brush_ui_services.h" #include "legacy_canvas_tool_services.h" #include "legacy_document_layer_services.h" #include "legacy_history_services.h" @@ -31,115 +32,19 @@ namespace { -class LegacyBrushUiServices final : public pp::app::BrushUiServices { -public: - LegacyBrushUiServices( - App& app, - bool update_quick = false, - bool update_color_panel = false, - const std::shared_ptr& preset_brush = nullptr) noexcept - : app_(app) - , update_quick_(update_quick) - , update_color_panel_(update_color_panel) - , preset_brush_(preset_brush) - { - } - - void set_tip_color(float r, float g, float b, float a) override - { - if (!Canvas::I || !Canvas::I->m_current_brush) - return; - - Canvas::I->m_current_brush->m_tip_color = glm::vec4(r, g, b, a); - if (update_quick_ && app_.quick) - app_.quick->set_color(Canvas::I->m_current_brush->m_tip_color); - if (update_color_panel_ && app_.color) - app_.color->set_color(Canvas::I->m_current_brush->m_tip_color); - } - - void set_texture( - pp::app::BrushUiTextureSlot slot, - std::string_view path, - std::string_view thumbnail_path) override - { - if (!Canvas::I || !Canvas::I->m_current_brush) - return; - - const std::string texture_path(path); - const std::string thumbnail(thumbnail_path); - switch (slot) - { - case pp::app::BrushUiTextureSlot::tip: - Canvas::I->m_current_brush->load_tip(texture_path, thumbnail); - break; - case pp::app::BrushUiTextureSlot::pattern: - Canvas::I->m_current_brush->load_pattern(texture_path, thumbnail); - break; - case pp::app::BrushUiTextureSlot::dual: - Canvas::I->m_current_brush->load_dual(texture_path, thumbnail); - break; - } - } - - void replace_brush_from_preset(bool preserve_existing_color, bool load_resources) override - { - if (!Canvas::I || !Canvas::I->m_current_brush || !preset_brush_) - return; - - const auto color = Canvas::I->m_current_brush->m_tip_color; - *Canvas::I->m_current_brush = *preset_brush_; - if (preserve_existing_color) - Canvas::I->m_current_brush->m_tip_color = color; - if (load_resources) - Canvas::I->m_current_brush->load(); - } - - void refresh_brush_ui(bool update_color_ui, bool update_brush_ui) override - { - app_.brush_update(update_color_ui, update_brush_ui); - } - -private: - App& app_; - bool update_quick_ = false; - bool update_color_panel_ = false; - std::shared_ptr preset_brush_; -}; - bool apply_brush_color_plan(App& app, glm::vec4 color, bool update_quick, bool update_color_panel) { - const auto plan = pp::app::plan_brush_ui_color(color.r, color.g, color.b, color.a); - if (!plan) - return false; - LegacyBrushUiServices services(app, update_quick, update_color_panel); - const auto status = pp::app::execute_brush_ui_plan(plan.value(), services); - if (!status.ok()) - LOG("Brush color action failed: %s", status.message); - return status.ok(); + return pp::panopainter::apply_legacy_brush_color_plan(app, color, update_quick, update_color_panel); } -bool apply_brush_texture_plan(pp::app::BrushUiTextureSlot slot, const std::string& path, const std::string& thumb) +bool apply_brush_texture_plan(App& app, pp::app::BrushUiTextureSlot slot, const std::string& path, const std::string& thumb) { - const auto plan = pp::app::plan_brush_ui_texture(slot, path, thumb); - if (!plan) - return false; - LegacyBrushUiServices services(*App::I); - const auto status = pp::app::execute_brush_ui_plan(plan.value(), services); - if (!status.ok()) - LOG("Brush texture action failed: %s", status.message); - return status.ok(); + return pp::panopainter::apply_legacy_brush_texture_plan(app, slot, path, thumb); } bool apply_brush_preset_plan(App& app, const std::shared_ptr& brush) { - const auto plan = pp::app::plan_brush_ui_preset_replace(static_cast(brush)); - if (!plan) - return false; - LegacyBrushUiServices services(app, false, false, brush); - const auto status = pp::app::execute_brush_ui_plan(plan.value(), services); - if (!status.ok()) - LOG("Brush preset action failed: %s", status.message); - return status.ok(); + return pp::panopainter::apply_legacy_brush_preset_plan(app, brush); } bool apply_document_export_menu_plan(App& app, pp::app::DocumentExportMenuKind kind) @@ -410,18 +315,16 @@ void App::init_sidebar() }; stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) { - apply_brush_texture_plan(pp::app::BrushUiTextureSlot::tip, path, thumb); + apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::tip, path, thumb); }; stroke->on_pattern_changed = [this](Node*target, const std::string& path, const std::string& thumb) { - apply_brush_texture_plan(pp::app::BrushUiTextureSlot::pattern, path, thumb); + apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::pattern, path, thumb); }; stroke->on_dual_changed = [this](Node*target, const std::string& path, const std::string& thumb) { - apply_brush_texture_plan(pp::app::BrushUiTextureSlot::dual, path, thumb); + apply_brush_texture_plan(*this, pp::app::BrushUiTextureSlot::dual, path, thumb); }; stroke->on_stroke_change = [this](Node*) { - const auto plan = pp::app::plan_brush_ui_stroke_settings_changed(); - LegacyBrushUiServices services(*this); - const auto status = pp::app::execute_brush_ui_plan(plan, services); + const auto status = pp::panopainter::execute_legacy_brush_stroke_changed_plan(*this); if (!status.ok()) LOG("Brush stroke settings action failed: %s", status.message); }; diff --git a/src/legacy_brush_ui_services.cpp b/src/legacy_brush_ui_services.cpp new file mode 100644 index 0000000..b83e77a --- /dev/null +++ b/src/legacy_brush_ui_services.cpp @@ -0,0 +1,388 @@ +#include "pch.h" + +#include "legacy_brush_ui_services.h" + +#include "app.h" +#include "asset.h" +#include "canvas.h" +#include "image.h" +#include "log.h" +#include "node_panel_brush.h" +#include "node_panel_stroke.h" + +namespace pp::panopainter { +namespace { + +class LegacyBrushUiServices final : public pp::app::BrushUiServices { +public: + LegacyBrushUiServices( + App& app, + bool update_quick = false, + bool update_color_panel = false, + const std::shared_ptr& preset_brush = nullptr) noexcept + : app_(app) + , update_quick_(update_quick) + , update_color_panel_(update_color_panel) + , preset_brush_(preset_brush) + { + } + + void set_tip_color(float r, float g, float b, float a) override + { + if (!Canvas::I || !Canvas::I->m_current_brush) + return; + + Canvas::I->m_current_brush->m_tip_color = glm::vec4(r, g, b, a); + if (update_quick_ && app_.quick) + app_.quick->set_color(Canvas::I->m_current_brush->m_tip_color); + if (update_color_panel_ && app_.color) + app_.color->set_color(Canvas::I->m_current_brush->m_tip_color); + } + + void set_texture( + pp::app::BrushUiTextureSlot slot, + std::string_view path, + std::string_view thumbnail_path) override + { + if (!Canvas::I || !Canvas::I->m_current_brush) + return; + + const std::string texture_path(path); + const std::string thumbnail(thumbnail_path); + switch (slot) + { + case pp::app::BrushUiTextureSlot::tip: + Canvas::I->m_current_brush->load_tip(texture_path, thumbnail); + break; + case pp::app::BrushUiTextureSlot::pattern: + Canvas::I->m_current_brush->load_pattern(texture_path, thumbnail); + break; + case pp::app::BrushUiTextureSlot::dual: + Canvas::I->m_current_brush->load_dual(texture_path, thumbnail); + break; + } + } + + void replace_brush_from_preset(bool preserve_existing_color, bool load_resources) override + { + if (!Canvas::I || !Canvas::I->m_current_brush || !preset_brush_) + return; + + const auto color = Canvas::I->m_current_brush->m_tip_color; + *Canvas::I->m_current_brush = *preset_brush_; + if (preserve_existing_color) + Canvas::I->m_current_brush->m_tip_color = color; + if (load_resources) + Canvas::I->m_current_brush->load(); + } + + void refresh_brush_ui(bool update_color_ui, bool update_brush_ui) override + { + app_.brush_update(update_color_ui, update_brush_ui); + } + +private: + App& app_; + bool update_quick_ = false; + bool update_color_panel_ = false; + std::shared_ptr preset_brush_; +}; + +class LegacyBrushStrokeControlServices final : public pp::app::BrushStrokeControlServices { +public: + explicit LegacyBrushStrokeControlServices(NodePanelStroke& panel) : panel_(panel) {} + + void set_float_setting(pp::app::BrushStrokeFloatSetting setting, float value) override + { + auto& brush = *Canvas::I->m_current_brush; + switch (setting) { + case pp::app::BrushStrokeFloatSetting::tip_size: brush.m_tip_size = value; break; + case pp::app::BrushStrokeFloatSetting::tip_spacing: brush.m_tip_spacing = value; break; + case pp::app::BrushStrokeFloatSetting::tip_flow: brush.m_tip_flow = value; break; + case pp::app::BrushStrokeFloatSetting::tip_opacity: brush.m_tip_opacity = value; break; + case pp::app::BrushStrokeFloatSetting::tip_angle: brush.m_tip_angle = value; break; + case pp::app::BrushStrokeFloatSetting::tip_angle_smooth: brush.m_tip_angle_smooth = value; break; + case pp::app::BrushStrokeFloatSetting::tip_mix: brush.m_tip_mix = value; break; + case pp::app::BrushStrokeFloatSetting::tip_wet: brush.m_tip_wet = value; break; + case pp::app::BrushStrokeFloatSetting::tip_noise: brush.m_tip_noise = value; break; + case pp::app::BrushStrokeFloatSetting::tip_hue: brush.m_tip_hue = value; break; + case pp::app::BrushStrokeFloatSetting::tip_saturation: brush.m_tip_sat = value; break; + case pp::app::BrushStrokeFloatSetting::tip_value: brush.m_tip_val = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_scale: brush.m_jitter_scale = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_angle: brush.m_jitter_angle = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_scatter: brush.m_jitter_scatter = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_flow: brush.m_jitter_flow = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_opacity: brush.m_jitter_opacity = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_hue: brush.m_jitter_hue = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_saturation: brush.m_jitter_sat = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_value: brush.m_jitter_val = value; break; + case pp::app::BrushStrokeFloatSetting::jitter_aspect: brush.m_jitter_aspect = value; break; + case pp::app::BrushStrokeFloatSetting::dual_size: brush.m_dual_size = value; break; + case pp::app::BrushStrokeFloatSetting::dual_spacing: brush.m_dual_spacing = value; break; + case pp::app::BrushStrokeFloatSetting::dual_scatter: brush.m_dual_scatter = value; break; + case pp::app::BrushStrokeFloatSetting::tip_aspect: brush.m_tip_aspect = value; break; + case pp::app::BrushStrokeFloatSetting::dual_opacity: brush.m_dual_opacity = value; break; + case pp::app::BrushStrokeFloatSetting::dual_flow: brush.m_dual_flow = value; break; + case pp::app::BrushStrokeFloatSetting::dual_rotate: brush.m_dual_rotate = value; break; + case pp::app::BrushStrokeFloatSetting::pattern_scale: brush.m_pattern_scale = value; break; + case pp::app::BrushStrokeFloatSetting::pattern_brightness: brush.m_pattern_brightness = value; break; + case pp::app::BrushStrokeFloatSetting::pattern_contrast: brush.m_pattern_contrast = value; break; + case pp::app::BrushStrokeFloatSetting::pattern_depth: brush.m_pattern_depth = value; break; + } + } + + void set_bool_setting(pp::app::BrushStrokeBoolSetting setting, bool value) override + { + auto& brush = *Canvas::I->m_current_brush; + switch (setting) { + case pp::app::BrushStrokeBoolSetting::tip_angle_init: brush.m_tip_angle_init = value; break; + case pp::app::BrushStrokeBoolSetting::tip_angle_follow: brush.m_tip_angle_follow = value; break; + case pp::app::BrushStrokeBoolSetting::tip_flow_pressure: brush.m_tip_flow_pressure = value; break; + case pp::app::BrushStrokeBoolSetting::tip_opacity_pressure: brush.m_tip_opacity_pressure = value; break; + case pp::app::BrushStrokeBoolSetting::tip_size_pressure: brush.m_tip_size_pressure = value; break; + case pp::app::BrushStrokeBoolSetting::jitter_scatter_both_axis: brush.m_jitter_scatter_bothaxis = value; break; + case pp::app::BrushStrokeBoolSetting::jitter_aspect_both_axis: brush.m_jitter_aspect_bothaxis = value; break; + case pp::app::BrushStrokeBoolSetting::jitter_hsv_each_sample: brush.m_jitter_hsv_eachsample = value; break; + case pp::app::BrushStrokeBoolSetting::tip_invert: brush.m_tip_invert = value; break; + case pp::app::BrushStrokeBoolSetting::tip_flip_x: brush.m_tip_flipx = value; break; + case pp::app::BrushStrokeBoolSetting::tip_flip_y: brush.m_tip_flipy = value; break; + case pp::app::BrushStrokeBoolSetting::pattern_enabled: brush.m_pattern_enabled = value; break; + case pp::app::BrushStrokeBoolSetting::dual_enabled: brush.m_dual_enabled = value; break; + case pp::app::BrushStrokeBoolSetting::dual_scatter_both_axis: brush.m_dual_scatter_bothaxis = value; break; + case pp::app::BrushStrokeBoolSetting::dual_invert: brush.m_dual_invert = value; break; + case pp::app::BrushStrokeBoolSetting::dual_flip_x: brush.m_dual_flipx = value; break; + case pp::app::BrushStrokeBoolSetting::dual_flip_y: brush.m_dual_flipy = value; break; + case pp::app::BrushStrokeBoolSetting::dual_random_flip: brush.m_dual_randflip = value; break; + case pp::app::BrushStrokeBoolSetting::tip_random_flip_x: brush.m_tip_randflipx = value; break; + case pp::app::BrushStrokeBoolSetting::tip_random_flip_y: brush.m_tip_randflipy = value; break; + case pp::app::BrushStrokeBoolSetting::pattern_each_sample: brush.m_pattern_eachsample = value; break; + case pp::app::BrushStrokeBoolSetting::pattern_invert: brush.m_pattern_invert = value; break; + case pp::app::BrushStrokeBoolSetting::pattern_flip_x: brush.m_pattern_flipx = value; break; + case pp::app::BrushStrokeBoolSetting::pattern_flip_y: brush.m_pattern_flipy = value; break; + case pp::app::BrushStrokeBoolSetting::pattern_random_offset: brush.m_pattern_rand_offset = value; break; + } + } + + void set_blend_mode(pp::app::BrushStrokeBlendSetting setting, int blend_mode) override + { + auto& brush = *Canvas::I->m_current_brush; + switch (setting) { + case pp::app::BrushStrokeBlendSetting::tip: brush.m_blend_mode = blend_mode; break; + case pp::app::BrushStrokeBlendSetting::dual: brush.m_dual_blend_mode = blend_mode; break; + case pp::app::BrushStrokeBlendSetting::pattern: brush.m_pattern_blend_mode = blend_mode; break; + } + } + + void reset_tip_aspect(float value) override + { + panel_.m_tip_aspect->set_value(value); + Canvas::I->m_current_brush->m_tip_aspect = value; + } + + void reset_default_brush() override + { + auto brush = std::make_shared(); + brush->load_tip( + panel_.m_brush_popup->get_texture_path(panel_.m_default_brush_index), + panel_.m_brush_popup->get_thumb_path(panel_.m_default_brush_index)); + brush->m_tip_size = 30; + brush->m_tip_flow = .9f; + brush->m_tip_spacing = .1f; + brush->m_tip_opacity = 1.f; + Canvas::I->m_current_brush = brush; + } + + void update_stroke_controls() override + { + panel_.update_controls(); + } + + void refresh_stroke_preview() override + { + if (panel_.m_preview) { + panel_.m_preview->m_brush = Canvas::I->m_current_brush; + } + } + + void notify_stroke_changed() override + { + if (panel_.on_stroke_change) { + panel_.on_stroke_change(&panel_); + } + } + +private: + NodePanelStroke& panel_; +}; + +} // namespace + +class LegacyBrushTextureListServices final : public pp::app::BrushTextureListServices { +public: + explicit LegacyBrushTextureListServices(NodePanelBrush& panel) noexcept + : panel_(panel) + { + } + + pp::foundation::Status add_texture_from_source( + std::string_view source_path, + std::string_view high_path, + std::string_view thumbnail_path, + std::string_view brush_name, + bool converts_brush_alpha) override + { + Image img; + if (!img.load_file(std::string(source_path))) { + return pp::foundation::Status::invalid_argument("brush texture source could not be loaded"); + } + + if (converts_brush_alpha) { + img.gayscale_alpha(); + } + + auto thumbnail_image = img.resize(64, 64).resize_squared(glm::u8vec4(255)); + thumbnail_image.save_png(std::string(thumbnail_path)); + img.save_png(std::string(high_path)); + + NodeButtonBrush* brush = new NodeButtonBrush; + panel_.m_container->add_child(brush); + brush->init(); + brush->create(); + brush->loaded(); + const auto thumbnail_path_string = std::string(thumbnail_path); + brush->set_icon(thumbnail_path_string.c_str()); + brush->thumb_path = std::string(thumbnail_path); + brush->high_path = std::string(high_path); + brush->brush_name = std::string(brush_name); + brush->m_user_brush = true; + brush->on_click = std::bind(&NodePanelBrush::handle_click, &panel_, std::placeholders::_1); + return pp::foundation::Status::success(); + } + + void remove_texture(int index, bool delete_texture_files) override + { + auto* brush = brush_at(index); + if (!brush) { + return; + } + + if (delete_texture_files) { + Asset::delete_file(brush->thumb_path); + Asset::delete_file(brush->high_path); + } + + if (panel_.m_current == brush) { + panel_.m_current = nullptr; + } + panel_.m_container->remove_child(brush); + } + + void move_texture(int from_index, int to_index) override + { + if (auto* brush = brush_at(from_index)) { + panel_.m_container->move_child(brush, to_index); + } + } + + void select_texture(int index) override + { + if (panel_.m_current) { + panel_.m_current->m_selected = false; + } + + panel_.m_current = brush_at(index); + if (!panel_.m_current) { + return; + } + + panel_.m_current->m_selected = true; + if (panel_.on_brush_changed) { + panel_.on_brush_changed(&panel_, index); + } + } + + void save_texture_list() override + { + panel_.save(); + } + +private: + NodeButtonBrush* brush_at(int index) const + { + if (index < 0 || index >= static_cast(panel_.m_container->m_children.size())) { + return nullptr; + } + return static_cast(panel_.m_container->m_children[index].get()); + } + + NodePanelBrush& panel_; +}; + +bool apply_legacy_brush_color_plan( + App& app, + glm::vec4 color, + bool update_quick, + bool update_color_panel) +{ + const auto plan = pp::app::plan_brush_ui_color(color.r, color.g, color.b, color.a); + if (!plan) + return false; + LegacyBrushUiServices services(app, update_quick, update_color_panel); + const auto status = pp::app::execute_brush_ui_plan(plan.value(), services); + if (!status.ok()) + LOG("Brush color action failed: %s", status.message); + return status.ok(); +} + +bool apply_legacy_brush_texture_plan( + App& app, + pp::app::BrushUiTextureSlot slot, + const std::string& path, + const std::string& thumb) +{ + const auto plan = pp::app::plan_brush_ui_texture(slot, path, thumb); + if (!plan) + return false; + LegacyBrushUiServices services(app); + const auto status = pp::app::execute_brush_ui_plan(plan.value(), services); + if (!status.ok()) + LOG("Brush texture action failed: %s", status.message); + return status.ok(); +} + +bool apply_legacy_brush_preset_plan(App& app, const std::shared_ptr& brush) +{ + const auto plan = pp::app::plan_brush_ui_preset_replace(static_cast(brush)); + if (!plan) + return false; + LegacyBrushUiServices services(app, false, false, brush); + const auto status = pp::app::execute_brush_ui_plan(plan.value(), services); + if (!status.ok()) + LOG("Brush preset action failed: %s", status.message); + return status.ok(); +} + +pp::foundation::Status execute_legacy_brush_stroke_changed_plan(App& app) +{ + const auto plan = pp::app::plan_brush_ui_stroke_settings_changed(); + LegacyBrushUiServices services(app); + return pp::app::execute_brush_ui_plan(plan, services); +} + +pp::foundation::Status execute_legacy_brush_texture_list_plan( + NodePanelBrush& panel, + const pp::app::BrushTextureListPlan& plan) +{ + LegacyBrushTextureListServices services(panel); + return pp::app::execute_brush_texture_list_plan(plan, services); +} + +pp::foundation::Status execute_legacy_brush_stroke_control_plan( + NodePanelStroke& panel, + const pp::app::BrushStrokeControlPlan& plan) +{ + LegacyBrushStrokeControlServices services(panel); + return pp::app::execute_brush_stroke_control_plan(plan, services); +} + +} // namespace pp::panopainter diff --git a/src/legacy_brush_ui_services.h b/src/legacy_brush_ui_services.h new file mode 100644 index 0000000..5912f52 --- /dev/null +++ b/src/legacy_brush_ui_services.h @@ -0,0 +1,38 @@ +#pragma once + +#include "app_core/brush_ui.h" +#include "foundation/result.h" +#include "glm/glm.hpp" + +#include +#include + +class App; +class Brush; +class NodePanelBrush; +class NodePanelStroke; + +namespace pp::panopainter { + +[[nodiscard]] bool apply_legacy_brush_color_plan( + App& app, + glm::vec4 color, + bool update_quick, + bool update_color_panel); +[[nodiscard]] bool apply_legacy_brush_texture_plan( + App& app, + pp::app::BrushUiTextureSlot slot, + const std::string& path, + const std::string& thumb); +[[nodiscard]] bool apply_legacy_brush_preset_plan( + App& app, + const std::shared_ptr& brush); +[[nodiscard]] pp::foundation::Status execute_legacy_brush_stroke_changed_plan(App& app); +[[nodiscard]] pp::foundation::Status execute_legacy_brush_texture_list_plan( + NodePanelBrush& panel, + const pp::app::BrushTextureListPlan& plan); +[[nodiscard]] pp::foundation::Status execute_legacy_brush_stroke_control_plan( + NodePanelStroke& panel, + const pp::app::BrushStrokeControlPlan& plan); + +} // namespace pp::panopainter diff --git a/src/node_panel_brush.cpp b/src/node_panel_brush.cpp index 33e122a..7b24904 100644 --- a/src/node_panel_brush.cpp +++ b/src/node_panel_brush.cpp @@ -2,6 +2,7 @@ #include "log.h" #include "node_panel_brush.h" #include "app_core/brush_ui.h" +#include "legacy_brush_ui_services.h" #include "asset.h" #include "texture.h" @@ -78,109 +79,7 @@ Node* NodePanelBrush::clone_instantiate() const void NodePanelBrush::execute_texture_list_plan(const pp::app::BrushTextureListPlan& plan) { - class LegacyBrushTextureListServices final : public pp::app::BrushTextureListServices { - public: - explicit LegacyBrushTextureListServices(NodePanelBrush& panel) noexcept - : panel_(panel) - { - } - - pp::foundation::Status add_texture_from_source( - std::string_view source_path, - std::string_view high_path, - std::string_view thumbnail_path, - std::string_view brush_name, - bool converts_brush_alpha) override - { - Image img; - if (!img.load_file(std::string(source_path))) { - return pp::foundation::Status::invalid_argument("brush texture source could not be loaded"); - } - - if (converts_brush_alpha) { - img.gayscale_alpha(); - } - - auto thumbnail_image = img.resize(64, 64).resize_squared(glm::u8vec4(255)); - thumbnail_image.save_png(std::string(thumbnail_path)); - img.save_png(std::string(high_path)); - - NodeButtonBrush* brush = new NodeButtonBrush; - panel_.m_container->add_child(brush); - brush->init(); - brush->create(); - brush->loaded(); - const auto thumbnail_path_string = std::string(thumbnail_path); - brush->set_icon(thumbnail_path_string.c_str()); - brush->thumb_path = std::string(thumbnail_path); - brush->high_path = std::string(high_path); - brush->brush_name = std::string(brush_name); - brush->m_user_brush = true; - brush->on_click = std::bind(&NodePanelBrush::handle_click, &panel_, std::placeholders::_1); - return pp::foundation::Status::success(); - } - - void remove_texture(int index, bool delete_texture_files) override - { - auto* brush = brush_at(index); - if (!brush) { - return; - } - - if (delete_texture_files) { - Asset::delete_file(brush->thumb_path); - Asset::delete_file(brush->high_path); - } - - if (panel_.m_current == brush) { - panel_.m_current = nullptr; - } - panel_.m_container->remove_child(brush); - } - - void move_texture(int from_index, int to_index) override - { - if (auto* brush = brush_at(from_index)) { - panel_.m_container->move_child(brush, to_index); - } - } - - void select_texture(int index) override - { - if (panel_.m_current) { - panel_.m_current->m_selected = false; - } - - panel_.m_current = brush_at(index); - if (!panel_.m_current) { - return; - } - - panel_.m_current->m_selected = true; - if (panel_.on_brush_changed) { - panel_.on_brush_changed(&panel_, index); - } - } - - void save_texture_list() override - { - panel_.save(); - } - - private: - NodeButtonBrush* brush_at(int index) const - { - if (index < 0 || index >= static_cast(panel_.m_container->m_children.size())) { - return nullptr; - } - return static_cast(panel_.m_container->m_children[index].get()); - } - - NodePanelBrush& panel_; - }; - - LegacyBrushTextureListServices services(*this); - const auto status = pp::app::execute_brush_texture_list_plan(plan, services); + const auto status = pp::panopainter::execute_legacy_brush_texture_list_plan(*this, plan); if (!status.ok()) { LOG("Brush texture list action failed: %s", status.message); } diff --git a/src/node_panel_brush.h b/src/node_panel_brush.h index 9d04590..aa3295f 100644 --- a/src/node_panel_brush.h +++ b/src/node_panel_brush.h @@ -12,6 +12,9 @@ namespace pp::app { struct BrushTextureListPlan; } +namespace pp::panopainter { +class LegacyBrushTextureListServices; +} class NodeButtonBrush : public NodeButtonCustom, public Serializer::Type { @@ -34,6 +37,8 @@ public: class NodePanelBrush : public Node { + friend class pp::panopainter::LegacyBrushTextureListServices; + // brushes that are marked as deleted but file still exists std::vector m_deleted; NodeButtonBrush* m_current = nullptr; diff --git a/src/node_panel_stroke.cpp b/src/node_panel_stroke.cpp index 428d2b9..714d80f 100644 --- a/src/node_panel_stroke.cpp +++ b/src/node_panel_stroke.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "app_core/brush_ui.h" +#include "legacy_brush_ui_services.h" #include "log.h" #include "node_panel_stroke.h" #include "canvas.h" @@ -7,137 +8,6 @@ #include "app.h" #include "abr.h" -namespace { - -class LegacyBrushStrokeControlServices final : public pp::app::BrushStrokeControlServices { -public: - explicit LegacyBrushStrokeControlServices(NodePanelStroke& panel) : panel_(panel) {} - - void set_float_setting(pp::app::BrushStrokeFloatSetting setting, float value) override - { - auto& brush = *Canvas::I->m_current_brush; - switch (setting) { - case pp::app::BrushStrokeFloatSetting::tip_size: brush.m_tip_size = value; break; - case pp::app::BrushStrokeFloatSetting::tip_spacing: brush.m_tip_spacing = value; break; - case pp::app::BrushStrokeFloatSetting::tip_flow: brush.m_tip_flow = value; break; - case pp::app::BrushStrokeFloatSetting::tip_opacity: brush.m_tip_opacity = value; break; - case pp::app::BrushStrokeFloatSetting::tip_angle: brush.m_tip_angle = value; break; - case pp::app::BrushStrokeFloatSetting::tip_angle_smooth: brush.m_tip_angle_smooth = value; break; - case pp::app::BrushStrokeFloatSetting::tip_mix: brush.m_tip_mix = value; break; - case pp::app::BrushStrokeFloatSetting::tip_wet: brush.m_tip_wet = value; break; - case pp::app::BrushStrokeFloatSetting::tip_noise: brush.m_tip_noise = value; break; - case pp::app::BrushStrokeFloatSetting::tip_hue: brush.m_tip_hue = value; break; - case pp::app::BrushStrokeFloatSetting::tip_saturation: brush.m_tip_sat = value; break; - case pp::app::BrushStrokeFloatSetting::tip_value: brush.m_tip_val = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_scale: brush.m_jitter_scale = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_angle: brush.m_jitter_angle = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_scatter: brush.m_jitter_scatter = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_flow: brush.m_jitter_flow = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_opacity: brush.m_jitter_opacity = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_hue: brush.m_jitter_hue = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_saturation: brush.m_jitter_sat = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_value: brush.m_jitter_val = value; break; - case pp::app::BrushStrokeFloatSetting::jitter_aspect: brush.m_jitter_aspect = value; break; - case pp::app::BrushStrokeFloatSetting::dual_size: brush.m_dual_size = value; break; - case pp::app::BrushStrokeFloatSetting::dual_spacing: brush.m_dual_spacing = value; break; - case pp::app::BrushStrokeFloatSetting::dual_scatter: brush.m_dual_scatter = value; break; - case pp::app::BrushStrokeFloatSetting::tip_aspect: brush.m_tip_aspect = value; break; - case pp::app::BrushStrokeFloatSetting::dual_opacity: brush.m_dual_opacity = value; break; - case pp::app::BrushStrokeFloatSetting::dual_flow: brush.m_dual_flow = value; break; - case pp::app::BrushStrokeFloatSetting::dual_rotate: brush.m_dual_rotate = value; break; - case pp::app::BrushStrokeFloatSetting::pattern_scale: brush.m_pattern_scale = value; break; - case pp::app::BrushStrokeFloatSetting::pattern_brightness: brush.m_pattern_brightness = value; break; - case pp::app::BrushStrokeFloatSetting::pattern_contrast: brush.m_pattern_contrast = value; break; - case pp::app::BrushStrokeFloatSetting::pattern_depth: brush.m_pattern_depth = value; break; - } - } - - void set_bool_setting(pp::app::BrushStrokeBoolSetting setting, bool value) override - { - auto& brush = *Canvas::I->m_current_brush; - switch (setting) { - case pp::app::BrushStrokeBoolSetting::tip_angle_init: brush.m_tip_angle_init = value; break; - case pp::app::BrushStrokeBoolSetting::tip_angle_follow: brush.m_tip_angle_follow = value; break; - case pp::app::BrushStrokeBoolSetting::tip_flow_pressure: brush.m_tip_flow_pressure = value; break; - case pp::app::BrushStrokeBoolSetting::tip_opacity_pressure: brush.m_tip_opacity_pressure = value; break; - case pp::app::BrushStrokeBoolSetting::tip_size_pressure: brush.m_tip_size_pressure = value; break; - case pp::app::BrushStrokeBoolSetting::jitter_scatter_both_axis: brush.m_jitter_scatter_bothaxis = value; break; - case pp::app::BrushStrokeBoolSetting::jitter_aspect_both_axis: brush.m_jitter_aspect_bothaxis = value; break; - case pp::app::BrushStrokeBoolSetting::jitter_hsv_each_sample: brush.m_jitter_hsv_eachsample = value; break; - case pp::app::BrushStrokeBoolSetting::tip_invert: brush.m_tip_invert = value; break; - case pp::app::BrushStrokeBoolSetting::tip_flip_x: brush.m_tip_flipx = value; break; - case pp::app::BrushStrokeBoolSetting::tip_flip_y: brush.m_tip_flipy = value; break; - case pp::app::BrushStrokeBoolSetting::pattern_enabled: brush.m_pattern_enabled = value; break; - case pp::app::BrushStrokeBoolSetting::dual_enabled: brush.m_dual_enabled = value; break; - case pp::app::BrushStrokeBoolSetting::dual_scatter_both_axis: brush.m_dual_scatter_bothaxis = value; break; - case pp::app::BrushStrokeBoolSetting::dual_invert: brush.m_dual_invert = value; break; - case pp::app::BrushStrokeBoolSetting::dual_flip_x: brush.m_dual_flipx = value; break; - case pp::app::BrushStrokeBoolSetting::dual_flip_y: brush.m_dual_flipy = value; break; - case pp::app::BrushStrokeBoolSetting::dual_random_flip: brush.m_dual_randflip = value; break; - case pp::app::BrushStrokeBoolSetting::tip_random_flip_x: brush.m_tip_randflipx = value; break; - case pp::app::BrushStrokeBoolSetting::tip_random_flip_y: brush.m_tip_randflipy = value; break; - case pp::app::BrushStrokeBoolSetting::pattern_each_sample: brush.m_pattern_eachsample = value; break; - case pp::app::BrushStrokeBoolSetting::pattern_invert: brush.m_pattern_invert = value; break; - case pp::app::BrushStrokeBoolSetting::pattern_flip_x: brush.m_pattern_flipx = value; break; - case pp::app::BrushStrokeBoolSetting::pattern_flip_y: brush.m_pattern_flipy = value; break; - case pp::app::BrushStrokeBoolSetting::pattern_random_offset: brush.m_pattern_rand_offset = value; break; - } - } - - void set_blend_mode(pp::app::BrushStrokeBlendSetting setting, int blend_mode) override - { - auto& brush = *Canvas::I->m_current_brush; - switch (setting) { - case pp::app::BrushStrokeBlendSetting::tip: brush.m_blend_mode = blend_mode; break; - case pp::app::BrushStrokeBlendSetting::dual: brush.m_dual_blend_mode = blend_mode; break; - case pp::app::BrushStrokeBlendSetting::pattern: brush.m_pattern_blend_mode = blend_mode; break; - } - } - - void reset_tip_aspect(float value) override - { - panel_.m_tip_aspect->set_value(value); - Canvas::I->m_current_brush->m_tip_aspect = value; - } - - void reset_default_brush() override - { - auto brush = std::make_shared(); - brush->load_tip( - panel_.m_brush_popup->get_texture_path(panel_.m_default_brush_index), - panel_.m_brush_popup->get_thumb_path(panel_.m_default_brush_index)); - brush->m_tip_size = 30; - brush->m_tip_flow = .9f; - brush->m_tip_spacing = .1f; - brush->m_tip_opacity = 1.f; - Canvas::I->m_current_brush = brush; - } - - void update_stroke_controls() override - { - panel_.update_controls(); - } - - void refresh_stroke_preview() override - { - if (panel_.m_preview) { - panel_.m_preview->m_brush = Canvas::I->m_current_brush; - } - } - - void notify_stroke_changed() override - { - if (panel_.on_stroke_change) { - panel_.on_stroke_change(&panel_); - } - } - -private: - NodePanelStroke& panel_; -}; - -} // namespace - Node* NodePanelStroke::clone_instantiate() const { return new NodePanelStroke(); @@ -704,8 +574,7 @@ void NodePanelStroke::handle_checkbox( void NodePanelStroke::execute_stroke_control_plan(const pp::app::BrushStrokeControlPlan& plan) { - LegacyBrushStrokeControlServices services(*this); - const auto status = pp::app::execute_brush_stroke_control_plan(plan, services); + const auto status = pp::panopainter::execute_legacy_brush_stroke_control_plan(*this, plan); if (!status.ok()) { LOG("Brush stroke control action failed: %s", status.message); }