Skip to content

Commit f4b383b

Browse files
feat(ui): implement exit animation
1 parent 49aad9a commit f4b383b

File tree

3 files changed

+85
-14
lines changed

3 files changed

+85
-14
lines changed

src/ui/widget.cc

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,33 @@
22
#include "ui.h"
33
#include <chrono>
44
#include <thread>
5+
6+
void ui::widget::update_children_basic(update_context &ctx,
7+
std::shared_ptr<widget> &w) {
8+
if (!w)
9+
return;
10+
// handle dying time
11+
if (w->dying_time.has_value() && !*w->dying_time) {
12+
w = nullptr;
13+
return;
14+
}
15+
update_context upd = ctx.with_offset(*x, *y);
16+
w->update(upd);
17+
}
18+
19+
void ui::widget::render_children_basic(nanovg_context ctx,
20+
std::shared_ptr<widget> &w) {
21+
if (!w)
22+
return;
23+
ctx.save();
24+
w->render(ctx.with_offset(*x, *y));
25+
ctx.restore();
26+
}
27+
528
void ui::widget::render(nanovg_context ctx) {
629
float orig_offset_x = ctx.offset_x, orig_offset_y = ctx.offset_y;
730
for (auto &child : children) {
8-
ctx.offset_x = *x + orig_offset_x;
9-
ctx.offset_y = *y + orig_offset_y;
10-
ctx.save();
11-
child->render(ctx);
12-
ctx.restore();
31+
render_children_basic(ctx, child);
1332
}
1433

1534
ctx.offset_x = orig_offset_x;
@@ -23,13 +42,18 @@ void ui::widget::update(update_context &ctx) {
2342
float orig_offset_x = ctx.offset_x, orig_offset_y = ctx.offset_y;
2443

2544
for (auto &child : children) {
26-
ctx.offset_x = *x + orig_offset_x;
27-
ctx.offset_y = *y + orig_offset_y;
28-
child->update(ctx);
45+
update_children_basic(ctx, child);
2946
}
3047

48+
// Remove dead children
49+
std::erase_if(children, [](auto &child) { return !child; });
50+
3151
ctx.offset_x = orig_offset_x;
3252
ctx.offset_y = orig_offset_y;
53+
54+
if (dying_time.has_value()) {
55+
*dying_time = std::max(0.f, *dying_time - ctx.delta_t);
56+
}
3357
}
3458
void ui::widget::add_child(std::shared_ptr<widget> child) {
3559
children.push_back(std::move(child));

src/ui/widget.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ struct widget : std::enable_shared_from_this<widget> {
7676
virtual ~widget() = default;
7777
virtual float measure_height(update_context &ctx);
7878
virtual float measure_width(update_context &ctx);
79+
// Update children with the offset.
80+
// Also deal with the dying time. (If the widget is died, it will be set to nullptr)
81+
void update_children_basic(update_context &ctx, std::shared_ptr<widget> &w);
82+
// Render children with the offset.
83+
void render_children_basic(nanovg_context ctx, std::shared_ptr<widget> &w);
7984

8085
template <typename T> inline auto downcast() {
8186
return std::dynamic_pointer_cast<T>(this->shared_from_this());
@@ -108,6 +113,10 @@ struct widget : std::enable_shared_from_this<widget> {
108113
}
109114
return res;
110115
}
116+
117+
// Time until the widget is removed from the tree
118+
// in milliseconds
119+
std::optional<float> dying_time;
111120
};
112121

113122
// A widget with child which lays out children in a row or column

src/ui_test/test.cc

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,12 @@ struct menu_widget : public ui::widget_flex {
183183
bg->y->reset_to(y->dest() - bg_padding_vertical);
184184
bg->update(ctx);
185185

186-
if (ctx.mouse_clicked) {
187-
std::println("Clicked on menu");
188-
auto i = items;
189-
ctx.rt.root->children.clear();
190-
ctx.rt.root->emplace_child<menu_widget>(i, ctx.mouse_x, ctx.mouse_y);
191-
}
186+
// if (ctx.mouse_clicked) {
187+
// std::println("Clicked on menu");
188+
// auto i = items;
189+
// ctx.rt.root->children.clear();
190+
// ctx.rt.root->emplace_child<menu_widget>(i, ctx.mouse_x, ctx.mouse_y);
191+
// }
192192
}
193193

194194
void render(ui::nanovg_context ctx) override {
@@ -197,6 +197,43 @@ struct menu_widget : public ui::widget_flex {
197197
}
198198
};
199199

200+
struct dying_widget_test : public ui::widget {
201+
using super = ui::widget;
202+
203+
ui::sp_anim_float opacity = anim_float(0, 200);
204+
205+
dying_widget_test() : super() {
206+
x->animate_to(100);
207+
y->animate_to(100);
208+
width->animate_to(100);
209+
height->animate_to(100);
210+
opacity->animate_to(255);
211+
}
212+
213+
void render(ui::nanovg_context ctx) override {
214+
super::render(ctx);
215+
std::println("Rendering dying widget");
216+
ctx.fillColor(nvgRGBAf(1, 0, 0, *opacity / 255.f));
217+
ctx.fillRect(*x, *y, *width, *height);
218+
}
219+
220+
221+
void update(ui::update_context &ctx) override {
222+
super::update(ctx);
223+
if (ctx.mouse_down_on(this)) {
224+
dying_time = 200;
225+
}
226+
227+
if (dying_time) {
228+
opacity->animate_to(0);
229+
} else if (ctx.hovered(this)) {
230+
opacity->animate_to(128);
231+
} else {
232+
opacity->animate_to(255);
233+
}
234+
}
235+
};
236+
200237
int main() {
201238

202239
if (auto res = ui::render_target::init_global(); !res) {
@@ -212,6 +249,7 @@ int main() {
212249
}
213250

214251
rt.root->emplace_child<menu_widget>(items, 20, 20);
252+
rt.root->emplace_child<dying_widget_test>();
215253

216254
nvgCreateFont(rt.nvg, "Yahei", "C:\\WINDOWS\\FONTS\\msyh.ttc");
217255

0 commit comments

Comments
 (0)