Changeset 43:1530d9c04d4d

Show
Ignore:
Timestamp:
05/15/08 05:39:57 (8 months ago)
Author:
Diggory Hardy <diggory.hardy@gmail.com>
branch:
default
convert_revision:
3f46d85fe9161935762020890cfc39ce37d3e422
Message:

Column/row resizing implemented for GridLayoutWidget? (finally)!

Also new exitImmediately option and a few debug scope(failure) log messages.

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

Files:

Legend:

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

    r41 r43  
    44 
    55In progress: 
    6 Implement row/col sizing. 
    76 
    87 
     
    109To do (importance 0-5: 0 pointless, 1 no obvious impact now, 2 todo sometime, 3 useful, 4 important, 5 urgent): 
    1110Also see todo.txt and FIXME/NOTE comment marks. 
     114   Not guaranteed to catch up-click ending callback! Appears not to be a problem... 
    12124   OutOfMemoryException is not currently checked for − it should be at least in critical places (use high-level catching of all errors?). 
    13133   on-event draw support (mde.events and GUI need to tell mde.mde) 
     
    15153   Update scheduler as outlined in FIXME. 
    16163   Windows building/compatibility (currently partial) 
     172   Options need a "level": simple options, for advanced users, for debugging only, etc. 
    17182   Command-line options for paths to by-pass normal path finding functionality. 
    18192   Consider replacing byte/short types with int type 
     
    5051 
    5152Done (for git log message): 
    52 The renderer now controls which parts of the window border allow resizing. 
  • data/L10n/OptionsMisc.mtt

    r29 r43  
    44<entry|logLevel=["Logging level","Controls which messages are logged, from 0=trace to 6=none (default: 1=info)."]> 
    55<entry|L10n=["Localisation","Specifies the language to use."]> 
     6<entry|pollInterval=["Polling interval","Delay in main loop to limit CPU usage"]> 
     7<entry|exitImmediately=["Exit immediately","Load files and exit immediately, without running main loop (for debugging)"]> 
  • data/conf/gui.mtt

    r40 r43  
    44<int|x=30> 
    55<int|y=80> 
    6 <int[][int]|widgetData=[0:[0x4010,200,200]]> 
     6<int[][int]|widgetData=[0:[0xB004,2,1,1,2],1:[0x4010,200,200],2:[0x1,100,100]]> 
    77{W2} 
    88<int|x=150> 
  • data/conf/options.mtt

    r36 r43  
    22{misc} 
    33<bool|useThreads=false> 
     4<bool|exitImmediately=false> 
    45<char[]|L10n="en-GB"> 
    5 <int|logLevel=0
     6<int|logLevel=1
    67<double|pollInterval=0.01> 
    78 
  • mde/Options.d

    r36 r43  
    342342OptionsMisc miscOpts; 
    343343class OptionsMisc : Options { 
    344     alias store!("useThreads") BOOL; 
     344    alias store!("useThreads", "exitImmediately") BOOL; 
    345345    alias store!("logLevel") INT; 
    346346    alias store!("pollInterval") DOUBLE; 
  • mde/gui/Gui.d

    r41 r43  
    146146    * Sends the event on to the relevant windows and all click callbacks. */ 
    147147    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 
     148        debug scope (failure) 
     149                logger.warn ("clickEvent: failed!"); 
    148150        // NOTE: buttons receive the up-event even when drag-callbacks are in place. 
    149151        foreach (dg; clickCallbacks) 
     
    166168    * Sends the event on to all motion callbacks. */ 
    167169    void motionEvent (ushort cx, ushort cy) { 
     170        debug scope (failure) 
     171                logger.warn ("motionEvent: failed!"); 
    168172        foreach (dg; motionCallbacks) 
    169173            dg (cx, cy); 
  • mde/gui/renderer/IRenderer.d

    r41 r43  
    7575    void drawWidgetBack (int x, int y, int w, int h); 
    7676     
     77    /** Draws a blank widget (temporary) */ 
     78    void drawBlank (int x, int y, int w, int h); 
     79     
    7780    /** Draws a button frame, in if pushed == true. */ 
    7881    void drawButton (int x, int y, int w, int h, bool pushed); 
  • mde/gui/renderer/SimpleRenderer.d

    r41 r43  
    9494    void drawWidgetBack (int x, int y, int w, int h) {} 
    9595     
     96    void drawBlank (int x, int y, int w, int h) { 
     97        gl.setColor (.4f, .4f, .4f); 
     98        gl.drawBox (x,y, w,h); 
     99    } 
     100     
    96101    void drawButton (int x, int y, int w, int h, bool pushed) { 
    97102        if (pushed) 
  • mde/gui/widget/Widget.d

    r41 r43  
    129129        h = (nh >= 0 ? nh : 0); 
    130130    } 
     131     
     132    void draw () { 
     133        super.draw; 
     134         
     135        window.renderer.drawBlank (x,y, w,h); 
     136    } 
    131137} 
    132138 
     
    138144        if (data.length != 3) throw new WidgetDataException; 
    139145        super (wind, data); 
     146    } 
     147    void draw () { 
     148        super.draw; 
     149         
     150        window.renderer.drawBlank (x,y, w,h); 
    140151    } 
    141152} 
     
    176187    // Called when a mouse motion/click event occurs while (held == true) 
    177188    bool clickWhileHeld (ushort cx, ushort cy, ubyte b, bool state) { 
    178         //NOTE: which button? test 
    179         if (cx >= x && cx < x+w && cy >= y && cy < y+h) // button event 
    180             Stdout ("Button clicked!").newline; 
    181          
    182         pushed = false; 
    183         window.requestRedraw; 
    184         window.gui.removeCallbacks (cast(void*) this); 
    185          
     189        if (b == 1 && state == false) { 
     190            if (cx >= x && cx < x+w && cy >= y && cy < y+h) // button event 
     191                Stdout ("Button clicked!").newline; 
     192             
     193            pushed = false; 
     194            window.requestRedraw; 
     195            window.gui.removeCallbacks (cast(void*) this); 
     196             
     197            return true; 
     198        } 
    186199        return false; 
    187200    } 
  • mde/gui/widget/layout.d

    r42 r43  
    1919import mde.gui.widget.Widget; 
    2020import mde.gui.exception; 
     21 
     22import tango.io.Stdout; 
     23debug { 
     24    import tango.util.log.Log : Log, Logger; 
     25    private Logger logger; 
     26    static this () { 
     27        logger = Log.getLogger ("mde.gui.widget.layout"); 
     28    } 
     29} 
    2130 
    2231/** Encapsulates a grid of Widgets. 
     
    5968            data = widget.adjust (data); 
    6069         
    61         // colWMin/rowHMin are needed as absolute quantities in this function: 
    62         int[] cwMin = new int[colWMin.length]; 
    63         foreach (i,x; colWMin) 
    64             cwMin[i] = x>=0 ? x : -x; 
    65         int[] rhMin = new int[rowHMin.length]; 
    66         foreach (i,x; rowHMin) 
    67             rhMin[i] = x>=0 ? x : -x; 
    68          
    6970        /* We basically short-cut setSize by loading previous col/row sizes and doing the final 
    7071         * calculations. 
     
    7475        int lenUsed = 0; 
    7576        if (data.length < rows + cols) {    // data error; use defaults 
    76             colW = cwMin
    77             rowH = rhMin
     77            colW = colWMin.dup
     78            rowH = rowHMin.dup
    7879        } else {                            // sufficient data 
    7980            lenUsed = rows+cols; 
     
    8586            //NOTE: could also check non-resizable sizes are not too large 
    8687            foreach (i, ref w; colW) 
    87                 if (w < cwMin[i]) w = cwMin[i]; 
     88                if (w < colWMin[i]) w = colWMin[i]; 
    8889            foreach (i, ref h; rowH) 
    89                 if (h < rhMin[i]) h = rhMin[i]; 
     90                if (h < rowHMin[i]) h = rowHMin[i]; 
    9091        } 
    9192         
     
    118119     
    119120    bool isWSizable () { 
    120         // True if any column is resizable: 
    121         foreach (d; colWMin) 
    122             if (d >= 0) 
    123                 return true; 
    124         return false; 
     121        return (sizableCols.length != 0); 
    125122    } 
    126123     
    127124    bool isHSizable () { 
    128         foreach (d; rowHMin) 
    129             if (d >= 0) 
    130                 return true; 
    131         return false; 
     125        return (sizableRows.length != 0); 
    132126    } 
    133127     
     
    140134    void setSize (int nw, int nh) { 
    141135        // Step 1: calculate the row/column sizes. 
    142         w += adjustCellSizes (colW, colWMin, nw - w, true); 
    143         h += adjustCellSizes (rowH, rowHMin, nh - h, true); 
    144          
    145         // Step 2: calculate the row/column offsets (positions) and set the sub-widgets sizes. 
     136        w += adjustCellSizes (colW, colWMin, sizableCols, nw - w, true); 
     137        h += adjustCellSizes (rowH, rowHMin, sizableRows, nh - h, true); 
     138         
     139        // Step 2: calculate the row/column offsets (positions) and set the sub-widget's sizes. 
    146140        genCachedMutableData; 
    147141         
     
    166160        int i = cols - 1;                   // starting from right... 
    167161        while (lx < colX[i]) {              // decrement while left of this column 
    168             assert (i > 0, "getWidget: left of first column");  // should be impossible 
     162            debug assert (i > 0, "getWidget: left of first column");  // should be impossible 
    169163            --i; 
    170164        }                                   // now (lx >= colX[i]) 
     
    174168        int j = rows - 1; 
    175169        while (ly < rowY[j]) { 
    176             assert (j > 0, "getWidget: above first row");   // should be impossible 
     170            debug assert (j > 0, "getWidget: above first row");   // should be impossible 
    177171            --j; 
    178172        } 
     
    191185    // Resizing columns & rows 
    192186    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 
     187        debug scope (failure) 
     188                logger.warn ("clickEvent: failure"); 
    193189        if (b == 1 && state == true) { 
    194             int l = cx - x;    // use relative coords 
     190            /* Note: Because of getWidget, this function is only called if the click is not on a 
     191            * sub-widget, so we know it's on some divisor (so at least one of resizeCol and 
     192            * resizeRow is non-negative). */ 
    195193             
    196194            // Find the column 
    197             resizeCol = cols - 1;           // from the right... 
    198             while (l < colX[resizeCol]) {   // decrement while left of this column 
    199                 assert (resizeCol > 0, "clickEvent: left of first column"); 
    200                 --resizeCol; 
    201             }                               // now (l >= colX[resizeCol]) 
    202             if (l < colX[resizeCol] + colW[resizeCol]) resizeCol = -1;  // on a sub-widget 
     195            if (sizableCols.length != 0) { 
     196                int l = cx - x;                 // use relative coords 
     197                size_t i = cols - 1;            // index, from right 
     198                while (l < colX[i]) {           // decrement while left of this column 
     199                    debug assert (i > 0, "clickEvent: left of first column"); 
     200                    --i; 
     201                }                               // now (l >= colX[resizeCol]) 
     202                if (l < colX[i] + colW[i]) i = -1;  // on a sub-widget 
     203                 
     204                // Set resizeColsL / resizeColsH 
     205                // Want to find j such that [0..j],[j..$] divide sizableCols about i: 
     206                size_t j = 0; 
     207                while (j < sizableCols.length && sizableCols[j] <= i) ++j; 
     208                 
     209                resizeColsL = sizableCols[0..j]; 
     210                resizeColsH = sizableCols[j..$]; 
     211                 
     212                // Cannot resize if either list is empty. resizeCallback checks the length of L, 
     213                // but to save it checking R too, we set L's length zero if R's is. 
     214                if (resizeColsH.length == 0) 
     215                    resizeColsL = null; 
     216            } 
    203217             
    204218            // Find the row 
    205             resizeRow = rows - 1; 
    206             while (l < rowY[resizeRow]) { 
    207                 assert (resizeRow > 0, "clickEvent: left of first column"); 
    208                 --resizeRow; 
     219            if (sizableRows.length != 0) { 
     220                int l = cy - y; 
     221                size_t i = rows - 1; 
     222                while (l < rowY[i]) { 
     223                    debug assert (i > 0, "clickEvent: above first row"); 
     224                    --i; 
     225                } 
     226                if (l < rowY[i] + rowH[i]) i = -1; 
     227                 
     228                size_t j = 0; 
     229                while (j < sizableRows.length && sizableRows[j] <= i) ++j; 
     230                 
     231                resizeRowsL = sizableRows[0..j]; 
     232                resizeRowsH = sizableRows[j..$]; 
     233                 
     234                if (resizeRowsH.length == 0) 
     235                    resizeRowsL = null; 
    209236            } 
    210             if (l < rowY[resizeRow] + rowH[resizeRow]) resizeRow = -1;  // on a sub-widget 
    211              
    212             /* Note: Because of getWidget, this function is only called if the click is not on a 
    213              * sub-widget, so we know it's on some divisor (so at least one of resizeCol and 
    214              * resizeRow is non-negative). */ 
     237             
     238            if (resizeColsL is null && resizeRowsL is null) 
     239                return;     // no resizing to do 
    215240             
    216241            dragX = cx; 
     
    261286         
    262287        // Find which cols/rows are resizable: 
     288        sizableCols = sizableRows = null;   // reset; we're about to concatenate to them 
     289         
    263290        forCols: 
    264291        for (uint i = 0; i < cols; ++i) {                       // for each column 
    265292            for (uint j = 0; j < subWidgets.length; j += cols)  // for each row 
    266                 if (!subWidgets[i+j].isWSizable) {      // column not resizable 
    267                     colWMin[i] = -colWMin[i];           // negate to show not resizable 
     293                if (!subWidgets[i+j].isWSizable)        // column not resizable 
    268294                    continue forCols;                   // continue the outer for loop 
    269                 } 
    270295                 
    271296            // column is resizable if we get to here 
    272             // entry is left positive, meaning it is resizable 
     297            sizableCols ~= i; 
    273298        } 
    274299         
     
    276301        for (uint i = 0; i < subWidgets.length; i += cols) {    // for each row 
    277302            for (uint j = 0; j < cols; ++j)                     // for each column 
    278                 if (!subWidgets[i+j].isHSizable) { 
    279                     j = i / cols;       // reuse: will be reinitialised next iteration 
    280                     rowHMin[j] = -rowHMin[j]; 
     303                if (!subWidgets[i+j].isHSizable) 
    281304                    continue forRows; 
    282                 } 
     305             
     306            sizableRows ~= i / cols; 
    283307        } 
    284308    } 
     
    315339     *  cellD       = current sizes; is adjusted by the function to new sizes 
    316340     *  cellDMin    = minimal sizes (see colWMin/rowHMin) 
     341     *  sizableCells= List of indexes in cellD for cells which are resizable 
    317342     *  diff        = amount to increase/decrease the total size 
    318343     *  startHigh   = if true, start resizing from the tail end of cellD, instead of the beginning 
     
    321346     *  The amount adjusted. This may be larger than diff, since cellD is clamped by cellDMin. 
    322347     */ 
    323     int adjustCellSizes (ref int[] cellD, ref int[] cellDMin, int diff, bool startHigh) 
     348    int adjustCellSizes (ref int[] cellD, ref int[] cellDMin, ref size_t[] sizableCells, int diff, bool startHigh) 
    324349    in {// Could occur if adjust isn't called first, but this would be a code error: 
    325350        assert (cellD !is null, "adjustCellSizes: cellD is null"); 
    326351    } body { 
    327         size_t i = (startHigh ? cellD.length-1 : 0); 
    328         size_t ic = (startHigh ? -1 : 1);   // amount to iterate to next cell 
     352        // Cannot resize if no cells are sizable: 
     353        if (sizableCells.length == 0) return 0; 
     354         
     355        size_t si = (startHigh ? sizableCells.length-1 : 0);    // starting index of sizableCells 
    329356         
    330357        // FIXME: could do with an overhaul 
    331358        if (diff > 0) {         // increase size of first resizable cell 
    332             do { 
    333                 if (cellDMin[i] >= 0) { // cell is resizable 
    334                     cellD[i] += diff; 
    335                     return diff; 
    336                 } 
    337                 i += ic; 
    338             } while (i >= 0 && i < cellD.length); 
    339             // no resizable cell: revert to original 
    340             cellD[(startHigh ? cellD.length-1 : 0)] += diff; 
     359            cellD[sizableCells[si]] += diff; 
    341360            return diff; 
    342361        } 
    343362        else if (diff < 0) {    // decrease 
     363            size_t sc = (startHigh ? -1 : 1);   // amount to iterate 
     364            size_t ci;          // index in cellD 
    344365            int rd = diff;      // running diff 
    345366            while (true) { 
    346                 // NOTE: could do this differently so that enlarged cells can be shrunk 
    347                 if (cellDMin[i] >= 0) { // i.e., if resizable: 
    348                     cellD[i] += rd; // decrease this cell's size (but may be too much) 
    349                     rd = cellD[i] - cellDMin[i]; 
    350                     if (rd >= 0)    // OK; we're done 
    351                         return diff;// we hit the mark exactly 
    352                      
    353                     // else we decreased it too much! 
    354                     cellD[i] = cellDMin[i]; 
    355                     // rd is remainder to decrease by 
    356                 } 
    357                  
    358                 i += (startHigh ? -1 : 1);  // next cell 
    359                 if (i < 0 || i >= cellD.length) // run out of next cells 
    360                     return diff - rd;       // still had rd left to decrease 
     367                ci = sizableCells[si]; 
     368                 
     369                cellD[ci] += rd; // decrease this cell's size (but may be too much) 
     370                rd = cellD[ci] - cellDMin[ci]; 
     371                if (rd >= 0)    // OK; we're done 
     372                    return diff;// we hit the mark exactly 
     373                 
     374                // else we decreased it too much! 
     375                cellD[ci] = cellDMin[ci]; 
     376                // rd is remainder to decrease by 
     377                 
     378                si += sc;       // iterate 
     379                if (si < 0 || si >= sizableCells.length)        // run out of next cells 
     380                    return diff - rd;   // still had rd left to decrease 
    361381            } 
    362382        } 
     
    369389        int move;           // NOTE: all resizing is relative, unlike in Window 
    370390         
    371         if (resizeCol >= 0) { 
     391        if (resizeColsL.length != 0) { 
    372392            move = cx - dragX; 
    373             int[] d0 = colW[0..resizeCol]; 
    374             int[] d1 = colW[resizeCol..$]; 
    375             int[] m0 = colWMin[0..resizeCol]; 
    376             int[] m1 = colWMin[resizeCol..$]; 
    377393             
    378394            // do shrinking first (in case we hit the minimum) 
    379395            // Note: we rely on x[a..b] pointing to the same memory as x 
    380             if (move > 0) { 
    381                 move = -adjustCellSizes (d1, m1, -move, false); 
    382                 adjustCellSizes (d0, m0, move, true); 
     396            if (move < 0) { 
     397                move = -adjustCellSizes (colW, colWMin, resizeColsL, move, false); 
     398                adjustCellSizes (colW, colWMin, resizeColsH, move, true); 
    383399            } else { 
    384                 move = -adjustCellSizes (d0, m0, move, true); 
    385                 adjustCellSizes (d1, m1, move, false); 
     400                move = -adjustCellSizes (colW, colWMin, resizeColsH, -move, true); 
     401                adjustCellSizes (colW, colWMin, resizeColsL, move, false); 
    386402            } 
    387         } 
    388         // FIXME: vertical 
    389          
     403             
     404            dragX = cx; 
     405        } 
     406         
     407        if (resizeRowsL.length != 0) { 
     408            move = cy - dragY; 
     409             
     410            // do shrinking first (in case we hit the minimum) 
     411            // Note: we rely on x[a..b] pointing to the same memory as x 
     412            if (move < 0) { 
     413                move = -adjustCellSizes (rowH, rowHMin, resizeRowsL, move, false); 
     414                adjustCellSizes (rowH, rowHMin, resizeRowsH, move, true); 
     415            } else { 
     416                move = -adjustCellSizes (rowH, rowHMin, resizeRowsH, -move, true); 
     417                adjustCellSizes (rowH, rowHMin, resizeRowsL, move, false); 
     418            } 
     419             
     420            dragY = cy; 
     421        } 
     422         
     423        // NOTE: this might be able to be made more efficient, but basically this all needs to happen: 
     424        genCachedMutableData; 
     425        setPosition (x,y); 
    390426        window.requestRedraw; 
    391427    } 
     
    393429        if (b == 1 && state == false) { 
    394430            window.gui.removeCallbacks (cast(void*) this); 
     431            // Remove unwanted data (although it shouldn't free any memory): 
     432            resizeColsL = resizeColsH = resizeRowsL = resizeRowsH = null; 
    395433            return true;    // we've handled the up-click 
    396434        } 
     
    400438protected: 
    401439    // Data for resizing cols/rows: 
    402     int resizeCol = -1, // col/row being resized; 
    403         resizeRow = -1; // negative if none 
    404440    int dragX, dragY;   // coords where drag starts 
     441    // Lists of columns/rows with lower/higher index than the resize position 
     442    size_t[] resizeColsL, resizeColsH, resizeRowsL, resizeRowsH; 
    405443    //END Col/row resizing 
    406444     
    407     // Construction data (saved): 
     445     
     446    //BEGIN Construction (i.e. non-mutable) data 
    408447    int cols, rows;     // number of cells in grid 
    409     IWidget[] subWidgets;   // all widgets in the grid (by row): 
    410     /* SubWidget order:    [ 0 1 ] 
    411     *                      [ 2 3 ] */ 
     448     
     449    /* All widgets in the grid, by row. Order:  [ 0 1 ] 
     450     *                                          [ 2 3 ] */ 
     451    IWidget[] subWidgets; 
    412452     
    413453    // Cached data calculated from construction data: 
    414     int[] colWMin;      // absolute value is minimal column width / row height 
    415     int[] rowHMin;      // negative if fixed size, entry >= 0 if resizible 
     454    // Minimal column width / row height: 
     455    int[] colWMin, rowHMin; 
    416456    int mw, mh;         // minimal dimensions 
    417457     
    418     // Mutable data (saved): 
    419     int[] colW;         // column width (widest widget) 
    420     int[] rowH;         // row height (highest widget in the row) 
     458    // All resizable cols/rows, in order: 
     459    size_t[] sizableCols, sizableRows; 
     460    //END Construction data 
     461     
     462     
     463    //BEGIN Mutable data 
     464    int[] colW, rowH;   // column width / row height (largest size in col/row) 
    421465     
    422466    // Cached data calculated from construction and mutable data: 
    423     int[] colX;         // cumulative colW[i-1] + padding (add x to get column's left x-coord) 
    424     int[] rowY;         // cumulative rowH[i-1] + padding 
     467    int[] colX, rowY;   // cumulative colW[i-1] + padding (add x to get column's left x-coord) 
     468    //END Mutable data 
    425469} 
  • mde/mde.d

    r36 r43  
    5555    } 
    5656     
    57     if (miscOpts.pollInterval !<= 0.1 || miscOpts.pollInterval !>= 0.0) 
    58         Options.setDouble ("misc", "pollInterval", 0.0); 
     57    if (miscOpts.pollInterval !<= 1.0 || miscOpts.pollInterval !>= 0.0) 
     58        Options.setDouble ("misc", "pollInterval", 0.01); 
    5959    //END Initialisation 
    6060     
  • mde/scheduler/Init.d

    r32 r43  
    140140        } 
    141141         
    142         // Now re-set the logging level: 
    143         Log.getRootLogger.setLevel (cast(Log.Level) miscOpts.logLevel, true);  // set the stored log level 
     142        // Now re-set the logging level, using the value from the config file: 
     143        Log.getRootLogger.setLevel (cast(Log.Level) miscOpts.logLevel, true); 
     144        // And set this (debug option): 
     145        imde.run = !miscOpts.exitImmediately; 
    144146        //END Pre-init 
    145147