From 391712b9805eda9d56a100f49d69b38863910565 Mon Sep 17 00:00:00 2001
From: Michael Abbott <michael@araneidae.co.uk>
Date: Sat, 29 Sep 2012 08:10:48 +0100
Subject: Add support for nearest corner or edge resizing

---
 doc/asciidoc/fluxbox-keys.txt | 12 ++++++--
 src/CurrentWindowCmd.cc       | 41 ++++++++++++++++++++++-----
 src/CurrentWindowCmd.hh       |  5 +++-
 src/Window.cc                 | 66 ++++++++++++++++++++++++++++++-------------
 src/Window.hh                 |  5 ++--
 5 files changed, 96 insertions(+), 33 deletions(-)

diff --git a/doc/asciidoc/fluxbox-keys.txt b/doc/asciidoc/fluxbox-keys.txt
index 0d0b52e..96b1141 100644
--- a/doc/asciidoc/fluxbox-keys.txt
+++ b/doc/asciidoc/fluxbox-keys.txt
@@ -178,8 +178,16 @@ Start dragging to resize the window as if you had grabbed the window
 at the specified 'corner'.
 +
 By default 'corner' is *BottomRight*, but may be overridden with one of:;;
-*NearestCorner NearestEdge Center TopLeft Top TopRight Left Right BottomLeft
-Bottom BottomRight*
+*NearestCorner NearestEdge NearestCornerOrEdge Center TopLeft Top TopRight
+Left Right BottomLeft Bottom BottomRight*
+
++
+If *NearestCornerOrEdge* is specified the size of the corner can also be
+specified to be the larger of one or two following numbers: ['pixel-size'
+['percent-size']] or 'percent-size'%, where 'percent-size' is the
+percentage of half the window width or height.  If no size is given, it
+defaults to 50 pixels and 30%.
+
 
 *StartTabbing*::
 	Start dragging to add this window to another's tabgroup.
diff --git a/src/CurrentWindowCmd.cc b/src/CurrentWindowCmd.cc
index 4363d0d..6138e64 100644
--- a/src/CurrentWindowCmd.cc
+++ b/src/CurrentWindowCmd.cc
@@ -20,6 +20,7 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 // DEALINGS IN THE SOFTWARE.
 
+#include <string.h>
 #include "CurrentWindowCmd.hh"
 
 #include "fluxbox.hh"
