Browse Source

Fix 1656 ; Introduce ImGuiPlugin with list of ImGuiWidgets (#1973)

Alec Jacobson 3 years ago
parent
commit
29ac7b213f

+ 77 - 157
include/igl/opengl/glfw/ViewerPlugin.h

@@ -19,164 +19,84 @@
 
 
 namespace igl
 namespace igl
 {
 {
-namespace opengl
-{
-namespace glfw
-{
-
-// Abstract class for plugins
-// All plugins MUST have this class as their parent and may implement any/all
-// the callbacks marked `virtual` here.
-//
-// /////For an example of a basic plugins see plugins/skeleton.h
-//
-// Return value of callbacks: returning true to any of the callbacks tells
-// Viewer that the event has been handled and that it should not be passed to
-// other plugins or to other internal functions of Viewer
-
-// Forward declaration of the viewer
-class Viewer;
-
-class ViewerPlugin
-{
-public:
-  IGL_INLINE ViewerPlugin()
-  {plugin_name = "dummy";}
-
-  virtual ~ViewerPlugin(){}
-
-  // This function is called when the viewer is initialized (no mesh will be loaded at this stage)
-  IGL_INLINE virtual void init(Viewer *_viewer)
-  {
-    viewer = _viewer;
-  }
-
-  // This function is called before shutdown
-  IGL_INLINE virtual void shutdown()
-  {
-  }
-
-  // This function is called before a mesh is loaded
-  IGL_INLINE virtual bool load(std::string filename)
-  {
-    return false;
-  }
-
-  // This function is called before a mesh is saved
-  IGL_INLINE virtual bool save(std::string filename)
-  {
-    return false;
-  }
-
-  // This function is called when the scene is serialized
-  IGL_INLINE virtual bool serialize(std::vector<char>& buffer) const
-  {
-    return false;
-  }
-
-  // This function is called when the scene is deserialized
-  IGL_INLINE virtual bool deserialize(const std::vector<char>& buffer)
-  {
-    return false;
-  }
-
-  // Runs immediately after a new mesh has been loaded.
-  IGL_INLINE virtual bool post_load()
-  {
-    return false;
-  }
-
-  // This function is called before the draw procedure of Preview3D
-  IGL_INLINE virtual bool pre_draw()
-  {
-    return false;
+  namespace opengl
+  {
+    namespace glfw
+    {
+
+      // Abstract class for plugins
+      // All plugins MUST have this class as their parent and may implement any/all
+      // the callbacks marked `virtual` here.
+      //
+      // Return value of callbacks: returning true to any of the callbacks tells
+      // Viewer that the event has been handled and that it should not be passed to
+      // other plugins or to other internal functions of Viewer
+
+      // Forward declaration of the viewer
+      class Viewer;
+
+      class ViewerPlugin
+      {
+        public:
+          IGL_INLINE ViewerPlugin() {plugin_name = "dummy";}
+          virtual ~ViewerPlugin(){}
+          // This function is called when the viewer is initialized (no mesh will be loaded at this stage)
+          IGL_INLINE virtual void init(Viewer *_viewer) { viewer = _viewer; }
+          // This function is called before shutdown
+          IGL_INLINE virtual void shutdown() { }
+          // This function is called before a mesh is loaded
+          IGL_INLINE virtual bool load(std::string filename) { return false; }
+          // This function is called before a mesh is saved
+          IGL_INLINE virtual bool save(std::string filename) { return false; }
+          // This function is called when the scene is serialized
+          IGL_INLINE virtual bool serialize(std::vector<char>& buffer) const 
+            { return false; }
+          // This function is called when the scene is deserialized
+          IGL_INLINE virtual bool deserialize(const std::vector<char>& buffer)
+            { return false; }
+          // Runs immediately after a new mesh has been loaded.
+          IGL_INLINE virtual bool post_load() { return false; }
+          // This function is called before the draw procedure of Viewer
+          IGL_INLINE virtual bool pre_draw() { return false; }
+          // This function is called after the draw procedure of Viewer
+          IGL_INLINE virtual bool post_draw() { return false; }
+          // This function is called after the window has been resized
+          IGL_INLINE virtual void post_resize(int w, int h) { }
+          IGL_INLINE virtual bool mouse_down(int button, int modifier)
+            { return false; }
+          IGL_INLINE virtual bool mouse_up(int button, int modifier)
+            { return false; }
+          IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y)
+            { return false; }
+          IGL_INLINE virtual bool mouse_scroll(float delta_y)
+            { return false; }
+          IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers)
+            { return false; }
+          IGL_INLINE virtual bool key_down(int key, int modifiers)
+            { return false; }
+          IGL_INLINE virtual bool key_up(int key, int modifiers)
+            { return false; }
+          std::string plugin_name;
+        protected:
+          // Pointer to the main Viewer class
+          Viewer *viewer;
+      };
+
+      namespace serialization
+      {
+        inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
+        {
+          obj.serialize(buffer);
+        }
+
+        inline void deserialize(ViewerPlugin& obj,const std::vector<char>& buffer)
+        {
+          obj.deserialize(buffer);
+        }
+      }
+
+    }
   }
   }
-
-  // This function is called after the draw procedure of Preview3D
-  IGL_INLINE virtual bool post_draw()
-  {
-    return false;
-  }
-
-  // This function is called after the window has been resized
-  IGL_INLINE virtual void post_resize(int w, int h)
-  {
-  }
-
-  // This function is called when the mouse button is pressed
-  // - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
-  // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
-  IGL_INLINE virtual bool mouse_down(int button, int modifier)
-  {
-    return false;
-  }
-
-  // This function is called when the mouse button is released
-  // - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
-  // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
-  IGL_INLINE virtual bool mouse_up(int button, int modifier)
-  {
-    return false;
-  }
-
-  // This function is called every time the mouse is moved
-  // - mouse_x and mouse_y are the new coordinates of the mouse pointer in screen coordinates
-  IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y)
-  {
-    return false;
-  }
-
-  // This function is called every time the scroll wheel is moved
-  // Note: this callback is not working with every glut implementation
-  IGL_INLINE virtual bool mouse_scroll(float delta_y)
-  {
-    return false;
-  }
-
-  // This function is called when a keyboard key is pressed. Unlike key_down
-  // this will reveal the actual character being sent (not just the physical
-  // key)
-  // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
-  IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers)
-  {
-    return false;
-  }
-
-  // This function is called when a keyboard key is down
-  // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
-  IGL_INLINE virtual bool key_down(int key, int modifiers)
-  {
-    return false;
-  }
-
-  // This function is called when a keyboard key is release
-  // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
-  IGL_INLINE virtual bool key_up(int key, int modifiers)
-  {
-    return false;
-  }
-
-  std::string plugin_name;
-protected:
-  // Pointer to the main Viewer class
-  Viewer *viewer;
-};
-
-namespace serialization
-{
-  inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
-  {
-    obj.serialize(buffer);
-  }
-
-  inline void deserialize(ViewerPlugin& obj,const std::vector<char>& buffer)
-  {
-    obj.deserialize(buffer);
-  }
-}
-
-}
-}
 }
 }
 
 
 #endif
 #endif

