yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
animator.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cmath>
5
7#include "imgui/imgui.h"
8
9namespace yaze {
10namespace gui {
11
12float Animator::Lerp(float a, float b, float t) {
13 return a + (b - a) * t;
14}
15
16float Animator::EaseOutCubic(float t) {
17 float inv = 1.0f - t;
18 return 1.0f - (inv * inv * inv);
19}
20
22 return t < 0.5f ? 4.0f * t * t * t
23 : 1.0f - std::pow(-2.0f * t + 2.0f, 3.0f) / 2.0f;
24}
25
27 const float c4 = (2.0f * 3.14159265f) / 3.0f;
28 if (t <= 0.0f) return 0.0f;
29 if (t >= 1.0f) return 1.0f;
30 return std::pow(2.0f, -10.0f * t) * std::sin((t * 10.0f - 0.75f) * c4) + 1.0f;
31}
32
33float Animator::EaseOutBack(float t) {
34 const float c1 = 1.70158f;
35 const float c3 = c1 + 1.0f;
36 float tm1 = t - 1.0f;
37 return 1.0f + c3 * tm1 * tm1 * tm1 + c1 * tm1 * tm1;
38}
39
40ImVec4 Animator::LerpColor(ImVec4 a, ImVec4 b, float t) {
41 return ImVec4(Lerp(a.x, b.x, t), Lerp(a.y, b.y, t), Lerp(a.z, b.z, t),
42 Lerp(a.w, b.w, t));
43}
44
45float Animator::Animate(const std::string& panel_id,
46 const std::string& anim_id, float target,
47 float speed) {
48 auto& state = GetState(panel_id, anim_id);
49 if (!state.has_value) {
50 state.value = target;
51 state.has_value = true;
52 }
53
54 if (!IsEnabled()) {
55 state.value = target;
56 return target;
57 }
58
59 float t = ComputeStep(speed);
60 state.value = Lerp(state.value, target, t);
61 return state.value;
62}
63
64ImVec4 Animator::AnimateColor(const std::string& panel_id,
65 const std::string& anim_id, ImVec4 target,
66 float speed) {
67 auto& state = GetState(panel_id, anim_id);
68 if (!state.has_color) {
69 state.color = target;
70 state.has_color = true;
71 }
72
73 if (!IsEnabled()) {
74 state.color = target;
75 return target;
76 }
77
78 float t = ComputeStep(speed);
79 state.color = LerpColor(state.color, target, t);
80 return state.color;
81}
82
83void Animator::ClearAnimationsForPanel(const std::string& panel_id) {
84 panels_.erase(panel_id);
85 panel_transitions_.erase(panel_id);
86 pushed_transition_alpha_.erase(panel_id);
87}
88
90 panel_transitions_.clear();
92
93 for (auto panel_it = panels_.begin(); panel_it != panels_.end();) {
94 panel_it->second.erase("panel_alpha");
95 panel_it->second.erase("category_transition");
96 if (panel_it->second.empty()) {
97 panel_it = panels_.erase(panel_it);
98 } else {
99 ++panel_it;
100 }
101 }
102}
103
105 panels_.clear();
106 panel_transitions_.clear();
108}
109
111 if (raw_profile <= static_cast<int>(MotionProfile::kSnappy)) {
113 }
114 if (raw_profile >= static_cast<int>(MotionProfile::kRelaxed)) {
116 }
118}
119
120void Animator::SetMotionPreferences(bool reduced_motion,
121 MotionProfile profile) {
123 motion_profile_ = profile;
124}
125
126void Animator::BeginPanelTransition(const std::string& panel_id,
127 TransitionType type) {
128 if (!IsEnabled() || type == TransitionType::kNone) {
129 return;
130 }
131
132 auto& state = panel_transitions_[panel_id];
133 state.type = type;
134 state.progress = 0.0f;
135 state.active = true;
136
137 // Set initial offsets based on transition type
138 switch (type) {
140 state.initial_offset_x = -50.0f;
141 state.initial_offset_y = 0.0f;
142 break;
144 state.initial_offset_x = 50.0f;
145 state.initial_offset_y = 0.0f;
146 break;
148 state.initial_offset_x = 0.0f;
149 state.initial_offset_y = 50.0f;
150 break;
152 state.initial_offset_x = 0.0f;
153 state.initial_offset_y = -50.0f;
154 break;
155 default:
156 state.initial_offset_x = 0.0f;
157 state.initial_offset_y = 0.0f;
158 break;
159 }
160}
161
163 const std::string& panel_id, float speed) {
164 PanelTransition result;
165
166 if (!IsEnabled()) {
167 return result; // Return default (fully visible, no offset)
168 }
169
170 auto iter = panel_transitions_.find(panel_id);
171 if (iter == panel_transitions_.end() || !iter->second.active) {
172 return result; // No active transition
173 }
174
175 auto& state = iter->second;
176
177 // Update progress
178 float step = ComputeStep(speed);
179 state.progress = std::min(state.progress + step, 1.0f);
180
181 // Apply profile-specific easing for editor/workspace transitions.
182 float eased = ApplyTransitionEasing(state.progress);
183
184 // Calculate current values based on transition type
185 switch (state.type) {
187 result.alpha = eased;
188 break;
189
194 result.alpha = eased;
195 result.offset_x = state.initial_offset_x * (1.0f - eased);
196 result.offset_y = state.initial_offset_y * (1.0f - eased);
197 break;
198
200 result.alpha = eased;
201 result.scale = 0.8f + (0.2f * eased); // Scale from 0.8 to 1.0
202 break;
203
205 result.alpha = eased;
206 result.scale = eased; // Scale from 0 to 1
207 break;
208
210 default:
211 break;
212 }
213
214 // Mark as complete when done
215 if (state.progress >= 1.0f) {
216 state.active = false;
217 result.is_complete = true;
218 } else {
219 result.is_complete = false;
220 }
221
222 return result;
223}
224
225bool Animator::IsPanelTransitioning(const std::string& panel_id) const {
226 auto iter = panel_transitions_.find(panel_id);
227 return iter != panel_transitions_.end() && iter->second.active;
228}
229
230void Animator::ApplyPanelTransitionPre(const std::string& panel_id) {
231 auto iter = panel_transitions_.find(panel_id);
232 if (iter == panel_transitions_.end() || !iter->second.active) {
233 return;
234 }
235
236 auto transition = UpdatePanelTransition(panel_id);
237 if (transition.is_complete) {
238 return;
239 }
240
241 // Set window position offset for slide transitions
242 if (transition.offset_x != 0.0f || transition.offset_y != 0.0f) {
243 ImVec2 window_pos = ImGui::GetCursorScreenPos();
244 ImGui::SetNextWindowPos(
245 ImVec2(window_pos.x + transition.offset_x,
246 window_pos.y + transition.offset_y),
247 ImGuiCond_Always);
248 }
249
250 // Multiply with any alpha already applied this frame so workspace fade
251 // transitions compose with panel-alpha fades instead of overwriting them.
252 ImGui::PushStyleVar(ImGuiStyleVar_Alpha,
253 ImGui::GetStyle().Alpha * transition.alpha);
254 pushed_transition_alpha_.insert(panel_id);
255}
256
257void Animator::ApplyPanelTransitionPost(const std::string& panel_id) {
258 // Pop only when pre-pass pushed this frame.
259 if (pushed_transition_alpha_.erase(panel_id) > 0) {
260 ImGui::PopStyleVar();
261 }
262}
263
265 if (ImGui::GetCurrentContext() == nullptr) {
266 return false;
267 }
268 if (reduced_motion_) {
269 return false;
270 }
271 const auto& theme = ThemeManager::Get().GetCurrentTheme();
272 return theme.enable_animations;
273}
274
275Animator::AnimationState& Animator::GetState(const std::string& panel_id,
276 const std::string& anim_id) {
277 return panels_[panel_id][anim_id];
278}
279
280float Animator::ComputeStep(float speed) const {
281 if (ImGui::GetCurrentContext() == nullptr) {
282 return 1.0f;
283 }
284
285 const auto& theme = ThemeManager::Get().GetCurrentTheme();
286 const float scaled_speed =
288 const float delta = ImGui::GetIO().DeltaTime;
289 const float t = 1.0f - std::exp(-scaled_speed * delta);
290 return std::clamp(t, 0.0f, 1.0f);
291}
292
294 switch (motion_profile_) {
296 return 1.35f;
298 return 0.72f;
300 default:
301 return 1.0f;
302 }
303}
304
306 t = std::clamp(t, 0.0f, 1.0f);
307 switch (motion_profile_) {
309 return EaseOutCubic(t);
311 return t * t * (3.0f - 2.0f * t); // Smoothstep
313 default:
314 return EaseInOutCubic(t);
315 }
316}
317
319 static Animator animator;
320 return animator;
321}
322
323} // namespace gui
324} // namespace yaze
static float EaseOutBack(float t)
Definition animator.cc:33
void ClearAnimationsForPanel(const std::string &panel_id)
Definition animator.cc:83
bool IsPanelTransitioning(const std::string &panel_id) const
Definition animator.cc:225
static MotionProfile ClampMotionProfile(int raw_profile)
Definition animator.cc:110
float ComputeStep(float speed) const
Definition animator.cc:280
PanelTransition UpdatePanelTransition(const std::string &panel_id, float speed=8.0f)
Definition animator.cc:162
static float EaseInOutCubic(float t)
Definition animator.cc:21
void SetMotionPreferences(bool reduced_motion, MotionProfile profile)
Definition animator.cc:120
void ApplyPanelTransitionPre(const std::string &panel_id)
Definition animator.cc:230
AnimationState & GetState(const std::string &panel_id, const std::string &anim_id)
Definition animator.cc:275
float ApplyTransitionEasing(float t) const
Definition animator.cc:305
static float Lerp(float a, float b, float t)
Definition animator.cc:12
ImVec4 AnimateColor(const std::string &panel_id, const std::string &anim_id, ImVec4 target, float speed=5.0f)
Definition animator.cc:64
bool reduced_motion() const
Definition animator.h:78
static float EaseOutElastic(float t)
Definition animator.cc:26
static ImVec4 LerpColor(ImVec4 a, ImVec4 b, float t)
Definition animator.cc:40
std::unordered_set< std::string > pushed_transition_alpha_
Definition animator.h:109
float Animate(const std::string &panel_id, const std::string &anim_id, float target, float speed=5.0f)
Definition animator.cc:45
MotionProfile motion_profile_
Definition animator.h:112
float GetProfileSpeedMultiplier() const
Definition animator.cc:293
std::unordered_map< std::string, AnimationMap > panels_
Definition animator.h:107
void ClearWorkspaceTransitionState()
Definition animator.cc:89
void ApplyPanelTransitionPost(const std::string &panel_id)
Definition animator.cc:257
bool IsEnabled() const
Definition animator.cc:264
void BeginPanelTransition(const std::string &panel_id, TransitionType type)
Definition animator.cc:126
void ClearAllAnimations()
Definition animator.cc:104
static float EaseOutCubic(float t)
Definition animator.cc:16
std::unordered_map< std::string, PanelTransitionState > panel_transitions_
Definition animator.h:108
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
Animator & GetAnimator()
Definition animator.cc:318