@@ -369,15 +370,13 @@ void StartMovingCmd::real_execute() {
 FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &args,
                                        bool trusted) {
     FluxboxWindow::ResizeModel mode = FluxboxWindow::DEFAULTRESIZE;
+    int corner_size_px = 0;
+    int corner_size_pc = 0;
     std::vector<string> tokens;
     FbTk::StringUtil::stringtok<std::vector<string> >(tokens, args);
     if (!tokens.empty()) {
         string arg = FbTk::StringUtil::toLower(tokens[0]);
-        if (arg == "nearestcorner")
-            mode = FluxboxWindow::QUADRANTRESIZE;
-        else if (arg == "nearestedge")
-            mode = FluxboxWindow::NEARESTEDGERESIZE;
-        else if (arg == "center")
+        if (arg == "center")
             mode = FluxboxWindow::CENTERRESIZE;
         else if (arg == "topleft")
             mode = FluxboxWindow::TOPLEFTRESIZE;
@@ -395,8 +394,35 @@ FbTk::Command<void> *StartResizingCmd::parse(const string &cmd, const string &ar
             mode = FluxboxWindow::BOTTOMRESIZE;
         else if (arg == "bottomright")
             mode = FluxboxWindow::BOTTOMRIGHTRESIZE;
+        else if (arg == "nearestcorner") {
+            mode = FluxboxWindow::EDGEORCORNERRESIZE;
+            corner_size_pc = 100;
+        } else if (arg == "nearestedge") {
+            mode = FluxboxWindow::EDGEORCORNERRESIZE;
+        } else if (arg == "nearestcorneroredge") {
+            mode = FluxboxWindow::EDGEORCORNERRESIZE;
+            /* The NearestCornerOrEdge can be followed by a corner size in
+             * one of three forms:
+             *      <size in pixels>
+             *      <size in pixels> <size in percent>
+             *      <size in percent>%
+             * If no corner size is given then it defaults to 50 pixels, 30%. */
+            if (tokens.size() > 1) {
+                const char * size1 = tokens[1].c_str();
+                if (size1[strlen(size1)-1] == '%')
+                    corner_size_pc = atoi(size1);
+                else {
+                    corner_size_px = atoi(size1);
+                    if (tokens.size() > 2)
+                        corner_size_pc = atoi(tokens[2].c_str());
+                }
+            } else {
+                corner_size_px = 50;
+                corner_size_pc = 30;
+            }
+        }
     }
-    return new StartResizingCmd(mode);
+    return new StartResizingCmd(mode, corner_size_px, corner_size_pc);
 }
 
 REGISTER_COMMAND_PARSER(startresizing, StartResizingCmd::parse, void);
@@ -422,7 +448,8 @@ void StartResizingCmd::real_execute() {
     x -= fbwindow().x() - fbwindow().frame().window().borderWidth();
     y -= fbwindow().y() - fbwindow().frame().window().borderWidth();
 
-    fbwindow().startResizing(x, y, fbwindow().getResizeDirection(x, y, m_mode));
+    fbwindow().startResizing(x, y, fbwindow().getResizeDirection(
+        x, y, m_mode, m_corner_size_px, m_corner_size_pc));
 }
 
 REGISTER_COMMAND(starttabbing, StartTabbingCmd, void);
diff --git a/src/CurrentWindowCmd.hh b/src/CurrentWindowCmd.hh
index f406796..95175f2 100644
--- a/src/CurrentWindowCmd.hh
+++ b/src/CurrentWindowCmd.hh
@@ -124,13 +124,16 @@ protected:
 // begin resizing with mouse
 class StartResizingCmd: public WindowHelperCmd {
 public:
-    explicit StartResizingCmd(FluxboxWindow::ResizeModel mode):m_mode(mode) { }
+    explicit StartResizingCmd(FluxboxWindow::ResizeModel mode, int corner_size_px, int corner_size_pc):
+        m_mode(mode), m_corner_size_px(corner_size_px), m_corner_size_pc(corner_size_pc) { }
     static FbTk::Command<void> *parse(const std::string &command,
                                 const std::string &args, bool trusted);
 protected:
     void real_execute();
 private:
     const FluxboxWindow::ResizeModel m_mode;
+    const int m_corner_size_px; // Corner size in pixels
+    const int m_corner_size_pc; // and in percent of half window width/height
 };
 
 // begin tabbing with mouse
diff --git a/src/Window.cc b/src/Window.cc
index 33a4c9e..0b8d1e5 100644
--- a/src/Window.cc
+++ b/src/Window.cc
@@ -251,6 +251,18 @@ private:
     int m_mode;
 };
 
+
+// Helper class for getResizeDirection below
+// Tests whether a point is on an edge or the corner.
+struct TestEdgeHelper {
+    int corner_size_px, corner_size_pc;
+    inline bool operator()(int xy, int wh)
+    {
+        /* The % checking must be right: 0% must fail, 100% must succeed. */
+        return xy < corner_size_px  ||  100 * xy < corner_size_pc * wh;
+    }
+};
+
 }
 
 
@@ -3004,30 +3016,44 @@ void FluxboxWindow::doSnapping(int &orig_left, int &orig_top) {
 
 }
 
