changeset 41:b3a6ca4516b4

The renderer now controls which parts of the window border allow resizing. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Tue, 13 May 2008 12:02:36 +0100
parents b28d7adc786b
children 8bf53e711cc7
files codeDoc/jobs.txt mde/gui/Gui.d mde/gui/IGui.d mde/gui/renderer/IRenderer.d mde/gui/renderer/SimpleRenderer.d mde/gui/widget/Ifaces.d mde/gui/widget/Widget.d mde/gui/widget/Window.d mde/gui/widget/layout.d mde/sdl.d
diffstat 10 files changed, 154 insertions(+), 105 deletions(-) [+]
line wrap: on
line diff
--- a/codeDoc/jobs.txt	Thu May 08 16:05:51 2008 +0100
+++ b/codeDoc/jobs.txt	Tue May 13 12:02:36 2008 +0100
@@ -3,7 +3,6 @@
 
 
 In progress:
-Make a widget with multiple sizable rows/cols.
 Implement row/col sizing.
 
 
@@ -50,3 +49,4 @@
 
 
 Done (for git log message):
+The renderer now controls which parts of the window border allow resizing.
--- a/mde/gui/Gui.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/Gui.d	Tue May 13 12:02:36 2008 +0100
@@ -24,7 +24,6 @@
 import mde.gui.IGui;
 import mde.gui.widget.Ifaces;
 import mde.gui.widget.Window;
-import mde.gui.renderer.createRenderer;
 import mde.gui.exception;
 
 // For adding the input event callbacks and requesting redraws:
@@ -84,7 +83,6 @@
             return;
         }
         rendName = *p;
-        rend = createRenderer (rendName);
         
         // get list
         windows.length = reader.dataset.sec.length; // pre-allocate
