2026-04-06 00:20:51 -05:00

504 lines
8.5 KiB
C++

/*
This file is part of KDDockWidgets.
SPDX-FileCopyrightText: 2020 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
Author: Sérgio Martins <sergio.martins@kdab.com>
SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
Contact KDAB at <info@kdab.com> for commercial licensing options.
*/
#pragma once
#ifdef KDDW_FLUTTER_QWINDOW
#include <QRect>
#include <QSize>
#include <QPoint>
#else
#include <cmath>
#include <algorithm>
/// QSize, QPoint and QRect replacements for Flutter
/// The goal is that Qt users can still use Qt's classes, to avoid porting churn.
/// For Flutter, we use these classes, which have the same API (or at least a subset) as Qt's
namespace KDDockWidgets {
class Size
{
public:
Size() = default;
Size(int width, int height)
: m_width(width)
, m_height(height)
{
}
int width() const
{
return m_width;
}
int height() const
{
return m_height;
}
void setWidth(int w)
{
m_width = w;
}
void setHeight(int h)
{
m_height = h;
}
bool isNull() const
{
return m_width == 0 && m_height == 0;
}
bool isEmpty() const
{
return m_width <= 0 || m_height <= 0;
}
bool isValid() const
{
return m_width >= 0 && m_height >= 0;
}
Size expandedTo(Size sz) const
{
return { ( std::max )(m_width, sz.m_width), ( std::max )(m_height, sz.height()) };
}
Size boundedTo(Size sz) const
{
return { ( std::min )(m_width, sz.m_width), ( std::min )(m_height, sz.height()) };
}
bool operator==(Size other) const
{
return m_width == other.m_width && m_height == other.m_height;
}
bool operator!=(Size other) const
{
return !operator==(other);
}
private:
int m_width = -1;
int m_height = -1;
};
class Point
{
public:
Point() = default;
Point(int x, int y)
: m_x(x)
, m_y(y)
{
}
int x() const
{
return m_x;
}
int y() const
{
return m_y;
}
void setX(int x)
{
m_x = x;
}
void setY(int y)
{
m_y = y;
}
bool isNull() const
{
return m_x == 0 && m_y == 0;
}
int manhattanLength() const
{
return std::abs(x()) + std::abs(y());
}
bool operator==(Point other) const
{
return m_x == other.m_x && m_y == other.m_y;
}
bool operator!=(Point other) const
{
return !operator==(other);
}
private:
int m_x = 0;
int m_y = 0;
};
class Margins
{
public:
Margins() = default;
Margins(int l, int t, int r, int b)
: m_left(l)
, m_top(t)
, m_right(r)
, m_bottom(b)
{
}
int left() const
{
return m_left;
}
int top() const
{
return m_top;
}
int right() const
{
return m_right;
}
int bottom() const
{
return m_bottom;
}
private:
int m_left = 0;
int m_top = 0;
int m_right = 0;
int m_bottom = 0;
};
class Rect
{
public:
Rect() = default;
Rect(Point pos, Size size)
: m_pos(pos)
, m_size(size)
{
}
Rect(int x, int y, int width, int height)
: m_pos(Point(x, y))
, m_size(Size(width, height))
{
}
Size size() const
{
return m_size;
}
int width() const
{
return m_size.width();
}
int height() const
{
return m_size.height();
}
void setWidth(int w)
{
m_size.setWidth(w);
}
void setHeight(int h)
{
m_size.setHeight(h);
}
int x() const
{
return m_pos.x();
}
int y() const
{
return m_pos.y();
}
void setSize(Size sz)
{
m_size = sz;
}
Point topLeft() const
{
return m_pos;
}
int top() const
{
return y();
}
int bottom() const
{
return y() + height() - 1;
}
int right() const
{
return x() + width() - 1;
}
bool isNull() const
{
return m_pos.isNull() && m_size.isNull();
}
bool isValid() const
{
return !isEmpty();
}
bool isEmpty() const
{
return m_size.isEmpty();
}
void moveTop(int y)
{
m_pos.setY(y);
}
void moveLeft(int x)
{
m_pos.setX(x);
}
void moveTopLeft(Point pt)
{
m_pos = pt;
}
void moveTo(Point pt)
{
moveTopLeft(pt);
}
void moveTo(int x, int y)
{
moveTopLeft({ x, y });
}
void setLeft(int x)
{
const int delta = m_pos.x() - x;
const int width = m_size.width();
m_pos.setX(x);
m_size.setWidth(width + delta);
}
void setRight(int r)
{
const int delta = r - right();
const int width = m_size.width();
m_size.setWidth(width + delta);
}
void setTop(int y)
{
const int delta = m_pos.y() - y;
const int height = m_size.height();
m_pos.setY(y);
m_size.setHeight(height + delta);
}
void setTopLeft(Point pt)
{
setLeft(pt.x());
setTop(pt.y());
}
void setBottom(int b)
{
const int delta = b - bottom();
const int height = m_size.height();
m_size.setHeight(height + delta);
}
void setX(int x)
{
setLeft(x);
}
void setY(int y)
{
setTop(y);
}
Rect marginsAdded(Margins m) const
{
Rect result = *this;
result.adjust(-m.left(), -m.top(), m.right(), m.bottom());
return result;
}
Rect intersected(Rect other) const
{
const int maxLeft = ( std::max )(x(), other.x());
const int minRight = ( std::min )(right(), other.right());
if (maxLeft > minRight)
return Rect();
const int maxTop = ( std::max )(y(), other.y());
const int minBottom = ( std::min )(bottom(), other.bottom());
if (maxTop > minBottom)
return Rect();
const int w = minRight - maxLeft + 1;
const int h = minBottom - maxTop + 1;
return Rect(maxLeft, maxTop, w, h);
}
int left() const
{
return m_pos.x();
}
Point bottomLeft() const
{
return { left(), bottom() };
}
Point bottomRight() const
{
return { right(), bottom() };
}
Point topRight() const
{
return { right(), top() };
}
bool contains(Point pt) const
{
return pt.x() >= x() && pt.y() >= y() && pt.x() <= right() && pt.y() <= bottom();
}
bool contains(Rect other) const
{
return contains(other.topLeft()) && contains(other.bottomRight());
}
Rect adjusted(int l, int t, int r, int b) const
{
Rect result = *this;
result.adjust(l, t, r, b);
return result;
}
void adjust(int l, int t, int r, int b);
Point center() const
{
return { left() + ((right() - left()) / 2), top() + ((bottom() - top()) / 2) };
}
void moveCenter(Point pt);
void moveRight(int r)
{
const int delta = r - right();
moveLeft(left() + delta);
}
void moveBottom(int b)
{
const int delta = b - bottom();
moveTop(top() + delta);
}
bool intersects(Rect other) const
{
return !intersected(other).isNull();
}
void translate(Point pt);
bool operator==(Rect other) const
{
return m_pos == other.m_pos && m_size == other.m_size;
}
bool operator!=(Rect other) const
{
return !operator==(other);
}
private:
Point m_pos;
Size m_size = { 0, 0 };
};
inline const Point operator-(Point pt1, Point pt2)
{
return { pt1.x() - pt2.x(), pt1.y() - pt2.y() };
}
inline const Point operator+(Point pt1, Point pt2)
{
return { pt1.x() + pt2.x(), pt1.y() + pt2.y() };
}
inline const Size operator+(Size sz1, Size sz2)
{
return { sz1.width() + sz2.width(), sz1.height() + sz2.height() };
}
inline const Size operator-(Size sz1, Size sz2)
{
return { sz1.width() - sz2.width(), sz1.height() - sz2.height() };
}
inline void Rect::translate(Point pt)
{
moveTopLeft(topLeft() + pt);
}
inline void Rect::moveCenter(Point pt)
{
const Point delta = pt - center();
moveTopLeft(topLeft() + delta);
}
inline void Rect::adjust(int l, int t, int r, int b)
{
setLeft(left() + l);
setTop(top() + t);
setRight(right() + r);
setBottom(bottom() + b);
}
}
#endif