Numworks Epsilon  1.4.1
Graphing Calculator Operating System
button_row_controller.cpp
Go to the documentation of this file.
2 #include <escher/palette.h>
3 #include <cmath>
4 
6  m_header(header),
7  m_footer(footer)
8 {
9 }
10 
11 ButtonRowController::ContentView::ContentView(ViewController * mainViewController, ButtonRowDelegate * delegate, Position position, Style style, Size size) :
12  View(),
13  m_mainViewController(mainViewController),
14  m_selectedButton(-1),
15  m_delegate(delegate),
16  m_position(position),
17  m_style(style),
18  m_size(size)
19 {
20 }
21 
22 int ButtonRowController::ContentView::numberOfButtons() const {
23  return m_delegate->numberOfButtons(m_position);
24 }
25 
26 Button * ButtonRowController::ContentView::buttonAtIndex(int index) const {
27  return m_delegate->buttonAtIndex(index, m_position);
28 }
29 
30 int ButtonRowController::ContentView::numberOfSubviews() const {
31  return numberOfButtons() + 1;
32 }
33 
34 View * ButtonRowController::ContentView::subviewAtIndex(int index) {
35  /* Warning: the order of the subviews is important for drity tracking.
36  * Indeed, when a child is redrawn, the redrawn area is the smallest
37  * rectangle unioniong the dirty rectangle and the previous redrawn area.
38  * As the main view is more likely to be bigger, we prefer to set it as the
39  * last child. */
40  if (index == numberOfSubviews() - 1) {
41  return m_mainViewController->view();
42  } else {
43  return buttonAtIndex(index);
44  }
45 }
46 
47 void ButtonRowController::ContentView::layoutSubviews() {
48  /* Position the main view */
49  if (numberOfButtons() == 0) {
50  KDCoordinate margin = m_position == Position::Top ? 1 : 0;
51  KDRect mainViewFrame(0, margin, bounds().width(), bounds().height()-margin);
52  m_mainViewController->view()->setFrame(mainViewFrame);
53  return;
54  }
55  KDCoordinate rowHeight;
56  if (m_style == Style::PlainWhite) {
57  rowHeight = k_plainStyleHeight;
58  } else {
59  rowHeight = m_size == Size::Small ? k_embossedStyleHeightSmall : k_embossedStyleHeightLarge;
60  }
61  KDCoordinate frameOrigin = m_position == Position::Top ? rowHeight+1 : 0;
62  KDRect mainViewFrame(0, frameOrigin, bounds().width(), bounds().height() - rowHeight - 1);
63  m_mainViewController->view()->setFrame(mainViewFrame);
64 
65  /* Position buttons */
66  int nbOfButtons = numberOfButtons();
67  KDCoordinate widthMargin = 0;
68  KDCoordinate buttonHeightMargin = 0;
69  KDCoordinate buttonHeight = rowHeight;
70  if (m_style == Style::EmbossedGrey) {
71  KDCoordinate totalButtonWidth = 0;
72  for (int i = 0; i < nbOfButtons; i++) {
73  Button * button = buttonAtIndex(i);
74  totalButtonWidth += button->minimalSizeForOptimalDisplay().width();
75  }
76  widthMargin = std::round(((float)(bounds().width() - totalButtonWidth))/((float)(nbOfButtons+1)));
77  buttonHeightMargin = m_size == Size::Small ? k_embossedStyleHeightMarginSmall : k_embossedStyleHeightMarginLarge;
78  buttonHeight = rowHeight- 2*buttonHeightMargin;
79  }
80  KDCoordinate yOrigin = m_position == Position::Top ? buttonHeightMargin : bounds().height()-rowHeight+buttonHeightMargin;
81  int currentXOrigin = widthMargin;
82  for (int i = 0; i < numberOfButtons(); i++) {
83  Button * button = buttonAtIndex(i);
84  KDCoordinate buttonWidth = button->minimalSizeForOptimalDisplay().width();
85  KDRect buttonFrame(currentXOrigin, yOrigin, buttonWidth, buttonHeight);
86  button->setFrame(buttonFrame);
87  currentXOrigin += buttonWidth + widthMargin;
88  }
89 }
90 
91 void ButtonRowController::ContentView::drawRect(KDContext * ctx, KDRect rect) const {
92  if (numberOfButtons() == 0) {
93  if (m_position == Position::Top) {
94  ctx->fillRect(KDRect(0, 0, bounds().width(), 1), Palette::GreyWhite);
95  }
96  return;
97  }
98  if (m_style == Style::PlainWhite) {
99  if (m_position == Position::Top) {
100  ctx->fillRect(KDRect(0, 0, bounds().width(), k_plainStyleHeight), KDColorWhite);
101  ctx->fillRect(KDRect(0, k_plainStyleHeight, bounds().width(), 1), Palette::GreyWhite);
102  } else {
103  ctx->fillRect(KDRect(0, bounds().height() - k_plainStyleHeight, bounds().width(), k_plainStyleHeight), KDColorWhite);
104  ctx->fillRect(KDRect(0, bounds().height() - k_plainStyleHeight-1, bounds().width(), 1), Palette::GreyWhite);
105  }
106  return;
107  }
108  int buttonHeight = m_size == Size::Small ? k_embossedStyleHeightSmall : k_embossedStyleHeightLarge;
109  int buttonMargin = m_size == Size::Small ? k_embossedStyleHeightMarginSmall : k_embossedStyleHeightMarginLarge;
110  if (m_position == Position::Top) {
111  ctx->fillRect(KDRect(0, 0, bounds().width(), buttonHeight), Palette::GreyWhite);
112  ctx->fillRect(KDRect(0, buttonHeight, bounds().width(), 1), Palette::GreyMiddle);
113  } else {
114  ctx->fillRect(KDRect(0, bounds().height() - buttonHeight, bounds().width(), buttonHeight), Palette::GreyWhite);
115  ctx->fillRect(KDRect(0, bounds().height() - buttonHeight-1, bounds().width(), 1), Palette::GreyMiddle);
116  }
117  KDCoordinate y0 = m_position == Position::Top ? buttonMargin-1 : bounds().height()-buttonHeight+buttonMargin-1;
118  KDCoordinate y1 = m_position == Position::Top ? buttonHeight-buttonMargin-2 : bounds().height()-buttonMargin;
119  KDCoordinate totalButtonWidth = 0;
120  for (int i = 0; i < numberOfButtons(); i++) {
121  Button * button = buttonAtIndex(i);
122  totalButtonWidth += button->minimalSizeForOptimalDisplay().width();
123  }
124  KDCoordinate widthMargin = std::round(((float)(bounds().width() - totalButtonWidth))/((float)(numberOfButtons()+1)));
125 
126  int currentXOrigin = widthMargin-1;
127  for (int i = 0; i < numberOfButtons(); i++) {
128  Button * button = buttonAtIndex(i);
129  KDCoordinate buttonWidth = button->minimalSizeForOptimalDisplay().width();
130  ctx->fillRect(KDRect(currentXOrigin, y0, 1, y1-y0+1), Palette::GreyMiddle);
131  ctx->fillRect(KDRect(currentXOrigin-1, y0, 1, y1-y0+2), Palette::GreyDark);
132  ctx->fillRect(KDRect(currentXOrigin, y0, buttonWidth+2, 1), Palette::GreyMiddle);
133  ctx->fillRect(KDRect(currentXOrigin, y1, buttonWidth+2, 1), Palette::GreyMiddle);
134  ctx->fillRect(KDRect(currentXOrigin, y1+1, buttonWidth+2, 1), Palette::GreyDark);
135  ctx->fillRect(KDRect(currentXOrigin+1+buttonWidth, y0, 1, y1-y0+1), Palette::GreyMiddle);
136  currentXOrigin += buttonWidth + widthMargin;
137  }
138 }
139 
140 bool ButtonRowController::ContentView::setSelectedButton(int selectedButton, App * application) {
141  if (selectedButton < -1 || selectedButton >= numberOfButtons() || selectedButton == m_selectedButton) {
142  return false;
143  }
144  if (m_selectedButton >= 0) {
145  Button * button = buttonAtIndex(m_selectedButton);
146  button->setHighlighted(false);
147  }
148  m_selectedButton = selectedButton;
149  if (m_selectedButton >= 0) {
150  Button * button = buttonAtIndex(selectedButton);
151  button->setHighlighted(true);
152  application->setFirstResponder(button);
153  return true;
154  }
155  return false;
156 }
157 
158 ButtonRowController::ButtonRowController(Responder * parentResponder, ViewController * mainViewController, ButtonRowDelegate * delegate, Position position, Style style, Size size) :
159  ViewController(parentResponder),
160  m_contentView(mainViewController, delegate, position, style, size)
161 {
162 }
163 
165  return m_contentView.mainViewController()->title();
166 }
167 
169  app()->setFirstResponder(m_contentView.mainViewController());
170 }
171 
173  return m_contentView.selectedButton();
174 }
175 
176 bool ButtonRowController::setSelectedButton(int selectedButton) {
177  App * application = app();
178  return m_contentView.setSelectedButton(selectedButton, application);
179 }
180 
182  if (event == Ion::Events::Left) {
183  if (m_contentView.selectedButton() == 0) {
184  } else {
185  setSelectedButton(m_contentView.selectedButton() - 1);
186  }
187  return true;
188  }
189  if (event == Ion::Events::Right) {
190  if (m_contentView.selectedButton() == - 1) {
191  } else {
192  setSelectedButton(m_contentView.selectedButton() + 1);
193  }
194  return true;
195  }
196  if (event == Ion::Events::OK || event == Ion::Events::EXE) {
197  return true;
198  }
199  return false;
200 }
201 
203  /* We need to layout subviews at first appearance because the number of
204  * buttons might have changed between 2 appearences. */
205  m_contentView.layoutSubviews();
206  m_contentView.mainViewController()->viewWillAppear();
207 }
208 
210  m_contentView.mainViewController()->viewDidDisappear();
211 }
const char * title() override
ButtonRowDelegate(ButtonRowController *header, ButtonRowController *footer)
void viewDidDisappear() override
void setFrame(KDRect frame)
Definition: view.cpp:125
constexpr Event EXE
Definition: events.h:114
int16_t KDCoordinate
Definition: coordinate.h:6
constexpr KDCoordinate width() const
Definition: size.h:10
static constexpr KDColor GreyDark
Definition: palette.h:15
KDSize minimalSizeForOptimalDisplay() const override
Definition: button.cpp:42
ButtonRowController(Responder *parentResponder, ViewController *mainViewController, ButtonRowDelegate *delegate, Position position=Position::Top, Style=Style::PlainWhite, Size size=Size::Small)
constexpr KDColor KDColorWhite
Definition: color.h:42
#define round(x)
Definition: math.h:192
void setHighlighted(bool highlight) override
Definition: button.cpp:35
bool handleEvent(Ion::Events::Event event) override
static constexpr KDColor GreyMiddle
Definition: palette.h:14
void didBecomeFirstResponder() override
constexpr Event Left
Definition: events.h:61
Definition: app.h:23
bool setSelectedButton(int selectedButton)
Definition: rect.h:26
void fillRect(KDRect rect, KDColor color)
Definition: context_rect.cpp:8
void setFirstResponder(Responder *responder)
Definition: app.cpp:62
Definition: view.h:23
constexpr Event Right
Definition: events.h:64
App * app()
Definition: responder.cpp:77
constexpr Event OK
Definition: events.h:65
Definition: button.h:10
static constexpr KDColor GreyWhite
Definition: palette.h:12