1 // This may look like C code, but it's really -*- C++ -*- 2 /* 3 * Copyright (C) 2008 Emweb bv, Herent, Belgium. 4 * 5 * See the LICENSE file for terms of use. 6 */ 7 #ifndef WGRID_LAYOUT_H_ 8 #define WGRID_LAYOUT_H_ 9 10 #include <vector> 11 #include <Wt/WLayout.h> 12 #include <Wt/WLength.h> 13 #include <Wt/WWidget.h> 14 15 namespace Wt { 16 17 namespace Impl { 18 19 struct Grid { 20 int horizontalSpacing_, verticalSpacing_; 21 22 struct Section { 23 int stretch_; 24 bool resizable_; 25 WLength initialSize_; 26 27 Section(int stretch = 0); 28 }; 29 30 struct Item { 31 std::unique_ptr<WLayoutItem> item_; 32 int rowSpan_; 33 int colSpan_; 34 bool update_; 35 WFlags<AlignmentFlag> alignment_; 36 37 Item(std::unique_ptr<WLayoutItem> item = nullptr, 38 WFlags<AlignmentFlag> alignment = None); 39 Item(Item&& other) = default; 40 Item& operator=(Item&& other) = default; 41 ~Item(); 42 }; 43 44 std::vector<Section> rows_; 45 std::vector<Section> columns_; 46 std::vector<std::vector<Item> > items_; // [row][column] 47 48 Grid(); 49 ~Grid(); 50 51 void clear(); 52 }; 53 54 } 55 56 /*! \class WGridLayout Wt/WGridLayout.h Wt/WGridLayout.h 57 * \brief A layout manager which arranges widgets in a grid 58 * 59 * This layout manager arranges widgets in a grid. 60 * 61 * Each grid cell (row, column) may contain one widget or nested 62 * layout. Orientation::Horizontal and vertical space are divided so that each 63 * non-stretchable column/row is given its preferred size (if 64 * possible) and the remaining space is divided according to stretch 65 * factors among the columns/rows. If not all columns/rows can be 66 * given their preferred size (there is not enough room), then 67 * columns/rows are given a smaller size (down to a minimum size based 68 * on widget minimum sizes). If necessary, the container (or parent 69 * layout) of this layout is resized to meet minimum size 70 * requirements. 71 * 72 * The preferred width/height of a column/row is based on the natural 73 * size of the widgets, where they present their contents without 74 * overflowing. WWidget::resize() or (CSS <tt>width</tt>, 75 * <tt>height</tt> properties) can be used to adjust the preferred 76 * size of a widget. 77 * 78 * The minimum width/height of a column/row is based on the minimum 79 * dimensions of contained widgets or nested layouts. The default 80 * minimum height and width for a widget is 0. It can be specified 81 * using WWidget::setMinimumSize() or using CSS <tt>min-width</tt> and 82 * <tt>min-height</tt> properties. 83 * 84 * You should use \link WContainerWidget::setOverflow() 85 * WContainerWidget::setOverflow(OverflowAuto) \endlink to automatically 86 * show scrollbars for widgets inserted 87 * in the layout to cope with a size set by the layout manager that is 88 * smaller than the preferred size. 89 * 90 * When the container of a layout manager has a maximum size set using 91 * WWidget::setMaximumSize(), then the size of the container will be 92 * based on the preferred size of the contents, up to this maximum 93 * size, instead of the default behaviour of constraining the size of 94 * the children based on the size of the container. 95 * 96 * A layout manager may provide resize handles between columns or rows 97 * which allow the user to change the automatic layout provided by the 98 * layout manager (see setRowResizable() and 99 * setColumnResizable()). 100 * 101 * Columns and rows are separated using a constant spacing, which 102 * defaults to 6 pixels by default, and can be changed using 103 * setHorizontalSpacing() and setVerticalSpacing(). In addition, when 104 * this layout is a top-level layout (i.e. is not nested inside 105 * another layout), a margin is set around the contents. This margin 106 * defaults to 9 pixels, and can be changed using setContentsMargins(). 107 * 108 * For each column or row, a stretch factor may be defined, which 109 * controls how remaining horizontal or vertical space is used. Each 110 * column and row is stretched using the stretch factor to fill the 111 * remaining space. When the stretch factor is 0, the height of the 112 * row and its contents is set to the preferred size (if 113 * possible). When the stretch factor is 1 or higher, these widgets 114 * will be given the remaining size, limited only by their minimum 115 * size (their preferred size is ignored). 116 * 117 * Usage example: 118 * \if cpp 119 * \code 120 * Wt::WContainerWidget *w = addWidget(std::make_unique<Wt::WContainerWidget>()); 121 * w->resize(WLength::Auto, 600); 122 * 123 * auto layout = std::make_unique<Wt::WGridLayout>(); 124 * layout->addWidget(std::make_unique<Wt::WText>("Item 0 0"), 0, 0); 125 * layout->addWidget(std::make_unique<Wt::WText>("Item 0 1"), 0, 1); 126 * layout->addWidget(std::make_unique<Wt::WText>("Item 1 0"), 1, 0); 127 * layout->addWidget(std::make_unique<Wt::WText>("Item 1 1"), 1, 1); 128 * 129 * w->setLayout(std::move(layout)); 130 * \endcode 131 * \elseif java 132 * \code 133 * WContainerWidget w = new WContainerWidget(this); 134 * w.resize(WLength.Auto, new WLength(600)); 135 * 136 * WGridLayout layout = new WGridLayout(); 137 * layout.addWidget(new WText("Item 0 0"), 0, 0); 138 * layout.addWidget(new WText("Item 0 1"), 0, 1); 139 * layout.addWidget(new WText("Item 1 0"), 1, 0); 140 * layout.addWidget(new WText("Item 1 1"), 1, 1); 141 * 142 * w.setLayout(layout); 143 * \endcode 144 * \endif 145 * 146 * \note When JavaScript support is not available, not all functionality 147 * of the layout is available. In particular, vertical size management is 148 * not available. 149 * 150 * \note When a layout is used on a first page with progressive 151 * bootstrap, then the layout will progress only in a limited way to a 152 * full JavaScript-based layout. You can thus not rely on it to behave 153 * properly for example when dynamically adding or removing widgets. 154 */ 155 class WT_API WGridLayout : public WLayout 156 { 157 public: 158 /*! \brief Create a new grid layout. 159 * 160 * The grid will grow dynamically as items are added. 161 * 162 * Use \p parent = \c 0 to create a layout manager that can be 163 * nested inside other layout managers or if you use 164 * WContainerWidget::setLayout() to add specify the container later. 165 */ 166 WGridLayout(); 167 168 virtual ~WGridLayout() override; 169 170 virtual void addItem(std::unique_ptr<WLayoutItem> item) override; 171 virtual std::unique_ptr<WLayoutItem> removeItem(WLayoutItem *item) override; 172 virtual WLayoutItem *itemAt(int index) const override; 173 virtual int count() const override; 174 175 /*! \brief Adds a layout item to the grid. 176 * 177 * Adds the <i>item</i> at (<i>row</i>, \p column). If an item 178 * was already added to that location, it is replaced. 179 * 180 * An item may span several more rows or columns, which is 181 * controlled by <i>rowSpan</i> and \p columnSpan. 182 * 183 * The \p alignment specifies the vertical and horizontal 184 * alignment of the item. The default value 0 indicates that the 185 * item is stretched to fill the entire grid cell. The alignment can 186 * be specified as a logical combination of a horizontal alignment 187 * (Wt::AlignmentFlag::Left, Wt::AlignmentFlag::Center, or Wt::AlignmentFlag::Right) and a 188 * vertical alignment (Wt::AlignmentFlag::Top, Wt::AlignmentFlag::Middle, or 189 * Wt::AlignmentFlag::Bottom). 190 * 191 * \sa addLayout(), addWidget() 192 */ 193 void addItem(std::unique_ptr<WLayoutItem> item, int row, int column, 194 int rowSpan = 1, int columnSpan = 1, 195 WFlags<AlignmentFlag> alignment = None); 196 197 /*! \brief Adds a nested layout item to the grid. 198 * 199 * Adds the <i>layout</i> at (<i>row</i>, \p column). If an item 200 * was already added to that location, it is replaced (but not 201 * deleted). 202 * 203 * The \p alignment specifies the vertical and horizontal 204 * alignment of the item. The default value 0 indicates that the 205 * item is stretched to fill the entire grid cell. The alignment can 206 * be specified as a logical combination of a horizontal alignment 207 * (Wt::AlignmentFlag::Left, Wt::AlignmentFlag::Center, or Wt::AlignmentFlag::Right) and a 208 * vertical alignment (Wt::AlignmentFlag::Top, Wt::AlignmentFlag::Middle, or 209 * Wt::AlignmentFlag::Bottom). 210 * 211 * \sa addLayout(WLayout *, int, int, int, int, WFlags<AlignmentFlag>) 212 */ 213 void addLayout(std::unique_ptr<WLayout> layout, int row, int column, 214 WFlags<AlignmentFlag> alignment = None); 215 216 /*! \brief Adds a nested layout item to the grid. 217 * 218 * Adds the <i>layout</i> at (<i>row</i>, \p column). If an item 219 * was already added to that location, it is replaced (but not 220 * deleted). 221 * 222 * An item may span several more rows or columns, which is 223 * controlled by <i>rowSpan</i> and \p columnSpan. 224 * 225 * The \p alignment specifies the vertical and horizontal 226 * alignment of the item. The default value 0 indicates that the 227 * item is stretched to fill the entire grid cell. The alignment can 228 * be specified as a logical combination of a horizontal alignment 229 * (Wt::AlignmentFlag::Left, Wt::AlignmentFlag::Center, or Wt::AlignmentFlag::Right) and a 230 * vertical alignment (Wt::AlignmentFlag::Top, Wt::AlignmentFlag::Middle, or 231 * Wt::AlignmentFlag::Bottom). 232 * 233 * \sa addLayout(WLayout *, int, int, WFlags<AlignmentFlag>) 234 */ 235 void addLayout(std::unique_ptr<WLayout> layout, int row, int column, 236 int rowSpan, int columnSpan, 237 WFlags<AlignmentFlag> alignment = None); 238 239 /*! \brief Adds a widget to the grid. 240 * 241 * Adds the <i>widget</i> at (<i>row</i>, \p column). If an item 242 * was already added to that location, it is replaced (but not 243 * deleted). 244 * 245 * The \p alignment specifies the vertical and horizontal 246 * alignment of the item. The default value 0 indicates that the 247 * item is stretched to fill the entire grid cell. The alignment can 248 * be specified as a logical combination of a horizontal alignment 249 * (Wt::AlignmentFlag::Left, Wt::AlignmentFlag::Center, or Wt::AlignmentFlag::Right) and a 250 * vertical alignment (Wt::AlignmentFlag::Top, Wt::AlignmentFlag::Middle, or 251 * Wt::AlignmentFlag::Bottom). 252 * 253 * \sa addWidget(WWidget *, int, int, int, int, WFlags<AlignmentFlag>) 254 */ 255 #ifndef WT_TARGET_JAVA 256 void addWidget(std::unique_ptr<WWidget> widget, int row, int column, 257 WFlags<AlignmentFlag> alignment); 258 #else // WT_TARGET_JAVA 259 void addWidget(std::unique_ptr<WWidget> widget, int row, int column, 260 WFlags<AlignmentFlag> alignment = None); 261 #endif // WT_TARGET_JAVA 262 263 #ifndef WT_TARGET_JAVA 264 /*! \brief Adds a widget to the grid, returning a raw pointer to the widget. 265 * 266 * This is implemented as: 267 * 268 * \code 269 * Widget *result = widget.get(); 270 * addWidget(std::unique_ptr<WWidget>(std::move(widget)), row, column, alignment); 271 * return result; 272 * \endcode 273 */ 274 template <typename Widget> 275 Widget *addWidget(std::unique_ptr<Widget> widget, int row, int column, 276 WFlags<AlignmentFlag> alignment = None) 277 { 278 Widget *result = widget.get(); 279 addWidget(std::unique_ptr<WWidget>(std::move(widget)), row, column, alignment); 280 return result; 281 } 282 #endif // WT_TARGET_JAVA 283 284 /*! \brief Adds a widget to the grid. 285 * 286 * Adds the <i>widget</i> at (<i>row</i>, \p column). If an item 287 * was already added to that location, it is replaced (but not 288 * deleted). 289 * 290 * The widget may span several more rows or columns, which is 291 * controlled by <i>rowSpan</i> and \p columnSpan. 292 * 293 * The \p alignment specifies the vertical and horizontal 294 * alignment of the item. The default value 0 indicates that the 295 * item is stretched to fill the entire grid cell. The alignment can 296 * be specified as a logical combination of a horizontal alignment 297 * (Wt::AlignmentFlag::Left, Wt::AlignmentFlag::Center, or Wt::AlignmentFlag::Right) and a 298 * vertical alignment (Wt::AlignmentFlag::Top, Wt::AlignmentFlag::Middle, or 299 * Wt::AlignmentFlag::Bottom). 300 * 301 * \sa addWidget(WWidget *, int, int, WFlags<AlignmentFlag>) 302 */ 303 #ifndef WT_TARGET_JAVA 304 void addWidget(std::unique_ptr<WWidget> widget, int row, int column, 305 int rowSpan, int columnSpan, 306 WFlags<AlignmentFlag> alignment); 307 #else // WT_TARGET_JAVA 308 void addWidget(std::unique_ptr<WWidget> widget, int row, int column, 309 int rowSpan, int columnSpan, 310 WFlags<AlignmentFlag> alignment = None); 311 #endif // WT_TARGET_JAVA 312 313 #ifndef WT_TARGET_JAVA 314 /*! \brief Adds a widget to the grid, returning a raw pointer to the widget. 315 * 316 * This is implemented as: 317 * 318 * \code 319 * Widget *result = widget.get(); 320 * addWidget(std::unique_ptr<WWidget>(std::move(widget)), row, column, 321 * rowSpan, columnSpan, alignment); 322 * return result; 323 * \endcode 324 */ 325 template <typename Widget> 326 Widget *addWidget(std::unique_ptr<Widget> widget, int row, int column, 327 int rowSpan, int columnSpan, 328 WFlags<AlignmentFlag> alignment = None) 329 { 330 Widget *result = widget.get(); 331 addWidget(std::unique_ptr<WWidget>(std::move(widget)), row, column, 332 rowSpan, columnSpan, alignment); 333 return result; 334 } 335 #endif // WT_TARGET_JAVA 336 337 /*! \brief Sets the horizontal spacing. 338 * 339 * The default horizontal spacing is 9 pixels. 340 * 341 * \sa setVerticalSpacing(int) 342 */ 343 void setHorizontalSpacing(int size); 344 345 /*! \brief Returns the horizontal spacing. 346 * 347 * \sa setHorizontalSpacing(int) 348 */ horizontalSpacing()349 int horizontalSpacing() const { return grid_.horizontalSpacing_; } 350 351 /*! \brief Sets the vertical spacing. 352 * 353 * The default vertical spacing is 9 pixels. 354 * 355 * \sa setHorizontalSpacing(int) 356 */ 357 void setVerticalSpacing(int size); 358 359 /*! \brief Returns the vertical spacing. 360 * 361 * \sa setVerticalSpacing(int) 362 */ verticalSpacing()363 int verticalSpacing() const { return grid_.verticalSpacing_; } 364 365 /*! \brief Returns the column count. 366 * 367 * The grid dimensions change dynamically when adding contents to 368 * the grid. 369 * 370 * \sa rowCount() 371 */ 372 int columnCount() const; 373 374 /*! \brief Returns the row count. 375 * 376 * The grid dimensions change dynamically when adding contents to 377 * the grid. 378 * 379 * \sa columnCount() 380 */ 381 int rowCount() const; 382 383 /*! \brief Sets the column stretch. 384 * 385 * Sets the <i>stretch</i> factor for column \p column. 386 * 387 * \sa columnStretch() 388 */ 389 void setColumnStretch(int column, int stretch); 390 391 /*! \brief Returns the column stretch. 392 * 393 * \sa setColumnStretch(int, int) 394 */ 395 int columnStretch(int column) const; 396 397 /*! \brief Sets the row stretch. 398 * 399 * Sets the <i>stretch</i> factor for row \p row. 400 * 401 * \sa rowStretch() 402 */ 403 void setRowStretch(int row, int stretch); 404 405 /*! \brief Returns the column stretch. 406 * 407 * \sa setRowStretch(int, int) 408 */ 409 int rowStretch(int row) const; 410 411 /*! \brief Sets whether the user may drag a particular column border. 412 * 413 * This method sets whether the border that separates column 414 * <i>column</i> from the next column may be resized by the user, 415 * depending on the value of <i>enabled</i>. 416 * 417 * The default value is <i>false</i>. 418 * 419 * If an \p initialSize is given (that is not WLength::Auto), then 420 * this size is used for the width of the column, overriding the width 421 * it would be given by the layout manager. 422 */ 423 void setColumnResizable(int column, bool enabled = true, 424 const WLength& initialSize = WLength::Auto); 425 426 /*! \brief Returns whether the user may drag a particular column border. 427 * 428 * This method returns whether the border that separates column 429 * <i>column</i> from the next column may be resized by the user. 430 * 431 * \sa setColumnResizable() 432 */ 433 bool columnIsResizable(int column) const; 434 435 /*! \brief Sets whether the user may drag a particular row border. 436 * 437 * This method sets whether the border that separates row <i>row</i> from 438 * the next row may be resized by the user, depending on the value of 439 * <i>enabled</i>. 440 * 441 * The default value is <i>false</i>. 442 * 443 * If an \p initialSize is given (that is not WLength::Auto), then 444 * this size is used for the height of the row, overriding the height 445 * it would be given by the layout manager. 446 */ 447 void setRowResizable(int row, bool enabled = true, 448 const WLength& initialSize = WLength::Auto); 449 450 /*! \brief Returns whether the user may drag a particular row border. 451 * 452 * This method returns whether the border that separates row 453 * <i>row</i> from the next row may be resized by the user. 454 * 455 * \sa setRowResizable() 456 */ 457 bool rowIsResizable(int row) const; 458 459 virtual void iterateWidgets(const HandleWidgetMethod& method) const override; 460 461 private: 462 Impl::Grid grid_; 463 464 void expand(int row, int column, int rowSpan, int columnSpan); 465 466 virtual void setParentWidget(WWidget *parent) override; 467 }; 468 469 } 470 471 #endif // WGRID_LAYOUT_H_ 472