diff mde/gui/widget/Window.d @ 38:8c4c96f04e7f

Windows can now be resized! Windows have both a resize border and a move border with independant size for each side. Windows resizing support. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Mon, 05 May 2008 17:02:21 +0100
parents 052df9b2fe07
children 5132301e9ed7
line wrap: on
line diff
--- a/mde/gui/widget/Window.d	Mon May 05 14:47:25 2008 +0100
+++ b/mde/gui/widget/Window.d	Mon May 05 17:02:21 2008 +0100
@@ -68,13 +68,17 @@
         widget = makeWidget (0, this);  // primary widget always has ID 0.
         widgetData = null;  // data is no longer needed: allow GC to collect (cannot safely delete)
         
+        // Get border sizes
+        border = rend.getBorder (BORDER_TYPES.WINDOW_TOTAL);
+        resize = rend.getBorder (BORDER_TYPES.WINDOW_RESIZE);
+        
         widget.setSize (0,0);           // set the minimal size
         widget.getCurrentSize (w,h);    // and get this size
-        w += rend.windowBorder * 2;     // Adjust for border
-        h += rend.windowBorder * 2;
+        w += border.l + border.r;       // Adjust for border
+        h += border.t + border.b;
         
-        widgetX = x + rend.windowBorder;    // widget position
-        widgetY = y + rend.windowBorder;    // must be updated if the window is moved
+        widgetX = x + border.l;         // widget position
+        widgetY = y + border.t;         // must be updated if the window is moved
         widget.setPosition (widgetX, widgetY);
         
         xw = x+w;
@@ -125,9 +129,6 @@
         return gui_;
     }
     
-    /+void requestRedraw () {
-    }+/
-    
     IRenderer renderer () {
         return rend;
     }
@@ -141,9 +142,14 @@
         return widget.isHSizable;
     }
     
