Freeciv21
Develop your civilization from humble roots to a global empire
decorations.cpp
Go to the documentation of this file.
1 /*** _ ************************************************************
2  /` '\ Copyright (c) 1996-2023 Freeciv21 and Freeciv
3  /| @ l contributors. This file is part of Freeciv21.
4  \| \ Freeciv21 is free software: you can redistribute it
5  `\ `\_ and/or modify it under the terms of the GNU
6  \ __ `\ General Public License as published by the Free
7  l \ `\ `\__ Software Foundation, either version 3 of the
8  \ `\./` ``\ License, or (at your option) any later version.
9  \ ____ / \ l You should have received a copy of the
10  || || ) / GNU General Public License along with Freeciv21.
11 -----------(((-(((---l /-----------
12  l / If not, see https://www.gnu.org/licenses/.
13  / / ********************************************/
14 
15 /*
16  * This file is used to add "decorations" to custom widgets in the client.
17  *
18  * close_widget - add a close "x" icon to the corner of a widget.
19  * move_widget - add a cross-like symbol to the corner of a widget.
20  * resizable_widget - set the widget to be resizable.
21  * scale_widget - add plus and minus buttons to the top of a widget to allow
22  * for scaling.
23  */
24 
25 #include "decorations.h"
26 // Qt
27 #include "fc_client.h"
28 #include "icons.h"
29 #include <QMouseEvent>
30 #include <QPainter>
31 #include <qnamespace.h>
32 
36 scale_widget::scale_widget(QRubberBand::Shape s, QWidget *p)
37  : QRubberBand(s, p)
38 {
39  QPixmap *pix;
40 
41  size = 12;
42  pix = fcIcons::instance()->getPixmap(QStringLiteral("plus"));
43  plus = pix->scaledToWidth(size);
44  delete pix;
45  pix = fcIcons::instance()->getPixmap(QStringLiteral("minus"));
46  minus = pix->scaledToWidth(size);
47  delete pix;
48  setFixedSize(2 * size, size);
49  scale = 1.0f;
50  setAttribute(Qt::WA_TransparentForMouseEvents, false);
51 }
52 
56 void scale_widget::paintEvent(QPaintEvent *event)
57 {
58  QRubberBand::paintEvent(event);
59  QPainter p;
60  p.begin(this);
61  p.drawPixmap(0, 0, minus);
62  p.drawPixmap(size, 0, plus);
63  p.end();
64 }
65 
70 {
71  if (event->button() == Qt::LeftButton) {
72  if (event->localPos().x() <= size) {
73  scale = scale / 1.2;
74  } else {
75  scale = scale * 1.2;
76  }
77  parentWidget()->update();
78  }
79 }
80 
84 move_widget::move_widget(QWidget *parent) : QLabel()
85 {
86  QPixmap pix;
87 
88  setParent(parent);
89  setCursor(Qt::SizeAllCursor);
90  pix = fcIcons::instance()->getIcon(QStringLiteral("move")).pixmap(32);
91  pix.setDevicePixelRatio(2);
92  setPixmap(pix);
93  setFixedSize(16, 16);
94 }
95 
99 void move_widget::put_to_corner() { move(0, 0); }
100 
105 {
106  if (!king()->interface_locked) {
107  auto new_location = event->globalPos() - point;
108  if (new_location.x() < 0) {
109  new_location.setX(0);
110  } else if (new_location.x() + width()
111  > parentWidget()->parentWidget()->width()) {
112  new_location.setX(parentWidget()->parentWidget()->width() - width());
113  }
114  if (new_location.y() < 0) {
115  new_location.setY(0);
116  } else if (new_location.y() + height()
117  > parentWidget()->parentWidget()->height()) {
118  new_location.setY(parentWidget()->parentWidget()->height() - height());
119  }
120  parentWidget()->move(new_location);
121  }
122 }
123 
128 {
129  if (!king()->interface_locked) {
130  point = event->globalPos() - parentWidget()->geometry().topLeft();
131  }
132  update();
133 }
134 
138 close_widget::close_widget(QWidget *parent) : QLabel()
139 {
140  QPixmap *pix;
141 
142  setParent(parent);
143  setCursor(Qt::ArrowCursor);
144  pix = fcIcons::instance()->getPixmap(QStringLiteral("close"));
145  *pix = pix->scaledToHeight(12);
146  setPixmap(*pix);
147  delete pix;
148 }
149 
153 void close_widget::put_to_corner() { move(parentWidget()->width() - 12, 0); }
154 
159 {
160  if (king()->interface_locked) {
161  return;
162  }
163  if (event->button() == Qt::LeftButton) {
164  parentWidget()->hide();
165  }
166 }
167 
172 {
173  Q_UNUSED(event);
174  if (auto fcw = qobject_cast<fcwidget *>(parentWidget()); fcw) {
175  fcw->update_menu();
176  }
177 }
178 
182 void resizable_widget::setResizable(Qt::Edges edges)
183 {
184  resizeFlags = edges;
185  auto margins = QMargins();
186  if (edges & Qt::LeftEdge) {
187  margins.setLeft(margin_width);
188  }
189  if (edges & Qt::RightEdge) {
190  margins.setRight(margin_width);
191  }
192  if (edges & Qt::TopEdge) {
193  margins.setTop(margin_width);
194  }
195  if (edges & Qt::BottomEdge) {
196  margins.setBottom(margin_width);
197  }
198  setContentsMargins(margins);
199 }
200 
204 Qt::Edges resizable_widget::getResizable() const { return resizeFlags; }
205 
210 {
211  if (king()->interface_locked) {
212  return;
213  }
214  if (event->button() == Qt::LeftButton) {
215  // Get flag from mouse position
217  }
218  event->setAccepted(true);
219 }
220 
224 Qt::Edges
226 {
227  auto flags = Qt::Edges();
228 
229  if (std::abs(event->x()) < event_width && event->x() < width() / 2) {
230  flags |= Qt::LeftEdge;
231  } else if (std::abs(event->x() - width()) < event_width
232  && event->x() >= width() / 2) {
233  flags |= Qt::RightEdge;
234  }
235 
236  if (std::abs(event->y()) < event_width) {
237  flags |= Qt::TopEdge;
238  } else if (std::abs(event->y() - height()) < event_width
239  && event->y() >= height() / 2) {
240  flags |= Qt::BottomEdge;
241  }
242 
243  return flags;
244 }
245 
250 {
251  if (king()->interface_locked) {
252  return;
253  }
254 
255  // If the event flag is active, then reset all
256  if (eventFlags != Qt::Edges()) {
257  eventFlags = Qt::Edges();
258  setCursor(Qt::ArrowCursor);
259  }
260  emit resized(rect());
261 }
268 {
269  if (king()->interface_locked) {
270  return;
271  }
272 
273  // Check left button state
274  if (event->buttons() & Qt::LeftButton) {
275  // If the event flag is active
276  if (eventFlags != Qt::Edges()) {
277  auto new_rect = QRect(pos(), size());
278 
279  // The x and y that we should reach, relative to the parent widget
280  const auto target = event->pos() + pos();
281 
282  // Resizing and moving depending on the type of event
283  if (eventFlags & Qt::TopEdge) {
284  new_rect.setTop(target.y());
285  if (new_rect.height() < minimumHeight()) {
286  new_rect.setTop(new_rect.bottom() - minimumHeight());
287  }
288  } else if (eventFlags & Qt::BottomEdge) {
289  new_rect.setBottom(target.y());
290  if (new_rect.height() < minimumHeight()) {
291  new_rect.setBottom(new_rect.top() + minimumHeight());
292  }
293  }
294 
295  if (eventFlags & Qt::LeftEdge) {
296  new_rect.setLeft(target.x());
297  if (new_rect.width() < minimumWidth()) {
298  new_rect.setLeft(new_rect.right() - minimumWidth());
299  }
300  } else if (eventFlags & Qt::RightEdge) {
301  new_rect.setRight(target.x());
302  if (new_rect.width() < minimumWidth()) {
303  new_rect.setRight(new_rect.left() + minimumWidth());
304  }
305  }
306 
307  // Prevent resizing out of the parent
308  new_rect &= parentWidget()->rect();
309 
310  resize(new_rect.size());
311  move(new_rect.topLeft());
312  }
313  } else {
314  // Get flag from mouse position
315  auto flags = get_in_event_mouse(event) & resizeFlags;
316 
317  // Change the cursor if the flag is active and the widget has this flag
318  if (flags == Qt::LeftEdge || flags == Qt::RightEdge) {
319  setCursor(Qt::SizeHorCursor);
320  } else if (flags == Qt::TopEdge || flags == Qt::BottomEdge) {
321  setCursor(Qt::SizeVerCursor);
322  } else if (flags == (Qt::TopEdge | Qt::LeftEdge)
323  || flags == (Qt::BottomEdge | Qt::RightEdge)) {
324  setCursor(Qt::SizeFDiagCursor);
325  } else if (flags == (Qt::TopEdge | Qt::RightEdge)
326  || flags == (Qt::BottomEdge | Qt::LeftEdge)) {
327  setCursor(Qt::SizeBDiagCursor);
328  } else {
329  // Otherwise change cursor to default
330  setCursor(Qt::ArrowCursor);
331  }
332  }
333  event->setAccepted(true);
334 }
void mousePressEvent(QMouseEvent *event) override
Mouse handler for close widget, hides parent widget.
void put_to_corner()
Puts close widget to right top corner.
close_widget(QWidget *parent)
Constructor for close widget.
void hideEvent(QHideEvent *event) override
Hide event handler for close widget.
QIcon getIcon(const QString &id)
Returns icon by given name.
Definition: icons.cpp:125
QPixmap * getPixmap(const QString &id)
Returns pixmap by given name, pixmap needs to be deleted by someone else.
Definition: icons.cpp:166
static fcIcons * instance()
Returns instance of fc_icons.
Definition: icons.cpp:36
void put_to_corner()
Puts move widget to left top corner.
Definition: decorations.cpp:99
void mousePressEvent(QMouseEvent *event) override
Sets moving point for move widget;.
QPoint point
Definition: decorations.h:34
void mouseMoveEvent(QMouseEvent *event) override
Mouse handler for move widget (moves parent widget)
move_widget(QWidget *parent)
Constructor for move widget.
Definition: decorations.cpp:84
Qt::Edges eventFlags
Definition: decorations.h:93
Qt::Edges get_in_event_mouse(const QMouseEvent *event) const
Get resizable_flag from mouse position.
void setResizable(Qt::Edges edges)
Set resizable flags.
Qt::Edges getResizable() const
Get resizable flags of wdiget.
void mousePressEvent(QMouseEvent *event) override
Checks if info_tab can be moved.
void resized(QRect rect)
Qt::Edges resizeFlags
Definition: decorations.h:94
static constexpr int event_width
Definition: decorations.h:77
void mouseMoveEvent(QMouseEvent *event) override
Called when mouse moved (mouse track is enabled).
static constexpr int margin_width
Definition: decorations.h:78
void mouseReleaseEvent(QMouseEvent *event) override
Restores cursor when resizing is done.
QPixmap minus
Definition: decorations.h:54
QPixmap plus
Definition: decorations.h:53
scale_widget(Shape s, QWidget *p=0)
Scale widget allowing scaling other widgets, shown in right top corner.
Definition: decorations.cpp:36
void paintEvent(QPaintEvent *event) override
Draws 2 icons for resizing.
Definition: decorations.cpp:56
void mousePressEvent(QMouseEvent *event) override
Mouse press event for scale widget.
Definition: decorations.cpp:69
enum event_type event
Definition: events.cpp:68
class fc_client * king()
Return fc_client instance.
Definition: gui_main.cpp:58
size_t size
Definition: specvec.h:64