1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 09:47:35 +00:00

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.
This commit is contained in:
Tom 2021-06-13 06:13:06 -06:00 committed by Andreas Kling
parent 20c066b8e0
commit 499c33ae0c
4 changed files with 458 additions and 0 deletions

View file

@ -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() }; }