Foundation classes for a basic GUI implementing simple widgets and events
Dependents: TouchScreenGUIDemo
Widgets/Widget.cpp@18:d849f3ada858, 2016-05-28 (annotated)
- Committer:
- duncanFrance
- Date:
- Sat May 28 14:50:14 2016 +0000
- Revision:
- 18:d849f3ada858
- Parent:
- 17:5184762fda6c
Moved the event queue into the EventDispatcher; Improved event handling across Window/Widget
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
duncanFrance | 12:63db16fea709 | 1 | #include "Widget.h" |
duncanFrance | 12:63db16fea709 | 2 | #include <algorithm> |
duncanFrance | 12:63db16fea709 | 3 | Widget::Widget(GraphicsContext* context) |
duncanFrance | 12:63db16fea709 | 4 | : _context(context), |
duncanFrance | 12:63db16fea709 | 5 | _fg(White), _bg(Black), |
duncanFrance | 13:6714534e7974 | 6 | _offset(0,0), _inner(0,0,0,0), _outer(0,0,0,0), |
duncanFrance | 12:63db16fea709 | 7 | _hidden(false), |
duncanFrance | 13:6714534e7974 | 8 | _padding(0), _borderWidth(0), _borderColour(Black), |
duncanFrance | 12:63db16fea709 | 9 | _adjusting(false), |
duncanFrance | 12:63db16fea709 | 10 | _dirtied(true), _dirtying(false), |
duncanFrance | 18:d849f3ada858 | 11 | _damaged(true), _damaging(false), |
duncanFrance | 18:d849f3ada858 | 12 | _handledEvents(0) |
duncanFrance | 12:63db16fea709 | 13 | { |
duncanFrance | 12:63db16fea709 | 14 | } |
duncanFrance | 12:63db16fea709 | 15 | |
duncanFrance | 12:63db16fea709 | 16 | void Widget::setParent(Widget* parent) { |
duncanFrance | 12:63db16fea709 | 17 | _parent = parent; |
duncanFrance | 12:63db16fea709 | 18 | } |
duncanFrance | 12:63db16fea709 | 19 | |
duncanFrance | 16:e9a771ecfdbe | 20 | Widget *Widget::getParent() { |
duncanFrance | 16:e9a771ecfdbe | 21 | return _parent; |
duncanFrance | 16:e9a771ecfdbe | 22 | } |
duncanFrance | 16:e9a771ecfdbe | 23 | |
duncanFrance | 13:6714534e7974 | 24 | // Location is referred to the offset |
duncanFrance | 12:63db16fea709 | 25 | void Widget::setLocation(int x, int y) |
duncanFrance | 12:63db16fea709 | 26 | { |
duncanFrance | 13:6714534e7974 | 27 | if( (_outer.x != (x+_offset.x())) || (_outer.y != y+_offset.y()) ) { |
duncanFrance | 13:6714534e7974 | 28 | _outer.x = x + _offset.x(); |
duncanFrance | 13:6714534e7974 | 29 | _outer.y = y + _offset.y(); |
duncanFrance | 12:63db16fea709 | 30 | damage(); |
duncanFrance | 12:63db16fea709 | 31 | adjust(); |
duncanFrance | 12:63db16fea709 | 32 | } |
duncanFrance | 12:63db16fea709 | 33 | } |
duncanFrance | 12:63db16fea709 | 34 | |
duncanFrance | 12:63db16fea709 | 35 | void Widget::setSize(int width, int height) |
duncanFrance | 12:63db16fea709 | 36 | { |
duncanFrance | 12:63db16fea709 | 37 | if(_outer.width != width || _outer.height != height) { |
duncanFrance | 12:63db16fea709 | 38 | _outer.width = width; |
duncanFrance | 12:63db16fea709 | 39 | _outer.height = height; |
duncanFrance | 12:63db16fea709 | 40 | damage(); |
duncanFrance | 12:63db16fea709 | 41 | adjust(); |
duncanFrance | 12:63db16fea709 | 42 | } |
duncanFrance | 12:63db16fea709 | 43 | } |
duncanFrance | 12:63db16fea709 | 44 | |
duncanFrance | 12:63db16fea709 | 45 | void Widget::setWidth(int width) { |
duncanFrance | 12:63db16fea709 | 46 | if(_outer.width != width) { |
duncanFrance | 12:63db16fea709 | 47 | _outer.width = width; |
duncanFrance | 12:63db16fea709 | 48 | damage(); |
duncanFrance | 12:63db16fea709 | 49 | adjust(); |
duncanFrance | 12:63db16fea709 | 50 | } |
duncanFrance | 12:63db16fea709 | 51 | } |
duncanFrance | 12:63db16fea709 | 52 | |
duncanFrance | 12:63db16fea709 | 53 | void Widget::setHeight(int height) { |
duncanFrance | 12:63db16fea709 | 54 | if(_outer.height != height) { |
duncanFrance | 12:63db16fea709 | 55 | _outer.height = height; |
duncanFrance | 12:63db16fea709 | 56 | damage(); |
duncanFrance | 12:63db16fea709 | 57 | adjust(); |
duncanFrance | 12:63db16fea709 | 58 | } |
duncanFrance | 12:63db16fea709 | 59 | } |
duncanFrance | 12:63db16fea709 | 60 | |
duncanFrance | 12:63db16fea709 | 61 | int Widget::x() |
duncanFrance | 12:63db16fea709 | 62 | { |
duncanFrance | 12:63db16fea709 | 63 | return _outer.x; |
duncanFrance | 12:63db16fea709 | 64 | } |
duncanFrance | 12:63db16fea709 | 65 | |
duncanFrance | 12:63db16fea709 | 66 | int Widget::y() |
duncanFrance | 12:63db16fea709 | 67 | { |
duncanFrance | 12:63db16fea709 | 68 | return _outer.y; |
duncanFrance | 12:63db16fea709 | 69 | } |
duncanFrance | 12:63db16fea709 | 70 | |
duncanFrance | 12:63db16fea709 | 71 | int Widget::height() |
duncanFrance | 12:63db16fea709 | 72 | { |
duncanFrance | 12:63db16fea709 | 73 | return _outer.height; |
duncanFrance | 12:63db16fea709 | 74 | } |
duncanFrance | 12:63db16fea709 | 75 | |
duncanFrance | 12:63db16fea709 | 76 | int Widget::width() |
duncanFrance | 12:63db16fea709 | 77 | { |
duncanFrance | 12:63db16fea709 | 78 | return _outer.width; |
duncanFrance | 12:63db16fea709 | 79 | } |
duncanFrance | 13:6714534e7974 | 80 | /** |
duncanFrance | 12:63db16fea709 | 81 | const Rectangle &Widget::outer() { |
duncanFrance | 12:63db16fea709 | 82 | return _outer; |
duncanFrance | 12:63db16fea709 | 83 | } |
duncanFrance | 12:63db16fea709 | 84 | |
duncanFrance | 12:63db16fea709 | 85 | const Rectangle &Widget::inner() { |
duncanFrance | 12:63db16fea709 | 86 | return _inner; |
duncanFrance | 12:63db16fea709 | 87 | } |
duncanFrance | 13:6714534e7974 | 88 | **/ |
duncanFrance | 13:6714534e7974 | 89 | void Widget::setOffset(int x, int y) { |
duncanFrance | 13:6714534e7974 | 90 | _outer.x = _outer.x - _offset.x() + x; |
duncanFrance | 13:6714534e7974 | 91 | _outer.y = _outer.y - _offset.y() + y; |
duncanFrance | 13:6714534e7974 | 92 | _offset.x(x); |
duncanFrance | 13:6714534e7974 | 93 | _offset.y(y); |
duncanFrance | 13:6714534e7974 | 94 | damage(); |
duncanFrance | 13:6714534e7974 | 95 | adjust(); |
duncanFrance | 13:6714534e7974 | 96 | } |
duncanFrance | 13:6714534e7974 | 97 | |
duncanFrance | 13:6714534e7974 | 98 | int Widget::offsetX() { |
duncanFrance | 13:6714534e7974 | 99 | return _offset.x(); |
duncanFrance | 13:6714534e7974 | 100 | } |
duncanFrance | 13:6714534e7974 | 101 | |
duncanFrance | 13:6714534e7974 | 102 | int Widget::offsetY() { |
duncanFrance | 13:6714534e7974 | 103 | return _offset.y(); |
duncanFrance | 13:6714534e7974 | 104 | } |
duncanFrance | 13:6714534e7974 | 105 | |
duncanFrance | 12:63db16fea709 | 106 | |
duncanFrance | 12:63db16fea709 | 107 | void Widget::setForeground(uint16_t color) |
duncanFrance | 12:63db16fea709 | 108 | { |
duncanFrance | 12:63db16fea709 | 109 | if(_fg != color) { |
duncanFrance | 12:63db16fea709 | 110 | _fg = color; |
duncanFrance | 12:63db16fea709 | 111 | dirty(); |
duncanFrance | 12:63db16fea709 | 112 | } |
duncanFrance | 12:63db16fea709 | 113 | } |
duncanFrance | 12:63db16fea709 | 114 | |
duncanFrance | 12:63db16fea709 | 115 | void Widget::setBackground(uint16_t color) |
duncanFrance | 12:63db16fea709 | 116 | { |
duncanFrance | 12:63db16fea709 | 117 | if(_bg != color) { |
duncanFrance | 12:63db16fea709 | 118 | _bg = color; |
duncanFrance | 12:63db16fea709 | 119 | dirty(); |
duncanFrance | 12:63db16fea709 | 120 | } |
duncanFrance | 12:63db16fea709 | 121 | } |
duncanFrance | 12:63db16fea709 | 122 | |
duncanFrance | 12:63db16fea709 | 123 | |
duncanFrance | 12:63db16fea709 | 124 | /** |
duncanFrance | 12:63db16fea709 | 125 | * Set the amount of padding between the border and a widget edge |
duncanFrance | 12:63db16fea709 | 126 | **/ |
duncanFrance | 12:63db16fea709 | 127 | void Widget::setPadding(int pixels) |
duncanFrance | 12:63db16fea709 | 128 | { |
duncanFrance | 12:63db16fea709 | 129 | if(_padding != pixels) { |
duncanFrance | 12:63db16fea709 | 130 | _padding = pixels; |
duncanFrance | 12:63db16fea709 | 131 | dirty(); |
duncanFrance | 12:63db16fea709 | 132 | } |
duncanFrance | 12:63db16fea709 | 133 | } |
duncanFrance | 12:63db16fea709 | 134 | |
duncanFrance | 12:63db16fea709 | 135 | void Widget::setBorder(int width, uint16_t colour) |
duncanFrance | 12:63db16fea709 | 136 | { |
duncanFrance | 12:63db16fea709 | 137 | if(_borderWidth != width || _borderColour != colour) { |
duncanFrance | 12:63db16fea709 | 138 | _borderColour = colour; |
duncanFrance | 12:63db16fea709 | 139 | _borderWidth = width; |
duncanFrance | 12:63db16fea709 | 140 | dirty(); |
duncanFrance | 12:63db16fea709 | 141 | } |
duncanFrance | 12:63db16fea709 | 142 | } |
duncanFrance | 12:63db16fea709 | 143 | |
duncanFrance | 12:63db16fea709 | 144 | void Widget::draw() |
duncanFrance | 12:63db16fea709 | 145 | { |
duncanFrance | 12:63db16fea709 | 146 | if(!_hidden && (_dirtied | _damaged)) { |
duncanFrance | 12:63db16fea709 | 147 | _draw(); |
duncanFrance | 12:63db16fea709 | 148 | _dirtied = false; |
duncanFrance | 12:63db16fea709 | 149 | _damaged = false; |
duncanFrance | 12:63db16fea709 | 150 | } |
duncanFrance | 12:63db16fea709 | 151 | } |
duncanFrance | 12:63db16fea709 | 152 | |
duncanFrance | 12:63db16fea709 | 153 | void Widget::clear() |
duncanFrance | 12:63db16fea709 | 154 | { |
duncanFrance | 12:63db16fea709 | 155 | if(!_hidden) _clear(); |
duncanFrance | 12:63db16fea709 | 156 | } |
duncanFrance | 12:63db16fea709 | 157 | |
duncanFrance | 12:63db16fea709 | 158 | void Widget::show() |
duncanFrance | 12:63db16fea709 | 159 | { |
duncanFrance | 12:63db16fea709 | 160 | _hidden = false; |
duncanFrance | 17:5184762fda6c | 161 | dirty(); |
duncanFrance | 17:5184762fda6c | 162 | damage(); |
duncanFrance | 12:63db16fea709 | 163 | } |
duncanFrance | 12:63db16fea709 | 164 | |
duncanFrance | 12:63db16fea709 | 165 | void Widget::hide() |
duncanFrance | 12:63db16fea709 | 166 | { |
duncanFrance | 15:e69fd74d42e4 | 167 | _clear(); |
duncanFrance | 12:63db16fea709 | 168 | _hidden = true; |
duncanFrance | 12:63db16fea709 | 169 | } |
duncanFrance | 12:63db16fea709 | 170 | |
duncanFrance | 12:63db16fea709 | 171 | bool Widget::isHidden() |
duncanFrance | 12:63db16fea709 | 172 | { |
duncanFrance | 12:63db16fea709 | 173 | return _hidden; |
duncanFrance | 12:63db16fea709 | 174 | } |
duncanFrance | 12:63db16fea709 | 175 | |
duncanFrance | 12:63db16fea709 | 176 | void Widget::setEventHandler(EventHandler* handler) |
duncanFrance | 12:63db16fea709 | 177 | { |
duncanFrance | 18:d849f3ada858 | 178 | _handlers.appendOnce(handler); |
duncanFrance | 18:d849f3ada858 | 179 | _reenumerateEvents(); |
duncanFrance | 12:63db16fea709 | 180 | } |
duncanFrance | 12:63db16fea709 | 181 | |
duncanFrance | 12:63db16fea709 | 182 | void Widget::unsetEventHandler(EventHandler *handler) |
duncanFrance | 12:63db16fea709 | 183 | { |
duncanFrance | 18:d849f3ada858 | 184 | _handlers.remove(handler); |
duncanFrance | 18:d849f3ada858 | 185 | _reenumerateEvents(); |
duncanFrance | 18:d849f3ada858 | 186 | } |
duncanFrance | 18:d849f3ada858 | 187 | |
duncanFrance | 18:d849f3ada858 | 188 | bool Widget::_isEventTarget(Event e) |
duncanFrance | 18:d849f3ada858 | 189 | { |
duncanFrance | 18:d849f3ada858 | 190 | return !_hidden |
duncanFrance | 18:d849f3ada858 | 191 | && e.screenX >= _outer.x |
duncanFrance | 18:d849f3ada858 | 192 | && e.screenX <= (_outer.x+_outer.width) |
duncanFrance | 18:d849f3ada858 | 193 | && e.screenY >= _outer.y |
duncanFrance | 18:d849f3ada858 | 194 | && e.screenY <= (_outer.y+_outer.height); |
duncanFrance | 12:63db16fea709 | 195 | } |
duncanFrance | 12:63db16fea709 | 196 | |
duncanFrance | 18:d849f3ada858 | 197 | void Widget::handleEvent(Event e) { |
duncanFrance | 18:d849f3ada858 | 198 | e.target = this; |
duncanFrance | 18:d849f3ada858 | 199 | if(_isEventTarget(e)) { |
duncanFrance | 18:d849f3ada858 | 200 | _handlers.reset(); |
duncanFrance | 18:d849f3ada858 | 201 | EventHandler *h; |
duncanFrance | 18:d849f3ada858 | 202 | while((h = _handlers.next()) != NULL) { |
duncanFrance | 18:d849f3ada858 | 203 | if(h->type == e.type) { |
duncanFrance | 18:d849f3ada858 | 204 | h->handle(e); |
duncanFrance | 18:d849f3ada858 | 205 | } |
duncanFrance | 18:d849f3ada858 | 206 | } |
duncanFrance | 18:d849f3ada858 | 207 | } |
duncanFrance | 18:d849f3ada858 | 208 | } |
duncanFrance | 18:d849f3ada858 | 209 | |
duncanFrance | 18:d849f3ada858 | 210 | void Widget::_reenumerateEvents() { |
duncanFrance | 18:d849f3ada858 | 211 | _reenumerateHandledEvents(); |
duncanFrance | 18:d849f3ada858 | 212 | if(_parent != NULL) { |
duncanFrance | 18:d849f3ada858 | 213 | _parent->_reenumerateEvents(); |
duncanFrance | 18:d849f3ada858 | 214 | } |
duncanFrance | 18:d849f3ada858 | 215 | } |
duncanFrance | 18:d849f3ada858 | 216 | |
duncanFrance | 18:d849f3ada858 | 217 | void Widget::_reenumerateHandledEvents() { |
duncanFrance | 18:d849f3ada858 | 218 | _handledEvents = 0; |
duncanFrance | 18:d849f3ada858 | 219 | EventHandler *h; |
duncanFrance | 18:d849f3ada858 | 220 | LinkedListIterator<EventHandler> eit = _handlers.getIterator(); |
duncanFrance | 18:d849f3ada858 | 221 | while((h = eit.next()) != NULL) { |
duncanFrance | 18:d849f3ada858 | 222 | _handledEvents |= h->type; |
duncanFrance | 18:d849f3ada858 | 223 | } |
duncanFrance | 18:d849f3ada858 | 224 | } |
duncanFrance | 18:d849f3ada858 | 225 | |
duncanFrance | 18:d849f3ada858 | 226 | uint16_t Widget::_getHandledEvents() { |
duncanFrance | 18:d849f3ada858 | 227 | return _handledEvents; |
duncanFrance | 18:d849f3ada858 | 228 | } |
duncanFrance | 18:d849f3ada858 | 229 | |
duncanFrance | 12:63db16fea709 | 230 | bool Widget::intersects(Widget *w) |
duncanFrance | 12:63db16fea709 | 231 | { |
duncanFrance | 13:6714534e7974 | 232 | return _outer.intersects(w->_outer); |
duncanFrance | 12:63db16fea709 | 233 | } |
duncanFrance | 12:63db16fea709 | 234 | |
duncanFrance | 12:63db16fea709 | 235 | void Widget::dirty() |
duncanFrance | 12:63db16fea709 | 236 | { |
duncanFrance | 12:63db16fea709 | 237 | if(!_dirtying) { |
duncanFrance | 12:63db16fea709 | 238 | _dirtying = true; |
duncanFrance | 12:63db16fea709 | 239 | _dirty(); |
duncanFrance | 12:63db16fea709 | 240 | _dirtying = false; |
duncanFrance | 12:63db16fea709 | 241 | } |
duncanFrance | 12:63db16fea709 | 242 | } |
duncanFrance | 12:63db16fea709 | 243 | |
duncanFrance | 12:63db16fea709 | 244 | bool Widget::isDirty() { |
duncanFrance | 12:63db16fea709 | 245 | return _dirtied; |
duncanFrance | 12:63db16fea709 | 246 | } |
duncanFrance | 12:63db16fea709 | 247 | |
duncanFrance | 12:63db16fea709 | 248 | void Widget::dirtyAll() |
duncanFrance | 12:63db16fea709 | 249 | { |
duncanFrance | 12:63db16fea709 | 250 | _dirtied = true; |
duncanFrance | 12:63db16fea709 | 251 | } |
duncanFrance | 12:63db16fea709 | 252 | |
duncanFrance | 12:63db16fea709 | 253 | void Widget::damage() { |
duncanFrance | 12:63db16fea709 | 254 | if(!_damaging) { |
duncanFrance | 12:63db16fea709 | 255 | _damaging = true; |
duncanFrance | 12:63db16fea709 | 256 | _damage(); |
duncanFrance | 12:63db16fea709 | 257 | _damaging = false; |
duncanFrance | 12:63db16fea709 | 258 | } |
duncanFrance | 12:63db16fea709 | 259 | } |
duncanFrance | 12:63db16fea709 | 260 | |
duncanFrance | 12:63db16fea709 | 261 | bool Widget::isDamaged() { |
duncanFrance | 12:63db16fea709 | 262 | return _damaged; |
duncanFrance | 12:63db16fea709 | 263 | } |
duncanFrance | 12:63db16fea709 | 264 | |
duncanFrance | 12:63db16fea709 | 265 | void Widget::adjust() |
duncanFrance | 12:63db16fea709 | 266 | { |
duncanFrance | 12:63db16fea709 | 267 | if(!_adjusting) { |
duncanFrance | 12:63db16fea709 | 268 | _adjusting = true; |
duncanFrance | 12:63db16fea709 | 269 | _adjust(); |
duncanFrance | 12:63db16fea709 | 270 | _adjusting = false; |
duncanFrance | 12:63db16fea709 | 271 | } |
duncanFrance | 12:63db16fea709 | 272 | } |
duncanFrance | 12:63db16fea709 | 273 | |
duncanFrance | 12:63db16fea709 | 274 | GraphicsDisplay* Widget::display() |
duncanFrance | 12:63db16fea709 | 275 | { |
duncanFrance | 12:63db16fea709 | 276 | return _context->display(); |
duncanFrance | 12:63db16fea709 | 277 | } |
duncanFrance | 12:63db16fea709 | 278 | |
duncanFrance | 12:63db16fea709 | 279 | /********************************************************** |
duncanFrance | 12:63db16fea709 | 280 | * Protected methods |
duncanFrance | 12:63db16fea709 | 281 | **********************************************************/ |
duncanFrance | 12:63db16fea709 | 282 | void Widget::_draw() { |
duncanFrance | 12:63db16fea709 | 283 | GraphicsDisplay *d = display(); |
duncanFrance | 18:d849f3ada858 | 284 | //_clear(); |
duncanFrance | 12:63db16fea709 | 285 | // Draw the border |
duncanFrance | 12:63db16fea709 | 286 | // Top |
duncanFrance | 12:63db16fea709 | 287 | d->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_borderWidth, _borderColour); |
duncanFrance | 12:63db16fea709 | 288 | // Bottom |
duncanFrance | 12:63db16fea709 | 289 | d->fillrect(_outer.x, _outer.y + _outer.height - _borderWidth, _outer.x + _outer.width, _outer.y+_outer.height, _borderColour); |
duncanFrance | 12:63db16fea709 | 290 | // Left |
duncanFrance | 12:63db16fea709 | 291 | d->fillrect(_outer.x, _outer.y, _outer.x+_borderWidth, _outer.y+_outer.height, _borderColour); |
duncanFrance | 12:63db16fea709 | 292 | // Right |
duncanFrance | 12:63db16fea709 | 293 | d->fillrect(_outer.x+_outer.width-_borderWidth, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, _borderColour); |
duncanFrance | 12:63db16fea709 | 294 | } |
duncanFrance | 12:63db16fea709 | 295 | |
duncanFrance | 12:63db16fea709 | 296 | void Widget::_clear() { |
duncanFrance | 12:63db16fea709 | 297 | display()->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, display()->getBackground()); |
duncanFrance | 12:63db16fea709 | 298 | } |
duncanFrance | 12:63db16fea709 | 299 | |
duncanFrance | 12:63db16fea709 | 300 | void Widget::_dirty() |
duncanFrance | 12:63db16fea709 | 301 | { |
duncanFrance | 12:63db16fea709 | 302 | _dirtied = true; |
duncanFrance | 12:63db16fea709 | 303 | if(_parent != NULL) { |
duncanFrance | 12:63db16fea709 | 304 | _parent->dirty(); |
duncanFrance | 12:63db16fea709 | 305 | } |
duncanFrance | 12:63db16fea709 | 306 | } |
duncanFrance | 12:63db16fea709 | 307 | |
duncanFrance | 12:63db16fea709 | 308 | void Widget::_damage() |
duncanFrance | 12:63db16fea709 | 309 | { |
duncanFrance | 12:63db16fea709 | 310 | _damaged = true; |
duncanFrance | 12:63db16fea709 | 311 | if(_parent != NULL) { |
duncanFrance | 12:63db16fea709 | 312 | _parent->dirty(); |
duncanFrance | 12:63db16fea709 | 313 | } |
duncanFrance | 12:63db16fea709 | 314 | } |
duncanFrance | 12:63db16fea709 | 315 | |
duncanFrance | 12:63db16fea709 | 316 | void Widget::_adjust() { |
duncanFrance | 12:63db16fea709 | 317 | // Recalculate size of inner Rect |
duncanFrance | 12:63db16fea709 | 318 | _inner.resize(_outer, _borderWidth + _padding); |
duncanFrance | 12:63db16fea709 | 319 | } |