// MassBuilderSaveTool // Copyright (C) 2021-2022 Guillaume Jacquemin // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include "../FontAwesome/IconsFontAwesome5.h" #include "ToastQueue.h" using namespace Containers::Literals; constexpr UnsignedInt success_colour = 0xff67d23bu; constexpr UnsignedInt info_colour = 0xffcc832fu; constexpr UnsignedInt warning_colour = 0xff2fcfc7u; constexpr UnsignedInt error_colour = 0xff3134cdu; constexpr UnsignedInt fade_time = 150; constexpr Float base_opacity = 1.0f; constexpr Vector2 padding{20.0f, 20.0f}; constexpr Float toast_spacing = 10.0f; Toast::Toast(Type type, Containers::StringView message, std::chrono::milliseconds timeout): _type{type}, _message{message}, _timeout{timeout}, _creationTime{std::chrono::steady_clock::now()} { _phaseTrack = Animation::Track{{ {0, Phase::FadeIn}, {fade_time, Phase::Wait}, {fade_time + timeout.count(), Phase::FadeOut}, {(fade_time * 2) + timeout.count(), Phase::TimedOut} }, Math::select, Animation::Extrapolation::Constant}; } auto Toast::type() -> Type { return _type; } auto Toast::message() -> Containers::StringView { return _message; } auto Toast::timeout() -> std::chrono::milliseconds { return _timeout; } auto Toast::creationTime() -> std::chrono::steady_clock::time_point { return _creationTime; } auto Toast::elapsedTime() -> std::chrono::milliseconds { return std::chrono::duration_cast(std::chrono::steady_clock::now() - _creationTime); } auto Toast::phase() -> Phase { return _phaseTrack.at(elapsedTime().count()); } auto Toast::opacity() -> Float { Phase phase = this->phase(); Long elapsed_time = elapsedTime().count(); if(phase == Phase::FadeIn) { return Float(elapsed_time) / Float(fade_time); } else if(phase == Phase::FadeOut) { return 1.0f - ((Float(elapsed_time) - Float(fade_time) - Float(_timeout.count())) / Float(fade_time)); } return 1.0f; } void ToastQueue::addToast(Toast&& toast) { _toasts.push_back(std::move(toast)); } void ToastQueue::addToast(Toast::Type type, Containers::StringView message, std::chrono::milliseconds timeout) { _toasts.emplace_back(type, message, timeout); } void ToastQueue::draw(Vector2i viewport_size) { Float height = 0.0f; for(UnsignedInt i = 0; i < _toasts.size(); i++) { Toast* current = &_toasts[i]; if(current->phase() == Toast::Phase::TimedOut) { removeToast(i); continue; } Containers::String win_id = Utility::format("##Toast{}", i); Float opacity = base_opacity * current->opacity(); ImGui::PushStyleVar(ImGuiStyleVar_Alpha, opacity); ImGui::SetNextWindowPos({viewport_size.x() - padding.x(), viewport_size.y() - padding.y() - height}, ImGuiCond_Always, {1.0f, 1.0f}); if(ImGui::Begin(win_id.data(), nullptr, ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoDecoration| ImGuiWindowFlags_NoInputs|ImGuiWindowFlags_NoNav|ImGuiWindowFlags_NoFocusOnAppearing)) { ImColor colour = 0xffffffff; switch(current->type()) { case Toast::Type::Default: break; case Toast::Type::Success: colour = success_colour; ImGui::TextColored(colour, ICON_FA_CHECK_CIRCLE); break; case Toast::Type::Info: colour = info_colour; ImGui::TextColored(colour, ICON_FA_INFO_CIRCLE); break; case Toast::Type::Warning: colour = warning_colour; ImGui::TextColored(colour, ICON_FA_EXCLAMATION_TRIANGLE); break; case Toast::Type::Error: colour = error_colour; ImGui::TextColored(colour, ICON_FA_TIMES_CIRCLE); break; } if(current->type() != Toast::Type::Default) { ImGui::SameLine(); } ImGui::PushTextWrapPos(500.0f); ImGui::TextColored(colour, current->message().data()); ImGui::PopTextWrapPos(); height += ImGui::GetWindowHeight() + toast_spacing; } ImGui::End(); ImGui::PopStyleVar(); } } void ToastQueue::removeToast(Long index) { _toasts.erase(_toasts.begin() + index); }