+ 6 - 148
include/igl/opengl/glfw/imgui/ImGuiMenu.cpp

@@ -1,5 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
 //
 //
+// Copyright (C) 2022 Alec Jacobson <[email protected]>
 // Copyright (C) 2018 Jérémie Dumas <[email protected]>
 // Copyright (C) 2018 Jérémie Dumas <[email protected]>
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // This Source Code Form is subject to the terms of the Mozilla Public License
@@ -8,14 +9,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 #include "ImGuiMenu.h"
 #include "ImGuiMenu.h"
 #include "ImGuiHelpers.h"
 #include "ImGuiHelpers.h"
-#include <igl/project.h>
-#include <backends/imgui_impl_glfw.h>
-#include <backends/imgui_impl_opengl3.h>
 #include <imgui.h>
 #include <imgui.h>
-#include <imgui_fonts_droid_sans.h>
-#include <GLFW/glfw3.h>
 #include <iostream>
 #include <iostream>
-////////////////////////////////////////////////////////////////////////////////
 
 
 namespace igl
 namespace igl
 {
 {
@@ -26,131 +21,13 @@ namespace glfw
 namespace imgui
 namespace imgui
 {
 {
 
 
-IGL_INLINE void ImGuiMenu::init(igl::opengl::glfw::Viewer *_viewer)
-{
-  ViewerPlugin::init(_viewer);
-  // Setup ImGui binding
-  if (_viewer)
-  {
-    IMGUI_CHECKVERSION();
-    if (!context_)
-    {
-      // Single global context by default, but can be overridden by the user
-      static ImGuiContext * __global_context = ImGui::CreateContext();
-      context_ = __global_context;
-    }
-    const char* glsl_version = "#version 150";
-    ImGui_ImplGlfw_InitForOpenGL(viewer->window, false);
-    ImGui_ImplOpenGL3_Init(glsl_version);
-    ImGui::GetIO().IniFilename = nullptr;
-    ImGui::StyleColorsDark();
-    ImGuiStyle& style = ImGui::GetStyle();
-    style.FrameRounding = 5.0f;
-    reload_font();
-  }
-}
-
-IGL_INLINE void ImGuiMenu::reload_font(int font_size)
-{
-  hidpi_scaling_ = hidpi_scaling();
-  pixel_ratio_ = pixel_ratio();
-  ImGuiIO& io = ImGui::GetIO();
-  io.Fonts->Clear();
-  io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data,
-    droid_sans_compressed_size, font_size * hidpi_scaling_);
-  io.FontGlobalScale = 1.0 / pixel_ratio_;
-}
-
-IGL_INLINE void ImGuiMenu::shutdown()
-{
-  // Cleanup
-  ImGui_ImplOpenGL3_Shutdown();
-  ImGui_ImplGlfw_Shutdown();
-  // User is responsible for destroying context if a custom context is given
-  // ImGui::DestroyContext(*context_);
-}
+  // Is this needed?
+IGL_INLINE void ImGuiMenu::init( Viewer *_viewer, ImGuiPlugin *_plugin) 
+  { viewer = _viewer; plugin = _plugin; }
 
 
-IGL_INLINE bool ImGuiMenu::pre_draw()
-{
-  glfwPollEvents();
-
-  // Check whether window dpi has changed
-  float scaling = hidpi_scaling();
-  if (std::abs(scaling - hidpi_scaling_) > 1e-5)
-  {
-    reload_font();
-    ImGui_ImplOpenGL3_DestroyDeviceObjects();
-  }
-
-  ImGui_ImplOpenGL3_NewFrame();
-  ImGui_ImplGlfw_NewFrame();
-  ImGui::NewFrame();
-  return false;
-}
-
-IGL_INLINE bool ImGuiMenu::post_draw()
-{
-  draw_menu();
-  ImGui::Render();
-  ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
-  return false;
-}
-
-IGL_INLINE void ImGuiMenu::post_resize(int width, int height)
-{
-  if (context_)
-  {
-    ImGui::GetIO().DisplaySize.x = float(width);
-    ImGui::GetIO().DisplaySize.y = float(height);
-  }
-}
+IGL_INLINE void ImGuiMenu::shutdown() { }
 
 
-// Mouse IO
-IGL_INLINE bool ImGuiMenu::mouse_down(int button, int modifier)
-{
-  ImGui_ImplGlfw_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier);
-  return ImGui::GetIO().WantCaptureMouse;
-}
-
-IGL_INLINE bool ImGuiMenu::mouse_up(int button, int modifier)
-{
-  //return ImGui::GetIO().WantCaptureMouse;
-  // !! Should not steal mouse up
-  return false;
-}
-
-IGL_INLINE bool ImGuiMenu::mouse_move(int mouse_x, int mouse_y)
-{
-  return ImGui::GetIO().WantCaptureMouse;
-}
-
-IGL_INLINE bool ImGuiMenu::mouse_scroll(float delta_y)
-{
-  ImGui_ImplGlfw_ScrollCallback(viewer->window, 0.f, delta_y);
-  return ImGui::GetIO().WantCaptureMouse;
-}
-
-// Keyboard IO
-IGL_INLINE bool ImGuiMenu::key_pressed(unsigned int key, int modifiers)
-{
-  ImGui_ImplGlfw_CharCallback(nullptr, key);
-  return ImGui::GetIO().WantCaptureKeyboard;
-}
-
-IGL_INLINE bool ImGuiMenu::key_down(int key, int modifiers)
-{
-  ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers);
-  return ImGui::GetIO().WantCaptureKeyboard;
-}
-
-IGL_INLINE bool ImGuiMenu::key_up(int key, int modifiers)
-{
-  ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers);
-  return ImGui::GetIO().WantCaptureKeyboard;
-}
-
-// Draw menu
-IGL_INLINE void ImGuiMenu::draw_menu()
+IGL_INLINE void ImGuiMenu::draw()
 {
 {
   // Viewer settings
   // Viewer settings
   if (callback_draw_viewer_window) { callback_draw_viewer_window(); }
   if (callback_draw_viewer_window) { callback_draw_viewer_window(); }
@@ -304,25 +181,6 @@ IGL_INLINE void ImGuiMenu::draw_viewer_menu()
   }
   }
 }
 }
 
 
