TWP: Move ImGui to backends

This commit is contained in:
scemino 2024-02-25 14:12:33 +01:00 committed by Eugene Sandulenko
parent 158257c0f9
commit 0cba66b204
32 changed files with 1191 additions and 1200 deletions

View File

@ -32,6 +32,10 @@
#include "engines/engine.h"
#include "gui/gui-manager.h"
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
#include "backends/imgui/backends/imgui_impl_sdl2_scummvm.h"
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
#define GAMECONTROLLERDB_FILE "gamecontrollerdb.txt"
@ -74,9 +78,10 @@ SdlEventSource::SdlEventSource()
: EventSource(), _scrollLock(false), _joystick(nullptr), _lastScreenID(0), _graphicsManager(nullptr), _queuedFakeMouseMove(false),
_lastHatPosition(SDL_HAT_CENTERED), _mouseX(0), _mouseY(0), _engineRunning(false)
#if SDL_VERSION_ATLEAST(2, 0, 0)
, _queuedFakeKeyUp(false), _fakeKeyUp(), _controller(nullptr)
,
_queuedFakeKeyUp(false), _fakeKeyUp(), _controller(nullptr)
#endif
{
{
int joystick_num = ConfMan.getInt("joystick_num");
if (joystick_num >= 0) {
// Initialize SDL joystick subsystem
@ -129,7 +134,7 @@ int SdlEventSource::mapKey(SDL_Keycode sdlKey, SDL_Keymod mod, Uint16 unicode) {
// We allow Hebrew characters
if (unicode >= 0x05D0 && unicode <= 0x05EA)
return unicode;
// Cyrillic
if (unicode >= 0x0400 && unicode <= 0x045F)
return unicode;
@ -210,198 +215,383 @@ void SdlEventSource::SDLModToOSystemKeyFlags(SDL_Keymod mod, Common::Event &even
Common::KeyCode SdlEventSource::SDLToOSystemKeycode(const SDL_Keycode key) {
switch (key) {
case SDLK_BACKSPACE: return Common::KEYCODE_BACKSPACE;
case SDLK_TAB: return Common::KEYCODE_TAB;
case SDLK_CLEAR: return Common::KEYCODE_CLEAR;
case SDLK_RETURN: return Common::KEYCODE_RETURN;
case SDLK_PAUSE: return Common::KEYCODE_PAUSE;
case SDLK_ESCAPE: return Common::KEYCODE_ESCAPE;
case SDLK_SPACE: return Common::KEYCODE_SPACE;
case SDLK_EXCLAIM: return Common::KEYCODE_EXCLAIM;
case SDLK_QUOTEDBL: return Common::KEYCODE_QUOTEDBL;
case SDLK_HASH: return Common::KEYCODE_HASH;
case SDLK_DOLLAR: return Common::KEYCODE_DOLLAR;
case SDLK_AMPERSAND: return Common::KEYCODE_AMPERSAND;
case SDLK_QUOTE: return Common::KEYCODE_QUOTE;
case SDLK_LEFTPAREN: return Common::KEYCODE_LEFTPAREN;
case SDLK_RIGHTPAREN: return Common::KEYCODE_RIGHTPAREN;
case SDLK_ASTERISK: return Common::KEYCODE_ASTERISK;
case SDLK_PLUS: return Common::KEYCODE_PLUS;
case SDLK_COMMA: return Common::KEYCODE_COMMA;
case SDLK_MINUS: return Common::KEYCODE_MINUS;
case SDLK_PERIOD: return Common::KEYCODE_PERIOD;
case SDLK_SLASH: return Common::KEYCODE_SLASH;
case SDLK_0: return Common::KEYCODE_0;
case SDLK_1: return Common::KEYCODE_1;
case SDLK_2: return Common::KEYCODE_2;
case SDLK_3: return Common::KEYCODE_3;
case SDLK_4: return Common::KEYCODE_4;
case SDLK_5: return Common::KEYCODE_5;
case SDLK_6: return Common::KEYCODE_6;
case SDLK_7: return Common::KEYCODE_7;
case SDLK_8: return Common::KEYCODE_8;
case SDLK_9: return Common::KEYCODE_9;
case SDLK_COLON: return Common::KEYCODE_COLON;
case SDLK_SEMICOLON: return Common::KEYCODE_SEMICOLON;
case SDLK_LESS: return Common::KEYCODE_LESS;
case SDLK_EQUALS: return Common::KEYCODE_EQUALS;
case SDLK_GREATER: return Common::KEYCODE_GREATER;
case SDLK_QUESTION: return Common::KEYCODE_QUESTION;
case SDLK_AT: return Common::KEYCODE_AT;
case SDLK_LEFTBRACKET: return Common::KEYCODE_LEFTBRACKET;
case SDLK_BACKSLASH: return Common::KEYCODE_BACKSLASH;
case SDLK_RIGHTBRACKET: return Common::KEYCODE_RIGHTBRACKET;
case SDLK_CARET: return Common::KEYCODE_CARET;
case SDLK_UNDERSCORE: return Common::KEYCODE_UNDERSCORE;
case SDLK_BACKQUOTE: return Common::KEYCODE_BACKQUOTE;
case SDLK_a: return Common::KEYCODE_a;
case SDLK_b: return Common::KEYCODE_b;
case SDLK_c: return Common::KEYCODE_c;
case SDLK_d: return Common::KEYCODE_d;
case SDLK_e: return Common::KEYCODE_e;
case SDLK_f: return Common::KEYCODE_f;
case SDLK_g: return Common::KEYCODE_g;
case SDLK_h: return Common::KEYCODE_h;
case SDLK_i: return Common::KEYCODE_i;
case SDLK_j: return Common::KEYCODE_j;
case SDLK_k: return Common::KEYCODE_k;
case SDLK_l: return Common::KEYCODE_l;
case SDLK_m: return Common::KEYCODE_m;
case SDLK_n: return Common::KEYCODE_n;
case SDLK_o: return Common::KEYCODE_o;
case SDLK_p: return Common::KEYCODE_p;
case SDLK_q: return Common::KEYCODE_q;
case SDLK_r: return Common::KEYCODE_r;
case SDLK_s: return Common::KEYCODE_s;
case SDLK_t: return Common::KEYCODE_t;
case SDLK_u: return Common::KEYCODE_u;
case SDLK_v: return Common::KEYCODE_v;
case SDLK_w: return Common::KEYCODE_w;
case SDLK_x: return Common::KEYCODE_x;
case SDLK_y: return Common::KEYCODE_y;
case SDLK_z: return Common::KEYCODE_z;
case SDLK_DELETE: return Common::KEYCODE_DELETE;
case SDLK_KP_PERIOD: return Common::KEYCODE_KP_PERIOD;
case SDLK_KP_DIVIDE: return Common::KEYCODE_KP_DIVIDE;
case SDLK_KP_MULTIPLY: return Common::KEYCODE_KP_MULTIPLY;
case SDLK_KP_MINUS: return Common::KEYCODE_KP_MINUS;
case SDLK_KP_PLUS: return Common::KEYCODE_KP_PLUS;
case SDLK_KP_ENTER: return Common::KEYCODE_KP_ENTER;
case SDLK_KP_EQUALS: return Common::KEYCODE_KP_EQUALS;
case SDLK_UP: return Common::KEYCODE_UP;
case SDLK_DOWN: return Common::KEYCODE_DOWN;
case SDLK_RIGHT: return Common::KEYCODE_RIGHT;
case SDLK_LEFT: return Common::KEYCODE_LEFT;
case SDLK_INSERT: return Common::KEYCODE_INSERT;
case SDLK_HOME: return Common::KEYCODE_HOME;
case SDLK_END: return Common::KEYCODE_END;
case SDLK_PAGEUP: return Common::KEYCODE_PAGEUP;
case SDLK_PAGEDOWN: return Common::KEYCODE_PAGEDOWN;
case SDLK_F1: return Common::KEYCODE_F1;
case SDLK_F2: return Common::KEYCODE_F2;
case SDLK_F3: return Common::KEYCODE_F3;
case SDLK_F4: return Common::KEYCODE_F4;
case SDLK_F5: return Common::KEYCODE_F5;
case SDLK_F6: return Common::KEYCODE_F6;
case SDLK_F7: return Common::KEYCODE_F7;
case SDLK_F8: return Common::KEYCODE_F8;
case SDLK_F9: return Common::KEYCODE_F9;
case SDLK_F10: return Common::KEYCODE_F10;
case SDLK_F11: return Common::KEYCODE_F11;
case SDLK_F12: return Common::KEYCODE_F12;
case SDLK_F13: return Common::KEYCODE_F13;
case SDLK_F14: return Common::KEYCODE_F14;
case SDLK_F15: return Common::KEYCODE_F15;
case SDLK_CAPSLOCK: return Common::KEYCODE_CAPSLOCK;
case SDLK_RSHIFT: return Common::KEYCODE_RSHIFT;
case SDLK_LSHIFT: return Common::KEYCODE_LSHIFT;
case SDLK_RCTRL: return Common::KEYCODE_RCTRL;
case SDLK_LCTRL: return Common::KEYCODE_LCTRL;
case SDLK_RALT: return Common::KEYCODE_RALT;
case SDLK_LALT: return Common::KEYCODE_LALT;
case SDLK_MODE: return Common::KEYCODE_MODE;
case SDLK_HELP: return Common::KEYCODE_HELP;
case SDLK_SYSREQ: return Common::KEYCODE_SYSREQ;
case SDLK_MENU: return Common::KEYCODE_MENU;
case SDLK_POWER: return Common::KEYCODE_POWER;
case SDLK_BACKSPACE:
return Common::KEYCODE_BACKSPACE;
case SDLK_TAB:
return Common::KEYCODE_TAB;
case SDLK_CLEAR:
return Common::KEYCODE_CLEAR;
case SDLK_RETURN:
return Common::KEYCODE_RETURN;
case SDLK_PAUSE:
return Common::KEYCODE_PAUSE;
case SDLK_ESCAPE:
return Common::KEYCODE_ESCAPE;
case SDLK_SPACE:
return Common::KEYCODE_SPACE;
case SDLK_EXCLAIM:
return Common::KEYCODE_EXCLAIM;
case SDLK_QUOTEDBL:
return Common::KEYCODE_QUOTEDBL;
case SDLK_HASH:
return Common::KEYCODE_HASH;
case SDLK_DOLLAR:
return Common::KEYCODE_DOLLAR;
case SDLK_AMPERSAND:
return Common::KEYCODE_AMPERSAND;
case SDLK_QUOTE:
return Common::KEYCODE_QUOTE;
case SDLK_LEFTPAREN:
return Common::KEYCODE_LEFTPAREN;
case SDLK_RIGHTPAREN:
return Common::KEYCODE_RIGHTPAREN;
case SDLK_ASTERISK:
return Common::KEYCODE_ASTERISK;
case SDLK_PLUS:
return Common::KEYCODE_PLUS;
case SDLK_COMMA:
return Common::KEYCODE_COMMA;
case SDLK_MINUS:
return Common::KEYCODE_MINUS;
case SDLK_PERIOD:
return Common::KEYCODE_PERIOD;
case SDLK_SLASH:
return Common::KEYCODE_SLASH;
case SDLK_0:
return Common::KEYCODE_0;
case SDLK_1:
return Common::KEYCODE_1;
case SDLK_2:
return Common::KEYCODE_2;
case SDLK_3:
return Common::KEYCODE_3;
case SDLK_4:
return Common::KEYCODE_4;
case SDLK_5:
return Common::KEYCODE_5;
case SDLK_6:
return Common::KEYCODE_6;
case SDLK_7:
return Common::KEYCODE_7;
case SDLK_8:
return Common::KEYCODE_8;
case SDLK_9:
return Common::KEYCODE_9;
case SDLK_COLON:
return Common::KEYCODE_COLON;
case SDLK_SEMICOLON:
return Common::KEYCODE_SEMICOLON;
case SDLK_LESS:
return Common::KEYCODE_LESS;
case SDLK_EQUALS:
return Common::KEYCODE_EQUALS;
case SDLK_GREATER:
return Common::KEYCODE_GREATER;
case SDLK_QUESTION:
return Common::KEYCODE_QUESTION;
case SDLK_AT:
return Common::KEYCODE_AT;
case SDLK_LEFTBRACKET:
return Common::KEYCODE_LEFTBRACKET;
case SDLK_BACKSLASH:
return Common::KEYCODE_BACKSLASH;
case SDLK_RIGHTBRACKET:
return Common::KEYCODE_RIGHTBRACKET;
case SDLK_CARET:
return Common::KEYCODE_CARET;
case SDLK_UNDERSCORE:
return Common::KEYCODE_UNDERSCORE;
case SDLK_BACKQUOTE:
return Common::KEYCODE_BACKQUOTE;
case SDLK_a:
return Common::KEYCODE_a;
case SDLK_b:
return Common::KEYCODE_b;
case SDLK_c:
return Common::KEYCODE_c;
case SDLK_d:
return Common::KEYCODE_d;
case SDLK_e:
return Common::KEYCODE_e;
case SDLK_f:
return Common::KEYCODE_f;
case SDLK_g:
return Common::KEYCODE_g;
case SDLK_h:
return Common::KEYCODE_h;
case SDLK_i:
return Common::KEYCODE_i;
case SDLK_j:
return Common::KEYCODE_j;
case SDLK_k:
return Common::KEYCODE_k;
case SDLK_l:
return Common::KEYCODE_l;
case SDLK_m:
return Common::KEYCODE_m;
case SDLK_n:
return Common::KEYCODE_n;
case SDLK_o:
return Common::KEYCODE_o;
case SDLK_p:
return Common::KEYCODE_p;
case SDLK_q:
return Common::KEYCODE_q;
case SDLK_r:
return Common::KEYCODE_r;
case SDLK_s:
return Common::KEYCODE_s;
case SDLK_t:
return Common::KEYCODE_t;
case SDLK_u:
return Common::KEYCODE_u;
case SDLK_v:
return Common::KEYCODE_v;
case SDLK_w:
return Common::KEYCODE_w;
case SDLK_x:
return Common::KEYCODE_x;
case SDLK_y:
return Common::KEYCODE_y;
case SDLK_z:
return Common::KEYCODE_z;
case SDLK_DELETE:
return Common::KEYCODE_DELETE;
case SDLK_KP_PERIOD:
return Common::KEYCODE_KP_PERIOD;
case SDLK_KP_DIVIDE:
return Common::KEYCODE_KP_DIVIDE;
case SDLK_KP_MULTIPLY:
return Common::KEYCODE_KP_MULTIPLY;
case SDLK_KP_MINUS:
return Common::KEYCODE_KP_MINUS;
case SDLK_KP_PLUS:
return Common::KEYCODE_KP_PLUS;
case SDLK_KP_ENTER:
return Common::KEYCODE_KP_ENTER;
case SDLK_KP_EQUALS:
return Common::KEYCODE_KP_EQUALS;
case SDLK_UP:
return Common::KEYCODE_UP;
case SDLK_DOWN:
return Common::KEYCODE_DOWN;
case SDLK_RIGHT:
return Common::KEYCODE_RIGHT;
case SDLK_LEFT:
return Common::KEYCODE_LEFT;
case SDLK_INSERT:
return Common::KEYCODE_INSERT;
case SDLK_HOME:
return Common::KEYCODE_HOME;
case SDLK_END:
return Common::KEYCODE_END;
case SDLK_PAGEUP:
return Common::KEYCODE_PAGEUP;
case SDLK_PAGEDOWN:
return Common::KEYCODE_PAGEDOWN;
case SDLK_F1:
return Common::KEYCODE_F1;
case SDLK_F2:
return Common::KEYCODE_F2;
case SDLK_F3:
return Common::KEYCODE_F3;
case SDLK_F4:
return Common::KEYCODE_F4;
case SDLK_F5:
return Common::KEYCODE_F5;
case SDLK_F6:
return Common::KEYCODE_F6;
case SDLK_F7:
return Common::KEYCODE_F7;
case SDLK_F8:
return Common::KEYCODE_F8;
case SDLK_F9:
return Common::KEYCODE_F9;
case SDLK_F10:
return Common::KEYCODE_F10;
case SDLK_F11:
return Common::KEYCODE_F11;
case SDLK_F12:
return Common::KEYCODE_F12;
case SDLK_F13:
return Common::KEYCODE_F13;
case SDLK_F14:
return Common::KEYCODE_F14;
case SDLK_F15:
return Common::KEYCODE_F15;
case SDLK_CAPSLOCK:
return Common::KEYCODE_CAPSLOCK;
case SDLK_RSHIFT:
return Common::KEYCODE_RSHIFT;
case SDLK_LSHIFT:
return Common::KEYCODE_LSHIFT;
case SDLK_RCTRL:
return Common::KEYCODE_RCTRL;
case SDLK_LCTRL:
return Common::KEYCODE_LCTRL;
case SDLK_RALT:
return Common::KEYCODE_RALT;
case SDLK_LALT:
return Common::KEYCODE_LALT;
case SDLK_MODE:
return Common::KEYCODE_MODE;
case SDLK_HELP:
return Common::KEYCODE_HELP;
case SDLK_SYSREQ:
return Common::KEYCODE_SYSREQ;
case SDLK_MENU:
return Common::KEYCODE_MENU;
case SDLK_POWER:
return Common::KEYCODE_POWER;
#if SDL_VERSION_ATLEAST(1, 2, 3)
case SDLK_UNDO: return Common::KEYCODE_UNDO;
case SDLK_UNDO:
return Common::KEYCODE_UNDO;
#endif
#if SDL_VERSION_ATLEAST(2, 0, 0)
case SDLK_SCROLLLOCK: return Common::KEYCODE_SCROLLOCK;
case SDLK_NUMLOCKCLEAR: return Common::KEYCODE_NUMLOCK;
case SDLK_LGUI: return Common::KEYCODE_LSUPER;
case SDLK_RGUI: return Common::KEYCODE_RSUPER;
case SDLK_PRINTSCREEN: return Common::KEYCODE_PRINT;
case SDLK_APPLICATION: return Common::KEYCODE_COMPOSE;
case SDLK_KP_0: return Common::KEYCODE_KP0;
case SDLK_KP_1: return Common::KEYCODE_KP1;
case SDLK_KP_2: return Common::KEYCODE_KP2;
case SDLK_KP_3: return Common::KEYCODE_KP3;
case SDLK_KP_4: return Common::KEYCODE_KP4;
case SDLK_KP_5: return Common::KEYCODE_KP5;
case SDLK_KP_6: return Common::KEYCODE_KP6;
case SDLK_KP_7: return Common::KEYCODE_KP7;
case SDLK_KP_8: return Common::KEYCODE_KP8;
case SDLK_KP_9: return Common::KEYCODE_KP9;
case SDLK_PERCENT: return Common::KEYCODE_PERCENT;
case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_GRAVE): return Common::KEYCODE_TILDE;
case SDLK_F16: return Common::KEYCODE_F16;
case SDLK_F17: return Common::KEYCODE_F17;
case SDLK_F18: return Common::KEYCODE_F18;
case SDLK_SLEEP: return Common::KEYCODE_SLEEP;
case SDLK_MUTE: return Common::KEYCODE_MUTE;
case SDLK_VOLUMEUP: return Common::KEYCODE_VOLUMEUP;
case SDLK_VOLUMEDOWN: return Common::KEYCODE_VOLUMEDOWN;
case SDLK_EJECT: return Common::KEYCODE_EJECT;
case SDLK_WWW: return Common::KEYCODE_WWW;
case SDLK_MAIL: return Common::KEYCODE_MAIL;
case SDLK_CALCULATOR: return Common::KEYCODE_CALCULATOR;
case SDLK_CUT: return Common::KEYCODE_CUT;
case SDLK_COPY: return Common::KEYCODE_COPY;
case SDLK_PASTE: return Common::KEYCODE_PASTE;
case SDLK_SELECT: return Common::KEYCODE_SELECT;
case SDLK_CANCEL: return Common::KEYCODE_CANCEL;
case SDLK_AC_SEARCH: return Common::KEYCODE_AC_SEARCH;
case SDLK_AC_HOME: return Common::KEYCODE_AC_HOME;
case SDLK_AC_BACK: return Common::KEYCODE_AC_BACK;
case SDLK_AC_FORWARD: return Common::KEYCODE_AC_FORWARD;
case SDLK_AC_STOP: return Common::KEYCODE_AC_STOP;
case SDLK_AC_REFRESH: return Common::KEYCODE_AC_REFRESH;
case SDLK_AC_BOOKMARKS: return Common::KEYCODE_AC_BOOKMARKS;
case SDLK_AUDIONEXT: return Common::KEYCODE_AUDIONEXT;
case SDLK_AUDIOPREV: return Common::KEYCODE_AUDIOPREV;
case SDLK_AUDIOSTOP: return Common::KEYCODE_AUDIOSTOP;
case SDLK_AUDIOPLAY: return Common::KEYCODE_AUDIOPLAYPAUSE;
case SDLK_AUDIOMUTE: return Common::KEYCODE_AUDIOMUTE;
case SDLK_SCROLLLOCK:
return Common::KEYCODE_SCROLLOCK;
case SDLK_NUMLOCKCLEAR:
return Common::KEYCODE_NUMLOCK;
case SDLK_LGUI:
return Common::KEYCODE_LSUPER;
case SDLK_RGUI:
return Common::KEYCODE_RSUPER;
case SDLK_PRINTSCREEN:
return Common::KEYCODE_PRINT;
case SDLK_APPLICATION:
return Common::KEYCODE_COMPOSE;
case SDLK_KP_0:
return Common::KEYCODE_KP0;
case SDLK_KP_1:
return Common::KEYCODE_KP1;
case SDLK_KP_2:
return Common::KEYCODE_KP2;
case SDLK_KP_3:
return Common::KEYCODE_KP3;
case SDLK_KP_4:
return Common::KEYCODE_KP4;
case SDLK_KP_5:
return Common::KEYCODE_KP5;
case SDLK_KP_6:
return Common::KEYCODE_KP6;
case SDLK_KP_7:
return Common::KEYCODE_KP7;
case SDLK_KP_8:
return Common::KEYCODE_KP8;
case SDLK_KP_9:
return Common::KEYCODE_KP9;
case SDLK_PERCENT:
return Common::KEYCODE_PERCENT;
case SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_GRAVE):
return Common::KEYCODE_TILDE;
case SDLK_F16:
return Common::KEYCODE_F16;
case SDLK_F17:
return Common::KEYCODE_F17;
case SDLK_F18:
return Common::KEYCODE_F18;
case SDLK_SLEEP:
return Common::KEYCODE_SLEEP;
case SDLK_MUTE:
return Common::KEYCODE_MUTE;
case SDLK_VOLUMEUP:
return Common::KEYCODE_VOLUMEUP;
case SDLK_VOLUMEDOWN:
return Common::KEYCODE_VOLUMEDOWN;
case SDLK_EJECT:
return Common::KEYCODE_EJECT;
case SDLK_WWW:
return Common::KEYCODE_WWW;
case SDLK_MAIL:
return Common::KEYCODE_MAIL;
case SDLK_CALCULATOR:
return Common::KEYCODE_CALCULATOR;
case SDLK_CUT:
return Common::KEYCODE_CUT;
case SDLK_COPY:
return Common::KEYCODE_COPY;
case SDLK_PASTE:
return Common::KEYCODE_PASTE;
case SDLK_SELECT:
return Common::KEYCODE_SELECT;
case SDLK_CANCEL:
return Common::KEYCODE_CANCEL;
case SDLK_AC_SEARCH:
return Common::KEYCODE_AC_SEARCH;
case SDLK_AC_HOME:
return Common::KEYCODE_AC_HOME;
case SDLK_AC_BACK:
return Common::KEYCODE_AC_BACK;
case SDLK_AC_FORWARD:
return Common::KEYCODE_AC_FORWARD;
case SDLK_AC_STOP:
return Common::KEYCODE_AC_STOP;
case SDLK_AC_REFRESH:
return Common::KEYCODE_AC_REFRESH;
case SDLK_AC_BOOKMARKS:
return Common::KEYCODE_AC_BOOKMARKS;
case SDLK_AUDIONEXT:
return Common::KEYCODE_AUDIONEXT;
case SDLK_AUDIOPREV:
return Common::KEYCODE_AUDIOPREV;
case SDLK_AUDIOSTOP:
return Common::KEYCODE_AUDIOSTOP;
case SDLK_AUDIOPLAY:
return Common::KEYCODE_AUDIOPLAYPAUSE;
case SDLK_AUDIOMUTE:
return Common::KEYCODE_AUDIOMUTE;
#if SDL_VERSION_ATLEAST(2, 0, 6)
case SDLK_AUDIOREWIND: return Common::KEYCODE_AUDIOREWIND;
case SDLK_AUDIOFASTFORWARD: return Common::KEYCODE_AUDIOFASTFORWARD;
case SDLK_AUDIOREWIND:
return Common::KEYCODE_AUDIOREWIND;
case SDLK_AUDIOFASTFORWARD:
return Common::KEYCODE_AUDIOFASTFORWARD;
#endif
#else
case SDLK_SCROLLOCK: return Common::KEYCODE_SCROLLOCK;
case SDLK_NUMLOCK: return Common::KEYCODE_NUMLOCK;
case SDLK_LSUPER: return Common::KEYCODE_LSUPER;
case SDLK_RSUPER: return Common::KEYCODE_RSUPER;
case SDLK_PRINT: return Common::KEYCODE_PRINT;
case SDLK_COMPOSE: return Common::KEYCODE_COMPOSE;
case SDLK_KP0: return Common::KEYCODE_KP0;
case SDLK_KP1: return Common::KEYCODE_KP1;
case SDLK_KP2: return Common::KEYCODE_KP2;
case SDLK_KP3: return Common::KEYCODE_KP3;
case SDLK_KP4: return Common::KEYCODE_KP4;
case SDLK_KP5: return Common::KEYCODE_KP5;
case SDLK_KP6: return Common::KEYCODE_KP6;
case SDLK_KP7: return Common::KEYCODE_KP7;
case SDLK_KP8: return Common::KEYCODE_KP8;
case SDLK_KP9: return Common::KEYCODE_KP9;
case SDLK_WORLD_16: return Common::KEYCODE_TILDE;
case SDLK_BREAK: return Common::KEYCODE_BREAK;
case SDLK_LMETA: return Common::KEYCODE_LMETA;
case SDLK_RMETA: return Common::KEYCODE_RMETA;
case SDLK_EURO: return Common::KEYCODE_EURO;
case SDLK_SCROLLOCK:
return Common::KEYCODE_SCROLLOCK;
case SDLK_NUMLOCK:
return Common::KEYCODE_NUMLOCK;
case SDLK_LSUPER:
return Common::KEYCODE_LSUPER;
case SDLK_RSUPER:
return Common::KEYCODE_RSUPER;
case SDLK_PRINT:
return Common::KEYCODE_PRINT;
case SDLK_COMPOSE:
return Common::KEYCODE_COMPOSE;
case SDLK_KP0:
return Common::KEYCODE_KP0;
case SDLK_KP1:
return Common::KEYCODE_KP1;
case SDLK_KP2:
return Common::KEYCODE_KP2;
case SDLK_KP3:
return Common::KEYCODE_KP3;
case SDLK_KP4:
return Common::KEYCODE_KP4;
case SDLK_KP5:
return Common::KEYCODE_KP5;
case SDLK_KP6:
return Common::KEYCODE_KP6;
case SDLK_KP7:
return Common::KEYCODE_KP7;
case SDLK_KP8:
return Common::KEYCODE_KP8;
case SDLK_KP9:
return Common::KEYCODE_KP9;
case SDLK_WORLD_16:
return Common::KEYCODE_TILDE;
case SDLK_BREAK:
return Common::KEYCODE_BREAK;
case SDLK_LMETA:
return Common::KEYCODE_LMETA;
case SDLK_RMETA:
return Common::KEYCODE_RMETA;
case SDLK_EURO:
return Common::KEYCODE_EURO;
#endif
default: return Common::KEYCODE_INVALID;
default:
return Common::KEYCODE_INVALID;
}
}
@ -434,6 +624,14 @@ bool SdlEventSource::pollEvent(Common::Event &event) {
SDL_Event ev;
while (SDL_PollEvent(&ev)) {
preprocessEvents(&ev);
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
if (ImGui_ImplSDL2_Ready()) {
ImGui_ImplSDL2_ProcessEvent(&ev);
ImGuiIO &io = ImGui::GetIO();
if (io.WantTextInput || io.WantCaptureMouse)
continue;
}
#endif
if (dispatchSDLEvent(ev, event))
return true;
}
@ -474,7 +672,7 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
} else {
return false;
}
}
}
case SDL_TEXTINPUT: {
// When we get a TEXTINPUT event it means we got some user input for
@ -495,7 +693,7 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
_fakeKeyUp.type = Common::EVENT_KEYUP;
return _queuedFakeKeyUp;
}
}
case SDL_WINDOWEVENT:
// We're only interested in events from the current display window
@ -524,7 +722,7 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
// However if the documentation is correct we can ignore SDL_WINDOWEVENT_RESIZED since when we
// get one we should always get a SDL_WINDOWEVENT_SIZE_CHANGED as well.
case SDL_WINDOWEVENT_SIZE_CHANGED:
//case SDL_WINDOWEVENT_RESIZED:
// case SDL_WINDOWEVENT_RESIZED:
return handleResizeEvent(event, ev.window.data1, ev.window.data2);
case SDL_WINDOWEVENT_FOCUS_GAINED: {
@ -617,7 +815,6 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
return false;
}
bool SdlEventSource::handleKeyDown(SDL_Event &ev, Common::Event &event) {
SDLModToOSystemKeyFlags(SDL_GetModState(), event);
@ -785,17 +982,16 @@ void SdlEventSource::closeJoystick() {
int SdlEventSource::mapSDLJoystickButtonToOSystem(Uint8 sdlButton) {
Common::JoystickButton osystemButtons[] = {
Common::JOYSTICK_BUTTON_A,
Common::JOYSTICK_BUTTON_B,
Common::JOYSTICK_BUTTON_X,
Common::JOYSTICK_BUTTON_Y,
Common::JOYSTICK_BUTTON_LEFT_SHOULDER,
Common::JOYSTICK_BUTTON_RIGHT_SHOULDER,
Common::JOYSTICK_BUTTON_BACK,
Common::JOYSTICK_BUTTON_START,
Common::JOYSTICK_BUTTON_LEFT_STICK,
Common::JOYSTICK_BUTTON_RIGHT_STICK
};
Common::JOYSTICK_BUTTON_A,
Common::JOYSTICK_BUTTON_B,
Common::JOYSTICK_BUTTON_X,
Common::JOYSTICK_BUTTON_Y,
Common::JOYSTICK_BUTTON_LEFT_SHOULDER,
Common::JOYSTICK_BUTTON_RIGHT_SHOULDER,
Common::JOYSTICK_BUTTON_BACK,
Common::JOYSTICK_BUTTON_START,
Common::JOYSTICK_BUTTON_LEFT_STICK,
Common::JOYSTICK_BUTTON_RIGHT_STICK};
if (sdlButton >= ARRAYSIZE(osystemButtons)) {
return -1;
@ -836,15 +1032,15 @@ bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
return true;
}
#define HANDLE_HAT_UP(new, old, mask, joybutton) \
if ((old & mask) && !(new & mask)) { \
event.joystick.button = joybutton; \
#define HANDLE_HAT_UP(new, old, mask, joybutton) \
if ((old & mask) && !(new &mask)) { \
event.joystick.button = joybutton; \
g_system->getEventManager()->pushEvent(event); \
}
#define HANDLE_HAT_DOWN(new, old, mask, joybutton) \
if ((new & mask) && !(old & mask)) { \
event.joystick.button = joybutton; \
#define HANDLE_HAT_DOWN(new, old, mask, joybutton) \
if ((new &mask) && !(old & mask)) { \
event.joystick.button = joybutton; \
g_system->getEventManager()->pushEvent(event); \
}
@ -912,22 +1108,21 @@ bool SdlEventSource::handleJoystickRemoved(const SDL_JoyDeviceEvent &device, Com
int SdlEventSource::mapSDLControllerButtonToOSystem(Uint8 sdlButton) {
Common::JoystickButton osystemButtons[] = {
Common::JOYSTICK_BUTTON_A,
Common::JOYSTICK_BUTTON_B,
Common::JOYSTICK_BUTTON_X,
Common::JOYSTICK_BUTTON_Y,
Common::JOYSTICK_BUTTON_BACK,
Common::JOYSTICK_BUTTON_GUIDE,
Common::JOYSTICK_BUTTON_START,
Common::JOYSTICK_BUTTON_LEFT_STICK,
Common::JOYSTICK_BUTTON_RIGHT_STICK,
Common::JOYSTICK_BUTTON_LEFT_SHOULDER,
Common::JOYSTICK_BUTTON_RIGHT_SHOULDER,
Common::JOYSTICK_BUTTON_DPAD_UP,
Common::JOYSTICK_BUTTON_DPAD_DOWN,
Common::JOYSTICK_BUTTON_DPAD_LEFT,
Common::JOYSTICK_BUTTON_DPAD_RIGHT
};
Common::JOYSTICK_BUTTON_A,
Common::JOYSTICK_BUTTON_B,
Common::JOYSTICK_BUTTON_X,
Common::JOYSTICK_BUTTON_Y,
Common::JOYSTICK_BUTTON_BACK,
Common::JOYSTICK_BUTTON_GUIDE,
Common::JOYSTICK_BUTTON_START,
Common::JOYSTICK_BUTTON_LEFT_STICK,
Common::JOYSTICK_BUTTON_RIGHT_STICK,
Common::JOYSTICK_BUTTON_LEFT_SHOULDER,
Common::JOYSTICK_BUTTON_RIGHT_SHOULDER,
Common::JOYSTICK_BUTTON_DPAD_UP,
Common::JOYSTICK_BUTTON_DPAD_DOWN,
Common::JOYSTICK_BUTTON_DPAD_LEFT,
Common::JOYSTICK_BUTTON_DPAD_RIGHT};
if (sdlButton >= ARRAYSIZE(osystemButtons)) {
return -1;
@ -970,9 +1165,9 @@ void SdlEventSource::fakeWarpMouse(const int x, const int y) {
bool SdlEventSource::isJoystickConnected() const {
return _joystick
#if SDL_VERSION_ATLEAST(2, 0, 0)
|| _controller
|| _controller
#endif
;
;
}
void SdlEventSource::setEngineRunning(const bool value) {
@ -1059,8 +1254,7 @@ uint32 SdlEventSource::obtainUnicode(const SDL_Keysym keySym) {
int n = SDL_PeepEvents(events, 2, SDL_PEEKEVENT, SDL_KEYDOWN, SDL_TEXTINPUT);
// Make sure that the TEXTINPUT event belongs to this KEYDOWN
// event and not another pending one.
if ((n > 0 && events[0].type == SDL_TEXTINPUT)
|| (n > 1 && events[0].type != SDL_KEYDOWN && events[1].type == SDL_TEXTINPUT)) {
if ((n > 0 && events[0].type == SDL_TEXTINPUT) || (n > 1 && events[0].type != SDL_KEYDOWN && events[1].type == SDL_TEXTINPUT)) {
// Remove the text input event we associate with the key press. This
// makes sure we never get any SDL_TEXTINPUT events which do "belong"
// to SDL_KEYDOWN events.

View File

@ -46,6 +46,11 @@
#include "image/bmp.h"
#endif
#ifdef USE_IMGUI
#include "backends/imgui/backends/imgui_impl_sdl2_scummvm.h"
#include "backends/imgui/backends/imgui_impl_opengl3_scummvm.h"
#endif
OpenGLSdlGraphics3dManager::OpenGLSdlGraphics3dManager(SdlEventSource *eventSource, SdlWindow *window, bool supportsFrameBuffer)
: SdlGraphicsManager(eventSource, window),
#if SDL_VERSION_ATLEAST(2, 0, 0)
@ -145,6 +150,12 @@ OpenGLSdlGraphics3dManager::OpenGLSdlGraphics3dManager(SdlEventSource *eventSour
}
OpenGLSdlGraphics3dManager::~OpenGLSdlGraphics3dManager() {
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
#endif
closeOverlay();
#if SDL_VERSION_ATLEAST(2, 0, 0)
deinitializeRenderer();
@ -307,7 +318,7 @@ void OpenGLSdlGraphics3dManager::setupScreen() {
int currentSamples = 0;
#if defined(__EMSCRIPTEN__)
// SDL_GL_MULTISAMPLESAMPLES isn't available on a WebGL 1.0 context
// SDL_GL_MULTISAMPLESAMPLES isn't available on a WebGL 1.0 context
// (or not bridged in Emscripten?). This forces a windows reset.
currentSamples = -1;
#else
@ -462,6 +473,21 @@ void OpenGLSdlGraphics3dManager::initializeOpenGLContext() const {
if (SDL_GL_SetSwapInterval(_vsync ? 1 : 0)) {
warning("Unable to %s VSync: %s", _vsync ? "enable" : "disable", SDL_GetError());
}
#ifdef USE_IMGUI
if(!_imguiInit) {
// Setup Dear ImGui
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGui_ImplSDL2_InitForOpenGL(_window->getSDLWindow(), _glContext);
ImGui_ImplOpenGL3_Init("#version 110");
ImGui::StyleColorsDark();
ImGuiIO &io = ImGui::GetIO();
Common::Path initPath(ConfMan.getPath("savepath"));
initPath = initPath.appendComponent("imgui.ini");
io.IniFilename = initPath.toString().c_str();
}
#endif
#endif
}
@ -591,6 +617,12 @@ bool OpenGLSdlGraphics3dManager::createOrUpdateGLContext(uint gameWidth, uint ga
return false;
initializeOpenGLContext();
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
_imguiInit = true;
const Plugin *plugin = EngineMan.findPlugin(ConfMan.get("engineid"));
plugin = PluginMan.getEngineFromMetaEngine(plugin);
_metaEngine = &plugin->get<MetaEngine>();
#endif
if (clear)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
@ -632,6 +664,17 @@ OpenGL::FrameBuffer *OpenGLSdlGraphics3dManager::createFramebuffer(uint width, u
}
void OpenGLSdlGraphics3dManager::updateScreen() {
#if defined(USE_IMGUI) && SDL_VERSION_ATLEAST(2, 0, 0)
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(_window->getSDLWindow());
ImGui::NewFrame();
_metaEngine->renderImGui();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
#endif
GLint prevStateViewport[4];
glGetIntegerv(GL_VIEWPORT, prevStateViewport);
if (_frameBuffer) {

View File

@ -120,6 +120,8 @@ protected:
int _glContextProfileMask, _glContextMajor, _glContextMinor;
SDL_GLContext _glContext;
void deinitializeRenderer();
MetaEngine* _metaEngine = nullptr;
bool _imguiInit = false;
#endif
OpenGL::ContextType _glContextType;

View File

@ -109,7 +109,7 @@
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "graphics/imgui/imgui.h"
#include "backends/imgui/imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_impl_opengl3_scummvm.h"
#include <stdio.h>
@ -162,7 +162,7 @@
// - You can temporarily use an unstripped version. See https://github.com/dearimgui/gl3w_stripped/releases
// Changes to this backend using new APIs should be accompanied by a regenerated stripped loader version.
#define IMGL3W_IMPL
#include "graphics/imgui/backends/imgui_impl_opengl3_loader.h"
#include "backends/imgui/backends/imgui_impl_opengl3_loader.h"
#endif
// Vertex arrays are not supported on ES2/WebGL1 unless Emscripten which uses an extension

View File

@ -26,7 +26,7 @@
// Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp.
#pragma once
#include "graphics/imgui/imgui.h" // IMGUI_IMPL_API
#include "backends/imgui/imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
// Backend API

View File

@ -0,0 +1,681 @@
// dear imgui: Platform Backend for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// (Prefer SDL 2.0.5+ for full feature support.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306)
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702)
// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644)
// 2023-02-07: Implement IME handler (io.SetPlatformImeDataFn will call SDL_SetTextInputRect()/SDL_StartTextInput()).
// 2023-02-07: *BREAKING CHANGE* Renamed this backend file from imgui_impl_sdl.cpp/.h to imgui_impl_sdl2.cpp/.h in prevision for the future release of SDL3.
// 2023-02-02: Avoid calling SDL_SetCursor() when cursor has not changed, as the function is surprisingly costly on Mac with latest SDL (may be fixed in next SDL version).
// 2023-02-02: Added support for SDL 2.0.18+ preciseX/preciseY mouse wheel data for smooth scrolling + Scaling X value on Emscripten (bug?). (#4019, #6096)
// 2023-02-02: Removed SDL_MOUSEWHEEL value clamping, as values seem correct in latest Emscripten. (#4019)
// 2023-02-01: Flipping SDL_MOUSEWHEEL 'wheel.x' value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463)
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 2022-09-26: Inputs: Disable SDL 2.0.22 new "auto capture" (SDL_HINT_MOUSE_AUTO_CAPTURE) which prevents drag and drop across windows for multi-viewport support + don't capture when drag and dropping. (#5710)
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2022-03-22: Inputs: Fix mouse position issues when dragging outside of boundaries. SDL_CaptureMouse() erroneously still gives out LEAVE events when hovering OS decorations.
// 2022-03-22: Inputs: Added support for extra mouse buttons (SDL_BUTTON_X1/SDL_BUTTON_X2).
// 2022-02-04: Added SDL_Renderer* parameter to ImGui_ImplSDL2_InitForSDLRenderer(), so we can use SDL_GetRendererOutputSize() instead of SDL_GL_GetDrawableSize() when bound to a SDL_Renderer.
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#ifndef IMGUI_DISABLE
#include "backends/platform/sdl/sdl.h"
#include "imgui_impl_sdl2_scummvm.h"
#if SDL_VERSION_ATLEAST(2, 0, 0)
// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
#endif
// SDL
#include <SDL.h>
#include <SDL_syswm.h>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
#else
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
#endif
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
// SDL Data
struct ImGui_ImplSDL2_Data
{
SDL_Window* Window;
SDL_Renderer* Renderer;
Uint64 Time;
Uint32 MouseWindowID;
int MouseButtonsDown;
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
SDL_Cursor* LastMouseCursor;
int PendingMouseLeaveFrame;
char* ClipboardTextData;
bool MouseCanUseGlobalState;
ImGui_ImplSDL2_Data() { memset((void*)this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplSDL2_Data* ImGui_ImplSDL2_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data*)ImGui::GetIO().BackendPlatformUserData : nullptr;
}
// Functions
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
bd->ClipboardTextData = SDL_GetClipboardText();
return bd->ClipboardTextData;
}
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
{
SDL_SetClipboardText(text);
}
// Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow().
static void ImGui_ImplSDL2_SetPlatformImeData(ImGuiViewport*, ImGuiPlatformImeData* data)
{
if (data->WantVisible)
{
SDL_Rect r;
r.x = (int)data->InputPos.x;
r.y = (int)data->InputPos.y;
r.w = 1;
r.h = (int)data->InputLineHeight;
SDL_SetTextInputRect(&r);
}
}
static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode)
{
switch (keycode)
{
case SDLK_TAB: return ImGuiKey_Tab;
case SDLK_LEFT: return ImGuiKey_LeftArrow;
case SDLK_RIGHT: return ImGuiKey_RightArrow;
case SDLK_UP: return ImGuiKey_UpArrow;
case SDLK_DOWN: return ImGuiKey_DownArrow;
case SDLK_PAGEUP: return ImGuiKey_PageUp;
case SDLK_PAGEDOWN: return ImGuiKey_PageDown;
case SDLK_HOME: return ImGuiKey_Home;
case SDLK_END: return ImGuiKey_End;
case SDLK_INSERT: return ImGuiKey_Insert;
case SDLK_DELETE: return ImGuiKey_Delete;
case SDLK_BACKSPACE: return ImGuiKey_Backspace;
case SDLK_SPACE: return ImGuiKey_Space;
case SDLK_RETURN: return ImGuiKey_Enter;
case SDLK_ESCAPE: return ImGuiKey_Escape;
case SDLK_QUOTE: return ImGuiKey_Apostrophe;
case SDLK_COMMA: return ImGuiKey_Comma;
case SDLK_MINUS: return ImGuiKey_Minus;
case SDLK_PERIOD: return ImGuiKey_Period;
case SDLK_SLASH: return ImGuiKey_Slash;
case SDLK_SEMICOLON: return ImGuiKey_Semicolon;
case SDLK_EQUALS: return ImGuiKey_Equal;
case SDLK_LEFTBRACKET: return ImGuiKey_LeftBracket;
case SDLK_BACKSLASH: return ImGuiKey_Backslash;
case SDLK_RIGHTBRACKET: return ImGuiKey_RightBracket;
case SDLK_BACKQUOTE: return ImGuiKey_GraveAccent;
case SDLK_CAPSLOCK: return ImGuiKey_CapsLock;
case SDLK_SCROLLLOCK: return ImGuiKey_ScrollLock;
case SDLK_NUMLOCKCLEAR: return ImGuiKey_NumLock;
case SDLK_PRINTSCREEN: return ImGuiKey_PrintScreen;
case SDLK_PAUSE: return ImGuiKey_Pause;
case SDLK_KP_0: return ImGuiKey_Keypad0;
case SDLK_KP_1: return ImGuiKey_Keypad1;
case SDLK_KP_2: return ImGuiKey_Keypad2;
case SDLK_KP_3: return ImGuiKey_Keypad3;
case SDLK_KP_4: return ImGuiKey_Keypad4;
case SDLK_KP_5: return ImGuiKey_Keypad5;
case SDLK_KP_6: return ImGuiKey_Keypad6;
case SDLK_KP_7: return ImGuiKey_Keypad7;
case SDLK_KP_8: return ImGuiKey_Keypad8;
case SDLK_KP_9: return ImGuiKey_Keypad9;
case SDLK_KP_PERIOD: return ImGuiKey_KeypadDecimal;
case SDLK_KP_DIVIDE: return ImGuiKey_KeypadDivide;
case SDLK_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
case SDLK_KP_MINUS: return ImGuiKey_KeypadSubtract;
case SDLK_KP_PLUS: return ImGuiKey_KeypadAdd;
case SDLK_KP_ENTER: return ImGuiKey_KeypadEnter;
case SDLK_KP_EQUALS: return ImGuiKey_KeypadEqual;
case SDLK_LCTRL: return ImGuiKey_LeftCtrl;
case SDLK_LSHIFT: return ImGuiKey_LeftShift;
case SDLK_LALT: return ImGuiKey_LeftAlt;
case SDLK_LGUI: return ImGuiKey_LeftSuper;
case SDLK_RCTRL: return ImGuiKey_RightCtrl;
case SDLK_RSHIFT: return ImGuiKey_RightShift;
case SDLK_RALT: return ImGuiKey_RightAlt;
case SDLK_RGUI: return ImGuiKey_RightSuper;
case SDLK_APPLICATION: return ImGuiKey_Menu;
case SDLK_0: return ImGuiKey_0;
case SDLK_1: return ImGuiKey_1;
case SDLK_2: return ImGuiKey_2;
case SDLK_3: return ImGuiKey_3;
case SDLK_4: return ImGuiKey_4;
case SDLK_5: return ImGuiKey_5;
case SDLK_6: return ImGuiKey_6;
case SDLK_7: return ImGuiKey_7;
case SDLK_8: return ImGuiKey_8;
case SDLK_9: return ImGuiKey_9;
case SDLK_a: return ImGuiKey_A;
case SDLK_b: return ImGuiKey_B;
case SDLK_c: return ImGuiKey_C;
case SDLK_d: return ImGuiKey_D;
case SDLK_e: return ImGuiKey_E;
case SDLK_f: return ImGuiKey_F;
case SDLK_g: return ImGuiKey_G;
case SDLK_h: return ImGuiKey_H;
case SDLK_i: return ImGuiKey_I;
case SDLK_j: return ImGuiKey_J;
case SDLK_k: return ImGuiKey_K;
case SDLK_l: return ImGuiKey_L;
case SDLK_m: return ImGuiKey_M;
case SDLK_n: return ImGuiKey_N;
case SDLK_o: return ImGuiKey_O;
case SDLK_p: return ImGuiKey_P;
case SDLK_q: return ImGuiKey_Q;
case SDLK_r: return ImGuiKey_R;
case SDLK_s: return ImGuiKey_S;
case SDLK_t: return ImGuiKey_T;
case SDLK_u: return ImGuiKey_U;
case SDLK_v: return ImGuiKey_V;
case SDLK_w: return ImGuiKey_W;
case SDLK_x: return ImGuiKey_X;
case SDLK_y: return ImGuiKey_Y;
case SDLK_z: return ImGuiKey_Z;
case SDLK_F1: return ImGuiKey_F1;
case SDLK_F2: return ImGuiKey_F2;
case SDLK_F3: return ImGuiKey_F3;
case SDLK_F4: return ImGuiKey_F4;
case SDLK_F5: return ImGuiKey_F5;
case SDLK_F6: return ImGuiKey_F6;
case SDLK_F7: return ImGuiKey_F7;
case SDLK_F8: return ImGuiKey_F8;
case SDLK_F9: return ImGuiKey_F9;
case SDLK_F10: return ImGuiKey_F10;
case SDLK_F11: return ImGuiKey_F11;
case SDLK_F12: return ImGuiKey_F12;
case SDLK_F13: return ImGuiKey_F13;
case SDLK_F14: return ImGuiKey_F14;
case SDLK_F15: return ImGuiKey_F15;
case SDLK_F16: return ImGuiKey_F16;
case SDLK_F17: return ImGuiKey_F17;
case SDLK_F18: return ImGuiKey_F18;
case SDLK_F19: return ImGuiKey_F19;
case SDLK_F20: return ImGuiKey_F20;
case SDLK_F21: return ImGuiKey_F21;
case SDLK_F22: return ImGuiKey_F22;
case SDLK_F23: return ImGuiKey_F23;
case SDLK_F24: return ImGuiKey_F24;
case SDLK_AC_BACK: return ImGuiKey_AppBack;
case SDLK_AC_FORWARD: return ImGuiKey_AppForward;
}
return ImGuiKey_None;
}
static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(ImGuiMod_Ctrl, (sdl_key_mods & KMOD_CTRL) != 0);
io.AddKeyEvent(ImGuiMod_Shift, (sdl_key_mods & KMOD_SHIFT) != 0);
io.AddKeyEvent(ImGuiMod_Alt, (sdl_key_mods & KMOD_ALT) != 0);
io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0);
}
bool ImGui_ImplSDL2_Ready()
{
return ImGui_ImplSDL2_GetBackendData() != nullptr;
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
switch (event->type)
{
case SDL_MOUSEMOTION:
{
ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
io.AddMouseSourceEvent(event->motion.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
return true;
}
case SDL_MOUSEWHEEL:
{
//IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY);
#if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten!
float wheel_x = -event->wheel.preciseX;
float wheel_y = event->wheel.preciseY;
#else
float wheel_x = -(float)event->wheel.x;
float wheel_y = (float)event->wheel.y;
#endif
#ifdef __EMSCRIPTEN__
wheel_x /= 100.0f;
#endif
io.AddMouseSourceEvent(event->wheel.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
io.AddMouseWheelEvent(wheel_x, wheel_y);
return true;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
int mouse_button = -1;
if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; }
if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; }
if (event->button.button == SDL_BUTTON_MIDDLE) { mouse_button = 2; }
if (event->button.button == SDL_BUTTON_X1) { mouse_button = 3; }
if (event->button.button == SDL_BUTTON_X2) { mouse_button = 4; }
if (mouse_button == -1)
break;
io.AddMouseSourceEvent(event->button.which == SDL_TOUCH_MOUSEID ? ImGuiMouseSource_TouchScreen : ImGuiMouseSource_Mouse);
io.AddMouseButtonEvent(mouse_button, (event->type == SDL_MOUSEBUTTONDOWN));
bd->MouseButtonsDown = (event->type == SDL_MOUSEBUTTONDOWN) ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button));
return true;
}
case SDL_TEXTINPUT:
{
io.AddInputCharactersUTF8(event->text.text);
return true;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod);
ImGuiKey key = ImGui_ImplSDL2_KeycodeToImGuiKey(event->key.keysym.sym);
io.AddKeyEvent(key, (event->type == SDL_KEYDOWN));
io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
return true;
}
case SDL_WINDOWEVENT:
{
// - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right.
// - However we won't get a correct LEAVE event for a captured window.
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
// causing SDL_WINDOWEVENT_LEAVE on previous frame to interrupt drag operation by clear mouse position. This is why
// we delay process the SDL_WINDOWEVENT_LEAVE events by one frame. See issue #5012 for details.
Uint8 window_event = event->window.event;
if (window_event == SDL_WINDOWEVENT_ENTER)
{
bd->MouseWindowID = event->window.windowID;
bd->PendingMouseLeaveFrame = 0;
}
if (window_event == SDL_WINDOWEVENT_LEAVE)
bd->PendingMouseLeaveFrame = ImGui::GetFrameCount() + 1;
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
io.AddFocusEvent(true);
else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
io.AddFocusEvent(false);
return true;
}
}
return false;
}
static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
// Check and store if we are on a SDL backend that supports global mouse position
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
bool mouse_can_use_global_state = false;
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
const char* sdl_backend = SDL_GetCurrentVideoDriver();
const char* global_mouse_whitelist[] = { "windows", "cocoa", "x11", "DIVE", "VMAN" };
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
mouse_can_use_global_state = true;
#endif
// Setup backend capabilities flags
ImGui_ImplSDL2_Data* bd = IM_NEW(ImGui_ImplSDL2_Data)();
io.BackendPlatformUserData = (void*)bd;
io.BackendPlatformName = "imgui_impl_sdl2";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
bd->Window = window;
bd->Renderer = renderer;
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
io.ClipboardUserData = nullptr;
io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData;
// Load mouse cursors
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
// Set platform dependent data in viewport
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandleRaw = nullptr;
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(window, &info))
{
#if defined(SDL_VIDEO_DRIVER_WINDOWS)
main_viewport->PlatformHandleRaw = (void*)info.info.win.window;
#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
main_viewport->PlatformHandleRaw = (void*)info.info.cocoa.window;
#endif
}
// From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
// you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
#endif
// From 2.0.18: Enable native IME.
// IMPORTANT: This is used at the time of SDL_CreateWindow() so this will only affects secondary windows, if any.
// For the main window to be affected, your application needs to call this manually before calling SDL_CreateWindow().
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
#endif
return true;
}
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
{
IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
{
#if !SDL_HAS_VULKAN
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
{
#if !defined(_WIN32)
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
{
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer)
{
return ImGui_ImplSDL2_Init(window, renderer);
}
bool ImGui_ImplSDL2_InitForOther(SDL_Window* window)
{
return ImGui_ImplSDL2_Init(window, nullptr);
}
void ImGui_ImplSDL2_Shutdown()
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
bd->LastMouseCursor = nullptr;
io.BackendPlatformName = nullptr;
io.BackendPlatformUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
IM_DELETE(bd);
}
static void ImGui_ImplSDL2_UpdateMouseData()
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
// We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below)
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE);
SDL_Window* focused_window = SDL_GetKeyboardFocus();
const bool is_app_focused = (bd->Window == focused_window);
#else
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
#endif
if (is_app_focused)
{
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
// (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0)
{
int window_x, window_y, mouse_x_global, mouse_y_global;
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
SDL_GetWindowPosition(bd->Window, &window_x, &window_y);
io.AddMousePosEvent((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
}
}
}
static void ImGui_ImplSDL2_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
SDL_ShowCursor(SDL_FALSE);
}
else
{
// Show OS mouse cursor
SDL_Cursor* expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow];
if (bd->LastMouseCursor != expected_cursor)
{
SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113)
bd->LastMouseCursor = expected_cursor;
}
SDL_ShowCursor(SDL_TRUE);
}
}
static void ImGui_ImplSDL2_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
return;
// Get gamepad
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
if (!game_controller)
return;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
// Update gamepad inputs
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
#define MAP_BUTTON(KEY_NO, BUTTON_NO) { io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0); }
#define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START);
MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK);
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square
MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle
MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle
MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP);
MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
MAP_BUTTON(ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
MAP_BUTTON(ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767);
MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767);
MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK);
MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
#undef MAP_BUTTON
#undef MAP_ANALOG
}
void ImGui_ImplSDL2_NewFrame()
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplSDL2_Init()?");
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
SDL_GetWindowSize(bd->Window, &w, &h);
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
w = h = 0;
if (bd->Renderer != nullptr)
SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h);
else
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
static Uint64 frequency = SDL_GetPerformanceFrequency();
Uint64 current_time = SDL_GetPerformanceCounter();
if (current_time <= bd->Time)
current_time = bd->Time + 1;
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
bd->Time = current_time;
if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0)
{
bd->MouseWindowID = 0;
bd->PendingMouseLeaveFrame = 0;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
ImGui_ImplSDL2_UpdateMouseData();
ImGui_ImplSDL2_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplSDL2_UpdateGamepads();
}
//-----------------------------------------------------------------------------
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif
#endif // #ifndef IMGUI_DISABLE

