Changeset 95:2a364c7d82c9

Show
Ignore:
Timestamp:
11/06/08 06:07:18 (2 months ago)
Author:
Diggory Hardy <diggory.hardy@gmail.com>
branch:
default
Message:

Boolean options can be adjusted from the gui now (using a very basic widget). Also some bug-fixes.

Fixed a minor bug where layouts with the same id but without shared alignments would be messed up.
Tracked down the "nothing trawn until a resize" bug (see jobs.txt).
If widgets throw during creation they're now replaced by debug widgets.
Function pointers are converted to delegates using a safer method.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • codeDoc/jobs.txt

    r91 r95  
    88 
    99Bugs: 
    10 Sometimes nothing is drawn until a resize, and fonts are blocks? External bug? Info: doesn't happen when limited to one thread
     10Sometimes 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
    1111 
    1212 
     
    1414To do (importance 0-5: 0 pointless, 1 no obvious impact now, 2 todo sometime, 3 useful, 4 important, 5 urgent): 
    1515Also 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) 
    18163   Use of dtors - don't rely on them? Or what happens when init throws during creation - relying on undefined behaviour. 
    19173   glBindTexture not working with non-0 index - perhaps use a higher level graphics library at some point. 
  • data/L10n/FontOptions.mtt

    r51 r95  
    11{MT01} 
    22{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  
    11{MT01} 
    22{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  
    88<WidgetData|button={0:[0x10,50,50]}> 
    99<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"]}> 
    1212<WidgetData|optBox={0:[0xC100,1,1,3],1:["optName","optSep","optVal"]}> 
    1313<WidgetData|optName={0:[0x4020, 1, 0xfe8c00]}> 
    1414<WidgetData|optDesc={0:[0x4020, 2, 0xaf6000]}> 
    15 <WidgetData|optVal={0:[0x4020, 0, 0xBF00]}> 
     15<WidgetData|optVal={0:[0x6030]}> 
    1616<WidgetData|optSep={0:[0x21, 0xff],1:["="]}> 
    1717<WidgetData|floating={0:[0x8200,20,20],1:["text"]}> 
  • data/conf/options.mtt

    r94 r95  
    1717<bool|fullscreen=false> 
    1818<int|screenW=1280> 
     19<int|screenH=1024> 
    1920<int|windowW=800> 
    20 <int|screenH=1024> 
    2121<int|windowH=600> 
    2222 
  • examples/guiDemo.d

    r85 r95  
    6868     * Note: probably drawing should start at the beginning of the loop and glFlush()/swapBuffers 
    6969     * be called at the end to optimise. */ 
    70     mainSchedule.add (SCHEDULE.DRAW, &Screen.draw); // Draw, per event only. 
     70    mainSchedule.add (SCHEDULE.DRAW, &Screen.draw).request = true;      // Draw, per event and first frame only. 
    7171    mainSchedule.add (mainSchedule.getNewID, &mde.events.pollEvents).frame = true; 
    7272    //END Main loop setup 
  • mde/gui/content/Content.d

    r94 r95  
    9595class BoolContent : ValueContent 
    9696{ 
    97     this () {} 
    98     this (bool val) { 
     97    /** Create a content with _symbol name symbol. */ 
     98    this (char[] symbol, bool val = false) { 
     99        symb = symbol; 
    99100        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; 
    100107    } 
    101108     
    102109    /// Get the text. 
    103110    char[] toString (uint i) { 
    104         debug logger.trace ("BoolContent.toString"); 
    105111        return (i == 0) ? v ? "true" : "false" 
    106112             : (i == 1) ? name_ 
     
    111117    void opAssign (bool val) { 
    112118        v = val; 
     119        foreach (cb; cngCb) 
     120            cb(symb, val); 
    113121    } 
    114122    bool opCall () { 
     
    116124    } 
    117125     
    118     protected bool v; 
     126    bool v;     //FIXME: should be protected but Options needs to set without calling callbacks 
     127protected: 
     128    char[] symb; 
     129    void delegate (char[],bool)[] cngCb;       // change callbacks 
    119130} 
    120131 
  • mde/gui/content/options.d

    r94 r95  
    2626import mde.lookup.Translation; 
    2727 
    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     } 
     28import tango.util.log.Log : Log, Logger; 
     29private Logger logger; 
     30static this () { 
     31    logger = Log.getLogger ("mde.gui.content.options"); 
    3432} 
    3533 
  • mde/gui/renderer/IRenderer.d

    r93 r95  
    7777     * restriction. */ 
    7878    void restrict (wdim x, wdim y, wdim w, wdim h); 
    79      
    80     /** See restrict. */ 
    81     void relax (); 
     79    void relax ();      /// ditto 
    8280     
    8381    /** Draw a window border plus background. */ 
     
    9391    void drawButton (wdim x, wdim y, wdim w, wdim h, bool pushed); 
    9492     
    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); 
    97103     
    98104    /** For drawing text - one instance per string. 
  • mde/gui/renderer/SimpleRenderer.d

    r93 r95  
    120120    } 
    121121     
     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     
    122137    TextAdapter getAdapter (char[] text, int col) { 
    123138        TextAdapter a; 
  • mde/gui/widget/Floating.d

    r92 r95  
    5454 * additionally an (x,y) coordinate for each subwidget (all x coords first, then all y coords). 
    5555 */ 
    56 class FloatingAreaWidget : ParentWidget 
     56class FloatingAreaWidget : AParentWidget 
    5757{ 
    5858    this (IWidgetManager mgr, widgetID id, WidgetData data) { 
  • mde/gui/widget/Ifaces.d

    r93 r95  
    152152    /** Called on all widgets after all widgets have been created in a deepest first order. 
    153153     * 
    154      * Must be called before any other methods on the widget, which means this cannot call sub- 
    155      * widgets' methods, but finalize can. */ 
     154     * finalize must be called before any other methods on the widget, which means this() cannot 
     155     * call sub-widgets' methods, but finalize() can. */ 
    156156    void prefinalize (); 
    157157    void finalize ();   /// ditto 
  • mde/gui/widget/TextWidget.d

    r94 r95  
    3333} 
    3434 
    35 /// Basic text widget 
    36 class TextLabelWidget : Widget 
     35/** Base text widget. 
     36 * 
     37 * Little use currently except to ease future additions. */ 
     38class ATextWidget : AWidget 
    3739{ 
    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); */ 
    4442    this (IWidgetManager mgr, widgetID id, WidgetData data) { 
    45         WDCheck (data, 2, 1); 
    46         adapter = mgr.renderer.getAdapter (data.strings[0], data.ints[1]); 
    4743        adapter.getDimensions (mw, mh); 
    4844        super (mgr, id, data); 
     
    5854} 
    5955 
     56 
     57/// Basic text widget 
     58class 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 
    6073/// Basic widget displaying a label from a content. 
    61 class ContentLabelWidget : Widget 
     74class ContentLabelWidget : ATextWidget 
    6275{ 
    6376    this (IWidgetManager mgr, widgetID id, WidgetData data, IContent c) { 
     
    6578        WDCheck (data, 3, 0); 
    6679        content = c; 
     80        if (!content) throw new ContentException (); 
    6781        index = data.ints[1]; 
    6882        adapter = mgr.renderer.getAdapter (content.toString(index), data.ints[2]); 
    69         adapter.getDimensions (mw, mh); 
    7083        super (mgr, id,data); 
    7184    } 
    7285     
    73     void draw () { 
    74         super.draw(); 
    75         adapter.draw (x,y); 
    76     } 
    77      
    7886protected: 
    79     IRenderer.TextAdapter adapter; 
    8087    IContent content; 
    8188    int index; 
  • mde/gui/widget/Widget.d

    r93 r95  
    2020 * inheriting one of them is by no means necessary for a widget so long as the IWidget interface 
    2121 * is implemented. 
     22 *  
     23 * Abstract widget classes have an 'A' prepended to the name, similar to the 'I' convention for 
     24 * interfaces. 
    2225 *************************************************************************************************/ 
    2326module mde.gui.widget.Widget; 
     
    4245 * implement IWidget); they are simply provided for convenience and to promote code reuse. 
    4346 *************************************************************************************************/ 
    44 abstract class Widget : IChildWidget 
     47abstract class AWidget : IChildWidget 
    4548{ 
    4649//BEGIN Load and save 
    4750    // Base this() for child Widgets. 
    48     this (IWidgetManager mgr, widgetID id, WidgetData) { 
     51    protected this (IWidgetManager mgr, widgetID id, WidgetData) { 
    4952        this.mgr = mgr; 
    5053        this.id = id; 
     
    156159* An abstract base widget class for parent widgets. 
    157160*************************************************************************************************/ 
    158 abstract class ParentWidget : Widget 
     161abstract class AParentWidget : AWidget 
    159162{ 
    160163    this (IWidgetManager mgr, widgetID id, WidgetData data) { 
     
    178181 
    179182/** A base for fixed-size widgets taking their size from the creation data. */ 
    180 class FixedWidget : Widget { 
     183class FixedWidget : AWidget { 
    181184    // Check data.length is at least 3 before calling! 
    182185    /** Constructor for a fixed-size [blank] widget. 
     
    187190    this (IWidgetManager mgr, widgetID id, WidgetData data) { 
    188191        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]; 
    193194    } 
    194195} 
    195196 
    196197/** A base for resizable widgets. */ 
    197 class SizableWidget : Widget { 
     198class SizableWidget : AWidget { 
    198199    // Check data.length is at least 1 before calling! 
    199200    /// Constructor for a completely resizable [blank] widget. 
     
    205206    bool isHSizable () {    return true;    } 
    206207} 
     208 
     209/** For pressable buttons. 
     210 * 
     211 * Normally overriding classes implement this, draw and activated. */ 
     212abstract 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     
     259protected: 
     260    bool pushed = false;        /// True if button is pushed in (visually) 
     261} 
     262 
     263 
  • mde/gui/widget/createWidget.d

    r91 r95  
    2828import mde.gui.widget.miscWidgets; 
    2929import mde.gui.widget.TextWidget; 
     30import mde.gui.widget.miscContent; 
    3031import mde.gui.widget.Floating; 
    3132import tango.util.log.Log : Log, Logger; 
     
    5758    int type = data.ints[0];    // type is first element of data 
    5859     
    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    } 
    6168     
    62     // Not returned a new widget... 
    63     logger.error ("Bad widget type: {}; creating a debug widget instead.",type); 
    6469    return new DebugWidget (mgr, id, data); 
    6570} 
     
    7883/// Widget types. 
    7984enum WIDGET_TYPE : int { 
     85    FUNCTION                = 0x2000,   // Function called instead of widget created (no "Widget" appended to fct name) 
    8086    TAKES_CONTENT           = 0x4000,   // Flag indicates widget's this should be passed an IContent reference. 
    8187    PARENT                  = 0x8000,   // widget can have children; not used by code (except in data files) 
     
    96102    TextLabel               = 0x21, 
    97103     
     104    // content editables: 0x30 
     105    editContent             = FUNCTION | TAKES_CONTENT | 0x30, 
     106    BoolContent             = TAKES_CONTENT | 0x31, 
     107     
    98108    GridLayout              = TAKES_CONTENT | PARENT | 0x100, 
    99109    TrialContentLayout      = PARENT | 0x110, 
     
    112122        "TextLabel", 
    113123        "ContentLabel", 
     124        "BoolContent", 
     125        "editContent", 
    114126        "TrialContentLayout", 
    115127        "FloatingArea", 
     
    129141            ret ~=  "if (" ~ var ~ " == WIDGET_TYPE." ~ c ~ ") {\n" ~ 
    130142                    "   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" ~ 
    132146                    "       return new " ~ c ~ "Widget (mgr, id, data, content);\n" ~ 
    133147                    "   else\n" ~ 
  • mde/gui/widget/layout.d

    r94 r95  
    107107        if ((rows = optsList.list.length) > 0) { 
    108108            // Get all sub-widgets 
    109             subWidgets.length = rows*cols
     109            subWidgets.length = rows
    110110            foreach (i, c; optsList.list) { 
    111111                subWidgets[i] = mgr.makeWidget (data.strings[0], c); 
     
    140140 * The grid has no border but has spacing between widgets. 
    141141 *************************************************************************************************/ 
    142 abstract class GridWidget : ParentWidget 
     142abstract class GridWidget : AParentWidget 
    143143{ 
    144144    //BEGIN Creation & saving 
     
    275275    } 
    276276     
    277 private: 
    278     //BEGIN Cache calculation functions 
     277package: 
    279278    /* Calculations which need to be run whenever a new sub-widget structure is set 
    280279     * (i.e. to produce cached data calculated from construction data). 
     
    321320        } 
    322321    } 
    323     //END Cache calculation functions 
    324      
    325      
     322     
     323private: 
    326324    void setColWidth (myIt i, wdim w, int dir) { 
    327325        for (myIt j = 0; j < rows; ++j) { 
     
    386384 * callback functions are used to adjust the width of any column. 
    387385 *************************************************************************************************/ 
    388 class AlignColumns 
     386package class AlignColumns 
    389387{ 
    390388    /** Instance returned will be shared with any other widgets of same widgetID. 
     
    396394            if (p.minWidth.length != columns) 
    397395                throw new GuiException ("AlignColumns: no. of columns varies between sharing widgets (code error)"); 
     396            //logger.trace ("Shared alignment for: "~id); 
    398397            return *p; 
    399398        } else { 
     
    418417    void reset (myIt columns) { 
    419418        if (columns < 1) 
    420             throw new GuiException("AlignColumns: created with <1 column"); 
     419            throw new GuiException("AlignColumns: created with <1 column (code error)"); 
    421420        minWidth = new wdim[columns]; 
    422421        sizable = new bool[columns]; 
     
    424423        firstSizable = -1; 
    425424        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) { 
    431432        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; 
    446455                } 
    447456            } 
    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            } 
    449465        } 
    450466    } 
     
    463479     * 
    464480     * 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. */ 
    467482    myDiff getCell (wdim l) { 
     483        debug assert (width, "AlignColumns not initialized when getCell called (code error)"); 
    468484        myDiff i = minWidth.length - 1;     // starting from right... 
    469485        while (l < pos[i]) {                // decrement while left of this column 
     
    471487            --i; 
    472488        }                                   // 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)"); 
    477491            return -i - 1;                  // note: i might be 0 so cannot just return -i 
    478492        } 
     
    484498     * nw should be at least the minimal width. */ 
    485499    wdim resizeWidth (wdim nw, int dir) { 
     500        debug assert (width, "AlignColumns not initialized when resizeWidth called (code error)"); 
    486501        if (nw < mw) { 
    487502            debug logger.warn ("Widget dimension set below minimal"); 
     
    491506         
    492507        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); 
    498512         
    499513        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); 
    501515            /+ Also print column widths & positions: 
    502516            logger.trace ("resizeWidth to {} failed! Column dimensions and positions:",nw); 
     
    512526    bool findResizeCols (wdim l) { 
    513527        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 cell 
     528        if (resizeU <= 0
     529            return true;        // not on a space between cells 
    516530        resizeD = resizeU - 1;              // potential start for downward-resizes 
    517531         
     
    546560            diff = -adjustCellSizes (diff, resizeD, -1); 
    547561            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 lastSizable 
    568         gotFirst: 
    569          
    570         foreach_reverse (i,s; sizable) { 
    571             if (s) { 
    572                 lastSizable = i; 
    573                 return; // done 
    574             } 
    575562        } 
    576563    } 
     
    633620                // rd is remainder to decrease by 
    634621                 
    635                  
    636                 bool it = true;     // iterate (force first time) 
    637                 while (it) { 
     622                do { 
    638623                    i += incr; 
    639624                    if (i < 0 || i >= minWidth.length) {    // run out of next cells 
     
    641626                        break aCSwhile;     // exception: Array index out of bounds 
    642627                    } 
    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 
    645629            } 
    646630        } 
     
    665649    /** Current width, relative position (for each column) 
    666650     * 
    667      * Treat as READ ONLY! */ 
     651     * Treat as READ ONLY outside this class! */ 
    668652    wdim[]  width;              // only adjusted within the class 
    669653    wdim[]  pos;                /// ditto 
    670     protected: 
     654protected: 
    671655    myDiff  resizeD,            // resizeCols works down from this index (<0 if not resizing) 
    672656            resizeU;            // and up from this index 
    673657    wdim    spacing;            // used by genPositions (which cannot access the layout class's data) 
    674     wdim    spare;              // fixed size only: extra blank space filler 
    675658    wdim    w,mw;               // current & minimal widths 
    676659    /* indicies of the first/last resizable column (negative if none are resizable). */ 
  • mde/gui/widget/miscWidgets.d

    r91 r95  
    7777 
    7878/// First interactible widget 
    79 class ButtonWidget : FixedWidget 
     79class ButtonWidget : AButtonWidget 
    8080{ 
    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      
    8581    this (IWidgetManager mgr, widgetID id, WidgetData data) { 
    8682        WDCheck (data, 3); 
     83        w = mw = cast(wdim) data.ints[1]; 
     84        h = mh = cast(wdim) data.ints[2]; 
    8785        super (mgr, id, data); 
    8886    } 
    8987     
    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; 
    12290    } 
    12391} 
  • mde/imde.d

    r75 r95  
    1414along with this program.  If not, see <http://www.gnu.org/licenses/>. */ 
    1515 
    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. */ 
    1718module mde.imde; 
    1819 
  • mde/input/joystick.d

    r89 r95  
    5555    foreach (js; joysticks) { 
    5656        // NOTE: This sometimes causes a SIGSEGV (Address boundary error) when init fails. 
     57        debug logger.trace ("Calling SDL_JoystickClose"); 
    5758        if(js !is null) SDL_JoystickClose(js);  // only close if successfully opened 
    5859    } 
  • mde/lookup/Options.d

    r94 r95  
    8282    // the supported types simply by changing this list now (untested). 
    8383    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; 
    8586    //BEGIN Templates: internal 
    8687    private { 
     
    123124    if (p) { 
    124125        auto q = cast(BoolContent) (*p); 
    125         if (q) q = parseTo!(`~T.stringof~`) (dt); 
     126        if (q) q.v = parseTo!(`~T.stringof~`) (dt); 
    126127    } 
    127128}`; 
     
    135136            else 
    136137                const char[] addTagMixin = ifBlock; 
    137         } 
    138          
    139         // For writeAll 
    140         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             } else 
    145                 const char[] writeAllMixin = ``; 
    146138        } 
    147139         
     
    289281    char[][] list () { 
    290282        char[][] ret; 
    291         mixin (listMixin!(TYPES)); 
     283        mixin (listMixin!(TYPES2)); 
    292284        return ret; 
    293285    } 
     
    306298         
    307299        // The "pointer lists", e.g. char[]*[ID] optscharA; 
    308         mixin (PLists!(TYPES)); //FIXME adds unused optsbool 
     300        mixin (PLists!(TYPES2)); //FIXME 
    309301        ValueContent[char[]] opts;      // generic list of option values 
    310302    } 
     
    314306        mixin(addTagMixin!(TYPES).addTagMixin); 
    315307    } 
    316