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