Foundation classes for a basic GUI implementing simple widgets and events
Dependents: TouchScreenGUIDemo
Widgets/Widget.cpp@17:5184762fda6c, 2016-05-22 (annotated)
- 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?
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 | 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 | } |