From 65e6fd1fade972a7a73ea37c0efa2973da9d08a7 Mon Sep 17 00:00:00 2001
From: Philip Trettner <Philip.Trettner@rwth-aachen.de>
Date: Tue, 15 Aug 2017 12:29:03 +0200
Subject: [PATCH] Added double/multi click support

---
 glfw/glow-extras/glfw/GlfwApp.cc | 129 ++++++++++++++++++++-----------
 glfw/glow-extras/glfw/GlfwApp.hh |  17 +++-
 2 files changed, 99 insertions(+), 47 deletions(-)

diff --git a/glfw/glow-extras/glfw/GlfwApp.cc b/glfw/glow-extras/glfw/GlfwApp.cc
index 0a92b76..2f2b85a 100644
--- a/glfw/glow-extras/glfw/GlfwApp.cc
+++ b/glfw/glow-extras/glfw/GlfwApp.cc
@@ -94,11 +94,16 @@ void GlfwApp::render(float elapsedSeconds)
 {
     if (mUseDefaultRendering)
     {
-        mPipeline->render([this, elapsedSeconds](const pipeline::RenderPass &pass) { renderPass(pass, elapsedSeconds); });
+        mPipeline->render([this, elapsedSeconds](const pipeline::RenderPass &pass)
+                          {
+                              renderPass(pass, elapsedSeconds);
+                          });
     }
 }
 
-void GlfwApp::renderPass(const pipeline::RenderPass &pass, float elapsedSeconds) {}
+void GlfwApp::renderPass(const pipeline::RenderPass &pass, float elapsedSeconds)
+{
+}
 
 void GlfwApp::onResize(int w, int h)
 {
@@ -109,7 +114,9 @@ void GlfwApp::onResize(int w, int h)
     }
 }
 
-void GlfwApp::onClose() {}
+void GlfwApp::onClose()
+{
+}
 
 bool GlfwApp::onKey(int key, int scancode, int action, int mods)
 {
@@ -185,7 +192,7 @@ bool GlfwApp::onMousePosition(double x, double y)
     return false;
 }
 
-bool GlfwApp::onMouseButton(double x, double y, int button, int action, int mods)
+bool GlfwApp::onMouseButton(double x, double y, int button, int action, int mods, int clickCount)
 {
     if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE)
         mMouseLeft = false;
@@ -200,6 +207,9 @@ bool GlfwApp::onMouseButton(double x, double y, int button, int action, int mods
     if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
         mMouseRight = true;
 
+    if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_PRESS && clickCount > 1)
+        onResetView(); // reset view
+
     return false;
 }
 
@@ -250,9 +260,28 @@ bool GlfwApp::onFileDrop(const std::vector<std::string> &files)
 
 void GlfwApp::onResetView()
 {
+    mCamera->setPosition(-mCamera->getForwardDirection() * mCamera->getLookAtDistance());
     mCamera->setTarget({0, 0, 0}, {0, 1, 0});
 }
 
