Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget Resizable now support multiple types of resize #1081

Merged
merged 1 commit into from
Jul 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions client/chatline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
6 changes: 5 additions & 1 deletion client/messagewin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
266 changes: 222 additions & 44 deletions client/widgetdecorations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,35 @@ void close_widget::notify_parent()
fcw->update_menu();
}

/**
Set resizable flags
*/
void resizable_widget::setResizable(QFlags<resizable_flag> flags)
{
resizeFlags = flags;
lmoureaux marked this conversation as resolved.
Show resolved Hide resolved
}

/**
Get resizable flags of wdiget
*/
QFlags<resizable_flag> resizable_widget::getResizable() const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a docstring. Does it make sense to inline it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add a docstring. Does it make sense to inline it?

The fact is that there is no point in doing inline in this place, this function is not called so often.
And as you said earlier, it makes sense to do inline only in header files.

{
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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it could be made inline

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it could be made inline

Are you talking about the inline specifier?

inline bool resizable_widget::hasResizable(resizable_flag flag) const {}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specifier is mostly ignored by compilers nowadays, but we could help them by moving the implementation to the header. Anyway not a critical issue :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specifier is mostly ignored by compilers nowadays, but we could help them by moving the implementation to the header. Anyway not a critical issue :)

Yeah

}

/**
Checks if info_tab can be moved
*/
Expand All @@ -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);
}
Loading