Foundation classes for a basic GUI implementing simple widgets and events

Dependents:   TouchScreenGUIDemo

Committer:
duncanFrance
Date:
Sun May 22 14:40:29 2016 +0000
Revision:
16:e9a771ecfdbe
Parent:
15:e69fd74d42e4
Child:
17:5184762fda6c
Added vertical alignment control to TextWidget; pumpEvents no longer blocks

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 12:63db16fea709 11 _damaged(true), _damaging(false)
duncanFrance 12:63db16fea709 12 {
duncanFrance 12:63db16fea709 13 }
duncanFrance 12:63db16fea709 14
duncanFrance 12:63db16fea709 15 void Widget::setParent(Widget* parent) {
duncanFrance 12:63db16fea709 16 _parent = parent;
duncanFrance 15:e69fd74d42e4 17 if(_parent != NULL && _handlers.size() != 0) {
duncanFrance 15:e69fd74d42e4 18 _context->eventDispatcher()->attachListener(this);
duncanFrance 15:e69fd74d42e4 19 } else if(_parent == NULL && _handlers.size() == 0) {
duncanFrance 15:e69fd74d42e4 20 _context->eventDispatcher()->detachListener(this);
duncanFrance 15:e69fd74d42e4 21 }
duncanFrance 12:63db16fea709 22 }
duncanFrance 12:63db16fea709 23
duncanFrance 16:e9a771ecfdbe 24 Widget *Widget::getParent() {
duncanFrance 16:e9a771ecfdbe 25 return _parent;
duncanFrance 16:e9a771ecfdbe 26 }
duncanFrance 16:e9a771ecfdbe 27
duncanFrance 12:63db16fea709 28 bool Widget::isEventTarget(Event e)
duncanFrance 12:63db16fea709 29 {
duncanFrance 12:63db16fea709 30 return !_hidden
duncanFrance 12:63db16fea709 31 && e.screenX >= _outer.x
duncanFrance 12:63db16fea709 32 && e.screenX <= (_outer.x+_outer.width)
duncanFrance 12:63db16fea709 33 && e.screenY >= _outer.y
duncanFrance 12:63db16fea709 34 && e.screenY <= (_outer.y+_outer.height);
duncanFrance 12:63db16fea709 35 }
duncanFrance 13:6714534e7974 36 // Location is referred to the offset
duncanFrance 12:63db16fea709 37 void Widget::setLocation(int x, int y)
duncanFrance 12:63db16fea709 38 {
duncanFrance 13:6714534e7974 39 if( (_outer.x != (x+_offset.x())) || (_outer.y != y+_offset.y()) ) {
duncanFrance 13:6714534e7974 40 _outer.x = x + _offset.x();
duncanFrance 13:6714534e7974 41 _outer.y = y + _offset.y();
duncanFrance 12:63db16fea709 42 damage();
duncanFrance 12:63db16fea709 43 adjust();
duncanFrance 12:63db16fea709 44 }
duncanFrance 12:63db16fea709 45 }
duncanFrance 12:63db16fea709 46
duncanFrance 12:63db16fea709 47 void Widget::setSize(int width, int height)
duncanFrance 12:63db16fea709 48 {
duncanFrance 12:63db16fea709 49 if(_outer.width != width || _outer.height != height) {
duncanFrance 12:63db16fea709 50 _outer.width = width;
duncanFrance 12:63db16fea709 51 _outer.height = height;
duncanFrance 12:63db16fea709 52 damage();
duncanFrance 12:63db16fea709 53 adjust();
duncanFrance 12:63db16fea709 54 }
duncanFrance 12:63db16fea709 55 }
duncanFrance 12:63db16fea709 56
duncanFrance 12:63db16fea709 57 void Widget::setWidth(int width) {
duncanFrance 12:63db16fea709 58 if(_outer.width != width) {
duncanFrance 12:63db16fea709 59 _outer.width = width;
duncanFrance 12:63db16fea709 60 damage();
duncanFrance 12:63db16fea709 61 adjust();
duncanFrance 12:63db16fea709 62 }
duncanFrance 12:63db16fea709 63 }
duncanFrance 12:63db16fea709 64
duncanFrance 12:63db16fea709 65 void Widget::setHeight(int height) {
duncanFrance 12:63db16fea709 66 if(_outer.height != height) {
duncanFrance 12:63db16fea709 67 _outer.height = height;
duncanFrance 12:63db16fea709 68 damage();
duncanFrance 12:63db16fea709 69 adjust();
duncanFrance 12:63db16fea709 70 }
duncanFrance 12:63db16fea709 71 }
duncanFrance 12:63db16fea709 72
duncanFrance 12:63db16fea709 73 int Widget::x()
duncanFrance 12:63db16fea709 74 {
duncanFrance 12:63db16fea709 75 return _outer.x;
duncanFrance 12:63db16fea709 76 }
duncanFrance 12:63db16fea709 77
duncanFrance 12:63db16fea709 78 int Widget::y()
duncanFrance 12:63db16fea709 79 {
duncanFrance 12:63db16fea709 80 return _outer.y;
duncanFrance 12:63db16fea709 81 }
duncanFrance 12:63db16fea709 82
duncanFrance 12:63db16fea709 83 int Widget::height()
duncanFrance 12:63db16fea709 84 {
duncanFrance 12:63db16fea709 85 return _outer.height;
duncanFrance 12:63db16fea709 86 }
duncanFrance 12:63db16fea709 87
duncanFrance 12:63db16fea709 88 int Widget::width()
duncanFrance 12:63db16fea709 89 {
duncanFrance 12:63db16fea709 90 return _outer.width;
duncanFrance 12:63db16fea709 91 }
duncanFrance 13:6714534e7974 92 /**
duncanFrance 12:63db16fea709 93 const Rectangle &Widget::outer() {
duncanFrance 12:63db16fea709 94 return _outer;
duncanFrance 12:63db16fea709 95 }
duncanFrance 12:63db16fea709 96
duncanFrance 12:63db16fea709 97 const Rectangle &Widget::inner() {
duncanFrance 12:63db16fea709 98 return _inner;
duncanFrance 12:63db16fea709 99 }
duncanFrance 13:6714534e7974 100 **/
duncanFrance 13:6714534e7974 101 void Widget::setOffset(int x, int y) {
duncanFrance 13:6714534e7974 102 _outer.x = _outer.x - _offset.x() + x;
duncanFrance 13:6714534e7974 103 _outer.y = _outer.y - _offset.y() + y;
duncanFrance 13:6714534e7974 104 _offset.x(x);
duncanFrance 13:6714534e7974 105 _offset.y(y);
duncanFrance 13:6714534e7974 106 damage();
duncanFrance 13:6714534e7974 107 adjust();
duncanFrance 13:6714534e7974 108 }
duncanFrance 13:6714534e7974 109
duncanFrance 13:6714534e7974 110 int Widget::offsetX() {
duncanFrance 13:6714534e7974 111 return _offset.x();
duncanFrance 13:6714534e7974 112 }
duncanFrance 13:6714534e7974 113
duncanFrance 13:6714534e7974 114 int Widget::offsetY() {
duncanFrance 13:6714534e7974 115 return _offset.y();
duncanFrance 13:6714534e7974 116 }
duncanFrance 13:6714534e7974 117
duncanFrance 12:63db16fea709 118
duncanFrance 12:63db16fea709 119 void Widget::setForeground(uint16_t color)
duncanFrance 12:63db16fea709 120 {
duncanFrance 12:63db16fea709 121 if(_fg != color) {
duncanFrance 12:63db16fea709 122 _fg = color;
duncanFrance 12:63db16fea709 123 dirty();
duncanFrance 12:63db16fea709 124 }
duncanFrance 12:63db16fea709 125 }
duncanFrance 12:63db16fea709 126
duncanFrance 12:63db16fea709 127 void Widget::setBackground(uint16_t color)
duncanFrance 12:63db16fea709 128 {
duncanFrance 12:63db16fea709 129 if(_bg != color) {
duncanFrance 12:63db16fea709 130 _bg = color;
duncanFrance 12:63db16fea709 131 dirty();
duncanFrance 12:63db16fea709 132 }
duncanFrance 12:63db16fea709 133 }
duncanFrance 12:63db16fea709 134
duncanFrance 12:63db16fea709 135
duncanFrance 12:63db16fea709 136 /**
duncanFrance 12:63db16fea709 137 * Set the amount of padding between the border and a widget edge
duncanFrance 12:63db16fea709 138 **/
duncanFrance 12:63db16fea709 139 void Widget::setPadding(int pixels)
duncanFrance 12:63db16fea709 140 {
duncanFrance 12:63db16fea709 141 if(_padding != pixels) {
duncanFrance 12:63db16fea709 142 _padding = pixels;
duncanFrance 12:63db16fea709 143 dirty();
duncanFrance 12:63db16fea709 144 }
duncanFrance 12:63db16fea709 145 }
duncanFrance 12:63db16fea709 146
duncanFrance 12:63db16fea709 147 void Widget::setBorder(int width, uint16_t colour)
duncanFrance 12:63db16fea709 148 {
duncanFrance 12:63db16fea709 149 if(_borderWidth != width || _borderColour != colour) {
duncanFrance 12:63db16fea709 150 _borderColour = colour;
duncanFrance 12:63db16fea709 151 _borderWidth = width;
duncanFrance 12:63db16fea709 152 dirty();
duncanFrance 12:63db16fea709 153 }
duncanFrance 12:63db16fea709 154 }
duncanFrance 12:63db16fea709 155
duncanFrance 12:63db16fea709 156 void Widget::draw()
duncanFrance 12:63db16fea709 157 {
duncanFrance 12:63db16fea709 158 if(!_hidden && (_dirtied | _damaged)) {
duncanFrance 12:63db16fea709 159 _draw();
duncanFrance 12:63db16fea709 160 _dirtied = false;
duncanFrance 12:63db16fea709 161 _damaged = false;
duncanFrance 12:63db16fea709 162 }
duncanFrance 12:63db16fea709 163 }
duncanFrance 12:63db16fea709 164
duncanFrance 12:63db16fea709 165 void Widget::clear()
duncanFrance 12:63db16fea709 166 {
duncanFrance 12:63db16fea709 167 if(!_hidden) _clear();
duncanFrance 12:63db16fea709 168 }
duncanFrance 12:63db16fea709 169
duncanFrance 12:63db16fea709 170 void Widget::show()
duncanFrance 12:63db16fea709 171 {
duncanFrance 12:63db16fea709 172 _hidden = false;
duncanFrance 12:63db16fea709 173 draw();
duncanFrance 12:63db16fea709 174 }
duncanFrance 12:63db16fea709 175
duncanFrance 12:63db16fea709 176 void Widget::hide()
duncanFrance 12:63db16fea709 177 {
duncanFrance 15:e69fd74d42e4 178 _clear();
duncanFrance 12:63db16fea709 179 _hidden = true;
duncanFrance 12:63db16fea709 180 }
duncanFrance 12:63db16fea709 181
duncanFrance 12:63db16fea709 182 bool Widget::isHidden()
duncanFrance 12:63db16fea709 183 {
duncanFrance 12:63db16fea709 184 return _hidden;
duncanFrance 12:63db16fea709 185 }
duncanFrance 12:63db16fea709 186
duncanFrance 12:63db16fea709 187 void Widget::setEventHandler(EventHandler* handler)
duncanFrance 12:63db16fea709 188 {
duncanFrance 12:63db16fea709 189 EventListener::setEventHandler(handler);
duncanFrance 12:63db16fea709 190 _context->eventDispatcher()->attachListener(this);
duncanFrance 12:63db16fea709 191 }
duncanFrance 12:63db16fea709 192
duncanFrance 12:63db16fea709 193 void Widget::unsetEventHandler(EventHandler *handler)
duncanFrance 12:63db16fea709 194 {
duncanFrance 12:63db16fea709 195 EventListener::unsetEventHandler(handler);
duncanFrance 15:e69fd74d42e4 196 if(_handlers.size() == 0) {
duncanFrance 15:e69fd74d42e4 197 _context->eventDispatcher()->detachListener(this);
duncanFrance 15:e69fd74d42e4 198 }
duncanFrance 12:63db16fea709 199 }
duncanFrance 12:63db16fea709 200
duncanFrance 12:63db16fea709 201 bool Widget::intersects(Widget *w)
duncanFrance 12:63db16fea709 202 {
duncanFrance 13:6714534e7974 203 return _outer.intersects(w->_outer);
duncanFrance 12:63db16fea709 204 }
duncanFrance 12:63db16fea709 205
duncanFrance 12:63db16fea709 206 void Widget::dirty()
duncanFrance 12:63db16fea709 207 {
duncanFrance 12:63db16fea709 208 if(!_dirtying) {
duncanFrance 12:63db16fea709 209 _dirtying = true;
duncanFrance 12:63db16fea709 210 _dirty();
duncanFrance 12:63db16fea709 211 _dirtying = false;
duncanFrance 12:63db16fea709 212 }
duncanFrance 12:63db16fea709 213 }
duncanFrance 12:63db16fea709 214
duncanFrance 12:63db16fea709 215 bool Widget::isDirty() {
duncanFrance 12:63db16fea709 216 return _dirtied;
duncanFrance 12:63db16fea709 217 }
duncanFrance 12:63db16fea709 218
duncanFrance 12:63db16fea709 219 void Widget::dirtyAll()
duncanFrance 12:63db16fea709 220 {
duncanFrance 12:63db16fea709 221 _dirtied = true;
duncanFrance 12:63db16fea709 222 }
duncanFrance 12:63db16fea709 223
duncanFrance 12:63db16fea709 224 void Widget::damage() {
duncanFrance 12:63db16fea709 225 if(!_damaging) {
duncanFrance 12:63db16fea709 226 _damaging = true;
duncanFrance 12:63db16fea709 227 _damage();
duncanFrance 12:63db16fea709 228 _damaging = false;
duncanFrance 12:63db16fea709 229 }
duncanFrance 12:63db16fea709 230 }
duncanFrance 12:63db16fea709 231
duncanFrance 12:63db16fea709 232 bool Widget::isDamaged() {
duncanFrance 12:63db16fea709 233 return _damaged;
duncanFrance 12:63db16fea709 234 }
duncanFrance 12:63db16fea709 235
duncanFrance 12:63db16fea709 236 void Widget::adjust()
duncanFrance 12:63db16fea709 237 {
duncanFrance 12:63db16fea709 238 if(!_adjusting) {
duncanFrance 12:63db16fea709 239 _adjusting = true;
duncanFrance 12:63db16fea709 240 _adjust();
duncanFrance 12:63db16fea709 241 _adjusting = false;
duncanFrance 12:63db16fea709 242 }
duncanFrance 12:63db16fea709 243 }
duncanFrance 12:63db16fea709 244
duncanFrance 12:63db16fea709 245 GraphicsDisplay* Widget::display()
duncanFrance 12:63db16fea709 246 {
duncanFrance 12:63db16fea709 247 return _context->display();
duncanFrance 12:63db16fea709 248 }
duncanFrance 12:63db16fea709 249
duncanFrance 12:63db16fea709 250 /**********************************************************
duncanFrance 12:63db16fea709 251 * Protected methods
duncanFrance 12:63db16fea709 252 **********************************************************/
duncanFrance 12:63db16fea709 253 void Widget::_draw() {
duncanFrance 12:63db16fea709 254 GraphicsDisplay *d = display();
duncanFrance 12:63db16fea709 255 // Draw the border
duncanFrance 12:63db16fea709 256 // Top
duncanFrance 12:63db16fea709 257 d->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_borderWidth, _borderColour);
duncanFrance 12:63db16fea709 258 // Bottom
duncanFrance 12:63db16fea709 259 d->fillrect(_outer.x, _outer.y + _outer.height - _borderWidth, _outer.x + _outer.width, _outer.y+_outer.height, _borderColour);
duncanFrance 12:63db16fea709 260 // Left
duncanFrance 12:63db16fea709 261 d->fillrect(_outer.x, _outer.y, _outer.x+_borderWidth, _outer.y+_outer.height, _borderColour);
duncanFrance 12:63db16fea709 262 // Right
duncanFrance 12:63db16fea709 263 d->fillrect(_outer.x+_outer.width-_borderWidth, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, _borderColour);
duncanFrance 12:63db16fea709 264 }
duncanFrance 12:63db16fea709 265
duncanFrance 12:63db16fea709 266 void Widget::_clear() {
duncanFrance 12:63db16fea709 267 display()->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, display()->getBackground());
duncanFrance 12:63db16fea709 268 }
duncanFrance 12:63db16fea709 269
duncanFrance 12:63db16fea709 270 void Widget::_dirty()
duncanFrance 12:63db16fea709 271 {
duncanFrance 12:63db16fea709 272 _dirtied = true;
duncanFrance 12:63db16fea709 273 if(_parent != NULL) {
duncanFrance 12:63db16fea709 274 _parent->dirty();
duncanFrance 12:63db16fea709 275 }
duncanFrance 12:63db16fea709 276 }
duncanFrance 12:63db16fea709 277
duncanFrance 12:63db16fea709 278 void Widget::_damage()
duncanFrance 12:63db16fea709 279 {
duncanFrance 12:63db16fea709 280 _damaged = true;
duncanFrance 12:63db16fea709 281 if(_parent != NULL) {
duncanFrance 12:63db16fea709 282 _parent->dirty();
duncanFrance 12:63db16fea709 283 }
duncanFrance 12:63db16fea709 284 }
duncanFrance 12:63db16fea709 285
duncanFrance 12:63db16fea709 286 void Widget::_adjust() {
duncanFrance 12:63db16fea709 287 // Recalculate size of inner Rect
duncanFrance 12:63db16fea709 288 _inner.resize(_outer, _borderWidth + _padding);
duncanFrance 12:63db16fea709 289 }