1 /// 2 module nanogui.layout; 3 4 import std.container.array : Array; 5 import std.algorithm : max; 6 7 import nanogui.window : Window; 8 import nanogui.common; 9 import nanogui.widget; 10 11 /* 12 NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>. 13 The widget drawing code is based on the NanoVG demo application 14 by Mikko Mononen. 15 16 All rights reserved. Use of this source code is governed by a 17 BSD-style license that can be found in the LICENSE.txt file. 18 */ 19 /** 20 * A collection of useful layout managers. The \ref nanogui.GridLayout 21 * was contributed by Christian Schueller. 22 */ 23 24 /// The different kinds of alignments a layout can perform. 25 enum Alignment : ubyte 26 { 27 Minimum = 0, /// Take only as much space as is required. 28 Middle, /// Center align. 29 Maximum, /// Take as much space as is allowed. 30 Fill /// Fill according to preferred sizes. 31 } 32 33 /// The direction of data flow for a layout. 34 enum Orientation 35 { 36 Horizontal = 0, /// Layout expands on horizontal axis. 37 Vertical /// Layout expands on vertical axis. 38 } 39 40 /** 41 * interface Layout 42 * 43 * Basic interface of a layout engine. 44 */ 45 interface Layout 46 { 47 public: 48 /** 49 * Performs any and all resizing applicable. 50 * 51 * Params: 52 * nvg = The `NanoVG` context being used for drawing. 53 * widget = The Widget this layout is controlling sizing for. 54 */ 55 void performLayout(NVGContext nvg, Widget widget) const; 56 57 /** 58 * The preferred size for this layout. 59 * 60 * Params: 61 * nvg = The `NanoVG` context being used for drawing. 62 * widget = The Widget this layout's preferred size is considering. 63 * 64 * Returns: 65 * The preferred size, accounting for things such as spacing, padding 66 * for icons, etc. 67 */ 68 Vector2i preferredSize(NVGContext nvg, const Widget widget, const Widget skipped = null) const; 69 } 70 71 /** 72 * Simple horizontal/vertical box layout 73 * 74 * This widget stacks up a bunch of widgets horizontally or vertically. It adds 75 * margins around the entire container and a custom spacing between adjacent 76 * widgets. 77 */ 78 class BoxLayout : Layout 79 { 80 public: 81 /** 82 * Construct a box layout which packs widgets in the given `Orientation` 83 * 84 * Params: 85 * orientation = The Orientation this BoxLayout expands along 86 * alignment = Widget alignment perpendicular to the chosen orientation 87 * margin = Margin around the layout container 88 * spacing = Extra spacing placed between widgets 89 */ 90 this(Orientation orientation, Alignment alignment = Alignment.Middle, 91 int margin = 0, int spacing = 0) 92 { 93 mOrientation = orientation; 94 mAlignment = alignment; 95 mMargin = margin; 96 mSpacing = spacing; 97 } 98 99 /// The Orientation this BoxLayout is using. 100 final Orientation orientation() const { return mOrientation; } 101 102 /// Sets the Orientation of this BoxLayout. 103 final void setOrientation(Orientation orientation) { mOrientation = orientation; } 104 105 /// The Alignment of this BoxLayout. 106 final Alignment alignment() const { return mAlignment; } 107 108 /// Sets the Alignment of this BoxLayout. 109 final void setAlignment(Alignment alignment) { mAlignment = alignment; } 110 111 /// The margin of this BoxLayout. 112 final int margin() const { return mMargin; } 113 114 /// Sets the margin of this BoxLayout. 115 final void setMargin(int margin) { mMargin = margin; } 116 117 /// The spacing this BoxLayout is using to pad in between widgets. 118 final int spacing() const { return mSpacing; } 119 120 /// Sets the spacing of this BoxLayout. 121 final void setSpacing(int spacing) { mSpacing = spacing; } 122 123 /// Implementation of the layout interface 124 /// See `Layout.preferredSize`. 125 override Vector2i preferredSize(NVGContext nvg, const Widget widget, const Widget skipped = null) const 126 { 127 Vector2i size = Vector2i(2*mMargin, 2*mMargin); 128 129 int yOffset = 0; 130 auto window = cast(Window) widget; 131 if (window && window.title().length) { 132 if (mOrientation == Orientation.Vertical) 133 size[1] += widget.theme.mWindowHeaderHeight - mMargin/2; 134 else 135 yOffset = widget.theme.mWindowHeaderHeight; 136 } 137 138 bool first = true; 139 int axis1 = cast(int) mOrientation; 140 int axis2 = (cast(int) mOrientation + 1)%2; 141 foreach (w; widget.children) 142 { 143 if (!w.visible || w is skipped) 144 continue; 145 if (first) 146 first = false; 147 else 148 size[axis1] += mSpacing; 149 150 Vector2i ps = w.preferredSize(nvg); 151 Vector2i fs = w.fixedSize(); 152 auto targetSize = Vector2i( 153 fs[0] ? fs[0] : ps[0], 154 fs[1] ? fs[1] : ps[1] 155 ); 156 157 size[axis1] += targetSize[axis1]; 158 size[axis2] = max(size[axis2], targetSize[axis2] + 2*mMargin); 159 first = false; 160 } 161 return size + Vector2i(0, yOffset); 162 } 163 164 /// See `Layout.performLayout`. 165 override void performLayout(NVGContext nvg, Widget widget) const 166 { 167 Vector2i fs_w = widget.fixedSize(); 168 auto containerSize = Vector2i( 169 fs_w[0] ? fs_w[0] : widget.width, 170 fs_w[1] ? fs_w[1] : widget.height 171 ); 172 173 int axis1 = cast(int) mOrientation; 174 int axis2 = (cast(int) mOrientation + 1)%2; 175 int position = mMargin; 176 int yOffset = 0; 177 178 import nanogui.window : Window; 179 auto window = cast(const Window)(widget); 180 if (window && window.title.length) 181 { 182 if (mOrientation == Orientation.Vertical) 183 { 184 position += widget.theme.mWindowHeaderHeight - mMargin/2; 185 } 186 else 187 { 188 yOffset = widget.theme.mWindowHeaderHeight; 189 containerSize[1] -= yOffset; 190 } 191 } 192 193 bool first = true; 194 foreach(w; widget.children) { 195 if (!w.visible) 196 continue; 197 if (first) 198 first = false; 199 else 200 position += mSpacing; 201 202 Vector2i ps = w.preferredSize(nvg), fs = w.fixedSize(); 203 auto targetSize = Vector2i( 204 fs[0] ? fs[0] : ps[0], 205 fs[1] ? fs[1] : ps[1] 206 ); 207 auto pos = Vector2i(0, yOffset); 208 209 pos[axis1] = position; 210 211 final switch (mAlignment) 212 { 213 case Alignment.Minimum: 214 pos[axis2] += mMargin; 215 break; 216 case Alignment.Middle: 217 pos[axis2] += (containerSize[axis2] - targetSize[axis2]) / 2; 218 break; 219 case Alignment.Maximum: 220 pos[axis2] += containerSize[axis2] - targetSize[axis2] - mMargin * 2; 221 break; 222 case Alignment.Fill: 223 pos[axis2] += mMargin; 224 targetSize[axis2] = fs[axis2] ? fs[axis2] : (containerSize[axis2] - mMargin * 2); 225 break; 226 } 227 228 w.position(pos); 229 w.size(targetSize); 230 w.performLayout(nvg); 231 position += targetSize[axis1]; 232 } 233 } 234 235 protected: 236 /// The Orientation of this BoxLayout. 237 Orientation mOrientation; 238 239 /// The Alignment of this BoxLayout. 240 Alignment mAlignment; 241 242 /// The margin of this BoxLayout. 243 int mMargin; 244 245 /// The spacing between widgets of this BoxLayout. 246 int mSpacing; 247 } 248 249 /** 250 * Special layout for widgets grouped by labels. 251 * 252 * This widget resembles a box layout in that it arranges a set of widgets 253 * vertically. All widgets are indented on the horizontal axis except for 254 * `Label` widgets, which are not indented. 255 * 256 * This creates a pleasing layout where a number of widgets are grouped 257 * under some high-level heading. 258 */ 259 class GroupLayout : Layout 260 { 261 public: 262 /** 263 * Creates a GroupLayout. 264 * 265 * Params: 266 * margin = The margin around the widgets added. 267 * spacing = The spacing between widgets added. 268 * groupSpacing = The spacing between groups (groups are defined by each Label added). 269 * groupIndent = The amount to indent widgets in a group (underneath a Label). 270 */ 271 this(int margin = 15, int spacing = 6, int groupSpacing = 14, 272 int groupIndent = 20) 273 { 274 mMargin = margin; 275 mSpacing = spacing; 276 mGroupSpacing = groupSpacing; 277 mGroupIndent = groupIndent; 278 } 279 280 /// The margin of this GroupLayout. 281 final int margin() const { return mMargin; } 282 283 /// Sets the margin of this GroupLayout. 284 final void margin(int margin) { mMargin = margin; } 285 286 /// The spacing between widgets of this GroupLayout. 287 final int spacing() const { return mSpacing; } 288 289 /// Sets the spacing between widgets of this GroupLayout. 290 final void spacing(int spacing) { mSpacing = spacing; } 291 292 /// The indent of widgets in a group (underneath a Label) of this GroupLayout. 293 final int groupIndent() const { return mGroupIndent; } 294 295 /// Sets the indent of widgets in a group (underneath a Label) of this GroupLayout. 296 final void groupIndent(int groupIndent) { mGroupIndent = groupIndent; } 297 298 /// The spacing between groups of this GroupLayout. 299 final int groupSpacing() const { return mGroupSpacing; } 300 301 /// Sets the spacing between groups of this GroupLayout. 302 final void groupSpacing(int groupSpacing) { mGroupSpacing = groupSpacing; } 303 304 /// Implementation of the layout interface 305 /// See `Layout.preferredSize`. 306 override Vector2i preferredSize(NVGContext nvg, const Widget widget, const Widget skipped = null) const 307 { 308 int height = mMargin, width = 2*mMargin; 309 310 import nanogui.window : Window; 311 auto window = cast(const Window) widget; 312 if (window && window.title.length) 313 height += widget.theme.mWindowHeaderHeight - mMargin/2; 314 315 bool first = true, indent = false; 316 foreach (c; widget.children) { 317 if (!c.visible || c is skipped) 318 continue; 319 import nanogui.label : Label; 320 auto label = cast(const Label) c; 321 if (!first) 322 height += (label is null) ? mSpacing : mGroupSpacing; 323 first = false; 324 325 Vector2i ps = c.preferredSize(nvg), fs = c.fixedSize(); 326 auto targetSize = Vector2i( 327 fs[0] ? fs[0] : ps[0], 328 fs[1] ? fs[1] : ps[1] 329 ); 330 331 bool indentCur = indent && label is null; 332 height += targetSize.y; 333 334 width = max(width, targetSize.x + 2*mMargin + (indentCur ? mGroupIndent : 0)); 335 336 if (label) 337 indent = label.caption().length != 0; 338 } 339 height += mMargin; 340 return Vector2i(width, height); 341 } 342 343 /// See `Layout.performLayout`. 344 override void performLayout(NVGContext nvg, Widget widget) const 345 { 346 int height = mMargin, availableWidth = 347 (widget.fixedWidth() ? widget.fixedWidth() : widget.width()) - 2*mMargin; 348 349 const Window window = cast(const Window) widget; 350 if (window && window.title.length) 351 height += widget.theme.mWindowHeaderHeight - mMargin/2; 352 353 bool first = true, indent = false; 354 foreach (c; widget.children) { 355 if (!c.visible) 356 continue; 357 import nanogui.label : Label; 358 const Label label = cast(const Label) c; 359 if (!first) 360 height += (label is null) ? mSpacing : mGroupSpacing; 361 first = false; 362 363 bool indentCur = indent && label is null; 364 Vector2i ps = Vector2i(availableWidth - (indentCur ? mGroupIndent : 0), 365 c.preferredSize(nvg).y); 366 Vector2i fs = c.fixedSize(); 367 368 auto targetSize = Vector2i( 369 fs[0] ? fs[0] : ps[0], 370 fs[1] ? fs[1] : ps[1] 371 ); 372 373 c.position = Vector2i(mMargin + (indentCur ? mGroupIndent : 0), height); 374 c.size = targetSize; 375 c.performLayout(nvg); 376 377 height += targetSize.y; 378 379 if (label) 380 indent = label.caption != ""; 381 } 382 } 383 384 protected: 385 /// The margin of this GroupLayout. 386 int mMargin; 387 388 /// The spacing between widgets of this GroupLayout. 389 int mSpacing; 390 391 /// The spacing between groups of this GroupLayout. 392 int mGroupSpacing; 393 394 /// The indent amount of a group under its defining Label of this GroupLayout. 395 int mGroupIndent; 396 } 397 398 /** 399 * Grid layout. 400 * 401 * Widgets are arranged in a grid that has a fixed grid resolution `resolution` 402 * along one of the axes. The layout orientation indicates the fixed dimension; 403 * widgets are also appended on this axis. The spacing between items can be 404 * specified per axis. The horizontal/vertical alignment can be specified per 405 * row and column. 406 */ 407 class GridLayout : Layout 408 { 409 public: 410 /** 411 * Create a 2-column grid layout by default. 412 * 413 * Params: 414 * orientation = The fixed dimension of this GridLayout. 415 * resolution = The number of rows or columns in the grid (depending on the Orientation). 416 * alignment = How widgets should be aligned within each grid cell. 417 * margin = The amount of spacing to add around the border of the grid. 418 * spacing = The amount of spacing between widgets added to the grid. 419 */ 420 this(Orientation orientation = Orientation.Horizontal, int resolution = 2, 421 Alignment alignment = Alignment.Middle, 422 int margin = 0, int spacing = 0) 423 { 424 mOrientation = orientation; 425 mResolution = resolution; 426 mMargin = margin; 427 mSpacing = Vector2i(spacing); 428 429 mDefaultAlignment[0] = mDefaultAlignment[1] = alignment; 430 } 431 432 /// The Orientation of this GridLayout. 433 final Orientation orientation() const { return mOrientation; } 434 435 /// Sets the Orientation of this GridLayout. 436 final void orientation(Orientation orientation) { 437 mOrientation = orientation; 438 } 439 440 /// The number of rows or columns (depending on the Orientation) of this GridLayout. 441 final int resolution() const { return mResolution; } 442 443 /// Sets the number of rows or columns (depending on the Orientation) of this GridLayout. 444 final void resolution(int resolution) { mResolution = resolution; } 445 446 /// The spacing at the specified axis (row or column number, depending on the Orientation). 447 final int spacing(int axis) const { return mSpacing[axis]; } 448 449 /// Sets the spacing for a specific axis. 450 final void spacing(int axis, int spacing) { mSpacing[axis] = spacing; } 451 452 /// Sets the spacing for all axes. 453 final void spacing(int spacing) { mSpacing[0] = mSpacing[1] = spacing; } 454 455 /// The margin around this GridLayout. 456 final int margin() const { return mMargin; } 457 458 /// Sets the margin of this GridLayout. 459 final void margin(int margin) { mMargin = margin; } 460 461 /** 462 * The Alignment of the specified axis (row or column number, depending on 463 * the Orientation) at the specified index of that row or column. 464 */ 465 final Alignment alignment(int axis, int item) const 466 { 467 if (item < cast(int) mAlignment[axis].length) 468 return mAlignment[axis][item]; 469 else 470 return mDefaultAlignment[axis]; 471 } 472 473 /// Sets the Alignment of the columns. 474 final void colAlignment(Alignment value) { mDefaultAlignment[0] = value; } 475 476 /// Sets the Alignment of the rows. 477 final void rowAlignment(Alignment value) { mDefaultAlignment[1] = value; } 478 479 /// Use this to set variable Alignment for columns. 480 final void colAlignment(Array!Alignment value) { mAlignment[0] = value; } 481 482 /// Use this to set variable Alignment for rows. 483 final void rowAlignment(Array!Alignment value) { mAlignment[1] = value; } 484 485 /// Implementation of the layout interface 486 /// See `Layout.preferredSize`. 487 override Vector2i preferredSize(NVGContext nvg, const Widget widget, const Widget skipped = null) const 488 { 489 /* Compute minimum row / column sizes */ 490 import std.algorithm : sum; 491 Array!(int)[2] grid; 492 computeLayout(nvg, widget, grid, skipped); 493 494 auto size = Vector2i( 495 2*mMargin + sum(grid[0][]) 496 + max(cast(int) grid[0].length - 1, 0) * mSpacing[0], 497 2*mMargin + sum(grid[1][]) 498 + max(cast(int) grid[1].length - 1, 0) * mSpacing[1] 499 ); 500 501 const Window window = cast(const Window) widget; 502 if (window && window.title.length) 503 size[1] += widget.theme.mWindowHeaderHeight - mMargin/2; 504 505 return size; 506 } 507 508 /// See `Layout.performLayout`. 509 override void performLayout(NVGContext nvg, Widget widget) const 510 { 511 Vector2i fs_w = widget.fixedSize; 512 auto containerSize = Vector2i( 513 fs_w[0] ? fs_w[0] : widget.width, 514 fs_w[1] ? fs_w[1] : widget.height 515 ); 516 517 /* Compute minimum row / column sizes */ 518 Array!(int)[2] grid; 519 computeLayout(nvg, widget, grid, null); 520 if (grid[1].length == 0) 521 return; 522 int[2] dim = [ cast(int) grid[0].length, cast(int) grid[1].length ]; 523 524 Vector2i extra; 525 const Window window = cast(const Window) widget; 526 if (window && window.title.length) 527 extra[1] += widget.theme.mWindowHeaderHeight - mMargin / 2; 528 529 /* Strech to size provided by \c widget */ 530 for (int i = 0; i < 2; i++) { 531 int gridSize = 2 * mMargin + extra[i]; 532 foreach (int s; grid[i]) { 533 gridSize += s; 534 if (i+1 < dim[i]) 535 gridSize += mSpacing[i]; 536 } 537 538 if (gridSize < containerSize[i]) { 539 /* Re-distribute remaining space evenly */ 540 int gap = containerSize[i] - gridSize; 541 int g = gap / dim[i]; 542 int rest = gap - g * dim[i]; 543 for (int j = 0; j < dim[i]; ++j) 544 grid[i][j] += g; 545 for (int j = 0; rest > 0 && j < dim[i]; --rest, ++j) 546 grid[i][j] += 1; 547 } 548 } 549 550 int axis1 = cast(int) mOrientation, axis2 = (axis1 + 1) % 2; 551 Vector2i start = Vector2i(mMargin, mMargin) + extra; 552 553 size_t numChildren = widget.children.length; 554 size_t child = 0; 555 556 Vector2i pos = start; 557 for (int i2 = 0; i2 < dim[axis2]; i2++) { 558 pos[axis1] = start[axis1]; 559 for (int i1 = 0; i1 < dim[axis1]; i1++) { 560 Widget w; 561 do { 562 if (child >= numChildren) 563 return; 564 w = widget.children()[child++]; 565 } while (!w.visible()); 566 567 Vector2i ps = w.preferredSize(nvg); 568 Vector2i fs = w.fixedSize(); 569 auto targetSize = Vector2i( 570 fs[0] ? fs[0] : ps[0], 571 fs[1] ? fs[1] : ps[1] 572 ); 573 574 auto itemPos = Vector2i(pos); 575 for (int j = 0; j < 2; j++) { 576 int axis = (axis1 + j) % 2; 577 int item = j == 0 ? i1 : i2; 578 Alignment algn = alignment(axis, item); 579 580 final switch (algn) { 581 case Alignment.Minimum: 582 break; 583 case Alignment.Middle: 584 itemPos[axis] += (grid[axis][item] - targetSize[axis]) / 2; 585 break; 586 case Alignment.Maximum: 587 itemPos[axis] += grid[axis][item] - targetSize[axis]; 588 break; 589 case Alignment.Fill: 590 targetSize[axis] = fs[axis] ? fs[axis] : grid[axis][item]; 591 break; 592 } 593 } 594 w.position(itemPos); 595 w.size(targetSize); 596 w.performLayout(nvg); 597 pos[axis1] += grid[axis1][i1] + mSpacing[axis1]; 598 } 599 pos[axis2] += grid[axis2][i2] + mSpacing[axis2]; 600 } 601 } 602 603 protected: 604 /// Compute the maximum row and column sizes 605 void computeLayout(NVGContext nvg, const Widget widget, 606 ref Array!(int)[2] grid, const Widget skipped) const 607 { 608 int axis1 = cast(int) mOrientation, axis2 = (axis1 + 1) % 2; 609 size_t numChildren = widget.children.length, visibleChildren = 0; 610 foreach (w; widget.children) 611 visibleChildren += w.visible ? 1 : 0; 612 613 Vector2i dim; 614 dim[axis1] = mResolution; 615 dim[axis2] = cast(int) ((visibleChildren + mResolution - 1) / mResolution); 616 617 grid[axis1].clear(); grid[axis1].length = dim[axis1]; grid[axis1][] = 0; 618 grid[axis2].clear(); grid[axis2].length = dim[axis2]; grid[axis2][] = 0; 619 620 size_t child; 621 for (int i2 = 0; i2 < dim[axis2]; i2++) { 622 for (int i1 = 0; i1 < dim[axis1]; i1++) { 623 import std.typecons : Rebindable; 624 Rebindable!(const Widget) w; 625 do { 626 if (child >= numChildren) 627 return; 628 w = widget.children[child++]; 629 } while (!w.visible || w is skipped); 630 631 Vector2i ps = w.preferredSize(nvg); 632 Vector2i fs = w.fixedSize(); 633 auto targetSize = Vector2i( 634 fs[0] ? fs[0] : ps[0], 635 fs[1] ? fs[1] : ps[1] 636 ); 637 638 grid[axis1][i1] = max(grid[axis1][i1], targetSize[axis1]); 639 grid[axis2][i2] = max(grid[axis2][i2], targetSize[axis2]); 640 } 641 } 642 } 643 644 /// The Orientation defining this GridLayout. 645 Orientation mOrientation; 646 647 /// The default Alignment for this GridLayout. 648 Alignment[2] mDefaultAlignment; 649 650 /// The actual Alignment being used. 651 Array!(Alignment)[2] mAlignment; 652 653 /// The number of rows or columns before starting a new one, depending on the Orientation. 654 int mResolution; 655 656 /// The spacing used for each dimension. 657 Vector2i mSpacing; 658 659 /// The margin around this GridLayout. 660 int mMargin; 661 } 662 663 ///** 664 // * \class AdvancedGridLayout layout.h nanogui/layout.h 665 // * 666 // * \brief Advanced Grid layout. 667 // * 668 // * The is a fancier grid layout with support for items that span multiple rows 669 // * or columns, and per-widget alignment flags. Each row and column additionally 670 // * stores a stretch factor that controls how additional space is redistributed. 671 // * The downside of this flexibility is that a layout anchor data structure must 672 // * be provided for each widget. 673 // * 674 // * An example: 675 // * 676 // * \rst 677 // * .. code-block. cpp 678 // * 679 // * using AdvancedGridLayout.Anchor; 680 // * Label *label = new Label(window, "A label"); 681 // * // Add a centered label at grid position (1, 5), which spans two horizontal cells 682 // * layout.setAnchor(label, Anchor(1, 5, 2, 1, Alignment.Middle, Alignment.Middle)); 683 // * 684 // * \endrst 685 // * 686 // * The grid is initialized with user-specified column and row size vectors 687 // * (which can be expanded later on if desired). If a size value of zero is 688 // * specified for a column or row, the size is set to the maximum preferred size 689 // * of any widgets contained in the same row or column. Any remaining space is 690 // * redistributed according to the row and column stretch factors. 691 // * 692 // * The high level usage somewhat resembles the classic HIG layout: 693 // * 694 // * - https://web.archive.org/web/20070813221705/http://www.autel.cz/dmi/tutorial.html 695 // * - https://github.com/jaapgeurts/higlayout 696 // */ 697 //class NANOGUI_EXPORT AdvancedGridLayout : public Layout { 698 //public: 699 // /** 700 // * \struct Anchor layout.h nanogui/layout.h 701 // * 702 // * \brief Helper struct to coordinate anchor points for the layout. 703 // */ 704 // struct Anchor { 705 // uint8_t pos[2]; ///< The ``(x, y)`` position. 706 // uint8_t size[2]; ///< The ``(x, y)`` size. 707 // Alignment align[2];///< The ``(x, y)`` Alignment. 708 709 // /// Creates a ``0`` Anchor. 710 // Anchor() { } 711 712 // /// Create an Anchor at position ``(x, y)`` with specified Alignment. 713 // Anchor(int x, int y, Alignment horiz = Alignment.Fill, 714 // Alignment vert = Alignment.Fill) { 715 // pos[0] = (uint8_t) x; pos[1] = (uint8_t) y; 716 // size[0] = size[1] = 1; 717 // align[0] = horiz; align[1] = vert; 718 // } 719 720 // /// Create an Anchor at position ``(x, y)`` of size ``(w, h)`` with specified alignments. 721 // Anchor(int x, int y, int w, int h, 722 // Alignment horiz = Alignment.Fill, 723 // Alignment vert = Alignment.Fill) { 724 // pos[0] = (uint8_t) x; pos[1] = (uint8_t) y; 725 // size[0] = (uint8_t) w; size[1] = (uint8_t) h; 726 // align[0] = horiz; align[1] = vert; 727 // } 728 729 // /// Allows for printing out Anchor position, size, and alignment. 730 // operator std.string() const { 731 // char buf[50]; 732 // NANOGUI_SNPRINTF(buf, 50, "Format[pos=(%i, %i), size=(%i, %i), align=(%i, %i)]", 733 // pos[0], pos[1], size[0], size[1], (int) align[0], (int) align[1]); 734 // return buf; 735 // } 736 // }; 737 738 // /// Creates an AdvancedGridLayout with specified columns, rows, and margin. 739 // AdvancedGridLayout(const std.vector<int> &cols = {}, const std.vector<int> &rows = {}, int margin = 0); 740 741 // /// The margin of this AdvancedGridLayout. 742 // int margin() const { return mMargin; } 743 744 // /// Sets the margin of this AdvancedGridLayout. 745 // void setMargin(int margin) { mMargin = margin; } 746 747 // /// Return the number of cols 748 // int colCount() const { return (int) mCols.size(); } 749 750 // /// Return the number of rows 751 // int rowCount() const { return (int) mRows.size(); } 752 753 // /// Append a row of the given size (and stretch factor) 754 // void appendRow(int size, float stretch = 0.f) { mRows.push_back(size); mRowStretch.push_back(stretch); }; 755 756 // /// Append a column of the given size (and stretch factor) 757 // void appendCol(int size, float stretch = 0.f) { mCols.push_back(size); mColStretch.push_back(stretch); }; 758 759 // /// Set the stretch factor of a given row 760 // void setRowStretch(int index, float stretch) { mRowStretch.at(index) = stretch; } 761 762 // /// Set the stretch factor of a given column 763 // void setColStretch(int index, float stretch) { mColStretch.at(index) = stretch; } 764 765 // /// Specify the anchor data structure for a given widget 766 // void setAnchor(const Widget *widget, const Anchor &anchor) { mAnchor[widget] = anchor; } 767 768 // /// Retrieve the anchor data structure for a given widget 769 // Anchor anchor(const Widget *widget) const { 770 // auto it = mAnchor.find(widget); 771 // if (it == mAnchor.end()) 772 // throw std.runtime_error("Widget was not registered with the grid layout!"); 773 // return it.second; 774 // } 775 776 // /* Implementation of the layout interface */ 777 // /// See \ref Layout.preferredSize. 778 // virtual Vector2i preferredSize(NVGContext *nvg, const Widget *widget) const override; 779 780 // /// See \ref Layout.performLayout. 781 // virtual void performLayout(NVGContext *nvg, Widget *widget) const override; 782 783 //protected: 784 // /// Computes the layout 785 // void computeLayout(NVGContext *nvg, const Widget *widget, 786 // std.vector<int> *grid) const; 787 788 //protected: 789 // /// The columns of this AdvancedGridLayout. 790 // std.vector<int> mCols; 791 792 // /// The rows of this AdvancedGridLayout. 793 // std.vector<int> mRows; 794 795 // /// The stretch for each column of this AdvancedGridLayout. 796 // std.vector<float> mColStretch; 797 798 // /// The stretch for each row of this AdvancedGridLayout. 799 // std.vector<float> mRowStretch; 800 801 // /// The mapping of widgets to their specified anchor points. 802 // std.unordered_map<const Widget *, Anchor> mAnchor; 803 804 // /// The margin around this AdvancedGridLayout. 805 // int mMargin; 806 //}