-IGL_INLINE float ImGuiMenu::pixel_ratio()
-{
-  // Computes pixel ratio for hidpi devices
-  int buf_size[2];
-  int win_size[2];
-  GLFWwindow* window = glfwGetCurrentContext();
-  glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]);
-  glfwGetWindowSize(window, &win_size[0], &win_size[1]);
-  return (float) buf_size[0] / (float) win_size[0];
-}
-
-IGL_INLINE float ImGuiMenu::hidpi_scaling()
-{
-  // Computes scaling factor for hidpi devices
-  float xscale, yscale;
-  GLFWwindow* window = glfwGetCurrentContext();
-  glfwGetWindowContentScale(window, &xscale, &yscale);
-  return 0.5 * (xscale + yscale);
-}
 
 
 } // end namespace
 } // end namespace
 } // end namespace
 } // end namespace

+ 36 - 92
include/igl/opengl/glfw/imgui/ImGuiMenu.h

@@ -1,5 +1,6 @@
 // This file is part of libigl, a simple c++ geometry processing library.
 // This file is part of libigl, a simple c++ geometry processing library.
 //
 //
+// Copyright (C) 2022 Alec Jacobson <[email protected]>
 // Copyright (C) 2018 Jérémie Dumas <[email protected]>
 // Copyright (C) 2018 Jérémie Dumas <[email protected]>
 //
 //
 // This Source Code Form is subject to the terms of the Mozilla Public License
 // This Source Code Form is subject to the terms of the Mozilla Public License
@@ -8,104 +9,47 @@
 #ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
 #ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
 #define IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
 #define IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
 
 
-////////////////////////////////////////////////////////////////////////////////
-#include <igl/opengl/glfw/Viewer.h>
-#include <igl/opengl/glfw/ViewerPlugin.h>
-#include <igl/igl_inline.h>
+#include "ImGuiPlugin.h"
+#include "ImGuiWidget.h"
+#include "../../../igl_inline.h"
 #include <memory>
 #include <memory>
-////////////////////////////////////////////////////////////////////////////////
-
-// Forward declarations
-struct ImGuiContext;
 
 
 namespace igl
 namespace igl
 {
 {
-namespace opengl
-{
-namespace glfw
-{
-namespace imgui
-{
-
-class ImGuiMenu : public igl::opengl::glfw::ViewerPlugin
-{
-protected:
-  // Hidpi scaling to be used for text rendering.
-  float hidpi_scaling_;
-
-  // Ratio between the framebuffer size and the window size.
-  // May be different from the hipdi scaling!
-  float pixel_ratio_;
-
-  // ImGui Context
-  ImGuiContext * context_ = nullptr;
-
-public:
-  IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
-
-  IGL_INLINE virtual void reload_font(int font_size = 13);
-
-  IGL_INLINE virtual void shutdown() override;
-
-  IGL_INLINE virtual bool pre_draw() override;
-
-  IGL_INLINE  virtual bool post_draw() override;
-
-  IGL_INLINE virtual void post_resize(int width, int height) override;
-
-  // Mouse IO
-  IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
-
-  IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
-
-  IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
-
-  IGL_INLINE virtual bool mouse_scroll(float delta_y) override;
-
-  // Keyboard IO
-  IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
-
-  IGL_INLINE virtual bool key_down(int key, int modifiers) override;
-
-  IGL_INLINE virtual bool key_up(int key, int modifiers) override;
-
-  // Draw menu
-  IGL_INLINE virtual void draw_menu();
-
-  // Can be overwritten by `callback_draw_viewer_window`
-  IGL_INLINE virtual void draw_viewer_window();
-
-  // Can be overwritten by `callback_draw_viewer_menu`
-  IGL_INLINE virtual void draw_viewer_menu();
-
-  // Can be overwritten by `callback_draw_custom_window`
-  IGL_INLINE virtual void draw_custom_window() { }
-
-  // Easy-to-customize callbacks
-  std::function<void(void)> callback_draw_viewer_window;
-  std::function<void(void)> callback_draw_viewer_menu;
-  std::function<void(void)> callback_draw_custom_window;
-
-  IGL_INLINE void draw_text(
-    Eigen::Vector3d pos,
-    Eigen::Vector3d normal,
-    const std::string &text,
-    const Eigen::Vector4f color = Eigen::Vector4f(0,0,0.04,1)); // old default color
-
-  IGL_INLINE float pixel_ratio();
-
-  IGL_INLINE float hidpi_scaling();
-
-  float menu_scaling() { return hidpi_scaling_ / pixel_ratio_; }
-};
-
-} // end namespace
-} // end namespace
-} // end namespace
-} // end namespace
+  namespace opengl
+  {
+    namespace glfw
+    {
+      namespace imgui
+      {
+
+        class ImGuiMenu : public ImGuiWidget
+        {
+          public:
+            IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin) override;
+            IGL_INLINE virtual void shutdown() override;
+            IGL_INLINE virtual void draw() override;
+            // Can be overwritten by `callback_draw_viewer_window`
+            IGL_INLINE virtual void draw_viewer_window();
+            // Can be overwritten by `callback_draw_viewer_menu`
+            IGL_INLINE virtual void draw_viewer_menu();
+            // Can be overwritten by `callback_draw_custom_window`
+            IGL_INLINE virtual void draw_custom_window() { }
+            // Customizable callbacks
+            std::function<void(void)> callback_draw_viewer_window;
+            std::function<void(void)> callback_draw_viewer_menu;
+            std::function<void(void)> callback_draw_custom_window;
+            float menu_scaling()
+              { return plugin->hidpi_scaling() / plugin->pixel_ratio(); }
+        };
+
+      }
+    }
+  }
+}
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
 #  include "ImGuiMenu.cpp"
 #  include "ImGuiMenu.cpp"
 #endif
 #endif
 
 
-#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
+#endif

+ 211 - 0
include/igl/opengl/glfw/imgui/ImGuiPlugin.cpp

