diff options
author | Tom <tomut@yahoo.com> | 2021-06-13 06:13:06 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-06-20 14:57:26 +0200 |
commit | 499c33ae0cf8892dfdf851c178b2b9f7a8bfb79f (patch) | |
tree | cb6c95f2d71ace932d6171e9c8be0a49d8552924 /Userland/Libraries/LibGfx/Rect.h | |
parent | 20c066b8e0d9c2097cd9a46fc7e56b92fc300255 (diff) | |
download | serenity-499c33ae0cf8892dfdf851c178b2b9f7a8bfb79f.zip |
LibGfx: Add a Line class and a Rect<T>::RelativeLocation class
These helpers will be useful in preparation for supporting multiple
displays, e.g. to measure distances to other screens or figure out
where rectangles are located relative to each other.
Diffstat (limited to 'Userland/Libraries/LibGfx/Rect.h')
-rw-r--r-- | Userland/Libraries/LibGfx/Rect.h | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/Userland/Libraries/LibGfx/Rect.h b/Userland/Libraries/LibGfx/Rect.h index 347d415705..1ec5f2273d 100644 --- a/Userland/Libraries/LibGfx/Rect.h +++ b/Userland/Libraries/LibGfx/Rect.h @@ -444,6 +444,131 @@ public: return intersection(*this, other); } + [[nodiscard]] Vector<Point<T>, 2> intersected(Line<T> const&) const; + [[nodiscard]] float center_point_distance_to(Rect<T> const&) const; + [[nodiscard]] Vector<Point<T>, 2> closest_outside_center_points(Rect<T> const&) const; + [[nodiscard]] float outside_center_point_distance_to(Rect<T> const&) const; + [[nodiscard]] Rect<T> constrained_to(Rect<T> const&) const; + [[nodiscard]] Rect<T> aligned_within(Size<T> const&, Point<T> const&, TextAlignment = TextAlignment::Center) const; + [[nodiscard]] Point<T> closest_to(Point<T> const&) const; + + class RelativeLocation { + friend class Rect<T>; + + RelativeLocation(Rect<T> const& base_rect, Rect<T> const& other_rect); + + public: + RelativeLocation() = default; + + bool top_left() const { return m_top_left; } + bool top() const { return m_top; } + bool top_right() const { return m_top_right; } + bool left() const { return m_left; } + bool right() const { return m_right; } + bool bottom_left() const { return m_bottom_left; } + bool bottom() const { return m_bottom; } + bool bottom_right() const { return m_bottom_right; } + bool anywhere_above() const { return m_top_left || m_top || m_top_right; } + bool anywhere_below() const { return m_bottom_left || m_bottom || m_bottom_right; } + bool anywhere_left() const { return m_top_left || m_left || m_bottom_left; } + bool anywhere_right() const { return m_top_right || m_right || m_bottom_right; } + + private: + bool m_top_left : 1 { false }; + bool m_top : 1 { false }; + bool m_top_right : 1 { false }; + bool m_left : 1 { false }; + bool m_right : 1 { false }; + bool m_bottom_left : 1 { false }; + bool m_bottom : 1 { false }; + bool m_bottom_right : 1 { false }; + }; + [[nodiscard]] RelativeLocation relative_location_to(Rect<T> const& other) const + { + return RelativeLocation(*this, other); + } + + enum class Side { + None = 0, + Left, + Top, + Right, + Bottom + }; + [[nodiscard]] Side side(Point<T> const& point) const + { + if (is_empty()) + return Side::None; + if (point.y() == y() || point.y() == bottom()) + return (point.x() >= x() && point.x() <= right()) ? (point.y() == y() ? Side::Top : Side::Bottom) : Side::None; + if (point.x() == x() || point.x() == right()) + return (point.y() > y() && point.y() < bottom()) ? (point.x() == x() ? Side::Left : Side::Right) : Side::None; + return Side::None; + } + + [[nodiscard]] Rect<T> rect_on_side(Side side, Rect<T> const& other) const + { + switch (side) { + case Side::None: + break; + case Side::Left: + // Return the area in other that is to the left of this rect + if (other.x() < x()) { + if (other.right() >= x()) + return { other.location(), { x() - other.x(), other.height() } }; + else + return other; + } + break; + case Side::Top: + // Return the area in other that is above this rect + if (other.y() < y()) { + if (other.bottom() >= y()) + return { other.location(), { other.width(), y() - other.y() } }; + else + return other; + } + break; + case Side::Right: + // Return the area in other that is to the right of this rect + if (other.right() >= x()) { + if (other.x() <= right()) + return { { right() + 1, other.y() }, { other.width() - (right() - other.x()), other.height() } }; + else + return other; + } + break; + case Side::Bottom: + // Return the area in other that is below this rect + if (other.bottom() >= y()) { + if (other.y() <= bottom()) + return { { other.x(), bottom() + 1 }, { other.width(), other.height() - (bottom() - other.y()) } }; + else + return other; + } + break; + } + return {}; + } + + [[nodiscard]] bool is_adjacent(Rect<T> const& other) const + { + if (is_empty() || other.is_empty()) + return false; + if (intersects(other)) + return false; + if (other.x() + other.width() == x() || other.x() == x() + width()) + return max(top(), other.top()) <= min(bottom(), other.bottom()); + if (other.y() + other.height() == y() || other.y() == y() + height()) + return max(left(), other.left()) <= min(right(), other.right()); + return false; + } + + [[nodiscard]] static Rect<T> centered_at(Point<T> const& point, Size<T> const& size) + { + return { { point.x() - size.width() / 2, point.y() - size.height() / 2 }, size }; + } + [[nodiscard]] Rect<T> united(Rect<T> const&) const; [[nodiscard]] Point<T> top_left() const { return { left(), top() }; } |