diff --git a/TODO.txt b/TODO.txt index c052aeb5..a9bc641e 100644 --- a/TODO.txt +++ b/TODO.txt @@ -64,6 +64,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - input text: add discard flag (e.g. ImGuiInputTextFlags_DiscardActiveBuffer) or make it easier to clear active focus for text replacement during edition (#725) - input text: display bug when clicking a drag/slider after an input text in a different window has all-selected text (order dependant). actually a very old bug but no one appears to have noticed it. - input text multi-line: don't directly call AddText() which does an unnecessary vertex reserve for character count prior to clipping. and/or more line-based clipping to AddText(). and/or reorganize TextUnformatted/RenderText for more efficiency for large text (e.g TextUnformatted could clip and log separately, etc). + - input text multi-line: support for cut/paste without selection (cut/paste the current line) - input text multi-line: line numbers? status bar? (follow up on #200) - input text multi-line: behave better when user changes input buffer while editing is active (even though it is illegal behavior). namely, the change of buffer can create a scrollbar glitch (#725) - input text multi-line: better horizontal scrolling support (#383, #1224) diff --git a/examples/allegro5_example/imgui_impl_a5.cpp b/examples/allegro5_example/imgui_impl_a5.cpp index 7a7d4cc1..d3ccffd2 100644 --- a/examples/allegro5_example/imgui_impl_a5.cpp +++ b/examples/allegro5_example/imgui_impl_a5.cpp @@ -177,6 +177,7 @@ bool ImGui_ImplA5_Init(ALLEGRO_DISPLAY* display) 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_Enter] = ALLEGRO_KEY_ENTER; diff --git a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm index 7fd7466c..9db45d0f 100644 --- a/examples/apple_example/imguiex-ios/imgui_impl_ios.mm +++ b/examples/apple_example/imguiex-ios/imgui_impl_ios.mm @@ -488,6 +488,7 @@ void ImGui_ClipboardCallback(uSynergyCookie cookie, enum uSynergyClipboardFormat io.KeyMap[ImGuiKey_DownArrow] = kVK_DownArrow+1; io.KeyMap[ImGuiKey_Home] = kVK_Home+1; io.KeyMap[ImGuiKey_End] = kVK_End+1; + io.KeyMap[ImGuiKey_Insert] = kVK_Help+1; io.KeyMap[ImGuiKey_Delete] = kVK_ForwardDelete+1; io.KeyMap[ImGuiKey_Backspace] = kVK_Delete+1; io.KeyMap[ImGuiKey_Enter] = kVK_Return+1; diff --git a/examples/directx10_example/imgui_impl_dx10.cpp b/examples/directx10_example/imgui_impl_dx10.cpp index d181f7a5..4f7117a7 100644 --- a/examples/directx10_example/imgui_impl_dx10.cpp +++ b/examples/directx10_example/imgui_impl_dx10.cpp @@ -545,6 +545,7 @@ bool ImGui_ImplDX10_Init(void* hwnd, ID3D10Device* device) 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_Enter] = VK_RETURN; diff --git a/examples/directx11_example/imgui_impl_dx11.cpp b/examples/directx11_example/imgui_impl_dx11.cpp index 833a0bb0..5df7bf1f 100644 --- a/examples/directx11_example/imgui_impl_dx11.cpp +++ b/examples/directx11_example/imgui_impl_dx11.cpp @@ -547,6 +547,7 @@ bool ImGui_ImplDX11_Init(void* hwnd, ID3D11Device* device, ID3D11DeviceContex 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_Enter] = VK_RETURN; diff --git a/examples/directx9_example/imgui_impl_dx9.cpp b/examples/directx9_example/imgui_impl_dx9.cpp index 40f675af..18ec0d9b 100644 --- a/examples/directx9_example/imgui_impl_dx9.cpp +++ b/examples/directx9_example/imgui_impl_dx9.cpp @@ -264,6 +264,7 @@ bool ImGui_ImplDX9_Init(void* hwnd, IDirect3DDevice9* device) 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_Enter] = VK_RETURN; diff --git a/examples/marmalade_example/imgui_impl_marmalade.cpp b/examples/marmalade_example/imgui_impl_marmalade.cpp index cae1be18..39623cc4 100644 --- a/examples/marmalade_example/imgui_impl_marmalade.cpp +++ b/examples/marmalade_example/imgui_impl_marmalade.cpp @@ -220,6 +220,7 @@ bool ImGui_Marmalade_Init(bool install_callbacks) 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_Enter] = s3eKeyEnter; diff --git a/examples/opengl2_example/imgui_impl_glfw.cpp b/examples/opengl2_example/imgui_impl_glfw.cpp index a635cc9a..d2eb657f 100644 --- a/examples/opengl2_example/imgui_impl_glfw.cpp +++ b/examples/opengl2_example/imgui_impl_glfw.cpp @@ -211,6 +211,7 @@ bool ImGui_ImplGlfwGL2_Init(GLFWwindow* window, bool install_callbacks) 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_Enter] = GLFW_KEY_ENTER; diff --git a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp index a608e370..f35b2654 100644 --- a/examples/opengl3_example/imgui_impl_glfw_gl3.cpp +++ b/examples/opengl3_example/imgui_impl_glfw_gl3.cpp @@ -217,7 +217,7 @@ bool ImGui_ImplGlfwGL3_CreateDeviceObjects() glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); const GLchar *vertex_shader = - "#version 330\n" + "#version 150\n" "uniform mat4 ProjMtx;\n" "in vec2 Position;\n" "in vec2 UV;\n" @@ -232,7 +232,7 @@ bool ImGui_ImplGlfwGL3_CreateDeviceObjects() "}\n"; const GLchar* fragment_shader = - "#version 330\n" + "#version 150\n" "uniform sampler2D Texture;\n" "in vec2 Frag_UV;\n" "in vec4 Frag_Color;\n" @@ -323,6 +323,7 @@ bool ImGui_ImplGlfwGL3_Init(GLFWwindow* window, bool install_callbacks) 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_Enter] = GLFW_KEY_ENTER; diff --git a/examples/opengl3_example/main.cpp b/examples/opengl3_example/main.cpp index 9e9a3fb6..6beb855d 100644 --- a/examples/opengl3_example/main.cpp +++ b/examples/opengl3_example/main.cpp @@ -21,7 +21,7 @@ int main(int, char**) if (!glfwInit()) return 1; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #if __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); diff --git a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp index c997d36d..ac920083 100644 --- a/examples/sdl_opengl2_example/imgui_impl_sdl.cpp +++ b/examples/sdl_opengl2_example/imgui_impl_sdl.cpp @@ -214,6 +214,7 @@ bool ImGui_ImplSdlGL2_Init(SDL_Window* window) 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] = SDLK_INSERT; io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE; io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE; io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN; diff --git a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp index 4cdbe0f1..f9e970f3 100644 --- a/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp +++ b/examples/sdl_opengl3_example/imgui_impl_sdl_gl3.cpp @@ -221,7 +221,7 @@ bool ImGui_ImplSdlGL3_CreateDeviceObjects() glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); const GLchar *vertex_shader = - "#version 330\n" + "#version 150\n" "uniform mat4 ProjMtx;\n" "in vec2 Position;\n" "in vec2 UV;\n" @@ -236,7 +236,7 @@ bool ImGui_ImplSdlGL3_CreateDeviceObjects() "}\n"; const GLchar* fragment_shader = - "#version 330\n" + "#version 150\n" "uniform sampler2D Texture;\n" "in vec2 Frag_UV;\n" "in vec4 Frag_Color;\n" @@ -325,6 +325,7 @@ bool ImGui_ImplSdlGL3_Init(SDL_Window* window) 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] = SDLK_INSERT; io.KeyMap[ImGuiKey_Delete] = SDLK_DELETE; io.KeyMap[ImGuiKey_Backspace] = SDLK_BACKSPACE; io.KeyMap[ImGuiKey_Enter] = SDLK_RETURN; diff --git a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp index 8eb35ec3..0af380cc 100644 --- a/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp +++ b/examples/vulkan_example/imgui_impl_glfw_vulkan.cpp @@ -750,6 +750,7 @@ bool ImGui_ImplGlfwVulkan_Init(GLFWwindow* window, bool install_callbacks, Im 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_Enter] = GLFW_KEY_ENTER; diff --git a/imgui.cpp b/imgui.cpp index d6bb4d02..bdbdab09 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4722,7 +4722,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags) return is_open; } -bool ImGui::BeginPopup(const char* str_id) +bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags) { ImGuiContext& g = *GImGui; if (g.OpenPopupStack.Size <= g.CurrentPopupStack.Size) // Early out for performance @@ -4730,7 +4730,7 @@ bool ImGui::BeginPopup(const char* str_id) g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values return false; } - return BeginPopupEx(g.CurrentWindow->GetID(str_id), ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); + return BeginPopupEx(g.CurrentWindow->GetID(str_id), flags|ImGuiWindowFlags_AlwaysAutoResize|ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoSavedSettings); } bool ImGui::IsPopupOpen(ImGuiID id) @@ -4745,7 +4745,7 @@ bool ImGui::IsPopupOpen(const char* str_id) return g.OpenPopupStack.Size > g.CurrentPopupStack.Size && g.OpenPopupStack[g.CurrentPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id); } -bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags extra_flags) +bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; @@ -4760,8 +4760,7 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags ext if (g.NextWindowData.PosCond == 0) SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - ImGuiWindowFlags flags = extra_flags|ImGuiWindowFlags_Popup|ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoSavedSettings; - bool is_open = Begin(name, p_open, flags); + bool is_open = Begin(name, p_open, flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings); if (!is_open || (p_open && !*p_open)) // NB: is_open can be 'false' when the popup is completely clipped (e.g. zero size display) { EndPopup(); @@ -9709,6 +9708,12 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 const bool is_shortcut_key_only = (io.OptMacOSXBehaviors ? (io.KeySuper && !io.KeyCtrl) : (io.KeyCtrl && !io.KeySuper)) && !io.KeyAlt && !io.KeyShift; // OS X style: Shortcuts using Cmd/Super instead of Ctrl const bool is_wordmove_key_down = io.OptMacOSXBehaviors ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl const bool is_startend_key_down = io.OptMacOSXBehaviors && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End + const bool is_ctrl_key_only = io.KeyCtrl && !io.KeyShift && !io.KeyAlt && !io.KeySuper; + const bool is_shift_key_only = io.KeyShift && !io.KeyCtrl && !io.KeyAlt && !io.KeySuper; + + const bool is_cut = ((is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Delete))) && is_editable && !is_password && (!is_multiline || edit_state.HasSelection()); + const bool is_copy = ((is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && !is_password && (!is_multiline || edit_state.HasSelection()); + const bool is_paste = ((is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressedMap(ImGuiKey_Insert))) && is_editable; if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); } else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { edit_state.OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); } @@ -9750,13 +9755,9 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Z) && is_editable && is_undoable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_UNDO); edit_state.ClearSelection(); } else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_Y) && is_editable && is_undoable) { edit_state.OnKeyPressed(STB_TEXTEDIT_K_REDO); edit_state.ClearSelection(); } else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_A)) { edit_state.SelectAll(); edit_state.CursorFollow = true; } - else if (is_shortcut_key_only && !is_password && ((IsKeyPressedMap(ImGuiKey_X) && is_editable) || IsKeyPressedMap(ImGuiKey_C)) && (!is_multiline || edit_state.HasSelection())) + else if (is_cut || is_copy) { // Cut, Copy - const bool cut = IsKeyPressedMap(ImGuiKey_X); - if (cut && !edit_state.HasSelection()) - edit_state.SelectAll(); - if (io.SetClipboardTextFn) { const int ib = edit_state.HasSelection() ? ImMin(edit_state.StbState.select_start, edit_state.StbState.select_end) : 0; @@ -9766,13 +9767,15 @@ bool ImGui::InputTextEx(const char* label, char* buf, int buf_size, const ImVec2 SetClipboardText(edit_state.TempTextBuffer.Data); } - if (cut) + if (is_cut) { + if (!edit_state.HasSelection()) + edit_state.SelectAll(); edit_state.CursorFollow = true; stb_textedit_cut(&edit_state, &edit_state.StbState); } } - else if (is_shortcut_key_only && IsKeyPressedMap(ImGuiKey_V) && is_editable) + else if (is_paste) { // Paste if (const char* clipboard = GetClipboardText()) diff --git a/imgui.h b/imgui.h index 622a35d2..7461b3fb 100644 --- a/imgui.h +++ b/imgui.h @@ -411,13 +411,13 @@ namespace ImGui // Popups IMGUI_API void OpenPopup(const char* str_id); // call to mark popup as open (don't call every frame!). popups are closed when user click outside, or if CloseCurrentPopup() is called within a BeginPopup()/EndPopup() block. By default, Selectable()/MenuItem() are calling CloseCurrentPopup(). Popup identifiers are relative to the current ID-stack (so OpenPopup and BeginPopup needs to be at the same level). - IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item. return true when just opened. - IMGUI_API bool BeginPopup(const char* str_id); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returned true! - IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags extra_flags = 0); // modal dialog (block interactions behind the modal window, can't close the modal window by clicking outside) + IMGUI_API bool BeginPopup(const char* str_id, ImGuiWindowFlags flags = 0); // return true if the popup is open, and you can start outputting to it. only call EndPopup() if BeginPopup() returned true! IMGUI_API bool BeginPopupContextItem(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked on last item. if you can pass a NULL str_id only if the previous item had an id. If you want to use that on a non-interactive item such as Text() you need to pass in an explicit ID here. read comments in .cpp! IMGUI_API bool BeginPopupContextWindow(const char* str_id = NULL, int mouse_button = 1, bool also_over_items = true); // helper to open and begin popup when clicked on current window. IMGUI_API bool BeginPopupContextVoid(const char* str_id = NULL, int mouse_button = 1); // helper to open and begin popup when clicked in void (where there are no imgui windows). + IMGUI_API bool BeginPopupModal(const char* name, bool* p_open = NULL, ImGuiWindowFlags flags = 0); // modal dialog (regular window with title bar, block interactions behind the modal window, can't close the modal window by clicking outside) IMGUI_API void EndPopup(); + IMGUI_API bool OpenPopupOnItemClick(const char* str_id = NULL, int mouse_button = 1); // helper to open popup when clicked on last item. return true when just opened. IMGUI_API bool IsPopupOpen(const char* str_id); // return true if the popup is open IMGUI_API void CloseCurrentPopup(); // close the popup we have begin-ed into. clicking on a MenuItem or Selectable automatically close the current popup. @@ -679,6 +679,7 @@ enum ImGuiKey_ ImGuiKey_PageDown, ImGuiKey_Home, // for text edit ImGuiKey_End, // for text edit + ImGuiKey_Insert, // for text edit ImGuiKey_Delete, // for text edit ImGuiKey_Backspace, // for text edit ImGuiKey_Enter, // for text edit