Foundation classes for a basic GUI implementing simple widgets and events

Dependents:   TouchScreenGUIDemo

Committer:
duncanFrance
Date:
Sun May 22 16:35:23 2016 +0000
Revision:
17:5184762fda6c
Parent:
16:e9a771ecfdbe
Child:
18:d849f3ada858
Improved Window attach/detach handling; Improved TextWidget MIDDLE layout for multi-line

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 17:5184762fda6c 173 dirty();
duncanFrance 17:5184762fda6c 174 damage();
duncanFrance 12:63db16fea709 175 }
duncanFrance 12:63db16fea709 176
duncanFrance 12:63db16fea709 177 void Widget::hide()
duncanFrance 12:63db16fea709 178 {
duncanFrance 15:e69fd74d42e4 179 _clear();
duncanFrance 12:63db16fea709 180 _hidden = true;
duncanFrance 12:63db16fea709 181 }
duncanFrance 12:63db16fea709 182
duncanFrance 12:63db16fea709 183 bool Widget::isHidden()
duncanFrance 12:63db16fea709 184 {
duncanFrance 12:63db16fea709 185 return _hidden;
duncanFrance 12:63db16fea709 186 }
duncanFrance 12:63db16fea709 187
duncanFrance 12:63db16fea709 188 void Widget::setEventHandler(EventHandler* handler)
duncanFrance 12:63db16fea709 189 {
duncanFrance 12:63db16fea709 190 EventListener::setEventHandler(handler);
duncanFrance 12:63db16fea709 191 _context->eventDispatcher()->attachListener(this);
duncanFrance 12:63db16fea709 192 }
duncanFrance 12:63db16fea709 193
duncanFrance 12:63db16fea709 194 void Widget::unsetEventHandler(EventHandler *handler)
duncanFrance 12:63db16fea709 195 {
duncanFrance 12:63db16fea709 196 EventListener::unsetEventHandler(handler);
duncanFrance 15:e69fd74d42e4 197 if(_handlers.size() == 0) {
duncanFrance 15:e69fd74d42e4 198 _context->eventDispatcher()->detachListener(this);
duncanFrance 15:e69fd74d42e4 199 }
duncanFrance 12:63db16fea709 200 }
duncanFrance 12:63db16fea709 201
duncanFrance 12:63db16fea709 202 bool Widget::intersects(Widget *w)
duncanFrance 12:63db16fea709 203 {
duncanFrance 13:6714534e7974 204 return _outer.intersects(w->_outer);
duncanFrance 12:63db16fea709 205 }
duncanFrance 12:63db16fea709 206
duncanFrance 12:63db16fea709 207 void Widget::dirty()
duncanFrance 12:63db16fea709 208 {
duncanFrance 12:63db16fea709 209 if(!_dirtying) {
duncanFrance 12:63db16fea709 210 _dirtying = true;
duncanFrance 12:63db16fea709 211 _dirty();
duncanFrance 12:63db16fea709 212 _dirtying = false;
duncanFrance 12:63db16fea709 213 }
duncanFrance 12:63db16fea709 214 }
duncanFrance 12:63db16fea709 215
duncanFrance 12:63db16fea709 216 bool Widget::isDirty() {
duncanFrance 12:63db16fea709 217 return _dirtied;
duncanFrance 12:63db16fea709 218 }
duncanFrance 12:63db16fea709 219
duncanFrance 12:63db16fea709 220 void Widget::dirtyAll()
duncanFrance 12:63db16fea709 221 {
duncanFrance 12:63db16fea709 222 _dirtied = true;
duncanFrance 12:63db16fea709 223 }
duncanFrance 12:63db16fea709 224
duncanFrance 12:63db16fea709 225 void Widget::damage() {
duncanFrance 12:63db16fea709 226 if(!_damaging) {
duncanFrance 12:63db16fea709 227 _damaging = true;
duncanFrance 12:63db16fea709 228 _damage();
duncanFrance 12:63db16fea709 229 _damaging = false;
duncanFrance 12:63db16fea709 230 }
duncanFrance 12:63db16fea709 231 }
duncanFrance 12:63db16fea709 232
duncanFrance 12:63db16fea709 233 bool Widget::isDamaged() {
duncanFrance 12:63db16fea709 234 return _damaged;
duncanFrance 12:63db16fea709 235 }
duncanFrance 12:63db16fea709 236
duncanFrance 12:63db16fea709 237 void Widget::adjust()
duncanFrance 12:63db16fea709 238 {
duncanFrance 12:63db16fea709 239 if(!_adjusting) {
duncanFrance 12:63db16fea709 240 _adjusting = true;
duncanFrance 12:63db16fea709 241 _adjust();
duncanFrance 12:63db16fea709 242 _adjusting = false;
duncanFrance 12:63db16fea709 243 }
duncanFrance 12:63db16fea709 244 }
duncanFrance 12:63db16fea709 245
duncanFrance 12:63db16fea709 246 GraphicsDisplay* Widget::display()
duncanFrance 12:63db16fea709 247 {
duncanFrance 12:63db16fea709 248 return _context->display();
duncanFrance 12:63db16fea709 249 }
duncanFrance 12:63db16fea709 250
duncanFrance 12:63db16fea709 251 /**********************************************************
duncanFrance 12:63db16fea709 252 * Protected methods
duncanFrance 12:63db16fea709 253 **********************************************************/
duncanFrance 12:63db16fea709 254 void Widget::_draw() {
duncanFrance 12:63db16fea709 255 GraphicsDisplay *d = display();
duncanFrance 12:63db16fea709 256 // Draw the border
duncanFrance 12:63db16fea709 257 // Top
duncanFrance 12:63db16fea709 258 d->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_borderWidth, _borderColour);
duncanFrance 12:63db16fea709 259 // Bottom
duncanFrance 12:63db16fea709 260 d->fillrect(_outer.x, _outer.y + _outer.height - _borderWidth, _outer.x + _outer.width, _outer.y+_outer.height, _borderColour);
duncanFrance 12:63db16fea709 261 // Left
duncanFrance 12:63db16fea709 262 d->fillrect(_outer.x, _outer.y, _outer.x+_borderWidth, _outer.y+_outer.height, _borderColour);
duncanFrance 12:63db16fea709 263 // Right
duncanFrance 12:63db16fea709 264 d->fillrect(_outer.x+_outer.width-_borderWidth, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, _borderColour);
duncanFrance 12:63db16fea709 265 }
duncanFrance 12:63db16fea709 266
duncanFrance 12:63db16fea709 267 void Widget::_clear() {
duncanFrance 12:63db16fea709 268 display()->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, display()->getBackground());
duncanFrance 12:63db16fea709 269 }
duncanFrance 12:63db16fea709 270
duncanFrance 12:63db16fea709 271 void Widget::_dirty()
duncanFrance 12:63db16fea709 272 {
duncanFrance 12:63db16fea709 273 _dirtied = true;
duncanFrance 12:63db16fea709 274 if(_parent != NULL) {
duncanFrance 12:63db16fea709 275 _parent->dirty();
duncanFrance 12:63db16fea709 276 }
duncanFrance 12:63db16fea709 277 }
duncanFrance 12:63db16fea709 278
duncanFrance 12:63db16fea709 279 void Widget::_damage()
duncanFrance 12:63db16fea709 280 {
duncanFrance 12:63db16fea709 281 _damaged = true;
duncanFrance 12:63db16fea709 282 if(_parent != NULL) {
duncanFrance 12:63db16fea709 283 _parent->dirty();
duncanFrance 12:63db16fea709 284 }
duncanFrance 12:63db16fea709 285 }
duncanFrance 12:63db16fea709 286
duncanFrance 12:63db16fea709 287 void Widget::_adjust() {
duncanFrance 12:63db16fea709 288 // Recalculate size of inner Rect
duncanFrance 12:63db16fea709 289 _inner.resize(_outer, _borderWidth + _padding);
duncanFrance 12:63db16fea709 290 }