Skip to content

File graphics_common.h

File List > disp > graphics_common.h

Go to the documentation of this file

Source Code

#pragma once

#include <cstdint>

namespace daisy
{
enum class Alignment
{
    centered,
    topLeft,
    topCentered,
    topRight,
    bottomLeft,
    bottomCentered,
    bottomRight,
    centeredLeft,
    centeredRight
};

class Rectangle
{
  public:
    Rectangle() : x_(0), y_(0), width_(0), height_(0) {}

    Rectangle(int16_t width, int16_t height)
    : x_(0), y_(0), width_(max(0, width)), height_(max(0, height))
    {
    }

    Rectangle(int16_t x, int16_t y, int16_t width, int16_t height)
    : x_(x), y_(y), width_(max(0, width)), height_(max(0, height))
    {
    }

    Rectangle(const Rectangle& other) { *this = other; }

    Rectangle& operator=(const Rectangle& other)
    {
        x_      = other.x_;
        y_      = other.y_;
        width_  = other.width_;
        height_ = other.height_;
        return *this;
    }

    bool operator==(const Rectangle& other) const
    {
        return (x_ == other.x_) && (y_ == other.y_) && (width_ == other.width_)
               && (height_ == other.height_);
    }
    bool operator!=(const Rectangle& other) const { return !(*this == other); }

    bool IsEmpty() const { return (width_ <= 0) || (height_ <= 0); }

    int16_t GetX() const { return x_; }
    int16_t GetY() const { return y_; }
    int16_t GetWidth() const { return width_; }
    int16_t GetHeight() const { return height_; }
    int16_t GetRight() const { return x_ + width_; }
    int16_t GetBottom() const { return y_ + height_; }
    int16_t GetCenterX() const { return x_ + width_ / 2; }
    int16_t GetCenterY() const { return y_ + height_ / 2; }

    Rectangle WithX(int16_t x) const { return {x, y_, width_, height_}; }
    Rectangle WithY(int16_t y) const { return {x_, y, width_, height_}; }
    Rectangle WithWidth(int16_t width) const
    {
        return {x_, y_, width, height_};
    }
    Rectangle WithHeight(int16_t height) const
    {
        return {x_, y_, width_, height};
    }
    Rectangle WithSize(int16_t width, int16_t height) const
    {
        return {x_, y_, width, height};
    }
    Rectangle WithWidthKeepingCenter(int16_t width) const
    {
        return Rectangle(x_, y_, width, height_)
            .WithCenter(GetCenterX(), GetCenterY());
    }
    Rectangle WithHeightKeepingCenter(int16_t height) const
    {
        return Rectangle(x_, y_, width_, height)
            .WithCenter(GetCenterX(), GetCenterY());
    }
    Rectangle WithSizeKeepingCenter(int16_t width, int16_t height) const
    {
        return Rectangle(x_, y_, width, height)
            .WithCenter(GetCenterX(), GetCenterY());
    }

    Rectangle Reduced(int16_t sizeToReduce) const
    {
        return {int16_t(x_ + sizeToReduce),
                int16_t(y_ + sizeToReduce),
                int16_t(width_ - 2 * sizeToReduce),
                int16_t(height_ - 2 * sizeToReduce)};
    }
    Rectangle Reduced(int16_t xToReduce, int16_t yToReduce) const
    {
        return {int16_t(x_ + xToReduce),
                int16_t(y_ + yToReduce),
                int16_t(width_ - 2 * xToReduce),
                int16_t(height_ - 2 * yToReduce)};
    }

    Rectangle Translated(int16_t x, int16_t y) const
    {
        return {int16_t(x_ + x), int16_t(y_ + y), width_, height_};
    }

    Rectangle WithLeft(int16_t left) const
    {
        const auto newWidth = int16_t((x_ - left) + width_);
        return {left, y_, newWidth, height_};
    }

    Rectangle WithRight(int16_t right) const
    {
        const auto newWidth = int16_t(right - x_);
        return {x_, y_, newWidth, height_};
    }

    Rectangle WithTop(int16_t top) const
    {
        const auto newHeight = int16_t((y_ - top) + height_);
        return {x_, top, width_, newHeight};
    }

    Rectangle WithBottom(int16_t bottom) const
    {
        const auto newHeight = int16_t(bottom - y_);
        return {x_, y_, width_, newHeight};
    }

