ManaPlus
layoutarray.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2007-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2018 The ManaPlus Developers
6  *
7  * This file is part of The ManaPlus Client.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
24 
25 #include "enums/gui/layouttype.h"
26 
27 #include "gui/widgets/layoutcell.h"
28 #include "gui/widgets/widget.h"
29 
30 #include <cassert>
31 
32 #include "debug.h"
33 
35  mCells(),
36  mSpacing(4)
37 {
38 }
39 
41 {
42  STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
43  i = mCells.begin();
44  const STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
45  i_end = mCells.end();
46  while (i != i_end)
47  {
48  STD_VECTOR< LayoutCell * >::iterator j = i->begin();
49  const STD_VECTOR< LayoutCell * >::iterator j_end = i->end();
50  while (j != j_end)
51  {
52  delete *j;
53  ++j;
54  }
55  ++i;
56  }
57 }
58 
59 LayoutCell &LayoutArray::at(const int x, const int y,
60  const int w, const int h)
61 {
62  resizeGrid(x + w, y + h);
63  LayoutCell *&cell = mCells[CAST_SIZE(y)][static_cast<size_t>(x)];
64  if (cell == nullptr)
65  cell = new LayoutCell;
66  return *cell;
67 }
68 
69 void LayoutArray::resizeGrid(int w, const int h)
70 {
71  const bool extW = (w != 0) && w > CAST_S32(mSizes[0].size());
72  const bool extH = (h != 0) && h > CAST_S32(mSizes[1].size());
73 
74  if (!extW && !extH)
75  return;
76 
77  if (extH)
78  {
79  mSizes[1].resize(CAST_SIZE(h), LayoutType::DEF);
80  mCells.resize(CAST_SIZE(h));
81  if (!extW)
82  w = CAST_S32(mSizes[0].size());
83  }
84 
85  if (extW)
86  mSizes[0].resize(CAST_SIZE(w), LayoutType::DEF);
87 
88  STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
89  i = mCells.begin();
90  const STD_VECTOR <STD_VECTOR <LayoutCell *> >::iterator
91  i_end = mCells.end();
92  while (i != i_end)
93  {
94  i->resize(CAST_SIZE(w), nullptr);
95  ++i;
96  }
97 }
98 
99 void LayoutArray::setColWidth(const int n, const int w)
100 {
101  resizeGrid(n + 1, 0);
102  mSizes[0U][CAST_SIZE(n)] = w;
103 }
104 
105 void LayoutArray::setRowHeight(const int n, const int h)
106 {
107  resizeGrid(0, n + 1);
108  mSizes[1][CAST_SIZE(n)] = h;
109 }
110 
111 void LayoutArray::matchColWidth(const int n1, const int n2)
112 {
113  resizeGrid(std::max(n1, n2) + 1, 0);
114  const STD_VECTOR<int> widths = getSizes(0, LayoutType::DEF);
115  const int s = std::max(widths[CAST_SIZE(n1)],
116  widths[CAST_SIZE(n2)]);
117  mSizes[0][CAST_SIZE(n1)] = s;
118  mSizes[0][CAST_SIZE(n2)] = s;
119 }
120 
121 void LayoutArray::extend(const int x, const int y, const int w, const int h)
122 {
123  LayoutCell &cell = at(x, y, w, h);
124  cell.mExtent[0] = w;
125  cell.mExtent[1] = h;
126 }
127 
128 LayoutCell &LayoutArray::place(Widget *const widget, const int x,
129  const int y, const int w, const int h)
130 {
131  LayoutCell &cell = at(x, y, w, h);
132  assert(cell.mType == LayoutCell::NONE);
133  cell.mType = LayoutCell::WIDGET;
134  cell.mWidget = widget;
135  if (widget != nullptr)
136  {
137  cell.mSize[0] = w == 1 ? widget->getWidth() : 0;
138  cell.mSize[1] = h == 1 ? widget->getHeight() : 0;
139  }
140  else
141  {
142  cell.mSize[0] = 1;
143  cell.mSize[1] = 1;
144  }
145  cell.mExtent[0] = w;
146  cell.mExtent[1] = h;
147  cell.mHPadding = 0;
148  cell.mVPadding = 0;
149  cell.mAlign[0] = LayoutCell::FILL;
150  cell.mAlign[1] = LayoutCell::FILL;
151  int &cs = mSizes[0][CAST_SIZE(x)];
152  int &rs = mSizes[1][CAST_SIZE(y)];
153  if (cs == LayoutType::DEF && w == 1)
154  cs = 0;
155  if (rs == LayoutType::DEF && h == 1)
156  rs = 0;
157  return cell;
158 }
159 
160 void LayoutArray::align(int &restrict pos, int &restrict size, const int dim,
161  LayoutCell const &restrict cell,
162  const int *restrict const sizes,
163  const int sizeCount) const
164 {
165  if (dim < 0 || dim >= 2)
166  return;
167  int size_max = sizes[0];
168  int cnt = cell.mExtent[dim];
169  if ((sizeCount != 0) && cell.mExtent[dim] > sizeCount)
170  cnt = sizeCount;
171 
172  for (int i = 1; i < cnt; ++i)
173  size_max += sizes[i] + mSpacing;
174  size = std::min<int>(cell.mSize[dim], size_max);
175 
176  switch (cell.mAlign[dim])
177  {
178  case LayoutCell::LEFT:
179  return;
180  case LayoutCell::RIGHT:
181  pos += size_max - size;
182  return;
183  case LayoutCell::CENTER:
184  pos += (size_max - size) / 2;
185  return;
186  case LayoutCell::FILL:
187  size = size_max;
188  return;
189  default:
190  logger->log1("LayoutArray::align unknown layout");
191  return;
192  }
193 }
194 
195 STD_VECTOR<int> LayoutArray::getSizes(const int dim, int upp) const
196 {
197  if (dim < 0 || dim >= 2)
198  return mSizes[1];
199 
200  const int gridW = CAST_S32(mSizes[0].size());
201  const int gridH = CAST_S32(mSizes[1].size());
202  STD_VECTOR<int> sizes = mSizes[dim];
203 
204  // Compute minimum sizes.
205  for (int gridY = 0; gridY < gridH; ++gridY)
206  {
207  for (int gridX = 0; gridX < gridW; ++gridX)
208  {
209  const LayoutCell *const cell = mCells[CAST_SIZE(gridY)]
210  [CAST_SIZE(gridX)];
211  if ((cell == nullptr) || cell->mType == LayoutCell::NONE)
212  continue;
213 
214  if (cell->mExtent[dim] == 1)
215  {
216  const int n = (dim == 0 ? gridX : gridY);
217  const int s = cell->mSize[dim] + cell->mVPadding * 2;
218  if (s > sizes[CAST_SIZE(n)])
219  sizes[CAST_SIZE(n)] = s;
220  }
221  }
222  }
223 
224  if (upp == LayoutType::DEF)
225  return sizes;
226 
227  // Compute the FILL sizes.
228  const int nb = CAST_S32(sizes.size());
229  int nbFill = 0;
230  for (int i = 0; i < nb; ++i)
231  {
232  if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)]
233  <= LayoutType::DEF)
234  {
235  ++nbFill;
236  if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] ==
237  LayoutType::SET ||
238  sizes[CAST_SIZE(i)] <= LayoutType::DEF)
239  {
240  sizes[CAST_SIZE(i)] = 0;
241  }
242  }
243  upp -= sizes[CAST_SIZE(i)] + mSpacing;
244  }
245  upp = upp + mSpacing;
246 
247  if (nbFill == 0)
248  return sizes;
249 
250  for (int i = 0; i < nb; ++i)
251  {
252  if (mSizes[CAST_SIZE(dim)][static_cast<size_t>(i)] >
254  {
255  continue;
256  }
257 
258  const int s = upp / nbFill;
259  sizes[CAST_SIZE(i)] += s;
260  upp -= s;
261  --nbFill;
262  }
263 
264  return sizes;
265 }
266 
267 int LayoutArray::getSize(const int dim) const
268 {
269  STD_VECTOR<int> sizes = getSizes(dim, LayoutType::DEF);
270  int size = 0;
271  const int nb = CAST_S32(sizes.size());
272  for (int i = 0; i < nb; ++i)
273  {
274  if (sizes[CAST_SIZE(i)] > LayoutType::DEF)
275  size += sizes[CAST_SIZE(i)];
276  size += mSpacing;
277  }
278  return size - mSpacing;
279 }
280 
281 void LayoutArray::reflow(const int nx, const int ny,
282  const int nw, const int nh)
283 {
284  const int gridW = CAST_S32(mSizes[0].size());
285  const int gridH = CAST_S32(mSizes[1].size());
286 
287  STD_VECTOR<int> widths = getSizes(0, nw);
288  STD_VECTOR<int> heights = getSizes(1, nh);
289 
290  const int szW = CAST_S32(widths.size());
291  const int szH = CAST_S32(heights.size());
292  int y = ny;
293  for (int gridY = 0; gridY < gridH; ++gridY)
294  {
295  int x = nx;
296  for (int gridX = 0; gridX < gridW; ++gridX)
297  {
298  LayoutCell *const cell = mCells[CAST_SIZE(gridY)]
299  [CAST_SIZE(gridX)];
300  if ((cell != nullptr) && cell->mType != LayoutCell::NONE)
301  {
302  int dx = x;
303  int dy = y;
304  int dw = 0;
305  int dh = 0;
306  align(dx, dw, 0, *cell,
307  &widths[CAST_SIZE(gridX)], szW - gridX);
308  align(dy, dh, 1, *cell,
309  &heights[CAST_SIZE(gridY)], szH - gridY);
310  cell->reflow(dx, dy, dw, dh);
311  }
312  x += widths[CAST_SIZE(gridX)] + mSpacing;
313  }
314  y += heights[CAST_SIZE(gridY)] + mSpacing;
315  }
316 }
void setColWidth(const int n, const int w)
Definition: layoutarray.cpp:99
int getWidth() const
Definition: widget.h:220
void log1(const char *const log_text)
Definition: logger.cpp:233
int mHPadding
Definition: layoutcell.h:196
int getSize(const int dim) const
LayoutCell & place(Widget *const widget, const int x, const int y, const int w, const int h)
void reflow(int nx, int ny, int nw, int nh)
Definition: layoutcell.cpp:63
int mVPadding
Definition: layoutcell.h:197
LayoutCell & at(const int x, const int y, const int w, const int h)
Definition: layoutarray.cpp:59
Logger * logger
Definition: logger.cpp:88
Widget * mWidget
Definition: layoutcell.h:180
int mSize[2]
Definition: layoutcell.h:195
void align(int &pos, int &size, const int dim, LayoutCell const &cell, const int *const sizes, const int sizeCount) const
#define CAST_S32
Definition: cast.h:29
friend class LayoutCell
Definition: layoutarray.h:38
int mExtent[2]
Definition: layoutcell.h:198
void setRowHeight(const int n, const int h)
std::vector< int > mSizes[2]
Definition: layoutarray.h:126
void reflow(const int nX, const int nY, const int nW, const int nH)
void matchColWidth(const int n1, const int n2)
Definition: widget.h:97
Alignment mAlign[2]
Definition: layoutcell.h:199
int getHeight() const
Definition: widget.h:239
void extend(const int x, const int y, const int w, const int h)
#define restrict
Definition: localconsts.h:164
#define CAST_SIZE
Definition: cast.h:33
std::vector< int > getSizes(const int dim, int upp) const
void resizeGrid(int w, const int h)
Definition: layoutarray.cpp:69
std::vector< std::vector< LayoutCell *> > mCells
Definition: layoutarray.h:127