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 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

+ 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.
 //
+// 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
@@ -8,14 +9,8 @@
 ////////////////////////////////////////////////////////////////////////////////
 #include "ImGuiMenu.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
 {
@@ -26,131 +21,13 @@ namespace glfw
 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
   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

+ 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.
 //
+// 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
@@ -8,104 +9,47 @@
 #ifndef 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>
-////////////////////////////////////////////////////////////////////////////////
-
-// Forward declarations
-struct ImGuiContext;
 
 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
 #  include "ImGuiMenu.cpp"
 #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 <backends/imgui_impl_glfw.h>
 #include <backends/imgui_impl_opengl3.h>
@@ -7,22 +7,17 @@
 
 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);
   ImGuizmo::BeginFrame();
   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
   Eigen::Matrix4f view = (viewer->core().view / viewer->core().camera_zoom);
   Eigen::Matrix4f proj = viewer->core().proj;
@@ -43,9 +38,6 @@ IGL_INLINE bool ImGuizmoPlugin::post_draw()
   const float diff = (T-T0).array().abs().maxCoeff();
   // Only call if actually changed; otherwise, triggers on all mouse events
   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{
 
-class ImGuizmoPlugin : public igl::opengl::glfw::imgui::ImGuiMenu
+class ImGuizmoWidget : public ImGuiWidget
 {
 public:
   // callback(T) called when the stored transform T changes
@@ -21,19 +21,15 @@ public:
   // stored transformation
   Eigen::Matrix4f T;
   // 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
-#  include "ImGuizmoPlugin.cpp"
+#  include "ImGuizmoWidget.cpp"
 #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 <backends/imgui_impl_glfw.h>
@@ -9,26 +16,20 @@
 
 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"(
-igl::opengl::glfw::imgui::SelectionPlugin usage:
+igl::opengl::glfw::imgui::SelectionWidget usage:
   [drag]  Draw a 2D selection
   l       Turn on and toggle between lasso and polygonal lasso tool
   M,m     Turn on and toggle between rectangular and circular marquee tool
   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();
 
   float width, height;
@@ -78,11 +79,9 @@ IGL_INLINE bool SelectionPlugin::post_draw()
   ImGui::Render();
   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;}
   is_down = true;
@@ -98,7 +97,7 @@ IGL_INLINE bool SelectionPlugin::mouse_down(int button, int modifier)
   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;
   // 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;
 }
 
-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(!has_moved_since_down)
@@ -141,7 +140,7 @@ IGL_INLINE bool SelectionPlugin::mouse_move(int mouse_x, int mouse_y)
   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;
   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;
 }
 
-IGL_INLINE void SelectionPlugin::clear()
+IGL_INLINE void SelectionWidget::clear()
 {
   M.setZero();
   L.clear();
@@ -183,7 +182,7 @@ IGL_INLINE void SelectionPlugin::clear()
   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.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[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));
 }
 
