From 577a4e4db7cbcc2d3d5609af46cce2a6b490b7d3 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Sun, 14 May 2017 21:48:25 +0100 Subject: [PATCH] split app.cpp into multiple files, add NodeScroll and use it to scroll the side panels, some fixes to the events system --- android/CMakeLists.txt | 4 + data/layout.xml | 4 +- engine.vcxproj | 5 + engine.vcxproj.filters | 15 + engine/app.cpp | 816 +--------------------------------- engine/app_events.cpp | 121 +++++ engine/app_layout.cpp | 385 ++++++++++++++++ engine/app_shaders.cpp | 334 ++++++++++++++ engine/main.cpp | 12 +- engine/node.cpp | 88 +++- engine/node.h | 10 +- engine/node_button_custom.cpp | 5 + engine/node_canvas.cpp | 2 +- engine/node_popup_menu.cpp | 1 + engine/node_scroll.cpp | 50 +++ engine/node_scroll.h | 14 + 16 files changed, 1028 insertions(+), 838 deletions(-) create mode 100644 engine/app_events.cpp create mode 100644 engine/app_layout.cpp create mode 100644 engine/app_shaders.cpp create mode 100644 engine/node_scroll.cpp create mode 100644 engine/node_scroll.h diff --git a/android/CMakeLists.txt b/android/CMakeLists.txt index 509d2a0..fc25afe 100644 --- a/android/CMakeLists.txt +++ b/android/CMakeLists.txt @@ -36,6 +36,9 @@ add_library( ../engine/shader.cpp ../engine/shape.cpp ../engine/app.cpp + ../engine/app_events.cpp + ../engine/app_layout.cpp + ../engine/app_shaders.cpp ../engine/brush.cpp ../engine/canvas.cpp ../engine/canvas_modes.cpp @@ -65,6 +68,7 @@ add_library( ../engine/node_text.cpp ../engine/node_text_input.cpp ../engine/node_viewport.cpp + ../engine/node_scroll.cpp ) target_include_directories(native-lib PRIVATE diff --git a/data/layout.xml b/data/layout.xml index 0649ddd..89ae41a 100644 --- a/data/layout.xml +++ b/data/layout.xml @@ -382,7 +382,7 @@ - + @@ -391,7 +391,7 @@ - + diff --git a/engine.vcxproj b/engine.vcxproj index 7c7b6fc..5832870 100644 --- a/engine.vcxproj +++ b/engine.vcxproj @@ -152,6 +152,9 @@ + + + @@ -180,6 +183,7 @@ + @@ -247,6 +251,7 @@ + diff --git a/engine.vcxproj.filters b/engine.vcxproj.filters index 2a31841..4cd7ca9 100644 --- a/engine.vcxproj.filters +++ b/engine.vcxproj.filters @@ -156,6 +156,18 @@ Source Files\ui + + Source Files\ui + + + Source Files + + + Source Files + + + Source Files + @@ -284,5 +296,8 @@ Header Files\ui + + Header Files + \ No newline at end of file diff --git a/engine/app.cpp b/engine/app.cpp index eba3f75..a14fe08 100644 --- a/engine/app.cpp +++ b/engine/app.cpp @@ -21,333 +21,6 @@ void App::clear() glClear(GL_COLOR_BUFFER_BIT); } -void App::initShaders() -{ - static const char* shader_v = - SHADER_VERSION - "uniform mat4 mvp;" - "in vec4 pos;" - "in vec2 uvs;" - "out vec3 uv;" - "void main(){" - " uv = vec3(uvs, pos.w);" - " gl_Position = mvp * vec4(pos.xyz, 1.0);" - "}"; - static const char* shader_f = - SHADER_VERSION - "uniform sampler2D tex;" - "in mediump vec3 uv;" - "out mediump vec4 frag;" - "void main(){" - //" frag = texture(tex, uv.xy/uv.z);" - " frag = texture(tex, uv.xy);" - "}"; - static const char* shader_uv_f = - SHADER_VERSION - "uniform sampler2D tex;" - "in mediump vec3 uv;" - "out mediump vec4 frag;" - "void main(){" - " frag = vec4(uv.xy, 0.0, 1.0);" - "}"; - // TEXTURE ALPHA - static const char* shader_alpha_f = - SHADER_VERSION - "uniform sampler2D tex;\n" - "uniform mediump float alpha;\n" - "in mediump vec3 uv;\n" - "out mediump vec4 frag;\n" - "void main(){\n" - " frag = texture(tex, uv.xy) * vec4(1,1,1,alpha);\n" - "}\n"; - - // TEXTURE ATLAS - static const char* shader_atlas_v = - SHADER_VERSION - "uniform mat4 mvp;" - "uniform vec2 tof;" - "uniform vec2 tsz;" - "in vec2 pos;" - "in vec2 uvs;" - "out vec2 uv;" - "void main(){" - " uv = tof + uvs * tsz;" - " gl_Position = mvp * vec4(pos, 0.0, 1.0);" - "}"; - static const char* shader_atlas_f = - SHADER_VERSION - "uniform sampler2D tex;" - "in mediump vec2 uv;" - "out mediump vec4 frag;" - "void main(){" - " frag = texture(tex, uv);" - "}"; - - // SOLID COLOR - static const char* shader_color_v = - SHADER_VERSION - "uniform mat4 mvp;" - "in vec4 pos;" - "void main(){" - " gl_Position = mvp * pos;" - " gl_PointSize = 15.0;" - "}"; - static const char* shader_color_f = - SHADER_VERSION - "uniform mediump vec4 col;" - "out mediump vec4 frag;" - "void main(){" - " frag = col;" - "}"; - - // COLOR QUAD - static const char* shader_color_quad_v = - SHADER_VERSION - "uniform mat4 mvp;" - "in vec4 pos;" - "in vec2 uvs;" - "out vec3 uv;" - "void main(){" - " gl_Position = mvp * pos;" - " uv = vec3(uvs, pos.w);" - "}"; - static const char* shader_color_quad_f = - SHADER_VERSION - "uniform mediump vec4 col;" - "in mediump vec3 uv;" - "out mediump vec4 frag;" - "void main(){" - " mediump vec4 gradient_x = mix(col, vec4(1.0, 1.0, 1.0, 1.0), uv.x);" - " frag = mix(gradient_x, vec4(0.0, 0.0, 0.0, 1.0), uv.y);" - "}"; - - // HUE - static const char* shader_color_hue_v = - SHADER_VERSION - "uniform mat4 mvp;" - "in vec4 pos;" - "in vec2 uvs;" - "out vec3 uv;" - "void main(){" - " gl_Position = mvp * pos;" - " uv = vec3(uvs, pos.w);" - "}"; - static const char* shader_color_hue_f = - SHADER_VERSION - "uniform mediump vec4 col;" - "in mediump vec3 uv;" - "out mediump vec4 frag;" - "mediump vec3 hsv2rgb(mediump vec3 c) {" - " mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" - " mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);" - " return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);" - "}" - "void main(){" - " frag = vec4(hsv2rgb(vec3(uv.y, 1.0, 1.0)), 1.0);" - "}"; - - // FONT - static const char* shader_font_v = - SHADER_VERSION - "uniform mat4 mvp;" - "in vec2 pos;" - "in vec2 uvs;" - "out vec2 uv;" - "void main(){" - " uv = uvs;" - " gl_Position = mvp * vec4(pos, 0.0, 1.0);" - "}"; - static const char* shader_font_f = - SHADER_VERSION - "uniform mediump sampler2D tex;" - "uniform mediump vec4 col;" - "in mediump vec2 uv;" - "out mediump vec4 frag;" - "void main(){" - " mediump float a = texture(tex, uv).r;" - " frag = vec4(col.rgb, a);" - "}"; - - // STROKE - static const char* shader_stroke_v = - SHADER_VERSION - "uniform mat4 mvp;\n" - "in vec4 pos;\n" - "in vec2 uvs;\n" - "out vec2 uv;\n" - "void main(){\n" - " uv = uvs;\n" - " gl_Position = mvp * vec4(pos.xyz, 1.0);\n" - "}\n"; - static const char* shader_stroke_f = - SHADER_VERSION - "uniform mediump sampler2D tex;\n" - "uniform mediump sampler2D tex_bg;\n" - "uniform mediump vec4 col;\n" - "uniform mediump vec2 resolution;\n" - "uniform mediump float alpha;\n" - "in mediump vec2 uv;\n" - "out mediump vec4 frag;\n" - "void main(){\n" - " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" - " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" - " mediump vec4 fg = vec4(col.rgb, brush_alpha);\n" - " mediump vec4 bg = texture(tex_bg, uv2);\n" - " if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" - " mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" - " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" - " frag = vec4(rgb, alpha_tot);\n" - "}\n"; - // ALPHA LOCK - static const char* shader_stroke_lock_f = - SHADER_VERSION - "uniform mediump sampler2D tex;\n" - "uniform mediump sampler2D tex_bg;\n" - "uniform mediump sampler2D tex_mask;\n" - "uniform mediump vec4 col;\n" - "uniform mediump vec2 resolution;\n" - "uniform mediump float alpha;\n" - "in mediump vec2 uv;\n" - "out mediump vec4 frag;\n" - "void main(){\n" - " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" - " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" - " mediump vec4 fg = vec4(col.rgb, brush_alpha);\n" - " mediump vec4 bg = texture(tex_bg, uv2);\n" - " mediump vec4 msk = texture(tex_mask, uv2);\n" - " if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" - " mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" - " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" - " frag = vec4(rgb, min(alpha_tot, msk.a));\n" - "}\n"; - // ERASER - static const char* shader_stroke_erase_f = - SHADER_VERSION - "uniform mediump sampler2D tex;\n" - "uniform mediump sampler2D tex_bg;\n" - "uniform mediump vec4 col;\n" - "uniform mediump vec2 resolution;\n" - "uniform mediump float alpha;\n" - "in mediump vec2 uv;\n" - "out mediump vec4 frag;\n" - "void main(){\n" - " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" - " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" - " mediump vec4 bg = texture(tex_bg, uv2);\n" - " frag = vec4(bg.rgb, bg.a - bg.a * brush_alpha);\n" - "}\n"; - - // STROKE LAYER BLEND - static const char* shader_stroke_layer_v = - SHADER_VERSION - "uniform mat4 mvp;" - "in vec4 pos;" - "in vec2 uvs;" - "out vec2 uv;" - "void main(){" - " uv = uvs;" - " gl_Position = mvp * vec4(pos.xyz, 1.0);" - "}"; - static const char* shader_stroke_layer_f = - SHADER_VERSION - "uniform mediump sampler2D tex;\n" - "uniform mediump sampler2D tex_bg;\n" - "uniform mediump vec2 resolution;\n" - "uniform mediump float alpha;\n" - "in mediump vec2 uv;\n" - "out mediump vec4 frag;\n" - "void main(){\n" - " mediump vec4 fg = texture(tex, uv) * vec4(1,1,1,alpha);\n" - " mediump vec4 bg = texture(tex_bg, uv);\n" - " if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" - " mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" - " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" - " frag = vec4(rgb, alpha_tot);\n" - "}\n"; - - static const char* shader_checkerboard_v = - SHADER_VERSION - "uniform mat4 mvp;\n" - "in vec4 pos;\n" - "in vec2 uvs;\n" - "out vec2 uv;\n" - "void main(){\n" - " uv = uvs;\n" - " gl_Position = mvp * vec4(pos.xyz, 1.0);\n" - "}"; - static const char* shader_checkerboard_f = - SHADER_VERSION - "in mediump vec2 uv;\n" - "out mediump vec4 frag;\n" - "void main(){\n" - " const mediump vec4 c1 = vec4(1.0, 1.0, 1.0, 1.0);\n" - " const mediump vec4 c2 = vec4(0.9, 0.9, 0.9, 1.0);\n" - " mediump vec2 c = floor(fract(uv * 10.0) * 2.0);\n" - " mediump float alpha = mix(c.x, 1.0 - c.x, c.y);\n" - " frag = mix(c1, c2, alpha);\n" - "}"; - - static const char* shader_equirect_v = - SHADER_VERSION - "#define PI 3.1415926535897932384626433832795\n" - "#define TWO_PI 6.283185307179586476925286766559\n" - "uniform mat4 mvp;\n" - "in vec4 pos;\n" - "in vec2 uvs;\n" - "out vec2 uv;\n" - "void main(){\n" - " uv = (vec2(1.0) - uvs + vec2(0.25,0.0)) * vec2(TWO_PI, PI);\n" - " gl_Position = mvp * vec4(pos.xyz, 1.0);\n" - "}"; - static const char* shader_equirect_f = - SHADER_VERSION - "uniform samplerCube tex;\n" - "in highp vec2 uv;\n" - "out mediump vec4 frag;\n" - "void main(){\n" - " highp float anglex = uv.x;\n" - " highp float angley = uv.y;\n" - " highp float sx = sin(anglex);\n" - " highp float cx = cos(anglex);\n" - " highp vec3 dir = vec3(0.0, 0.0, 0.0);\n" - " dir.x = sin(angley) * cx;\n" - " dir.y = cos(angley);\n" - " dir.z = sin(angley) * sx;\n" - " frag = texture(tex, dir);\n" - "}"; - - LOG("initializing shaders"); - if (!ShaderManager::create(kShader::Texture, shader_v, shader_f)) - LOG("Failed to create shader Texture"); - if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f)) - LOG("Failed to create shader TextureAlpha"); - if (!ShaderManager::create(kShader::Color, shader_color_v, shader_color_f)) - LOG("Failed to create shader Color"); - if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f)) - LOG("Failed to create shader ColorQuad"); - if (!ShaderManager::create(kShader::ColorHue, shader_color_hue_v, shader_color_hue_f)) - LOG("Failed to create shader ColorHue"); - if (!ShaderManager::create(kShader::UVs, shader_v, shader_uv_f)) - LOG("Failed to create shader UVs"); - if (!ShaderManager::create(kShader::Font, shader_font_v, shader_font_f)) - LOG("Failed to create shader Font"); - if (!ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f)) - LOG("Failed to create shader Atlas"); - if (!ShaderManager::create(kShader::Stroke, shader_stroke_v, shader_stroke_f)) - LOG("Failed to create shader Stroke"); - if (!ShaderManager::create(kShader::StrokeLock, shader_stroke_v, shader_stroke_lock_f)) - LOG("Failed to create shader StrokeLock"); - if (!ShaderManager::create(kShader::StrokeErase, shader_stroke_v, shader_stroke_erase_f)) - LOG("Failed to create shader StrokeErase"); - if (!ShaderManager::create(kShader::StrokeLayer, shader_stroke_layer_v, shader_stroke_layer_f)) - LOG("Failed to create shader StrokeLayer"); - if (!ShaderManager::create(kShader::Checkerboard, shader_checkerboard_v, shader_checkerboard_f)) - LOG("Failed to create shader Checkerboard"); - if (!ShaderManager::create(kShader::Equirect, shader_equirect_v, shader_equirect_f)) - LOG("Failed to create shader Equirect"); - LOG("shaders initialized"); -} - void App::initAssets() { LOG("initializing assets"); @@ -364,383 +37,11 @@ void App::initAssets() LOG("initializing assets completed"); } -void App::initLayout() -{ - LOG("initializing layout statics"); - NodeBorder::static_init(); - NodeImage::static_init(); - NodeIcon::static_init(); - NodeStrokePreview::static_init(); - - layout.on_loaded = [&] { - LOG("initializing layout updating after load"); - layout[main_id]->update(width, height, zoom); - - LOG("initializing layout components"); - sidebar = layout[main_id]->find("sidebar"); - panels = layout[main_id]->find("panels"); - canvas = layout[main_id]->find("paint-canvas"); - canvas->data_path = data_path; - - //brushes = layout[main_id]->find("panel-brush"); - //layers = layout[main_id]->find("panel-layer"); - //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(); - - if (canvas) - { - stroke->m_canvas->m_brush.m_tip_color = color->m_color; - stroke->m_canvas->draw_stroke(); - canvas->m_brush = stroke->m_canvas->m_brush; - } - - brushes->on_brush_changed = [this](Node* target, int index) { - auto tid = brushes->get_texture_id(index); - stroke->m_canvas->m_brush.m_tex_id = tid; - stroke->m_canvas->draw_stroke(); - canvas->m_brush = stroke->m_canvas->m_brush; - if (on_brush_select) - on_brush_select(index); - }; - - color->on_color_changed = [this](Node* target, glm::vec4 color) { - stroke->m_canvas->m_brush.m_tip_color = color; -// stroke->m_canvas->draw_stroke(); - if (canvas) - canvas->m_brush = stroke->m_canvas->m_brush; - if (on_color_change) - on_color_change(color); - }; - - stroke->on_stroke_change = [this](Node*target) { - if (canvas) - canvas->m_brush = stroke->m_canvas->m_brush; - if (on_stroke_change) - on_stroke_change(); - }; - - layers->on_layer_add = [this](Node*) { - canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str()); - }; - - layers->on_layer_change = [this](Node*, int old_idx, int new_idx) { - canvas->m_canvas->m_current_layer_idx = canvas->m_canvas->m_order[new_idx]; - }; - - layers->on_layer_order = [this](Node*, int old_idx, int new_idx) { - canvas->m_canvas->layer_order(old_idx, new_idx); - }; - - 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; - }; - - 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->layer_add("Default"); - layers->add_layer("Default"); - - static glm::vec4 color_button_normal{.1, .1, .1, 1}; - static glm::vec4 color_button_hlight{ 1, .0, .0, 1}; - if (auto* button = layout[main_id]->find("btn-pen")) - { - button->on_click = [this](Node*) { - layout[main_id]->find("btn-pen")->set_color(color_button_hlight); - layout[main_id]->find("btn-erase")->set_color(color_button_normal); - layout[main_id]->find("btn-line")->set_color(color_button_normal); - layout[main_id]->find("btn-cam")->set_color(color_button_normal); - layout[main_id]->find("btn-grid")->set_color(color_button_normal); - layout[main_id]->find("btn-fill")->set_color(color_button_normal); - Canvas::set_mode(Canvas::kCanvasMode::Draw); - }; - layout[main_id]->find("btn-pen")->set_color(color_button_hlight); - Canvas::set_mode(Canvas::kCanvasMode::Draw); - } - if (auto* button = layout[main_id]->find("btn-erase")) - { - button->on_click = [this](Node*) { - layout[main_id]->find("btn-pen")->set_color(color_button_normal); - layout[main_id]->find("btn-erase")->set_color(color_button_hlight); - layout[main_id]->find("btn-line")->set_color(color_button_normal); - layout[main_id]->find("btn-cam")->set_color(color_button_normal); - layout[main_id]->find("btn-grid")->set_color(color_button_normal); - layout[main_id]->find("btn-fill")->set_color(color_button_normal); - Canvas::set_mode(Canvas::kCanvasMode::Erase); - }; - } - if (auto* button = layout[main_id]->find("btn-line")) - { - button->on_click = [this](Node*) { - layout[main_id]->find("btn-pen")->set_color(color_button_normal); - layout[main_id]->find("btn-erase")->set_color(color_button_normal); - layout[main_id]->find("btn-line")->set_color(color_button_hlight); - layout[main_id]->find("btn-cam")->set_color(color_button_normal); - layout[main_id]->find("btn-grid")->set_color(color_button_normal); - layout[main_id]->find("btn-fill")->set_color(color_button_normal); - Canvas::set_mode(Canvas::kCanvasMode::Line); - }; - } - if (auto* button = layout[main_id]->find("btn-cam")) - { - button->on_click = [this](Node*) { - layout[main_id]->find("btn-pen")->set_color(color_button_normal); - layout[main_id]->find("btn-erase")->set_color(color_button_normal); - layout[main_id]->find("btn-line")->set_color(color_button_normal); - layout[main_id]->find("btn-cam")->set_color(color_button_hlight); - layout[main_id]->find("btn-grid")->set_color(color_button_normal); - layout[main_id]->find("btn-fill")->set_color(color_button_normal); - Canvas::set_mode(Canvas::kCanvasMode::Camera); - }; - } - if (auto* button = layout[main_id]->find("btn-grid")) - { - button->on_click = [this](Node*) { - layout[main_id]->find("btn-pen")->set_color(color_button_normal); - layout[main_id]->find("btn-erase")->set_color(color_button_normal); - layout[main_id]->find("btn-line")->set_color(color_button_normal); - layout[main_id]->find("btn-cam")->set_color(color_button_normal); - layout[main_id]->find("btn-grid")->set_color(color_button_hlight); - layout[main_id]->find("btn-fill")->set_color(color_button_normal); - Canvas::set_mode(Canvas::kCanvasMode::Grid); - }; - } - if (auto* button = layout[main_id]->find("btn-fill")) - { - button->on_click = [this](Node*) { - layout[main_id]->find("btn-pen")->set_color(color_button_normal); - layout[main_id]->find("btn-erase")->set_color(color_button_normal); - layout[main_id]->find("btn-line")->set_color(color_button_normal); - layout[main_id]->find("btn-cam")->set_color(color_button_normal); - layout[main_id]->find("btn-grid")->set_color(color_button_normal); - layout[main_id]->find("btn-fill")->set_color(color_button_hlight); - Canvas::set_mode(Canvas::kCanvasMode::Fill); - }; - } - if (auto* button = layout[main_id]->find("btn-bucket")) - { - button->on_click = [this](Node*) { - canvas->m_canvas->clear(canvas->m_brush.m_tip_color); - }; - } - if (auto* button = layout[main_id]->find("btn-stroke")) - { - button->on_click = [this, button](Node*) { - panels->get_child_index(stroke.get()) == -1 ? panels->add_child(stroke) : panels->remove_child(stroke.get()); - button->set_color(panels->get_child_index(stroke.get()) == -1 ? color_button_normal : color_button_hlight); - }; - } - if (auto* button = layout[main_id]->find("btn-brush")) - { - button->on_click = [this, button](Node*) { - panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get()); - button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight); - }; - } - if (auto* button = layout[main_id]->find("btn-color")) - { - button->on_click = [this, button](Node*) { - panels->get_child_index(color.get()) == -1 ? panels->add_child(color) : panels->remove_child(color.get()); - button->set_color(panels->get_child_index(color.get()) == -1 ? color_button_normal : color_button_hlight); - }; - } - if (auto* button = layout[main_id]->find("btn-layer")) - { - button->on_click = [this, button](Node*) { - panels->get_child_index(layers.get()) == -1 ? panels->add_child(layers) : panels->remove_child(layers.get()); - button->set_color(panels->get_child_index(layers.get()) == -1 ? color_button_normal : color_button_hlight); - }; - } - - if (auto* button = layout[main_id]->find("btn-export")) - { - button->on_click = [this,button](Node*) { - if (canvas) - { - canvas->m_canvas->export_equirectangular(data_path); - } - }; - } - if (auto* button = layout[main_id]->find("btn-anim")) - { - button->on_click = [this,button](Node*) { - if (canvas) - { - //canvas->m_canvas->export_anim(data_path); - } - }; - } - if (auto* button = layout[main_id]->find("btn-open")) - { - button->on_click = [this,button](Node*) { - if (canvas) - { - // load thumbnail test - auto open_dialog = std::make_shared(); - open_dialog->m_manager = &layout; - open_dialog->data_path = data_path; - open_dialog->init(); - open_dialog->create(); - open_dialog->loaded(); - - layout[main_id]->add_child(open_dialog); - layout[main_id]->update(); - - open_dialog->btn_ok->on_click = [this,open_dialog](Node*) - { - layers->clear(); - canvas->m_canvas->project_open(data_path); - for (auto& i : canvas->m_canvas->m_order) - layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str()); - open_dialog->destroy(); - }; - } - }; - } - if (auto* button = layout[main_id]->find("btn-save")) - { - button->on_click = [this,button](Node*) { - if (canvas) - { - canvas->m_canvas->project_save(data_path); - } - }; - } - if (auto* button = layout[main_id]->find("btn-undo")) - { - button->on_click = [this,button](Node*) { - if (!ActionManager::empty()) - ActionManager::undo(); - }; - } - if (auto* button = layout[main_id]->find("btn-clean-memory")) - { - button->on_click = [this](Node*) { - ActionManager::clear(); - }; - } - if (auto* button = layout[main_id]->find("btn-clear")) - { - button->on_click = [this](Node*) { - //exit(0); - if (canvas) - canvas->m_canvas->clear({ 0, 0, 0, 0 }); - }; - } - if (auto* button = layout[main_id]->find("btn-popup")) - { - button->on_click = [this](Node*) { - msgbox = new NodeMessageBox(); - msgbox->m_manager = &layout; - msgbox->init(); - layout[main_id]->add_child(msgbox); - layout[main_id]->update(); - }; - } - if (auto* button = layout[main_id]->find("btn-settings")) - { - button->on_click = [this](Node*) { - settings = new NodeSettings(); - settings->m_manager = &layout; - settings->init(); - layout[main_id]->add_child(settings); - layout[main_id]->update(); - }; - } - if (auto* menu_file = layout[main_id]->find("menu-file")) - { - menu_file->on_click = [=](Node*) { - glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); - popup = (NodePopupMenu*)layout[const_hash("file-menu")]->m_children[0]->clone(); - popup->SetPositioning(YGPositionTypeAbsolute); - popup->SetPosition(pos.x, pos.y); - layout[main_id]->add_child(popup); - layout[main_id]->update(); - popup->mouse_capture(); - popup->m_mouse_ignore = false; - }; - } - if (auto* menu_file = layout[main_id]->find("menu-edit")) - { - menu_file->on_click = [=](Node*) { - glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); - popup = (NodePopupMenu*)layout[const_hash("edit-menu")]->m_children[0]->clone(); - popup->SetPositioning(YGPositionTypeAbsolute); - popup->SetPosition(pos.x, pos.y); - layout[main_id]->add_child(popup); - layout[main_id]->update(); - popup->mouse_capture(); - popup->m_mouse_ignore = false; - }; - } - if (auto* menu_file = layout[main_id]->find("menu-layers")) - { - menu_file->on_click = [=](Node*) { - glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); - popup = (NodePopupMenu*)layout[const_hash("layers-menu")]->m_children[0]->clone(); - popup->SetPositioning(YGPositionTypeAbsolute); - popup->SetPosition(pos.x, pos.y); - layout[main_id]->add_child(popup); - layout[main_id]->update(); - popup->mouse_capture(); - popup->m_mouse_ignore = false; - popup->find("clear-grids")->on_click = [this](Node*) { - CanvasModeGrid* mode = (CanvasModeGrid*)ui::Canvas::modes[(int)ui::Canvas::kCanvasMode::Grid][0]; - mode->clear(); - popup->mouse_release(); - popup->destroy(); - }; - }; - } - if (auto* toolbar = layout[main_id]->find("toolbar")) - { - toolbar->m_flood_events = true; - } - }; - LOG("initializing layout xml"); - if (layout.m_loaded) - { - LOG("restore layout"); - layout.restore_context(); - if (panels->get_child_index(brushes.get()) == -1) brushes->restore_context(); - if (panels->get_child_index(layers.get()) == -1) layers->restore_context(); - if (panels->get_child_index(color.get()) == -1) color->restore_context(); - if (panels->get_child_index(stroke.get()) == -1) stroke->restore_context(); - } - else - layout.load("data/layout.xml"); - LOG("initializing layout completed"); -} - void App::initLog() { LogRemote::I.start(); } + void App::init() { #ifdef _WIN32 @@ -836,121 +137,6 @@ void App::update(float dt) glDisable(GL_SCISSOR_TEST); } -void App::resize(float w, float h) -{ - width = w; - height = h; - if (auto* main = layout[main_id]) - main->update(w , h, zoom); -} - -bool App::mouse_down(int button, float x, float y) -{ - MouseEvent e; - e.m_type = button ? kEventType::MouseDownR : kEventType::MouseDownL; - e.m_pos = { x / zoom, y / zoom }; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::mouse_move(float x, float y) -{ - MouseEvent e; - e.m_type = kEventType::MouseMove; - e.m_pos = { x / zoom, y / zoom }; - kEventResult ret = kEventResult::Available; - if (auto* main = layout[main_id]) - ret = main->on_event(&e); - return ret == kEventResult::Consumed; -} -bool App::mouse_up(int button, float x, float y) -{ - MouseEvent e; - e.m_type = button ? kEventType::MouseUpR : kEventType::MouseUpL; - e.m_pos = { x / zoom, y / zoom }; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::mouse_scroll(float x, float y, float delta) -{ - MouseEvent e; - e.m_type = kEventType::MouseScroll; - e.m_pos = { x / zoom, y / zoom }; - e.m_scroll_delta = delta * 0.1f; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::mouse_cancel(int button) -{ - MouseEvent e; - e.m_type = kEventType::MouseCancel; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1) -{ - GestureEvent e; - glm::vec2 p = glm::lerp(p0, p1, 0.5f); - e.m_type = kEventType::GestureStart; - e.m_pos = p; - e.m_distance = glm::distance(p0, p1); - gesture_p0 = p0; - gesture_p1 = p1; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1) -{ - GestureEvent e; - glm::vec2 p = glm::lerp(p0, p1, 0.5f); - e.m_type = kEventType::GestureMove; - e.m_pos = p; - e.m_distance = glm::distance(p0, p1); - e.m_distance_delta = e.m_distance - glm::distance(gesture_p0, gesture_p1); - e.m_pos_delta = p - glm::lerp(gesture_p0, gesture_p1, 0.5f); - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::gesture_end() -{ - GestureEvent e; - e.m_type = kEventType::GestureEnd; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::key_down(kKey key) -{ - KeyEvent e; - e.m_type = kEventType::KeyDown; - e.m_key = key; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::key_up(kKey key) -{ - KeyEvent e; - e.m_type = kEventType::KeyUp; - e.m_key = key; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} -bool App::key_char(char key) -{ - KeyEvent e; - e.m_type = kEventType::KeyChar; - e.m_char = key; - auto ret = layout[main_id]->on_event(&e); - layout[main_id]->update(); - return ret == kEventResult::Consumed; -} void App::terminate() { diff --git a/engine/app_events.cpp b/engine/app_events.cpp new file mode 100644 index 0000000..fb9a39d --- /dev/null +++ b/engine/app_events.cpp @@ -0,0 +1,121 @@ +#include "pch.h" +#include "app.h" + +using namespace ui; + +void App::resize(float w, float h) +{ + width = w; + height = h; + if (auto* main = layout[main_id]) + main->update(w , h, zoom); +} + +bool App::mouse_down(int button, float x, float y) +{ + MouseEvent e; + e.m_type = button ? kEventType::MouseDownR : kEventType::MouseDownL; + e.m_pos = { x / zoom, y / zoom }; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::mouse_move(float x, float y) +{ + MouseEvent e; + e.m_type = kEventType::MouseMove; + e.m_pos = { x / zoom, y / zoom }; + kEventResult ret = kEventResult::Available; + if (auto* main = layout[main_id]) + ret = main->on_event(&e); + return ret == kEventResult::Consumed; +} +bool App::mouse_up(int button, float x, float y) +{ + MouseEvent e; + e.m_type = button ? kEventType::MouseUpR : kEventType::MouseUpL; + e.m_pos = { x / zoom, y / zoom }; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::mouse_scroll(float x, float y, float delta) +{ + MouseEvent e; + e.m_type = kEventType::MouseScroll; + e.m_pos = { x / zoom, y / zoom }; + e.m_scroll_delta = delta * 0.1f; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + LOG("wheel x %.2f y %.2f", x, y); + return ret == kEventResult::Consumed; +} +bool App::mouse_cancel(int button) +{ + MouseEvent e; + e.m_type = kEventType::MouseCancel; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::gesture_start(const glm::vec2& p0, const glm::vec2& p1) +{ + GestureEvent e; + glm::vec2 p = glm::lerp(p0, p1, 0.5f); + e.m_type = kEventType::GestureStart; + e.m_pos = p; + e.m_distance = glm::distance(p0, p1); + gesture_p0 = p0; + gesture_p1 = p1; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::gesture_move(const glm::vec2& p0, const glm::vec2& p1) +{ + GestureEvent e; + glm::vec2 p = glm::lerp(p0, p1, 0.5f); + e.m_type = kEventType::GestureMove; + e.m_pos = p; + e.m_distance = glm::distance(p0, p1); + e.m_distance_delta = e.m_distance - glm::distance(gesture_p0, gesture_p1); + e.m_pos_delta = p - glm::lerp(gesture_p0, gesture_p1, 0.5f); + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::gesture_end() +{ + GestureEvent e; + e.m_type = kEventType::GestureEnd; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::key_down(kKey key) +{ + KeyEvent e; + e.m_type = kEventType::KeyDown; + e.m_key = key; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::key_up(kKey key) +{ + KeyEvent e; + e.m_type = kEventType::KeyUp; + e.m_key = key; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} +bool App::key_char(char key) +{ + KeyEvent e; + e.m_type = kEventType::KeyChar; + e.m_char = key; + auto ret = layout[main_id]->on_event(&e); + layout[main_id]->update(); + return ret == kEventResult::Consumed; +} diff --git a/engine/app_layout.cpp b/engine/app_layout.cpp new file mode 100644 index 0000000..61c4eee --- /dev/null +++ b/engine/app_layout.cpp @@ -0,0 +1,385 @@ +#include "pch.h" +#include "app.h" +#include "node_icon.h" +#include "node_dialog_open.h" + +using namespace ui; + +void App::initLayout() +{ + LOG("initializing layout statics"); + NodeBorder::static_init(); + NodeImage::static_init(); + NodeIcon::static_init(); + NodeStrokePreview::static_init(); + + layout.on_loaded = [&] { + LOG("initializing layout updating after load"); + layout[main_id]->update(width, height, zoom); + + LOG("initializing layout components"); + sidebar = layout[main_id]->find("sidebar"); + panels = layout[main_id]->find("panels"); + canvas = layout[main_id]->find("paint-canvas"); + canvas->data_path = data_path; + + //brushes = layout[main_id]->find("panel-brush"); + //layers = layout[main_id]->find("panel-layer"); + //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(); + + if (canvas) + { + stroke->m_canvas->m_brush.m_tip_color = color->m_color; + stroke->m_canvas->draw_stroke(); + canvas->m_brush = stroke->m_canvas->m_brush; + } + + brushes->on_brush_changed = [this](Node* target, int index) { + auto tid = brushes->get_texture_id(index); + stroke->m_canvas->m_brush.m_tex_id = tid; + stroke->m_canvas->draw_stroke(); + canvas->m_brush = stroke->m_canvas->m_brush; + if (on_brush_select) + on_brush_select(index); + }; + + color->on_color_changed = [this](Node* target, glm::vec4 color) { + stroke->m_canvas->m_brush.m_tip_color = color; +// stroke->m_canvas->draw_stroke(); + if (canvas) + canvas->m_brush = stroke->m_canvas->m_brush; + if (on_color_change) + on_color_change(color); + }; + + stroke->on_stroke_change = [this](Node*target) { + if (canvas) + canvas->m_brush = stroke->m_canvas->m_brush; + if (on_stroke_change) + on_stroke_change(); + }; + + layers->on_layer_add = [this](Node*) { + canvas->m_canvas->layer_add(layers->m_layers.back()->m_label_text.c_str()); + }; + + layers->on_layer_change = [this](Node*, int old_idx, int new_idx) { + canvas->m_canvas->m_current_layer_idx = canvas->m_canvas->m_order[new_idx]; + }; + + layers->on_layer_order = [this](Node*, int old_idx, int new_idx) { + canvas->m_canvas->layer_order(old_idx, new_idx); + }; + + 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; + }; + + 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->layer_add("Default"); + layers->add_layer("Default"); + + static glm::vec4 color_button_normal{.1, .1, .1, 1}; + static glm::vec4 color_button_hlight{ 1, .0, .0, 1}; + if (auto* button = layout[main_id]->find("btn-pen")) + { + button->on_click = [this](Node*) { + layout[main_id]->find("btn-pen")->set_color(color_button_hlight); + layout[main_id]->find("btn-erase")->set_color(color_button_normal); + layout[main_id]->find("btn-line")->set_color(color_button_normal); + layout[main_id]->find("btn-cam")->set_color(color_button_normal); + layout[main_id]->find("btn-grid")->set_color(color_button_normal); + layout[main_id]->find("btn-fill")->set_color(color_button_normal); + Canvas::set_mode(Canvas::kCanvasMode::Draw); + }; + layout[main_id]->find("btn-pen")->set_color(color_button_hlight); + Canvas::set_mode(Canvas::kCanvasMode::Draw); + } + if (auto* button = layout[main_id]->find("btn-erase")) + { + button->on_click = [this](Node*) { + layout[main_id]->find("btn-pen")->set_color(color_button_normal); + layout[main_id]->find("btn-erase")->set_color(color_button_hlight); + layout[main_id]->find("btn-line")->set_color(color_button_normal); + layout[main_id]->find("btn-cam")->set_color(color_button_normal); + layout[main_id]->find("btn-grid")->set_color(color_button_normal); + layout[main_id]->find("btn-fill")->set_color(color_button_normal); + Canvas::set_mode(Canvas::kCanvasMode::Erase); + }; + } + if (auto* button = layout[main_id]->find("btn-line")) + { + button->on_click = [this](Node*) { + layout[main_id]->find("btn-pen")->set_color(color_button_normal); + layout[main_id]->find("btn-erase")->set_color(color_button_normal); + layout[main_id]->find("btn-line")->set_color(color_button_hlight); + layout[main_id]->find("btn-cam")->set_color(color_button_normal); + layout[main_id]->find("btn-grid")->set_color(color_button_normal); + layout[main_id]->find("btn-fill")->set_color(color_button_normal); + Canvas::set_mode(Canvas::kCanvasMode::Line); + }; + } + if (auto* button = layout[main_id]->find("btn-cam")) + { + button->on_click = [this](Node*) { + layout[main_id]->find("btn-pen")->set_color(color_button_normal); + layout[main_id]->find("btn-erase")->set_color(color_button_normal); + layout[main_id]->find("btn-line")->set_color(color_button_normal); + layout[main_id]->find("btn-cam")->set_color(color_button_hlight); + layout[main_id]->find("btn-grid")->set_color(color_button_normal); + layout[main_id]->find("btn-fill")->set_color(color_button_normal); + Canvas::set_mode(Canvas::kCanvasMode::Camera); + }; + } + if (auto* button = layout[main_id]->find("btn-grid")) + { + button->on_click = [this](Node*) { + layout[main_id]->find("btn-pen")->set_color(color_button_normal); + layout[main_id]->find("btn-erase")->set_color(color_button_normal); + layout[main_id]->find("btn-line")->set_color(color_button_normal); + layout[main_id]->find("btn-cam")->set_color(color_button_normal); + layout[main_id]->find("btn-grid")->set_color(color_button_hlight); + layout[main_id]->find("btn-fill")->set_color(color_button_normal); + Canvas::set_mode(Canvas::kCanvasMode::Grid); + }; + } + if (auto* button = layout[main_id]->find("btn-fill")) + { + button->on_click = [this](Node*) { + layout[main_id]->find("btn-pen")->set_color(color_button_normal); + layout[main_id]->find("btn-erase")->set_color(color_button_normal); + layout[main_id]->find("btn-line")->set_color(color_button_normal); + layout[main_id]->find("btn-cam")->set_color(color_button_normal); + layout[main_id]->find("btn-grid")->set_color(color_button_normal); + layout[main_id]->find("btn-fill")->set_color(color_button_hlight); + Canvas::set_mode(Canvas::kCanvasMode::Fill); + }; + } + if (auto* button = layout[main_id]->find("btn-bucket")) + { + button->on_click = [this](Node*) { + canvas->m_canvas->clear(canvas->m_brush.m_tip_color); + }; + } + if (auto* button = layout[main_id]->find("btn-stroke")) + { + button->on_click = [this, button](Node*) { + panels->get_child_index(stroke.get()) == -1 ? panels->add_child(stroke) : panels->remove_child(stroke.get()); + button->set_color(panels->get_child_index(stroke.get()) == -1 ? color_button_normal : color_button_hlight); + }; + } + if (auto* button = layout[main_id]->find("btn-brush")) + { + button->on_click = [this, button](Node*) { + panels->get_child_index(brushes.get()) == -1 ? panels->add_child(brushes) : panels->remove_child(brushes.get()); + button->set_color(panels->get_child_index(brushes.get()) == -1 ? color_button_normal : color_button_hlight); + }; + } + if (auto* button = layout[main_id]->find("btn-color")) + { + button->on_click = [this, button](Node*) { + panels->get_child_index(color.get()) == -1 ? panels->add_child(color) : panels->remove_child(color.get()); + button->set_color(panels->get_child_index(color.get()) == -1 ? color_button_normal : color_button_hlight); + }; + } + if (auto* button = layout[main_id]->find("btn-layer")) + { + button->on_click = [this, button](Node*) { + panels->get_child_index(layers.get()) == -1 ? panels->add_child(layers) : panels->remove_child(layers.get()); + button->set_color(panels->get_child_index(layers.get()) == -1 ? color_button_normal : color_button_hlight); + }; + } + + if (auto* button = layout[main_id]->find("btn-export")) + { + button->on_click = [this,button](Node*) { + if (canvas) + { + canvas->m_canvas->export_equirectangular(data_path); + } + }; + } + if (auto* button = layout[main_id]->find("btn-anim")) + { + button->on_click = [this,button](Node*) { + if (canvas) + { + //canvas->m_canvas->export_anim(data_path); + } + }; + } + if (auto* button = layout[main_id]->find("btn-open")) + { + button->on_click = [this,button](Node*) { + if (canvas) + { + // load thumbnail test + auto open_dialog = std::make_shared(); + open_dialog->m_manager = &layout; + open_dialog->data_path = data_path; + open_dialog->init(); + open_dialog->create(); + open_dialog->loaded(); + + layout[main_id]->add_child(open_dialog); + layout[main_id]->update(); + + open_dialog->btn_ok->on_click = [this,open_dialog](Node*) + { + layers->clear(); + canvas->m_canvas->project_open(data_path); + for (auto& i : canvas->m_canvas->m_order) + layers->add_layer(canvas->m_canvas->m_layers[i].m_name.c_str()); + open_dialog->destroy(); + }; + } + }; + } + if (auto* button = layout[main_id]->find("btn-save")) + { + button->on_click = [this,button](Node*) { + if (canvas) + { + canvas->m_canvas->project_save(data_path); + } + }; + } + if (auto* button = layout[main_id]->find("btn-undo")) + { + button->on_click = [this,button](Node*) { + if (!ActionManager::empty()) + ActionManager::undo(); + }; + } + if (auto* button = layout[main_id]->find("btn-clean-memory")) + { + button->on_click = [this](Node*) { + ActionManager::clear(); + }; + } + if (auto* button = layout[main_id]->find("btn-clear")) + { + button->on_click = [this](Node*) { + //exit(0); + if (canvas) + canvas->m_canvas->clear({ 0, 0, 0, 0 }); + }; + } + if (auto* button = layout[main_id]->find("btn-popup")) + { + button->on_click = [this](Node*) { + msgbox = new NodeMessageBox(); + msgbox->m_manager = &layout; + msgbox->init(); + layout[main_id]->add_child(msgbox); + layout[main_id]->update(); + }; + } + if (auto* button = layout[main_id]->find("btn-settings")) + { + button->on_click = [this](Node*) { + settings = new NodeSettings(); + settings->m_manager = &layout; + settings->init(); + layout[main_id]->add_child(settings); + layout[main_id]->update(); + }; + } + if (auto* menu_file = layout[main_id]->find("menu-file")) + { + menu_file->on_click = [=](Node*) { + glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); + popup = (NodePopupMenu*)layout[const_hash("file-menu")]->m_children[0]->clone(); + popup->SetPositioning(YGPositionTypeAbsolute); + popup->SetPosition(pos.x, pos.y); + layout[main_id]->add_child(popup); + layout[main_id]->update(); + popup->mouse_capture(); + popup->m_mouse_ignore = false; + popup->m_flood_events = true; + popup->m_capture_children = false; + }; + } + if (auto* menu_file = layout[main_id]->find("menu-edit")) + { + menu_file->on_click = [=](Node*) { + glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); + popup = (NodePopupMenu*)layout[const_hash("edit-menu")]->m_children[0]->clone(); + popup->SetPositioning(YGPositionTypeAbsolute); + popup->SetPosition(pos.x, pos.y); + layout[main_id]->add_child(popup); + layout[main_id]->update(); + popup->mouse_capture(); + popup->m_mouse_ignore = false; + popup->m_flood_events = true; + popup->m_capture_children = false; + }; + } + if (auto* menu_file = layout[main_id]->find("menu-layers")) + { + menu_file->on_click = [=](Node*) { + glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y); + popup = (NodePopupMenu*)layout[const_hash("layers-menu")]->m_children[0]->clone(); + popup->SetPositioning(YGPositionTypeAbsolute); + popup->SetPosition(pos.x, pos.y); + layout[main_id]->add_child(popup); + layout[main_id]->update(); + popup->mouse_capture(); + popup->m_mouse_ignore = false; + popup->m_flood_events = true; + popup->m_capture_children = false; + popup->find("clear-grids")->on_click = [this](Node*) { + CanvasModeGrid* mode = (CanvasModeGrid*)ui::Canvas::modes[(int)ui::Canvas::kCanvasMode::Grid][0]; + mode->clear(); + popup->mouse_release(); + popup->destroy(); + }; + }; + } + if (auto* toolbar = layout[main_id]->find("toolbar")) + { + toolbar->m_flood_events = true; + } + }; + LOG("initializing layout xml"); + if (layout.m_loaded) + { + LOG("restore layout"); + layout.restore_context(); + if (panels->get_child_index(brushes.get()) == -1) brushes->restore_context(); + if (panels->get_child_index(layers.get()) == -1) layers->restore_context(); + if (panels->get_child_index(color.get()) == -1) color->restore_context(); + if (panels->get_child_index(stroke.get()) == -1) stroke->restore_context(); + } + else + layout.load("data/layout.xml"); + LOG("initializing layout completed"); +} diff --git a/engine/app_shaders.cpp b/engine/app_shaders.cpp new file mode 100644 index 0000000..0f5b53a --- /dev/null +++ b/engine/app_shaders.cpp @@ -0,0 +1,334 @@ +#include "pch.h" +#include "app.h" +#include "shader.h" + +using namespace ui; + +void App::initShaders() +{ + static const char* shader_v = + SHADER_VERSION + "uniform mat4 mvp;" + "in vec4 pos;" + "in vec2 uvs;" + "out vec3 uv;" + "void main(){" + " uv = vec3(uvs, pos.w);" + " gl_Position = mvp * vec4(pos.xyz, 1.0);" + "}"; + static const char* shader_f = + SHADER_VERSION + "uniform sampler2D tex;" + "in mediump vec3 uv;" + "out mediump vec4 frag;" + "void main(){" + //" frag = texture(tex, uv.xy/uv.z);" + " frag = texture(tex, uv.xy);" + "}"; + static const char* shader_uv_f = + SHADER_VERSION + "uniform sampler2D tex;" + "in mediump vec3 uv;" + "out mediump vec4 frag;" + "void main(){" + " frag = vec4(uv.xy, 0.0, 1.0);" + "}"; + // TEXTURE ALPHA + static const char* shader_alpha_f = + SHADER_VERSION + "uniform sampler2D tex;\n" + "uniform mediump float alpha;\n" + "in mediump vec3 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " frag = texture(tex, uv.xy) * vec4(1,1,1,alpha);\n" + "}\n"; + + // TEXTURE ATLAS + static const char* shader_atlas_v = + SHADER_VERSION + "uniform mat4 mvp;" + "uniform vec2 tof;" + "uniform vec2 tsz;" + "in vec2 pos;" + "in vec2 uvs;" + "out vec2 uv;" + "void main(){" + " uv = tof + uvs * tsz;" + " gl_Position = mvp * vec4(pos, 0.0, 1.0);" + "}"; + static const char* shader_atlas_f = + SHADER_VERSION + "uniform sampler2D tex;" + "in mediump vec2 uv;" + "out mediump vec4 frag;" + "void main(){" + " frag = texture(tex, uv);" + "}"; + + // SOLID COLOR + static const char* shader_color_v = + SHADER_VERSION + "uniform mat4 mvp;" + "in vec4 pos;" + "void main(){" + " gl_Position = mvp * pos;" + " gl_PointSize = 15.0;" + "}"; + static const char* shader_color_f = + SHADER_VERSION + "uniform mediump vec4 col;" + "out mediump vec4 frag;" + "void main(){" + " frag = col;" + "}"; + + // COLOR QUAD + static const char* shader_color_quad_v = + SHADER_VERSION + "uniform mat4 mvp;" + "in vec4 pos;" + "in vec2 uvs;" + "out vec3 uv;" + "void main(){" + " gl_Position = mvp * pos;" + " uv = vec3(uvs, pos.w);" + "}"; + static const char* shader_color_quad_f = + SHADER_VERSION + "uniform mediump vec4 col;" + "in mediump vec3 uv;" + "out mediump vec4 frag;" + "void main(){" + " mediump vec4 gradient_x = mix(col, vec4(1.0, 1.0, 1.0, 1.0), uv.x);" + " frag = mix(gradient_x, vec4(0.0, 0.0, 0.0, 1.0), uv.y);" + "}"; + + // HUE + static const char* shader_color_hue_v = + SHADER_VERSION + "uniform mat4 mvp;" + "in vec4 pos;" + "in vec2 uvs;" + "out vec3 uv;" + "void main(){" + " gl_Position = mvp * pos;" + " uv = vec3(uvs, pos.w);" + "}"; + static const char* shader_color_hue_f = + SHADER_VERSION + "uniform mediump vec4 col;" + "in mediump vec3 uv;" + "out mediump vec4 frag;" + "mediump vec3 hsv2rgb(mediump vec3 c) {" + " mediump vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" + " mediump vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);" + " return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);" + "}" + "void main(){" + " frag = vec4(hsv2rgb(vec3(uv.y, 1.0, 1.0)), 1.0);" + "}"; + + // FONT + static const char* shader_font_v = + SHADER_VERSION + "uniform mat4 mvp;" + "in vec2 pos;" + "in vec2 uvs;" + "out vec2 uv;" + "void main(){" + " uv = uvs;" + " gl_Position = mvp * vec4(pos, 0.0, 1.0);" + "}"; + static const char* shader_font_f = + SHADER_VERSION + "uniform mediump sampler2D tex;" + "uniform mediump vec4 col;" + "in mediump vec2 uv;" + "out mediump vec4 frag;" + "void main(){" + " mediump float a = texture(tex, uv).r;" + " frag = vec4(col.rgb, a);" + "}"; + + // STROKE + static const char* shader_stroke_v = + SHADER_VERSION + "uniform mat4 mvp;\n" + "in vec4 pos;\n" + "in vec2 uvs;\n" + "out vec2 uv;\n" + "void main(){\n" + " uv = uvs;\n" + " gl_Position = mvp * vec4(pos.xyz, 1.0);\n" + "}\n"; + static const char* shader_stroke_f = + SHADER_VERSION + "uniform mediump sampler2D tex;\n" + "uniform mediump sampler2D tex_bg;\n" + "uniform mediump vec4 col;\n" + "uniform mediump vec2 resolution;\n" + "uniform mediump float alpha;\n" + "in mediump vec2 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" + " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" + " mediump vec4 fg = vec4(col.rgb, brush_alpha);\n" + " mediump vec4 bg = texture(tex_bg, uv2);\n" + " if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" + " mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" + " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" + " frag = vec4(rgb, alpha_tot);\n" + "}\n"; + // ALPHA LOCK + static const char* shader_stroke_lock_f = + SHADER_VERSION + "uniform mediump sampler2D tex;\n" + "uniform mediump sampler2D tex_bg;\n" + "uniform mediump sampler2D tex_mask;\n" + "uniform mediump vec4 col;\n" + "uniform mediump vec2 resolution;\n" + "uniform mediump float alpha;\n" + "in mediump vec2 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" + " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" + " mediump vec4 fg = vec4(col.rgb, brush_alpha);\n" + " mediump vec4 bg = texture(tex_bg, uv2);\n" + " mediump vec4 msk = texture(tex_mask, uv2);\n" + " if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" + " mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" + " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" + " frag = vec4(rgb, min(alpha_tot, msk.a));\n" + "}\n"; + // ERASER + static const char* shader_stroke_erase_f = + SHADER_VERSION + "uniform mediump sampler2D tex;\n" + "uniform mediump sampler2D tex_bg;\n" + "uniform mediump vec4 col;\n" + "uniform mediump vec2 resolution;\n" + "uniform mediump float alpha;\n" + "in mediump vec2 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " mediump vec2 uv2 = gl_FragCoord.st / resolution;\n" + " mediump float brush_alpha = ( 1.0 - texture(tex, uv).r ) * alpha;\n" + " mediump vec4 bg = texture(tex_bg, uv2);\n" + " frag = vec4(bg.rgb, bg.a - bg.a * brush_alpha);\n" + "}\n"; + + // STROKE LAYER BLEND + static const char* shader_stroke_layer_v = + SHADER_VERSION + "uniform mat4 mvp;" + "in vec4 pos;" + "in vec2 uvs;" + "out vec2 uv;" + "void main(){" + " uv = uvs;" + " gl_Position = mvp * vec4(pos.xyz, 1.0);" + "}"; + static const char* shader_stroke_layer_f = + SHADER_VERSION + "uniform mediump sampler2D tex;\n" + "uniform mediump sampler2D tex_bg;\n" + "uniform mediump vec2 resolution;\n" + "uniform mediump float alpha;\n" + "in mediump vec2 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " mediump vec4 fg = texture(tex, uv) * vec4(1,1,1,alpha);\n" + " mediump vec4 bg = texture(tex_bg, uv);\n" + " if (fg.a < (1.0/255.0)) { frag = bg; return; }\n" + " mediump float alpha_tot = fg.a + (1.0 - fg.a) * bg.a;" + " mediump vec3 rgb = mix(bg.rgb, fg.rgb, fg.a / alpha_tot);\n" + " frag = vec4(rgb, alpha_tot);\n" + "}\n"; + + static const char* shader_checkerboard_v = + SHADER_VERSION + "uniform mat4 mvp;\n" + "in vec4 pos;\n" + "in vec2 uvs;\n" + "out vec2 uv;\n" + "void main(){\n" + " uv = uvs;\n" + " gl_Position = mvp * vec4(pos.xyz, 1.0);\n" + "}"; + static const char* shader_checkerboard_f = + SHADER_VERSION + "in mediump vec2 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " const mediump vec4 c1 = vec4(1.0, 1.0, 1.0, 1.0);\n" + " const mediump vec4 c2 = vec4(0.9, 0.9, 0.9, 1.0);\n" + " mediump vec2 c = floor(fract(uv * 10.0) * 2.0);\n" + " mediump float alpha = mix(c.x, 1.0 - c.x, c.y);\n" + " frag = mix(c1, c2, alpha);\n" + "}"; + + static const char* shader_equirect_v = + SHADER_VERSION + "#define PI 3.1415926535897932384626433832795\n" + "#define TWO_PI 6.283185307179586476925286766559\n" + "uniform mat4 mvp;\n" + "in vec4 pos;\n" + "in vec2 uvs;\n" + "out vec2 uv;\n" + "void main(){\n" + " uv = (vec2(1.0) - uvs + vec2(0.25,0.0)) * vec2(TWO_PI, PI);\n" + " gl_Position = mvp * vec4(pos.xyz, 1.0);\n" + "}"; + static const char* shader_equirect_f = + SHADER_VERSION + "uniform samplerCube tex;\n" + "in highp vec2 uv;\n" + "out mediump vec4 frag;\n" + "void main(){\n" + " highp float anglex = uv.x;\n" + " highp float angley = uv.y;\n" + " highp float sx = sin(anglex);\n" + " highp float cx = cos(anglex);\n" + " highp vec3 dir = vec3(0.0, 0.0, 0.0);\n" + " dir.x = sin(angley) * cx;\n" + " dir.y = cos(angley);\n" + " dir.z = sin(angley) * sx;\n" + " frag = texture(tex, dir);\n" + "}"; + + LOG("initializing shaders"); + if (!ShaderManager::create(kShader::Texture, shader_v, shader_f)) + LOG("Failed to create shader Texture"); + if (!ShaderManager::create(kShader::TextureAlpha, shader_v, shader_alpha_f)) + LOG("Failed to create shader TextureAlpha"); + if (!ShaderManager::create(kShader::Color, shader_color_v, shader_color_f)) + LOG("Failed to create shader Color"); + if (!ShaderManager::create(kShader::ColorQuad, shader_color_quad_v, shader_color_quad_f)) + LOG("Failed to create shader ColorQuad"); + if (!ShaderManager::create(kShader::ColorHue, shader_color_hue_v, shader_color_hue_f)) + LOG("Failed to create shader ColorHue"); + if (!ShaderManager::create(kShader::UVs, shader_v, shader_uv_f)) + LOG("Failed to create shader UVs"); + if (!ShaderManager::create(kShader::Font, shader_font_v, shader_font_f)) + LOG("Failed to create shader Font"); + if (!ShaderManager::create(kShader::Atlas, shader_atlas_v, shader_atlas_f)) + LOG("Failed to create shader Atlas"); + if (!ShaderManager::create(kShader::Stroke, shader_stroke_v, shader_stroke_f)) + LOG("Failed to create shader Stroke"); + if (!ShaderManager::create(kShader::StrokeLock, shader_stroke_v, shader_stroke_lock_f)) + LOG("Failed to create shader StrokeLock"); + if (!ShaderManager::create(kShader::StrokeErase, shader_stroke_v, shader_stroke_erase_f)) + LOG("Failed to create shader StrokeErase"); + if (!ShaderManager::create(kShader::StrokeLayer, shader_stroke_layer_v, shader_stroke_layer_f)) + LOG("Failed to create shader StrokeLayer"); + if (!ShaderManager::create(kShader::Checkerboard, shader_checkerboard_v, shader_checkerboard_f)) + LOG("Failed to create shader Checkerboard"); + if (!ShaderManager::create(kShader::Equirect, shader_equirect_v, shader_equirect_f)) + LOG("Failed to create shader Equirect"); + LOG("shaders initialized"); +} + + diff --git a/engine/main.cpp b/engine/main.cpp index 4edecef..e7a1c46 100644 --- a/engine/main.cpp +++ b/engine/main.cpp @@ -659,20 +659,30 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) break; case WM_LBUTTONDOWN: App::I.mouse_down(0, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp)); + SetCapture(hWnd); break; case WM_LBUTTONUP: App::I.mouse_up(0, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp)); + ReleaseCapture(); break; case WM_RBUTTONDOWN: App::I.mouse_down(1, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp)); + SetCapture(hWnd); break; case WM_RBUTTONUP: App::I.mouse_up(1, (float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp)); + ReleaseCapture(); break; case WM_MOUSEWHEEL: - App::I.mouse_scroll((float)GET_X_LPARAM(lp), (float)GET_Y_LPARAM(lp), + { + POINT pt; + pt.x = GET_X_LPARAM(lp); + pt.y = GET_Y_LPARAM(lp); + ScreenToClient(hWnd, &pt); + App::I.mouse_scroll((float)pt.x, (float)pt.y, (float)GET_WHEEL_DELTA_WPARAM(wp) / (float)WHEEL_DELTA); break; + } case WM_POINTERUPDATE: { POINTER_TOUCH_INFO touchInfo; diff --git a/engine/node.cpp b/engine/node.cpp index 91fd0d8..0190e3f 100644 --- a/engine/node.cpp +++ b/engine/node.cpp @@ -23,6 +23,7 @@ #include "node_color_quad.h" #include "node_stroke_preview.h" #include "node_canvas.h" +#include "node_scroll.h" void Node::watch(std::function observer) { @@ -47,26 +48,35 @@ Node* Node::root() kEventResult Node::on_event(Event* e) { + kEventResult ret = kEventResult::Available; + if (current_mouse_capture) return current_mouse_capture->on_event(e); - kEventResult ret = kEventResult::Available; - for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) + bool skip_children = false; + skip_children |= (e->m_cat == kEventCategory::MouseEvent) && + (m_mouse_captured) && (root()->current_mouse_capture == this) && m_capture_children; + + if (!skip_children) { - if ((*it)->on_event(e) == kEventResult::Consumed) + for (auto it = m_children.rbegin(); it != m_children.rend(); ++it) { - if (m_flood_events) + if ((*it)->on_event(e) == kEventResult::Consumed) { - ret = kEventResult::Consumed; - } - else - { - return kEventResult::Consumed; + if (m_flood_events) + { + ret = kEventResult::Consumed; + } + else + { + return kEventResult::Consumed; + } } } + if (ret == kEventResult::Consumed) + return ret; } - if (ret == kEventResult::Consumed) - return ret; + switch (e->m_cat) { case kEventCategory::MouseEvent: @@ -79,6 +89,7 @@ kEventResult Node::on_event(Event* e) m_mouse_inside = inside; switch (e->m_type) { + case kEventType::MouseScroll: case kEventType::MouseDownL: case kEventType::MouseDownR: case kEventType::MouseUpL: @@ -240,24 +251,39 @@ int Node::get_child_index(Node* n) return -1; } +glm::vec4 Node::get_children_rect() const +{ + if (m_children.empty()) + return glm::vec4(0); + glm::vec4 ret = m_children[0]->m_clip_uncut; + for (auto& c : m_children) + ret = rect_union(ret, c->m_clip_uncut); + return ret; +} + void Node::mouse_capture() { - root()->current_mouse_capture = this; m_mouse_captured = true; + root()->current_mouse_capture = this; + m_mouse_captured = true; } void Node::mouse_release() { - root()->current_mouse_capture = nullptr; m_mouse_captured = false; + if (root()->current_mouse_capture == this) + root()->current_mouse_capture = nullptr; + m_mouse_captured = false; } void Node::key_capture() { - root()->current_key_capture = this; m_key_captured = true; + root()->current_key_capture = this; + m_key_captured = true; } void Node::key_release() { - root()->current_key_capture = nullptr; m_key_captured = false; + root()->current_key_capture = nullptr; + m_key_captured = false; } Node&& Node::operator=(Node&& o) @@ -335,6 +361,15 @@ void Node::SetPadding(float t, float r, float b, float l) YGNodeStyleSetPadding(y_node, YGEdgeLeft, l); } +glm::vec4 Node::GetPadding() const +{ + float t = YGNodeLayoutGetPadding(y_node, YGEdgeTop); + float r = YGNodeLayoutGetPadding(y_node, YGEdgeRight); + float b = YGNodeLayoutGetPadding(y_node, YGEdgeBottom); + float l = YGNodeLayoutGetPadding(y_node, YGEdgeLeft); + return{ t, r, b, l }; +} + void Node::SetPosition(const glm::vec2 pos) { SetPosition(pos.x, pos.y); @@ -414,12 +449,26 @@ glm::vec2 Node::GetSize() return{ GetWidth(), GetHeight() }; } -glm::vec4 Node::rect_intersection(glm::vec4 a, glm::vec4 b) +glm::vec4 Node::rect_intersection(glm::vec4 a, glm::vec4 b) const { // convert from [x,y,w,h] to [x1,y1,x2,y1] a = glm::vec4(a.xy(), a.xy() + a.zw()); b = glm::vec4(b.xy(), b.xy() + b.zw()); + // compute intersection auto o = glm::vec4(glm::max(a.xy(), b.xy()), glm::min(a.zw(), b.zw())); + // back to rect form + o = glm::vec4(o.xy(), glm::max({ 0, 0 }, o.zw() - o.xy())); + return o; +} + +glm::vec4 Node::rect_union(glm::vec4 a, glm::vec4 b) const +{ + // convert from rect [x,y,w,h] to bb [x1,y1,x2,y1] + a = glm::vec4(a.xy(), a.xy() + a.zw()); + b = glm::vec4(b.xy(), b.xy() + b.zw()); + // compute union + glm::vec4 o = { glm::min(a.xy(), b.xy()), glm::max(a.zw(), b.zw()) }; + // back to rect form o = glm::vec4(o.xy(), glm::max({ 0, 0 }, o.zw() - o.xy())); return o; } @@ -459,7 +508,9 @@ void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj) float w = YGNodeLayoutGetWidth(y_node); float h = YGNodeLayoutGetHeight(y_node); auto old_size = m_size; - m_pos = glm::floor(origin + glm::vec2(x, y)); + glm::vec2 parent_offset = parent ? parent->m_pos_offset_childred : glm::vec2(0.f); + m_pos = glm::floor(origin + glm::vec2(x, y) + m_pos_offset + parent_offset); + m_pos_origin = glm::floor(origin + glm::vec2(x, y)); m_size = glm::floor(glm::vec2(w, h)); if (parent) @@ -478,7 +529,7 @@ void Node::update_internal(const glm::vec2& origin, const glm::mat4& proj) } else { - m_clip = glm::vec4(m_pos, m_size); + m_clip_uncut = m_clip = glm::vec4(m_pos, m_size); } glm::mat4 pivot = glm::translate(glm::vec3(.5f, .5f, 0.f)); @@ -726,6 +777,7 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node) CASE(kWidget::ColorQuad, NodeColorQuad); CASE(kWidget::StrokePreview, NodeStrokePreview); CASE(kWidget::Canvas, NodeCanvas); + CASE(kWidget::Scroll, NodeScroll); #undef CASE case kWidget::Ref: { diff --git a/engine/node.h b/engine/node.h index 889194d..bc18568 100644 --- a/engine/node.h +++ b/engine/node.h @@ -67,6 +67,7 @@ enum class kWidget : uint16_t ColorQuad = const_hash("color-quad"), StrokePreview = const_hash("stroke-preview"), Canvas = const_hash("canvas"), + Scroll = const_hash("scroll"), }; class Node @@ -88,12 +89,16 @@ public: glm::mat4 m_mvp; bool m_mouse_inside = false; bool m_flood_events = false; + bool m_capture_children = true; // wether to capture children events when xx_capture() is used bool m_destroyed = false; bool m_mouse_ignore = true; float m_zoom = 1.f; glm::vec2 m_scale{ 1.f }; glm::vec2 m_pos; + glm::vec2 m_pos_origin; // original layout position without offset + glm::vec2 m_pos_offset; // artificial position offset for scrolling + glm::vec2 m_pos_offset_childred; // artificial position offset for scrolling glm::vec2 m_size; glm::vec4 m_clip; glm::vec4 m_clip_uncut; @@ -114,6 +119,7 @@ public: void SetSize(float w, float h); void SetPadding(float t, float r, float b, float l); + glm::vec4 GetPadding() const; void SetPosition(float l, float t, float r, float b); void SetPosition(float l, float t); void SetPosition(const glm::vec2 pos); @@ -132,7 +138,8 @@ public: float GetHeight(); glm::vec2 GetSize(); - glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b); + glm::vec4 rect_intersection(glm::vec4 a, glm::vec4 b) const; + glm::vec4 rect_union(glm::vec4 a, glm::vec4 b) const; virtual void restore_context();; virtual void clear_context(); @@ -177,6 +184,7 @@ public: void move_child(Node* n, int index); void move_child_offset(Node* n, int offset); int get_child_index(Node* n); + glm::vec4 get_children_rect() const; void mouse_capture(); void mouse_release(); void key_capture(); diff --git a/engine/node_button_custom.cpp b/engine/node_button_custom.cpp index 3e02ba7..04a57a4 100644 --- a/engine/node_button_custom.cpp +++ b/engine/node_button_custom.cpp @@ -46,11 +46,16 @@ kEventResult NodeButtonCustom::handle_event(Event* e) break; case kEventType::MouseDownL: m_color = color_down; + mouse_capture(); break; case kEventType::MouseUpL: m_color = m_mouse_inside ? color_hover : color_normal; if (m_mouse_inside && on_click != nullptr) on_click(this); + mouse_release(); + break; + case kEventType::MouseCancel: + mouse_release(); break; default: return kEventResult::Available; diff --git a/engine/node_canvas.cpp b/engine/node_canvas.cpp index 5d44acb..00ddfe0 100644 --- a/engine/node_canvas.cpp +++ b/engine/node_canvas.cpp @@ -162,12 +162,12 @@ kEventResult NodeCanvas::handle_event(Event* e) switch (e->m_type) { + case kEventType::MouseScroll: case kEventType::MouseDownL: case kEventType::MouseUpL: case kEventType::MouseDownR: case kEventType::MouseUpR: case kEventType::MouseMove: - case kEventType::MouseScroll: case kEventType::MouseCancel: for (auto& mode : *m_canvas->m_mode) mode->on_MouseEvent(me, loc); diff --git a/engine/node_popup_menu.cpp b/engine/node_popup_menu.cpp index c27d4aa..f197dc9 100644 --- a/engine/node_popup_menu.cpp +++ b/engine/node_popup_menu.cpp @@ -15,6 +15,7 @@ void NodePopupMenu::init() SetHeight(400); SetPositioning(YGPositionTypeAbsolute); m_mouse_ignore = false; + m_capture_children = false; } kEventResult NodePopupMenu::handle_event(Event* e) diff --git a/engine/node_scroll.cpp b/engine/node_scroll.cpp new file mode 100644 index 0000000..bb41c06 --- /dev/null +++ b/engine/node_scroll.cpp @@ -0,0 +1,50 @@ +#include "pch.h" +#include "log.h" +#include "node_scroll.h" +#include "event.h" + +Node* NodeScroll::clone_instantiate() const +{ + return new NodeScroll; +} + +kEventResult NodeScroll::handle_event(Event* e) +{ + NodeBorder::handle_event(e); + auto me = static_cast(e); + auto loc = (me->m_pos - m_pos) * root()->m_zoom; + switch (e->m_type) + { + case kEventType::MouseDownL: + m_dragging = true; + m_drag_start = me->m_pos; + m_offset_start = m_offset; + mouse_capture(); + break; + case kEventType::MouseMove: + if (m_dragging) + { + auto pad = GetPadding(); + glm::vec2 padoff = { pad.y + pad.w, pad.x + pad.z }; + auto rect = get_children_rect(); + m_offset = m_offset_start + (me->m_pos - m_drag_start) * m_mask; + m_offset = glm::clamp(m_offset, -rect.zw() + m_clip_uncut.zw() - padoff, { 0, 0 }); + m_pos_offset_childred = m_offset; + } + break; + case kEventType::MouseUpL: + mouse_release(); + m_dragging = false; + break; +// case kEventType::MouseScroll: +// break; + case kEventType::MouseCancel: + mouse_release(); + m_dragging = false; + break; + default: + return kEventResult::Available; + break; + } + return kEventResult::Consumed; +} diff --git a/engine/node_scroll.h b/engine/node_scroll.h new file mode 100644 index 0000000..3478c81 --- /dev/null +++ b/engine/node_scroll.h @@ -0,0 +1,14 @@ +#pragma once +#include "node_border.h" + +class NodeScroll : public NodeBorder +{ + bool m_dragging = false; + glm::vec2 m_drag_start; + glm::vec2 m_offset_start; + glm::vec2 m_offset; + glm::vec2 m_mask{ 0, 1 }; +public: + virtual Node* clone_instantiate() const override; + virtual kEventResult handle_event(Event* e) override; +};