Foundation classes for a basic GUI implementing simple widgets and events

Dependents:   TouchScreenGUIDemo

Widgets/Widget.cpp

Committer:
duncanFrance
Date:
2016-05-08
Revision:
12:63db16fea709
Child:
13:6714534e7974

File content as of revision 12:63db16fea709:

#include "Widget.h"
#include <algorithm>
Widget::Widget(GraphicsContext* context) 
:   _context(context), 
    _fg(White), _bg(Black), 
    _inner(0,0,0,0), _outer(0,0,0,0),
    _hidden(false), 
    _padding(0), _borderWidth(1), _borderColour(White),
    _adjusting(false), 
    _dirtied(true), _dirtying(false), 
    _damaged(true), _damaging(false)
{
}

void Widget::setParent(Widget* parent) {
    _parent = parent;
}

bool Widget::isEventTarget(Event e)
{
    return !_hidden 
        && e.screenX >= _outer.x 
        && e.screenX <= (_outer.x+_outer.width) 
        && e.screenY >= _outer.y 
        && e.screenY <= (_outer.y+_outer.height);
}

void Widget::setLocation(int x, int y)
{
    if(_outer.x != x || _outer.y != y) {
        _outer.x = x;
        _outer.y = y;
        damage();
        adjust();
    }
}

void Widget::setSize(int width, int height)
{
    if(_outer.width != width || _outer.height != height) {
        _outer.width = width;
        _outer.height = height;
        damage();
        adjust();
    }
}

void Widget::setWidth(int width) {
    if(_outer.width != width) {
        _outer.width = width;
        damage();
        adjust();
    }
}

void Widget::setHeight(int height) {
    if(_outer.height != height) {
        _outer.height = height;
        damage();
        adjust();
    }
}

int Widget::x()
{
    return _outer.x;
}

int Widget::y()
{
    return _outer.y;
}

int Widget::height()
{
    return _outer.height;
}

int Widget::width()
{
    return _outer.width;
}

const Rectangle &Widget::outer() {
    return _outer;
}

const Rectangle &Widget::inner() {
    return _inner;
}

void Widget::setForeground(uint16_t color)
{
    if(_fg != color) {
        _fg = color;
        dirty();
    }
}

void Widget::setBackground(uint16_t color)
{
    if(_bg != color) {
        _bg = color;
        dirty();
    }
}


/**
* Set the amount of padding between the border and a widget edge
**/
void Widget::setPadding(int pixels)
{
    if(_padding != pixels) {
        _padding = pixels;
        dirty();
    }
}

void Widget::setBorder(int width, uint16_t colour)
{
    if(_borderWidth != width || _borderColour != colour) {
        _borderColour = colour;
        _borderWidth = width;
        dirty();
    }
}

void Widget::draw()
{
    if(!_hidden && (_dirtied | _damaged)) {
        _draw();
        _dirtied = false;
        _damaged = false;
    }
}

void Widget::clear()
{
    if(!_hidden) _clear();
}

void Widget::show()
{
    _hidden = false;
    draw();
}

void Widget::hide()
{
    clear();
    _hidden = true;
}

bool Widget::isHidden()
{
    return _hidden;
}

void Widget::setEventHandler(EventHandler* handler)
{
    EventListener::setEventHandler(handler);
    _context->eventDispatcher()->detachListener(this);
    _context->eventDispatcher()->attachListener(this);
}

void Widget::unsetEventHandler(EventHandler *handler)
{
    EventListener::unsetEventHandler(handler);
}

bool Widget::intersects(Widget *w)
{
    return _outer.intersects(w->outer());
}

void Widget::dirty()
{
    if(!_dirtying) {
        _dirtying = true;
        _dirty();
        _dirtying = false;
    }
}

bool Widget::isDirty() {
    return _dirtied;
}

void Widget::dirtyAll()
{
    _dirtied = true;
}

void Widget::damage() {
    if(!_damaging) {
        _damaging = true;
        _damage();
        _damaging = false;
    }
}

bool Widget::isDamaged() {
    return _damaged;
}

void Widget::adjust()
{
    if(!_adjusting) {
        _adjusting = true;
        _adjust();
        _adjusting = false;
    }
}

GraphicsDisplay* Widget::display()
{
    return _context->display();
}

/**********************************************************
* Protected methods
**********************************************************/
void Widget::_draw() {
    GraphicsDisplay *d = display();
    // Draw the border
    // Top
    d->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_borderWidth, _borderColour);
    // Bottom
    d->fillrect(_outer.x, _outer.y + _outer.height - _borderWidth, _outer.x + _outer.width, _outer.y+_outer.height, _borderColour);
    // Left
    d->fillrect(_outer.x, _outer.y, _outer.x+_borderWidth, _outer.y+_outer.height, _borderColour);
    // Right
    d->fillrect(_outer.x+_outer.width-_borderWidth, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, _borderColour);
}

void Widget::_clear() {
    display()->fillrect(_outer.x, _outer.y, _outer.x+_outer.width, _outer.y+_outer.height, display()->getBackground());
}

void Widget::_dirty()
{
    _dirtied = true;
    if(_parent != NULL) {
        _parent->dirty();
    }
}

void Widget::_damage()
{
    _damaged = true;
    if(_parent != NULL) {
        _parent->dirty();
    }
}

void Widget::_adjust() {
    // Recalculate size of inner Rect
    _inner.resize(_outer, _borderWidth + _padding);
}