-IGL_INLINE Eigen::RowVector2f SelectionPlugin::xy(const Viewer * vr)
+IGL_INLINE Eigen::RowVector2f SelectionWidget::xy(const Viewer * vr)
 {
   return Eigen::RowVector2f(
     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 <vector>
+#include <string>
+#include <functional>
 
 namespace igl{ namespace opengl{ namespace glfw{ namespace imgui{
 
-class SelectionPlugin: public igl::opengl::glfw::imgui::ImGuiMenu
+class SelectionWidget: public ImGuiWidget
 {
 public:
   // customizable hotkeys
@@ -38,15 +37,8 @@ public:
   std::function<void(void)> callback;
   // callback called after mode is changed
   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_up(int button, int modifier) override;
   IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
@@ -63,6 +55,6 @@ public:
 }}}}
 
 #ifndef IGL_STATIC_LIBRARY
-#include "SelectionPlugin.cpp"
+#include "SelectionWidget.cpp"
 #endif
 #endif

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

@@ -1,5 +1,6 @@
 #include <igl/readOFF.h>
 #include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #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
   // plugin to show text labels.
+  igl::opengl::glfw::imgui::ImGuiPlugin plugin;
+  viewer.plugins.push_back(&plugin);
   igl::opengl::glfw::imgui::ImGuiMenu menu;
+  plugin.widgets.push_back(&menu);
   menu.callback_draw_viewer_window = [](){};
-  viewer.plugins.push_back(&menu);
 
   // Launch the viewer
   viewer.launch();

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

@@ -1,5 +1,6 @@
 #include <igl/readOFF.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/ImGuiHelpers.h>
 #include <iostream>
@@ -16,8 +17,10 @@ int main(int argc, char *argv[])
   igl::opengl::glfw::Viewer viewer;
 
   // Attach a menu plugin
+  igl::opengl::glfw::imgui::ImGuiPlugin plugin;
+  viewer.plugins.push_back(&plugin);
   igl::opengl::glfw::imgui::ImGuiMenu menu;
-  viewer.plugins.push_back(&menu);
+  plugin.widgets.push_back(&menu);
 
   // Customize the menu
   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/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>
 
 int main(int argc, char *argv[])
@@ -12,16 +14,20 @@ int main(int argc, char *argv[])
   // Set up viewer
   igl::opengl::glfw::Viewer vr;
   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
-  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>();
   // 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
-  plugin.callback = [&](const Eigen::Matrix4f & T)
+  gizmo.callback = [&](const Eigen::Matrix4f & T)
   {
     const Eigen::Matrix4d TT = (T*T0.inverse()).cast<double>().transpose();
     vr.data().set_vertices(
@@ -33,13 +39,17 @@ int main(int argc, char *argv[])
   {
     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;
   };
+
+  igl::opengl::glfw::imgui::ImGuiMenu menu;
+  imgui_plugin.widgets.push_back(&menu);
+
   std::cout<<R"(
 W,w  Switch to translate operation
 E,e  Switch to rotate operation

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

@@ -5,7 +5,8 @@
 #include <igl/AABB.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[])
 {
@@ -17,7 +18,11 @@ int main(int argc, char *argv[])
 
   // Plot the mesh
   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::Array<double,Eigen::Dynamic,1> and_visible = 
     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;
   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();
   };
   vr.callback_key_pressed = [&](decltype(vr) &,unsigned int key, int mod)
@@ -55,7 +60,6 @@ Usage:
   [space]  Toggle whether to take visibility into account
   D,d      Clear selection
 )";
-  vr.plugins.push_back(&plugin);
   vr.data().set_mesh(V,F);
   vr.data().set_face_based(true);
   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/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/imgui/ImGuiPlugin.h>
 #include <igl/opengl/glfw/imgui/ImGuiMenu.h>
 #include <igl/readOFF.h>
 #include <igl/unproject.h>
@@ -34,9 +35,10 @@ int main()
   F1 = OrigF;
 
   igl::opengl::glfw::Viewer viewer;
+  igl::opengl::glfw::imgui::ImGuiPlugin plugin;
+  viewer.plugins.push_back(&plugin);
   igl::opengl::glfw::imgui::ImGuiMenu menu;
-
-  viewer.plugins.push_back(&menu);
+  plugin.widgets.push_back(&menu);
 
   auto brushRadius = 1.;
   auto brushType = igl::BrushType::GRAB;
@@ -70,7 +72,6 @@ int main()
 
   viewer.callback_key_down =
     [&](igl::opengl::glfw::Viewer& viewer, unsigned char key, int) {
-      std::cout << "Key: " << key << " " << (unsigned int)key << std::endl;
       if (key == '1') {
         viewer.data().clear();
         viewer.data().set_mesh(OrigV, OrigF);
@@ -152,8 +153,8 @@ int main()
         mat,
         igl::KelvinletParams<double>(brushRadius, scale, brushType),
         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 false;