xaizek / tos (License: GPLv3 only) (since 2018-12-07)
This is an alternative version of sources presented as part of Write Your Own OS video tutorial by Viktor Engelmann.
<root> / src / gui / Widget.cpp (3d209b2447bdcede53a62b8a30aad2bd2133d493) (3,637B) (mode 100644) [raw]
#include "gui/Widget.hpp"

#include <cstdint>

using namespace gui;

Position
gui::operator-(const Position &lhs, const Position &rhs)
{
    return { lhs.x - rhs.x, lhs.y - rhs.y };
}

Position &
gui::operator+=(Position &lhs, const Position &rhs)
{
    lhs.x += rhs.x;
    lhs.y += rhs.y;
    return lhs;
}

Widget::Widget(Widget *parent, Position pos, Dimentions size, Color color)
    : parent(parent), pos(pos), size(size), color(color), focusable(false)
{
}

void
Widget::focus(Widget &widget)
{
    if (parent != nullptr) {
        parent->focus(widget);
    }
}

Position
Widget::modelToScreen(Position p)
{
    if (parent != nullptr) {
        p = parent->modelToScreen(p);
    }

    p.x += pos.x;
    p.y += pos.y;
    return p;
}

bool
Widget::containsCoordinate(Position p)
{
    return p.x >= pos.x
        && p.y >= pos.y
        && p.x < pos.x + size.w
        && p.y < pos.y + size.h;
}

void
Widget::draw(GraphicsContext &gc)
{
    Position p = modelToScreen({ 0, 0 });
    gc.fillRectangle(drv::Position { p.x, p.y },
                     drv::Dimentions { size.w, size.h },
                     drv::Color { color.r, color.g, color.b });
}

void
Widget::onMouseDown(Position /*p*/, std::uint8_t /*button*/)
{
    if (focusable) {
        focus(*this);
    }
}

void
Widget::onMouseUp(Position /*p*/, std::uint8_t /*button*/)
{
}

void
Widget::onMouseMove(Position /*oldPos*/, Position /*newPos*/)
{
}

CompositeWidget::CompositeWidget(Widget *parent, Position pos, Dimentions size,
                                 Color color)
    : Widget(parent, pos, size, color)
{
    focusedChild = nullptr;
    numChildren = 0;
}

bool
CompositeWidget::addChild(Widget &child)
{
    if (&child == this) {
        return false;
    }

    if (numChildren == 100) {
        return false;
    }
    children[numChildren++] = &child;
    return true;
}

void
CompositeWidget::focus(Widget &widget)
{
    focusedChild = &widget;
    if (parent != nullptr) {
        parent->focus(*this);
    }
}

void
CompositeWidget::draw(GraphicsContext &gc)
{
    Widget::draw(gc);
    for (int i = numChildren - 1; i >= 0; --i) {
        children[i]->draw(gc);
    }
}

void
CompositeWidget::onMouseDown(Position p, std::uint8_t button)
{
    Position rp = p - pos;
    for (int i = 0; i < numChildren; ++i) {
        if (children[i]->containsCoordinate(rp)) {
            children[i]->onMouseDown(rp, button);
            break;
        }
    }
}

void
CompositeWidget::onMouseUp(Position p, std::uint8_t button)
{
    Position rp = p - pos;
    for (int i = 0; i < numChildren; ++i) {
        if (children[i]->containsCoordinate(rp)) {
            children[i]->onMouseUp(rp, button);
            break;
        }
    }
}

void
CompositeWidget::onMouseMove(Position oldPos, Position newPos)
{
    Position rOldPos = oldPos - pos;
    Position rNewPos = newPos - pos;

    int firstchild = -1;
    for (int i = 0; i < numChildren; ++i) {
        if (children[i]->containsCoordinate(rOldPos)) {
            children[i]->onMouseMove(rOldPos, rNewPos);
            firstchild = i;
            break;
        }
    }

    for (int i = 0; i < numChildren; ++i)  {
        if (children[i]->containsCoordinate(rNewPos)) {
            if (firstchild != i) {
                children[i]->onMouseMove(rOldPos, rNewPos);
            }
            break;
        }
    }
}

void
CompositeWidget::onKeyDown(std::uint8_t scanCode)
{
    if (focusedChild != nullptr) {
        focusedChild->onKeyDown(scanCode);
    }
}

void
CompositeWidget::onKeyUp(std::uint8_t scanCode)
{
    if (focusedChild != nullptr) {
        focusedChild->onKeyUp(scanCode);
    }
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master