123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- // imgui-notify by patrickcjk
- // https://github.com/patrickcjk/imgui-notify
- /*
- MIT License
- Copyright (c) 2021 Patrick
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in all
- copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- SOFTWARE.
- */
- #ifndef IMGUI_NOTIFY
- #define IMGUI_NOTIFY
- //#pragma once
- #include <vector>
- #include <string>
- #include "font_awesome_5.h"
- #include "fa_solid_900.h"
- #define NOTIFY_MAX_MSG_LENGTH 4096 // Max message content length
- #define NOTIFY_PADDING_X 20.f // Bottom-left X padding
- #define NOTIFY_PADDING_Y 20.f // Bottom-left Y padding
- #define NOTIFY_PADDING_MESSAGE_Y 10.f // Padding Y between each message
- #define NOTIFY_FADE_IN_OUT_TIME 150 // Fade in and out duration
- #define NOTIFY_DEFAULT_DISMISS 3000 // Auto dismiss after X ms (default, applied only of no data provided in constructors)
- #define NOTIFY_OPACITY 1.0f // 0-1 Toast opacity
- #define NOTIFY_TOAST_FLAGS ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing
- // Comment out if you don't want any separator between title and content
- #define NOTIFY_USE_SEPARATOR
- #define NOTIFY_INLINE inline
- #define NOTIFY_NULL_OR_EMPTY(str) (!str ||! strlen(str))
- #define NOTIFY_FORMAT(fn, format, ...) if (format) { va_list args; va_start(args, format); fn(format, args, __VA_ARGS__); va_end(args); }
- typedef int ImGuiToastType;
- typedef int ImGuiToastPhase;
- typedef int ImGuiToastPos;
- enum ImGuiToastType_
- {
- ImGuiToastType_None,
- ImGuiToastType_Success,
- ImGuiToastType_Warning,
- ImGuiToastType_Error,
- ImGuiToastType_Info,
- ImGuiToastType_COUNT
- };
- enum ImGuiToastPhase_
- {
- ImGuiToastPhase_FadeIn,
- ImGuiToastPhase_Wait,
- ImGuiToastPhase_FadeOut,
- ImGuiToastPhase_Expired,
- ImGuiToastPhase_COUNT
- };
- enum ImGuiToastPos_
- {
- ImGuiToastPos_TopLeft,
- ImGuiToastPos_TopCenter,
- ImGuiToastPos_TopRight,
- ImGuiToastPos_BottomLeft,
- ImGuiToastPos_BottomCenter,
- ImGuiToastPos_BottomRight,
- ImGuiToastPos_Center,
- ImGuiToastPos_COUNT
- };
- class ImGuiToast
- {
- private:
- ImGuiToastType type = ImGuiToastType_None;
- char title[NOTIFY_MAX_MSG_LENGTH];
- char content[NOTIFY_MAX_MSG_LENGTH];
- int dismiss_time = NOTIFY_DEFAULT_DISMISS;
- uint64_t creation_time = 0;
- private:
- // Setters
- NOTIFY_INLINE auto set_title(const char* format, va_list args) { vsnprintf(this->title, sizeof(this->title), format, args); }
- NOTIFY_INLINE auto set_content(const char* format, va_list args) { vsnprintf(this->content, sizeof(this->content), format, args); }
- public:
- NOTIFY_INLINE auto set_title(const char* format, ...) -> void { NOTIFY_FORMAT(this->set_title, format); }
- NOTIFY_INLINE auto set_content(const char* format, ...) -> void { NOTIFY_FORMAT(this->set_content, format); }
- NOTIFY_INLINE auto set_type(const ImGuiToastType& type) -> void { IM_ASSERT(type < ImGuiToastType_COUNT); this->type = type; };
- public:
- // Getters
- NOTIFY_INLINE auto get_title() -> char* { return this->title; };
- NOTIFY_INLINE auto get_default_title() -> const char*
- {
- if (!strlen(this->title))
- {
- switch (this->type)
- {
- case ImGuiToastType_None:
- return NULL;
- case ImGuiToastType_Success:
- return "Success";
- case ImGuiToastType_Warning:
- return "Warning";
- case ImGuiToastType_Error:
- return "Error";
- case ImGuiToastType_Info:
- return "Info";
- }
- }
- return this->title;
- };
- NOTIFY_INLINE auto get_type() -> const ImGuiToastType& { return this->type; };
- NOTIFY_INLINE auto get_color() -> const ImVec4&
- {
- switch (this->type)
- {
- case ImGuiToastType_None:
- return { 255, 255, 255, 255 }; // White
- case ImGuiToastType_Success:
- return { 0, 255, 0, 255 }; // Green
- case ImGuiToastType_Warning:
- return { 255, 255, 0, 255 }; // Yellow
- case ImGuiToastType_Error:
- return { 255, 0, 0, 255 }; // Error
- case ImGuiToastType_Info:
- return { 0, 157, 255, 255 }; // Blue
- }
- }
- NOTIFY_INLINE auto get_icon() -> const char*
- {
- switch (this->type)
- {
- case ImGuiToastType_None:
- return NULL;
- case ImGuiToastType_Success:
- return ICON_FA_CHECK_CIRCLE;
- case ImGuiToastType_Warning:
- return ICON_FA_EXCLAMATION_TRIANGLE;
- case ImGuiToastType_Error:
- return ICON_FA_TIMES_CIRCLE;
- case ImGuiToastType_Info:
- return ICON_FA_INFO_CIRCLE;
- }
- }
- NOTIFY_INLINE auto get_content() -> char* { return this->content; };
- NOTIFY_INLINE auto get_elapsed_time() { return GetTickCount64() - this->creation_time; }
- NOTIFY_INLINE auto get_phase() -> const ImGuiToastPhase&
- {
- const auto elapsed = get_elapsed_time();
- if (elapsed > NOTIFY_FADE_IN_OUT_TIME + this->dismiss_time + NOTIFY_FADE_IN_OUT_TIME)
- {
- return ImGuiToastPhase_Expired;
- }
- else if (elapsed > NOTIFY_FADE_IN_OUT_TIME + this->dismiss_time)
- {
- return ImGuiToastPhase_FadeOut;
- }
- else if (elapsed > NOTIFY_FADE_IN_OUT_TIME)
- {
- return ImGuiToastPhase_Wait;
- }
- else
- {
- return ImGuiToastPhase_FadeIn;
- }
- }
- NOTIFY_INLINE auto get_fade_percent() -> const float
- {
- const auto phase = get_phase();
- const auto elapsed = get_elapsed_time();
- if (phase == ImGuiToastPhase_FadeIn)
- {
- return ((float)elapsed / (float)NOTIFY_FADE_IN_OUT_TIME) * NOTIFY_OPACITY;
- }
- else if (phase == ImGuiToastPhase_FadeOut)
- {
- return (1.f - (((float)elapsed - (float)NOTIFY_FADE_IN_OUT_TIME - (float)this->dismiss_time) / (float)NOTIFY_FADE_IN_OUT_TIME)) * NOTIFY_OPACITY;
- }
- return 1.f * NOTIFY_OPACITY;
- }
- public:
- // Constructors
- ImGuiToast(ImGuiToastType type, int dismiss_time = NOTIFY_DEFAULT_DISMISS)
- {
- IM_ASSERT(type < ImGuiToastType_COUNT);
- this->type = type;
- this->dismiss_time = dismiss_time;
- this->creation_time = GetTickCount64();
- memset(this->title, 0, sizeof(this->title));
- memset(this->content, 0, sizeof(this->content));
- }
- ImGuiToast(ImGuiToastType type, const char* format, ...) : ImGuiToast(type) { NOTIFY_FORMAT(this->set_content, format); }
- ImGuiToast(ImGuiToastType type, int dismiss_time, const char* format, ...) : ImGuiToast(type, dismiss_time) { NOTIFY_FORMAT(this->set_content, format); }
- };
- namespace {
- extern auto iconno = "null_icon";
- }
- namespace ImGui
- {
- //extern auto iconno = "null_icon";
- NOTIFY_INLINE std::vector<ImGuiToast> notifications;
- /// <summary>
- /// Insert a new toast in the list
- /// </summary>
- NOTIFY_INLINE VOID InsertNotification(const ImGuiToast& toast)
- {
- notifications.push_back(toast);
- }
- /// <summary>
- /// Remove a toast from the list by its index
- /// </summary>
- /// <param name="index">index of the toast to remove</param>
- NOTIFY_INLINE VOID RemoveNotification(int index)
- {
- notifications.erase(notifications.begin() + index);
- }
- /// <summary>
- /// Render toasts, call at the end of your rendering!
- /// </summary>
- NOTIFY_INLINE VOID RenderNotifications()
- {
- const auto vp_size = GetMainViewport()->Size;
- float height = 0.f;
- for (auto i = 0; i < notifications.size(); i++)
- {
- auto* current_toast = ¬ifications[i];
- // Remove toast if expired
- if (current_toast->get_phase() == ImGuiToastPhase_Expired)
- {
- RemoveNotification(i);
- continue;
- }
- // Get icon, title and other data
- iconno = current_toast->get_icon();
- const auto title = current_toast->get_title();
- const auto content = current_toast->get_content();
- const auto default_title = current_toast->get_default_title();
- const auto opacity = current_toast->get_fade_percent(); // Get opacity based of the current phase
- // Window rendering
- auto text_color = current_toast->get_color();
- text_color.w = opacity;
- // Generate new unique name for this toast
- char window_name[50];
- sprintf_s(window_name, "##TOAST%d", i);
- //PushStyleColor(ImGuiCol_Text, text_color);
- SetNextWindowBgAlpha(opacity);
- SetNextWindowPos(ImVec2(vp_size.x - NOTIFY_PADDING_X, vp_size.y - NOTIFY_PADDING_Y - height), ImGuiCond_Always, ImVec2(1.0f, 1.0f));
- Begin(window_name, NULL, NOTIFY_TOAST_FLAGS);
- // Here we render the toast content
- {
- PushTextWrapPos(vp_size.x / 3.f); // We want to support multi-line text, this will wrap the text after 1/3 of the screen width
- bool was_title_rendered = false;
-
- // If an icon is set
- if (!NOTIFY_NULL_OR_EMPTY(iconno))
- {
- //Text(icon); // Render icon text
- TextColored(text_color, iconno);
- was_title_rendered = true;
- }
- // If a title is set
- if (!NOTIFY_NULL_OR_EMPTY(title))
- {
- // If a title and an icon is set, we want to render on same line
- if (!NOTIFY_NULL_OR_EMPTY(iconno))
- SameLine();
- Text(title); // Render title text
- was_title_rendered = true;
- }
- else if (!NOTIFY_NULL_OR_EMPTY(default_title))
- {
- if (!NOTIFY_NULL_OR_EMPTY(iconno))
- SameLine();
- Text(default_title); // Render default title text (ImGuiToastType_Success -> "Success", etc...)
- was_title_rendered = true;
- }
- // In case ANYTHING was rendered in the top, we want to add a small padding so the text (or icon) looks centered vertically
- if (was_title_rendered && !NOTIFY_NULL_OR_EMPTY(content))
- {
- SetCursorPosY(GetCursorPosY() + 5.f); // Must be a better way to do this!!!!
- }
- // If a content is set
- if (!NOTIFY_NULL_OR_EMPTY(content))
- {
- if (was_title_rendered)
- {
- #ifdef NOTIFY_USE_SEPARATOR
- Separator();
- #endif
- }
- Text(content); // Render content text
- }
- PopTextWrapPos();
- }
- // Save height for next toasts
- height += GetWindowHeight() + NOTIFY_PADDING_MESSAGE_Y;
- // End
- End();
- }
- }
- /// <summary>
- /// Adds font-awesome font, must be called ONCE on initialization
- /// <param name="FontDataOwnedByAtlas">Fonts are loaded from read-only memory, should be set to false!</param>
- /// </summary>
- NOTIFY_INLINE VOID MergeIconsWithLatestFont(float font_size, bool FontDataOwnedByAtlas = false)
- {
- static const ImWchar icons_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
- ImFontConfig icons_config;
- icons_config.MergeMode = true;
- icons_config.PixelSnapH = true;
- icons_config.FontDataOwnedByAtlas = FontDataOwnedByAtlas;
- GetIO().Fonts->AddFontFromMemoryTTF((void*)fa_solid_900, sizeof(fa_solid_900), font_size, &icons_config, icons_ranges);
- }
- }
- #endif
|