diff options
author | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2025-08-30 16:53:58 -0700 |
commit | 6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch) | |
tree | 34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/test/testpopup.c | |
parent | 8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff) |
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testpopup.c')
-rw-r--r-- | src/contrib/SDL-3.2.20/test/testpopup.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testpopup.c b/src/contrib/SDL-3.2.20/test/testpopup.c new file mode 100644 index 0000000..987eab8 --- /dev/null +++ b/src/contrib/SDL-3.2.20/test/testpopup.c | |||
@@ -0,0 +1,317 @@ | |||
1 | /* | ||
2 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> | ||
3 | |||
4 | This software is provided 'as-is', without any express or implied | ||
5 | warranty. In no event will the authors be held liable for any damages | ||
6 | arising from the use of this software. | ||
7 | |||
8 | Permission is granted to anyone to use this software for any purpose, | ||
9 | including commercial applications, and to alter it and redistribute it | ||
10 | freely. | ||
11 | */ | ||
12 | /* Simple program: Move N sprites around on the screen as fast as possible */ | ||
13 | |||
14 | #include <SDL3/SDL_main.h> | ||
15 | #include <SDL3/SDL_test_common.h> | ||
16 | #include <SDL3/SDL_test_font.h> | ||
17 | |||
18 | #ifdef SDL_PLATFORM_EMSCRIPTEN | ||
19 | #include <emscripten/emscripten.h> | ||
20 | #endif | ||
21 | |||
22 | #include <stdlib.h> | ||
23 | |||
24 | #define MENU_WIDTH 120 | ||
25 | #define MENU_HEIGHT 300 | ||
26 | |||
27 | #define TOOLTIP_DELAY 500 | ||
28 | #define TOOLTIP_WIDTH 175 | ||
29 | #define TOOLTIP_HEIGHT 32 | ||
30 | |||
31 | static SDLTest_CommonState *state; | ||
32 | static int num_menus; | ||
33 | static Uint64 tooltip_timer; | ||
34 | static int done; | ||
35 | static const SDL_Color colors[] = { | ||
36 | { 0x7F, 0x00, 0x00, 0xFF }, | ||
37 | { 0x00, 0x7F, 0x00, 0xFF }, | ||
38 | { 0x00, 0x00, 0x7F, 0xFF } | ||
39 | }; | ||
40 | |||
41 | struct PopupWindow | ||
42 | { | ||
43 | SDL_Window *win; | ||
44 | SDL_Window *parent; | ||
45 | SDL_Renderer *renderer; | ||
46 | int idx; | ||
47 | }; | ||
48 | |||
49 | static struct PopupWindow *menus; | ||
50 | static struct PopupWindow tooltip; | ||
51 | |||
52 | static bool no_constraints; | ||
53 | static bool no_grab; | ||
54 | |||
55 | /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ | ||
56 | static void quit(int rc) | ||
57 | { | ||
58 | SDL_free(menus); | ||
59 | menus = NULL; | ||
60 | |||
61 | SDLTest_CleanupTextDrawing(); | ||
62 | SDLTest_CommonQuit(state); | ||
63 | /* Let 'main()' return normally */ | ||
64 | if (rc != 0) { | ||
65 | exit(rc); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static int get_menu_index_by_window(SDL_Window *window) | ||
70 | { | ||
71 | int i; | ||
72 | for (i = 0; i < num_menus; ++i) { | ||
73 | if (menus[i].win == window) { | ||
74 | return i; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | return -1; | ||
79 | } | ||
80 | |||
81 | static bool window_is_root(SDL_Window *window) | ||
82 | { | ||
83 | int i; | ||
84 | for (i = 0; i < state->num_windows; ++i) { | ||
85 | if (window == state->windows[i]) { | ||
86 | return true; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | return false; | ||
91 | } | ||
92 | |||
93 | static bool create_popup(struct PopupWindow *new_popup, bool is_menu) | ||
94 | { | ||
95 | SDL_Window *focus; | ||
96 | SDL_Window *new_win; | ||
97 | SDL_Renderer *new_renderer; | ||
98 | const int w = is_menu ? MENU_WIDTH : TOOLTIP_WIDTH; | ||
99 | const int h = is_menu ? MENU_HEIGHT : TOOLTIP_HEIGHT; | ||
100 | const int v_off = is_menu ? 0 : 32; | ||
101 | float x, y; | ||
102 | |||
103 | focus = SDL_GetMouseFocus(); | ||
104 | |||
105 | SDL_GetMouseState(&x, &y); | ||
106 | |||
107 | SDL_PropertiesID props = SDL_CreateProperties(); | ||
108 | SDL_SetPointerProperty(props, SDL_PROP_WINDOW_CREATE_PARENT_POINTER, focus); | ||
109 | SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_CONSTRAIN_POPUP_BOOLEAN, !no_constraints); | ||
110 | SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FOCUSABLE_BOOLEAN, !no_grab); | ||
111 | if (is_menu) { | ||
112 | SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_MENU_BOOLEAN, true); | ||
113 | } else { | ||
114 | SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_TOOLTIP_BOOLEAN, true); | ||
115 | } | ||
116 | SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, w); | ||
117 | SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, h); | ||
118 | SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_X_NUMBER, (int)x); | ||
119 | SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_Y_NUMBER, (int)y + v_off); | ||
120 | new_win = SDL_CreateWindowWithProperties(props); | ||
121 | SDL_DestroyProperties(props); | ||
122 | |||
123 | if (new_win) { | ||
124 | new_renderer = SDL_CreateRenderer(new_win, state->renderdriver); | ||
125 | |||
126 | new_popup->win = new_win; | ||
127 | new_popup->renderer = new_renderer; | ||
128 | new_popup->parent = focus; | ||
129 | |||
130 | return true; | ||
131 | } | ||
132 | |||
133 | SDL_zerop(new_popup); | ||
134 | return false; | ||
135 | } | ||
136 | |||
137 | static void close_popups(void) | ||
138 | { | ||
139 | int i; | ||
140 | |||
141 | for (i = 0; i < num_menus; ++i) { | ||
142 | /* Destroying the lowest level window recursively destroys the child windows */ | ||
143 | if (window_is_root(menus[i].parent)) { | ||
144 | SDL_DestroyWindow(menus[i].win); | ||
145 | } | ||
146 | } | ||
147 | SDL_free(menus); | ||
148 | menus = NULL; | ||
149 | num_menus = 0; | ||
150 | |||
151 | /* If the tooltip was a child of a popup, it was recursively destroyed with the popup */ | ||
152 | if (!window_is_root(tooltip.parent)) { | ||
153 | SDL_zero(tooltip); | ||
154 | } | ||
155 | } | ||
156 | |||
157 | static void loop(void) | ||
158 | { | ||
159 | int i; | ||
160 | char fmt_str[128]; | ||
161 | SDL_Event event; | ||
162 | |||
163 | /* Check for events */ | ||
164 | while (SDL_PollEvent(&event)) { | ||
165 | if (event.type == SDL_EVENT_MOUSE_MOTION) { | ||
166 | /* Hide the tooltip and restart the timer if the mouse is moved */ | ||
167 | if (tooltip.win) { | ||
168 | SDL_DestroyWindow(tooltip.win); | ||
169 | SDL_zero(tooltip); | ||
170 | } | ||
171 | tooltip_timer = SDL_GetTicks() + TOOLTIP_DELAY; | ||
172 | |||
173 | if (num_menus > 0 && event.motion.windowID == SDL_GetWindowID(menus[0].parent)) { | ||
174 | int x = (int)event.motion.x; | ||
175 | int y = (int)event.motion.y; | ||
176 | |||
177 | SDL_SetWindowPosition(menus[0].win, x, y); | ||
178 | } | ||
179 | } else if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { | ||
180 | /* Left click closes the popup menus */ | ||
181 | if (event.button.button == SDL_BUTTON_LEFT) { | ||
182 | close_popups(); | ||
183 | } else if (event.button.button == SDL_BUTTON_RIGHT) { | ||
184 | /* Create a new popup menu */ | ||
185 | menus = SDL_realloc(menus, sizeof(struct PopupWindow) * (num_menus + 1)); | ||
186 | if (create_popup(&menus[num_menus], true)) { | ||
187 | ++num_menus; | ||
188 | } | ||
189 | } | ||
190 | } else if (event.type == SDL_EVENT_KEY_DOWN) { | ||
191 | if (event.key.key == SDLK_SPACE) { | ||
192 | for (i = 0; i < num_menus; ++i) { | ||
193 | if (SDL_GetWindowFlags(menus[i].win) & SDL_WINDOW_HIDDEN) { | ||
194 | SDL_ShowWindow(menus[i].win); | ||
195 | } else { | ||
196 | SDL_HideWindow(menus[i].win); | ||
197 | } | ||
198 | } | ||
199 | /* Don't process this event in SDLTest_CommonEvent() */ | ||
200 | continue; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | SDLTest_CommonEvent(state, &event, &done); | ||
205 | } | ||
206 | |||
207 | if (done) { | ||
208 | return; | ||
209 | } | ||
210 | |||
211 | /* Show the tooltip if the delay period has elapsed */ | ||
212 | if (SDL_GetTicks() > tooltip_timer) { | ||
213 | if (!tooltip.win) { | ||
214 | create_popup(&tooltip, false); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | /* Draw the window */ | ||
219 | for (i = 0; i < state->num_windows; ++i) { | ||
220 | SDL_Renderer *renderer = state->renderers[i]; | ||
221 | SDL_RenderClear(renderer); | ||
222 | SDL_RenderPresent(renderer); | ||
223 | } | ||
224 | |||
225 | /* Draw the menus in alternating colors */ | ||
226 | for (i = 0; i < num_menus; ++i) { | ||
227 | const SDL_Color *c = &colors[i % SDL_arraysize(colors)]; | ||
228 | SDL_Renderer *renderer = menus[i].renderer; | ||
229 | |||
230 | SDL_SetRenderDrawColor(renderer, c->r, c->g, c->b, c->a); | ||
231 | SDL_RenderClear(renderer); | ||
232 | SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); | ||
233 | SDL_snprintf(fmt_str, sizeof(fmt_str), "Popup Menu %i", i); | ||
234 | SDLTest_DrawString(renderer, 10.0f, 10.0f, fmt_str); | ||
235 | SDL_RenderPresent(renderer); | ||
236 | } | ||
237 | |||
238 | /* Draw the tooltip */ | ||
239 | if (tooltip.win) { | ||
240 | int menu_idx; | ||
241 | |||
242 | SDL_SetRenderDrawColor(tooltip.renderer, 0x00, 0x00, 0x00, 0xFF); | ||
243 | SDL_RenderClear(tooltip.renderer); | ||
244 | SDL_SetRenderDrawColor(tooltip.renderer, 0xFF, 0xFF, 0xFF, 0xFF); | ||
245 | |||
246 | menu_idx = get_menu_index_by_window(tooltip.parent); | ||
247 | if (menu_idx >= 0) { | ||
248 | SDL_snprintf(fmt_str, sizeof(fmt_str), "Tooltip for popup %i", menu_idx); | ||
249 | } else { | ||
250 | SDL_snprintf(fmt_str, sizeof(fmt_str), "Toplevel tooltip"); | ||
251 | } | ||
252 | SDLTest_DrawString(tooltip.renderer, 10.0f, TOOLTIP_HEIGHT / 2, fmt_str); | ||
253 | SDL_RenderPresent(tooltip.renderer); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | int main(int argc, char *argv[]) | ||
258 | { | ||
259 | int i; | ||
260 | |||
261 | /* Initialize test framework */ | ||
262 | state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); | ||
263 | if (!state) { | ||
264 | return 1; | ||
265 | } | ||
266 | |||
267 | /* Parse commandline */ | ||
268 | for (i = 1; i < argc;) { | ||
269 | int consumed; | ||
270 | |||
271 | consumed = SDLTest_CommonArg(state, i); | ||
272 | if (consumed == 0) { | ||
273 | consumed = -1; | ||
274 | if (SDL_strcasecmp(argv[i], "--no-constraints") == 0) { | ||
275 | no_constraints = true; | ||
276 | consumed = 1; | ||
277 | } else if (SDL_strcasecmp(argv[i], "--no-grab") == 0) { | ||
278 | no_grab = true; | ||
279 | consumed = 1; | ||
280 | } | ||
281 | } | ||
282 | if (consumed < 0) { | ||
283 | static const char *options[] = { | ||
284 | "[--no-constraints]", | ||
285 | "[--no-grab]", | ||
286 | NULL | ||
287 | }; | ||
288 | SDLTest_CommonLogUsage(state, argv[0], options); | ||
289 | return 1; | ||
290 | } | ||
291 | i += consumed; | ||
292 | } | ||
293 | |||
294 | if (!SDLTest_CommonInit(state)) { | ||
295 | SDLTest_CommonQuit(state); | ||
296 | quit(2); | ||
297 | } | ||
298 | |||
299 | for (i = 0; i < state->num_windows; ++i) { | ||
300 | SDL_Renderer *renderer = state->renderers[i]; | ||
301 | SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF); | ||
302 | SDL_RenderClear(renderer); | ||
303 | } | ||
304 | |||
305 | /* Main render loop */ | ||
306 | done = 0; | ||
307 | #ifdef SDL_PLATFORM_EMSCRIPTEN | ||
308 | emscripten_set_main_loop(loop, 0, 1); | ||
309 | #else | ||
310 | while (!done) { | ||
311 | loop(); | ||
312 | } | ||
313 | #endif | ||
314 | quit(0); | ||
315 | /* keep the compiler happy ... */ | ||
316 | return 0; | ||
317 | } | ||