From 137068d83d196a4e9c8391365886996a9581e54d Mon Sep 17 00:00:00 2001 From: NIKEA-SOFT Date: Sun, 3 Jul 2022 09:19:54 +0300 Subject: [PATCH] Widget Resizable now support multiple types of resize --- client/chatline.cpp | 7 + client/messagewin.cpp | 6 +- client/widgetdecorations.cpp | 266 +++++++++++++++++++++++++++++------ client/widgetdecorations.h | 41 +++++- 4 files changed, 269 insertions(+), 51 deletions(-) diff --git a/client/chatline.cpp b/client/chatline.cpp index 2f9106ad91..d6c5d761e4 100644 --- a/client/chatline.cpp +++ b/client/chatline.cpp @@ -255,6 +255,12 @@ chat_widget::chat_widget(QWidget *parent) { QGridLayout *gl; setParent(parent); + setMinimumSize(200, 100); + setResizable(resizable_flag::top | resizable_flag::topLeft + | resizable_flag::topRight | resizable_flag::bottom + | resizable_flag::bottomLeft | resizable_flag::bottomRight + | resizable_flag::left | resizable_flag::right); + gl = new QGridLayout; gl->setVerticalSpacing(0); gl->setMargin(0); @@ -300,6 +306,7 @@ chat_widget::chat_widget(QWidget *parent) auto title = new QLabel(_("Chat")); title->setAlignment(Qt::AlignCenter); + title->setMouseTracking(true); gl->addWidget(mw, 0, 0, Qt::AlignLeft | Qt::AlignTop); gl->addWidget(title, 0, 1, 1, 2); diff --git a/client/messagewin.cpp b/client/messagewin.cpp index 6ef71cfff0..1358d2cda2 100644 --- a/client/messagewin.cpp +++ b/client/messagewin.cpp @@ -36,12 +36,16 @@ message_widget::message_widget(QWidget *parent) { setParent(parent); + setMinimumSize(200, 100); layout = new QGridLayout; - layout->setMargin(0); + layout->setMargin(2); setLayout(layout); + setResizable(resizable_flag::bottom | resizable_flag::bottomLeft + | resizable_flag::left); auto title = new QLabel(_("Messages")); title->setAlignment(Qt::AlignCenter); + title->setMouseTracking(true); layout->addWidget(title, 0, 1); layout->setColumnStretch(1, 100); diff --git a/client/widgetdecorations.cpp b/client/widgetdecorations.cpp index 20fda8aefc..b7d6602c3c 100644 --- a/client/widgetdecorations.cpp +++ b/client/widgetdecorations.cpp @@ -170,6 +170,35 @@ void close_widget::notify_parent() fcw->update_menu(); } +/** + Set resizable flags + */ +void resizable_widget::setResizable(QFlags flags) +{ + resizeFlags = flags; +} + +/** + Get resizable flags of wdiget + */ +QFlags resizable_widget::getResizable() const +{ + return resizeFlags; +} + +/** + Remove all resizable flags + */ +void resizable_widget::removeResizable() { resizeFlags = {}; } + +/** + Check if resizable flag is active + */ +bool resizable_widget::hasResizable(resizable_flag flag) const +{ + return resizeFlags.testFlag(flag); +} + /** Checks if info_tab can be moved */ @@ -179,77 +208,226 @@ void resizable_widget::mousePressEvent(QMouseEvent *event) return; } if (event->button() == Qt::LeftButton) { - cursor = event->globalPos() - geometry().topLeft(); - if (event->y() > 0 && event->y() < 25 && event->x() > width() - 25 - && event->x() < width()) { - resize_mode = true; - resxy = true; - return; - } - if (event->y() > 0 && event->y() < 5) { - resize_mode = true; - resy = true; - } else if (event->x() > width() - 5 && event->x() < width()) { - resize_mode = true; - resx = true; + // Get flag from mouse position + auto flag = get_in_event_mouse(event); + + // Check the flag and widget for the presence of a flag + if (flag != resizable_flag::none && resizeFlags.testFlag(flag)) { + // Save flag and mouse position for mouse move event + eventFlag = flag; + last_position = event->globalPos(); } } event->setAccepted(true); } +/** + Get resizable_flag from mouse position + */ +resizable_flag +resizable_widget::get_in_event_mouse(const QMouseEvent *event) const +{ + if (event->x() >= width() / 2 - event_width + && event->x() <= width() / 2 + event_width && event->y() >= 0 + && event->y() <= event_width) { + return resizable_flag::top; + } + + if (event->x() >= 0 && event->x() <= event_width && event->y() >= 0 + && event->y() <= event_width) { + return resizable_flag::topLeft; + } + + if (event->x() >= width() - event_width && event->x() <= width() + && event->y() >= 0 && event->y() <= event_width) { + return resizable_flag::topRight; + } + + if (event->x() >= width() / 2 - event_width + && event->x() <= width() / 2 + event_width + && event->y() >= height() - event_width && event->y() <= height()) { + return resizable_flag::bottom; + } + + if (event->x() >= 0 && event->x() <= event_width + && event->y() >= height() - event_width && event->y() <= height()) { + return resizable_flag::bottomLeft; + } + + if (event->x() >= width() - event_width && event->x() <= width() + && event->y() >= height() - event_width && event->y() <= height()) { + return resizable_flag::bottomRight; + } + + if (event->x() >= 0 && event->x() <= event_width + && event->y() >= height() / 2 - event_width + && event->y() <= height() / 2 + event_width) { + return resizable_flag::left; + } + + if (event->x() >= width() - event_width && event->x() <= width() + && event->y() >= height() / 2 - event_width + && event->y() <= height() / 2 + event_width) { + return resizable_flag::right; + } + + return resizable_flag::none; +} + /** Restores cursor when resizing is done. */ void resizable_widget::mouseReleaseEvent(QMouseEvent *event) { - QPoint p; if (king()->interface_locked) { return; } - if (resize_mode) { - resize_mode = false; - resx = false; - resy = false; - resxy = false; + + // If the event flag is active, then reset all + if (eventFlag != resizable_flag::none) { + eventFlag = resizable_flag::none; + last_position = QPoint{}; setCursor(Qt::ArrowCursor); } - p = pos(); emit resized(rect()); } /** Called when mouse moved (mouse track is enabled). Used for resizing resizable_widget. */ + void resizable_widget::mouseMoveEvent(QMouseEvent *event) { if (king()->interface_locked) { return; } - if ((event->buttons() & Qt::LeftButton) && resize_mode && resy) { - QPoint to_move; - int newheight = event->globalY() - cursor.y() - geometry().y(); - resize(width(), this->geometry().height() - newheight); - to_move = event->globalPos() - cursor; - move(this->x(), to_move.y()); - setCursor(Qt::SizeVerCursor); - } else if (event->x() > width() - 9 && event->y() > 0 && event->y() < 9) { - setCursor(Qt::SizeBDiagCursor); - } else if ((event->buttons() & Qt::LeftButton) && resize_mode && resx) { - resize(event->x(), height()); - setCursor(Qt::SizeHorCursor); - } else if (event->x() > width() - 5 && event->x() < width()) { - setCursor(Qt::SizeHorCursor); - } else if (event->y() > 0 && event->y() < 5) { - setCursor(Qt::SizeVerCursor); - } else if (resxy && (event->buttons() & Qt::LeftButton)) { - QPoint to_move; - int newheight = event->globalY() - cursor.y() - geometry().y(); - resize(event->x(), this->geometry().height() - newheight); - to_move = event->globalPos() - cursor; - move(this->x(), to_move.y()); - setCursor(Qt::SizeBDiagCursor); + + // Check left button state + if (event->buttons() & Qt::LeftButton) { + // If the event flag is active + if (eventFlag != resizable_flag::none) { + QSize size{width(), height()}; + QPoint pos{x(), y()}; + + // Calculate diff betwen position and update last position + auto diff = event->globalPos() - last_position; + last_position = event->globalPos(); + + // Resizing and moving depending on the type of event + switch (eventFlag) { + case resizable_flag::top: { + if (minimumHeight() < height() - diff.y()) { + size.setHeight(height() - diff.y()); + pos.setY(y() + diff.y()); + } + + resize(size.width(), size.height()); + move(pos.x(), pos.y()); + } break; + + case resizable_flag::topLeft: { + if (minimumWidth() < width() - diff.x()) { + size.setWidth(width() - diff.x()); + pos.setX(x() + diff.x()); + } + + if (minimumHeight() < height() - diff.y()) { + size.setHeight(height() - diff.y()); + pos.setY(y() + diff.y()); + } + + resize(size.width(), size.height()); + move(pos.x(), pos.y()); + } break; + + case resizable_flag::topRight: { + if (minimumWidth() < width() + diff.x()) { + size.setWidth(width() + diff.x()); + } + + if (minimumHeight() < height() - diff.y()) { + size.setHeight(height() - diff.y()); + pos.setY(y() + diff.y()); + } + + resize(size.width(), size.height()); + move(pos.x(), pos.y()); + } break; + + case resizable_flag::bottom: { + if (minimumHeight() < height() + diff.y()) { + size.setHeight(height() + diff.y()); + } + + resize(size.width(), size.height()); + } break; + + case resizable_flag::bottomLeft: { + if (minimumWidth() < width() - diff.x()) { + size.setWidth(width() - diff.x()); + pos.setX(x() + diff.x()); + } + + if (minimumHeight() < height() + diff.y()) { + size.setHeight(height() + diff.y()); + } + + resize(size.width(), size.height()); + move(pos.x(), pos.y()); + } break; + + case resizable_flag::bottomRight: { + if (minimumWidth() < width() + diff.x()) { + size.setWidth(width() + diff.x()); + } + + if (minimumHeight() < height() + diff.y()) { + size.setHeight(height() + diff.y()); + } + + resize(size.width(), size.height()); + } break; + + case resizable_flag::left: { + if (minimumWidth() < width() - diff.x()) { + size.setWidth(width() - diff.x()); + pos.setX(x() + diff.x()); + } + + resize(size.width(), size.height()); + move(pos.x(), pos.y()); + } break; + + case resizable_flag::right: { + resize((std::max)(minimumWidth(), width() + diff.x()), height()); + } break; + + default: + break; + } + } } else { - setCursor(Qt::ArrowCursor); + // Get flag from mouse position + auto flag = get_in_event_mouse(event); + + // Change the cursor if the flag is active and the widget has this flag + if (flag != resizable_flag::none && resizeFlags.testFlag(flag)) { + if (flag == resizable_flag::top || flag == resizable_flag::bottom) { + setCursor(Qt::SizeVerCursor); + } else if (flag == resizable_flag::topLeft + || flag == resizable_flag::bottomRight) { + setCursor(Qt::SizeFDiagCursor); + } else if (flag == resizable_flag::topRight + || flag == resizable_flag::bottomLeft) { + setCursor(Qt::SizeBDiagCursor); + } else if (flag == resizable_flag::left + || flag == resizable_flag::right) { + setCursor(Qt::SizeHorCursor); + } + } else { + // Otherwise change cursor to default + setCursor(Qt::ArrowCursor); + } } event->setAccepted(true); } diff --git a/client/widgetdecorations.h b/client/widgetdecorations.h index f50c1fc498..cbf73ac3ec 100644 --- a/client/widgetdecorations.h +++ b/client/widgetdecorations.h @@ -12,6 +12,7 @@ ************* V ******************************************************/ #pragma once +#include #include #include #include @@ -70,19 +71,45 @@ class fcwidget : public QFrame { /************************************************************************** Abstract class for widgets that can be resized by dragging the edges. **************************************************************************/ +enum class resizable_flag : std::uint8_t { + none = 0, + top = 1, + topLeft = 2, + topRight = 4, + bottom = 8, + bottomLeft = 16, + bottomRight = 32, + left = 64, + right = 128 +}; + class resizable_widget : public fcwidget { Q_OBJECT + static constexpr int event_width = 25; + signals: void resized(QRect rect); +public: + // make widget resizable (multiple flags supported) + void setResizable(QFlags resizeFlags); + + // get resizable flags + QFlags getResizable() const; + + // remove resizable for widget + void removeResizable(); + + // check exist a resizable_type + bool hasResizable(resizable_flag flag) const; + private: - QPoint cursor; - QSize last_size; - bool resize_mode; - bool resxy; - bool resx; - bool resy; + resizable_flag get_in_event_mouse(const QMouseEvent *event) const; + + QPoint last_position{}; + resizable_flag eventFlag{}; + QFlags resizeFlags{}; protected: void mousePressEvent(QMouseEvent *event) override; @@ -90,6 +117,8 @@ class resizable_widget : public fcwidget { void mouseReleaseEvent(QMouseEvent *event) override; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QFlags) + /************************************************************************** Widget allowing closing other widgets **************************************************************************/