6#include "decorationbutton.h"
7#include "decoratedclient.h"
9#include "decoration_p.h"
10#include "decorationbutton_p.h"
11#include "decorationsettings.h"
13#include <KLocalizedString>
16#include <QElapsedTimer>
17#include <QGuiApplication>
27 return qHash(uint(type), seed);
35 : decoration(decoration)
43 , doubleClickEnabled(false)
51DecorationButton::Private::~Private() =
default;
53void DecorationButton::Private::init()
55 auto c = decoration->client();
56 auto settings = decoration->settings();
58 case DecorationButtonType::Menu:
61 &DecorationButton::clicked,
65 decoration->requestShowWindowMenu(q->geometry().toRect());
71 &DecorationSettings::closeOnDoubleClickOnMenuChanged,
73 [
this](
bool enabled) {
74 doubleClickEnabled = enabled;
75 setPressAndHold(enabled);
78 doubleClickEnabled = settings->isCloseOnDoubleClickOnMenu();
79 setPressAndHold(settings->isCloseOnDoubleClickOnMenu());
82 case DecorationButtonType::ApplicationMenu:
83 setVisible(c->hasApplicationMenu());
88 &DecorationButton::clicked,
91 decoration->requestShowApplicationMenu(q->geometry().toRect(), 0 );
94 QObject::connect(c, &DecoratedClient::hasApplicationMenuChanged, q, &DecorationButton::setVisible);
95 QObject::connect(c, &DecoratedClient::applicationMenuActiveChanged, q, &DecorationButton::setChecked);
97 case DecorationButtonType::OnAllDesktops:
98 setVisible(settings->isOnAllDesktopsAvailable());
100 setChecked(c->isOnAllDesktops());
102 QObject::connect(settings.get(), &DecorationSettings::onAllDesktopsAvailableChanged, q, &DecorationButton::setVisible);
103 QObject::connect(c, &DecoratedClient::onAllDesktopsChanged, q, &DecorationButton::setChecked);
105 case DecorationButtonType::Minimize:
106 setEnabled(c->isMinimizeable());
108 QObject::connect(c, &DecoratedClient::minimizeableChanged, q, &DecorationButton::setEnabled);
110 case DecorationButtonType::Maximize:
111 setEnabled(c->isMaximizeable());
113 setChecked(c->isMaximized());
116 QObject::connect(c, &DecoratedClient::maximizeableChanged, q, &DecorationButton::setEnabled);
117 QObject::connect(c, &DecoratedClient::maximizedChanged, q, &DecorationButton::setChecked);
119 case DecorationButtonType::Close:
120 setEnabled(c->isCloseable());
122 QObject::connect(c, &DecoratedClient::closeableChanged, q, &DecorationButton::setEnabled);
124 case DecorationButtonType::ContextHelp:
125 setVisible(c->providesContextHelp());
127 QObject::connect(c, &DecoratedClient::providesContextHelpChanged, q, &DecorationButton::setVisible);
129 case DecorationButtonType::KeepAbove:
131 setChecked(c->isKeepAbove());
133 QObject::connect(c, &DecoratedClient::keepAboveChanged, q, &DecorationButton::setChecked);
135 case DecorationButtonType::KeepBelow:
137 setChecked(c->isKeepBelow());
139 QObject::connect(c, &DecoratedClient::keepBelowChanged, q, &DecorationButton::setChecked);
141 case DecorationButtonType::Shade:
142 setEnabled(c->isShadeable());
144 setChecked(c->isShaded());
146 QObject::connect(c, &DecoratedClient::shadedChanged, q, &DecorationButton::setChecked);
147 QObject::connect(c, &DecoratedClient::shadeableChanged, q, &DecorationButton::setEnabled);
149 case DecorationButtonType::Spacer:
158void DecorationButton::Private::setHovered(
bool set)
160 if (hovered == set) {
164 Q_EMIT q->hoveredChanged(hovered);
167void DecorationButton::Private::setEnabled(
bool set)
169 if (enabled == set) {
173 Q_EMIT q->enabledChanged(enabled);
178 Q_EMIT q->pressedChanged(
false);
183void DecorationButton::Private::setVisible(
bool set)
185 if (visible == set) {
189 Q_EMIT q->visibilityChanged(set);
194 Q_EMIT q->pressedChanged(
false);
199void DecorationButton::Private::setChecked(
bool set)
201 if (!checkable || checked == set) {
205 Q_EMIT q->checkedChanged(checked);
208void DecorationButton::Private::setCheckable(
bool set)
210 if (checkable == set) {
217 Q_EMIT q->checkableChanged(checkable);
220void DecorationButton::Private::setPressed(
Qt::MouseButton button,
bool pressed)
223 m_pressed = m_pressed | button;
225 m_pressed = m_pressed & ~button;
227 Q_EMIT q->pressedChanged(isPressed());
232 if (acceptedButtons == buttons) {
235 acceptedButtons = buttons;
236 Q_EMIT q->acceptedButtonsChanged(acceptedButtons);
239void DecorationButton::Private::startDoubleClickTimer()
241 if (!doubleClickEnabled) {
244 if (!m_doubleClickTimer) {
245 m_doubleClickTimer = std::make_unique<QElapsedTimer>();
247 m_doubleClickTimer->start();
250void DecorationButton::Private::invalidateDoubleClickTimer()
252 if (!m_doubleClickTimer) {
255 m_doubleClickTimer->invalidate();
258bool DecorationButton::Private::wasDoubleClick()
const
260 if (!m_doubleClickTimer || !m_doubleClickTimer->isValid()) {
266void DecorationButton::Private::setPressAndHold(
bool enable)
268 if (pressAndHold == enable) {
271 pressAndHold = enable;
273 m_pressAndHoldTimer.reset();
277void DecorationButton::Private::startPressAndHold()
282 if (!m_pressAndHoldTimer) {
283 m_pressAndHoldTimer.reset(
new QTimer());
284 m_pressAndHoldTimer->setSingleShot(
true);
286 q->clicked(Qt::LeftButton);
292void DecorationButton::Private::stopPressAndHold()
294 if (m_pressAndHoldTimer) {
295 m_pressAndHoldTimer->stop();
299QString DecorationButton::Private::typeToString(DecorationButtonType type)
302 case DecorationButtonType::Menu:
303 return i18n(
"More actions for this window");
304 case DecorationButtonType::ApplicationMenu:
305 return i18n(
"Application menu");
306 case DecorationButtonType::OnAllDesktops:
307 if (this->q->isChecked())
308 return i18n(
"On one desktop");
310 return i18n(
"On all desktops");
311 case DecorationButtonType::Minimize:
312 return i18n(
"Minimize");
313 case DecorationButtonType::Maximize:
314 if (this->q->isChecked())
315 return i18n(
"Restore");
317 return i18n(
"Maximize");
318 case DecorationButtonType::Close:
319 return i18n(
"Close");
320 case DecorationButtonType::ContextHelp:
321 return i18n(
"Context help");
322 case DecorationButtonType::Shade:
323 if (this->q->isChecked())
324 return i18n(
"Unshade");
326 return i18n(
"Shade");
327 case DecorationButtonType::KeepBelow:
328 if (this->q->isChecked())
329 return i18n(
"Don't keep below other windows");
331 return i18n(
"Keep below other windows");
332 case DecorationButtonType::KeepAbove:
333 if (this->q->isChecked())
334 return i18n(
"Don't keep above other windows");
336 return i18n(
"Keep above other windows");
342DecorationButton::DecorationButton(DecorationButtonType type, Decoration *decoration,
QObject *parent)
344 , d(new Private(
type, decoration, this))
346 decoration->d->addButton(
this);
347 connect(
this, &DecorationButton::geometryChanged,
this,
static_cast<void (DecorationButton::*)(
const QRectF &)
>(&DecorationButton::update));
348 auto updateSlot =
static_cast<void (DecorationButton::*)()
>(&DecorationButton::update);
349 connect(
this, &DecorationButton::hoveredChanged,
this, updateSlot);
350 connect(
this, &DecorationButton::hoveredChanged,
this, [
this](
bool hovered) {
353 const QString type = this->d->typeToString(this->type());
354 this->decoration()->requestShowToolTip(type);
356 this->decoration()->requestHideToolTip();
359 connect(
this, &DecorationButton::pressedChanged,
this, updateSlot);
360 connect(
this, &DecorationButton::pressedChanged,
this, [
this](
bool pressed) {
362 this->decoration()->requestHideToolTip();
365 connect(
this, &DecorationButton::checkedChanged,
this, updateSlot);
366 connect(
this, &DecorationButton::enabledChanged,
this, updateSlot);
367 connect(
this, &DecorationButton::visibilityChanged,
this, updateSlot);
368 connect(
this, &DecorationButton::hoveredChanged,
this, [
this](
bool hovered) {
370 Q_EMIT pointerEntered();
372 Q_EMIT pointerLeft();
375 connect(
this, &DecorationButton::pressedChanged,
this, [
this](
bool p) {
384DecorationButton::~DecorationButton() =
default;
386void DecorationButton::update(
const QRectF &rect)
388 decoration()->update(rect.
isNull() ? geometry().toRect() : rect.
toRect());
391void DecorationButton::update()
396QSizeF DecorationButton::size()
const
398 return d->geometry.size();
401bool DecorationButton::isPressed()
const
403 return d->isPressed();
406bool DecorationButton::isHovered()
const
411bool DecorationButton::isEnabled()
const
416bool DecorationButton::isChecked()
const
421bool DecorationButton::isCheckable()
const
426bool DecorationButton::isVisible()
const
431QRectF DecorationButton::geometry()
const
436Decoration *DecorationButton::decoration()
const
438 return d->decoration;
443 return d->acceptedButtons;
453 d->setAcceptedButtons(value);
456void DecorationButton::setEnabled(
bool value)
458 d->setEnabled(value);
461void DecorationButton::setChecked(
bool value)
463 d->setChecked(value);
466void DecorationButton::setCheckable(
bool value)
468 d->setCheckable(value);
471void DecorationButton::setVisible(
bool value)
473 d->setVisible(value);
476void DecorationButton::setGeometry(
const QRectF &geometry)
478 if (d->geometry == geometry) {
481 d->geometry = geometry;
482 Q_EMIT geometryChanged(d->geometry);
485bool DecorationButton::contains(
const QPointF &pos)
const
487 auto flooredPoint =
QPoint(std::floor(pos.
x()), std::floor(pos.
y()));
488 return d->geometry.toRect().contains(flooredPoint);
491bool DecorationButton::event(
QEvent *event)
493 switch (event->type()) {
495 hoverEnterEvent(
static_cast<QHoverEvent *
>(event));
498 hoverLeaveEvent(
static_cast<QHoverEvent *
>(event));
504 mousePressEvent(
static_cast<QMouseEvent *
>(event));
507 mouseReleaseEvent(
static_cast<QMouseEvent *
>(event));
520void DecorationButton::hoverEnterEvent(
QHoverEvent *event)
522 if (!d->enabled || !d->visible || !contains(
event->position())) {
526 event->setAccepted(
true);
529void DecorationButton::hoverLeaveEvent(
QHoverEvent *event)
531 if (!d->enabled || !d->visible || !d->hovered || contains(
event->position())) {
534 d->setHovered(
false);
535 event->setAccepted(
true);
538void DecorationButton::hoverMoveEvent(
QHoverEvent *event)
543void DecorationButton::mouseMoveEvent(
QMouseEvent *event)
545 if (!d->enabled || !d->visible || !d->hovered) {
548 if (!contains(
event->position())) {
549 d->setHovered(
false);
550 event->setAccepted(
true);
554void DecorationButton::mousePressEvent(
QMouseEvent *event)
556 if (!d->enabled || !d->visible || !contains(
event->position()) || !d->acceptedButtons.testFlag(
event->button())) {
559 d->setPressed(
event->button(),
true);
560 event->setAccepted(
true);
563 if (d->wasDoubleClick()) {
564 event->setAccepted(
true);
565 Q_EMIT doubleClicked();
567 d->invalidateDoubleClickTimer();
570 d->startPressAndHold();
574void DecorationButton::mouseReleaseEvent(
QMouseEvent *event)
576 if (!d->enabled || !d->visible || !d->isPressed(
event->button())) {
579 if (contains(
event->position())) {
581 Q_EMIT clicked(
event->button());
583 d->stopPressAndHold();
586 d->setPressed(
event->button(),
false);
587 event->setAccepted(
true);
590 d->startDoubleClickTimer();
594void DecorationButton::wheelEvent(
QWheelEvent *event)
601#include "moc_decorationbutton.cpp"
QString i18n(const char *text, const TYPE &arg...)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
Type type(const QSqlDatabase &db)
Framework for creating window decorations.
DecorationButtonType
The DecorationButtonType is a helper type for the DecorationButton.
KTEXTEDITOR_EXPORT size_t qHash(KTextEditor::Cursor cursor, size_t seed=0) noexcept
QStyleHints * styleHints()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual bool event(QEvent *e)
bool isNull() const const
QRect toRect() const const
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)