#include "pch.h" #include "app_core/quick_ui.h" #include "legacy_quick_ui_services.h" #include "node_panel_quick.h" #include "node_stroke_preview.h" #include "node_image.h" #include "app.h" Node* NodePanelQuick::clone_instantiate() const { return new this_class; } void NodePanelQuick::clone_finalize(Node* dest) const { parent::clone_finalize(dest); auto n = static_cast(dest); n->init_controls(); } void NodePanelQuick::init() { parent::init(); init_template_file("data/dialogs/panel-quick.xml", "tpl-panel-quick"); init_controls(); } void NodePanelQuick::set_color(glm::vec3 color) { m_button_color_current_inner->m_color = glm::vec4(color, 1.f); } int NodePanelQuick::get_selected_brush_index() const { auto it = std::find(m_button_brushes.begin(), m_button_brushes.end(), m_button_brush_current); return static_cast(std::distance(m_button_brushes.begin(), it)); } void NodePanelQuick::set_selected_brush_index(int idx, bool fire_event /*= false*/) { if (!pp::app::validate_quick_slot_index(idx, static_cast(m_button_brushes.size())).ok()) return; if (m_button_brush_current) m_button_brush_current->set_active(false); m_button_brush_current = m_button_brushes[idx]; m_button_brush_current->set_active(true); m_button_brush_current_preview = static_cast(m_button_brush_current->m_children[0].get()); if (fire_event && on_brush_change) on_brush_change(this, m_button_brush_current_preview->m_brush); } int NodePanelQuick::get_selected_color_index() const { auto it = std::find(m_button_colors.begin(), m_button_colors.end(), m_button_color_current); return static_cast(std::distance(m_button_colors.begin(), it)); } void NodePanelQuick::set_selected_color_index(int idx, bool fire_event /*= false*/) { if (!pp::app::validate_quick_slot_index(idx, static_cast(m_button_colors.size())).ok()) return; if (m_button_color_current) m_button_color_current->set_active(false); m_button_color_current = m_button_colors[idx]; m_button_color_current->set_active(true); m_button_color_current_inner = static_cast(m_button_color_current->m_children[0].get()); if (fire_event && on_color_change) on_color_change(this, m_button_color_current_inner->m_color); } NodePanelQuick::MiniState NodePanelQuick::get_state() const { MiniState s; s.brush_index = get_selected_brush_index(); s.color_index = get_selected_color_index(); for (int i = 0; i < 3; i++) { s.brushes[i] = static_cast(m_button_brushes[i]->m_children[0].get())->m_brush; s.colors[i] = static_cast(m_button_colors[i]->m_children[0].get())->m_color; } return s; } void NodePanelQuick::set_state(const MiniState& state, bool fire_event /*= false*/) { const auto plan = pp::app::plan_quick_state_restore( state.brush_index, state.color_index, static_cast(m_button_brushes.size()), fire_event); if (!plan) return; const auto status = pp::panopainter::execute_legacy_quick_ui_plan(*this, plan.value(), &state); if (!status.ok()) LOG("Quick restore action failed: %s", status.message); } void NodePanelQuick::reset_state(bool fire_event /*= false*/) { const auto plan = pp::app::plan_quick_state_reset(static_cast(m_button_brushes.size()), fire_event); if (!plan) return; const auto status = pp::panopainter::execute_legacy_quick_ui_plan(*this, plan.value()); if (!status.ok()) LOG("Quick reset action failed: %s", status.message); } void NodePanelQuick::init_controls() { m_picker = std::make_shared(); m_picker->set_manager(m_manager); m_picker->init(); m_picker->create(); m_picker->loaded(); m_picker->m_mouse_ignore = false; m_picker->m_flood_events = true; m_picker->m_capture_children = false; m_picker->SetWidth(300); m_slider_size = find("quick-size"); m_slider_size->on_value_changed = [this](Node* target, float value) { update_slider_preview(); if (on_size_change) on_size_change(target, value); }; m_slider_flow = find("quick-flow"); m_slider_flow->on_value_changed = [this](Node* target, float value) { update_slider_preview(); if (on_flow_change) on_flow_change(target, value); }; for (int i = 0; i < m_button_colors.size(); i++) { m_button_colors[i] = find(fmt::format("quick-color{}", i + 1).c_str()); m_button_colors[i]->on_click = std::bind(&this_class::handle_button_color_click, this, std::placeholders::_1); m_button_colors[i]->color_active = { 0, 0, 0, 0.5f }; m_button_colors[i]->set_color({ 0, 0, 0, 0 }); } m_button_color_current = m_button_colors[0]; m_button_color_current->set_active(true); m_button_color_current_inner = static_cast(m_button_color_current->m_children[0].get()); m_button_brushes[0] = init_button_brush("quick-brush1", true, false); m_button_brushes[1] = init_button_brush("quick-brush2", false, true); m_button_brushes[2] = init_button_brush("quick-brush3", false, false); m_button_brush_current = m_button_brushes[0]; m_button_brush_current->set_active(true); m_button_brush_current_preview = static_cast(m_button_brush_current->m_children[0].get()); } NodeButtonCustom* NodePanelQuick::init_button_brush(const std::string& name, bool szp, bool flp) { LOG("init_button_brush %s", name.c_str()); auto button = find(name.c_str()); if (!button) { LOG("couldn't find button %s", name.c_str()); return nullptr; } button->on_click = std::bind(&this_class::handle_button_brush_click, this, std::placeholders::_1); LOG("button has %d children", static_cast(button->m_children.size())); auto pr = static_cast(button->m_children[0].get()); pr->m_brush = std::make_shared(); pr->m_brush->m_tip_size_pressure = szp; pr->m_brush->m_tip_flow_pressure = flp; pr->m_brush->load_tip("data/brushes/Round-Hard.png", "data/brushes/thumbs/Round-Hard.png"); pr->m_max_size = 20; pr->m_pad_override = 0; pr->m_draw_first = true; pr->draw_stroke(); return button; } void NodePanelQuick::update_slider_preview() { if (!App::I || !Canvas::I || !Canvas::I->m_mode || Canvas::I->m_mode->empty() || !m_slider_flow || !m_button_brush_current_preview) return; auto* mode = (*Canvas::I->m_mode)[0]; auto* pen_mode = dynamic_cast(mode); auto* line_mode = dynamic_cast(mode); const auto plan = pp::app::plan_quick_slider_preview(pp::app::QuickSliderPreviewInput { .ui_rtl = App::I->ui_rtl, .slider_x = m_slider_flow->m_pos.x, .slider_y = m_slider_flow->m_pos.y, .slider_height = m_slider_flow->m_size.y, .zoom = App::I->zoom, .has_pen_mode = pen_mode != nullptr, .has_line_mode = line_mode != nullptr, }); if (!plan) { LOG("Quick slider preview failed: %s", plan.status().message); return; } const glm::vec2 cursor(plan.value().cursor_x, plan.value().cursor_y); if (plan.value().updates_pen_mode && pen_mode) { pen_mode->m_cur_pos = cursor; pen_mode->m_draw_tip = plan.value().draws_tip; pen_mode->m_draw_outline = !plan.value().disables_pen_outline; } if (plan.value().updates_line_mode && line_mode) { line_mode->m_cur_pos = cursor; line_mode->m_draw_tip = plan.value().draws_tip; } if (plan.value().redraws_brush_preview) m_button_brush_current_preview->draw_stroke(); } void NodePanelQuick::handle_button_brush_click(Node* button) { const auto clicked = std::find(m_button_brushes.begin(), m_button_brushes.end(), button); const int clicked_index = static_cast(std::distance(m_button_brushes.begin(), clicked)); const auto plan = pp::app::plan_quick_slot_click( pp::app::QuickUiSlotKind::brush, get_selected_brush_index(), clicked_index, static_cast(m_button_brushes.size())); if (!plan) return; const auto status = pp::panopainter::execute_legacy_quick_ui_plan(*this, plan.value()); if (!status.ok()) LOG("Quick brush action failed: %s", status.message); } void NodePanelQuick::handle_button_color_click(Node* target) { const auto clicked = std::find(m_button_colors.begin(), m_button_colors.end(), target); const int clicked_index = static_cast(std::distance(m_button_colors.begin(), clicked)); const auto plan = pp::app::plan_quick_slot_click( pp::app::QuickUiSlotKind::color, get_selected_color_index(), clicked_index, static_cast(m_button_colors.size())); if (!plan) return; const auto status = pp::panopainter::execute_legacy_quick_ui_plan(*this, plan.value()); if (!status.ok()) LOG("Quick color action failed: %s", status.message); }