HoverRace  2.0
FlexGrid.h
Go to the documentation of this file.
1 
2 // FlexGrid.h
3 //
4 // Copyright (c) 2014, 2015 Michael Imamura.
5 //
6 // Licensed under GrokkSoft HoverRace SourceCode License v1.0(the "License");
7 // you may not use this file except in compliance with the License.
8 //
9 // A copy of the license should have been attached to the package from which
10 // you have taken this file. If you can not find the license you can not use
11 // this file.
12 //
13 //
14 // The author makes no representations about the suitability of
15 // this software for any purpose. It is provided "as is" "AS IS",
16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
17 // implied.
18 //
19 // See the License for the specific language governing permissions
20 // and limitations under the License.
21 
22 #pragma once
23 
24 #include "../Exception.h"
25 #include "BaseContainer.h"
26 #include "MPL.h"
27 
28 #if defined(_WIN32) && defined(HR_ENGINE_SHARED)
29 # ifdef MR_ENGINE
30 # define MR_DllDeclare __declspec( dllexport )
31 # else
32 # define MR_DllDeclare __declspec( dllimport )
33 # endif
34 #else
35 # define MR_DllDeclare
36 #endif
37 
38 namespace HoverRace {
39  namespace Display {
40  class Display;
41  }
42 }
43 
44 namespace HoverRace {
45 namespace Display {
46 
53 {
55 
56 public:
57  struct Props
58  {
59  enum
60  {
61  MARGIN = SUPER::Props::NEXT_,
64  };
65  };
66 
67 public:
68  FlexGrid(Display &display, uiLayoutFlags_t layoutFlags = 0);
69  virtual ~FlexGrid() { }
70 
71 public:
72  bool OnAction() override
73  {
74  if (focusedCell) {
75  return rows[focusedCell->first][focusedCell->second]->OnAction();
76  }
77  return false;
78  }
79 
80  bool OnNavigate(const Control::Nav &nav) override
81  {
82  if (focusedCell) {
83  return rows[focusedCell->first][focusedCell->second]->
84  OnNavigate(nav);
85  }
86  return false;
87  }
88 
89 protected:
90  void OnChildRequestedFocus(UiViewModel &child) override;
91  void OnChildRelinquishedFocus(UiViewModel &child,
92  const Control::Nav &nav) override;
93 
94 private:
95  void SetFocusedCell(size_t row, size_t col);
96 
121  template<class Fn>
122  bool FocusFrom(size_t row, size_t col, const Control::Nav &nav, Fn nextFn)
123  {
124  while (nextFn(row, col)) {
125  auto &cols = rows[row];
126  if (col >= cols.size()) break;
127 
128  auto &cell = cols[col];
129  if (cell && cell->TryFocus(nav)) {
130  SetFocusedCell(row, col);
131  return true;
132  }
133  }
134 
135  return false;
136  }
137 
138  bool FocusUpFrom(size_t row, size_t col, const Control::Nav &nav);
139  bool FocusDownFrom(size_t row, size_t col, const Control::Nav &nav);
140  bool FocusLeftFrom(size_t row, size_t col, const Control::Nav &nav);
141  bool FocusRightFrom(size_t row, size_t col, const Control::Nav &nav);
142  bool FocusNextFrom(size_t row, size_t col, const Control::Nav &nav);
143  bool FocusPrevFrom(size_t row, size_t col, const Control::Nav &nav);
144 
145 public:
146  bool TryFocus(const Control::Nav &nav = Control::Nav::NEUTRAL) override;
147  void DropFocus() override;
148 
149 public:
150  const Vec2 &GetMargin() const { return margin; }
151  void SetMargin(double width, double height);
152 
153  const Vec2 &GetPadding() const { return padding; }
154  void SetPadding(double width, double height);
155 
156  static const double AUTOSIZE;
157 
158  bool IsFixedWidth() const;
159  bool IsFixedHeight() const;
160  void SetFixedSize(double w, double h);
161  void SetFixedWidth(double w);
162  void SetFixedHeight(double h);
163 
164  static const size_t BOTTOM;
165  static const size_t RIGHT;
166 
167  boost::optional<std::pair<size_t, size_t>> GetFocusHint(
168  const Control::Nav &nav);
169  void SetFocusHint(const Control::Nav &nav, size_t row, size_t col);
170  void ClearFocusHint(const Control::Nav &nav);
171 
172 public:
173  static Vec2 AlignCellContents(double x, double y, double w, double h,
174  Alignment alignment);
175 
176  class Cell
177  {
178  friend class FlexGrid;
179  public:
180  Cell() { }
181  virtual ~Cell() { }
182 
183  public:
189  virtual void SetAlignment(Alignment alignment) = 0;
190 
200  virtual void SetFill(bool fill) = 0;
201 
202  protected:
212  virtual void SetExtents(double x, double y,
213  double w, double h, double paddingX, double paddingY) = 0;
214 
219  virtual Vec3 Measure() = 0;
220 
222  virtual bool TryFocus(const Control::Nav &nav) = 0;
223 
225  virtual void DropFocus() = 0;
226 
228  virtual bool OnAction() = 0;
229 
231  virtual bool OnNavigate(const Control::Nav&) = 0;
232 
238  virtual bool Contains(const UiViewModel *child) const = 0;
239  };
240 
241 protected:
242  class DefaultCell : public Cell
243  {
244  using SUPER = Cell;
245 
246  public:
248  alignment(Alignment::NW), fill(false) { }
250  alignment(o.alignment), fill(o.fill) { }
251  virtual ~DefaultCell() { }
252 
253  public:
255  alignment = o.alignment;
256  fill = o.fill;
257  return *this;
258  }
259 
260  public:
261  Alignment GetAlignment() const { return alignment; }
262 
263  void SetAlignment(Alignment alignment) override
264  {
265  this->alignment = alignment;
266  }
267 
268  bool IsFill() const { return fill; }
269 
270  void SetFill(bool fill) override
271  {
272  this->fill = fill;
273  }
274 
275  protected:
276  void SetExtents(double, double, double, double,
277  double, double) override { }
278  Vec3 Measure() override { return Vec3(0, 0, 0); }
279  bool TryFocus(const Control::Nav&) override { return false; }
280  void DropFocus() override { }
281  bool OnAction() override { return false; }
282  bool OnNavigate(const Control::Nav&) override { return false; }
283  bool Contains(const UiViewModel*) const override { return false; }
284 
285  private:
287  bool fill;
288  };
289 
290  template<typename T>
291  class BasicCell : public Cell
292  {
293  using SUPER = Cell;
294 
295  public:
296  BasicCell(FlexGrid *parent, const DefaultCell &defaultCell,
297  std::shared_ptr<T> contents) :
298  SUPER(), parent(parent), contents(std::move(contents)),
299  fill(defaultCell.IsFill())
300  {
301  SetAlignment(defaultCell.GetAlignment());
302  }
303 
304  virtual ~BasicCell()
305  {
306  parent->RemoveChild(contents);
307  }
308 
309  public:
310  void SetAlignment(Alignment alignment) override
311  {
312  // We track the alignment using the contents' own alignment
313  // since the caller has implicitly given us control over
314  // the position.
315  if (alignment != contents->GetAlignment()) {
316  contents->SetAlignment(alignment);
317  parent->RequestLayout();
318  }
319  }
320 
321  void SetFill(bool fill) override
322  {
323  this->fill = fill;
324  }
325 
326  protected:
327  void SetSize(double w, double h)
328  {
329  MPL::SetSize(*contents, w, h);
330  }
331 
332  void SetExtents(double x, double y,
333  double w, double h,
334  double paddingX, double paddingY) override
335  {
337  w - (paddingX * 2), h - (paddingY * 2),
338  contents->GetAlignment());
339  contents->SetPos(pos.x + paddingX, pos.y + paddingY);
340  if (fill) {
341  SetSize(w, h);
342  }
343  }
344 
345  Vec3 Measure() override
346  {
347  return contents->Measure();
348  }
349 
350  bool TryFocus(const Control::Nav &nav) override
351  {
352  return contents->TryFocus(nav);
353  }
354 
355  void DropFocus() override
356  {
357  contents->DropFocus();
358  }
359 
360  bool OnAction() override
361  {
362  return contents->OnAction();
363  }
364 
365  bool OnNavigate(const Control::Nav &nav) override
366  {
367  return contents->OnNavigate(nav);
368  }
369 
370  bool Contains(const UiViewModel *child) const override
371  {
372  return contents.get() == child;
373  }
374 
375  public:
376  std::shared_ptr<T> &GetContents() { return contents; }
377 
378  private:
380  std::shared_ptr<T> contents;
381  bool fill;
382  };
383 
384 public:
389  class CellProxy : public Cell
390  {
391  using SUPER = Cell;
392 
393  public:
394  CellProxy(size_t row, size_t col, FlexGrid &grid, Cell *cell) :
395  SUPER(), row(row), col(col), grid(grid), cell(cell) { }
396  CellProxy(const CellProxy&) = default;
397  CellProxy(CellProxy&&) = default;
398  virtual ~CellProxy() { }
399 
400  public:
401  CellProxy &operator=(const CellProxy&) = delete;
402  CellProxy &operator=(CellProxy&&) = delete;
403 
404  private:
405  Cell *CheckCell() const
406  {
407  if (!cell) {
408  std::ostringstream oss;
409  oss << "Cell at row=" << row << ", col=" << col <<
410  " is empty.";
411  throw Exception(oss.str());
412  }
413  else {
414  return cell;
415  }
416  }
417 
418  public:
419  void SetAlignment(Alignment alignment) override
420  {
421  CheckCell()->SetAlignment(alignment);
422  }
423 
424  void SetFill(bool fill) override
425  {
426  CheckCell()->SetFill(fill);
427  }
428 
429  protected:
430  void SetExtents(double x, double y,
431  double w, double h,
432  double paddingX, double paddingY) override
433  {
434  CheckCell()->SetExtents(x, y, w, h, paddingX, paddingY);
435  }
436 
437  Vec3 Measure() override
438  {
439  return CheckCell()->Measure();
440  }
441 
442  bool TryFocus(const Control::Nav &nav) override
443  {
444  return CheckCell()->TryFocus(nav);
445  }
446 
447  void DropFocus() override
448  {
449  CheckCell()->DropFocus();
450  }
451 
452  bool OnAction() override
453  {
454  return CheckCell()->OnAction();
455  }
456 
457  bool OnNavigate(const Control::Nav &nav) override
458  {
459  return CheckCell()->OnNavigate(nav);
460  }
461 
462  bool Contains(const UiViewModel *child) const override
463  {
464  return CheckCell()->Contains(child);
465  }
466 
467  public:
479  template<class T, class... Args>
480  typename std::enable_if<
481  std::is_base_of<UiViewModel, T>::value,
482  std::shared_ptr<BasicCell<T>>
483  >::type
484  NewChild(Args&&... args)
485  {
486  return grid.NewGridCell<T>(row, col, std::forward<Args>(args)...);
487  }
488 
489  private:
490  size_t row;
491  size_t col;
494  };
495 
496 public:
508  CellProxy At(size_t row, size_t col)
509  {
510  Cell *cell = nullptr;
511  if (row < rows.size()) {
512  if (col < rows[row].size()) {
513  cell = rows[row][col].get();
514  }
515  }
516  return { row, col, *this, cell };
517  }
518 
528  Cell &GetColumnDefault(size_t col)
529  {
530  if (col >= defaultCols.size()) {
531  defaultCols.resize(col + 1);
532  }
533 
534  return defaultCols[col];
535  }
536 
537 protected:
538  template<class T, class... Args>
539  typename std::enable_if<
540  std::is_base_of<UiViewModel, T>::value,
541  std::shared_ptr<BasicCell<T>>
542  >::type
543  NewGridCell(size_t row, size_t col, Args&&... args)
544  {
545  auto sharedChild = NewChild<T>(std::forward<Args>(args)...);
546 
547  // Resize the grid to accomodate the cell.
548  if (row >= rows.size()) {
549  size_t oldSize = rows.size();
550  rows.resize(row + 1);
551  if (colReserve > 0) {
552  auto iter = rows.begin();
553  std::advance(iter, oldSize);
554  for (; iter != rows.end(); ++iter) {
555  iter->reserve(colReserve);
556  }
557  }
558  }
559  auto &cols = rows[row];
560  if (col >= cols.size()) {
561  cols.resize(col + 1);
562  if (col >= defaultCols.size()) {
563  defaultCols.resize(col + 1);
564  }
565  }
566 
567  std::shared_ptr<BasicCell<T>> cell =
568  std::make_shared<BasicCell<T>>(this, defaultCols[col],
569  sharedChild);
570 
571  // Add the new cell, replacing the old one if necessary.
572  cols[col] = cell;
573 
574  RequestLayout();
575 
576  return cell;
577  }
578 
579  boost::optional<std::pair<size_t, size_t>> FindChild(
580  UiViewModel *child) const;
581 
582 public:
583  void Clear() override;
584 
585 protected:
586  // We define this here to silence warnings about Reserve(size_t, size_t)
587  // hiding the superclass' Reserve(size_t).
588  void Reserve(size_t capacity) override { SUPER::Reserve(capacity); }
589 public:
590  void Reserve(size_t rows, size_t cols);
591 
592 protected:
593  void Layout() override;
594 
595 public:
596  Vec3 Measure() override;
597 
598 private:
603  size_t colReserve;
604  std::map<Control::Nav::dir_t, std::pair<size_t, size_t>> focusHints;
605  using cells_t = std::vector<std::shared_ptr<Cell>>;
606  std::vector<DefaultCell> defaultCols;
607  std::vector<cells_t> rows;
608  boost::optional<std::pair<size_t, size_t>> focusedCell;
609 };
610 
611 } // namespace Display
612 } // namespace HoverRace
613 
614 #undef MR_DllDeclare
size_t col
Definition: FlexGrid.h:491
bool fill
Definition: FlexGrid.h:287
bool fill
Definition: FlexGrid.h:381
Vec2 margin
Definition: FlexGrid.h:599
std::vector< cells_t > rows
Definition: FlexGrid.h:607
void Reserve(size_t capacity) override
Increase the capacity of the of this container.
Definition: FlexGrid.h:588
bool FocusFrom(size_t row, size_t col, const Control::Nav &nav, Fn nextFn)
Find the next focusable widget in a given direction.
Definition: FlexGrid.h:122
std::shared_ptr< T > & GetContents()
Definition: FlexGrid.h:376
bool Contains(const UiViewModel *child) const override
Check if this contains the specified widget.
Definition: FlexGrid.h:370
void SetAlignment(Alignment alignment) override
Set the how the widget is aligned inside the cell when the cell is larger than the widget...
Definition: FlexGrid.h:419
static const double AUTOSIZE
Indicator that the dimension of the column or table is automatic (instead of fixed).
Definition: FlexGrid.h:156
static const size_t RIGHT
Definition: FlexGrid.h:165
FlexGrid & grid
Definition: FlexGrid.h:492
Vec2 fixedSize
Definition: FlexGrid.h:602
Vec3 Measure() override
Measure the size of the cell contents.
Definition: FlexGrid.h:278
std::enable_if< MPL::HasSetSize< T >::value, void >::type SetSize(T &widget, double w, double h)
Definition: MPL.h:60
std::enable_if< std::is_base_of< UiViewModel, T >::value, std::shared_ptr< BasicCell< T > > >::type NewChild(Args &&...args)
Creates a new child widget in this cell.
Definition: FlexGrid.h:484
double y
Definition: Vec.h:45
Base class for UI (2D) components.
Definition: UiViewModel.h:56
bool OnNavigate(const Control::Nav &nav) override
Trigger OnNavigate() on the contents.
Definition: FlexGrid.h:457
const Vec2 & GetPadding() const
Definition: FlexGrid.h:153
FlexGrid * parent
Definition: FlexGrid.h:379
Upper-left quadrant.
Alignment
Imagine the component pinned to the container with a thumbtack.
Definition: UiViewModel.h:77
size_t row
Definition: FlexGrid.h:490
BasicCell(FlexGrid *parent, const DefaultCell &defaultCell, std::shared_ptr< T > contents)
Definition: FlexGrid.h:296
Cell * CheckCell() const
Definition: FlexGrid.h:405
Definition: FlexGrid.h:176
void SetFill(bool fill) override
Set whether the widget is resized to fill the space of the cell.
Definition: FlexGrid.h:321
STL namespace.
bool TryFocus(const Control::Nav &nav) override
Trigger TryFocus() on the contents.
Definition: FlexGrid.h:350
Definition: FlexGrid.h:57
std::vector< std::shared_ptr< Cell >> cells_t
Definition: FlexGrid.h:605
bool OnAction() override
Trigger OnAction() on the contents.
Definition: FlexGrid.h:281
std::map< Control::Nav::dir_t, std::pair< size_t, size_t > > focusHints
Definition: FlexGrid.h:604
CellProxy At(size_t row, size_t col)
Access a cell of the grid.
Definition: FlexGrid.h:508
Alignment alignment
Definition: FlexGrid.h:286
void SetAlignment(Alignment alignment) override
Set the how the widget is aligned inside the cell when the cell is larger than the widget...
Definition: FlexGrid.h:310
CellProxy(size_t row, size_t col, FlexGrid &grid, Cell *cell)
Definition: FlexGrid.h:394
Base class for widgets that contain other widgets.
Definition: BaseContainer.h:63
void DropFocus() override
Trigger DropFocus() on the contents.
Definition: FlexGrid.h:447
virtual ~DefaultCell()
Definition: FlexGrid.h:251
void SetAlignment(Alignment alignment) override
Set the how the widget is aligned inside the cell when the cell is larger than the widget...
Definition: FlexGrid.h:263
size_t colReserve
Definition: FlexGrid.h:603
Definition: Vec.h:38
double x
Definition: Vec.h:44
MR_UInt32 uiLayoutFlags_t
Definition: UiLayoutFlags.h:53
void SetFill(bool fill) override
Set whether the widget is resized to fill the space of the cell.
Definition: FlexGrid.h:270
void SetExtents(double, double, double, double, double, double) override
Set the position and size of the cell.
Definition: FlexGrid.h:276
Vec3 Measure() override
Measure the size of the cell contents.
Definition: FlexGrid.h:437
void DropFocus() override
Trigger DropFocus() on the contents.
Definition: FlexGrid.h:280
virtual ~FlexGrid()
Definition: FlexGrid.h:69
bool Contains(const UiViewModel *child) const override
Check if this contains the specified widget.
Definition: FlexGrid.h:462
Cell()
Definition: FlexGrid.h:180
Cell & GetColumnDefault(size_t col)
Set the default cell settings for a column.
Definition: FlexGrid.h:528
Base class for display managers.
Definition: Display.h:73
void SetExtents(double x, double y, double w, double h, double paddingX, double paddingY) override
Set the position and size of the cell.
Definition: FlexGrid.h:332
std::vector< DefaultCell > defaultCols
Definition: FlexGrid.h:606
size_t row
Definition: TestLabScene.cpp:163
Vec2 size
Definition: FlexGrid.h:601
bool OnNavigate(const Control::Nav &nav) override
Definition: FlexGrid.h:80
This is used to reference a cell of the grid without directly accessing it; useful for adding new wid...
Definition: FlexGrid.h:389
std::enable_if< std::is_base_of< UiViewModel, T >::value, std::shared_ptr< BasicCell< T > > >::type NewGridCell(size_t row, size_t col, Args &&...args)
Definition: FlexGrid.h:543
bool OnNavigate(const Control::Nav &nav) override
Trigger OnNavigate() on the contents.
Definition: FlexGrid.h:365
bool OnAction() override
Trigger OnAction() on the contents.
Definition: FlexGrid.h:452
virtual ~Cell()
Definition: FlexGrid.h:181
virtual ~BasicCell()
Definition: FlexGrid.h:304
static Vec2 AlignCellContents(double x, double y, double w, double h, Alignment alignment)
Adjust the cell origin position to the position of the contents, based on the contents&#39; alignment...
Definition: FlexGrid.cpp:430
boost::optional< std::pair< size_t, size_t > > focusedCell
Definition: FlexGrid.h:608
void SetSize(double w, double h)
Definition: FlexGrid.h:327
A navigation direction.
Definition: Nav.h:45
#define MR_DllDeclare
Definition: FlexGrid.h:35
A container that arranges components into a grid that is automatically sized to the contents...
Definition: FlexGrid.h:52
Cell * cell
Definition: FlexGrid.h:493
DefaultCell(DefaultCell &&o)
Definition: FlexGrid.h:249
DefaultCell()
Definition: FlexGrid.h:247
bool TryFocus(const Control::Nav &nav) override
Trigger TryFocus() on the contents.
Definition: FlexGrid.h:442
bool IsFill() const
Definition: FlexGrid.h:268
void DropFocus() override
Trigger DropFocus() on the contents.
Definition: FlexGrid.h:355
bool OnNavigate(const Control::Nav &) override
Trigger OnNavigate() on the contents.
Definition: FlexGrid.h:282
Definition: FlexGrid.h:291
std::shared_ptr< T > contents
Definition: FlexGrid.h:380
Definition: Announcement.h:24
Alignment GetAlignment() const
Definition: FlexGrid.h:261
void SetFill(bool fill) override
Set whether the widget is resized to fill the space of the cell.
Definition: FlexGrid.h:424
void SetExtents(double x, double y, double w, double h, double paddingX, double paddingY) override
Set the position and size of the cell.
Definition: FlexGrid.h:430
bool Contains(const UiViewModel *) const override
Check if this contains the specified widget.
Definition: FlexGrid.h:283
bool OnAction() override
Trigger OnAction() on the contents.
Definition: FlexGrid.h:360
DefaultCell & operator=(DefaultCell &&o)
Definition: FlexGrid.h:254
Base exception, providing constructors for setting the message.
Definition: Exception.h:42
Definition: Vec.h:114
virtual ~CellProxy()
Definition: FlexGrid.h:398
Vec2 padding
Definition: FlexGrid.h:600
bool OnAction() override
Definition: FlexGrid.h:72
static const size_t BOTTOM
Definition: FlexGrid.h:164
const Vec2 & GetMargin() const
Definition: FlexGrid.h:150
Vec3 Measure() override
Measure the size of the cell contents.
Definition: FlexGrid.h:345
bool TryFocus(const Control::Nav &) override
Trigger TryFocus() on the contents.
Definition: FlexGrid.h:279
First index for subclasses.
Definition: FlexGrid.h:63
size_t col
Definition: ProfileEditScene.cpp:151