Changeset 42:8bf53e711cc7

Show
Ignore:
Timestamp:
05/14/08 07:31:09 (8 months ago)
Author:
Diggory Hardy <diggory.hardy@gmail.com>
branch:
default
convert_revision:
44b6fc606630ec0d9281e44bae67daa8c4938520
Message:

Partially implemented column/row resizing (code not working well).

Committing before reverting/deleting many edits.

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

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • mde/gui/widget/layout.d

    r41 r42  
    5959            data = widget.adjust (data); 
    6060         
     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         
    6169        /* We basically short-cut setSize by loading previous col/row sizes and doing the final 
    6270         * calculations. 
     
    6674        int lenUsed = 0; 
    6775        if (data.length < rows + cols) {    // data error; use defaults 
    68             colW = colWMin.dup
    69             rowH = rowHMin.dup
     76            colW = cwMin
     77            rowH = rhMin
    7078        } else {                            // sufficient data 
    7179            lenUsed = rows+cols; 
     
    7583            // Check row sizes are valid: 
    7684            //NOTE: this could be made optional 
     85            //NOTE: could also check non-resizable sizes are not too large 
    7786            foreach (i, ref w; colW) 
    78                 if (w < colWMin[i]) w = colWMin[i]; 
     87                if (w < cwMin[i]) w = cwMin[i]; 
    7988            foreach (i, ref h; rowH) 
    80                 if (h < rowHMin[i]) h = rowHMin[i]; 
     89                if (h < rhMin[i]) h = rhMin[i]; 
    8190        } 
    8291         
     
    109118     
    110119    bool isWSizable () { 
    111         return (sizableCols.length != 0); 
     120        // True if any column is resizable: 
     121        foreach (d; colWMin) 
     122            if (d >= 0) 
     123                return true; 
     124        return false; 
    112125    } 
    113126     
    114127    bool isHSizable () { 
    115         return (sizableRows.length != 0); 
     128        foreach (d; rowHMin) 
     129            if (d >= 0) 
     130                return true; 
     131        return false; 
    116132    } 
    117133     
     
    124140    void setSize (int nw, int nh) { 
    125141        // Step 1: calculate the row/column sizes. 
    126         setSizeImpl!(true)  (nw); 
    127         setSizeImpl!(false) (nh); 
     142        w += adjustCellSizes (colW, colWMin, nw - w, true); 
     143        h += adjustCellSizes (rowH, rowHMin, nh - h, true); 
    128144         
    129145        // Step 2: calculate the row/column offsets (positions) and set the sub-widgets sizes. 
     
    150166        int i = cols - 1;                   // starting from right... 
    151167        while (lx < colX[i]) {              // decrement while left of this column 
    152             if (i == 0) return this;        // left of first column 
     168            assert (i > 0, "getWidget: left of first column");  // should be impossible 
    153169            --i; 
    154170        }                                   // now (lx >= colX[i]) 
     
    158174        int j = rows - 1; 
    159175        while (ly < rowY[j]) { 
    160             if (j == 0) return this; 
     176            assert (j > 0, "getWidget: above first row");   // should be impossible 
    161177            --j; 
    162178        } 
     
    173189    } 
    174190     
     191    // Resizing columns & rows 
     192    void clickEvent (ushort cx, ushort cy, ubyte b, bool state) { 
     193        if (b == 1 && state == true) { 
     194            int l = cx - x;    // use relative coords 
     195             
     196            // 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 
     203             
     204            // Find the row 
     205            resizeRow = rows - 1; 
     206            while (l < rowY[resizeRow]) { 
     207                assert (resizeRow > 0, "clickEvent: left of first column"); 
     208                --resizeRow; 
     209            } 
     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). */ 
     215             
     216            dragX = cx; 
     217            dragY = cy; 
     218             
     219            window.gui.addClickCallback (&endCallback); 
     220            window.gui.addMotionCallback (&resizeCallback); 
     221        } 
     222    } 
     223     
    175224    void draw () { 
    176225        super.draw (); 
     
    181230     
    182231private: 
     232    //BEGIN Cache calculation functions 
    183233    /* Calculations which need to be run whenever a new sub-widget structure is set 
    184234     * (i.e. to produce cached data calculated from construction data). */ 
     
    211261         
    212262        // Find which cols/rows are resizable: 
    213         sizableCols = null;     // clear these because we append to them 
    214         sizableRows = null; 
    215          
    216263        forCols: 
    217264        for (uint i = 0; i < cols; ++i) {                       // for each column 
    218265            for (uint j = 0; j < subWidgets.length; j += cols)  // for each row 
    219                 if (!subWidgets[i+j].isWSizable)        // column not resizable 
     266                if (!subWidgets[i+j].isWSizable) {      // column not resizable 
     267                    colWMin[i] = -colWMin[i];           // negate to show not resizable 
    220268                    continue forCols;                   // continue the outer for loop 
     269                } 
    221270                 
    222271            // column is resizable if we get to here 
    223             sizableCols ~= i; 
     272            // entry is left positive, meaning it is resizable 
    224273        } 
    225274         
     
    227276        for (uint i = 0; i < subWidgets.length; i += cols) {    // for each row 
    228277            for (uint j = 0; j < cols; ++j)                     // for each column 
    229                 if (!subWidgets[i+j].isHSizable) 
     278                if (!subWidgets[i+j].isHSizable) { 
     279                    j = i / cols;       // reuse: will be reinitialised next iteration 
     280                    rowHMin[j] = -rowHMin[j]; 
    230281                    continue forRows; 
    231                  
    232             sizableRows ~= i / cols;    // the current row 
     282                } 
    233283        } 
    234284    } 
     
    258308            widget.setSize (colW[i % cols], rowH[i / cols]); 
    259309    } 
    260      
    261     /* setSize generalised for either dimension; w/h is renamed d, col/row renamed cell. */ 
    262     void setSizeImpl(bool W) (int nd) { 
    263         static if (W) { 
    264             alias w         d; 
    265             alias mw        md; 
    266             alias colW      cellD; 
    267             alias colWMin   cellDMin; 
    268             alias sizableCols sizableCells; 
    269         } else { 
    270             alias h         d; 
    271             alias mh        md; 
    272             alias rowH      cellD; 
    273             alias rowHMin   cellDMin; 
    274             alias sizableRows sizableCells; 
    275         } 
    276         // Could occur if adjust isn't called first, but this would be a code error: 
    277         assert (cellD !is null, "setSizeImpl: cellD is null"); 
    278          
    279         /* For each of width and height, there are several cases: 
    280         *  [new value is] more than old value 
    281         *  ->  enlarge any row/column 
    282         *  same as old value 
    283         *  ->  do nothing 
    284         *  more than min but less than current value 
    285         *  ->  find an enlarged row/col and reduce size 
    286         *  ->  repeat if necessary 
    287         *  minimal value or less 
    288         *  -> clamp to min and use min col/row sizes 
    289         */ 
    290         if (nd > d) {       // expand (d < nd) 
    291             if (sizableCells.length) {               // check there is a resizable col/row 
    292                 cellD[sizableCells[$-1]] += nd - d;  // new size 
    293                 d = nd; 
     310    //END Cache calculation functions 
     311     
     312    /* Adjust the total size of rows/columns (including spacing) by diff. 
     313     * 
     314     * Params: 
     315     *  cellD       = current sizes; is adjusted by the function to new sizes 
     316     *  cellDMin    = minimal sizes (see colWMin/rowHMin) 
     317     *  diff        = amount to increase/decrease the total size 
     318     *  startHigh   = if true, start resizing from the tail end of cellD, instead of the beginning 
     319     * 
     320     * Returns: 
     321     *  The amount adjusted. This may be larger than diff, since cellD is clamped by cellDMin. 
     322     */ 
     323    int adjustCellSizes (ref int[] cellD, ref int[] cellDMin, int diff, bool startHigh) 
     324    in {// Could occur if adjust isn't called first, but this would be a code error: 
     325        assert (cellD !is null, "adjustCellSizes: cellD is null"); 
     326    } body { 
     327        size_t i = (startHigh ? cellD.length-1 : 0); 
     328        size_t ic = (startHigh ? -1 : 1);   // amount to iterate to next cell 
     329         
     330        // FIXME: could do with an overhaul 
     331        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; 
     341            return diff; 
     342        } 
     343        else if (diff < 0) {    // decrease 
     344            int rd = diff;      // running diff 
     345            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 
    294361            } 
    295         } else if (nd < d) { 
    296             if (nd > md) {  // shrink (md < nd < d) 
    297                 int toReduce = nd - d;  // negative 
    298                 foreach_reverse (cell; sizableCells) { 
    299                     cellD[cell] += toReduce; 
    300                     toReduce = cellD[cell] - cellDMin[cell]; 
    301                     if (toReduce < 0)   // reduced too far 
    302                         cellD[cell] = cellDMin[cell]; 
    303                     else                // ok; cellD >= cellDMin 
    304                         break; 
    305                 } 
    306                 d = nd; 
    307             } else {        // clamp  (nd <= md) 
    308                 cellD = cellDMin.dup;   // duplicate so future edits don't affect cellDMin 
    309                 d = md; 
     362        } 
     363        else                   // no adjustment needed 
     364            return 0; 
     365    } 
     366     
     367    //BEGIN Col/row resizing 
     368    void resizeCallback (ushort cx, ushort cy) { 
     369        int move;           // NOTE: all resizing is relative, unlike in Window 
     370         
     371        if (resizeCol >= 0) { 
     372            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..$]; 
     377             
     378            // do shrinking first (in case we hit the minimum) 
     379            // 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); 
     383            } else { 
     384                move = -adjustCellSizes (d0, m0, move, true); 
     385                adjustCellSizes (d1, m1, move, false); 
    310386            } 
    311         }                   // third possibility: nd = d 
     387        } 
     388        // FIXME: vertical 
     389         
     390        window.requestRedraw; 
     391    } 
     392    bool endCallback (ushort cx, ushort cy, ubyte b, bool state) { 
     393        if (b == 1 && state == false) { 
     394            window.gui.removeCallbacks (cast(void*) this); 
     395            return true;    // we've handled the up-click 
     396        } 
     397        return false;       // we haven't handled it 
    312398    } 
    313399     
    314400protected: 
     401    // Data for resizing cols/rows: 
     402    int resizeCol = -1, // col/row being resized; 
     403        resizeRow = -1; // negative if none 
     404    int dragX, dragY;   // coords where drag starts 
     405    //END Col/row resizing 
     406     
    315407    // Construction data (saved): 
    316408    int cols, rows;     // number of cells in grid 
     
    320412     
    321413    // Cached data calculated from construction data: 
    322     int[] colWMin;      // minimal column width 
    323     int[] rowHMin;      // minimal row height 
     414    int[] colWMin;      // absolute value is minimal column width / row height 
     415    int[] rowHMin;      // negative if fixed size, entry >= 0 if resizible 
    324416    int mw, mh;         // minimal dimensions 
    325      
    326     int[] sizableCols;   // all resizable columns / rows, empty if not resizable 
    327     int[] sizableRows;   // resizing is done from last entry 
    328417     
    329418    // Mutable data (saved):