|
2 | 2 | #include "display.h" |
3 | 3 | #include "gui.h" |
4 | 4 | #include "license.h" // Generated at build time from LICENSE |
| 5 | +#include "notifications.h" |
5 | 6 | #include "usage.h" |
6 | 7 | #include <stdio.h> |
7 | 8 |
|
@@ -96,6 +97,86 @@ static void gui_help_windows(void) { |
96 | 97 | } |
97 | 98 | } |
98 | 99 |
|
| 100 | +static void gui_notifications(void) { |
| 101 | + int count; |
| 102 | + const struct notification *notifications = notify_get_notifications(&count); |
| 103 | + |
| 104 | + if (count == 0) { |
| 105 | + return; |
| 106 | + } |
| 107 | + |
| 108 | + ImGuiIO& io = ImGui::GetIO(); |
| 109 | + float spacing = 10.0f; |
| 110 | + float y_offset = io.DisplaySize.y - spacing; |
| 111 | + |
| 112 | + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 5.0f); |
| 113 | + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(10, 10)); |
| 114 | + |
| 115 | + for (int i = 0; i < 8; i++) { |
| 116 | + if (!notify_is_active(¬ifications[i])) { |
| 117 | + continue; |
| 118 | + } |
| 119 | + |
| 120 | + const char *message; |
| 121 | + int type; |
| 122 | + double time_remaining; |
| 123 | + notify_get_info(¬ifications[i], &message, &type, &time_remaining); |
| 124 | + |
| 125 | + /* Calculate alpha for fade out effect */ |
| 126 | + float alpha = 1.0f; |
| 127 | + if (time_remaining < 0.5) { |
| 128 | + alpha = (float)(time_remaining / 0.5); |
| 129 | + } |
| 130 | + |
| 131 | + /* Set colors based on notification type */ |
| 132 | + ImVec4 bg_color; |
| 133 | + if (type == NOTIFY_SUCCESS) { |
| 134 | + bg_color = ImVec4(0.1f, 0.4f, 0.1f, 0.85f * alpha); |
| 135 | + } else if (type == NOTIFY_ERROR) { |
| 136 | + bg_color = ImVec4(0.5f, 0.1f, 0.1f, 0.85f * alpha); |
| 137 | + } else { |
| 138 | + bg_color = ImVec4(0.25f, 0.25f, 0.25f, 0.85f * alpha); |
| 139 | + } |
| 140 | + |
| 141 | + ImGui::PushStyleColor(ImGuiCol_WindowBg, bg_color); |
| 142 | + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, alpha)); |
| 143 | + |
| 144 | + /* Begin window to calculate size */ |
| 145 | + char window_name[32]; |
| 146 | + snprintf(window_name, sizeof(window_name), "##notification%d", i); |
| 147 | + |
| 148 | + /* Set max width for notifications */ |
| 149 | + float max_width = 300.0f; |
| 150 | + ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(max_width, FLT_MAX)); |
| 151 | + |
| 152 | + ImGui::Begin(window_name, NULL, |
| 153 | + ImGuiWindowFlags_NoTitleBar | |
| 154 | + ImGuiWindowFlags_NoResize | |
| 155 | + ImGuiWindowFlags_NoMove | |
| 156 | + ImGuiWindowFlags_NoScrollbar | |
| 157 | + ImGuiWindowFlags_NoSavedSettings | |
| 158 | + ImGuiWindowFlags_AlwaysAutoResize); |
| 159 | + |
| 160 | + /* Wrap text to max width */ |
| 161 | + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + max_width - 20); |
| 162 | + ImGui::TextWrapped("%s", message); |
| 163 | + ImGui::PopTextWrapPos(); |
| 164 | + |
| 165 | + /* Get actual window size and reposition from bottom-right */ |
| 166 | + ImVec2 window_size = ImGui::GetWindowSize(); |
| 167 | + ImVec2 window_pos = ImVec2(io.DisplaySize.x - window_size.x - spacing, y_offset - window_size.y); |
| 168 | + ImGui::SetWindowPos(window_pos); |
| 169 | + |
| 170 | + y_offset -= window_size.y + spacing; |
| 171 | + |
| 172 | + ImGui::End(); |
| 173 | + |
| 174 | + ImGui::PopStyleColor(2); |
| 175 | + } |
| 176 | + |
| 177 | + ImGui::PopStyleVar(2); |
| 178 | +} |
| 179 | + |
99 | 180 | static void gui_main_menu(void) { |
100 | 181 | bool before; |
101 | 182 |
|
@@ -242,6 +323,7 @@ void gui_process_events(SDL_Event *event) { |
242 | 323 | void gui_new_frame(void) { |
243 | 324 | ImGui_ImplSdl_NewFrame(display.window); |
244 | 325 | gui_main_menu(); |
| 326 | + gui_notifications(); |
245 | 327 | } |
246 | 328 |
|
247 | 329 | void gui_render(void) { |
|
0 commit comments