Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_floating_message.cpp
Go to the documentation of this file.
1/*
2 * This file is part of KimageShop^WKrayon^WKrita
3 *
4 * SPDX-FileCopyrightText: 2004 Christian Muehlhaeuser <chris@chris.de>
5 * SPDX-FileCopyrightText: 2004-2006 Seb Ruiz <ruiz@kde.org>
6 * SPDX-FileCopyrightText: 2004, 2005 Max Howell <max.howell@methylblue.com>
7 * SPDX-FileCopyrightText: 2005 Gabor Lehel <illissius@gmail.com>
8 * SPDX-FileCopyrightText: 2008, 2009 Mark Kretschmann <kretschmann@kde.org>
9 * SPDX-FileCopyrightText: 2012 Boudewijn Rempt <boud@valdyas.org>
10 * SPDX-FileCopyrightText: 2021 Alvin Wong <alvin@alvinhc.com>
11 *
12 */
14
15#include <QApplication>
16#include <QScreen>
17#include <QMouseEvent>
18#include <QPainter>
19#include <QRegularExpression>
20#include <QScreen>
21#include <QLabel>
22#include <QGraphicsDropShadowEffect>
23
24#include <kis_icon.h>
25#include <kis_debug.h>
26#include "kis_global.h"
27
28
29#define OSD_WINDOW_OPACITY 0.85
30
31static void addDropShadow(QWidget *widget, QColor color)
32{
33 QGraphicsDropShadowEffect *effect = new QGraphicsDropShadowEffect(widget);
34 effect->setBlurRadius(6);
35 effect->setOffset(0);
36 effect->setColor(color);
37 widget->setGraphicsEffect(effect);
38}
39
40static Qt::AlignmentFlag flagsToAlignmentFlags(int flags)
41{
42 constexpr int mask = Qt::AlignLeft
43 | Qt::AlignRight
44 | Qt::AlignHCenter
45 | Qt::AlignJustify
46 | Qt::AlignTop
47 | Qt::AlignBottom
48 | Qt::AlignVCenter
49 | Qt::AlignCenter;
50 return Qt::AlignmentFlag(flags & mask);
51}
52
53KisFloatingMessage::KisFloatingMessage(const QString &message, QWidget *parent, bool showOverParent, int timeout, Priority priority, int alignment)
54 : QWidget(parent)
55 , m_message(message)
56 , m_showOverParent(showOverParent)
57 , m_timeout(timeout)
58 , m_priority(priority)
59 , m_alignment(alignment)
60{
61 m_icon = KisIconUtils::loadIcon("krita-branding").pixmap(256, 256).toImage();
62
63 setWindowFlags(Qt::FramelessWindowHint | Qt::ToolTip | Qt::WindowTransparentForInput);
64 setFocusPolicy(Qt::NoFocus);
65 setAttribute(Qt::WA_ShowWithoutActivating);
66
67 m_messageLabel = new QLabel(message, this);
68 m_messageLabel->setAttribute(Qt::WA_TranslucentBackground);
69 m_iconLabel = new QLabel(this);
70 m_iconLabel->setAttribute(Qt::WA_TranslucentBackground);
71 {
72 int h, s, v;
73 palette().color( QPalette::Normal, QPalette::WindowText ).getHsv( &h, &s, &v );
74 const QColor shadowColor = v > 128 ? Qt::black : Qt::white;
75 addDropShadow(m_messageLabel, shadowColor);
76 addDropShadow(m_iconLabel, shadowColor);
77 }
78
79 m_timer.setSingleShot( true );
80 connect(&m_timer, SIGNAL(timeout()), SLOT(startFade()));
81 connect(this, SIGNAL(destroyed()), SLOT(widgetDeleted()));
82}
83
84void KisFloatingMessage::tryOverrideMessage(const QString message,
85 const QIcon& icon,
86 int timeout,
88 int alignment)
89{
90#ifndef Q_OS_HAIKU
91 if ((int)priority > (int)m_priority) return;
92
93 m_message = message;
94 m_messageLabel->setText(message);
95 setIcon(icon);
96 m_timeout = timeout;
97 m_priority = priority;
98 m_alignment = alignment;
100 update();
101#endif
102}
103
105{
106 if (widgetQueuedForDeletion) return;
107
109 m_messageLabel->setWordWrap(m_alignment & Qt::TextWordWrap);
110 m_messageLabel->adjustSize();
111
112 QRect geom = determineMetrics(fontMetrics().horizontalAdvance('x'));
113 setGeometry(geom);
114 setWindowOpacity(OSD_WINDOW_OPACITY);
115
116 QRect rect(QPoint(), geom.size());
117 rect.adjust(m_m, m_m, -m_m, -m_m);
118 if (!m_icon.isNull()) {
119 QRect r(rect);
120 r.setTop((size().height() - m_scaledIcon.height() ) / 2);
121 r.setSize(m_scaledIcon.size());
122 m_iconLabel->setPixmap(m_scaledIcon);
123 m_iconLabel->setFixedSize(r.size());
124 m_iconLabel->move(r.topLeft());
125 m_iconLabel->show();
126 rect.setLeft(rect.left() + m_scaledIcon.width() + m_m);
127 } else {
128 m_iconLabel->hide();
129 }
130 m_messageLabel->setFixedSize(rect.size());
131 m_messageLabel->move(rect.topLeft());
132
133 QWidget::setVisible(true);
134 m_fadeTimeLine.stop();
135 m_timer.start(m_timeout);
136}
137
139{
140 m_showOverParent = show;
141}
142
143void KisFloatingMessage::setIcon(const QIcon& icon)
144{
145 m_icon = icon.pixmap(256, 256).toImage();
146}
147
148const int MARGIN = 20;
149
151{
152 m_m = M;
153
154 const QSize minImageSize = m_icon.size().boundedTo(QSize(100, 100));
155
156 // determine a sensible maximum size, don't cover the whole desktop or cross the screen
157 const QSize margin( (M + MARGIN) * 2, (M + MARGIN) * 2); //margins
158 const QSize image = m_icon.isNull() ? QSize(0, 0) : minImageSize;
159 QRect geom = parentWidget()->geometry();
160 QPoint p(geom.width() / 2 + geom.left(), geom.height() / 2 + geom.top());
161 QScreen *s = qApp->screenAt(p);
162 QSize max;
163 if (s) {
164 max = QSize(s->availableGeometry().size() - margin);
165 }
166 else {
167 max = QSize(1024, 768);
168 }
169 // If we don't do that, the boundingRect() might not be suitable for drawText() (Qt issue N67674)
170 m_message.replace(QRegularExpression( " +\n"), "\n");
171 // remove consecutive line breaks
172 m_message.replace(QRegularExpression( "\n+"), "\n");
173
174 // The osd cannot be larger than the screen
175 QRect rect = fontMetrics().boundingRect(0, 0, max.width() - image.width(), max.height(),
177
178 if (!m_icon.isNull()) {
179 const int availableWidth = max.width() - rect.width() - M; //WILL be >= (minImageSize.width() - M)
180
181 m_scaledIcon = QPixmap::fromImage(m_icon.scaled(qMin(availableWidth, m_icon.width()),
182 qMin( rect.height(), m_icon.height()),
183 Qt::KeepAspectRatio, Qt::SmoothTransformation));
184
185 const int widthIncludingImage = rect.width() + m_scaledIcon.width() + M; //margin between text + image
186 rect.setWidth( widthIncludingImage );
187 }
188
189 // expand in all directions by 2*M
190 //
191 // take care with this rect, because it must be *bigger*
192 // than the rect we paint the message in
193 rect = kisGrowRect(rect, 2 * M);
194
195
196
197 const QSize newSize = rect.size();
198 QRect screen;
199 if (s) {
200 screen = s->availableGeometry();
201 }
202 else {
203 screen = QRect(0, 0, 1024, 768);
204 }
205
206 QPoint newPos(MARGIN, MARGIN);
207
208 if (parentWidget() && m_showOverParent) {
209 screen = parentWidget()->geometry();
210 screen.setTopLeft(parentWidget()->mapToGlobal(QPoint(MARGIN, MARGIN + 50)));
211 newPos = screen.topLeft();
212 }
213 else {
214 // move to the right
215 newPos.rx() = screen.width() - MARGIN - newSize.width();
216
217 //ensure we don't dip below the screen
218 if (newPos.y() + newSize.height() > screen.height() - MARGIN) {
219 newPos.ry() = screen.height() - MARGIN - newSize.height();
220 }
221 // correct for screen position
222 newPos += screen.topLeft();
223
224 if (parentWidget()) {
225 // Move a bit to the left as there could be a scrollbar
226 newPos.setX(newPos.x() - MARGIN);
227 }
228 }
229
230 QRect rc(newPos, rect.size());
231
232 return rc;
233}
234
236{
237 m_fadeTimeLine.setDuration(500);
238 m_fadeTimeLine.setEasingCurve(QEasingCurve::InCurve);
239 m_fadeTimeLine.setLoopCount(1);
240 m_fadeTimeLine.setFrameRange(0, 10);
241 connect(&m_fadeTimeLine, SIGNAL(finished()), SLOT(removeMessage()));
242 connect(&m_fadeTimeLine, SIGNAL(frameChanged(int)), SLOT(updateOpacity(int)));
243 m_fadeTimeLine.start();
244}
245
247{
248 m_timer.stop();
249 m_fadeTimeLine.stop();
251
252 hide();
253 deleteLater();
254}
255
257{
258 setWindowOpacity(OSD_WINDOW_OPACITY / 10.0 * (10 - value));
259}
260
float value(const T *src, size_t ch)
const Params2D p
qreal v
#define MARGIN
void setIcon(const QIcon &icon)
KisFloatingMessage(const QString &message, QWidget *parent, bool showOverParent, int timeout, Priority priority, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
void tryOverrideMessage(const QString message, const QIcon &icon, int timeout, KisFloatingMessage::Priority priority, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
QRect determineMetrics(const int M)
void setShowOverParent(bool show)
Show message above parent widget instead of screen.
static Qt::AlignmentFlag flagsToAlignmentFlags(int flags)
const int MARGIN
static void addDropShadow(QWidget *widget, QColor color)
#define OSD_WINDOW_OPACITY
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
static void addDropShadow(QWidget *widget)
QIcon loadIcon(const QString &name)
rgba palette[MAX_PALETTE]
Definition palette.c:35