diff --git a/data/dialogs/panel-animation.xml b/data/dialogs/panel-animation.xml index 31fd38d..8d4bfe4 100644 --- a/data/dialogs/panel-animation.xml +++ b/data/dialogs/panel-animation.xml @@ -49,7 +49,21 @@ - + + + + + + + + + + + + + + + diff --git a/src/app.cpp b/src/app.cpp index d123b21..6bc384d 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -987,7 +987,7 @@ void App::ui_thread_main() // move the task list locally to free the queue for other threads { std::unique_lock lock(ui_task_mutex); - ui_cv.wait_for(lock, std::chrono::milliseconds(100), + ui_cv.wait_for(lock, std::chrono::milliseconds(idle_ms), [this] { return ui_tasklist.empty() && ui_running ? false : true; }); working_list = std::move(ui_tasklist); } diff --git a/src/app.h b/src/app.h index 54efe6f..a111121 100644 --- a/src/app.h +++ b/src/app.h @@ -152,6 +152,7 @@ public: glm::vec2 gesture_p1; float display_density = 1.f; float zoom = 1.f; + int idle_ms = 100; #if defined(__IOS__) && defined(__OBJC__) GameViewController* ios_view; diff --git a/src/canvas.cpp b/src/canvas.cpp index eef1954..a936aa3 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1351,6 +1351,11 @@ void Canvas::anim_goto_frame(int frame) noexcept l->goto_frame(frame); } +void Canvas::anim_goto_next() noexcept +{ + anim_goto_frame((m_anim_frame + 1) % anim_duration()); +} + void Canvas::flood_fill(int layer, int plane, std::vector pos, FloodData& plane_data, float threshold, glm::vec4 dest_color, std::unique_ptr& source_color) { diff --git a/src/canvas.h b/src/canvas.h index 2ec36b4..3695c8e 100644 --- a/src/canvas.h +++ b/src/canvas.h @@ -188,6 +188,7 @@ public: void layer_merge(int source_idx, int dest_idx); int anim_duration() const noexcept; void anim_goto_frame(int frame) noexcept; + void anim_goto_next() noexcept; void flood_fill(int layer, int plane, std::vector pos, FloodData& plane_data, float threshold, glm::vec4 dest_color, std::unique_ptr& source_color); void stroke_start(glm::vec3 point, float pressure); diff --git a/src/node_combobox.cpp b/src/node_combobox.cpp index 3c742ea..6a4b813 100644 --- a/src/node_combobox.cpp +++ b/src/node_combobox.cpp @@ -114,3 +114,8 @@ float NodeComboBox::get_float(int index) const noexcept { return std::stof(m_data[index]); } + +float NodeComboBox::get_float() const noexcept +{ + return std::stof(m_data[m_current_index]); +} diff --git a/src/node_combobox.h b/src/node_combobox.h index 731228e..60ef833 100644 --- a/src/node_combobox.h +++ b/src/node_combobox.h @@ -15,4 +15,5 @@ public: virtual void parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr) override; void set_index(int index); float get_float(int index) const noexcept; + float get_float() const noexcept; }; diff --git a/src/node_panel_animation.cpp b/src/node_panel_animation.cpp index 15eee27..4ea0235 100644 --- a/src/node_panel_animation.cpp +++ b/src/node_panel_animation.cpp @@ -34,6 +34,10 @@ void NodePanelAnimation::init_controls() btn_up = find("btn-up"); btn_down = find("btn-down"); btn_duplicate = find("btn-duplicate"); + btn_next = find("btn-next"); + btn_prev = find("btn-prev"); + btn_play = find("btn-play"); + m_fps = find("fps"); btn_add->on_click = [this](Node*) { Canvas::I->layer().add_frame(); @@ -57,6 +61,25 @@ void NodePanelAnimation::init_controls() Canvas::I->anim_goto_frame(frame); load_layers(); }; + + btn_play->on_click = [this] (Node* target) { + static auto mode = Canvas::I->m_current_mode; + auto b = static_cast(target); + if (b->is_active()) + { + Canvas::set_mode(mode); + b->set_active(false); + App::I->idle_ms = 100; + } + else + { + mode = Canvas::I->m_current_mode; + Canvas::set_mode(kCanvasMode::Camera); + m_playback_timer = 0; + b->set_active(true); + App::I->idle_ms = 10; + } + }; } void NodePanelAnimation::load_layers() @@ -102,6 +125,21 @@ void NodePanelAnimation::load_layers() m_timeline->SetWidth(max_width); } +void NodePanelAnimation::on_tick(float dt) +{ + parent::on_tick(dt); + if (btn_play->is_active()) + { + m_playback_timer += dt; + if (m_playback_timer > (1.f / m_fps->get_float())) + { + m_playback_timer = 0; + Canvas::I->anim_goto_next(); + m_timeline->m_frame = Canvas::I->m_anim_frame; + } + } +} + void NodePanelAnimation::added(Node* parent) { parent::added(parent); diff --git a/src/node_panel_animation.h b/src/node_panel_animation.h index 5c2864f..af26936 100644 --- a/src/node_panel_animation.h +++ b/src/node_panel_animation.h @@ -5,6 +5,7 @@ #include "node_text.h" #include "node_checkbox.h" #include "node_button_custom.h" +#include "node_combobox.h" class NodeAnimationFrame : public NodeButtonCustom { @@ -43,6 +44,9 @@ public: class NodePanelAnimation : public Node { + NodeButtonCustom* btn_next = nullptr; + NodeButtonCustom* btn_prev = nullptr; + NodeButtonCustom* btn_play = nullptr; NodeButtonCustom* btn_add = nullptr; NodeButtonCustom* btn_remove = nullptr; NodeButtonCustom* btn_up = nullptr; @@ -52,8 +56,10 @@ class NodePanelAnimation : public Node Node* m_frames_container = nullptr; NodeAnimationFrame* m_selected_frame = nullptr; NodeAnimationTimeline* m_timeline = nullptr; + NodeComboBox* m_fps = nullptr; int m_selected_frame_index = -1; uint32_t m_selected_frame_layer_id = 0; + float m_playback_timer = 0; public: using this_class = NodePanelAnimation; using parent = Node; @@ -62,7 +68,8 @@ public: virtual void clone_finalize(Node* dest) const override; virtual void init() override; virtual void added(Node* parent) override; - + virtual void on_tick(float dt) override; + void init_controls(); void load_layers(); };