diff --git a/data/layout.xml b/data/layout.xml
index 2f24734..3bcb434 100644
--- a/data/layout.xml
+++ b/data/layout.xml
@@ -35,15 +35,14 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -54,6 +53,17 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -69,9 +79,6 @@
-
-
-
@@ -1116,7 +1123,7 @@ Here's a list of what's available in this release.
-
+
diff --git a/data/ui/check-layer-visibility.png b/data/ui/check-layer-visibility.png
new file mode 100644
index 0000000..7328d2c
Binary files /dev/null and b/data/ui/check-layer-visibility.png differ
diff --git a/data/ui/check-lock-transparency.png b/data/ui/check-lock-transparency.png
new file mode 100644
index 0000000..2267b43
Binary files /dev/null and b/data/ui/check-lock-transparency.png differ
diff --git a/data/ui/check-test.png b/data/ui/check-test.png
new file mode 100644
index 0000000..d0a8463
Binary files /dev/null and b/data/ui/check-test.png differ
diff --git a/extra/ui/checkbox-icons.psd b/extra/ui/checkbox-icons.psd
new file mode 100644
index 0000000..e593023
Binary files /dev/null and b/extra/ui/checkbox-icons.psd differ
diff --git a/src/app.cpp b/src/app.cpp
index a344355..0b3da56 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -44,10 +44,7 @@ void App::open_document(std::string path)
async_start();
title_update();
for (auto& i : canvas->m_canvas->m_order)
- {
- auto* l = layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
- l->m_opacity->m_value.x = canvas->m_canvas->m_layers[i].m_opacity;
- }
+ layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str());
async_end();
}
else
diff --git a/src/app_layout.cpp b/src/app_layout.cpp
index b2cbd9d..d72f080 100644
--- a/src/app_layout.cpp
+++ b/src/app_layout.cpp
@@ -88,6 +88,26 @@ void App::init_toolbar_main()
}
}
+template std::shared_ptr find_or_create_panel(NodeScroll* panels)
+{
+ std::shared_ptr ret;
+ auto node_find = std::find_if(panels->m_children.begin(), panels->m_children.end(),
+ [](const std::shared_ptr&p) { return (bool)std::dynamic_pointer_cast(p); });
+ if (node_find != panels->m_children.end())
+ {
+ ret = std::static_pointer_cast(*node_find);
+ }
+ else
+ {
+ ret = std::make_shared();
+ ret->m_manager = panels->m_manager;
+ ret->init();
+ ret->create();
+ ret->loaded();
+ }
+ return ret;
+}
+
void App::init_sidebar()
{
sidebar = layout[main_id]->find("sidebar");
@@ -99,50 +119,12 @@ void App::init_sidebar()
//color = layout[main_id]->find("panel-color");
//stroke = layout[main_id]->find("panel-stroke");
- brushes = std::make_shared();
- brushes->m_manager = &layout;
- brushes->init();
- brushes->create();
- brushes->loaded();
-
- layers = std::make_shared();
- layers->m_manager = &layout;
- layers->init();
- layers->create();
- layers->loaded();
-
- color = std::make_shared();
- color->m_manager = &layout;
- color->init();
- color->create();
- color->loaded();
-
- stroke = std::make_shared();
- stroke->m_manager = &layout;
- stroke->init();
- stroke->create();
- stroke->loaded();
-
- auto grid_find = std::find_if(panels->m_children.begin(), panels->m_children.end(),
- [](const std::shared_ptr&p) { return (bool)std::dynamic_pointer_cast(p); });
- if (grid_find != panels->m_children.end())
- {
- grid = std::static_pointer_cast(*grid_find);
- }
- else
- {
- grid = std::make_shared();
- grid->m_manager = &layout;
- grid->init();
- grid->create();
- grid->loaded();
- }
-
- presets = std::make_shared();
- presets->m_manager = &layout;
- presets->init();
- presets->create();
- presets->loaded();
+ brushes = find_or_create_panel(panels);
+ layers = find_or_create_panel(panels);
+ color = find_or_create_panel(panels);
+ stroke = find_or_create_panel(panels);
+ grid = find_or_create_panel(panels);
+ presets = find_or_create_panel(panels);
// if (canvas)
// {
@@ -175,6 +157,8 @@ void App::init_sidebar()
layers->on_layer_add = [this](Node*) {
canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str());
+ canvas->m_canvas->m_unsaved = true;
+ title_update();
};
layers->on_layer_change = [this](Node*, int old_idx, int new_idx) {
@@ -183,18 +167,38 @@ void App::init_sidebar()
layers->on_layer_order = [this](Node*, int old_idx, int new_idx) {
canvas->m_canvas->layer_order(old_idx, new_idx);
+ canvas->m_canvas->m_unsaved = true;
+ title_update();
};
layers->on_layer_delete = [this](Node*, int idx) {
canvas->m_canvas->layer_remove(idx);
+ canvas->m_canvas->m_unsaved = true;
+ title_update();
};
layers->on_layer_opacity_changed = [this](Node*, int idx, float value) {
canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_opacity = value;
+ canvas->m_canvas->m_unsaved = true;
+ title_update();
};
layers->on_layer_visibility_changed = [this](Node*, int idx, bool visible) {
- canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_alpha_locked = visible;
+ canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_visible = visible;
+ canvas->m_canvas->m_unsaved = true;
+ title_update();
+ };
+
+ layers->on_layer_alpha_lock_changed = [this](Node*, int idx, bool locked) {
+ canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_alpha_locked = locked;
+ canvas->m_canvas->m_unsaved = true;
+ title_update();
+ };
+
+ layers->on_layer_blend_mode_changed = [this](Node*, int idx, int mode) {
+ canvas->m_canvas->m_layers[canvas->m_canvas->m_order[idx]].m_blend_mode = mode;
+ canvas->m_canvas->m_unsaved = true;
+ title_update();
};
layers->on_layer_highlight_changed = [this](Node*, int idx, bool highlight) {
diff --git a/src/app_shaders.cpp b/src/app_shaders.cpp
index 400431b..a602480 100644
--- a/src/app_shaders.cpp
+++ b/src/app_shaders.cpp
@@ -77,17 +77,32 @@ void App::initShaders()
SHADER_VERSION
"uniform sampler2D tex;\n"
"uniform sampler2D tex_stroke;\n"
+ "uniform sampler2D tex_mask;\n"
"uniform mediump float alpha;\n"
+ "uniform mediump float stroke_alpha;\n"
"uniform mediump vec2 resolution;\n"
"uniform bool fragUV2;\n"
+ "uniform bool mask;\n"
"in mediump vec2 uv;\n"
"out mediump vec4 frag;\n"
+ "mediump vec4 blur(sampler2D t, mediump vec2 uv){\n"
+ " mediump vec4 sum = texture(t, uv);\n"
+ " sum += textureOffset(t, uv, ivec2(-1, -1));\n"
+ " sum += textureOffset(t, uv, ivec2(-1, 0));\n"
+ " sum += textureOffset(t, uv, ivec2(-1, 1));\n"
+ " sum += textureOffset(t, uv, ivec2( 0, -1));\n"
+ " sum += textureOffset(t, uv, ivec2( 0, 1));\n"
+ " sum += textureOffset(t, uv, ivec2( 1, -1));\n"
+ " sum += textureOffset(t, uv, ivec2( 1, 0));\n"
+ " sum += textureOffset(t, uv, ivec2( 1, 1));\n"
+ " return sum / vec4(9.0);\n"
+ "}\n"
"void main(){\n"
" mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n"
" mediump vec4 base = texture(tex, uv2);\n"
" mediump vec4 stroke = texture(tex_stroke, uv);\n"
- " mediump float a = base.a - (stroke.a * alpha);\n"
- " frag = vec4(base.rgb, clamp(a, 0.0, 1.0));\n"
+ " stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n"
+ " frag = vec4(base.rgb, clamp((base.a - stroke.a) * alpha, 0.0, 1.0));\n"
"}\n";
// TEXTURE COMP DRAW
static const char* shader_comp_draw_f =
@@ -97,6 +112,7 @@ void App::initShaders()
"uniform sampler2D tex_mask;\n"
"uniform sampler2D tex_stencil;\n"
"uniform mediump float alpha;\n"
+ "uniform mediump float stroke_alpha;\n"
"uniform mediump int blend_mode;\n"
"uniform mediump vec2 resolution;\n"
"uniform bool lock;\n"
@@ -141,13 +157,12 @@ void App::initShaders()
" mediump vec2 uv2 = fragUV2 ? (gl_FragCoord.st / resolution) : uv;\n"
" mediump vec4 base = texture(tex, uv2);\n"
" mediump vec4 stroke = texture(tex_stroke, uv);\n"
- " stroke.a = mask ? stroke.a * alpha * blur(tex_mask, uv2).r : stroke.a * alpha;\n"
-
- " if (!lock && base.a == 0.0) { frag = stroke; return; }\n"
+ " stroke.a = mask ? stroke.a * stroke_alpha * blur(tex_mask, uv2).r : stroke.a * stroke_alpha;\n"
+ " if (!lock && base.a == 0.0) { frag = stroke * vec4(1.0, 1.0, 1.0, alpha); return; }\n"
" mediump float contribution = (1.0 - base.a) * stroke.a;\n"
" mediump float alpha_tot = base.a + contribution;"
" mediump vec3 rgb = blend(base, stroke, alpha_tot, blend_mode);\n"
- " frag = vec4(rgb, (lock ? base.a : alpha_tot));\n"
+ " frag = vec4(rgb, (lock ? base.a : alpha_tot) * alpha);\n"
"}\n";
// TEXTURE ATLAS
diff --git a/src/app_vr.cpp b/src/app_vr.cpp
index c4a7330..e7fde59 100644
--- a/src/app_vr.cpp
+++ b/src/app_vr.cpp
@@ -46,7 +46,7 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
auto layer_index = canvas->m_canvas->m_order[i];
for (int plane_index = 0; plane_index < 6; plane_index++)
{
- if (canvas->m_canvas->m_layers[layer_index].m_opacity == .0f)
+ if (!canvas->m_canvas->m_layers[layer_index].m_visible || canvas->m_canvas->m_layers[layer_index].m_opacity == .0f)
continue;
int z = (int)(canvas->m_canvas->m_order.size() - i);
@@ -62,10 +62,11 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
ShaderManager::use(kShader::CompErase);
ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
- //ShaderManager::u_int(kShaderUniform::TexMask, 2);
- ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_int(kShaderUniform::TexMask, 2);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index].m_opacity);
//ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
- //ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
+ ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active);
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
glActiveTexture(GL_TEXTURE0);
canvas->m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
@@ -90,7 +91,8 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
ShaderManager::u_int(kShaderUniform::TexMask, 2);
ShaderManager::u_vec2(kShaderUniform::Resolution, canvas->m_canvas->m_size);
//ShaderManager::u_int(kShaderUniform::TexStencil, 3);
- ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, canvas->m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::Alpha, canvas->m_canvas->m_layers[layer_index].m_opacity);
ShaderManager::u_int(kShaderUniform::Lock, canvas->m_canvas->m_layers[layer_index].m_alpha_locked);
ShaderManager::u_int(kShaderUniform::Mask, canvas->m_canvas->m_smask_active);
ShaderManager::u_int(kShaderUniform::BlendMode, canvas->m_canvas->m_current_stroke->m_brush.m_blend_mode);
diff --git a/src/canvas.cpp b/src/canvas.cpp
index 097f7cf..5c819bd 100644
--- a/src/canvas.cpp
+++ b/src/canvas.cpp
@@ -91,6 +91,8 @@ void Canvas::pick_update(int plane)
m_sampler.bind(0);
for (auto layer_index : m_order)
{
+ if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f)
+ continue;
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity);
m_layers[layer_index].m_rtt[i].bindTexture();
m_plane.draw_fill();
@@ -242,7 +244,7 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
auto layer_index = m_current_layer_idx;
for (int plane_index = 0; plane_index < 6; plane_index++)
{
- if (m_layers[layer_index].m_opacity == .0f)
+ if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == .0f)
continue;
glm::mat4 proj = glm::perspective(glm::radians(m_cam_fov), (float)m_mixer.getWidth() / m_mixer.getHeight(), 0.1f, 1000.f);
@@ -293,7 +295,8 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
ShaderManager::u_int(kShaderUniform::TexMask, 2);
//ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
//ShaderManager::u_int(kShaderUniform::TexStencil, 3);
- ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_int(kShaderUniform::Lock, m_layers[layer_index].m_alpha_locked);
ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
@@ -804,9 +807,11 @@ void Canvas::stroke_commit()
ShaderManager::use(kShader::CompErase);
ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
- //ShaderManager::u_int(kShaderUniform::TexMask, 2);
+ ShaderManager::u_int(kShaderUniform::TexMask, 2);
+ ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
- ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_mat4(kShaderUniform::MVP, glm::ortho(-.5f, .5f, -.5f, .5f, -1.f, 1.f));
glActiveTexture(GL_TEXTURE0);
@@ -831,7 +836,8 @@ void Canvas::stroke_commit()
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ShaderManager::u_int(kShaderUniform::TexMask, 2);
//ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
- ShaderManager::u_float(kShaderUniform::Alpha, m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::Alpha, 1);
ShaderManager::u_int(kShaderUniform::Mask, m_smask_active);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
ShaderManager::u_int(kShaderUniform::BlendMode, m_current_stroke->m_brush.m_blend_mode);
@@ -1009,6 +1015,7 @@ void Canvas::layer_merge(int source_idx, int dest_idx) // m_layer index
ShaderManager::u_int(kShaderUniform::TexStroke, 1); // source
//ShaderManager::u_vec2(kShaderUniform::Resolution, m_size);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1);
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[source_idx].m_opacity);
ShaderManager::u_int(kShaderUniform::Lock, false);
ShaderManager::u_int(kShaderUniform::BlendMode, 0); // TODO: defaulted to normal, change to layer blend mode when implemented
@@ -1284,6 +1291,8 @@ void Canvas::export_equirectangular_thread(std::string file_path)
m_sampler_mask.bind(0);
for (auto layer_index : m_order)
{
+ if (!m_layers[layer_index].m_visible || m_layers[layer_index].m_opacity == 0.f)
+ continue;
ShaderManager::u_float(kShaderUniform::Alpha, m_layers[layer_index].m_opacity);
m_layers[layer_index].m_rtt[i].bindTexture();
m_plane.draw_fill();
diff --git a/src/canvas.h b/src/canvas.h
index 42034c3..e6aa04e 100644
--- a/src/canvas.h
+++ b/src/canvas.h
@@ -20,6 +20,7 @@ public:
bool m_alpha_locked = false;
float m_opacity = 1.f;
bool m_hightlight = false;
+ bool m_blend_mode = 0;
std::string m_name;
int w = 0;
int h = 0;
diff --git a/src/canvas_modes.cpp b/src/canvas_modes.cpp
index 0df2fc1..7afc7d6 100644
--- a/src/canvas_modes.cpp
+++ b/src/canvas_modes.cpp
@@ -1112,6 +1112,7 @@ void CanvasModeTransform::leave()
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
ShaderManager::u_int(kShaderUniform::TexMask, 2);
ShaderManager::u_float(kShaderUniform::Alpha, 1);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, 1);
ShaderManager::u_int(kShaderUniform::Lock, false);
ShaderManager::u_int(kShaderUniform::Mask, false);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, true);
diff --git a/src/node_canvas.cpp b/src/node_canvas.cpp
index 878585a..2351f3b 100644
--- a/src/node_canvas.cpp
+++ b/src/node_canvas.cpp
@@ -137,7 +137,7 @@ void NodeCanvas::draw()
auto layer_index = m_canvas->m_order[i];
for (int plane_index = 0; plane_index < 6; plane_index++)
{
- if (m_canvas->m_layers[layer_index].m_opacity == .0f)
+ if (!m_canvas->m_layers[layer_index].m_visible || m_canvas->m_layers[layer_index].m_opacity == .0f)
continue;
int z = (int)(m_canvas->m_order.size() - i);
@@ -153,11 +153,12 @@ void NodeCanvas::draw()
ShaderManager::use(kShader::CompErase);
ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_int(kShaderUniform::TexStroke, 1);
- //ShaderManager::u_int(kShaderUniform::TexMask, 2);
- ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_int(kShaderUniform::TexMask, 2);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
//ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
- //ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
+ ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
ShaderManager::u_mat4(kShaderUniform::MVP, plane_mvp_z);
glActiveTexture(GL_TEXTURE0);
m_canvas->m_layers[layer_index].m_rtt[plane_index].bindTexture();
@@ -182,7 +183,8 @@ void NodeCanvas::draw()
ShaderManager::u_int(kShaderUniform::TexMask, 2);
//ShaderManager::u_vec2(kShaderUniform::Resolution, zw(m_canvas->m_box) / zoom);
//ShaderManager::u_int(kShaderUniform::TexStencil, 3);
- ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::StrokeAlpha, m_canvas->m_current_stroke->m_brush.m_tip_opacity);
+ ShaderManager::u_float(kShaderUniform::Alpha, m_canvas->m_layers[layer_index].m_opacity);
ShaderManager::u_int(kShaderUniform::Lock, m_canvas->m_layers[layer_index].m_alpha_locked);
ShaderManager::u_int(kShaderUniform::Mask, m_canvas->m_smask_active);
ShaderManager::u_int(kShaderUniform::UseFragCoordUV2, false);
diff --git a/src/node_checkbox.cpp b/src/node_checkbox.cpp
index b549c50..4e89700 100644
--- a/src/node_checkbox.cpp
+++ b/src/node_checkbox.cpp
@@ -1,6 +1,7 @@
#include "pch.h"
#include "log.h"
#include "node_checkbox.h"
+#include "texture.h"
Node* NodeCheckBox::clone_instantiate() const
{
@@ -13,7 +14,9 @@ void NodeCheckBox::clone_children(Node* dest) const
NodeCheckBox* n = static_cast(dest);
n->m_outer = (NodeBorder*)n->m_children[0].get();
n->m_inner = (NodeBorder*)n->m_outer->m_children[0].get();
+ n->m_icon = n->m_inner->m_children.empty() ? nullptr : (NodeImage*)n->m_inner->m_children[0].get();
n->m_mouse_ignore = false;
+ n->m_icon_path = m_icon_path;
}
void NodeCheckBox::init()
@@ -43,6 +46,8 @@ void NodeCheckBox::create()
{
m_outer->create();
m_inner->create();
+ if (!m_icon_path.empty())
+ set_icon(m_icon_path);
}
kEventResult NodeCheckBox::handle_event(Event* e)
@@ -58,6 +63,7 @@ kEventResult NodeCheckBox::handle_event(Event* e)
break;
case kEventType::MouseUpL:
checked = !checked;
+ update_icon();
if (on_value_changed)
on_value_changed(this, checked);
break;
@@ -73,3 +79,42 @@ void NodeCheckBox::draw()
m_inner->m_color = checked ? glm::vec4(.4, .4, .4, 1) : glm::vec4(.8, .8, .8, 1);
Node::draw();
}
+
+void NodeCheckBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
+{
+ switch (ka)
+ {
+ case kAttribute::Icon:
+ m_icon_path = attr->Value();
+ break;
+ default:
+ Node::parse_attributes(ka, attr);
+ break;
+ }
+}
+
+void NodeCheckBox::set_icon(const std::string& icon_path)
+{
+ if (icon_path.empty() || !TextureManager::load(icon_path.c_str()))
+ {
+ if (m_icon)
+ m_icon->destroy();
+ m_icon = nullptr;
+ return;
+ }
+ m_icon_path = icon_path;
+ update_icon();
+}
+
+void NodeCheckBox::update_icon()
+{
+ auto& t = TextureManager::get(const_hash(m_icon_path.c_str()));
+ if (!m_icon)
+ m_icon = m_inner->add_child();
+ auto region = checked ? glm::vec4(.5f, 0, 1, 1) : glm::vec4(0, 0, .5f, 1);
+ m_icon->m_region = region * glm::vec4(t.size(), t.size());
+ m_icon->m_use_atlas = true;
+ m_icon->set_image(m_icon_path);
+ m_icon->SetWidthP(100);
+ m_icon->SetHeightP(100);
+}
diff --git a/src/node_checkbox.h b/src/node_checkbox.h
index c7e5fd1..9b45b88 100644
--- a/src/node_checkbox.h
+++ b/src/node_checkbox.h
@@ -1,6 +1,7 @@
#pragma once
#include "node.h"
#include "node_border.h"
+#include "node_image.h"
class NodeCheckBox : public Node
{
@@ -8,6 +9,8 @@ public:
std::function on_value_changed;
NodeBorder* m_outer;
NodeBorder* m_inner;
+ NodeImage* m_icon;
+ std::string m_icon_path;
bool checked = false;
virtual Node* clone_instantiate() const override;
virtual void clone_children(Node* dest) const override;
@@ -15,4 +18,8 @@ public:
virtual void create() override;
virtual kEventResult handle_event(Event* e) override;
virtual void draw() override;
+ virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
+ void set_icon(const std::string& icon_path);
+ void set_value(bool checked) { this->checked = checked; update_icon(); }
+ void update_icon();
};
diff --git a/src/node_combobox.cpp b/src/node_combobox.cpp
index 1995a1b..fefa424 100644
--- a/src/node_combobox.cpp
+++ b/src/node_combobox.cpp
@@ -13,7 +13,9 @@ void NodeComboBox::clone_copy(Node* dest) const
NodeButton::clone_copy(dest);
NodeComboBox* n = static_cast(dest);
n->m_data = m_data;
+ n->m_items = m_items;
n->m_current_index = m_current_index;
+ n->m_selected_child_index = m_selected_child_index;
}
void NodeComboBox::loaded()
@@ -85,6 +87,9 @@ void NodeComboBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute*
case kAttribute::ComboList:
{
m_data = split(attr->Value(), ',');
+ m_items.clear();
+ for (auto& i : m_data)
+ if (i != "-") m_items.push_back(i);
break;
}
case kAttribute::Default:
@@ -94,3 +99,12 @@ void NodeComboBox::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute*
break;
}
}
+
+void NodeComboBox::set_index(int index)
+{
+ m_current_index = index;
+ m_selected_child_index = index;
+ m_text->set_text(m_items[index].c_str());
+ //if (on_select)
+ // on_select(this, index);
+}
diff --git a/src/node_combobox.h b/src/node_combobox.h
index a505a90..72230b4 100644
--- a/src/node_combobox.h
+++ b/src/node_combobox.h
@@ -13,4 +13,5 @@ public:
virtual void clone_copy(Node* dest) const override;
virtual void loaded() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
+ void set_index(int index);
};
diff --git a/src/node_image.cpp b/src/node_image.cpp
index 18e803f..1f68214 100644
--- a/src/node_image.cpp
+++ b/src/node_image.cpp
@@ -105,3 +105,19 @@ void NodeImage::draw()
TextureManager::get(m_tex_id).unbind();
glDisable(GL_BLEND);
}
+
+bool NodeImage::set_image(const std::string& path)
+{
+ m_path = path;
+ m_tex_id = const_hash(path.c_str());
+ if (!m_path.empty() && TextureManager::load(m_path.c_str(), m_use_mipmaps))
+ {
+ auto tex_sz = TextureManager::get(m_tex_id).size();
+ m_off = xy(m_region) / tex_sz;
+ m_sz = (zw(m_region) - xy(m_region)) / tex_sz;
+ if (m_autosize)
+ SetAspectRatio(tex_sz.x / tex_sz.y);
+ return true;
+ }
+ return false;
+}
diff --git a/src/node_image.h b/src/node_image.h
index 1280607..e4bdeaa 100644
--- a/src/node_image.h
+++ b/src/node_image.h
@@ -24,4 +24,5 @@ public:
virtual void restore_context() override;
virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override;
virtual void draw() override;
+ bool set_image(const std::string& path);
};
diff --git a/src/node_panel_layer.cpp b/src/node_panel_layer.cpp
index 0c9532f..f58d40c 100644
--- a/src/node_panel_layer.cpp
+++ b/src/node_panel_layer.cpp
@@ -1,6 +1,8 @@
#include "pch.h"
#include "log.h"
#include "node_panel_layer.h"
+#include "canvas.h"
+#include "node_combobox.h"
Node* NodeLayer::clone_instantiate() const
{
@@ -31,7 +33,6 @@ void NodeLayer::init()
m_thinkness = m_template->m_thinkness;
m_label = find("label");
m_visibility = find("cb");
- m_opacity = find("sl-opacity");
}
void NodeLayer::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
@@ -54,10 +55,6 @@ void NodeLayer::loaded()
NodeBorder::loaded();
if (!m_label_text.empty())
m_label->set_text(m_label_text.c_str());
- m_opacity->on_value_changed = [this](Node*, float value) {
- if (on_opacity_changed)
- on_opacity_changed(this, value);
- };
m_visibility->on_value_changed = [this](Node*, bool checked) {
if (on_visibility_changed)
on_visibility_changed(this, checked);
@@ -159,6 +156,18 @@ void NodePanelLayer::init()
on_layer_order(this, old_idx, new_idx);
}
};
+ m_opacity = find("opacity");
+ m_opacity->on_value_changed = [this](Node*, float value) {
+ handle_layer_opacity(m_current_layer, value);
+ };
+ m_alpha_lock = find("alpha-lock");
+ m_alpha_lock->on_value_changed = [this](Node*, bool locked) {
+ handle_layer_alpha_lock(m_current_layer, locked);
+ };
+ m_blend_mode = find("blend-mode");
+ m_blend_mode->on_select = [this](Node*, int index) {
+ handle_layer_blend_mode(m_current_layer, index);
+ };
LOG("done init");
}
@@ -170,8 +179,8 @@ NodeLayer* NodePanelLayer::add_layer(const char* name)
l->create();
l->loaded();
l->set_name(name);
+ l->m_visibility->set_value(true);
l->on_selected = std::bind(&NodePanelLayer::handle_layer_selected, this, std::placeholders::_1);
- l->on_opacity_changed = std::bind(&NodePanelLayer::handle_layer_opacity, this, std::placeholders::_1, std::placeholders::_2);
l->on_visibility_changed = std::bind(&NodePanelLayer::handle_layer_visibility, this, std::placeholders::_1, std::placeholders::_2);
l->on_highlight = std::bind(&NodePanelLayer::handle_layer_highlight, this, std::placeholders::_1, std::placeholders::_2);
if (m_current_layer)
@@ -179,6 +188,7 @@ NodeLayer* NodePanelLayer::add_layer(const char* name)
m_current_layer = l;
m_current_layer->m_selected = true;
m_layers.push_back(l);
+ update_attributes();
return l;
}
@@ -208,6 +218,7 @@ void NodePanelLayer::remove_layer(NodeLayer* layer)
on_layer_delete(this, old_idx);
if (on_layer_change)
on_layer_change(this, -1, i);
+ update_attributes();
}
void NodePanelLayer::handle_layer_opacity(NodeLayer* target, float value)
@@ -228,6 +239,18 @@ void NodePanelLayer::handle_layer_visibility(NodeLayer* target, bool visible)
on_layer_visibility_changed(this, m_layers_container->get_child_index(target), visible);
}
+void NodePanelLayer::handle_layer_alpha_lock(NodeLayer* target, bool locked)
+{
+ if (on_layer_alpha_lock_changed)
+ on_layer_alpha_lock_changed(this, m_layers_container->get_child_index(target), locked);
+}
+
+void NodePanelLayer::handle_layer_blend_mode(NodeLayer* target, int mode)
+{
+ if (on_layer_blend_mode_changed)
+ on_layer_blend_mode_changed(this, m_layers_container->get_child_index(target), mode);
+}
+
void NodePanelLayer::handle_layer_selected(NodeLayer* target)
{
if (m_current_layer)
@@ -236,6 +259,7 @@ void NodePanelLayer::handle_layer_selected(NodeLayer* target)
m_current_layer->m_selected = true;
if (on_layer_change)
on_layer_change(this, -1, m_layers_container->get_child_index(m_current_layer));
+ update_attributes();
}
void NodePanelLayer::clear()
@@ -244,3 +268,11 @@ void NodePanelLayer::clear()
m_layers.clear();
m_current_layer = nullptr;
}
+
+void NodePanelLayer::update_attributes()
+{
+ auto& l = Canvas::I->m_layers[Canvas::I->m_current_layer_idx];
+ m_opacity->set_value(l.m_opacity);
+ m_alpha_lock->set_value(l.m_alpha_locked);
+ m_blend_mode->set_index(l.m_blend_mode);
+}
diff --git a/src/node_panel_layer.h b/src/node_panel_layer.h
index 93330f6..f069cf2 100644
--- a/src/node_panel_layer.h
+++ b/src/node_panel_layer.h
@@ -4,12 +4,12 @@
#include "node_checkbox.h"
#include "node_slider.h"
#include "node_button_custom.h"
+#include "node_combobox.h"
class NodeLayer : public NodeBorder
{
public:
std::function on_selected;
- std::function on_opacity_changed;
std::function on_visibility_changed;
std::function on_highlight;
bool m_selected = false;
@@ -19,7 +19,6 @@ public:
std::string m_label_text;
NodeText* m_label;
NodeCheckBox* m_visibility;
- NodeSliderH* m_opacity;
virtual Node* clone_instantiate() const override;
virtual void clone_children(Node* dest) const override;
virtual void clone_copy(Node* dest) const override;
@@ -42,13 +41,18 @@ public:
std::function on_layer_change;
std::function on_layer_opacity_changed;
std::function on_layer_visibility_changed;
+ std::function on_layer_alpha_lock_changed;
std::function on_layer_highlight_changed;
+ std::function on_layer_blend_mode_changed;
std::function on_layer_delete;
std::function on_layer_add;
std::function on_layer_order;
NodeLayer* m_current_layer = nullptr;
std::vector m_layers;
NodeBorder* m_layers_container;
+ NodeSliderH* m_opacity;
+ NodeCheckBox* m_alpha_lock;
+ NodeComboBox* m_blend_mode;
virtual Node* clone_instantiate() const override;
virtual void init() override;
void add_layer();
@@ -57,7 +61,10 @@ public:
void remove_layer(NodeLayer* layer);
void handle_layer_opacity(NodeLayer* target, float value);
void handle_layer_visibility(NodeLayer* target, bool visible);
+ void handle_layer_alpha_lock(NodeLayer* target, bool locked);
void handle_layer_highlight(NodeLayer* target, bool highlight);
+ void handle_layer_blend_mode(NodeLayer* target, int mode);
void handle_layer_selected(NodeLayer* target);
void clear();
+ void update_attributes();
};
diff --git a/src/node_slider.cpp b/src/node_slider.cpp
index 16aad8e..b5ace62 100644
--- a/src/node_slider.cpp
+++ b/src/node_slider.cpp
@@ -42,8 +42,8 @@ void NodeSliderH::draw()
void NodeSliderH::set_value(float value)
{
m_value = glm::vec2(value) * m_mask;
- if (on_value_changed)
- on_value_changed(this, glm::length(m_value));
+ //if (on_value_changed)
+ // on_value_changed(this, glm::length(m_value));
}
float NodeSliderH::get_value()
diff --git a/src/shader.h b/src/shader.h
index 2ca307b..d103acd 100644
--- a/src/shader.h
+++ b/src/shader.h
@@ -16,6 +16,7 @@ enum class kShaderUniform : uint16_t
StencilOffset = const_hash("stencil_offset"),
StencilAlpha = const_hash("stencil_alpha"),
MixAlpha = const_hash("mix_alpha"),
+ StrokeAlpha = const_hash("stroke_alpha"),
Wet = const_hash("wet"),
Lock = const_hash("lock"),
Col = const_hash("col"),