diff --git a/src/client/component/gui.cpp b/src/client/component/gui.cpp index 4ad15f53..36875ca1 100644 --- a/src/client/component/gui.cpp +++ b/src/client/component/gui.cpp @@ -26,6 +26,8 @@ namespace gui bool initialized = false; bool toggled = false; + std::vector notifications; + void initialize_gui_context() { ImGui::CreateContext(); @@ -58,8 +60,49 @@ namespace gui enabled_menus[name] = !enabled_menus[name]; } + void show_notifications() + { + static auto window_flags = ImGuiWindowFlags_NoDecoration | + ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | + ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoMove; + + auto index = 0; + for (auto i = notifications.begin(); i != notifications.end(); ++i) + { + const auto now = std::chrono::high_resolution_clock::now(); + if (now - i->creation_time >= i->duration) + { + notifications.erase(i--); + continue; + } + + const auto title = i->title.size() <= 34 + ? i->title + : i->title.substr(0, 31) + "..."; + + const auto text = i->text.size() <= 34 + ? i->text + : i->text.substr(0, 31) + "..."; + + ImGui::SetNextWindowSizeConstraints(ImVec2(250, 50), ImVec2(250, 50)); + ImGui::SetNextWindowBgAlpha(0.6f); + ImGui::Begin(utils::string::va("Notification #%i", index), nullptr, window_flags); + + ImGui::SetWindowPos(ImVec2(10, 30.f + static_cast(index) * 60.f)); + ImGui::SetWindowSize(ImVec2(250, 0)); + ImGui::Text(title.data()); + ImGui::Text(text.data()); + + ImGui::End(); + + index++; + } + } + void gui_draw() { + show_notifications(); + on_frame_callbacks.access([](std::vector>& callbacks) { for (const auto& callback : callbacks) @@ -180,6 +223,17 @@ namespace gui return enabled_menus[name]; } + void notification(const std::string& title, const std::string& text, const std::chrono::milliseconds duration) + { + notification_t notification{}; + notification.title = title; + notification.text = text; + notification.duration = duration; + notification.creation_time = std::chrono::high_resolution_clock::now(); + + notifications.insert(notifications.begin(), notification); + } + class component final : public component_interface { public: diff --git a/src/client/component/gui.hpp b/src/client/component/gui.hpp index e570de33..8d0e2e98 100644 --- a/src/client/component/gui.hpp +++ b/src/client/component/gui.hpp @@ -2,6 +2,14 @@ namespace gui { + struct notification_t + { + std::string title; + std::string text; + std::chrono::milliseconds duration{}; + std::chrono::high_resolution_clock::time_point creation_time{}; + }; + extern std::unordered_map enabled_menus; bool gui_key_event(const int local_client_num, const int key, const int down); @@ -10,4 +18,5 @@ namespace gui void on_frame(const std::function& callback); bool is_menu_open(const std::string& name); + void notification(const std::string& title, const std::string& text, const std::chrono::milliseconds duration = 3s); } \ No newline at end of file diff --git a/src/client/component/gui_asset_list.cpp b/src/client/component/gui_asset_list.cpp index cb2715f5..19c7756f 100644 --- a/src/client/component/gui_asset_list.cpp +++ b/src/client/component/gui_asset_list.cpp @@ -81,6 +81,7 @@ namespace asset_list if (ImGui::Button(asset_name)) { utils::string::set_clipboard_data(asset_name); + gui::notification("Text copied to clipboard!", utils::string::va("\"%s\"", asset_name)); } }, true); diff --git a/src/client/component/gui_entity_list.cpp b/src/client/component/gui_entity_list.cpp index de682e65..e452d726 100644 --- a/src/client/component/gui_entity_list.cpp +++ b/src/client/component/gui_entity_list.cpp @@ -789,6 +789,7 @@ namespace entity_list if (ImGui::Button(field.first.data())) { utils::string::set_clipboard_data(field.first); + gui::notification("Text copied to clipboard!", utils::string::va("\"%s\"", field.first.data())); } ImGui::SameLine(); @@ -796,6 +797,7 @@ namespace entity_list if (ImGui::Button(field.second.data())) { utils::string::set_clipboard_data(field.second); + gui::notification("Text copied to clipboard!", utils::string::va("\"%s\"", field.second.data())); } }