# HG changeset patch # User Diggory Hardy # Date 1226335484 0 # Node ID 30470bc19ca4ceaf41881ce90da360bb7982a0cd # Parent dbf332403c6e5732bb1ff406d093a497bbdea376 Floating widgets now work nicely: customizable borders added, resizing, moving. gl.basic abstraction module removed (seemed pointless). Some changes to SimpleRenderer (largely to accomodate floating widgets). diff -r dbf332403c6e -r 30470bc19ca4 codeDoc/jobs.txt --- a/codeDoc/jobs.txt Thu Nov 06 13:16:39 2008 +0000 +++ b/codeDoc/jobs.txt Mon Nov 10 16:44:44 2008 +0000 @@ -8,6 +8,7 @@ Bugs: Sometimes nothing is drawn until a resize, and fonts are blocks. Cause: init-stages always appear to get divided between two threads. If Inpt, Font and SWnd are called by the main thread and not a sub-thread, the bug doesn't occur. A temporary fix is just to set maxThreads=1. A redesign of threading init stages could solve this, but doesn't seem worth the effort right now. +Drawing of floating widgets is not restricted to the floating area; see SimpleRenderer.restrict(). diff -r dbf332403c6e -r 30470bc19ca4 data/conf/gui.mtt --- a/data/conf/gui.mtt Thu Nov 06 13:16:39 2008 +0000 +++ b/data/conf/gui.mtt Mon Nov 10 16:44:44 2008 +0000 @@ -14,7 +14,10 @@ + + + + {Basic} diff -r dbf332403c6e -r 30470bc19ca4 mde/font/FontTexture.d --- a/mde/font/FontTexture.d Thu Nov 06 13:16:39 2008 +0000 +++ b/mde/font/FontTexture.d Mon Nov 10 16:44:44 2008 +0000 @@ -217,6 +217,7 @@ glEnd (); } + glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } @@ -321,6 +322,7 @@ glTexCoord2f (0f, 1f); glVertex2i (0, dimH); glEnd (); + glDisable(GL_TEXTURE_2D); glDisable(GL_BLEND); } diff -r dbf332403c6e -r 30470bc19ca4 mde/font/font.d --- a/mde/font/font.d Thu Nov 06 13:16:39 2008 +0000 +++ b/mde/font/font.d Mon Nov 10 16:44:44 2008 +0000 @@ -27,7 +27,6 @@ import mde.setup.exception; // InitStage stuff import derelict.freetype.ft; -import derelict.opengl.gl; import mde.file.deserialize; import tango.stdc.stringz; diff -r dbf332403c6e -r 30470bc19ca4 mde/gl/basic.d --- a/mde/gl/basic.d Thu Nov 06 13:16:39 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,35 +0,0 @@ -/* LICENSE BLOCK -Part of mde: a Modular D game-oriented Engine -Copyright © 2007-2008 Diggory Hardy - -This program is free software: you can redistribute it and/or modify it under the terms -of the GNU General Public License as published by the Free Software Foundation, either -version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . */ - -/** Some basic OpenGL code for drawing. -* -* Everything here is really intended as makeshift code to enable GUI development. */ -module mde.gl.basic; - -import derelict.opengl.gl; - -import tango.time.Time; // TimeSpan (type only; unused) - -//BEGIN Drawing utils -// Simple drawing commands for use by GUI -// (temporary) -void setColor (float r, float g, float b) { - glColor3f (r, g, b); -} -void drawBox (int x, int y, int w, int h) { - glDisable(GL_TEXTURE_2D); - glRecti(x, y+h, x+w, y); -} -//END Drawing utils diff -r dbf332403c6e -r 30470bc19ca4 mde/gui/WidgetManager.d --- a/mde/gui/WidgetManager.d Thu Nov 06 13:16:39 2008 +0000 +++ b/mde/gui/WidgetManager.d Mon Nov 10 16:44:44 2008 +0000 @@ -127,7 +127,6 @@ w = cast(wdim) nw; h = cast(wdim) nh; - debug logger.trace ("Resize to: {},{}", nw, nh); if (w < mw || h < mh) logger.warn ("Minimal dimensions ({},{}) not met: ({},{}), but I cannot resize myself!",mw,mh,w,h); diff -r dbf332403c6e -r 30470bc19ca4 mde/gui/renderer/IRenderer.d --- a/mde/gui/renderer/IRenderer.d Thu Nov 06 13:16:39 2008 +0000 +++ b/mde/gui/renderer/IRenderer.d Mon Nov 10 16:44:44 2008 +0000 @@ -28,79 +28,60 @@ * The renderer is intended to be per-GUI. */ interface IRenderer { - //BEGIN Get dimensions - /// A container for the dimensions - struct BorderDimensions { - /// The dimensions: left, top, right, bottom - wdim l, t, r, b; + //BEGIN Types + /** For floating widget borders. Like TextAdapter above, could be more flexible. */ + struct Border { + /** Border type. + * + * No border, small non-functional border, movement only border, resize only border, or + * full border. */ + enum BTYPE : int { + NONE = 0, SMALL = 1, LARGE = 2, MOVE = 4, RESIZE = 8, BOTH = MOVE | RESIZE + } + /** Which edges of a window are being resized. + * + * E.g. X1 == left, X2 | Y1 == right and top. */ + enum RESIZE : int { + NONE = 0x0, X1 = 0x1, X2 = 0x2, Y1 = 0x4, Y2 = 0x8 + } + + wdim x1,x2; /// First and second (lef & right) horizontal borders + wdim y1,y2; /// First and second vertical borders + RESIZE capability; /// Which resizes are possible. - void opAddAssign (BorderDimensions d) { - l += d.l; - t += d.t; - r += d.r; - b += d.b; + void opAddAssign (Border d) { + x1 += d.x1; + x2 += d.x2; + y1 += d.y1; + y2 += d.y2; + } + + /** 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 = Describes whether the click resizes or moves the widget. */ + RESIZE getResize (wdim cx, wdim cy, wdim w, wdim h) { + RESIZE r = RESIZE.NONE; + if (cx + cy < x1 + y1) + r = RESIZE.X1 | RESIZE.Y1; + else if (cx + h - cy < x1 + y2) + r = RESIZE.X1 | RESIZE.Y2; + else if (w - cx + cy < x2 + y1) + r = RESIZE.X2 | RESIZE.Y1; + else if (w - cx + h - cy < x2 + y2) + r = RESIZE.X2 | RESIZE.Y2; + return r & capability; } } - /** 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 - } - - /** 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 (wdim cx, wdim cy, wdim w, wdim h); - - /** Return the renderer's between-widget spacing (for layout widgets). */ - wdim layoutSpacing (); - //END Get dimensions - - //BEGIN draw routines - /** Restrict following draw operations to given box. - * - * Restrict "pushes" a restriction onto a stack; relax must be called afterwards to "pop" the - * restriction. */ - void restrict (wdim x, wdim y, wdim w, wdim h); - void relax (); /// ditto - - /** Draw a window border plus background. */ - void drawWindow (wdim x, wdim y, wdim w, wdim h); - - /** Draws a widget background. Usually doesn't do anything since backgrounds are transparent. */ - void drawWidgetBack (wdim x, wdim y, wdim w, wdim h); - - /** Draws a blank widget (temporary) */ - void drawBlank (wdim x, wdim y, wdim w, wdim h); - - /** Draws a button frame, in if pushed == true. */ - void drawButton (wdim x, wdim y, wdim w, wdim h, bool pushed); - - /** Toggle buttons. - * - * These have a fixed size which getToggleSize returns. */ - wdimPair getToggleSize (); - void drawToggle (wdim x, wdim y, bool state, bool pushed); /// ditto - - /** Get a TextAdapter to draw some text. - * - * If no colour is passes, a default is used (white). */ - TextAdapter getAdapter (char[] text, int colour = 0xFFFFFF); - /** For drawing text - one instance per string. * * NOTE: currently inflexible. Could use (function) pointers, class interfaces or struct @@ -126,5 +107,46 @@ Colour colour; FontStyle font; } - //END draw routines + //END Types + + //BEGIN Methods + /** Returns a Border containing dimensions. + * + * The dimensions may depend on whether the widget is resizable (horizontally and vertically). + */ + Border getBorder (Border.BTYPE type, bool wSizable, bool hSizable); + + /** Return the renderer's between-widget spacing (for layout widgets). */ + wdim layoutSpacing (); + + /** Restrict following draw operations to given box. + * + * Restrict "pushes" a restriction onto a stack; relax must be called afterwards to "pop" the + * restriction. */ + void restrict (wdim x, wdim y, wdim w, wdim h); + void relax (); /// ditto + + /** Draw a window border plus background. */ + void drawWindow (Border* border, wdim x, wdim y, wdim w, wdim h); + + /** Draws a widget background. Usually doesn't do anything since backgrounds are transparent. */ + void drawWidgetBack (wdim x, wdim y, wdim w, wdim h); + + /** Draws a blank widget (temporary) */ + void drawBlank (wdim x, wdim y, wdim w, wdim h); + + /** Draws a button frame, in if pushed == true. */ + void drawButton (wdim x, wdim y, wdim w, wdim h, bool pushed); + + /** Toggle buttons. + * + * These have a fixed size which getToggleSize returns. */ + wdimPair getToggleSize (); + void drawToggle (wdim x, wdim y, bool state, bool pushed); /// ditto + + /** Get a TextAdapter to draw some text. + * + * If no colour is passes, a default is used (white). */ + TextAdapter getAdapter (char[] text, int colour = 0xFFFFFF); + //END Methods } diff -r dbf332403c6e -r 30470bc19ca4 mde/gui/renderer/SimpleRenderer.d --- a/mde/gui/renderer/SimpleRenderer.d Thu Nov 06 13:16:39 2008 +0000 +++ b/mde/gui/renderer/SimpleRenderer.d Mon Nov 10 16:44:44 2008 +0000 @@ -18,7 +18,7 @@ import mde.gui.renderer.IRenderer; -import gl = mde.gl.basic; +import derelict.opengl.gl; import mde.font.font; /** Interface for renderers. @@ -34,51 +34,25 @@ defaultFont = FontStyle.get("default"); } - BorderDimensions setSizable (bool wS, bool hS) { - wSizable = wS; - hSizable = hS; - - // Set the border size based on the above + alias Border.BTYPE BTYPE; + Border getBorder (BTYPE type, bool wS, bool hS) { + Border border; with (border) { - l = r = t = b = 14; + if (type & BTYPE.RESIZE) { + if (wS) capability = RESIZE.X1 | RESIZE.X2; + if (hS) capability |= RESIZE.Y1 | RESIZE.Y2; + } + if (type & BTYPE.LARGE) { + y1 = 12; + y2 = 6; + } + else if (type & BTYPE.SMALL) + y1 = y2 = 4; + x1 = x2 = y2; } - with (resize) { - if (wSizable) - l = r = 6; - else - l = r = 0; - if (hSizable) { - t = b = 6; - } else - t = b = 0; - } - border += resize; return border; } - RESIZE_TYPE getResizeType (wdim cx, wdim cy, wdim w, wdim 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 resizeType; - } - wdim layoutSpacing () { return 4; } @@ -88,35 +62,57 @@ void restrict (wdim x, wdim y, wdim w, wdim h) {} void relax () {} - void drawWindow (wdim x, wdim y, wdim w, wdim h) { - gl.setColor (0f, 0f, .7f); - gl.drawBox (x,y, w,h); + void drawWindow (Border* border, wdim x, wdim y, wdim w, wdim h) { + glColor3f (0f, 0f, .8f); + glRecti(x, y+h, x+w, y); - gl.setColor (0f, 0f, 1f); - gl.drawBox (x+resize.l, y+resize.t, w-resize.l-resize.r, h-resize.t-resize.b); + if (border.capability != 0) { + glColor3f (0f, 0f, .7f); + glBegin (GL_TRIANGLES); + wdim t = border.x1 + border.y1; + glVertex2i (x, y); + glVertex2i (x+t, y); + glVertex2i (x, y+t); + + t = border.x2 + border.y1; + glVertex2i (x+w, y); + glVertex2i (x+w, y+t); + glVertex2i (x+w-t, y); + + t = border.x2 + border.y2; + glVertex2i (x+w, y+h); + glVertex2i (x+w-t, y+h); + glVertex2i (x+w, y+h-t); + + t = border.x1 + border.y2; + glVertex2i (x, y+h); + glVertex2i (x, y+h-t); + glVertex2i (x+t, y+h); + glEnd (); + } - gl.setColor (.3f, .3f, .3f); - gl.drawBox (x+border.l, y+border.t, w-border.l-border.r, h-border.t-border.b); + glColor3f (0f, 0f, 0f); + glRecti(x+border.x1, y+h-border.y2, x+w-border.x2, y+border.y1); } void drawWidgetBack (wdim x, wdim y, wdim w, wdim h) { debug { - gl.setColor (0f, .2f, .2f); - gl.drawBox (x,y, w,h); + glColor3f (0f, .2f, .2f); + glRecti (x,y+h, x+w,y); } } void drawBlank (wdim x, wdim y, wdim w, wdim h) { - gl.setColor (.4f, .4f, .4f); - gl.drawBox (x,y, w,h); + glColor3f (.4f, .4f, .4f); + glRecti(x, y+h, x+w, y); } void drawButton (wdim x, wdim y, wdim w, wdim h, bool pushed) { if (pushed) - gl.setColor (1f, 0f, 1f); + glColor3f (1f, 0f, 1f); else - gl.setColor (.6f, 0f, .6f); - gl.drawBox (x,y, w,h); + glColor3f (.6f, 0f, .6f); + glRecti(x, y+h, x+w, y); } wdimPair getToggleSize () { @@ -128,10 +124,10 @@ void drawToggle (wdim x, wdim y, bool state, bool pushed) { float c = pushed ? .7f : .5f; if (state) - gl.setColor (0f, c, 0f); + glColor3f (0f, c, 0f); else - gl.setColor (c, 0f, 0f); - gl.drawBox (x+2,y+2, 12,12); + glColor3f (c, 0f, 0f); + glRecti (x+2,y+14, x+14,y+2); } TextAdapter getAdapter (char[] text, int col) { @@ -142,8 +138,5 @@ } protected: - bool wSizable, hSizable; - BorderDimensions border; - BorderDimensions resize; FontStyle defaultFont; } diff -r dbf332403c6e -r 30470bc19ca4 mde/gui/widget/Floating.d --- a/mde/gui/widget/Floating.d Thu Nov 06 13:16:39 2008 +0000 +++ b/mde/gui/widget/Floating.d Mon Nov 10 16:44:44 2008 +0000 @@ -18,15 +18,7 @@ import mde.gui.widget.Widget; import mde.gui.exception; -/+import mde.gui.widget.createWidget; -import mde.gui.IGui; -import mde.gui.renderer.createRenderer; - -import mt = mde.mergetag.DataSet; -import mde.mergetag.parse.parseTo : parseTo; -import mde.mergetag.parse.parseFrom : parseFrom; -+/ import tango.util.log.Log : Log, Logger; private Logger logger; @@ -47,410 +39,223 @@ class FloatingAreaWidget : AParentWidget { this (IWidgetManager mgr, widgetID id, WidgetData data) { - if (data.ints.length != 1) + if (data.ints.length != 1 + data.strings.length) throw new WidgetDataException (this); subWidgets.length = data.strings.length; // widgets created from string data sWOrder.length = subWidgets.length; + sWData.length = subWidgets.length; foreach (i,s; data.strings) { subWidgets[i] = mgr.makeWidget (s); sWOrder[i] = i; + sWData[i].borderType = cast(BTYPE) data.ints[i+1]; } - sWCoords = mgr.dimData (id); - if (sWCoords.length != subWidgets.length * 2) { - // don't bother logging a warning; correct data will be saved anyway - sWCoords.length = subWidgets.length * 2; // maybe some data kept + wdim[] dd = mgr.dimData (id); + if (dd.length == subWidgets.length * 4) { + foreach (i, ref d; sWData) + (&d.x)[0..4] = dd[i*4..i*4+4]; } super (mgr, id, data); } + void finalize () { + foreach (i, ref d; sWData) with (d) { + auto widg = subWidgets[i]; + d.border = mgr.renderer.getBorder (borderType, widg.isWSizable, widg.isHSizable); + mw = widg.minWidth + border.x1 + border.x2; + mh = widg.minHeight + border.y1 + border.y2; + if (w < mw) w = mw; + if (h < mh) h = mh; + widg.setWidth (w - border.x1 - border.x2, -1); + widg.setHeight (h - border.y1 - border.y2, -1); + } + } + bool saveChanges () { - foreach (widget; subWidgets) - widget.saveChanges (); + wdim[] dd = new wdim[sWData.length*4]; + foreach (i, ref d; sWData) { + subWidgets[i].saveChanges (); + dd[4*i..4*i+4] = (&d.x)[0..4]; + } - mgr.setDimData (id, sWCoords); // save positions + mgr.setDimData (id, dd); // save positions return true; } void setWidth (wdim nw, int) { w = nw; // check all floating widgets are visible - foreach (i, widg; subWidgets) { - wdim d; - if (sWCoords[i] + (d = widg.width) > w) { - if (d > w) - sWCoords[i] = 0; - else - sWCoords[i] = w - d; - } + foreach (i, ref d; sWData) with (d) { + if (x + w > this.w) + x = (w > this.w) ? 0 : this.w - w; } } void setHeight (wdim nh, int) { h = nh; - foreach (i, widg; subWidgets) { - wdim d; - size_t n = i + subWidgets.length; - if (sWCoords[n] + (d = widg.height) > h) { - if (d > h) - sWCoords[n] = 0; - else - sWCoords[n] = h - d; - } + foreach (i, ref d; sWData) with (d) { + if (y + h > this.h) + y = (h > this.h) ? 0 : this.h - h; } } bool isWSizable () { return true; } bool isHSizable () { return true; } - void setPosition (wdim x, wdim y) { - super.setPosition (x,y); + void setPosition (wdim nx, wdim ny) { + x = nx; + y = ny; size_t n = subWidgets.length; - foreach (i,widg; subWidgets) - widg.setPosition (x+sWCoords[i], y+sWCoords[i+n]); + foreach (i, ref d; sWData) + subWidgets[i].setPosition (x + d.x + d.border.x1, y + d.y + d.border.y1); } void draw () { super.draw; mgr.renderer.restrict (x,y, w,h); - foreach (i; sWOrder) - subWidgets[i].draw; + with (sWData[i]) { + mgr.renderer.drawWindow (&border, this.x + x, this.y + y, w, h); + subWidgets[i].draw; + } + mgr.renderer.relax; } IChildWidget getWidget (wdim cx, wdim cy) { + debug scope (failure) + logger.warn ("getWidget: failure; values: click, pos, width - {}, {}, {} - {}, {}, {}", cx, x, w, cy, y, h); debug assert (cx >= x && cx < x + w && cy >= y && cy < y + h, "getWidget: not on widget (code error)"); - size_t n = subWidgets.length; - foreach_reverse (j,i; sWOrder) { - wdim lx = cx - (x + sWCoords[i ]); - wdim ly = cy - (y + sWCoords[i+n]); - if (lx >= 0 && lx < subWidgets[i].width && - ly >= 0 && ly < subWidgets[i].height) + foreach_reverse (j,i; sWOrder) with (sWData[i]) { + wdim lx = cx - (this.x + x); + wdim ly = cy - (this.y + y); + if (lx >= 0 && lx < w && + ly >= 0 && ly < h) { sWOrder[j..$-1] = sWOrder[j+1..$].dup; sWOrder[$-1] = i; mgr.requestRedraw; - return subWidgets[i]; + if (lx >= border.x1 && lx < w-border.x2 && + ly >= border.y1 && ly < h-border.y2) + return subWidgets[i].getWidget (cx,cy); + event = i; + return this; } } + event = size_t.max; return this; // no match } -protected: - wdim[] sWCoords; // coords for subwidgets, relative to this widget: [x1,x2,...,y1,y2,...] - size_t[] sWOrder; // indexes for draw order (top widget at end of list) - - /+ - /** Call after loading is finished to setup the window and confirm that it's valid. - * - * Throws: WindowLoadException (or possibly other exceptions). Do not use the instance if an - * exception occurs! */ - void finalise (IGui gui) - in { - assert (gui !is null, "Window.finalise ("~name~"): gui is null"); - } body { - // Check data was loaded: - if (widgetData is null) - throw new WindowLoadException ("No widget creation data"); - - // Save gui and create the renderer: - gui_ = gui; - rend = createRenderer (gui.rendererName); - - // Create the primary widget (and indirectly all sub-widgets), throwing on error: - // Note: GridLayoutWidget's this relies on rend.layoutSpacing. - widget = makeWidget (0); // primary widget always has ID 0. - // This data is no longer needed by Window, although its sub-arrays may still be used, so - // let the GC collect what it can: - widgetData = null; - widgetStrings = null; - - // 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: - if ((widget.adjust (mutableData)).length != 0) // adjust/set size, etc., depends on rend - logger.warn ("Local widget position data is invalid!"); - mutableData = null; // no longer needed - - widget.getCurrentSize (w,h); // and get this size - w += border.l + border.r; // Adjust for border - h += border.t + border.b; - - widgetX = x + border.l; // widget position - widgetY = y + border.t; // must be updated if the window is moved - widget.setPosition (widgetX, widgetY); - - // Calculate mw/mh and xw/yh (cached data): - mw = widget.minWidth + border.l + border.r; - mh = widget.minHeight + border.t + border.b; - - xw = x+w; - yh = y+h; - } - //END Methods for GUI - - //BEGIN IWindow methods - /** Get/create a widget by ID. - * - * Should $(I only) be called internally and by sub-widgets! */ - IWidget makeWidget (widgetID i) - in { - // widgetData is normally left to be garbage collected after widgets have been created: - assert (widgetData !is null, "Window.makeWidget ("~name~"): widgetData is null"); - } body { - /* Each widget returned should be a unique object; if multiple widgets are requested with - * the same ID, a new widget is created each time. */ - - int[]* d = i in widgetData; - if (d is null) - throw new WindowLoadException ("Window.makeWidget ("~name~"): Widget not found"); - - // Throws WidgetDataException (a WindowLoadException) if bad data: - return createWidget (this, *d); - } - - char[] getWidgetString (int i) - in { - // widgetStrings is freed at same time as widgetData - // but widgetData is guaranteed to be read - assert (widgetData !is null, "getWidgetString called after widget creation finished"); - } body { - char[]* p; - if (widgetStrings is null || - (p = i in widgetStrings) is null ) - throw new WindowLoadException ("Needed widgetStrings not set for Window"); - - return *p; - } - - /** Add this widget's data to that to be saved, returning it's widgetID. */ - widgetID addCreationData (IWidget widget) - { - widgetID i; - if (widgetData is null) - i = 0; - else - i = widgetData.keys[$-1] + 1; - - /+ Doesn't this have no effect except when getCreationData throws, in which case the data - + isn't used anyway? I'm sure it was added for a reason... FIXME and below - widgetData[i] = null; // Make sure the same ID doesn't get used by a recursive call - +/ - widgetData[i] = widget.getCreationData; - - return i; - } - - int addWidgetString (char[] str) - { - int i; - if (widgetStrings is null) - i = 0; - else - i = widgetStrings.keys[$-1] + 1; - - /+ See above. FIXME - widgetStrings[i] = null; // Make sure the same ID doesn't get used by a recursive call - +/ - widgetStrings[i] = str; - - return i; - } - - IGui gui () { - return gui_; - } - - void requestRedraw () { - gui_.requestRedraw; - } - - IRenderer renderer () - in { - assert (rend !is null, "Window.renderer: rend is null"); - } body { - return rend; - } - //END IWindow methods - - //BEGIN IWidget methods - //FIXME: how many of these methods are actually needed/used? - int[] adjust (int[]) { // simply not relevant (never used) - return []; - } - int[] getCreationData () { // simply not relevant (never used) - return []; - } - int[] getMutableData () { // simply not relevant (never used) - return []; - } - - bool isWSizable () { - return widget.isWSizable; - } - bool isHSizable () { - return widget.isHSizable; - } - - wdim minWidth () { - return mw; - } - wdim minHeight () { - return mh; - } - void getCurrentSize (out wdim cw, out wdim ch) { - cw = w; - ch = h; - } - - void setWidth (wdim nw, int dir) { - if (nw < mw) w = mw; // clamp - else w = nw; - xw = x + w; - widget.setWidth (w - border.l - border.r, dir); - } - void setHeight (wdim nh, int dir) { - if (nh < mh) h = mh; // clamp - else h = nh; - yh = y + h; - widget.setHeight (h - border.t - border.b, dir); - } - - void setPosition (wdim nx, wdim ny) { - x = nx; - y = ny; - - xw = x+w; - yh = y+h; - - widgetX = x + border.l; - widgetY = y + border.t; - - widget.setPosition (widgetX, widgetY); - - gui_.requestRedraw (); // necessary whenever the window is moved; setPosition is called after resizes and moves - } - - IWidget getWidget (wdim cx, wdim cy) { - if (cx < x || cx >= xw || cy < y || cy >= yh) // not over window - return null; - 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 - return this; - } void clickEvent (wdabs cx, wdabs cy, ubyte b, bool state) { + if (event > subWidgets.length) return; if (b == 1 && state == true) { - 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; + active = event; + with (sWData[active]) { + resizeType = border.getResize (cx - this.x - x, cy - this.y - y, w,h); + alias border.RESIZE RESIZE; - if (resizeType & RESIZE_TYPE.T) - yDrag = h + cy; - else if (resizeType & RESIZE_TYPE.B) - yDrag = h - cy; - - // 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; - - gui_.addClickCallback (&endCallback); - gui_.addMotionCallback (&moveCallback); + if (resizeType != RESIZE.NONE) { + // Set x/yDrag (unfortunately these need to be different for each edge) + if (resizeType & RESIZE.X1) + xDrag = w + cx; + else if (resizeType & RESIZE.X2) + xDrag = w - cx; + + if (resizeType & RESIZE.Y1) + yDrag = h + cy; + else if (resizeType & RESIZE.Y2) + yDrag = h - cy; + + mgr.addClickCallback (&endCallback); + mgr.addMotionCallback (&resizeCallback); + } else if (borderType & BTYPE.MOVE) { // window is being moved + xDrag = cx - x; + yDrag = cy - y; + + mgr.addClickCallback (&endCallback); + mgr.addMotionCallback (&moveCallback); + } } } } - void draw () { - // background - rend.drawWindow (x,y, w,h); - - // Tell the widget to draw itself: - widget.draw(); - } - //END IWidget methods - -private: - alias IRenderer.BorderDimensions BorderDimensions; - alias IRenderer.RESIZE_TYPE RESIZE_TYPE; - - //BEGIN Window moving and resizing +protected: void moveCallback (wdabs cx, wdabs cy) { - setPosition (cx-xDrag, cy-yDrag); + with (sWData[active]) { + x = cx-xDrag; + y = cy-yDrag; + + if (x < 0) + x = 0; + else if (x + w > this.w) + x = (w > this.w) ? 0 : this.w - w; + if (y < 0) + y = 0; + else if (y + h > this.h) + y = (h > this.h) ? 0 : this.h - h; + + subWidgets[active].setPosition (this.x + x + border.x1, this.y + y + border.y1); + } + mgr.requestRedraw; } void resizeCallback (wdabs cx, wdabs cy) { - debug scope(failure) - logger.trace ("resizeCallback: failure"); - - // This function is only called if some resize is going to happen. - // x,y are used as parameters to setPosition as well as being affected by it; somewhat - // pointless but fairly effective. - - if (resizeType & RESIZE_TYPE.L) { - wdim xSize = xDrag - cx; - if (xSize < mw) xSize = mw; // clamp - x += w - xSize; - setWidth (xSize, 1); - } - else if (resizeType & RESIZE_TYPE.R) { - setWidth (xDrag + cx, -1); + with (sWData[active]) { + if (resizeType & RESIZE.X1) { + wdim ow = w; + w = xDrag - cx; + if (w < mw) w = mw; + x += ow - w; + subWidgets[active].setWidth (w - border.x1 - border.x2, 1); + } + else if (resizeType & RESIZE.X2) { + w = xDrag + cx; + if (w < mw) w = mw; + subWidgets[active].setWidth (w - border.x1 - border.x2, -1); + } + if (resizeType & RESIZE.Y1) { + wdim oh = h; + h = yDrag - cy; + if (h < mh) h = mh; + y += oh - h; + subWidgets[active].setHeight (h - border.y1 - border.y2, 1); + } + else if (resizeType & RESIZE.Y2) { + h = yDrag + cy; + if (h < mh) h = mh; + subWidgets[active].setHeight (h - border.y1 - border.y2, -1); + } + // Reposition widget and sub-widgets: + subWidgets[active].setPosition (this.x + x + border.x1, this.y + y + border.y1); } - if (resizeType & RESIZE_TYPE.T) { - wdim ySize = yDrag - cy; - if (ySize < mh) ySize = mh; - y += h - ySize; - setHeight (ySize, 1); - } - else if (resizeType & RESIZE_TYPE.B) { - setHeight (yDrag + cy, -1); - } - - // Moves lower (x,y) coordinate if necessary and repositions any sub-widgets moved by the - // resizing: - setPosition (x, y); + mgr.requestRedraw; } - bool endCallback (wdabs cx, wdabs 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); - + bool endCallback (wdabs, wdabs, ubyte b, bool state) { + if (b == 1 && state == false) { // end of a move/resize + mgr.removeCallbacks (cast(void*) this); return true; // we've handled the up-click } return false; // we haven't handled it } - wdim xDrag, yDrag; // where a drag starts relative to x and y - 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) - - IGui gui_; // The gui managing this window - IRenderer rend; // The window's renderer - IWidget widget; // The primary widget in this window. + struct SWData { // NOTE: x,y,w,h must be first elements; search (&d.x) + wdim x,y; // position (corner of border) + wdim w,h; // size (including border) + wdim mw,mh; + BTYPE borderType; // what type of border to put around the widget + IRenderer.Border border; + } + static assert (SWData.alignof == 4); // assumptions for optimization; search (&d.x) + SWData[] sWData; + size_t[] sWOrder; // indexes for draw order (top widget at end of list) - wdim x = -1, y = -1; // Window position - wdsize w,h; // Window size (calculated from Widgets) - wdim xw, yh; // x+w, y+h (frequent use by clickEvent) - wdim widgetX, widgetY; // Widget position (= window position plus BORDER_WIDTH) - wdim mw = -1, mh = -1; // minimal size (negative means requires calculation) - - BorderDimensions border; // Total border size (move plus resize) - +/ + // Click/drag information: + alias IRenderer.Border.BTYPE BTYPE; + alias IRenderer.Border.RESIZE RESIZE; + size_t event = size_t.max; // Border with last click/release: size_t.max: main area (no subwidget), i: subwidget[i] + size_t active = size_t.max; // Like event, but refers to widget being moved/resized + wdim xDrag, yDrag; // where a drag starts relative to x and y + RESIZE resizeType; // Type of current resize } diff -r dbf332403c6e -r 30470bc19ca4 mde/setup/Screen.d --- a/mde/setup/Screen.d Thu Nov 06 13:16:39 2008 +0000 +++ b/mde/setup/Screen.d Mon Nov 10 16:44:44 2008 +0000 @@ -28,7 +28,7 @@ import tango.time.Time; // TimeSpan (type only; unused) import derelict.sdl.sdl; -import derelict.opengl.gl; // for loading a later gl version +import derelict.opengl.gl; import derelict.util.exception; /** Currently just used as a namespace. Potential for multiple screen support later? */ @@ -56,9 +56,8 @@ /** Init function to initialize SDL. */ StageState init () { // init func // Initialise SDL - debug logger.trace ("Calling SDL_Init"); - //FIXME: init SDL_INIT_TIMER? - if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER /+| SDL_INIT_EVENTTHREAD+/)) { + debug logger.trace ("Calling SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)"); + if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_JOYSTICK /+| SDL_INIT_EVENTTHREAD+/)) { logger.fatal ("SDL initialisation failed:"); char* msg = SDL_GetError (); logger.fatal (msg ? fromStringz(msg) : "no reason available"); @@ -69,7 +68,7 @@ } /** SDL shutdown */ StageState cleanup () { - debug logger.trace ("Calling SDL_Quit"); + debug logger.trace ("Calling SDL_Quit ()"); SDL_Quit(); return StageState.INACTIVE; } @@ -134,7 +133,6 @@ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glEnable(GL_TEXTURE_2D); glShadeModel(GL_SMOOTH); glClearColor (0.0f, 0.0f, 0.0f, 0.0f); @@ -148,7 +146,6 @@ //NOTE: wrap mode may have an effect, but shouldn't be noticed... // Window-manager settings - debug logger.trace ("Calling SDL_WM_SetCaption"); SDL_WM_SetCaption (toStringz ("mde"), null); // SDL_WM_GrabInput (use later) //END Create window and initialize OpenGL @@ -217,7 +214,7 @@ } //debug logger.trace ("Setting video mode {}x{}, 32-bit, flags: {}", w,h,flags); - debug logger.trace ("Calling SDL_SetVideoMode"); + debug logger.trace ("Calling SDL_SetVideoMode ({}, {}, 32, 0x{:x})", w,h, flags); if (SDL_SetVideoMode (w, h, 32, flags) is null) { logger.fatal ("Unable to set video mode:"); char* msg = SDL_GetError ();