@@ -0,0 +1,211 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2022 Alec Jacobson <[email protected]>
+// Copyright (C) 2018 Jérémie Dumas <[email protected]>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+////////////////////////////////////////////////////////////////////////////////
+#include "ImGuiPlugin.h"
+#include "ImGuiHelpers.h"
+#include <igl/project.h>
+#include <backends/imgui_impl_glfw.h>
+#include <backends/imgui_impl_opengl3.h>
+#include <imgui.h>
+#include <imgui_fonts_droid_sans.h>
+#include <GLFW/glfw3.h>
+#include <iostream>
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+namespace imgui
+{
+
+IGL_INLINE void ImGuiPlugin::init(igl::opengl::glfw::Viewer *_viewer)
+{
+  ViewerPlugin::init(_viewer);
+  // Setup ImGui binding
+  if (_viewer)
+  {
+    IMGUI_CHECKVERSION();
+    if (!context_)
+    {
+      // Single global context by default, but can be overridden by the user
+      static ImGuiContext * __global_context = ImGui::CreateContext();
+      context_ = __global_context;
+    }
+    const char* glsl_version = "#version 150";
+    ImGui_ImplGlfw_InitForOpenGL(viewer->window, false);
+    ImGui_ImplOpenGL3_Init(glsl_version);
+    ImGui::GetIO().IniFilename = nullptr;
+    ImGui::StyleColorsDark();
+    ImGuiStyle& style = ImGui::GetStyle();
+    style.FrameRounding = 5.0f;
+    reload_font();
+  }
+  init_widgets();
+}
+
+IGL_INLINE void ImGuiPlugin::init_widgets()
+{
+  // Init all widgets
+  for(auto & widget : widgets) { widget->init(viewer, this); }
+}
+IGL_INLINE void ImGuiPlugin::reload_font(int font_size)
+{
+  hidpi_scaling_ = hidpi_scaling();
+  pixel_ratio_ = pixel_ratio();
+  ImGuiIO& io = ImGui::GetIO();
+  io.Fonts->Clear();
+  io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data,
+    droid_sans_compressed_size, font_size * hidpi_scaling_);
+  io.FontGlobalScale = 1.0 / pixel_ratio_;
+}
+
+IGL_INLINE void ImGuiPlugin::shutdown()
+{
+  // Cleanup
+  ImGui_ImplOpenGL3_Shutdown();
+  ImGui_ImplGlfw_Shutdown();
+  // User is responsible for destroying context if a custom context is given
+  // ImGui::DestroyContext(*context_);
+}
+
+IGL_INLINE bool ImGuiPlugin::pre_draw()
+{
+  glfwPollEvents();
+
+  // Check whether window dpi has changed
+  float scaling = hidpi_scaling();
+  if (std::abs(scaling - hidpi_scaling_) > 1e-5)
+  {
+    reload_font();
+    ImGui_ImplOpenGL3_DestroyDeviceObjects();
+  }
+
+  ImGui_ImplOpenGL3_NewFrame();
+  ImGui_ImplGlfw_NewFrame();
+  ImGui::NewFrame();
+  return false;
+}
+
+IGL_INLINE bool ImGuiPlugin::post_draw()
+{
+  for(auto & widget : widgets){ widget->draw(); }
+  ImGui::Render();
+  ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
+  return false;
+}
+
+IGL_INLINE void ImGuiPlugin::post_resize(int width, int height)
+{
+  if (context_)
+  {
+    ImGui::GetIO().DisplaySize.x = float(width);
+    ImGui::GetIO().DisplaySize.y = float(height);
+  }
+}
+
+// Mouse IO
+IGL_INLINE bool ImGuiPlugin::mouse_down(int button, int modifier)
+{
+  ImGui_ImplGlfw_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier);
+  if(ImGui::GetIO().WantCaptureMouse){ return true; }
+  for( auto & widget : widgets)
+  { 
+    if(widget->mouse_down(button, modifier)) { return true; }
+  }
+  return false;
+}
+
+IGL_INLINE bool ImGuiPlugin::mouse_up(int button, int modifier)
+{
+  //return ImGui::GetIO().WantCaptureMouse;
+  // !! Should not steal mouse up
+  for( auto & widget : widgets)
+  { 
+    widget->mouse_up(button, modifier);
+  }
+  return false;
+}
+
+IGL_INLINE bool ImGuiPlugin::mouse_move(int mouse_x, int mouse_y)
+{
+  if(ImGui::GetIO().WantCaptureMouse){ return true; }
+  for( auto & widget : widgets)
+  { 
+    if(widget->mouse_move(mouse_x, mouse_y)) { return true; }
+  }
+  return false;
+}
+
+IGL_INLINE bool ImGuiPlugin::mouse_scroll(float delta_y)
+{
+  ImGui_ImplGlfw_ScrollCallback(viewer->window, 0.f, delta_y);
+  return ImGui::GetIO().WantCaptureMouse;
+}
+
+// Keyboard IO
+IGL_INLINE bool ImGuiPlugin::key_pressed(unsigned int key, int modifiers)
+{
+  ImGui_ImplGlfw_CharCallback(nullptr, key);
+  if(ImGui::GetIO().WantCaptureKeyboard) { return true; }
+  for(auto & widget : widgets)
+  { 
+    if(widget->key_pressed(key,modifiers)) {return true; }
+  }
+  return false;
+}
+
+IGL_INLINE bool ImGuiPlugin::key_down(int key, int modifiers)
+{
+  ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers);
+  if(ImGui::GetIO().WantCaptureKeyboard) { return true; }
+  for(auto & widget : widgets)
+  { 
+    if(widget->key_down(key,modifiers)) {return true; }
+  }
+  return false;
+}
+
+IGL_INLINE bool ImGuiPlugin::key_up(int key, int modifiers)
+{
+  ImGui_ImplGlfw_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers);
+  if(ImGui::GetIO().WantCaptureKeyboard) { return true; }
+  for(auto & widget : widgets)
+  { 
+    if(widget->key_up(key,modifiers)) { return true; }
+  }
+  return false;
+}
+
+IGL_INLINE float ImGuiPlugin::pixel_ratio()
+{
+  // Computes pixel ratio for hidpi devices
+  int buf_size[2];
+  int win_size[2];
+  GLFWwindow* window = glfwGetCurrentContext();
+  glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]);
+  glfwGetWindowSize(window, &win_size[0], &win_size[1]);
+  return (float) buf_size[0] / (float) win_size[0];
+}
+
+IGL_INLINE float ImGuiPlugin::hidpi_scaling()
+{
+  // Computes scaling factor for hidpi devices
+  float xscale, yscale;
+  GLFWwindow* window = glfwGetCurrentContext();
+  glfwGetWindowContentScale(window, &xscale, &yscale);
+  return 0.5 * (xscale + yscale);
+}
+
+} // end namespace
+} // end namespace
+} // end namespace
+} // end namespace
+

+ 77 - 0
include/igl/opengl/glfw/imgui/ImGuiPlugin.h

