CheeseBoard
A library for use with the CheeseBoard Cheddar platform
GfxSSIDListBox.cpp
1 #include <MutilaDebug.h>
2 #include <Millis.h>
3 #include "GfxSSIDListBox.h"
4 #include "GfxTextBox.h"
5 #include "GfxSignalStrength.h"
6 #include "CbOledDisplay.h"
7 #include "CheeseboardConfig.h"
8 
9 GfxSSIDListBox::GfxSSIDListBox(uint16_t x, uint16_t y) :
10  _selected(-1)
11 {
12  for(uint8_t i=0; i<MaxItems; i++) {
13  _items[i] = NULL;
14  }
15 
16  // TODO: calculate screen lines based on line height and screen size
17  // as ooposed to this hard-coded value
18  _lineHeight = (CBOLED_MESSAGE_FONT_HEIGHT + (2*CBOLED_MESSAGE_FONT_VSEP));
19  _screenLines = CbOledDisplay.getDisplayHeight() / _lineHeight;
20  _screenStart = 0;
21 }
22 
23 GfxSSIDListBox::~GfxSSIDListBox()
24 {
25  for(uint8_t i=0; i<MaxItems; i++) {
26  if (_items[i] != NULL) {
27  delete _items[i];
28  _items[i] = NULL;
29  }
30  }
31 }
32 
34 {
35  int16_t i = findGap();
36  if (i >= 0) {
37  _items[i] = new GfxNetInfo(s);
38  return true;
39  } else {
40  return false;
41  }
42 }
43 
44 bool GfxSSIDListBox::remove(const uint8_t idx, bool compactAfter)
45 {
46  if (idx >= 0 && idx <MaxItems && _items[idx] != NULL) {
47  delete _items[idx];
48  _items[idx] = NULL;
49 
50  // remove selection
51  if (_selected == idx) {
52  _selected = -1;
53  }
54 
55  // compact if requested
56  if (compactAfter) {
57  compact();
58  }
59  return true;
60  } else {
61  return false;
62  }
63 }
64 
65 void GfxSSIDListBox::draw(uint16_t xOffset, uint16_t yOffset)
66 {
67  uint8_t drawn = 0;
68  for(uint8_t i=0; i<MaxItems && drawn<_screenLines; i++) {
69  if (_items[i] != NULL) {
70  if (isOnScreen(i)) {
71  uint16_t y = drawn * _items[i]->height();
72  _items[i]->draw(xOffset, yOffset+y);
73  if (_selected == i) {
74  CbOledDisplay.drawFrame(xOffset, y, _items[i]->width(), _items[i]->height());
75  }
76  drawn++;
77  }
78  }
79  }
80 }
81 
83 {
84  return 128;
85 }
86 
88 {
89  return _lineHeight * (count() < _screenLines ? count() : _screenLines);
90 }
91 
93 {
94  if (idx < 0 or idx >= MaxItems) {
95  return NULL;
96  } else {
97  return _items[idx];
98  }
99 }
100 
102 {
103  int16_t idx = this->find(ssid, 1);
104  if (idx == -1) {
105  return NULL;
106  } else {
107  return _items[idx];
108  }
109 }
110 
111 int16_t GfxSSIDListBox::findGap(uint8_t startAt)
112 {
113  uint8_t i;
114  for(i=startAt; i<MaxItems && _items[i] != NULL; i++) {;}
115  if (i<MaxItems) {
116  return i;
117  } else {
118  return -1;
119  }
120 }
121 
122 int16_t GfxSSIDListBox::findNext(uint8_t from)
123 {
124  for(uint8_t i=from+1; i<MaxItems; i++) {
125  if (_items[i] != NULL) {
126  return i;
127  }
128  }
129  return -1;
130 }
131 
132 int16_t GfxSSIDListBox::findPreceding(uint8_t from)
133 {
134  if (from == 0 || from >= MaxItems) {
135  return -1;
136  }
137 
138  for(uint8_t i=from-1; i>=0; i--) {
139  if (_items[i] != NULL) {
140  return i;
141  }
142  }
143  return -1;
144 }
145 
147 {
148  uint8_t count=0;
149  for (uint8_t i=0; i<MaxItems; i++) {
150  if (_items[i] != NULL) {
151  count++;
152  }
153  }
154  return count;
155 }
156 
157 int16_t GfxSSIDListBox::find(const String& ssid, uint8_t n)
158 {
159  for (uint8_t i=0; i<MaxItems; i++) {
160  if (_items[i] != NULL) {
161  if (_items[i]->ssid() == ssid) {
162  if (n-- == 1) {
163  return i;
164  }
165  }
166  }
167  }
168  return -1;
169 }
170 
172 // TODO: void GfxSSIDListBox::sort();
173 
175 {
176  int16_t gap = findGap();
177  if (gap >= 0) {
178  for (uint8_t i=gap+1; i<MaxItems; i++) {
179  if (_items[i] != NULL) {
180  return false;
181  }
182  }
183  }
184  return true;
185 }
186 
189 {
190  while (!isCompacted()) {
191  int16_t gap = findGap();
192  if (gap >= 0) {
193  for(uint8_t i=gap; i<MaxItems-1; i++) {
194  _items[i] = _items[i+1];
195  if (i+1 == _selected) {
196  _selected = i;
197  }
198  }
199  _items[MaxItems-1] = NULL;
200  }
201  }
202 }
203 
204 bool GfxSSIDListBox::select(int16_t idx)
205 {
206  if (idx >= MaxItems || !(idx == -1 || _items[idx] != NULL)) {
207  return false;
208  } else {
209  _selected = idx;
210  return true;
211  return false;
212  }
213 }
214 
217 {
218  return _selected;
219 }
220 
221 bool GfxSSIDListBox::isOnScreen(uint8_t idx)
222 {
223  uint8_t lines = _screenLines;
224  for (uint8_t i=_screenStart; i<MaxItems && lines>0; i++) {
225  if (i == idx) {
226  return true;
227  }
228  if (_items[i] != NULL) {
229  lines--;
230  }
231  }
232  return false;
233 }
234 
235 uint8_t GfxSSIDListBox::rowsFrom(uint8_t idx)
236 {
237  uint8_t count = 0;
238  for (uint8_t i=idx; i<MaxItems; i++) {
239  if (_items[i] != NULL) {
240  count++;
241  }
242  }
243  return count;
244 }
245 
246 uint8_t GfxSSIDListBox::scrollDown(uint8_t rows)
247 {
248  uint8_t scrolled = 0;
249  while(rows > 0) {
250  int16_t nextItem = findNext(_screenStart);
251  if (nextItem == -1) {
252  return scrolled;
253  }
254  if (rowsFrom(nextItem) < _screenLines) {
255  return scrolled;
256  } else {
257  _screenStart = nextItem;
258  scrolled++;
259  }
260  rows--;
261  }
262  return scrolled;
263 }
264 
265 uint8_t GfxSSIDListBox::scrollUp(uint8_t rows)
266 {
267  uint8_t scrolled = 0;
268  while(rows > 0) {
269  int16_t preItem = findPreceding(_screenStart);
270  if (preItem == -1) {
271  return scrolled;
272  }
273  _screenStart = preItem;
274  scrolled++;
275  rows--;
276  }
277  return scrolled;
278 }
279 
280 bool GfxSSIDListBox::scrollTo(uint8_t idx)
281 {
282  if (_items[idx] == NULL || idx > MaxItems) {
283  return false;
284  }
285 
286  if (idx < _screenStart) {
287  // Ohhhh... I feel like I'm tempting an infinite loop here
288  while(!isOnScreen(idx)) {
289  scrollUp(1);
290  }
291  } else {
292  while(!isOnScreen(idx)) {
293  // Ohhhh... I feel like I'm tempting an infinite loop here
294  scrollDown(1);
295  }
296  }
297 }
298 
299 int16_t GfxSSIDListBox::update(String ssid, int8_t channel, uint8_t signal)
300 {
301  int16_t idx = this->find(ssid);
302  if (idx != -1) {
303  _items[idx]->update(channel, signal);
304  return idx;
305  } else {
306  GfxNetInfo* netInfo = new GfxNetInfo(ssid, channel, signal);
307  if (netInfo == NULL) {
308  // ERROR, could not allocate new object
309  return -1;
310  }
311  idx = this->add(*netInfo);
312  if (idx == -1) {
313  // ERROR could not add item to list
314  delete netInfo;
315  }
316  return idx;
317  }
318 }
319 
int16_t add(const GfxNetInfo s)
void compact()
Make used items contiguous (remove gaps)
bool isOnScreen(uint8_t idx)
int16_t update(String ssid, int8_t channel, uint8_t signal)
uint8_t scrollUp(uint8_t rows)
bool remove(const uint8_t idx, bool compactAfter=true)
int16_t findGap(uint8_t startAt=0)
bool scrollTo(uint8_t idx)
uint8_t rowsFrom(uint8_t idx)
void draw(uint16_t xOffset=0, uint16_t yOffset=0)
uint16_t height()
GfxNetInfo * operator[](int16_t idx)
uint8_t scrollDown(uint8_t rows)
bool select(int16_t idx)
int16_t findNext(uint8_t from=0)
bool isCompacted()
Sort the items contained in the list box using quicksort.
int16_t find(const String &ssid, uint8_t n=1)
int16_t findPreceding(uint8_t from=MaxItems)
uint16_t width()