Changeset 95:2a364c7d82c9
- Timestamp:
- 11/06/08 06:07:18 (2 months ago)
- Files:
-
- codeDoc/jobs.txt (modified) (2 diffs)
- data/L10n/FontOptions.mtt (moved) (moved from data/L10n/OptionsFont.mtt) (1 diff)
- data/L10n/MiscOptions.mtt (moved) (moved from data/L10n/OptionsMisc.mtt)
- data/L10n/VideoOptions.mtt (moved) (moved from data/L10n/OptionsVideo.mtt) (1 diff)
- data/conf/gui.mtt (modified) (1 diff)
- data/conf/options.mtt (modified) (1 diff)
- examples/guiDemo.d (modified) (1 diff)
- mde/gui/content/Content.d (modified) (3 diffs)
- mde/gui/content/options.d (modified) (1 diff)
- mde/gui/renderer/IRenderer.d (modified) (2 diffs)
- mde/gui/renderer/SimpleRenderer.d (modified) (1 diff)
- mde/gui/widget/Floating.d (modified) (1 diff)
- mde/gui/widget/Ifaces.d (modified) (1 diff)
- mde/gui/widget/TextWidget.d (modified) (3 diffs)
- mde/gui/widget/Widget.d (modified) (6 diffs)
- mde/gui/widget/createWidget.d (modified) (6 diffs)
- mde/gui/widget/layout.d (modified) (17 diffs)
- mde/gui/widget/miscContent.d (added)
- mde/gui/widget/miscWidgets.d (modified) (1 diff)
- mde/imde.d (modified) (1 diff)
- mde/input/joystick.d (modified) (1 diff)
- mde/lookup/Options.d (modified) (11 diffs)
- mde/mde.d (modified) (1 diff)
- mde/scheduler/Scheduler.d (modified) (2 diffs)
- mde/setup/Init.d (modified) (4 diffs)
- mde/setup/InitStage.d (modified) (2 diffs)
- mde/setup/Screen.d (modified) (4 diffs)
- mde/util.d (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
codeDoc/jobs.txt
r91 r95 8 8 9 9 Bugs: 10 Sometimes nothing is drawn until a resize, and fonts are blocks ? External bug? Info: doesn't happen when limited to one thread.10 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. 11 11 12 12 … … 14 14 To do (importance 0-5: 0 pointless, 1 no obvious impact now, 2 todo sometime, 3 useful, 4 important, 5 urgent): 15 15 Also see todo.txt and FIXME/NOTE comment marks. 16 4 Data saving for widgetIDs with multiple instances?17 3 Try to correlate names of option sections more. (i.e. symbol name, class name, name of i18n translation file)18 16 3 Use of dtors - don't rely on them? Or what happens when init throws during creation - relying on undefined behaviour. 19 17 3 glBindTexture not working with non-0 index - perhaps use a higher level graphics library at some point. data/L10n/FontOptions.mtt
r51 r95 1 1 {MT01} 2 2 {en-GB} 3 <entry|lcdFilter= ["LCD filtering","Enable or disable sub-pixel rendering. Note that the FreeType library may be compiled without support due to patent issues."]>4 <entry|renderMode= ["Font rendering mode","Controls how fonts are rendered: in gray-scale, or for LCDs (with a horizontal (usual) or vertical layout, with an RGB (usual) or BGR sub-pixel mode."]>3 <entry|lcdFilter={0:"LCD filtering",1:"Enable or disable sub-pixel rendering. Note that the FreeType library may be compiled without support due to patent issues."}> 4 <entry|renderMode={0:"Font rendering mode",1:"Controls how fonts are rendered: in gray-scale, or for LCDs (with a horizontal (usual) or vertical layout, with an RGB (usual) or BGR sub-pixel mode."}> data/L10n/VideoOptions.mtt
r22 r95 1 1 {MT01} 2 2 {en-GB} 3 <entry|fullscreen= ["Fullscreen","If true use the whole screen, if false use a window."]>4 <entry|hardware= ["Hardware","Create the video surface in hardware or software memory."]>5 <entry|resizable= ["Resizable","In windowed mode, allow the window to be resized by the window manager."]>6 <entry|noFrame= ["No frame","In windowed mode, don't draw a window border."]>7 <entry|screenW= ["Screen width","Horizontal resolution (fullscreen mode)."]>8 <entry|screenH= ["Screen height","Vertical resolution (fullscreen mode)."]>9 <entry|windowW= ["Window width","Horizontal size (windowed mode)."]>10 <entry|windowH= ["Window height","Vertical size (windowed mode)."]>3 <entry|fullscreen={0:"Fullscreen",1:"If true use the whole screen, if false use a window."}> 4 <entry|hardware={0:"Hardware",1:"Create the video surface in hardware or software memory."}> 5 <entry|resizable={0:"Resizable",1:"In windowed mode, allow the window to be resized by the window manager."}> 6 <entry|noFrame={0:"No frame",1:"In windowed mode, don't draw a window border."}> 7 <entry|screenW={0:"Screen width",1:"Horizontal resolution (fullscreen mode)."}> 8 <entry|screenH={0:"Screen height",1:"Vertical resolution (fullscreen mode)."}> 9 <entry|windowW={0:"Window width",1:"Horizontal size (windowed mode)."}> 10 <entry|windowH={0:"Window height",1:"Vertical size (windowed mode)."}> data/conf/gui.mtt
r94 r95 8 8 <WidgetData|button={0:[0x10,50,50]}> 9 9 <WidgetData|blank={0:[0x2]}> 10 <WidgetData|opts={0:[0x8110,0],1:["optDBox"," MiscOptions"]}>11 <WidgetData|optDBox={0:[0xC100, 0,2,1],1:["optBox","optDesc"]}>10 <WidgetData|opts={0:[0x8110,0],1:["optDBox","VideoOptions"]}> 11 <WidgetData|optDBox={0:[0xC100,1,2,1],1:["optBox","optDesc"]}> 12 12 <WidgetData|optBox={0:[0xC100,1,1,3],1:["optName","optSep","optVal"]}> 13 13 <WidgetData|optName={0:[0x4020, 1, 0xfe8c00]}> 14 14 <WidgetData|optDesc={0:[0x4020, 2, 0xaf6000]}> 15 <WidgetData|optVal={0:[0x 4020, 0, 0xBF00]}>15 <WidgetData|optVal={0:[0x6030]}> 16 16 <WidgetData|optSep={0:[0x21, 0xff],1:["="]}> 17 17 <WidgetData|floating={0:[0x8200,20,20],1:["text"]}> data/conf/options.mtt
r94 r95 17 17 <bool|fullscreen=false> 18 18 <int|screenW=1280> 19 <int|screenH=1024> 19 20 <int|windowW=800> 20 <int|screenH=1024>21 21 <int|windowH=600> 22 22 examples/guiDemo.d
r85 r95 68 68 * Note: probably drawing should start at the beginning of the loop and glFlush()/swapBuffers 69 69 * be called at the end to optimise. */ 70 mainSchedule.add (SCHEDULE.DRAW, &Screen.draw) ; // Draw, per eventonly.70 mainSchedule.add (SCHEDULE.DRAW, &Screen.draw).request = true; // Draw, per event and first frame only. 71 71 mainSchedule.add (mainSchedule.getNewID, &mde.events.pollEvents).frame = true; 72 72 //END Main loop setup mde/gui/content/Content.d
r94 r95 95 95 class BoolContent : ValueContent 96 96 { 97 this () {} 98 this (bool val) { 97 /** Create a content with _symbol name symbol. */ 98 this (char[] symbol, bool val = false) { 99 symb = symbol; 99 100 v = val; 101 } 102 103 /** Adds cb to the list of callback functions called when the value is changed. Returns this. */ 104 BoolContent addChangeCb (void delegate (char[] symbol,bool value) cb) { 105 cngCb ~= cb; 106 return this; 100 107 } 101 108 102 109 /// Get the text. 103 110 char[] toString (uint i) { 104 debug logger.trace ("BoolContent.toString");105 111 return (i == 0) ? v ? "true" : "false" 106 112 : (i == 1) ? name_ … … 111 117 void opAssign (bool val) { 112 118 v = val; 119 foreach (cb; cngCb) 120 cb(symb, val); 113 121 } 114 122 bool opCall () { … … 116 124 } 117 125 118 protected bool v; 126 bool v; //FIXME: should be protected but Options needs to set without calling callbacks 127 protected: 128 char[] symb; 129 void delegate (char[],bool)[] cngCb; // change callbacks 119 130 } 120 131 mde/gui/content/options.d
r94 r95 26 26 import mde.lookup.Translation; 27 27 28 debug { 29 import tango.util.log.Log : Log, Logger; 30 private Logger logger; 31 static this () { 32 logger = Log.getLogger ("mde.gui.content.options"); 33 } 28 import tango.util.log.Log : Log, Logger; 29 private Logger logger; 30 static this () { 31 logger = Log.getLogger ("mde.gui.content.options"); 34 32 } 35 33 mde/gui/renderer/IRenderer.d
r93 r95 77 77 * restriction. */ 78 78 void restrict (wdim x, wdim y, wdim w, wdim h); 79 80 /** See restrict. */ 81 void relax (); 79 void relax (); /// ditto 82 80 83 81 /** Draw a window border plus background. */ … … 93 91 void drawButton (wdim x, wdim y, wdim w, wdim h, bool pushed); 94 92 95 /** Get a TextAdapter to draw some text. */ 96 TextAdapter getAdapter (char[] text, int colour); 93 /** Toggle buttons. 94 * 95 * These have a fixed size which getToggleSize returns. */ 96 wdimPair getToggleSize (); 97 void drawToggle (wdim x, wdim y, bool state, bool pushed); /// ditto 98 99 /** Get a TextAdapter to draw some text. 100 * 101 * If no colour is passes, a default is used (white). */ 102 TextAdapter getAdapter (char[] text, int colour = 0xFFFFFF); 97 103 98 104 /** For drawing text - one instance per string. mde/gui/renderer/SimpleRenderer.d
r93 r95 120 120 } 121 121 122 wdimPair getToggleSize () { 123 wdimPair r; 124 r.x = 16; 125 r.y = 16; 126 return r; 127 } 128 void drawToggle (wdim x, wdim y, bool state, bool pushed) { 129 float c = pushed ? .7f : .5f; 130 if (state) 131 gl.setColor (0f, c, 0f); 132 else 133 gl.setColor (c, 0f, 0f); 134 gl.drawBox (x+2,y+2, 12,12); 135 } 136 122 137 TextAdapter getAdapter (char[] text, int col) { 123 138 TextAdapter a; mde/gui/widget/Floating.d
r92 r95 54 54 * additionally an (x,y) coordinate for each subwidget (all x coords first, then all y coords). 55 55 */ 56 class FloatingAreaWidget : ParentWidget56 class FloatingAreaWidget : AParentWidget 57 57 { 58 58 this (IWidgetManager mgr, widgetID id, WidgetData data) { mde/gui/widget/Ifaces.d
r93 r95 152 152 /** Called on all widgets after all widgets have been created in a deepest first order. 153 153 * 154 * Must be called before any other methods on the widget, which means this cannot call sub-155 * widgets' methods, but finalizecan. */154 * finalize must be called before any other methods on the widget, which means this() cannot 155 * call sub-widgets' methods, but finalize() can. */ 156 156 void prefinalize (); 157 157 void finalize (); /// ditto mde/gui/widget/TextWidget.d
r94 r95 33 33 } 34 34 35 /// Basic text widget 36 class TextLabelWidget : Widget 35 /** Base text widget. 36 * 37 * Little use currently except to ease future additions. */ 38 class ATextWidget : AWidget 37 39 { 38 /** Constructor for a widget containing [fixed] content. 39 * 40 * Widget uses the initialisation data: 41 * [widgetID, contentID, colour] 42 * where contentID is an ID for the string ID of the contained content 43 * and colour is an 8-bit-per-channel RGB colour of the form 0xRRGGBB. */ 40 /** Set the adapter first: 41 * adapter = mgr.renderer.getAdapter ("string", 0xRRGGBB); */ 44 42 this (IWidgetManager mgr, widgetID id, WidgetData data) { 45 WDCheck (data, 2, 1);46 adapter = mgr.renderer.getAdapter (data.strings[0], data.ints[1]);47 43 adapter.getDimensions (mw, mh); 48 44 super (mgr, id, data); … … 58 54 } 59 55 56 57 /// Basic text widget 58 class TextLabelWidget : ATextWidget 59 { 60 /** Constructor for a widget containing [fixed] content. 61 * 62 * Widget uses the initialisation data: 63 * [widgetID, contentID, colour] 64 * where contentID is an ID for the string ID of the contained content 65 * and colour is an 8-bit-per-channel RGB colour of the form 0xRRGGBB. */ 66 this (IWidgetManager mgr, widgetID id, WidgetData data) { 67 WDCheck (data, 2, 1); 68 adapter = mgr.renderer.getAdapter (data.strings[0], data.ints[1]); 69 super (mgr, id, data); 70 } 71 } 72 60 73 /// Basic widget displaying a label from a content. 61 class ContentLabelWidget : Widget74 class ContentLabelWidget : ATextWidget 62 75 { 63 76 this (IWidgetManager mgr, widgetID id, WidgetData data, IContent c) { … … 65 78 WDCheck (data, 3, 0); 66 79 content = c; 80 if (!content) throw new ContentException (); 67 81 index = data.ints[1]; 68 82 adapter = mgr.renderer.getAdapter (content.toString(index), data.ints[2]); 69 adapter.getDimensions (mw, mh);70 83 super (mgr, id,data); 71 84 } 72 85 73 void draw () {74 super.draw();75 adapter.draw (x,y);76 }77 78 86 protected: 79 IRenderer.TextAdapter adapter;80 87 IContent content; 81 88 int index; mde/gui/widget/Widget.d
r93 r95 20 20 * inheriting one of them is by no means necessary for a widget so long as the IWidget interface 21 21 * is implemented. 22 * 23 * Abstract widget classes have an 'A' prepended to the name, similar to the 'I' convention for 24 * interfaces. 22 25 *************************************************************************************************/ 23 26 module mde.gui.widget.Widget; … … 42 45 * implement IWidget); they are simply provided for convenience and to promote code reuse. 43 46 *************************************************************************************************/ 44 abstract class Widget : IChildWidget47 abstract class AWidget : IChildWidget 45 48 { 46 49 //BEGIN Load and save 47 50 // Base this() for child Widgets. 48 this (IWidgetManager mgr, widgetID id, WidgetData) {51 protected this (IWidgetManager mgr, widgetID id, WidgetData) { 49 52 this.mgr = mgr; 50 53 this.id = id; … … 156 159 * An abstract base widget class for parent widgets. 157 160 *************************************************************************************************/ 158 abstract class ParentWidget :Widget161 abstract class AParentWidget : AWidget 159 162 { 160 163 this (IWidgetManager mgr, widgetID id, WidgetData data) { … … 178 181 179 182 /** A base for fixed-size widgets taking their size from the creation data. */ 180 class FixedWidget : Widget {183 class FixedWidget : AWidget { 181 184 // Check data.length is at least 3 before calling! 182 185 /** Constructor for a fixed-size [blank] widget. … … 187 190 this (IWidgetManager mgr, widgetID id, WidgetData data) { 188 191 super (mgr, id, data); 189 mw = cast(wdim) data.ints[1]; 190 mh = cast(wdim) data.ints[2]; 191 w = mw; 192 h = mh; 192 w = mw = cast(wdim) data.ints[1]; 193 h = mh = cast(wdim) data.ints[2]; 193 194 } 194 195 } 195 196 196 197 /** A base for resizable widgets. */ 197 class SizableWidget : Widget {198 class SizableWidget : AWidget { 198 199 // Check data.length is at least 1 before calling! 199 200 /// Constructor for a completely resizable [blank] widget. … … 205 206 bool isHSizable () { return true; } 206 207 } 208 209 /** For pressable buttons. 210 * 211 * Normally overriding classes implement this, draw and activated. */ 212 abstract class AButtonWidget : AWidget 213 { 214 protected this (IWidgetManager mgr, widgetID id, WidgetData data) { 215 super (mgr, id, data); 216 } 217 218 /// May be over-ridden. Pushed is true if the button has been pushed and not released. 219 void draw () { 220 mgr.renderer.drawButton (x,y, w,h, pushed); 221 } 222 223 /// Handles the down-click 224 void clickEvent (wdabs, wdabs, ubyte b, bool state) { 225 if (b == 1 && state == true) { 226 pushed = true; 227 mgr.requestRedraw; 228 mgr.addClickCallback (&clickWhilePushed); 229 mgr.addMotionCallback (&motionWhilePushed); 230 } 231 } 232 233 /// Called when a mouse click event occurs while held; handles up-click 234 bool clickWhilePushed (wdabs cx, wdabs cy, ubyte b, bool state) { 235 if (b == 1 && state == false) { 236 if (cx >= x && cx < x+w && cy >= y && cy < y+h) // button event 237 activated(); 238 239 pushed = false; 240 mgr.requestRedraw; 241 mgr.removeCallbacks (cast(void*) this); 242 243 return true; 244 } 245 return false; 246 } 247 /// Called when a mouse motion event occurs while held; handles pushing in/out on hover 248 void motionWhilePushed (wdabs cx, wdabs cy) { 249 bool oldPushed = pushed; 250 if (cx >= x && cx < x+w && cy >= y && cy < y+h) pushed = true; 251 else pushed = false; 252 if (oldPushed != pushed) 253 mgr.requestRedraw; 254 } 255 256 /// The action triggered when the button is clicked... 257 void activated (); 258 259 protected: 260 bool pushed = false; /// True if button is pushed in (visually) 261 } 262 263 mde/gui/widget/createWidget.d
r91 r95 28 28 import mde.gui.widget.miscWidgets; 29 29 import mde.gui.widget.TextWidget; 30 import mde.gui.widget.miscContent; 30 31 import mde.gui.widget.Floating; 31 32 import tango.util.log.Log : Log, Logger; … … 57 58 int type = data.ints[0]; // type is first element of data 58 59 59 //pragma (msg, binarySearch ("type", WIDGETS)); 60 mixin (binarySearch ("type", WIDGETS)); // creates widget by type: new XWidget (mgr, data [, parent]); 60 try { 61 //pragma (msg, binarySearch ("type", WIDGETS)); 62 mixin (binarySearch ("type", WIDGETS)); // creates widget by type: new XWidget (mgr, data [, parent]); 63 // Not returned a new widget or thrown: 64 logger.error ("Bad widget type: {}; creating a debug widget instead",type); 65 } catch (Exception e) { 66 logger.error ("Error creating widget: {}; creating a debug widget instead.", e.msg); 67 } 61 68 62 // Not returned a new widget...63 logger.error ("Bad widget type: {}; creating a debug widget instead.",type);64 69 return new DebugWidget (mgr, id, data); 65 70 } … … 78 83 /// Widget types. 79 84 enum WIDGET_TYPE : int { 85 FUNCTION = 0x2000, // Function called instead of widget created (no "Widget" appended to fct name) 80 86 TAKES_CONTENT = 0x4000, // Flag indicates widget's this should be passed an IContent reference. 81 87 PARENT = 0x8000, // widget can have children; not used by code (except in data files) … … 96 102 TextLabel = 0x21, 97 103 104 // content editables: 0x30 105 editContent = FUNCTION | TAKES_CONTENT | 0x30, 106 BoolContent = TAKES_CONTENT | 0x31, 107 98 108 GridLayout = TAKES_CONTENT | PARENT | 0x100, 99 109 TrialContentLayout = PARENT | 0x110, … … 112 122 "TextLabel", 113 123 "ContentLabel", 124 "BoolContent", 125 "editContent", 114 126 "TrialContentLayout", 115 127 "FloatingArea", … … 129 141 ret ~= "if (" ~ var ~ " == WIDGET_TYPE." ~ c ~ ") {\n" ~ 130 142 " debug (mdeWidgets) logger.trace (\"Creating new "~c~"Widget.\");\n" ~ 131 " static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.TAKES_CONTENT)\n" ~ 143 " static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.FUNCTION)\n" ~ 144 " return " ~ c ~ " (mgr, id, data, content);\n" ~ 145 " else static if (WIDGET_TYPE."~c~" & WIDGET_TYPE.TAKES_CONTENT)\n" ~ 132 146 " return new " ~ c ~ "Widget (mgr, id, data, content);\n" ~ 133 147 " else\n" ~ mde/gui/widget/layout.d
r94 r95 107 107 if ((rows = optsList.list.length) > 0) { 108 108 // Get all sub-widgets 109 subWidgets.length = rows *cols;109 subWidgets.length = rows; 110 110 foreach (i, c; optsList.list) { 111 111 subWidgets[i] = mgr.makeWidget (data.strings[0], c); … … 140 140 * The grid has no border but has spacing between widgets. 141 141 *************************************************************************************************/ 142 abstract class GridWidget : ParentWidget142 abstract class GridWidget : AParentWidget 143 143 { 144 144 //BEGIN Creation & saving … … 275 275 } 276 276 277 private: 278 //BEGIN Cache calculation functions 277 package: 279 278 /* Calculations which need to be run whenever a new sub-widget structure is set 280 279 * (i.e. to produce cached data calculated from construction data). … … 321 320 } 322 321 } 323 //END Cache calculation functions 324 325 322 323 private: 326 324 void setColWidth (myIt i, wdim w, int dir) { 327 325 for (myIt j = 0; j < rows; ++j) { … … 386 384 * callback functions are used to adjust the width of any column. 387 385 *************************************************************************************************/ 388 class AlignColumns386 package class AlignColumns 389 387 { 390 388 /** Instance returned will be shared with any other widgets of same widgetID. … … 396 394 if (p.minWidth.length != columns) 397 395 throw new GuiException ("AlignColumns: no. of columns varies between sharing widgets (code error)"); 396 //logger.trace ("Shared alignment for: "~id); 398 397 return *p; 399 398 } else { … … 418 417 void reset (myIt columns) { 419 418 if (columns < 1) 420 throw new GuiException("AlignColumns: created with <1 column ");419 throw new GuiException("AlignColumns: created with <1 column (code error)"); 421 420 minWidth = new wdim[columns]; 422 421 sizable = new bool[columns]; … … 424 423 firstSizable = -1; 425 424 lastSizable = -1; 426 spare = 0; 427 } 428 429 /** Initialize widths as minimal widths. */ 430 void setWidths () { 425 } 426 427 /** Initialize widths, either from minWidths or from supplied list, checking validity. 428 * 429 * Also calculates first/lastSizable from sizable, overall minimal width and column positions. 430 */ 431 void setWidths (wdim[] data = null) { 431 432 if (!width) { 432 width = minWidth.dup; 433 initCalc; 434 } 435 } 436 /** Initialize widths from supplied list, checking validity. */ 437 void setWidths (wdim[] data) { 438 if (!width) { 439 // Set to provided data: 440 width = data; 441 // And check sizes are valid: 442 foreach (i, m; minWidth) { 443 // if fixed width or width is less than minimum: 444 if (!sizable[i] || width[i] < m) { 445 width[i] = m; 433 if (data) { 434 debug assert (data.length == minWidth.length, "setWidths called with bad data length (code error)"); 435 width = data.dup; // data is shared by other widgets with same id so must be .dup'ed 436 // And check sizes are valid: 437 foreach (i, m; minWidth) { 438 if (!sizable[i] || width[i] < m) // if width is fixed or less than minimum 439 width[i] = m; 440 } 441 } else 442 width = minWidth.dup; 443 444 /* Calculate the minimal width of all columns plus spacing. */ 445 mw = spacing * cast(wdim)(minWidth.length - 1); 446 foreach (imw; minWidth) 447 mw += imw; 448 449 genPositions; 450 451 foreach (i,s; sizable) { 452 if (s) { 453 firstSizable = i; 454 goto gotFirst; 446 455 } 447 456 } 448 initCalc; 457 return; // none resizable - don't search for lastSizable 458 gotFirst: 459 foreach_reverse (i,s; sizable) { 460 if (s) { 461 lastSizable = i; 462 return; // done 463 } 464 } 449 465 } 450 466 } … … 463 479 * 464 480 * returns: 465 * -i if in space to left of col i, or i if on col i, or -(num cols + 1) if in $(I spare) 466 * space to right of last column. */ 481 * -i if in space to left of col i, or i if on col i. */ 467 482 myDiff getCell (wdim l) { 483 debug assert (width, "AlignColumns not initialized when getCell called (code error)"); 468 484 myDiff i = minWidth.length - 1; // starting from right... 469 485 while (l < pos[i]) { // decrement while left of this column … … 471 487 --i; 472 488 } // now (l >= pos[i]) 473 if (l >= pos[i] + width[i]) { // between columns or in spare space after last column 474 debug assert (i+1 < minWidth.length || 475 l < pos[i] + width[i] + spare, 476 "getCell: l >= total width (code error)"); 489 if (l >= pos[i] + width[i]) { // between columns 490 debug assert (i+1 < minWidth.length, "getCell: l >= total width (code error)"); 477 491 return -i - 1; // note: i might be 0 so cannot just return -i 478 492 } … … 484 498 * nw should be at least the minimal width. */ 485 499 wdim resizeWidth (wdim nw, int dir) { 500 debug assert (width, "AlignColumns not initialized when resizeWidth called (code error)"); 486 501 if (nw < mw) { 487 502 debug logger.warn ("Widget dimension set below minimal"); … … 491 506 492 507 wdim diff = nw - w; 493 if (firstSizable == -1) { 494 spare += diff; 495 w = nw; 496 } else 497 adjustCellSizes (diff, (dir == -1 ? lastSizable : firstSizable), dir); 508 if (firstSizable == -1) 509 diff = adjustCellSizes (diff, minWidth.length-1, -1); 510 else 511 diff = adjustCellSizes (diff, (dir == -1 ? lastSizable : firstSizable), dir); 498 512 499 513 debug if (nw != w) { 500 logger.trace ("resizeWidth to {} failed, new width: {}",nw,w);514 logger.trace ("resizeWidth on {} to {} failed, new width: {}, diff {}, firstSizable {}, columns {}",cast(void*)this, nw,w, diff, firstSizable, minWidth.length); 501 515 /+ Also print column widths & positions: 502 516 logger.trace ("resizeWidth to {} failed! Column dimensions and positions:",nw); … … 512 526 bool findResizeCols (wdim l) { 513 527 resizeU = -getCell (l); // potential start for upward-resizes 514 if (resizeU <= 0 || resizeU > minWidth.length)515 return true; // not on a space between cells or in spare space after last cell528 if (resizeU <= 0) 529 return true; // not on a space between cells 516 530 resizeD = resizeU - 1; // potential start for downward-resizes 517 531 … … 546 560 diff = -adjustCellSizes (diff, resizeD, -1); 547 561 adjustCellSizes (diff, resizeU, 1); 548 }549 }550 551 /** Intitialization triggered by setWidths.552 *553 * Calculates first/lastSizable from sizable, minimal width and positions. */554 private void initCalc () {555 /* Calculate the minimal width of all columns plus spacing. */556 mw = spacing * cast(wdim)(minWidth.length - 1);557 foreach (w; minWidth)558 mw += w;559 560 genPositions;561 foreach (i,s; sizable) {562 if (s) {563 firstSizable = i;564 goto gotFirst;565 }566 }567 return; // none resizable - don't search for lastSizable568 gotFirst:569 570 foreach_reverse (i,s; sizable) {571 if (s) {572 lastSizable = i;573 return; // done574 }575 562 } 576 563 } … … 633 620 // rd is remainder to decrease by 634 621 635 636 bool it = true; // iterate (force first time) 637 while (it) { 622 do { 638 623 i += incr; 639 624 if (i < 0 || i >= minWidth.length) { // run out of next cells … … 641 626 break aCSwhile; // exception: Array index out of bounds 642 627 } 643 it = !sizable[i]; // iterate again if row/col isn't resizable 644 } 628 } while (!sizable[i]) // iterate again if row/col isn't resizable 645 629 } 646 630 } … … 665 649 /** Current width, relative position (for each column) 666 650 * 667 * Treat as READ ONLY ! */651 * Treat as READ ONLY outside this class! */ 668 652 wdim[] width; // only adjusted within the class 669 653 wdim[] pos; /// ditto 670 protected:654 protected: 671 655 myDiff resizeD, // resizeCols works down from this index (<0 if not resizing) 672 656 resizeU; // and up from this index 673 657 wdim spacing; // used by genPositions (which cannot access the layout class's data) 674 wdim spare; // fixed size only: extra blank space filler675 658 wdim w,mw; // current & minimal widths 676 659 /* indicies of the first/last resizable column (negative if none are resizable). */ mde/gui/widget/miscWidgets.d
r91 r95 77 77 78 78 /// First interactible widget 79 class ButtonWidget : FixedWidget79 class ButtonWidget : AButtonWidget 80 80 { 81 bool pushed = false; // true if button is pushed in (visually)82 // pushed is not the same as the button being clicked but not yet released.83 // it is whether the mouse is over the button after being clicked.84 85 81 this (IWidgetManager mgr, widgetID id, WidgetData data) { 86 82 WDCheck (data, 3); 83 w = mw = cast(wdim) data.ints[1]; 84 h = mh = cast(wdim) data.ints[2]; 87 85 super (mgr, id, data); 88 86 } 89 87 90 void draw () { 91 mgr.renderer.drawButton (x,y, w,h, pushed); 92 } 93 94 void clickEvent (wdabs, wdabs, ubyte b, bool state) { 95 if (b == 1 && state == true) { 96 pushed = true; 97 mgr.requestRedraw; 98 mgr.addClickCallback (&clickWhileHeld); 99 mgr.addMotionCallback (&motionWhileHeld); 100 } 101 } 102 // Called when a mouse motion/click event occurs while (held == true) 103 bool clickWhileHeld (wdabs cx, wdabs cy, ubyte b, bool state) { 104 if (b == 1 && state == false) { 105 if (cx >= x && cx < x+w && cy >= y && cy < y+h) // button event 106 Stdout ("Button clicked!").newline; 107 108 pushed = false; 109 mgr.requestRedraw; 110 mgr.removeCallbacks (cast(void*) this); 111 112 return true; 113 } 114 return false; 115 } 116 void motionWhileHeld (wdabs cx, wdabs cy) { 117 bool oldPushed = pushed; 118 if (cx >= x && cx < x+w && cy >= y && cy < y+h) pushed = true; 119 else pushed = false; 120 if (oldPushed != pushed) 121 mgr.requestRedraw; 88 void activated () { 89 Stdout ("Button clicked!").newline; 122 90 } 123 91 } mde/imde.d
r75 r95 14 14 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 15 16 /** This module is for interfacing with the mde.mde module and some global items. */ 16 /** This module is for interfacing with the mde.mde module (or other module containing main()) and 17 * some global items. */ 17 18 module mde.imde; 18 19 mde/input/joystick.d
r89 r95 55 55 foreach (js; joysticks) { 56 56 // NOTE: This sometimes causes a SIGSEGV (Address boundary error) when init fails. 57 debug logger.trace ("Calling SDL_JoystickClose"); 57 58 if(js !is null) SDL_JoystickClose(js); // only close if successfully opened 58 59 } mde/lookup/Options.d
r94 r95 82 82 // the supported types simply by changing this list now (untested). 83 83 template store(A...) { alias A store; } 84 alias store!(int, double, char[]) TYPES;//FIXME removed bool 84 alias store!(bool, int, double, char[]) TYPES; 85 alias store!(int, double, char[]) TYPES2; 85 86 //BEGIN Templates: internal 86 87 private { … … 123 124 if (p) { 124 125 auto q = cast(BoolContent) (*p); 125 if (q) q = parseTo!(`~T.stringof~`) (dt);126 if (q) q.v = parseTo!(`~T.stringof~`) (dt); 126 127 } 127 128 }`; … … 135 136 else 136 137 const char[] addTagMixin = ifBlock; 137 }138 139 // For writeAll140 template writeAllMixin(A...) {141 static if (A.length) {142 const char[] writeAllMixin =143 `foreach (ID id, `~A[0].stringof~`* val; opts`~TName!(A[0])~`) dlg ("`~A[0].stringof~`", id, parseFrom!(`~A[0].stringof~`) (*val));` ~ writeAllMixin!(A[1..$]);144 } else145 const char[] writeAllMixin = ``;146 138 } 147 139 … … 289 281 char[][] list () { 290 282 char[][] ret; 291 mixin (listMixin!(TYPES ));283 mixin (listMixin!(TYPES2)); 292 284 return ret; 293 285 } … … 306 298 307 299 // The "pointer lists", e.g. char[]*[ID] optscharA; 308 mixin (PLists!(TYPES )); //FIXME adds unused optsbool300 mixin (PLists!(TYPES2)); //FIXME 309 301 ValueContent[char[]] opts; // generic list of option values 310 302 } … … 314 306 mixin(addTagMixin!(TYPES).addTagMixin); 315 307 } 316