@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2022 Alec Jacobson <[email protected]>
+// Copyright (C) 2018 Jérémie Dumas <[email protected]>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIPLUGIN_H
+#define IGL_OPENGL_GLFW_IMGUI_IMGUIPLUGIN_H
+
+#include "../Viewer.h"
+#include "../ViewerPlugin.h"
+#include "../../../igl_inline.h"
+#include "ImGuiWidget.h"
+
+// Forward declarations
+struct ImGuiContext;
+
+namespace igl
+{
+  namespace opengl
+  {
+    namespace glfw
+    {
+      namespace imgui
+      {
+        // Forward declaration of child widget abstract type
+        class ImGuiWidget;
+        class ImGuiPlugin : public igl::opengl::glfw::ViewerPlugin
+        {
+          protected:
+            // Hidpi scaling to be used for text rendering.
+            float hidpi_scaling_;
+            // Ratio between the framebuffer size and the window size.
+            // May be different from the hipdi scaling!
+            float pixel_ratio_;
+            // ImGui Context
+            ImGuiContext * context_ = nullptr;
+          public:
+            // List of registered widgets
+            std::vector<ImGuiWidget*> widgets;
+          public:
+            IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
+            IGL_INLINE void init_widgets();
+            IGL_INLINE virtual void reload_font(int font_size = 13);
+            IGL_INLINE virtual void shutdown() override;
+            IGL_INLINE virtual bool pre_draw() override;
+            IGL_INLINE virtual bool post_draw() override;
+            IGL_INLINE virtual void post_resize(int width, int height) override;
+            IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
+            IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
+            IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
+            IGL_INLINE virtual bool mouse_scroll(float delta_y) override;
+            // Keyboard IO
+            IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
+            IGL_INLINE virtual bool key_down(int key, int modifiers) override;
+            IGL_INLINE virtual bool key_up(int key, int modifiers) override;
+            IGL_INLINE void draw_text(
+                const Eigen::Vector3d pos,
+                const Eigen::Vector3d normal,
+                const std::string &text,
+                const Eigen::Vector4f color = Eigen::Vector4f(0,0,0.04,1)); // old default color
+            IGL_INLINE float pixel_ratio();
+            IGL_INLINE float hidpi_scaling();
+        };
+      }
+    }
+  }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#  include "ImGuiPlugin.cpp"
+#endif
+
+#endif 
+

+ 65 - 0
include/igl/opengl/glfw/imgui/ImGuiWidget.h

@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2022 Alec Jacobson <[email protected]>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIWIDGET_H
+#define IGL_OPENGL_GLFW_IMGUI_IMGUIWIDGET_H
+
+#include "ImGuiPlugin.h"
+#include "ImGuiWidget.h"
+#include "../../../igl_inline.h"
+#include <memory>
+
+namespace igl
+{
+  namespace opengl
+  {
+    namespace glfw
+    {
+      class Viewer;
+      namespace imgui
+      {
+        // Forward declaration of the parent plugin
+        class ImGuiPlugin;
+        // Abstract class for imgui "widgets". A widget is something that uses
+        // imgui, but doesn't own the entire imgui IO stack: the single
+        // ImGuiPlugin owns that and widgets are registered with it.
+        class ImGuiWidget 
+        {
+          public:
+            IGL_INLINE ImGuiWidget(){ name = "dummy"; }
+            virtual ~ImGuiWidget(){}
+            IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin)
+              { viewer = _viewer; plugin = _plugin; }
+            IGL_INLINE virtual void shutdown() {}
+            IGL_INLINE virtual void draw() {}
+            IGL_INLINE virtual bool mouse_down(int button, int modifier)
+              { return false;}
+            IGL_INLINE virtual bool mouse_up(int button, int modifier)
+              { return false;}
+            IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y)
+              { return false;}
+            IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers)
+              { return false;}
+            IGL_INLINE virtual bool key_down(int key, int modifiers)
+              { return false;}
+            IGL_INLINE virtual bool key_up(int key, int modifiers)
+              { return false;}
+            std::string name;
+          protected:
+            // Pointer to ImGuiPlugin's parent viewer
+            Viewer *viewer;
+            // Pointer to parent ImGuiPlugin class
+            ImGuiPlugin *plugin;
+        };
+
+      }
+    }
+  }
+}
+
+#endif
+

+ 6 - 14
include/igl/opengl/glfw/imgui/ImGuizmoPlugin.cpp → include/igl/opengl/glfw/imgui/ImGuizmoWidget.cpp

@@ -1,4 +1,4 @@
-#include "ImGuizmoPlugin.h"
+#include "ImGuizmoWidget.h"
 #include <imgui.h>
 #include <imgui.h>
 #include <backends/imgui_impl_glfw.h>
 #include <backends/imgui_impl_glfw.h>
 #include <backends/imgui_impl_opengl3.h>
 #include <backends/imgui_impl_opengl3.h>
@@ -7,22 +7,17 @@
 
 
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 
 
-IGL_INLINE void ImGuizmoPlugin::init(igl::opengl::glfw::Viewer *_viewer)
+IGL_INLINE void ImGuizmoWidget::init(Viewer *_viewer, ImGuiPlugin *_plugin)
 {
 {
-  ImGuiMenu::init(_viewer);
+  ImGuiWidget::init(_viewer,_plugin);
 }
 }
-IGL_INLINE bool ImGuizmoPlugin::pre_draw()
+
+IGL_INLINE void ImGuizmoWidget::draw()
 {
 {
-  if(!visible){ return false; }
-  ImGuiMenu::pre_draw();
+  if(!visible){ return; }
   ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
   ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
   ImGuizmo::BeginFrame();
   ImGuizmo::BeginFrame();
   ImGui::PopStyleVar();
   ImGui::PopStyleVar();
-  return false;
-}
-IGL_INLINE bool ImGuizmoPlugin::post_draw()
-{
-  if(!visible){ return false; }
   // Don't draw the Viewer's default menu: draw just the ImGuizmo
   // Don't draw the Viewer's default menu: draw just the ImGuizmo
   Eigen::Matrix4f view = (viewer->core().view / viewer->core().camera_zoom);
   Eigen::Matrix4f view = (viewer->core().view / viewer->core().camera_zoom);
   Eigen::Matrix4f proj = viewer->core().proj;
   Eigen::Matrix4f proj = viewer->core().proj;
@@ -43,9 +38,6 @@ IGL_INLINE bool ImGuizmoPlugin::post_draw()
   const float diff = (T-T0).array().abs().maxCoeff();
   const float diff = (T-T0).array().abs().maxCoeff();
   // Only call if actually changed; otherwise, triggers on all mouse events
   // Only call if actually changed; otherwise, triggers on all mouse events
   if( diff > 1e-7) { callback(T); }
   if( diff > 1e-7) { callback(T); }
-  ImGui::Render();
-  ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
-  return false;
 }
 }
 
 
 }}}}
 }}}}

+ 5 - 9
include/igl/opengl/glfw/imgui/ImGuizmoPlugin.h → include/igl/opengl/glfw/imgui/ImGuizmoWidget.h

@@ -9,7 +9,7 @@
 
 
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 
 
-class ImGuizmoPlugin : public igl::opengl::glfw::imgui::ImGuiMenu
+class ImGuizmoWidget : public ImGuiWidget
 {
 {
 public:
 public:
   // callback(T) called when the stored transform T changes
   // callback(T) called when the stored transform T changes
@@ -21,19 +21,15 @@ public:
   // stored transformation
   // stored transformation
   Eigen::Matrix4f T;
   Eigen::Matrix4f T;
   // Initilize with rotate operation on an identity transform (at origin)
   // Initilize with rotate operation on an identity transform (at origin)
-  ImGuizmoPlugin():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){};
-  /////////////////////////////////////////////////////////////////////////////
-  // Boilerplate
-  virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
-  virtual bool pre_draw() override;
-  /////////////////////////////////////////////////////////////////////////////
-  virtual bool post_draw() override;
+  ImGuizmoWidget():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){};
+  IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin) override;
+  IGL_INLINE virtual void draw() override;
 };
 };
 
 
 }}}}
 }}}}
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
-#  include "ImGuizmoPlugin.cpp"
+#  include "ImGuizmoWidget.cpp"
 #endif
 #endif
 
 
 #endif
 #endif

