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();
};