View File

@ -19,29 +19,26 @@
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "graphics/imgui/imgui.h" // IMGUI_IMPL_API
#include "backends/imgui/imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct SDL_Window;
struct SDL_Renderer;
typedef union SDL_Event SDL_Event;
namespace Common {
struct Event;
}
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window *window, void *sdl_gl_context);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window *window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window *window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window *window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window *window, SDL_Renderer *renderer);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window *window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const Common::Event *event);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);
IMGUI_IMPL_API bool ImGui_ImplSDL2_Ready();
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window *) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
static inline void ImGui_ImplSDL2_NewFrame(SDL_Window*) { ImGui_ImplSDL2_NewFrame(); } // 1.84: removed unnecessary parameter
#endif
#endif // #ifndef IMGUI_DISABLE

View File

@ -93,8 +93,10 @@ Index of this file:
#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1)))
#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0)))
#elif !defined(IMGUI_USE_STB_SPRINTF) && (defined(__clang__) || defined(__GNUC__))
#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1)))
#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0)))
//#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1)))
//#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0)))
#define IM_FMTARGS(FMT)
#define IM_FMTLIST(FMT)
#else
#define IM_FMTARGS(FMT)
#define IM_FMTLIST(FMT)

View File

@ -488,5 +488,15 @@ MODULE_OBJS += \
saves/recorder/recorder-saves.o
endif
ifdef USE_IMGUI
MODULE_OBJS += \
imgui/imgui.o \
imgui/imgui_draw.o \
imgui/imgui_widgets.o \
imgui/imgui_tables.o \
imgui/backends/imgui_impl_opengl3_scummvm.o \
imgui/backends/imgui_impl_sdl2_scummvm.o
endif
# Include common rules
include $(srcdir)/rules.mk

