Serenity Operating System
at hosted 330 lines 9.5 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include <AK/LogStream.h> 30#include <AK/String.h> 31#include <LibGfx/FloatPoint.h> 32#include <LibGfx/FloatSize.h> 33#include <LibGfx/Orientation.h> 34#include <LibGfx/Rect.h> 35#include <LibGfx/TextAlignment.h> 36#include <math.h> 37 38namespace Gfx { 39 40class FloatRect { 41public: 42 FloatRect() {} 43 FloatRect(float x, float y, float width, float height) 44 : m_location(x, y) 45 , m_size(width, height) 46 { 47 } 48 FloatRect(const FloatPoint& location, const FloatSize& size) 49 : m_location(location) 50 , m_size(size) 51 { 52 } 53 FloatRect(const FloatRect& other) 54 : m_location(other.m_location) 55 , m_size(other.m_size) 56 { 57 } 58 59 bool is_null() const 60 { 61 return width() == 0 && height() == 0; 62 } 63 64 bool is_empty() const 65 { 66 return width() <= 0 || height() <= 0; 67 } 68 69 void move_by(float dx, float dy) 70 { 71 m_location.move_by(dx, dy); 72 } 73 74 void move_by(const FloatPoint& delta) 75 { 76 m_location.move_by(delta); 77 } 78 79 FloatPoint center() const 80 { 81 return { x() + width() / 2, y() + height() / 2 }; 82 } 83 84 void set_location(const FloatPoint& location) 85 { 86 m_location = location; 87 } 88 89 void set_size(const FloatSize& size) 90 { 91 m_size = size; 92 } 93 94 void set_size(float width, float height) 95 { 96 m_size.set_width(width); 97 m_size.set_height(height); 98 } 99 100 void inflate(float w, float h) 101 { 102 set_x(x() - w / 2); 103 set_width(width() + w); 104 set_y(y() - h / 2); 105 set_height(height() + h); 106 } 107 108 void shrink(float w, float h) 109 { 110 set_x(x() + w / 2); 111 set_width(width() - w); 112 set_y(y() + h / 2); 113 set_height(height() - h); 114 } 115 116 FloatRect shrunken(float w, float h) const 117 { 118 FloatRect rect = *this; 119 rect.shrink(w, h); 120 return rect; 121 } 122 123 FloatRect inflated(float w, float h) const 124 { 125 FloatRect rect = *this; 126 rect.inflate(w, h); 127 return rect; 128 } 129 130 FloatRect translated(float dx, float dy) const 131 { 132 FloatRect rect = *this; 133 rect.move_by(dx, dy); 134 return rect; 135 } 136 137 FloatRect translated(const FloatPoint& delta) const 138 { 139 FloatRect rect = *this; 140 rect.move_by(delta); 141 return rect; 142 } 143 144 bool contains_vertically(float y) const 145 { 146 return y >= top() && y <= bottom(); 147 } 148 149 bool contains_horizontally(float x) const 150 { 151 return x >= left() && x <= right(); 152 } 153 154 bool contains(float x, float y) const 155 { 156 return x >= m_location.x() && x <= right() && y >= m_location.y() && y <= bottom(); 157 } 158 159 bool contains(const FloatPoint& point) const 160 { 161 return contains(point.x(), point.y()); 162 } 163 164 bool contains(const FloatRect& other) const 165 { 166 return left() <= other.left() 167 && right() >= other.right() 168 && top() <= other.top() 169 && bottom() >= other.bottom(); 170 } 171 172 float primary_offset_for_orientation(Orientation orientation) const { return m_location.primary_offset_for_orientation(orientation); } 173 void set_primary_offset_for_orientation(Orientation orientation, float value) { m_location.set_primary_offset_for_orientation(orientation, value); } 174 float secondary_offset_for_orientation(Orientation orientation) const { return m_location.secondary_offset_for_orientation(orientation); } 175 void set_secondary_offset_for_orientation(Orientation orientation, float value) { m_location.set_secondary_offset_for_orientation(orientation, value); } 176 177 float primary_size_for_orientation(Orientation orientation) const { return m_size.primary_size_for_orientation(orientation); } 178 float secondary_size_for_orientation(Orientation orientation) const { return m_size.secondary_size_for_orientation(orientation); } 179 void set_primary_size_for_orientation(Orientation orientation, float value) { m_size.set_primary_size_for_orientation(orientation, value); } 180 void set_secondary_size_for_orientation(Orientation orientation, float value) { m_size.set_secondary_size_for_orientation(orientation, value); } 181 182 float first_edge_for_orientation(Orientation orientation) const 183 { 184 if (orientation == Orientation::Vertical) 185 return top(); 186 return left(); 187 } 188 189 float last_edge_for_orientation(Orientation orientation) const 190 { 191 if (orientation == Orientation::Vertical) 192 return bottom(); 193 return right(); 194 } 195 196 float left() const { return x(); } 197 float right() const { return x() + width() - 1; } 198 float top() const { return y(); } 199 float bottom() const { return y() + height() - 1; } 200 201 void set_left(float left) 202 { 203 set_x(left); 204 } 205 206 void set_top(float top) 207 { 208 set_y(top); 209 } 210 211 void set_right(float right) 212 { 213 set_width(right - x() + 1); 214 } 215 216 void set_bottom(float bottom) 217 { 218 set_height(bottom - y() + 1); 219 } 220 221 void set_right_without_resize(float new_right) 222 { 223 float delta = new_right - right(); 224 move_by(delta, 0); 225 } 226 227 void set_bottom_without_resize(float new_bottom) 228 { 229 float delta = new_bottom - bottom(); 230 move_by(0, delta); 231 } 232 233 bool intersects(const FloatRect& other) const 234 { 235 return left() <= other.right() 236 && other.left() <= right() 237 && top() <= other.bottom() 238 && other.top() <= bottom(); 239 } 240 241 float x() const { return location().x(); } 242 float y() const { return location().y(); } 243 float width() const { return m_size.width(); } 244 float height() const { return m_size.height(); } 245 246 void set_x(float x) { m_location.set_x(x); } 247 void set_y(float y) { m_location.set_y(y); } 248 void set_width(float width) { m_size.set_width(width); } 249 void set_height(float height) { m_size.set_height(height); } 250 251 FloatPoint location() const { return m_location; } 252 FloatSize size() const { return m_size; } 253 254 Vector<FloatRect, 4> shatter(const FloatRect& hammer) const; 255 256 bool operator==(const FloatRect& other) const 257 { 258 return m_location == other.m_location 259 && m_size == other.m_size; 260 } 261 262 void intersect(const FloatRect&); 263 264 static FloatRect intersection(const FloatRect& a, const FloatRect& b) 265 { 266 FloatRect r(a); 267 r.intersect(b); 268 return r; 269 } 270 271 FloatRect intersected(const FloatRect& other) const 272 { 273 return intersection(*this, other); 274 } 275 276 FloatRect united(const FloatRect&) const; 277 278 FloatPoint top_left() const { return { left(), top() }; } 279 FloatPoint top_right() const { return { right(), top() }; } 280 FloatPoint bottom_left() const { return { left(), bottom() }; } 281 FloatPoint bottom_right() const { return { right(), bottom() }; } 282 283 void align_within(const FloatRect&, TextAlignment); 284 285 void center_within(const FloatRect& other) 286 { 287 center_horizontally_within(other); 288 center_vertically_within(other); 289 } 290 291 void center_horizontally_within(const FloatRect& other) 292 { 293 set_x(other.center().x() - width() / 2); 294 } 295 296 void center_vertically_within(const FloatRect& other) 297 { 298 set_y(other.center().y() - height() / 2); 299 } 300 301 String to_string() const { return String::format("[%g,%g %gx%g]", x(), y(), width(), height()); } 302 303private: 304 FloatPoint m_location; 305 FloatSize m_size; 306}; 307 308inline void FloatPoint::constrain(const FloatRect& rect) 309{ 310 if (x() < rect.left()) 311 set_x(rect.left()); 312 else if (x() > rect.right()) 313 set_x(rect.right()); 314 if (y() < rect.top()) 315 set_y(rect.top()); 316 else if (y() > rect.bottom()) 317 set_y(rect.bottom()); 318} 319 320inline const LogStream& operator<<(const LogStream& stream, const FloatRect& value) 321{ 322 return stream << value.to_string(); 323} 324 325inline Rect enclosing_int_rect(const FloatRect& float_rect) 326{ 327 return { (int)float_rect.x(), (int)float_rect.y(), (int)ceilf(float_rect.width()), (int)ceilf(float_rect.height()) }; 328} 329 330}