From 150733eb7cbcc732347dd40688e40ca089ff36db Mon Sep 17 00:00:00 2001 From: Albert Slepak Date: Sun, 30 Aug 2020 12:18:44 -0400 Subject: [PATCH 1/7] UITextArea will update its label's text only when it changes --- src/ui/elements/UITextArea.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ui/elements/UITextArea.cpp b/src/ui/elements/UITextArea.cpp index e2991fe5..a1611046 100644 --- a/src/ui/elements/UITextArea.cpp +++ b/src/ui/elements/UITextArea.cpp @@ -57,7 +57,6 @@ namespace mc m_TextSource->layer.frame.position.y = TopMargins; m_TextSource->layer.frame.size.width = layer.frame.size.width - (RightMargins + LeftMargins); m_TextSource->color = TextColor; - m_TextSource->Text = Text; m_TextSource->Properties = Properties; if (Text != m_PreviousText) @@ -68,6 +67,8 @@ namespace mc void UITextArea::OnTextChanged() { + m_TextSource->Text = Text; + auto text_metrics = Graphics::CalculateTextMetrics( Text, Properties, From 0464858104e6a429e8f344b85a5c055c64f9f9b0 Mon Sep 17 00:00:00 2001 From: Albert Slepak Date: Sun, 30 Aug 2020 21:22:25 -0400 Subject: [PATCH 2/7] added a UITimer class --- src/Monochrome.h | 1 + src/ui/CMakeLists.txt | 2 ++ src/ui/UITimer.cpp | 42 +++++++++++++++++++++++++++++++++++++++ src/ui/UITimer.h | 33 ++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 3 +++ tests/animations_test.cpp | 20 +++++++++++++++++++ 6 files changed, 101 insertions(+) create mode 100644 src/ui/UITimer.cpp create mode 100644 src/ui/UITimer.h create mode 100644 tests/animations_test.cpp diff --git a/src/Monochrome.h b/src/Monochrome.h index c518db44..dd17fb85 100644 --- a/src/Monochrome.h +++ b/src/Monochrome.h @@ -2,4 +2,5 @@ #include "window/UIWindow.h" #include "ui/UIElements.h" #include "ui/UIFileDialogue.h" +#include "ui/UITimer.h" #include "events/Events.h" \ No newline at end of file diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 4a144c86..79c0ca26 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -13,6 +13,7 @@ set( src/ui/UIView.h src/ui/UIFileDialogue.h src/ui/UICursor.h + src/ui/UITimer.h PARENT_SCOPE ) @@ -24,6 +25,7 @@ set( src/ui/UIView.cpp src/ui/UIFileDialogue.cpp src/ui/UICursor.cpp + src/ui/UITimer.cpp PARENT_SCOPE ) diff --git a/src/ui/UITimer.cpp b/src/ui/UITimer.cpp new file mode 100644 index 00000000..4bf9e949 --- /dev/null +++ b/src/ui/UITimer.cpp @@ -0,0 +1,42 @@ +#include "UITimer.h" + +namespace mc +{ + UITimer::UITimer(OnTickCallback_t fn) + : m_OnTickCallback(fn) + { + } + + void UITimer::Start(uint32_t intervals) + { + std::thread timer_thread([this, intervals]() { + m_Running = true; + uint32_t tick = 0; + while (m_Running) + { + std::this_thread::sleep_for(std::chrono::milliseconds(intervals)); + tick++; + + if (m_OnTickCallback) + m_OnTickCallback(tick, this); + } + }); + timer_thread.detach(); + } + + void UITimer::Schedule(uint32_t wait_time, uint32_t intervals) + { + std::this_thread::sleep_for(std::chrono::milliseconds(wait_time)); + Start(intervals); + } + + void UITimer::Stop() + { + m_Running = false; + } + + void UITimer::SetOnTickFunction(OnTickCallback_t fn) + { + m_OnTickCallback = fn; + } +} diff --git a/src/ui/UITimer.h b/src/ui/UITimer.h new file mode 100644 index 00000000..4df203ec --- /dev/null +++ b/src/ui/UITimer.h @@ -0,0 +1,33 @@ +#pragma once +#include +#include + +namespace mc +{ + class UITimer + { + public: + using OnTickCallback_t = std::function; + + public: + UITimer() = default; + UITimer(OnTickCallback_t fn); + ~UITimer() = default; + + /// Starts the timer that will call its on-tick callback once per specified interval. + void Start(uint32_t intervals); + + /// Waits for the specified wait_time and starts the timer. + void Schedule(uint32_t wait_time, uint32_t intervals); + + /// Stops the timer's loop and exits out of its thread. + void Stop(); + + /// Specified the callback function to call on every tick. + void SetOnTickFunction(OnTickCallback_t fn); + + private: + bool m_Running = false; + OnTickCallback_t m_OnTickCallback = nullptr; + }; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5b9737f1..01873dfe 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,3 +26,6 @@ target_link_libraries(FileChooserTest PUBLIC Monochrome) add_executable(MultipleWindowsTest multiple_windows_test.cpp) target_link_libraries(MultipleWindowsTest PUBLIC Monochrome) + +add_executable(AnimationsTest animations_test.cpp) +target_link_libraries(AnimationsTest PUBLIC Monochrome) diff --git a/tests/animations_test.cpp b/tests/animations_test.cpp new file mode 100644 index 00000000..ef576199 --- /dev/null +++ b/tests/animations_test.cpp @@ -0,0 +1,20 @@ +#include +using namespace mc; + +int main() +{ + auto window = UIWindow::Create(WindowStyle::Modern, 400, 660, "Animations Test"); + window->SetBackgroundColor(Color(6, 47, 103, 1)); + window->SetModernWindowButtonsColor(Color(6, 47, 103, 1)); + + UITimer timer([](uint32_t tick, UITimer* timer) { + printf("Tick: %u\n", tick); + if (tick == 10) + timer->Stop(); + }); + + timer.Start(500); + + window->StartWindowLoop(); + return 0; +} From 043a3924a2c7a5cf599d420a742631350303109a Mon Sep 17 00:00:00 2001 From: Albert Slepak Date: Mon, 31 Aug 2020 17:59:07 -0400 Subject: [PATCH 3/7] added a UITimer and an animation system --- src/Monochrome.h | 1 + src/ui/CMakeLists.txt | 4 ++ src/ui/UITimer.cpp | 7 ++- src/ui/UITimer.h | 4 ++ src/ui/animations/Animation.cpp | 64 ++++++++++++++++++++ src/ui/animations/Animation.h | 39 ++++++++++++ src/ui/animations/Animations.h | 5 ++ src/ui/animations/CMakeLists.txt | 26 ++++++++ src/ui/animations/FadeInAnimation.cpp | 39 ++++++++++++ src/ui/animations/FadeInAnimation.h | 26 ++++++++ src/ui/animations/FadeOutAnimation.cpp | 39 ++++++++++++ src/ui/animations/FadeOutAnimation.h | 26 ++++++++ src/ui/animations/ScaleAnimation.cpp | 40 +++++++++++++ src/ui/animations/ScaleAnimation.h | 29 +++++++++ src/ui/animations/TranslationAnimation.cpp | 39 ++++++++++++ src/ui/animations/TranslationAnimation.h | 29 +++++++++ src/ui/elements/UICircularProgressBar.cpp | 2 + src/ui/elements/UILabel.cpp | 3 +- src/ui/elements/UIProgressBar.cpp | 2 + tests/animations_test.cpp | 69 +++++++++++++++++++--- 20 files changed, 482 insertions(+), 11 deletions(-) create mode 100644 src/ui/animations/Animation.cpp create mode 100644 src/ui/animations/Animation.h create mode 100644 src/ui/animations/Animations.h create mode 100644 src/ui/animations/CMakeLists.txt create mode 100644 src/ui/animations/FadeInAnimation.cpp create mode 100644 src/ui/animations/FadeInAnimation.h create mode 100644 src/ui/animations/FadeOutAnimation.cpp create mode 100644 src/ui/animations/FadeOutAnimation.h create mode 100644 src/ui/animations/ScaleAnimation.cpp create mode 100644 src/ui/animations/ScaleAnimation.h create mode 100644 src/ui/animations/TranslationAnimation.cpp create mode 100644 src/ui/animations/TranslationAnimation.h diff --git a/src/Monochrome.h b/src/Monochrome.h index dd17fb85..214c38b3 100644 --- a/src/Monochrome.h +++ b/src/Monochrome.h @@ -3,4 +3,5 @@ #include "ui/UIElements.h" #include "ui/UIFileDialogue.h" #include "ui/UITimer.h" +#include "ui/animations/Animations.h" #include "events/Events.h" \ No newline at end of file diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 79c0ca26..bb5fc08c 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -1,11 +1,13 @@ cmake_minimum_required(VERSION 3.0) add_subdirectory(elements) +add_subdirectory(animations) set( MC_UI_HEADERS ${MC_UIELEMENTS_HEADERS} + ${MC_ANIMATIONS_HEADERS} src/ui/IDrawable.h src/ui/Layer.h @@ -22,6 +24,8 @@ set( MC_UI_SOURCES ${MC_UIELEMENTS_SOURCES} + ${MC_ANIMATIONS_SOURCES} + src/ui/UIView.cpp src/ui/UIFileDialogue.cpp src/ui/UICursor.cpp diff --git a/src/ui/UITimer.cpp b/src/ui/UITimer.cpp index 4bf9e949..a18f9e0b 100644 --- a/src/ui/UITimer.cpp +++ b/src/ui/UITimer.cpp @@ -26,8 +26,11 @@ namespace mc void UITimer::Schedule(uint32_t wait_time, uint32_t intervals) { - std::this_thread::sleep_for(std::chrono::milliseconds(wait_time)); - Start(intervals); + std::thread scheduler_thread([this, wait_time, intervals]() { + std::this_thread::sleep_for(std::chrono::milliseconds(wait_time)); + Start(intervals); + }); + scheduler_thread.detach(); } void UITimer::Stop() diff --git a/src/ui/UITimer.h b/src/ui/UITimer.h index 4df203ec..b0a1e833 100644 --- a/src/ui/UITimer.h +++ b/src/ui/UITimer.h @@ -15,15 +15,19 @@ namespace mc ~UITimer() = default; /// Starts the timer that will call its on-tick callback once per specified interval. + /// All time parameters are measured in miliseconds. void Start(uint32_t intervals); /// Waits for the specified wait_time and starts the timer. + /// All time parameters are measured in miliseconds. void Schedule(uint32_t wait_time, uint32_t intervals); /// Stops the timer's loop and exits out of its thread. + /// All time parameters are measured in miliseconds. void Stop(); /// Specified the callback function to call on every tick. + /// All time parameters are measured in miliseconds. void SetOnTickFunction(OnTickCallback_t fn); private: diff --git a/src/ui/animations/Animation.cpp b/src/ui/animations/Animation.cpp new file mode 100644 index 00000000..21244b40 --- /dev/null +++ b/src/ui/animations/Animation.cpp @@ -0,0 +1,64 @@ +#include "Animation.h" +#include "Animations.h" + +#include +#include + +namespace mc +{ + std::vector> s_RunningAnimations; + std::mutex s_AnimationManagementMutex; + + void Animation::DestroyAnimation(Animation* animation) + { + s_AnimationManagementMutex.lock(); + + for (auto it = s_RunningAnimations.begin(); it != s_RunningAnimations.end(); it++) + { + if (it->get() == animation) + { + s_RunningAnimations.erase(it); + break; + } + } + + s_AnimationManagementMutex.unlock(); + } + + Ref Animation::Create(AnimationType type, UIView* target) + { + Ref instance = nullptr; + switch (type) + { + case AnimationType::FadeOut: + { + instance = MakeRef(); + break; + } + case AnimationType::FadeIn: + { + instance = MakeRef(); + break; + } + case AnimationType::Translation: + { + instance = MakeRef(); + break; + } + case AnimationType::Scale: + { + instance = MakeRef(); + break; + } + default: break; + } + + if (instance) + { + instance->Target = target; + s_RunningAnimations.push_back(instance); + } + + return instance; + } +} diff --git a/src/ui/animations/Animation.h b/src/ui/animations/Animation.h new file mode 100644 index 00000000..519e19f0 --- /dev/null +++ b/src/ui/animations/Animation.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include + +namespace mc +{ + enum class AnimationType + { + FadeOut, + FadeIn, + Translation, + Scale + }; + +#define ANIMATION_INSTANCE_CONSTRUCTOR \ + m_Timer.SetOnTickFunction([this](uint32_t tick, UITimer* timer) { OnTick(tick, timer); }); + +#define AnimCast(type, anim) std::dynamic_pointer_cast(anim) + + class Animation + { + public: + static Ref Create(AnimationType type, UIView* target); + virtual ~Animation() = default; + + virtual void Animate( + uint32_t duration, + std::function completion_handler = nullptr + ) = 0; + + protected: + UITimer m_Timer; + virtual void OnTick(uint32_t tick, UITimer* timer) = 0; + + protected: + UIView* Target = nullptr; + void DestroyAnimation(Animation* animation); + }; +} diff --git a/src/ui/animations/Animations.h b/src/ui/animations/Animations.h new file mode 100644 index 00000000..cbccefc0 --- /dev/null +++ b/src/ui/animations/Animations.h @@ -0,0 +1,5 @@ +#pragma once +#include "FadeOutAnimation.h" +#include "FadeInAnimation.h" +#include "TranslationAnimation.h" +#include "ScaleAnimation.h" diff --git a/src/ui/animations/CMakeLists.txt b/src/ui/animations/CMakeLists.txt new file mode 100644 index 00000000..ac28ab4f --- /dev/null +++ b/src/ui/animations/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.0) + +set( + MC_ANIMATIONS_HEADERS + + src/ui/animations/Animations.h + src/ui/animations/Animation.h + src/ui/animations/FadeOutAnimation.h + src/ui/animations/FadeInAnimation.h + src/ui/animations/TranslationAnimation.h + src/ui/animations/ScaleAnimation.h + + PARENT_SCOPE +) + +set( + MC_ANIMATIONS_SOURCES + + src/ui/animations/Animation.cpp + src/ui/animations/FadeOutAnimation.cpp + src/ui/animations/FadeInAnimation.cpp + src/ui/animations/TranslationAnimation.cpp + src/ui/animations/ScaleAnimation.cpp + + PARENT_SCOPE +) diff --git a/src/ui/animations/FadeInAnimation.cpp b/src/ui/animations/FadeInAnimation.cpp new file mode 100644 index 00000000..0442747d --- /dev/null +++ b/src/ui/animations/FadeInAnimation.cpp @@ -0,0 +1,39 @@ +#include "FadeInAnimation.h" + +namespace mc +{ + FadeInAnimation::FadeInAnimation() + { + ANIMATION_INSTANCE_CONSTRUCTOR + } + + void FadeInAnimation::Animate( + uint32_t duration, + std::function completion_handler + ) + { + if (m_Started) return; + m_Started = true; + + m_FadeStep = (m_TargetAlpha - Target->layer.color.alpha) / (float)duration; + Target->Visible = true; + + m_CompletionHandler = completion_handler; + m_Timer.Start(1); + } + + void FadeInAnimation::OnTick(uint32_t tick, UITimer* timer) + { + Target->layer.color.alpha += m_FadeStep; + + if (Target->layer.color.alpha >= m_TargetAlpha) + { + m_Timer.Stop(); + Target->layer.color.alpha = m_TargetAlpha; + if (m_CompletionHandler) + m_CompletionHandler(); + + DestroyAnimation(this); + } + } +} diff --git a/src/ui/animations/FadeInAnimation.h b/src/ui/animations/FadeInAnimation.h new file mode 100644 index 00000000..ece07a77 --- /dev/null +++ b/src/ui/animations/FadeInAnimation.h @@ -0,0 +1,26 @@ +#pragma once +#include "Animation.h" + +namespace mc +{ + class FadeInAnimation : public Animation + { + public: + FadeInAnimation(); + + void Animate( + uint32_t duration, + std::function completion_handler = nullptr + ) override; + + private: + std::function m_CompletionHandler = nullptr; + + bool m_Started = false; + void OnTick(uint32_t tick, UITimer* timer) override; + + private: + float m_TargetAlpha = 1.0f; + float m_FadeStep = 0.0f; + }; +} diff --git a/src/ui/animations/FadeOutAnimation.cpp b/src/ui/animations/FadeOutAnimation.cpp new file mode 100644 index 00000000..f4e825e5 --- /dev/null +++ b/src/ui/animations/FadeOutAnimation.cpp @@ -0,0 +1,39 @@ +#include "FadeOutAnimation.h" + +namespace mc +{ + FadeOutAnimation::FadeOutAnimation() + { + ANIMATION_INSTANCE_CONSTRUCTOR + } + + void FadeOutAnimation::Animate( + uint32_t duration, + std::function completion_handler + ) + { + if (m_Started) return; + m_Started = true; + + m_FadeStep = (Target->layer.color.alpha - m_TargetAlpha) / (float)duration; + + m_CompletionHandler = completion_handler; + m_Timer.Start(1); + } + + void FadeOutAnimation::OnTick(uint32_t tick, UITimer* timer) + { + Target->layer.color.alpha -= m_FadeStep; + + if (Target->layer.color.alpha <= m_TargetAlpha) + { + m_Timer.Stop(); + Target->layer.color.alpha = m_TargetAlpha; + Target->Visible = false; + if (m_CompletionHandler) + m_CompletionHandler(); + + DestroyAnimation(this); + } + } +} diff --git a/src/ui/animations/FadeOutAnimation.h b/src/ui/animations/FadeOutAnimation.h new file mode 100644 index 00000000..a321aac3 --- /dev/null +++ b/src/ui/animations/FadeOutAnimation.h @@ -0,0 +1,26 @@ +#pragma once +#include "Animation.h" + +namespace mc +{ + class FadeOutAnimation : public Animation + { + public: + FadeOutAnimation(); + + void Animate( + uint32_t duration, + std::function completion_handler = nullptr + ) override; + + private: + std::function m_CompletionHandler = nullptr; + + bool m_Started = false; + void OnTick(uint32_t tick, UITimer* timer) override; + + private: + float m_TargetAlpha = 0.0f; + float m_FadeStep = 0.0f; + }; +} diff --git a/src/ui/animations/ScaleAnimation.cpp b/src/ui/animations/ScaleAnimation.cpp new file mode 100644 index 00000000..73698907 --- /dev/null +++ b/src/ui/animations/ScaleAnimation.cpp @@ -0,0 +1,40 @@ +#include "ScaleAnimation.h" + +namespace mc +{ + ScaleAnimation::ScaleAnimation() + { + ANIMATION_INSTANCE_CONSTRUCTOR + } + + void ScaleAnimation::Animate( + uint32_t duration, + std::function completion_handler + ) + { + if (m_Started) return; + m_Started = true; + + m_ScaleStep.width = (m_TargetSize.width - Target->layer.frame.size.width) / (float)duration; + m_ScaleStep.height = (m_TargetSize.height - Target->layer.frame.size.height) / (float)duration; + + m_CompletionHandler = completion_handler; + m_Duration = duration; + m_Timer.Start(1); + } + + void ScaleAnimation::OnTick(uint32_t tick, UITimer* timer) + { + Target->layer.frame.size += m_ScaleStep; + + if (tick >= m_Duration) + { + m_Timer.Stop(); + if (m_CompletionHandler) + m_CompletionHandler(); + + DestroyAnimation(this); + } + } +} + diff --git a/src/ui/animations/ScaleAnimation.h b/src/ui/animations/ScaleAnimation.h new file mode 100644 index 00000000..5d21e899 --- /dev/null +++ b/src/ui/animations/ScaleAnimation.h @@ -0,0 +1,29 @@ +#pragma once +#include "Animation.h" + +namespace mc +{ + class ScaleAnimation : public Animation + { + public: + ScaleAnimation(); + + void SetTargetSize(Size size) { m_TargetSize = size; } + + void Animate( + uint32_t duration, + std::function completion_handler = nullptr + ) override; + + private: + std::function m_CompletionHandler = nullptr; + + bool m_Started = false; + void OnTick(uint32_t tick, UITimer* timer) override; + + private: + float m_Duration = 0.0f; + Size m_TargetSize = { 0.0f, 0.0f }; + Size m_ScaleStep = { 0.0f, 0.0f }; + }; +} \ No newline at end of file diff --git a/src/ui/animations/TranslationAnimation.cpp b/src/ui/animations/TranslationAnimation.cpp new file mode 100644 index 00000000..efa2cc0d --- /dev/null +++ b/src/ui/animations/TranslationAnimation.cpp @@ -0,0 +1,39 @@ +#include "TranslationAnimation.h" + +namespace mc +{ + TranslationAnimation::TranslationAnimation() + { + ANIMATION_INSTANCE_CONSTRUCTOR + } + + void TranslationAnimation::Animate( + uint32_t duration, + std::function completion_handler + ) + { + if (m_Started) return; + m_Started = true; + + m_MovementStep.x = m_TargetDistance.x / (float)duration; + m_MovementStep.y = m_TargetDistance.y / (float)duration; + + m_CompletionHandler = completion_handler; + m_Duration = duration; + m_Timer.Start(1); + } + + void TranslationAnimation::OnTick(uint32_t tick, UITimer* timer) + { + Target->layer.frame.position += m_MovementStep; + + if (tick >= m_Duration) + { + m_Timer.Stop(); + if (m_CompletionHandler) + m_CompletionHandler(); + + DestroyAnimation(this); + } + } +} diff --git a/src/ui/animations/TranslationAnimation.h b/src/ui/animations/TranslationAnimation.h new file mode 100644 index 00000000..73465a60 --- /dev/null +++ b/src/ui/animations/TranslationAnimation.h @@ -0,0 +1,29 @@ +#pragma once +#include "Animation.h" + +namespace mc +{ + class TranslationAnimation : public Animation + { + public: + TranslationAnimation(); + + void SetTargetTranslation(Size distance) { m_TargetDistance = distance; } + + void Animate( + uint32_t duration, + std::function completion_handler = nullptr + ) override; + + private: + std::function m_CompletionHandler = nullptr; + + bool m_Started = false; + void OnTick(uint32_t tick, UITimer* timer) override; + + private: + float m_Duration = 0.0f; + Size m_TargetDistance = { 0.0f, 0.0f }; + Size m_MovementStep = { 0.0f, 0.0f }; + }; +} \ No newline at end of file diff --git a/src/ui/elements/UICircularProgressBar.cpp b/src/ui/elements/UICircularProgressBar.cpp index 83ad20da..98167658 100644 --- a/src/ui/elements/UICircularProgressBar.cpp +++ b/src/ui/elements/UICircularProgressBar.cpp @@ -54,6 +54,8 @@ namespace mc void UICircularProgressBar::Update() { + ProgressColor.alpha = layer.color.alpha; + if (Value != m_PreviousValue) for (auto& cb : m_ValueChangedCallbacks) cb(Value, this); diff --git a/src/ui/elements/UILabel.cpp b/src/ui/elements/UILabel.cpp index 68099fac..9488af89 100644 --- a/src/ui/elements/UILabel.cpp +++ b/src/ui/elements/UILabel.cpp @@ -11,8 +11,7 @@ namespace mc void UILabel::Draw() { // Adjusting text color opacity according to frame's color opacity - if (color.alpha > layer.color.alpha) - color.alpha = layer.color.alpha; + color.alpha = layer.color.alpha; if (UseWidestringText) Graphics::DrawTextWideString(layer.frame.position.x, layer.frame.position.y, layer.frame.size.width, layer.frame.size.height, WidestringText, Properties, color); diff --git a/src/ui/elements/UIProgressBar.cpp b/src/ui/elements/UIProgressBar.cpp index a49dab95..62cf7bd5 100644 --- a/src/ui/elements/UIProgressBar.cpp +++ b/src/ui/elements/UIProgressBar.cpp @@ -54,6 +54,8 @@ namespace mc void UIProgressBar::Update() { + ProgressColor.alpha = layer.color.alpha; + if (Value != m_PreviousValue) for (auto& cb : m_ValueChangedCallbacks) cb(Value, this); diff --git a/tests/animations_test.cpp b/tests/animations_test.cpp index ef576199..c853ede5 100644 --- a/tests/animations_test.cpp +++ b/tests/animations_test.cpp @@ -1,19 +1,74 @@ #include using namespace mc; +Ref cpb; +Ref label; + +void ProgressBar_ValueChanged(float value, UICircularProgressBar* sender) +{ + if (value == 100.0f) + { + auto fadeout = Animation::Create(AnimationType::FadeOut, sender); + fadeout->Animate(100, []() { + auto label_fadein = Animation::Create(AnimationType::FadeIn, label.get()); + label_fadein->Animate(1200); + }); + } +} + +bool StartAnimBtn_OnClick(Event& event, UIView* sender) +{ + auto translate_down = Animation::Create(AnimationType::Translation, sender); + AnimCast(TranslationAnimation, translate_down)->SetTargetTranslation({ 0, 320 }); + translate_down->Animate(900, [sender]() { + auto fadeout = Animation::Create(AnimationType::FadeOut, sender); + fadeout->Animate(200); + + auto scaleup = Animation::Create(AnimationType::Scale, cpb.get()); + AnimCast(ScaleAnimation, scaleup)->SetTargetSize({ 100.0f, 100.0f }); + scaleup->Animate(200, []() { + std::thread progressbar_thread([]() { + while (cpb->Value < 100.0f) + { + cpb->Value++; + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + } + }); + progressbar_thread.detach(); + }); + }); + + return EVENT_HANDLED; +} + int main() { auto window = UIWindow::Create(WindowStyle::Modern, 400, 660, "Animations Test"); window->SetBackgroundColor(Color(6, 47, 103, 1)); - window->SetModernWindowButtonsColor(Color(6, 47, 103, 1)); + window->SetModernWindowButtonsColor(Color(46, 147, 203, 1)); - UITimer timer([](uint32_t tick, UITimer* timer) { - printf("Tick: %u\n", tick); - if (tick == 10) - timer->Stop(); - }); + auto button = MakeRef(Frame(120, 200, 160, 50)); + button->layer.color = Color(16, 27, 63, 1.0f); + button->Label->Text = "Start"; + button->Label->color = Color::white; + button->AddEventHandler(StartAnimBtn_OnClick); + window->AddView(button); - timer.Start(500); + cpb = MakeRef(Frame(150, 200, 0, 0)); + cpb->layer.color = Color(16, 17, 13, 1.0f); + cpb->ProgressColor = Color::green; + cpb->Stroke = 6.0f; + cpb->Value = 0; + cpb->AddValueChangedEventHandler(ProgressBar_ValueChanged); + window->AddView(cpb); + + label = MakeRef(Frame(100, 200, 200, 50)); + label->color = Color::white; + label->layer.color.alpha = 0.0f; + label->Visible = false; + label->Properties.FontSize = 20.0f; + label->Text = "Animation Finished"; + window->AddView(label); window->StartWindowLoop(); return 0; From fb661184b87428ed1991dc1d9fa34af4d6180fe8 Mon Sep 17 00:00:00 2001 From: Albert Slepak Date: Mon, 31 Aug 2020 19:05:48 -0400 Subject: [PATCH 4/7] added support for creating custom animations that user can specify --- src/ui/animations/Animation.cpp | 5 ++++ src/ui/animations/Animation.h | 3 ++- src/ui/animations/Animations.h | 1 + src/ui/animations/CMakeLists.txt | 2 ++ src/ui/animations/CustomAnimation.cpp | 39 +++++++++++++++++++++++++++ src/ui/animations/CustomAnimation.h | 28 +++++++++++++++++++ tests/animations_test.cpp | 12 ++++----- 7 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 src/ui/animations/CustomAnimation.cpp create mode 100644 src/ui/animations/CustomAnimation.h diff --git a/src/ui/animations/Animation.cpp b/src/ui/animations/Animation.cpp index 21244b40..8d3ab5d6 100644 --- a/src/ui/animations/Animation.cpp +++ b/src/ui/animations/Animation.cpp @@ -50,6 +50,11 @@ namespace mc instance = MakeRef(); break; } + case AnimationType::Custom: + { + instance = MakeRef(); + break; + } default: break; } diff --git a/src/ui/animations/Animation.h b/src/ui/animations/Animation.h index 519e19f0..dfe63b98 100644 --- a/src/ui/animations/Animation.h +++ b/src/ui/animations/Animation.h @@ -9,7 +9,8 @@ namespace mc FadeOut, FadeIn, Translation, - Scale + Scale, + Custom }; #define ANIMATION_INSTANCE_CONSTRUCTOR \ diff --git a/src/ui/animations/Animations.h b/src/ui/animations/Animations.h index cbccefc0..c24bb82b 100644 --- a/src/ui/animations/Animations.h +++ b/src/ui/animations/Animations.h @@ -3,3 +3,4 @@ #include "FadeInAnimation.h" #include "TranslationAnimation.h" #include "ScaleAnimation.h" +#include "CustomAnimation.h" diff --git a/src/ui/animations/CMakeLists.txt b/src/ui/animations/CMakeLists.txt index ac28ab4f..fad69ab5 100644 --- a/src/ui/animations/CMakeLists.txt +++ b/src/ui/animations/CMakeLists.txt @@ -9,6 +9,7 @@ set( src/ui/animations/FadeInAnimation.h src/ui/animations/TranslationAnimation.h src/ui/animations/ScaleAnimation.h + src/ui/animations/CustomAnimation.h PARENT_SCOPE ) @@ -21,6 +22,7 @@ set( src/ui/animations/FadeInAnimation.cpp src/ui/animations/TranslationAnimation.cpp src/ui/animations/ScaleAnimation.cpp + src/ui/animations/CustomAnimation.cpp PARENT_SCOPE ) diff --git a/src/ui/animations/CustomAnimation.cpp b/src/ui/animations/CustomAnimation.cpp new file mode 100644 index 00000000..fd5daae2 --- /dev/null +++ b/src/ui/animations/CustomAnimation.cpp @@ -0,0 +1,39 @@ +#include "CustomAnimation.h" + +namespace mc +{ + CustomAnimation::CustomAnimation() + { + ANIMATION_INSTANCE_CONSTRUCTOR + } + + void CustomAnimation::Animate( + uint32_t duration, + std::function completion_handler + ) + { + if (m_Started) return; + m_Started = true; + + m_CompletionHandler = completion_handler; + m_Duration = duration; + m_Timer.Start(1); + } + + void CustomAnimation::OnTick(uint32_t tick, UITimer* timer) + { + if (m_UserOnTick) + m_UserOnTick(tick); + + if (tick >= m_Duration) + { + m_Timer.Stop(); + if (m_CompletionHandler) + m_CompletionHandler(); + + DestroyAnimation(this); + } + } +} + + diff --git a/src/ui/animations/CustomAnimation.h b/src/ui/animations/CustomAnimation.h new file mode 100644 index 00000000..46854acf --- /dev/null +++ b/src/ui/animations/CustomAnimation.h @@ -0,0 +1,28 @@ +#pragma once +#include "Animation.h" + +namespace mc +{ + class CustomAnimation : public Animation + { + public: + CustomAnimation(); + + void SetAnimationFunction(std::function fn) { m_UserOnTick = fn; } + + void Animate( + uint32_t duration, + std::function completion_handler = nullptr + ) override; + + private: + std::function m_CompletionHandler = nullptr; + + bool m_Started = false; + void OnTick(uint32_t tick, UITimer* timer) override; + + private: + float m_Duration = 0.0f; + std::function m_UserOnTick; + }; +} \ No newline at end of file diff --git a/tests/animations_test.cpp b/tests/animations_test.cpp index c853ede5..eed7813f 100644 --- a/tests/animations_test.cpp +++ b/tests/animations_test.cpp @@ -27,14 +27,12 @@ bool StartAnimBtn_OnClick(Event& event, UIView* sender) auto scaleup = Animation::Create(AnimationType::Scale, cpb.get()); AnimCast(ScaleAnimation, scaleup)->SetTargetSize({ 100.0f, 100.0f }); scaleup->Animate(200, []() { - std::thread progressbar_thread([]() { - while (cpb->Value < 100.0f) - { - cpb->Value++; - std::this_thread::sleep_for(std::chrono::milliseconds(16)); - } + auto cpb_anim = Animation::Create(AnimationType::Custom, 0); + AnimCast(CustomAnimation, cpb_anim)->SetAnimationFunction([](uint32_t tick) { + std::this_thread::sleep_for(std::chrono::milliseconds(16)); + cpb->Value++; }); - progressbar_thread.detach(); + cpb_anim->Animate(100); }); }); From 46c3e97abc992acdcc2f47fce0f368fdf3902c2b Mon Sep 17 00:00:00 2001 From: Albert Slepak Date: Mon, 31 Aug 2020 22:41:38 -0400 Subject: [PATCH 5/7] added API documentation to the latest animation classes --- src/ui/animations/Animation.h | 24 ++++++++++++++++++++++++ src/ui/animations/CustomAnimation.h | 9 +++++++++ src/ui/animations/FadeInAnimation.h | 7 +++++++ src/ui/animations/FadeOutAnimation.h | 7 +++++++ src/ui/animations/ScaleAnimation.h | 8 ++++++++ src/ui/animations/TranslationAnimation.h | 8 ++++++++ 6 files changed, 63 insertions(+) diff --git a/src/ui/animations/Animation.h b/src/ui/animations/Animation.h index dfe63b98..cc8dffe0 100644 --- a/src/ui/animations/Animation.h +++ b/src/ui/animations/Animation.h @@ -4,26 +4,50 @@ namespace mc { + /// Specifies the type of animation. enum class AnimationType { + /// Reduces the alpha value of the color of the view until it reaches 0. FadeOut, + + /// Increases the alpha value of the color of the view until it reaches 1. FadeIn, + + /// Translates the view by a certain amount in pixels. Translation, + + /// Resizes the view by a specifies amount in pixels. Scale, + + /// Performs a user specified callback over a duration. Custom }; +/// Sets the OnTick member function to be the tick callback for the timer. #define ANIMATION_INSTANCE_CONSTRUCTOR \ m_Timer.SetOnTickFunction([this](uint32_t tick, UITimer* timer) { OnTick(tick, timer); }); +/// Performs a dynamic pointer cast #define AnimCast(type, anim) std::dynamic_pointer_cast(anim) + /// Base class for all framework animations. class Animation { public: + /// Creates an instance of an appropriate animation class depending on the specified type. + /// @param type Specifies the type of the animation to be created. + /// @param target Specifies the target UIView on which specified animation will perform. + /// @note If the animation type is Custom, target parameter can be left blank. + /// @returns Ref to the base animation class that can be casted to an appropriate + /// subclass using AnimCast macro. static Ref Create(AnimationType type, UIView* target); + virtual ~Animation() = default; + /// Starts the animation that will be performed in a separate background thread. + /// @param duration Time in miliseconds the animation is going to run for. + /// @param completion_handler Optional user-defined function that will run + /// upon completion of the animation. virtual void Animate( uint32_t duration, std::function completion_handler = nullptr diff --git a/src/ui/animations/CustomAnimation.h b/src/ui/animations/CustomAnimation.h index 46854acf..14035804 100644 --- a/src/ui/animations/CustomAnimation.h +++ b/src/ui/animations/CustomAnimation.h @@ -3,13 +3,22 @@ namespace mc { + /// CustomAnimation is an animation class that allows the user to define their own animation logic. + /// Before starting the animation, SetAnimationFunction() must be called + /// to set the user defined function that controls the animation logic. class CustomAnimation : public Animation { public: CustomAnimation(); + /// Sets the user defined callback that gets executed + /// on every tick (every milisecond) during the animation. void SetAnimationFunction(std::function fn) { m_UserOnTick = fn; } + /// Starts the animation that will be performed in a separate background thread. + /// @param duration Time in miliseconds the animation is going to run for. + /// @param completion_handler Optional user-defined function that will run + /// upon completion of the animation. void Animate( uint32_t duration, std::function completion_handler = nullptr diff --git a/src/ui/animations/FadeInAnimation.h b/src/ui/animations/FadeInAnimation.h index ece07a77..0cdecd57 100644 --- a/src/ui/animations/FadeInAnimation.h +++ b/src/ui/animations/FadeInAnimation.h @@ -3,11 +3,18 @@ namespace mc { + /// FadeInAnimation is an animation class that allows to gradually fade a UIView out over a specified duration. + /// The animation is performed by decreasing the alpha value of the view's layer's color on every tick. + /// *Remarks: If the target view initially has the Visible flag set to false, the animation will set it to true. class FadeInAnimation : public Animation { public: FadeInAnimation(); + /// Starts the animation that will be performed in a separate background thread. + /// @param duration Time in miliseconds the animation is going to run for. + /// @param completion_handler Optional user-defined function that will run + /// upon completion of the animation. void Animate( uint32_t duration, std::function completion_handler = nullptr diff --git a/src/ui/animations/FadeOutAnimation.h b/src/ui/animations/FadeOutAnimation.h index a321aac3..1e3d17f2 100644 --- a/src/ui/animations/FadeOutAnimation.h +++ b/src/ui/animations/FadeOutAnimation.h @@ -3,11 +3,18 @@ namespace mc { + /// FadeOutAnimation is an animation class that allows to gradually fade a UIView in over a specified duration. + /// The animation is performed by decreasing the alpha value of the view's layer's color on every tick. + /// *Remarks: At the end of the animation, it will set the view's Visible flag to false. class FadeOutAnimation : public Animation { public: FadeOutAnimation(); + /// Starts the animation that will be performed in a separate background thread. + /// @param duration Time in miliseconds the animation is going to run for. + /// @param completion_handler Optional user-defined function that will run + /// upon completion of the animation. void Animate( uint32_t duration, std::function completion_handler = nullptr diff --git a/src/ui/animations/ScaleAnimation.h b/src/ui/animations/ScaleAnimation.h index 5d21e899..d6646b83 100644 --- a/src/ui/animations/ScaleAnimation.h +++ b/src/ui/animations/ScaleAnimation.h @@ -3,13 +3,21 @@ namespace mc { + /// ScaleAnimation is an animation class that allows to gradually resize/scale a UIView over a specified duration. + /// Before starting the animation, SetTargetSize() must be called + /// to set the desired final size the UIView should be. class ScaleAnimation : public Animation { public: ScaleAnimation(); + /// Sets the final desired size the target UIView should be. void SetTargetSize(Size size) { m_TargetSize = size; } + /// Starts the animation that will be performed in a separate background thread. + /// @param duration Time in miliseconds the animation is going to run for. + /// @param completion_handler Optional user-defined function that will run + /// upon completion of the animation. void Animate( uint32_t duration, std::function completion_handler = nullptr diff --git a/src/ui/animations/TranslationAnimation.h b/src/ui/animations/TranslationAnimation.h index 73465a60..7815b969 100644 --- a/src/ui/animations/TranslationAnimation.h +++ b/src/ui/animations/TranslationAnimation.h @@ -3,13 +3,21 @@ namespace mc { + /// TranslationAnimation is an animation class that allows to gradually displace/translate a UIView over a specified duration. + /// Before starting the animation, SetTargetTranslation() must be called + /// to set the desired distance the UIView should be moved. class TranslationAnimation : public Animation { public: TranslationAnimation(); + /// Sets the desired distance the target UIView should be moved. void SetTargetTranslation(Size distance) { m_TargetDistance = distance; } + /// Starts the animation that will be performed in a separate background thread. + /// @param duration Time in miliseconds the animation is going to run for. + /// @param completion_handler Optional user-defined function that will run + /// upon completion of the animation. void Animate( uint32_t duration, std::function completion_handler = nullptr From 977c1d9da6133a86679efd820d4210c410715fa4 Mon Sep 17 00:00:00 2001 From: Albert Slepak Date: Mon, 31 Aug 2020 22:54:21 -0400 Subject: [PATCH 6/7] fixed compiler warnings --- src/ui/animations/CustomAnimation.h | 2 +- src/ui/animations/ScaleAnimation.h | 2 +- src/ui/animations/TranslationAnimation.h | 2 +- src/ui/elements/UICombobox.cpp | 8 ++++---- src/ui/elements/UITabView.cpp | 6 +++--- src/ui/elements/UITextbox.cpp | 8 +------- tests/animations_test.cpp | 2 +- 7 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/ui/animations/CustomAnimation.h b/src/ui/animations/CustomAnimation.h index 14035804..5a8322f6 100644 --- a/src/ui/animations/CustomAnimation.h +++ b/src/ui/animations/CustomAnimation.h @@ -31,7 +31,7 @@ namespace mc void OnTick(uint32_t tick, UITimer* timer) override; private: - float m_Duration = 0.0f; + uint32_t m_Duration = 0.0f; std::function m_UserOnTick; }; } \ No newline at end of file diff --git a/src/ui/animations/ScaleAnimation.h b/src/ui/animations/ScaleAnimation.h index d6646b83..4161ad99 100644 --- a/src/ui/animations/ScaleAnimation.h +++ b/src/ui/animations/ScaleAnimation.h @@ -30,7 +30,7 @@ namespace mc void OnTick(uint32_t tick, UITimer* timer) override; private: - float m_Duration = 0.0f; + uint32_t m_Duration = 0.0f; Size m_TargetSize = { 0.0f, 0.0f }; Size m_ScaleStep = { 0.0f, 0.0f }; }; diff --git a/src/ui/animations/TranslationAnimation.h b/src/ui/animations/TranslationAnimation.h index 7815b969..791b78c4 100644 --- a/src/ui/animations/TranslationAnimation.h +++ b/src/ui/animations/TranslationAnimation.h @@ -30,7 +30,7 @@ namespace mc void OnTick(uint32_t tick, UITimer* timer) override; private: - float m_Duration = 0.0f; + uint32_t m_Duration = 0.0f; Size m_TargetDistance = { 0.0f, 0.0f }; Size m_MovementStep = { 0.0f, 0.0f }; }; diff --git a/src/ui/elements/UICombobox.cpp b/src/ui/elements/UICombobox.cpp index da453fcb..2e0116e5 100644 --- a/src/ui/elements/UICombobox.cpp +++ b/src/ui/elements/UICombobox.cpp @@ -107,7 +107,7 @@ namespace mc void UICombobox::InsertItem(const std::string& item, size_t index) { - if (index < 0 || index > m_Items.size()) return; + if (index > m_Items.size()) return; auto ItemButton = MakeRef(); ItemButton->Label->Text = item; @@ -172,7 +172,7 @@ namespace mc std::string UICombobox::GetItem(size_t index) { - if (index < 0 || index >= m_Items.size()) + if (index >= m_Items.size()) return ""; else return m_Items[index].first; @@ -180,7 +180,7 @@ namespace mc void UICombobox::RemoveItem(size_t index) { - if (index < 0 || index >= m_Items.size()) return; + if (index >= m_Items.size()) return; auto& button = m_Items[index].second; m_Items.erase(m_Items.begin() + index); @@ -222,7 +222,7 @@ namespace mc void UICombobox::SelectItem(size_t index) { - if (index < 0 || index > m_Items.size() || !m_Items.size()) return; + if (index > m_Items.size() || !m_Items.size()) return; if (index != m_SelectedIndex) { diff --git a/src/ui/elements/UITabView.cpp b/src/ui/elements/UITabView.cpp index ae62c9a6..5b3c07c5 100644 --- a/src/ui/elements/UITabView.cpp +++ b/src/ui/elements/UITabView.cpp @@ -149,7 +149,7 @@ namespace mc void UITabView::RemoveTab(size_t index) { - if (!m_Tabs.size() || index < 0 || index > m_Tabs.size()) return; + if (!m_Tabs.size() || index > m_Tabs.size()) return; auto [name, tab_btn, view] = m_Tabs[index]; m_Tabs.erase(m_Tabs.begin() + index); @@ -180,7 +180,7 @@ namespace mc void UITabView::OpenTab(size_t index) { - if (!m_Tabs.size() || index < 0 || index > m_Tabs.size()) return; + if (!m_Tabs.size() || index > m_Tabs.size()) return; auto [name, button, view] = m_Tabs[index]; m_SelectedView = view; @@ -213,7 +213,7 @@ namespace mc Ref UITabView::operator[](size_t index) { - if (!m_Tabs.size() || index < 0 || index > m_Tabs.size()) return nullptr; + if (!m_Tabs.size() || index > m_Tabs.size()) return nullptr; auto [name, button, view] = m_Tabs[index]; return view; diff --git a/src/ui/elements/UITextbox.cpp b/src/ui/elements/UITextbox.cpp index 817339e7..398f0a23 100644 --- a/src/ui/elements/UITextbox.cpp +++ b/src/ui/elements/UITextbox.cpp @@ -259,9 +259,6 @@ namespace mc if (m_CursorIndex > Text.size() && m_CursorIndex > 0) m_CursorIndex = Text.size() - 1; - if (m_CursorIndex < 0) - m_CursorIndex = 0; - // Sanitizing visible text indices SanitizeVisibleText(); @@ -292,7 +289,7 @@ namespace mc void UITextbox::RecalculateVisibleText() { // Extra edge-case sanitization - if (m_VisibleStartIndex > Text.size() || m_VisibleEndIndex < 0) + if (m_VisibleStartIndex > Text.size()) return; bool success = false; @@ -324,9 +321,6 @@ namespace mc } else { - if (m_VisibleStartIndex < 0) - m_VisibleStartIndex = 0; - if (m_VisibleEndIndex > Text.size()) m_VisibleEndIndex = Text.size(); } diff --git a/tests/animations_test.cpp b/tests/animations_test.cpp index eed7813f..f623531d 100644 --- a/tests/animations_test.cpp +++ b/tests/animations_test.cpp @@ -64,7 +64,7 @@ int main() label->color = Color::white; label->layer.color.alpha = 0.0f; label->Visible = false; - label->Properties.FontSize = 20.0f; + label->Properties.FontSize = 20; label->Text = "Animation Finished"; window->AddView(label); From 93de9e48321dc491115e18f2776c7d37d4f56c04 Mon Sep 17 00:00:00 2001 From: Albert Slepak Date: Mon, 31 Aug 2020 23:03:34 -0400 Subject: [PATCH 7/7] fixed more OSX and Windows specific compiler warnings --- src/ui/animations/CustomAnimation.h | 2 +- src/ui/animations/ScaleAnimation.h | 2 +- src/ui/animations/TranslationAnimation.h | 2 +- src/ui/elements/UICombobox.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ui/animations/CustomAnimation.h b/src/ui/animations/CustomAnimation.h index 5a8322f6..5cf4dd7b 100644 --- a/src/ui/animations/CustomAnimation.h +++ b/src/ui/animations/CustomAnimation.h @@ -31,7 +31,7 @@ namespace mc void OnTick(uint32_t tick, UITimer* timer) override; private: - uint32_t m_Duration = 0.0f; + uint32_t m_Duration = 0; std::function m_UserOnTick; }; } \ No newline at end of file diff --git a/src/ui/animations/ScaleAnimation.h b/src/ui/animations/ScaleAnimation.h index 4161ad99..15f27d14 100644 --- a/src/ui/animations/ScaleAnimation.h +++ b/src/ui/animations/ScaleAnimation.h @@ -30,7 +30,7 @@ namespace mc void OnTick(uint32_t tick, UITimer* timer) override; private: - uint32_t m_Duration = 0.0f; + uint32_t m_Duration = 0; Size m_TargetSize = { 0.0f, 0.0f }; Size m_ScaleStep = { 0.0f, 0.0f }; }; diff --git a/src/ui/animations/TranslationAnimation.h b/src/ui/animations/TranslationAnimation.h index 791b78c4..e39f5f64 100644 --- a/src/ui/animations/TranslationAnimation.h +++ b/src/ui/animations/TranslationAnimation.h @@ -30,7 +30,7 @@ namespace mc void OnTick(uint32_t tick, UITimer* timer) override; private: - uint32_t m_Duration = 0.0f; + uint32_t m_Duration = 0; Size m_TargetDistance = { 0.0f, 0.0f }; Size m_MovementStep = { 0.0f, 0.0f }; }; diff --git a/src/ui/elements/UICombobox.cpp b/src/ui/elements/UICombobox.cpp index 2e0116e5..2efc5bd1 100644 --- a/src/ui/elements/UICombobox.cpp +++ b/src/ui/elements/UICombobox.cpp @@ -189,7 +189,7 @@ namespace mc RecalculateItemPositions(); size_t display_item_index = IndexOf(m_DisplayItemLabel->Text); - if (display_item_index < 0 || display_item_index > m_Items.size()) + if (display_item_index > m_Items.size()) { if (!m_Items.size()) m_DisplayItemLabel->Text = "";