Size.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Format.h>
  8. #include <LibGfx/Orientation.h>
  9. #include <LibGfx/Point.h>
  10. #include <LibIPC/Forward.h>
  11. namespace Gfx {
  12. template<typename T>
  13. class Size {
  14. public:
  15. constexpr Size() = default;
  16. constexpr Size(T w, T h)
  17. : m_width(w)
  18. , m_height(h)
  19. {
  20. }
  21. template<typename U>
  22. constexpr Size(U width, U height)
  23. : m_width(width)
  24. , m_height(height)
  25. {
  26. }
  27. template<typename U>
  28. explicit constexpr Size(Size<U> const& other)
  29. : m_width(other.width())
  30. , m_height(other.height())
  31. {
  32. }
  33. [[nodiscard]] ALWAYS_INLINE constexpr T width() const { return m_width; }
  34. [[nodiscard]] ALWAYS_INLINE constexpr T height() const { return m_height; }
  35. [[nodiscard]] ALWAYS_INLINE constexpr T area() const { return width() * height(); }
  36. ALWAYS_INLINE constexpr void set_width(T w) { m_width = w; }
  37. ALWAYS_INLINE constexpr void set_height(T h) { m_height = h; }
  38. [[nodiscard]] ALWAYS_INLINE constexpr bool is_empty() const { return m_width <= 0 || m_height <= 0; }
  39. constexpr void scale_by(T dx, T dy)
  40. {
  41. m_width *= dx;
  42. m_height *= dy;
  43. }
  44. constexpr void transform_by(AffineTransform const& transform) { *this = transform.map(*this); }
  45. ALWAYS_INLINE constexpr void scale_by(T dboth) { scale_by(dboth, dboth); }
  46. ALWAYS_INLINE constexpr void scale_by(Point<T> const& s) { scale_by(s.x(), s.y()); }
  47. [[nodiscard]] constexpr Size scaled(T dx, T dy) const
  48. {
  49. Size<T> size = *this;
  50. size.scale_by(dx, dy);
  51. return size;
  52. }
  53. [[nodiscard]] constexpr Size scaled(T dboth) const
  54. {
  55. Size<T> size = *this;
  56. size.scale_by(dboth);
  57. return size;
  58. }
  59. [[nodiscard]] constexpr Size scaled(Point<T> const& s) const
  60. {
  61. Size<T> size = *this;
  62. size.scale_by(s);
  63. return size;
  64. }
  65. [[nodiscard]] constexpr Size transformed_by(AffineTransform const& transform) const
  66. {
  67. Size<T> size = *this;
  68. size.transform_by(transform);
  69. return size;
  70. }
  71. [[nodiscard]] constexpr float aspect_ratio() const
  72. {
  73. VERIFY(height() != 0);
  74. return static_cast<float>(width()) / static_cast<float>(height());
  75. }
  76. // Horizontal means preserve the width, Vertical means preserve the height.
  77. [[nodiscard]] constexpr Size<T> match_aspect_ratio(float aspect_ratio, Orientation side_to_preserve) const
  78. {
  79. VERIFY(aspect_ratio != 0.0f);
  80. auto matched = *this;
  81. auto height_corresponding_to_width = static_cast<T>(static_cast<float>(width()) / aspect_ratio);
  82. auto width_corresponding_to_height = static_cast<T>(static_cast<float>(height()) * aspect_ratio);
  83. switch (side_to_preserve) {
  84. case Orientation::Vertical:
  85. matched.m_width = width_corresponding_to_height;
  86. break;
  87. case Orientation::Horizontal:
  88. matched.m_height = height_corresponding_to_width;
  89. break;
  90. }
  91. return matched;
  92. }
  93. template<typename U>
  94. [[nodiscard]] constexpr bool contains(Size<U> const& other) const
  95. {
  96. return other.m_width <= m_width && other.m_height <= m_height;
  97. }
  98. template<class U>
  99. [[nodiscard]] constexpr bool operator==(Size<U> const& other) const
  100. {
  101. return width() == other.width() && height() == other.height();
  102. }
  103. constexpr Size<T>& operator-=(Size<T> const& other)
  104. {
  105. m_width -= other.m_width;
  106. m_height -= other.m_height;
  107. return *this;
  108. }
  109. Size<T>& operator+=(Size<T> const& other)
  110. {
  111. m_width += other.m_width;
  112. m_height += other.m_height;
  113. return *this;
  114. }
  115. [[nodiscard]] constexpr Size<T> operator*(T factor) const { return { m_width * factor, m_height * factor }; }
  116. constexpr Size<T>& operator*=(T factor)
  117. {
  118. m_width *= factor;
  119. m_height *= factor;
  120. return *this;
  121. }
  122. [[nodiscard]] constexpr T primary_size_for_orientation(Orientation orientation) const
  123. {
  124. return orientation == Orientation::Vertical ? height() : width();
  125. }
  126. constexpr void set_primary_size_for_orientation(Orientation orientation, T value)
  127. {
  128. if (orientation == Orientation::Vertical) {
  129. set_height(value);
  130. } else {
  131. set_width(value);
  132. }
  133. }
  134. [[nodiscard]] constexpr T secondary_size_for_orientation(Orientation orientation) const
  135. {
  136. return orientation == Orientation::Vertical ? width() : height();
  137. }
  138. constexpr void set_secondary_size_for_orientation(Orientation orientation, T value)
  139. {
  140. if (orientation == Orientation::Vertical) {
  141. set_width(value);
  142. } else {
  143. set_height(value);
  144. }
  145. }
  146. template<typename U>
  147. requires(!IsSame<T, U>)
  148. [[nodiscard]] ALWAYS_INLINE constexpr Size<U> to_type() const
  149. {
  150. return Size<U>(*this);
  151. }
  152. [[nodiscard]] ByteString to_byte_string() const;
  153. template<Integral I>
  154. [[nodiscard]] Size<I> to_rounded() const
  155. {
  156. return Size<I>(round_to<I>(width()), round_to<I>(height()));
  157. }
  158. private:
  159. T m_width { 0 };
  160. T m_height { 0 };
  161. };
  162. using IntSize = Size<int>;
  163. using FloatSize = Size<float>;
  164. }
  165. namespace AK {
  166. template<typename T>
  167. struct Formatter<Gfx::Size<T>> : Formatter<FormatString> {
  168. ErrorOr<void> format(FormatBuilder& builder, Gfx::Size<T> const& value)
  169. {
  170. return Formatter<FormatString>::format(builder, "[{}x{}]"sv, value.width(), value.height());
  171. }
  172. };
  173. }
  174. namespace IPC {
  175. template<>
  176. ErrorOr<void> encode(Encoder&, Gfx::IntSize const&);
  177. template<>
  178. ErrorOr<Gfx::IntSize> decode(Decoder&);
  179. }