Changeset 37:052df9b2fe07

Show
Ignore:
Timestamp:
05/05/08 09:47:25 (8 months ago)
Author:
Diggory Hardy <diggory.hardy@gmail.com>
branch:
default
convert_revision:
e575716b0c2bb87799171b8553ff39221e59706d
Message:

Allowed widget resizing, changed widget IDs and made Input catch any callback exceptions.

Enabled widget resizing.
Removed IRenderer's temporary drawBox method and added drawButton for ButtonWidget?.
Made the Widget class abstract and added FixedWidget? and SizableWidget? classes.
Rewrote much of createWidget to use meta-code; changed widget IDs.
Made Input catch callback exceptions and report error messages.

committer: Diggory Hardy <diggory.hardy@gmail.com>

Files:

Legend:

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

    r36 r37  
    4949 
    5050Done (for git log message): 
    51 Renamed mde.global to mde.imde. 
    52 Enabled drawing on demand. 
    53 Allowed options to take double values. 
    54 Made the main loop's polling interval (sleep duration) settable from config files. 
  • data/conf/gui.mtt

    r36 r37  
    44<int|x=30> 
    55<int|y=80> 
    6 <int[][int]|widgetData=[0:[1003,200,200]]> 
     6<int[][int]|widgetData=[0:[0x4010,200,200]]> 
    77{W2} 
    88<int|x=150> 
    99<int|y=200> 
    10 <int[][int]|widgetData=[0:[1002,1,3,2,3,5],2:[1001,150,150],3:[1003,150,150],5:[1002,2,1,6,6],6:[1003,73,73]]> 
     10<int[][int]|widgetData=[0:[0xB004,1,3,2,3,5],2:[0x1,150,150],3:[0x4010,100,100],5:[0xB004,3,1,6,1,6],6:[0x4010,60,60],1:[0x3001]]> 
  • mde/gui/renderer/IRenderer.d

    r32 r37  
    4141    void drawWidgetBack (int x, int y, int w, int h); 
    4242     
    43     /** Draw a basic box. Doesn't set the colour. Eventually to be removed. */ 
    44     void drawBox (int x, int y, int w, int h); 
     43    /** Draws a button frame, in if pushed == true. */ 
     44    void drawButton (int x, int y, int w, int h, bool pushed); 
    4545    //END draw routines 
    4646} 
  • mde/gui/renderer/SimpleRenderer.d

    r32 r37  
    4949    void drawWidgetBack (int x, int y, int w, int h) {} 
    5050     
    51     void drawBox (int x, int y, int w, int h) { 
     51    void drawButton (int x, int y, int w, int h, bool pushed) { 
     52        if (pushed) 
     53            gl.setColor (1f, 0f, 1f); 
     54        else 
     55            gl.setColor (.6f, 0f, .6f); 
    5256        gl.drawBox (x,y, w,h); 
    5357    } 
  • mde/gui/widget/Ifaces.d

    r36 r37  
    6666* widget, and data is an array of initialisation data. The method should throw a 
    6767* WidgetDataException (created without parameters) if the data has wrong length or is otherwise 
    68 * invalid. */ 
     68* invalid. 
     69
     70* The widget's size should be set either by it's this() method or by the first call to 
     71* setSize(). setSize() is called on all widgets immediately after their creation, and throwing an 
     72* exception at this point (but not on later calls to setSize) is an acceptible method of failure. 
     73*/ 
     74//NOTE: add another this() without the data for default initialization, for the GUI editor? 
    6975interface IWidget 
    7076{ 
    71     /** Calculate the minimum size the widget could be shrunk to, taking into account 
     77    /** is the width / height resizable? 
     78     * 
     79     * If not, the widget has fixed dimensions equal the output of getMinimalSize. */ 
     80    bool isWSizable (); 
     81    bool isHSizable (); /// ditto 
     82     
     83    /** Calculate the minimal size the widget could be shrunk to, taking into account 
    7284     * child-widgets. */ 
    73     void getMinimumSize (out int w, out int h); 
     85    void getMinimalSize (out int w, out int h); 
    7486     
    75     /** Get the current size of the widget. 
     87    /** Get the current size of the widget. */ 
     88    void getCurrentSize (out int w, out int h); 
     89     
     90    /** Used to adjust the size. 
    7691     * 
    77      * On the first call (during loading), this may be a value saved as part of the config or 
    78      * something else (e.g. revert to getMinimumSize). */ 
    79     void getCurrentSize (out int w, out int h); 
     92     * The size should be clamped to the widget's minimal size, i.e. the size set may be larger 
     93     * than that given by the parameters. Conversely, the size should not be reduced to the 
     94     * widget's maximal size (if any) but expanded as necessary (alignment to be implemented). 
     95     * 
     96     * If the actual size is needed, call getCurrentSize afterwards. */ 
     97    void setSize (int w, int h); 
    8098     
    8199    /** Set the current position (i.e. called on init and move). */ 
    82100    void setPosition (int x, int y); 
     101     
    83102     
    84103    /** Recursively scan the widget tree to find the widget under (x,y). 
     
    101120    void clickEvent (ushort cx, ushort cy, ubyte b, bool state); 
    102121     
     122     
    103123    /** Draw, using the stored values of x and y. 
    104124     * 
  • mde/gui/widget/Widget.d

    r36 r37  
    2121import mde.gui.exception; 
    2222 
    23 import gl = mde.gl.basic; 
    24  
    2523import tango.io.Stdout; 
    2624 
    27 /** A base widget class. Widgets need not inherit this (they only need implement IWidget), but this 
    28 * class provides a useful basic implementation for widgets. 
     25/** An abstract base widget class. 
    2926* 
    30 * Do not use directly (i.e. only for inheriting from). 
    31 */ 
    32 class Widget : IWidget 
     27* This abstract class, and the more concrete FixedWidget and ScalableWidget classes provides a 
     28* useful basic implementation for widgets. Widgets need not inherit these (they only need implement 
     29* IWidget); they are simply provided for convenience and to promote code reuse. */ 
     30abstract class Widget : IWidget 
    3331{ 
    34     /** Minimum size is zero. */ 
    35     void getMinimumSize (out int w, out int h) {}   // w,h initialised to 0 
    36     /** Current size. */ 
    37     void getCurrentSize (out int w, out int h) { 
    38         w = this.w; 
    39         h = this.h; 
     32    void getCurrentSize (out int cw, out int ch) { 
     33        cw = w; 
     34        ch = h; 
    4035    } 
    4136     
    42     void setPosition (int x, int y) { 
    43         this.x = x; 
    44         this.y = y; 
     37    void setPosition (int nx, int ny) { 
     38        x = nx; 
     39        y = ny; 
    4540    } 
    4641     
    47     /** Return self, since we don't have child widgets and the method wouldn't have been called 
     42    /* Return self, since we don't have child widgets and the method wouldn't have been called 
    4843    * unless the location was over us. Valid for all widgets without children. */ 
    4944    IWidget getWidget (int,int) { 
     
    5146    } 
    5247     
    53     /** Dummy event method (widget doesn't respond to events) */ 
     48    /* Dummy event method (widget doesn't respond to events) */ 
    5449    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {} 
    5550     
    56     /** Basic draw method: draw the background (all widgets should do this) */ 
     51    /* Basic draw method: draw the background (all widgets should do this) */ 
    5752    void draw () { 
    5853        window.renderer.drawWidgetBack (x,y, w,h); 
     
    6459    int w, h;               // size 
    6560} 
     61/** A base for fixed-size widgets. */ 
     62class FixedWidget : Widget { 
     63    bool isWSizable () {    return false;   } 
     64    bool isHSizable () {    return false;   } 
     65     
     66    /* Not resizable, so return current size. */ 
     67    void getMinimalSize (out int mw, out int mh) { 
     68        mw = wF; 
     69        mh = hF; 
     70    } 
     71     
     72    /* Ignore: a fixed size widget. */ 
     73    void setSize (int nw, int nh) { 
     74        w = (nw >= wF ? nw : wF); 
     75        h = (nh >= hF ? nh : hF); 
     76    } 
     77     
     78protected: 
     79    int wF, hF;             // The "fixed" size, i.e. the preferred & minimal size 
     80} 
     81/** A base for resizable widgets. */ 
     82class SizableWidget : Widget { 
     83    bool isWSizable () {    return true;    } 
     84    bool isHSizable () {    return true;    } 
     85     
     86    /* Return zero. */ 
     87    void getMinimalSize (out int mw, out int mh) {} 
     88     
     89    /* Set size: a fully resizable widget. */ 
     90    void setSize (int nw, int nh) { 
     91        w = (nw >= 0 ? nw : 0); 
     92        h = (nh >= 0 ? nh : 0); 
     93    } 
     94} 
    6695 
    6796//BEGIN Widgets 
    68 /// Draws a box. That's it. 
    69 class BoxWidget : Widget 
     97/// A fixed-size blank widget. 
     98class FixedBlankWidget : FixedWidget 
    7099{ 
    71100    this (IWindow wind, IWidget, int[] data) { 
     
    74103        window = wind; 
    75104         
    76         w = data[0]; 
    77         h = data[1]; 
     105        w = wF = data[0]; 
     106        h = hF = data[1]; 
    78107    } 
    79     void draw () { 
    80         gl.setColor(1f,0f,0f); 
    81         window.renderer.drawBox (x,y, w,h); 
     108
     109 
     110/// A completely resizable blank widget (initial size zero). 
     111class SizableBlankWidget : SizableWidget 
     112
     113    this (IWindow wind, IWidget, int[] data) { 
     114        if (data.length != 0) throw new WidgetDataException; 
     115         
     116        window = wind; 
    82117    } 
    83118} 
    84119 
    85120/// First interactible widget 
    86 class ButtonWidget : Widget 
     121class ButtonWidget : FixedWidget 
    87122{ 
    88123    bool pushed = false;    // true if button is pushed in (visually) 
     
    95130        window = wind; 
    96131         
    97         w = data[0]; 
    98         h = data[1]; 
     132        w = wF = data[0]; 
     133        h = hF = data[1]; 
    99134    } 
    100135     
    101136    void draw () { 
    102         if (pushed) 
    103             gl.setColor (1f, 0f, 1f); 
    104         else 
    105             gl.setColor (.6f, 0f, .6f); 
    106         window.renderer.drawBox (x,y, w,h); 
    107     } 
    108      
    109     void getMinimumSize (out int w, out int h) { 
    110         w = this.w; // button is not resizable 
    111         h = this.h; 
     137        window.renderer.drawButton (x,y, w,h, pushed); 
    112138    } 
    113139     
  • mde/gui/widget/Window.d

    r36 r37  
    5353    /** Call after loading is finished to setup the window and confirm that it's valid. 
    5454     * 
    55      * Throws: WindowLoadException. Do not use the instance in this case! */ 
     55     * Throws: WindowLoadException (or possibly other exceptions). Do not use the instance if an 
     56     * exception occurs! */ 
    5657    void finalise (IGui gui) 
    5758    in { 
     
    6566         
    6667        // Create the primary widget (and indirectly all sub-widgets), throwing on error: 
    67         widget = makeWidget (0, this);// primary widget always has ID 0. 
    68          
    69         widgetData = null;          // data is no longer needed: allow GC to collect (cannot safely delete) 
    70          
    71         widgetX = x + rend.windowBorder;  // widget position 
    72         widgetY = y + rend.windowBorder;  // must be updated if the window is moved 
     68        widget = makeWidget (0, this);  // primary widget always has ID 0. 
     69        widgetData = null;  // data is no longer needed: allow GC to collect (cannot safely delete) 
     70         
     71        widget.setSize (0,0);           // set the minimal size 
     72        widget.getCurrentSize (w,h);    // and get this size 
     73        w += rend.windowBorder * 2;     // Adjust for border 
     74        h += rend.windowBorder * 2; 
     75         
     76        widgetX = x + rend.windowBorder;    // widget position 
     77        widgetY = y + rend.windowBorder;    // must be updated if the window is moved 
    7378        widget.setPosition (widgetX, widgetY); 
    74          
    75         widget.getCurrentSize (w,h);// Find the initial size 
    76         w += rend.windowBorder * 2;       // Adjust for border 
    77         h += rend.windowBorder * 2; 
    7879         
    7980        xw = x+w; 
     
    134135     
    135136    //BEGIN IWidget methods 
    136     void getMinimumSize (out int w, out int h) { 
    137         widget.getMinimumSize (x,y); 
    138         w += rend.windowBorder * 2;       // Adjust for border 
    139         h += rend.windowBorder * 2; 
     137    bool isWSizable () { 
     138        return widget.isWSizable; 
     139    } 
     140    bool isHSizable () { 
     141        return widget.isHSizable; 
     142    } 
     143     
     144    void getMinimalSize (out int mw, out int mh) { 
     145        mw = w + rend.windowBorder * 2; 
     146        mh = h + rend.windowBorder * 2; 
    140147    } 
    141148    void getCurrentSize (out int cw, out int ch) { 
     
    144151    } 
    145152     
    146     void setPosition (int x, int y) { 
    147         // Currently only used internally 
    148         this.x = x; 
    149         this.y = y; 
     153    void setSize (int nw, int nh) { 
     154        w = nw; 
     155        h = nh; 
     156         
     157        xw = x+w; 
     158        yh = y+h; 
     159         
     160        widget.setSize (w - rend.windowBorder * 2, h - rend.windowBorder * 2); 
     161    } 
     162     
     163    void setPosition (int nx, int ny) { 
     164        x = nx; 
     165        y = ny; 
    150166         
    151167        xw = x+w; 
  • mde/gui/widget/createWidget.d

    r34 r37  
    2323import mde.gui.exception : WidgetDataException; 
    2424 
    25 //BEGIN createWidget 
    26 /// Widget types. Start high so they can be reordered easily later. 
    27 enum WIDGET_TYPE : int { 
    28     BOX = 1001, GRID, BUTTON 
    29 } 
    30  
    3125/** Create a widget of type data[0] (see enum WIDGET_TYPES) for _window window, with initialisation 
    3226* data [1..$]. */ 
     
    4034    data = data[1..$];      // the rest is passed to the Widget 
    4135     
    42     if (type == WIDGET_TYPE.BOX) return new BoxWidget (window, parent, data); 
    43     else if (type == WIDGET_TYPE.GRID) return new GridWidget (window, parent, data); 
    44     else if (type == WIDGET_TYPE.BUTTON) return new ButtonWidget (window, parent, data); 
    45     else throw new WidgetDataException ("Bad widget type"); 
     36    mixin (binarySearch ("type", WIDGETS)); 
     37    throw new WidgetDataException ("Bad widget type"); 
    4638} 
    47 //END createWidget 
     39 
     40/+ for converting to a char[] name (unused) 
     41static this() { 
     42    WIDGET_NAMES = [ 
     43            FixedBlank : "FixedBlank", 
     44            SizableBlank : "SizableBlank", 
     45            Button : "Button", 
     46            GridLayout : "GridLayout" 
     47                    ]; 
     48}+/ 
     49 
     50private: 
     51/// Widget types. 
     52enum WIDGET_TYPE : int { 
     53    WSIZABLE                = 0x1000,   // horizontally resizable 
     54    HSIZABLE                = 0x2000,   // vertically resizable 
     55    INTERACTIBLE            = 0x4000,   // any specific interaction 
     56    LAYOUT                  = 0x8000,   // is a layout widget (i.e. has sub-widgets)? 
     57     
     58    // Use widget names rather than usual capitals convention 
     59     
     60    // blank: 0x1 
     61    FixedBlank              = 0x1, 
     62    SizableBlank            = WSIZABLE | HSIZABLE | 0x1, 
     63     
     64    // buttons: 0x10 
     65    Button                  = INTERACTIBLE | 0x10, 
     66     
     67    GridLayout              = LAYOUT | WSIZABLE | HSIZABLE | 0x4 
     68
     69 
     70//const char[][int] WIDGET_NAMES; 
     71 
     72// Only used for binarySearch algorithm generation; must be ordered by numerical values. 
     73const char[][] WIDGETS = [ 
     74        "FixedBlank", 
     75        "SizableBlank", 
     76        "Button", 
     77        "GridLayout"   ]; 
     78 
     79// Purely to add indentation. Could just return "" without affecting functionality. 
     80/+static char[] indent (uint i) { 
     81    char[] ret; 
     82    for (; i > 0; --i) ret ~= "  "; 
     83        // This is not executable at compile time: 
     84        //ret.length = i * 4;       // number of characters for each indentation 
     85        //ret[] = ' ';      // character to indent with 
     86    return ret; 
     87}+/ 
     88char[] indent (uint) {  return "";  } 
     89 
     90/* Generates a binary search algorithm. */ 
     91char[] binarySearch (char[] var, char[][] consts, int indents = 0) { 
     92    if (consts.length > 3) { 
     93        return indent(indents) ~ "if (" ~ var ~ " <= WIDGET_TYPE." ~ consts[$/2 - 1] ~ ") {\n" ~ 
     94                binarySearch (var, consts[0 .. $/2], indents + 1) ~ 
     95                indent(indents) ~ "} else {\n" ~ 
     96                binarySearch (var, consts[$/2 .. $], indents + 1) ~ 
     97                indent(indents) ~ "}\n"; 
     98    } else { 
     99        char[] ret; 
     100        ret ~= indent(indents); 
     101        foreach (c; consts) { 
     102            ret ~= "if (" ~ var ~ " == WIDGET_TYPE." ~ c ~ ") {\n" ~ 
     103                    indent(indents+1) ~ "return new " ~ c ~ "Widget (window, parent, data);\n" ~ 
     104                    indent(indents) ~ "} else "; 
     105        } 
     106        ret = ret[0..$-6] ~ '\n';  // remove last else 
     107        return ret; 
     108    } 
     109
  • mde/gui/widget/layout.d

    r34 r37  
    2020import mde.gui.exception : WidgetDataException; 
    2121 
    22 /// Encapsulates a grid of Widgets 
    23 class GridWidget : Widget 
     22/** Encapsulates a grid of Widgets. 
     23
     24* Since a grid with either dimension zero is not useful, there must be at least one sub-widget. */ 
     25class GridLayoutWidget : Widget 
    2426{ 
    2527    this (IWindow wind, IWidget, int[] data) { 
    26         // Get grid size 
    27         if (data.length < 2) throw new WidgetDataException; 
     28        // Get grid size and check data 
     29        // Check sufficient data for rows, cols, and at least one widget: 
     30        if (data.length < 3) throw new WidgetDataException; 
    2831        rows = data[0]; 
    2932        cols = data[1]; 
     33        if (data.length != 2 + rows * cols) throw new WidgetDataException; 
     34        /* data.length >= 3 so besides checking the length is correct, this tells us: 
     35         *      rows * cols >= 3 - 2 = 1            a free check! 
     36         * The only thing not checked is whether both rows and cols are negative, which would 
     37         * cause an exception when dynamic arrays are allocated later (and is unlikely). */ 
    3038         
    3139        window = wind; 
    3240         
    3341        // Get all sub-widgets 
    34         // Check: correct data length and rows*cols >= 0 (know data.length - 2 >= 0). 
    35         if (data.length != 2 + rows * cols) throw new WidgetDataException; 
    3642        subWidgets.length = rows*cols; 
    3743        foreach (i, inout subWidget; subWidgets) { 
    3844            subWidget = window.makeWidget (data[i+2], this); 
    3945        } 
    40          
    41         getMinimumSize (w,h);   // Calculate the size (current size is not saved) 
    42     } 
    43      
    44     // Calculates from all rows and columns of widgets. 
    45     void getMinimumSize (out int w, out int h) { 
    46         if (rows*cols == 0) {    // special case 
    47             w = h = 0; 
    48             return; 
    49         } 
    50          
    51         // Find the sizes of all subWidgets 
    52         int[] widgetW = new int[subWidgets.length]; // dimensions 
    53         int[] widgetH = new int[subWidgets.length]; 
    54         foreach (i,widget; subWidgets) widget.getCurrentSize (widgetW[i],widgetH[i]); 
    55          
    56         // Find row heights and column widths (non cumulative) 
    57         rowH.length = rows; 
    58         colW.length = cols; //WARNING: code reliant on these being initialised to zero 
    59         for (uint i = 0; i < subWidgets.length; ++i) { 
    60             uint n = i / cols;  // row 
    61             if (rowH[n] < widgetH[i]) rowH[n] = widgetH[i]; 
    62             n = i % cols;       // column 
    63             if (colW[n] < widgetW[i]) colW[n] = widgetW[i]; 
    64         } 
    65          
    66         // rowY / colX 
     46    } 
     47     
     48    bool isWSizable () { 
     49        if (colSizable == -2) {     // check whether any columns are resizable 
     50            for1: 
     51            for (uint i = 0; i < cols; ++i) {                       // for each column 
     52                for (uint j = 0; j < subWidgets.length; j += cols)  // for each row 
     53                    if (!subWidgets[i+j].isWSizable)        // column not resizable 
     54                        continue for1;                      // continue the outer for loop 
     55                 
     56                // column is resizable if we get to here 
     57                colSizable = i; 
     58                goto break1;        // use goto in lieu of for...else 
     59            } 
     60             
     61            // if we get here, no resizable column was found 
     62            colSizable = -1; 
     63             
     64            break1:; 
     65        } 
     66         
     67        if (colSizable >= 0) return true; 
     68        else return false; 
     69    } 
     70     
     71    bool isHSizable () { 
     72        if (rowSizable == -2) {     // check whether any columns are resizable 
     73            for2: 
     74            for (uint i = 0; i < subWidgets.length; i += cols) {    // for each row 
     75                for (uint j = 0; j < cols; ++j)                     // for each column 
     76                    if (!subWidgets[i+j].isHSizable) 
     77                        continue for2; 
     78                 
     79                rowSizable = i / cols;  // the current row 
     80                goto break2; 
     81            } 
     82             
     83            rowSizable = -1; 
     84             
     85            break2:; 
     86        } 
     87         
     88        if (rowSizable >= 0) return true; 
     89        else return false; 
     90    } 
     91     
     92    /* Calculates the minimal size from all rows and columns of widgets. */ 
     93    void getMinimalSize (out int mw, out int mh) { 
     94        // If rowHMin & colWMin are null, calculate them. They are set null whenever the contents 
     95        // or the contents' minimal size change, as well as when this widget is created. 
     96        if (rowHMin is null) 
     97            genMinRowColSizes; 
     98         
     99        // Calculate the size, starting with the spacing: 
     100        mh = window.renderer.layoutSpacing;     // use temporarily 
     101        mw = mh * (cols - 1); 
     102        mh *= (rows - 1); 
     103         
     104        foreach (x; colWMin)            // add the column/row's dimensions 
     105            mw += x; 
     106        foreach (x; rowHMin) 
     107            mh += x; 
     108    } 
     109     
     110    void setSize (int nw, int nh) { 
     111        // Step 1: calculate the minimal row/column sizes. 
     112        int mw, mh; // FIXME: use w,h directly? 
     113        getMinimalSize (mw, mh); 
     114        colW = colWMin;         // start with these dimensions, and increase if necessary 
     115        rowH = rowHMin; 
     116         
     117        // Step 2: clamp nw/nh or expand a column/row to achieve the required size 
     118        if (nw <= mw) nw = mw;  // clamp to minimal size 
     119        else { 
     120            if (isWSizable)     // calculates colSizable; true if any is resizable 
     121                colW[colSizable] += nw - mw; // new width 
     122            else                // no resizable column; so force the last one 
     123                colW[$-1] += nw - mw; 
     124        } 
     125         
     126        if (nh <= mh) nh = mh; 
     127        else { 
     128            if (isHSizable) 
     129                rowH[rowSizable] += nh - mh; 
     130            else 
     131                rowH[$-1] += nh - mh; 
     132        } 
     133         
     134        // Step 3: set each sub-widget's size. 
     135        foreach (i,widget; subWidgets) 
     136            widget.setSize (colW[i % cols], rowH[i / cols]); 
     137         
     138        // Step 4: calculate the column and row positions 
     139        colX.length = cols; 
    67140        rowY.length = rows; 
    68         colX.length = cols; 
    69141        int spacing = window.renderer.layoutSpacing; 
    70142         
     
    74146            cum += x + spacing; 
    75147        } 
    76         h = cum - spacing;      // total height 
     148        h = cum - spacing;      // set the total height 
     149        assert (h == nh);       // FIXME: remove and set w/h directly once this is asserted 
     150         
    77151        cum = 0; 
    78152        foreach (i, x; colW) { 
     
    81155        } 
    82156        w = cum - spacing;      // total width 
     157        assert (w == nw); 
    83158    } 
    84159     
     
    91166    } 
    92167     
     168     
    93169    // Find the relevant widget. 
    94170    IWidget getWidget (int cx, int cy) { 
    95         if (rows*cols == 0) return this;    // special case 
    96          
    97171        int lx = cx - x, ly = cy - y;       // use coords relative to this widget 
    98172         
     
    120194        if (lx < i && ly < j) 
    121195            return widg.getWidget (cx, cy); 
     196        return this;    // wasn't in cell 
    122197    } 
    123198     
     
    129204    } 
    130205     
     206private: 
     207    void genMinRowColSizes () { 
     208        // Find the sizes of all subWidgets 
     209        int[] widgetW = new int[subWidgets.length]; // dimensions 
     210        int[] widgetH = new int[subWidgets.length]; 
     211        foreach (i,widget; subWidgets) 
     212            widget.getMinimalSize (widgetW[i],widgetH[i]); 
     213             
     214        // Find the minimal row heights and column widths (non cumulative) 
     215        colWMin = new int[cols];    // set length 
     216        rowHMin = new int[rows]; 
     217        for (uint i = 0; i < subWidgets.length; ++i) { 
     218            uint n; 
     219            n = i % cols;           // column 
     220            if (colWMin[n] < widgetW[i]) colWMin[n] = widgetW[i]; 
     221            n = i / cols;           // row 
     222            if (rowHMin[n] < widgetH[i]) rowHMin[n] = widgetH[i]; 
     223        } 
     224    } 
     225     
    131226protected: 
    132     int rows, cols;     // number of cells in grid 
     227    int cols, rows;     // number of cells in grid 
     228     
     229    int colSizable = -2;// 0..cols-1 means this column is resizable 
     230    int rowSizable = -2;// -2 means not calculated yet, -1 means not resizable 
     231     
     232    int[] colWMin;      // minimal column width 
     233    int[] rowHMin;      // minimal row height 
     234    int[] colW;         // column width (widest widget) 
    133235    int[] rowH;         // row height (highest widget in the row) 
    134     int[] colW;         // column width (widest widget) 
    135     int[] rowY;         // cumulative rowH[i-1] + border and padding 
    136     int[] colX;         // cumulative colW[i-1] + border and padding 
     236     
     237    int[] colX;         // cumulative colW[i-1] + padding (add x to get column's left x-coord) 
     238    int[] rowY;         // cumulative rowH[i-1] + padding 
     239     
    137240    IWidget[] subWidgets;   // all widgets in the grid (by row): 
    138241    /* SubWidget order:    [ 0 1 ] 
  • mde/input/Input.d

    r34 r37  
    197197            case SDL_MOUSEBUTTONDOWN: 
    198198            case SDL_MOUSEBUTTONUP: 
    199                 foreach (dg; mouseClickCallbacks) 
    200                     dg (event.button.x - 1, event.button.y - 1, 
    201                         event.button.button, event.button.state == SDL_PRESSED); 
     199                foreach (dg; mouseClickCallbacks) { 
     200                    try 
     201                        dg (event.button.x - 1, event.button.y - 1, 
     202                            event.button.button, event.button.state == SDL_PRESSED); 
     203                    catch (Exception e) 
     204                        logger.error (CB_EXC ~ e.msg); 
     205                } 
    202206                break; 
    203207             
     
    206210                mouse_y = event.motion.y - 1; 
    207211                 
    208                 foreach (dg; mouseMotionCallbacks) 
    209                     dg (event.motion.x - 1, event.motion.y - 1); 
     212                foreach (dg; mouseMotionCallbacks) { 
     213                    try 
     214                        dg (event.motion.x - 1, event.motion.y - 1); 
     215                    catch (Exception e) 
     216                        logger.error (CB_EXC ~ e.msg); 
     217                } 
    210218                break; 
    211219             
     
    370378    } 
    371379     
     380    static const CB_EXC = "Callback exception: "; 
     381     
    372382    static Logger logger; 
    373383 
     
    486496         
    487497        ButtonCallback[]* cb_p = id in myThis.buttonCallbacks; 
    488         if (cb_p) foreach (cb; *cb_p) cb (id, b); 
     498        if (cb_p) foreach (cb; *cb_p) { 
     499            try 
     500                cb (id, b); 
     501            catch (Exception e) 
     502                logger.error (CB_EXC ~ e.msg); 
     503        } 
    489504    } 
    490505    // Adjuster to check modifier keys 
     
    498513         
    499514        AxisCallback[]* cb_p = id in myThis.axisCallbacks; 
    500         if (cb_p) foreach (cb; *cb_p) cb (id, x); 
     515        if (cb_p) foreach (cb; *cb_p) { 
     516            try 
     517                cb (id, x); 
     518            catch (Exception e) 
     519                logger.error (CB_EXC ~ e.msg); 
     520        } 
    501521    } 
    502522     
     
    513533         
    514534        RelMotionCallback[]* cb_p = id in myThis.relMotionCallbacks; 
    515         if (cb_p) foreach (cb; *cb_p) cb (id, x,y); 
     535        if (cb_p) foreach (cb; *cb_p) { 
     536            try 
     537                cb (id, x,y); 
     538            catch (Exception e) 
     539                logger.error (CB_EXC ~ e.msg); 
     540        } 
    516541    } 
    517542    //END ES Functions