Atlas - testcustomcursor.c

Home / ext / SDL / test Lines: 1 | Size: 18363 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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 13#include <SDL3/SDL_test_common.h> 14#include <SDL3/SDL_main.h> 15 16#ifdef SDL_PLATFORM_EMSCRIPTEN 17#include <emscripten/emscripten.h> 18#endif 19 20#include <stdlib.h> 21 22/* Stolen from the mailing list */ 23/* Creates a new mouse cursor from an XPM */ 24 25/* XPM */ 26static const char *arrow[] = { 27 /* width height num_colors chars_per_pixel */ 28 " 32 32 3 1", 29 /* colors */ 30 "X c #000000", 31 ". c #ffffff", 32 " c None", 33 /* pixels */ 34 "X ", 35 "XX ", 36 "X.X ", 37 "X..X ", 38 "X...X ", 39 "X....X ", 40 "X.....X ", 41 "X......X ", 42 "X.......X ", 43 "X........X ", 44 "X.....XXXXX ", 45 "X..X..X ", 46 "X.X X..X ", 47 "XX X..X ", 48 "X X..X ", 49 " X..X ", 50 " X..X ", 51 " X..X ", 52 " XX ", 53 " ", 54 " ", 55 " ", 56 " ", 57 " ", 58 " ", 59 " ", 60 " ", 61 " ", 62 " ", 63 " ", 64 " ", 65 " ", 66 "0,0" 67}; 68 69static const char *cross[] = { 70 /* width height num_colors chars_per_pixel */ 71 " 32 32 3 1", 72 /* colors */ 73 "o c #000000", 74 ". c #ffffff", 75 " c None", 76 /* pixels */ 77 " ", 78 " ", 79 " ", 80 " ", 81 " oo ", 82 " oo ", 83 " oo ", 84 " oo ", 85 " oo ", 86 " oo ", 87 " oo ", 88 " oo ", 89 " oo ", 90 " oo ", 91 " oo ", 92 " oooooooooooooooooooooooo ", 93 " oooooooooooooooooooooooo ", 94 " oo ", 95 " oo ", 96 " oo ", 97 " oo ", 98 " oo ", 99 " oo ", 100 " oo ", 101 " oo ", 102 " oo ", 103 " oo ", 104 " oo ", 105 " ", 106 " ", 107 " ", 108 " ", 109 "16,16" 110}; 111 112static SDL_Surface *load_image_file(const char *file) 113{ 114 SDL_Surface *surface = SDL_LoadSurface(file); 115 if (surface) { 116 if (SDL_GetSurfacePalette(surface)) { 117 const Uint8 bpp = SDL_BITSPERPIXEL(surface->format); 118 const Uint8 mask = (1 << bpp) - 1; 119 if (SDL_PIXELORDER(surface->format) == SDL_BITMAPORDER_4321) 120 SDL_SetSurfaceColorKey(surface, 1, (*(Uint8 *)surface->pixels) & mask); 121 else 122 SDL_SetSurfaceColorKey(surface, 1, ((*(Uint8 *)surface->pixels) >> (8 - bpp)) & mask); 123 } else { 124 switch (SDL_BITSPERPIXEL(surface->format)) { 125 case 15: 126 SDL_SetSurfaceColorKey(surface, 1, (*(Uint16 *)surface->pixels) & 0x00007FFF); 127 break; 128 case 16: 129 SDL_SetSurfaceColorKey(surface, 1, *(Uint16 *)surface->pixels); 130 break; 131 case 24: 132 SDL_SetSurfaceColorKey(surface, 1, (*(Uint32 *)surface->pixels) & 0x00FFFFFF); 133 break; 134 case 32: 135 SDL_SetSurfaceColorKey(surface, 1, *(Uint32 *)surface->pixels); 136 break; 137 } 138 } 139 } 140 return surface; 141} 142 143static SDL_Surface *load_image(const char *file) 144{ 145 SDL_Surface *surface = load_image_file(file); 146 if (surface) { 147 /* Add a 2x version of this image, if available */ 148 SDL_Surface *surface2x = NULL; 149 const char *ext = SDL_strrchr(file, '.'); 150 size_t len = SDL_strlen(file) + 2 + 1; 151 char *file2x = (char *)SDL_malloc(len); 152 if (file2x) { 153 SDL_strlcpy(file2x, file, len); 154 if (ext) { 155 SDL_memcpy(file2x + (ext - file), "2x", 3); 156 SDL_strlcat(file2x, ext, len); 157 } else { 158 SDL_strlcat(file2x, "2x", len); 159 } 160 surface2x = load_image_file(file2x); 161 SDL_free(file2x); 162 } 163 if (surface2x) { 164 SDL_AddSurfaceAlternateImage(surface, surface2x); 165 SDL_DestroySurface(surface2x); 166 } 167 } 168 return surface; 169} 170 171static SDL_Cursor *init_color_cursor(char **files, int num_frames) 172{ 173 SDL_Cursor *cursor = NULL; 174 SDL_CursorFrameInfo *frames = (SDL_CursorFrameInfo *)SDL_calloc(num_frames, sizeof(SDL_CursorFrameInfo)); 175 int i; 176 177 for (i = 0; i < num_frames; i++) { 178 SDL_Surface *img = load_image(files[i]); 179 if (!img) { 180 SDL_LogWarn(SDL_LOG_CATEGORY_TEST, "Failed to load %s", files[i]); 181 goto cleanup; 182 } 183 frames[i].surface = img; 184 if (i > 0) { 185 frames[i].duration = 150; 186 } 187 } 188 189 if (num_frames == 1) { 190 cursor = SDL_CreateColorCursor(frames[0].surface, 0, 0); 191 } else { 192 cursor = SDL_CreateAnimatedCursor(frames, num_frames, 0, 0); 193 } 194 195cleanup: 196 for (i = 0; i < num_frames; ++i) { 197 SDL_DestroySurface(frames[i].surface); 198 } 199 SDL_free(frames); 200 201 return cursor; 202} 203 204static SDL_Cursor *init_system_cursor(const char *image[]) 205{ 206 int i, row, col; 207 Uint8 data[4 * 32]; 208 Uint8 mask[4 * 32]; 209 int hot_x = 0; 210 int hot_y = 0; 211 212 i = -1; 213 for (row = 0; row < 32; ++row) { 214 for (col = 0; col < 32; ++col) { 215 if (col % 8) { 216 data[i] <<= 1; 217 mask[i] <<= 1; 218 } else { 219 ++i; 220 data[i] = mask[i] = 0; 221 } 222 switch (image[4 + row][col]) { 223 case 'X': 224 data[i] |= 0x01; 225 mask[i] |= 0x01; 226 break; 227 case '.': 228 mask[i] |= 0x01; 229 break; 230 case 'o': 231 data[i] |= 0x01; 232 break; 233 case ' ': 234 break; 235 } 236 } 237 } 238 (void)SDL_sscanf(image[4 + row], "%d,%d", &hot_x, &hot_y); 239 return SDL_CreateCursor(data, mask, 32, 32, hot_x, hot_y); 240} 241 242static SDL_Cursor *init_animated_cursor(const char *image[], bool oneshot) 243{ 244 int row, col; 245 SDL_Surface *surface, *invsurface; 246 Uint32 *pixels, *invpixels; 247 SDL_CursorFrameInfo frames[6]; 248 int hot_x = 0; 249 int hot_y = 0; 250 251 surface = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_ARGB8888); 252 if (!surface) { 253 return NULL; 254 } 255 256 invsurface = SDL_CreateSurface(32, 32, SDL_PIXELFORMAT_ARGB8888); 257 if (!invsurface) { 258 SDL_DestroySurface(surface); 259 return NULL; 260 } 261 262 for (row = 4; row < 36; ++row) { 263 pixels = (Uint32 *)((Uint8 *)surface->pixels + ((row - 4) * surface->pitch)); 264 invpixels = (Uint32 *)((Uint8 *)invsurface->pixels + ((row - 4) * surface->pitch)); 265 for (col = 0; col < 32; ++col) { 266 switch (image[row][col]) { 267 case 'X': 268 pixels[col] = 0xFFFFFFFF; 269 invpixels[col] = 0xFF000000; 270 break; 271 case '.': 272 pixels[col] = 0xFF000000; 273 invpixels[col] = 0xFFFFFFFF; 274 break; 275 case ' ': 276 pixels[col] = 0; 277 invpixels[col] = 0; 278 break; 279 } 280 } 281 } 282 283 int frame_count = 2; 284 285 frames[0].surface = surface; 286 frames[0].duration = 100; 287 288 frames[1].surface = invsurface; 289 frames[1].duration = 100; 290 291 if (oneshot) { 292 frames[2].surface = surface; 293 frames[2].duration = 200; 294 295 frames[3].surface = invsurface; 296 frames[3].duration = 300; 297 298 frames[4].surface = surface; 299 frames[4].duration = 400; 300 301 frames[5].surface = invsurface; 302 frames[5].duration = 0; 303 304 frame_count = 6; 305 } 306 307 SDL_Cursor *cursor = SDL_CreateAnimatedCursor(frames, frame_count, hot_x, hot_y); 308 309 SDL_DestroySurface(surface); 310 SDL_DestroySurface(invsurface); 311 312 return cursor; 313} 314 315static SDLTest_CommonState *state; 316static int done; 317static SDL_Cursor *cursors[5 + SDL_SYSTEM_CURSOR_COUNT]; 318static SDL_SystemCursor cursor_types[5 + SDL_SYSTEM_CURSOR_COUNT]; 319static int num_cursors; 320static int current_cursor; 321static bool show_cursor; 322 323/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 324static void 325quit(int rc) 326{ 327 SDLTest_CommonQuit(state); 328 /* Let 'main()' return normally */ 329 if (rc != 0) { 330 exit(rc); 331 } 332} 333 334static void loop(void) 335{ 336 int i; 337 SDL_Event event; 338 /* Check for events */ 339 while (SDL_PollEvent(&event)) { 340 SDLTest_CommonEvent(state, &event, &done); 341 if (event.type == SDL_EVENT_MOUSE_BUTTON_DOWN) { 342 if (event.button.button == SDL_BUTTON_LEFT) { 343 if (num_cursors == 0) { 344 continue; 345 } 346 347 ++current_cursor; 348 if (current_cursor == num_cursors) { 349 current_cursor = 0; 350 } 351 352 SDL_SetCursor(cursors[current_cursor]); 353 354 switch ((int)cursor_types[current_cursor]) { 355 case (SDL_SystemCursor)-3: 356 SDL_Log("Animated custom cursor (one-shot)"); 357 break; 358 case (SDL_SystemCursor)-2: 359 SDL_Log("Animated custom cursor"); 360 break; 361 case (SDL_SystemCursor)-1: 362 SDL_Log("Custom cursor"); 363 break; 364 case SDL_SYSTEM_CURSOR_DEFAULT: 365 SDL_Log("Default"); 366 break; 367 case SDL_SYSTEM_CURSOR_TEXT: 368 SDL_Log("Text"); 369 break; 370 case SDL_SYSTEM_CURSOR_WAIT: 371 SDL_Log("Wait"); 372 break; 373 case SDL_SYSTEM_CURSOR_CROSSHAIR: 374 SDL_Log("Crosshair"); 375 break; 376 case SDL_SYSTEM_CURSOR_PROGRESS: 377 SDL_Log("Progress: Small wait cursor (or Wait if not available)"); 378 break; 379 case SDL_SYSTEM_CURSOR_NWSE_RESIZE: 380 SDL_Log("Double arrow pointing northwest and southeast"); 381 break; 382 case SDL_SYSTEM_CURSOR_NESW_RESIZE: 383 SDL_Log("Double arrow pointing northeast and southwest"); 384 break; 385 case SDL_SYSTEM_CURSOR_EW_RESIZE: 386 SDL_Log("Double arrow pointing west and east"); 387 break; 388 case SDL_SYSTEM_CURSOR_NS_RESIZE: 389 SDL_Log("Double arrow pointing north and south"); 390 break; 391 case SDL_SYSTEM_CURSOR_MOVE: 392 SDL_Log("Move: Four pointed arrow pointing north, south, east, and west"); 393 break; 394 case SDL_SYSTEM_CURSOR_NOT_ALLOWED: 395 SDL_Log("Not Allowed: Slashed circle or crossbones"); 396 break; 397 case SDL_SYSTEM_CURSOR_POINTER: 398 SDL_Log("Pointer: Hand"); 399 break; 400 case SDL_SYSTEM_CURSOR_NW_RESIZE: 401 SDL_Log("Window resize top-left"); 402 break; 403 case SDL_SYSTEM_CURSOR_N_RESIZE: 404 SDL_Log("Window resize top"); 405 break; 406 case SDL_SYSTEM_CURSOR_NE_RESIZE: 407 SDL_Log("Window resize top-right"); 408 break; 409 case SDL_SYSTEM_CURSOR_E_RESIZE: 410 SDL_Log("Window resize right"); 411 break; 412 case SDL_SYSTEM_CURSOR_SE_RESIZE: 413 SDL_Log("Window resize bottom-right"); 414 break; 415 case SDL_SYSTEM_CURSOR_S_RESIZE: 416 SDL_Log("Window resize bottom"); 417 break; 418 case SDL_SYSTEM_CURSOR_SW_RESIZE: 419 SDL_Log("Window resize bottom-left"); 420 break; 421 case SDL_SYSTEM_CURSOR_W_RESIZE: 422 SDL_Log("Window resize left"); 423 break; 424 default: 425 SDL_Log("UNKNOWN CURSOR TYPE, FIX THIS PROGRAM."); 426 break; 427 } 428 429 } else { 430 show_cursor = !show_cursor; 431 if (show_cursor) { 432 SDL_ShowCursor(); 433 } else { 434 SDL_HideCursor(); 435 } 436 } 437 } 438 } 439 440 for (i = 0; i < state->num_windows; ++i) { 441 SDL_Renderer *renderer = state->renderers[i]; 442 SDL_FRect rect; 443 int x, y, row; 444 int window_w = 0, window_h = 0; 445 const float scale = SDL_GetWindowPixelDensity(state->windows[i]); 446 447 SDL_GetWindowSizeInPixels(state->windows[i], &window_w, &window_h); 448 rect.w = 128.0f * scale; 449 rect.h = 128.0f * scale; 450 for (y = 0, row = 0; y < window_h; y += (int)rect.h, ++row) { 451 bool black = ((row % 2) == 0) ? true : false; 452 for (x = 0; x < window_w; x += (int)rect.w) { 453 rect.x = (float)x; 454 rect.y = (float)y; 455 456 if (black) { 457 SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 0xFF); 458 } else { 459 SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF); 460 } 461 SDL_RenderFillRect(renderer, &rect); 462 463 black = !black; 464 } 465 } 466 SDL_RenderPresent(renderer); 467 } 468#ifdef SDL_PLATFORM_EMSCRIPTEN 469 if (done) { 470 emscripten_cancel_main_loop(); 471 } 472#endif 473} 474 475int main(int argc, char *argv[]) 476{ 477 int i; 478 char **frames = NULL; 479 int num_frames = -1; 480 SDL_Cursor *cursor; 481 482 /* Initialize test framework */ 483 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 484 if (!state) { 485 return 1; 486 } 487 488 for (i = 1; i < argc;) { 489 int consumed; 490 491 consumed = SDLTest_CommonArg(state, i); 492 if (consumed == 0) { 493 if (SDL_strcmp(argv[i], "--frames") == 0 && frames == NULL) { 494 num_frames = 0; 495 while (i + 1 + num_frames < argc && argv[i + 1 + num_frames][0] != '-') { 496 num_frames += 1; 497 } 498 frames = &argv[i + 1]; 499 consumed = num_frames + 1; 500 } 501 } 502 if (consumed <= 0) { 503 static const char *options[] = { "[--frames frame0.bmp [frame1.bmp [frame2.bmp ...]]]", NULL}; 504 SDLTest_CommonLogUsage(state, argv[0], options); 505 quit(1); 506 } 507 i += consumed; 508 } 509 510 if (!SDLTest_CommonInit(state)) { 511 quit(2); 512 } 513 514 num_cursors = 0; 515 516 if (num_frames > 0) { 517 /* Only load the first file in the list for the icon. */ 518 SDL_Surface *icon = load_image(frames[0]); 519 if (icon) { 520 for (i = 0; i < state->num_windows; ++i) { 521 SDL_SetWindowIcon(state->windows[i], icon); 522 } 523 SDL_DestroySurface(icon); 524 } 525 526 cursor = init_color_cursor(frames, num_frames); 527 if (cursor) { 528 cursors[num_cursors] = cursor; 529 cursor_types[num_cursors] = (SDL_SystemCursor)-1; 530 num_cursors++; 531 } 532 } 533 534 cursor = init_system_cursor(arrow); 535 if (cursor) { 536 cursors[num_cursors] = cursor; 537 cursor_types[num_cursors] = (SDL_SystemCursor)-1; 538 num_cursors++; 539 } 540 541 cursor = init_system_cursor(cross); 542 if (cursor) { 543 cursors[num_cursors] = cursor; 544 cursor_types[num_cursors] = (SDL_SystemCursor)-1; 545 num_cursors++; 546 } 547 548 cursor = init_animated_cursor(arrow, false); 549 if (cursor) { 550 cursors[num_cursors] = cursor; 551 cursor_types[num_cursors] = (SDL_SystemCursor)-2; 552 num_cursors++; 553 } 554 555 cursor = init_animated_cursor(arrow, true); 556 if (cursor) { 557 cursors[num_cursors] = cursor; 558 cursor_types[num_cursors] = (SDL_SystemCursor)-3; 559 num_cursors++; 560 } 561 562 for (i = 0; i < SDL_SYSTEM_CURSOR_COUNT; ++i) { 563 cursor = SDL_CreateSystemCursor((SDL_SystemCursor)i); 564 if (cursor) { 565 cursors[num_cursors] = cursor; 566 cursor_types[num_cursors] = i; 567 num_cursors++; 568 } 569 } 570 571 if (num_cursors > 0) { 572 SDL_SetCursor(cursors[0]); 573 } 574 575 show_cursor = SDL_CursorVisible(); 576 577 /* Main render loop */ 578 done = 0; 579#ifdef SDL_PLATFORM_EMSCRIPTEN 580 emscripten_set_main_loop(loop, 0, 1); 581#else 582 while (!done) { 583 loop(); 584 } 585#endif 586 587 for (i = 0; i < num_cursors; ++i) { 588 SDL_DestroyCursor(cursors[i]); 589 } 590 quit(0); 591 592 /* keep the compiler happy ... */ 593 return 0; 594} 595
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.