+ 21 - 22
include/igl/opengl/glfw/imgui/SelectionPlugin.cpp → include/igl/opengl/glfw/imgui/SelectionWidget.cpp

@@ -1,4 +1,11 @@
-#include "SelectionPlugin.h"
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2022 Alec Jacobson <[email protected]>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "SelectionWidget.h"
 
 
 #include <imgui.h>
 #include <imgui.h>
 #include <backends/imgui_impl_glfw.h>
 #include <backends/imgui_impl_glfw.h>
@@ -9,26 +16,20 @@
 
 
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 
 
-IGL_INLINE void SelectionPlugin::init(igl::opengl::glfw::Viewer *_viewer)
+IGL_INLINE void SelectionWidget::init(Viewer *_viewer, ImGuiPlugin *_plugin)
 {
 {
-  ImGuiMenu::init(_viewer);
+  ImGuiWidget::init(_viewer,_plugin);
   std::cout<<R"(
   std::cout<<R"(
-igl::opengl::glfw::imgui::SelectionPlugin usage:
+igl::opengl::glfw::imgui::SelectionWidget usage:
   [drag]  Draw a 2D selection
   [drag]  Draw a 2D selection
   l       Turn on and toggle between lasso and polygonal lasso tool
   l       Turn on and toggle between lasso and polygonal lasso tool
   M,m     Turn on and toggle between rectangular and circular marquee tool
   M,m     Turn on and toggle between rectangular and circular marquee tool
   V,v     Turn off interactive selection
   V,v     Turn off interactive selection
 )";
 )";
 }
 }
-IGL_INLINE bool SelectionPlugin::pre_draw()
+IGL_INLINE void SelectionWidget::draw()
 {
 {
-  if(mode == OFF){ return false; }
-  ImGuiMenu::pre_draw();
-  return false;
-}
-IGL_INLINE bool SelectionPlugin::post_draw()
-{
-  if(mode == OFF){ return false; }
+  if(mode == OFF){ return; }
   ImGuiIO& io = ImGui::GetIO();
   ImGuiIO& io = ImGui::GetIO();
 
 
   float width, height;
   float width, height;
@@ -78,11 +79,9 @@ IGL_INLINE bool SelectionPlugin::post_draw()
   ImGui::Render();
   ImGui::Render();
   ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
   ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
 
 
-
-  return false;
 }
 }
 
 
-IGL_INLINE bool SelectionPlugin::mouse_down(int button, int modifier)
+IGL_INLINE bool SelectionWidget::mouse_down(int button, int modifier)
 {
 {
   if(mode == OFF || (modifier & IGL_MOD_ALT) ){ return false;}
   if(mode == OFF || (modifier & IGL_MOD_ALT) ){ return false;}
   is_down = true;
   is_down = true;
@@ -98,7 +97,7 @@ IGL_INLINE bool SelectionPlugin::mouse_down(int button, int modifier)
   return true;
   return true;
 }
 }
 
 
-IGL_INLINE bool SelectionPlugin::mouse_up(int button, int modifier)
+IGL_INLINE bool SelectionWidget::mouse_up(int button, int modifier)
 {
 {
   is_down = false;
   is_down = false;
   // are we done? Check first and last lasso point (need at least 3 (2 real
   // are we done? Check first and last lasso point (need at least 3 (2 real
@@ -112,7 +111,7 @@ IGL_INLINE bool SelectionPlugin::mouse_up(int button, int modifier)
   return false;
   return false;
 }
 }
 
 
-IGL_INLINE bool SelectionPlugin::mouse_move(int mouse_x, int mouse_y)
+IGL_INLINE bool SelectionWidget::mouse_move(int mouse_x, int mouse_y)
 {
 {
   if(!is_drawing){ return false; }
   if(!is_drawing){ return false; }
   if(!has_moved_since_down)
   if(!has_moved_since_down)
@@ -141,7 +140,7 @@ IGL_INLINE bool SelectionPlugin::mouse_move(int mouse_x, int mouse_y)
   return true;
   return true;
 }
 }
 
 
-IGL_INLINE bool SelectionPlugin::key_pressed(unsigned int key, int modifiers)
+IGL_INLINE bool SelectionWidget::key_pressed(unsigned int key, int modifiers)
 {
 {
   Mode old = mode;
   Mode old = mode;
   if(OFF_KEY.find(char(key)) != std::string::npos)
   if(OFF_KEY.find(char(key)) != std::string::npos)
@@ -175,7 +174,7 @@ IGL_INLINE bool SelectionPlugin::key_pressed(unsigned int key, int modifiers)
   return false;
   return false;
 }
 }
 
 
-IGL_INLINE void SelectionPlugin::clear()
+IGL_INLINE void SelectionWidget::clear()
 {
 {
   M.setZero();
   M.setZero();
   L.clear();
   L.clear();
@@ -183,7 +182,7 @@ IGL_INLINE void SelectionPlugin::clear()
   is_down = false;
   is_down = false;
 };
 };
 
 
-IGL_INLINE void SelectionPlugin::circle(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L)
+IGL_INLINE void SelectionWidget::circle(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L)
 {
 {
   L.clear();
   L.clear();
   L.reserve(64);
   L.reserve(64);
@@ -194,7 +193,7 @@ IGL_INLINE void SelectionPlugin::circle(const Eigen::Matrix<float,2,2> & M,  std
   }
   }
 }
 }
 
 
