Changeset 31:baa87e68d7dc

Show
Ignore:
Timestamp:
04/29/08 13:10:58 (9 months ago)
Author:
Diggory Hardy <diggory.hardy@gmail.com>
branch:
default
convert_revision:
1824e8f635e1d65fac426880572526ca088413e1
Message:

GUI now supports basic interactible widgets, widget colour and border are more unified, and some code cleanup.

Removed some circular dependencies which slipped in. As a result, the OpenGL code got separated into different files.
Enabled widgets to recieve events.
New IParentWidget interface allowing widgets to interact with their parents.
New Widget base class.
New WidgetDecoration? class.
New ButtonWidget? class responding to events (in a basic way).

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

Files:

Legend:

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

    r30 r31  
    44 
    55In progress: 
    6 Started buttonWidget (on hold) 
    76 
    87 
     
    5049 
    5150Done (for git log message): 
    52 Revamped Scheduler. Functions can be removed, have multiple schedules, have their scheduling changed, etc. 
    53 Scheduler has a unittest. Checked all pass. 
    54 Main loop scheduler moved to mde. Draw-on-demand currently disabled, simplifying this. 
    55 Made mtunitest.d remove the temporary file it uses afterwards. 
     51Removed some circular dependencies which slipped in. As a result, the OpenGL code got separated into different files. 
     52Enabled widgets to recieve events. 
     53New IParentWidget interface allowing widgets to interact with their parents. 
     54New Widget base class. 
     55New WidgetDecoration class. 
     56New ButtonWidget class responding to events (in a basic way). 
  • codeDoc/todo.txt

    r26 r31  
    33 
    44 
     5* means done 
     6 
    57GUI: 
    68->  Basic OpenGL code to: 
    7     -> create orthographic projection 
    8     -> draw boxes 
    9     -> maybe more (text, textures, ...) 
    10 -> Windows with size & position 
     9    ->* create orthographic projection 
     10    ->* draw boxes 
     11    -> maybe more (text, textures, ...) 
     12->* Windows with size & position 
    1113->  Widgets: 
    12     ->  minimum size but expandable, auto-set 
    13     ->  grid "layout" widgets 
     14    ->* minimum size but expandable, auto-set 
     15        ->  no ability to resize yet except from config files 
     16    ->* grid "layout" widgets 
     17    ->  scripted widgets 
     18    ->  decent rendering/theme system 
    1419->  Text rendering 
    1520    -> text library? 
  • data/conf/gui.mtt

    r29 r31  
    11{MT01} 
    22{W1} 
    3 <int|x=10> 
    4 <int|y=50> 
    5 <int[][int]|widgetData=[0:[1001,200,200]]> 
     3<int|x=0> 
     4<int|y=0> 
     5<int[][int]|widgetData=[0:[1003,200,200]]> 
    66{W2} 
    77<int|x=150> 
    88<int|y=200> 
    9 <int[][int]|widgetData=[0:[1002,3,2,2,2,3,3,3,3],2:[1001,150,150],3:[1001,100,100]]> 
     9<int[][int]|widgetData=[0:[1002,3,2,2,2,3,3,2,5],2:[1001,150,150],3:[1003,150,150],5:[1002,2,2,6,6,6,6],6:[1003,73,73]]> 
  • mde/SDL.d

    r29 r31  
    2121import mde.input.joystick; 
    2222import mde.options; 
    23 import mde.gl
     23import mde.gl.basic
    2424import global = mde.global; 
    2525 
     
    108108    // OpenGL stuff: 
    109109    glSetup(); 
    110      
    111     // Projection (mde.gl) 
    112110    setProjection (w, h); 
    113111     
  • mde/events.d

    r30 r31  
    2121 
    2222import mde.input.input; 
    23 import mde.input.exception; 
    24  
    25 import mde.scheduler.InitFunctions; 
    2623 
    2724import derelict.sdl.events; 
     
    3330static this() { 
    3431    logger = Log.getLogger ("mde.events"); 
    35      
    36     init.addFunc (&initInput, "initInput"); 
    37 } 
    38  
    39 void initInput () { // init func 
    40     try { 
    41         global.input = new Input(); 
    42         global.input.loadConfig ();         // (may also create instance) 
    43      
    44         global.input.addButtonCallback (cast(Input.inputID) 0x0u, delegate void(Input.inputID i, bool b) { 
    45             if (b) { 
    46                 logger.info ("Quiting..."); 
    47                 global.run = false; 
    48             } 
    49         } ); 
    50     } catch (Exception) { 
    51         setInitFailure; 
    52     } 
    5332} 
    5433 
     
    7251                try { 
    7352                    global.input (event); 
    74                 } catch (InputClassException e) { 
     53                } catch (Exception e) { 
    7554                    logger.error ("Caught input exception; event will be ignored. Exception was:"); 
    7655                    logger.error (e.msg); 
  • mde/gui/Widget.d

    r30 r31  
    1717module mde.gui.Widget; 
    1818 
    19 import mde.gui.IWindow
     19import mde.gui.Ifaces
    2020import mde.gui.exception; 
    2121 
    22 import gl = mde.gl; 
    23 import mde.scheduler.InitFunctions; 
    24  
    25 //BEGIN Iface and createWidget 
    26 /** Interface for widgets (may become a base class). 
    27 
    28 * A widget is a region of a GUI window which handles rendering and user-interaction for itself 
    29 * and is able to communicate with it's window and parent/child widgets as necessary. 
    30 
    31 * A widget's constructor should have this prototype: 
    32 * ---------------------------------- 
    33 * this (IWindow window, int[] data); 
    34 * ---------------------------------- 
    35 * Where window is the parent window and data is an array of initialisation data. The method should 
    36 * throw a WidgetDataException (created without parameters) if the data has wrong length or is 
    37 * otherwise invalid. 
    38 */ 
    39 //FIXME: check code reuse later! 
    40 interface IWidget 
    41 
    42     /** Draw, starting from given x and y. 
    43     * 
    44     * Maybe later enforce clipping of all sub-widget drawing, particularly for cases where only 
    45     * part of the widget is visible: scroll bars or a hidden window. */ 
    46     void draw (int x, int y); 
    47      
    48     /** Calculate the minimum size the widget could be shrunk to, taking into account 
    49     * child-widgets. */ 
    50     void getMinimumSize (out int w, out int h); 
    51      
    52     /** Get the current size of the widget. 
    53     * 
    54     * On the first call (during loading), this may be a value saved as part of the config or 
    55     * something else (e.g. revert to getMinimumSize). */ 
    56     void getCurrentSize (out int w, out int h); 
    57 
    58  
     22import gl = mde.gl.basic; 
     23 
     24import tango.io.Stdout; 
     25 
     26//BEGIN createWidget 
    5927/// Widget types. Start high so they can be reordered easily later. 
    60 enum WIDGET_TYPES : int { 
    61     BOX = 1001, GRID 
     28enum WIDGET_TYPE : int { 
     29    BOX = 1001, GRID, BUTTON 
    6230} 
    6331 
    6432/** Create a widget of type data[0] (see enum WIDGET_TYPES) for _window window, with initialisation 
    6533* data [1..$]. */ 
    66 IWidget createWidget (IWindow window, int[] data) { 
     34IWidget createWidget (IWindow window, IParentWidget parent, int[] data) 
     35in { 
     36    assert (window !is null, "createWidget: window is null"); 
     37    assert (parent !is null, "createWidget: parent is null"); 
     38} body { 
    6739    if (data.length < 1) throw new WidgetDataException ("No widget data"); 
    6840    int type = data[0];     // type is first element of data 
    6941    data = data[1..$];      // the rest is passed to the Widget 
    7042     
    71     if (type == WIDGET_TYPES.BOX) return new BoxWidget (window, data); 
    72     else if (type == WIDGET_TYPES.GRID) return new GridWidget (window, data); 
     43    if (type == WIDGET_TYPE.BOX) return new BoxWidget (window, parent, data); 
     44    else if (type == WIDGET_TYPE.GRID) return new GridWidget (window, parent, data); 
     45    else if (type == WIDGET_TYPE.BUTTON) return new ButtonWidget (window, parent, data); 
    7346    else throw new WidgetDataException ("Bad widget type"); 
    7447} 
    75 //END Iface and createWidget 
    76  
    77 //BEGIN Widgets 
    78 /// Draws a box. That's it. 
    79 class BoxWidget : IWidget 
    80 
    81     int w, h;   // size 
    82      
    83     this (IWindow, int[] data) { 
    84         if (data.length != 2) throw new WidgetDataException; 
    85          
    86         w = data[0]; 
    87         h = data[1]; 
    88     } 
    89      
     48//END createWidget 
     49 
     50/** A base widget class. Widgets need not inherit this (they only need implement IWidget), but this 
     51* class provides a useful basic implementation for widgets. 
     52
     53* Technically this class could be instantiated, but it wouldn't do anything, not even draw itself. 
     54*/ 
     55class Widget : IWidget 
     56
     57    /** Basic draw method: draw the background */ 
    9058    void draw (int x, int y) { 
    91         gl.setColor (1.0f, 1.0f, 0.0f); 
    92         gl.drawBox (x,x+w, y,y+h); 
    93     } 
    94      
    95     void getMinimumSize (out int w, out int h) { 
    96         w = h = 0;  // box has no content 
    97     } 
     59        deco.setColor(); 
     60        gl.drawBox (x,y, w,h); 
     61    } 
     62     
     63    /** Dummy event method (ignore) */ 
     64    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) {} 
     65     
     66    /** Minimum size is zero. */ 
     67    void getMinimumSize (out int w, out int h) {}   // w,h initialised to 0 
     68    /** Current size. */ 
    9869    void getCurrentSize (out int w, out int h) { 
    9970        w = this.w; 
    10071        h = this.h; 
    10172    } 
     73     
     74    WidgetDecoration decoration () { 
     75        return deco; 
     76    } 
     77     
     78protected: 
     79    WidgetDecoration deco;  // the widget's decoration 
     80    int w, h;               // size 
     81} 
     82 
     83//BEGIN Widgets 
     84/// Draws a box. That's it. 
     85class BoxWidget : Widget 
     86{ 
     87    this (IWindow, IParentWidget parent, int[] data) { 
     88        if (data.length != 2) throw new WidgetDataException; 
     89         
     90        deco = new WidgetDecoration (parent.decoration); 
     91         
     92        w = data[0] + 2*deco.border; 
     93        h = data[1] + 2*deco.border; 
     94    } 
    10295} 
    10396 
    10497/// Encapsulates a grid of Widgets 
    105 class GridWidget : IWidget 
    106 
    107     //NOTE: maybe remove the padding and have each widget include a border? Or vice-versa (no borders on widgets)? 
    108     const PADDING = 3;  // padding between rows/cols 
    109     const BORDER = 8;   // border width 
    110     int w, h;           // size 
    111     int rows, cols;     // number of cells in grid 
    112     int[] rowH;         // row height (highest widget in the row) 
    113     int[] colW;         // column width (widest widget) 
    114     int[] rowY;         // cumulative rowH[i-1] + BORDER/PADDING 
    115     int[] colX;         // cumulative colW[i-1] + BORDER/PADDING 
    116     IWidget[] subWidgets;   // all widgets in the grid (by row): 
    117     /* SubWidget order:    [ 2 3 ] 
    118     *                      [ 0 1 ] */ 
    119      
    120     this (IWindow window, int[] data) { 
     98class GridWidget : Widget 
     99
     100    this (IWindow window, IParentWidget parent, int[] data) { 
    121101        // Get grid size 
    122102        if (data.length < 2) throw new WidgetDataException; 
     
    124104        cols = data[1]; 
    125105         
     106        deco = new WidgetDecoration (parent.decoration, TypeFlags.LAYOUT); 
     107         
    126108        // Get all sub-widgets 
     109        // Check: correct data length and rows*cols >= 0 (know data.length - 2 >= 0). 
    127110        if (data.length != 2 + rows * cols) throw new WidgetDataException; 
    128111        subWidgets.length = rows*cols; 
    129112        foreach (i, inout subWidget; subWidgets) { 
    130             subWidget = window.getWidget (data[i+2]); 
     113            subWidget = window.getWidget (data[i+2], this); 
    131114        } 
    132115         
     
    135118     
    136119    void draw (int x, int y) { 
    137         gl.setColor (1.0f, 0.6f, 0.0f)
    138         gl.drawBox (x,x+w, y,y+h); 
     120        deco.setColor
     121        gl.drawBox (x,y, w,h); 
    139122         
    140123        foreach (i,widget; subWidgets) { 
     
    143126    } 
    144127     
    145     /** Also recalculates row/column widths. */ 
     128    // Calculates from all rows and columns of widgets. 
    146129    void getMinimumSize (out int w, out int h) { 
    147130        if (rows*cols == 0) {    // special case 
    148             w = h = 2*BORDER
     131            w = h = 2*deco.border
    149132            return; 
    150133        } 
     
    157140        // Find row heights and column widths (non cumulative) 
    158141        rowH.length = rows; 
    159         colW.length = cols; 
     142        colW.length = cols; //WARNING: code reliant on these being initialised to zero 
    160143        for (uint i = 0; i < subWidgets.length; ++i) { 
    161144            uint x = i / cols;  // row 
     
    168151        rowY.length = rows; 
    169152        colX.length = cols; 
    170         int cum = BORDER
     153        int cum = deco.border
    171154        foreach (i, x; rowH) { 
    172155            rowY[i] = cum; 
    173156            cum += x + PADDING; 
    174157        } 
    175         h = cum + BORDER - PADDING;     // total height 
    176         cum = BORDER
     158        h = cum + deco.border - PADDING;     // total height 
     159        cum = deco.border
    177160        foreach (i, x; colW) { 
    178161            colX[i] = cum; 
    179162            cum += x + PADDING; 
    180163        } 
    181         w = cum + BORDER - PADDING;     // total width 
    182     } 
    183     void getCurrentSize (out int wC, out int hC) { 
    184         wC = w; 
    185         hC = h; 
    186     } 
    187 
    188 /+ On hold until after next commit 
     164        w = cum + deco.border - PADDING;     // total width 
     165    } 
     166     
     167    // Pass event on to relevant widget. Simply return if not on a widget. 
     168    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 
     169        if (rows*cols == 0) return; // special case 
     170         
     171        // Find the column 
     172        int i = cols - 1;          // starting from right... 
     173        while (cx < colX[i]) {      // decrement while left of this column 
     174            if (i == 0) return;     // left of first column 
     175            --i; 
     176        }                           // now (cx >= colX[i]) 
     177        if (cx >= colX[i] + colW[i]) return;    // between columns 
     178         
     179        // Find the row; 
     180        int j = rows - 1; 
     181        while (cy < rowY[j]) { 
     182            if (j == 0) return; 
     183            --j; 
     184        } 
     185        if (cy >= rowY[j] + rowH[j]) return; 
     186         
     187        // Now we know it's in widget (i,j)'s cell (but the widget may not take up the whole cell) 
     188        cx -= colX[i]; 
     189        cy -= rowY[j]; 
     190        IWidget widg = subWidgets[i + j*cols]; 
     191        widg.getCurrentSize (i,j); 
     192        if (cx < i && cy < j) 
     193            widg.clickEvent (cx, cy, b, state); 
     194    } 
     195     
     196protected: 
     197    const PADDING = 4;  // padding between rows/cols 
     198    int rows, cols;     // number of cells in grid 
     199    int[] rowH;         // row height (highest widget in the row) 
     200    int[] colW;         // column width (widest widget) 
     201    int[] rowY;         // cumulative rowH[i-1] + border and padding 
     202    int[] colX;         // cumulative colW[i-1] + border and padding 
     203    IWidget[] subWidgets;   // all widgets in the grid (by row): 
     204    /* SubWidget order:    [ 2 3 ] 
     205    *                      [ 0 1 ] */ 
     206
     207 
    189208/// First interactible widget 
    190 class ButtonWidget : IWidget 
    191 
    192     const BORDER = 5;   // border width 
    193     int w, h;           // size 
     209class ButtonWidget : Widget 
     210
    194211    bool pushed = false;// true if button is pushed in 
    195212     
    196     this (IWindow, int[] data) { 
     213    this (IWindow, IParentWidget parent, int[] data) { 
    197214        if (data.length != 2) throw new WidgetDataException; 
    198215         
    199         w = data[0] + 2*BORDER; 
    200         h = data[1] + 2*BORDER; 
     216        deco = new WidgetDecoration (parent.decoration); 
     217         
     218        w = data[0] + 2*deco.border; 
     219        h = data[1] + 2*deco.border; 
    201220    } 
    202221     
     
    206225        else 
    207226            gl.setColor (.6f, 0f, .6f); 
    208         gl.drawBox (x,x+w, y,y+h); 
     227        gl.drawBox (x,y, w,h); 
    209228    } 
    210229     
     
    213232        h = this.h; 
    214233    } 
    215     void getCurrentSize (out int w, out int h) { 
    216         w = this.w; 
    217         h = this.h; 
    218     } 
    219      
    220 
    221 +/ 
     234     
     235    void clickEvent (ushort, ushort, ubyte b, bool state) { 
     236        if (b == 1) pushed = state; // very basic 
     237    } 
     238
    222239//END Widgets 
  • mde/gui/gui.d

    r30 r31  
    1414along with this program.  If not, see <http://www.gnu.org/licenses/>. */ 
    1515 
    16 /// Base GUI module. 
     16/** The GUI struct and Window class. 
     17
     18* Possibly add a GUIManager to update all active GUIs and pass coordinates (remapping if necessary). */ 
    1719module mde.gui.gui; 
    1820 
    19 import mde.gui.IWindow; 
    20 import mde.gui.Widget; 
     21import mde.gui.Window; 
    2122import mde.gui.exception; 
    2223 
     
    2627 
    2728import mde.resource.paths; 
    28 import mde.scheduler.InitFunctions; 
    29  
    30 import tango.scrapple.text.convert.parseTo : parseTo; 
    31 import tango.scrapple.text.convert.parseFrom : parseFrom; 
    3229 
    3330import tango.util.log.Log : Log, Logger; 
     
    3633static this () { 
    3734    logger = Log.getLogger ("mde.gui.gui"); 
    38      
    39     init.addFunc (&loadGUI, "loadGUI"); 
    4035} 
    4136 
    4237GUI gui;    // Currently just one instance; handle differently later. 
    43 // Wrap gui.load, since init doesn't handle delegates 
    44 // (do it this way since GUI handling will eventually be changed) 
    45 void loadGUI () { 
    46     gui.load(); 
    47 
     38// Handle externally or with a GUI Manager? 
    4839 
    4940/** A GUI handles a bunch of windows, all to be drawn to the same device. */ 
     41/* NOTE: currently GUI just keeps a list of windows and draw and clickEvent simply calls them all. 
     42* Coords should be stored (and functionality like z-order?). */ 
    5043struct GUI { 
    5144    /** Load all windows from the file gui. */ 
    52     void load() { 
    53         static const fileName = "gui"; 
     45    void load(char[] fileName) { 
    5446        if (!confDir.exists (fileName)) { 
    5547            logger.error ("Unable to load GUI: no config file!"); 
     
    8173            } 
    8274            try { 
    83                 //logger.trace ("1"); 
    84                 int x; 
    8575                w.finalise(); 
    86                 x = 6; 
    8776                windows ~= w;       // only add if load successful 
    88             } catch (WindowLoadException e) { 
     77            } catch (Exception e) { 
    8978                logger.error ("Window failed to load: " ~ e.msg); 
    9079            } 
     
    10190    } 
    10291     
     92    /** Send an input event. 
     93    * 
     94    * I.e. send all mouse click events to all active GUIs, which check the coordinates and forward 
     95    * to any relevent windows. */ 
     96    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 
     97        foreach (w; windows) 
     98            w.clickEvent (cx,cy,b,state); 
     99    } 
     100     
    103101    private: 
    104102    Window[] windows; 
    105103} 
    106  
    107 package:    // Nothing else here is for external use. 
    108  
    109 /** GUI Window class 
    110 * 
    111 * A window class instance does two things: (1) specify a region of the screen upon which the window 
    112 * and its associated widgets are drawn, and (2) load, save, and generally manage all its widgets. 
    113 * 
    114 * Let the window load a table of widget data, of type int[][widgetID]. Each widget will, when 
    115 * created, be given its int[] of data, which this() must confirm is valid (or throw). 
    116 */ 
    117 class Window : mt.IDataSection, IWindow 
    118 { 
    119     alias int widgetID;     // Widget ID type. Each ID is unique under this window. Type is int since this is the widget data type. 
    120      
    121     /** Call after loading is finished to setup the window and confirm that it's valid. 
    122     * 
    123     * Throws: WindowLoadException. Do not use the instance in this case! */ 
    124     void finalise () { 
    125         // Check data was loaded: 
    126         if (widgetData is null) throw new WindowLoadException ("No widget data"); 
    127          
    128         // Create the primary widget (and indirectly all sub-widgets), throwing on error: 
    129         widget = getWidget (0);     // primary widget always has ID 0. 
    130          
    131         widgetData = null;          // data is no longer needed: allow GC to collect (cannot safely delete) 
    132          
    133         widget.getCurrentSize (w,h);// Find the initial size 
    134         w += BORDER_WIDTH * 2;      // Adjust for border 
    135         h += BORDER_WIDTH * 2; 
    136     } 
    137      
    138     /** Get/create a widget by ID. 
    139     * 
    140     * Should $(I only) be called internally and by sub-widgets! */ 
    141     IWidget getWidget (widgetID i) 
    142     in { 
    143         // widgetData is normally left to be garbage collected after widgets have been created: 
    144         assert (widgetData !is null, "getWidget: widgetData is null"); 
    145     } body { 
    146         // See if it's already been created: 
    147         IWidget* p = i in widgets; 
    148         if (p !is null) return *p;  // yes 
    149         else {                      // no 
    150             int[]* d = i in widgetData; 
    151             if (d is null) throw new WindowLoadException ("Widget not found"); 
    152              
    153             // Throws WidgetDataException (a WindowLoadException) if bad data: 
    154             IWidget w = createWidget (this, *d); 
    155             widgets[i] = w; 
    156             return w; 
    157         } 
    158     } 
    159      
    160     void requestRedraw () { 
    161     //FIXME 
    162     } 
    163      
    164     void draw () { 
    165         //BEGIN Window border/back 
    166         gl.setColor (0.0f, 0.0f, 0.5f); 
    167         gl.drawBox (x,x+w, y,y+h); 
    168         //END Window border/back 
    169          
    170         // Tell the widget to draw itself: 
    171         widget.draw(x + BORDER_WIDTH, y + BORDER_WIDTH); 
    172     } 
    173      
    174     //BEGIN Mergetag code 
    175     void addTag (char[] tp, mt.ID id, char[] dt) { 
    176         if (tp == "int[][int]") { 
    177             if (id == "widgetData") { 
    178                 widgetData = cast(int[][widgetID]) parseTo!(int[][int]) (dt); 
    179             } 
    180         } else if (tp == "int") { 
    181             if (id == "x") { 
    182                 x = parseTo!(int) (dt); 
    183             } else if (id == "y") { 
    184                 y = parseTo!(int) (dt); 
    185             } 
    186         } 
    187     } 
    188     void writeAll (ItemDelg dlg) { 
    189     } 
    190     //END Mergetag code 
    191      
    192     private: 
    193     int[][widgetID] widgetData;     // Data for all widgets under this window (deleted after loading) 
    194     IWidget[widgetID] widgets;      // List of all widgets under this window (created on demand). 
    195      
    196     IWidget widget;                 // The primary widget in this window. 
    197     int x,y;                        // Window position 
    198     int w,h;                        // Window size (calculated from Widgets) 
    199      
    200     const BORDER_WIDTH = 8;         // Temporary way to handle window decorations 
    201  
    202 } 
  • mde/input/input.d

    r26 r31  
    149149        * Mouse events don't need config for the GUI. Handle them first so that if no config exists 
    150150        * some functionality at least is retained. 
     151        * 
     152        * Note that the mouse coordinates as reported by SDL put the top-left most pixel at 1,1. 
     153        * Internal coordinates put that pixel at 0,0 (see gui/GUI notes.txt). 
    151154        */ 
    152155        switch (event.type) { 
     
    154157            case SDL_MOUSEBUTTONUP: 
    155158                foreach (dg; mouseClickCallbacks) 
    156                     dg (event.button.x, event.button.y, event.button.button, event.button.state == SDL_PRESSED); 
     159                    dg (event.button.x - 1, event.button.y - 1, 
     160                        event.button.button, event.button.state == SDL_PRESSED); 
    157161                break; 
    158162             
    159163            case SDL_MOUSEMOTION: 
    160                 mouse_x = event.motion.x
    161                 mouse_y = event.motion.y
     164                mouse_x = event.motion.x - 1
     165                mouse_y = event.motion.y - 1
    162166                break; 
    163167             
     
    293297    /** Loads all configs, activating the requested id. 
    294298    * 
    295     * Returns: true if the requested config id wasn't found. 
    296     */ 
    297     bool loadConfig (char[] profile = "Default") { 
     299    * Throws: ConfigLoadException if unable to load any configs or the requested config id wasn't 
     300    *   found. 
     301    */ 
     302    void loadConfig (char[] profile = "Default") { 
    298303        Config.load("input");   // FIXME: filename 
    299304        Config* c_p = profile in Config.configs; 
    300         if (c_p) { 
    301             config = *c_p; 
    302             return false; 
    303         } 
    304         logger.error ("Config profile \""~profile~"\" not found: input won't work unless a valid profile is loaded!"); 
    305         return true; 
     305        if (c_p) config = *c_p; 
     306        else { 
     307            throw new ConfigLoadException; 
     308            logger.error ("Config profile \""~profile~"\" not found: input won't work unless a valid profile is loaded!"); 
     309        } 
    306310    } 
    307311     
  • mde/input/joystick.d

    r29 r31  
    5454        // FIXME: this is sometimes causing a SIGSEGV (Address boundary error) 
    5555        // FIXME: when init fails 
     56        debug logger.trace ("Closing joysticks (this sometimes fails when mde exits prematurely)"); 
    5657        if(js !is null) SDL_JoystickClose(js);  // only close if successfully opened 
     58        debug logger.trace ("Done closing joysticks"); 
    5759    } 
    5860} 
  • mde/mde.d

    r30 r31  
    2323 
    2424import global = mde.global;             // global.run 
    25 import gl = mde.gl;                     // gl.draw 
     25import gl = mde.gl.draw;                // gl.draw() 
    2626import mde.events;                      // pollEvents 
    2727 
  • mde/scheduler/Init.d

    r30 r31  
    2323module mde.scheduler.Init; 
    2424 
     25import mde.scheduler.Init2;     // This module is responsible for setting up some init functions. 
    2526import mde.scheduler.InitFunctions; 
    2627import mde.scheduler.exception; 
  • mde/scheduler/InitFunctions.d

    r30 r31  
    2424module mde.scheduler.InitFunctions; 
    2525 
     26/+ unused 
    2627import tango.util.log.Log : Log, Logger; 
    2728static this() { 
    2829    logger = Log.getLogger ("mde.scheduler.InitFunctions"); 
    29 } 
     30}+/ 
    3031 
    3132void setInitFailure () {    /// Call to indicate failure in an init function 
     
    3738{ 
    3839    struct InitFunction { 
    39         void function() func;       // the actual function 
     40        void delegate() func;       // the actual function 
    4041        char[] name;                // it's name; 
    4142    } 
     
    4849    * thread exceptions is not guaranteed to work. Log a message, call setFailure() and return 
    4950    * instead. */ 
    50     void addFunc (void function() f, char[] name) { 
     51    void addFunc (void delegate() f, char[] name) { 
    5152        InitFunction s; 
    5253        s.func = f; 
     54        s.name = name; 
     55        funcs ~= s; 
     56    } 
     57    void addFunc (void function() f, char[] name) { /// ditto 
     58        InitFunction s; 
     59        s.func.funcptr = f; 
    5360        s.name = name; 
    5461        funcs ~= s; 
     
    6572 
    6673private: 
    67 Logger logger; 
    68 /+ I keep changing my mind about wrapping all init functions: 
    69 const LOG_MSG = "Init function "; 
    70 const TRACE_START = " - running"; 
    71 const TRACE_END = " - completed"; 
    72 const FAIL_MSG = " - failed: "; 
    73 // Template to call function, catching exceptions: 
    74 void initInput(alias Func, char[] name) () { 
    75     try { 
    76         debug logger.trace (LOG_MSG ~ name ~ TRACE_START); 
    77         Func(); 
    78         debug logger.trace (LOG_MSG ~ name ~ TRACE_END); 
    79     } catch (Exception e) { 
    80         logger.fatal (LOG_MSG ~ name ~ FAIL_MSG ~ e.msg); 
    81         initFailure = true; 
    82     } 
    83 
    84 +/ 
     74//Logger logger;