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 <QRegExp>
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 (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
170 // If we don't do that, the boundingRect() might not be suitable for drawText() (Qt issue N67674)
171 m_message.replace(QRegExp( " +\n"), "\n");
172 // remove consecutive line breaks
173 m_message.replace(QRegExp( "\n+"), "\n");
174#else
175 // If we don't do that, the boundingRect() might not be suitable for drawText() (Qt issue N67674)
176 QRegExp r(" +\n");
177 r.replaceIn(m_message, "\n");
178
179 // remove consecutive line breaks
180 QRegExp r2(( "\n+"));
181 r2.replaceIn(m_message, "\n");
182#endif
183
184 // The osd cannot be larger than the screen
185 QRect rect = fontMetrics().boundingRect(0, 0, max.width() - image.width(), max.height(),
187
188 if (!m_icon.isNull()) {
189 const int availableWidth = max.width() - rect.width() - M; //WILL be >= (minImageSize.width() - M)
190
191 m_scaledIcon = QPixmap::fromImage(m_icon.scaled(qMin(availableWidth, m_icon.width()),
192 qMin( rect.height(), m_icon.height()),
193 Qt::KeepAspectRatio, Qt::SmoothTransformation));
194
195 const int widthIncludingImage = rect.width() + m_scaledIcon.width() + M; //margin between text + image
196 rect.setWidth( widthIncludingImage );
197 }
198
199 // expand in all directions by 2*M
200 //
201 // take care with this rect, because it must be *bigger*
202 // than the rect we paint the message in
203 rect = kisGrowRect(rect, 2 * M);
204
205
206
207 const QSize newSize = rect.size();
208 QRect screen;
209 if (s) {
210 screen = s->availableGeometry();
211 }
212 else {
213 screen = QRect(0, 0, 1024, 768);
214 }
215
216 QPoint newPos(MARGIN, MARGIN);
217
218 if (parentWidget() && m_showOverParent) {
219 screen = parentWidget()->geometry();
220 screen.setTopLeft(parentWidget()->mapToGlobal(QPoint(MARGIN, MARGIN + 50)));
221 newPos = screen.topLeft();
222 }
223 else {
224 // move to the right
225 newPos.rx() = screen.width() - MARGIN - newSize.width();
226
227 //ensure we don't dip below the screen
228 if (newPos.y() + newSize.height() > screen.height() - MARGIN) {
229 newPos.ry() = screen.height() - MARGIN - newSize.height();
230 }
231 // correct for screen position
232 newPos += screen.topLeft();
233
234 if (parentWidget()) {
235 // Move a bit to the left as there could be a scrollbar
236 newPos.setX(newPos.x() - MARGIN);
237 }
238 }
239
240 QRect rc(newPos, rect.size());
241
242 return rc;
243}
244
246{
247 m_fadeTimeLine.setDuration(500);
248 m_fadeTimeLine.setEasingCurve(QEasingCurve::InCurve);
249 m_fadeTimeLine.setLoopCount(1);
250 m_fadeTimeLine.setFrameRange(0, 10);
251 connect(&m_fadeTimeLine, SIGNAL(finished()), SLOT(removeMessage()));
252 connect(&m_fadeTimeLine, SIGNAL(frameChanged(int)), SLOT(updateOpacity(int)));
253 m_fadeTimeLine.start();
254}
255
257{
258 m_timer.stop();
259 m_fadeTimeLine.stop();
261
262 hide();
263 deleteLater();
264}
265
267{
268 setWindowOpacity(OSD_WINDOW_OPACITY / 10.0 * (10 - value));
269}
270
float value(const T *src, size_t ch)
QPointF r2
const Params2D p
qreal v
#define MARGIN
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
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