// MassBuilderSaveTool // Copyright (C) 2021-2024 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; namespace mbst { constexpr std::uint32_t success_colour = 0xff67d23bu; constexpr std::uint32_t info_colour = 0xffcc832fu; constexpr std::uint32_t warning_colour = 0xff2fcfc7u; constexpr std::uint32_t error_colour = 0xff3134cdu; constexpr std::uint32_t 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}; } Toast::Type Toast::type() { return _type; } Containers::StringView Toast::message() { return _message; } std::chrono::milliseconds Toast::timeout() { return _timeout; } std::chrono::steady_clock::time_point Toast::creationTime() { return _creationTime; } std::chrono::milliseconds Toast::elapsedTime() { return std::chrono::duration_cast(std::chrono::steady_clock::now() - _creationTime); } Toast::Phase Toast::phase() { return _phaseTrack.at(elapsedTime().count()); } float Toast::opacity() { Phase phase = this->phase(); std::int64_t 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(Utility::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(std::uint32_t 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({float(viewport_size.x()) - padding.x(), float(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(std::int64_t index) { _toasts.erase(_toasts.begin() + index); } }