| | 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 | |
|---|
| 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 |
|---|
| 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); |
|---|