View File

@ -564,6 +564,8 @@ public:
* Read the extended savegame header from the given savegame file.
*/
WARN_UNUSED_RESULT static bool readSavegameHeader(Common::InSaveFile *in, ExtendedSavegameHeader *header, bool skipThumbnail = true);
virtual void renderImGui() {}
};
/**

View File

@ -19,8 +19,7 @@
*
*/
#include "graphics/imgui/imgui.h"
#include "backends/imgui/imgui.h"
#include "common/debug-channels.h"
#include "twp/twp.h"
#include "twp/debugtools.h"

View File

@ -37,6 +37,7 @@
#include "twp/savegame.h"
#include "twp/time.h"
#include "twp/actions.h"
#include "twp/debugtools.h"
#include "twp/dialogs.h"
#define MAX_SAVES 99
@ -188,6 +189,12 @@ Common::Array<Common::Keymap *> TwpMetaEngine::initKeymaps(const char *target) c
return Common::Keymap::arrayOf(engineKeyMap);
}
void TwpMetaEngine::renderImGui() {
#ifdef USE_IMGUI
Twp::onImGuiRender();
#endif
}
#if PLUGIN_ENABLED_DYNAMIC(TWP)
REGISTER_PLUGIN_DYNAMIC(TWP, PLUGIN_TYPE_ENGINE, TwpMetaEngine);
#else