-    void getMinimalSize (out int mw, out int mh) {
-        mw = w + rend.windowBorder * 2;
-        mh = h + rend.windowBorder * 2;
+    void getMinimalSize (out int wM, out int hM) {
+        if (mh < 0) {       // calculate if necessary
+            widget.getMinimalSize (mw, mh);
+            mw += border.l + border.r;
+            mh += border.t + border.b;
+        }
+        wM = mw;
+        hM = mh;
     }
     void getCurrentSize (out int cw, out int ch) {
         cw = w;
@@ -151,13 +157,16 @@
     }
     
     void setSize (int nw, int nh) {
-        w = nw;
-        h = nh;
+        getMinimalSize (w,h);
+        if (nw > w) w = nw;     // expand if new size is larger, but don't go smaller
+        if (nh > h) h = nh;
         
         xw = x+w;
         yh = y+h;
         
-        widget.setSize (w - rend.windowBorder * 2, h - rend.windowBorder * 2);
+        widget.setSize (w - border.l - border.r, h - border.t - border.b);
+        
+        gui_.requestRedraw ();  // obviously necessary whenever the window's size is changed
     }
     
     void setPosition (int nx, int ny) {
@@ -167,8 +176,8 @@
         xw = x+w;
         yh = y+h;
         
-        widgetX = x + rend.windowBorder;
-        widgetY = y + rend.windowBorder;
+        widgetX = x + border.l;
+        widgetY = y + border.t;
         
         widget.setPosition (widgetX, widgetY);
         
@@ -178,7 +187,7 @@
     IWidget getWidget (int cx, int cy) {
         if (cx < x || cx >= xw || cy < y || cy >= yh)   // not over window
             return null;
-        if (cx >= widgetX && cx < xw-rend.windowBorder && cy >= widgetY && cy < yh-rend.windowBorder)
+        if (cx >= widgetX && cx < xw-border.r && cy >= widgetY && cy < yh-border.b)
                                                         // over the widget
             return widget.getWidget (cx, cy);
         else                                            // over the window border
@@ -186,11 +195,37 @@
     }
     void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {
         if (b == 1 && state == true) {
-            xDrag = cx;
-            yDrag = cy;
-            
-            gui_.addClickCallback (&dragEndCallback);   // handle repositioning
-            gui_.addMotionCallback (&dragCallback);     // handle repositioning
+            if (cx < x + resize.l || cx >= xw - resize.r ||
+                cy < y + resize.t || cy >= yh - resize.b) { // window is being resized
+                /* check for resizes (different to above; use whole border giving larger area for
+                 * diagonal resizes). */
+                resizeType = RESIZE.NONE;
+                if (cx < x + border.l) {
+                    xDrag = w + cx;
+                    resizeType = RESIZE.L;
+                }
+                else if (cx >= xw - border.r) {
+                    xDrag = w - cx;
+                    resizeType = RESIZE.R;
+                }
+                if (cy < y + border.t) {
+                    yDrag = h + cy;
+                    resizeType |= RESIZE.T;
+                }
+                else if (cy >= yh - border.b) {
+                    yDrag = h - cy;
+                    resizeType |= RESIZE.B;
+                }
+                
+                gui_.addClickCallback (&endCallback);
+                gui_.addMotionCallback (&resizeCallback);
+            } else {                // window is being moved
+                xDrag = cx - x;
+                yDrag = cy - y;
+                
+                gui_.addClickCallback (&endCallback);
+                gui_.addMotionCallback (&moveCallback);
+            }
         }
     }
     
@@ -204,19 +239,50 @@
     //END IWidget methods
     
 private:
-    /* For window dragging. */
-    void dragCallback (ushort cx, ushort cy) {
-        setPosition (x+cx-xDrag, y+cy-yDrag);
-        xDrag = cx;
-        yDrag = cy;
+    alias IRenderer.BorderDimensions    BorderDimensions;
+    alias IRenderer.BORDER_TYPES        BORDER_TYPES;
+    
+    //BEGIN Window moving and resizing
+    void moveCallback (ushort cx, ushort cy) {
+        setPosition (cx-xDrag, cy-yDrag);
     }
-    void dragEndCallback (ushort cx, ushort cy, ubyte b, bool state) {
+    void resizeCallback (ushort cx, ushort cy) {
+        if (resizeType & RESIZE.L) {
+            int mw, nw;
+            getMinimalSize (mw, nw);    // (only want mw)
+            nw = xDrag - cx;
+            if (nw < mw) nw = mw;       // clamp
+            setPosition (x + w - nw, y);
+            setSize (nw, h);
+        }
+        else if (resizeType & RESIZE.R) {
+            setSize (xDrag + cx, h);
+        }
+        if (resizeType & RESIZE.T) {
+            int mh, nh;
+            getMinimalSize (nh, mh);    // (only want mh)
+            nh = yDrag - cy;
+            if (nh < mh) nh = mh;       // clamp
+            setPosition (x, y + h - nh);
+            setSize (w, nh);
+        }
+        else if (resizeType & RESIZE.B) {
+            setSize (w, yDrag + cy);
+        }
+    }
+    void endCallback (ushort cx, ushort cy, ubyte b, bool state) {
         if (b == 1 && state == false) {
-            setPosition (x+cx-xDrag, y+cy-yDrag);
+            // The mouse shouldn't have moved since the motion callback
+            // was last called, so there's nothing else to do now.
             gui_.removeCallbacks (cast(void*) this);
         }
     }
-    int xDrag, yDrag;               // locations where a drag starts (used by dragCallback).
+    int xDrag, yDrag;               // where a drag starts relative to x and y
+    enum RESIZE : ubyte {
+        NONE = 0x0, L = 0x1, R = 0x2, T = 0x4, B = 0x8
+    }
+    RESIZE resizeType;              // Type of current resize
+    //END Window moving and resizing
     
     char[] name;                    // The window's name (id from config file)
     IGui gui_;                      // The gui managing this window
@@ -231,4 +297,8 @@
     int w,h;                        // Window size (calculated from Widgets)
     int xw, yh;                     // x+w, y+h (frequent use by clickEvent)
     int widgetX, widgetY;           // Widget position (= window position plus BORDER_WIDTH)
+    int mw = -1, mh = -1;           // minimal size
+    
+    BorderDimensions border;        // Total border size (move plus resize)
+    BorderDimensions resize;        // The outer resize part of the border
 }