-IGL_INLINE void SelectionPlugin::rect(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L)
+IGL_INLINE void SelectionWidget::rect(const Eigen::Matrix<float,2,2> & M,  std::vector<Eigen::RowVector2f> & L)
 {
 {
   L.resize(4);
   L.resize(4);
   L[0] = Eigen::RowVector2f(M(0,0),M(0,1));
   L[0] = Eigen::RowVector2f(M(0,0),M(0,1));
@@ -203,7 +202,7 @@ IGL_INLINE void SelectionPlugin::rect(const Eigen::Matrix<float,2,2> & M,  std::
   L[3] = Eigen::RowVector2f(M(0,0),M(1,1));
   L[3] = Eigen::RowVector2f(M(0,0),M(1,1));
 }
 }
 
 
-IGL_INLINE Eigen::RowVector2f SelectionPlugin::xy(const Viewer * vr)
+IGL_INLINE Eigen::RowVector2f SelectionWidget::xy(const Viewer * vr)
 {
 {
   return Eigen::RowVector2f(
   return Eigen::RowVector2f(
     vr->current_mouse_x,
     vr->current_mouse_x,

+ 10 - 18
include/igl/opengl/glfw/imgui/SelectionPlugin.h → include/igl/opengl/glfw/imgui/SelectionWidget.h

@@ -1,16 +1,15 @@
-#ifndef IGL_OPENGL_GFLW_IMGUI_IMGUIDRAWLISTPLUGIN_H
-#define IGL_OPENGL_GFLW_IMGUI_IMGUIDRAWLISTPLUGIN_H
-#include <igl/igl_inline.h>
-#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
-#include <imgui.h>
-#include <imgui_internal.h>
-#include <ImGuizmo.h>
+#ifndef IGL_OPENGL_GFLW_IMGUI_SELECTIONWIDGET_H
+#define IGL_OPENGL_GFLW_IMGUI_SELECTIONWIDGET_H
+#include "../../../igl_inline.h"
+#include "ImGuiWidget.h"
 #include <Eigen/Dense>
 #include <Eigen/Dense>
 #include <vector>
 #include <vector>
+#include <string>
+#include <functional>
 
 
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 
 
-class SelectionPlugin: public igl::opengl::glfw::imgui::ImGuiMenu
+class SelectionWidget: public ImGuiWidget
 {
 {
 public:
 public:
   // customizable hotkeys
   // customizable hotkeys
@@ -38,15 +37,8 @@ public:
   std::function<void(void)> callback;
   std::function<void(void)> callback;
   // callback called after mode is changed
   // callback called after mode is changed
   std::function<void(Mode)> callback_post_mode_change;
   std::function<void(Mode)> callback_post_mode_change;
-  // whether rotating, translating or scaling
-  ImGuizmo::OPERATION operation;
-  // stored transformation
-  Eigen::Matrix4f T;
-  // Initilize with rotate operation on an identity transform (at origin)
-  SelectionPlugin():operation(ImGuizmo::ROTATE),T(Eigen::Matrix4f::Identity()){};
-  IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
-  IGL_INLINE virtual bool pre_draw() override;
-  IGL_INLINE virtual bool post_draw() override;
+  IGL_INLINE virtual void init(Viewer *_viewer, ImGuiPlugin *_plugin) override;
+  IGL_INLINE virtual void draw() override;
   IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
   IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
   IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
   IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
   IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
   IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
@@ -63,6 +55,6 @@ public:
 }}}}
 }}}}
 
 
 #ifndef IGL_STATIC_LIBRARY
 #ifndef IGL_STATIC_LIBRARY
-#include "SelectionPlugin.cpp"
+#include "SelectionWidget.cpp"
 #endif
 #endif
 #endif
 #endif

+ 4 - 1
tutorial/105_Overlays/main.cpp

@@ -1,5 +1,6 @@
 #include <igl/readOFF.h>
 #include <igl/readOFF.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #include <sstream>
 #include <sstream>
 
 
@@ -71,9 +72,11 @@ int main(int argc, char *argv[])
 
 
   // Rendering of text labels is handled by ImGui, so we need to enable the ImGui
   // Rendering of text labels is handled by ImGui, so we need to enable the ImGui
   // plugin to show text labels.
   // plugin to show text labels.
+  igl::opengl::glfw::imgui::ImGuiPlugin plugin;
+  viewer.plugins.push_back(&plugin);
   igl::opengl::glfw::imgui::ImGuiMenu menu;
   igl::opengl::glfw::imgui::ImGuiMenu menu;
+  plugin.widgets.push_back(&menu);
   menu.callback_draw_viewer_window = [](){};
   menu.callback_draw_viewer_window = [](){};
-  viewer.plugins.push_back(&menu);
 
 
   // Launch the viewer
   // Launch the viewer
   viewer.launch();
   viewer.launch();

+ 4 - 1
tutorial/106_ViewerMenu/main.cpp

@@ -1,5 +1,6 @@
 #include <igl/readOFF.h>
 #include <igl/readOFF.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #include <igl/opengl/glfw/imgui/ImGuiHelpers.h>
 #include <igl/opengl/glfw/imgui/ImGuiHelpers.h>
 #include <iostream>
 #include <iostream>
@@ -16,8 +17,10 @@ int main(int argc, char *argv[])
   igl::opengl::glfw::Viewer viewer;
   igl::opengl::glfw::Viewer viewer;
 
 
   // Attach a menu plugin
   // Attach a menu plugin
+  igl::opengl::glfw::imgui::ImGuiPlugin plugin;
+  viewer.plugins.push_back(&plugin);
   igl::opengl::glfw::imgui::ImGuiMenu menu;
   igl::opengl::glfw::imgui::ImGuiMenu menu;
-  viewer.plugins.push_back(&menu);
+  plugin.widgets.push_back(&menu);
 
 
   // Customize the menu
   // Customize the menu
   double doubleVariable = 0.1f; // Shared between two menus
   double doubleVariable = 0.1f; // Shared between two menus

+ 21 - 11
tutorial/109_ImGuizmo/main.cpp

@@ -1,6 +1,8 @@
 #include <igl/read_triangle_mesh.h>
 #include <igl/read_triangle_mesh.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/opengl/glfw/Viewer.h>
-#include <igl/opengl/glfw/imgui/ImGuizmoPlugin.h>
+#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
+#include <igl/opengl/glfw/imgui/ImGuiMenu.h>
+#include <igl/opengl/glfw/imgui/ImGuizmoWidget.h>
 #include <GLFW/glfw3.h>
 #include <GLFW/glfw3.h>
 
 
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
@@ -12,16 +14,20 @@ int main(int argc, char *argv[])
   // Set up viewer
   // Set up viewer
   igl::opengl::glfw::Viewer vr;
   igl::opengl::glfw::Viewer vr;
   vr.data().set_mesh(V,F);
   vr.data().set_mesh(V,F);
-  // Custom menu
-  igl::opengl::glfw::imgui::ImGuizmoPlugin plugin;
-  vr.plugins.push_back(&plugin);
+ 
+  igl::opengl::glfw::imgui::ImGuiPlugin imgui_plugin;
+  vr.plugins.push_back(&imgui_plugin);
+
+  // Add a 3D gizmo plugin
+  igl::opengl::glfw::imgui::ImGuizmoWidget gizmo;
+  imgui_plugin.widgets.push_back(&gizmo);
   // Initialize ImGuizmo at mesh centroid
   // Initialize ImGuizmo at mesh centroid
-  plugin.T.block(0,3,3,1) =
+  gizmo.T.block(0,3,3,1) =
     0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff()).transpose().cast<float>();
     0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff()).transpose().cast<float>();
   // Update can be applied relative to this remembered initial transform
   // Update can be applied relative to this remembered initial transform
-  const Eigen::Matrix4f T0 = plugin.T;
+  const Eigen::Matrix4f T0 = gizmo.T;
   // Attach callback to apply imguizmo's transform to mesh
   // Attach callback to apply imguizmo's transform to mesh
