diff --git a/CMakeLists.txt b/CMakeLists.txt index dfb31afa..cea7231d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,6 +219,8 @@ target_sources( lib/utils/priority-helper.hpp lib/utils/regex-config.cpp lib/utils/regex-config.hpp + lib/utils/resizable-widget.cpp + lib/utils/resizable-widget.hpp lib/utils/resizing-text-edit.cpp lib/utils/resizing-text-edit.hpp lib/utils/resource-table.cpp diff --git a/lib/utils/resizable-widget.cpp b/lib/utils/resizable-widget.cpp new file mode 100644 index 00000000..646e35cf --- /dev/null +++ b/lib/utils/resizable-widget.cpp @@ -0,0 +1,106 @@ +#include "resizable-widget.hpp" + +namespace advss { + +ResizableWidget::ResizableWidget(QWidget *parent) : QWidget(parent) {} + +void ResizableWidget::SetResizingEnabled(bool enable) +{ + setMouseTracking(enable); + _customHeight = enable ? sizeHint().height() : 0; + auto pol = sizePolicy(); + pol.setVerticalPolicy(enable ? QSizePolicy::Fixed + : QSizePolicy::Preferred); + _resizingEnabled = enable; +} + +void ResizableWidget::mousePressEvent(QMouseEvent *event) +{ + if (!_resizingEnabled) { + QWidget::mousePressEvent(event); + return; + } + + if (IsInResizeArea(event->pos())) { + _resizing = true; + _lastMousePos = event->globalPosition().toPoint(); + event->accept(); + } else { + QWidget::mousePressEvent(event); + } +} + +void ResizableWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (!_resizingEnabled) { + QWidget::mouseMoveEvent(event); + return; + } + + if (_resizing) { + const int dy = event->globalPosition().toPoint().y() - + _lastMousePos.y(); + const int baseHeight = _customHeight == 0 ? height() + : _customHeight; + const int newHeight = baseHeight + dy; + _customHeight = + std::clamp(newHeight, minimumHeight(), maximumHeight()); + updateGeometry(); + _lastMousePos = event->globalPosition().toPoint(); + event->accept(); + } else { + setCursor(IsInResizeArea(event->pos()) ? Qt::SizeVerCursor + : Qt::ArrowCursor); + QWidget::mouseMoveEvent(event); + } +} + +void ResizableWidget::mouseReleaseEvent(QMouseEvent *event) +{ + if (_resizing) { + event->accept(); + _resizing = false; + } else { + QWidget::mouseReleaseEvent(event); + } +} + +void ResizableWidget::paintEvent(QPaintEvent *event) +{ + QWidget::paintEvent(event); + + if (!_resizingEnabled) { + return; + } + + // Draw a triangle in bottom-right as resize indicator + QPainter painter(this); + QPolygon triangle; + triangle << QPoint(width() - 1, height() - _gripSize) + << QPoint(width() - _gripSize, height() - 1) + << QPoint(width() - 1, height() - 1); + painter.setBrush(Qt::gray); + painter.drawPolygon(triangle); +} + +QSize ResizableWidget::sizeHint() const +{ + if (!_resizingEnabled) { + return QWidget::sizeHint(); + } + + if (_customHeight == 0) { + return QWidget::sizeHint(); + } + + return QSize(width(), _customHeight); +} + +bool ResizableWidget::IsInResizeArea(const QPoint &pos) const +{ + return QRect(width() - _gripSize, height() - _gripSize, _gripSize, + _gripSize) + .contains(pos); +} + +} // namespace advss diff --git a/lib/utils/resizable-widget.hpp b/lib/utils/resizable-widget.hpp new file mode 100644 index 00000000..bb3441a6 --- /dev/null +++ b/lib/utils/resizable-widget.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include +#include + +namespace advss { + +class ResizableWidget : public QWidget { + Q_OBJECT + +public: + ResizableWidget(QWidget *parent = nullptr); + +protected: + void SetResizingEnabled(bool enable); + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void paintEvent(QPaintEvent *event) override; + QSize sizeHint() const override; + int GetCustomHeight() const { return _customHeight; } + void SetCustomHeight(int value) { _customHeight = value; } + +private: + bool IsInResizeArea(const QPoint &pos) const; + + bool _resizingEnabled = false; + bool _resizing = false; + QPoint _lastMousePos; + int _customHeight = 0; + const int _gripSize = 15; +}; + +} // namespace advss