diff --git a/README.md b/README.md index b3a14999..273be08c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ ImGui ===== [![Build Status](https://travis-ci.org/ocornut/imgui.svg?branch=master)](https://travis-ci.org/ocornut/imgui) +[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/imgui) + ImGui is a bloat-free graphical user interface library for C++. It outputs vertex buffers that you can render in your 3D-pipeline enabled application. It is portable, renderer agnostic and carries minimal amount of dependencies. It is based on an "immediate" graphical user interface paradigm which allows you to build user interfaces with ease. ImGui is designed to enable fast iteration and allow programmers to create "content creation" or "debug" tools (as opposed to UI for the average end-user). It favors simplicity and productivity toward this goal, and thus lacks certain features normally found in more high-level libraries. @@ -32,6 +34,7 @@ Gallery ![screenshot 2](/web/test_window_02.png?raw=true) ![screenshot 3](/web/test_window_03.png?raw=true) ![screenshot 4](/web/test_window_04.png?raw=true) +![screenshot 4](/web/examples_02.png?raw=true) ImGui can load TTF fonts. UTF-8 is supported for text display and input. Here using M+ font to display Japanese: diff --git a/examples/directx11_example/directx11_example.vcxproj b/examples/directx11_example/directx11_example.vcxproj index 5f731ac7..92ad83aa 100644 --- a/examples/directx11_example/directx11_example.vcxproj +++ b/examples/directx11_example/directx11_example.vcxproj @@ -18,7 +18,7 @@ Application true - MultiByte + Unicode Application diff --git a/examples/directx11_example/main.cpp b/examples/directx11_example/main.cpp index 1a87d3c1..ce6fbb23 100644 --- a/examples/directx11_example/main.cpp +++ b/examples/directx11_example/main.cpp @@ -517,11 +517,11 @@ void UpdateImGui() int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) { // Register the window class - WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, "ImGui Example", NULL }; + WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(NULL), NULL, LoadCursor(NULL, IDC_ARROW), NULL, NULL, L"ImGui Example", NULL }; RegisterClassEx(&wc); // Create the application's window - hWnd = CreateWindow("ImGui Example", "ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); + hWnd = CreateWindow(L"ImGui Example", L"ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, wc.hInstance, NULL); if (!QueryPerformanceFrequency((LARGE_INTEGER *)&ticks_per_second)) return 1; @@ -532,7 +532,7 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) if (InitDeviceD3D(hWnd) < 0) { CleanupDevice(); - UnregisterClass("ImGui Example", wc.hInstance); + UnregisterClass(L"ImGui Example", wc.hInstance); return 1; } @@ -603,7 +603,7 @@ int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE, LPWSTR, int) } ImGui::Shutdown(); - UnregisterClass("ImGui Example", wc.hInstance); + UnregisterClass(L"ImGui Example", wc.hInstance); return 0; } diff --git a/imgui.cpp b/imgui.cpp index 37865c9e..4f49d1cd 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1102,6 +1102,11 @@ static ImGuiWindow* GetCurrentWindow() return GImGui->CurrentWindow; } +static void SetActiveId(ImGuiID id) +{ + GImGui.ActiveId = id; +} + static void RegisterAliveId(const ImGuiID& id) { if (GImGui->ActiveId == id) @@ -1682,7 +1687,7 @@ void ImGui::NewFrame() // Clear reference to active widget if the widget isn't alive anymore g.HoveredId = 0; if (!g.ActiveIdIsAlive && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0) - g.ActiveId = 0; + SetActiveId(0); g.ActiveIdPreviousFrame = g.ActiveId; g.ActiveIdIsAlive = false; @@ -1868,7 +1873,7 @@ void ImGui::Render() // Select window for move/focus when we're done with all our widgets (we only consider non-childs windows here) if (g.ActiveId == 0 && g.HoveredId == 0 && g.HoveredRootWindow != NULL && g.IO.MouseClicked[0]) - g.ActiveId = g.HoveredRootWindow->GetID("#MOVE"); + SetActiveId(g.HoveredRootWindow->GetID("#MOVE")); // Sort the window list so that all child windows are after their parent // We cannot do that on FocusWindow() because childs may not exist yet @@ -2554,7 +2559,7 @@ bool ImGui::Begin(const char* name, bool* p_opened, ImVec2 size, float fill_alph } else { - g.ActiveId = 0; + SetActiveId(0); } } @@ -3567,7 +3572,7 @@ static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_ho { if (g.IO.MouseClicked[0]) { - g.ActiveId = id; + SetActiveId(id); FocusWindow(window); } else if (repeat && g.ActiveId && ImGui::IsMouseClicked(0, true)) @@ -3588,7 +3593,7 @@ static bool ButtonBehaviour(const ImGuiAabb& bb, const ImGuiID& id, bool* out_ho { if (hovered) pressed = true; - g.ActiveId = 0; + SetActiveId(0); } } @@ -4244,7 +4249,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c bool start_text_input = false; if (tab_focus_requested || (hovered && g.IO.MouseClicked[0])) { - g.ActiveId = id; + SetActiveId(id); FocusWindow(window); const bool is_ctrl_down = g.IO.KeyCtrl; @@ -4262,7 +4267,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c char text_buf[64]; ImFormatString(text_buf, IM_ARRAYSIZE(text_buf), "%.*f", decimal_precision, *v); - g.ActiveId = g.SliderAsInputTextId; + SetActiveId(g.SliderAsInputTextId); g.HoveredId = 0; window->FocusItemUnregister(); // Our replacement slider will override the focus ID (registered previously to allow for a TAB focus to happen) value_changed = ImGui::InputText(label, text_buf, IM_ARRAYSIZE(text_buf), ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_AutoSelectAll); @@ -4271,15 +4276,18 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c // First frame IM_ASSERT(g.ActiveId == id); // InputText ID should match the Slider ID (else we'd need to store them both which is also possible) g.SliderAsInputTextId = g.ActiveId; - g.ActiveId = id; + SetActiveId(id); g.HoveredId = id; } else { if (g.ActiveId == g.SliderAsInputTextId) - g.ActiveId = id; + SetActiveId(id); else - g.ActiveId = g.SliderAsInputTextId = 0; + { + SetActiveId(0); + g.SliderAsInputTextId = 0; + } } if (value_changed) { @@ -4343,7 +4351,7 @@ bool ImGui::SliderFloat(const char* label, float* v, float v_min, float v_max, c } else { - g.ActiveId = 0; + SetActiveId(0); } } @@ -5084,7 +5092,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (tab_focus_requested || is_ctrl_down) select_all = true; } - g.ActiveId = id; + SetActiveId(id); FocusWindow(window); } else if (io.MouseClicked[0]) @@ -5092,7 +5100,7 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT // Release focus when we click outside if (g.ActiveId == id) { - g.ActiveId = 0; + SetActiveId(0); } } @@ -5130,6 +5138,25 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT if (edit_state.SelectedAllMouseLock && !io.MouseDown[0]) edit_state.SelectedAllMouseLock = false; + if (g.IO.InputCharacters[0]) + { + // Process text input (before we check for Return because using some IME will effectively send a Return?) + for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++) + { + const ImWchar c = g.IO.InputCharacters[n]; + if (c) + { + // Insert character if they pass filtering + if (InputTextFilterCharacter(c, flags)) + continue; + edit_state.OnKeyPressed(c); + } + } + + // Consume characters + memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); + } + const int k_mask = (is_shift_down ? STB_TEXTEDIT_K_SHIFT : 0); if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDLEFT | k_mask : STB_TEXTEDIT_K_LEFT | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_WORDRIGHT | k_mask : STB_TEXTEDIT_K_RIGHT | k_mask); } @@ -5137,8 +5164,8 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT else if (IsKeyPressedMap(ImGuiKey_End)) { edit_state.OnKeyPressed(is_ctrl_down ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Delete)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); } else if (IsKeyPressedMap(ImGuiKey_Backspace)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask); } - else if (IsKeyPressedMap(ImGuiKey_Enter)) { g.ActiveId = 0; enter_pressed = true; } - else if (IsKeyPressedMap(ImGuiKey_Escape)) { g.ActiveId = 0; cancel_edit = true; } + else if (IsKeyPressedMap(ImGuiKey_Enter)) { SetActiveId(0); enter_pressed = true; } + else if (IsKeyPressedMap(ImGuiKey_Escape)) { SetActiveId(0); cancel_edit = true; } else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Z)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); } else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_Y)) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); } else if (is_ctrl_down && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); } @@ -5191,24 +5218,6 @@ bool ImGui::InputText(const char* label, char* buf, size_t buf_size, ImGuiInputT } } } - else if (g.IO.InputCharacters[0]) - { - // Text input - for (int n = 0; n < IM_ARRAYSIZE(g.IO.InputCharacters) && g.IO.InputCharacters[n]; n++) - { - const ImWchar c = g.IO.InputCharacters[n]; - if (c) - { - // Insert character if they pass filtering - if (InputTextFilterCharacter(c, flags)) - continue; - edit_state.OnKeyPressed(c); - } - } - - // Consume characters - memset(g.IO.InputCharacters, 0, sizeof(g.IO.InputCharacters)); - } edit_state.CursorAnim += g.IO.DeltaTime; edit_state.UpdateScrollOffset(); @@ -5527,7 +5536,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi } if (item_pressed) { - g.ActiveId = 0; + SetActiveId(0); g.ActiveComboID = 0; value_changed = true; *current_item = item_idx; @@ -7827,7 +7836,8 @@ void ImGui::ShowTestWindow(bool* opened) // Most compiler appears to support UTF-8 in source code (with Visual Studio you need to save your file as 'UTF-8 without signature') // However for the sake for maximum portability here we are *not* including raw UTF-8 character in this source file, instead we encode the string with hexadecimal constants. // In your own application be reasonable and use UTF-8 in source or retrieve the data from file system! - ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to specify extra character ranges. Note that characters values are preserved even if the font cannot be displayed, so you can safely copy & paste garbled characters into another application."); + // Note that characters values are preserved even if the font cannot be displayed, so you can safely copy & paste garbled characters into another application. + ImGui::TextWrapped("CJK text will only appears if the font was loaded with the appropriate CJK character ranges. Call io.Font->LoadFromFileTTF() manually to load extra character ranges."); ImGui::Text("Hiragana: \xe3\x81\x8b\xe3\x81\x8d\xe3\x81\x8f\xe3\x81\x91\xe3\x81\x93 (kakikukeko)"); ImGui::Text("Kanjis: \xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e (nihongo)"); static char buf[32] = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"; diff --git a/web/code_sample_01.png b/web/code_sample_01.png index 6178f8d8..d872db82 100644 Binary files a/web/code_sample_01.png and b/web/code_sample_01.png differ diff --git a/web/examples_01.png b/web/examples_01.png new file mode 100644 index 00000000..151eab19 Binary files /dev/null and b/web/examples_01.png differ diff --git a/web/examples_02.png b/web/examples_02.png new file mode 100644 index 00000000..bd6a720c Binary files /dev/null and b/web/examples_02.png differ diff --git a/web/test_window_01.png b/web/test_window_01.png index f54485a1..608cc961 100644 Binary files a/web/test_window_01.png and b/web/test_window_01.png differ diff --git a/web/test_window_02.png b/web/test_window_02.png index 331e6380..8cb4df81 100644 Binary files a/web/test_window_02.png and b/web/test_window_02.png differ diff --git a/web/test_window_03.png b/web/test_window_03.png index c4068cbe..4f109861 100644 Binary files a/web/test_window_03.png and b/web/test_window_03.png differ diff --git a/web/test_window_04.png b/web/test_window_04.png index 02f5d8b1..59c3b85a 100644 Binary files a/web/test_window_04.png and b/web/test_window_04.png differ diff --git a/web/test_window_05.png b/web/test_window_05.png deleted file mode 100644 index 27947829..00000000 Binary files a/web/test_window_05.png and /dev/null differ diff --git a/web/test_window_06.png b/web/test_window_06.png deleted file mode 100644 index 6b7a8299..00000000 Binary files a/web/test_window_06.png and /dev/null differ diff --git a/web/utf8_sample_01.png b/web/utf8_sample_01.png index 023bc66e..d0462774 100644 Binary files a/web/utf8_sample_01.png and b/web/utf8_sample_01.png differ