View File

@ -46,6 +46,8 @@ public:
GUI::OptionsContainerWidget *buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const override;
virtual Common::Array<Common::Keymap *> initKeymaps(const char *target) const override;
void renderImGui() override;
};
#endif // TWP_METAENGINE_H

View File

@ -38,7 +38,6 @@ MODULE_OBJS = \
time.o \
tsv.o \
twp.o \
twpimgui.o \
util.o \
vm.o \
walkboxnode.o \

View File

@ -31,7 +31,6 @@
#include "twp/actions.h"
#include "twp/callback.h"
#include "twp/console.h"
#include "twp/debugtools.h"
#include "twp/detection.h"
#include "twp/enginedialogtarget.h"
#include "twp/hud.h"
@ -45,7 +44,6 @@
#include "twp/task.h"
#include "twp/thread.h"
#include "twp/tsv.h"
#include "twp/twpimgui.h"
#include "twp/vm.h"
#include "twp/walkboxnode.h"
@ -73,7 +71,6 @@ TwpEngine::TwpEngine(OSystem *syst, const ADGameDescription *gameDesc)
_hud.reset(new Hud());
_pack.reset(new GGPackSet());
_saveGameManager.reset(new SaveGameManager());
_imgui.reset(new TwpImGui());
_screenScene->setName("Screen");
_scene->addChild(_walkboxNode.get());
@ -722,7 +719,6 @@ void TwpEngine::draw(RenderTexture *outTexture) {
// imgui render
_gfx.use(nullptr);
_imgui->render();
g_system->updateScreen();
}
@ -736,7 +732,6 @@ void TwpEngine::updateSettingVars() {
Common::Error TwpEngine::run() {
initGraphics3d(SCREEN_WIDTH, SCREEN_HEIGHT);
_screen = new Graphics::Screen(SCREEN_WIDTH, SCREEN_HEIGHT);
_imgui->init();
// Set the engine's debugger console
setDebugger(new Console());
@ -789,9 +784,6 @@ Common::Error TwpEngine::run() {
while (!shouldQuit()) {
Math::Vector2d camPos = _gfx.cameraPos();
while (g_system->getEventManager()->pollEvent(e)) {
if(_imgui->processEvent(&e))
continue;
switch (e.type) {
case Common::EVENT_CUSTOM_ENGINE_ACTION_START: {
switch ((TwpAction)e.customType) {
@ -956,9 +948,6 @@ Common::Error TwpEngine::run() {
}
}
// Cleanup
_imgui->cleanup();
return Common::kNoError;
}

View File

@ -250,7 +250,6 @@ private:
unique_ptr<Shader> _bwShader;
unique_ptr<Shader> _ghostShader;
unique_ptr<Shader> _sepiaShader;
unique_ptr<TwpImGui> _imgui;
};
extern TwpEngine *g_twp;

View File

@ -1,108 +0,0 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "twp/twpimgui.h"
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#ifdef USE_IMGUI
#include "graphics/imgui/backends/imgui_impl_sdl2_scummvm.h"
#include "graphics/imgui/backends/imgui_impl_opengl3_scummvm.h"
#include "backends/graphics3d/openglsdl/openglsdl-graphics3d.h"
// here I undefined these symbols because of the <X11/Xlib.h> defining them
// and messing with all classes or structure using the same names
#undef Bool
#undef CursorShape
#undef Expose
#undef KeyPress
#undef KeyRelease
#undef FocusIn
#undef FocusOut
#undef FontChange
#undef None
#undef Status
#undef Unsorted
#include "twp/debugtools.h"
#endif
namespace Twp {
#ifdef USE_IMGUI
SDL_Window *g_window = nullptr;
#endif
void DearImGui::init() {
#ifdef USE_IMGUI
// Setup Dear ImGui
OpenGLSdlGraphics3dManager *manager = dynamic_cast<OpenGLSdlGraphics3dManager *>(g_system->getPaletteManager());
IMGUI_CHECKVERSION();
ImGui::CreateContext();
g_window = manager->getWindow()->getSDLWindow();
SDL_GLContext glContext = SDL_GL_GetCurrentContext();
ImGui_ImplSDL2_InitForOpenGL(g_window, glContext);
ImGui_ImplOpenGL3_Init("#version 110");
ImGui::StyleColorsDark();
ImGuiIO &io = ImGui::GetIO();
Common::Path initPath(ConfMan.getPath("savepath"));
initPath = initPath.appendComponent("twp_imgui.ini");
io.IniFilename = initPath.toString().c_str();
#endif
}
void DearImGui::cleanup() {
#ifdef USE_IMGUI
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
#endif
}
bool DearImGui::processEvent(const Common::Event *event) {
#ifdef USE_IMGUI
ImGui_ImplSDL2_ProcessEvent(event);
ImGuiIO &io = ImGui::GetIO();
if (io.WantTextInput || io.WantCaptureMouse)
return true;
#endif
return false;
}
void DearImGui::render() {
#ifdef USE_IMGUI
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplSDL2_NewFrame(g_window);
ImGui::NewFrame();
onRender();
ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
#endif
}
void TwpImGui::onRender() {
#ifdef USE_IMGUI
onImGuiRender();
#endif
}
} // namespace Twp

View File

@ -1,51 +0,0 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TWP_IMGUI_H
#define TWP_IMGUI_H
namespace Common {
struct Event;
}
namespace Twp {
class DearImGui {
public:
virtual ~DearImGui() = default;
void init();
bool processEvent(const Common::Event *event);
void render();
void cleanup();
protected:
virtual void onRender() = 0;
};
class TwpImGui : public DearImGui {
private:
void onRender() override;
};
} // namespace Twp
#endif

View File

@ -1,766 +0,0 @@
// dear imgui: Platform Backend for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// (Prefer SDL 2.0.5+ for full feature support.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Basic IME support. App needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306)
// 2023-04-04: Inputs: Added support for io.AddMouseSourceEvent() to discriminate ImGuiMouseSource_Mouse/ImGuiMouseSource_TouchScreen. (#2702)
// 2023-02-23: Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. (#6189, #6114, #3644)
// 2023-02-07: Implement IME handler (io.SetPlatformImeDataFn will call SDL_SetTextInputRect()/SDL_StartTextInput()).
// 2023-02-07: *BREAKING CHANGE* Renamed this backend file from imgui_impl_sdl.cpp/.h to imgui_impl_sdl2.cpp/.h in prevision for the future release of SDL3.
// 2023-02-02: Avoid calling SDL_SetCursor() when cursor has not changed, as the function is surprisingly costly on Mac with latest SDL (may be fixed in next SDL version).
// 2023-02-02: Added support for SDL 2.0.18+ preciseX/preciseY mouse wheel data for smooth scrolling + Scaling X value on Emscripten (bug?). (#4019, #6096)
// 2023-02-02: Removed SDL_MOUSEWHEEL value clamping, as values seem correct in latest Emscripten. (#4019)
// 2023-02-01: Flipping SDL_MOUSEWHEEL 'wheel.x' value to match other backends and offer consistent horizontal scrolling direction. (#4019, #6096, #1463)
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 2022-09-26: Inputs: Disable SDL 2.0.22 new "auto capture" (SDL_HINT_MOUSE_AUTO_CAPTURE) which prevents drag and drop across windows for multi-viewport support + don't capture when drag and dropping. (#5710)
// 2022-09-26: Inputs: Renamed ImGuiKey_ModXXX introduced in 1.87 to ImGuiMod_XXX (old names still supported).
// 2022-03-22: Inputs: Fix mouse position issues when dragging outside of boundaries. SDL_CaptureMouse() erroneously still gives out LEAVE events when hovering OS decorations.
// 2022-03-22: Inputs: Added support for extra mouse buttons (SDL_BUTTON_X1/SDL_BUTTON_X2).
// 2022-02-04: Added SDL_Renderer* parameter to ImGui_ImplSDL2_InitForSDLRenderer(), so we can use SDL_GetRendererOutputSize() instead of SDL_GL_GetDrawableSize() when bound to a SDL_Renderer.
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2021-01-20: Inputs: calling new io.AddKeyAnalogEvent() for gamepad support, instead of writing directly to io.NavInputs[].
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always update key mods next and before key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: Update mouse inputs using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback to provide it when focused but not hovered/captured. More standard and will allow us to pass it to future input queue API.
// 2022-01-12: Maintain our own copy of MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2021-08-17: Calling io.AddFocusEvent() on SDL_WINDOWEVENT_FOCUS_GAINED/SDL_WINDOWEVENT_FOCUS_LOST.
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using SDL_GetMouseFocus() + SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, requires SDL 2.0.5+)
// 2021-06-29: *BREAKING CHANGE* Removed 'SDL_Window* window' parameter to ImGui_ImplSDL2_NewFrame() which was unnecessary.
// 2021-06-29: Reorganized backend to pull data from a single structure to facilitate usage with multiple-contexts (all g_XXXX access changed to bd->XXXX).
// 2021-03-22: Rework global mouse pos availability check listing supported platforms explicitly, effectively fixing mouse access on Raspberry Pi. (#2837, #3950)
// 2020-05-25: Misc: Report a zero display-size when window is minimized, to be consistent with other backends.
// 2020-02-20: Inputs: Fixed mapping for ImGuiKey_KeyPadEnter (using SDL_SCANCODE_KP_ENTER instead of SDL_SCANCODE_RETURN2).
// 2019-12-17: Inputs: On Wayland, use SDL_GetMouseState (because there is no global mouse state).
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "graphics/imgui/imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_impl_sdl2_scummvm.h"
#include "common/events.h"
// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion" // warning: implicit conversion from 'xxx' to 'float' may lose precision
#endif
// SDL
#include <SDL.h>
#include <SDL_syswm.h>
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if SDL_VERSION_ATLEAST(2, 0, 4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
#else
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 0
#endif
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2, 0, 6)
// SDL Data
struct ImGui_ImplSDL2_Data {
SDL_Window *Window;
SDL_Renderer *Renderer;
Uint64 Time;
Uint32 MouseWindowID;
int MouseButtonsDown;
SDL_Cursor *MouseCursors[ImGuiMouseCursor_COUNT];
SDL_Cursor *LastMouseCursor;
int PendingMouseLeaveFrame;
char *ClipboardTextData;
bool MouseCanUseGlobalState;
ImGui_ImplSDL2_Data() { memset((void *)this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendPlatformUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
// FIXME: multi-context support is not well tested and probably dysfunctional in this backend.
// FIXME: some shared resources (mouse cursor shape, gamepad) are mishandled when using multi-context.
static ImGui_ImplSDL2_Data *ImGui_ImplSDL2_GetBackendData() {
return ImGui::GetCurrentContext() ? (ImGui_ImplSDL2_Data *)ImGui::GetIO().BackendPlatformUserData : nullptr;
}
// Functions
static const char *ImGui_ImplSDL2_GetClipboardText(void *) {
ImGui_ImplSDL2_Data *bd = ImGui_ImplSDL2_GetBackendData();
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
bd->ClipboardTextData = SDL_GetClipboardText();
return bd->ClipboardTextData;
}
static void ImGui_ImplSDL2_SetClipboardText(void *, const char *text) {
SDL_SetClipboardText(text);
}
// Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow().
static void ImGui_ImplSDL2_SetPlatformImeData(ImGuiViewport *, ImGuiPlatformImeData *data) {
if (data->WantVisible) {
SDL_Rect r;
r.x = (int)data->InputPos.x;
r.y = (int)data->InputPos.y;
r.w = 1;
r.h = (int)data->InputLineHeight;
SDL_SetTextInputRect(&r);
}
}
static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode) {
switch (keycode) {
case SDLK_TAB:
return ImGuiKey_Tab;
case SDLK_LEFT:
return ImGuiKey_LeftArrow;
case SDLK_RIGHT:
return ImGuiKey_RightArrow;
case SDLK_UP:
return ImGuiKey_UpArrow;
case SDLK_DOWN:
return ImGuiKey_DownArrow;
case SDLK_PAGEUP:
return ImGuiKey_PageUp;
case SDLK_PAGEDOWN:
return ImGuiKey_PageDown;
case SDLK_HOME:
return ImGuiKey_Home;
case SDLK_END:
return ImGuiKey_End;
case SDLK_INSERT:
return ImGuiKey_Insert;
case SDLK_DELETE:
return ImGuiKey_Delete;
case SDLK_BACKSPACE:
return ImGuiKey_Backspace;
case SDLK_SPACE:
return ImGuiKey_Space;
case SDLK_RETURN:
return ImGuiKey_Enter;
case SDLK_ESCAPE:
return ImGuiKey_Escape;
case SDLK_QUOTE:
return ImGuiKey_Apostrophe;
case SDLK_COMMA:
return ImGuiKey_Comma;
case SDLK_MINUS:
return ImGuiKey_Minus;
case SDLK_PERIOD:
return ImGuiKey_Period;
case SDLK_SLASH:
return ImGuiKey_Slash;
case SDLK_SEMICOLON:
return ImGuiKey_Semicolon;
case SDLK_EQUALS:
return ImGuiKey_Equal;
case SDLK_LEFTBRACKET:
return ImGuiKey_LeftBracket;
case SDLK_BACKSLASH:
return ImGuiKey_Backslash;
case SDLK_RIGHTBRACKET:
return ImGuiKey_RightBracket;
case SDLK_BACKQUOTE:
return ImGuiKey_GraveAccent;
case SDLK_CAPSLOCK:
return ImGuiKey_CapsLock;
case SDLK_SCROLLLOCK:
return ImGuiKey_ScrollLock;
case SDLK_NUMLOCKCLEAR:
return ImGuiKey_NumLock;
case SDLK_PRINTSCREEN:
return ImGuiKey_PrintScreen;
case SDLK_PAUSE:
return ImGuiKey_Pause;
case SDLK_KP_0:
return ImGuiKey_Keypad0;
case SDLK_KP_1:
return ImGuiKey_Keypad1;
case SDLK_KP_2:
return ImGuiKey_Keypad2;
case SDLK_KP_3:
return ImGuiKey_Keypad3;
case SDLK_KP_4:
return ImGuiKey_Keypad4;
case SDLK_KP_5:
return ImGuiKey_Keypad5;
case SDLK_KP_6:
return ImGuiKey_Keypad6;
case SDLK_KP_7:
return ImGuiKey_Keypad7;
case SDLK_KP_8:
return ImGuiKey_Keypad8;
case SDLK_KP_9:
return ImGuiKey_Keypad9;
case SDLK_KP_PERIOD:
return ImGuiKey_KeypadDecimal;
case SDLK_KP_DIVIDE:
return ImGuiKey_KeypadDivide;
case SDLK_KP_MULTIPLY:
return ImGuiKey_KeypadMultiply;
case SDLK_KP_MINUS:
return ImGuiKey_KeypadSubtract;
case SDLK_KP_PLUS:
return ImGuiKey_KeypadAdd;
case SDLK_KP_ENTER:
return ImGuiKey_KeypadEnter;
case SDLK_KP_EQUALS:
return ImGuiKey_KeypadEqual;
case SDLK_LCTRL:
return ImGuiKey_LeftCtrl;
case SDLK_LSHIFT:
return ImGuiKey_LeftShift;
case SDLK_LALT:
return ImGuiKey_LeftAlt;
case SDLK_LGUI:
return ImGuiKey_LeftSuper;
case SDLK_RCTRL:
return ImGuiKey_RightCtrl;
case SDLK_RSHIFT:
return ImGuiKey_RightShift;
case SDLK_RALT:
return ImGuiKey_RightAlt;
case SDLK_RGUI:
return ImGuiKey_RightSuper;
case SDLK_APPLICATION:
return ImGuiKey_Menu;
case SDLK_0:
return ImGuiKey_0;
case SDLK_1:
return ImGuiKey_1;
case SDLK_2:
return ImGuiKey_2;
case SDLK_3:
return ImGuiKey_3;
case SDLK_4:
return ImGuiKey_4;
case SDLK_5:
return ImGuiKey_5;
case SDLK_6:
return ImGuiKey_6;
case SDLK_7:
return ImGuiKey_7;
case SDLK_8:
return ImGuiKey_8;
case SDLK_9:
return ImGuiKey_9;
case SDLK_a:
return ImGuiKey_A;
case SDLK_b:
return ImGuiKey_B;
case SDLK_c:
return ImGuiKey_C;
case SDLK_d:
return ImGuiKey_D;
case SDLK_e:
return ImGuiKey_E;
case SDLK_f:
return ImGuiKey_F;
case SDLK_g:
return ImGuiKey_G;
case SDLK_h:
return ImGuiKey_H;
case SDLK_i:
return ImGuiKey_I;
case SDLK_j:
return ImGuiKey_J;
case SDLK_k:
return ImGuiKey_K;
case SDLK_l:
return ImGuiKey_L;
case SDLK_m:
return ImGuiKey_M;
case SDLK_n:
return ImGuiKey_N;
case SDLK_o:
return ImGuiKey_O;
case SDLK_p:
return ImGuiKey_P;
case SDLK_q:
return ImGuiKey_Q;
case SDLK_r:
return ImGuiKey_R;
case SDLK_s:
return ImGuiKey_S;
case SDLK_t:
return ImGuiKey_T;
case SDLK_u:
return ImGuiKey_U;
case SDLK_v:
return ImGuiKey_V;
case SDLK_w:
return ImGuiKey_W;
case SDLK_x:
return ImGuiKey_X;
case SDLK_y:
return ImGuiKey_Y;
case SDLK_z:
return ImGuiKey_Z;
case SDLK_F1:
return ImGuiKey_F1;
case SDLK_F2:
return ImGuiKey_F2;
case SDLK_F3:
return ImGuiKey_F3;
case SDLK_F4:
return ImGuiKey_F4;
case SDLK_F5:
return ImGuiKey_F5;
case SDLK_F6:
return ImGuiKey_F6;
case SDLK_F7:
return ImGuiKey_F7;
case SDLK_F8:
return ImGuiKey_F8;
case SDLK_F9:
return ImGuiKey_F9;
case SDLK_F10:
return ImGuiKey_F10;
case SDLK_F11:
return ImGuiKey_F11;
case SDLK_F12:
return ImGuiKey_F12;
case SDLK_F13:
return ImGuiKey_F13;
case SDLK_F14:
return ImGuiKey_F14;
case SDLK_F15:
return ImGuiKey_F15;
case SDLK_F16:
return ImGuiKey_F16;
case SDLK_F17:
return ImGuiKey_F17;
case SDLK_F18:
return ImGuiKey_F18;
case SDLK_F19:
return ImGuiKey_F19;
case SDLK_F20:
return ImGuiKey_F20;
case SDLK_F21:
return ImGuiKey_F21;
case SDLK_F22:
return ImGuiKey_F22;
case SDLK_F23:
return ImGuiKey_F23;
case SDLK_F24:
return ImGuiKey_F24;
case SDLK_AC_BACK:
return ImGuiKey_AppBack;
case SDLK_AC_FORWARD:
return ImGuiKey_AppForward;
}
return ImGuiKey_None;
}
static void ImGui_ImplSDL2_UpdateKeyModifiers(const Common::KeyState &keyState) {
ImGuiIO &io = ImGui::GetIO();
io.AddKeyEvent(ImGuiMod_Ctrl, keyState.hasFlags(Common::KBD_CTRL));
io.AddKeyEvent(ImGuiMod_Shift, keyState.hasFlags(Common::KBD_SHIFT));
io.AddKeyEvent(ImGuiMod_Alt, keyState.hasFlags(Common::KBD_ALT));
io.AddKeyEvent(ImGuiMod_Super, keyState.hasFlags(Common::KBD_META));
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
bool ImGui_ImplSDL2_ProcessEvent(const Common::Event *event) {
ImGuiIO &io = ImGui::GetIO();
ImGui_ImplSDL2_Data *bd = ImGui_ImplSDL2_GetBackendData();
switch (event->type) {
case Common::EVENT_MOUSEMOVE: {
ImVec2 mouse_pos((float)event->mouse.x, (float)event->mouse.y);
io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
return true;
}
case Common::EVENT_WHEELDOWN:
case Common::EVENT_WHEELUP: {
float wheel_x = 0;
float wheel_y = event->type == Common::EVENT_WHEELDOWN ? -1.f : 1.f;
io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
io.AddMouseWheelEvent(wheel_x, wheel_y);
return true;
}
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_LBUTTONUP:
case Common::EVENT_MBUTTONDOWN:
case Common::EVENT_MBUTTONUP:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_RBUTTONUP: {
int mouse_button = -1;
bool mouse_down = false;
if (event->type == Common::EVENT_LBUTTONDOWN) {
mouse_button = 0;
mouse_down = true;
}
if (event->type == Common::EVENT_LBUTTONUP) {
mouse_button = 0;
}
if (event->type == Common::EVENT_MBUTTONDOWN) {
mouse_button = 1;
mouse_down = true;
}
if (event->type == Common::EVENT_MBUTTONUP) {
mouse_button = 2;
}
if (event->type == Common::EVENT_RBUTTONDOWN) {
mouse_button = 3;
mouse_down = true;
}
if (event->type == Common::EVENT_RBUTTONUP) {
mouse_button = 4;
}
if (mouse_button == -1)
break;
io.AddMouseSourceEvent(ImGuiMouseSource_Mouse);
io.AddMouseButtonEvent(mouse_button, mouse_down);
bd->MouseButtonsDown = mouse_down ? (bd->MouseButtonsDown | (1 << mouse_button)) : (bd->MouseButtonsDown & ~(1 << mouse_button));
return true;
}
case Common::EVENT_KEYDOWN:
case Common::EVENT_KEYUP: {
ImGui_ImplSDL2_UpdateKeyModifiers(event->kbd);
ImGuiKey key = ImGui_ImplSDL2_KeycodeToImGuiKey(event->kbd.keycode);
io.AddKeyEvent(key, (event->type == Common::EVENT_KEYDOWN));
io.SetKeyEventNativeData(key, event->kbd.keycode, event->kbd.keycode);
if (event->type == Common::EVENT_KEYUP) {
io.AddInputCharacter(event->kbd.ascii);
}
return true;
}
case Common::EVENT_FOCUS_GAINED:
io.AddFocusEvent(true);
return true;
case Common::EVENT_FOCUS_LOST:
io.AddFocusEvent(false);
return true;
default:
return false;
}
return false;
}
static bool ImGui_ImplSDL2_Init(SDL_Window *window, SDL_Renderer *renderer) {
ImGuiIO &io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == nullptr && "Already initialized a platform backend!");
// Check and store if we are on a SDL backend that supports global mouse position
// ("wayland" and "rpi" don't support it, but we chose to use a white-list instead of a black-list)
bool mouse_can_use_global_state = false;
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
const char *sdl_backend = SDL_GetCurrentVideoDriver();
const char *global_mouse_whitelist[] = {"windows", "cocoa", "x11", "DIVE", "VMAN"};
for (int n = 0; n < IM_ARRAYSIZE(global_mouse_whitelist); n++)
if (strncmp(sdl_backend, global_mouse_whitelist[n], strlen(global_mouse_whitelist[n])) == 0)
mouse_can_use_global_state = true;
#endif
// Setup backend capabilities flags
ImGui_ImplSDL2_Data *bd = IM_NEW(ImGui_ImplSDL2_Data)();
io.BackendPlatformUserData = (void *)bd;
io.BackendPlatformName = "imgui_impl_sdl2";
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
bd->Window = window;
bd->Renderer = renderer;
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
io.ClipboardUserData = nullptr;
io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData;
// Load mouse cursors
bd->MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
bd->MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
bd->MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
bd->MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
bd->MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
bd->MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
bd->MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
bd->MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
bd->MouseCursors[ImGuiMouseCursor_NotAllowed] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NO);
// Set platform dependent data in viewport
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport *main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandleRaw = nullptr;
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(window, &info)) {
#if defined(SDL_VIDEO_DRIVER_WINDOWS)
main_viewport->PlatformHandleRaw = (void *)info.info.win.window;
#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
main_viewport->PlatformHandleRaw = (void *)info.info.cocoa.window;
#endif
}
// From 2.0.5: Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
// Without this, when clicking to gain focus, our widgets wouldn't activate even though they showed as hovered.
// (This is unfortunately a global SDL setting, so enabling it might have a side-effect on your application.
// It is unlikely to make a difference, but if your app absolutely needs to ignore the initial on-focus click:
// you can ignore SDL_MOUSEBUTTONDOWN events coming right after a SDL_WINDOWEVENT_FOCUS_GAINED)
#ifdef SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
#endif
// From 2.0.18: Enable native IME.
// IMPORTANT: This is used at the time of SDL_CreateWindow() so this will only affects secondary windows, if any.
// For the main window to be affected, your application needs to call this manually before calling SDL_CreateWindow().
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
// From 2.0.22: Disable auto-capture, this is preventing drag and drop across multiple windows (see #5710)
#ifdef SDL_HINT_MOUSE_AUTO_CAPTURE
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0");
#endif
return true;
}
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window *window, void *sdl_gl_context) {
IM_UNUSED(sdl_gl_context); // Viewport branch will need this.
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window *window) {
#if !SDL_HAS_VULKAN
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForD3D(SDL_Window *window) {
#if !defined(_WIN32)
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForMetal(SDL_Window *window) {
return ImGui_ImplSDL2_Init(window, nullptr);
}
bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window *window, SDL_Renderer *renderer) {
return ImGui_ImplSDL2_Init(window, renderer);
}
bool ImGui_ImplSDL2_InitForOther(SDL_Window *window) {
return ImGui_ImplSDL2_Init(window, nullptr);
}
void ImGui_ImplSDL2_Shutdown() {
ImGui_ImplSDL2_Data *bd = ImGui_ImplSDL2_GetBackendData();
IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?");
ImGuiIO &io = ImGui::GetIO();
if (bd->ClipboardTextData)
SDL_free(bd->ClipboardTextData);
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
SDL_FreeCursor(bd->MouseCursors[cursor_n]);
bd->LastMouseCursor = nullptr;
io.BackendPlatformName = nullptr;
io.BackendPlatformUserData = nullptr;
io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad);
IM_DELETE(bd);
}
static void ImGui_ImplSDL2_UpdateMouseData() {
ImGui_ImplSDL2_Data *bd = ImGui_ImplSDL2_GetBackendData();
ImGuiIO &io = ImGui::GetIO();
// We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below)
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE);
SDL_Window *focused_window = SDL_GetKeyboardFocus();
const bool is_app_focused = (bd->Window == focused_window);
#else
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
#endif
if (is_app_focused) {
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
// (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0) {
int window_x, window_y, mouse_x_global, mouse_y_global;
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
SDL_GetWindowPosition(bd->Window, &window_x, &window_y);
io.AddMousePosEvent((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
}
}
}
static void ImGui_ImplSDL2_UpdateMouseCursor() {
ImGuiIO &io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGui_ImplSDL2_Data *bd = ImGui_ImplSDL2_GetBackendData();
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None) {
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
SDL_ShowCursor(SDL_FALSE);
} else {
// Show OS mouse cursor
SDL_Cursor *expected_cursor = bd->MouseCursors[imgui_cursor] ? bd->MouseCursors[imgui_cursor] : bd->MouseCursors[ImGuiMouseCursor_Arrow];
if (bd->LastMouseCursor != expected_cursor) {
SDL_SetCursor(expected_cursor); // SDL function doesn't have an early out (see #6113)
bd->LastMouseCursor = expected_cursor;
}
SDL_ShowCursor(SDL_TRUE);
}
}
static void ImGui_ImplSDL2_UpdateGamepads() {
ImGuiIO &io = ImGui::GetIO();
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0) // FIXME: Technically feeding gamepad shouldn't depend on this now that they are regular inputs.
return;
// Get gamepad
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
SDL_GameController *game_controller = SDL_GameControllerOpen(0);
if (!game_controller)
return;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
// Update gamepad inputs
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f \
: V)
#define MAP_BUTTON(KEY_NO, BUTTON_NO) \
{ io.AddKeyEvent(KEY_NO, SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0); }
#define MAP_ANALOG(KEY_NO, AXIS_NO, V0, V1) \
{ \
float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); \
vn = IM_SATURATE(vn); \
io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); \
}
const int thumb_dead_zone = 8000; // SDL_gamecontroller.h suggests using this value.
MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START);
MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK);
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square
MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle
MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle
MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT);
MAP_BUTTON(ImGuiKey_GamepadDpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT);
MAP_BUTTON(ImGuiKey_GamepadDpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP);
MAP_BUTTON(ImGuiKey_GamepadDpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN);
MAP_BUTTON(ImGuiKey_GamepadL1, SDL_CONTROLLER_BUTTON_LEFTSHOULDER);
MAP_BUTTON(ImGuiKey_GamepadR1, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER);
MAP_ANALOG(ImGuiKey_GamepadL2, SDL_CONTROLLER_AXIS_TRIGGERLEFT, 0.0f, 32767);
MAP_ANALOG(ImGuiKey_GamepadR2, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, 0.0f, 32767);
MAP_BUTTON(ImGuiKey_GamepadL3, SDL_CONTROLLER_BUTTON_LEFTSTICK);
MAP_BUTTON(ImGuiKey_GamepadR3, SDL_CONTROLLER_BUTTON_RIGHTSTICK);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, SDL_CONTROLLER_AXIS_RIGHTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, SDL_CONTROLLER_AXIS_RIGHTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, SDL_CONTROLLER_AXIS_RIGHTY, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, SDL_CONTROLLER_AXIS_RIGHTY, +thumb_dead_zone, +32767);
#undef MAP_BUTTON
#undef MAP_ANALOG
}
void ImGui_ImplSDL2_NewFrame() {
ImGui_ImplSDL2_Data *bd = ImGui_ImplSDL2_GetBackendData();
IM_ASSERT(bd != nullptr && "Did you call ImGui_ImplSDL2_Init()?");
ImGuiIO &io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w, h;
int display_w, display_h;
SDL_GetWindowSize(bd->Window, &w, &h);
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
w = h = 0;
if (bd->Renderer != nullptr)
SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h);
else
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
if (w > 0 && h > 0)
io.DisplayFramebufferScale = ImVec2((float)display_w / w, (float)display_h / h);
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
// (Accept SDL_GetPerformanceCounter() not returning a monotonically increasing value. Happens in VMs and Emscripten, see #6189, #6114, #3644)
static Uint64 frequency = SDL_GetPerformanceFrequency();
Uint64 current_time = SDL_GetPerformanceCounter();
if (current_time <= bd->Time)
current_time = bd->Time + 1;
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
bd->Time = current_time;
if (bd->PendingMouseLeaveFrame && bd->PendingMouseLeaveFrame >= ImGui::GetFrameCount() && bd->MouseButtonsDown == 0) {
bd->MouseWindowID = 0;
bd->PendingMouseLeaveFrame = 0;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
ImGui_ImplSDL2_UpdateMouseData();
ImGui_ImplSDL2_UpdateMouseCursor();
// Update game controllers (if enabled and available)
ImGui_ImplSDL2_UpdateGamepads();
}
//-----------------------------------------------------------------------------
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
#endif // #ifndef IMGUI_DISABLE

View File

@ -154,15 +154,5 @@ MODULE_OBJS += \
blit/blit-avx2.o
endif
ifdef USE_IMGUI
MODULE_OBJS += \
imgui/imgui.o \
imgui/imgui_draw.o \
imgui/imgui_widgets.o \
imgui/imgui_tables.o \
imgui/backends/imgui_impl_opengl3_scummvm.o \
imgui/backends/imgui_impl_sdl2_scummvm.o
endif
# Include common rules
include $(srcdir)/rules.mk