Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_statusbar.cc
Go to the documentation of this file.
1/* This file is part of KimageShop^WKrayon^WKrita
2 *
3 * SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include "kis_statusbar.h"
9
10#include <QToolButton>
11#include <QAction>
12#include <QToolTip>
13#include <QStatusBar>
14
15#include <ksqueezedtextlabel.h>
16#include <klocalizedstring.h>
17#include <kformat.h>
18
19#include <KoColorProfile.h>
20#include <KoColorSpace.h>
21#include <KoToolManager.h>
22#include <KoViewConverter.h>
23#include <QHBoxLayout>
24
25#include <KisUsageLogger.h>
26
27#include <kis_icon_utils.h>
28
29#include <kis_types.h>
30#include <kis_image.h>
31#include <kis_layer_utils.h>
32#include <kis_selection.h>
33#include <kis_paint_device.h>
36
37#include "KisView.h"
38#include "KisDocument.h"
39#include "KisViewManager.h"
40#include "canvas/kis_canvas2.h"
41#include "kis_progress_widget.h"
42#include "kis_zoom_manager.h"
43#include <KisAngleSelector.h>
45#include <kis_signals_blocker.h>
46
47#include "KisMainWindow.h"
48#include "kis_config.h"
49
51
52enum {
55};
56
58 : m_viewManager(viewManager)
59 , m_imageView(0)
60 , m_statusBar(0)
61{
62}
63
65{
66 m_selectionStatus = new QToolButton();
67 m_selectionStatus->setObjectName("selection status");
68 m_selectionStatus->setIconSize(QSize(16,16));
69 m_selectionStatus->setAutoRaise(true);
70 m_selectionStatus->setEnabled(false);
72
73 m_statusBar = m_viewManager->mainWindow()->statusBar();
74
75 connect(m_selectionStatus, SIGNAL(clicked()), m_viewManager->selectionManager(), SLOT(slotToggleSelectionDecoration()));
76 connect(m_viewManager->selectionManager(), SIGNAL(displaySelectionChanged()), SLOT(updateSelectionToolTip()));
77 connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), this, SLOT(updateSelectionIcon()));
78
80 m_selectionStatus->setVisible(false);
81
82 m_statusBarStatusLabel = new KSqueezedTextLabel();
83 m_statusBarStatusLabel->setObjectName("statsBarStatusLabel");
84 m_statusBarStatusLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
85 m_statusBarStatusLabel->setContentsMargins(5, 5, 5, 5);
86 connect(KoToolManager::instance(), SIGNAL(changedStatusText(QString)),
87 m_statusBarStatusLabel, SLOT(setText(QString)));
89 m_statusBarStatusLabel->setVisible(false);
90
91 m_statusBarProfileLabel = new KSqueezedTextLabel();
92 m_statusBarProfileLabel->setObjectName("statsBarProfileLabel");
93 m_statusBarProfileLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
94 m_statusBarProfileLabel->setContentsMargins(5, 5, 5, 5);
96 m_statusBarProfileLabel->setVisible(false);
97
99 m_progress->setObjectName("ProgressBar");
101 m_progress->setVisible(false);
102 connect(m_progress, SIGNAL(sigCancellationRequested()), this, SIGNAL(sigCancellationRequested()));
103
105 m_progressUpdater->setAutoNestNames(true);
106
107 m_extraWidgetsParent = new QFrame;
108 m_extraWidgetsParent->setMinimumWidth(50);
109 m_extraWidgetsParent->setObjectName("Extra Widgets Parent");
110 m_extraWidgetsLayout = new QHBoxLayout;
111 m_extraWidgetsLayout->setContentsMargins(0, 0, 0, 0);
112 m_extraWidgetsLayout->setObjectName("Extra Widgets Layout");
115
117 m_memoryReportBox->setObjectName("memoryReportBox");
118 m_memoryReportBox->setFlat(true);
119 m_memoryReportBox->setContentsMargins(5, 5, 5, 5);
120 m_memoryReportBox->setMinimumWidth(120);
122 m_memoryReportBox->setVisible(false);
123
124 connect(m_memoryReportBox, SIGNAL(clicked()), SLOT(showMemoryInfoToolTip()));
125
127 SIGNAL(sigUpdateMemoryStatistics()),
128 SLOT(imageSizeChanged()));
129
131 m_canvasAngleSelector->setRange(-360.00, 360.0);
136
137 connect(m_canvasAngleSelector, SIGNAL(angleChanged(qreal)), SLOT(slotCanvasAngleSelectorAngleChanged(qreal)));
138 m_canvasAngleSelector->setVisible(false);
139}
140
144
146{
147 if (m_imageView) {
148 if (m_imageView->canvasBase()) {
149 m_imageView->canvasBase()->canvasController()->proxyObject->disconnect(this);
150 }
151 m_imageView->disconnect(this);
152 removeStatusBarItem(m_imageView->zoomManager()->zoomActionWidget());
153 m_imageView = 0;
154 }
155
156 if (imageView) {
157 m_imageView = imageView;
158 m_canvasAngleSelector->setVisible(true);
159 connect(m_imageView, SIGNAL(sigColorSpaceChanged(const KoColorSpace*)),
160 this, SLOT(updateStatusBarProfileLabel()));
161 connect(m_imageView, SIGNAL(sigProfileChanged(const KoColorProfile*)),
162 this, SLOT(updateStatusBarProfileLabel()));
163 connect(m_imageView, SIGNAL(sigSizeChanged(QPointF,QPointF)),
164 this, SLOT(imageSizeChanged()));
165 connect(m_imageView->canvasController()->proxyObject, &KoCanvasControllerProxyObject::documentRotationChanged,
169 addStatusBarItem(m_imageView->zoomManager()->zoomActionWidget());
170 }
171 else {
172 m_canvasAngleSelector->setVisible(false);
173 }
174
176}
177
178void KisStatusBar::addStatusBarItem(QWidget *widget, int stretch, bool permanent)
179{
180 StatusBarItem sbItem(widget);
181 if (permanent) {
182 m_statusBar->addPermanentWidget(widget, stretch);
183 }
184 else {
185 m_statusBar->addWidget(widget, stretch);
186 }
187 widget->setVisible(true);
188 m_statusBarItems.append(sbItem);
189}
190
192{
193 int i = 0;
194 Q_FOREACH(const StatusBarItem& sbItem, m_statusBarItems) {
195 if (sbItem.widget() == widget) {
196 break;
197 }
198 i++;
199 }
200
201 if (i < m_statusBarItems.count()) {
202 m_statusBar->removeWidget(m_statusBarItems[i].widget());
203 m_statusBarItems.remove(i);
204 }
205}
206
208{
209 Q_FOREACH(const StatusBarItem& sbItem, m_statusBarItems) {
210 sbItem.hide();
211 }
212}
213
215{
216 Q_FOREACH(const StatusBarItem& sbItem, m_statusBarItems) {
217 sbItem.show();
218 }
219}
220
221
223{
225
226 QString sizeText;
227 KisImageWSP image = m_imageView ? m_imageView->image() : 0;
228 if (image) {
229 qint32 w = image->width();
230 qint32 h = image->height();
231 sizeText = i18nc("@info:status width x height (file size)", "%1 &x %2 (%3)", w, h, m_shortMemoryTag);
232 } else {
233 sizeText = m_shortMemoryTag;
234 }
235
237 m_memoryReportBox->setText(sizeText);
239}
240
242{
243 QIcon icon;
244 if (!m_viewManager->selectionManager()->displaySelection()) {
245 icon = KisIconUtils::loadIcon("selection-mode_invisible");
246 } else if (m_viewManager->selectionManager()->showSelectionAsMask()) {
247 icon = KisIconUtils::loadIcon("selection-mode_mask");
248 } else /* if (!m_view->selectionManager()->showSelectionAsMask()) */ {
249 icon = KisIconUtils::loadIcon("selection-mode_ants");
250 }
251 m_selectionStatus->setIcon(icon);
252}
253
254namespace {
255QVector<KisNodeSP> fetchLayersWithSlowThumbnailGeneration(KisImageSP image)
256{
257 QVector<KisNodeSP> result;
258
260 [&result] (KisNodeSP node) {
261 if (node->preferredThumbnailBoundsMode() == KisThumbnailBoundsMode::Coarse) {
262 result.append(node);
263 }
264 });
265
266 return result;
267}
268}
269
270
272{
276 const KFormat format;
277
278 const QString imageStatsMsg =
279 i18nc("tooltip on statusbar memory reporting button (image stats)",
280 "Image size:\t %1\n"
281 " - layers:\t\t %2\n"
282 " - projections:\t %3\n"
283 " - instant preview:\t %4\n",
284 format.formatByteSize(stats.imageSize),
285 format.formatByteSize(stats.layersSize),
286 format.formatByteSize(stats.projectionsSize),
287 format.formatByteSize(stats.lodSize));
288
289 const QString memoryStatsMsg =
290 i18nc("tooltip on statusbar memory reporting button (total stats)",
291 "Memory used:\t %1 / %2\n"
292 " image data:\t %3 / %4\n"
293 " pool:\t\t %5 / %6\n"
294 " undo data:\t %7\n"
295 "\n"
296 "Swap used:\t %8",
297 format.formatByteSize(stats.totalMemorySize),
298 format.formatByteSize(stats.totalMemoryLimit),
299
300 format.formatByteSize(stats.realMemorySize),
301 format.formatByteSize(stats.tilesHardLimit),
302
303 format.formatByteSize(stats.poolSize),
304 format.formatByteSize(stats.tilesPoolLimit),
305
306 format.formatByteSize(stats.historicalMemorySize),
307 format.formatByteSize(stats.swapSize));
308
309 QString longStats = imageStatsMsg + "\n" + memoryStatsMsg;
310
311 QString shortStats = format.formatByteSize(stats.imageSize);
312 bool shouldUseWarningIcon = false;
313 const qint64 warnLevel = stats.tilesHardLimit - stats.tilesHardLimit / 8;
314
315 if (stats.imageSize > warnLevel ||
316 stats.realMemorySize > warnLevel) {
317
320 KisUsageLogger::log(QString("WARNING: %1 is running out of memory:%2\n").arg(m_imageView->document()->path()).arg(longStats));
321 }
322
323 shouldUseWarningIcon = true;
324 QString suffix =
325 i18nc("tooltip on statusbar memory reporting button",
326 "\n\nWARNING:\tOut of memory! Swapping has been started.\n"
327 "\t\tPlease configure more RAM for Krita in Settings dialog");
328 longStats += suffix;
329
330
331 }
332
333 if (m_imageView) {
334 const QVector<KisNodeSP> slowThumbnailNodes = fetchLayersWithSlowThumbnailGeneration(m_imageView->image());
335 if (!slowThumbnailNodes.isEmpty()) {
336 QString suffix =
337 i18nc("tooltip on statusbar memory reporting button",
338 "\n\nWARNING:\tSome layers took too much time to calculate\n"
339 "\t\ttheir thumbnails. They were switched into low-quality\n"
340 "\t\tthumbnails mode. Try purging unused image data with\n"
341 "\t\tImage->Purge Unused Image Data action.\n"
342 "Slow layers: ");
343
344 bool needsSeparator = false;
345 Q_FOREACH(KisNodeSP node, slowThumbnailNodes) {
346 if (needsSeparator) {
347 suffix += ", ";
348 }
349 suffix.append(QString("\"%1\"").arg(node->name()));
350 needsSeparator = true;
351 }
352 longStats += suffix;
353 shouldUseWarningIcon = true;
354 }
355 }
356
357 m_shortMemoryTag = shortStats;
358 m_longMemoryTag = longStats;
359
360 QIcon icon;
361 if (shouldUseWarningIcon) {
362 icon = KisIconUtils::loadIcon("warning");
363 }
364
365 m_memoryStatusIcon = icon;
366
370}
371
373{
374 QToolTip::showText(QCursor::pos(), m_memoryReportBox->toolTip(), m_memoryReportBox);
375}
376
378{
379 KisCanvas2 *canvas = m_viewManager->canvasBase();
380 if (!canvas) return;
381
382 KisCanvasController *canvasController = dynamic_cast<KisCanvasController*>(canvas->canvasController());
383 if (canvasController) {
384 canvasController->rotateCanvas(angle - canvas->rotationAngle());
385 }
386}
387
389{
390 KisCanvas2 *canvas = m_viewManager->canvasBase();
391 if (!canvas) return;
392
393 const qreal angleDiff = qAbs(m_canvasAngleSelector->angle()) -
394 qAbs(canvas->rotationAngle());
395
396 // Only update the UI if the angle difference is big enough. This improves the performance.
397 if (qAbs(angleDiff) >= 0.01) {
400 }
401}
402
404{
406
407 KisSelectionSP selection = m_viewManager->selection();
408 if (selection) {
409 m_selectionStatus->setEnabled(true);
410
411 QRect r = selection->selectedExactRect();
412
413 QString displayMode =
414 !m_viewManager->selectionManager()->displaySelection() ?
415 i18n("Hidden") :
416 (m_viewManager->selectionManager()->showSelectionAsMask() ?
417 i18n("Mask") : i18n("Ants"));
418
419 m_selectionStatus->setToolTip(
420 i18n("Selection: x = %1 y = %2 width = %3 height = %4\n"
421 "Display Mode: %5",
422 r.x(), r.y(), r.width(), r.height(), displayMode));
423 } else {
424 m_selectionStatus->setEnabled(false);
425 m_selectionStatus->setToolTip(i18n("No Selection"));
426 }
427}
428
430{
431 Q_UNUSED(image);
433}
434
436{
437 if (m_statusBarProfileLabel == 0) {
438 return;
439 }
440
441 if (!image) return;
442 if (image->profile() == 0) {
443 m_statusBarProfileLabel->setText(i18n("No profile"));
444 } else {
445 m_statusBarProfileLabel->setText(i18nc("<color space> <image profile>", "%1 %2", image->colorSpace()->name(), image->profile()->name()));
446 }
447
448}
449
450void KisStatusBar::setHelp(const QString &t)
451{
452 Q_UNUSED(t);
453}
454
456{
457 if (!m_imageView) return;
458
459 setProfile(m_imageView->image());
460}
461
466
467void KisStatusBar::addExtraWidget(QWidget *widget)
468{
469 m_extraWidgetsLayout->addWidget(widget);
470}
471
473{
474 m_extraWidgetsLayout->removeWidget(widget);
475}
476
@ IncreasingDirection_Clockwise
A widget with several options to select an angle.
@ FlipOptionsMode_ContextMenu
The flip options are shown only as a context menu when right-clicking the gauge widget.
qreal angle() const
Gets the current angle.
void setFlipOptionsMode(FlipOptionsMode newMode)
Sets the mode in which the flip options should be shown.
void setIncreasingDirection(KisAngleGauge::IncreasingDirection newIncreasingDirection)
Sets the increasing direction in the angle gauge.
void useFlatSpinBox(bool newUseFlatSpinBox)
Sets if the spin box should be flat.
void setAngle(qreal newAngle)
Sets the current angle.
void setRange(qreal newMinimum, qreal newMaximum)
Sets the minimum and maximum values for the angle.
qreal rotationAngle() const
canvas rotation in degrees
void rotateCanvas(qreal angle, const std::optional< KoViewTransformStillPoint > &stillPoint, bool isNativeGesture=false)
const KoColorSpace * colorSpace() const
qint32 width() const
qint32 height() const
const KoColorProfile * profile() const
void setCurrentMemory(qint64 memory)
void setImageWeight(qint64 memory)
KoProgressProxy * progressProxy()
QToolButton * m_selectionStatus
void updateStatusBarProfileLabel()
void setSelection(KisImageWSP image)
void removeStatusBarItem(QWidget *widget)
QIcon m_memoryStatusIcon
QString m_longMemoryTag
void showMemoryInfoToolTip()
QPointer< KisView > m_imageView
QString m_shortMemoryTag
void updateSelectionIcon()
void updateSelectionToolTip()
void addStatusBarItem(QWidget *widget, int stretch=0, bool permanent=false)
KSqueezedTextLabel * m_statusBarProfileLabel
void slotCanvasAngleSelectorAngleChanged(qreal angle)
QScopedPointer< KoProgressUpdater > m_progressUpdater
void removeExtraWidget(QWidget *widget)
void sigCancellationRequested()
void updateMemoryStatus()
QVector< StatusBarItem > m_statusBarItems
QPointer< KisViewManager > m_viewManager
bool m_memoryWarningLogged
QWidget * m_extraWidgetsParent
KisAngleSelector * m_canvasAngleSelector
void setProfile(KisImageWSP image)
KSqueezedTextLabel * m_statusBarStatusLabel
void setView(QPointer< KisView > imageView)
QBoxLayout * m_extraWidgetsLayout
KisProgressWidget * m_progress
void slotCanvasRotationChanged()
KisStatusBar(KisViewManager *view)
void addExtraWidget(QWidget *widget)
void hideAllStatusBarItems()
~KisStatusBar() override
void setHelp(const QString &t)
QPointer< QStatusBar > m_statusBar
void imageSizeChanged()
KisMemoryReportButton * m_memoryReportBox
void showAllStatusBarItems()
KoProgressUpdater * progressUpdater()
static void log(const QString &message)
Logs with date/time.
KoCanvasController * canvasController() const
void documentRotationChanged(qreal angle)
static KoToolManager * instance()
Return the toolmanager singleton.
@ IMAGE_SIZE_ID
@ POINTER_POSITION_ID
QIcon loadIcon(const QString &name)
void recursiveApplyNodes(NodePointer node, Functor func)
QString name() const
Statistics fetchMemoryStatistics(KisImageSP image) const
static KisMemoryStatisticsServer * instance()
QRect selectedExactRect() const
Slow, but exact way of determining the rectangle that encloses the selection.