Merged from imgui/docking (1e14cc5) (v1.87 + some fixes)

docking
TheCherno 3 years ago
commit 972d43347c

@ -1,12 +1,12 @@
(Click "Preview" above ^ to turn URL into clickable links)
1. PLEASE CAREFULLY READ: [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md)
1. FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING or LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
2. PLEASE CAREFULLY READ: [Issue Submitting Guidelines](https://github.com/ocornut/imgui/issues/2261)
2. PLEASE CAREFULLY READ: [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md)
3. FOR FIRST-TIME USERS ISSUES COMPILING/LINKING/RUNNING/LOADING FONTS, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
3. PLEASE CAREFULLY READ: [Issue Submitting Guidelines](https://github.com/ocornut/imgui/issues/2261)
4. PLEASE MAKE SURE that you have: read the FAQ; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the link provided in (1) (2).
4. PLEASE MAKE SURE that you have: read the FAQ; explored the contents of `ShowDemoWindow()` including the Examples menu; searched among Issues; used your IDE to search for keywords in all sources and text files; and read the links above.
5. Be mindful that messages are being sent to the e-mail box of "Watching" users. Try to proof-read your messages before sending them. Edits are not seen by those users.

@ -1,6 +1,6 @@
(Click "Preview" to turn any http URL into a clickable link)
PLEASE CAREFULLY READ:
https://github.com/ocornut/imgui/issues/2261
1. PLEASE CAREFULLY READ: [Issue Submitting Guidelines](https://github.com/ocornut/imgui/issues/2261)
2. Clear this template before submitting your PR.
(Clear this template before submitting your PR)

@ -37,20 +37,30 @@ jobs:
- name: Fix Projects
shell: powershell
run: |
# WARNING: This will need updating if toolset/sdk change in project files!
# CI workers do not supporter older Visual Studio versions. Fix projects to target newer available version.
gci -recurse -filter "*.vcxproj" | ForEach-Object {
# Fix SDK and toolset for most samples.
(Get-Content $_.FullName) -Replace "<PlatformToolset>v110</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName
(Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName
# Fix SDK and toolset for samples that require newer SDK/toolset. At the moment it is only dx12.
(Get-Content $_.FullName) -Replace "<PlatformToolset>v140</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName
(Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>10.0.14393.0</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName
(Get-Content $_.FullName) -Replace "<PlatformToolset>v\d{3}</PlatformToolset>","<PlatformToolset>v142</PlatformToolset>" | Set-Content -Path $_.FullName
(Get-Content $_.FullName) -Replace "<WindowsTargetPlatformVersion>[\d\.]+</WindowsTargetPlatformVersion>","<WindowsTargetPlatformVersion>10.0.18362.0</WindowsTargetPlatformVersion>" | Set-Content -Path $_.FullName
}
# Not using matrix here because it would inflate job count too much. Check out and setup is done for every job and that makes build times way too long.
- name: Build example_null (extra warnings, mingw 64-bit)
run: mingw32-make -C examples/example_null WITH_EXTRA_WARNINGS=1
- name: Build example_null (mingw 64-bit, as DLL)
shell: bash
run: |
echo '#ifdef _EXPORT' > example_single_file.cpp
echo '# define IMGUI_API __declspec(dllexport)' >> example_single_file.cpp
echo '#else' >> example_single_file.cpp
echo '# define IMGUI_API __declspec(dllimport)' >> example_single_file.cpp
echo '#endif' >> example_single_file.cpp
echo '#define IMGUI_IMPLEMENTATION' >> example_single_file.cpp
echo '#include "misc/single_file/imgui_single_file.h"' >> example_single_file.cpp
g++ -I. -Wall -Wformat -D_EXPORT -shared -o libimgui.dll -Wl,--out-implib,libimgui.a example_single_file.cpp -limm32
g++ -I. -Wall -Wformat -o example_null.exe examples/example_null/main.cpp -L. -limgui
rm -f example_null.exe libimgui.* example_single_file.*
- name: Build example_null (extra warnings, msvc 64-bit)
shell: cmd
run: |
@ -226,6 +236,18 @@ jobs:
make -C examples/example_null clean
CXXFLAGS="$CXXFLAGS -m64 -Werror" CXX=clang++ make -C examples/example_null WITH_EXTRA_WARNINGS=1
- name: Build example_null (extra warnings, empty IM_ASSERT)
run: |
cat > example_single_file.cpp <<'EOF'
#define IM_ASSERT(x)
#define IMGUI_IMPLEMENTATION
#include "misc/single_file/imgui_single_file.h"
#include "examples/example_null/main.cpp"
EOF
g++ -I. -Wall -Wformat -Wextra -Werror -Wno-zero-as-null-pointer-constant -Wno-double-promotion -Wno-variadic-macros -Wno-empty-body -o example_single_file example_single_file.cpp
- name: Build example_null (freetype)
run: |
make -C examples/example_null clean
@ -279,6 +301,18 @@ jobs:
EOF
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
- name: Build example_null (with IMGUI_DISABLE_OBSOLETE_KEYIO)
run: |
cat > example_single_file.cpp <<'EOF'
#define IMGUI_DISABLE_OBSOLETE_KEYIO
#define IMGUI_IMPLEMENTATION
#include "misc/single_file/imgui_single_file.h"
#include "examples/example_null/main.cpp"
EOF
g++ -I. -Wall -Wformat -o example_single_file example_single_file.cpp
- name: Build example_null (with IMGUI_DISABLE_DEMO_WINDOWS and IMGUI_DISABLE_METRICS_WINDOW)
run: |
cat > example_single_file.cpp <<'EOF'
@ -471,34 +505,3 @@ jobs:
run: |
cd examples/example_android_opengl3/android
gradle assembleDebug
Discord-CI:
runs-on: ubuntu-18.04
if: always()
needs: [Windows, Linux, MacOS, iOS, Emscripten, Android]
steps:
- uses: dearimgui/github_discord_notifier@latest
with:
discord-webhook: ${{ secrets.DISCORD_CI_WEBHOOK }}
github-token: ${{ github.token }}
action-task: discord-jobs
discord-filter: "'{{ github.branch }}'.match(/master|docking/g) != null && '{{ run.conclusion }}' != '{{ last_run.conclusion }}'"
discord-username: GitHub Actions
discord-job-new-failure-message: ''
discord-job-fixed-failure-message: ''
discord-job-new-failure-embed: |
{
"title": "`{{ job.name }}` job is failing on `{{ github.branch }}`!",
"description": "Commit [{{ github.context.payload.head_commit.title }}]({{ github.context.payload.head_commit.url }}) pushed to [{{ github.branch }}]({{ github.branch_url }}) broke [{{ job.name }}]({{ job.url }}) build job.\nFailing steps: {{ failing_steps }}",
"url": "{{ job.url }}",
"color": "0xFF0000",
"timestamp": "{{ run.updated_at }}"
}
discord-job-fixed-failure-embed: |
{
"title": "`{{ github.branch }}` branch is no longer failing!",
"description": "Build failures were fixed on [{{ github.branch }}]({{ github.branch_url }}) branch.",
"color": "0x00FF00",
"url": "{{ github.context.payload.head_commit.url }}",
"timestamp": "{{ run.completed_at }}"
}

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2014-2021 Omar Cornut
Copyright (c) 2014-2022 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

@ -3,6 +3,7 @@
// Implemented features:
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
// [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 ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues:
@ -16,6 +17,11 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-17: Inputs: always calling io.AddKeyModsEvent() next and before key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2021-12-08: Renderer: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86.
// 2021-08-17: Calling io.AddFocusEvent() on ALLEGRO_EVENT_DISPLAY_SWITCH_OUT/ALLEGRO_EVENT_DISPLAY_SWITCH_IN events.
// 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-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
@ -155,7 +161,6 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
}
// Render command lists
int idx_offset = 0;
ImVec2 clip_off = draw_data->DisplayPos;
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
@ -171,12 +176,17 @@ void ImGui_ImplAllegro5_RenderDrawData(ImDrawData* draw_data)
}
else
{
// Draw
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle, Draw
ALLEGRO_BITMAP* texture = (ALLEGRO_BITMAP*)pcmd->GetTexID();
al_set_clipping_rectangle(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y, pcmd->ClipRect.z - pcmd->ClipRect.x, pcmd->ClipRect.w - pcmd->ClipRect.y);
al_draw_prim(&vertices[0], bd->VertexDecl, texture, idx_offset, idx_offset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
al_set_clipping_rectangle(clip_min.x, clip_min.y, clip_max.x - clip_min.x, clip_max.y - clip_min.y);
al_draw_prim(&vertices[0], bd->VertexDecl, texture, pcmd->IdxOffset, pcmd->IdxOffset + pcmd->ElemCount, ALLEGRO_PRIM_TRIANGLE_LIST);
}
idx_offset += pcmd->ElemCount;
}
}
@ -269,6 +279,119 @@ static void ImGui_ImplAllegro5_SetClipboardText(void*, const char* text)
}
#endif
static ImGuiKey ImGui_ImplAllegro5_KeyCodeToImGuiKey(int key_code)
{
switch (key_code)
{
case ALLEGRO_KEY_TAB: return ImGuiKey_Tab;
case ALLEGRO_KEY_LEFT: return ImGuiKey_LeftArrow;
case ALLEGRO_KEY_RIGHT: return ImGuiKey_RightArrow;
case ALLEGRO_KEY_UP: return ImGuiKey_UpArrow;
case ALLEGRO_KEY_DOWN: return ImGuiKey_DownArrow;
case ALLEGRO_KEY_PGUP: return ImGuiKey_PageUp;
case ALLEGRO_KEY_PGDN: return ImGuiKey_PageDown;
case ALLEGRO_KEY_HOME: return ImGuiKey_Home;
case ALLEGRO_KEY_END: return ImGuiKey_End;
case ALLEGRO_KEY_INSERT: return ImGuiKey_Insert;
case ALLEGRO_KEY_DELETE: return ImGuiKey_Delete;
case ALLEGRO_KEY_BACKSPACE: return ImGuiKey_Backspace;
case ALLEGRO_KEY_SPACE: return ImGuiKey_Space;
case ALLEGRO_KEY_ENTER: return ImGuiKey_Enter;
case ALLEGRO_KEY_ESCAPE: return ImGuiKey_Escape;
case ALLEGRO_KEY_QUOTE: return ImGuiKey_Apostrophe;
case ALLEGRO_KEY_COMMA: return ImGuiKey_Comma;
case ALLEGRO_KEY_MINUS: return ImGuiKey_Minus;
case ALLEGRO_KEY_FULLSTOP: return ImGuiKey_Period;
case ALLEGRO_KEY_SLASH: return ImGuiKey_Slash;
case ALLEGRO_KEY_SEMICOLON: return ImGuiKey_Semicolon;
case ALLEGRO_KEY_EQUALS: return ImGuiKey_Equal;
case ALLEGRO_KEY_OPENBRACE: return ImGuiKey_LeftBracket;
case ALLEGRO_KEY_BACKSLASH: return ImGuiKey_Backslash;
case ALLEGRO_KEY_CLOSEBRACE: return ImGuiKey_RightBracket;
case ALLEGRO_KEY_TILDE: return ImGuiKey_GraveAccent;
case ALLEGRO_KEY_CAPSLOCK: return ImGuiKey_CapsLock;
case ALLEGRO_KEY_SCROLLLOCK: return ImGuiKey_ScrollLock;
case ALLEGRO_KEY_NUMLOCK: return ImGuiKey_NumLock;
case ALLEGRO_KEY_PRINTSCREEN: return ImGuiKey_PrintScreen;
case ALLEGRO_KEY_PAUSE: return ImGuiKey_Pause;
case ALLEGRO_KEY_PAD_0: return ImGuiKey_Keypad0;
case ALLEGRO_KEY_PAD_1: return ImGuiKey_Keypad1;
case ALLEGRO_KEY_PAD_2: return ImGuiKey_Keypad2;
case ALLEGRO_KEY_PAD_3: return ImGuiKey_Keypad3;
case ALLEGRO_KEY_PAD_4: return ImGuiKey_Keypad4;
case ALLEGRO_KEY_PAD_5: return ImGuiKey_Keypad5;
case ALLEGRO_KEY_PAD_6: return ImGuiKey_Keypad6;
case ALLEGRO_KEY_PAD_7: return ImGuiKey_Keypad7;
case ALLEGRO_KEY_PAD_8: return ImGuiKey_Keypad8;
case ALLEGRO_KEY_PAD_9: return ImGuiKey_Keypad9;
case ALLEGRO_KEY_PAD_DELETE: return ImGuiKey_KeypadDecimal;
case ALLEGRO_KEY_PAD_SLASH: return ImGuiKey_KeypadDivide;
case ALLEGRO_KEY_PAD_ASTERISK: return ImGuiKey_KeypadMultiply;
case ALLEGRO_KEY_PAD_MINUS: return ImGuiKey_KeypadSubtract;
case ALLEGRO_KEY_PAD_PLUS: return ImGuiKey_KeypadAdd;
case ALLEGRO_KEY_PAD_ENTER: return ImGuiKey_KeypadEnter;
case ALLEGRO_KEY_PAD_EQUALS: return ImGuiKey_KeypadEqual;
case ALLEGRO_KEY_LCTRL: return ImGuiKey_LeftCtrl;
case ALLEGRO_KEY_LSHIFT: return ImGuiKey_LeftShift;
case ALLEGRO_KEY_ALT: return ImGuiKey_LeftAlt;
case ALLEGRO_KEY_LWIN: return ImGuiKey_LeftSuper;
case ALLEGRO_KEY_RCTRL: return ImGuiKey_RightCtrl;
case ALLEGRO_KEY_RSHIFT: return ImGuiKey_RightShift;
case ALLEGRO_KEY_ALTGR: return ImGuiKey_RightAlt;
case ALLEGRO_KEY_RWIN: return ImGuiKey_RightSuper;
case ALLEGRO_KEY_MENU: return ImGuiKey_Menu;
case ALLEGRO_KEY_0: return ImGuiKey_0;
case ALLEGRO_KEY_1: return ImGuiKey_1;
case ALLEGRO_KEY_2: return ImGuiKey_2;
case ALLEGRO_KEY_3: return ImGuiKey_3;
case ALLEGRO_KEY_4: return ImGuiKey_4;
case ALLEGRO_KEY_5: return ImGuiKey_5;
case ALLEGRO_KEY_6: return ImGuiKey_6;
case ALLEGRO_KEY_7: return ImGuiKey_7;
case ALLEGRO_KEY_8: return ImGuiKey_8;
case ALLEGRO_KEY_9: return ImGuiKey_9;
case ALLEGRO_KEY_A: return ImGuiKey_A;
case ALLEGRO_KEY_B: return ImGuiKey_B;
case ALLEGRO_KEY_C: return ImGuiKey_C;
case ALLEGRO_KEY_D: return ImGuiKey_D;
case ALLEGRO_KEY_E: return ImGuiKey_E;
case ALLEGRO_KEY_F: return ImGuiKey_F;
case ALLEGRO_KEY_G: return ImGuiKey_G;
case ALLEGRO_KEY_H: return ImGuiKey_H;
case ALLEGRO_KEY_I: return ImGuiKey_I;
case ALLEGRO_KEY_J: return ImGuiKey_J;
case ALLEGRO_KEY_K: return ImGuiKey_K;
case ALLEGRO_KEY_L: return ImGuiKey_L;
case ALLEGRO_KEY_M: return ImGuiKey_M;
case ALLEGRO_KEY_N: return ImGuiKey_N;
case ALLEGRO_KEY_O: return ImGuiKey_O;
case ALLEGRO_KEY_P: return ImGuiKey_P;
case ALLEGRO_KEY_Q: return ImGuiKey_Q;
case ALLEGRO_KEY_R: return ImGuiKey_R;
case ALLEGRO_KEY_S: return ImGuiKey_S;
case ALLEGRO_KEY_T: return ImGuiKey_T;
case ALLEGRO_KEY_U: return ImGuiKey_U;
case ALLEGRO_KEY_V: return ImGuiKey_V;
case ALLEGRO_KEY_W: return ImGuiKey_W;
case ALLEGRO_KEY_X: return ImGuiKey_X;
case ALLEGRO_KEY_Y: return ImGuiKey_Y;
case ALLEGRO_KEY_Z: return ImGuiKey_Z;
case ALLEGRO_KEY_F1: return ImGuiKey_F1;
case ALLEGRO_KEY_F2: return ImGuiKey_F2;
case ALLEGRO_KEY_F3: return ImGuiKey_F3;
case ALLEGRO_KEY_F4: return ImGuiKey_F4;
case ALLEGRO_KEY_F5: return ImGuiKey_F5;
case ALLEGRO_KEY_F6: return ImGuiKey_F6;
case ALLEGRO_KEY_F7: return ImGuiKey_F7;
case ALLEGRO_KEY_F8: return ImGuiKey_F8;
case ALLEGRO_KEY_F9: return ImGuiKey_F9;
case ALLEGRO_KEY_F10: return ImGuiKey_F10;
case ALLEGRO_KEY_F11: return ImGuiKey_F11;
case ALLEGRO_KEY_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
{
ImGuiIO& io = ImGui::GetIO();
@ -294,30 +417,6 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
};
bd->VertexDecl = al_create_vertex_decl(elems, sizeof(ImDrawVertAllegro));
io.KeyMap[ImGuiKey_Tab] = ALLEGRO_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = ALLEGRO_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = ALLEGRO_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = ALLEGRO_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = ALLEGRO_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = ALLEGRO_KEY_PGUP;
io.KeyMap[ImGuiKey_PageDown] = ALLEGRO_KEY_PGDN;
io.KeyMap[ImGuiKey_Home] = ALLEGRO_KEY_HOME;
io.KeyMap[ImGuiKey_End] = ALLEGRO_KEY_END;
io.KeyMap[ImGuiKey_Insert] = ALLEGRO_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = ALLEGRO_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = ALLEGRO_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = ALLEGRO_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = ALLEGRO_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = ALLEGRO_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = ALLEGRO_KEY_PAD_ENTER;
io.KeyMap[ImGuiKey_A] = ALLEGRO_KEY_A;
io.KeyMap[ImGuiKey_C] = ALLEGRO_KEY_C;
io.KeyMap[ImGuiKey_V] = ALLEGRO_KEY_V;
io.KeyMap[ImGuiKey_X] = ALLEGRO_KEY_X;
io.KeyMap[ImGuiKey_Y] = ALLEGRO_KEY_Y;
io.KeyMap[ImGuiKey_Z] = ALLEGRO_KEY_Z;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
#if ALLEGRO_HAS_CLIPBOARD
io.SetClipboardTextFn = ImGui_ImplAllegro5_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplAllegro5_GetClipboardText;
@ -329,8 +428,9 @@ bool ImGui_ImplAllegro5_Init(ALLEGRO_DISPLAY* display)
void ImGui_ImplAllegro5_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData();
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplAllegro5_InvalidateDeviceObjects();
if (bd->VertexDecl)
@ -343,6 +443,18 @@ void ImGui_ImplAllegro5_Shutdown()
IM_DELETE(bd);
}
// ev->keyboard.modifiers seems always zero so using that...
static void ImGui_ImplAllegro5_UpdateKeyModifiers()
{
ImGuiIO& io = ImGui::GetIO();
ALLEGRO_KEYBOARD_STATE keys;
al_get_keyboard_state(&keys);
io.AddKeyEvent(ImGuiKey_ModCtrl, al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL));
io.AddKeyEvent(ImGuiKey_ModShift, al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT));
io.AddKeyEvent(ImGuiKey_ModAlt, al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR));
io.AddKeyEvent(ImGuiKey_ModSuper, al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN));
}
// 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.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
@ -357,29 +469,28 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
case ALLEGRO_EVENT_MOUSE_AXES:
if (ev->mouse.display == bd->Display)
{
io.MouseWheel += ev->mouse.dz;
io.MouseWheelH -= ev->mouse.dw;
io.MousePos = ImVec2(ev->mouse.x, ev->mouse.y);
io.AddMousePosEvent(ev->mouse.x, ev->mouse.y);
io.AddMouseWheelEvent(-ev->mouse.dw, ev->mouse.dz);
}
return true;
case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
if (ev->mouse.display == bd->Display && ev->mouse.button <= 5)
io.MouseDown[ev->mouse.button - 1] = (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
if (ev->mouse.display == bd->Display && ev->mouse.button > 0 && ev->mouse.button <= 5)
io.AddMouseButtonEvent(ev->mouse.button - 1, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);
return true;
case ALLEGRO_EVENT_TOUCH_MOVE:
if (ev->touch.display == bd->Display)
io.MousePos = ImVec2(ev->touch.x, ev->touch.y);
io.AddMousePosEvent(ev->touch.x, ev->touch.y);
return true;
case ALLEGRO_EVENT_TOUCH_BEGIN:
case ALLEGRO_EVENT_TOUCH_END:
case ALLEGRO_EVENT_TOUCH_CANCEL:
if (ev->touch.display == bd->Display && ev->touch.primary)
io.MouseDown[0] = (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
io.AddMouseButtonEvent(0, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);
return true;
case ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY:
if (ev->mouse.display == bd->Display)
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
return true;
case ALLEGRO_EVENT_KEY_CHAR:
if (ev->keyboard.display == bd->Display)
@ -389,7 +500,12 @@ bool ImGui_ImplAllegro5_ProcessEvent(ALLEGRO_EVENT* ev)
case ALLEGRO_EVENT_KEY_DOWN:
case ALLEGRO_EVENT_KEY_UP:
if (ev->keyboard.display == bd->Display)
io.KeysDown[ev->keyboard.keycode] = (ev->type == ALLEGRO_EVENT_KEY_DOWN);
{
ImGui_ImplAllegro5_UpdateKeyModifiers();
ImGuiKey key = ImGui_ImplAllegro5_KeyCodeToImGuiKey(ev->keyboard.keycode);
io.AddKeyEvent(key, (ev->type == ALLEGRO_EVENT_KEY_DOWN));
io.SetKeyEventNativeData(key, ev->keyboard.keycode, -1); // To support legacy indexing (<1.87 user code)
}
return true;
case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
if (ev->display.source == bd->Display)
@ -459,13 +575,6 @@ void ImGui_ImplAllegro5_NewFrame()
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
bd->Time = current_time;
// Setup inputs
ALLEGRO_KEYBOARD_STATE keys;
al_get_keyboard_state(&keys);
io.KeyCtrl = al_key_down(&keys, ALLEGRO_KEY_LCTRL) || al_key_down(&keys, ALLEGRO_KEY_RCTRL);
io.KeyShift = al_key_down(&keys, ALLEGRO_KEY_LSHIFT) || al_key_down(&keys, ALLEGRO_KEY_RSHIFT);
io.KeyAlt = al_key_down(&keys, ALLEGRO_KEY_ALT) || al_key_down(&keys, ALLEGRO_KEY_ALTGR);
io.KeySuper = al_key_down(&keys, ALLEGRO_KEY_LWIN) || al_key_down(&keys, ALLEGRO_KEY_RWIN);
// Setup mouse cursor shape
ImGui_ImplAllegro5_UpdateMouseCursor();
}

@ -3,13 +3,14 @@
// Implemented features:
// [X] Renderer: User texture binding. Use 'ALLEGRO_BITMAP*' as ImTextureID. Read the FAQ about ImTextureID!
// [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 ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues:
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs

@ -2,29 +2,31 @@
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// Implemented features:
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
// [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 AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// Missing features:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// Important:
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago)with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2021-03-04: Initial version.
#include "imgui.h"
#include "imgui_impl_android.h"
#include <time.h>
#include <map>
#include <queue>
#include <android/native_window.h>
#include <android/input.h>
#include <android/keycodes.h>
@ -34,7 +36,119 @@
static double g_Time = 0.0;
static ANativeWindow* g_Window;
static char g_LogTag[] = "ImGuiExample";
static std::map<int32_t, std::queue<int32_t>> g_KeyEventQueues; // FIXME: Remove dependency on map and queue once we use upcoming input queue.
static ImGuiKey ImGui_ImplAndroid_KeyCodeToImGuiKey(int32_t key_code)
{
switch (key_code)
{
case AKEYCODE_TAB: return ImGuiKey_Tab;
case AKEYCODE_DPAD_LEFT: return ImGuiKey_LeftArrow;
case AKEYCODE_DPAD_RIGHT: return ImGuiKey_RightArrow;
case AKEYCODE_DPAD_UP: return ImGuiKey_UpArrow;
case AKEYCODE_DPAD_DOWN: return ImGuiKey_DownArrow;
case AKEYCODE_PAGE_UP: return ImGuiKey_PageUp;
case AKEYCODE_PAGE_DOWN: return ImGuiKey_PageDown;
case AKEYCODE_MOVE_HOME: return ImGuiKey_Home;
case AKEYCODE_MOVE_END: return ImGuiKey_End;
case AKEYCODE_INSERT: return ImGuiKey_Insert;
case AKEYCODE_FORWARD_DEL: return ImGuiKey_Delete;
case AKEYCODE_DEL: return ImGuiKey_Backspace;
case AKEYCODE_SPACE: return ImGuiKey_Space;
case AKEYCODE_ENTER: return ImGuiKey_Enter;
case AKEYCODE_ESCAPE: return ImGuiKey_Escape;
case AKEYCODE_APOSTROPHE: return ImGuiKey_Apostrophe;
case AKEYCODE_COMMA: return ImGuiKey_Comma;
case AKEYCODE_MINUS: return ImGuiKey_Minus;
case AKEYCODE_PERIOD: return ImGuiKey_Period;
case AKEYCODE_SLASH: return ImGuiKey_Slash;
case AKEYCODE_SEMICOLON: return ImGuiKey_Semicolon;
case AKEYCODE_EQUALS: return ImGuiKey_Equal;
case AKEYCODE_LEFT_BRACKET: return ImGuiKey_LeftBracket;
case AKEYCODE_BACKSLASH: return ImGuiKey_Backslash;
case AKEYCODE_RIGHT_BRACKET: return ImGuiKey_RightBracket;
case AKEYCODE_GRAVE: return ImGuiKey_GraveAccent;
case AKEYCODE_CAPS_LOCK: return ImGuiKey_CapsLock;
case AKEYCODE_SCROLL_LOCK: return ImGuiKey_ScrollLock;
case AKEYCODE_NUM_LOCK: return ImGuiKey_NumLock;
case AKEYCODE_SYSRQ: return ImGuiKey_PrintScreen;
case AKEYCODE_BREAK: return ImGuiKey_Pause;
case AKEYCODE_NUMPAD_0: return ImGuiKey_Keypad0;
case AKEYCODE_NUMPAD_1: return ImGuiKey_Keypad1;
case AKEYCODE_NUMPAD_2: return ImGuiKey_Keypad2;
case AKEYCODE_NUMPAD_3: return ImGuiKey_Keypad3;
case AKEYCODE_NUMPAD_4: return ImGuiKey_Keypad4;
case AKEYCODE_NUMPAD_5: return ImGuiKey_Keypad5;
case AKEYCODE_NUMPAD_6: return ImGuiKey_Keypad6;
case AKEYCODE_NUMPAD_7: return ImGuiKey_Keypad7;
case AKEYCODE_NUMPAD_8: return ImGuiKey_Keypad8;
case AKEYCODE_NUMPAD_9: return ImGuiKey_Keypad9;
case AKEYCODE_NUMPAD_DOT: return ImGuiKey_KeypadDecimal;
case AKEYCODE_NUMPAD_DIVIDE: return ImGuiKey_KeypadDivide;
case AKEYCODE_NUMPAD_MULTIPLY: return ImGuiKey_KeypadMultiply;
case AKEYCODE_NUMPAD_SUBTRACT: return ImGuiKey_KeypadSubtract;
case AKEYCODE_NUMPAD_ADD: return ImGuiKey_KeypadAdd;
case AKEYCODE_NUMPAD_ENTER: return ImGuiKey_KeypadEnter;
case AKEYCODE_NUMPAD_EQUALS: return ImGuiKey_KeypadEqual;
case AKEYCODE_CTRL_LEFT: return ImGuiKey_LeftCtrl;
case AKEYCODE_SHIFT_LEFT: return ImGuiKey_LeftShift;
case AKEYCODE_ALT_LEFT: return ImGuiKey_LeftAlt;
case AKEYCODE_META_LEFT: return ImGuiKey_LeftSuper;
case AKEYCODE_CTRL_RIGHT: return ImGuiKey_RightCtrl;
case AKEYCODE_SHIFT_RIGHT: return ImGuiKey_RightShift;
case AKEYCODE_ALT_RIGHT: return ImGuiKey_RightAlt;
case AKEYCODE_META_RIGHT: return ImGuiKey_RightSuper;
case AKEYCODE_MENU: return ImGuiKey_Menu;
case AKEYCODE_0: return ImGuiKey_0;
case AKEYCODE_1: return ImGuiKey_1;
case AKEYCODE_2: return ImGuiKey_2;
case AKEYCODE_3: return ImGuiKey_3;
case AKEYCODE_4: return ImGuiKey_4;
case AKEYCODE_5: return ImGuiKey_5;
case AKEYCODE_6: return ImGuiKey_6;
case AKEYCODE_7: return ImGuiKey_7;
case AKEYCODE_8: return ImGuiKey_8;
case AKEYCODE_9: return ImGuiKey_9;
case AKEYCODE_A: return ImGuiKey_A;
case AKEYCODE_B: return ImGuiKey_B;
case AKEYCODE_C: return ImGuiKey_C;
case AKEYCODE_D: return ImGuiKey_D;
case AKEYCODE_E: return ImGuiKey_E;
case AKEYCODE_F: return ImGuiKey_F;
case AKEYCODE_G: return ImGuiKey_G;
case AKEYCODE_H: return ImGuiKey_H;
case AKEYCODE_I: return ImGuiKey_I;
case AKEYCODE_J: return ImGuiKey_J;
case AKEYCODE_K: return ImGuiKey_K;
case AKEYCODE_L: return ImGuiKey_L;
case AKEYCODE_M: return ImGuiKey_M;
case AKEYCODE_N: return ImGuiKey_N;
case AKEYCODE_O: return ImGuiKey_O;
case AKEYCODE_P: return ImGuiKey_P;
case AKEYCODE_Q: return ImGuiKey_Q;
case AKEYCODE_R: return ImGuiKey_R;
case AKEYCODE_S: return ImGuiKey_S;
case AKEYCODE_T: return ImGuiKey_T;
case AKEYCODE_U: return ImGuiKey_U;
case AKEYCODE_V: return ImGuiKey_V;
case AKEYCODE_W: return ImGuiKey_W;
case AKEYCODE_X: return ImGuiKey_X;
case AKEYCODE_Y: return ImGuiKey_Y;
case AKEYCODE_Z: return ImGuiKey_Z;
case AKEYCODE_F1: return ImGuiKey_F1;
case AKEYCODE_F2: return ImGuiKey_F2;
case AKEYCODE_F3: return ImGuiKey_F3;
case AKEYCODE_F4: return ImGuiKey_F4;
case AKEYCODE_F5: return ImGuiKey_F5;
case AKEYCODE_F6: return ImGuiKey_F6;
case AKEYCODE_F7: return ImGuiKey_F7;
case AKEYCODE_F8: return ImGuiKey_F8;
case AKEYCODE_F9: return ImGuiKey_F9;
case AKEYCODE_F10: return ImGuiKey_F10;
case AKEYCODE_F11: return ImGuiKey_F11;
case AKEYCODE_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
{
@ -45,12 +159,14 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
case AINPUT_EVENT_TYPE_KEY:
{
int32_t event_key_code = AKeyEvent_getKeyCode(input_event);
int32_t event_scan_code = AKeyEvent_getScanCode(input_event);
int32_t event_action = AKeyEvent_getAction(input_event);
int32_t event_meta_state = AKeyEvent_getMetaState(input_event);
io.KeyCtrl = ((event_meta_state & AMETA_CTRL_ON) != 0);
io.KeyShift = ((event_meta_state & AMETA_SHIFT_ON) != 0);
io.KeyAlt = ((event_meta_state & AMETA_ALT_ON) != 0);
io.AddKeyEvent(ImGuiKey_ModCtrl, (event_meta_state & AMETA_CTRL_ON) != 0);
io.AddKeyEvent(ImGuiKey_ModShift, (event_meta_state & AMETA_SHIFT_ON) != 0);
io.AddKeyEvent(ImGuiKey_ModAlt, (event_meta_state & AMETA_ALT_ON) != 0);
io.AddKeyEvent(ImGuiKey_ModSuper, (event_meta_state & AMETA_META_ON) != 0);
switch (event_action)
{
@ -59,8 +175,16 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
// ImGui_ImplAndroid_NewFrame()...or consider using IO queue, if suitable: https://github.com/ocornut/imgui/issues/2787
case AKEY_EVENT_ACTION_DOWN:
case AKEY_EVENT_ACTION_UP:
g_KeyEventQueues[event_key_code].push(event_action);
{
ImGuiKey key = ImGui_ImplAndroid_KeyCodeToImGuiKey(event_key_code);
if (key != ImGuiKey_None && (event_action == AKEY_EVENT_ACTION_DOWN || event_action == AKEY_EVENT_ACTION_UP))
{
io.AddKeyEvent(key, event_action == AKEY_EVENT_ACTION_DOWN);
io.SetKeyEventNativeData(key, event_key_code, event_scan_code);
}
break;
}
default:
break;
}
@ -81,26 +205,25 @@ int32_t ImGui_ImplAndroid_HandleInputEvent(AInputEvent* input_event)
if((AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_FINGER)
|| (AMotionEvent_getToolType(input_event, event_pointer_index) == AMOTION_EVENT_TOOL_TYPE_UNKNOWN))
{
io.MouseDown[0] = (event_action == AMOTION_EVENT_ACTION_DOWN);
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
io.AddMouseButtonEvent(0, event_action == AMOTION_EVENT_ACTION_DOWN);
}
break;
case AMOTION_EVENT_ACTION_BUTTON_PRESS:
case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
{
int32_t button_state = AMotionEvent_getButtonState(input_event);
io.MouseDown[0] = ((button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
io.MouseDown[1] = ((button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
io.MouseDown[2] = ((button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
io.AddMouseButtonEvent(0, (button_state & AMOTION_EVENT_BUTTON_PRIMARY) != 0);
io.AddMouseButtonEvent(1, (button_state & AMOTION_EVENT_BUTTON_SECONDARY) != 0);
io.AddMouseButtonEvent(2, (button_state & AMOTION_EVENT_BUTTON_TERTIARY) != 0);
}
break;
case AMOTION_EVENT_ACTION_HOVER_MOVE: // Hovering: Tool moves while NOT pressed (such as a physical mouse)
case AMOTION_EVENT_ACTION_MOVE: // Touch pointer moves while DOWN
io.MousePos = ImVec2(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
io.AddMousePosEvent(AMotionEvent_getX(input_event, event_pointer_index), AMotionEvent_getY(input_event, event_pointer_index));
break;
case AMOTION_EVENT_ACTION_SCROLL:
io.MouseWheel = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index);
io.MouseWheelH = AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index);
io.AddMouseWheelEvent(AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_HSCROLL, event_pointer_index), AMotionEvent_getAxisValue(input_event, AMOTION_EVENT_AXIS_VSCROLL, event_pointer_index));
break;
default:
break;
@ -123,30 +246,6 @@ bool ImGui_ImplAndroid_Init(ANativeWindow* window)
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformName = "imgui_impl_android";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = AKEYCODE_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = AKEYCODE_DPAD_LEFT; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_RightArrow] = AKEYCODE_DPAD_RIGHT; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_UpArrow] = AKEYCODE_DPAD_UP; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_DownArrow] = AKEYCODE_DPAD_DOWN; // also covers physical keyboard arrow key
io.KeyMap[ImGuiKey_PageUp] = AKEYCODE_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = AKEYCODE_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = AKEYCODE_MOVE_HOME;
io.KeyMap[ImGuiKey_End] = AKEYCODE_MOVE_END;
io.KeyMap[ImGuiKey_Insert] = AKEYCODE_INSERT;
io.KeyMap[ImGuiKey_Delete] = AKEYCODE_FORWARD_DEL;
io.KeyMap[ImGuiKey_Backspace] = AKEYCODE_DEL;
io.KeyMap[ImGuiKey_Space] = AKEYCODE_SPACE;
io.KeyMap[ImGuiKey_Enter] = AKEYCODE_ENTER;
io.KeyMap[ImGuiKey_Escape] = AKEYCODE_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = AKEYCODE_NUMPAD_ENTER;
io.KeyMap[ImGuiKey_A] = AKEYCODE_A;
io.KeyMap[ImGuiKey_C] = AKEYCODE_C;
io.KeyMap[ImGuiKey_V] = AKEYCODE_V;
io.KeyMap[ImGuiKey_X] = AKEYCODE_X;
io.KeyMap[ImGuiKey_Y] = AKEYCODE_Y;
io.KeyMap[ImGuiKey_Z] = AKEYCODE_Z;
return true;
}
@ -158,16 +257,6 @@ void ImGui_ImplAndroid_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
// Process queued key events
// FIXME: This is a workaround for multiple key event actions occurring at once (see above) and can be removed once we use upcoming input queue.
for (auto& key_queue : g_KeyEventQueues)
{
if (key_queue.second.empty())
continue;
io.KeysDown[key_queue.first] = (key_queue.second.front() == AKEY_EVENT_ACTION_DOWN);
key_queue.second.pop();
}
// Setup display size (every frame to accommodate for window resizing)
int32_t window_width = ANativeWindow_getWidth(g_Window);
int32_t window_height = ANativeWindow_getHeight(g_Window);

@ -2,16 +2,17 @@
// This needs to be used along with the OpenGL 3 Renderer (imgui_impl_opengl3)
// Implemented features:
// [X] Platform: Keyboard arrays indexed using AKEYCODE_* codes, e.g. ImGui::IsKeyPressed(AKEYCODE_SPACE).
// [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 AKEYCODE_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// Missing features:
// [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// Important:
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)
// - FIXME: Unicode character inputs needs to be passed by Dear ImGui by the application (see examples/ and issue #3446)
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs

@ -13,7 +13,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 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-05-19: DirectX10: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX10: Change blending equation to preserve alpha in output buffer.
@ -259,8 +259,14 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data)
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
const D3D10_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y)};
const D3D10_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
@ -559,8 +565,9 @@ bool ImGui_ImplDX10_Init(ID3D10Device* device)
void ImGui_ImplDX10_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX10_ShutdownPlatformInterface();
ImGui_ImplDX10_InvalidateDeviceObjects();

@ -13,7 +13,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 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-05-19: DirectX11: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX11: Change blending equation to preserve alpha in output buffer.
@ -269,8 +269,14 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data)
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
const D3D11_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
const D3D11_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
ctx->RSSetScissorRects(1, &r);
// Bind texture, Draw
@ -575,8 +581,9 @@ bool ImGui_ImplDX11_Init(ID3D11Device* device, ID3D11DeviceContext* device_co
void ImGui_ImplDX11_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX11_ShutdownPlatformInterface();
ImGui_ImplDX11_InvalidateDeviceObjects();

@ -22,7 +22,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 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-05-19: DirectX12: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: DirectX12: Change blending equation to preserve alpha in output buffer.
@ -337,16 +337,19 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL
}
else
{
// Apply Scissor, Bind texture, Draw
const D3D12_RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
if (r.right > r.left && r.bottom > r.top)
{
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
texture_handle.ptr = (UINT64)pcmd->GetTexID();
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
ctx->RSSetScissorRects(1, &r);
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
const D3D12_RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
D3D12_GPU_DESCRIPTOR_HANDLE texture_handle = {};
texture_handle.ptr = (UINT64)pcmd->GetTexID();
ctx->SetGraphicsRootDescriptorTable(1, texture_handle);
ctx->RSSetScissorRects(1, &r);
ctx->DrawIndexedInstanced(pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
@ -796,8 +799,9 @@ bool ImGui_ImplDX12_Init(ID3D12Device* device, int num_frames_in_flight, DXGI_FO
void ImGui_ImplDX12_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
// Manually delete main viewport render resources in-case we haven't initialized for viewports
ImGuiViewport* main_viewport = ImGui::GetMainViewport();

@ -7,23 +7,17 @@
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Important: to compile on 32-bit systems, this backend requires code to be compiled with '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// This define is set in the example .vcxproj file and need to be replicated in your app or by adding it to your imconfig.h file.
// See imgui_impl_dx12.cpp file for details.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
#include <dxgiformat.h> // DXGI_FORMAT
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4471) // a forward declaration of an unscoped enumeration must have an underlying type
#endif
enum DXGI_FORMAT;
struct ID3D12Device;
struct ID3D12DescriptorHeap;
struct ID3D12GraphicsCommandList;
@ -43,8 +37,3 @@ IMGUI_IMPL_API void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_ImplDX12_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_ImplDX12_CreateDeviceObjects();
#ifdef _MSC_VER
#pragma warning (pop)
#endif

@ -13,7 +13,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 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-06-25: DirectX9: Explicitly disable texture state stages after >= 1.
// 2021-05-19: DirectX9: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
@ -256,7 +256,14 @@ void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data)
}
else
{
const RECT r = { (LONG)(pcmd->ClipRect.x - clip_off.x), (LONG)(pcmd->ClipRect.y - clip_off.y), (LONG)(pcmd->ClipRect.z - clip_off.x), (LONG)(pcmd->ClipRect.w - clip_off.y) };
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min(pcmd->ClipRect.x - clip_off.x, pcmd->ClipRect.y - clip_off.y);
ImVec2 clip_max(pcmd->ClipRect.z - clip_off.x, pcmd->ClipRect.w - clip_off.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply Scissor/clipping rectangle, Bind texture, Draw
const RECT r = { (LONG)clip_min.x, (LONG)clip_min.y, (LONG)clip_max.x, (LONG)clip_max.y };
const LPDIRECT3DTEXTURE9 texture = (LPDIRECT3DTEXTURE9)pcmd->GetTexID();
bd->pd3dDevice->SetTexture(0, texture);
bd->pd3dDevice->SetScissorRect(&r);
@ -305,8 +312,9 @@ bool ImGui_ImplDX9_Init(IDirect3DDevice9* device)
void ImGui_ImplDX9_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplDX9_ShutdownPlatformInterface();
ImGui_ImplDX9_InvalidateDeviceObjects();

@ -5,9 +5,9 @@
// Implemented features:
// [X] Platform: Clipboard support.
// [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 GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Issues:
@ -20,7 +20,15 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-02-07: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing callbacks after iniitializing backend.
// 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: *BREAKING CHANGE*: Now using glfwSetCursorPosCallback(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetCursorPosCallback() and forward it to the backend via ImGui_ImplGlfw_CursorPosCallback().
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2022-01-05: Inputs: Converting GLFW untranslated keycodes back to translated keycodes (in the ImGui_ImplGlfw_KeyCallback() function) in order to match the behavior of every other backend, and facilitate the use of GLFW with lettered-shortcuts API.
// 2021-08-17: *BREAKING CHANGE*: Now using glfwSetWindowFocusCallback() to calling io.AddFocusEvent(). If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() and forward it to the backend via ImGui_ImplGlfw_WindowFocusCallback().
// 2021-07-29: *BREAKING CHANGE*: Now using glfwSetCursorEnterCallback(). MousePos is correctly reported when the host platform window is hovered but not focused. If you called ImGui_ImplGlfw_InitXXX() with install_callbacks = false, you MUST install glfwSetWindowFocusCallback() callback and forward it to the backend via ImGui_ImplGlfw_CursorEnterCallback().
// 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).
@ -49,6 +57,16 @@
#include "imgui.h"
#include "imgui_impl_glfw.h"
// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
#endif
// GLFW
#include <GLFW/glfw3.h>
#ifdef _WIN32
@ -75,6 +93,8 @@
#else
#define GLFW_HAS_MOUSE_PASSTHROUGH (0)
#endif
#define GLFW_HAS_GAMEPAD_API (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetGamepadState() new api
#define GLFW_HAS_GET_KEY_NAME (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwGetKeyName()
// GLFW data
enum GlfwClientApi
@ -90,14 +110,15 @@ struct ImGui_ImplGlfw_Data
GlfwClientApi ClientApi;
double Time;
GLFWwindow* MouseWindow;
bool MouseJustPressed[ImGuiMouseButton_COUNT];
GLFWcursor* MouseCursors[ImGuiMouseCursor_COUNT];
GLFWwindow* KeyOwnerWindows[512];
ImVec2 LastValidMousePos;
GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST];
bool InstalledCallbacks;
bool WantUpdateMonitors;
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
GLFWwindowfocusfun PrevUserCallbackWindowFocus;
GLFWcursorposfun PrevUserCallbackCursorPos;
GLFWcursorenterfun PrevUserCallbackCursorEnter;
GLFWmousebuttonfun PrevUserCallbackMousebutton;
GLFWscrollfun PrevUserCallbackScroll;
@ -136,6 +157,128 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
glfwSetClipboardString((GLFWwindow*)user_data, text);
}
static ImGuiKey ImGui_ImplGlfw_KeyToImGuiKey(int key)
{
switch (key)
{
case GLFW_KEY_TAB: return ImGuiKey_Tab;
case GLFW_KEY_LEFT: return ImGuiKey_LeftArrow;
case GLFW_KEY_RIGHT: return ImGuiKey_RightArrow;
case GLFW_KEY_UP: return ImGuiKey_UpArrow;
case GLFW_KEY_DOWN: return ImGuiKey_DownArrow;
case GLFW_KEY_PAGE_UP: return ImGuiKey_PageUp;
case GLFW_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
case GLFW_KEY_HOME: return ImGuiKey_Home;
case GLFW_KEY_END: return ImGuiKey_End;
case GLFW_KEY_INSERT: return ImGuiKey_Insert;
case GLFW_KEY_DELETE: return ImGuiKey_Delete;
case GLFW_KEY_BACKSPACE: return ImGuiKey_Backspace;
case GLFW_KEY_SPACE: return ImGuiKey_Space;
case GLFW_KEY_ENTER: return ImGuiKey_Enter;
case GLFW_KEY_ESCAPE: return ImGuiKey_Escape;
case GLFW_KEY_APOSTROPHE: return ImGuiKey_Apostrophe;
case GLFW_KEY_COMMA: return ImGuiKey_Comma;
case GLFW_KEY_MINUS: return ImGuiKey_Minus;
case GLFW_KEY_PERIOD: return ImGuiKey_Period;
case GLFW_KEY_SLASH: return ImGuiKey_Slash;
case GLFW_KEY_SEMICOLON: return ImGuiKey_Semicolon;
case GLFW_KEY_EQUAL: return ImGuiKey_Equal;
case GLFW_KEY_LEFT_BRACKET: return ImGuiKey_LeftBracket;
case GLFW_KEY_BACKSLASH: return ImGuiKey_Backslash;
case GLFW_KEY_RIGHT_BRACKET: return ImGuiKey_RightBracket;
case GLFW_KEY_GRAVE_ACCENT: return ImGuiKey_GraveAccent;
case GLFW_KEY_CAPS_LOCK: return ImGuiKey_CapsLock;
case GLFW_KEY_SCROLL_LOCK: return ImGuiKey_ScrollLock;
case GLFW_KEY_NUM_LOCK: return ImGuiKey_NumLock;
case GLFW_KEY_PRINT_SCREEN: return ImGuiKey_PrintScreen;
case GLFW_KEY_PAUSE: return ImGuiKey_Pause;
case GLFW_KEY_KP_0: return ImGuiKey_Keypad0;
case GLFW_KEY_KP_1: return ImGuiKey_Keypad1;
case GLFW_KEY_KP_2: return ImGuiKey_Keypad2;
case GLFW_KEY_KP_3: return ImGuiKey_Keypad3;
case GLFW_KEY_KP_4: return ImGuiKey_Keypad4;
case GLFW_KEY_KP_5: return ImGuiKey_Keypad5;
case GLFW_KEY_KP_6: return ImGuiKey_Keypad6;
case GLFW_KEY_KP_7: return ImGuiKey_Keypad7;
case GLFW_KEY_KP_8: return ImGuiKey_Keypad8;
case GLFW_KEY_KP_9: return ImGuiKey_Keypad9;
case GLFW_KEY_KP_DECIMAL: return ImGuiKey_KeypadDecimal;
case GLFW_KEY_KP_DIVIDE: return ImGuiKey_KeypadDivide;
case GLFW_KEY_KP_MULTIPLY: return ImGuiKey_KeypadMultiply;
case GLFW_KEY_KP_SUBTRACT: return ImGuiKey_KeypadSubtract;
case GLFW_KEY_KP_ADD: return ImGuiKey_KeypadAdd;
case GLFW_KEY_KP_ENTER: return ImGuiKey_KeypadEnter;
case GLFW_KEY_KP_EQUAL: return ImGuiKey_KeypadEqual;
case GLFW_KEY_LEFT_SHIFT: return ImGuiKey_LeftShift;
case GLFW_KEY_LEFT_CONTROL: return ImGuiKey_LeftCtrl;
case GLFW_KEY_LEFT_ALT: return ImGuiKey_LeftAlt;
case GLFW_KEY_LEFT_SUPER: return ImGuiKey_LeftSuper;
case GLFW_KEY_RIGHT_SHIFT: return ImGuiKey_RightShift;
case GLFW_KEY_RIGHT_CONTROL: return ImGuiKey_RightCtrl;
case GLFW_KEY_RIGHT_ALT: return ImGuiKey_RightAlt;
case GLFW_KEY_RIGHT_SUPER: return ImGuiKey_RightSuper;
case GLFW_KEY_MENU: return ImGuiKey_Menu;
case GLFW_KEY_0: return ImGuiKey_0;
case GLFW_KEY_1: return ImGuiKey_1;
case GLFW_KEY_2: return ImGuiKey_2;
case GLFW_KEY_3: return ImGuiKey_3;
case GLFW_KEY_4: return ImGuiKey_4;
case GLFW_KEY_5: return ImGuiKey_5;
case GLFW_KEY_6: return ImGuiKey_6;
case GLFW_KEY_7: return ImGuiKey_7;
case GLFW_KEY_8: return ImGuiKey_8;
case GLFW_KEY_9: return ImGuiKey_9;
case GLFW_KEY_A: return ImGuiKey_A;
case GLFW_KEY_B: return ImGuiKey_B;
case GLFW_KEY_C: return ImGuiKey_C;
case GLFW_KEY_D: return ImGuiKey_D;
case GLFW_KEY_E: return ImGuiKey_E;
case GLFW_KEY_F: return ImGuiKey_F;
case GLFW_KEY_G: return ImGuiKey_G;
case GLFW_KEY_H: return ImGuiKey_H;
case GLFW_KEY_I: return ImGuiKey_I;
case GLFW_KEY_J: return ImGuiKey_J;
case GLFW_KEY_K: return ImGuiKey_K;
case GLFW_KEY_L: return ImGuiKey_L;
case GLFW_KEY_M: return ImGuiKey_M;
case GLFW_KEY_N: return ImGuiKey_N;
case GLFW_KEY_O: return ImGuiKey_O;
case GLFW_KEY_P: return ImGuiKey_P;
case GLFW_KEY_Q: return ImGuiKey_Q;
case GLFW_KEY_R: return ImGuiKey_R;
case GLFW_KEY_S: return ImGuiKey_S;
case GLFW_KEY_T: return ImGuiKey_T;
case GLFW_KEY_U: return ImGuiKey_U;
case GLFW_KEY_V: return ImGuiKey_V;
case GLFW_KEY_W: return ImGuiKey_W;
case GLFW_KEY_X: return ImGuiKey_X;
case GLFW_KEY_Y: return ImGuiKey_Y;
case GLFW_KEY_Z: return ImGuiKey_Z;
case GLFW_KEY_F1: return ImGuiKey_F1;
case GLFW_KEY_F2: return ImGuiKey_F2;
case GLFW_KEY_F3: return ImGuiKey_F3;
case GLFW_KEY_F4: return ImGuiKey_F4;
case GLFW_KEY_F5: return ImGuiKey_F5;
case GLFW_KEY_F6: return ImGuiKey_F6;
case GLFW_KEY_F7: return ImGuiKey_F7;
case GLFW_KEY_F8: return ImGuiKey_F8;
case GLFW_KEY_F9: return ImGuiKey_F9;
case GLFW_KEY_F10: return ImGuiKey_F10;
case GLFW_KEY_F11: return ImGuiKey_F11;
case GLFW_KEY_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
static void ImGui_ImplGlfw_UpdateKeyModifiers(int mods)
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(ImGuiKey_ModCtrl, (mods & GLFW_MOD_CONTROL) != 0);
io.AddKeyEvent(ImGuiKey_ModShift, (mods & GLFW_MOD_SHIFT) != 0);
io.AddKeyEvent(ImGuiKey_ModAlt, (mods & GLFW_MOD_ALT) != 0);
io.AddKeyEvent(ImGuiKey_ModSuper, (mods & GLFW_MOD_SUPER) != 0);
}
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
@ -144,8 +287,11 @@ void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int acti
//if (g_PrevUserCallbackMousebutton != NULL)
// g_PrevUserCallbackMousebutton(g_Window, button, action, mods);
if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(bd->MouseJustPressed))
bd->MouseJustPressed[button] = true;
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
ImGuiIO& io = ImGui::GetIO();
if (button >= 0 && button < ImGuiMouseButton_COUNT)
io.AddMouseButtonEvent(button, action == GLFW_PRESS);
}
void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
@ -157,42 +303,56 @@ void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yo
// g_PrevUserCallbackScroll(g_Window, xoffset, yoffset);
ImGuiIO& io = ImGui::GetIO();
io.MouseWheelH += (float)xoffset;
io.MouseWheel += (float)yoffset;
io.AddMouseWheelEvent((float)xoffset, (float)yoffset);
}
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
static int ImGui_ImplGlfw_TranslateUntranslatedKey(int key, int scancode)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
bd->PrevUserCallbackKey(window, key, scancode, action, mods);
//if (g_PrevUserCallbackKey != NULL)
// g_PrevUserCallbackKey(g_Window, key, scancode, action, mods);
ImGuiIO& io = ImGui::GetIO();
if (key >= 0 && key < IM_ARRAYSIZE(io.KeysDown))
#if GLFW_HAS_GET_KEY_NAME && !defined(__EMSCRIPTEN__)
// GLFW 3.1+ attempts to "untranslate" keys, which goes the opposite of what every other framework does, making using lettered shortcuts difficult.
// (It had reasons to do so: namely GLFW is/was more likely to be used for WASD-type game controls rather than lettered shortcuts, but IHMO the 3.1 change could have been done differently)
// See https://github.com/glfw/glfw/issues/1502 for details.
// Adding a workaround to undo this (so our keys are translated->untranslated->translated, likely a lossy process).
// This won't cover edge cases but this is at least going to cover common cases.
if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_EQUAL)
return key;
const char* key_name = glfwGetKeyName(key, scancode);
if (key_name && key_name[0] != 0 && key_name[1] == 0)
{
if (action == GLFW_PRESS)
{
io.KeysDown[key] = true;
bd->KeyOwnerWindows[key] = window;
}
if (action == GLFW_RELEASE)
{
io.KeysDown[key] = false;
bd->KeyOwnerWindows[key] = NULL;
}
const char char_names[] = "`-=[]\\,;\'./";
const int char_keys[] = { GLFW_KEY_GRAVE_ACCENT, GLFW_KEY_MINUS, GLFW_KEY_EQUAL, GLFW_KEY_LEFT_BRACKET, GLFW_KEY_RIGHT_BRACKET, GLFW_KEY_BACKSLASH, GLFW_KEY_COMMA, GLFW_KEY_SEMICOLON, GLFW_KEY_APOSTROPHE, GLFW_KEY_PERIOD, GLFW_KEY_SLASH, 0 };
IM_ASSERT(IM_ARRAYSIZE(char_names) == IM_ARRAYSIZE(char_keys));
if (key_name[0] >= '0' && key_name[0] <= '9') { key = GLFW_KEY_0 + (key_name[0] - '0'); }
else if (key_name[0] >= 'A' && key_name[0] <= 'Z') { key = GLFW_KEY_A + (key_name[0] - 'A'); }
else if (const char* p = strchr(char_names, key_name[0])) { key = char_keys[p - char_names]; }
}
// Modifiers are not reliable across systems
io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
#ifdef _WIN32
io.KeySuper = false;
// if (action == GLFW_PRESS) printf("key %d scancode %d name '%s'\n", key, scancode, key_name);
#else
io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
IM_UNUSED(scancode);
#endif
return key;
}
void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int mods)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackKey != NULL && window == bd->Window)
bd->PrevUserCallbackKey(window, keycode, scancode, action, mods);
if (action != GLFW_PRESS && action != GLFW_RELEASE)
return;
ImGui_ImplGlfw_UpdateKeyModifiers(mods);
if (keycode >= 0 && keycode < IM_ARRAYSIZE(bd->KeyOwnerWindows))
bd->KeyOwnerWindows[keycode] = (action == GLFW_PRESS) ? window : NULL;
keycode = ImGui_ImplGlfw_TranslateUntranslatedKey(keycode, scancode);
ImGuiIO& io = ImGui::GetIO();
ImGuiKey imgui_key = ImGui_ImplGlfw_KeyToImGuiKey(keycode);
io.AddKeyEvent(imgui_key, (action == GLFW_PRESS));
io.SetKeyEventNativeData(imgui_key, keycode, scancode); // To support legacy indexing (<1.87 user code)
}
void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
@ -205,16 +365,44 @@ void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused)
io.AddFocusEvent(focused != 0);
}
void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorPos != NULL && window == bd->Window)
bd->PrevUserCallbackCursorPos(window, x, y);
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
int window_x, window_y;
glfwGetWindowPos(window, &window_x, &window_y);
x += window_x;
y += window_y;
}
io.AddMousePosEvent((float)x, (float)y);
bd->LastValidMousePos = ImVec2((float)x, (float)y);
}
// Workaround: X11 seems to send spurious Leave/Enter events which would make us lose our position,
// so we back it up and restore on Leave/Enter (see https://github.com/ocornut/imgui/issues/4984)
void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
if (bd->PrevUserCallbackCursorEnter != NULL && window == bd->Window)
bd->PrevUserCallbackCursorEnter(window, entered);
ImGuiIO& io = ImGui::GetIO();
if (entered)
{
bd->MouseWindow = window;
if (!entered && bd->MouseWindow == window)
io.AddMousePosEvent(bd->LastValidMousePos.x, bd->LastValidMousePos.y);
}
else if (!entered && bd->MouseWindow == window)
{
bd->LastValidMousePos = io.MousePos;
bd->MouseWindow = NULL;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
}
void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c)
@ -233,6 +421,48 @@ void ImGui_ImplGlfw_MonitorCallback(GLFWmonitor*, int)
bd->WantUpdateMonitors = true;
}
void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd->InstalledCallbacks == false && "Callbacks already installed!");
IM_ASSERT(bd->Window == window);
bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
bd->PrevUserCallbackCursorPos = glfwSetCursorPosCallback(window, ImGui_ImplGlfw_CursorPosCallback);
bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
bd->InstalledCallbacks = true;
}
void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window)
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd->InstalledCallbacks == true && "Callbacks not installed!");
IM_ASSERT(bd->Window == window);
glfwSetWindowFocusCallback(window, bd->PrevUserCallbackWindowFocus);
glfwSetCursorEnterCallback(window, bd->PrevUserCallbackCursorEnter);
glfwSetCursorPosCallback(window, bd->PrevUserCallbackCursorPos);
glfwSetMouseButtonCallback(window, bd->PrevUserCallbackMousebutton);
glfwSetScrollCallback(window, bd->PrevUserCallbackScroll);
glfwSetKeyCallback(window, bd->PrevUserCallbackKey);
glfwSetCharCallback(window, bd->PrevUserCallbackChar);
glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
bd->InstalledCallbacks = false;
bd->PrevUserCallbackWindowFocus = NULL;
bd->PrevUserCallbackCursorEnter = NULL;
bd->PrevUserCallbackCursorPos = NULL;
bd->PrevUserCallbackMousebutton = NULL;
bd->PrevUserCallbackScroll = NULL;
bd->PrevUserCallbackKey = NULL;
bd->PrevUserCallbackChar = NULL;
bd->PrevUserCallbackMonitor = NULL;
}
static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api)
{
ImGuiIO& io = ImGui::GetIO();
@ -246,37 +476,13 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
#endif
bd->Window = window;
bd->Time = 0.0;
bd->WantUpdateMonitors = true;
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = GLFW_KEY_KP_ENTER;
io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
io.ClipboardUserData = bd->Window;
@ -305,23 +511,8 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
glfwSetErrorCallback(prev_error_callback);
// Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any.
bd->PrevUserCallbackWindowFocus = NULL;
bd->PrevUserCallbackMousebutton = NULL;
bd->PrevUserCallbackScroll = NULL;
bd->PrevUserCallbackKey = NULL;
bd->PrevUserCallbackChar = NULL;
bd->PrevUserCallbackMonitor = NULL;
if (install_callbacks)
{
bd->InstalledCallbacks = true;
bd->PrevUserCallbackWindowFocus = glfwSetWindowFocusCallback(window, ImGui_ImplGlfw_WindowFocusCallback);
bd->PrevUserCallbackCursorEnter = glfwSetCursorEnterCallback(window, ImGui_ImplGlfw_CursorEnterCallback);
bd->PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback);
bd->PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback);
bd->PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback);
bd->PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback);
bd->PrevUserCallbackMonitor = glfwSetMonitorCallback(ImGui_ImplGlfw_MonitorCallback);
}
ImGui_ImplGlfw_InstallCallbacks(window);
// Update monitors the first time (note: monitor callback are broken in GLFW 3.2 and earlier, see github.com/glfw/glfw/issues/784)
ImGui_ImplGlfw_UpdateMonitors();
@ -357,21 +548,14 @@ bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool install_callbacks)
void ImGui_ImplGlfw_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplGlfw_ShutdownPlatformInterface();
if (bd->InstalledCallbacks)
{
glfwSetWindowFocusCallback(bd->Window, bd->PrevUserCallbackWindowFocus);
glfwSetCursorEnterCallback(bd->Window, bd->PrevUserCallbackCursorEnter);
glfwSetMouseButtonCallback(bd->Window, bd->PrevUserCallbackMousebutton);
glfwSetScrollCallback(bd->Window, bd->PrevUserCallbackScroll);
glfwSetKeyCallback(bd->Window, bd->PrevUserCallbackKey);
glfwSetCharCallback(bd->Window, bd->PrevUserCallbackChar);
glfwSetMonitorCallback(bd->PrevUserCallbackMonitor);
}
ImGui_ImplGlfw_RestoreCallbacks(bd->Window);
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
glfwDestroyCursor(bd->MouseCursors[cursor_n]);
@ -381,72 +565,59 @@ void ImGui_ImplGlfw_Shutdown()
IM_DELETE(bd);
}
static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
static void ImGui_ImplGlfw_UpdateMouseData()
{
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
ImGuiID mouse_viewport_id = 0;
const ImVec2 mouse_pos_prev = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
io.MouseHoveredViewport = 0;
// Update mouse buttons
// (if a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame)
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{
io.MouseDown[i] = bd->MouseJustPressed[i] || glfwGetMouseButton(bd->Window, i) != 0;
bd->MouseJustPressed[i] = false;
}
for (int n = 0; n < platform_io.Viewports.Size; n++)
{
ImGuiViewport* viewport = platform_io.Viewports[n];
GLFWwindow* window = (GLFWwindow*)viewport->PlatformHandle;
#ifdef __EMSCRIPTEN__
const bool focused = true;
const bool is_window_focused = true;
#else
const bool focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
const bool is_window_focused = glfwGetWindowAttrib(window, GLFW_FOCUSED) != 0;
#endif
GLFWwindow* mouse_window = (bd->MouseWindow == window || focused) ? window : NULL;
// Update mouse buttons
if (focused)
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
io.MouseDown[i] |= glfwGetMouseButton(window, i) != 0;
// Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
// (When multi-viewports are enabled, all Dear ImGui positions are same as OS positions)
if (io.WantSetMousePos && focused)
glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y));
// Set Dear ImGui mouse position from OS position
if (mouse_window != NULL)
if (is_window_focused)
{
double mouse_x, mouse_y;
glfwGetCursorPos(mouse_window, &mouse_x, &mouse_y);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
int window_x, window_y;
glfwGetWindowPos(window, &window_x, &window_y);
io.MousePos = ImVec2((float)mouse_x + window_x, (float)mouse_y + window_y);
}
else
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
if (io.WantSetMousePos)
glfwSetCursorPos(window, (double)(mouse_pos_prev.x - viewport->Pos.x), (double)(mouse_pos_prev.y - viewport->Pos.y));
// (Optional) Fallback to provide mouse position when focused (ImGui_ImplGlfw_CursorPosCallback already provides this when hovered or captured)
if (bd->MouseWindow == NULL)
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
io.MousePos = ImVec2((float)mouse_x, (float)mouse_y);
double mouse_x, mouse_y;
glfwGetCursorPos(window, &mouse_x, &mouse_y);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
int window_x, window_y;
glfwGetWindowPos(window, &window_x, &window_y);
mouse_x += window_x;
mouse_y += window_y;
}
bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y);
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
}
}
// (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
// Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
// - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
// - This is _regardless_ of whether another viewport is focused or being dragged from.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, imgui will ignore this field and infer the information by relying on the
// rectangles and last focused time of every viewports it knows about. It will be unaware of other windows that may be sitting between or over your windows.
// [GLFW] FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
// - [X] GLFW >= 3.3 backend ON WINDOWS ONLY does correctly ignore viewports with the _NoInputs flag.
// - [!] GLFW <= 3.2 backend CANNOT correctly ignore viewports with the _NoInputs flag, and CANNOT reported Hovered Viewport because of mouse capture.
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
// by the backend, and use its flawed heuristic to guess the viewport behind.
// - [X] GLFW backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
// FIXME: This is currently only correct on Win32. See what we do below with the WM_NCHITTEST, missing an equivalent for other systems.
// See https://github.com/glfw/glfw/issues/1236 if you want to help in making this a GLFW feature.
#if GLFW_HAS_MOUSE_PASSTHROUGH || (GLFW_HAS_WINDOW_HOVERED && defined(_WIN32))
const bool window_no_input = (viewport->Flags & ImGuiViewportFlags_NoInputs) != 0;
@ -454,9 +625,14 @@ static void ImGui_ImplGlfw_UpdateMousePosAndButtons()
glfwSetWindowAttrib(window, GLFW_MOUSE_PASSTHROUGH, window_no_input);
#endif
if (glfwGetWindowAttrib(window, GLFW_HOVERED) && !window_no_input)
io.MouseHoveredViewport = viewport->ID;
mouse_viewport_id = viewport->ID;
#else
// We cannot use bd->MouseWindow maintained from CursorEnter/Leave callbacks, because it is locked to the window capturing mouse.
#endif
}
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
io.AddMouseViewportEvent(mouse_viewport_id);
}
static void ImGui_ImplGlfw_UpdateMouseCursor()
@ -486,41 +662,57 @@ static void ImGui_ImplGlfw_UpdateMouseCursor()
}
}
// Update gamepad inputs
static inline float Saturate(float v) { return v < 0.0f ? 0.0f : v > 1.0f ? 1.0f : v; }
static void ImGui_ImplGlfw_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; }
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
#if GLFW_HAS_GAMEPAD_API
GLFWgamepadstate gamepad;
if (!glfwGetGamepadState(GLFW_JOYSTICK_1, &gamepad))
return;
#define MAP_BUTTON(KEY_NO, BUTTON_NO, _UNUSED) do { io.AddKeyEvent(KEY_NO, gamepad.buttons[BUTTON_NO] != 0); } while (0)
#define MAP_ANALOG(KEY_NO, AXIS_NO, _UNUSED, V0, V1) do { float v = gamepad.axes[AXIS_NO]; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
#else
int axes_count = 0, buttons_count = 0;
const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count);
const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count);
MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f);
MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f);
MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f);
if (axes_count == 0 || buttons_count == 0)
return;
#define MAP_BUTTON(KEY_NO, _UNUSED, BUTTON_NO) do { io.AddKeyEvent(KEY_NO, (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS)); } while (0)
#define MAP_ANALOG(KEY_NO, _UNUSED, AXIS_NO, V0, V1) do { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); io.AddKeyAnalogEvent(KEY_NO, v > 0.10f, Saturate(v)); } while (0)
#endif
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
MAP_BUTTON(ImGuiKey_GamepadStart, GLFW_GAMEPAD_BUTTON_START, 7);
MAP_BUTTON(ImGuiKey_GamepadBack, GLFW_GAMEPAD_BUTTON_BACK, 6);
MAP_BUTTON(ImGuiKey_GamepadFaceDown, GLFW_GAMEPAD_BUTTON_A, 0); // Xbox A, PS Cross
MAP_BUTTON(ImGuiKey_GamepadFaceRight, GLFW_GAMEPAD_BUTTON_B, 1); // Xbox B, PS Circle
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, GLFW_GAMEPAD_BUTTON_X, 2); // Xbox X, PS Square
MAP_BUTTON(ImGuiKey_GamepadFaceUp, GLFW_GAMEPAD_BUTTON_Y, 3); // Xbox Y, PS Triangle
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, GLFW_GAMEPAD_BUTTON_DPAD_LEFT, 13);
MAP_BUTTON(ImGuiKey_GamepadDpadRight, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT, 11);
MAP_BUTTON(ImGuiKey_GamepadDpadUp, GLFW_GAMEPAD_BUTTON_DPAD_UP, 10);
MAP_BUTTON(ImGuiKey_GamepadDpadDown, GLFW_GAMEPAD_BUTTON_DPAD_DOWN, 12);
MAP_BUTTON(ImGuiKey_GamepadL1, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER, 4);
MAP_BUTTON(ImGuiKey_GamepadR1, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER, 5);
MAP_ANALOG(ImGuiKey_GamepadL2, GLFW_GAMEPAD_AXIS_LEFT_TRIGGER, 4, -0.75f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadR2, GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER, 5, -0.75f, +1.0f);
MAP_BUTTON(ImGuiKey_GamepadL3, GLFW_GAMEPAD_BUTTON_LEFT_THUMB, 8);
MAP_BUTTON(ImGuiKey_GamepadR3, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB, 9);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, GLFW_GAMEPAD_AXIS_LEFT_X, 0, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, GLFW_GAMEPAD_AXIS_LEFT_X, 0, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, GLFW_GAMEPAD_AXIS_LEFT_Y, 1, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, GLFW_GAMEPAD_AXIS_RIGHT_X, 2, +0.25f, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, -0.25f, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, GLFW_GAMEPAD_AXIS_RIGHT_Y, 3, +0.25f, +1.0f);
#undef MAP_BUTTON
#undef MAP_ANALOG
if (axes_count > 0 && buttons_count > 0)
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
else
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
}
static void ImGui_ImplGlfw_UpdateMonitors()
@ -571,7 +763,7 @@ void ImGui_ImplGlfw_NewFrame()
glfwGetFramebufferSize(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);
io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h);
if (bd->WantUpdateMonitors)
ImGui_ImplGlfw_UpdateMonitors();
@ -580,7 +772,7 @@ void ImGui_ImplGlfw_NewFrame()
io.DeltaTime = bd->Time > 0.0 ? (float)(current_time - bd->Time) : (float)(1.0f / 60.0f);
bd->Time = current_time;
ImGui_ImplGlfw_UpdateMousePosAndButtons();
ImGui_ImplGlfw_UpdateMouseData();
ImGui_ImplGlfw_UpdateMouseCursor();
// Update game controllers (if enabled and available)
@ -676,6 +868,7 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
// Install GLFW callbacks for secondary viewports
glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback);
glfwSetCursorEnterCallback(vd->Window, ImGui_ImplGlfw_CursorEnterCallback);
glfwSetCursorPosCallback(vd->Window, ImGui_ImplGlfw_CursorPosCallback);
glfwSetMouseButtonCallback(vd->Window, ImGui_ImplGlfw_MouseButtonCallback);
glfwSetScrollCallback(vd->Window, ImGui_ImplGlfw_ScrollCallback);
glfwSetKeyCallback(vd->Window, ImGui_ImplGlfw_KeyCallback);
@ -724,7 +917,7 @@ static LRESULT CALLBACK WndProcNoInputs(HWND hWnd, UINT msg, WPARAM wParam, LPAR
{
if (msg == WM_NCHITTEST)
{
// Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL).
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() properly (which is OPTIONAL).
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
@ -871,31 +1064,6 @@ static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*)
}
}
//--------------------------------------------------------------------------------------------------------
// IME (Input Method Editor) basic support for e.g. Asian language users
//--------------------------------------------------------------------------------------------------------
// We provide a Win32 implementation because this is such a common issue for IME users
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
#define HAS_WIN32_IME 1
#include <imm.h>
#ifdef _MSC_VER
#pragma comment(lib, "imm32")
#endif
static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos)
{
COMPOSITIONFORM cf = { CFS_FORCE_POSITION, { (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) }, { 0, 0, 0, 0 } };
if (HWND hwnd = (HWND)viewport->PlatformHandleRaw)
if (HIMC himc = ::ImmGetContext(hwnd))
{
::ImmSetCompositionWindow(himc, &cf);
::ImmReleaseContext(hwnd, himc);
}
}
#else
#define HAS_WIN32_IME 0
#endif
//--------------------------------------------------------------------------------------------------------
// Vulkan support (the Vulkan renderer needs to call a platform-side support function to create the surface)
//--------------------------------------------------------------------------------------------------------
@ -950,9 +1118,6 @@ static void ImGui_ImplGlfw_InitPlatformInterface()
#if GLFW_HAS_VULKAN
platform_io.Platform_CreateVkSurface = ImGui_ImplGlfw_CreateVkSurface;
#endif
#if HAS_WIN32_IME
platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos;
#endif
// Register main window handle (which is owned by the main application, not by us)
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
@ -966,4 +1131,9 @@ static void ImGui_ImplGlfw_InitPlatformInterface()
static void ImGui_ImplGlfw_ShutdownPlatformInterface()
{
ImGui::DestroyPlatformWindows();
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif

@ -1,12 +1,13 @@
// dear imgui: Platform Backend for GLFW
// This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan, WebGPU..)
// (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.)
// (Requires: GLFW 3.1+. Prefer GLFW 3.3+ for full feature support.)
// Implemented features:
// [X] Platform: Clipboard support.
// [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 GLFW_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW.
// [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE).
// [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange' (note: the resizing cursors requires GLFW 3.4+).
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Issues:
@ -33,11 +34,16 @@ IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOther(GLFWwindow* window, bool ins
IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown();
IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame();
// GLFW callbacks
// - When calling Init with 'install_callbacks=true': GLFW callbacks will be installed for you. They will call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call those function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused);
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered);
// GLFW callbacks (installer)
// - When calling Init with 'install_callbacks=true': ImGui_ImplGlfw_InstallCallbacks() is called. GLFW callbacks will be installed for you. They will chain-call user's previously installed callbacks, if any.
// - When calling Init with 'install_callbacks=false': GLFW callbacks won't be installed. You will need to call individual function yourself from your own GLFW callbacks.
IMGUI_IMPL_API void ImGui_ImplGlfw_InstallCallbacks(GLFWwindow* window);
IMGUI_IMPL_API void ImGui_ImplGlfw_RestoreCallbacks(GLFWwindow* window);
// GLFW callbacks (individual callbacks to call if you didn't install callbacks)
IMGUI_IMPL_API void ImGui_ImplGlfw_WindowFocusCallback(GLFWwindow* window, int focused); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorEnterCallback(GLFWwindow* window, int entered); // Since 1.84
IMGUI_IMPL_API void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y); // Since 1.87
IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset);
IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);

@ -5,19 +5,24 @@
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
// !!! Nowadays, prefer using GLFW or SDL instead!
// Implemented features:
// [X] Platform: Partial 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 GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// Issues:
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
// [ ] Platform: Missing mouse cursor shape/visibility support.
// [ ] Platform: Missing clipboard support (not supported by Glut).
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-01-26: Inputs: replaced short-lived io.AddKeyModsEvent() (added two weeks ago) with io.AddKeyEvent() using ImGuiKey_ModXXX flags. Sorry for the confusion.
// 2022-01-17: Inputs: calling new io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() API (1.87+).
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2019-04-03: Misc: Renamed imgui_impl_freeglut.cpp/.h to imgui_impl_glut.cpp/.h.
// 2019-03-25: Misc: Made io.DeltaTime always above zero.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
@ -37,6 +42,120 @@
static int g_Time = 0; // Current time, in milliseconds
// Glut has 1 function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above.
static ImGuiKey ImGui_ImplGLUT_KeyToImGuiKey(int key)
{
switch (key)
{
case '\t': return ImGuiKey_Tab;
case 256 + GLUT_KEY_LEFT: return ImGuiKey_LeftArrow;
case 256 + GLUT_KEY_RIGHT: return ImGuiKey_RightArrow;
case 256 + GLUT_KEY_UP: return ImGuiKey_UpArrow;
case 256 + GLUT_KEY_DOWN: return ImGuiKey_DownArrow;
case 256 + GLUT_KEY_PAGE_UP: return ImGuiKey_PageUp;
case 256 + GLUT_KEY_PAGE_DOWN: return ImGuiKey_PageDown;
case 256 + GLUT_KEY_HOME: return ImGuiKey_Home;
case 256 + GLUT_KEY_END: return ImGuiKey_End;
case 256 + GLUT_KEY_INSERT: return ImGuiKey_Insert;
case 127: return ImGuiKey_Delete;
case 8: return ImGuiKey_Backspace;
case ' ': return ImGuiKey_Space;
case 13: return ImGuiKey_Enter;
case 27: return ImGuiKey_Escape;
case 39: return ImGuiKey_Apostrophe;
case 44: return ImGuiKey_Comma;
case 45: return ImGuiKey_Minus;
case 46: return ImGuiKey_Period;
case 47: return ImGuiKey_Slash;
case 59: return ImGuiKey_Semicolon;
case 61: return ImGuiKey_Equal;
case 91: return ImGuiKey_LeftBracket;
case 92: return ImGuiKey_Backslash;
case 93: return ImGuiKey_RightBracket;
case 96: return ImGuiKey_GraveAccent;
//case 0: return ImGuiKey_CapsLock;
//case 0: return ImGuiKey_ScrollLock;
case 256 + 0x006D: return ImGuiKey_NumLock;
//case 0: return ImGuiKey_PrintScreen;
//case 0: return ImGuiKey_Pause;
//case '0': return ImGuiKey_Keypad0;
//case '1': return ImGuiKey_Keypad1;
//case '2': return ImGuiKey_Keypad2;
//case '3': return ImGuiKey_Keypad3;
//case '4': return ImGuiKey_Keypad4;
//case '5': return ImGuiKey_Keypad5;
//case '6': return ImGuiKey_Keypad6;
//case '7': return ImGuiKey_Keypad7;
//case '8': return ImGuiKey_Keypad8;
//case '9': return ImGuiKey_Keypad9;
//case 46: return ImGuiKey_KeypadDecimal;
//case 47: return ImGuiKey_KeypadDivide;
case 42: return ImGuiKey_KeypadMultiply;
//case 45: return ImGuiKey_KeypadSubtract;
case 43: return ImGuiKey_KeypadAdd;
//case 13: return ImGuiKey_KeypadEnter;
//case 0: return ImGuiKey_KeypadEqual;
case 256 + 0x0072: return ImGuiKey_LeftCtrl;
case 256 + 0x0070: return ImGuiKey_LeftShift;
case 256 + 0x0074: return ImGuiKey_LeftAlt;
//case 0: return ImGuiKey_LeftSuper;
case 256 + 0x0073: return ImGuiKey_RightCtrl;
case 256 + 0x0071: return ImGuiKey_RightShift;
case 256 + 0x0075: return ImGuiKey_RightAlt;
//case 0: return ImGuiKey_RightSuper;
//case 0: return ImGuiKey_Menu;
case '0': return ImGuiKey_0;
case '1': return ImGuiKey_1;
case '2': return ImGuiKey_2;
case '3': return ImGuiKey_3;
case '4': return ImGuiKey_4;
case '5': return ImGuiKey_5;
case '6': return ImGuiKey_6;
case '7': return ImGuiKey_7;
case '8': return ImGuiKey_8;
case '9': return ImGuiKey_9;
case 'A': case 'a': return ImGuiKey_A;
case 'B': case 'b': return ImGuiKey_B;
case 'C': case 'c': return ImGuiKey_C;
case 'D': case 'd': return ImGuiKey_D;
case 'E': case 'e': return ImGuiKey_E;
case 'F': case 'f': return ImGuiKey_F;
case 'G': case 'g': return ImGuiKey_G;
case 'H': case 'h': return ImGuiKey_H;
case 'I': case 'i': return ImGuiKey_I;
case 'J': case 'j': return ImGuiKey_J;
case 'K': case 'k': return ImGuiKey_K;
case 'L': case 'l': return ImGuiKey_L;
case 'M': case 'm': return ImGuiKey_M;
case 'N': case 'n': return ImGuiKey_N;
case 'O': case 'o': return ImGuiKey_O;
case 'P': case 'p': return ImGuiKey_P;
case 'Q': case 'q': return ImGuiKey_Q;
case 'R': case 'r': return ImGuiKey_R;
case 'S': case 's': return ImGuiKey_S;
case 'T': case 't': return ImGuiKey_T;
case 'U': case 'u': return ImGuiKey_U;
case 'V': case 'v': return ImGuiKey_V;
case 'W': case 'w': return ImGuiKey_W;
case 'X': case 'x': return ImGuiKey_X;
case 'Y': case 'y': return ImGuiKey_Y;
case 'Z': case 'z': return ImGuiKey_Z;
case 256 + GLUT_KEY_F1: return ImGuiKey_F1;
case 256 + GLUT_KEY_F2: return ImGuiKey_F2;
case 256 + GLUT_KEY_F3: return ImGuiKey_F3;
case 256 + GLUT_KEY_F4: return ImGuiKey_F4;
case 256 + GLUT_KEY_F5: return ImGuiKey_F5;
case 256 + GLUT_KEY_F6: return ImGuiKey_F6;
case 256 + GLUT_KEY_F7: return ImGuiKey_F7;
case 256 + GLUT_KEY_F8: return ImGuiKey_F8;
case 256 + GLUT_KEY_F9: return ImGuiKey_F9;
case 256 + GLUT_KEY_F10: return ImGuiKey_F10;
case 256 + GLUT_KEY_F11: return ImGuiKey_F11;
case 256 + GLUT_KEY_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
bool ImGui_ImplGLUT_Init()
{
ImGuiIO& io = ImGui::GetIO();
@ -46,33 +165,8 @@ bool ImGui_ImplGLUT_Init()
#else
io.BackendPlatformName = "imgui_impl_glut";
#endif
g_Time = 0;
// Glut has 1 function for characters and one for "special keys". We map the characters in the 0..255 range and the keys above.
io.KeyMap[ImGuiKey_Tab] = '\t'; // == 9 == CTRL+I
io.KeyMap[ImGuiKey_LeftArrow] = 256 + GLUT_KEY_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = 256 + GLUT_KEY_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = 256 + GLUT_KEY_UP;
io.KeyMap[ImGuiKey_DownArrow] = 256 + GLUT_KEY_DOWN;
io.KeyMap[ImGuiKey_PageUp] = 256 + GLUT_KEY_PAGE_UP;
io.KeyMap[ImGuiKey_PageDown] = 256 + GLUT_KEY_PAGE_DOWN;
io.KeyMap[ImGuiKey_Home] = 256 + GLUT_KEY_HOME;
io.KeyMap[ImGuiKey_End] = 256 + GLUT_KEY_END;
io.KeyMap[ImGuiKey_Insert] = 256 + GLUT_KEY_INSERT;
io.KeyMap[ImGuiKey_Delete] = 127;
io.KeyMap[ImGuiKey_Backspace] = 8; // == CTRL+H
io.KeyMap[ImGuiKey_Space] = ' ';
io.KeyMap[ImGuiKey_Enter] = 13; // == CTRL+M
io.KeyMap[ImGuiKey_Escape] = 27;
io.KeyMap[ImGuiKey_KeyPadEnter] = 13; // == CTRL+M
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
return true;
}
@ -110,13 +204,20 @@ void ImGui_ImplGLUT_NewFrame()
ImGui::NewFrame();
}
static void ImGui_ImplGLUT_UpdateKeyboardMods()
static void ImGui_ImplGLUT_UpdateKeyModifiers()
{
ImGuiIO& io = ImGui::GetIO();
int glut_key_mods = glutGetModifiers();
io.AddKeyEvent(ImGuiKey_ModCtrl, (glut_key_mods & GLUT_ACTIVE_CTRL) != 0);
io.AddKeyEvent(ImGuiKey_ModShift, (glut_key_mods & GLUT_ACTIVE_SHIFT) != 0);
io.AddKeyEvent(ImGuiKey_ModAlt, (glut_key_mods & GLUT_ACTIVE_ALT) != 0);
}
static void ImGui_ImplGLUT_AddKeyEvent(ImGuiKey key, bool down, int native_keycode)
{
ImGuiIO& io = ImGui::GetIO();
int mods = glutGetModifiers();
io.KeyCtrl = (mods & GLUT_ACTIVE_CTRL) != 0;
io.KeyShift = (mods & GLUT_ACTIVE_SHIFT) != 0;
io.KeyAlt = (mods & GLUT_ACTIVE_ALT) != 0;
io.AddKeyEvent(key, down);
io.SetKeyEventNativeData(key, native_keycode, -1); // To support legacy indexing (<1.87 user code)
}
void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
@ -127,79 +228,58 @@ void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y)
if (c >= 32)
io.AddInputCharacter((unsigned int)c);
// Store letters in KeysDown[] array as both uppercase and lowercase + Handle GLUT translating CTRL+A..CTRL+Z as 1..26.
// This is a hacky mess but GLUT is unable to distinguish e.g. a TAB key from CTRL+I so this is probably the best we can do here.
if (c >= 1 && c <= 26)
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = true;
else if (c >= 'a' && c <= 'z')
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = true;
else if (c >= 'A' && c <= 'Z')
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = true;
else
io.KeysDown[c] = true;
ImGui_ImplGLUT_UpdateKeyboardMods();
ImGuiKey key = ImGui_ImplGLUT_KeyToImGuiKey(c);
ImGui_ImplGLUT_AddKeyEvent(key, true, c);
ImGui_ImplGLUT_UpdateKeyModifiers();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y)
{
//printf("char_up_func %d '%c'\n", c, c);
ImGuiIO& io = ImGui::GetIO();
if (c >= 1 && c <= 26)
io.KeysDown[c] = io.KeysDown[c - 1 + 'a'] = io.KeysDown[c - 1 + 'A'] = false;
else if (c >= 'a' && c <= 'z')
io.KeysDown[c] = io.KeysDown[c - 'a' + 'A'] = false;
else if (c >= 'A' && c <= 'Z')
io.KeysDown[c] = io.KeysDown[c - 'A' + 'a'] = false;
else
io.KeysDown[c] = false;
ImGui_ImplGLUT_UpdateKeyboardMods();
ImGuiKey key = ImGui_ImplGLUT_KeyToImGuiKey(c);
ImGui_ImplGLUT_AddKeyEvent(key, false, c);
ImGui_ImplGLUT_UpdateKeyModifiers();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y)
{
//printf("key_down_func %d\n", key);
ImGuiIO& io = ImGui::GetIO();
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
io.KeysDown[key + 256] = true;
ImGui_ImplGLUT_UpdateKeyboardMods();
ImGuiKey imgui_key = ImGui_ImplGLUT_KeyToImGuiKey(key + 256);
ImGui_ImplGLUT_AddKeyEvent(imgui_key, true, key + 256);
ImGui_ImplGLUT_UpdateKeyModifiers();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y)
{
//printf("key_up_func %d\n", key);
ImGuiIO& io = ImGui::GetIO();
if (key + 256 < IM_ARRAYSIZE(io.KeysDown))
io.KeysDown[key + 256] = false;
ImGui_ImplGLUT_UpdateKeyboardMods();
ImGuiKey imgui_key = ImGui_ImplGLUT_KeyToImGuiKey(key + 256);
ImGui_ImplGLUT_AddKeyEvent(imgui_key, false, key + 256);
ImGui_ImplGLUT_UpdateKeyModifiers();
(void)x; (void)y; // Unused
}
void ImGui_ImplGLUT_MouseFunc(int glut_button, int state, int x, int y)
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2((float)x, (float)y);
io.AddMousePosEvent((float)x, (float)y);
int button = -1;
if (glut_button == GLUT_LEFT_BUTTON) button = 0;
if (glut_button == GLUT_RIGHT_BUTTON) button = 1;
if (glut_button == GLUT_MIDDLE_BUTTON) button = 2;
if (button != -1 && state == GLUT_DOWN)
io.MouseDown[button] = true;
if (button != -1 && state == GLUT_UP)
io.MouseDown[button] = false;
if (button != -1 && state == GLUT_DOWN || state == GLUT_UP)
io.AddMouseButtonEvent(button, state == GLUT_DOWN);
}
#ifdef __FREEGLUT_EXT_H__
void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y)
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2((float)x, (float)y);
if (dir > 0)
io.MouseWheel += 1.0;
else if (dir < 0)
io.MouseWheel -= 1.0;
io.AddMousePosEvent((float)x, (float)y);
if (dir != 0)
io.AddMouseWheelEvent(0.0f, dir > 0 ? 1.0f : -1.0f);
(void)button; // Unused
}
#endif
@ -213,5 +293,5 @@ void ImGui_ImplGLUT_ReshapeFunc(int w, int h)
void ImGui_ImplGLUT_MotionFunc(int x, int y)
{
ImGuiIO& io = ImGui::GetIO();
io.MousePos = ImVec2((float)x, (float)y);
io.AddMousePosEvent((float)x, (float)y);
}

@ -5,13 +5,15 @@
// !!! If someone or something is teaching you GLUT today, you are being abused. Please show some resistance. !!!
// !!! Nowadays, prefer using GLFW or SDL instead!
// Implemented features:
// [X] Platform: Partial 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 GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// Issues:
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
// [ ] Platform: Missing mouse cursor shape/visibility support.
// [ ] Platform: Missing clipboard support (not supported by Glut).
// [ ] Platform: Missing gamepad support.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs

@ -1,318 +0,0 @@
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
// Implemented features:
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
// Missing features:
// [ ] Renderer: Clipping rectangles are not honored.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-05-19: Renderer: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-05-11: Inputs: Don't filter value from character callback before calling AddInputCharacter().
// 2018-11-30: Misc: Setting up io.BackendPlatformName/io.BackendRendererName so they can be displayed in the About Window.
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_Marmalade_RenderDrawData() in the .h file so you can call it yourself.
// 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.
#include "imgui.h"
#include "imgui_impl_marmalade.h"
#include <s3eClipboard.h>
#include <s3ePointer.h>
#include <s3eKeyboard.h>
#include <IwTexture.h>
#include <IwGx.h>
// Data
static double g_Time = 0.0f;
static bool g_MousePressed[3] = { false, false, false };
static CIwTexture* g_FontTexture = NULL;
static char* g_ClipboardText = NULL;
static bool g_osdKeyboardEnabled = false;
// use this setting to scale the interface - e.g. on device you could use 2 or 3 scale factor
static ImVec2 g_RenderScale = ImVec2(1.0f, 1.0f);
// Render function.
void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data)
{
// Avoid rendering when minimized
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
return;
// Render command lists
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
const int nVert = cmd_list->VtxBuffer.Size;
CIwFVec2* pVertStream = IW_GX_ALLOC(CIwFVec2, nVert);
CIwFVec2* pUVStream = IW_GX_ALLOC(CIwFVec2, nVert);
CIwColour* pColStream = IW_GX_ALLOC(CIwColour, nVert);
for (int i = 0; i < nVert; i++)
{
// FIXME-OPT: optimize multiplication on GPU using vertex shader/projection matrix.
pVertStream[i].x = cmd_list->VtxBuffer[i].pos.x * g_RenderScale.x;
pVertStream[i].y = cmd_list->VtxBuffer[i].pos.y * g_RenderScale.y;
pUVStream[i].x = cmd_list->VtxBuffer[i].uv.x;
pUVStream[i].y = cmd_list->VtxBuffer[i].uv.y;
pColStream[i] = cmd_list->VtxBuffer[i].col;
}
IwGxSetVertStreamScreenSpace(pVertStream, nVert);
IwGxSetUVStream(pUVStream);
IwGxSetColStream(pColStream, nVert);
IwGxSetNormStream(0);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// FIXME: Not honoring ClipRect fields.
CIwMaterial* pCurrentMaterial = IW_GX_ALLOC_MATERIAL();
pCurrentMaterial->SetShadeMode(CIwMaterial::SHADE_FLAT);
pCurrentMaterial->SetCullMode(CIwMaterial::CULL_NONE);
pCurrentMaterial->SetFiltering(false);
pCurrentMaterial->SetAlphaMode(CIwMaterial::ALPHA_BLEND);
pCurrentMaterial->SetDepthWriteMode(CIwMaterial::DEPTH_WRITE_NORMAL);
pCurrentMaterial->SetAlphaTestMode(CIwMaterial::ALPHATEST_DISABLED);
pCurrentMaterial->SetTexture((CIwTexture*)pcmd->GetTexID());
IwGxSetMaterial(pCurrentMaterial);
IwGxDrawPrims(IW_GX_TRI_LIST, (uint16*)idx_buffer, pcmd->ElemCount);
}
idx_buffer += pcmd->ElemCount;
}
IwGxFlush();
}
// TODO: restore modified state (i.e. mvp matrix)
}
static const char* ImGui_Marmalade_GetClipboardText(void* /*user_data*/)
{
if (!s3eClipboardAvailable())
return NULL;
if (int size = s3eClipboardGetText(NULL, 0))
{
if (g_ClipboardText)
delete[] g_ClipboardText;
g_ClipboardText = new char[size];
g_ClipboardText[0] = '\0';
s3eClipboardGetText(g_ClipboardText, size);
}
return g_ClipboardText;
}
static void ImGui_Marmalade_SetClipboardText(void* /*user_data*/, const char* text)
{
if (s3eClipboardAvailable())
s3eClipboardSetText(text);
}
int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data)
{
// pEvent->m_Button is of type s3ePointerButton and indicates which mouse
// button was pressed. For touchscreen this should always have the value
// S3E_POINTER_BUTTON_SELECT
s3ePointerEvent* pEvent = (s3ePointerEvent*)system_data;
if (pEvent->m_Pressed == 1)
{
if (pEvent->m_Button == S3E_POINTER_BUTTON_LEFTMOUSE)
g_MousePressed[0] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_RIGHTMOUSE)
g_MousePressed[1] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MIDDLEMOUSE)
g_MousePressed[2] = true;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELUP)
io.MouseWheel += pEvent->m_y;
if (pEvent->m_Button == S3E_POINTER_BUTTON_MOUSEWHEELDOWN)
io.MouseWheel += pEvent->m_y;
}
return 0;
}
int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data)
{
ImGuiIO& io = ImGui::GetIO();
s3eKeyboardEvent* e = (s3eKeyboardEvent*)system_data;
if (e->m_Pressed == 1)
io.KeysDown[e->m_Key] = true;
if (e->m_Pressed == 0)
io.KeysDown[e->m_Key] = false;
io.KeyCtrl = s3eKeyboardGetState(s3eKeyLeftControl) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightControl) == S3E_KEY_STATE_DOWN;
io.KeyShift = s3eKeyboardGetState(s3eKeyLeftShift) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightShift) == S3E_KEY_STATE_DOWN;
io.KeyAlt = s3eKeyboardGetState(s3eKeyLeftAlt) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightAlt) == S3E_KEY_STATE_DOWN;
io.KeySuper = s3eKeyboardGetState(s3eKeyLeftWindows) == S3E_KEY_STATE_DOWN || s3eKeyboardGetState(s3eKeyRightWindows) == S3E_KEY_STATE_DOWN;
return 0;
}
int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data)
{
ImGuiIO& io = ImGui::GetIO();
s3eKeyboardCharEvent* e = (s3eKeyboardCharEvent*)system_data;
io.AddInputCharacter((unsigned int)e->m_Char);
return 0;
}
bool ImGui_Marmalade_CreateDeviceObjects()
{
// Build texture atlas
ImGuiIO& io = ImGui::GetIO();
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
// Upload texture to graphics system
g_FontTexture = new CIwTexture();
g_FontTexture->SetModifiable(true);
CIwImage& image = g_FontTexture->GetImage();
image.SetFormat(CIwImage::ARGB_8888);
image.SetWidth(width);
image.SetHeight(height);
image.SetBuffers(); // allocates and own buffers
image.ReadTexels(pixels);
g_FontTexture->SetMipMapping(false);
g_FontTexture->SetFiltering(false);
g_FontTexture->Upload();
// Store our identifier
io.Fonts->SetTexID((ImTextureID)g_FontTexture);
return true;
}
void ImGui_Marmalade_InvalidateDeviceObjects()
{
if (g_ClipboardText)
{
delete[] g_ClipboardText;
g_ClipboardText = NULL;
}
if (g_FontTexture)
{
ImGui::GetIO().Fonts->SetTexID(0);
delete g_FontTexture;
g_FontTexture = NULL;
}
}
bool ImGui_Marmalade_Init(bool install_callbacks)
{
ImGuiIO& io = ImGui::GetIO();
io.BackendPlatformName = io.BackendRendererName = "imgui_impl_marmalade";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = s3eKeyTab
io.KeyMap[ImGuiKey_LeftArrow] = s3eKeyLeft;
io.KeyMap[ImGuiKey_RightArrow] = s3eKeyRight;
io.KeyMap[ImGuiKey_UpArrow] = s3eKeyUp;
io.KeyMap[ImGuiKey_DownArrow] = s3eKeyDown;
io.KeyMap[ImGuiKey_PageUp] = s3eKeyPageUp;
io.KeyMap[ImGuiKey_PageDown] = s3eKeyPageDown;
io.KeyMap[ImGuiKey_Home] = s3eKeyHome;
io.KeyMap[ImGuiKey_End] = s3eKeyEnd;
io.KeyMap[ImGuiKey_Insert] = s3eKeyInsert;
io.KeyMap[ImGuiKey_Delete] = s3eKeyDelete;
io.KeyMap[ImGuiKey_Backspace] = s3eKeyBackspace;
io.KeyMap[ImGuiKey_Space] = s3eKeySpace;
io.KeyMap[ImGuiKey_Enter] = s3eKeyEnter;
io.KeyMap[ImGuiKey_Escape] = s3eKeyEsc;
io.KeyMap[ImGuiKey_KeyPadEnter] = s3eKeyNumPadEnter;
io.KeyMap[ImGuiKey_A] = s3eKeyA;
io.KeyMap[ImGuiKey_C] = s3eKeyC;
io.KeyMap[ImGuiKey_V] = s3eKeyV;
io.KeyMap[ImGuiKey_X] = s3eKeyX;
io.KeyMap[ImGuiKey_Y] = s3eKeyY;
io.KeyMap[ImGuiKey_Z] = s3eKeyZ;
io.SetClipboardTextFn = ImGui_Marmalade_SetClipboardText;
io.GetClipboardTextFn = ImGui_Marmalade_GetClipboardText;
if (install_callbacks)
{
s3ePointerRegister(S3E_POINTER_BUTTON_EVENT, ImGui_Marmalade_PointerButtonEventCallback, 0);
s3eKeyboardRegister(S3E_KEYBOARD_KEY_EVENT, ImGui_Marmalade_KeyCallback, 0);
s3eKeyboardRegister(S3E_KEYBOARD_CHAR_EVENT, ImGui_Marmalade_CharCallback, 0);
}
return true;
}
void ImGui_Marmalade_Shutdown()
{
ImGui_Marmalade_InvalidateDeviceObjects();
}
void ImGui_Marmalade_NewFrame()
{
if (!g_FontTexture)
ImGui_Marmalade_CreateDeviceObjects();
ImGuiIO& io = ImGui::GetIO();
// Setup display size (every frame to accommodate for window resizing)
int w = IwGxGetScreenWidth(), h = IwGxGetScreenHeight();
io.DisplaySize = ImVec2((float)w, (float)h);
// For retina display or other situations where window coordinates are different from framebuffer coordinates. User storage only, presently not used by ImGui.
io.DisplayFramebufferScale = g_scale;
// Setup time step
double current_time = s3eTimerGetUST() / 1000.0f;
io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f / 60.0f);
g_Time = current_time;
double mouse_x, mouse_y;
mouse_x = s3ePointerGetX();
mouse_y = s3ePointerGetY();
io.MousePos = ImVec2((float)mouse_x / g_scale.x, (float)mouse_y / g_scale.y); // Mouse position (set to -FLT_MAX,-FLT_MAX if no mouse / on another screen, etc.)
for (int i = 0; i < 3; i++)
{
io.MouseDown[i] = g_MousePressed[i] || s3ePointerGetState((s3ePointerButton)i) != S3E_POINTER_STATE_UP; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
g_MousePressed[i] = false;
}
// TODO: Hide OS mouse cursor if ImGui is drawing it
// s3ePointerSetInt(S3E_POINTER_HIDE_CURSOR,(io.MouseDrawCursor ? 0 : 1));
// Show/hide OSD keyboard
if (io.WantTextInput)
{
// Some text input widget is active?
if (!g_osdKeyboardEnabled)
{
g_osdKeyboardEnabled = true;
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 1); // show OSD keyboard
}
}
else
{
// No text input widget is active
if (g_osdKeyboardEnabled)
{
g_osdKeyboardEnabled = false;
s3eKeyboardSetInt(S3E_KEYBOARD_GET_CHAR, 0); // hide OSD keyboard
}
}
}

@ -1,28 +0,0 @@
// dear imgui: Renderer + Platform Backend for Marmalade + IwGx
// Marmalade code: Copyright (C) 2015 by Giovanni Zito (this file is part of Dear ImGui)
// Implemented features:
// [X] Renderer: User texture binding. Use 'CIwTexture*' as ImTextureID. Read the FAQ about ImTextureID!
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
IMGUI_IMPL_API bool ImGui_Marmalade_Init(bool install_callbacks);
IMGUI_IMPL_API void ImGui_Marmalade_Shutdown();
IMGUI_IMPL_API void ImGui_Marmalade_NewFrame();
IMGUI_IMPL_API void ImGui_Marmalade_RenderDrawData(ImDrawData* draw_data);
// Use if you want to reset your rendering device without losing Dear ImGui state.
IMGUI_IMPL_API void ImGui_Marmalade_InvalidateDeviceObjects();
IMGUI_IMPL_API bool ImGui_Marmalade_CreateDeviceObjects();
// Callbacks (installed by default if you enable 'install_callbacks' during initialization)
// You can also handle inputs yourself and use those as a reference.
IMGUI_IMPL_API int32 ImGui_Marmalade_PointerButtonEventCallback(void* system_data, void* user_data);
IMGUI_IMPL_API int32 ImGui_Marmalade_KeyCallback(void* system_data, void* user_data);
IMGUI_IMPL_API int32 ImGui_Marmalade_CharCallback(void* system_data, void* user_data);

@ -14,6 +14,12 @@
#include "imgui.h" // IMGUI_IMPL_API
//-----------------------------------------------------------------------------
// ObjC API
//-----------------------------------------------------------------------------
#ifdef __OBJC__
@class MTLRenderPassDescriptor;
@protocol MTLDevice, MTLCommandBuffer, MTLRenderCommandEncoder;
@ -29,3 +35,35 @@ IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(id<MTLDevice> device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
#endif
//-----------------------------------------------------------------------------
// C++ API
//-----------------------------------------------------------------------------
// Enable Metal C++ binding support with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file
// More info about using Metal from C++: https://developer.apple.com/metal/cpp/
#ifdef IMGUI_IMPL_METAL_CPP
#include <Metal/Metal.hpp>
#ifndef __OBJC__
IMGUI_IMPL_API bool ImGui_ImplMetal_Init(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_Shutdown();
IMGUI_IMPL_API void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor);
IMGUI_IMPL_API void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
MTL::CommandBuffer* commandBuffer,
MTL::RenderCommandEncoder* commandEncoder);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device);
IMGUI_IMPL_API void ImGui_ImplMetal_DestroyDeviceObjects();
#endif
#endif

@ -7,13 +7,16 @@
// Missing features:
// [ ] Renderer: Multi-viewport / platform windows.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-01-03: Metal: Ignore ImDrawCmd where ElemCount == 0 (very rare but can technically be manufactured by user code).
// 2021-12-30: Metal: Added Metal C++ support. Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file.
// 2021-08-24: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted. (#4464)
// 2021-05-19: Metal: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-02-18: Metal: Change blending equation to preserve alpha in output buffer.
// 2021-01-25: Metal: Fixed texture storage mode when building on Mac Catalyst.
@ -78,7 +81,43 @@
static MetalContext *g_sharedMetalContext = nil;
#pragma mark - ImGui API implementation
#ifdef IMGUI_IMPL_METAL_CPP
#pragma mark - Dear ImGui Metal C++ Backend API
bool ImGui_ImplMetal_Init(MTL::Device* device)
{
return ImGui_ImplMetal_Init((id<MTLDevice>)(device));
}
void ImGui_ImplMetal_NewFrame(MTL::RenderPassDescriptor* renderPassDescriptor)
{
ImGui_ImplMetal_NewFrame((MTLRenderPassDescriptor*)(renderPassDescriptor));
}
void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data,
MTL::CommandBuffer* commandBuffer,
MTL::RenderCommandEncoder* commandEncoder)
{
ImGui_ImplMetal_RenderDrawData(draw_data,
(id<MTLCommandBuffer>)(commandBuffer),
(id<MTLRenderCommandEncoder>)(commandEncoder));
}
bool ImGui_ImplMetal_CreateFontsTexture(MTL::Device* device)
{
return ImGui_ImplMetal_CreateFontsTexture((id<MTLDevice>)(device));
}
bool ImGui_ImplMetal_CreateDeviceObjects(MTL::Device* device)
{
return ImGui_ImplMetal_CreateDeviceObjects((id<MTLDevice>)(device));
}
#endif // #ifdef IMGUI_IMPL_METAL_CPP
#pragma mark - Dear ImGui Metal Backend API
bool ImGui_ImplMetal_Init(id<MTLDevice> device)
{
@ -506,36 +545,39 @@ void ImGui_ImplMetal_DestroyDeviceObjects()
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
// Clamp to viewport as setScissorRect() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
if (pcmd->ElemCount == 0) // drawIndexedPrimitives() validation doesn't accept this
continue;
// Apply scissor/clipping rectangle
MTLScissorRect scissorRect =
{
// Apply scissor/clipping rectangle
MTLScissorRect scissorRect =
{
.x = NSUInteger(clip_rect.x),
.y = NSUInteger(clip_rect.y),
.width = NSUInteger(clip_rect.z - clip_rect.x),
.height = NSUInteger(clip_rect.w - clip_rect.y)
};
[commandEncoder setScissorRect:scissorRect];
// Bind texture, Draw
if (ImTextureID tex_id = pcmd->GetTexID())
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];
[commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:pcmd->ElemCount
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
indexBuffer:indexBuffer.buffer
indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
}
.x = NSUInteger(clip_min.x),
.y = NSUInteger(clip_min.y),
.width = NSUInteger(clip_max.x - clip_min.x),
.height = NSUInteger(clip_max.y - clip_min.y)
};
[commandEncoder setScissorRect:scissorRect];
// Bind texture, Draw
if (ImTextureID tex_id = pcmd->GetTexID())
[commandEncoder setFragmentTexture:(__bridge id<MTLTexture>)(tex_id) atIndex:0];
[commandEncoder setVertexBufferOffset:(vertexBufferOffset + pcmd->VtxOffset * sizeof(ImDrawVert)) atIndex:0];
[commandEncoder drawIndexedPrimitives:MTLPrimitiveTypeTriangle
indexCount:pcmd->ElemCount
indexType:sizeof(ImDrawIdx) == 2 ? MTLIndexTypeUInt16 : MTLIndexTypeUInt32
indexBuffer:indexBuffer.buffer
indexBufferOffset:indexBufferOffset + pcmd->IdxOffset * sizeof(ImDrawIdx)];
}
}

@ -20,7 +20,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2021-12-08: OpenGL: Fixed mishandling of the the ImDrawCmd::IdxOffset field! This is an old bug but it never had an effect until some internal rendering changes in 1.86.
// 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-05-19: OpenGL: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-01-03: OpenGL: Backup, setup and restore GL_SHADE_MODEL state, disable GL_STENCIL_TEST and disable GL_NORMAL_ARRAY client state to increase compatibility with legacy OpenGL applications.
@ -96,8 +97,9 @@ bool ImGui_ImplOpenGL2_Init()
void ImGui_ImplOpenGL2_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL2_ShutdownPlatformInterface();
ImGui_ImplOpenGL2_DestroyDeviceObjects();
@ -211,23 +213,18 @@ void ImGui_ImplOpenGL2_RenderDrawData(ImDrawData* draw_data)
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer);
}
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer + pcmd->IdxOffset);
}
idx_buffer += pcmd->ElemCount;
}
}

@ -15,7 +15,9 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2021-12-15: OpenGL: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports with some Intel HD drivers.
// 2021-08-23: OpenGL: Fixed ES 3.0 shader ("#version 300 es") use normal precision floats to avoid wobbly rendering at HD resolutions.
// 2021-08-19: OpenGL: Embed and use our own minimal GL loader (imgui_impl_opengl3_loader.h), removing requirement and support for third-party loader.
// 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-06-25: OpenGL: Use OES_vertex_array extension on Emscripten + backup/restore current state.
@ -96,9 +98,23 @@
#include <stdint.h> // intptr_t
#endif
// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
#endif
// GL includes
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <GLES2/gl2.h>
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
#include <OpenGLES/ES2/gl.h> // Use GL ES 2
#else
#include <GLES2/gl2.h> // Use GL ES 2
#endif
#if defined(__EMSCRIPTEN__)
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
@ -106,6 +122,9 @@
#include <GLES2/gl2ext.h>
#endif
#elif defined(IMGUI_IMPL_OPENGL_ES3)
#if defined(__APPLE__)
#include <TargetConditionals.h>
#endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV))
#include <OpenGLES/ES3/gl.h> // Use GL ES 3
#else
@ -172,6 +191,8 @@ struct ImGui_ImplOpenGL3_Data
GLuint AttribLocationVtxUV;
GLuint AttribLocationVtxColor;
unsigned int VboHandle, ElementsHandle;
GLsizeiptr VertexBufferSize;
GLsizeiptr IndexBufferSize;
bool HasClipOrigin;
ImGui_ImplOpenGL3_Data() { memset(this, 0, sizeof(*this)); }
@ -275,8 +296,9 @@ bool ImGui_ImplOpenGL3_Init(const char* glsl_version)
void ImGui_ImplOpenGL3_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplOpenGL3_ShutdownPlatformInterface();
ImGui_ImplOpenGL3_DestroyDeviceObjects();
@ -431,8 +453,20 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
const ImDrawList* cmd_list = draw_data->CmdLists[n];
// Upload vertex/index buffers
glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert), (const GLvoid*)cmd_list->VtxBuffer.Data, GL_STREAM_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx), (const GLvoid*)cmd_list->IdxBuffer.Data, GL_STREAM_DRAW);
GLsizeiptr vtx_buffer_size = (GLsizeiptr)cmd_list->VtxBuffer.Size * (int)sizeof(ImDrawVert);
GLsizeiptr idx_buffer_size = (GLsizeiptr)cmd_list->IdxBuffer.Size * (int)sizeof(ImDrawIdx);
if (bd->VertexBufferSize < vtx_buffer_size)
{
bd->VertexBufferSize = vtx_buffer_size;
glBufferData(GL_ARRAY_BUFFER, bd->VertexBufferSize, NULL, GL_STREAM_DRAW);
}
if (bd->IndexBufferSize < idx_buffer_size)
{
bd->IndexBufferSize = idx_buffer_size;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bd->IndexBufferSize, NULL, GL_STREAM_DRAW);
}
glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_buffer_size, (const GLvoid*)cmd_list->VtxBuffer.Data);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_buffer_size, (const GLvoid*)cmd_list->IdxBuffer.Data);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
@ -449,26 +483,22 @@ void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
{
// Apply scissor/clipping rectangle
glScissor((int)clip_rect.x, (int)(fb_height - clip_rect.w), (int)(clip_rect.z - clip_rect.x), (int)(clip_rect.w - clip_rect.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle (Y is inverted in OpenGL)
glScissor((int)clip_min.x, (int)((float)fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y));
// Bind texture, Draw
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID());
#ifdef IMGUI_IMPL_OPENGL_MAY_HAVE_VTX_OFFSET
if (bd->GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else
if (bd->GlVersion >= 320)
glDrawElementsBaseVertex(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)), (GLint)pcmd->VtxOffset);
else
#endif
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx)));
}
}
}
@ -636,7 +666,7 @@ bool ImGui_ImplOpenGL3_CreateDeviceObjects()
"}\n";
const GLchar* vertex_shader_glsl_300_es =
"precision mediump float;\n"
"precision highp float;\n"
"layout (location = 0) in vec2 Position;\n"
"layout (location = 1) in vec2 UV;\n"
"layout (location = 2) in vec4 Color;\n"
@ -814,3 +844,7 @@ static void ImGui_ImplOpenGL3_ShutdownPlatformInterface()
{
ImGui::DestroyPlatformWindows();
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif

@ -43,7 +43,7 @@ IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects();
// Try to detect GLES on matching platforms
#if defined(__APPLE__)
#include "TargetConditionals.h"
#include <TargetConditionals.h>
#endif
#if (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_TV)) || (defined(__ANDROID__))
#define IMGUI_IMPL_OPENGL_ES3 // iOS, Android -> GL ES 3, "#version 300 es"

@ -1,3 +1,22 @@
//-----------------------------------------------------------------------------
// About imgui_impl_opengl3_loader.h:
//
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours,
// which proved to be endless problems for users.
// Our loader is custom-generated, based on gl3w but automatically filtered to only include
// enums/functions that we use in our imgui_impl_opengl3.cpp source file in order to be small.
//
// YOU SHOULD NOT NEED TO INCLUDE/USE THIS DIRECTLY. THIS IS USED BY imgui_impl_opengl3.cpp ONLY.
// THE REST OF YOUR APP SHOULD USE A DIFFERENT GL LOADER: ANY GL LOADER OF YOUR CHOICE.
//
// Regenerate with:
// python gl3w_gen.py --output ../imgui/backends/imgui_impl_opengl3_loader.h --ref ../imgui/backends/imgui_impl_opengl3.cpp ./extra_symbols.txt
//
// More info:
// https://github.com/dearimgui/gl3w_stripped
// https://github.com/ocornut/imgui/issues/4445
//-----------------------------------------------------------------------------
/*
* This file was generated with gl3w_gen.py, part of imgl3w
* (hosted at https://github.com/dearimgui/gl3w_stripped)
@ -26,14 +45,11 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
// We embed our own OpenGL loader to not require user to provide their own or to have to use ours, which proved to be endless problems for users.
// Our loader is custom-generated, based on gl3w but automatically filtered to only include enums/functions that we use in this source file.
// Regenerate with: python gl3w_gen.py --imgui-dir /path/to/imgui/
// see https://github.com/dearimgui/gl3w_stripped for more info.
#ifndef __gl3w_h_
#define __gl3w_h_
// Adapted from KHR/khrplatform.h to avoid including entire file.
#ifndef __khrplatform_h_
typedef float khronos_float_t;
typedef signed char khronos_int8_t;
typedef unsigned char khronos_uint8_t;
@ -58,6 +74,7 @@ typedef uint64_t khronos_uint64_t;
typedef signed long long khronos_int64_t;
typedef unsigned long long khronos_uint64_t;
#endif
#endif // __khrplatform_h_
#ifndef __gl_glcorearb_h_
#define __gl_glcorearb_h_ 1
@ -162,6 +179,7 @@ typedef void (APIENTRYP PFNGLDISABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLENABLEPROC) (GLenum cap);
typedef void (APIENTRYP PFNGLPIXELSTOREIPROC) (GLenum pname, GLint param);
typedef void (APIENTRYP PFNGLREADPIXELSPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
typedef GLenum (APIENTRYP PFNGLGETERRORPROC) (void);
typedef void (APIENTRYP PFNGLGETINTEGERVPROC) (GLenum pname, GLint *data);
typedef const GLubyte *(APIENTRYP PFNGLGETSTRINGPROC) (GLenum name);
typedef GLboolean (APIENTRYP PFNGLISENABLEDPROC) (GLenum cap);
@ -177,6 +195,7 @@ GLAPI void APIENTRY glDisable (GLenum cap);
GLAPI void APIENTRY glEnable (GLenum cap);
GLAPI void APIENTRY glPixelStorei (GLenum pname, GLint param);
GLAPI void APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels);
GLAPI GLenum APIENTRY glGetError (void);
GLAPI void APIENTRY glGetIntegerv (GLenum pname, GLint *data);
GLAPI const GLubyte *APIENTRY glGetString (GLenum name);
GLAPI GLboolean APIENTRY glIsEnabled (GLenum cap);
@ -230,11 +249,13 @@ typedef void (APIENTRYP PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
typedef void (APIENTRYP PFNGLDELETEBUFFERSPROC) (GLsizei n, const GLuint *buffers);
typedef void (APIENTRYP PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
typedef void (APIENTRYP PFNGLBUFFERDATAPROC) (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
typedef void (APIENTRYP PFNGLBUFFERSUBDATAPROC) (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glBindBuffer (GLenum target, GLuint buffer);
GLAPI void APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
GLAPI void APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
GLAPI void APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void *data, GLenum usage);
GLAPI void APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
#endif
#endif /* GL_VERSION_1_5 */
#ifndef GL_VERSION_2_0
@ -416,7 +437,7 @@ GL3W_API GL3WglProc imgl3wGetProcAddress(const char *proc);
/* gl3w internal state */
union GL3WProcs {
GL3WglProc ptr[52];
GL3WglProc ptr[54];
struct {
PFNGLACTIVETEXTUREPROC ActiveTexture;
PFNGLATTACHSHADERPROC AttachShader;
@ -428,6 +449,7 @@ union GL3WProcs {
PFNGLBLENDEQUATIONSEPARATEPROC BlendEquationSeparate;
PFNGLBLENDFUNCSEPARATEPROC BlendFuncSeparate;
PFNGLBUFFERDATAPROC BufferData;
PFNGLBUFFERSUBDATAPROC BufferSubData;
PFNGLCLEARPROC Clear;
PFNGLCLEARCOLORPROC ClearColor;
PFNGLCOMPILESHADERPROC CompileShader;
@ -448,6 +470,7 @@ union GL3WProcs {
PFNGLGENTEXTURESPROC GenTextures;
PFNGLGENVERTEXARRAYSPROC GenVertexArrays;
PFNGLGETATTRIBLOCATIONPROC GetAttribLocation;
PFNGLGETERRORPROC GetError;
PFNGLGETINTEGERVPROC GetIntegerv;
PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog;
PFNGLGETPROGRAMIVPROC GetProgramiv;
@ -473,61 +496,63 @@ union GL3WProcs {
} gl;
};
GL3W_API extern union GL3WProcs gl3wProcs;
GL3W_API extern union GL3WProcs imgl3wProcs;
/* OpenGL functions */
#define glActiveTexture gl3wProcs.gl.ActiveTexture
#define glAttachShader gl3wProcs.gl.AttachShader
#define glBindBuffer gl3wProcs.gl.BindBuffer
#define glBindSampler gl3wProcs.gl.BindSampler
#define glBindTexture gl3wProcs.gl.BindTexture
#define glBindVertexArray gl3wProcs.gl.BindVertexArray
#define glBlendEquation gl3wProcs.gl.BlendEquation
#define glBlendEquationSeparate gl3wProcs.gl.BlendEquationSeparate
#define glBlendFuncSeparate gl3wProcs.gl.BlendFuncSeparate
#define glBufferData gl3wProcs.gl.BufferData
#define glClear gl3wProcs.gl.Clear
#define glClearColor gl3wProcs.gl.ClearColor
#define glCompileShader gl3wProcs.gl.CompileShader
#define glCreateProgram gl3wProcs.gl.CreateProgram
#define glCreateShader gl3wProcs.gl.CreateShader
#define glDeleteBuffers gl3wProcs.gl.DeleteBuffers
#define glDeleteProgram gl3wProcs.gl.DeleteProgram
#define glDeleteShader gl3wProcs.gl.DeleteShader
#define glDeleteTextures gl3wProcs.gl.DeleteTextures
#define glDeleteVertexArrays gl3wProcs.gl.DeleteVertexArrays
#define glDetachShader gl3wProcs.gl.DetachShader
#define glDisable gl3wProcs.gl.Disable
#define glDrawElements gl3wProcs.gl.DrawElements
#define glDrawElementsBaseVertex gl3wProcs.gl.DrawElementsBaseVertex
#define glEnable gl3wProcs.gl.Enable
#define glEnableVertexAttribArray gl3wProcs.gl.EnableVertexAttribArray
#define glGenBuffers gl3wProcs.gl.GenBuffers
#define glGenTextures gl3wProcs.gl.GenTextures
#define glGenVertexArrays gl3wProcs.gl.GenVertexArrays
#define glGetAttribLocation gl3wProcs.gl.GetAttribLocation
#define glGetIntegerv gl3wProcs.gl.GetIntegerv
#define glGetProgramInfoLog gl3wProcs.gl.GetProgramInfoLog
#define glGetProgramiv gl3wProcs.gl.GetProgramiv
#define glGetShaderInfoLog gl3wProcs.gl.GetShaderInfoLog
#define glGetShaderiv gl3wProcs.gl.GetShaderiv
#define glGetString gl3wProcs.gl.GetString
#define glGetStringi gl3wProcs.gl.GetStringi
#define glGetUniformLocation gl3wProcs.gl.GetUniformLocation
#define glIsEnabled gl3wProcs.gl.IsEnabled
#define glLinkProgram gl3wProcs.gl.LinkProgram
#define glPixelStorei gl3wProcs.gl.PixelStorei
#define glPolygonMode gl3wProcs.gl.PolygonMode
#define glReadPixels gl3wProcs.gl.ReadPixels
#define glScissor gl3wProcs.gl.Scissor
#define glShaderSource gl3wProcs.gl.ShaderSource
#define glTexImage2D gl3wProcs.gl.TexImage2D
#define glTexParameteri gl3wProcs.gl.TexParameteri
#define glUniform1i gl3wProcs.gl.Uniform1i
#define glUniformMatrix4fv gl3wProcs.gl.UniformMatrix4fv
#define glUseProgram gl3wProcs.gl.UseProgram
#define glVertexAttribPointer gl3wProcs.gl.VertexAttribPointer
#define glViewport gl3wProcs.gl.Viewport
#define glActiveTexture imgl3wProcs.gl.ActiveTexture
#define glAttachShader imgl3wProcs.gl.AttachShader
#define glBindBuffer imgl3wProcs.gl.BindBuffer
#define glBindSampler imgl3wProcs.gl.BindSampler
#define glBindTexture imgl3wProcs.gl.BindTexture
#define glBindVertexArray imgl3wProcs.gl.BindVertexArray
#define glBlendEquation imgl3wProcs.gl.BlendEquation
#define glBlendEquationSeparate imgl3wProcs.gl.BlendEquationSeparate
#define glBlendFuncSeparate imgl3wProcs.gl.BlendFuncSeparate
#define glBufferData imgl3wProcs.gl.BufferData
#define glBufferSubData imgl3wProcs.gl.BufferSubData
#define glClear imgl3wProcs.gl.Clear
#define glClearColor imgl3wProcs.gl.ClearColor
#define glCompileShader imgl3wProcs.gl.CompileShader
#define glCreateProgram imgl3wProcs.gl.CreateProgram
#define glCreateShader imgl3wProcs.gl.CreateShader
#define glDeleteBuffers imgl3wProcs.gl.DeleteBuffers
#define glDeleteProgram imgl3wProcs.gl.DeleteProgram
#define glDeleteShader imgl3wProcs.gl.DeleteShader
#define glDeleteTextures imgl3wProcs.gl.DeleteTextures
#define glDeleteVertexArrays imgl3wProcs.gl.DeleteVertexArrays
#define glDetachShader imgl3wProcs.gl.DetachShader
#define glDisable imgl3wProcs.gl.Disable
#define glDrawElements imgl3wProcs.gl.DrawElements
#define glDrawElementsBaseVertex imgl3wProcs.gl.DrawElementsBaseVertex
#define glEnable imgl3wProcs.gl.Enable
#define glEnableVertexAttribArray imgl3wProcs.gl.EnableVertexAttribArray
#define glGenBuffers imgl3wProcs.gl.GenBuffers
#define glGenTextures imgl3wProcs.gl.GenTextures
#define glGenVertexArrays imgl3wProcs.gl.GenVertexArrays
#define glGetAttribLocation imgl3wProcs.gl.GetAttribLocation
#define glGetError imgl3wProcs.gl.GetError
#define glGetIntegerv imgl3wProcs.gl.GetIntegerv
#define glGetProgramInfoLog imgl3wProcs.gl.GetProgramInfoLog
#define glGetProgramiv imgl3wProcs.gl.GetProgramiv
#define glGetShaderInfoLog imgl3wProcs.gl.GetShaderInfoLog
#define glGetShaderiv imgl3wProcs.gl.GetShaderiv
#define glGetString imgl3wProcs.gl.GetString
#define glGetStringi imgl3wProcs.gl.GetStringi
#define glGetUniformLocation imgl3wProcs.gl.GetUniformLocation
#define glIsEnabled imgl3wProcs.gl.IsEnabled
#define glLinkProgram imgl3wProcs.gl.LinkProgram
#define glPixelStorei imgl3wProcs.gl.PixelStorei
#define glPolygonMode imgl3wProcs.gl.PolygonMode
#define glReadPixels imgl3wProcs.gl.ReadPixels
#define glScissor imgl3wProcs.gl.Scissor
#define glShaderSource imgl3wProcs.gl.ShaderSource
#define glTexImage2D imgl3wProcs.gl.TexImage2D
#define glTexParameteri imgl3wProcs.gl.TexParameteri
#define glUniform1i imgl3wProcs.gl.Uniform1i
#define glUniformMatrix4fv imgl3wProcs.gl.UniformMatrix4fv
#define glUseProgram imgl3wProcs.gl.UseProgram
#define glVertexAttribPointer imgl3wProcs.gl.VertexAttribPointer
#define glViewport imgl3wProcs.gl.Viewport
#ifdef __cplusplus
}
@ -671,6 +696,7 @@ static const char *proc_names[] = {
"glBlendEquationSeparate",
"glBlendFuncSeparate",
"glBufferData",
"glBufferSubData",
"glClear",
"glClearColor",
"glCompileShader",
@ -691,6 +717,7 @@ static const char *proc_names[] = {
"glGenTextures",
"glGenVertexArrays",
"glGetAttribLocation",
"glGetError",
"glGetIntegerv",
"glGetProgramInfoLog",
"glGetProgramiv",
@ -715,13 +742,13 @@ static const char *proc_names[] = {
"glViewport",
};
GL3W_API union GL3WProcs gl3wProcs;
GL3W_API union GL3WProcs imgl3wProcs;
static void load_procs(GL3WGetProcAddressProc proc)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(proc_names); i++)
gl3wProcs.ptr[i] = proc(proc_names[i]);
imgl3wProcs.ptr[i] = proc(proc_names[i]);
}
#ifdef __cplusplus

@ -4,12 +4,14 @@
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [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 kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: IME support.
// Issues:
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
// [ ] Platform: Multi-viewport / platform windows.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
@ -19,7 +21,7 @@
@class NSEvent;
@class NSView;
IMGUI_IMPL_API bool ImGui_ImplOSX_Init();
IMGUI_IMPL_API bool ImGui_ImplOSX_Init(NSView* _Nonnull view);
IMGUI_IMPL_API void ImGui_ImplOSX_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOSX_NewFrame(NSView* _Nullable view);
IMGUI_IMPL_API bool ImGui_ImplOSX_HandleEvent(NSEvent* _Nonnull event, NSView* _Nullable view);

@ -4,9 +4,11 @@
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [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 kVK_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: OSX clipboard is supported within core Dear ImGui (no specific code in this backend).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: IME support.
// Issues:
// [ ] Platform: Keys are all generally very broken. Best using [event keycode] and not [event characters]..
// [ ] Platform: Multi-viewport / platform windows.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@ -14,12 +16,25 @@
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
#include "imgui.h"
#include "imgui_impl_osx.h"
#import "imgui.h"
#import "imgui_impl_osx.h"
#import <Cocoa/Cocoa.h>
#import <mach/mach_time.h>
#import <Carbon/Carbon.h>
#import <GameController/GameController.h>
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2022-02-07: Inputs: Forward keyDown/keyUp events to OS when unused by dear imgui.
// 2022-01-31: Fix building with old Xcode versions that are missing gamepad features.
// 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-12: Inputs: Added basic Platform IME support, hooking the io.SetPlatformImeDataFn() function.
// 2022-01-10: Inputs: calling new io.AddKeyEvent(), io.AddKeyModsEvent() + io.SetKeyEventNativeData() API (1.87+). Support for full ImGuiKey range.
// 2021-12-13: *BREAKING CHANGE* Add NSView parameter to ImGui_ImplOSX_Init(). Generally fix keyboard support. Using kVK_* codes for keyboard keys.
// 2021-12-13: Add game controller support.
// 2021-09-21: Use mach_absolute_time as CFAbsoluteTimeGetCurrent can jump backwards.
// 2021-08-17: Calling io.AddFocusEvent() on NSApplicationDidBecomeActiveNotification/NSApplicationDidResignActiveNotification events.
// 2021-06-23: Inputs: Added a fix for shortcuts using CTRL key instead of CMD key.
// 2021-04-19: Inputs: Added a fix for keys remaining stuck in pressed state when CMD-tabbing into different application.
@ -35,15 +50,21 @@
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-07-07: Initial version.
#define APPLE_HAS_BUTTON_OPTIONS (__IPHONE_OS_VERSION_MIN_REQUIRED >= 130000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500 || __TV_OS_VERSION_MIN_REQUIRED >= 130000)
#define APPLE_HAS_CONTROLLER (__IPHONE_OS_VERSION_MIN_REQUIRED >= 140000 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 110000 || __TV_OS_VERSION_MIN_REQUIRED >= 140000)
#define APPLE_HAS_THUMBSTICKS (__IPHONE_OS_VERSION_MIN_REQUIRED >= 120100 || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101401 || __TV_OS_VERSION_MIN_REQUIRED >= 120100)
@class ImFocusObserver;
@class KeyEventResponder;
// Data
static CFAbsoluteTime g_Time = 0.0;
static NSCursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static bool g_MouseCursorHidden = false;
static bool g_MouseJustPressed[ImGuiMouseButton_COUNT] = {};
static bool g_MouseDown[ImGuiMouseButton_COUNT] = {};
static ImFocusObserver* g_FocusObserver = NULL;
static double g_HostClockPeriod = 0.0;
static double g_Time = 0.0;
static NSCursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static bool g_MouseCursorHidden = false;
static ImFocusObserver* g_FocusObserver = nil;
static KeyEventResponder* g_KeyEventResponder = nil;
static NSTextInputContext* g_InputContext = nil;
// Undocumented methods for creating cursors.
@interface NSCursor()
@ -53,13 +74,146 @@ static ImFocusObserver* g_FocusObserver = NULL;
+ (id)_windowResizeEastWestCursor;
@end
static void resetKeys()
static void InitHostClockPeriod()
{
struct mach_timebase_info info;
mach_timebase_info(&info);
g_HostClockPeriod = 1e-9 * ((double)info.denom / (double)info.numer); // Period is the reciprocal of frequency.
}
static double GetMachAbsoluteTimeInSeconds()
{
return (double)mach_absolute_time() * g_HostClockPeriod;
}
/**
KeyEventResponder implements the NSTextInputClient protocol as is required by the macOS text input manager.
The macOS text input manager is invoked by calling the interpretKeyEvents method from the keyDown method.
Keyboard events are then evaluated by the macOS input manager and valid text input is passed back via the
insertText:replacementRange method.
This is the same approach employed by other cross-platform libraries such as SDL2:
https://github.com/spurious/SDL-mirror/blob/e17aacbd09e65a4fd1e166621e011e581fb017a8/src/video/cocoa/SDL_cocoakeyboard.m#L53
and GLFW:
https://github.com/glfw/glfw/blob/b55a517ae0c7b5127dffa79a64f5406021bf9076/src/cocoa_window.m#L722-L723
*/
@interface KeyEventResponder: NSView<NSTextInputClient>
@end
@implementation KeyEventResponder
{
float _posX;
float _posY;
NSRect _imeRect;
}
#pragma mark - Public
- (void)setImePosX:(float)posX imePosY:(float)posY
{
_posX = posX;
_posY = posY;
}
- (void)updateImePosWithView:(NSView *)view
{
NSWindow *window = view.window;
if (!window)
return;
NSRect contentRect = [window contentRectForFrameRect:window.frame];
NSRect rect = NSMakeRect(_posX, contentRect.size.height - _posY, 0, 0);
_imeRect = [window convertRectToScreen:rect];
}
- (void)viewDidMoveToWindow
{
// Ensure self is a first responder to receive the input events.
[self.window makeFirstResponder:self];
}
- (void)keyDown:(NSEvent*)event
{
if (!ImGui_ImplOSX_HandleEvent(event, self))
[super keyDown:event];
// Call to the macOS input manager system.
[self interpretKeyEvents:@[event]];
}
- (void)keyUp:(NSEvent*)event
{
if (!ImGui_ImplOSX_HandleEvent(event, self))
[super keyUp:event];
}
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
{
ImGuiIO& io = ImGui::GetIO();
memset(io.KeysDown, 0, sizeof(io.KeysDown));
io.KeyCtrl = io.KeyShift = io.KeyAlt = io.KeySuper = false;
NSString* characters;
if ([aString isKindOfClass:[NSAttributedString class]])
characters = [aString string];
else
characters = (NSString*)aString;
io.AddInputCharactersUTF8(characters.UTF8String);
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (void)doCommandBySelector:(SEL)myselector
{
}
- (nullable NSAttributedString*)attributedSubstringForProposedRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange
{
return nil;
}
- (NSUInteger)characterIndexForPoint:(NSPoint)point
{
return 0;
}
- (NSRect)firstRectForCharacterRange:(NSRange)range actualRange:(nullable NSRangePointer)actualRange
{
return _imeRect;
}
- (BOOL)hasMarkedText
{
return NO;
}
- (NSRange)markedRange
{
return NSMakeRange(NSNotFound, 0);
}
- (NSRange)selectedRange
{
return NSMakeRange(NSNotFound, 0);
}
- (void)setMarkedText:(nonnull id)string selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{
}
- (void)unmarkText
{
}
- (nonnull NSArray<NSAttributedStringKey>*)validAttributesForMarkedText
{
return @[];
}
@end
@interface ImFocusObserver : NSObject
- (void)onApplicationBecomeActive:(NSNotification*)aNotification;
@ -79,17 +233,135 @@ static void resetKeys()
{
ImGuiIO& io = ImGui::GetIO();
io.AddFocusEvent(false);
// Unfocused applications do not receive input events, therefore we must manually
// release any pressed keys when application loses focus, otherwise they would remain
// stuck in a pressed state. https://github.com/ocornut/imgui/issues/3832
resetKeys();
}
@end
// Functions
bool ImGui_ImplOSX_Init()
static ImGuiKey ImGui_ImplOSX_KeyCodeToImGuiKey(int key_code)
{
switch (key_code)
{
case kVK_ANSI_A: return ImGuiKey_A;
case kVK_ANSI_S: return ImGuiKey_S;
case kVK_ANSI_D: return ImGuiKey_D;
case kVK_ANSI_F: return ImGuiKey_F;
case kVK_ANSI_H: return ImGuiKey_H;
case kVK_ANSI_G: return ImGuiKey_G;
case kVK_ANSI_Z: return ImGuiKey_Z;
case kVK_ANSI_X: return ImGuiKey_X;
case kVK_ANSI_C: return ImGuiKey_C;
case kVK_ANSI_V: return ImGuiKey_V;
case kVK_ANSI_B: return ImGuiKey_B;
case kVK_ANSI_Q: return ImGuiKey_Q;
case kVK_ANSI_W: return ImGuiKey_W;
case kVK_ANSI_E: return ImGuiKey_E;
case kVK_ANSI_R: return ImGuiKey_R;
case kVK_ANSI_Y: return ImGuiKey_Y;
case kVK_ANSI_T: return ImGuiKey_T;
case kVK_ANSI_1: return ImGuiKey_1;
case kVK_ANSI_2: return ImGuiKey_2;
case kVK_ANSI_3: return ImGuiKey_3;
case kVK_ANSI_4: return ImGuiKey_4;
case kVK_ANSI_6: return ImGuiKey_6;
case kVK_ANSI_5: return ImGuiKey_5;
case kVK_ANSI_Equal: return ImGuiKey_Equal;
case kVK_ANSI_9: return ImGuiKey_9;
case kVK_ANSI_7: return ImGuiKey_7;
case kVK_ANSI_Minus: return ImGuiKey_Minus;
case kVK_ANSI_8: return ImGuiKey_8;
case kVK_ANSI_0: return ImGuiKey_0;
case kVK_ANSI_RightBracket: return ImGuiKey_RightBracket;
case kVK_ANSI_O: return ImGuiKey_O;
case kVK_ANSI_U: return ImGuiKey_U;
case kVK_ANSI_LeftBracket: return ImGuiKey_LeftBracket;
case kVK_ANSI_I: return ImGuiKey_I;
case kVK_ANSI_P: return ImGuiKey_P;
case kVK_ANSI_L: return ImGuiKey_L;
case kVK_ANSI_J: return ImGuiKey_J;
case kVK_ANSI_Quote: return ImGuiKey_Apostrophe;
case kVK_ANSI_K: return ImGuiKey_K;
case kVK_ANSI_Semicolon: return ImGuiKey_Semicolon;
case kVK_ANSI_Backslash: return ImGuiKey_Backslash;
case kVK_ANSI_Comma: return ImGuiKey_Comma;
case kVK_ANSI_Slash: return ImGuiKey_Slash;
case kVK_ANSI_N: return ImGuiKey_N;
case kVK_ANSI_M: return ImGuiKey_M;
case kVK_ANSI_Period: return ImGuiKey_Period;
case kVK_ANSI_Grave: return ImGuiKey_GraveAccent;
case kVK_ANSI_KeypadDecimal: return ImGuiKey_KeypadDecimal;
case kVK_ANSI_KeypadMultiply: return ImGuiKey_KeypadMultiply;
case kVK_ANSI_KeypadPlus: return ImGuiKey_KeypadAdd;
case kVK_ANSI_KeypadClear: return ImGuiKey_NumLock;
case kVK_ANSI_KeypadDivide: return ImGuiKey_KeypadDivide;
case kVK_ANSI_KeypadEnter: return ImGuiKey_KeypadEnter;
case kVK_ANSI_KeypadMinus: return ImGuiKey_KeypadSubtract;
case kVK_ANSI_KeypadEquals: return ImGuiKey_KeypadEqual;
case kVK_ANSI_Keypad0: return ImGuiKey_Keypad0;
case kVK_ANSI_Keypad1: return ImGuiKey_Keypad1;
case kVK_ANSI_Keypad2: return ImGuiKey_Keypad2;
case kVK_ANSI_Keypad3: return ImGuiKey_Keypad3;
case kVK_ANSI_Keypad4: return ImGuiKey_Keypad4;
case kVK_ANSI_Keypad5: return ImGuiKey_Keypad5;
case kVK_ANSI_Keypad6: return ImGuiKey_Keypad6;
case kVK_ANSI_Keypad7: return ImGuiKey_Keypad7;
case kVK_ANSI_Keypad8: return ImGuiKey_Keypad8;
case kVK_ANSI_Keypad9: return ImGuiKey_Keypad9;
case kVK_Return: return ImGuiKey_Enter;
case kVK_Tab: return ImGuiKey_Tab;
case kVK_Space: return ImGuiKey_Space;
case kVK_Delete: return ImGuiKey_Backspace;
case kVK_Escape: return ImGuiKey_Escape;
case kVK_CapsLock: return ImGuiKey_CapsLock;
case kVK_Control: return ImGuiKey_LeftCtrl;
case kVK_Shift: return ImGuiKey_LeftShift;
case kVK_Option: return ImGuiKey_LeftAlt;
case kVK_Command: return ImGuiKey_LeftSuper;
case kVK_RightControl: return ImGuiKey_RightCtrl;
case kVK_RightShift: return ImGuiKey_RightShift;
case kVK_RightOption: return ImGuiKey_RightAlt;
case kVK_RightCommand: return ImGuiKey_RightSuper;
// case kVK_Function: return ImGuiKey_;
// case kVK_F17: return ImGuiKey_;
// case kVK_VolumeUp: return ImGuiKey_;
// case kVK_VolumeDown: return ImGuiKey_;
// case kVK_Mute: return ImGuiKey_;
// case kVK_F18: return ImGuiKey_;
// case kVK_F19: return ImGuiKey_;
// case kVK_F20: return ImGuiKey_;
case kVK_F5: return ImGuiKey_F5;
case kVK_F6: return ImGuiKey_F6;
case kVK_F7: return ImGuiKey_F7;
case kVK_F3: return ImGuiKey_F3;
case kVK_F8: return ImGuiKey_F8;
case kVK_F9: return ImGuiKey_F9;
case kVK_F11: return ImGuiKey_F11;
case kVK_F13: return ImGuiKey_PrintScreen;
// case kVK_F16: return ImGuiKey_;
// case kVK_F14: return ImGuiKey_;
case kVK_F10: return ImGuiKey_F10;
case 0x6E: return ImGuiKey_Menu;
case kVK_F12: return ImGuiKey_F12;
// case kVK_F15: return ImGuiKey_;
case kVK_Help: return ImGuiKey_Insert;
case kVK_Home: return ImGuiKey_Home;
case kVK_PageUp: return ImGuiKey_PageUp;
case kVK_ForwardDelete: return ImGuiKey_Delete;
case kVK_F4: return ImGuiKey_F4;
case kVK_End: return ImGuiKey_End;
case kVK_F2: return ImGuiKey_F2;
case kVK_PageDown: return ImGuiKey_PageDown;
case kVK_F1: return ImGuiKey_F1;
case kVK_LeftArrow: return ImGuiKey_LeftArrow;
case kVK_RightArrow: return ImGuiKey_RightArrow;
case kVK_DownArrow: return ImGuiKey_DownArrow;
case kVK_UpArrow: return ImGuiKey_UpArrow;
default: return ImGuiKey_None;
}
}
bool ImGui_ImplOSX_Init(NSView* view)
{
ImGuiIO& io = ImGui::GetIO();
@ -97,34 +369,9 @@ bool ImGui_ImplOSX_Init()
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
//io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
//io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
//io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
//io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
io.BackendPlatformName = "imgui_impl_osx";
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeyDown[] array.
const int offset_for_function_keys = 256 - 0xF700;
io.KeyMap[ImGuiKey_Tab] = '\t';
io.KeyMap[ImGuiKey_LeftArrow] = NSLeftArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_RightArrow] = NSRightArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_UpArrow] = NSUpArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_DownArrow] = NSDownArrowFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_PageUp] = NSPageUpFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_PageDown] = NSPageDownFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Home] = NSHomeFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_End] = NSEndFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Insert] = NSInsertFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Delete] = NSDeleteFunctionKey + offset_for_function_keys;
io.KeyMap[ImGuiKey_Backspace] = 127;
io.KeyMap[ImGuiKey_Space] = 32;
io.KeyMap[ImGuiKey_Enter] = 13;
io.KeyMap[ImGuiKey_Escape] = 27;
io.KeyMap[ImGuiKey_KeyPadEnter] = 3;
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
// Load cursors. Some of them are undocumented.
g_MouseCursorHidden = false;
g_MouseCursors[ImGuiMouseCursor_Arrow] = [NSCursor arrowCursor];
@ -176,6 +423,36 @@ bool ImGui_ImplOSX_Init()
name:NSApplicationDidResignActiveNotification
object:nil];
// Add the NSTextInputClient to the view hierarchy,
// to receive keyboard events and translate them to input text.
g_KeyEventResponder = [[KeyEventResponder alloc] initWithFrame:NSZeroRect];
g_InputContext = [[NSTextInputContext alloc] initWithClient:g_KeyEventResponder];
[view addSubview:g_KeyEventResponder];
// Some events do not raise callbacks of AppView in some circumstances (for example when CMD key is held down).
// This monitor taps into global event stream and captures these events.
NSEventMask eventMask = NSEventMaskFlagsChanged;
[NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event)
{
ImGui_ImplOSX_HandleEvent(event, g_KeyEventResponder);
return event;
}];
io.SetPlatformImeDataFn = [](ImGuiViewport* viewport, ImGuiPlatformImeData* data) -> void
{
if (data->WantVisible)
{
[g_InputContext activate];
}
else
{
[g_InputContext discardMarkedText];
[g_InputContext invalidateCharacterCoordinates];
[g_InputContext deactivate];
}
[g_KeyEventResponder setImePosX:data->InputPos.x imePosY:data->InputPos.y + data->InputLineHeight];
};
return true;
}
@ -184,17 +461,9 @@ void ImGui_ImplOSX_Shutdown()
g_FocusObserver = NULL;
}
static void ImGui_ImplOSX_UpdateMouseCursorAndButtons()
static void ImGui_ImplOSX_UpdateMouseCursor()
{
// Update buttons
ImGuiIO& io = ImGui::GetIO();
for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++)
{
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[i] = g_MouseJustPressed[i] || g_MouseDown[i];
g_MouseJustPressed[i] = false;
}
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
@ -210,8 +479,12 @@ static void ImGui_ImplOSX_UpdateMouseCursorAndButtons()
}
else
{
// Show OS mouse cursor
[g_MouseCursors[g_MouseCursors[imgui_cursor] ? imgui_cursor : ImGuiMouseCursor_Arrow] set];
NSCursor* desired = g_MouseCursors[imgui_cursor] ?: g_MouseCursors[ImGuiMouseCursor_Arrow];
// -[NSCursor set] generates measureable overhead if called unconditionally.
if (desired != NSCursor.currentCursor)
{
[desired set];
}
if (g_MouseCursorHidden)
{
g_MouseCursorHidden = false;
@ -220,6 +493,72 @@ static void ImGui_ImplOSX_UpdateMouseCursorAndButtons()
}
}
static void ImGui_ImplOSX_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
#if APPLE_HAS_CONTROLLER
GCController* controller = GCController.current;
#else
GCController* controller = GCController.controllers.firstObject;
#endif
if (controller == nil || controller.extendedGamepad == nil)
{
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
return;
}
GCExtendedGamepad* gp = controller.extendedGamepad;
// Update gamepad inputs
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
#define MAP_BUTTON(KEY_NO, BUTTON_NAME) { io.AddKeyEvent(KEY_NO, gp.BUTTON_NAME.isPressed); }
#define MAP_ANALOG(KEY_NO, AXIS_NAME, V0, V1) { float vn = (float)(gp.AXIS_NAME.value - V0) / (float)(V1 - V0); vn = IM_SATURATE(vn); io.AddKeyAnalogEvent(KEY_NO, vn > 0.1f, vn); }
const float thumb_dead_zone = 0.0f;
#if APPLE_HAS_BUTTON_OPTIONS
MAP_BUTTON(ImGuiKey_GamepadBack, buttonOptions);
#endif
MAP_BUTTON(ImGuiKey_GamepadFaceDown, buttonA); // Xbox A, PS Cross
MAP_BUTTON(ImGuiKey_GamepadFaceRight, buttonB); // Xbox B, PS Circle
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, buttonX); // Xbox X, PS Square
MAP_BUTTON(ImGuiKey_GamepadFaceUp, buttonY); // Xbox Y, PS Triangle
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, dpad.left);
MAP_BUTTON(ImGuiKey_GamepadDpadRight, dpad.right);
MAP_BUTTON(ImGuiKey_GamepadDpadUp, dpad.up);
MAP_BUTTON(ImGuiKey_GamepadDpadDown, dpad.down);
MAP_ANALOG(ImGuiKey_GamepadL1, leftShoulder, 0.0f, 1.0f);
MAP_ANALOG(ImGuiKey_GamepadR1, rightShoulder, 0.0f, 1.0f);
MAP_ANALOG(ImGuiKey_GamepadL2, leftTrigger, 0.0f, 1.0f);
MAP_ANALOG(ImGuiKey_GamepadR2, rightTrigger, 0.0f, 1.0f);
#if APPLE_HAS_THUMBSTICKS
MAP_BUTTON(ImGuiKey_GamepadL3, leftThumbstickButton);
MAP_BUTTON(ImGuiKey_GamepadR3, rightThumbstickButton);
#endif
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, leftThumbstick.xAxis, -thumb_dead_zone, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, leftThumbstick.xAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, leftThumbstick.yAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, leftThumbstick.yAxis, -thumb_dead_zone, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, rightThumbstick.xAxis, -thumb_dead_zone, -1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, rightThumbstick.xAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, rightThumbstick.yAxis, +thumb_dead_zone, +1.0f);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, rightThumbstick.yAxis, -thumb_dead_zone, -1.0f);
#undef MAP_BUTTON
#undef MAP_ANALOG
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
}
static void ImGui_ImplOSX_UpdateImePosWithView(NSView* view)
{
ImGuiIO& io = ImGui::GetIO();
if (io.WantTextInput)
[g_KeyEventResponder updateImePosWithView:view];
}
void ImGui_ImplOSX_NewFrame(NSView* view)
{
// Setup display size
@ -233,25 +572,17 @@ void ImGui_ImplOSX_NewFrame(NSView* view)
// Setup time step
if (g_Time == 0.0)
g_Time = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime current_time = CFAbsoluteTimeGetCurrent();
{
InitHostClockPeriod();
g_Time = GetMachAbsoluteTimeInSeconds();
}
double current_time = GetMachAbsoluteTimeInSeconds();
io.DeltaTime = (float)(current_time - g_Time);
g_Time = current_time;
ImGui_ImplOSX_UpdateMouseCursorAndButtons();
}
static int mapCharacterToKey(int c)
{
if (c >= 'a' && c <= 'z')
return c - 'a' + 'A';
if (c == 25) // SHIFT+TAB -> TAB
return 9;
if (c >= 0 && c < 256)
return c;
if (c >= 0xF700 && c < 0xF700 + 256)
return c - 0xF700 + 256;
return -1;
ImGui_ImplOSX_UpdateMouseCursor();
ImGui_ImplOSX_UpdateGamepads();
ImGui_ImplOSX_UpdateImePosWithView(view);
}
bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
@ -261,16 +592,16 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
if (event.type == NSEventTypeLeftMouseDown || event.type == NSEventTypeRightMouseDown || event.type == NSEventTypeOtherMouseDown)
{
int button = (int)[event buttonNumber];
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
g_MouseDown[button] = g_MouseJustPressed[button] = true;
if (button >= 0 && button < ImGuiMouseButton_COUNT)
io.AddMouseButtonEvent(button, true);
return io.WantCaptureMouse;
}
if (event.type == NSEventTypeLeftMouseUp || event.type == NSEventTypeRightMouseUp || event.type == NSEventTypeOtherMouseUp)
{
int button = (int)[event buttonNumber];
if (button >= 0 && button < IM_ARRAYSIZE(g_MouseDown))
g_MouseDown[button] = false;
if (button >= 0 && button < ImGuiMouseButton_COUNT)
io.AddMouseButtonEvent(button, false);
return io.WantCaptureMouse;
}
@ -279,11 +610,26 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
NSPoint mousePoint = event.locationInWindow;
mousePoint = [view convertPoint:mousePoint fromView:nil];
mousePoint = NSMakePoint(mousePoint.x, view.bounds.size.height - mousePoint.y);
io.MousePos = ImVec2((float)mousePoint.x, (float)mousePoint.y);
io.AddMousePosEvent((float)mousePoint.x, (float)mousePoint.y);
}
if (event.type == NSEventTypeScrollWheel)
{
// Ignore canceled events.
//
// From macOS 12.1, scrolling with two fingers and then decelerating
// by tapping two fingers results in two events appearing:
//
// 1. A scroll wheel NSEvent, with a phase == NSEventPhaseMayBegin, when the user taps
// two fingers to decelerate or stop the scroll events.
//
// 2. A scroll wheel NSEvent, with a phase == NSEventPhaseCancelled, when the user releases the
// two-finger tap. It is this event that sometimes contains large values for scrollingDeltaX and
// scrollingDeltaY. When these are added to the current x and y positions of the scrolling view,
// it appears to jump up or down. It can be observed in Preview, various JetBrains IDEs and here.
if (event.phase == NSEventPhaseCancelled)
return false;
double wheel_dx = 0.0;
double wheel_dy = 0.0;
@ -304,65 +650,61 @@ bool ImGui_ImplOSX_HandleEvent(NSEvent* event, NSView* view)
wheel_dx = [event deltaX];
wheel_dy = [event deltaY];
}
if (wheel_dx != 0.0 || wheel_dx != 0.0)
io.AddMouseWheelEvent((float)wheel_dx * 0.1f, (float)wheel_dy * 0.1f);
if (fabs(wheel_dx) > 0.0)
io.MouseWheelH += (float)wheel_dx * 0.1f;
if (fabs(wheel_dy) > 0.0)
io.MouseWheel += (float)wheel_dy * 0.1f;
return io.WantCaptureMouse;
}
// FIXME: All the key handling is wrong and broken. Refer to GLFW's cocoa_init.mm and cocoa_window.mm.
if (event.type == NSEventTypeKeyDown)
if (event.type == NSEventTypeKeyDown || event.type == NSEventTypeKeyUp)
{
NSString* str = [event characters];
NSUInteger len = [str length];
for (NSUInteger i = 0; i < len; i++)
{
int c = [str characterAtIndex:i];
if (!io.KeySuper && !(c >= 0xF700 && c <= 0xFFFF) && c != 127)
io.AddInputCharacter((unsigned int)c);
// We must reset in case we're pressing a sequence of special keys while keeping the command pressed
int key = mapCharacterToKey(c);
if (key != -1 && key < 256 && !io.KeySuper)
resetKeys();
if (key != -1)
io.KeysDown[key] = true;
}
if ([event isARepeat])
return io.WantCaptureKeyboard;
int key_code = (int)[event keyCode];
ImGuiKey key = ImGui_ImplOSX_KeyCodeToImGuiKey(key_code);
io.AddKeyEvent(key, event.type == NSEventTypeKeyDown);
io.SetKeyEventNativeData(key, key_code, -1); // To support legacy indexing (<1.87 user code)
return io.WantCaptureKeyboard;
}
if (event.type == NSEventTypeKeyUp)
if (event.type == NSEventTypeFlagsChanged)
{
NSString* str = [event characters];
NSUInteger len = [str length];
for (NSUInteger i = 0; i < len; i++)
unsigned short key_code = [event keyCode];
NSEventModifierFlags modifier_flags = [event modifierFlags];
io.AddKeyEvent(ImGuiKey_ModShift, (modifier_flags & NSEventModifierFlagShift) != 0);
io.AddKeyEvent(ImGuiKey_ModCtrl, (modifier_flags & NSEventModifierFlagControl) != 0);
io.AddKeyEvent(ImGuiKey_ModAlt, (modifier_flags & NSEventModifierFlagOption) != 0);
io.AddKeyEvent(ImGuiKey_ModSuper, (modifier_flags & NSEventModifierFlagCommand) != 0);
ImGuiKey key = ImGui_ImplOSX_KeyCodeToImGuiKey(key_code);
if (key != ImGuiKey_None)
{
int c = [str characterAtIndex:i];
int key = mapCharacterToKey(c);
if (key != -1)
io.KeysDown[key] = false;
// macOS does not generate down/up event for modifiers. We're trying
// to use hardware dependent masks to extract that information.
// 'imgui_mask' is left as a fallback.
NSEventModifierFlags mask = 0;
switch (key)
{
case ImGuiKey_LeftCtrl: mask = 0x0001; break;
case ImGuiKey_RightCtrl: mask = 0x2000; break;
case ImGuiKey_LeftShift: mask = 0x0002; break;
case ImGuiKey_RightShift: mask = 0x0004; break;
case ImGuiKey_LeftSuper: mask = 0x0008; break;
case ImGuiKey_RightSuper: mask = 0x0010; break;
case ImGuiKey_LeftAlt: mask = 0x0020; break;
case ImGuiKey_RightAlt: mask = 0x0040; break;
default:
return io.WantCaptureKeyboard;
}
NSEventModifierFlags modifier_flags = [event modifierFlags];
io.AddKeyEvent(key, (modifier_flags & mask) != 0);
io.SetKeyEventNativeData(key, key_code, -1); // To support legacy indexing (<1.87 user code)
}
return io.WantCaptureKeyboard;
}
if (event.type == NSEventTypeFlagsChanged)
{
unsigned int flags = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
bool oldKeyCtrl = io.KeyCtrl;
bool oldKeyShift = io.KeyShift;
bool oldKeyAlt = io.KeyAlt;
bool oldKeySuper = io.KeySuper;
io.KeyCtrl = flags & NSEventModifierFlagControl;
io.KeyShift = flags & NSEventModifierFlagShift;
io.KeyAlt = flags & NSEventModifierFlagOption;
io.KeySuper = flags & NSEventModifierFlagCommand;
// We must reset them as we will not receive any keyUp event if they where pressed with a modifier
if ((oldKeyShift && !io.KeyShift) || (oldKeyCtrl && !io.KeyCtrl) || (oldKeyAlt && !io.KeyAlt) || (oldKeySuper && !io.KeySuper))
resetKeys();
return io.WantCaptureKeyboard;
}

@ -4,10 +4,10 @@
// (Prefer SDL 2.0.5+ for full feature support.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [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: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
@ -20,7 +20,15 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 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.
@ -61,7 +69,7 @@
#include <SDL.h>
#include <SDL_syswm.h>
#if defined(__APPLE__)
#include "TargetConditionals.h"
#include <TargetConditionals.h>
#endif
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS)
@ -82,13 +90,15 @@ static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
// SDL Data
struct ImGui_ImplSDL2_Data
{
SDL_Window* Window;
Uint64 Time;
bool MousePressed[3];
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
char* ClipboardTextData;
bool MouseCanUseGlobalState;
bool UseVulkan;
SDL_Window* Window;
SDL_Renderer* Renderer;
Uint64 Time;
Uint32 MouseWindowID;
int MouseButtonsDown;
SDL_Cursor* MouseCursors[ImGuiMouseCursor_COUNT];
char* ClipboardTextData;
bool MouseCanUseGlobalState;
bool UseVulkan;
ImGui_ImplSDL2_Data() { memset(this, 0, sizeof(*this)); }
};
@ -122,6 +132,128 @@ static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
SDL_SetClipboardText(text);
}
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;
}
return ImGuiKey_None;
}
static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(ImGuiKey_ModCtrl, (sdl_key_mods & KMOD_CTRL) != 0);
io.AddKeyEvent(ImGuiKey_ModShift, (sdl_key_mods & KMOD_SHIFT) != 0);
io.AddKeyEvent(ImGuiKey_ModAlt, (sdl_key_mods & KMOD_ALT) != 0);
io.AddKeyEvent(ImGuiKey_ModSuper, (sdl_key_mods & KMOD_GUI) != 0);
}
// 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.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
@ -134,66 +266,87 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
switch (event->type)
{
case SDL_MOUSEWHEEL:
case SDL_MOUSEMOTION:
{
if (event->wheel.x > 0) io.MouseWheelH += 1;
if (event->wheel.x < 0) io.MouseWheelH -= 1;
if (event->wheel.y > 0) io.MouseWheel += 1;
if (event->wheel.y < 0) io.MouseWheel -= 1;
ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
int window_x, window_y;
SDL_GetWindowPosition(SDL_GetWindowFromID(event->motion.windowID), &window_x, &window_y);
mouse_pos.x += window_x;
mouse_pos.y += window_y;
}
io.AddMousePosEvent(mouse_pos.x, mouse_pos.y);
return true;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEWHEEL:
{
if (event->button.button == SDL_BUTTON_LEFT) { bd->MousePressed[0] = true; }
if (event->button.button == SDL_BUTTON_RIGHT) { bd->MousePressed[1] = true; }
if (event->button.button == SDL_BUTTON_MIDDLE) { bd->MousePressed[2] = true; }
float wheel_x = (event->wheel.x > 0) ? 1.0f : (event->wheel.x < 0) ? -1.0f : 0.0f;
float wheel_y = (event->wheel.y > 0) ? 1.0f : (event->wheel.y < 0) ? -1.0f : 0.0f;
io.AddMouseWheelEvent(wheel_x, wheel_y);
return true;
}
case SDL_TEXTINPUT:
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 (mouse_button == -1)
break;
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:
case SDL_KEYDOWN:
case SDL_KEYUP:
{
int key = event->key.keysym.scancode;
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
#ifdef _WIN32
io.KeySuper = false;
#else
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
#endif
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;
}
// Multi-viewport support
case SDL_WINDOWEVENT:
Uint8 window_event = event->window.event;
if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED || window_event == SDL_WINDOWEVENT_FOCUS_GAINED || window_event == SDL_WINDOWEVENT_FOCUS_LOST)
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID)))
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.
Uint8 window_event = event->window.event;
if (window_event == SDL_WINDOWEVENT_ENTER)
bd->MouseWindowID = event->window.windowID;
if (window_event == SDL_WINDOWEVENT_LEAVE)
{
if (window_event == SDL_WINDOWEVENT_CLOSE)
viewport->PlatformRequestClose = true;
if (window_event == SDL_WINDOWEVENT_MOVED)
viewport->PlatformRequestMove = true;
if (window_event == SDL_WINDOWEVENT_RESIZED)
viewport->PlatformRequestResize = true;
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
io.AddFocusEvent(true);
else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST)
io.AddFocusEvent(false);
return true;
bd->MouseWindowID = 0;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
}
break;
if (window_event == SDL_WINDOWEVENT_FOCUS_GAINED)
io.AddFocusEvent(true);
else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST)
io.AddFocusEvent(false);
if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED)
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID)))
{
if (window_event == SDL_WINDOWEVENT_CLOSE)
viewport->PlatformRequestClose = true;
if (window_event == SDL_WINDOWEVENT_MOVED)
viewport->PlatformRequestMove = true;
if (window_event == SDL_WINDOWEVENT_RESIZED)
viewport->PlatformRequestResize = true;
return true;
}
return true;
}
}
return false;
}
static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void* sdl_gl_context)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendPlatformUserData == NULL && "Already initialized a platform backend!");
@ -218,33 +371,16 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
if (mouse_can_use_global_state)
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
// SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
#ifndef __APPLE__
if (mouse_can_use_global_state)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;// We can call io.AddMouseViewportEvent() with correct data (optional)
#endif
bd->Window = window;
bd->Renderer = renderer;
bd->MouseCanUseGlobalState = mouse_can_use_global_state;
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_KP_ENTER;
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
io.ClipboardUserData = NULL;
@ -260,6 +396,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
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->PlatformHandle = (void*)window;
@ -267,7 +404,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(window, &info))
main_viewport->PlatformHandleRaw = info.info.win.window;
main_viewport->PlatformHandleRaw = (void*)info.info.win.window;
#endif
// Set SDL hint to receive mouse click events on window focus, otherwise SDL doesn't emit the event.
@ -292,7 +429,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context)
{
return ImGui_ImplSDL2_Init(window, sdl_gl_context);
return ImGui_ImplSDL2_Init(window, NULL, sdl_gl_context);
}
bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
@ -300,7 +437,7 @@ bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window)
#if !SDL_HAS_VULKAN
IM_ASSERT(0 && "Unsupported");
#endif
if (!ImGui_ImplSDL2_Init(window, NULL))
if (!ImGui_ImplSDL2_Init(window, NULL, NULL))
return false;
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
bd->UseVulkan = true;
@ -312,18 +449,24 @@ bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window)
#if !defined(_WIN32)
IM_ASSERT(0 && "Unsupported");
#endif
return ImGui_ImplSDL2_Init(window, NULL);
return ImGui_ImplSDL2_Init(window, NULL, NULL);
}
bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window)
{
return ImGui_ImplSDL2_Init(window, NULL);
return ImGui_ImplSDL2_Init(window, NULL, NULL);
}
bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer)
{
return ImGui_ImplSDL2_Init(window, renderer, NULL);
}
void ImGui_ImplSDL2_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDL2_ShutdownPlatformInterface();
@ -338,76 +481,66 @@ void ImGui_ImplSDL2_Shutdown()
}
// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
static void ImGui_ImplSDL2_UpdateMouseData()
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
ImVec2 mouse_pos_prev = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
io.MouseHoveredViewport = 0;
// Update mouse buttons
int mouse_x_local, mouse_y_local;
Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local);
io.MouseDown[0] = bd->MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = bd->MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = bd->MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
bd->MousePressed[0] = bd->MousePressed[1] = bd->MousePressed[2] = false;
// Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing)
// We forward mouse input when hovered or captured (via SDL_MOUSEMOTION) or when focused (below)
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
SDL_Window* focused_window = SDL_GetKeyboardFocus();
SDL_Window* hovered_window = SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH ? SDL_GetMouseFocus() : NULL; // This is better but is only reliably useful with SDL 2.0.5+ and SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH.
SDL_Window* mouse_window = NULL;
if (hovered_window && (bd->Window == hovered_window || ImGui::FindViewportByPlatformHandle((void*)hovered_window)))
mouse_window = hovered_window;
else if (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window)))
mouse_window = focused_window;
// 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(ImGui::IsAnyMouseDown() ? SDL_TRUE : SDL_FALSE);
SDL_CaptureMouse(bd->MouseButtonsDown != 0 ? SDL_TRUE : SDL_FALSE);
SDL_Window* focused_window = SDL_GetKeyboardFocus();
const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window)));
#else
// SDL 2.0.3 and non-windowed systems: single-viewport only
SDL_Window* mouse_window = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) ? bd->Window : NULL;
SDL_Window* focused_window = bd->Window;
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 (mouse_window == NULL)
return;
// Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
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)
{
#if SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
SDL_WarpMouseGlobal((int)mouse_pos_prev.x, (int)mouse_pos_prev.y);
else
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
SDL_WarpMouseGlobal((int)io.MousePos.x, (int)io.MousePos.y);
else
#endif
SDL_WarpMouseInWindow(bd->Window, (int)mouse_pos_prev.x, (int)mouse_pos_prev.y);
}
// Set Dear ImGui mouse position from OS position + get buttons. (this is the common behavior)
if (bd->MouseCanUseGlobalState)
{
int mouse_x_global, mouse_y_global;
SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
io.MousePos = ImVec2((float)mouse_x_global, (float)mouse_y_global);
SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y);
}
else
// (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured)
if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0)
{
// Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
// Unlike local position obtained earlier this will be valid when straying out of bounds.
int window_x, window_y;
SDL_GetWindowPosition(mouse_window, &window_x, &window_y);
io.MousePos = ImVec2((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y));
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
int mouse_x, mouse_y, window_x, window_y;
SDL_GetGlobalMouseState(&mouse_x, &mouse_y);
if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
{
SDL_GetWindowPosition(focused_window, &window_x, &window_y);
mouse_x -= window_x;
mouse_y -= window_y;
}
io.AddMousePosEvent((float)mouse_x, (float)mouse_y);
}
}
else
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
// - [!] SDL backend does NOT correctly ignore viewports with the _NoInputs flag.
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
// by the backend, and use its flawed heuristic to guess the viewport behind.
// - [X] SDL backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
{
io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local);
ImGuiID mouse_viewport_id = 0;
if (SDL_Window* sdl_mouse_window = SDL_GetWindowFromID(bd->MouseWindowID))
if (ImGuiViewport* mouse_viewport = ImGui::FindViewportByPlatformHandle((void*)sdl_mouse_window))
mouse_viewport_id = mouse_viewport->ID;
io.AddMouseViewportEvent(mouse_viewport_id);
}
}
@ -435,40 +568,45 @@ static void ImGui_ImplSDL2_UpdateMouseCursor()
static void ImGui_ImplSDL2_UpdateGamepads()
{
ImGuiIO& io = ImGui::GetIO();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
// Get gamepad
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
SDL_GameController* game_controller = SDL_GameControllerOpen(0);
if (!game_controller)
{
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
return;
}
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
// Update gamepad inputs
#define MAP_BUTTON(NAV_NO, BUTTON_NO) { io.NavInputs[NAV_NO] = (SDL_GameControllerGetButton(game_controller, BUTTON_NO) != 0) ? 1.0f : 0.0f; }
#define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float vn = (float)(SDL_GameControllerGetAxis(game_controller, AXIS_NO) - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
#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(ImGuiNavInput_Activate, SDL_CONTROLLER_BUTTON_A); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, SDL_CONTROLLER_BUTTON_B); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, SDL_CONTROLLER_BUTTON_X); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, SDL_CONTROLLER_BUTTON_Y); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, SDL_CONTROLLER_BUTTON_DPAD_UP); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, SDL_CONTROLLER_BUTTON_LEFTSHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, SDL_CONTROLLER_AXIS_LEFTX, -thumb_dead_zone, -32768);
MAP_ANALOG(ImGuiNavInput_LStickRight, SDL_CONTROLLER_AXIS_LEFTX, +thumb_dead_zone, +32767);
MAP_ANALOG(ImGuiNavInput_LStickUp, SDL_CONTROLLER_AXIS_LEFTY, -thumb_dead_zone, -32767);
MAP_ANALOG(ImGuiNavInput_LStickDown, SDL_CONTROLLER_AXIS_LEFTY, +thumb_dead_zone, +32767);
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
MAP_BUTTON(ImGuiKey_GamepadStart, SDL_CONTROLLER_BUTTON_START);
MAP_BUTTON(ImGuiKey_GamepadBack, SDL_CONTROLLER_BUTTON_BACK);
MAP_BUTTON(ImGuiKey_GamepadFaceDown, SDL_CONTROLLER_BUTTON_A); // Xbox A, PS Cross
MAP_BUTTON(ImGuiKey_GamepadFaceRight, SDL_CONTROLLER_BUTTON_B); // Xbox B, PS Circle
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, SDL_CONTROLLER_BUTTON_X); // Xbox X, PS Square
MAP_BUTTON(ImGuiKey_GamepadFaceUp, SDL_CONTROLLER_BUTTON_Y); // Xbox Y, PS Triangle
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
}
@ -513,7 +651,10 @@ void ImGui_ImplSDL2_NewFrame()
SDL_GetWindowSize(bd->Window, &w, &h);
if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_MINIMIZED)
w = h = 0;
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
if (bd->Renderer != NULL)
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);
@ -524,7 +665,7 @@ void ImGui_ImplSDL2_NewFrame()
io.DeltaTime = bd->Time > 0 ? (float)((double)(current_time - bd->Time) / frequency) : (float)(1.0f / 60.0f);
bd->Time = current_time;
ImGui_ImplSDL2_UpdateMousePosAndButtons();
ImGui_ImplSDL2_UpdateMouseData();
ImGui_ImplSDL2_UpdateMouseCursor();
// Update game controllers (if enabled and available)
@ -770,4 +911,5 @@ static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_g
static void ImGui_ImplSDL2_ShutdownPlatformInterface()
{
ImGui::DestroyPlatformWindows();
}

@ -3,10 +3,10 @@
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [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: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
@ -21,12 +21,14 @@
#include "imgui.h" // IMGUI_IMPL_API
struct SDL_Window;
struct SDL_Renderer;
typedef union SDL_Event SDL_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 void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);

@ -0,0 +1,249 @@
// dear imgui: Renderer Backend for SDL_Renderer
// (Requires: SDL 2.0.17+)
// Important to understand: SDL_Renderer is an _optional_ component of SDL.
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
// If your application will want to render any non trivial amount of graphics other than UI,
// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
// be difficult to step out of those boundaries.
// However, we understand it is a convenient choice to get an app started easily.
// Implemented features:
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows).
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
// 2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
// 2021-10-06: Backup and restore modified ClipRect/Viewport.
// 2021-09-21: Initial version.
#include "imgui.h"
#include "imgui_impl_sdlrenderer.h"
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
#include <stddef.h> // intptr_t
#else
#include <stdint.h> // intptr_t
#endif
// SDL
#include <SDL.h>
#if !SDL_VERSION_ATLEAST(2,0,17)
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
#endif
// SDL_Renderer data
struct ImGui_ImplSDLRenderer_Data
{
SDL_Renderer* SDLRenderer;
SDL_Texture* FontTexture;
ImGui_ImplSDLRenderer_Data() { memset(this, 0, sizeof(*this)); }
};
// Backend data stored in io.BackendRendererUserData 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.
static ImGui_ImplSDLRenderer_Data* ImGui_ImplSDLRenderer_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer_Data*)ImGui::GetIO().BackendRendererUserData : NULL;
}
// Functions
bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer)
{
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(io.BackendRendererUserData == NULL && "Already initialized a renderer backend!");
IM_ASSERT(renderer != NULL && "SDL_Renderer not initialized!");
// Setup backend capabilities flags
ImGui_ImplSDLRenderer_Data* bd = IM_NEW(ImGui_ImplSDLRenderer_Data)();
io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_sdlrenderer";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
bd->SDLRenderer = renderer;
return true;
}
void ImGui_ImplSDLRenderer_Shutdown()
{
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDLRenderer_DestroyDeviceObjects();
io.BackendRendererName = NULL;
io.BackendRendererUserData = NULL;
IM_DELETE(bd);
}
static void ImGui_ImplSDLRenderer_SetupRenderState()
{
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
// Clear out any viewports and cliprect set by the user
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
SDL_RenderSetViewport(bd->SDLRenderer, NULL);
SDL_RenderSetClipRect(bd->SDLRenderer, NULL);
}
void ImGui_ImplSDLRenderer_NewFrame()
{
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
IM_ASSERT(bd != NULL && "Did you call ImGui_ImplSDLRenderer_Init()?");
if (!bd->FontTexture)
ImGui_ImplSDLRenderer_CreateDeviceObjects();
}
void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data)
{
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
// If there's a scale factor set by the user, use that instead
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
float rsx = 1.0f;
float rsy = 1.0f;
SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy);
ImVec2 render_scale;
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
if (fb_width == 0 || fb_height == 0)
return;
// Backup SDL_Renderer state that will be modified to restore it afterwards
struct BackupSDLRendererState
{
SDL_Rect Viewport;
bool ClipEnabled;
SDL_Rect ClipRect;
};
BackupSDLRendererState old = {};
old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE;
SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport);
SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect);
// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = render_scale;
// Render command lists
ImGui_ImplSDLRenderer_SetupRenderState();
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
if (pcmd->UserCallback)
{
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplSDLRenderer_SetupRenderState();
else
pcmd->UserCallback(cmd_list, pcmd);
}
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
SDL_RenderSetClipRect(bd->SDLRenderer, &r);
const float* xy = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, pos));
const float* uv = (const float*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, uv));
#if SDL_VERSION_ATLEAST(2,0,19)
const SDL_Color* color = (const SDL_Color*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.19+
#else
const int* color = (const int*)((const char*)(vtx_buffer + pcmd->VtxOffset) + IM_OFFSETOF(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18
#endif
// Bind texture, Draw
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
xy, (int)sizeof(ImDrawVert),
color, (int)sizeof(ImDrawVert),
uv, (int)sizeof(ImDrawVert),
cmd_list->VtxBuffer.Size - pcmd->VtxOffset,
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
}
}
}
// Restore modified SDL_Renderer state
SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport);
SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : NULL);
}
// Called by Init/NewFrame/Shutdown
bool ImGui_ImplSDLRenderer_CreateFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
// Build texture atlas
unsigned char* pixels;
int width, height;
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
// Upload texture to graphics system
bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
if (bd->FontTexture == NULL)
{
SDL_Log("error creating texture");
return false;
}
SDL_UpdateTexture(bd->FontTexture, NULL, pixels, 4 * width);
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
// Store our identifier
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
return true;
}
void ImGui_ImplSDLRenderer_DestroyFontsTexture()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDLRenderer_Data* bd = ImGui_ImplSDLRenderer_GetBackendData();
if (bd->FontTexture)
{
io.Fonts->SetTexID(0);
SDL_DestroyTexture(bd->FontTexture);
bd->FontTexture = NULL;
}
}
bool ImGui_ImplSDLRenderer_CreateDeviceObjects()
{
return ImGui_ImplSDLRenderer_CreateFontsTexture();
}
void ImGui_ImplSDLRenderer_DestroyDeviceObjects()
{
ImGui_ImplSDLRenderer_DestroyFontsTexture();
}

@ -0,0 +1,31 @@
// dear imgui: Renderer Backend for SDL_Renderer
// (Requires: SDL 2.0.17+)
// Important to understand: SDL_Renderer is an _optional_ component of SDL.
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
// If your application will want to render any non trivial amount of graphics other than UI,
// please be aware that SDL_Renderer offers a limited graphic API to the end-user and it might
// be difficult to step out of those boundaries.
// However, we understand it is a convenient choice to get an app started easily.
// Implemented features:
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows).
#pragma once
#include "imgui.h" // IMGUI_IMPL_API
struct SDL_Renderer;
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_Init(SDL_Renderer* renderer);
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_NewFrame();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_RenderDrawData(ImDrawData* draw_data);
// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateFontsTexture();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyFontsTexture();
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer_CreateDeviceObjects();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer_DestroyDeviceObjects();

@ -4,8 +4,15 @@
// Implemented features:
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// [x] Platform: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// Missing features:
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
// This is because we need ImTextureID to carry a 64-bit value and by default ImTextureID is defined as void*.
// To build this on 32-bit systems and support texture changes:
// - [Solution 1] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'ImTextureID=ImU64' (this is what we do in our .vcxproj files)
// - [Solution 2] IDE/msbuild: in "Properties/C++/Preprocessor Definitions" add 'IMGUI_USER_CONFIG="my_imgui_config.h"' and inside 'my_imgui_config.h' add '#define ImTextureID ImU64' and as many other options as you like.
// - [Solution 3] IDE/msbuild: edit imconfig.h and add '#define ImTextureID ImU64' (prefer solution 2 to create your own config file!)
// - [Solution 4] command-line: add '/D ImTextureID=ImU64' to your cl.exe command-line (this is what we do in our batch files)
// 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.
@ -24,7 +31,8 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2021-10-15: Vulkan: Call vkCmdSetScissor() at the end of render a full-viewport to reduce likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling vkCmdSetScissor() explicitly every frame.
// 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: Vulkan: Fix mapped memory validation error when buffer sizes are not multiple of VkPhysicalDeviceLimits::nonCoherentAtomSize.
// 2021-02-18: Vulkan: Change blending equation to preserve alpha in output buffer.
@ -58,6 +66,11 @@
#include "imgui_impl_vulkan.h"
#include <stdio.h>
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant
#endif
// Reusable buffers used for rendering 1 current in-flight frame, for ImGui_ImplVulkan_RenderDrawData()
// [Please zero-clear before use!]
struct ImGui_ImplVulkanH_FrameRenderBuffers
@ -100,7 +113,6 @@ struct ImGui_ImplVulkan_Data
VkPipelineCreateFlags PipelineCreateFlags;
VkDescriptorSetLayout DescriptorSetLayout;
VkPipelineLayout PipelineLayout;
VkDescriptorSet DescriptorSet;
VkPipeline Pipeline;
uint32_t Subpass;
VkShaderModule ShaderModuleVert;
@ -111,6 +123,7 @@ struct ImGui_ImplVulkan_Data
VkDeviceMemory FontMemory;
VkImage FontImage;
VkImageView FontView;
VkDescriptorSet FontDescriptorSet;
VkDeviceMemory UploadBufferMemory;
VkBuffer UploadBuffer;
@ -405,11 +418,9 @@ static void ImGui_ImplVulkan_SetupRenderState(ImDrawData* draw_data, VkPipeline
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
// Bind pipeline and descriptor sets:
// Bind pipeline:
{
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
VkDescriptorSet desc_set[1] = { bd->DescriptorSet };
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, NULL);
}
// Bind Vertex And Index Buffer:
@ -543,36 +554,52 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm
else
{
// Project scissor/clipping rectangles into framebuffer space
ImVec4 clip_rect;
clip_rect.x = (pcmd->ClipRect.x - clip_off.x) * clip_scale.x;
clip_rect.y = (pcmd->ClipRect.y - clip_off.y) * clip_scale.y;
clip_rect.z = (pcmd->ClipRect.z - clip_off.x) * clip_scale.x;
clip_rect.w = (pcmd->ClipRect.w - clip_off.y) * clip_scale.y;
if (clip_rect.x < fb_width && clip_rect.y < fb_height && clip_rect.z >= 0.0f && clip_rect.w >= 0.0f)
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
// Clamp to viewport as vkCmdSetScissor() won't accept values that are off bounds
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
if (clip_max.x > fb_width) { clip_max.x = (float)fb_width; }
if (clip_max.y > fb_height) { clip_max.y = (float)fb_height; }
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle
VkRect2D scissor;
scissor.offset.x = (int32_t)(clip_min.x);
scissor.offset.y = (int32_t)(clip_min.y);
scissor.extent.width = (uint32_t)(clip_max.x - clip_min.x);
scissor.extent.height = (uint32_t)(clip_max.y - clip_min.y);
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
// Bind DescriptorSet with font or user texture
VkDescriptorSet desc_set[1] = { (VkDescriptorSet)pcmd->TextureId };
if (sizeof(ImTextureID) < sizeof(ImU64))
{
// Negative offsets are illegal for vkCmdSetScissor
if (clip_rect.x < 0.0f)
clip_rect.x = 0.0f;
if (clip_rect.y < 0.0f)
clip_rect.y = 0.0f;
// Apply scissor/clipping rectangle
VkRect2D scissor;
scissor.offset.x = (int32_t)(clip_rect.x);
scissor.offset.y = (int32_t)(clip_rect.y);
scissor.extent.width = (uint32_t)(clip_rect.z - clip_rect.x);
scissor.extent.height = (uint32_t)(clip_rect.w - clip_rect.y);
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
// We don't support texture switches if ImTextureID hasn't been redefined to be 64-bit. Do a flaky check that other textures haven't been used.
IM_ASSERT(pcmd->TextureId == (ImTextureID)bd->FontDescriptorSet);
desc_set[0] = bd->FontDescriptorSet;
}
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, bd->PipelineLayout, 0, 1, desc_set, 0, NULL);
// Draw
vkCmdDrawIndexed(command_buffer, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
}
global_idx_offset += cmd_list->IdxBuffer.Size;
global_vtx_offset += cmd_list->VtxBuffer.Size;
}
// Note: at this point both vkCmdSetViewport() and vkCmdSetScissor() have been called.
// Our last values will leak into user/application rendering IF:
// - Your app uses a pipeline with VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR dynamic state
// - And you forgot to call vkCmdSetViewport() and vkCmdSetScissor() yourself to explicitely set that state.
// If you use VK_DYNAMIC_STATE_VIEWPORT or VK_DYNAMIC_STATE_SCISSOR you are responsible for setting the values before rendering.
// In theory we should aim to backup/restore those values but I am not sure this is possible.
// We perform a call to vkCmdSetScissor() to set back a full viewport which is likely to fix things for 99% users but technically this is not perfect. (See github #4644)
VkRect2D scissor = { { 0, 0 }, { (uint32_t)fb_width, (uint32_t)fb_height } };
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
}
bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
@ -632,20 +659,8 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
check_vk_result(err);
}
// Update the Descriptor Set:
{
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = bd->FontSampler;
desc_image[0].imageView = bd->FontView;
desc_image[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = bd->DescriptorSet;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
// Create the Descriptor Set:
bd->FontDescriptorSet = (VkDescriptorSet)ImGui_ImplVulkan_AddTexture(bd->FontSampler, bd->FontView, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
// Create the Upload Buffer:
{
@ -723,7 +738,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer)
}
// Store our identifier
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontImage);
io.Fonts->SetTexID((ImTextureID)bd->FontDescriptorSet);
return true;
}
@ -732,7 +747,7 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca
{
// Create the shader modules
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
if (bd->ShaderModuleVert == NULL)
if (bd->ShaderModuleVert == VK_NULL_HANDLE)
{
VkShaderModuleCreateInfo vert_info = {};
vert_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
@ -741,7 +756,7 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca
VkResult err = vkCreateShaderModule(device, &vert_info, allocator, &bd->ShaderModuleVert);
check_vk_result(err);
}
if (bd->ShaderModuleFrag == NULL)
if (bd->ShaderModuleFrag == VK_NULL_HANDLE)
{
VkShaderModuleCreateInfo frag_info = {};
frag_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
@ -962,17 +977,6 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
check_vk_result(err);
}
// Create Descriptor Set:
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayout;
err = vkAllocateDescriptorSets(v->Device, &alloc_info, &bd->DescriptorSet);
check_vk_result(err);
}
if (!bd->PipelineLayout)
{
// Constants: we are using 'vec2 offset' and 'vec2 scale' instead of a full 3d projection matrix
@ -1092,8 +1096,9 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass rend
void ImGui_ImplVulkan_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
IM_ASSERT(bd != NULL && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
// First destroy objects in all viewports
ImGui_ImplVulkan_DestroyDeviceObjects();
@ -1135,6 +1140,41 @@ void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count)
bd->VulkanInitInfo.MinImageCount = min_image_count;
}
// Register a texture
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout)
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
// Create Descriptor Set:
VkDescriptorSet descriptor_set;
{
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = v->DescriptorPool;
alloc_info.descriptorSetCount = 1;
alloc_info.pSetLayouts = &bd->DescriptorSetLayout;
VkResult err = vkAllocateDescriptorSets(v->Device, &alloc_info, &descriptor_set);
check_vk_result(err);
}
// Update the Descriptor Set:
{
VkDescriptorImageInfo desc_image[1] = {};
desc_image[0].sampler = sampler;
desc_image[0].imageView = image_view;
desc_image[0].imageLayout = image_layout;
VkWriteDescriptorSet write_desc[1] = {};
write_desc[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_desc[0].dstSet = descriptor_set;
write_desc[0].descriptorCount = 1;
write_desc[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write_desc[0].pImageInfo = desc_image;
vkUpdateDescriptorSets(v->Device, 1, write_desc, 0, NULL);
}
return descriptor_set;
}
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers
@ -1284,7 +1324,7 @@ void ImGui_ImplVulkanH_CreateWindowSwapChain(VkPhysicalDevice physical_device, V
{
VkResult err;
VkSwapchainKHR old_swapchain = wd->Swapchain;
wd->Swapchain = NULL;
wd->Swapchain = VK_NULL_HANDLE;
err = vkDeviceWaitIdle(device);
check_vk_result(err);

@ -3,9 +3,11 @@
// Implemented features:
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// Missing features:
// [ ] Platform: Multi-viewport / platform windows.
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this backend! See https://github.com/ocornut/imgui/pull/914
// [x] Platform: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// [!] Renderer: User texture binding. Use 'VkDescriptorSet' as ImTextureID. Read the FAQ about ImTextureID! See https://github.com/ocornut/imgui/pull/914 for discussions.
// Important: on 32-bit systems, user texture binding is only supported if your imconfig file has '#define ImTextureID ImU64'.
// See imgui_impl_vulkan.cpp file for details.
// 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.
@ -57,23 +59,27 @@ struct ImGui_ImplVulkan_InitInfo
uint32_t Subpass;
uint32_t MinImageCount; // >= 2
uint32_t ImageCount; // >= MinImageCount
VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT
VkSampleCountFlagBits MSAASamples; // >= VK_SAMPLE_COUNT_1_BIT (0 -> default to VK_SAMPLE_COUNT_1_BIT)
const VkAllocationCallbacks* Allocator;
void (*CheckVkResultFn)(VkResult err);
};
// Called by user code
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info, VkRenderPass render_pass);
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
IMGUI_IMPL_API bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer);
IMGUI_IMPL_API void ImGui_ImplVulkan_DestroyFontUploadObjects();
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
// Register a texture (VkDescriptorSet == ImTextureID)
// FIXME: This is experimental in the sense that we are unsure how to best design/tackle this problem, please post to https://github.com/ocornut/imgui/pull/914 if you have suggestions.
IMGUI_IMPL_API VkDescriptorSet ImGui_ImplVulkan_AddTexture(VkSampler sampler, VkImageView image_view, VkImageLayout image_layout);
// Optional: load Vulkan functions with a custom function loader
// This is only useful with IMGUI_IMPL_VULKAN_NO_PROTOTYPES / VK_NO_PROTOTYPES
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL);
IMGUI_IMPL_API bool ImGui_ImplVulkan_LoadFunctions(PFN_vkVoidFunction(*loader_func)(const char* function_name, void* user_data), void* user_data = NULL);
//-------------------------------------------------------------------------
// Internal / Miscellaneous Vulkan Helpers

@ -6,13 +6,15 @@
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bit indices.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-11-29: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer()/wgpuRenderPassEncoderSetIndexBuffer().
// 2021-08-24: Fix for latest specs.
// 2021-05-24: Add support for draw_data->FramebufferScale.
// 2021-05-19: Replaced direct access to ImDrawCmd::TextureId with a call to ImDrawCmd::GetTexID(). (will become a requirement)
// 2021-05-16: Update to latest WebGPU specs (compatible with Emscripten 2.0.20 and Chrome Canary 92).
@ -269,7 +271,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(uint32_
spirv_desc.codeSize = binary_data_size;
spirv_desc.code = binary_data;
WGPUShaderModuleDescriptor desc;
WGPUShaderModuleDescriptor desc = {};
desc.nextInChain = reinterpret_cast<WGPUChainedStruct*>(&spirv_desc);
WGPUProgrammableStageDescriptor stage_desc = {};
@ -280,7 +282,7 @@ static WGPUProgrammableStageDescriptor ImGui_ImplWGPU_CreateShaderModule(uint32_
static WGPUBindGroup ImGui_ImplWGPU_CreateImageBindGroup(WGPUBindGroupLayout layout, WGPUTextureView texture)
{
WGPUBindGroupEntry image_bg_entries[] = { { 0, 0, 0, 0, 0, texture } };
WGPUBindGroupEntry image_bg_entries[] = { { nullptr, 0, 0, 0, 0, 0, texture } };
WGPUBindGroupDescriptor image_bg_descriptor = {};
image_bg_descriptor.layout = layout;
@ -312,8 +314,8 @@ static void ImGui_ImplWGPU_SetupRenderState(ImDrawData* draw_data, WGPURenderPas
wgpuRenderPassEncoderSetViewport(ctx, 0, 0, draw_data->FramebufferScale.x * draw_data->DisplaySize.x, draw_data->FramebufferScale.y * draw_data->DisplaySize.y, 0, 1);
// Bind shader and vertex buffers
wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, 0);
wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, 0);
wgpuRenderPassEncoderSetVertexBuffer(ctx, 0, fr->VertexBuffer, 0, fr->VertexBufferSize * sizeof(ImDrawVert));
wgpuRenderPassEncoderSetIndexBuffer(ctx, fr->IndexBuffer, sizeof(ImDrawIdx) == 2 ? WGPUIndexFormat_Uint16 : WGPUIndexFormat_Uint32, 0, fr->IndexBufferSize * sizeof(ImDrawIdx));
wgpuRenderPassEncoderSetPipeline(ctx, g_pipelineState);
wgpuRenderPassEncoderSetBindGroup(ctx, 0, g_resources.CommonBindGroup, 0, NULL);
@ -442,13 +444,14 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, image_bind_group, 0, NULL);
}
// Apply Scissor, Bind texture, Draw
uint32_t clip_rect[4];
clip_rect[0] = (uint32_t)(clip_scale.x * (pcmd->ClipRect.x - clip_off.x));
clip_rect[1] = (uint32_t)(clip_scale.y * (pcmd->ClipRect.y - clip_off.y));
clip_rect[2] = (uint32_t)(clip_scale.x * (pcmd->ClipRect.z - clip_off.x));
clip_rect[3] = (uint32_t)(clip_scale.y * (pcmd->ClipRect.w - clip_off.y));
wgpuRenderPassEncoderSetScissorRect(pass_encoder, clip_rect[0], clip_rect[1], clip_rect[2] - clip_rect[0], clip_rect[3] - clip_rect[1]);
// Project scissor/clipping rectangles into framebuffer space
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
continue;
// Apply scissor/clipping rectangle, Draw
wgpuRenderPassEncoderSetScissorRect(pass_encoder, (uint32_t)clip_min.x, (uint32_t)clip_min.y, (uint32_t)(clip_max.x - clip_min.x), (uint32_t)(clip_max.y - clip_min.y));
wgpuRenderPassEncoderDrawIndexed(pass_encoder, pcmd->ElemCount, 1, pcmd->IdxOffset + global_idx_offset, pcmd->VtxOffset + global_vtx_offset, 0);
}
}
@ -476,7 +479,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture()
tex_desc.sampleCount = 1;
tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
tex_desc.mipLevelCount = 1;
tex_desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_Sampled;
tex_desc.usage = WGPUTextureUsage_CopyDst | WGPUTextureUsage_TextureBinding;
g_resources.FontTexture = wgpuDeviceCreateTexture(g_wgpuDevice, &tex_desc);
WGPUTextureViewDescriptor tex_view_desc = {};
@ -544,7 +547,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
ImGui_ImplWGPU_InvalidateDeviceObjects();
// Create render pipeline
WGPURenderPipelineDescriptor2 graphics_pipeline_desc = {};
WGPURenderPipelineDescriptor graphics_pipeline_desc = {};
graphics_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
graphics_pipeline_desc.primitive.stripIndexFormat = WGPUIndexFormat_Undefined;
graphics_pipeline_desc.primitive.frontFace = WGPUFrontFace_CW;
@ -569,7 +572,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
WGPUVertexBufferLayout buffer_layouts[1];
buffer_layouts[0].arrayStride = sizeof(ImDrawVert);
buffer_layouts[0].stepMode = WGPUInputStepMode_Vertex;
buffer_layouts[0].stepMode = WGPUVertexStepMode_Vertex;
buffer_layouts[0].attributeCount = 3;
buffer_layouts[0].attributes = attribute_desc;
@ -610,7 +613,7 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
// Configure disabled depth-stencil state
graphics_pipeline_desc.depthStencil = nullptr;
g_pipelineState = wgpuDeviceCreateRenderPipeline2(g_wgpuDevice, &graphics_pipeline_desc);
g_pipelineState = wgpuDeviceCreateRenderPipeline(g_wgpuDevice, &graphics_pipeline_desc);
ImGui_ImplWGPU_CreateFontsTexture();
ImGui_ImplWGPU_CreateUniformBuffer();
@ -622,8 +625,8 @@ bool ImGui_ImplWGPU_CreateDeviceObjects()
WGPUBindGroupEntry common_bg_entries[] =
{
{ 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 },
{ 1, 0, 0, 0, g_resources.Sampler, 0 },
{ nullptr, 0, g_resources.Uniforms, 0, sizeof(Uniforms), 0, 0 },
{ nullptr, 1, 0, 0, 0, g_resources.Sampler, 0 },
};
WGPUBindGroupDescriptor common_bg_descriptor = {};

@ -3,9 +3,9 @@
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
// [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 VK_* 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: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
@ -19,6 +19,7 @@
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <windowsx.h> // GET_X_LPARAM(), GET_Y_LPARAM()
#include <tchar.h>
#include <dwmapi.h>
@ -34,9 +35,17 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*);
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2022-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 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 a key event (not in NewFrame) to fix input queue with very low framerates.
// 2022-01-12: Inputs: Update mouse inputs using WM_MOUSEMOVE/WM_MOUSELEAVE + 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: Inputs: 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-12-16: Inputs: Fill VK_LCONTROL/VK_RCONTROL/VK_LSHIFT/VK_RSHIFT/VK_LMENU/VK_RMENU for completeness.
// 2021-08-17: Calling io.AddFocusEvent() on WM_SETFOCUS/WM_KILLFOCUS messages.
// 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host windo doesn't have focus.
// 2021-08-02: Inputs: Fixed keyboard modifiers being reported when host window doesn't have focus.
// 2021-07-29: Inputs: MousePos is correctly reported when the host platform window is hovered but not focused (using TrackMouseEvent() to receive WM_MOUSELEAVE events).
// 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-06-08: Fixed ImGui_ImplWin32_EnableDpiAwareness() and ImGui_ImplWin32_GetDpiScaleForMonitor() to handle Windows 8.1/10 features without a manifest (per-monitor DPI, and properly calls SetProcessDpiAwareness() on 8.1).
@ -79,6 +88,7 @@ struct ImGui_ImplWin32_Data
HWND hWnd;
HWND MouseHwnd;
bool MouseTracked;
int MouseButtonsDown;
INT64 Time;
INT64 TicksPerSecond;
ImGuiMouseCursor LastMouseCursor;
@ -123,7 +133,7 @@ bool ImGui_ImplWin32_Init(void* hwnd)
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used)
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can set io.MouseHoveredViewport correctly (optional, not easy)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport; // We can call io.AddMouseViewportEvent() with correct data (optional)
bd->hWnd = (HWND)hwnd;
bd->WantUpdateHasGamepad = true;
@ -138,30 +148,6 @@ bool ImGui_ImplWin32_Init(void* hwnd)
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplWin32_InitPlatformInterface();
// Keyboard mapping. Dear ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
io.KeyMap[ImGuiKey_Tab] = VK_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = VK_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = VK_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = VK_UP;
io.KeyMap[ImGuiKey_DownArrow] = VK_DOWN;
io.KeyMap[ImGuiKey_PageUp] = VK_PRIOR;
io.KeyMap[ImGuiKey_PageDown] = VK_NEXT;
io.KeyMap[ImGuiKey_Home] = VK_HOME;
io.KeyMap[ImGuiKey_End] = VK_END;
io.KeyMap[ImGuiKey_Insert] = VK_INSERT;
io.KeyMap[ImGuiKey_Delete] = VK_DELETE;
io.KeyMap[ImGuiKey_Backspace] = VK_BACK;
io.KeyMap[ImGuiKey_Space] = VK_SPACE;
io.KeyMap[ImGuiKey_Enter] = VK_RETURN;
io.KeyMap[ImGuiKey_Escape] = VK_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = VK_RETURN;
io.KeyMap[ImGuiKey_A] = 'A';
io.KeyMap[ImGuiKey_C] = 'C';
io.KeyMap[ImGuiKey_V] = 'V';
io.KeyMap[ImGuiKey_X] = 'X';
io.KeyMap[ImGuiKey_Y] = 'Y';
io.KeyMap[ImGuiKey_Z] = 'Z';
// Dynamically load XInput library
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
const char* xinput_dll_names[] =
@ -187,8 +173,10 @@ bool ImGui_ImplWin32_Init(void* hwnd)
void ImGui_ImplWin32_Shutdown()
{
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
IM_ASSERT(bd != NULL && "No platform backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplWin32_ShutdownPlatformInterface();
// Unload XInput library
@ -235,68 +223,95 @@ static bool ImGui_ImplWin32_UpdateMouseCursor()
return true;
}
static bool IsVkDown(int vk)
{
return (::GetKeyState(vk) & 0x8000) != 0;
}
static void ImGui_ImplWin32_AddKeyEvent(ImGuiKey key, bool down, int native_keycode, int native_scancode = -1)
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(key, down);
io.SetKeyEventNativeData(key, native_keycode, native_scancode); // To support legacy indexing (<1.87 user code)
IM_UNUSED(native_scancode);
}
static void ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
{
// Left & right Shift keys: when both are pressed together, Windows tend to not generate the WM_KEYUP event for the first released one.
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) && !IsVkDown(VK_LSHIFT))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, false, VK_LSHIFT);
if (ImGui::IsKeyDown(ImGuiKey_RightShift) && !IsVkDown(VK_RSHIFT))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, false, VK_RSHIFT);
// Sometimes WM_KEYUP for Win key is not passed down to the app (e.g. for Win+V on some setups, according to GLFW).
if (ImGui::IsKeyDown(ImGuiKey_LeftSuper) && !IsVkDown(VK_LWIN))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftSuper, false, VK_LWIN);
if (ImGui::IsKeyDown(ImGuiKey_RightSuper) && !IsVkDown(VK_RWIN))
ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightSuper, false, VK_RWIN);
}
static void ImGui_ImplWin32_UpdateKeyModifiers()
{
ImGuiIO& io = ImGui::GetIO();
io.AddKeyEvent(ImGuiKey_ModCtrl, IsVkDown(VK_CONTROL));
io.AddKeyEvent(ImGuiKey_ModShift, IsVkDown(VK_SHIFT));
io.AddKeyEvent(ImGuiKey_ModAlt, IsVkDown(VK_MENU));
io.AddKeyEvent(ImGuiKey_ModSuper, IsVkDown(VK_APPS));
}
// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
// Because of that, it is a little more complicated than your typical single-viewport binding code!
static void ImGui_ImplWin32_UpdateMousePos()
static void ImGui_ImplWin32_UpdateMouseData()
{
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
ImGuiIO& io = ImGui::GetIO();
IM_ASSERT(bd->hWnd != 0);
const ImVec2 mouse_pos_prev = io.MousePos;
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
io.MouseHoveredViewport = 0;
POINT mouse_screen_pos;
bool has_mouse_screen_pos = ::GetCursorPos(&mouse_screen_pos) != 0;
// Obtain focused and hovered window. We forward mouse input when focused or when hovered (and no other window is capturing)
HWND focused_window = ::GetForegroundWindow();
HWND hovered_window = bd->MouseHwnd;
HWND mouse_window = NULL;
if (hovered_window && (hovered_window == bd->hWnd || ::IsChild(hovered_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)hovered_window)))
mouse_window = hovered_window;
else if (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)focused_window)))
mouse_window = focused_window;
if (mouse_window == NULL)
return;
// Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
// (When multi-viewports are enabled, all Dear ImGui positions are same as OS positions)
if (io.WantSetMousePos)
const bool is_app_focused = (focused_window && (focused_window == bd->hWnd || ::IsChild(focused_window, bd->hWnd) || ImGui::FindViewportByPlatformHandle((void*)focused_window)));
if (is_app_focused)
{
POINT pos = { (int)mouse_pos_prev.x, (int)mouse_pos_prev.y };
if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
::ClientToScreen(mouse_window, &pos);
::SetCursorPos(pos.x, pos.y);
}
// (Optional) Set OS mouse position from Dear ImGui if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
// When multi-viewports are enabled, all Dear ImGui positions are same as OS positions.
if (io.WantSetMousePos)
{
POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
if ((io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) == 0)
::ClientToScreen(focused_window, &pos);
::SetCursorPos(pos.x, pos.y);
}
// Set Dear ImGui mouse position from OS position
POINT mouse_screen_pos;
if (!::GetCursorPos(&mouse_screen_pos))
return;
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
// This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same.
io.MousePos = ImVec2((float)mouse_screen_pos.x, (float)mouse_screen_pos.y);
}
else
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
// This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.
POINT mouse_client_pos = mouse_screen_pos;
::ScreenToClient(bd->hWnd, &mouse_client_pos);
io.MousePos = ImVec2((float)mouse_client_pos.x, (float)mouse_client_pos.y);
// (Optional) Fallback to provide mouse position when focused (WM_MOUSEMOVE already provides this when hovered or captured)
if (!io.WantSetMousePos && !bd->MouseTracked && has_mouse_screen_pos)
{
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window)
// (This is the position you can get with ::GetCursorPos() + ::ScreenToClient() or WM_MOUSEMOVE.)
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
// (This is the position you can get with ::GetCursorPos() or WM_MOUSEMOVE + ::ClientToScreen(). In theory adding viewport->Pos to a client position would also be the same.)
POINT mouse_pos = mouse_screen_pos;
if (!(io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable))
::ScreenToClient(bd->hWnd, &mouse_pos);
io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
}
}
// (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
// Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
// - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
// - This is _regardless_ of whether another viewport is focused or being dragged from.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, imgui will ignore this field and infer the information by relying on the
// rectangles and last focused time of every viewports it knows about. It will be unaware of foreign windows that may be sitting between or over your windows.
if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd))
if ((viewport->Flags & ImGuiViewportFlags_NoInputs) == 0) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated?
io.MouseHoveredViewport = viewport->ID;
// (Optional) When using multiple viewports: call io.AddMouseViewportEvent() with the viewport the OS mouse cursor is hovering.
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, Dear imGui will ignore this field and infer the information using its flawed heuristic.
// - [X] Win32 backend correctly ignore viewports with the _NoInputs flag (here using ::WindowFromPoint with WM_NCHITTEST + HTTRANSPARENT in WndProc does that)
// Some backend are not able to handle that correctly. If a backend report an hovered viewport that has the _NoInputs flag (e.g. when dragging a window
// for docking, the viewport has the _NoInputs flag in order to allow us to find the viewport under), then Dear ImGui is forced to ignore the value reported
// by the backend, and use its flawed heuristic to guess the viewport behind.
// - [X] Win32 backend correctly reports this regardless of another viewport behind focused and dragged from (we need this to find a useful drag and drop target).
ImGuiID mouse_viewport_id = 0;
if (has_mouse_screen_pos)
if (HWND hovered_hwnd = ::WindowFromPoint(mouse_screen_pos))
if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)hovered_hwnd))
mouse_viewport_id = viewport->ID;
io.AddMouseViewportEvent(mouse_viewport_id);
}
// Gamepad navigation mapping
@ -305,7 +320,6 @@ static void ImGui_ImplWin32_UpdateGamepads()
#ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
ImGuiIO& io = ImGui::GetIO();
ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData();
memset(io.NavInputs, 0, sizeof(io.NavInputs));
if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) == 0)
return;
@ -313,39 +327,47 @@ static void ImGui_ImplWin32_UpdateGamepads()
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
if (bd->WantUpdateHasGamepad)
{
XINPUT_CAPABILITIES caps;
XINPUT_CAPABILITIES caps = {};
bd->HasGamepad = bd->XInputGetCapabilities ? (bd->XInputGetCapabilities(0, XINPUT_FLAG_GAMEPAD, &caps) == ERROR_SUCCESS) : false;
bd->WantUpdateHasGamepad = false;
}
io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad;
XINPUT_STATE xinput_state;
if (bd->HasGamepad && bd->XInputGetState && bd->XInputGetState(0, &xinput_state) == ERROR_SUCCESS)
{
const XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
#define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
#define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
MAP_BUTTON(ImGuiNavInput_Activate, XINPUT_GAMEPAD_A); // Cross / A
MAP_BUTTON(ImGuiNavInput_Cancel, XINPUT_GAMEPAD_B); // Circle / B
MAP_BUTTON(ImGuiNavInput_Menu, XINPUT_GAMEPAD_X); // Square / X
MAP_BUTTON(ImGuiNavInput_Input, XINPUT_GAMEPAD_Y); // Triangle / Y
MAP_BUTTON(ImGuiNavInput_DpadLeft, XINPUT_GAMEPAD_DPAD_LEFT); // D-Pad Left
MAP_BUTTON(ImGuiNavInput_DpadRight, XINPUT_GAMEPAD_DPAD_RIGHT); // D-Pad Right
MAP_BUTTON(ImGuiNavInput_DpadUp, XINPUT_GAMEPAD_DPAD_UP); // D-Pad Up
MAP_BUTTON(ImGuiNavInput_DpadDown, XINPUT_GAMEPAD_DPAD_DOWN); // D-Pad Down
MAP_BUTTON(ImGuiNavInput_FocusPrev, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_FocusNext, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
MAP_BUTTON(ImGuiNavInput_TweakSlow, XINPUT_GAMEPAD_LEFT_SHOULDER); // L1 / LB
MAP_BUTTON(ImGuiNavInput_TweakFast, XINPUT_GAMEPAD_RIGHT_SHOULDER); // R1 / RB
MAP_ANALOG(ImGuiNavInput_LStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiNavInput_LStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiNavInput_LStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiNavInput_LStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32767);
#undef MAP_BUTTON
#undef MAP_ANALOG
}
XINPUT_GAMEPAD& gamepad = xinput_state.Gamepad;
if (!bd->HasGamepad || bd->XInputGetState == NULL || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS)
return;
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
#define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V)
#define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); }
#define MAP_ANALOG(KEY_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); io.AddKeyAnalogEvent(KEY_NO, vn > 0.10f, IM_SATURATE(vn)); }
MAP_BUTTON(ImGuiKey_GamepadStart, XINPUT_GAMEPAD_START);
MAP_BUTTON(ImGuiKey_GamepadBack, XINPUT_GAMEPAD_BACK);
MAP_BUTTON(ImGuiKey_GamepadFaceDown, XINPUT_GAMEPAD_A);
MAP_BUTTON(ImGuiKey_GamepadFaceRight, XINPUT_GAMEPAD_B);
MAP_BUTTON(ImGuiKey_GamepadFaceLeft, XINPUT_GAMEPAD_X);
MAP_BUTTON(ImGuiKey_GamepadFaceUp, XINPUT_GAMEPAD_Y);
MAP_BUTTON(ImGuiKey_GamepadDpadLeft, XINPUT_GAMEPAD_DPAD_LEFT);
MAP_BUTTON(ImGuiKey_GamepadDpadRight, XINPUT_GAMEPAD_DPAD_RIGHT);
MAP_BUTTON(ImGuiKey_GamepadDpadUp, XINPUT_GAMEPAD_DPAD_UP);
MAP_BUTTON(ImGuiKey_GamepadDpadDown, XINPUT_GAMEPAD_DPAD_DOWN);
MAP_BUTTON(ImGuiKey_GamepadL1, XINPUT_GAMEPAD_LEFT_SHOULDER);
MAP_BUTTON(ImGuiKey_GamepadR1, XINPUT_GAMEPAD_RIGHT_SHOULDER);
MAP_ANALOG(ImGuiKey_GamepadL2, gamepad.bLeftTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
MAP_ANALOG(ImGuiKey_GamepadR2, gamepad.bRightTrigger, XINPUT_GAMEPAD_TRIGGER_THRESHOLD, 255);
MAP_BUTTON(ImGuiKey_GamepadL3, XINPUT_GAMEPAD_LEFT_THUMB);
MAP_BUTTON(ImGuiKey_GamepadR3, XINPUT_GAMEPAD_RIGHT_THUMB);
MAP_ANALOG(ImGuiKey_GamepadLStickLeft, gamepad.sThumbLX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadLStickRight, gamepad.sThumbLX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickUp, gamepad.sThumbLY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadLStickDown, gamepad.sThumbLY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickLeft, gamepad.sThumbRX, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
MAP_ANALOG(ImGuiKey_GamepadRStickRight, gamepad.sThumbRX, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickUp, gamepad.sThumbRY, +XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, +32767);
MAP_ANALOG(ImGuiKey_GamepadRStickDown, gamepad.sThumbRY, -XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, -32768);
#undef MAP_BUTTON
#undef MAP_ANALOG
#endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
}
@ -397,7 +419,10 @@ void ImGui_ImplWin32_NewFrame()
bd->Time = current_time;
// Update OS mouse position
ImGui_ImplWin32_UpdateMousePos();
ImGui_ImplWin32_UpdateMouseData();
// Process workarounds for known Windows key handling issues
ImGui_ImplWin32_ProcessKeyEventsWorkarounds();
// Update OS mouse cursor with the cursor requested by imgui
ImGuiMouseCursor mouse_cursor = io.MouseDrawCursor ? ImGuiMouseCursor_None : ImGui::GetMouseCursor();
@ -411,6 +436,122 @@ void ImGui_ImplWin32_NewFrame()
ImGui_ImplWin32_UpdateGamepads();
}
// There is no distinct VK_xxx for keypad enter, instead it is VK_RETURN + KF_EXTENDED, we assign it an arbitrary value to make code more readable (VK_ codes go up to 255)
#define IM_VK_KEYPAD_ENTER (VK_RETURN + 256)
// Map VK_xxx to ImGuiKey_xxx.
static ImGuiKey ImGui_ImplWin32_VirtualKeyToImGuiKey(WPARAM wParam)
{
switch (wParam)
{
case VK_TAB: return ImGuiKey_Tab;
case VK_LEFT: return ImGuiKey_LeftArrow;
case VK_RIGHT: return ImGuiKey_RightArrow;
case VK_UP: return ImGuiKey_UpArrow;
case VK_DOWN: return ImGuiKey_DownArrow;
case VK_PRIOR: return ImGuiKey_PageUp;
case VK_NEXT: return ImGuiKey_PageDown;
case VK_HOME: return ImGuiKey_Home;
case VK_END: return ImGuiKey_End;
case VK_INSERT: return ImGuiKey_Insert;
case VK_DELETE: return ImGuiKey_Delete;
case VK_BACK: return ImGuiKey_Backspace;
case VK_SPACE: return ImGuiKey_Space;
case VK_RETURN: return ImGuiKey_Enter;
case VK_ESCAPE: return ImGuiKey_Escape;
case VK_OEM_7: return ImGuiKey_Apostrophe;
case VK_OEM_COMMA: return ImGuiKey_Comma;
case VK_OEM_MINUS: return ImGuiKey_Minus;
case VK_OEM_PERIOD: return ImGuiKey_Period;
case VK_OEM_2: return ImGuiKey_Slash;
case VK_OEM_1: return ImGuiKey_Semicolon;
case VK_OEM_PLUS: return ImGuiKey_Equal;
case VK_OEM_4: return ImGuiKey_LeftBracket;
case VK_OEM_5: return ImGuiKey_Backslash;
case VK_OEM_6: return ImGuiKey_RightBracket;
case VK_OEM_3: return ImGuiKey_GraveAccent;
case VK_CAPITAL: return ImGuiKey_CapsLock;
case VK_SCROLL: return ImGuiKey_ScrollLock;
case VK_NUMLOCK: return ImGuiKey_NumLock;
case VK_SNAPSHOT: return ImGuiKey_PrintScreen;
case VK_PAUSE: return ImGuiKey_Pause;
case VK_NUMPAD0: return ImGuiKey_Keypad0;
case VK_NUMPAD1: return ImGuiKey_Keypad1;
case VK_NUMPAD2: return ImGuiKey_Keypad2;
case VK_NUMPAD3: return ImGuiKey_Keypad3;
case VK_NUMPAD4: return ImGuiKey_Keypad4;
case VK_NUMPAD5: return ImGuiKey_Keypad5;
case VK_NUMPAD6: return ImGuiKey_Keypad6;
case VK_NUMPAD7: return ImGuiKey_Keypad7;
case VK_NUMPAD8: return ImGuiKey_Keypad8;
case VK_NUMPAD9: return ImGuiKey_Keypad9;
case VK_DECIMAL: return ImGuiKey_KeypadDecimal;
case VK_DIVIDE: return ImGuiKey_KeypadDivide;
case VK_MULTIPLY: return ImGuiKey_KeypadMultiply;
case VK_SUBTRACT: return ImGuiKey_KeypadSubtract;
case VK_ADD: return ImGuiKey_KeypadAdd;
case IM_VK_KEYPAD_ENTER: return ImGuiKey_KeypadEnter;
case VK_LSHIFT: return ImGuiKey_LeftShift;
case VK_LCONTROL: return ImGuiKey_LeftCtrl;
case VK_LMENU: return ImGuiKey_LeftAlt;
case VK_LWIN: return ImGuiKey_LeftSuper;
case VK_RSHIFT: return ImGuiKey_RightShift;
case VK_RCONTROL: return ImGuiKey_RightCtrl;
case VK_RMENU: return ImGuiKey_RightAlt;
case VK_RWIN: return ImGuiKey_RightSuper;
case VK_APPS: return ImGuiKey_Menu;
case '0': return ImGuiKey_0;
case '1': return ImGuiKey_1;
case '2': return ImGuiKey_2;
case '3': return ImGuiKey_3;
case '4': return ImGuiKey_4;
case '5': return ImGuiKey_5;
case '6': return ImGuiKey_6;
case '7': return ImGuiKey_7;
case '8': return ImGuiKey_8;
case '9': return ImGuiKey_9;
case 'A': return ImGuiKey_A;
case 'B': return ImGuiKey_B;
case 'C': return ImGuiKey_C;
case 'D': return ImGuiKey_D;
case 'E': return ImGuiKey_E;
case 'F': return ImGuiKey_F;
case 'G': return ImGuiKey_G;
case 'H': return ImGuiKey_H;
case 'I': return ImGuiKey_I;
case 'J': return ImGuiKey_J;
case 'K': return ImGuiKey_K;
case 'L': return ImGuiKey_L;
case 'M': return ImGuiKey_M;
case 'N': return ImGuiKey_N;
case 'O': return ImGuiKey_O;
case 'P': return ImGuiKey_P;
case 'Q': return ImGuiKey_Q;
case 'R': return ImGuiKey_R;
case 'S': return ImGuiKey_S;
case 'T': return ImGuiKey_T;
case 'U': return ImGuiKey_U;
case 'V': return ImGuiKey_V;
case 'W': return ImGuiKey_W;
case 'X': return ImGuiKey_X;
case 'Y': return ImGuiKey_Y;
case 'Z': return ImGuiKey_Z;
case VK_F1: return ImGuiKey_F1;
case VK_F2: return ImGuiKey_F2;
case VK_F3: return ImGuiKey_F3;
case VK_F4: return ImGuiKey_F4;
case VK_F5: return ImGuiKey_F5;
case VK_F6: return ImGuiKey_F6;
case VK_F7: return ImGuiKey_F7;
case VK_F8: return ImGuiKey_F8;
case VK_F9: return ImGuiKey_F9;
case VK_F10: return ImGuiKey_F10;
case VK_F11: return ImGuiKey_F11;
case VK_F12: return ImGuiKey_F12;
default: return ImGuiKey_None;
}
}
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
#ifndef WM_MOUSEHWHEEL
#define WM_MOUSEHWHEEL 0x020E
@ -442,6 +583,7 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
switch (msg)
{
case WM_MOUSEMOVE:
{
// We need to call TrackMouseEvent in order to receive WM_MOUSELEAVE events
bd->MouseHwnd = hwnd;
if (!bd->MouseTracked)
@ -450,11 +592,17 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
::TrackMouseEvent(&tme);
bd->MouseTracked = true;
}
POINT mouse_pos = { (LONG)GET_X_LPARAM(lParam), (LONG)GET_Y_LPARAM(lParam) };
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
::ClientToScreen(hwnd, &mouse_pos);
io.AddMousePosEvent((float)mouse_pos.x, (float)mouse_pos.y);
break;
}
case WM_MOUSELEAVE:
if (bd->MouseHwnd == hwnd)
bd->MouseHwnd = NULL;
bd->MouseTracked = false;
io.AddMousePosEvent(-FLT_MAX, -FLT_MAX);
break;
case WM_LBUTTONDOWN: case WM_LBUTTONDBLCLK:
case WM_RBUTTONDOWN: case WM_RBUTTONDBLCLK:
@ -466,9 +614,10 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONDBLCLK) { button = 1; }
if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONDBLCLK) { button = 2; }
if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONDBLCLK) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == NULL)
if (bd->MouseButtonsDown == 0 && ::GetCapture() == NULL)
::SetCapture(hwnd);
io.MouseDown[button] = true;
bd->MouseButtonsDown |= 1 << button;
io.AddMouseButtonEvent(button, true);
return 0;
}
case WM_LBUTTONUP:
@ -481,31 +630,59 @@ IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hwnd, UINT msg, WPARA
if (msg == WM_RBUTTONUP) { button = 1; }
if (msg == WM_MBUTTONUP) { button = 2; }
if (msg == WM_XBUTTONUP) { button = (GET_XBUTTON_WPARAM(wParam) == XBUTTON1) ? 3 : 4; }
io.MouseDown[button] = false;
if (!ImGui::IsAnyMouseDown() && ::GetCapture() == hwnd)
bd->MouseButtonsDown &= ~(1 << button);
if (bd->MouseButtonsDown == 0 && ::GetCapture() == hwnd)
::ReleaseCapture();
io.AddMouseButtonEvent(button, false);
return 0;
}
case WM_MOUSEWHEEL:
io.MouseWheel += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
io.AddMouseWheelEvent(0.0f, (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA);
return 0;
case WM_MOUSEHWHEEL:
io.MouseWheelH += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
io.AddMouseWheelEvent((float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA, 0.0f);
return 0;
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
{
bool down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);
const bool is_key_down = (msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN);
if (wParam < 256)
io.KeysDown[wParam] = down;
if (wParam == VK_CONTROL)
io.KeyCtrl = down;
if (wParam == VK_SHIFT)
io.KeyShift = down;
if (wParam == VK_MENU)
io.KeyAlt = down;
{
// Submit modifiers
ImGui_ImplWin32_UpdateKeyModifiers();
// Obtain virtual key code
// (keypad enter doesn't have its own... VK_RETURN with KF_EXTENDED flag means keypad enter, see IM_VK_KEYPAD_ENTER definition for details, it is mapped to ImGuiKey_KeyPadEnter.)
int vk = (int)wParam;
if ((wParam == VK_RETURN) && (HIWORD(lParam) & KF_EXTENDED))
vk = IM_VK_KEYPAD_ENTER;
// Submit key event
const ImGuiKey key = ImGui_ImplWin32_VirtualKeyToImGuiKey(vk);
const int scancode = (int)LOBYTE(HIWORD(lParam));
if (key != ImGuiKey_None)
ImGui_ImplWin32_AddKeyEvent(key, is_key_down, vk, scancode);
// Submit individual left/right modifier events
if (vk == VK_SHIFT)
{
// Important: Shift keys tend to get stuck when pressed together, missing key-up events are corrected in ImGui_ImplWin32_ProcessKeyEventsWorkarounds()
if (IsVkDown(VK_LSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftShift, is_key_down, VK_LSHIFT, scancode); }
if (IsVkDown(VK_RSHIFT) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightShift, is_key_down, VK_RSHIFT, scancode); }
}
else if (vk == VK_CONTROL)
{
if (IsVkDown(VK_LCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftCtrl, is_key_down, VK_LCONTROL, scancode); }
if (IsVkDown(VK_RCONTROL) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightCtrl, is_key_down, VK_RCONTROL, scancode); }
}
else if (vk == VK_MENU)
{
if (IsVkDown(VK_LMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_LeftAlt, is_key_down, VK_LMENU, scancode); }
if (IsVkDown(VK_RMENU) == is_key_down) { ImGui_ImplWin32_AddKeyEvent(ImGuiKey_RightAlt, is_key_down, VK_RMENU, scancode); }
}
}
return 0;
}
case WM_SETFOCUS:
@ -655,35 +832,6 @@ float ImGui_ImplWin32_GetDpiScaleForHwnd(void* hwnd)
return ImGui_ImplWin32_GetDpiScaleForMonitor(monitor);
}
//--------------------------------------------------------------------------------------------------------
// IME (Input Method Editor) basic support for e.g. Asian language users
//--------------------------------------------------------------------------------------------------------
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
#endif
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
#define HAS_WIN32_IME 1
#include <imm.h>
#ifdef _MSC_VER
#pragma comment(lib, "imm32")
#endif
static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos)
{
COMPOSITIONFORM cf = { CFS_FORCE_POSITION,{ (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) },{ 0, 0, 0, 0 } };
if (HWND hwnd = (HWND)viewport->PlatformHandle)
if (HIMC himc = ::ImmGetContext(hwnd))
{
::ImmSetCompositionWindow(himc, &cf);
::ImmReleaseContext(hwnd, himc);
}
}
#else
#define HAS_WIN32_IME 0
#endif
//--------------------------------------------------------------------------------------------------------
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
@ -937,7 +1085,7 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd,
return MA_NOACTIVATE;
break;
case WM_NCHITTEST:
// Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL).
// Let mouse pass-through the window. This will allow the backend to call io.AddMouseViewportEvent() correctly. (which is optional).
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
@ -986,9 +1134,6 @@ static void ImGui_ImplWin32_InitPlatformInterface()
platform_io.Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow;
platform_io.Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale; // FIXME-DPI
platform_io.Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport; // FIXME-DPI
#if HAS_WIN32_IME
platform_io.Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos;
#endif
// Register main window handle (which is owned by the main application, not by us)
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
@ -1004,6 +1149,7 @@ static void ImGui_ImplWin32_InitPlatformInterface()
static void ImGui_ImplWin32_ShutdownPlatformInterface()
{
::UnregisterClass(_T("ImGui Platform"), ::GetModuleHandle(NULL));
ImGui::DestroyPlatformWindows();
}
//---------------------------------------------------------------------------------------------------------

@ -3,12 +3,12 @@
// Implemented features:
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
// [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 VK_* 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: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// 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.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs

@ -9,10 +9,10 @@ your application or engine to easily integrate Dear ImGui.** Each backend is typ
e.g. Windows ([imgui_impl_win32.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_win32.cpp)), GLFW ([imgui_impl_glfw.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_glfw.cpp)), SDL2 ([imgui_impl_sdl.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_sdl.cpp)), etc.
- The 'Renderer' backends are in charge of: creating atlas texture, rendering imgui draw data.<BR>
e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp), etc.
e.g. DirectX11 ([imgui_impl_dx11.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_dx11.cpp)), OpenGL/WebGL ([imgui_impl_opengl3.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_opengl3.cpp)), Vulkan ([imgui_impl_vulkan.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_vulkan.cpp)), etc.
- For some high-level frameworks, a single backend usually handle both 'Platform' and 'Renderer' parts.<BR>
e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)), Marmalade ([imgui_impl_marmalade.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_marmalade.cpp)). If you end up creating a custom backend for your engine, you may want to do the same.
e.g. Allegro 5 ([imgui_impl_allegro5.cpp](https://github.com/ocornut/imgui/blob/master/backends/imgui_impl_allegro5.cpp)). If you end up creating a custom backend for your engine, you may want to do the same.
An application usually combines 1 Platform backend + 1 Renderer backend + main Dear ImGui sources.
For example, the [example_win32_directx11](https://github.com/ocornut/imgui/tree/master/examples/example_win32_directx11) application combines imgui_impl_win32.cpp + imgui_impl_dx11.cpp. There are 20+ examples in the [examples/](https://github.com/ocornut/imgui/blob/master/examples/) folder. See [EXAMPLES.MD](https://github.com/ocornut/imgui/blob/master/docs/EXAMPLES.md) for details.
@ -38,7 +38,7 @@ Dear ImGui is highly portable and only requires a few things to run and render,
- Optional: multi-viewports support.
etc.
This is essentially what each backends are doing + obligatory portability cruft. Using default backends ensure you can get all those features including the ones that would be harder to implement on your side (e.g. multi-viewports support).
This is essentially what each backend is doing + obligatory portability cruft. Using default backends ensure you can get all those features including the ones that would be harder to implement on your side (e.g. multi-viewports support).
It is important to understand the difference between the core Dear ImGui library (files in the root folder)
and backends which we are describing here (backends/ folder).
@ -75,20 +75,20 @@ List of Renderer Backends:
imgui_impl_metal.mm ; Metal (with ObjC)
imgui_impl_opengl2.cpp ; OpenGL 2 (legacy, fixed pipeline <- don't use with modern OpenGL context)
imgui_impl_opengl3.cpp ; OpenGL 3/4, OpenGL ES 2, OpenGL ES 3 (modern programmable pipeline)
imgui_impl_sdlrenderer.cpp; SDL_Renderer (optional component of SDL2 available from SDL 2.0.18+)
imgui_impl_vulkan.cpp ; Vulkan
imgui_impl_wgpu.cpp ; WebGPU
List of high-level Frameworks Backends (combining Platform + Renderer):
imgui_impl_allegro5.cpp
imgui_impl_marmalade.cpp
Emscripten is also supported.
The [example_emscripten_opengl3](https://github.com/ocornut/imgui/tree/master/examples/example_emscripten_opengl3) app uses imgui_impl_sdl.cpp + imgui_impl_opengl3.cpp, but other combos are possible.
### Backends for third-party frameworks, graphics API or other languages
See https://github.com/ocornut/imgui/wiki/Bindings for the full list.
See https://github.com/ocornut/imgui/wiki/Bindings for the full list (e.g. Adventure Game Studio, Cinder, Cocos2d-x, Game Maker Studio2, Godot, LÖVE+LUA, Magnum, Monogame, Ogre, openFrameworks, OpenSceneGraph, SFML, Sokol, Unity, Unreal Engine and many others).
### Recommended Backends
@ -127,7 +127,10 @@ Once it works, if you really need it you can replace parts of backends with your
and you have high-level systems everywhere.<BR>
Suggestion: try using a non-portable backend first (e.g. win32 + underlying graphics API) to get
your desktop builds working first. This will get you running faster and get your acquainted with
how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API.
how Dear ImGui works and is setup. You can then rewrite a custom backend using your own engine API...
Generally:
It is unlikely you will add value to your project by creating your own backend.
Also:
The [multi-viewports feature](https://github.com/ocornut/imgui/issues/1542) of the 'docking' branch allows

@ -67,7 +67,6 @@ Breaking Changes:
- Likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them.
e.g. subtract GetWindowViewport()->Pos.
- IO: Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
- IO: Removed io.DisplayVisibleMin, io.DisplayVisibleMax settings (they were marked obsoleted, used to clip within the (0,0)..(DisplaySize) range).
Other changes:
@ -91,7 +90,7 @@ Other changes:
- Added io.ConfigViewportsNoDecoration option.
- Added io.ConfigViewportsNoDefaultParent option.
- Added ImGuiBackendFlags_PlatformHasViewports, ImGuiBackendFlags_RendererHasViewports, ImGuiBackendFlags_HasMouseHoveredViewport backend flags.
- Added io.MouseHoveredViewport (optional _even_ for multi-viewport support, tied to ImGuiBackendFlags_HasMouseHoveredViewport flag).
- Added io.AddMouseViewportEvent() (optional _even_ for multi-viewport support, tied to ImGuiBackendFlags_HasMouseHoveredViewport flag).
- Expanded ImGuiViewport structure, ImGuiViewportFlags flags.
- Added ImGuiWindowClass and SetNextWindowClass() for passing viewport related hints to the OS/platform back-end.
- Examples: Renderer: OpenGL2, OpenGL3, DirectX9, DirectX10, DirectX11, DirectX12, Vulkan: Added support for multi-viewports.
@ -99,20 +98,432 @@ Other changes:
Note that Linux/Mac still have inconsistent support for multi-viewports. If you want to help see https://github.com/ocornut/imgui/issues/2117.
-----------------------------------------------------------------------
VERSION 1.88 WIP (In Progress)
-----------------------------------------------------------------------
Docking+Viewports Branch:
- Docking: fixed settings load issue when mouse wheeling. (#4310)
- Viewports: Fixed main viewport size not matching ImDrawData::DisplaySize for one frame during resize
when multi-viewports are disabled. (#4900)
-----------------------------------------------------------------------
VERSION 1.84.1 (Released 2021-08-20)
VERSION 1.87 (Released 2022-02-07)
-----------------------------------------------------------------------
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.84.1
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.87
Breaking Changes:
- Removed support for pre-C++11 compilers. We'll stop supporting VS2010. (#4537)
- Reworked IO mouse input API: (#4921, #4858) [@thedmd, @ocornut]
- Added io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() functions,
obsoleting writing directly to io.MousePos, io.MouseDown[], io.MouseWheel, etc.
- This enable input queue trickling to support low framerates. (#2787, #1992, #3383, #2525, #1320)
- Reworked IO keyboard input API: (#4921, #2625, #3724) [@thedmd, @ocornut]
- Added io.AddKeyEvent() function, obsoleting writing directly to io.KeyMap[], io.KeysDown[] arrays.
- For keyboard modifiers, you can call io.AddKeyEvent() with ImGuiKey_ModXXX values,
obsoleting writing directly to io.KeyCtrl, io.KeyShift etc.
- Added io.SetKeyEventNativeData() function (optional) to pass native and old legacy indices.
- Added full range of key enums in ImGuiKey (e.g. ImGuiKey_F1).
- Added GetKeyName() helper function.
- Obsoleted GetKeyIndex(): it is now unnecessary and will now return the same value.
- All keyboard related functions taking 'int user_key_index' now take 'ImGuiKey key':
- IsKeyDown(), IsKeyPressed(), IsKeyReleased(), GetKeyPressedAmount().
- Added io.ConfigInputTrickleEventQueue (defaulting to true) to disable input queue trickling.
- Backward compatibility:
- All backends updated to use new functions.
- Old backends populating those arrays should still work!
- Calling e.g. IsKeyPressed(MY_NATIVE_KEY_XXX) will still work! (for a while)
- Those legacy arrays will only be disabled if '#define IMGUI_DISABLE_OBSOLETE_KEYIO' is set in your imconfig.
In a few versions, IMGUI_DISABLE_OBSOLETE_FUNCTIONS will automatically enable IMGUI_DISABLE_OBSOLETE_KEYIO,
so this will be moved into the regular obsolescence path.
- BREAKING: If your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A")
this is a use case that will now assert and be breaking for your old backend.
- Transition guide:
- IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
- Backend writing to io.KeyMap[],KeysDown[] -> backend should call io.AddKeyEvent(), if legacy indexing is desired, call io.SetKeyEventNativeData()
- Basically the trick we took advantage of is that we previously only supported native keycode from 0 to 511,
so ImGuiKey values can still express a legacy native keycode, and new named keys are all >= 512.
- This will enable a few things in the future:
- Access to portable keys allows for backend-agnostic keyboard input code. Until now it was difficult
to share code using keyboard across project because of this gap. (#2625, #3724)
- Access to full key ranges will allow us to develop a proper keyboard shortcut system. (#456)
- io.SetKeyEventNativeData() include native keycode/scancode which may later be exposed. (#3141, #2959)
- Reworked IO nav/gamepad input API and unifying inputs sources: (#4921, #4858, #787)
- Added full range of ImGuiKey_GamepadXXXX enums (e.g. ImGuiKey_GamepadDpadUp, ImGuiKey_GamepadR2) to use with
io.AddKeyEvent(), io.AddKeyAnalogEvent().
- Added io.AddKeyAnalogEvent() function, obsoleting writing directly to io.NavInputs[] arrays.
- Renamed ImGuiKey_KeyPadEnter to ImGuiKey_KeypadEnter to align with new symbols. Kept redirection enum. (#2625)
- Removed support for legacy arithmetic operators (+,+-,*,/) when inputing text into a slider/drag. (#4917, #3184)
This doesn't break any api/code but a feature that was accessible by end-users (which seemingly no one used).
(Instead you may implement custom expression evaluators to provide a better version of this).
- Backends: GLFW: backend now uses glfwSetCursorPosCallback().
- If calling ImGui_ImplGlfw_InitXXX with install_callbacks=true: nothing to do. is already done for you.
- If calling ImGui_ImplGlfw_InitXXX with install_callbacks=false: you WILL NEED to register the GLFW callback
using glfwSetCursorPosCallback() and forward it to the backend function ImGui_ImplGlfw_CursorPosCallback().
- Backends: SDL: Added SDL_Renderer* parameter to ImGui_ImplSDL2_InitForSDLRenderer(), so backend can call
SDL_GetRendererOutputSize() to obtain framebuffer size valid for hi-dpi. (#4927) [@Clownacy]
- Commented out redirecting functions/enums names that were marked obsolete in 1.69, 1.70, 1.71, 1.72 (March-July 2019)
- ImGui::SetNextTreeNodeOpen() -> use ImGui::SetNextItemOpen()
- ImGui::GetContentRegionAvailWidth() -> use ImGui::GetContentRegionAvail().x
- ImGui::TreeAdvanceToLabelPos() -> use ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetTreeNodeToLabelSpacing());
- ImFontAtlas::CustomRect -> use ImFontAtlasCustomRect
- ImGuiColorEditFlags_RGB/HSV/HEX -> use ImGuiColorEditFlags_DisplayRGB/HSV/Hex
- Removed io.ImeSetInputScreenPosFn() in favor of more flexible io.SetPlatformImeDataFn() for IME support.
Because this field was mostly only ever used by Dear ImGui internally, not by backends nor the vast majority
of user code, this should only affect a very small fraction for users who are already very IME-aware.
- Obsoleted 'void* io.ImeWindowHandle' in favor of writing to 'void* ImGuiViewport::PlatformHandleRaw'.
This removes an incompatibility between 'master' and 'multi-viewports' backends and toward enabling
better support for IME. Updated backends accordingly. Because the old field is set by existing backends,
we are keeping it (marked as obsolete).
Other Changes:
- IO: Added event based input queue API, which now trickles events to support low framerates. [@thedmd, @ocornut]
Previously the most common issue case (button presses in low framerates) was handled by backend. This is now
handled by core automatically for all kind of inputs. (#4858, #2787, #1992, #3383, #2525, #1320)
- New IO functions for keyboard/gamepad: AddKeyEvent(), AddKeyAnalogEvent().
- New IO functions for mouse: AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent().
- IO: Unified key enums allow using key functions on key mods and gamepad values.
- Fixed CTRL+Tab into an empty window causing artifacts on the highlight rectangle due to bad reordering on ImDrawCmd.
- Fixed a situation where CTRL+Tab or Modal can occasionally lead to the creation of ImDrawCmd with zero triangles,
which would makes the draw operation of some backends assert (e.g. Metal with debugging). (#4857)
- Popups: Fixed a regression crash when a new window is created after a modal on the same frame. (#4920) [@rokups]
- Popups: Fixed an issue when reopening a same popup multiple times would offset them by 1 pixel on the right. (#4936)
- Tables, ImDrawListSplitter: Fixed erroneously stripping trailing ImDrawList::AddCallback() when submitted in
last column or last channel and when there are no other drawing operation. (#4843, #4844) [@hoffstadt]
- Tables: Fixed positioning of Sort icon on right-most column with some settings (not resizable + no borders). (#4918).
- Nav: Fixed gamepad navigation in wrapping popups not wrapping all the way. (#4365)
- Sliders, Drags: Fixed text input of values with a leading sign, common when using a format enforcing sign. (#4917)
- Demo: draw a section of keyboard in "Inputs > Keyboard, Gamepad & Navigation state" to visualize keys. [@thedmd]
- Platform IME: changed io.ImeSetInputScreenPosFn() to io.SetPlatformImeDataFn() API,
now taking a ImGuiPlatformImeData structure which we can more easily extend in the future.
- Platform IME: moved io.ImeWindowHandle to GetMainViewport()->PlatformHandleRaw.
- Platform IME: add ImGuiPlatformImeData::WantVisible, hide IME composition window when not used. (#2589) [@actboy168]
- Platform IME: add ImGuiPlatformImeData::InputLineHeight. (#3113) [@liuliu]
- Platform IME: [windows] call ImmSetCandidateWindow() to position candidate window.
- Backends: GLFW: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts.
We are now converting GLFW untranslated keycodes back to translated keycodes in order to match the behavior of
other backend, and facilitate the use of GLFW with lettered-shortcuts API. (#456, #2625)
- Backends: GLFW: Submit keys and key mods using io.AddKeyEvent(). (#2625, #4921)
- Backends: GLFW: Submit mouse data using io.AddMousePosEvent(), io.AddMouseButtonEvent(), io.AddMouseWheelEvent() functions. (#4921)
- Backends: GLFW: Retrieve mouse position using glfwSetCursorPosCallback() + fallback when focused but not hovered/captured.
- Backends: GLFW: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4921)
- Backends: GLFW: Added ImGui_ImplGlfw_InstallCallbacks()/ImGui_ImplGlfw_RestoreCallbacks() helpers to facilitate user installing
callbacks after iniitializing backend. (#4981)
- Backends: Win32: Submit keys and key mods using io.AddKeyEvent(). (#2625, #4921)
- Backends: Win32: Retrieve mouse position using WM_MOUSEMOVE/WM_MOUSELEAVE + fallback when focused but not hovered/captured.
- Backends: Win32: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4921)
- Backends: Win32: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
- Backends: Win32: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4921)
- Backends: SDL: Pass localized keys (matching keyboard layout). Fix e.g. CTRL+A, CTRL+Z, CTRL+Y shortcuts. (#456, #2625)
- Backends: SDL: Submit key data using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: SDL: Retrieve mouse position using SDL_MOUSEMOTION/SDL_WINDOWEVENT_LEAVE + fallback when focused but not hovered/captured.
- Backends: SDL: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4921)
- Backends: SDL: Maintain a MouseButtonsDown mask instead of using ImGui::IsAnyMouseDown() which will be obsoleted.
- Backends: SDL: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4921)
- Backends: Allegro5: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: Allegro5: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4921)
- Backends: OSX: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: OSX: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4921)
- Backends: OSX: Submit gamepad data using io.AddKeyEvent/AddKeyAnalogEvent() functions, stopped writing to io.NavInputs[]. (#4921)
- Backends: OSX: Added basic Platform IME support. (#3108, #2598) [@liuliu]
- Backends: OSX: Fix Game Controller nav mapping to use shoulder for both focusing and tweak speed. (#4759)
- Backends: OSX: Fix building with old Xcode versions that are missing gamepad features. [@rokups]
- Backends: OSX: Forward keyDown/keyUp events to OS when unused by Dear ImGui.
- Backends: Android, GLUT: Submit keys using io.AddKeyEvent(). Submit keymods using io.AddKeyModsEvent() at the same time. (#2625)
- Backends: Android, GLUT: Submit mouse data using io.AddMousePosEvent(), AddMouseButtonEvent(), AddMouseWheelEvent() functions. (#4858)
- Backends: OpenGL3: Fixed a buffer overflow in imgui_impl_opengl3_loader.h init (added in 1.86). (#4468, #4830) [@dymk]
It would generally not have noticeable side-effect at runtime but would be detected by runtime checkers.
- Backends: OpenGL3: Fix OpenGL ES2 includes on Apple systems. [@rokups]
- Backends: Metal: Added Apple Metal C++ API support. (#4824, #4746) [@luigifcruz]
Enable with '#define IMGUI_IMPL_METAL_CPP' in your imconfig.h file.
- Backends: Metal: Ignore ImDrawCmd where ElemCount == 0, which are normally not emitted by the library but
can theoretically be created by user code manipulating a ImDrawList. (#4857)
- Backends: Vulkan: Added support for ImTextureID as VkDescriptorSet, add ImGui_ImplVulkan_AddTexture(). (#914) [@martty]
- Backends: SDL_Renderer: Fix texture atlas format on big-endian hardware (#4927) [@Clownacy]
- Backends: WebGPU: Fixed incorrect size parameters in wgpuRenderPassEncoderSetIndexBuffer() and
wgpuRenderPassEncoderSetVertexBuffer() calls. (#4891) [@FeepsDev]
Docking+Viewports Branch:
- Docking: Fixed a CTRL+TAB crash when aiming at an empty docked window. (#4792)
- Docking: Tabs use their own identifier instead of the Window identifier.
(This will invalidate some stored .ini data such as last selected tab, sorry!)
- Docking: Fixed size constraints not working on single window holding on a dock id (still doesn't work on docked windows).
- Docking: Fixed CTRL+TAB back into a docked window not selecting menu layer when no item are on main layer.
- Viewports, IO: Added io.AddMouseViewportEvent() function to queue hovered viewport change (when known by backend).
- Viewports: Relaxed specs for backend supporting ImGuiBackendFlags_HasMouseHoveredViewport: it is now _optional_
for the backend to have to ignore viewports with the _NoInputs flag when call io.AddMouseViewportEvent(). It is
much better if they can (Win32 and GLFW 3.3+ backends can, SDL and GLFW 3.2 backends cannot, they are lacking data).
A concrete example is: when dragging a viewport for docking, the viewport is marked with _NoInputs to allow us
to pick the target viewports for docking. If the backend reports a viewport with _NoInputs when calling the
io.AddMouseViewportEvent() function, then Dear ImGui will revert to its flawed heuristic to find the viewport under.
By lowering those specs, we allow the SDL and more backend to support this, only relying on the heuristic in a few
drag and drop situations rather that relying on it everywhere.
- Viewports: Fixed a CTRL+TAB crash with viewports enabled when the window list needs to appears in
its own viewport (regression from 1.86). (#4023, #787)
- Viewports: Fixed active InputText() from preventing viewports to merge. (#4212)
- Backends: SDL: Added support for ImGuiBackendFlags_HasMouseHoveredViewport now that its specs have been lowered.
- (Breaking) Removed ImGuiPlatformIO::Platform_SetImeInputPos() in favor of newly standardized
io.SetPlatformImeDataFn() function. Should not affect more than default backends.
-----------------------------------------------------------------------
VERSION 1.86 (Released 2021-12-22)
-----------------------------------------------------------------------
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.86
Breaking Changes:
- Removed CalcListClipping() function. Prefer using ImGuiListClipper which can return non-contiguous ranges.
Please open an issue if you think you really need this function. (#3841)
- Backends: OSX: Added NSView* parameter to ImGui_ImplOSX_Init(). (#4759) [@stuartcarnie]
- Backends: Marmalade: Removed obsolete Marmalade backend (imgui_impl_marmalade.cpp) + example app. (#368, #375)
Find last supported version at https://github.com/ocornut/imgui/wiki/Bindings
Other Changes:
- Added an assertion for the common user mistake of using "" as an identifier at the root level of a window
instead of using "##something". Empty identifiers are valid and useful in a very small amount of cases,
but 99.9% of the time if you need an empty label you should use "##something". (#1414, #2562, #2807, #4008,
#4158, #4375, #4548, #4657, #4796). READ THE FAQ ABOUT HOW THE ID STACK WORKS -> https://dearimgui.org/faq
- Added GetMouseClickedCount() function, returning the number of successive clicks. (#3229) [@kudaba]
(so IsMouseDoubleClicked(ImGuiMouseButton_Left) is same as GetMouseClickedCount(ImGuiMouseButton_Left) == 2,
but it allows testing for triple clicks and more).
- Modals: fixed issue hovering popups inside a child windows inside a modal. (#4676, #4527)
- Modals, Popups, Windows: changes how appearing windows are interrupting popups and modals. (#4317) [@rokups]
- appearing windows created from within the begin stack of a popup/modal will no longer close it.
- appearing windows created not within the begin stack of a modal will no longer close the modal,
and automatically appear behind it.
- Fixed IsWindowFocused()/IsWindowHovered() issues with child windows inside popups. (#4676)
- Nav: Ctrl+tabbing to cycle through windows is now enabled regardless of using the _NavEnableKeyboard
configuration flag. This is part of an effort to generalize the use of keyboard inputs. (#4023, #787).
Note that while this is active you can also moving windows (with arrow) and resize (shift+arrows).
- Nav: tabbing now cycles through clipped items and scroll accordingly. (#4449)
- Nav: pressing PageUp/PageDown/Home/End when in Menu layer automatically moves back to Main layer.
- Nav: fixed resizing window from borders setting navigation to Menu layer.
- Nav: prevent child from clipping items when using _NavFlattened and parent has a pending request.
- Nav: pressing Esc to exit a child window reactivates the Nav highlight if it was disabled by mouse.
- Nav: with ImGuiConfigFlags_NavEnableSetMousePos enabled: Fixed absolute mouse position when using
Home/End leads to scrolling. Fixed not setting mouse position when a failed move request (e.g. when
already at edge) reactivates the navigation highlight.
- Menus: fixed closing a menu inside a popup/modal by clicking on the popup/modal. (#3496, #4797)
- Menus: fixed closing a menu by clicking on its menu-bar item when inside a popup. (#3496, #4797) [@xndcn]
- Menus: fixed menu inside a popup/modal not inhibiting hovering of items in the popup/modal. (#3496, #4797)
- Menus: fixed sub-menu items inside a popups from closing the popup.
- Menus: fixed top-level menu from not consistently using style.PopupRounding. (#4788)
- InputText, Nav: fixed repeated calls to SetKeyboardFocusHere() preventing to use InputText(). (#4682)
- Inputtext, Nav: fixed using SetKeyboardFocusHere() on InputTextMultiline(). (#4761)
- InputText: made double-click select word, triple-line select line. Word delimitation logic differs
slightly from the one used by CTRL+arrows. (#2244)
- InputText: fixed ReadOnly flag preventing callbacks from receiving the text buffer. (#4762) [@actondev]
- InputText: fixed Shift+Delete from not cutting into clipboard. (#4818, #1541) [@corporateshark]
- InputTextMultiline: fixed incorrect padding when FrameBorder > 0. (#3781, #4794)
- InputTextMultiline: fixed vertical tracking with large values of FramePadding.y. (#3781, #4794)
- Separator: fixed cover all columns while called inside a table. (#4787)
- Clipper: currently focused item is automatically included in clipper range.
Fixes issue where e.g. drag and dropping an item and scrolling ensure the item source location is
still submitted. (#3841, #1725) [@GamingMinds-DanielC, @ocornut]
- Clipper: added ForceDisplayRangeByIndices() to force a given item (or several) to be stepped out
during a clipping operation. (#3841) [@@GamingMinds-DanielC]
- Clipper: rework so gamepad/keyboard navigation doesn't create spikes in number of items requested
by the clipper to display. (#3841)
- Clipper: fixed content height declaration slightly mismatching the value of when not using a clipper.
(an additional ItemSpacing.y was declared, affecting scrollbar range).
- Clipper: various and incomplete changes to tame down scrolling and precision issues on very large ranges.
Passing an explicit height to the clipper now allows larger ranges. (#3609, #3962).
- Clipper: fixed invalid state when number of frozen table row is smaller than ItemCount.
- Drag and Drop: BeginDragDropSource() with ImGuiDragDropFlags_SourceAllowNullID doesn't lose
tooltip when scrolling. (#143)
- Fonts: fixed infinite loop in ImFontGlyphRangesBuilder::AddRanges() when passing UINT16_MAX or UINT32_MAX
without the IMGUI_USE_WCHAR32 compile-time option. (#4802) [@SlavicPotato]
- Metrics: Added a node showing windows in submission order and showing the Begin() stack.
- Misc: Added missing ImGuiMouseCursor_NotAllowed cursor for software rendering (when the
io.MouseDrawCursor flag is enabled). (#4713) [@nobody-special666]
- Misc: Fixed software mouse cursor being rendered multiple times if Render() is called more than once.
- Misc: Fix MinGW DLL build issue (when IMGUI_API is defined). [@rokups]
- CI: Add MinGW DLL build to test suite. [@rokups]
- Backends: Vulkan: Call vkCmdSetScissor() at the end of render with a full-viewport to reduce
likehood of issues with people using VK_DYNAMIC_STATE_SCISSOR in their app without calling
vkCmdSetScissor() explicitly every frame. (#4644)
- Backends: OpenGL3: Using buffer orphaning + glBufferSubData(), seems to fix leaks with multi-viewports
with some Intel HD drivers, and perhaps improve performances. (#4468, #4504, #2981, #3381) [@parbo]
- Backends: OpenGL2, Allegro5, Marmalade: Fixed mishandling of the ImDrawCmd::IdxOffset field.
This is an old bug, but due to the way we created drawlists, it never had any visible side-effect before.
The new code for handling Modal and CTRL+Tab dimming/whitening recently made the bug surface. (#4790)
- Backends: Win32: Store left/right variants of Ctrl/Shift/Alt mods in KeysDown[] array. (#2625) [@thedmd]
- Backends: DX12: Fixed DRAW_EMPTY_SCISSOR_RECTANGLE warnings. (#4775)
- Backends: SDL_Renderer: Added support for large meshes (64k+ vertices) with 16-bit indices,
enabling 'ImGuiBackendFlags_RendererHasVtxOffset' in the backend. (#3926) [@rokups]
- Backends: SDL_Renderer: Fix for SDL 2.0.19+ RenderGeometryRaw() API signature change. (#4819) [@sridenour]
- Backends: OSX: Generally fix keyboard support. Keyboard arrays indexed using kVK_* codes, e.g.
ImGui::IsKeyPressed(kVK_Space). Don't set mouse cursor shape unconditionally. Handle two fingers scroll
cancel event. (#4759, #4253, #1873) [@stuartcarnie]
- Backends: OSX: Add Game Controller support (need linking GameController framework) (#4759) [@stuartcarnie]
- Backends: WebGPU: Passing explicit buffer sizes to wgpuRenderPassEncoderSetVertexBuffer() and
wgpuRenderPassEncoderSetIndexBuffer() functions as validation layers appears to not do what the
in-flux specs says. (#4766) [@meshula]
Docking+Viewports Branch:
- Docking: Revert removal of io.ConfigDockingWithShift config option (removed in 1.83). (#4643)
- Docking: Fixed a bug undocking windows docked into a non-visible or _KeepAliveOnly dockspace
when unrelated windows submitted before the dockspace have dynamic visibility. (#4757)
- Docking, Style: Docked windows honor ImGuiCol_WindowBg. (#2700, #2539)
- Docking, Style: Docked windows honor display their border properly. (#2522)
- Docking: Fixed incorrectly rounded tab bars for dock node that are not at the top of their dock tree.
- Docking: Fixed single-frame node pos/size inconsistencies when window stop or start being submitted.
- Docking: Prevent docking any window created above a popup/modal. (#4317)
- Viewports: Made it possible to explicitly assign ImGuiWindowClass::ParentViewportId to 0 in order
to ensure a window is not parented. Previously this would use the global default (which might be 0,
but not always as it would depend on io.ConfigViewportsNoDefaultParent). (#3152, #2871)
- Viewports: Fixed tooltip in own viewport over modal from being incorrectly dimmed. (#4729)
- Viewports: Fixed CTRL+TAB highlight outline on docked windows not always fitting in host viewport.
- Backends: Made it possible to shutdown default Platform Backends before the Renderer backends. (#4656)
- Disabled: Fixed nested BeginDisabled()/EndDisabled() bug in Docking branch due to bad merge. (#4655, #4452, #4453, #4462)
-----------------------------------------------------------------------
VERSION 1.85 (Released 2021-10-12)
-----------------------------------------------------------------------
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.85
This is the last release officially supporting C++03 and Visual Studio 2008/2010. (#4537)
We expect that the next release will require a subset of the C++11 language (VS 2012~, GCC 4.8.1, Clang 3.3).
We may use some C++11 language features but we will not use any C++ library headers.
If you are stuck on ancient compiler you may need to stay at this version onward.
Breaking Changes:
- Removed GetWindowContentRegionWidth() function. keep inline redirection helper.
Can use 'GetWindowContentRegionMax().x - GetWindowContentRegionMin().x' instead but it's not
very useful in practice, and the only use of it in the demo was illfit.
Using 'GetContentRegionAvail().x' is generally a better choice.
- (Docking branch) IsWindowFocused() and IsWindowHovered() with only the _ChildWindows flag
and without the _RootWindow flag used to leak docking hierarchy, so a docked window would
return as the child of the window hosting the dockspace. This was inconsistent and incorrect
with other behaviors so we fixed it. Added a new _DockHierarchy flag to opt-in this behavior.
Other Changes:
- Fixed BeginDisabled(false) - BeginDisabled(true) was working. (#211, #4452, #4453)
- Debug: Stack Tool: Added "Stack Tool" available in "Demo->Tools->Stack Tool", "Metrics->Tools",
or by calling the ShowStackToolWindow() function. The tool run queries on hovered id to display
details about individual components that were hashed to create an ID. It helps understanding
the ID stack system and debugging potential ID collisions. (#4631) [@ocornut, @rokups]
- Windows: Fixed background order of overlapping childs submitted sequentially. (#4493)
- IsWindowFocused: Added ImGuiFocusedFlags_NoPopupHierarchy flag allowing to exclude child popups
from the tested windows when combined with _ChildWindows.
- IsWindowHovered: Added ImGuiHoveredFlags_NoPopupHierarchy flag allowing to exclude child popups
from the tested windows when combined with _ChildWindows.
- InputTextMultiline: Fixed label size not being included into window contents rect unless
the whole widget is clipped.
- InputText: Allow activating/cancelling/validating input with gamepad nav events. (#2321, #4552)
- InputText: Fixed selection rectangle appearing one frame late when selecting all.
- TextUnformatted: Accept null ranges including (NULL,NULL) without asserting, in order to conform
to common idioms (e.g. passing .data(), .data() + .size() from a null string). (#3615)
- Disabled: Added assert guard for mismatching BeginDisabled()/EndDisabled() blocks. (#211)
- Nav: Fixed using SetKeyboardFocusHere() on non-visible/clipped items. It now works and will scroll
toward the item. When called during a frame where the parent window is appearing, scrolling will
aim to center the item in the window. When calling during a frame where the parent window is already
visible, scrolling will aim to scroll as little as possible to make the item visible. We will later
expose scroll functions and flags in public API to select those behaviors. (#343, #4079, #2352)
- Nav: Fixed using SetKeyboardFocusHere() from activating a different item on the next frame if
submitted items have changed during that frame. (#432)
- Nav: Fixed toggling menu layer with Alt or exiting menu layer with Esc not moving mouse when
the ImGuiConfigFlags_NavEnableSetMousePos config flag is set.
- Nav: Fixed a few widgets from not setting reference keyboard/gamepad navigation ID when
activated with mouse. More specifically: BeginTabItem(), the scrolling arrows of BeginTabBar(),
the arrow section of TreeNode(), the +/- buttons of InputInt()/InputFloat(), Selectable() with
ImGuiSelectableFlags_SelectOnRelease. More generally: any direct use of ButtonBehavior() with
the PressedOnClick/PressedOnDoubleClick/PressedOnRelease button policy.
- Nav: Fixed an issue with losing focus on docked windows when pressing Alt while keyboard navigation
is disabled. (#4547, #4439) [@PathogenDavid]
- Nav: Fixed vertical scoring offset when wrapping on Y in a decorated window.
- Nav: Improve scrolling behavior when navigating to an item larger than view.
- TreePush(): removed unnecessary/inconsistent legacy behavior where passing a NULL value to
the TreePush(const char*) and TreePush(const void*) functions would use an hard-coded replacement.
The only situation where that change would make a meaningful difference is TreePush((const char*)NULL)
(_explicitly_ casting a null pointer to const char*), which is unlikely and will now crash.
You may replace it with anything else.
- ColorEdit4: Fixed not being able to change hue when saturation is 0. (#4014) [@rokups]
- ColorEdit4: Fixed hue resetting to 0 when it is set to 255. [@rokups]
- ColorEdit4: Fixed hue value jitter when source color is stored as RGB in 32-bit integer and perform
RGB<>HSV round trips every frames. [@rokups]
- ColorPicker4: Fixed picker being unable to select exact 1.0f color when dragging toward the edges
of the SV square (previously picked 0.999989986f). (#3517) [@rokups]
- Menus: Fixed vertical alignments of MenuItem() calls within a menu bar (broken in 1.84). (#4538)
- Menus: Improve closing logic when moving diagonally in empty between between parent and child menus to
accommodate for varying font size and dpi.
- Menus: Fixed crash when navigating left inside a child window inside a sub-menu. (#4510).
- Menus: Fixed an assertion happening in some situations when closing nested menus (broken in 1.83). (#4640)
- Drag and Drop: Fixed using BeginDragDropSource() inside a BeginChild() that returned false. (#4515)
- PlotHistogram: Fixed zero-line position when manually specifying min<0 and max>0. (#4349) [@filippocrocchini]
- Misc: Added asserts for missing PopItemFlag() calls.
- Misc: Fixed printf-style format checks on Clang+MinGW. (#4626, #4183, #3592) [@guusw]
- IO: Added 'io.WantCaptureMouseUnlessPopupClose' alternative to `io.WantCaptureMouse'. (#4480)
This allows apps to receive the click on void when that click is used to close popup (by default,
clicking on a void when a popup is open will close the popup but not release io.WantCaptureMouse).
- Fonts: imgui_freetype: Fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL
(which apparently happens with Freetype 2.11). (#4394, #4145?).
- Fonts: Fixed ImFontAtlas::ClearInputData() marking atlas as not built. (#4455, #3487)
- Backends: Added more implicit asserts to detect invalid/redundant calls to Shutdown functions. (#4562)
- Backends: OpenGL3: Fixed our custom GL loader conflicting with user using GL3W. (#4445) [@rokups]
- Backends: WebGPU: Fixed for latest specs. (#4472, #4512) [@Kangz, @bfierz]
- Backends: SDL_Renderer: Added SDL_Renderer backend compatible with upcoming SDL 2.0.18. (#3926) [@1bsyl]
- Backends: Metal: Fixed a crash when clipping rect larger than framebuffer is submitted via
a direct unclipped PushClipRect() call. (#4464)
- Backends: OSX: Use mach_absolute_time as CFAbsoluteTimeGetCurrent can jump backwards. (#4557, #4563) [@lfnoise]
- Backends: All renderers: Normalize clipping rect handling across backends. (#4464)
- Examples: Added SDL + SDL_Renderer example in "examples/example_sdl_sdlrenderer/" folder. (#3926) [@1bsyl]
Docking+Viewports Branch:
- IsWindowFocused: Fixed using ImGuiFocusedFlags_ChildWindows (without _RootWindow) from leaking the
docking hierarchy. Added ImGuiFocusedFlags_DockHierarchy flag to consider docking hierarchy in the test.
- IsWindowHovered: Fixed using ImGuiHoveredFlags_ChildWindows (without _RootWindow) from leaking the
docking hierarchy. Added ImGuiHoveredFlags_DockHierarchy flag to consider docking hierarchy in the test.
- Nav: Fixed an issue with losing focus on docked windows when pressing Alt while keyboard navigation
is disabled. (#4547, #4439) [@PathogenDavid]
- Docking: Fixed IsItemHovered() and functions depending on it (e.g. BeginPopupContextItem()) when
called after Begin() on a docked window (broken 2021/03/04). (#3851)
- Docking: Improved resizing system so that non-central zone are better at keeping their fixed size.
The algorithm is still not handling the allocation of size ideally for nested sibling, but it got better.
- Docking: Fixed settings load issue when mouse wheeling. (#4310)
- Docking: Fixed manually created floating node with a central node from not hiding when windows are gone.
- Docking + Drag and Drop: Fixed using BeginDragDropSource() or BeginDragDropTarget() inside a Begin()
that returned false because the window is docked. (#4515)
- Viewports: Fixed a crash while a window owning its viewport disappear while being dragged.
It would manifest when e.g. reconfiguring dock nodes while dragging.
- Viewports: Fixed unnecessary creation of temporary viewports when multiple docked windows
got reassigned to a new node (created mid-frame) which already has a HostWindow.
- Viewports: Fixed window with viewport ini data immediately merged into a host viewport from
leaving a temporary viewport alive for a frame (would leak into backend).
-----------------------------------------------------------------------
VERSION 1.84.2 (Released 2021-08-23)
-----------------------------------------------------------------------
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.84.2
- Disabled: Fixed nested BeginDisabled()/EndDisabled() calls. (#211, #4452, #4453, #4462) [@Legulysse]
- Backends: OpenGL3: OpenGL: Fixed ES 3.0 shader ("#version 300 es") to use normal precision
floats. Avoid wobbly rendering at HD resolutions. (#4463) [@nicolasnoble]
-----------------------------------------------------------------------
VERSION 1.84.1 (Released 2021-08-20)
-----------------------------------------------------------------------
Decorated log: https://github.com/ocornut/imgui/releases/tag/v1.84.1
- Disabled: Fixed BeginDisabled(false) - BeginDisabled(true) was working. (#211, #4452, #4453)
-----------------------------------------------------------------------

@ -72,7 +72,7 @@ Please read 'PROGRAMMER GUIDE' in imgui.cpp for notes on how to setup Dear ImGui
Please read the comments and instruction at the top of each file.
Please read FAQ at http://www.dearimgui.org/faq
If you are using of the backend provided here, you can add the backends/imgui_impl_xxxx(.cpp,.h)
If you are using any of the backends provided here, you can add the backends/imgui_impl_xxxx(.cpp,.h)
files to your project and use as-in. Each imgui_impl_xxxx.cpp file comes with its own individual
Changelog, so if you want to update them later it will be easier to catch up with what changed.
@ -141,10 +141,6 @@ GLUT (e.g., FreeGLUT on Linux/Windows, GLUT framework on OSX) + OpenGL2 example.
= main.cpp + imgui_impl_glut.cpp + imgui_impl_opengl2.cpp <BR>
Note that GLUT/FreeGLUT is largely obsolete software, prefer using GLFW or SDL.
[example_marmalade/](https://github.com/ocornut/imgui/blob/master/examples/example_marmalade/) <BR>
Marmalade example using IwGx. <BR>
= main.cpp + imgui_impl_marmalade.cpp
[example_null/](https://github.com/ocornut/imgui/blob/master/examples/example_null/) <BR>
Null example, compile and link imgui, create context, run headless with no inputs and no graphics output. <BR>
= main.cpp <BR>
@ -175,6 +171,12 @@ SDL2 (Win32, Mac, Linux, etc.) + OpenGL3+/ES2/ES3 example. <BR>
This uses more modern OpenGL calls and custom shaders. <BR>
This may actually also work with OpenGL 2.x contexts! <BR>
[example_sdl_sdlrenderer/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl_sdlrenderer/) <BR>
SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer (most graphics backends are supported underneath) <BR>
= main.cpp + imgui_impl_sdl.cpp + imgui_impl_sdlrenderer.cpp <BR>
This requires SDL 2.0.17+ (expected to release November 2021) <BR>
We do not really recommend using SDL_Renderer as it is a rather primitive API.
[example_sdl_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl_vulkan/) <BR>
SDL2 (Win32, Mac, Linux, etc.) + Vulkan example. <BR>
= main.cpp + imgui_impl_sdl.cpp + imgui_impl_vulkan.cpp <BR>
@ -220,7 +222,7 @@ If you are interested in using Cmake to build and links examples, see:
**About mouse cursor latency**
Dear ImGui has no particular extra lag for most behaviors,
e.g. the value of 'io.MousePos' provided at the time of NewFrame() will result in windows being moved
e.g. the last value passed to 'io.AddMousePosEvent()' before NewFrame() will result in windows being moved
to the right spot at the time of EndFrame()/Render(). At 60 FPS your experience should be pleasant.
However, consider that OS mouse cursors are typically drawn through a very specific hardware accelerated

@ -23,7 +23,7 @@ or view this file with any Markdown viewer.
| [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) |
| [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) |
| **Q&A: Usage** |
| **[Why is my widget not reacting when I click on it?<br>How can I have widgets with an empty label?<br>How can I have multiple widgets with the same label?](#q-why-is-my-widget-not-reacting-when-i-click-on-it)** |
| **[About the ID Stack system..<br>Why is my widget not reacting when I click on it?<br>How can I have widgets with an empty label?<br>How can I have multiple widgets with the same label?<br>How can I have multiple windows with the same label?](#q-about-the-id-stack-system)** |
| [How can I display an image? What is ImTextureID, how does it work?](#q-how-can-i-display-an-image-what-is-imtextureid-how-does-it-work)|
| [How can I use my own math types instead of ImVec2/ImVec4?](#q-how-can-i-use-my-own-math-types-instead-of-imvec2imvec4) |
| [How can I interact with standard C++ types (such as std::string and std::vector)?](#q-how-can-i-interact-with-standard-c-types-such-as-stdstring-and-stdvector) |
@ -94,6 +94,8 @@ Read [BACKENDS.md](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md
Read `PROGRAMMER GUIDE` section of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp). <BR>
The [Wiki](https://github.com/ocornut/imgui/wiki) is a hub to many resources and links.
For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
##### [Return to Index](#index)
---
@ -112,7 +114,7 @@ void MyLowLevelMouseButtonHandler(int button, bool down)
{
// (1) ALWAYS forward mouse data to ImGui! This is automatic with default backends. With your own backend:
ImGuiIO& io = ImGui::GetIO();
io.MouseDown[button] = down;
io.AddMouseButtonEvent(button, down);
// (2) ONLY forward mouse data to your underlying app/game.
if (!io.WantCaptureMouse)
@ -137,7 +139,7 @@ void MyLowLevelMouseButtonHandler(int button, bool down)
- The gamepad/keyboard navigation is fairly functional and keeps being improved. The initial focus was to support game controllers, but keyboard is becoming increasingly and decently usable. Gamepad support is particularly useful to use Dear ImGui on a game console (e.g. PS4, Switch, XB1) without a mouse connected!
- Keyboard: set `io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard` to enable.
- Gamepad: set `io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad` to enable (with a supporting backend).
- See [Control Sheets for Gamepads](http://www.dearimgui.org/controls_sheets) (reference PNG/PSD for for PS4, XB1, Switch gamepads).
- See [Control Sheets for Gamepads](http://www.dearimgui.org/controls_sheets) (reference PNG/PSD for PS4, XB1, Switch gamepads).
- See `USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS` section of [imgui.cpp](https://github.com/ocornut/imgui/blob/master/imgui.cpp) for more details.
##### [Return to Index](#index)
@ -160,7 +162,7 @@ Console SDK also sometimes provide equivalent tooling or wrapper for Synergy-lik
---
### Q: I integrated Dear ImGui in my engine and little squares are showing instead of text...
Your renderer is not using the font texture correctly or it hasn't be uploaded to GPU.
Your renderer is not using the font texture correctly or it hasn't been uploaded to the GPU.
- If this happens using the standard backends: A) have you modified the font atlas after `ImGui_ImplXXX_NewFrame()`? B) maybe the texture failed to upload, which could happens if for some reason your texture is too big. Also see [docs/FONTS.md](https://github.com/ocornut/imgui/blob/master/docs/FONTS.md).
- If this happens with a custom backend: make sure you have uploaded the font texture to the GPU, that all shaders are rendering states are setup properly (e.g. texture is bound). Compare your code to existing backends and use a graphics debugger such as [RenderDoc](https://renderdoc.org) to debug your rendering states.
@ -184,17 +186,24 @@ Refer to rendering backends in the [examples/](https://github.com/ocornut/imgui/
# Q&A: Usage
### Q: About the ID Stack system...
### Q: Why is my widget not reacting when I click on it?
### Q: How can I have widgets with an empty label?
### Q: How can I have multiple widgets with the same label?
### Q: How can I have multiple windows with the same label?
A primer on labels and the ID Stack...
Dear ImGui internally need to uniquely identify UI elements.
Dear ImGui internally needs to uniquely identify UI elements.
Elements that are typically not clickable (such as calls to the Text functions) don't need an ID.
Interactive widgets (such as calls to Button buttons) need a unique ID.
Unique ID are used internally to track active widgets and occasionally associate state to widgets.
Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element.
**Unique ID are used internally to track active widgets and occasionally associate state to widgets.<BR>
Unique ID are implicitly built from the hash of multiple elements that identify the "path" to the UI element.**
Since Dear ImGui 1.85 you can use `Demo>Tools>Stack Tool` or call `ImGui::ShowStackToolWindow()`. The tool display intermediate values leading to the creation of a unique ID, making things easier to debug and understand.
![Stack tool](https://user-images.githubusercontent.com/8225057/136235657-a0ea5665-dcd1-423f-9be6-dc3f8ced8f12.png)
- Unique ID are often derived from a string label and at minimum scoped within their host window:
```cpp
@ -454,7 +463,7 @@ draw_list->AddCircleFilled(ImVec2(p.x + 50, p.y + 50), 30.0f, IM_COL32(255, 0, 0
// Draw a 3 pixel thick yellow line
draw_list->AddLine(ImVec2(p.x, p.y), ImVec2(p.x + 100.0f, p.y + 100.0f), IM_COL32(255, 255, 0, 255), 3.0f);
// Advance the ImGui cursor to claim space in the window (otherwise the window will appears small and needs to be resized)
// Advance the ImGui cursor to claim space in the window (otherwise the window will appear small and needs to be resized)
ImGui::Dummy(ImVec2(200, 200));
ImGui::End();
@ -466,7 +475,7 @@ ImGui::End();
- Math operators: if you have setup `IM_VEC2_CLASS_EXTRA` in `imconfig.h` to bind your own math types, you can use your own math types and their natural operators instead of ImVec2. ImVec2 by default doesn't export any math operators in the public API. You may use `#define IMGUI_DEFINE_MATH_OPERATORS` `#include "imgui_internal.h"` to use the internally defined math operators, but instead prefer using your own math library and set it up in `imconfig.h`.
- You can use `ImGui::GetBackgroundDrawList()` or `ImGui::GetForegroundDrawList()` to access draw lists which will be displayed behind and over every other dear imgui windows (one bg/fg drawlist per viewport). This is very convenient if you need to quickly display something on the screen that is not associated to a dear imgui window.
- You can also create your own empty window and draw inside it. Call Begin() with the NoBackground | NoDecoration | NoSavedSettings | NoInputs flags (The `ImGuiWindowFlags_NoDecoration` flag itself is a shortcut for NoTitleBar | NoResize | NoScrollbar | NoCollapse). Then you can retrieve the ImDrawList* via `GetWindowDrawList()` and draw to it in any way you like.
`- You can create your own ImDrawList instance. You'll need to initialize them with `ImGui::GetDrawListSharedData()`, or create your own instancing ImDrawListSharedData`, and then call your renderer function with your own ImDrawList or ImDrawData data.
- You can create your own ImDrawList instance. You'll need to initialize them with `ImGui::GetDrawListSharedData()`, or create your own instancing `ImDrawListSharedData`, and then call your renderer function with your own ImDrawList or ImDrawData data.
- Looking for fun? The [ImDrawList coding party 2020](https://github.com/ocornut/imgui/issues/3606) thread is full of "don't do this at home" extreme uses of the ImDrawList API.
##### [Return to Index](#index)
@ -598,8 +607,8 @@ Text input: it is up to your application to pass the right character code by cal
The applications in examples/ are doing that.
Windows: you can use the WM_CHAR or WM_UNICHAR or WM_IME_CHAR message (depending if your app is built using Unicode or MultiByte mode).
You may also use MultiByteToWideChar() or ToUnicode() to retrieve Unicode codepoints from MultiByte characters or keyboard state.
Windows: if your language is relying on an Input Method Editor (IME), you copy the HWND of your window to io.ImeWindowHandle in order for
the default implementation of io.ImeSetInputScreenPosFn() to set your Microsoft IME position correctly.
Windows: if your language is relying on an Input Method Editor (IME), you can write your HWND to ImGui::GetMainViewport()->PlatformHandleRaw
in order for the default the default implementation of io.SetPlatformImeDataFn() to set your Microsoft IME position correctly.
##### [Return to Index](#index)
@ -645,7 +654,7 @@ A reasonably skinned application may look like (screenshot from [#2529](https://
### Q: Why using C++ (as opposed to C)?
Dear ImGui takes advantage of a few C++ languages features for convenience but nothing anywhere Boost insanity/quagmire. Dear ImGui does NOT require C++11 so it can be used with most old C++ compilers. Dear ImGui doesn't use any C++ header file. Language-wise, function overloading and default parameters are used to make the API easier to use and code more terse. Doing so I believe the API is sitting on a sweet spot and giving up on those features would make the API more cumbersome. Other features such as namespace, constructors and templates (in the case of the ImVector<> class) are also relied on as a convenience.
Dear ImGui takes advantage of a few C++ languages features for convenience but nothing anywhere Boost insanity/quagmire. Dear ImGui doesn't use any C++ header file. Dear ImGui uses a very small subset of C++11 features. In particular, function overloading and default parameters are used to make the API easier to use and code more terse. Doing so I believe the API is sitting on a sweet spot and giving up on those features would make the API more cumbersome. Other features such as namespace, constructors and templates (in the case of the ImVector<> class) are also relied on as a convenience.
There is an auto-generated [c-api for Dear ImGui (cimgui)](https://github.com/cimgui/cimgui) by Sonoro1234 and Stephan Dilly. It is designed for creating bindings to other languages. If possible, I would suggest using your target language functionalities to try replicating the function overloading and default parameters used in C++ else the API may be harder to use. Also see [Bindings](https://github.com/ocornut/imgui/wiki/Bindings) for various third-party bindings.

@ -27,11 +27,11 @@ In the [misc/fonts/](https://github.com/ocornut/imgui/tree/master/misc/fonts) fo
---------------------------------------
## Readme First
- All loaded fonts glyphs are rendered into a single texture atlas ahead of time. Calling either of `io.Fonts->GetTexDataAsAlpha8()`, `io.Fonts->GetTexDataAsRGBA32()` or `io.Fonts->Build()` will build the atlas.
- You can use the `Metrics/Debugger` window (available in `Demo>Tools`) to browse your fonts and understand what's going on if you have an issue. You can also reach it in `Demo->Tools->Style Editor->Fonts`. The same information are also available in the Style Editor under Fonts.
- You can use the style editor `ImGui::ShowStyleEditor()` in the "Fonts" section to browse your fonts and understand what's going on if you have an issue. You can also reach it in `Demo->Tools->Style Editor->Fonts`:
![imgui_capture_0008](https://user-images.githubusercontent.com/8225057/135429892-0e41ef8d-33c5-4991-bcf6-f997a0bcfd6b.png)
![imgui_capture_0008](https://user-images.githubusercontent.com/8225057/84162822-1a731f00-aa71-11ea-9b6b-89c2332aa161.png)
- All loaded fonts glyphs are rendered into a single texture atlas ahead of time. Calling either of `io.Fonts->GetTexDataAsAlpha8()`, `io.Fonts->GetTexDataAsRGBA32()` or `io.Fonts->Build()` will build the atlas.
- Make sure your font ranges data are persistent (available during the calls to `GetTexDataAsAlpha8()`/`GetTexDataAsRGBA32()/`Build()`.
@ -292,8 +292,8 @@ for (int rect_n = 0; rect_n < IM_ARRAYSIZE(rect_ids); rect_n++)
## Using Font Data Embedded In Source Code
- Compile and use [binary_to_compressed_c.cpp](https://github.com/ocornut/imgui/blob/master/misc/fonts/binary_to_compressed_c.cpp) to create a compressed C style array that you can embed in source code.
- See the documentation in [binary_to_compressed_c.cpp](https://github.com/ocornut/imgui/blob/master/misc/fonts/binary_to_compressed_c.cpp) for instruction on how to use the tool.
- You may find a precompiled version binary_to_compressed_c.exe for Windows instead of demo binaries package (see [README](https://github.com/ocornut/imgui/blob/master/docs/README.md)).
- See the documentation in [binary_to_compressed_c.cpp](https://github.com/ocornut/imgui/blob/master/misc/fonts/binary_to_compressed_c.cpp) for instructions on how to use the tool.
- You may find a precompiled version binary_to_compressed_c.exe for Windows inside the demo binaries package (see [README](https://github.com/ocornut/imgui/blob/master/docs/README.md)).
- The tool can optionally output Base85 encoding to reduce the size of _source code_ but the read-only arrays in the actual binary will be about 20% bigger.
Then load the font with:
@ -309,7 +309,7 @@ ImFont* font = io.Fonts->AddFontFromMemoryCompressedBase85TTF(compressed_data_ba
## About filenames
**Please note that many new C/C++ users have issues their files _because the filename they provide is wrong_.**
**Please note that many new C/C++ users have issues loading their files _because the filename they provide is wrong_.**
Two things to watch for:
- Make sure your IDE/debugger settings starts your executable from the right working directory. In Visual Studio you can change your working directory in project `Properties > General > Debugging > Working Directory`. People assume that their execution will start from the root folder of the project, where by default it oftens start from the folder where object or executable files are stored.

@ -116,9 +116,9 @@ On most platforms and when using C++, **you should be able to use a combination
Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading one texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that. If you are an experienced programmer at ease with those concepts, it should take you less than two hours to integrate Dear ImGui in your custom engine. **Make sure to spend time reading the [FAQ](https://www.dearimgui.org/faq), comments, and some of the examples/ application!**
Officially maintained backends/bindings (in repository):
- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, Vulkan, WebGPU.
- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_Renderer, Vulkan, WebGPU.
- Platforms: GLFW, SDL2, Win32, Glut, OSX, Android.
- Frameworks: Emscripten, Allegro5, Marmalade.
- Frameworks: Allegro5, Emscripten.
[Third-party backends/bindings](https://github.com/ocornut/imgui/wiki/Bindings) wiki page:
- Languages: C, C# and: Beef, ChaiScript, Crystal, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lobster, Lua, Odin, Pascal, PureBasic, Python, Ruby, Rust, Swift...
@ -132,7 +132,7 @@ Also see [Wiki](https://github.com/ocornut/imgui/wiki) for more links and ideas.
### Upcoming Changes
Some of the goals for 2021 are:
Some of the goals for 2022 are:
- Work on Docking (see [#2109](https://github.com/ocornut/imgui/issues/2109), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch)
- Work on Multi-Viewport / Multiple OS windows. (see [#1542](https://github.com/ocornut/imgui/issues/1542), in public [docking](https://github.com/ocornut/imgui/tree/docking) branch looking for feedback)
- Work on gamepad/keyboard controls. (see [#787](https://github.com/ocornut/imgui/issues/787))
@ -162,7 +162,9 @@ See: [Wiki](https://github.com/ocornut/imgui/wiki) for many links, references, a
See: [Articles about the IMGUI paradigm](https://github.com/ocornut/imgui/wiki#about-the-imgui-paradigm) to read/learn about the Immediate Mode GUI paradigm.
For questions, bug reports, requests, feedback, you may post on [GitHub Issues](https://github.com/ocornut/imgui/issues) or [GitHub Discussions](https://github.com/ocornut/imgui/discussions). Please read and fill the New Issue template carefully.
Getting started? For first-time users having issues compiling/linking/running or issues loading fonts, please use [GitHub Discussions](https://github.com/ocornut/imgui/discussions).
For other questions, bug reports, requests, feedback, you may post on [GitHub Issues](https://github.com/ocornut/imgui/issues). Please read and fill the New Issue template carefully.
Private support is available for paying business customers (E-mail: _contact @ dearimgui dot com_).
@ -199,13 +201,13 @@ Ongoing Dear ImGui development is currently financially supported by users and p
- [Blizzard](https://careers.blizzard.com/en-us/openings/engineering/all/all/all/1)
*Double-chocolate sponsors*
- [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui)
- [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui), [Supercell](https://supercell.com)
*Chocolate sponsors*
- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Adobe](https://www.adobe.com/products/medium.html), [Aras Pranckevičius](https://aras-p.info), [Arkane Studios](https://www.arkane-studios.com), [Epic](https://www.unrealengine.com/en-US/megagrants), [RAD Game Tools](http://www.radgametools.com/)
- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Adobe](https://www.adobe.com/products/medium.html), [Aras Pranckevičius](https://aras-p.info), [Arkane Studios](https://www.arkane-studios.com), [Epic](https://www.unrealengine.com/en-US/megagrants), [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [RAD Game Tools](http://www.radgametools.com/)
*Salty-caramel sponsors*
- [Framefield](http://framefield.com), [Grinding Gear Games](https://www.grindinggear.com), [Kylotonn](https://www.kylotonn.com), [Next Level Games](https://www.nextlevelgames.com), [O-Net Communications (USA)](http://en.o-netcom.com), [Supercell](https://supercell.com).
- [Framefield](http://framefield.com), [Grinding Gear Games](https://www.grindinggear.com), [Kylotonn](https://www.kylotonn.com), [Next Level Games](https://www.nextlevelgames.com), [O-Net Communications (USA)](http://en.o-netcom.com)
Please see [detailed list of Dear ImGui supporters](https://github.com/ocornut/imgui/wiki/Sponsors) for past sponsors.
From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations.

@ -113,7 +113,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- input number: optional range min/max for Input*() functions
- input number: holding [-]/[+] buttons could increase the step speed non-linearly (or user-controlled)
- input number: use mouse wheel to step up/down
- input number: applying arithmetics ops (+,-,*,/) messes up with text edit undo stack.
- layout: helper or a way to express ImGui::SameLine(ImGui::GetCursorStartPos().x + ImGui::CalcItemWidth() + ImGui::GetStyle().ItemInnerSpacing.x); in a simpler manner.
- layout, font: horizontal tab support, A) text mode: forward only tabs (e.g. every 4 characters/N pixels from pos x1), B) manual mode: explicit tab stops acting as mini columns, no clipping (for menu items, many kind of uses, also vaguely relate to #267, #395)
@ -142,7 +141,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- plot: option/feature: draw unit
- plot: add a helper e.g. Plot(char* label, float value, float time_span=2.0f) that stores values and Plot them for you - probably another function name. and/or automatically allow to plot ANY displayed value (more reliance on stable ID)
- clipper: ability to force display 1 item in the list would be convenient (for patterns where we need to set active id etc.)
- clipper: ability to disable the clipping through a simple flag/bool.
- clipper: ability to run without knowing full count in advance.
- clipper: horizontal clipping support. (#2580)
@ -354,6 +352,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- nav: some features such as PageUp/Down/Home/End should probably work without ImGuiConfigFlags_NavEnableKeyboard? (where do we draw the line?)
- nav: configuration flag to disable global shortcuts (currently only CTRL-Tab) ?
! nav: never clear NavId on some setup (e.g. gamepad centric)
- nav: scroll up/down if possible when move request fails
- nav: there's currently no way to completely clear focus with the keyboard. depending on patterns used by the application to dispatch inputs, it may be desirable.
- nav: code to focus child-window on restoring NavId appears to have issue: e.g. when focus change is implicit because of window closure.
- nav: Home/End behavior when navigable item is not fully visible at the edge of scrolling? should be backtrack to keep item into view?
@ -362,12 +361,12 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- nav: patterns to make it possible for arrows key to update selection (see JustMovedTo in range_select branch)
- nav: restore/find nearest NavId when current one disappear (e.g. pressed a button that disappear, or perhaps auto restoring when current button change name)
- nav: SetItemDefaultFocus() level of priority, so widget like Selectable when inside a popup could claim a low-priority default focus on the first selected iem
- nav: NavFlattened: init requests don't work properly on flattened siblings.
- nav: NavFlattened: pageup/pagedown/home/end don't work properly on flattened siblings.
- nav: NavFlattened: ESC on a flattened child should select something.
- nav: NavFlattened: broken: in typical usage scenario, the items of a fully clipped child are currently not considered to enter into a NavFlattened child.
- nav: NavFlattened: init request doesn't select items that are part of a NavFlattened child
- nav: NavFlattened: cannot access menu-bar of a flattened child window with Alt/menu key (not a very common use case..).
- nav: simulate right-click or context activation? (SHIFT+F10)
- nav/tabbing: refactor old tabbing system and turn into navigation, should pass through all widgets (in submission order?).
- nav/popup: esc/enter default behavior for popups, e.g. be able to mark an "ok" or "cancel" button that would get triggered by those keys, default validation button, etc.
- nav/treenode: left within a tree node block as a fallback (ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default?)
- nav/menus: pressing left-right on a vertically clipped menu bar tends to jump to the collapse/close buttons.
@ -380,8 +379,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
- nav/windowing: when CTRL-Tab/windowing is active, the HoveredWindow detection doesn't take account of the window display re-ordering.
- nav/windowing: Resizing window will currently fail with certain types of resizing constraints/callback applied
- focus: preserve ActiveId/focus stack state, e.g. when opening a menu and close it, previously selected InputText() focus gets restored (#622)
- focus: SetKeyboardFocusHere() on with >= 0 offset could be done on same frame (else latch and modulate on beginning of next frame)
- focus: unable to use SetKeyboardFocusHere() on clipped widgets. (#787, #343)
- viewport: make it possible to have no main/hosting viewport
- viewport: We set ImGuiViewportFlags_NoFocusOnAppearing in a way that is required for GLFW/SDL binding, but could be handled better without

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05318E0E274C397200A8DE2E /* GameController.framework */; };
07A82ED82139413D0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
07A82ED92139418F0078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82ED72139413C0078D120 /* imgui_widgets.cpp */; };
5079822E257677DB0038A28D /* imgui_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5079822D257677DB0038A28D /* imgui_tables.cpp */; };
@ -32,6 +33,7 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
05318E0E274C397200A8DE2E /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
07A82ED62139413C0078D120 /* imgui_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = imgui_internal.h; path = ../../imgui_internal.h; sourceTree = "<group>"; };
07A82ED72139413C0078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; };
5079822D257677DB0038A28D /* imgui_tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_tables.cpp; path = ../../imgui_tables.cpp; sourceTree = "<group>"; };
@ -76,6 +78,7 @@
files = (
8309BDC6253CCCFE0045E2A1 /* AppKit.framework in Frameworks */,
83BBE9EC20EB471700295997 /* MetalKit.framework in Frameworks */,
05318E0F274C397200A8DE2E /* GameController.framework in Frameworks */,
83BBE9ED20EB471700295997 /* Metal.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -133,6 +136,7 @@
83BBE9E320EB46B800295997 /* Frameworks */ = {
isa = PBXGroup;
children = (
05318E0E274C397200A8DE2E /* GameController.framework */,
8309BDC5253CCCFE0045E2A1 /* AppKit.framework */,
8309BD8E253CCAAA0045E2A1 /* UIKit.framework */,
83BBE9EE20EB471C00295997 /* ModelIO.framework */,

@ -107,19 +107,7 @@
userInfo:nil];
[self.view addTrackingArea:trackingArea];
// If we want to receive key events, we either need to be in the responder chain of the key view,
// or else we can install a local monitor. The consequence of this heavy-handed approach is that
// we receive events for all controls, not just Dear ImGui widgets. If we had native controls in our
// window, we'd want to be much more careful than just ingesting the complete event stream.
// To match the behavior of other backends, we pass every event down to the OS.
NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged;
[NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event)
{
ImGui_ImplOSX_HandleEvent(event, self.view);
return event;
}];
ImGui_ImplOSX_Init();
ImGui_ImplOSX_Init(self.view);
#endif
}
@ -223,8 +211,7 @@
#if TARGET_OS_OSX
// Forward Mouse/Keyboard events to Dear ImGui OSX backend.
// Other events are registered via addLocalMonitorForEventsMatchingMask()
// Forward Mouse events to Dear ImGui OSX backend.
-(void)mouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); }
-(void)rightMouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); }
-(void)otherMouseDown:(NSEvent *)event { ImGui_ImplOSX_HandleEvent(event, self.view); }
@ -251,7 +238,7 @@
UITouch *anyTouch = event.allTouches.anyObject;
CGPoint touchLocation = [anyTouch locationInView:self.view];
ImGuiIO &io = ImGui::GetIO();
io.MousePos = ImVec2(touchLocation.x, touchLocation.y);
io.AddMousePosEvent(touchLocation.x, touchLocation.y);
BOOL hasActiveTouch = NO;
for (UITouch *touch in event.allTouches)
@ -262,7 +249,7 @@
break;
}
}
io.MouseDown[0] = hasActiveTouch;
io.AddMouseButtonEvent(0, hasActiveTouch);
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [self updateIOWithTouchEvent:event]; }

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05E31B57274EF0360083FCB6 /* GameController.framework */; };
07A82EDB213941D00078D120 /* imgui_widgets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 07A82EDA213941D00078D120 /* imgui_widgets.cpp */; };
4080A99820B02D340036BA46 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4080A98A20B02CD90036BA46 /* main.mm */; };
4080A9A220B034280036BA46 /* imgui_impl_opengl2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4080A99E20B034280036BA46 /* imgui_impl_opengl2.cpp */; };
@ -32,6 +33,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
05E31B57274EF0360083FCB6 /* GameController.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameController.framework; path = System/Library/Frameworks/GameController.framework; sourceTree = SDKROOT; };
07A82EDA213941D00078D120 /* imgui_widgets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = imgui_widgets.cpp; path = ../../imgui_widgets.cpp; sourceTree = "<group>"; };
4080A96B20B029B00036BA46 /* example_osx_opengl2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = example_osx_opengl2; sourceTree = BUILT_PRODUCTS_DIR; };
4080A98A20B02CD90036BA46 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = SOURCE_ROOT; };
@ -57,6 +59,7 @@
files = (
4080A9B520B034EA0036BA46 /* OpenGL.framework in Frameworks */,
4080A9B320B034E40036BA46 /* Cocoa.framework in Frameworks */,
05E31B59274EF0700083FCB6 /* GameController.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -95,6 +98,7 @@
4080A9B120B034E40036BA46 /* Frameworks */ = {
isa = PBXGroup;
children = (
05E31B57274EF0360083FCB6 /* GameController.framework */,
4080A9B420B034EA0036BA46 /* OpenGL.framework */,
4080A9B220B034E40036BA46 /* Cocoa.framework */,
);

@ -36,15 +36,6 @@
-(void)initialize
{
// Some events do not raise callbacks of AppView in some circumstances (for example when CMD key is held down).
// This monitor taps into global event stream and captures these events.
NSEventMask eventMask = NSEventMaskKeyDown | NSEventMaskKeyUp | NSEventMaskFlagsChanged;
[NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^NSEvent * _Nullable(NSEvent *event)
{
ImGui_ImplOSX_HandleEvent(event, self);
return event;
}];
// Setup Dear ImGui context
// FIXME: This example doesn't have proper cleanup...
IMGUI_CHECKVERSION();
@ -59,7 +50,7 @@
//ImGui::StyleColorsClassic();
// Setup Platform/Renderer backends
ImGui_ImplOSX_Init();
ImGui_ImplOSX_Init(self);
ImGui_ImplOpenGL2_Init();
// Load Fonts
@ -147,12 +138,9 @@
animationTimer = [NSTimer scheduledTimerWithTimeInterval:0.017 target:self selector:@selector(animationTimerFired:) userInfo:nil repeats:YES];
}
-(void)reshape { [[self openGLContext] update]; [self updateAndDrawDemoView]; }
-(void)reshape { [super reshape]; [[self openGLContext] update]; [self updateAndDrawDemoView]; }
-(void)drawRect:(NSRect)bounds { [self updateAndDrawDemoView]; }
-(void)animationTimerFired:(NSTimer*)timer { [self setNeedsDisplay:YES]; }
-(BOOL)acceptsFirstResponder { return (YES); }
-(BOOL)becomeFirstResponder { return (YES); }
-(BOOL)resignFirstResponder { return (YES); }
-(void)dealloc { animationTimer = nil; }
//-----------------------------------------------------------------------------------

@ -1,8 +1,11 @@
## How to Build
- You need to install Emscripten from https://emscripten.org/docs/getting_started/downloads.html, and have the environment variables set, as described in https://emscripten.org/docs/getting_started/downloads.html#installation-instructions
- You may also refer to our [Continuous Integration setup](https://github.com/ocornut/imgui/tree/master/.github/workflows) for Emscripten setup.
- Depending on your configuration, in Windows you may need to run `emsdk/emsdk_env.bat` in your console to access the Emscripten command-line tools.
- You may also refer to our [Continuous Integration setup](https://github.com/ocornut/imgui/tree/master/.github/workflows) for Emscripten setup.
- Then build using `make` while in the `example_emscripten_opengl3/` directory.
## How to Run
@ -15,6 +18,7 @@ _"Unfortunately several browsers (including Chrome, Safari, and Internet Explore
- Emscripten SDK has a handy `emrun` command: `emrun web/example_emscripten_opengl3.html --browser firefox` which will spawn a temporary local webserver (in Firefox). See https://emscripten.org/docs/compiling/Running-html-files-with-emrun.html for details.
- You may use Python 3 builtin webserver: `python -m http.server -d web` (this is what `make serve` uses).
- You may use Python 2 builtin webserver: `cd web && python -m SimpleHTTPServer`.
- If you are accessing the files over a network, certain browsers, such as Firefox, will restrict Gamepad API access to secure contexts only (e.g. https only).
## Obsolete features:

@ -1,10 +1,24 @@
# How to Build
## How to Build
- You need to install Emscripten from https://emscripten.org/docs/getting_started/downloads.html, and have the environment variables set, as described in https://emscripten.org/docs/getting_started/downloads.html#installation-instructions
- Depending on your configuration, in Windows you may need to run `emsdk/emsdk_env.bat` in your console to access the Emscripten command-line tools.
- You may also refer to our [Continuous Integration setup](https://github.com/ocornut/imgui/tree/master/.github/workflows) for Emscripten setup.
- Then build using `make` while in the `example_emscripten_wgpu/` directory.
- Requires Emscripten 2.0.10 (December 2020) due to GLFW adaptations
- Requires recent Emscripten as WGPU is still a work-in-progress API.
## How to Run
To run on a local machine:
- Make sure your browse supports WGPU and it is enabled. WGPU is still WIP not enabled by default in most browser.
- `make serve` will use Python3 to spawn a local webserver, you can then browse http://localhost:8000 to access your build.
- Otherwise, generally you will need a local webserver:
- Quoting [https://emscripten.org/docs/getting_started](https://emscripten.org/docs/getting_started/Tutorial.html#generating-html):<br>
_"Unfortunately several browsers (including Chrome, Safari, and Internet Explorer) do not support file:// [XHR](https://emscripten.org/docs/site/glossary.html#term-xhr) requests, and cant load extra files needed by the HTML (like a .wasm file, or packaged file data as mentioned lower down). For these browsers youll need to serve the files using a [local webserver](https://emscripten.org/docs/getting_started/FAQ.html#faq-local-webserver) and then open http://localhost:8000/hello.html."_
- Emscripten SDK has a handy `emrun` command: `emrun web/example_emscripten_opengl3.html --browser firefox` which will spawn a temporary local webserver (in Firefox). See https://emscripten.org/docs/compiling/Running-html-files-with-emrun.html for details.
- You may use Python 3 builtin webserver: `python -m http.server -d web` (this is what `make serve` uses).
- You may use Python 2 builtin webserver: `cd web && python -m SimpleHTTPServer`.
- If you are accessing the files over a network, certain browsers, such as Firefox, will restrict Gamepad API access to secure contexts only (e.g. https only).

@ -41,3 +41,4 @@ file(GLOB sources *.cpp)
add_executable(example_glfw_vulkan ${sources} ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp ${IMGUI_DIR}/backends/imgui_impl_vulkan.cpp ${IMGUI_DIR}/imgui.cpp ${IMGUI_DIR}/imgui_draw.cpp ${IMGUI_DIR}/imgui_demo.cpp ${IMGUI_DIR}/imgui_tables.cpp ${IMGUI_DIR}/imgui_widgets.cpp)
target_link_libraries(example_glfw_vulkan ${LIBRARIES})
target_compile_definitions(example_glfw_vulkan PUBLIC -DImTextureID=ImU64)

@ -7,8 +7,8 @@
@set OUT_DIR=Debug
mkdir %OUT_DIR%
cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
cl /nologo /Zi /MD %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
@set OUT_DIR=Release
mkdir %OUT_DIR%
cl /nologo /Zi /MD /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
cl /nologo /Zi /MD /Ox /Oi %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%

@ -6,8 +6,8 @@
@set OUT_DIR=Debug
mkdir %OUT_DIR%
cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
cl /nologo /Zi /MD %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
@set OUT_DIR=Release
mkdir %OUT_DIR%
cl /nologo /Zi /MD /Ox /Oi %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%
cl /nologo /Zi /MD /Ox /Oi %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS%

@ -91,6 +91,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -105,6 +106,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -122,6 +124,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -142,6 +145,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;..\libs\glfw\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

@ -416,9 +416,11 @@ int main(int, char**)
init_info.Queue = g_Queue;
init_info.PipelineCache = g_PipelineCache;
init_info.DescriptorPool = g_DescriptorPool;
init_info.Allocator = g_Allocator;
init_info.Subpass = 0;
init_info.MinImageCount = g_MinImageCount;
init_info.ImageCount = wd->ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = g_Allocator;
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);

@ -1,32 +0,0 @@
# This file is for configuration settings for your
# application.
#
# The syntax is similar to windows .ini files ie
#
# [GroupName]
# Setting = Value
#
# Which can be read by your application using
# e.g s3eConfigGetString("GroupName", "Setting", string)
#
# All settings must be documented in .config.txt files.
# New settings specific to this application should be
# documented in app.config.txt
#
# Some conditional operations are also permitted, see the
# S3E documentation for details.
[S3E]
MemSize=6000000
MemSizeDebug=6000000
DispFixRot=FixedLandscape
# emulate iphone 5 resolution, change these settings to emulate other display resolution
WinWidth=1136
WinHeight=640
[GX]
DataCacheSize=131070
[Util]
#MemoryBreakpoint=1282

@ -1,47 +0,0 @@
#!/usr/bin/env mkb
# ImGui - standalone example application for Marmalade
# Copyright (C) 2015 by Giovanni Zito
# This file is part of ImGui
# https://github.com/ocornut/imgui
define IMGUI_DISABLE_INCLUDE_IMCONFIG_H
define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCS
define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCS
define _snprintf=snprintf
options
{
optimise-speed=1
}
includepaths
{
../..
../../backends
}
subprojects
{
iwgx
}
files
{
(.)
["imgui"]
../../imgui.cpp
../../imgui_demo.cpp
../../imgui_draw.cpp
../../imgui_tables.cpp
../../imgui_widgets.cpp
../../imconfig.h
../../imgui.h
../../imgui_internal.h
["imgui","Marmalade backend"]
../../backends/imgui_impl_marmalade.h
../../backends/imgui_impl_marmalade.cpp
main.cpp
}

@ -8,9 +8,10 @@
#include "imgui_impl_opengl3.h"
#include <stdio.h>
#include <SDL.h>
#include <SDL_opengl.h>
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL_opengles2.h>
#else
#include <SDL_opengl.h>
#endif
// Main code

@ -0,0 +1,79 @@
#
# Cross Platform Makefile
# Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X
#
# You will need SDL2 (http://www.libsdl.org):
# Linux:
# apt-get install libsdl2-dev
# Mac OS X:
# brew install sdl2
# MSYS2:
# pacman -S mingw-w64-i686-SDL2
#
#CXX = g++
#CXX = clang++
EXE = example_sdl_sdlrenderer
IMGUI_DIR = ../..
SOURCES = main.cpp
SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp
SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlrenderer.cpp
OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s)
CXXFLAGS = -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends
CXXFLAGS += -g -Wall -Wformat
LIBS =
##---------------------------------------------------------------------
## BUILD FLAGS PER PLATFORM
##---------------------------------------------------------------------
ifeq ($(UNAME_S), Linux) #LINUX
ECHO_MESSAGE = "Linux"
LIBS += -lGL -ldl `sdl2-config --libs`
CXXFLAGS += `sdl2-config --cflags`
CFLAGS = $(CXXFLAGS)
endif
ifeq ($(UNAME_S), Darwin) #APPLE
ECHO_MESSAGE = "Mac OS X"
LIBS += -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo `sdl2-config --libs`
LIBS += -L/usr/local/lib -L/opt/local/lib
CXXFLAGS += `sdl2-config --cflags`
CXXFLAGS += -I/usr/local/include -I/opt/local/include
CFLAGS = $(CXXFLAGS)
endif
ifeq ($(OS), Windows_NT)
ECHO_MESSAGE = "MinGW"
LIBS += -lgdi32 -lopengl32 -limm32 `pkg-config --static --libs sdl2`
CXXFLAGS += `pkg-config --cflags sdl2`
CFLAGS = $(CXXFLAGS)
endif
##---------------------------------------------------------------------
## BUILD RULES
##---------------------------------------------------------------------
%.o:%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
%.o:$(IMGUI_DIR)/backends/%.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
all: $(EXE)
@echo Build complete for $(ECHO_MESSAGE)
$(EXE): $(OBJS)
$(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS)
clean:
rm -f $(EXE) $(OBJS)

@ -0,0 +1,25 @@
# How to Build
- On Windows with Visual Studio's CLI
```
set SDL2_DIR=path_to_your_sdl2_folder
cl /Zi /MD /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_sdlrenderer.cpp ..\..\imgui*.cpp /FeDebug/example_sdl_sdlrenderer.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib /subsystem:console
# ^^ include paths ^^ source files ^^ output exe ^^ output dir ^^ libraries
# or for 64-bit:
cl /Zi /MD /I.. /I..\.. /I%SDL2_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_sdlrenderer.cpp ..\..\imgui*.cpp /FeDebug/example_sdl_sdlrenderer.exe /FoDebug/ /link /libpath:%SDL2_DIR%\lib\x64 SDL2.lib SDL2main.lib /subsystem:console
```
- On Linux and similar Unixes
```
c++ `sdl2-config --cflags` -I .. -I ../.. main.cpp ../../backends/imgui_impl_sdl.cpp ../../backends/imgui_impl_sdlrenderer.cpp ../../imgui*.cpp `sdl2-config --libs` -lGL
```
- On Mac OS X
```
brew install sdl2
c++ `sdl2-config --cflags` -I .. -I ../.. main.cpp ../../backends/imgui_impl_sdl.cpp ../../backends/imgui_impl_sdlrenderer.cpp ../../imgui*.cpp `sdl2-config --libs` -framework OpenGl
```

@ -0,0 +1,8 @@
@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler.
@set OUT_DIR=Debug
@set OUT_EXE=example_sdl_sdlrenderer_
@set INCLUDES=/I..\.. /I..\..\backends /I%SDL2_DIR%\include
@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl.cpp ..\..\backends\imgui_impl_sdlrenderer.cpp ..\..\imgui*.cpp
@set LIBS=/LIBPATH:%SDL2_DIR%\lib\x86 SDL2.lib SDL2main.lib
mkdir %OUT_DIR%
cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console

@ -0,0 +1,181 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2AE17FDE-F7F3-4CAC-ADAB-0710EDA4F741}</ProjectGuid>
<RootNamespace>example_sdl_sdlrenderer</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(ProjectDir)$(Configuration)\</OutDir>
<IntDir>$(ProjectDir)$(Configuration)\</IntDir>
<IncludePath>$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%SDL2_DIR%\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>%SDL2_DIR%\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<IgnoreSpecificDefaultLibraries>
</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\imgui.cpp" />
<ClCompile Include="..\..\imgui_demo.cpp" />
<ClCompile Include="..\..\imgui_draw.cpp" />
<ClCompile Include="..\..\imgui_tables.cpp" />
<ClCompile Include="..\..\imgui_widgets.cpp" />
<ClCompile Include="..\..\backends\imgui_impl_sdlrenderer.cpp" />
<ClCompile Include="..\..\backends\imgui_impl_sdl.cpp" />
<ClCompile Include="main.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\imconfig.h" />
<ClInclude Include="..\..\imgui.h" />
<ClInclude Include="..\..\imgui_internal.h" />
<ClInclude Include="..\..\backends\imgui_impl_sdlrenderer.h" />
<ClInclude Include="..\..\backends\imgui_impl_sdl.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\misc\debuggers\imgui.natvis" />
<None Include="..\README.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="imgui">
<UniqueIdentifier>{20b90ce4-7fcb-4731-b9a0-075f875de82d}</UniqueIdentifier>
</Filter>
<Filter Include="sources">
<UniqueIdentifier>{f18ab499-84e1-499f-8eff-9754361e0e52}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\imgui.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_demo.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_draw.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="main.cpp">
<Filter>sources</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_tables.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\imgui_widgets.cpp">
<Filter>imgui</Filter>
</ClCompile>
<ClCompile Include="..\..\backends\imgui_impl_sdl.cpp">
<Filter>sources</Filter>
</ClCompile>
<ClCompile Include="..\..\backends\imgui_impl_sdlrenderer.cpp">
<Filter>sources</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\imconfig.h">
<Filter>imgui</Filter>
</ClInclude>
<ClInclude Include="..\..\imgui.h">
<Filter>imgui</Filter>
</ClInclude>
<ClInclude Include="..\..\imgui_internal.h">
<Filter>imgui</Filter>
</ClInclude>
<ClInclude Include="..\..\backends\imgui_impl_sdlrenderer.h">
<Filter>sources</Filter>
</ClInclude>
<ClInclude Include="..\..\backends\imgui_impl_sdl.h">
<Filter>sources</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\README.txt" />
<None Include="..\..\misc\debuggers\imgui.natvis">
<Filter>sources</Filter>
</None>
</ItemGroup>
</Project>

@ -1,35 +1,63 @@
// Dear ImGui: standalone example application for Marmalade
// Dear ImGui: standalone example application for SDL2 + SDL_Renderer
// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.)
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
// Copyright (C) 2015 by Giovanni Zito
// This file is part of Dear ImGui
// Important to understand: SDL_Renderer is an _optional_ component of SDL. We do not recommend you use SDL_Renderer
// because it provide a rather limited API to the end-user. We provide this backend for the sake of completeness.
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
#include "imgui.h"
#include "imgui_impl_marmalade.h"
#include "imgui_impl_sdl.h"
#include "imgui_impl_sdlrenderer.h"
#include <stdio.h>
#include <SDL.h>
#include <s3eKeyboard.h>
#include <s3ePointer.h>
#include <IwGx.h>
#if !SDL_VERSION_ATLEAST(2,0,17)
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
#endif
// Main code
int main(int, char**)
{
IwGxInit();
// Setup SDL
// (Some versions of SDL before <2.0.10 appears to have performance/stalling issues on a minority of Windows systems,
// depending on whether SDL_INIT_GAMECONTROLLER is enabled or disabled.. updating to latest version of SDL is recommended!)
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) != 0)
{
printf("Error: %s\n", SDL_GetError());
return -1;
}
// Setup window
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL2+SDL_Renderer example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
// Setup SDL_Renderer instance
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
if (renderer == NULL)
{
SDL_Log("Error creating SDL_Renderer!");
return false;
}
//SDL_RendererInfo info;
//SDL_GetRendererInfo(renderer, &info);
//SDL_Log("Current SDL_Renderer: %s", info.name);
// Setup Dear ImGui context
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
// Setup Platform/Renderer backends
ImGui_Marmalade_Init(true);
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
ImGui_ImplSDLRenderer_Init(renderer);
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
@ -52,21 +80,27 @@ int main(int, char**)
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Main loop
while (true)
bool done = false;
while (!done)
{
if (s3eDeviceCheckQuitRequest())
break;
// Poll and handle inputs
// Poll and handle events (inputs, window resize, etc.)
// 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.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
s3eKeyboardUpdate();
s3ePointerUpdate();
SDL_Event event;
while (SDL_PollEvent(&event))
{
ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
done = true;
}
// Start the Dear ImGui frame
ImGui_Marmalade_NewFrame();
ImGui_ImplSDLRenderer_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
@ -108,18 +142,20 @@ int main(int, char**)
// Rendering
ImGui::Render();
IwGxSetColClear(clear_color.x * 255, clear_color.y * 255, clear_color.z * 255, clear_color.w * 255);
IwGxClear();
ImGui_Marmalade_RenderDrawData(ImGui::GetDrawData());
IwGxSwapBuffers();
s3eDeviceYield(0);
SDL_SetRenderDrawColor(renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255));
SDL_RenderClear(renderer);
ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData());
SDL_RenderPresent(renderer);
}
// Cleanup
ImGui_Marmalade_Shutdown();
ImGui_ImplSDLRenderer_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
IwGxTerminate();
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}

@ -7,4 +7,4 @@
@set OUT_DIR=Debug
mkdir %OUT_DIR%
cl /nologo /Zi /MD %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console
cl /nologo /Zi /MD %INCLUDES% /D ImTextureID=ImU64 %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console

@ -91,6 +91,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -105,6 +106,7 @@
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -122,6 +124,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@ -142,6 +145,7 @@
<IntrinsicFunctions>true</IntrinsicFunctions>
<AdditionalIncludeDirectories>..\..;..\..\backends;%VULKAN_SDK%\include;%SDL2_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL2;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>ImTextureID=ImU64;_MBCS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

@ -408,9 +408,11 @@ int main(int, char**)
init_info.Queue = g_Queue;
init_info.PipelineCache = g_PipelineCache;
init_info.DescriptorPool = g_DescriptorPool;
init_info.Allocator = g_Allocator;
init_info.Subpass = 0;
init_info.MinImageCount = g_MinImageCount;
init_info.ImageCount = wd->ImageCount;
init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT;
init_info.Allocator = g_Allocator;
init_info.CheckVkResultFn = check_vk_result;
ImGui_ImplVulkan_Init(&init_info, wd->RenderPass);

@ -28,12 +28,13 @@
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
//---- Disable all of Dear ImGui or don't implement standard windows.
// It is very strongly recommended to NOT disable the demo windows during development. Please read comments in imgui_demo.cpp.
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty. Not recommended.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger window: ShowMetricsWindow() will be empty.
//#define IMGUI_DISABLE_METRICS_WINDOW // Disable metrics/debugger and other debug tools: ShowMetricsWindow() and ShowStackToolWindow() will be empty.
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,4 +1,4 @@
// dear imgui, v1.84
// dear imgui, v1.87
// (drawing and font code)
/*
@ -408,10 +408,11 @@ void ImDrawListSharedData::SetCircleTessellationMaxError(float max_error)
void ImDrawList::_ResetForNewFrame()
{
// Verify that the ImDrawCmd fields we want to memcmp() are contiguous in memory.
// (those should be IM_STATIC_ASSERT() in theory but with our pre C++11 setup the whole check doesn't compile with GCC)
IM_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
IM_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
IM_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, ClipRect) == 0);
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, TextureId) == sizeof(ImVec4));
IM_STATIC_ASSERT(IM_OFFSETOF(ImDrawCmd, VtxOffset) == sizeof(ImVec4) + sizeof(ImTextureID));
if (_Splitter._Count > 1)
_Splitter.Merge(this);
CmdBuffer.resize(0);
IdxBuffer.resize(0);
@ -484,6 +485,7 @@ void ImDrawList::_PopUnusedDrawCmd()
void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
{
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
IM_ASSERT(curr_cmd->UserCallback == NULL);
if (curr_cmd->ElemCount != 0)
@ -498,16 +500,18 @@ void ImDrawList::AddCallback(ImDrawCallback callback, void* callback_data)
}
// Compare ClipRect, TextureId and VtxOffset with a single memcmp()
#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset
#define ImDrawCmd_HeaderSize (IM_OFFSETOF(ImDrawCmd, VtxOffset) + sizeof(unsigned int))
#define ImDrawCmd_HeaderCompare(CMD_LHS, CMD_RHS) (memcmp(CMD_LHS, CMD_RHS, ImDrawCmd_HeaderSize)) // Compare ClipRect, TextureId, VtxOffset
#define ImDrawCmd_HeaderCopy(CMD_DST, CMD_SRC) (memcpy(CMD_DST, CMD_SRC, ImDrawCmd_HeaderSize)) // Copy ClipRect, TextureId, VtxOffset
#define ImDrawCmd_AreSequentialIdxOffset(CMD_0, CMD_1) (CMD_0->IdxOffset + CMD_0->ElemCount == CMD_1->IdxOffset)
// Try to merge two last draw commands
void ImDrawList::_TryMergeDrawCmds()
{
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
ImDrawCmd* prev_cmd = curr_cmd - 1;
if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL)
if (ImDrawCmd_HeaderCompare(curr_cmd, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && curr_cmd->UserCallback == NULL && prev_cmd->UserCallback == NULL)
{
prev_cmd->ElemCount += curr_cmd->ElemCount;
CmdBuffer.pop_back();
@ -519,6 +523,7 @@ void ImDrawList::_TryMergeDrawCmds()
void ImDrawList::_OnChangedClipRect()
{
// If current command is used with different settings we need to add a new command
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
if (curr_cmd->ElemCount != 0 && memcmp(&curr_cmd->ClipRect, &_CmdHeader.ClipRect, sizeof(ImVec4)) != 0)
{
@ -529,7 +534,7 @@ void ImDrawList::_OnChangedClipRect()
// Try to merge with previous command if it matches, else use current command
ImDrawCmd* prev_cmd = curr_cmd - 1;
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
{
CmdBuffer.pop_back();
return;
@ -541,6 +546,7 @@ void ImDrawList::_OnChangedClipRect()
void ImDrawList::_OnChangedTextureID()
{
// If current command is used with different settings we need to add a new command
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
if (curr_cmd->ElemCount != 0 && curr_cmd->TextureId != _CmdHeader.TextureId)
{
@ -551,7 +557,7 @@ void ImDrawList::_OnChangedTextureID()
// Try to merge with previous command if it matches, else use current command
ImDrawCmd* prev_cmd = curr_cmd - 1;
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && prev_cmd->UserCallback == NULL)
if (curr_cmd->ElemCount == 0 && CmdBuffer.Size > 1 && ImDrawCmd_HeaderCompare(&_CmdHeader, prev_cmd) == 0 && ImDrawCmd_AreSequentialIdxOffset(prev_cmd, curr_cmd) && prev_cmd->UserCallback == NULL)
{
CmdBuffer.pop_back();
return;
@ -564,6 +570,7 @@ void ImDrawList::_OnChangedVtxOffset()
{
// We don't need to compare curr_cmd->VtxOffset != _CmdHeader.VtxOffset because we know it'll be different at the time we call this.
_VtxCurrentIdx = 0;
IM_ASSERT_PARANOID(CmdBuffer.Size > 0);
ImDrawCmd* curr_cmd = &CmdBuffer.Data[CmdBuffer.Size - 1];
//IM_ASSERT(curr_cmd->VtxOffset != _CmdHeader.VtxOffset); // See #3349
if (curr_cmd->ElemCount != 0)
@ -1739,13 +1746,13 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list)
for (int i = 1; i < _Count; i++)
{
ImDrawChannel& ch = _Channels[i];
// Equivalent of PopUnusedDrawCmd() for this channel's cmdbuffer and except we don't need to test for UserCallback.
if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0)
if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0 && ch._CmdBuffer.back().UserCallback == NULL) // Equivalent of PopUnusedDrawCmd()
ch._CmdBuffer.pop_back();
if (ch._CmdBuffer.Size > 0 && last_cmd != NULL)
{
// Do not include ImDrawCmd_AreSequentialIdxOffset() in the compare as we rebuild IdxOffset values ourselves.
// Manipulating IdxOffset (e.g. by reordering draw commands like done by RenderDimmedBackgroundBehindWindow()) is not supported within a splitter.
ImDrawCmd* next_cmd = &ch._CmdBuffer[0];
if (ImDrawCmd_HeaderCompare(last_cmd, next_cmd) == 0 && last_cmd->UserCallback == NULL && next_cmd->UserCallback == NULL)
{
@ -1930,37 +1937,38 @@ ImFontConfig::ImFontConfig()
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
// The 2x2 white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 108; // Actual texture will be 2 times that + 1 spacing.
// (This is used when io.MouseDrawCursor = true)
const int FONT_ATLAS_DEFAULT_TEX_DATA_W = 122; // Actual texture will be 2 times that + 1 spacing.
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
static const char FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS[FONT_ATLAS_DEFAULT_TEX_DATA_W * FONT_ATLAS_DEFAULT_TEX_DATA_H + 1] =
{
"..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX "
"..- -X.....X- X.X - X.X -X.....X - X.....X- X..X "
"--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X "
"X - X.X - X.....X - X.....X -X...X - X...X- X..X "
"XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X "
"X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX "
"X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX "
"X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX "
"X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X "
"X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X"
"X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X"
"X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X"
"X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X"
"X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X"
"X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X"
"X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X"
"X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X "
"X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X "
"X.X X..X - -X.......X- X.......X - XX XX - - X..........X "
"XX X..X - - X.....X - X.....X - X.X X.X - - X........X "
" X..X - X...X - X...X - X..X X..X - - X........X "
" XX - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX "
"------------ - X - X -X.....................X- ------------------"
" ----------------------------------- X...XXXXXXXXXXXXX...X - "
" - X..X X..X - "
" - X.X X.X - "
" - XX XX - "
"..- -XXXXXXX- X - X -XXXXXXX - XXXXXXX- XX - XX XX "
"..- -X.....X- X.X - X.X -X.....X - X.....X- X..X -X..X X..X"
"--- -XXX.XXX- X...X - X...X -X....X - X....X- X..X -X...X X...X"
"X - X.X - X.....X - X.....X -X...X - X...X- X..X - X...X X...X "
"XX - X.X -X.......X- X.......X -X..X.X - X.X..X- X..X - X...X...X "
"X.X - X.X -XXXX.XXXX- XXXX.XXXX -X.X X.X - X.X X.X- X..XXX - X.....X "
"X..X - X.X - X.X - X.X -XX X.X - X.X XX- X..X..XXX - X...X "
"X...X - X.X - X.X - XX X.X XX - X.X - X.X - X..X..X..XX - X.X "
"X....X - X.X - X.X - X.X X.X X.X - X.X - X.X - X..X..X..X.X - X...X "
"X.....X - X.X - X.X - X..X X.X X..X - X.X - X.X -XXX X..X..X..X..X- X.....X "
"X......X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X XX-XX X.X -X..XX........X..X- X...X...X "
"X.......X - X.X - X.X -X.....................X- X.X X.X-X.X X.X -X...X...........X- X...X X...X "
"X........X - X.X - X.X - X...XXXXXX.XXXXXX...X - X.X..X-X..X.X - X..............X-X...X X...X"
"X.........X -XXX.XXX- X.X - X..X X.X X..X - X...X-X...X - X.............X-X..X X..X"
"X..........X-X.....X- X.X - X.X X.X X.X - X....X-X....X - X.............X- XX XX "
"X......XXXXX-XXXXXXX- X.X - XX X.X XX - X.....X-X.....X - X............X--------------"
"X...X..X --------- X.X - X.X - XXXXXXX-XXXXXXX - X...........X - "
"X..X X..X - -XXXX.XXXX- XXXX.XXXX ------------------------------------- X..........X - "
"X.X X..X - -X.......X- X.......X - XX XX - - X..........X - "
"XX X..X - - X.....X - X.....X - X.X X.X - - X........X - "
" X..X - - X...X - X...X - X..X X..X - - X........X - "
" XX - - X.X - X.X - X...XXXXXXXXXXXXX...X - - XXXXXXXXXX - "
"------------- - X - X -X.....................X- ------------------- "
" ----------------------------------- X...XXXXXXXXXXXXX...X - "
" - X..X X..X - "
" - X.X X.X - "
" - XX XX - "
};
static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3] =
@ -1974,6 +1982,7 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3
{ ImVec2(73,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNESW
{ ImVec2(55,0), ImVec2(17,17), ImVec2( 8, 8) }, // ImGuiMouseCursor_ResizeNWSE
{ ImVec2(91,0), ImVec2(17,22), ImVec2( 5, 0) }, // ImGuiMouseCursor_Hand
{ ImVec2(109,0),ImVec2(13,15), ImVec2( 6, 7) }, // ImGuiMouseCursor_NotAllowed
};
ImFontAtlas::ImFontAtlas()
@ -2009,7 +2018,7 @@ void ImFontAtlas::ClearInputData()
ConfigData.clear();
CustomRects.clear();
PackIdMouseCursors = PackIdLines = -1;
TexReady = false;
// Important: we leave TexReady untouched
}
void ImFontAtlas::ClearTexData()
@ -3084,8 +3093,8 @@ void ImFontGlyphRangesBuilder::AddText(const char* text, const char* text_end)
void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
{
for (; ranges[0]; ranges += 2)
for (ImWchar c = ranges[0]; c <= ranges[1]; c++)
AddChar(c);
for (unsigned int c = ranges[0]; c <= ranges[1] && c <= IM_UNICODE_CODEPOINT_MAX; c++) //-V560
AddChar((ImWchar)c);
}
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
@ -3740,7 +3749,6 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
// - RenderArrow()
// - RenderBullet()
// - RenderCheckMark()
// - RenderMouseCursor()
// - RenderArrowDockMenu()
// - RenderArrowPointingAt()
// - RenderRectFilledRangeH()
@ -3802,27 +3810,6 @@ void ImGui::RenderCheckMark(ImDrawList* draw_list, ImVec2 pos, ImU32 col, float
draw_list->PathStroke(col, 0, thickness);
}
void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
{
if (mouse_cursor == ImGuiMouseCursor_None)
return;
IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas;
ImVec2 offset, size, uv[4];
if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
{
pos -= offset;
ImTextureID tex_id = font_atlas->TexID;
draw_list->PushTextureID(tex_id);
draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);
draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);
draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border);
draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill);
draw_list->PopTextureID();
}
}
// Render an arrow. 'pos' is position of the arrow tip. half_sz.x is length from base to tip. half_sz.y is length on each side.
void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col)
{
@ -3919,16 +3906,27 @@ void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect
const bool fill_R = (inner.Max.x < outer.Max.x);
const bool fill_U = (inner.Min.y > outer.Min.y);
const bool fill_D = (inner.Max.y < outer.Max.y);
if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomLeft));
if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_U ? 0 : ImDrawFlags_RoundCornersTopRight) | (fill_D ? 0 : ImDrawFlags_RoundCornersBottomRight));
if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersTopLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersTopRight));
if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersNone | (fill_L ? 0 : ImDrawFlags_RoundCornersBottomLeft) | (fill_R ? 0 : ImDrawFlags_RoundCornersBottomRight));
if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopLeft);
if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawFlags_RoundCornersTopRight);
if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomLeft);
if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawFlags_RoundCornersBottomRight);
}
ImDrawFlags ImGui::CalcRoundingFlagsForRectInRect(const ImRect& r_in, const ImRect& r_outer, float threshold)
{
bool round_l = r_in.Min.x <= r_outer.Min.x + threshold;
bool round_r = r_in.Max.x >= r_outer.Max.x - threshold;
bool round_t = r_in.Min.y <= r_outer.Min.y + threshold;
bool round_b = r_in.Max.y >= r_outer.Max.y - threshold;
return ImDrawFlags_RoundCornersNone
| ((round_t && round_l) ? ImDrawFlags_RoundCornersTopLeft : 0) | ((round_t && round_r) ? ImDrawFlags_RoundCornersTopRight : 0)
| ((round_b && round_l) ? ImDrawFlags_RoundCornersBottomLeft : 0) | ((round_b && round_r) ? ImDrawFlags_RoundCornersBottomRight : 0);
}
// Helper for ColorPicker4()
// NB: This is rather brittle and will show artifact when rounding this enabled if rounded corners overlap multiple cells. Caller currently responsible for avoiding that.
// Spent a non reasonable amount of time trying to getting this right for ColorButton with rounding+anti-aliasing+ImGuiColorEditFlags_HalfAlphaPreview flag + various grid sizes and offsets, and eventually gave up... probably more reasonable to disable rounding altogether.

File diff suppressed because it is too large Load Diff

@ -1,4 +1,4 @@
// dear imgui, v1.84
// dear imgui, v1.87
// (tables and columns code)
/*
@ -324,7 +324,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
const ImVec2 avail_size = GetContentRegionAvail();
ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);
ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
if (use_child_window && IsClippedEx(outer_rect, 0, false))
if (use_child_window && IsClippedEx(outer_rect, 0))
{
ItemSize(outer_rect);
return false;
@ -340,10 +340,9 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Acquire temporary buffers
const int table_idx = g.Tables.GetIndex(table);
g.CurrentTableStackIdx++;
if (g.CurrentTableStackIdx + 1 > g.TablesTempDataStack.Size)
g.TablesTempDataStack.resize(g.CurrentTableStackIdx + 1, ImGuiTableTempData());
ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempDataStack[g.CurrentTableStackIdx];
if (++g.TablesTempDataStacked > g.TablesTempData.Size)
g.TablesTempData.resize(g.TablesTempDataStacked, ImGuiTableTempData());
ImGuiTableTempData* temp_data = table->TempData = &g.TablesTempData[g.TablesTempDataStacked - 1];
temp_data->TableIndex = table_idx;
table->DrawSplitter = &table->TempData->DrawSplitter;
table->DrawSplitter->Clear();
@ -564,6 +563,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// + 0 (for ImGuiTable instance, we are pooling allocations in g.Tables)
// + 1 (for table->RawData allocated below)
// + 1 (for table->ColumnsNames, if names are used)
// Shared allocations per number of nested tables
// + 1 (for table->Splitter._Channels)
// + 2 * active_channels_count (for ImDrawCmd and ImDrawIdx buffers inside channels)
// Where active_channels_count is variable but often == columns_count or columns_count + 1, see TableSetupDrawChannels() for details.
@ -1170,7 +1170,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
KeepAliveID(column_id);
bool hovered = false, held = false;
bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick);
bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick | ImGuiButtonFlags_NoNavFocus);
if (pressed && IsMouseDoubleClicked(0))
{
TableSetColumnWidthAutoSingle(table, column_n);
@ -1381,9 +1381,8 @@ void ImGui::EndTable()
// Clear or restore current table, if any
IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table);
IM_ASSERT(g.CurrentTableStackIdx >= 0);
g.CurrentTableStackIdx--;
temp_data = g.CurrentTableStackIdx >= 0 ? &g.TablesTempDataStack[g.CurrentTableStackIdx] : NULL;
IM_ASSERT(g.TablesTempDataStacked > 0);
temp_data = (--g.TablesTempDataStacked > 0) ? &g.TablesTempData[g.TablesTempDataStacked - 1] : NULL;
g.CurrentTable = temp_data ? g.Tables.GetByIndex(temp_data->TableIndex) : NULL;
if (g.CurrentTable)
{
@ -1479,6 +1478,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
// Ensure frozen columns are ordered in their section. We still allow multiple frozen columns to be reordered.
// FIXME-TABLE: This work for preserving 2143 into 21|43. How about 4321 turning into 21|43? (preserve relative order in each section)
for (int column_n = 0; column_n < table->FreezeColumnsRequest; column_n++)
{
int order_n = table->DisplayOrderToIndex[column_n];
@ -1569,18 +1569,21 @@ ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n)
// Return the cell rectangle based on currently known height.
// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations.
// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it.
// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it, or in TableEndRow() when we locked that height.
// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right
// columns report a small offset so their CellBgRect can extend up to the outer border.
// FIXME: But the rendering code in TableEndRow() nullifies that with clamping required for scrolling.
ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
{
const ImGuiTableColumn* column = &table->Columns[column_n];
float x1 = column->MinX;
float x2 = column->MaxX;
if (column->PrevEnabledColumn == -1)
x1 -= table->CellSpacingX1;
if (column->NextEnabledColumn == -1)
x2 += table->CellSpacingX2;
//if (column->PrevEnabledColumn == -1)
// x1 -= table->OuterPaddingX;
//if (column->NextEnabledColumn == -1)
// x2 += table->OuterPaddingX;
x1 = ImMax(x1, table->WorkRect.Min.x);
x2 = ImMin(x2, table->WorkRect.Max.x);
return ImRect(x1, table->RowPosY1, x2, table->RowPosY2);
}
@ -1797,10 +1800,12 @@ void ImGui::TableEndRow(ImGuiTable* table)
ImGuiTableCellData* cell_data_end = &table->RowCellData[table->RowCellDataCurrent];
for (ImGuiTableCellData* cell_data = &table->RowCellData[0]; cell_data <= cell_data_end; cell_data++)
{
// As we render the BG here we need to clip things (for layout we would not)
// FIXME: This cancels the OuterPadding addition done by TableGetCellBgRect(), need to keep it while rendering correctly while scrolling.
const ImGuiTableColumn* column = &table->Columns[cell_data->Column];
ImRect cell_bg_rect = TableGetCellBgRect(table, cell_data->Column);
cell_bg_rect.ClipWith(table->BgClipRect);
cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped
cell_bg_rect.Min.x = ImMax(cell_bg_rect.Min.x, column->ClipRect.Min.x); // So that first column after frozen one gets clipped when scrolling
cell_bg_rect.Max.x = ImMin(cell_bg_rect.Max.x, column->MaxX);
window->DrawList->AddRectFilled(cell_bg_rect.Min, cell_bg_rect.Max, cell_data->BgColor);
}
@ -2353,7 +2358,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
// Don't attempt to merge if there are multiple draw calls within the column
ImDrawChannel* src_channel = &splitter->_Channels[channel_no];
if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0)
if (src_channel->_CmdBuffer.Size > 0 && src_channel->_CmdBuffer.back().ElemCount == 0 && src_channel->_CmdBuffer.back().UserCallback != NULL) // Equivalent of PopUnusedDrawCmd()
src_channel->_CmdBuffer.pop_back();
if (src_channel->_CmdBuffer.Size != 1)
continue;
@ -3987,7 +3992,7 @@ void ImGui::EndColumns()
const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
KeepAliveID(column_id);
if (IsClippedEx(column_hit_rect, column_id, false))
if (IsClippedEx(column_hit_rect, column_id)) // FIXME: Can be removed or replaced with a lower-level test
continue;
bool hovered = false, held = false;

File diff suppressed because it is too large Load Diff

@ -1,10 +1,6 @@
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
// This is also an example of how you may wrap your own similar types.
// Compatibility:
// - std::string support is only guaranteed to work from C++11.
// If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture)
// Changelog:
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string

@ -1,10 +1,6 @@
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
// This is also an example of how you may wrap your own similar types.
// Compatibility:
// - std::string support is only guaranteed to work from C++11.
// If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture)
// Changelog:
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string

@ -26,12 +26,12 @@ See https://gist.github.com/ocornut/b3a9ecf13502fd818799a452969649ad
### Comparaison
Small, thin anti-aliased fonts are typically benefiting a lots from Freetype's hinting:
Small, thin anti-aliased fonts typically benefit a lot from FreeType's hinting:
![comparing_font_rasterizers](https://user-images.githubusercontent.com/8225057/107550178-fef87f00-6bd0-11eb-8d09-e2edb2f0ccfc.gif)
### Colorful glyphs/emojis
You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain colorful glyphs. See
You can use the `ImGuiFreeTypeBuilderFlags_LoadColor` flag to load certain colorful glyphs. See the
["Using Colorful Glyphs/Emojis"](https://github.com/ocornut/imgui/edit/master/docs/FONTS.md#using-colorful-glyphsemojis) section of FONTS.md.
![colored glyphs](https://user-images.githubusercontent.com/8225057/106171241-9dc4ba80-6191-11eb-8a69-ca1467b206d1.png)

@ -6,6 +6,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2021/08/23: fixed crash when FT_Render_Glyph() fails to render a glyph and returns NULL.
// 2021/03/05: added ImGuiFreeTypeBuilderFlags_Bitmap to load bitmap glyphs.
// 2021/03/02: set 'atlas->TexPixelsUseColors = true' to help some backends with deciding of a prefered texture format.
// 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+).
@ -225,6 +226,12 @@ namespace
uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
if (glyph_index == 0)
return NULL;
// If this crash for you: FreeType 2.11.0 has a crash bug on some bitmap/colored fonts.
// - https://gitlab.freedesktop.org/freetype/freetype/-/issues/1076
// - https://github.com/ocornut/imgui/issues/4567
// - https://github.com/ocornut/imgui/issues/4566
// You can use FreeType 2.10, or the patched version of 2.11.0 in VcPkg, or probably any upcoming FreeType version.
FT_Error error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
if (error)
return NULL;
@ -539,7 +546,8 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u
// Render glyph into a bitmap (currently held by FreeType)
const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
IM_ASSERT(ft_bitmap);
if (ft_bitmap == NULL)
continue;
// Allocate new temporary chunk if needed
const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4;

Loading…
Cancel
Save