# HG changeset patch # User Diggory Hardy # Date 1210003341 -3600 # Node ID 8c4c96f04e7fd0e6683e3f99abca575197753ed6 # Parent 052df9b2fe07d439e1536f0f4b3ce870d1d7af0e 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 diff -r 052df9b2fe07 -r 8c4c96f04e7f data/conf/gui.mtt --- a/data/conf/gui.mtt Mon May 05 14:47:25 2008 +0100 +++ b/data/conf/gui.mtt Mon May 05 17:02:21 2008 +0100 @@ -7,4 +7,4 @@ {W2} - + diff -r 052df9b2fe07 -r 8c4c96f04e7f mde/gui/renderer/IRenderer.d --- a/mde/gui/renderer/IRenderer.d Mon May 05 14:47:25 2008 +0100 +++ b/mde/gui/renderer/IRenderer.d Mon May 05 17:02:21 2008 +0100 @@ -26,8 +26,30 @@ interface IRenderer { //BEGIN Get dimensions - /** Return the renderer's window border width. */ - int windowBorder (); + /// A container for the dimensions + struct BorderDimensions { + /// The dimensions: left, top, right, bottom + ubyte l, t, r, b; + + void opAddAssign (BorderDimensions d) { + l += d.l; + t += d.t; + r += d.r; + b += d.b; + } + } + + /// An enum for border types + enum BORDER_TYPES { + WINDOW_TOTAL, + WINDOW_RESIZE, + } + + /** 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); /** Return the renderer's between-widget spacing (for layout widgets). */ int layoutSpacing (); diff -r 052df9b2fe07 -r 8c4c96f04e7f mde/gui/renderer/SimpleRenderer.d --- a/mde/gui/renderer/SimpleRenderer.d Mon May 05 14:47:25 2008 +0100 +++ b/mde/gui/renderer/SimpleRenderer.d Mon May 05 17:02:21 2008 +0100 @@ -29,8 +29,19 @@ * The renderer is intended to be per-GUI. */ class SimpleRenderer : IRenderer { - int windowBorder () { - return 20; + + + 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; + } + } + return dims; } int layoutSpacing () { @@ -39,8 +50,11 @@ void drawWindow (int x, int y, int w, int h) { + gl.setColor (0f, 0f, .7f); + gl.drawBox (x,y, w,h); + gl.setColor (0f, 0f, 1f); - gl.drawBox (x,y, w,h); + gl.drawBox (x+20,y+5, w-25,h-25); gl.setColor (.3f, .3f, .3f); gl.drawBox (x+20, y+20, w-40, h-40); diff -r 052df9b2fe07 -r 8c4c96f04e7f mde/gui/widget/Window.d --- 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 } diff -r 052df9b2fe07 -r 8c4c96f04e7f mde/gui/widget/layout.d --- a/mde/gui/widget/layout.d Mon May 05 14:47:25 2008 +0100 +++ b/mde/gui/widget/layout.d Mon May 05 17:02:21 2008 +0100 @@ -109,10 +109,11 @@ void setSize (int nw, int nh) { // Step 1: calculate the minimal row/column sizes. - int mw, mh; // FIXME: use w,h directly? + alias w mw; // no need for extra vars, just use these + alias h mh; getMinimalSize (mw, mh); - colW = colWMin; // start with these dimensions, and increase if necessary - rowH = rowHMin; + colW = colWMin.dup; // start with these dimensions, and increase if necessary + rowH = rowHMin.dup; // duplicate, because we may want to resize without recalculating *Min // Step 2: clamp nw/nh or expand a column/row to achieve the required size if (nw <= mw) nw = mw; // clamp to minimal size @@ -135,6 +136,9 @@ foreach (i,widget; subWidgets) widget.setSize (colW[i % cols], rowH[i / cols]); + w = nw; + h = nh; + // Step 4: calculate the column and row positions colX.length = cols; rowY.length = rows; @@ -145,16 +149,17 @@ rowY[i] = cum; cum += x + spacing; } - h = cum - spacing; // set the total height - assert (h == nh); // FIXME: remove and set w/h directly once this is asserted cum = 0; foreach (i, x; colW) { colX[i] = cum; cum += x + spacing; } - w = cum - spacing; // total width - assert (w == nw); + + // Step 5: position needs resetting + // FIXME: find a more efficient method of doing this? + // maybe setPosition should ALWAYS be called after setSize? + setPosition (x,y); } void setPosition (int x, int y) {