-  plugin.callback = [&](const Eigen::Matrix4f & T)
+  gizmo.callback = [&](const Eigen::Matrix4f & T)
   {
   {
     const Eigen::Matrix4d TT = (T*T0.inverse()).cast<double>().transpose();
     const Eigen::Matrix4d TT = (T*T0.inverse()).cast<double>().transpose();
     vr.data().set_vertices(
     vr.data().set_vertices(
@@ -33,13 +39,17 @@ int main(int argc, char *argv[])
   {
   {
     switch(key)
     switch(key)
     {
     {
-      case ' ': plugin.visible = !plugin.visible; return true;
-      case 'W': case 'w': plugin.operation = ImGuizmo::TRANSLATE; return true;
-      case 'E': case 'e': plugin.operation = ImGuizmo::ROTATE;    return true;
-      case 'R': case 'r': plugin.operation = ImGuizmo::SCALE;     return true;
+      case ' ': gizmo.visible = !gizmo.visible; return true;
+      case 'W': case 'w': gizmo.operation = ImGuizmo::TRANSLATE; return true;
+      case 'E': case 'e': gizmo.operation = ImGuizmo::ROTATE;    return true;
+      case 'R': case 'r': gizmo.operation = ImGuizmo::SCALE;     return true;
     }
     }
     return false;
     return false;
   };
   };
+
+  igl::opengl::glfw::imgui::ImGuiMenu menu;
+  imgui_plugin.widgets.push_back(&menu);
+
   std::cout<<R"(
   std::cout<<R"(
 W,w  Switch to translate operation
 W,w  Switch to translate operation
 E,e  Switch to rotate operation
 E,e  Switch to rotate operation

+ 9 - 5
tutorial/112_Selection/main.cpp

@@ -5,7 +5,8 @@
 #include <igl/AABB.h>
 #include <igl/AABB.h>
 #include <igl/screen_space_selection.h>
 #include <igl/screen_space_selection.h>
 
 
-#include <igl/opengl/glfw/imgui/SelectionPlugin.h>
+#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
+#include <igl/opengl/glfw/imgui/SelectionWidget.h>
 
 
 int main(int argc, char *argv[])
 int main(int argc, char *argv[])
 {
 {
@@ -17,7 +18,11 @@ int main(int argc, char *argv[])
 
 
   // Plot the mesh
   // Plot the mesh
   igl::opengl::glfw::Viewer vr;
   igl::opengl::glfw::Viewer vr;
-  igl::opengl::glfw::imgui::SelectionPlugin plugin;
+  igl::opengl::glfw::imgui::ImGuiPlugin imgui_plugin;
+  vr.plugins.push_back(&imgui_plugin);
+  igl::opengl::glfw::imgui::SelectionWidget widget;
+  imgui_plugin.widgets.push_back(&widget);
+
   Eigen::VectorXd W = Eigen::VectorXd::Zero(V.rows());
   Eigen::VectorXd W = Eigen::VectorXd::Zero(V.rows());
   Eigen::Array<double,Eigen::Dynamic,1> and_visible = 
   Eigen::Array<double,Eigen::Dynamic,1> and_visible = 
     Eigen::Array<double,Eigen::Dynamic,1>::Zero(V.rows());
     Eigen::Array<double,Eigen::Dynamic,1>::Zero(V.rows());
@@ -36,9 +41,9 @@ int main(int argc, char *argv[])
   };
   };
   igl::AABB<Eigen::MatrixXd, 3> tree;
   igl::AABB<Eigen::MatrixXd, 3> tree;
   tree.init(V,F);
   tree.init(V,F);
-  plugin.callback = [&]()
+  widget.callback = [&]()
   {
   {
-    screen_space_selection(V,F,tree,vr.core().view,vr.core().proj,vr.core().viewport,plugin.L,W,and_visible);
+    screen_space_selection(V,F,tree,vr.core().view,vr.core().proj,vr.core().viewport,widget.L,W,and_visible);
     update();
     update();
   };
   };
   vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod)
   vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod)
@@ -55,7 +60,6 @@ Usage:
   [space]  Toggle whether to take visibility into account
   [space]  Toggle whether to take visibility into account
   D,d      Clear selection
   D,d      Clear selection
 )";
 )";
-  vr.plugins.push_back(&plugin);
   vr.data().set_mesh(V,F);
   vr.data().set_mesh(V,F);
   vr.data().set_face_based(true);
   vr.data().set_face_based(true);
   vr.core().background_color.head(3) = CM.row(0).head(3).cast<float>();
   vr.core().background_color.head(3) = CM.row(0).head(3).cast<float>();

+ 6 - 5
tutorial/409_Kelvinlets/main.cpp

@@ -1,5 +1,6 @@
 #include <igl/kelvinlets.h>
 #include <igl/kelvinlets.h>
 #include <igl/opengl/glfw/Viewer.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #include <igl/readOFF.h>
 #include <igl/readOFF.h>
 #include <igl/unproject.h>
 #include <igl/unproject.h>
@@ -34,9 +35,10 @@ int main()
   F1 = OrigF;
   F1 = OrigF;
 
 
   igl::opengl::glfw::Viewer viewer;
   igl::opengl::glfw::Viewer viewer;
+  igl::opengl::glfw::imgui::ImGuiPlugin plugin;
+  viewer.plugins.push_back(&plugin);
   igl::opengl::glfw::imgui::ImGuiMenu menu;
   igl::opengl::glfw::imgui::ImGuiMenu menu;
-
-  viewer.plugins.push_back(&menu);
+  plugin.widgets.push_back(&menu);
 
 
   auto brushRadius = 1.;
   auto brushRadius = 1.;
   auto brushType = igl::BrushType::GRAB;
   auto brushType = igl::BrushType::GRAB;
@@ -70,7 +72,6 @@ int main()
 
 
   viewer.callback_key_down =
   viewer.callback_key_down =
     [&](igl::opengl::glfw::Viewer& viewer, unsigned char key, int) {
     [&](igl::opengl::glfw::Viewer& viewer, unsigned char key, int) {
-      std::cout << "Key: " << key << " " << (unsigned int)key << std::endl;
       if (key == '1') {
       if (key == '1') {
         viewer.data().clear();
         viewer.data().clear();
         viewer.data().set_mesh(OrigV, OrigF);
         viewer.data().set_mesh(OrigV, OrigF);
@@ -152,8 +153,8 @@ int main()
         mat,
         mat,
         igl::KelvinletParams<double>(brushRadius, scale, brushType),
         igl::KelvinletParams<double>(brushRadius, scale, brushType),
         result);
         result);
-      viewer.data().set_mesh(result, F1);
-      viewer.core().align_camera_center(result, F1);
+      viewer.data().set_vertices(result);
+      viewer.data().compute_normals();
       return true;
       return true;
     }
     }
     return false;
     return false;