Add ToastQueue for in-app notifications.
This commit is contained in:
parent
445d7323b3
commit
d9efe8191e
3 changed files with 244 additions and 0 deletions
|
@ -46,6 +46,8 @@ add_executable(MassBuilderSaveTool WIN32
|
|||
Mass/Mass.cpp
|
||||
Maps/LastMissionId.h
|
||||
Maps/StoryProgress.h
|
||||
ToastQueue/ToastQueue.h
|
||||
ToastQueue/ToastQueue.cpp
|
||||
FontAwesome/IconsFontAwesome5.h
|
||||
FontAwesome/IconsFontAwesome5Brands.h
|
||||
resource.rc
|
||||
|
|
160
src/ToastQueue/ToastQueue.cpp
Normal file
160
src/ToastQueue/ToastQueue.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <Corrade/Utility/FormatStl.h>
|
||||
|
||||
#include <Magnum/Math/Functions.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "../FontAwesome/IconsFontAwesome5.h"
|
||||
|
||||
#include "ToastQueue.h"
|
||||
|
||||
using namespace Corrade;
|
||||
|
||||
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, const std::string& message, std::chrono::milliseconds timeout):
|
||||
_type{type}, _message{message}, _timeout{timeout}, _creationTime{std::chrono::steady_clock::now()}
|
||||
{
|
||||
_phaseTrack = Animation::Track<UnsignedInt, Phase>{{
|
||||
{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() -> const std::string& {
|
||||
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::milliseconds>(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, const std::string& 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;
|
||||
}
|
||||
|
||||
std::string win_id = Utility::formatString("##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.c_str(), 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;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if(current->message().length() > 127) {
|
||||
ImGui::TextColored(colour, "%.*s...", 127, current->message().c_str());
|
||||
}
|
||||
else {
|
||||
ImGui::TextColored(colour, current->message().c_str());
|
||||
}
|
||||
|
||||
height += ImGui::GetWindowHeight() + toast_spacing;
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
}
|
||||
|
||||
void ToastQueue::removeToast(Long index) {
|
||||
_toasts.erase(_toasts.begin() + index);
|
||||
}
|
82
src/ToastQueue/ToastQueue.h
Normal file
82
src/ToastQueue/ToastQueue.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
#pragma once
|
||||
|
||||
// MassBuilderSaveTool
|
||||
// Copyright (C) 2021 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <Magnum/Magnum.h>
|
||||
#include <Magnum/Animation/Track.h>
|
||||
|
||||
using namespace Magnum;
|
||||
|
||||
class Toast {
|
||||
public:
|
||||
enum class Type : UnsignedByte {
|
||||
Default, Success, Info, Warning, Error
|
||||
};
|
||||
|
||||
enum class Phase : UnsignedByte {
|
||||
FadeIn, Wait, FadeOut, TimedOut
|
||||
};
|
||||
|
||||
explicit Toast(Type type, const std::string& message,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds{3000});
|
||||
|
||||
Toast(const Toast& other) = delete;
|
||||
Toast& operator=(const Toast& other) = delete;
|
||||
|
||||
Toast(Toast&& other) = default;
|
||||
Toast& operator=(Toast&& other) = default;
|
||||
|
||||
auto type() -> Type;
|
||||
|
||||
auto message() -> std::string const&;
|
||||
|
||||
auto timeout() -> std::chrono::milliseconds;
|
||||
|
||||
auto creationTime() -> std::chrono::steady_clock::time_point;
|
||||
|
||||
auto elapsedTime() -> std::chrono::milliseconds;
|
||||
|
||||
auto phase() -> Phase;
|
||||
|
||||
auto opacity() -> Float;
|
||||
|
||||
private:
|
||||
Type _type{Type::Default};
|
||||
std::string _message;
|
||||
std::chrono::milliseconds _timeout;
|
||||
std::chrono::steady_clock::time_point _creationTime;
|
||||
Animation::Track<UnsignedInt, Phase> _phaseTrack;
|
||||
};
|
||||
|
||||
class ToastQueue {
|
||||
public:
|
||||
void addToast(Toast&& toast);
|
||||
|
||||
void addToast(Toast::Type type, const std::string& message,
|
||||
std::chrono::milliseconds timeout = std::chrono::milliseconds{3000});
|
||||
|
||||
void draw(Vector2i viewport_size);
|
||||
|
||||
private:
|
||||
void removeToast(Long index);
|
||||
|
||||
std::vector<Toast> _toasts;
|
||||
};
|
Loading…
Reference in a new issue