+void GlfwApp::internalOnMouseButton(double x, double y, int button, int action, int mods)
+{
+    // check double click
+    if (distance(mClickPos, glm::vec2(x, y)) > 5) // too far
+        mClickCount = 0;
+    if (mClickTimer.getTimeDiffInSecondsD() > mDoubleClickTime) // too slow
+        mClickCount = 0;
+    if (mClickButton != button) // wrong button
+        mClickCount = 0;
+
+    mClickTimer.restart();
+    mClickButton = button;
+    mClickPos = {x, y};
+    mClickCount++;
+
+    onMouseButton(x, y, button, action, mods, mClickCount);
+}
+
 static std::string thousandSep(size_t val)
 {
     auto s = std::to_string(val);
@@ -314,46 +343,58 @@ int GlfwApp::run(int argc, char *argv[])
 
     // input callbacks
     {
-        glfwSetKeyCallback(mWindow, [](GLFWwindow *win, int key, int scancode, int action, int mods) {
-            currApp->onKey(key, scancode, action, mods);
-        });
-        glfwSetCharModsCallback(
-            mWindow, [](GLFWwindow *win, unsigned int codepoint, int mods) { currApp->onChar(codepoint, mods); });
-        glfwSetMouseButtonCallback(mWindow, [](GLFWwindow *win, int button, int action, int mods) {
-            currApp->onMouseButton(currApp->mMouseX, currApp->mMouseY, button, action, mods);
-        });
-        glfwSetCursorEnterCallback(mWindow, [](GLFWwindow *win, int entered) {
-            if (entered)
-                currApp->onMouseEnter();
-            else
-                currApp->onMouseExit();
-        });
-
-        glfwSetCursorPosCallback(mWindow, [](GLFWwindow *win, double x, double y) {
-            currApp->mMouseX = x;
-            currApp->mMouseY = y;
-            currApp->onMousePosition(x, y);
-        });
-        glfwSetScrollCallback(mWindow, [](GLFWwindow *win, double sx, double sy) { currApp->onMouseScroll(sx, sy); });
-        glfwSetFramebufferSizeCallback(mWindow, [](GLFWwindow *win, int w, int h) {
-            currApp->mWindowWidth = w;
-            currApp->mWindowHeight = h;
-
-            currApp->onResize(w, h);
-            TwWindowSize(w, h);
-        });
-        glfwSetWindowFocusCallback(mWindow, [](GLFWwindow *win, int focused) {
-            if (focused)
-                currApp->onFocusGain();
-            else
-                currApp->onFocusLost();
-        });
-        glfwSetDropCallback(mWindow, [](GLFWwindow *win, int count, const char **paths) {
-            std::vector<std::string> files;
-            for (auto i = 0; i < count; ++i)
-                files.push_back(paths[i]);
-            currApp->onFileDrop(files);
-        });
+        glfwSetKeyCallback(mWindow, [](GLFWwindow *win, int key, int scancode, int action, int mods)
+                           {
+                               currApp->onKey(key, scancode, action, mods);
+                           });
+        glfwSetCharModsCallback(mWindow, [](GLFWwindow *win, unsigned int codepoint, int mods)
+                                {
+                                    currApp->onChar(codepoint, mods);
+                                });
+        glfwSetMouseButtonCallback(mWindow, [](GLFWwindow *win, int button, int action, int mods)
+                                   {
+                                       currApp->internalOnMouseButton(currApp->mMouseX, currApp->mMouseY, button, action, mods);
+                                   });
+        glfwSetCursorEnterCallback(mWindow, [](GLFWwindow *win, int entered)
+                                   {
+                                       if (entered)
+                                           currApp->onMouseEnter();
+                                       else
+                                           currApp->onMouseExit();
+                                   });
+
+        glfwSetCursorPosCallback(mWindow, [](GLFWwindow *win, double x, double y)
+                                 {
+                                     currApp->mMouseX = x;
+                                     currApp->mMouseY = y;
+                                     currApp->onMousePosition(x, y);
+                                 });
+        glfwSetScrollCallback(mWindow, [](GLFWwindow *win, double sx, double sy)
+                              {
+                                  currApp->onMouseScroll(sx, sy);
+                              });
+        glfwSetFramebufferSizeCallback(mWindow, [](GLFWwindow *win, int w, int h)
+                                       {
+                                           currApp->mWindowWidth = w;
+                                           currApp->mWindowHeight = h;
+
+                                           currApp->onResize(w, h);
+                                           TwWindowSize(w, h);
+                                       });
+        glfwSetWindowFocusCallback(mWindow, [](GLFWwindow *win, int focused)
+                                   {
+                                       if (focused)
+                                           currApp->onFocusGain();
+                                       else
+                                           currApp->onFocusLost();
+                                   });
+        glfwSetDropCallback(mWindow, [](GLFWwindow *win, int count, const char **paths)
+                            {
+                                std::vector<std::string> files;
+                                for (auto i = 0; i < count; ++i)
+                                    files.push_back(paths[i]);
+                                currApp->onFileDrop(files);
+                            });
     }
 
     // init app
diff --git a/glfw/glow-extras/glfw/GlfwApp.hh b/glfw/glow-extras/glfw/GlfwApp.hh
index c63aa25..b6c1bdd 100644
--- a/glfw/glow-extras/glfw/GlfwApp.hh
+++ b/glfw/glow-extras/glfw/GlfwApp.hh
@@ -8,6 +8,8 @@
 #include <glow/common/shared.hh>
 #include <glow/fwd.hh>
 
+#include <glow-extras/timing/PerformanceTimer.hh>
+
 struct GLFWwindow;
 struct CTwBar;
 typedef struct CTwBar TwBar; // structure CTwBar is not exposed.
@@ -100,6 +102,12 @@ private:
 
     double mCurrentTime = 0.0; ///< current frame time (starts with 0)
 
+    double mDoubleClickTime = 0.35f; ///< max number of seconds for multi clicks
+    int mClickCount = 0;             ///< current click count
+    int mClickButton = -1;           ///< last clicked button
+    glm::vec2 mClickPos;             ///< last clicked position
+    timing::SystemTimer mClickTimer; ///< click timing
+
     // Default graphics
 private:
     camera::SharedGenericCamera mCamera;         ///< default camera
@@ -136,6 +144,7 @@ public:
     GLOW_PROPERTY(OutputStatsInterval);
     GLOW_PROPERTY(QueryStats);
     GLOW_PROPERTY(UseDefaultRendering);
+    GLOW_PROPERTY(DoubleClickTime);
     float getCurrentTime() const { return mCurrentTime; }
     double getCurrentTimeD() const { return mCurrentTime; }
     GLOW_GETTER(Camera);
@@ -151,7 +160,6 @@ public:
     glm::vec2 getMousePosition() const { return {mMouseX, mMouseY}; }
     GLFWwindow* window() const { return mWindow; }
     TwBar* tweakbar() const { return mTweakbar; }
-
 public:
     /// sets the current clipboard content
     void setClipboardString(std::string const& s) const;
@@ -178,8 +186,8 @@ protected:
     virtual bool onChar(unsigned int codepoint, int mods);
     /// Called whenever the mouse position changes
     virtual bool onMousePosition(double x, double y);
-    /// Called whenever a mouse button is pressed
-    virtual bool onMouseButton(double x, double y, int button, int action, int mods);
+    /// Called whenever a mouse button is pressed (clickCount is 1 for single clicks, 2 for double, 3+ for multi)
+    virtual bool onMouseButton(double x, double y, int button, int action, int mods, int clickCount);
     /// Called whenever the mouse is scrolled
     virtual bool onMouseScroll(double sx, double sy);
     /// Called whenever the mouse enters the window
@@ -196,6 +204,9 @@ protected:
     /// Called when view should be reset
     virtual void onResetView();
 
+private:
+    void internalOnMouseButton(double x, double y, int button, int action, int mods);
+
 public:
     /// Initializes GLFW and GLOW, and runs until window is closed
     int run(int argc, char* argv[]);
-- 
GitLab