From 2de814d4787cdd12818024addefcc2cd3d71b847 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Fri, 15 Feb 2019 15:35:32 +0100 Subject: [PATCH 1/4] Imgui: Implement keyboard input, fix #1797 --- src/slic3r/GUI/GLCanvas3D.cpp | 38 +++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/GLCanvas3DManager.cpp | 2 +- src/slic3r/GUI/ImGuiWrapper.cpp | 88 ++++++++++++++++++++++++++++ src/slic3r/GUI/ImGuiWrapper.hpp | 8 +++ 5 files changed, 128 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 799d6d632..8aa6352f5 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5161,7 +5161,8 @@ void GLCanvas3D::bind_event_handlers() m_canvas->Bind(wxEVT_SIZE, &GLCanvas3D::on_size, this); m_canvas->Bind(wxEVT_IDLE, &GLCanvas3D::on_idle, this); m_canvas->Bind(wxEVT_CHAR, &GLCanvas3D::on_char, this); - m_canvas->Bind(wxEVT_KEY_UP, &GLCanvas3D::on_key_up, this); + m_canvas->Bind(wxEVT_KEY_DOWN, &GLCanvas3D::on_key, this); + m_canvas->Bind(wxEVT_KEY_UP, &GLCanvas3D::on_key, this); m_canvas->Bind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Bind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); m_canvas->Bind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); @@ -5187,7 +5188,8 @@ void GLCanvas3D::unbind_event_handlers() m_canvas->Unbind(wxEVT_SIZE, &GLCanvas3D::on_size, this); m_canvas->Unbind(wxEVT_IDLE, &GLCanvas3D::on_idle, this); m_canvas->Unbind(wxEVT_CHAR, &GLCanvas3D::on_char, this); - m_canvas->Unbind(wxEVT_KEY_UP, &GLCanvas3D::on_key_up, this); + m_canvas->Unbind(wxEVT_KEY_DOWN, &GLCanvas3D::on_key, this); + m_canvas->Unbind(wxEVT_KEY_UP, &GLCanvas3D::on_key, this); m_canvas->Unbind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Unbind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); m_canvas->Unbind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); @@ -5224,6 +5226,17 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) // see include/wx/defs.h enum wxKeyCode int keyCode = evt.GetKeyCode(); int ctrlMask = wxMOD_CONTROL; + +#if ENABLE_IMGUI + auto imgui = wxGetApp().imgui(); + if (imgui->update_key_data(evt)) { + render(); + if (imgui->want_any_input()) { + return; + } + } +#endif // ENABLE_IMGUI + //#ifdef __APPLE__ // ctrlMask |= wxMOD_RAW_CONTROL; //#endif /* __APPLE__ */ @@ -5299,14 +5312,23 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) } } -void GLCanvas3D::on_key_up(wxKeyEvent& evt) +void GLCanvas3D::on_key(wxKeyEvent& evt) { - // see include/wx/defs.h enum wxKeyCode - int keyCode = evt.GetKeyCode(); +#if ENABLE_IMGUI + auto imgui = wxGetApp().imgui(); + if (imgui->update_key_data(evt)) { + render(); + } else +#endif // ENABLE_IMGUI + if (evt.GetEventType() == wxEVT_KEY_UP) { + const int keyCode = evt.GetKeyCode(); + + // shift has been just released - SLA gizmo might want to close rectangular selection. + if (m_gizmos.get_current_type() == Gizmos::SlaSupports && keyCode == WXK_SHIFT && m_gizmos.mouse_event(SLAGizmoEventType::ShiftUp)) + m_dirty = true; + } - // shift has been just released - SLA gizmo might want to close rectangular selection. - if (m_gizmos.get_current_type() == Gizmos::SlaSupports && keyCode == WXK_SHIFT && m_gizmos.mouse_event(SLAGizmoEventType::ShiftUp)) - m_dirty = true; + evt.Skip(); // Needed to have EVT_CHAR generated as well } void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 3317c6378..3d44aa13f 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1075,7 +1075,7 @@ public: void on_size(wxSizeEvent& evt); void on_idle(wxIdleEvent& evt); void on_char(wxKeyEvent& evt); - void on_key_up(wxKeyEvent& evt); + void on_key(wxKeyEvent& evt); void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); diff --git a/src/slic3r/GUI/GLCanvas3DManager.cpp b/src/slic3r/GUI/GLCanvas3DManager.cpp index 8f2e5b219..71299f777 100644 --- a/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -233,7 +233,7 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent) attribList[4] = 0; } - return new wxGLCanvas(parent, wxID_ANY, attribList); + return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); } GLCanvas3DManager::CanvasesMap::iterator GLCanvas3DManager::_get_canvas(wxGLCanvas* canvas) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 63fa09ae2..38d90fbfa 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -44,6 +45,7 @@ bool ImGuiWrapper::init() ImGui::CreateContext(); init_default_font(m_style_scaling); + init_input(); ImGui::GetIO().IniFilename = nullptr; @@ -109,6 +111,28 @@ bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt) return res; } +bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) +{ + ImGuiIO& io = ImGui::GetIO(); + + if (evt.GetEventType() == wxEVT_CHAR) { + // Char event + io.AddInputCharacter(evt.GetUnicodeKey()); + } else { + // Key up/down event + int key = evt.GetKeyCode(); + wxCHECK_MSG(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown), false, "Received invalid key code"); + + io.KeysDown[key] = evt.GetEventType() == wxEVT_KEY_DOWN; + io.KeyShift = evt.ShiftDown(); + io.KeyCtrl = evt.ControlDown(); + io.KeyAlt = evt.AltDown(); + io.KeySuper = evt.MetaDown(); + } + + return true; +} + void ImGuiWrapper::new_frame() { if (m_font_texture == 0) @@ -307,6 +331,39 @@ void ImGuiWrapper::create_fonts_texture() glBindTexture(GL_TEXTURE_2D, last_texture); } +void ImGuiWrapper::init_input() +{ + ImGuiIO& io = ImGui::GetIO(); + + // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. + io.KeyMap[ImGuiKey_Tab] = WXK_TAB; + io.KeyMap[ImGuiKey_LeftArrow] = WXK_LEFT; + io.KeyMap[ImGuiKey_RightArrow] = WXK_RIGHT; + io.KeyMap[ImGuiKey_UpArrow] = WXK_UP; + io.KeyMap[ImGuiKey_DownArrow] = WXK_DOWN; + io.KeyMap[ImGuiKey_PageUp] = WXK_PAGEUP; + io.KeyMap[ImGuiKey_PageDown] = WXK_PAGEDOWN; + io.KeyMap[ImGuiKey_Home] = WXK_HOME; + io.KeyMap[ImGuiKey_End] = WXK_END; + io.KeyMap[ImGuiKey_Insert] = WXK_INSERT; + io.KeyMap[ImGuiKey_Delete] = WXK_DELETE; + io.KeyMap[ImGuiKey_Backspace] = WXK_BACK; + io.KeyMap[ImGuiKey_Space] = WXK_SPACE; + io.KeyMap[ImGuiKey_Enter] = WXK_RETURN; + io.KeyMap[ImGuiKey_Escape] = WXK_ESCAPE; + 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'; + + // Setup clipboard interaction callbacks + io.SetClipboardTextFn = clipboard_set; + io.GetClipboardTextFn = clipboard_get; + io.ClipboardUserData = this; +} + void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) @@ -420,6 +477,37 @@ void ImGuiWrapper::destroy_fonts_texture() } } +const char* ImGuiWrapper::clipboard_get(void* user_data) +{ + ImGuiWrapper *self = reinterpret_cast(user_data); + + const char* res = ""; + + if (wxTheClipboard->Open()) { + if (wxTheClipboard->IsSupported(wxDF_TEXT)) { + wxTextDataObject data; + wxTheClipboard->GetData(data); + + if (data.GetTextLength() > 0) { + self->clipboard_text = into_u8(data.GetText()); + res = self->clipboard_text.c_str(); + } + } + + wxTheClipboard->Close(); + } + + return res; +} + +void ImGuiWrapper::clipboard_set(void* /* user_data */, const char* text) +{ + if (wxTheClipboard->Open()) { + wxTheClipboard->SetData(new wxTextDataObject(wxString::FromUTF8(text))); // object owned by the clipboard + wxTheClipboard->Close(); + } +} + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index a4f5a8976..b0b5cc858 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -10,6 +10,7 @@ class wxString; class wxMouseEvent; +class wxKeyEvent; namespace Slic3r { @@ -37,6 +38,7 @@ public: void set_display_size(float w, float h); void set_style_scaling(float scaling); bool update_mouse_data(wxMouseEvent &evt); + bool update_key_data(wxKeyEvent &evt); void new_frame(); void render(); @@ -65,12 +67,18 @@ public: bool want_any_input() const; private: + std::string clipboard_text; + void init_default_font(float scaling); void create_device_objects(); void create_fonts_texture(); + void init_input(); void render_draw_data(ImDrawData *draw_data); void destroy_device_objects(); void destroy_fonts_texture(); + + static const char* clipboard_get(void* user_data); + static void clipboard_set(void* user_data, const char* text); }; From 5de52b7da4fa2c3f7fa17ac3414c2396f658df65 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Mon, 18 Feb 2019 16:44:35 +0100 Subject: [PATCH 2/4] imgui: Fix keyboard modifiers on Mac --- src/slic3r/GUI/ImGuiWrapper.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 38d90fbfa..228d336c2 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -358,6 +358,9 @@ void ImGuiWrapper::init_input() io.KeyMap[ImGuiKey_Y] = 'Y'; io.KeyMap[ImGuiKey_Z] = 'Z'; + // Don't let imgui special-case Mac, wxWidgets already do that + io.ConfigMacOSXBehaviors = false; + // Setup clipboard interaction callbacks io.SetClipboardTextFn = clipboard_set; io.GetClipboardTextFn = clipboard_get; From 1045b43d4f1df4ddcdd01c26b0428a0d12f1ddf8 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 19 Feb 2019 12:39:24 +0100 Subject: [PATCH 3/4] imgui: Input fixes --- src/slic3r/GUI/GLCanvas3D.cpp | 8 ++------ src/slic3r/GUI/ImGuiWrapper.cpp | 25 ++++++++++++++++++++----- src/slic3r/GUI/ImGuiWrapper.hpp | 4 ++-- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8aa6352f5..53a28ef24 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -5230,10 +5230,8 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) #if ENABLE_IMGUI auto imgui = wxGetApp().imgui(); if (imgui->update_key_data(evt)) { + return; render(); - if (imgui->want_any_input()) { - return; - } } #endif // ENABLE_IMGUI @@ -5385,9 +5383,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) auto imgui = wxGetApp().imgui(); if (imgui->update_mouse_data(evt)) { render(); - if (imgui->want_any_input()) { - return; - } + return; } #endif // ENABLE_IMGUI diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 228d336c2..b94aa59d3 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -31,6 +31,7 @@ ImGuiWrapper::ImGuiWrapper() , m_style_scaling(1.0) , m_mouse_buttons(0) , m_disabled(false) + , m_new_frame_open(false) { } @@ -106,9 +107,10 @@ bool ImGuiWrapper::update_mouse_data(wxMouseEvent& evt) io.MouseDown[2] = evt.MiddleDown(); unsigned buttons = (evt.LeftDown() ? 1 : 0) | (evt.RightDown() ? 2 : 0) | (evt.MiddleDown() ? 4 : 0); - bool res = buttons != m_mouse_buttons; m_mouse_buttons = buttons; - return res; + + new_frame(); + return want_mouse(); } bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) @@ -117,7 +119,10 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) if (evt.GetEventType() == wxEVT_CHAR) { // Char event - io.AddInputCharacter(evt.GetUnicodeKey()); + const auto key = evt.GetUnicodeKey(); + if (key != 0) { + io.AddInputCharacter(key); + } } else { // Key up/down event int key = evt.GetKeyCode(); @@ -130,21 +135,31 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt) io.KeySuper = evt.MetaDown(); } + // XXX: Unfortunatelly this seems broken due to some interference with wxWidgets, + // we have to return true always (perform re-render). + // new_frame(); + // return want_keyboard() || want_text_input(); return true; } void ImGuiWrapper::new_frame() { + if (m_new_frame_open) { + return; + } + if (m_font_texture == 0) create_device_objects(); ImGui::NewFrame(); + m_new_frame_open = true; } void ImGuiWrapper::render() { ImGui::Render(); render_draw_data(ImGui::GetDrawData()); + m_new_frame_open = false; } void ImGuiWrapper::set_next_window_pos(float x, float y, int flag) @@ -492,8 +507,8 @@ const char* ImGuiWrapper::clipboard_get(void* user_data) wxTheClipboard->GetData(data); if (data.GetTextLength() > 0) { - self->clipboard_text = into_u8(data.GetText()); - res = self->clipboard_text.c_str(); + self->m_clipboard_text = into_u8(data.GetText()); + res = self->m_clipboard_text.c_str(); } } diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index b0b5cc858..ac77ab17f 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -26,6 +26,8 @@ class ImGuiWrapper float m_style_scaling; unsigned m_mouse_buttons; bool m_disabled; + bool m_new_frame_open; + std::string m_clipboard_text; public: ImGuiWrapper(); @@ -67,8 +69,6 @@ public: bool want_any_input() const; private: - std::string clipboard_text; - void init_default_font(float scaling); void create_device_objects(); void create_fonts_texture(); From 47e04ec8e539425be52a4d1458a91c581458fd83 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 19 Feb 2019 14:46:29 +0100 Subject: [PATCH 4/4] imgui: Tweak style --- src/slic3r/GUI/ImGuiWrapper.cpp | 41 +++++++++++++++++++++++++++++++++ src/slic3r/GUI/ImGuiWrapper.hpp | 1 + 2 files changed, 42 insertions(+) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index b94aa59d3..d8d8089c2 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -47,6 +47,7 @@ bool ImGuiWrapper::init() init_default_font(m_style_scaling); init_input(); + init_style(); ImGui::GetIO().IniFilename = nullptr; @@ -382,6 +383,46 @@ void ImGuiWrapper::init_input() io.ClipboardUserData = this; } +void ImGuiWrapper::init_style() +{ + ImGuiStyle &style = ImGui::GetStyle(); + + auto set_color = [&](ImGuiCol_ col, unsigned hex_color) { + style.Colors[col] = ImVec4( + ((hex_color >> 24) & 0xff) / 255.0f, + ((hex_color >> 16) & 0xff) / 255.0f, + ((hex_color >> 8) & 0xff) / 255.0f, + (hex_color & 0xff) / 255.0f); + }; + + static const unsigned COL_GREY_DARK = 0x444444ff; + static const unsigned COL_GREY_LIGHT = 0x666666ff; + static const unsigned COL_ORANGE_DARK = 0xba5418ff; + static const unsigned COL_ORANGE_LIGHT = 0xff6f22ff; + + // Generics + set_color(ImGuiCol_TitleBgActive, COL_ORANGE_DARK); + set_color(ImGuiCol_FrameBg, COL_GREY_DARK); + set_color(ImGuiCol_FrameBgHovered, COL_GREY_LIGHT); + set_color(ImGuiCol_FrameBgActive, COL_GREY_LIGHT); + + // Text selection + set_color(ImGuiCol_TextSelectedBg, COL_ORANGE_DARK); + + // Buttons + set_color(ImGuiCol_Button, COL_ORANGE_DARK); + set_color(ImGuiCol_ButtonHovered, COL_ORANGE_LIGHT); + set_color(ImGuiCol_ButtonActive, COL_ORANGE_LIGHT); + + // Checkbox + set_color(ImGuiCol_CheckMark, COL_ORANGE_LIGHT); + + // ComboBox items + set_color(ImGuiCol_Header, COL_ORANGE_DARK); + set_color(ImGuiCol_HeaderHovered, COL_ORANGE_LIGHT); + set_color(ImGuiCol_HeaderActive, COL_ORANGE_LIGHT); +} + void ImGuiWrapper::render_draw_data(ImDrawData *draw_data) { // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates) diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index ac77ab17f..e8755718b 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -73,6 +73,7 @@ private: void create_device_objects(); void create_fonts_texture(); void init_input(); + void init_style(); void render_draw_data(ImDrawData *draw_data); void destroy_device_objects(); void destroy_fonts_texture();