diff --git a/data/layout.xml b/data/layout.xml index c0e8df1..b910318 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -758,38 +758,49 @@ --> - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + @@ -1413,7 +1424,7 @@ Here's a list of what's available in this release. - + @@ -1593,7 +1604,7 @@ Here's a list of what's available in this release. - + diff --git a/src/app.h b/src/app.h index 6a8525f..b5e88d2 100644 --- a/src/app.h +++ b/src/app.h @@ -32,6 +32,7 @@ #include "main.h" #endif #include "node_panel_grid.h" +#include "node_panel_quick.h" class App { @@ -64,6 +65,7 @@ public: std::shared_ptr color; std::shared_ptr stroke; std::shared_ptr grid; + NodePanelQuick* quick; NodeCanvas* canvas; Node* current_panel = nullptr; NodeScroll* panels; diff --git a/src/app_layout.cpp b/src/app_layout.cpp index 99b8bdf..c62cc31 100644 --- a/src/app_layout.cpp +++ b/src/app_layout.cpp @@ -110,6 +110,7 @@ void App::init_sidebar() sidebar = layout[main_id]->find("sidebar"); panels = layout[main_id]->find("panels"); canvas = layout[main_id]->find("paint-canvas"); + quick = layout[main_id]->find("panel-quick"); //brushes = layout[main_id]->find("panel-brush"); //layers = layout[main_id]->find("panel-layer"); @@ -128,6 +129,7 @@ void App::init_sidebar() color->on_color_changed = [this](Node* target, glm::vec4 color) { Canvas::I->m_current_brush->m_tip_color = color; }; + stroke->on_brush_changed = [this](Node* target, const std::string& path, const std::string& thumb) { Canvas::I->m_current_brush->load_tip(path, thumb); stroke->m_preview->draw_stroke(); @@ -140,6 +142,20 @@ void App::init_sidebar() Canvas::I->m_current_brush->load_dual(path, thumb); stroke->m_preview->draw_stroke(); }; + stroke->on_stroke_change = [this](Node*) { + quick->m_slider_flow->set_value(stroke->m_tip_flow->get_value()); + quick->m_slider_size->set_value(stroke->m_tip_size->get_value()); + }; + + quick->on_color_change = [this](Node*, glm::vec3 color) { + Canvas::I->m_current_brush->m_tip_color = glm::vec4(color, 1.f); + }; + quick->on_flow_change = [this](Node*, float value) { + stroke->set_flow(value, true, true); + }; + quick->on_size_change = [this](Node*, float value) { + stroke->set_size(value, true, true); + }; layers->on_layer_add = [this](Node*) { canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str()); diff --git a/src/node_button_custom.cpp b/src/node_button_custom.cpp index 84d307f..9703c0d 100644 --- a/src/node_button_custom.cpp +++ b/src/node_button_custom.cpp @@ -29,6 +29,11 @@ void NodeButtonCustom::loaded() m_mouse_ignore = false; } +bool NodeButtonCustom::is_active() +{ + return m_active; +} + void NodeButtonCustom::set_active(bool active) { if (m_active == active) @@ -40,7 +45,7 @@ void NodeButtonCustom::set_active(bool active) void NodeButtonCustom::set_color(const glm::vec4& c) { color_normal = c; - m_color = color_normal; + m_color = m_active ? color_active : (m_mouse_inside ? color_hover : color_normal); } kEventResult NodeButtonCustom::handle_event(Event* e) diff --git a/src/node_button_custom.h b/src/node_button_custom.h index d9789fa..f1fa6d0 100644 --- a/src/node_button_custom.h +++ b/src/node_button_custom.h @@ -13,6 +13,7 @@ public: virtual Node* clone_instantiate() const override; virtual void clone_copy(Node* dest) const override; virtual void loaded() override; + bool is_active(); void set_active(bool active); void set_color(const glm::vec4& c); virtual kEventResult handle_event(Event* e) override; diff --git a/src/node_dialog_picker.cpp b/src/node_dialog_picker.cpp index abb2e69..b1cf93e 100644 --- a/src/node_dialog_picker.cpp +++ b/src/node_dialog_picker.cpp @@ -48,6 +48,12 @@ kEventResult NodeColorPicker::handle_event(Event* e) case kEventType::MouseUpL: if (!m_mouse_inside) { + if (m_color_cur->m_color != m_color_old->m_color) + { + m_color_old2->m_color = m_color_old1->m_color; + m_color_old1->m_color = m_color_old->m_color; + m_color_old->m_color = m_color_cur->m_color; + } mouse_release(); parent->remove_child(this); if (on_popup_close) @@ -74,34 +80,65 @@ void NodeColorPicker::init_controls() m_color_old = find("color-old"); m_color_old1 = find("color-old1"); m_color_old2 = find("color-old2"); - m_button_select = find("btn-select"); - - m_button_select->on_click = [this](Node*) - { - m_color_old2->m_color = m_color_old1->m_color; - m_color_old1->m_color = m_color_old->m_color; - m_color_old->m_color = m_color_cur->m_color; - }; + m_wheel->on_value_changed = [this](Node*, glm::vec3 hsv) { m_slider_h->m_value.x = hsv.x; m_slider_s->m_value.x = hsv.y; m_slider_v->m_value.x = hsv.z; glm::vec3 rgb = convert_hsv2rgb(hsv); - m_slider_r->m_value.x = rgb.x; - m_slider_g->m_value.x = rgb.y; - m_slider_b->m_value.x = rgb.z; - m_color_cur->m_color = {rgb,1}; + m_slider_h->set_value(hsv.x); + m_slider_s->set_value(hsv.y); + m_slider_v->set_value(hsv.z); + m_color_cur->m_color = { rgb, 1 }; + if (on_color_change) + on_color_change(this, rgb); }; auto hsv_setter = [this](Node* target, float v) { - m_wheel->m_hsv = get_hsv(); - glm::vec3 rgb = convert_hsv2rgb(get_hsv()); - m_color_cur->m_color = {rgb,1}; + auto hsv = get_hsv(); + m_wheel->m_hsv = hsv; + glm::vec3 rgb = convert_hsv2rgb(hsv); + m_color_cur->m_color = { rgb, 1 }; + m_slider_r->m_value.x = rgb.x; + m_slider_g->m_value.x = rgb.y; + m_slider_b->m_value.x = rgb.z; + if (on_color_change) + on_color_change(this, rgb); }; m_slider_h->on_value_changed = hsv_setter; m_slider_s->on_value_changed = hsv_setter; m_slider_v->on_value_changed = hsv_setter; + + auto rgb_setter = [this](Node* target, float v) + { + glm::vec3 rgb = get_rgb(); + glm::vec3 hsv = convert_rgb2hsv(rgb); + m_wheel->m_hsv = hsv; + m_color_cur->m_color = { rgb, 1 }; + m_slider_h->set_value(hsv.x); + m_slider_s->set_value(hsv.y); + m_slider_v->set_value(hsv.z); + if (on_color_change) + on_color_change(this, rgb); + }; + m_slider_r->on_value_changed = rgb_setter; + m_slider_g->on_value_changed = rgb_setter; + m_slider_b->on_value_changed = rgb_setter; +} + +void NodeColorPicker::set_color(glm::vec3 rgb) +{ + auto hsv = convert_rgb2hsv(rgb); + m_slider_h->set_value(hsv.x); + m_slider_s->set_value(hsv.y); + m_slider_v->set_value(hsv.z); + m_slider_r->set_value(rgb.x); + m_slider_g->set_value(rgb.y); + m_slider_b->set_value(rgb.z); + m_wheel->m_hsv = hsv; + m_color_cur->m_color = { rgb, 1 }; + m_color_old->m_color = { rgb, 1 }; } glm::vec3 NodeColorPicker::get_hsv() const @@ -111,3 +148,11 @@ glm::vec3 NodeColorPicker::get_hsv() const float v = m_slider_v->get_value(); return glm::vec3(h, s, v); } + +glm::vec3 NodeColorPicker::get_rgb() const +{ + float r = m_slider_r->get_value(); + float g = m_slider_g->get_value(); + float b = m_slider_b->get_value(); + return glm::vec3(r, g, b); +} diff --git a/src/node_dialog_picker.h b/src/node_dialog_picker.h index fe67c89..b5974ec 100644 --- a/src/node_dialog_picker.h +++ b/src/node_dialog_picker.h @@ -9,6 +9,7 @@ class NodeColorPicker : public NodeBorder { public: std::function on_popup_close; + std::function on_color_change; NodeSliderH* m_slider_h; NodeSliderH* m_slider_s; @@ -21,7 +22,6 @@ public: NodeBorder* m_color_old; NodeBorder* m_color_old1; NodeBorder* m_color_old2; - NodeButton* m_button_select; glm::vec3 m_rgb; glm::vec3 m_hsv; @@ -32,6 +32,8 @@ public: virtual void draw() override; virtual kEventResult handle_event(Event* e) override; void init_controls(); + void set_color(glm::vec3 rgb); glm::vec3 get_hsv() const; + glm::vec3 get_rgb() const; void handle_value_changed(); }; diff --git a/src/node_panel_quick.cpp b/src/node_panel_quick.cpp index bd3a8fd..c2e7f96 100644 --- a/src/node_panel_quick.cpp +++ b/src/node_panel_quick.cpp @@ -18,7 +18,7 @@ void NodePanelQuick::clone_finalize(Node* dest) const void NodePanelQuick::init() { parent::init(); - auto t = static_cast(init_template("panel-quick")); + auto t = static_cast(init_template("tpl-panel-quick")); init_controls(); } @@ -39,32 +39,77 @@ void NodePanelQuick::init_controls() m_picker->m_flood_events = true; m_picker->m_capture_children = false; - if (auto b = find("quick-color1")) - { - b->on_click = [this,b](Node*) { - auto screen = root()->m_size; - glm::vec2 pos = b->m_pos + glm::vec2(b->m_size.x, 0); - root()->add_child(m_picker); - auto tick = root()->add_child(); - tick->SetPositioning(YGPositionTypeAbsolute); - tick->SetSize(16, 32); - tick->SetPosition(pos.x, pos.y + (b->m_size.y - 32) * 0.5f); - tick->set_image("data/ui/popup-tick.png"); - //float hh = m_picker->m_container->m_children.size() > 10 ? App::I.height / App::I.zoom * .75f : 400.f; - //m_picker->SetHeight(4); - root()->update(); - pos.y -= 130; - if ((pos.y + m_picker->m_size.y) > screen.y) - pos.y = screen.y - m_picker->m_size.y; - if (pos.y < 0) - pos.y = 0; - m_picker->SetPosition(pos.x + 16, pos.y); - m_picker->mouse_capture(); - root()->update(); + m_slider_size = find("quick-size"); + m_slider_size->on_value_changed = [this](Node* target, float value) { + 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) { + if (on_flow_change) + on_flow_change(target, value); + }; - m_picker->on_popup_close = [this, tick](Node*) { - tick->destroy(); - }; - }; - } + m_button_color1 = find("quick-color1"); + m_button_color2 = find("quick-color2"); + m_button_color3 = find("quick-color3"); + m_button_color_current = m_button_color1; + m_button_color_current->set_active(true); + m_button_color1->on_click = std::bind(&this_class::handle_button_color_click, this, std::placeholders::_1); + m_button_color2->on_click = std::bind(&this_class::handle_button_color_click, this, std::placeholders::_1); + m_button_color3->on_click = std::bind(&this_class::handle_button_color_click, this, std::placeholders::_1); + m_button_color1->color_active = { 0, 0, 0, 0.5f }; + m_button_color2->color_active = { 0, 0, 0, 0.5f }; + m_button_color3->color_active = { 0, 0, 0, 0.5f }; + m_button_color1->set_color({ 0, 0, 0, 0 }); + m_button_color2->set_color({ 0, 0, 0, 0 }); + m_button_color3->set_color({ 0, 0, 0, 0 }); +} + +void NodePanelQuick::handle_button_color_click(Node* target) +{ + // the first time select the box + if (m_button_color_current != target) + { + auto button = static_cast(target); + button->set_active(true); + m_button_color_current->set_active(false); + m_button_color_current = button; + if (on_color_change) + on_color_change(this, static_cast(button->m_children[0].get())->m_color); + return; + } + + // if the box is already selected show the popup + + auto screen = root()->m_size; + glm::vec2 pos = target->m_pos + glm::vec2(target->m_size.x, 0); + root()->add_child(m_picker); + auto tick = root()->add_child(); + tick->SetPositioning(YGPositionTypeAbsolute); + tick->SetSize(16, 32); + tick->SetPosition(pos.x, pos.y + (target->m_size.y - 32) * 0.5f); + tick->set_image("data/ui/popup-tick.png"); + //float hh = m_picker->m_container->m_children.size() > 10 ? App::I.height / App::I.zoom * .75f : 400.f; + //m_picker->SetHeight(4); + root()->update(); + pos.y -= 130; + if ((pos.y + m_picker->m_size.y) > screen.y) + pos.y = screen.y - m_picker->m_size.y; + if (pos.y < 0) + pos.y = 0; + m_picker->SetPosition(pos.x + 16, pos.y); + m_picker->mouse_capture(); + root()->update(); + + auto c = static_cast(target->m_children[0].get()); + m_picker->set_color(c->m_color); + m_picker->on_popup_close = [this, tick](Node*) { + tick->destroy(); + }; + m_picker->on_color_change = [this, c](Node*, glm::vec3 rgb) { + c->m_color = glm::vec4(rgb, 1.f); + if (on_color_change) + on_color_change(this, rgb); + }; } diff --git a/src/node_panel_quick.h b/src/node_panel_quick.h index 70f773e..f558f1d 100644 --- a/src/node_panel_quick.h +++ b/src/node_panel_quick.h @@ -7,18 +7,24 @@ class NodePanelQuick : public NodeBorder { public: + std::function on_color_change; + std::function on_flow_change; + std::function on_size_change; + using this_class = NodePanelQuick; using parent = NodeBorder; - NodeButtonCustom* m_slider_size; - NodeButtonCustom* m_slider_flow; + NodeSliderV* m_slider_size; + NodeSliderV* m_slider_flow; NodeButtonCustom* m_button_color1; NodeButtonCustom* m_button_color2; NodeButtonCustom* m_button_color3; + NodeButtonCustom* m_button_color_current; std::shared_ptr m_picker; virtual Node* clone_instantiate() const override; virtual void clone_finalize(Node* dest) const override; virtual void init() override; private: void init_controls(); + void handle_button_color_click(Node* target); }; diff --git a/src/node_panel_stroke.cpp b/src/node_panel_stroke.cpp index a6c7986..ceefacd 100644 --- a/src/node_panel_stroke.cpp +++ b/src/node_panel_stroke.cpp @@ -218,6 +218,18 @@ void NodePanelStroke::update_controls() m_pattern_thumb->set_image(b->m_pattern_thumb_path); } +void NodePanelStroke::set_flow(float value, bool normalized, bool propagate) +{ + float v = normalized ? value : m_curves[m_tip_flow].to_slider(value); + m_tip_flow->set_value(v, propagate); +} + +void NodePanelStroke::set_size(float value, bool normalized, bool propagate) +{ + float v = normalized ? value : m_curves[m_tip_size].to_value(value); + m_tip_size->set_value(v, propagate); +} + void NodePanelStroke::init_fold(const std::string& name) { if (auto b = find(("button-unfold-" + name).c_str())) { @@ -316,6 +328,8 @@ void NodePanelStroke::init_controls() m_dual_brush_thumb->set_image(b->m_dual_thumb_path); m_pattern_thumb->set_image(b->m_pattern_thumb_path); update_controls(); + if (on_stroke_change) + on_stroke_change(this); }; }; diff --git a/src/node_panel_stroke.h b/src/node_panel_stroke.h index b67aa15..8f180b2 100644 --- a/src/node_panel_stroke.h +++ b/src/node_panel_stroke.h @@ -107,6 +107,9 @@ public: bool import_abr(const std::string& path); void init_controls(); void update_controls(); + + void set_flow(float value, bool normalized, bool propagate); + void set_size(float value, bool normalized, bool propagate); void init_fold(const std::string& name); void init_slider(NodeSliderH*& slider, const char* id, float Brush::* prop); diff --git a/src/node_slider.cpp b/src/node_slider.cpp index d98b880..71b1ae7 100644 --- a/src/node_slider.cpp +++ b/src/node_slider.cpp @@ -39,11 +39,14 @@ void NodeSliderH::draw() m_plane.draw_fill(); } -void NodeSliderH::set_value(float value) +void NodeSliderH::set_value(float value, bool propagate) { + // don't accept external values while user interaction + if (dragging) + return; m_value = glm::vec2(value) * m_mask; - //if (on_value_changed) - // on_value_changed(this, glm::length(m_value)); + if (propagate && on_value_changed) + on_value_changed(this, glm::length(m_value)); } float NodeSliderH::get_value() diff --git a/src/node_slider.h b/src/node_slider.h index 28a8665..9baa8e9 100644 --- a/src/node_slider.h +++ b/src/node_slider.h @@ -14,7 +14,7 @@ public: virtual void clone_copy(Node* dest) const override; virtual void init() override; virtual void draw() override; - void set_value(float value); + void set_value(float value, bool propagate = false); float get_value(); virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override; virtual kEventResult handle_event(Event* e) override;