Foundation classes for a basic GUI implementing simple widgets and events

Dependents:   TouchScreenGUIDemo

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?

UserRevisionLine numberNew 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 }