123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- /*
- * ui_sdl.h
- * https://gitlab.com/bztsrc/smgui
- *
- * Copyright (C) 2024 bzt (bztsrc@gitlab), MIT license
- *
- * 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 ANY
- * DEVELOPER OR DISTRIBUTOR 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.
- *
- * @brief SDL2/3 backend for SMGUI
- */
- #ifndef UI_SDL_H
- #define UI_SDL_H 1
- #ifndef UI_BACKEND
- #define UI_BACKEND 1
- #else
- #error "An UI backend has already been included"
- #endif
- #include <stdint.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #define SDL_ENABLE_OLD_NAMES
- #include <SDL.h>
- #if SDL_VERSION_ATLEAST(3,0,0)
- #define SDL_ENABLE 1
- #define SDL_DISABLE 0
- #define cdevice jdevice
- #define caxis jaxis
- #define cbutton button
- #endif
- #ifndef UI_H
- #include <ui.h>
- #undef UI_H
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- /**
- * Gamepad structure
- */
- typedef struct {
- int id, btn, lx, ly, rx, ry;
- #if SDL_VERSION_ATLEAST(3,0,0)
- SDL_Gamepad *pad;
- #else
- SDL_GameController *pad;
- #endif
- } ui_gamepad_t;
- /**
- * The UI backend structure, it's backend specific
- */
- typedef struct ui_backend_s {
- void *ctx;
- SDL_Window *window;
- SDL_Renderer *renderer;
- ui_gamepad_t controller[4];
- int btn, nodraw, fullscr, x, y, w, h;
- char path[4096];
- } ui_backend_t;
- /**
- * Toggle fullscreen
- */
- int ui_backend_fullscreen(ui_backend_t *bck)
- {
- SDL_Event event;
- #if SDL_VERSION_ATLEAST(3,0,0)
- const SDL_DisplayMode *dm;
- #else
- SDL_DisplayMode dm;
- #endif
- if(!bck || !bck->window) return UI_ERR_BADINP;
- if((bck->fullscr ^= 1)) {
- bck->w = ((ui_t*)bck->ctx)->screen.w;
- bck->h = ((ui_t*)bck->ctx)->screen.h;
- SDL_GetWindowPosition(bck->window, &bck->x, &bck->y);
- SDL_RenderClear(bck->renderer);
- SDL_RenderPresent(bck->renderer);
- #if SDL_VERSION_ATLEAST(3,0,0)
- dm = SDL_GetDesktopDisplayMode(SDL_GetPrimaryDisplay());
- SDL_SetWindowSize(bck->window, dm->w, dm->h);
- _ui_resize(bck->ctx, dm->w, dm->h);
- #else
- SDL_GetDesktopDisplayMode(0, &dm);
- SDL_SetWindowSize(bck->window, dm.w, dm.h);
- _ui_resize(bck->ctx, dm.w, dm.h);
- #endif
- SDL_SetWindowFullscreen(bck->window, 1);
- while(SDL_PollEvent(&event));
- SDL_WarpMouseInWindow(bck->window, ((ui_t*)bck->ctx)->mousex + bck->x, ((ui_t*)bck->ctx)->mousey + bck->y);
- } else {
- SDL_SetWindowFullscreen(bck->window, 0);
- SDL_SetWindowSize(bck->window, bck->w, bck->h);
- _ui_resize(bck->ctx, bck->w, bck->h);
- while(SDL_PollEvent(&event));
- SDL_WarpMouseInWindow(bck->window, ((ui_t*)bck->ctx)->mousex - bck->x, ((ui_t*)bck->ctx)->mousey - bck->y);
- }
- return UI_OK;
- }
- /**
- * Set window focus
- */
- int ui_backend_focus(ui_backend_t *bck)
- {
- if(!bck || !bck->window) return UI_ERR_BADINP;
- SDL_ShowWindow(bck->window);
- SDL_RaiseWindow(bck->window);
- return UI_OK;
- }
- /**
- * Set window title
- */
- int ui_backend_settitle(ui_backend_t *bck, char *title)
- {
- if(!bck || !title || !*title || !bck->window) return UI_ERR_BADINP;
- SDL_SetWindowTitle(bck->window, title);
- return UI_OK;
- }
- /**
- * Get the clipboard's text
- */
- char *ui_backend_getclipboard(ui_backend_t *bck)
- {
- const char *str = SDL_GetClipboardText();
- char *ret = NULL;
- (void)bck;
- if(str && *str && (ret = (char*)malloc(strlen(str) + 1)))
- strcpy(ret, str);
- return ret;
- }
- /**
- * Set the clipboard's text
- */
- int ui_backend_setclipboard(ui_backend_t *bck, char *str)
- {
- (void)bck;
- SDL_SetClipboardText(str);
- return UI_OK;
- }
- /**
- * Hide hardware mouse cursor
- */
- int ui_backend_hidecursor(ui_backend_t *bck)
- {
- if(!bck || !bck->window) return UI_ERR_BADINP;
- #if SDL_VERSION_ATLEAST(3,0,0)
- SDL_HideCursor();
- #else
- SDL_ShowCursor(SDL_DISABLE);
- #endif
- return UI_OK;
- }
- /**
- * Show hardware mouse cursor
- */
- int ui_backend_showcursor(ui_backend_t *bck)
- {
- if(!bck || !bck->window) return UI_ERR_BADINP;
- #if SDL_VERSION_ATLEAST(3,0,0)
- SDL_ShowCursor();
- #else
- SDL_ShowCursor(SDL_ENABLE);
- #endif
- return UI_OK;
- }
- /**
- * Hide OS-native on-screen keyboard
- */
- int ui_backend_hideosk(ui_backend_t *bck)
- {
- (void)bck;
- #if (!defined(__ANDROID__) && !defined(__IOS__)) || !defined(UI_TEXTOSK)
- SDL_StopTextInput();
- #endif
- return UI_OK;
- }
- /**
- * Show OS-native on-screen keyboard
- */
- int ui_backend_showosk(ui_backend_t *bck)
- {
- (void)bck;
- #if (!defined(__ANDROID__) && !defined(__IOS__)) || !defined(UI_TEXTOSK)
- SDL_StartTextInput();
- #endif
- return UI_OK;
- }
- /**
- * Workaround a stupid iOS and Android bug
- */
- int _ui_backend_stupidios(void *data, SDL_Event *event)
- {
- ui_backend_t *bck = (ui_backend_t*)data;
- if(bck)
- switch(event->type) {
- case SDL_APP_WILLENTERBACKGROUND: bck->nodraw = 1; break;
- case SDL_APP_WILLENTERFOREGROUND: bck->nodraw = 0; break;
- }
- return 1;
- }
- /**
- * Initialize the backend
- */
- int ui_backend_init(ui_t *ctx, char *title, int w, int h, ui_image_t *icon)
- {
- ui_backend_t *bck;
- int i;
- SDL_Surface *srf;
- if(!ctx || !title || !*title || w < 1 || h < 1) return UI_ERR_BADINP;
- if(!(ctx->bck = bck = (ui_backend_t*)realloc(ctx->bck, sizeof(ui_backend_t)))) return UI_ERR_NOMEM;
- memset(bck, 0, sizeof(ui_backend_t));
- bck->ctx = ctx;
- for(i = 0; i < 4; i++)
- bck->controller[i].id = -1;
- #ifndef UI_BACKEND_INITIALIZED
- if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS|SDL_INIT_GAMECONTROLLER)) return UI_ERR_BACKEND;
- #endif
- #if SDL_VERSION_ATLEAST(3,0,0)
- SDL_SetGamepadEventsEnabled(SDL_ENABLE);
- bck->window = SDL_CreateWindow(title, w, h, 0);
- #else
- SDL_GameControllerEventState(SDL_ENABLE);
- bck->window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, SDL_WINDOW_RESIZABLE);
- #endif
- if(!bck->window) {
- memset(bck, 0, sizeof(ui_backend_t));
- #ifndef UI_BACKEND_INITIALIZED
- SDL_Quit();
- #endif
- return UI_ERR_BACKEND;
- }
- SDL_AddEventWatch(_ui_backend_stupidios, bck);
- #if SDL_VERSION_ATLEAST(3,0,0)
- bck->renderer = SDL_CreateRenderer(bck->window, NULL, SDL_RENDERER_ACCELERATED);
- if(!bck->renderer) bck->renderer = SDL_CreateRenderer(bck->window, NULL, SDL_RENDERER_SOFTWARE);
- #else
- bck->renderer = SDL_CreateRenderer(bck->window, -1, SDL_RENDERER_ACCELERATED);
- if(!bck->renderer) bck->renderer = SDL_CreateRenderer(bck->window, -1, SDL_RENDERER_SOFTWARE);
- #endif
- if(!bck->renderer) {
- SDL_DestroyWindow(bck->window);
- memset(bck, 0, sizeof(ui_backend_t));
- #ifndef UI_BACKEND_INITIALIZED
- SDL_Quit();
- #endif
- return UI_ERR_BACKEND;
- }
- if(icon && icon->buf) {
- #if SDL_VERSION_ATLEAST(3,0,0)
- srf = SDL_CreateSurfaceFrom((Uint32 *)icon->buf, icon->w, icon->h, icon->p, SDL_PIXELFORMAT_RGBA8888);
- #else
- srf = SDL_CreateRGBSurfaceFrom((Uint32 *)icon->buf, icon->w, icon->h, 32, icon->p, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
- #endif
- if(srf) {
- SDL_SetWindowIcon(bck->window, srf);
- #if SDL_VERSION_ATLEAST(3,0,0)
- SDL_DestroySurface(srf);
- #else
- SDL_FreeSurface(srf);
- #endif
- }
- }
- ui_backend_focus(bck);
- return UI_OK;
- }
- /**
- * Return a backend specific window handle
- */
- void *ui_backend_getwindow(ui_backend_t *bck)
- {
- return bck ? bck->window : NULL;
- }
- /**
- * Main event handler
- */
- int ui_backend_event(ui_backend_t *bck)
- {
- ui_event_t *evt;
- char keystr[8] = { 0 };
- int i, m, key;
- SDL_Event event = { 0 };
- #if SDL_VERSION_ATLEAST(3,0,0)
- float mx, my;
- #else
- int mx, my;
- #endif
- if(!bck || !bck->window) return UI_ERR_BADINP;
- /* check mouse position */
- SDL_GetMouseState(&mx, &my);
- _ui_setmouse(bck->ctx, (int)mx, (int)my);
- while(SDL_PollEvent(&event)) {
- switch(event.type) {
- #if SDL_VERSION_ATLEAST(3,0,0)
- case SDL_EVENT_QUIT: return 1;
- case SDL_EVENT_WINDOW_RESIZED: {
- #else
- case SDL_QUIT: return 1;
- case SDL_WINDOWEVENT:
- switch(event.window.event) {
- case SDL_WINDOWEVENT_CLOSE: return 1;
- case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SIZE_CHANGED:
- #endif
- _ui_resize(bck->ctx, event.window.data1, event.window.data2);
- break;
- }
- break;
- case SDL_MOUSEBUTTONDOWN:
- m = 0;
- switch(event.button.button) {
- case SDL_BUTTON_LEFT: m = UI_BTN_L; break;
- case SDL_BUTTON_MIDDLE: m = UI_BTN_M; break;
- case SDL_BUTTON_RIGHT: m = UI_BTN_R; break;
- }
- bck->btn |= m;
- if((evt = _ui_evtslot(bck->ctx))) {
- evt->x = (int)mx;
- evt->y = (int)my;
- evt->btn = bck->btn;
- evt->type = UI_EVT_MOUSE;
- }
- break;
- case SDL_MOUSEBUTTONUP:
- m = 0;
- switch(event.button.button) {
- case SDL_BUTTON_LEFT: m = UI_BTN_L; break;
- case SDL_BUTTON_MIDDLE: m = UI_BTN_M; break;
- case SDL_BUTTON_RIGHT: m = UI_BTN_R; break;
- }
- bck->btn &= ~m;
- if((evt = _ui_evtslot(bck->ctx))) {
- evt->x = (int)mx;
- evt->y = (int)my;
- evt->btn = bck->btn | UI_BTN_RELEASE;
- evt->type = UI_EVT_MOUSE;
- }
- break;
- case SDL_MOUSEWHEEL:
- if((evt = _ui_evtslot(bck->ctx))) {
- evt->x = (int)mx;
- evt->y = (int)my;
- evt->btn = bck->btn | (event.wheel.y > 0 ? UI_BTN_U : 0) | (event.wheel.y < 0 ? UI_BTN_D : 0) |
- (event.wheel.x > 0 ? UI_BTN_A : 0) | (event.wheel.x < 0 ? UI_BTN_B : 0);
- evt->type = UI_EVT_MOUSE;
- }
- break;
- case SDL_KEYDOWN:
- switch((key = event.key.keysym.sym)) {
- case SDLK_LSHIFT: bck->btn |= UI_BTN_SHIFT; memcpy(keystr, "LShift", 6); break;
- case SDLK_RSHIFT: bck->btn |= UI_BTN_SHIFT; memcpy(keystr, "RShift", 6); break;
- case SDLK_LCTRL: bck->btn |= UI_BTN_CONTROL; memcpy(keystr, "LCtrl", 5); break;
- case SDLK_RCTRL: bck->btn |= UI_BTN_CONTROL; memcpy(keystr, "RCtrl", 5); break;
- case SDLK_LALT: bck->btn |= UI_BTN_ALT; memcpy(keystr, "LAlt", 4); break;
- case SDLK_RALT: bck->btn |= UI_BTN_ALT; memcpy(keystr, "RAlt", 4); break;
- case SDLK_LGUI: bck->btn |= UI_BTN_GUI; memcpy(keystr, "LGui", 4); break;
- case SDLK_RGUI: bck->btn |= UI_BTN_GUI; memcpy(keystr, "RGui", 4); break;
- case SDLK_ESCAPE: keystr[0] = 0x1b; break;
- case SDLK_BACKSPACE: keystr[0] = '\b'; break;
- case SDLK_TAB: keystr[0] = '\t'; break;
- case SDLK_RETURN: keystr[0] = '\n'; break;
- case SDLK_F1: memcpy(keystr, "F1", 2); break;
- case SDLK_F2: memcpy(keystr, "F2", 2); break;
- case SDLK_F3: memcpy(keystr, "F3", 2); break;
- case SDLK_F4: memcpy(keystr, "F4", 2); break;
- case SDLK_F5: memcpy(keystr, "F5", 2); break;
- case SDLK_F6: memcpy(keystr, "F6", 2); break;
- case SDLK_F7: memcpy(keystr, "F7", 2); break;
- case SDLK_F8: memcpy(keystr, "F8", 2); break;
- case SDLK_F9: memcpy(keystr, "F9", 2); break;
- case SDLK_F10: memcpy(keystr, "F10", 3); break;
- case SDLK_F11: memcpy(keystr, "F11", 3); break;
- case SDLK_F12: memcpy(keystr, "F12", 3); break;
- case SDLK_PRINTSCREEN: memcpy(keystr, "PrScr", 5); break;
- case SDLK_CAPSLOCK: memcpy(keystr, "CLck", 4); break;
- case SDLK_SCROLLLOCK: memcpy(keystr, "SLck", 4); break;
- case SDLK_NUMLOCKCLEAR: memcpy(keystr, "NLck", 4); break;
- case SDLK_UP: memcpy(keystr, "Up", 2); break;
- case SDLK_DOWN: memcpy(keystr, "Down", 4); break;
- case SDLK_LEFT: memcpy(keystr, "Left", 4); break;
- case SDLK_RIGHT: memcpy(keystr, "Right", 5); break;
- case SDLK_HOME: memcpy(keystr, "Home", 4); break;
- case SDLK_END: memcpy(keystr, "End", 3); break;
- case SDLK_PAGEUP: memcpy(keystr, "PgUp", 4); break;
- case SDLK_PAGEDOWN: memcpy(keystr, "PgDown", 6); break;
- case SDLK_INSERT: memcpy(keystr, "Ins", 3); break;
- case SDLK_DELETE: memcpy(keystr, "Del", 3); break;
- case SDLK_APP1: memcpy(keystr, "Int1", 4); break;
- case SDLK_APP2: memcpy(keystr, "Int2", 4); break;
- case SDLK_MENU: memcpy(keystr, "Menu", 4); break;
- case SDLK_z: if(bck->btn == UI_BTN_CONTROL) memcpy(keystr, "Undo", 4); else if(bck->btn & ~UI_BTN_SHIFT) keystr[0] = key; break;
- case SDLK_y: if(bck->btn == UI_BTN_CONTROL) memcpy(keystr, "Redo", 4); else if(bck->btn & ~UI_BTN_SHIFT) keystr[0] = key; break;
- case SDLK_x: if(bck->btn == UI_BTN_CONTROL) memcpy(keystr, "Cut", 3); else if(bck->btn & ~UI_BTN_SHIFT) keystr[0] = key; break;
- case SDLK_c: if(bck->btn == UI_BTN_CONTROL) memcpy(keystr, "Copy", 4); else if(bck->btn & ~UI_BTN_SHIFT) keystr[0] = key; break;
- case SDLK_v: if(bck->btn == UI_BTN_CONTROL) memcpy(keystr, "Paste", 5); else if(bck->btn & ~UI_BTN_SHIFT) keystr[0] = key; break;
- case SDLK_SELECT: memcpy(keystr, "Select", 6); break;
- case SDLK_STOP: memcpy(keystr, "Stop", 4); break;
- case SDLK_AGAIN: memcpy(keystr, "Redo", 4); break;
- case SDLK_UNDO: memcpy(keystr, "Undo", 4); break;
- case SDLK_CUT: memcpy(keystr, "Cut", 3); break;
- case SDLK_COPY: memcpy(keystr, "Copy", 4); break;
- case SDLK_PASTE: memcpy(keystr, "Paste", 5); break;
- case SDLK_FIND: memcpy(keystr, "Find", 4); break;
- case SDLK_MUTE: memcpy(keystr, "Mute", 4); break;
- case SDLK_VOLUMEUP: memcpy(keystr, "Vol+", 4); break;
- case SDLK_VOLUMEDOWN: memcpy(keystr, "Vol-", 4); break;
- default: if((bck->btn & ~UI_BTN_SHIFT) && key >= SDLK_a && key <= SDLK_z) keystr[0] = key; break;
- }
- if(keystr[0] && (evt = _ui_evtslot(bck->ctx))) {
- memcpy(evt->key, keystr, 8);
- evt->btn = (bck->btn & 0xf00000);
- evt->type = UI_EVT_KEY;
- }
- break;
- case SDL_KEYUP:
- switch(event.key.keysym.sym) {
- case SDLK_LSHIFT: bck->btn &= ~UI_BTN_SHIFT; memcpy(keystr, "LShift", 6); break;
- case SDLK_RSHIFT: bck->btn &= ~UI_BTN_SHIFT; memcpy(keystr, "RShift", 6); break;
- case SDLK_LCTRL: bck->btn &= ~UI_BTN_CONTROL; memcpy(keystr, "LCtrl", 5); break;
- case SDLK_RCTRL: bck->btn &= ~UI_BTN_CONTROL; memcpy(keystr, "RCtrl", 5); break;
- case SDLK_LALT: bck->btn &= ~UI_BTN_ALT; memcpy(keystr, "LAlt", 4); break;
- case SDLK_RALT: bck->btn &= ~UI_BTN_ALT; memcpy(keystr, "RAlt", 4); break;
- case SDLK_LGUI: bck->btn &= ~UI_BTN_GUI; memcpy(keystr, "LGui", 4); break;
- case SDLK_RGUI: bck->btn &= ~UI_BTN_GUI; memcpy(keystr, "RGui", 4); break;
- }
- if(keystr[0] && (evt = _ui_evtslot(bck->ctx))) {
- memcpy(evt->key, keystr, 8);
- evt->btn = (bck->btn & 0xf00000) | UI_BTN_RELEASE;
- evt->type = UI_EVT_KEY;
- }
- break;
- case SDL_TEXTINPUT:
- if(!(bck->btn & ~UI_BTN_SHIFT) && (uint8_t)event.text.text[0] >= 32 && (evt = _ui_evtslot(bck->ctx))) {
- memcpy(evt->key, &event.text.text, 8);
- evt->btn = (bck->btn & 0xf00000);
- evt->type = UI_EVT_KEY;
- }
- break;
- case SDL_CONTROLLERDEVICEADDED:
- for(i = 0; i < 4 && bck->controller[i].id != (int)event.cdevice.which; i++);
- if(i >= 4) for(i = 0; i < 4 && bck->controller[i].id != -1; i++);
- if(i < 4) {
- if(bck->controller[i].pad) SDL_GameControllerClose(bck->controller[i].pad);
- bck->controller[i].pad = SDL_GameControllerOpen(event.cdevice.which);
- bck->controller[i].id = event.cdevice.which;
- }
- break;
- case SDL_CONTROLLERDEVICEREMOVED:
- for(i = 0; i < 4 && bck->controller[i].id != (int)event.cdevice.which; i++);
- if(i < 4) {
- if(bck->controller[i].pad) SDL_GameControllerClose(bck->controller[i].pad);
- bck->controller[i].pad = NULL;
- bck->controller[i].id = -1;
- }
- break;
- case SDL_CONTROLLERBUTTONDOWN:
- for(i = 0; i < 4 && bck->controller[i].id != (int)event.cbutton.which; i++);
- if(i < 4) {
- m = 0;
- switch(event.cbutton.button) {
- case SDL_CONTROLLER_BUTTON_DPAD_LEFT: m |= UI_BTN_L; break;
- case SDL_CONTROLLER_BUTTON_DPAD_UP: m |= UI_BTN_U; break;
- case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: m |= UI_BTN_R; break;
- case SDL_CONTROLLER_BUTTON_DPAD_DOWN: m |= UI_BTN_D; break;
- case SDL_CONTROLLER_BUTTON_A: m |= UI_BTN_A; break;
- case SDL_CONTROLLER_BUTTON_B: m |= UI_BTN_B; break;
- case SDL_CONTROLLER_BUTTON_X: m |= UI_BTN_X; break;
- case SDL_CONTROLLER_BUTTON_Y: m |= UI_BTN_Y; break;
- case SDL_CONTROLLER_BUTTON_BACK: m |= UI_BTN_BA; break;
- case SDL_CONTROLLER_BUTTON_GUIDE: m |= UI_BTN_GU; break;
- case SDL_CONTROLLER_BUTTON_START: m |= UI_BTN_ST; break;
- case SDL_CONTROLLER_BUTTON_LEFTSTICK: m |= UI_BTN_LT; break;
- case SDL_CONTROLLER_BUTTON_RIGHTSTICK: m |= UI_BTN_RT; break;
- case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: m |= UI_BTN_LS; break;
- case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: m |= UI_BTN_RS; break;
- }
- bck->controller[i].btn |= m;
- if((evt = _ui_evtslot(bck->ctx))) {
- evt->key[0] = i;
- evt->btn = (bck->btn & 0xf00000) | bck->controller[i].btn;
- evt->x = bck->controller[i].lx;
- evt->y = bck->controller[i].ly;
- evt->rx = bck->controller[i].rx;
- evt->ry = bck->controller[i].ry;
- evt->type = UI_EVT_GAMEPAD;
- }
- }
- break;
- case SDL_CONTROLLERBUTTONUP:
- for(i = 0; i < 4 && bck->controller[i].id != (int)event.cbutton.which; i++);
- if(i < 4) {
- m = 0;
- switch(event.cbutton.button) {
- case SDL_CONTROLLER_BUTTON_DPAD_LEFT: m |= UI_BTN_L; break;
- case SDL_CONTROLLER_BUTTON_DPAD_UP: m |= UI_BTN_U; break;
- case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: m |= UI_BTN_R; break;
- case SDL_CONTROLLER_BUTTON_DPAD_DOWN: m |= UI_BTN_D; break;
- case SDL_CONTROLLER_BUTTON_A: m |= UI_BTN_A; break;
- case SDL_CONTROLLER_BUTTON_B: m |= UI_BTN_B; break;
- case SDL_CONTROLLER_BUTTON_X: m |= UI_BTN_X; break;
- case SDL_CONTROLLER_BUTTON_Y: m |= UI_BTN_Y; break;
- case SDL_CONTROLLER_BUTTON_BACK: m |= UI_BTN_BA; break;
- case SDL_CONTROLLER_BUTTON_GUIDE: m |= UI_BTN_GU; break;
- case SDL_CONTROLLER_BUTTON_START: m |= UI_BTN_ST; break;
- case SDL_CONTROLLER_BUTTON_LEFTSTICK: m |= UI_BTN_LT; break;
- case SDL_CONTROLLER_BUTTON_RIGHTSTICK: m |= UI_BTN_RT; break;
- case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: m |= UI_BTN_LS; break;
- case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: m |= UI_BTN_RS; break;
- }
- bck->controller[i].btn &= ~m;
- if((evt = _ui_evtslot(bck->ctx))) {
- evt->key[0] = i;
- evt->btn = (bck->btn & 0xf00000) | bck->controller[i].btn | UI_BTN_RELEASE;
- evt->x = bck->controller[i].lx;
- evt->y = bck->controller[i].ly;
- evt->rx = bck->controller[i].rx;
- evt->ry = bck->controller[i].ry;
- evt->type = UI_EVT_GAMEPAD;
- }
- }
- break;
- case SDL_CONTROLLERAXISMOTION:
- for(i = 0; i < 4 && bck->controller[i].id != (int)event.cbutton.which; i++);
- if(i < 4) {
- switch(event.caxis.axis) {
- case SDL_CONTROLLER_AXIS_LEFTX: bck->controller[i].lx = event.caxis.value; break;
- case SDL_CONTROLLER_AXIS_LEFTY: bck->controller[i].ly = event.caxis.value; break;
- case SDL_CONTROLLER_AXIS_RIGHTX: bck->controller[i].rx = event.caxis.value; break;
- case SDL_CONTROLLER_AXIS_RIGHTY: bck->controller[i].ry = event.caxis.value; break;
- }
- if((evt = _ui_evtslot(bck->ctx))) {
- evt->key[0] = i;
- evt->btn = (bck->btn & 0xf00000) | bck->controller[i].btn;
- evt->x = bck->controller[i].lx;
- evt->y = bck->controller[i].ly;
- evt->rx = bck->controller[i].rx;
- evt->ry = bck->controller[i].ry;
- evt->type = UI_EVT_GAMEPAD;
- }
- }
- break;
- case SDL_DROPFILE:
- if(event.drop.file) {
- if((evt = _ui_evtslot(bck->ctx))) {
- evt->x = (int)mx;
- evt->y = (int)my;
- strncpy(bck->path, !memcmp(event.drop.file, "file://", 7) ? event.drop.file + 7 : event.drop.file, sizeof(bck->path) - 1);
- evt->fn = bck->path;
- evt->btn = (bck->btn & 0xf00000);
- evt->type = UI_EVT_DROP;
- }
- SDL_free(event.drop.file);
- }
- break;
- }
- }
- return UI_OK;
- }
- /**
- * Main redraw handler
- */
- int ui_backend_redraw(ui_backend_t *bck)
- {
- ui_t *ctx;
- int i, p;
- uint8_t *s, *d;
- SDL_Texture *screen;
- #if SDL_VERSION_ATLEAST(3,0,0)
- SDL_FRect rect;
- #else
- SDL_Rect rect;
- #endif
- if(!bck || !bck->window) return UI_ERR_BADINP;
- if(bck->nodraw) return UI_OK;
- ctx = (ui_t*)bck->ctx;
- if(!ctx || !ctx->screen.buf) return UI_ERR_BADINP;
- if(!(screen = SDL_CreateTexture(bck->renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STREAMING, ctx->screen.w, ctx->screen.h)))
- return UI_ERR_BACKEND;
- #if SDL_VERSION_ATLEAST(2,0,12)
- SDL_SetTextureScaleMode(screen,
- #if SDL_VERSION_ATLEAST(3,0,0)
- SDL_SCALEMODE_NEAREST
- #else
- SDL_ScaleModeNearest
- #endif
- );
- #endif
- SDL_SetTextureBlendMode(screen, SDL_BLENDMODE_BLEND);
- SDL_LockTexture(screen, NULL, (void**)&d, &p);
- for(i = 0, s = ctx->screen.buf; i < ctx->screen.h; i++, s += ctx->screen.p, d += p)
- memcpy(d, s, ctx->screen.p);
- SDL_UnlockTexture(screen);
- rect.x = rect.y = 0; rect.w = ctx->screen.w; rect.h = ctx->screen.h;
- SDL_RenderCopy(bck->renderer, screen, &rect, &rect);
- SDL_DestroyTexture(screen);
- #ifndef UI_BACKEND_NOFLUSH
- SDL_RenderPresent(bck->renderer);
- #endif
- return UI_OK;
- }
- /**
- * Free backend resources
- */
- int ui_backend_free(ui_backend_t *bck)
- {
- if(!bck) return UI_ERR_BADINP;
- if(bck->fullscr) ui_backend_fullscreen(bck);
- /* this crashes sometimes... but only sometimes... We are about to exit so should be freed anyway */
- /* if(bck->renderer) SDL_DestroyRenderer(bck->renderer);*/
- if(bck->window) SDL_DestroyWindow(bck->window);
- free(bck);
- #ifndef UI_BACKEND_INITIALIZED
- SDL_Quit();
- #endif
- return UI_OK;
- }
- #ifdef __cplusplus
- }
- #endif
- #endif /* UI_SDL_H */
|