Rect.h 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. * Copyright (c) 2021-2022, 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/Line.h>
  12. #include <LibGfx/Orientation.h>
  13. #include <LibGfx/Point.h>
  14. #include <LibGfx/Size.h>
  15. #include <LibGfx/TextAlignment.h>
  16. #include <math.h>
  17. namespace Gfx {
  18. template<typename T>
  19. T abst(T value)
  20. {
  21. return value < 0 ? -value : value;
  22. }
  23. template<typename T>
  24. class Rect {
  25. public:
  26. Rect() = default;
  27. Rect(T x, T y, T width, T height)
  28. : m_location(x, y)
  29. , m_size(width, height)
  30. {
  31. }
  32. template<typename U>
  33. Rect(U x, U y, U width, U height)
  34. : m_location(x, y)
  35. , m_size(width, height)
  36. {
  37. }
  38. Rect(Point<T> const& location, Size<T> const& size)
  39. : m_location(location)
  40. , m_size(size)
  41. {
  42. }
  43. template<typename U>
  44. Rect(Point<U> const& location, Size<U> const& size)
  45. : m_location(location)
  46. , m_size(size)
  47. {
  48. }
  49. template<typename U>
  50. explicit Rect(Rect<U> const& other)
  51. : m_location(other.location())
  52. , m_size(other.size())
  53. {
  54. }
  55. [[nodiscard]] ALWAYS_INLINE T x() const { return location().x(); }
  56. [[nodiscard]] ALWAYS_INLINE T y() const { return location().y(); }
  57. [[nodiscard]] ALWAYS_INLINE T width() const { return m_size.width(); }
  58. [[nodiscard]] ALWAYS_INLINE T height() const { return m_size.height(); }
  59. ALWAYS_INLINE void set_x(T x) { m_location.set_x(x); }
  60. ALWAYS_INLINE void set_y(T y) { m_location.set_y(y); }
  61. ALWAYS_INLINE void set_width(T width) { m_size.set_width(width); }
  62. ALWAYS_INLINE void set_height(T height) { m_size.set_height(height); }
  63. [[nodiscard]] ALWAYS_INLINE Point<T> const& location() const { return m_location; }
  64. [[nodiscard]] ALWAYS_INLINE Size<T> const& size() const { return m_size; }
  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(T width, T height)
  90. {
  91. m_size.set_width(width);
  92. m_size.set_height(height);
  93. }
  94. void inflate(T w, T h)
  95. {
  96. set_x(x() - w / 2);
  97. set_width(width() + w);
  98. set_y(y() - h / 2);
  99. set_height(height() + h);
  100. }
  101. void inflate(T top, T right, T bottom, T left)
  102. {
  103. set_x(x() - left);
  104. set_width(width() + left + right);
  105. set_y(y() - top);
  106. set_height(height() + top + bottom);
  107. }
  108. void inflate(Size<T> const& size)
  109. {
  110. set_x(x() - size.width() / 2);
  111. set_width(width() + size.width());
  112. set_y(y() - size.height() / 2);
  113. set_height(height() + size.height());
  114. }
  115. void shrink(T w, T h)
  116. {
  117. set_x(x() + w / 2);
  118. set_width(width() - w);
  119. set_y(y() + h / 2);
  120. set_height(height() - h);
  121. }
  122. void shrink(T top, T right, T bottom, T left)
  123. {
  124. set_x(x() + left);
  125. set_width(width() - (left + right));
  126. set_y(y() + top);
  127. set_height(height() - (top + bottom));
  128. }
  129. void shrink(Size<T> const& size)
  130. {
  131. set_x(x() + size.width() / 2);
  132. set_width(width() - size.width());
  133. set_y(y() + size.height() / 2);
  134. set_height(height() - size.height());
  135. }
  136. [[nodiscard]] Rect<T> translated(T dx, T dy) const
  137. {
  138. Rect<T> rect = *this;
  139. rect.translate_by(dx, dy);
  140. return rect;
  141. }
  142. [[nodiscard]] Rect<T> translated(T dboth) const
  143. {
  144. Rect<T> rect = *this;
  145. rect.translate_by(dboth);
  146. return rect;
  147. }
  148. [[nodiscard]] Rect<T> translated(Point<T> const& delta) const
  149. {
  150. Rect<T> rect = *this;
  151. rect.translate_by(delta);
  152. return rect;
  153. }
  154. [[nodiscard]] Rect<T> scaled(T sx, T sy) const
  155. {
  156. Rect<T> rect = *this;
  157. rect.scale_by(sx, sy);
  158. return rect;
  159. }
  160. [[nodiscard]] Rect<T> scaled(Point<T> const& s) const
  161. {
  162. Rect<T> rect = *this;
  163. rect.scale_by(s);
  164. return rect;
  165. }
  166. [[nodiscard]] Rect<T> transformed(AffineTransform const& transform) const
  167. {
  168. Rect<T> rect = *this;
  169. rect.transform_by(transform);
  170. return rect;
  171. }
  172. [[nodiscard]] Rect<T> shrunken(T w, T h) const
  173. {
  174. Rect<T> rect = *this;
  175. rect.shrink(w, h);
  176. return rect;
  177. }
  178. [[nodiscard]] Rect<T> shrunken(T top, T right, T bottom, T left) const
  179. {
  180. Rect<T> rect = *this;
  181. rect.shrink(top, right, bottom, left);
  182. return rect;
  183. }
  184. [[nodiscard]] Rect<T> shrunken(Size<T> const& size) const
  185. {
  186. Rect<T> rect = *this;
  187. rect.shrink(size);
  188. return rect;
  189. }
  190. [[nodiscard]] Rect<T> inflated(T w, T h) const
  191. {
  192. Rect<T> rect = *this;
  193. rect.inflate(w, h);
  194. return rect;
  195. }
  196. [[nodiscard]] Rect<T> inflated(T top, T right, T bottom, T left) const
  197. {
  198. Rect<T> rect = *this;
  199. rect.inflate(top, right, bottom, left);
  200. return rect;
  201. }
  202. [[nodiscard]] Rect<T> inflated(Size<T> const& size) const
  203. {
  204. Rect<T> rect = *this;
  205. rect.inflate(size);
  206. return rect;
  207. }
  208. Rect<T> take_from_right(T w)
  209. {
  210. if (w > width())
  211. w = width();
  212. Rect<T> rect = *this;
  213. set_width(width() - w);
  214. rect.set_x(x() + width());
  215. rect.set_width(w);
  216. return rect;
  217. }
  218. Rect<T> take_from_left(T w)
  219. {
  220. if (w > width())
  221. w = width();
  222. Rect<T> rect = *this;
  223. set_x(x() + w);
  224. set_width(width() - w);
  225. rect.set_width(w);
  226. return rect;
  227. }
  228. Rect<T> take_from_top(T h)
  229. {
  230. if (h > height())
  231. h = height();
  232. Rect<T> rect = *this;
  233. set_y(y() + h);
  234. set_height(height() - h);
  235. rect.set_height(h);
  236. return rect;
  237. }
  238. Rect<T> take_from_bottom(T h)
  239. {
  240. if (h > height())
  241. h = height();
  242. Rect<T> rect = *this;
  243. set_height(height() - h);
  244. rect.set_y(y() + height());
  245. rect.set_height(h);
  246. return rect;
  247. }
  248. [[nodiscard]] bool contains_vertically(T y) const
  249. {
  250. return y >= top() && y <= bottom();
  251. }
  252. [[nodiscard]] bool contains_horizontally(T x) const
  253. {
  254. return x >= left() && x <= right();
  255. }
  256. [[nodiscard]] bool contains(T x, T y) const
  257. {
  258. return x >= m_location.x() && x <= right() && y >= m_location.y() && y <= bottom();
  259. }
  260. [[nodiscard]] ALWAYS_INLINE bool contains(Point<T> const& point) const
  261. {
  262. return contains(point.x(), point.y());
  263. }
  264. [[nodiscard]] bool contains(Rect<T> const& other) const
  265. {
  266. return left() <= other.left()
  267. && right() >= other.right()
  268. && top() <= other.top()
  269. && bottom() >= other.bottom();
  270. }
  271. template<typename Container>
  272. [[nodiscard]] bool contains(Container const& others) const
  273. {
  274. bool have_any = false;
  275. for (auto const& other : others) {
  276. if (!contains(other))
  277. return false;
  278. have_any = true;
  279. }
  280. return have_any;
  281. }
  282. [[nodiscard]] ALWAYS_INLINE T primary_offset_for_orientation(Orientation orientation) const { return m_location.primary_offset_for_orientation(orientation); }
  283. ALWAYS_INLINE void set_primary_offset_for_orientation(Orientation orientation, T value) { m_location.set_primary_offset_for_orientation(orientation, value); }
  284. [[nodiscard]] ALWAYS_INLINE T secondary_offset_for_orientation(Orientation orientation) const { return m_location.secondary_offset_for_orientation(orientation); }
  285. ALWAYS_INLINE void set_secondary_offset_for_orientation(Orientation orientation, T value) { m_location.set_secondary_offset_for_orientation(orientation, value); }
  286. [[nodiscard]] ALWAYS_INLINE T primary_size_for_orientation(Orientation orientation) const { return m_size.primary_size_for_orientation(orientation); }
  287. [[nodiscard]] ALWAYS_INLINE T secondary_size_for_orientation(Orientation orientation) const { return m_size.secondary_size_for_orientation(orientation); }
  288. ALWAYS_INLINE void set_primary_size_for_orientation(Orientation orientation, T value) { m_size.set_primary_size_for_orientation(orientation, value); }
  289. ALWAYS_INLINE void set_secondary_size_for_orientation(Orientation orientation, T value) { m_size.set_secondary_size_for_orientation(orientation, value); }
  290. [[nodiscard]] T first_edge_for_orientation(Orientation orientation) const
  291. {
  292. if (orientation == Orientation::Vertical)
  293. return top();
  294. return left();
  295. }
  296. [[nodiscard]] T last_edge_for_orientation(Orientation orientation) const
  297. {
  298. if (orientation == Orientation::Vertical)
  299. return bottom();
  300. return right();
  301. }
  302. [[nodiscard]] ALWAYS_INLINE T left() const { return x(); }
  303. [[nodiscard]] ALWAYS_INLINE T right() const { return x() + width() - 1; }
  304. [[nodiscard]] ALWAYS_INLINE T top() const { return y(); }
  305. [[nodiscard]] ALWAYS_INLINE T bottom() const { return y() + height() - 1; }
  306. ALWAYS_INLINE void set_left(T left)
  307. {
  308. set_x(left);
  309. }
  310. ALWAYS_INLINE void set_top(T top)
  311. {
  312. set_y(top);
  313. }
  314. ALWAYS_INLINE void set_right(T right)
  315. {
  316. set_width(right - x() + 1);
  317. }
  318. ALWAYS_INLINE void set_bottom(T bottom)
  319. {
  320. set_height(bottom - y() + 1);
  321. }
  322. void set_right_without_resize(T new_right)
  323. {
  324. auto delta = new_right - right();
  325. translate_by(delta, 0);
  326. }
  327. void set_bottom_without_resize(T new_bottom)
  328. {
  329. auto delta = new_bottom - bottom();
  330. translate_by(0, delta);
  331. }
  332. [[nodiscard]] bool intersects_vertically(Rect<T> const& other) const
  333. {
  334. return top() <= other.bottom() && other.top() <= bottom();
  335. }
  336. [[nodiscard]] bool intersects_horizontally(Rect<T> const& other) const
  337. {
  338. return left() <= other.right() && other.left() <= right();
  339. }
  340. [[nodiscard]] bool intersects(Rect<T> const& other) const
  341. {
  342. return left() <= other.right()
  343. && other.left() <= right()
  344. && top() <= other.bottom()
  345. && other.top() <= bottom();
  346. }
  347. template<typename Container>
  348. [[nodiscard]] bool intersects(Container const& others) const
  349. {
  350. for (auto const& other : others) {
  351. if (intersects(other))
  352. return true;
  353. }
  354. return false;
  355. }
  356. template<typename Container, typename Function>
  357. IterationDecision for_each_intersected(Container const& others, Function f) const
  358. {
  359. if (is_empty())
  360. return IterationDecision::Continue;
  361. for (auto const& other : others) {
  362. auto intersected_rect = intersected(other);
  363. if (!intersected_rect.is_empty()) {
  364. IterationDecision decision = f(intersected_rect);
  365. if (decision != IterationDecision::Continue)
  366. return decision;
  367. }
  368. }
  369. return IterationDecision::Continue;
  370. }
  371. [[nodiscard]] Vector<Rect<T>, 4> shatter(Rect<T> const& hammer) const
  372. {
  373. Vector<Rect<T>, 4> pieces;
  374. if (!intersects(hammer)) {
  375. pieces.unchecked_append(*this);
  376. return pieces;
  377. }
  378. Rect<T> top_shard {
  379. x(),
  380. y(),
  381. width(),
  382. hammer.y() - y()
  383. };
  384. Rect<T> bottom_shard {
  385. x(),
  386. hammer.y() + hammer.height(),
  387. width(),
  388. (y() + height()) - (hammer.y() + hammer.height())
  389. };
  390. Rect<T> left_shard {
  391. x(),
  392. max(hammer.y(), y()),
  393. hammer.x() - x(),
  394. min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
  395. };
  396. Rect<T> right_shard {
  397. hammer.x() + hammer.width(),
  398. max(hammer.y(), y()),
  399. right() - hammer.right(),
  400. min((hammer.y() + hammer.height()), (y() + height())) - max(hammer.y(), y())
  401. };
  402. if (!top_shard.is_empty())
  403. pieces.unchecked_append(top_shard);
  404. if (!bottom_shard.is_empty())
  405. pieces.unchecked_append(bottom_shard);
  406. if (!left_shard.is_empty())
  407. pieces.unchecked_append(left_shard);
  408. if (!right_shard.is_empty())
  409. pieces.unchecked_append(right_shard);
  410. return pieces;
  411. }
  412. template<class U>
  413. [[nodiscard]] bool operator==(Rect<U> const& other) const
  414. {
  415. return location() == other.location() && size() == other.size();
  416. }
  417. [[nodiscard]] Rect<T> operator*(T factor) const { return { m_location * factor, m_size * factor }; }
  418. Rect<T>& operator*=(T factor)
  419. {
  420. m_location *= factor;
  421. m_size *= factor;
  422. return *this;
  423. }
  424. void intersect(Rect<T> const& other)
  425. {
  426. T l = max(left(), other.left());
  427. T r = min(right(), other.right());
  428. T t = max(top(), other.top());
  429. T b = min(bottom(), other.bottom());
  430. if (l > r || t > b) {
  431. m_location = {};
  432. m_size = {};
  433. return;
  434. }
  435. m_location.set_x(l);
  436. m_location.set_y(t);
  437. m_size.set_width((r - l) + 1);
  438. m_size.set_height((b - t) + 1);
  439. }
  440. [[nodiscard]] static Rect<T> centered_on(Point<T> const& center, Size<T> const& size)
  441. {
  442. return { { center.x() - size.width() / 2, center.y() - size.height() / 2 }, size };
  443. }
  444. [[nodiscard]] static Rect<T> from_two_points(Point<T> const& a, Point<T> const& b)
  445. {
  446. return { min(a.x(), b.x()), min(a.y(), b.y()), abst(a.x() - b.x()), abst(a.y() - b.y()) };
  447. }
  448. [[nodiscard]] static Rect<T> intersection(Rect<T> const& a, Rect<T> const& b)
  449. {
  450. Rect<T> r = a;
  451. r.intersect(b);
  452. return r;
  453. }
  454. [[nodiscard]] ALWAYS_INLINE Rect<T> intersected(Rect<T> const& other) const
  455. {
  456. return intersection(*this, other);
  457. }
  458. [[nodiscard]] Vector<Point<T>, 2> intersected(Line<T> const& line) const
  459. {
  460. if (is_empty())
  461. return {};
  462. Vector<Point<T>, 2> points;
  463. if (auto point = line.intersected({ top_left(), top_right() }); point.has_value())
  464. points.append({ point.value().x(), y() });
  465. if (auto point = line.intersected({ bottom_left(), bottom_right() }); point.has_value()) {
  466. points.append({ point.value().x(), bottom() });
  467. if (points.size() == 2)
  468. return points;
  469. }
  470. if (height() > 2) {
  471. if (auto point = line.intersected({ { x(), y() + 1 }, { x(), bottom() - 1 } }); point.has_value()) {
  472. points.append({ x(), point.value().y() });
  473. if (points.size() == 2)
  474. return points;
  475. }
  476. if (auto point = line.intersected({ { right(), y() + 1 }, { right(), bottom() - 1 } }); point.has_value())
  477. points.append({ right(), point.value().y() });
  478. }
  479. return points;
  480. }
  481. template<typename U = T>
  482. [[nodiscard]] Gfx::Rect<U> interpolated_to(Gfx::Rect<T> const& to, float factor) const
  483. {
  484. VERIFY(factor >= 0.0f);
  485. VERIFY(factor <= 1.0f);
  486. if (factor == 0.0f)
  487. return *this;
  488. if (factor == 1.0f)
  489. return to;
  490. if (this == &to)
  491. return *this;
  492. auto interpolated_left = round_to<U>(mix<float>(x(), to.x(), factor));
  493. auto interpolated_top = round_to<U>(mix<float>(y(), to.y(), factor));
  494. auto interpolated_right = round_to<U>(mix<float>(right(), to.right(), factor));
  495. auto interpolated_bottom = round_to<U>(mix<float>(bottom(), to.bottom(), factor));
  496. return { interpolated_left, interpolated_top, interpolated_right - interpolated_left + 1, interpolated_bottom - interpolated_top + 1 };
  497. }
  498. [[nodiscard]] float center_point_distance_to(Rect<T> const& other) const
  499. {
  500. return Line { center(), other.center() }.length();
  501. }
  502. [[nodiscard]] Vector<Point<T>, 2> closest_outside_center_points(Rect<T> const& other) const
  503. {
  504. if (intersects(other))
  505. return {};
  506. Line centers_line { center(), other.center() };
  507. auto points_this = intersected(centers_line);
  508. VERIFY(points_this.size() == 1);
  509. auto points_other = other.intersected(centers_line);
  510. VERIFY(points_other.size() == 1);
  511. return { points_this[0], points_other[0] };
  512. }
  513. [[nodiscard]] float outside_center_point_distance_to(Rect<T> const& other) const
  514. {
  515. auto points = closest_outside_center_points(other);
  516. if (points.is_empty())
  517. return 0.0;
  518. return Line { points[0], points[0] }.length();
  519. }
  520. [[nodiscard]] Rect<T> constrained_to(Rect<T> const& constrain_rect) const
  521. {
  522. if (constrain_rect.contains(*this))
  523. return *this;
  524. T move_x = 0, move_y = 0;
  525. if (right() > constrain_rect.right())
  526. move_x = constrain_rect.right() - right();
  527. if (bottom() > constrain_rect.bottom())
  528. move_y = constrain_rect.bottom() - bottom();
  529. if (x() < constrain_rect.x())
  530. move_x = x() - constrain_rect.x();
  531. if (y() < constrain_rect.y())
  532. move_y = y() - constrain_rect.y();
  533. auto rect = *this;
  534. if (move_x != 0 || move_y != 0)
  535. rect.translate_by(move_x, move_y);
  536. return rect;
  537. }
  538. [[nodiscard]] Rect<T> aligned_within(Size<T> const& rect_size, Point<T> const& align_at, TextAlignment alignment = TextAlignment::Center) const
  539. {
  540. if (rect_size.is_empty())
  541. return {};
  542. if (!size().contains(rect_size))
  543. return {};
  544. if (!contains(align_at))
  545. return {};
  546. Rect<T> rect;
  547. switch (alignment) {
  548. case TextAlignment::TopCenter:
  549. rect = { { align_at.x() - rect_size.width() / 2, align_at.y() }, rect_size };
  550. break;
  551. case TextAlignment::TopLeft:
  552. rect = { align_at, rect_size };
  553. break;
  554. case TextAlignment::TopRight:
  555. rect = { { align_at.x() - rect_size.width(), align_at.y() }, rect_size };
  556. break;
  557. case TextAlignment::CenterLeft:
  558. rect = { { align_at.x(), align_at.y() - rect_size.height() / 2 }, rect_size };
  559. break;
  560. case TextAlignment::Center:
  561. rect = { { align_at.x() - rect_size.width() / 2, align_at.y() - rect_size.height() / 2 }, rect_size };
  562. break;
  563. case TextAlignment::CenterRight:
  564. rect = { { align_at.x() - rect_size.width() / 2, align_at.y() }, rect_size };
  565. break;
  566. case TextAlignment::BottomCenter:
  567. rect = { { align_at.x() - rect_size.width() / 2, align_at.y() - rect_size.width() }, rect_size };
  568. break;
  569. case TextAlignment::BottomLeft:
  570. rect = { { align_at.x(), align_at.y() - rect_size.width() }, rect_size };
  571. break;
  572. case TextAlignment::BottomRight:
  573. rect = { { align_at.x() - rect_size.width(), align_at.y() - rect_size.width() }, rect_size };
  574. break;
  575. }
  576. return rect.constrained_to(*this);
  577. }
  578. [[nodiscard]] Point<T> closest_to(Point<T> const& point) const
  579. {
  580. if (is_empty())
  581. return {};
  582. Optional<Point<T>> closest_point;
  583. float closest_distance = 0.0;
  584. auto check_distance = [&](Line<T> const& line) {
  585. auto point_on_line = line.closest_to(point);
  586. auto distance = Line { point_on_line, point }.length();
  587. if (!closest_point.has_value() || distance < closest_distance) {
  588. closest_point = point_on_line;
  589. closest_distance = distance;
  590. }
  591. };
  592. check_distance({ top_left(), top_right() });
  593. check_distance({ bottom_left(), bottom_right() });
  594. if (height() > 2) {
  595. check_distance({ { x(), y() + 1 }, { x(), bottom() - 1 } });
  596. check_distance({ { right(), y() + 1 }, { right(), bottom() - 1 } });
  597. }
  598. VERIFY(closest_point.has_value());
  599. VERIFY(side(closest_point.value()) != Side::None);
  600. return closest_point.value();
  601. }
  602. class RelativeLocation {
  603. friend class Rect<T>;
  604. RelativeLocation(Rect<T> const& base_rect, Rect<T> const& other_rect)
  605. {
  606. if (base_rect.is_empty() || other_rect.is_empty())
  607. return;
  608. auto parts = base_rect.shatter(other_rect);
  609. for (auto& part : parts) {
  610. if (part.x() < other_rect.x()) {
  611. if (part.y() < other_rect.y())
  612. m_top_left = true;
  613. if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom()) || (part.y() <= other_rect.bottom() && part.bottom() > other_rect.y()))
  614. m_left = true;
  615. if (part.y() >= other_rect.bottom() || part.bottom() > other_rect.y())
  616. m_bottom_left = true;
  617. }
  618. if (part.x() >= other_rect.x() || part.right() > other_rect.x()) {
  619. if (part.y() < other_rect.y())
  620. m_top = true;
  621. if (part.y() >= other_rect.bottom() || part.bottom() > other_rect.bottom())
  622. m_bottom = true;
  623. }
  624. if (part.x() >= other_rect.right() || part.right() > other_rect.right()) {
  625. if (part.y() < other_rect.y())
  626. m_top_right = true;
  627. if ((part.y() >= other_rect.y() && part.y() < other_rect.bottom()) || (part.y() <= other_rect.bottom() && part.bottom() > other_rect.y()))
  628. m_right = true;
  629. if (part.y() >= other_rect.bottom() || part.bottom() > other_rect.y())
  630. m_bottom_right = true;
  631. }
  632. }
  633. }
  634. public:
  635. RelativeLocation() = default;
  636. bool top_left() const { return m_top_left; }
  637. bool top() const { return m_top; }
  638. bool top_right() const { return m_top_right; }
  639. bool left() const { return m_left; }
  640. bool right() const { return m_right; }
  641. bool bottom_left() const { return m_bottom_left; }
  642. bool bottom() const { return m_bottom; }
  643. bool bottom_right() const { return m_bottom_right; }
  644. bool anywhere_above() const { return m_top_left || m_top || m_top_right; }
  645. bool anywhere_below() const { return m_bottom_left || m_bottom || m_bottom_right; }
  646. bool anywhere_left() const { return m_top_left || m_left || m_bottom_left; }
  647. bool anywhere_right() const { return m_top_right || m_right || m_bottom_right; }
  648. private:
  649. bool m_top_left : 1 { false };
  650. bool m_top : 1 { false };
  651. bool m_top_right : 1 { false };
  652. bool m_left : 1 { false };
  653. bool m_right : 1 { false };
  654. bool m_bottom_left : 1 { false };
  655. bool m_bottom : 1 { false };
  656. bool m_bottom_right : 1 { false };
  657. };
  658. [[nodiscard]] RelativeLocation relative_location_to(Rect<T> const& other) const
  659. {
  660. return RelativeLocation(*this, other);
  661. }
  662. enum class Side {
  663. None = 0,
  664. Left,
  665. Top,
  666. Right,
  667. Bottom
  668. };
  669. [[nodiscard]] Side side(Point<T> const& point) const
  670. {
  671. if (is_empty())
  672. return Side::None;
  673. if (point.y() == y() || point.y() == bottom())
  674. return (point.x() >= x() && point.x() <= right()) ? (point.y() == y() ? Side::Top : Side::Bottom) : Side::None;
  675. if (point.x() == x() || point.x() == right())
  676. return (point.y() > y() && point.y() < bottom()) ? (point.x() == x() ? Side::Left : Side::Right) : Side::None;
  677. return Side::None;
  678. }
  679. [[nodiscard]] Rect<T> rect_on_side(Side side, Rect<T> const& other) const
  680. {
  681. switch (side) {
  682. case Side::None:
  683. break;
  684. case Side::Left:
  685. // Return the area in other that is to the left of this rect
  686. if (other.x() < x()) {
  687. if (other.right() >= x())
  688. return { other.location(), { x() - other.x(), other.height() } };
  689. else
  690. return other;
  691. }
  692. break;
  693. case Side::Top:
  694. // Return the area in other that is above this rect
  695. if (other.y() < y()) {
  696. if (other.bottom() >= y())
  697. return { other.location(), { other.width(), y() - other.y() } };
  698. else
  699. return other;
  700. }
  701. break;
  702. case Side::Right:
  703. // Return the area in other that is to the right of this rect
  704. if (other.right() >= x()) {
  705. if (other.x() <= right())
  706. return { { right() + 1, other.y() }, { other.width() - (right() - other.x()), other.height() } };
  707. else
  708. return other;
  709. }
  710. break;
  711. case Side::Bottom:
  712. // Return the area in other that is below this rect
  713. if (other.bottom() >= y()) {
  714. if (other.y() <= bottom())
  715. return { { other.x(), bottom() + 1 }, { other.width(), other.height() - (bottom() - other.y()) } };
  716. else
  717. return other;
  718. }
  719. break;
  720. }
  721. return {};
  722. }
  723. template<typename Container>
  724. static bool disperse(Container& rects)
  725. {
  726. auto has_intersecting = [&]() {
  727. for (auto& rect : rects) {
  728. for (auto& other_rect : rects) {
  729. if (&rect == &other_rect)
  730. continue;
  731. if (rect.intersects(other_rect))
  732. return true;
  733. }
  734. }
  735. return false;
  736. };
  737. if (!has_intersecting())
  738. return false;
  739. auto calc_delta = [&](Rect<T> const& rect) -> Point<T> {
  740. auto rect_center = rect.center();
  741. Point<T> center_sum;
  742. for (auto& other_rect : rects) {
  743. if (&other_rect == &rect)
  744. continue;
  745. if (rect.intersects(other_rect))
  746. center_sum += rect_center - other_rect.center();
  747. }
  748. double m = sqrt((double)center_sum.x() * (double)center_sum.x() + (double)center_sum.y() * (double)center_sum.y());
  749. if (m != 0.0)
  750. return { (double)center_sum.x() / m + 0.5, (double)center_sum.y() / m + 0.5 };
  751. return {};
  752. };
  753. Vector<Point<T>, 8> deltas;
  754. do {
  755. bool changes = false;
  756. deltas.clear_with_capacity();
  757. for (auto& rect : rects) {
  758. auto delta = calc_delta(rect);
  759. if (!delta.is_zero())
  760. changes = true;
  761. deltas.append(delta);
  762. }
  763. // TODO: If we have no changes we would loop infinitely!
  764. // Figure out some way to resolve this. Maybe randomly moving an intersecting rect?
  765. VERIFY(changes);
  766. size_t i = 0;
  767. for (auto& rect : rects)
  768. rect.translate_by(deltas[i++]);
  769. } while (has_intersecting());
  770. return true;
  771. }
  772. [[nodiscard]] bool is_adjacent(Rect<T> const& other) const
  773. {
  774. if (is_empty() || other.is_empty())
  775. return false;
  776. if (intersects(other))
  777. return false;
  778. if (other.x() + other.width() == x() || other.x() == x() + width())
  779. return max(top(), other.top()) <= min(bottom(), other.bottom());
  780. if (other.y() + other.height() == y() || other.y() == y() + height())
  781. return max(left(), other.left()) <= min(right(), other.right());
  782. return false;
  783. }
  784. [[nodiscard]] static Rect<T> centered_at(Point<T> const& point, Size<T> const& size)
  785. {
  786. return { { point.x() - size.width() / 2, point.y() - size.height() / 2 }, size };
  787. }
  788. [[nodiscard]] Rect<T> united(Rect<T> const& other) const
  789. {
  790. if (is_empty())
  791. return other;
  792. if (other.is_empty())
  793. return *this;
  794. Rect<T> rect;
  795. rect.set_left(min(left(), other.left()));
  796. rect.set_top(min(top(), other.top()));
  797. rect.set_right(max(right(), other.right()));
  798. rect.set_bottom(max(bottom(), other.bottom()));
  799. return rect;
  800. }
  801. [[nodiscard]] Point<T> top_left() const { return { left(), top() }; }
  802. [[nodiscard]] Point<T> top_right() const { return { right(), top() }; }
  803. [[nodiscard]] Point<T> bottom_left() const { return { left(), bottom() }; }
  804. [[nodiscard]] Point<T> bottom_right() const { return { right(), bottom() }; }
  805. void align_within(Rect<T> const& other, TextAlignment alignment)
  806. {
  807. switch (alignment) {
  808. case TextAlignment::Center:
  809. center_within(other);
  810. return;
  811. case TextAlignment::TopCenter:
  812. center_horizontally_within(other);
  813. set_y(other.y());
  814. return;
  815. case TextAlignment::TopLeft:
  816. set_location(other.location());
  817. return;
  818. case TextAlignment::TopRight:
  819. set_x(other.x() + other.width() - width());
  820. set_y(other.y());
  821. return;
  822. case TextAlignment::CenterLeft:
  823. set_x(other.x());
  824. center_vertically_within(other);
  825. return;
  826. case TextAlignment::CenterRight:
  827. set_x(other.x() + other.width() - width());
  828. center_vertically_within(other);
  829. return;
  830. case TextAlignment::BottomCenter:
  831. center_horizontally_within(other);
  832. set_y(other.y() + other.height() - height());
  833. return;
  834. case TextAlignment::BottomLeft:
  835. set_x(other.x());
  836. set_y(other.y() + other.height() - height());
  837. return;
  838. case TextAlignment::BottomRight:
  839. set_x(other.x() + other.width() - width());
  840. set_y(other.y() + other.height() - height());
  841. return;
  842. }
  843. }
  844. void center_within(Rect<T> const& other)
  845. {
  846. center_horizontally_within(other);
  847. center_vertically_within(other);
  848. }
  849. [[nodiscard]] Rect centered_within(Rect const& other) const
  850. {
  851. Rect rect { *this };
  852. rect.center_horizontally_within(other);
  853. rect.center_vertically_within(other);
  854. return rect;
  855. }
  856. void center_horizontally_within(Rect<T> const& other)
  857. {
  858. set_x(other.center().x() - width() / 2);
  859. }
  860. void center_vertically_within(Rect<T> const& other)
  861. {
  862. set_y(other.center().y() - height() / 2);
  863. }
  864. template<typename U>
  865. requires(!IsSame<T, U>)
  866. [[nodiscard]] ALWAYS_INLINE Rect<U> to_type() const
  867. {
  868. return Rect<U>(*this);
  869. }
  870. template<FloatingPoint U>
  871. [[nodiscard]] ALWAYS_INLINE Rect<U> to_rounded() const
  872. {
  873. // FIXME: We may get away with `rint[lf]?()` here.
  874. // This would even give us some more control of these internals,
  875. // while the break-tie algorithm does not really matter
  876. if constexpr (IsSame<T, float>) {
  877. return {
  878. static_cast<U>(roundf(x())),
  879. static_cast<U>(roundf(y())),
  880. static_cast<U>(roundf(width())),
  881. static_cast<U>(roundf(height())),
  882. };
  883. }
  884. if constexpr (IsSame<T, double>) {
  885. return {
  886. static_cast<U>(round(x())),
  887. static_cast<U>(round(y())),
  888. static_cast<U>(round(width())),
  889. static_cast<U>(round(height())),
  890. };
  891. }
  892. return {
  893. static_cast<U>(roundl(x())),
  894. static_cast<U>(roundl(y())),
  895. static_cast<U>(roundl(width())),
  896. static_cast<U>(roundl(height())),
  897. };
  898. }
  899. template<Integral I>
  900. ALWAYS_INLINE Rect<I> to_rounded() const
  901. {
  902. return {
  903. round_to<I>(x()),
  904. round_to<I>(y()),
  905. round_to<I>(width()),
  906. round_to<I>(height()),
  907. };
  908. }
  909. [[nodiscard]] DeprecatedString to_deprecated_string() const;
  910. private:
  911. Point<T> m_location;
  912. Size<T> m_size;
  913. };
  914. using IntRect = Rect<int>;
  915. using FloatRect = Rect<float>;
  916. [[nodiscard]] ALWAYS_INLINE IntRect enclosing_int_rect(FloatRect const& float_rect)
  917. {
  918. int x1 = floorf(float_rect.x());
  919. int y1 = floorf(float_rect.y());
  920. int x2 = ceilf(float_rect.x() + float_rect.width());
  921. int y2 = ceilf(float_rect.y() + float_rect.height());
  922. return Gfx::IntRect::from_two_points({ x1, y1 }, { x2, y2 });
  923. }
  924. }
  925. namespace AK {
  926. template<typename T>
  927. struct Formatter<Gfx::Rect<T>> : Formatter<FormatString> {
  928. ErrorOr<void> format(FormatBuilder& builder, Gfx::Rect<T> const& value)
  929. {
  930. return Formatter<FormatString>::format(builder, "[{},{} {}x{}]"sv, value.x(), value.y(), value.width(), value.height());
  931. }
  932. };
  933. }
  934. namespace IPC {
  935. template<>
  936. ErrorOr<void> encode(Encoder&, Gfx::IntRect const&);
  937. template<>
  938. ErrorOr<Gfx::IntRect> decode(Decoder&);
  939. }