1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include "Wt/WGridLayout.h"
8 #include "Wt/WWidgetItem.h"
9 
10 #include "StdGridLayoutImpl2.h"
11 
12 #include <algorithm>
13 
14 namespace Wt {
15 
16   namespace Impl {
17 
Section(int stretch)18 Grid::Section::Section(int stretch)
19   : stretch_(stretch),
20     resizable_(false)
21 { }
22 
Item(std::unique_ptr<WLayoutItem> item,WFlags<AlignmentFlag> alignment)23 Grid::Item::Item(std::unique_ptr<WLayoutItem> item,
24 		 WFlags<AlignmentFlag> alignment)
25   : item_(std::move(item)),
26     rowSpan_(1),
27     colSpan_(1),
28     update_(true),
29     alignment_(alignment)
30 { }
31 
~Item()32 Grid::Item::~Item()
33 { }
34 
Grid()35 Grid::Grid()
36   : horizontalSpacing_(6),
37     verticalSpacing_(6)
38 { }
39 
~Grid()40 Grid::~Grid()
41 {
42 }
43 
clear()44 void Grid::clear()
45 {
46   rows_.clear();
47   columns_.clear();
48   items_.clear();
49 }
50 
51   }
52 
WGridLayout()53 WGridLayout::WGridLayout()
54 { }
55 
~WGridLayout()56 WGridLayout::~WGridLayout()
57 { }
58 
addItem(std::unique_ptr<WLayoutItem> item)59 void WGridLayout::addItem(std::unique_ptr<WLayoutItem> item)
60 {
61   addItem(std::move(item), 0, columnCount());
62 }
63 
removeItem(WLayoutItem * item)64 std::unique_ptr<WLayoutItem> WGridLayout::removeItem(WLayoutItem *item)
65 {
66   int index = indexOf(item);
67 
68   std::unique_ptr<WLayoutItem> result;
69 
70   if (index != -1) {
71     int row = index / columnCount();
72     int col = index % columnCount();
73 
74     result = std::move(grid_.items_[row][col].item_);
75     itemRemoved(item);
76   }
77 
78   return result;
79 }
80 
itemAt(int index)81 WLayoutItem *WGridLayout::itemAt(int index) const
82 {
83   int row = index / columnCount();
84   int col = index % columnCount();
85 
86   return grid_.items_[row][col].item_.get();
87 }
88 
iterateWidgets(const HandleWidgetMethod & method)89 void WGridLayout::iterateWidgets(const HandleWidgetMethod& method) const
90 {
91   for (unsigned r = 0; r < grid_.rows_.size(); ++r) {
92     for (unsigned c = 0; c < grid_.columns_.size(); ++c) {
93       WLayoutItem *item = grid_.items_[r][c].item_.get();
94       if (item)
95 	item->iterateWidgets(method);
96     }
97   }
98 }
99 
count()100 int WGridLayout::count() const
101 {
102   return grid_.rows_.size() * grid_.columns_.size();
103 }
104 
addItem(std::unique_ptr<WLayoutItem> item,int row,int column,int rowSpan,int columnSpan,WFlags<AlignmentFlag> alignment)105 void WGridLayout::addItem(std::unique_ptr<WLayoutItem> item,
106 			  int row, int column,
107 			  int rowSpan, int columnSpan,
108 			  WFlags<AlignmentFlag> alignment)
109 {
110   columnSpan = std::max(1, columnSpan);
111   rowSpan = std::max(1, rowSpan);
112 
113   expand(row, column, rowSpan, columnSpan);
114 
115   Impl::Grid::Item& gridItem = grid_.items_[row][column];
116 
117   if (gridItem.item_) {
118     auto oldItem = std::move(gridItem.item_);
119     itemRemoved(oldItem.get());
120   }
121 
122   gridItem.item_ = std::move(item);
123   gridItem.rowSpan_ = rowSpan;
124   gridItem.colSpan_ = columnSpan;
125   gridItem.alignment_ = alignment;
126 
127   itemAdded(gridItem.item_.get());
128 }
129 
addLayout(std::unique_ptr<WLayout> layout,int row,int column,WFlags<AlignmentFlag> alignment)130 void WGridLayout::addLayout(std::unique_ptr<WLayout> layout,
131 			    int row, int column,
132 			    WFlags<AlignmentFlag> alignment)
133 {
134   addItem(std::move(layout), row, column, 1, 1, alignment);
135 }
136 
addLayout(std::unique_ptr<WLayout> layout,int row,int column,int rowSpan,int columnSpan,WFlags<AlignmentFlag> alignment)137 void WGridLayout::addLayout(std::unique_ptr<WLayout> layout,
138 			    int row, int column,
139 			    int rowSpan, int columnSpan,
140 			    WFlags<AlignmentFlag> alignment)
141 {
142   addItem(std::move(layout), row, column, rowSpan, columnSpan, alignment);
143 }
144 
addWidget(std::unique_ptr<WWidget> widget,int row,int column,WFlags<AlignmentFlag> alignment)145 void WGridLayout::addWidget(std::unique_ptr<WWidget> widget,
146 			    int row, int column,
147 			    WFlags<AlignmentFlag> alignment)
148 {
149   addItem(std::unique_ptr<WLayoutItem>(new WWidgetItem(std::move(widget))),
150 	  row, column, 1, 1, alignment);
151 }
152 
addWidget(std::unique_ptr<WWidget> widget,int row,int column,int rowSpan,int columnSpan,WFlags<AlignmentFlag> alignment)153 void WGridLayout::addWidget(std::unique_ptr<WWidget> widget,
154 			    int row, int column,
155 			    int rowSpan, int columnSpan,
156 			    WFlags<AlignmentFlag> alignment)
157 {
158   addItem(std::unique_ptr<WLayoutItem>(new WWidgetItem(std::move(widget))),
159 	  row, column, rowSpan, columnSpan, alignment);
160 }
161 
setHorizontalSpacing(int size)162 void WGridLayout::setHorizontalSpacing(int size)
163 {
164   grid_.horizontalSpacing_ = size;
165 
166   update();
167 }
168 
setVerticalSpacing(int size)169 void WGridLayout::setVerticalSpacing(int size)
170 {
171   grid_.verticalSpacing_ = size;
172 
173   update();
174 }
175 
columnCount()176 int WGridLayout::columnCount() const
177 {
178   return grid_.columns_.size();
179 }
180 
rowCount()181 int WGridLayout::rowCount() const
182 {
183   return grid_.rows_.size();
184 }
185 
setColumnStretch(int column,int stretch)186 void WGridLayout::setColumnStretch(int column, int stretch)
187 {
188   expand(0, column, 0, 1);
189   grid_.columns_[column].stretch_ = stretch;
190 
191   update();
192 }
193 
columnStretch(int column)194 int WGridLayout::columnStretch(int column) const
195 {
196   return grid_.columns_[column].stretch_;
197 }
198 
setRowStretch(int row,int stretch)199 void WGridLayout::setRowStretch(int row, int stretch)
200 {
201   expand(row, 0, 1, 0);
202   grid_.rows_[row].stretch_ = stretch;
203 
204   update();
205 }
206 
rowStretch(int row)207 int WGridLayout::rowStretch(int row) const
208 {
209   return grid_.rows_[row].stretch_;
210 }
211 
setRowResizable(int row,bool enabled,const WLength & initialSize)212 void WGridLayout::setRowResizable(int row, bool enabled,
213 				  const WLength& initialSize)
214 {
215   expand(row, 0, 1, 0);
216   grid_.rows_[row].resizable_ = enabled;
217   grid_.rows_[row].initialSize_ = initialSize;
218 
219   update();
220 }
221 
rowIsResizable(int row)222 bool WGridLayout::rowIsResizable(int row) const
223 {
224   return grid_.rows_[row].resizable_;
225 }
226 
setColumnResizable(int column,bool enabled,const WLength & initialSize)227 void WGridLayout::setColumnResizable(int column, bool enabled,
228 				     const WLength& initialSize)
229 {
230   expand(0, column, 0, 1);
231   grid_.columns_[column].resizable_ = enabled;
232   grid_.columns_[column].initialSize_ = initialSize;
233 
234   update();
235 }
236 
columnIsResizable(int column)237 bool WGridLayout::columnIsResizable(int column) const
238 {
239   return grid_.columns_[column].resizable_;
240 }
241 
expand(int row,int column,int rowSpan,int columnSpan)242 void WGridLayout::expand(int row, int column, int rowSpan, int columnSpan)
243 {
244   int newRowCount = std::max(rowCount(), row + rowSpan);
245   int newColumnCount = std::max(columnCount(), column + columnSpan);
246 
247   int extraRows = newRowCount - rowCount();
248   int extraColumns = newColumnCount - columnCount();
249 
250   if (extraColumns > 0) {
251     for (int a_row = 0; a_row < rowCount(); ++a_row) {
252       for (int i = 0; i < extraColumns; ++i)
253 	grid_.items_[a_row].push_back(Impl::Grid::Item());
254     }
255 
256     grid_.columns_.insert(grid_.columns_.end(), extraColumns,
257 			  Impl::Grid::Section());
258   }
259 
260   if (extraRows > 0) {
261 #ifndef WT_TARGET_JAVA
262     for (int i = 0; i < extraRows; ++i) {
263       std::vector<Impl::Grid::Item> row;
264       for (int a_col = 0; a_col < columnCount(); ++a_col)
265 	row.push_back(Impl::Grid::Item());
266       grid_.items_.push_back(std::move(row));
267     }
268 #else
269     grid_.items_.insert(grid_.items_.end(), extraRows,
270 			std::vector<Impl::Grid::Item>());
271     for (int i = 0; i < extraRows; ++i) {
272       std::vector<Impl::Grid::Item>& items
273 	= grid_.items_[grid_.items_.size() - extraRows + i];
274       items.insert(items.end(), newColumnCount, Impl::Grid::Item());
275     }
276 #endif // WT_TARGET_JAVA
277     grid_.rows_.insert(grid_.rows_.end(), extraRows, Impl::Grid::Section());
278   }
279 }
280 
setParentWidget(WWidget * parent)281 void WGridLayout::setParentWidget(WWidget *parent)
282 {
283   WLayout::setParentWidget(parent);
284 
285   if (parent)
286     setImpl(std::unique_ptr<WLayoutImpl>
287 	    (new StdGridLayoutImpl2(this, grid_)));
288 }
289 
290 
291 }
292