    Rectangle WithTrimmedLeft(int16_t pxToTrim) const
    {
        return {
            int16_t(x_ + pxToTrim), y_, int16_t(width_ - pxToTrim), height_};
    }

    Rectangle WithTrimmedRight(int16_t pxToTrim) const
    {
        return {x_, y_, int16_t(width_ - pxToTrim), height_};
    }

    Rectangle WithTrimmedTop(int16_t pxToTrim) const
    {
        return {
            x_, int16_t(y_ + pxToTrim), width_, int16_t(height_ - pxToTrim)};
    }

    Rectangle WithTrimmedBottom(int16_t pxToTrim) const
    {
        return {x_, y_, width_, int16_t(height_ - pxToTrim)};
    }

    Rectangle WithCenterX(int16_t centerX) const
    {
        return {int16_t(x_ + centerX - GetCenterX()), y_, width_, height_};
    }

    Rectangle WithCenterY(int16_t centerY) const
    {
        return {x_, int16_t(y_ + centerY - GetCenterY()), width_, height_};
    }

    Rectangle WithCenter(int16_t centerX, int16_t centerY) const
    {
        return {int16_t(x_ + centerX - GetCenterX()),
                int16_t(y_ + centerY - GetCenterY()),
                width_,
                height_};
    }

    Rectangle RemoveFromLeft(int16_t pxToRemove)
    {
        const auto result = this->WithWidth(min(pxToRemove, width_));
        x_ += min(pxToRemove, width_);
        width_ = max(int16_t(width_ - pxToRemove), 0);
        return result;
    }

    Rectangle RemoveFromRight(int16_t pxToRemove)
    {
        const auto canRemove = min(pxToRemove, width_);
        width_ -= canRemove;
        return {int16_t(x_ + width_), y_, canRemove, height_};
    }

    Rectangle RemoveFromTop(int16_t pxToRemove)
    {
        const auto result = this->WithHeight(min(pxToRemove, height_));
        y_ += min(pxToRemove, height_);
        height_ = max(height_ - pxToRemove, 0);
        return result;
    }

    Rectangle RemoveFromBottom(int16_t pxToRemove)
    {
        const auto canRemove = min(pxToRemove, height_);
        height_ -= canRemove;
        return {x_, int16_t(y_ + height_), width_, canRemove};
    }

    Rectangle AlignedWithin(const Rectangle& other, Alignment alignment) const
    {
        switch(alignment)
        {
            case Alignment::topLeft:
                return {other.x_, other.y_, width_, height_};
            case Alignment::topRight:
                return {int16_t(other.GetRight() - width_),
                        other.y_,
                        width_,
                        height_};
            case Alignment::topCentered:
                return {int16_t(x_ + (other.GetCenterX() - GetCenterX())),
                        other.y_,
                        width_,
                        height_};
            case Alignment::bottomLeft:
                return {other.x_,
                        int16_t(other.GetBottom() - height_),
                        width_,
                        height_};
            case Alignment::bottomRight:
                return {int16_t(other.GetRight() - width_),
                        int16_t(other.GetBottom() - height_),
                        width_,
                        height_};
            case Alignment::bottomCentered:
                return {int16_t(x_ + (other.GetCenterX() - GetCenterX())),
                        int16_t(other.GetBottom() - height_),
                        width_,
                        height_};
            case Alignment::centeredLeft:
                return {other.x_,
                        int16_t(y_ + (other.GetCenterY() - GetCenterY())),
                        width_,
                        height_};
            case Alignment::centeredRight:
                return {int16_t(other.GetRight() - width_),
                        int16_t(y_ + (other.GetCenterY() - GetCenterY())),
                        width_,
                        height_};
            case Alignment::centered:
                return {int16_t(x_ + (other.GetCenterX() - GetCenterX())),
                        int16_t(y_ + (other.GetCenterY() - GetCenterY())),
                        width_,
                        height_};
            default: return {};
        }
    }

  private:
    int16_t x_, y_, width_, height_;
    int16_t max(int16_t a, int16_t b) { return (a > b) ? a : b; }
    int16_t min(int16_t a, int16_t b) { return (a < b) ? a : b; }
};

} // namespace daisy