Rect.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
  4. * Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #pragma once
  9. #include <AK/Format.h>
  10. #include <LibGfx/AffineTransform.h>
  11. #include <LibGfx/Orientation.h>
  12. #include <LibGfx/Point.h>
  13. #include <LibGfx/Size.h>
  14. #include <LibGfx/TextAlignment.h>
  15. #include <math.h>
  16. namespace Gfx {
  17. template<typename T>
  18. T abst(T value)
  19. {
  20. return value < 0 ? -value : value;
  21. }
  22. template<typename T>
  23. class Rect {
  24. public:
  25. Rect() = default;
  26. Rect(T x, T y, T width, T height)
  27. : m_location(x, y)
  28. , m_size(width, height)
  29. {
  30. }
  31. template<typename U>
  32. Rect(U x, U y, U width, U height)
  33. : m_location(x, y)
  34. , m_size(width, height)
  35. {
  36. }
  37. Rect(Point<T> const& location, Size<T> const& size)
  38. : m_location(location)
  39. , m_size(size)
  40. {
  41. }
  42. template<typename U>
  43. Rect(Point<U> const& location, Size<U> const& size)
  44. : m_location(location)
  45. , m_size(size)
  46. {
  47. }
  48. template<typename U>
  49. explicit Rect(Rect<U> const& other)
  50. : m_location(other.location())
  51. , m_size(other.size())
  52. {
  53. }
  54. [[nodiscard]] ALWAYS_INLINE T x() const { return location().x(); }
  55. [[nodiscard]] ALWAYS_INLINE T y() const { return location().y(); }
  56. [[nodiscard]] ALWAYS_INLINE T width() const { return m_size.width(); }
  57. [[nodiscard]] ALWAYS_INLINE T height() const { return m_size.height(); }
  58. ALWAYS_INLINE void set_x(T x) { m_location.set_x(x); }
  59. ALWAYS_INLINE void set_y(T y) { m_location.set_y(y); }
  60. ALWAYS_INLINE void set_width(T width) { m_size.set_width(width); }
  61. ALWAYS_INLINE void set_height(T height) { m_size.set_height(height); }
  62. [[nodiscard]] ALWAYS_INLINE Point<T> const& location() const { return m_location; }
  63. [[nodiscard]] ALWAYS_INLINE Size<T> const& size() const { return m_size; }
  64. [[nodiscard]] ALWAYS_INLINE bool is_null() const { return width() == 0 && height() == 0; }
  65. [[nodiscard]] ALWAYS_INLINE bool is_empty() const { return width() <= 0 || height() <= 0; }
  66. ALWAYS_INLINE void translate_by(T dx, T dy) { m_location.translate_by(dx, dy); }
  67. ALWAYS_INLINE void translate_by(T dboth) { m_location.translate_by(dboth); }
  68. ALWAYS_INLINE void translate_by(Point<T> const& delta) { m_location.translate_by(delta); }
  69. ALWAYS_INLINE void scale_by(T dx, T dy)
  70. {
  71. m_location.scale_by(dx, dy);
  72. m_size.scale_by(dx, dy);
  73. }
  74. ALWAYS_INLINE void scale_by(T dboth) { scale_by(dboth, dboth); }
  75. ALWAYS_INLINE void scale_by(Point<T> const& delta) { scale_by(delta.x(), delta.y()); }
  76. void transform_by(AffineTransform const& transform) { *this = transform.map(*this); }
  77. [[nodiscard]] Point<T> center() const
  78. {
  79. return { x() + width() / 2, y() + height() / 2 };
  80. }
  81. ALWAYS_INLINE void set_location(Point<T> const& location)
  82. {
  83. m_location = location;
  84. }
  85. ALWAYS_INLINE void set_size(Size<T> const& size)
  86. {
  87. m_size = size;
  88. }
  89. void set_size_around(Size<T> const&, Point<T> const& fixed_point);
  90. void set_size(T width, T height)
  91. {
  92. m_size.set_width(width);
  93. m_size.set_height(height);
  94. }
  95. void inflate(T w, T h)
  96. {
  97. set_x(x() - w / 2);
  98. set_width(width() + w);
  99. set_y(y() - h / 2);
  100. set_height(height() + h);
  101. }
  102. void inflate(T top, T right, T bottom, T left)
  103. {
  104. set_x(x() - left);
  105. set_width(width() + left + right);
  106. set_y(y() - top);
  107. set_height(height() + top + bottom);
  108. }
  109. void inflate(Size<T> const& size)
  110. {
  111. set_x(x() - size.width() / 2);
  112. set_width(width() + size.width());
  113. set_y(y() - size.height() / 2);
  114. set_height(height() + size.height());
  115. }
  116. void shrink(T w, T h)
  117. {
  118. set_x(x() + w / 2);
  119. set_width(width() - w);
  120. set_y(y() + h / 2);
  121. set_height(height() - h);
  122. }
  123. void shrink(T top, T right, T bottom, T left)
  124. {
  125. set_x(x() + left);
  126. set_width(width() - (left + right));
  127. set_y(y() + top);
  128. set_height(height() - (top + bottom));
  129. }
  130. void shrink(Size<T> const& size)
  131. {
  132. set_x(x() + size.width() / 2);
  133. set_width(width() - size.width());
  134. set_y(y() + size.height() / 2);
  135. set_height(height() - size.height());
  136. }
  137. [[nodiscard]] Rect<T> translated(T dx, T dy) const
  138. {
  139. Rect<T> rect = *this;
  140. rect.translate_by(dx, dy);
  141. return rect;
  142. }
  143. [[nodiscard]] Rect<T> translated(Point<T> const& delta) const
  144. {
  145. Rect<T> rect = *this;
  146. rect.translate_by(delta);
  147. return rect;
  148. }
  149. [[nodiscard]] Rect<T> scaled(T sx, T sy) const
  150. {
  151. Rect<T> rect = *this;
  152. rect.scale_by(sx, sy);
  153. return rect;
  154. }
  155. [[nodiscard]] Rect<T> scaled(Point<T> const& s) const
  156. {
  157. Rect<T> rect = *this;
  158. rect.scale_by(s);
  159. return rect;
  160. }
  161. [[nodiscard]] Rect<T> transformed(AffineTransform const& transform) const
  162. {
  163. Rect<T> rect = *this;
  164. rect.transform_by(transform);
  165. return rect;
  166. }
  167. [[nodiscard]] Rect<T> shrunken(T w, T h) const
  168. {
  169. Rect<T> rect = *this;
  170. rect.shrink(w, h);
  171. return rect;
  172. }
  173. [[nodiscard]] Rect<T> shrunken(T top, T right, T bottom, T left) const
  174. {
  175. Rect<T> rect = *this;
  176. rect.shrink(top, right, bottom, left);
  177. return rect;
  178. }
  179. [[nodiscard]] Rect<T> shrunken(Size<T> const& size) const
  180. {
  181. Rect<T> rect = *this;
  182. rect.shrink(size);
  183. return rect;
  184. }
  185. [[nodiscard]] Rect<T> inflated(T w, T h) const
  186. {
  187. Rect<T> rect = *this;
  188. rect.inflate(w, h);
  189. return rect;
  190. }
  191. [[nodiscard]] Rect<T> inflated(T top, T right, T bottom, T left) const
  192. {
  193. Rect<T> rect = *this;
  194. rect.inflate(top, right, bottom, left);
  195. return rect;
  196. }
  197. [[nodiscard]] Rect<T> inflated(Size<T> const& size) const
  198. {
  199. Rect<T> rect = *this;
  200. rect.inflate(size);
  201. return rect;
  202. }
  203. Rect<T> take_from_right(T w)
  204. {
  205. if (w > width())
  206. w = width();
  207. Rect<T> rect = *this;
  208. set_width(width() - w);
  209. rect.set_x(x() + width());
  210. rect.set_width(w);
  211. return rect;
  212. }
  213. Rect<T> take_from_left(T w)
  214. {
  215. if (w > width())
  216. w = width();
  217. Rect<T> rect = *this;
  218. set_x(x() + w);
  219. set_width(width() - w);
  220. rect.set_width(w);
  221. return rect;
  222. }
  223. Rect<T> take_from_top(T h)
  224. {
  225. if (h > height())
  226. h = height();
  227. Rect<T> rect = *this;
  228. set_y(y() + h);
  229. set_height(height() - h);
  230. rect.set_height(h);
  231. return rect;
  232. }
  233. Rect<T> take_from_bottom(T h)
  234. {
  235. if (h > height())
  236. h = height();
  237. Rect<T> rect = *this;
  238. set_height(height() - h);
  239. rect.set_y(y() + height());
  240. rect.set_height(h);
  241. return rect;
  242. }
  243. [[nodiscard]] bool contains_vertically(T y) const
  244. {
  245. return y >= top() && y <= bottom();
  246. }
  247. [[nodiscard]] bool contains_horizontally(T x) const
  248. {
  249. return x >= left() && x <= right();
  250. }
  251. [[nodiscard]] bool contains(T x, T y) const
  252. {
  253. return x >= m_location.x() && x <= right() && y >= m_location.y() && y <= bottom();
  254. }
  255. [[nodiscard]] ALWAYS_INLINE bool contains(Point<T> const& point) const
  256. {
  257. return contains(point.x(), point.y());
  258. }
  259. [[nodiscard]] bool contains(Rect<T> const& other) const
  260. {
  261. return left() <= other.left()
  262. && right() >= other.right()
  263. && top() <= other.top()
  264. && bottom() >= other.bottom();
  265. }
  266. template<typename Container>
  267. [[nodiscard]] bool contains(Container const& others) const
  268. {
  269. bool have_any = false;
  270. for (auto const& other : others) {
  271. if (!contains(other))
  272. return false;
  273. have_any = true;
  274. }
  275. return have_any;
  276. }
  277. [[nodiscard]] ALWAYS_INLINE int primary_offset_for_orientation(Orientation orientation) const { return m_location.primary_offset_for_orientation(orientation); }
  278. ALWAYS_INLINE void set_primary_offset_for_orientation(Orientation orientation, int value) { m_location.set_primary_offset_for_orientation(orientation, value); }
  279. [[nodiscard]] ALWAYS_INLINE int secondary_offset_for_orientation(Orientation orientation) const { return m_location.secondary_offset_for_orientation(orientation); }
  280. ALWAYS_INLINE void set_secondary_offset_for_orientation(Orientation orientation, int value) { m_location.set_secondary_offset_for_orientation(orientation, value); }
  281. [[nodiscard]] ALWAYS_INLINE int primary_size_for_orientation(Orientation orientation) const { return m_size.primary_size_for_orientation(orientation); }
  282. [[nodiscard]] ALWAYS_INLINE int secondary_size_for_orientation(Orientation orientation) const { return m_size.secondary_size_for_orientation(orientation); }
  283. ALWAYS_INLINE void set_primary_size_for_orientation(Orientation orientation, int value) { m_size.set_primary_size_for_orientation(orientation, value); }
  284. ALWAYS_INLINE void set_secondary_size_for_orientation(Orientation orientation, int value) { m_size.set_secondary_size_for_orientation(orientation, value); }
  285. [[nodiscard]] T first_edge_for_orientation(Orientation orientation) const
  286. {
  287. if (orientation == Orientation::Vertical)
  288. return top();
  289. return left();
  290. }
  291. [[nodiscard]] T last_edge_for_orientation(Orientation orientation) const
  292. {
  293. if (orientation == Orientation::Vertical)
  294. return bottom();
  295. return right();
  296. }
  297. [[nodiscard]] ALWAYS_INLINE T left() const { return x(); }
  298. [[nodiscard]] ALWAYS_INLINE T right() const { return x() + width() - 1; }
  299. [[nodiscard]] ALWAYS_INLINE T top() const { return y(); }
  300. [[nodiscard]] ALWAYS_INLINE T bottom() const { return y() + height() - 1; }
  301. ALWAYS_INLINE void set_left(T left)
  302. {
  303. set_x(left);
  304. }
  305. ALWAYS_INLINE void set_top(T top)
  306. {
  307. set_y(top);
  308. }
  309. ALWAYS_INLINE void set_right(T right)
  310. {
  311. set_width(right - x() + 1);
  312. }
  313. ALWAYS_INLINE void set_bottom(T bottom)
  314. {
  315. set_height(bottom - y() + 1);
  316. }
  317. void set_right_without_resize(T new_right)
  318. {
  319. int delta = new_right - right();
  320. translate_by(delta, 0);
  321. }
  322. void set_bottom_without_resize(T new_bottom)
  323. {
  324. int delta = new_bottom - bottom();
  325. translate_by(0, delta);
  326. }
  327. [[nodiscard]] bool intersects_vertically(Rect<T> const& other) const
  328. {
  329. return top() <= other.bottom() && other.top() <= bottom();
  330. }
  331. [[nodiscard]] bool intersects_horizontally(Rect<T> const& other) const
  332. {
  333. return left() <= other.right() && other.left() <= right();
  334. }
  335. [[nodiscard]] bool intersects(Rect<T> const& other) const
  336. {
  337. return left() <= other.right()
  338. && other.left() <= right()
  339. && top() <= other.bottom()
  340. && other.top() <= bottom();
  341. }
  342. template<typename Container>
  343. [[nodiscard]] bool intersects(Container const& others) const
  344. {
  345. for (auto const& other : others) {
  346. if (intersects(other))
  347. return true;
  348. }
  349. return false;
  350. }
  351. template<typename Container, typename Function>
  352. IterationDecision for_each_intersected(Container const& others, Function f) const
  353. {
  354. if (is_empty())
  355. return IterationDecision::Continue;
  356. for (auto const& other : others) {
  357. auto intersected_rect = intersected(other);
  358. if (!intersected_rect.is_empty()) {
  359. IterationDecision decision = f(intersected_rect);
  360. if (decision != IterationDecision::Continue)
  361. return decision;
  362. }
  363. }
  364. return IterationDecision::Continue;
  365. }
  366. [[nodiscard]] Vector<Rect<T>, 4> shatter(Rect<T> const& hammer) const;
  367. template<class U>
  368. [[nodiscard]] bool operator==(Rect<U> const& other) const
  369. {
  370. return location() == other.location() && size() == other.size();
  371. }
  372. template<class U>
  373. [[nodiscard]] bool operator!=(Rect<U> const& other) const
  374. {
  375. return !(*this == other);
  376. }
  377. [[nodiscard]] Rect<T> operator*(T factor) const { return { m_location * factor, m_size * factor }; }
  378. Rect<T>& operator*=(T factor)
  379. {
  380. m_location *= factor;
  381. m_size *= factor;
  382. return *this;
  383. }
  384. void intersect(Rect<T> const&);
  385. [[nodiscard]] static Rect<T> centered_on(Point<T> const& center, Size<T> const& size)
  386. {
  387. return { { center.x() - size.width() / 2, center.y() - size.height() / 2 }, size };
  388. }
  389. [[nodiscard]] static Rect<T> from_two_points(Point<T> const& a, Point<T> const& b)
  390. {
  391. return { min(a.x(), b.x()), min(a.y(), b.y()), abst(a.x() - b.x()), abst(a.y() - b.y()) };
  392. }
  393. [[nodiscard]] static Rect<T> intersection(Rect<T> const& a, Rect<T> const& b)
  394. {
  395. Rect<T> r = a;
  396. r.intersect(b);
  397. return r;
  398. }
  399. [[nodiscard]] ALWAYS_INLINE Rect<T> intersected(Rect<T> const& other) const
  400. {
  401. return intersection(*this, other);
  402. }
  403. [[nodiscard]] Vector<Point<T>, 2> intersected(Line<T> const&) const;
  404. [[nodiscard]] float center_point_distance_to(Rect<T> const&) const;
  405. [[nodiscard]] Vector<Point<T>, 2> closest_outside_center_points(Rect<T> const&) const;
  406. [[nodiscard]] float outside_center_point_distance_to(Rect<T> const&) const;
  407. [[nodiscard]] Rect<T> constrained_to(Rect<T> const&) const;
  408. [[nodiscard]] Rect<T> aligned_within(Size<T> const&, Point<T> const&, TextAlignment = TextAlignment::Center) const;
  409. [[nodiscard]] Point<T> closest_to(Point<T> const&) const;
  410. class RelativeLocation {
  411. friend class Rect<T>;
  412. RelativeLocation(Rect<T> const& base_rect, Rect<T> const& other_rect);
  413. public:
  414. RelativeLocation() = default;
  415. bool top_left() const { return m_top_left; }
  416. bool top() const { return m_top; }
  417. bool top_right() const { return m_top_right; }
  418. bool left() const { return m_left; }
  419. bool right() const { return m_right; }
  420. bool bottom_left() const { return m_bottom_left; }
  421. bool bottom() const { return m_bottom; }
  422. bool bottom_right() const { return m_bottom_right; }
  423. bool anywhere_above() const { return m_top_left || m_top || m_top_right; }
  424. bool anywhere_below() const { return m_bottom_left || m_bottom || m_bottom_right; }
  425. bool anywhere_left() const { return m_top_left || m_left || m_bottom_left; }
  426. bool anywhere_right() const { return m_top_right || m_right || m_bottom_right; }
  427. private:
  428. bool m_top_left : 1 { false };
  429. bool m_top : 1 { false };
  430. bool m_top_right : 1 { false };
  431. bool m_left : 1 { false };
  432. bool m_right : 1 { false };
  433. bool m_bottom_left : 1 { false };
  434. bool m_bottom : 1 { false };
  435. bool m_bottom_right : 1 { false };
  436. };
  437. [[nodiscard]] RelativeLocation relative_location_to(Rect<T> const& other) const
  438. {
  439. return RelativeLocation(*this, other);
  440. }
  441. enum class Side {
  442. None = 0,
  443. Left,
  444. Top,
  445. Right,
  446. Bottom
  447. };
  448. [[nodiscard]] Side side(Point<T> const& point) const
  449. {
  450. if (is_empty())
  451. return Side::None;
  452. if (point.y() == y() || point.y() == bottom())
  453. return (point.x() >= x() && point.x() <= right()) ? (point.y() == y() ? Side::Top : Side::Bottom) : Side::None;
  454. if (point.x() == x() || point.x() == right())
  455. return (point.y() > y() && point.y() < bottom()) ? (point.x() == x() ? Side::Left : Side::Right) : Side::None;
  456. return Side::None;
  457. }
  458. [[nodiscard]] Rect<T> rect_on_side(Side side, Rect<T> const& other) const
  459. {
  460. switch (side) {
  461. case Side::None:
  462. break;
  463. case Side::Left:
  464. // Return the area in other that is to the left of this rect
  465. if (other.x() < x()) {
  466. if (other.right() >= x())
  467. return { other.location(), { x() - other.x(), other.height() } };
  468. else
  469. return other;
  470. }
  471. break;
  472. case Side::Top:
  473. // Return the area in other that is above this rect
  474. if (other.y() < y()) {
  475. if (other.bottom() >= y())
  476. return { other.location(), { other.width(), y() - other.y() } };
  477. else
  478. return other;
  479. }
  480. break;
  481. case Side::Right:
  482. // Return the area in other that is to the right of this rect
  483. if (other.right() >= x()) {
  484. if (other.x() <= right())
  485. return { { right() + 1, other.y() }, { other.width() - (right() - other.x()), other.height() } };
  486. else
  487. return other;
  488. }
  489. break;
  490. case Side::Bottom:
  491. // Return the area in other that is below this rect
  492. if (other.bottom() >= y()) {
  493. if (other.y() <= bottom())
  494. return { { other.x(), bottom() + 1 }, { other.width(), other.height() - (bottom() - other.y()) } };
  495. else
  496. return other;
  497. }
  498. break;
  499. }
  500. return {};
  501. }
  502. template<typename Container>
  503. static bool disperse(Container& rects)
  504. {
  505. auto has_intersecting = [&]() {
  506. for (auto& rect : rects) {
  507. for (auto& other_rect : rects) {
  508. if (&rect == &other_rect)
  509. continue;
  510. if (rect.intersects(other_rect))
  511. return true;
  512. }
  513. }
  514. return false;
  515. };
  516. if (!has_intersecting())
  517. return false;
  518. auto calc_delta = [&](Rect<T> const& rect) -> Point<T> {
  519. auto rect_center = rect.center();
  520. Point<T> center_sum;
  521. for (auto& other_rect : rects) {
  522. if (&other_rect == &rect)
  523. continue;
  524. if (rect.intersects(other_rect))
  525. center_sum += rect_center - other_rect.center();
  526. }
  527. double m = sqrt((double)center_sum.x() * (double)center_sum.x() + (double)center_sum.y() * (double)center_sum.y());
  528. if (m != 0.0)
  529. return { (double)center_sum.x() / m + 0.5, (double)center_sum.y() / m + 0.5 };
  530. return {};
  531. };
  532. Vector<Point<T>, 8> deltas;
  533. do {
  534. bool changes = false;
  535. deltas.clear_with_capacity();
  536. for (auto& rect : rects) {
  537. auto delta = calc_delta(rect);
  538. if (!delta.is_null())
  539. changes = true;
  540. deltas.append(delta);
  541. }
  542. // TODO: If we have no changes we would loop infinitely!
  543. // Figure out some way to resolve this. Maybe randomly moving an intersecting rect?
  544. VERIFY(changes);
  545. size_t i = 0;
  546. for (auto& rect : rects)
  547. rect.translate_by(deltas[i++]);
  548. } while (has_intersecting());
  549. return true;
  550. }
  551. [[nodiscard]] bool is_adjacent(Rect<T> const& other) const
  552. {
  553. if (is_empty() || other.is_empty())
  554. return false;
  555. if (intersects(other))
  556. return false;
  557. if (other.x() + other.width() == x() || other.x() == x() + width())
  558. return max(top(), other.top()) <= min(bottom(), other.bottom());
  559. if (other.y() + other.height() == y() || other.y() == y() + height())
  560. return max(left(), other.left()) <= min(right(), other.right());
  561. return false;
  562. }
  563. [[nodiscard]] static Rect<T> centered_at(Point<T> const& point, Size<T> const& size)
  564. {
  565. return { { point.x() - size.width() / 2, point.y() - size.height() / 2 }, size };
  566. }
  567. [[nodiscard]] Rect<T> united(Rect<T> const&) const;
  568. [[nodiscard]] Point<T> top_left() const { return { left(), top() }; }
  569. [[nodiscard]] Point<T> top_right() const { return { right(), top() }; }
  570. [[nodiscard]] Point<T> bottom_left() const { return { left(), bottom() }; }
  571. [[nodiscard]] Point<T> bottom_right() const { return { right(), bottom() }; }
  572. void align_within(Rect<T> const&, TextAlignment);
  573. void center_within(Rect<T> const& other)
  574. {
  575. center_horizontally_within(other);
  576. center_vertically_within(other);
  577. }
  578. [[nodiscard]] Rect centered_within(Rect const& other) const
  579. {
  580. Rect rect { *this };
  581. rect.center_horizontally_within(other);
  582. rect.center_vertically_within(other);
  583. return rect;
  584. }
  585. void center_horizontally_within(Rect<T> const& other)
  586. {
  587. set_x(other.center().x() - width() / 2);
  588. }
  589. void center_vertically_within(Rect<T> const& other)
  590. {
  591. set_y(other.center().y() - height() / 2);
  592. }
  593. template<typename U>
  594. [[nodiscard]] ALWAYS_INLINE Rect<U> to_type() const
  595. {
  596. return Rect<U>(*this);
  597. }
  598. template<typename U>
  599. [[nodiscard]] ALWAYS_INLINE Rect<U> to_rounded() const
  600. {
  601. if constexpr (IsSame<T, float>) {
  602. return {
  603. static_cast<U>(llroundf(x())),
  604. static_cast<U>(llroundf(y())),
  605. static_cast<U>(llroundf(width())),
  606. static_cast<U>(llroundf(height())),
  607. };
  608. } else {
  609. return {
  610. static_cast<U>(llroundd(x())),
  611. static_cast<U>(llroundd(y())),
  612. static_cast<U>(llroundd(width())),
  613. static_cast<U>(llroundd(height())),
  614. };
  615. }
  616. }
  617. [[nodiscard]] String to_string() const;
  618. private:
  619. Point<T> m_location;
  620. Size<T> m_size;
  621. };
  622. using IntRect = Rect<int>;
  623. using FloatRect = Rect<float>;
  624. [[nodiscard]] ALWAYS_INLINE IntRect enclosing_int_rect(FloatRect const& float_rect)
  625. {
  626. int x1 = floorf(float_rect.x());
  627. int y1 = floorf(float_rect.y());
  628. int x2 = ceilf(float_rect.x() + float_rect.width());
  629. int y2 = ceilf(float_rect.y() + float_rect.height());
  630. return Gfx::IntRect::from_two_points({ x1, y1 }, { x2, y2 });
  631. }
  632. }
  633. namespace AK {
  634. template<typename T>
  635. struct Formatter<Gfx::Rect<T>> : Formatter<StringView> {
  636. ErrorOr<void> format(FormatBuilder& builder, Gfx::Rect<T> const& value)
  637. {
  638. return Formatter<StringView>::format(builder, value.to_string());
  639. }
  640. };
  641. }
  642. namespace IPC {
  643. bool encode(Encoder&, Gfx::IntRect const&);
  644. ErrorOr<void> decode(Decoder&, Gfx::IntRect&);
  645. }