@@ -149,7 +147,7 @@
     void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {
         // NOTE: buttons receive the up-event even when drag-callbacks are in place.
         foreach (dg; clickCallbacks)
-            dg (cx, cy, b, state);
+            if (dg (cx, cy, b, state)) return;      // See IGui.addClickCallback's documentation
         
         foreach (i,w; windows) {
             IWidget widg = w.getWidget (cx,cy);
@@ -174,18 +172,15 @@
     //END Methods for external use
     
     //BEGIN IGui methods
-    IRenderer renderer ()
-    in {
-        assert (rend !is null, "Gui: rend is null");
-    } body {
-        return rend;
+    char[] rendererName () {
+        return rendName;
     }
     
     void requestRedraw () {
         imde.mainSchedule.request(imde.SCHEDULE.DRAW);
     }
     
-    void addClickCallback (void delegate(ushort, ushort, ubyte, bool) dg) {
+    void addClickCallback (bool delegate(ushort, ushort, ubyte, bool) dg) {
         clickCallbacks[dg.ptr] = dg;
     }
     void addMotionCallback (void delegate(ushort, ushort) dg) {
@@ -200,10 +195,9 @@
 private:
     Window[] windows;   // Windows. First window is "on top", others may be obscured.
     
-    IRenderer rend;     // Renderer (synonymous with theme)
-    char[] rendName;    // Name of renderer; for saving
+    char[] rendName;    // Name of renderer; for saving and creating renderers
     
     // callbacks indexed by their frame pointers:
-    void delegate(ushort cx, ushort cy, ubyte b, bool state) [void*] clickCallbacks;
+    bool delegate(ushort cx, ushort cy, ubyte b, bool state) [void*] clickCallbacks;
     void delegate(ushort cx, ushort cy) [void*] motionCallbacks;
 }
--- a/mde/gui/IGui.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/IGui.d	Tue May 13 12:02:36 2008 +0100
@@ -15,16 +15,14 @@
 
 module mde.gui.IGui;
 
-public import mde.gui.renderer.IRenderer;
-
 /** The Gui interface.
 *
 * This contains the functions for use by Windows, not those for external use (use Gui directly for
 * that). */
 interface IGui
 {
-    /** Get the Gui's renderer. May be overriden by the window. */
-    IRenderer renderer ();
+    /**  Get the GUI's rendererName for creating a renderer (may be overridden by the window). */
+    char[] rendererName ();
     
     /** Called by a sub-widget when a redraw is necessary (since drawing may sometimes be done on
     * event.
@@ -32,8 +30,13 @@
     * Currently forces the whole Gui to be redrawn. */
     void requestRedraw ();
     
-    /** Add a mouse click callback: delegate will be called for all mouse click events recieved. */
-    void addClickCallback (void delegate (ushort cx, ushort cy, ubyte b, bool state) dg);
+    /** Add a mouse click callback: delegate will be called for all mouse click events recieved.
+     *
+     * The delegate should return true if it accepts the event and no further processing is
+     * required (i.e. the event should not be handled by anything else), false otherwise.
+     * Note that this is not a mechanism to prevent unwanted event handling, and in the future may
+     * be removed (so event handling cannot be cut short). */
+    void addClickCallback (bool delegate (ushort cx, ushort cy, ubyte b, bool state) dg);
     /** Add a mouse motion callback: delegate will be called for all motion events recieved. */
     void addMotionCallback (void delegate (ushort cx, ushort cy) dg);
     /** Remove all event callbacks with _frame pointer frame. */
--- a/mde/gui/renderer/IRenderer.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/renderer/IRenderer.d	Tue May 13 12:02:36 2008 +0100
@@ -39,17 +39,29 @@
         }
     }
     
-    /// An enum for border types
-    enum BORDER_TYPES {
-        WINDOW_TOTAL,
-        WINDOW_RESIZE,
+    /** Use to set and reset these parameters, and to get the border size (which may depend on
+     * them). */
+    BorderDimensions setSizable (bool wSizable, bool hSizable);
+    
+    /// Which edges of a window are being resized
+    enum RESIZE_TYPE : ubyte {
+        NONE = 0x0, L = 0x1, R = 0x2, T = 0x4, B = 0x8
     }
     
-    /** Return the renderer's window border width.
-     *
-     * Type should be an element of BORDER_TYPES; if not the method may throw or simply return
-     * without an error. */
-    BorderDimensions getBorder (BORDER_TYPES type);
+    /** Used to tell if a click on a window's border is for resizing or moving.
+    *
+    * Depends on setSizable's parameters.
+    *
+    * Params:
+    *   cx =
+    *   cy = click coordinates relative to window border
+    *   w  =
+    *   h  = window size
+    *
+    * Returns:
+    *   RESIZE_TYPE = NONE for a move, an or'd combination of L/R/T/B for resizing.
+    */
+    RESIZE_TYPE getResizeType (int cx, int cy, int w, int h);
     
     /** Return the renderer's between-widget spacing (for layout widgets). */
     int layoutSpacing ();
--- a/mde/gui/renderer/SimpleRenderer.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/renderer/SimpleRenderer.d	Tue May 13 12:02:36 2008 +0100
@@ -29,17 +29,50 @@
 * The renderer is intended to be per-GUI. */
 class SimpleRenderer : IRenderer
 {
-    BorderDimensions getBorder (BORDER_TYPES type) {
-        BorderDimensions dims;
-        with (BORDER_TYPES) with (dims) {
-            if (type == WINDOW_TOTAL) {
-                l = t = r = b = 20;
-            } else if (type == WINDOW_RESIZE) {
-                r = t = 5;
-                l = b = 20;
+    BorderDimensions setSizable (bool wS, bool hS) {
+        wSizable = wS;
+        hSizable = hS;
+        
+        // Set the border size based on the above
+        with (border) {
+            l = r = t = b = 14;
+        }
+        with (resize) {
+            if (wSizable)
+                l = r = 6;
+            else
+                l = r = 0;
+            if (hSizable) {
+                t = 2;
+                b = 6;
+            } else
+                t = b = 0;
+        }
+        border += resize;
+        return border;
+    }
+    
+    RESIZE_TYPE getResizeType (int cx, int cy, int w, int h) {
+        RESIZE_TYPE resizeType = RESIZE_TYPE.NONE;
+        if (cx < resize.l || cx >= w - resize.r ||
+            cy < resize.t || cy >= h - resize.b) { // window is being resized
+                /* check for resizes (different to above; use whole border giving larger area for
+                * diagonal resizes). */
+            
+            if (wSizable) {
+                if (cx < border.l)
+                    resizeType = RESIZE_TYPE.L;
+                else if (cx >= w - border.r)
+                    resizeType = RESIZE_TYPE.R;
+            }
+            if (hSizable) {
+                if (cy < border.t)
+                    resizeType |= RESIZE_TYPE.T;
+                else if (cy >= h - border.b)
+                    resizeType |= RESIZE_TYPE.B;
             }
         }
-        return dims;
+        return resizeType;
     }
     
     int layoutSpacing () {
@@ -52,10 +85,10 @@
         gl.drawBox (x,y, w,h);
         
         gl.setColor (0f, 0f, 1f);
-        gl.drawBox (x+20,y+5, w-25,h-25);
+        gl.drawBox (x+resize.l, y+resize.t, w-resize.l-resize.r, h-resize.t-resize.b);
         
         gl.setColor (.3f, .3f, .3f);
-        gl.drawBox (x+20, y+20, w-40, h-40);
+        gl.drawBox (x+border.l, y+border.t, w-border.l-border.r, h-border.t-border.b);
     }
 
     void drawWidgetBack (int x, int y, int w, int h) {}
@@ -67,4 +100,9 @@
             gl.setColor (.6f, 0f, .6f);
         gl.drawBox (x,y, w,h);
     }
+    
+protected:
+    bool wSizable, hSizable;
+    BorderDimensions border;
+    BorderDimensions resize;
 }
--- a/mde/gui/widget/Ifaces.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/widget/Ifaces.d	Tue May 13 12:02:36 2008 +0100
@@ -38,10 +38,13 @@
     /** Add widget's saveData to the data to be saved, returning it's widgetID. */
     widgetID addCreationData (IWidget widget);
     
-    /** Get the managing Gui. */
-    //FIXME: remove and add requestRedraw to allow for only redrawing the window
+    /** Returns the window's gui. */
+    //NOTE: was going to remove this, but it's used more than I thought
     IGui gui ();
     
+    /** The widget/window needs redrawing. */
+    void requestRedraw ();
+    
     /** Get the window's renderer.
     *
     * Normally specific to the GUI, but widgets have no direct contact with the GUI and this
--- a/mde/gui/widget/Widget.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/widget/Widget.d	Tue May 13 12:02:36 2008 +0100
@@ -17,8 +17,8 @@
 module mde.gui.widget.Widget;
 
 public import mde.gui.widget.Ifaces;
-import mde.gui.IGui;
 import mde.gui.exception;
+import mde.gui.renderer.IRenderer;
 
 import tango.io.Stdout;
 
@@ -168,26 +168,29 @@
     void clickEvent (ushort, ushort, ubyte b, bool state) {
         if (b == 1 && state == true) {
             pushed = true;
-            window.gui.requestRedraw;
+            window.requestRedraw;
             window.gui.addClickCallback (&clickWhileHeld);
             window.gui.addMotionCallback (&motionWhileHeld);
         }
     }
     // Called when a mouse motion/click event occurs while (held == true)
-    void clickWhileHeld (ushort cx, ushort cy, ubyte b, bool state) {
+    bool clickWhileHeld (ushort cx, ushort cy, ubyte b, bool state) {
+        //NOTE: which button? test
         if (cx >= x && cx < x+w && cy >= y && cy < y+h) // button event
             Stdout ("Button clicked!").newline;
         
         pushed = false;
-        window.gui.requestRedraw;
+        window.requestRedraw;
         window.gui.removeCallbacks (cast(void*) this);
+        
+        return false;
     }
     void motionWhileHeld (ushort cx, ushort cy) {
         bool oldPushed = pushed;
         if (cx >= x && cx < x+w && cy >= y && cy < y+h) pushed = true;
         else pushed = false;
         if (oldPushed != pushed)
-            window.gui.requestRedraw;
+            window.requestRedraw;
     }
 }
 //END Widgets
--- a/mde/gui/widget/Window.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/widget/Window.d	Tue May 13 12:02:36 2008 +0100
@@ -22,6 +22,7 @@
 
 import mde.gui.IGui;
 import mde.gui.exception;
+import mde.gui.renderer.createRenderer;
 
 import mt = mde.mergetag.DataSet;
 import tango.scrapple.text.convert.parseTo : parseTo;
@@ -61,19 +62,20 @@
         if (widgetData is null)
             throw new WindowLoadException ("No widget creation data");
         
+        // Save gui and create the renderer:
         gui_ = gui;
-        rend = gui.renderer;
-        
-        // Get border sizes
-        border = rend.getBorder (BORDER_TYPES.WINDOW_TOTAL);
-        resize = rend.getBorder (BORDER_TYPES.WINDOW_RESIZE);
+        rend = createRenderer (gui.rendererName);
         
         // Create the primary widget (and indirectly all sub-widgets), throwing on error:
-        widget = makeWidget (0);    // primary widget always has ID 0.
+        // Note: GridLayoutWidget's this relies on rend.layoutSpacing.
+        widget = makeWidget (0);        // primary widget always has ID 0.
         widgetData = null;  // data is no longer needed: allow GC to collect (cannot safely delete)
         
-        // Note: this should return an empty array, but nothing much should happen if it's not empty:
-        widget.adjust (mutableData);    // adjust/set size, etc.
+        // get border sizes:
+        border = rend.setSizable (isWSizable, isHSizable);  // depends on widget
+        
+        // Note: this should return an empty array, but we shouldn't make a fuss if it's not empty:
+        widget.adjust (mutableData);    // adjust/set size, etc., depends on rend
         mutableData = null;             // no longer needed
         
         widget.getCurrentSize (w,h);    // and get this size
@@ -167,12 +169,19 @@
         
         return i;
     }
-
+    
     IGui gui () {
         return gui_;
     }
     
-    IRenderer renderer () {
+    void requestRedraw () {
+        gui_.requestRedraw;
+    }
+    
+    IRenderer renderer ()
+    in {
+        assert (rend !is null, "Window.renderer: rend is null");
+    } body {
         return rend;
     }
     //END IWindow methods
@@ -249,38 +258,24 @@
     }
     void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {
         if (b == 1 && state == true) {
-            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;
+            resizeType = rend.getResizeType (cx-x, cy-y, w,h);
+            
+            if (resizeType != RESIZE_TYPE.NONE) {    // Some type of resize
+                // Set x/yDrag (unfortunately these need to be different for each edge)
+                if (resizeType & RESIZE_TYPE.L)
+                    xDrag = w + cx;
+                else if (resizeType & RESIZE_TYPE.R)
+                    xDrag = w - cx;
                 
-                if (isWSizable) {
-                    if (cx < x + border.l) {
-                        xDrag = w + cx;
-                        resizeType = RESIZE.L;
-                    }
-                    else if (cx >= xw - border.r) {
-                        xDrag = w - cx;
-                        resizeType = RESIZE.R;
-                    }
-                }
-                if (isHSizable) {
-                    if (cy < y + border.t) {
-                        yDrag = h + cy;
-                        resizeType |= RESIZE.T;
-                    }
-                    else if (cy >= yh - border.b) {
-                        yDrag = h - cy;
-                        resizeType |= RESIZE.B;
-                    }
-                }
+                if (resizeType & RESIZE_TYPE.T)
+                    yDrag = h + cy;
+                else if (resizeType & RESIZE_TYPE.B)
+                    yDrag = h - cy;
                 
-                if (resizeType != RESIZE.NONE) {    // only if some valid size is being done
-                    gui_.addClickCallback (&endCallback);
-                    gui_.addMotionCallback (&resizeCallback);
-                }
-            } else {                // window is being moved
+                // Add the callbacks (they use resizeType which has already been set)
+                gui_.addClickCallback (&endCallback);
+                gui_.addMotionCallback (&resizeCallback);
+            } else {                             // window is being moved
                 xDrag = cx - x;
                 yDrag = cy - y;
                 
@@ -300,15 +295,15 @@
     //END IWidget methods
     
 private:
-    alias IRenderer.BorderDimensions    BorderDimensions;
-    alias IRenderer.BORDER_TYPES        BORDER_TYPES;
+    alias IRenderer.BorderDimensions BorderDimensions;
+    alias IRenderer.RESIZE_TYPE RESIZE_TYPE;
     
     //BEGIN Window moving and resizing
     void moveCallback (ushort cx, ushort cy) {
         setPosition (cx-xDrag, cy-yDrag);
     }
     void resizeCallback (ushort cx, ushort cy) {
-        if (resizeType & RESIZE.L) {
+        if (resizeType & RESIZE_TYPE.L) {
             int mw, nw;
             getMinimalSize (mw, nw);    // (only want mw)
             nw = xDrag - cx;
@@ -317,11 +312,11 @@
             setSize (nw, h);
             setPosition (mw, y);
         }
-        else if (resizeType & RESIZE.R) {
+        else if (resizeType & RESIZE_TYPE.R) {
             setSize (xDrag + cx, h);
-            setPosition (x, y);
+            setPosition (x, y);         // required to call after setSize.
         }
-        if (resizeType & RESIZE.T) {
+        if (resizeType & RESIZE_TYPE.T) {
             int mh, nh;
             getMinimalSize (nh, mh);
             nh = yDrag - cy;
@@ -330,28 +325,29 @@
             setSize (w, nh);
             setPosition (x, mh);
         }
-        else if (resizeType & RESIZE.B) {
+        else if (resizeType & RESIZE_TYPE.B) {
             setSize (w, yDrag + cy);
             setPosition (x, y);
         }
     }
-    void endCallback (ushort cx, ushort cy, ubyte b, bool state) {
+    bool endCallback (ushort cx, ushort cy, ubyte b, bool state) {
         if (b == 1 && state == false) {
             // 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);
+            
+            return true;    // we've handled the up-click
         }
+        return false;       // we haven't handled it
     }
     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
+    IRenderer.RESIZE_TYPE resizeType;   // Type of current resize
     //END Window moving and resizing
     
     // Load/save data:
     public char[] name;             // The window's name (id from config file)
     //bool edited = false;            // True if any widgets have been edited (excluding scaling)
+    
     // Data used for saving and loading (null in between):
     int[][widgetID] widgetData = null;// Data for all widgets under this window
     int[] mutableData = null;       // Widget's mutable data (adjusted sizes, etc.)
@@ -365,8 +361,7 @@
     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
+    int mw = -1, mh = -1;           // minimal size (negative means requires calculation)
     
     BorderDimensions border;        // Total border size (move plus resize)
-    BorderDimensions resize;        // The outer resize part of the border
 }
--- a/mde/gui/widget/layout.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/gui/widget/layout.d	Tue May 13 12:02:36 2008 +0100
@@ -45,7 +45,7 @@
         
         // Get all sub-widgets
         subWidgets.length = rows*cols;
-        foreach (i, inout subWidget; subWidgets) {
+        foreach (i, ref subWidget; subWidgets) {
             subWidget = window.makeWidget (data[i+3]);
         }
         
@@ -74,9 +74,9 @@
             
             // Check row sizes are valid:
             //NOTE: this could be made optional
-            foreach (i, inout w; colW)
+            foreach (i, ref w; colW)
                 if (w < colWMin[i]) w = colWMin[i];
-            foreach (i, inout h; rowH)
+            foreach (i, ref h; rowH)
                 if (h < rowHMin[i]) h = rowHMin[i];
         }
         
@@ -199,7 +199,7 @@
         
         
         // Calculate the overall minimal size, starting with the spacing:
-        mh = window.renderer.layoutSpacing;     // use temporarily
+        mh = window.renderer.layoutSpacing;     // use mh temporarily
         mw = mh * (cols - 1);
         mh *= (rows - 1);
         
--- a/mde/sdl.d	Thu May 08 16:05:51 2008 +0100
+++ b/mde/sdl.d	Tue May 13 12:02:36 2008 +0100
@@ -53,7 +53,7 @@
     // Must be called after SDL has been initialised, so cannot be a separate Init function.
     openJoysticks ();                   // after SDL init
     cleanup.addFunc (&cleanupSDL, "cleanupSDL");
-
+    
     setupWindow();
 }
 
@@ -83,6 +83,7 @@
     SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
     
     // Open a window
+    debug logger.trace ("Opening a window (this can crash if the libraries are messed up)");
     if (SDL_SetVideoMode (w, h, 32, flags) is null) {
         logger.fatal ("Unable to set video mode:");
         char* msg = SDL_GetError ();