+
 FluxboxWindow::ReferenceCorner FluxboxWindow::getResizeDirection(int x, int y,
-        ResizeModel model) const {
+        ResizeModel model, int corner_size_px, int corner_size_pc) const
+{
+    if (model == TOPLEFTRESIZE)     return LEFTTOP;
+    if (model == TOPRESIZE)         return TOP;
+    if (model == TOPRIGHTRESIZE)    return RIGHTTOP;
+    if (model == LEFTRESIZE)        return LEFT;
+    if (model == RIGHTRESIZE)       return RIGHT;
+    if (model == BOTTOMLEFTRESIZE)  return LEFTBOTTOM;
+    if (model == BOTTOMRESIZE)      return BOTTOM;
+    if (model == CENTERRESIZE)      return CENTER;
+
+    if (model == EDGEORCORNERRESIZE)
+    {
+        int w = frame().width();
+        int h = frame().height();
+        int cx = w / 2;
+        int cy = h / 2;
+        TestEdgeHelper test_edge = { corner_size_px, corner_size_pc };
+        if (x < cx  &&  test_edge(x, cx)) {
+            if (y < cy  &&  test_edge(y, cy))
+                return LEFTTOP;
+            else if (test_edge(h - y - 1, h - cy))
+                return LEFTBOTTOM;
+        } else if (test_edge(w - x - 1, w - cx)) {
+            if (y < cy  &&  test_edge(y, cy))
+                return RIGHTTOP;
+            else if (test_edge(h - y - 1, h - cy))
+                return RIGHTBOTTOM;
+        }
 
-    int cx = frame().width() / 2;
-    int cy = frame().height() / 2;
-    if (model == CENTERRESIZE)
-        return CENTER;
-    if (model == NEARESTEDGERESIZE) {
+        /* Nope, not a corner; find the nearest edge instead. */
         if (cy - abs(y - cy) < cx - abs(x - cx)) // y is nearest
             return (y > cy) ? BOTTOM : TOP;
-        return (x > cx) ? RIGHT : LEFT;
-    }
-    if (model == QUADRANTRESIZE) {
-        if (x < cx)
-            return (y < cy) ? LEFTTOP : LEFTBOTTOM;
-        return (y < cy) ? RIGHTTOP : RIGHTBOTTOM;
-    }
-    if (model == TOPLEFTRESIZE) return LEFTTOP;
-    if (model == TOPRESIZE) return TOP;
-    if (model == TOPRIGHTRESIZE) return RIGHTTOP;
-    if (model == LEFTRESIZE) return LEFT;
-    if (model == RIGHTRESIZE) return RIGHT;
-    if (model == BOTTOMLEFTRESIZE) return LEFTBOTTOM;
-    if (model == BOTTOMRESIZE) return BOTTOM;
+        else
+            return (x > cx) ? RIGHT : LEFT;
+    }
     return RIGHTBOTTOM;
 }
 
diff --git a/src/Window.hh b/src/Window.hh
index 09374af..b7975f5 100644
--- a/src/Window.hh
+++ b/src/Window.hh
@@ -89,9 +89,7 @@ public:
 
     /// Different resize modes when resizing a window
     enum ResizeModel {
-        QUADRANTRESIZE,                   ///< resizes from one quadrant
         CENTERRESIZE,                     ///< resizes from center
-        NEARESTEDGERESIZE,                ///< resizes the nearest edge
         TOPLEFTRESIZE,                    ///< resizes top left corner
         TOPRESIZE,                        ///< resizes top edge
         TOPRIGHTRESIZE,                   ///< resizes top right corner
@@ -100,6 +98,7 @@ public:
         BOTTOMLEFTRESIZE,                 ///< resizes bottom left corner
         BOTTOMRESIZE,                     ///< resizes bottom edge
         BOTTOMRIGHTRESIZE,                ///< resizes bottom right corner
+        EDGEORCORNERRESIZE,               ///< resizes nearest edge or corner
         DEFAULTRESIZE = BOTTOMRIGHTRESIZE ///< default resize mode
     };
 
@@ -341,7 +340,7 @@ public:
      */
     void startResizing(int x, int y, ReferenceCorner dir);
     /// determine which edge or corner to resize
-    ReferenceCorner getResizeDirection(int x, int y, ResizeModel model) const;
+    ReferenceCorner getResizeDirection(int x, int y, ResizeModel model, int corner_size_px, int corner_size_pc) const;
     /// stops the resizing
     void stopResizing(bool interrupted = false);
     /// starts tabbing
-- 
cgit v0.11.2