KDecoration2

decorationbuttongroup.cpp
1 /*
2  * SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5  */
6 #include "decorationbuttongroup.h"
7 #include "decoration.h"
8 #include "decorationbuttongroup_p.h"
9 #include "decorationsettings.h"
10 
11 #include <QDebug>
12 
13 namespace KDecoration2
14 {
15 DecorationButtonGroup::Private::Private(Decoration *decoration, DecorationButtonGroup *parent)
16  : decoration(decoration)
17  , spacing(0.0)
18  , q(parent)
19 {
20 }
21 
22 DecorationButtonGroup::Private::~Private() = default;
23 
24 void DecorationButtonGroup::Private::setGeometry(const QRectF &geo)
25 {
26  if (geometry == geo) {
27  return;
28  }
29  geometry = geo;
30  Q_EMIT q->geometryChanged(geometry);
31 }
32 
33 namespace
34 {
35 static bool s_layoutRecursion = false;
36 }
37 
38 void DecorationButtonGroup::Private::updateLayout()
39 {
40  if (s_layoutRecursion) {
41  return;
42  }
43  s_layoutRecursion = true;
44  const QPointF &pos = geometry.topLeft();
45  // first calculate new size
46  qreal height = 0;
47  qreal width = 0;
48  for (auto it = buttons.constBegin(); it != buttons.constEnd(); ++it) {
49  if (!(*it)->isVisible()) {
50  continue;
51  }
52  height = qMax(height, qreal((*it)->size().height()));
53  width += (*it)->size().width();
54  if (it + 1 != buttons.constEnd()) {
55  width += spacing;
56  }
57  }
58  setGeometry(QRectF(pos, QSizeF(width, height)));
59 
60  // now position all buttons
61  qreal position = pos.x();
62  const auto &constButtons = buttons;
63  for (auto button : constButtons) {
64  if (!button->isVisible()) {
65  continue;
66  }
67  const QSizeF size = button->size();
68  // TODO: center
69  button->setGeometry(QRectF(QPointF(position, pos.y()), size));
70  position += size.width() + spacing;
71  }
72  s_layoutRecursion = false;
73 }
74 
75 DecorationButtonGroup::DecorationButtonGroup(Decoration *parent)
76  : QObject(parent)
77  , d(new Private(parent, this))
78 {
79 }
80 
81 DecorationButtonGroup::DecorationButtonGroup(DecorationButtonGroup::Position type,
82  Decoration *parent,
83  std::function<DecorationButton *(DecorationButtonType, Decoration *, QObject *)> buttonCreator)
84  : QObject(parent)
85  , d(new Private(parent, this))
86 {
87  auto settings = parent->settings();
88  auto createButtons = [=] {
89  const auto &buttons = (type == Position::Left) ? settings->decorationButtonsLeft() : settings->decorationButtonsRight();
90  for (DecorationButtonType type : buttons) {
91  if (DecorationButton *b = buttonCreator(type, parent, this)) {
92  addButton(QPointer<DecorationButton>(b));
93  }
94  }
95  };
96  createButtons();
97  auto changed = type == Position::Left ? &DecorationSettings::decorationButtonsLeftChanged : &DecorationSettings::decorationButtonsRightChanged;
98  connect(settings.data(), changed, this, [this, createButtons] {
99  qDeleteAll(d->buttons);
100  d->buttons.clear();
101  createButtons();
102  });
103 }
104 
105 DecorationButtonGroup::~DecorationButtonGroup() = default;
106 
107 QPointer<Decoration> DecorationButtonGroup::decoration() const
108 {
109  return QPointer<Decoration>(d->decoration);
110 }
111 
112 QRectF DecorationButtonGroup::geometry() const
113 {
114  return d->geometry;
115 }
116 
118 {
119  // TODO: check for deletion of button
120  auto it = std::find_if(d->buttons.begin(), d->buttons.end(), [type](const QPointer<DecorationButton> &button) {
121  return button->type() == type;
122  });
123  return it != d->buttons.end();
124 }
125 
126 qreal DecorationButtonGroup::spacing() const
127 {
128  return d->spacing;
129 }
130 
131 QPointF DecorationButtonGroup::pos() const
132 {
133  return d->geometry.topLeft();
134 }
135 
136 void DecorationButtonGroup::setPos(const QPointF &pos)
137 {
138  if (d->geometry.topLeft() == pos) {
139  return;
140  }
141  d->setGeometry(QRectF(pos, d->geometry.size()));
142  d->updateLayout();
143 }
144 
145 void DecorationButtonGroup::setSpacing(qreal spacing)
146 {
147  if (d->spacing == spacing) {
148  return;
149  }
150  d->spacing = spacing;
151  Q_EMIT spacingChanged(d->spacing);
152  d->updateLayout();
153 }
154 
156 {
157  Q_ASSERT(!button.isNull());
158  connect(button.data(), &DecorationButton::visibilityChanged, this, [this]() {
159  d->updateLayout();
160  });
161  connect(button.data(), &DecorationButton::geometryChanged, this, [this]() {
162  d->updateLayout();
163  });
164  d->buttons.append(button);
165  d->updateLayout();
166 }
167 
169 {
170  return d->buttons;
171 }
172 
174 {
175  bool needUpdate = false;
176  auto it = d->buttons.begin();
177  while (it != d->buttons.end()) {
178  if ((*it)->type() == type) {
179  it = d->buttons.erase(it);
180  needUpdate = true;
181  } else {
182  it++;
183  }
184  }
185  if (needUpdate) {
186  d->updateLayout();
187  }
188 }
189 
191 {
192  bool needUpdate = false;
193  auto it = d->buttons.begin();
194  while (it != d->buttons.end()) {
195  if (*it == button) {
196  it = d->buttons.erase(it);
197  needUpdate = true;
198  } else {
199  it++;
200  }
201  }
202  if (needUpdate) {
203  d->updateLayout();
204  }
205 }
206 
207 void DecorationButtonGroup::paint(QPainter *painter, const QRect &repaintArea)
208 {
209  const auto &buttons = d->buttons;
210  for (auto button : buttons) {
211  if (!button->isVisible()) {
212  continue;
213  }
214  button->paint(painter, repaintArea);
215  }
216 }
217 
218 } // namespace
T * data() const const
Framework for creating window decorations.
virtual void paint(QPainter *painter, const QRect &repaintArea)
Paints the DecorationButtonGroup.
Left
DecorationButtonType
The DecorationButtonType is a helper type for the DecorationButton.
qreal x() const const
qreal y() const const
void addButton(const QPointer< DecorationButton > &button)
Adds button to the DecorationButtonGroup and triggers a re-layout of all DecorationButtons.
bool hasButton(DecorationButtonType type) const
void removeButton(const QPointer< DecorationButton > &button)
Removes button from the DecorationButtonGroup and triggers a re-layout of all DecorationButtons.
bool isNull() const const
QPointF topLeft() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
QVector< QPointer< DecorationButton > > buttons() const
qreal width() const const
QRectF geometry
The geometry of the DecorationButton in Decoration-local coordinates.
Q_EMITQ_EMIT
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sun Jun 20 2021 23:07:39 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.