File indexing completed on 2024-05-19 04:29:08
0001 /* This file is part of KimageShop^WKrayon^WKrita 0002 * 0003 * SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "kis_statusbar.h" 0009 0010 #include <QLabel> 0011 #include <QFontMetrics> 0012 #include <QToolButton> 0013 #include <QPushButton> 0014 #include <QAction> 0015 #include <QToolTip> 0016 #include <QStatusBar> 0017 0018 #include <ksqueezedtextlabel.h> 0019 #include <klocalizedstring.h> 0020 #include <kformat.h> 0021 0022 #include <KoColorProfile.h> 0023 #include <KoColorSpace.h> 0024 #include <KoToolManager.h> 0025 #include <KoViewConverter.h> 0026 #include <QHBoxLayout> 0027 0028 #include <KisUsageLogger.h> 0029 0030 #include <kis_icon_utils.h> 0031 0032 #include <kis_types.h> 0033 #include <kis_image.h> 0034 #include <kis_selection.h> 0035 #include <kis_paint_device.h> 0036 #include <kis_selection_manager.h> 0037 #include "kis_memory_statistics_server.h" 0038 0039 #include "KisView.h" 0040 #include "KisDocument.h" 0041 #include "KisViewManager.h" 0042 #include "canvas/kis_canvas2.h" 0043 #include "kis_progress_widget.h" 0044 #include "kis_zoom_manager.h" 0045 #include <KisAngleSelector.h> 0046 #include <kis_canvas_controller.h> 0047 #include <kis_signals_blocker.h> 0048 0049 #include "KisMainWindow.h" 0050 #include "kis_config.h" 0051 0052 #include "widgets/KisMemoryReportButton.h" 0053 0054 enum { 0055 IMAGE_SIZE_ID, 0056 POINTER_POSITION_ID 0057 }; 0058 0059 KisStatusBar::KisStatusBar(KisViewManager *viewManager) 0060 : m_viewManager(viewManager) 0061 , m_imageView(0) 0062 , m_statusBar(0) 0063 { 0064 } 0065 0066 void KisStatusBar::setup() 0067 { 0068 m_selectionStatus = new QToolButton(); 0069 m_selectionStatus->setObjectName("selection status"); 0070 m_selectionStatus->setIconSize(QSize(16,16)); 0071 m_selectionStatus->setAutoRaise(true); 0072 m_selectionStatus->setEnabled(false); 0073 updateSelectionIcon(); 0074 0075 m_statusBar = m_viewManager->mainWindow()->statusBar(); 0076 0077 connect(m_selectionStatus, SIGNAL(clicked()), m_viewManager->selectionManager(), SLOT(slotToggleSelectionDecoration())); 0078 connect(m_viewManager->selectionManager(), SIGNAL(displaySelectionChanged()), SLOT(updateSelectionToolTip())); 0079 connect(m_viewManager->mainWindow(), SIGNAL(themeChanged()), this, SLOT(updateSelectionIcon())); 0080 0081 addStatusBarItem(m_selectionStatus); 0082 m_selectionStatus->setVisible(false); 0083 0084 #ifdef Q_OS_ANDROID 0085 m_fullscreenToggle = new QToolButton; 0086 m_fullscreenToggle->setObjectName("Toggle Fullscreen"); 0087 m_fullscreenToggle->setCheckable(false); 0088 m_fullscreenToggle->setToolTip(i18n("Toggle Fullscreen")); 0089 m_fullscreenToggle->setAutoRaise(true); 0090 m_fullscreenToggle->setIcon(KisIconUtils::loadIcon("view-fullscreen")); 0091 addStatusBarItem(m_fullscreenToggle); 0092 m_fullscreenToggle->setVisible(true); 0093 connect(m_fullscreenToggle, SIGNAL(clicked()), m_viewManager, SLOT(slotToggleFullscreen())); 0094 #endif 0095 0096 m_statusBarStatusLabel = new KSqueezedTextLabel(); 0097 m_statusBarStatusLabel->setObjectName("statsBarStatusLabel"); 0098 m_statusBarStatusLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); 0099 m_statusBarStatusLabel->setContentsMargins(5, 5, 5, 5); 0100 connect(KoToolManager::instance(), SIGNAL(changedStatusText(QString)), 0101 m_statusBarStatusLabel, SLOT(setText(QString))); 0102 addStatusBarItem(m_statusBarStatusLabel, 2); 0103 m_statusBarStatusLabel->setVisible(false); 0104 0105 m_statusBarProfileLabel = new KSqueezedTextLabel(); 0106 m_statusBarProfileLabel->setObjectName("statsBarProfileLabel"); 0107 m_statusBarProfileLabel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); 0108 m_statusBarProfileLabel->setContentsMargins(5, 5, 5, 5); 0109 addStatusBarItem(m_statusBarProfileLabel, 3); 0110 m_statusBarProfileLabel->setVisible(false); 0111 0112 m_progress = new KisProgressWidget(); 0113 m_progress->setObjectName("ProgressBar"); 0114 addStatusBarItem(m_progress); 0115 m_progress->setVisible(false); 0116 connect(m_progress, SIGNAL(sigCancellationRequested()), this, SIGNAL(sigCancellationRequested())); 0117 0118 m_progressUpdater.reset(new KisProgressUpdater(m_progress, m_progress->progressProxy())); 0119 m_progressUpdater->setAutoNestNames(true); 0120 0121 m_extraWidgetsParent = new QFrame; 0122 m_extraWidgetsParent->setMinimumWidth(50); 0123 m_extraWidgetsParent->setObjectName("Extra Widgets Parent"); 0124 m_extraWidgetsLayout = new QHBoxLayout; 0125 m_extraWidgetsLayout->setContentsMargins(0, 0, 0, 0); 0126 m_extraWidgetsLayout->setObjectName("Extra Widgets Layout"); 0127 m_extraWidgetsParent->setLayout(m_extraWidgetsLayout); 0128 addStatusBarItem(m_extraWidgetsParent); 0129 0130 m_memoryReportBox = new KisMemoryReportButton(); 0131 m_memoryReportBox->setObjectName("memoryReportBox"); 0132 m_memoryReportBox->setFlat(true); 0133 m_memoryReportBox->setContentsMargins(5, 5, 5, 5); 0134 m_memoryReportBox->setMinimumWidth(120); 0135 addStatusBarItem(m_memoryReportBox); 0136 m_memoryReportBox->setVisible(false); 0137 0138 connect(m_memoryReportBox, SIGNAL(clicked()), SLOT(showMemoryInfoToolTip())); 0139 0140 connect(KisMemoryStatisticsServer::instance(), 0141 SIGNAL(sigUpdateMemoryStatistics()), 0142 SLOT(imageSizeChanged())); 0143 0144 m_canvasAngleSelector = new KisAngleSelector; 0145 m_canvasAngleSelector->setRange(-360.00, 360.0); 0146 m_canvasAngleSelector->setIncreasingDirection(KisAngleGauge::IncreasingDirection_Clockwise); 0147 m_canvasAngleSelector->setFlipOptionsMode(KisAngleSelector::FlipOptionsMode_ContextMenu); 0148 m_canvasAngleSelector->useFlatSpinBox(true); 0149 addStatusBarItem(m_canvasAngleSelector); 0150 0151 connect(m_canvasAngleSelector, SIGNAL(angleChanged(qreal)), SLOT(slotCanvasAngleSelectorAngleChanged(qreal))); 0152 m_canvasAngleSelector->setVisible(false); 0153 } 0154 0155 KisStatusBar::~KisStatusBar() 0156 { 0157 } 0158 0159 void KisStatusBar::setView(QPointer<KisView> imageView) 0160 { 0161 if (m_imageView) { 0162 if (m_imageView->canvasBase()) { 0163 m_imageView->canvasBase()->canvasController()->proxyObject->disconnect(this); 0164 } 0165 m_imageView->disconnect(this); 0166 removeStatusBarItem(m_imageView->zoomManager()->zoomActionWidget()); 0167 m_imageView = 0; 0168 } 0169 0170 if (imageView) { 0171 m_imageView = imageView; 0172 m_canvasAngleSelector->setVisible(true); 0173 connect(m_imageView, SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), 0174 this, SLOT(updateStatusBarProfileLabel())); 0175 connect(m_imageView, SIGNAL(sigProfileChanged(const KoColorProfile*)), 0176 this, SLOT(updateStatusBarProfileLabel())); 0177 connect(m_imageView, SIGNAL(sigSizeChanged(QPointF,QPointF)), 0178 this, SLOT(imageSizeChanged())); 0179 connect(m_imageView->canvasController()->proxyObject, SIGNAL(canvasOffsetXChanged(int)), 0180 this, SLOT(slotCanvasRotationChanged())); 0181 updateStatusBarProfileLabel(); 0182 slotCanvasRotationChanged(); 0183 addStatusBarItem(m_imageView->zoomManager()->zoomActionWidget()); 0184 } 0185 else { 0186 m_canvasAngleSelector->setVisible(false); 0187 } 0188 0189 imageSizeChanged(); 0190 } 0191 0192 void KisStatusBar::addStatusBarItem(QWidget *widget, int stretch, bool permanent) 0193 { 0194 StatusBarItem sbItem(widget); 0195 if (permanent) { 0196 m_statusBar->addPermanentWidget(widget, stretch); 0197 } 0198 else { 0199 m_statusBar->addWidget(widget, stretch); 0200 } 0201 widget->setVisible(true); 0202 m_statusBarItems.append(sbItem); 0203 } 0204 0205 void KisStatusBar::removeStatusBarItem(QWidget *widget) 0206 { 0207 int i = 0; 0208 Q_FOREACH(const StatusBarItem& sbItem, m_statusBarItems) { 0209 if (sbItem.widget() == widget) { 0210 break; 0211 } 0212 i++; 0213 } 0214 0215 if (i < m_statusBarItems.count()) { 0216 m_statusBar->removeWidget(m_statusBarItems[i].widget()); 0217 m_statusBarItems.remove(i); 0218 } 0219 } 0220 0221 void KisStatusBar::hideAllStatusBarItems() 0222 { 0223 Q_FOREACH(const StatusBarItem& sbItem, m_statusBarItems) { 0224 sbItem.hide(); 0225 } 0226 } 0227 0228 void KisStatusBar::showAllStatusBarItems() 0229 { 0230 Q_FOREACH(const StatusBarItem& sbItem, m_statusBarItems) { 0231 sbItem.show(); 0232 } 0233 } 0234 0235 0236 void KisStatusBar::imageSizeChanged() 0237 { 0238 updateMemoryStatus(); 0239 0240 QString sizeText; 0241 KisImageWSP image = m_imageView ? m_imageView->image() : 0; 0242 if (image) { 0243 qint32 w = image->width(); 0244 qint32 h = image->height(); 0245 sizeText = i18nc("@info:status width x height (file size)", "%1 &x %2 (%3)", w, h, m_shortMemoryTag); 0246 } else { 0247 sizeText = m_shortMemoryTag; 0248 } 0249 0250 m_memoryReportBox->setIcon(m_memoryStatusIcon); 0251 m_memoryReportBox->setText(sizeText); 0252 m_memoryReportBox->setToolTip(m_longMemoryTag); 0253 } 0254 0255 void KisStatusBar::updateSelectionIcon() 0256 { 0257 QIcon icon; 0258 if (!m_viewManager->selectionManager()->displaySelection()) { 0259 icon = KisIconUtils::loadIcon("selection-mode_invisible"); 0260 } else if (m_viewManager->selectionManager()->showSelectionAsMask()) { 0261 icon = KisIconUtils::loadIcon("selection-mode_mask"); 0262 } else /* if (!m_view->selectionManager()->showSelectionAsMask()) */ { 0263 icon = KisIconUtils::loadIcon("selection-mode_ants"); 0264 } 0265 m_selectionStatus->setIcon(icon); 0266 } 0267 0268 void KisStatusBar::updateMemoryStatus() 0269 { 0270 KisMemoryStatisticsServer::Statistics stats = 0271 KisMemoryStatisticsServer::instance() 0272 ->fetchMemoryStatistics(m_imageView ? m_imageView->image() : 0); 0273 const KFormat format; 0274 0275 const QString imageStatsMsg = 0276 i18nc("tooltip on statusbar memory reporting button (image stats)", 0277 "Image size:\t %1\n" 0278 " - layers:\t\t %2\n" 0279 " - projections:\t %3\n" 0280 " - instant preview:\t %4\n", 0281 format.formatByteSize(stats.imageSize), 0282 format.formatByteSize(stats.layersSize), 0283 format.formatByteSize(stats.projectionsSize), 0284 format.formatByteSize(stats.lodSize)); 0285 0286 const QString memoryStatsMsg = 0287 i18nc("tooltip on statusbar memory reporting button (total stats)", 0288 "Memory used:\t %1 / %2\n" 0289 " image data:\t %3 / %4\n" 0290 " pool:\t\t %5 / %6\n" 0291 " undo data:\t %7\n" 0292 "\n" 0293 "Swap used:\t %8", 0294 format.formatByteSize(stats.totalMemorySize), 0295 format.formatByteSize(stats.totalMemoryLimit), 0296 0297 format.formatByteSize(stats.realMemorySize), 0298 format.formatByteSize(stats.tilesHardLimit), 0299 0300 format.formatByteSize(stats.poolSize), 0301 format.formatByteSize(stats.tilesPoolLimit), 0302 0303 format.formatByteSize(stats.historicalMemorySize), 0304 format.formatByteSize(stats.swapSize)); 0305 0306 QString longStats = imageStatsMsg + "\n" + memoryStatsMsg; 0307 0308 QString shortStats = format.formatByteSize(stats.imageSize); 0309 QIcon icon; 0310 const qint64 warnLevel = stats.tilesHardLimit - stats.tilesHardLimit / 8; 0311 0312 if (stats.imageSize > warnLevel || 0313 stats.realMemorySize > warnLevel) { 0314 0315 if (!m_memoryWarningLogged) { 0316 m_memoryWarningLogged = true; 0317 KisUsageLogger::log(QString("WARNING: %1 is running out of memory:%2\n").arg(m_imageView->document()->path()).arg(longStats)); 0318 } 0319 0320 icon = KisIconUtils::loadIcon("warning"); 0321 QString suffix = 0322 i18nc("tooltip on statusbar memory reporting button", 0323 "\n\nWARNING:\tOut of memory! Swapping has been started.\n" 0324 "\t\tPlease configure more RAM for Krita in Settings dialog"); 0325 longStats += suffix; 0326 0327 0328 } 0329 0330 m_shortMemoryTag = shortStats; 0331 m_longMemoryTag = longStats; 0332 m_memoryStatusIcon = icon; 0333 0334 m_memoryReportBox->setMaximumMemory(stats.totalMemoryLimit); 0335 m_memoryReportBox->setCurrentMemory(stats.totalMemorySize); 0336 m_memoryReportBox->setImageWeight(stats.imageSize); 0337 } 0338 0339 void KisStatusBar::showMemoryInfoToolTip() 0340 { 0341 QToolTip::showText(QCursor::pos(), m_memoryReportBox->toolTip(), m_memoryReportBox); 0342 } 0343 0344 void KisStatusBar::slotCanvasAngleSelectorAngleChanged(qreal angle) 0345 { 0346 KisCanvas2 *canvas = m_viewManager->canvasBase(); 0347 if (!canvas) return; 0348 0349 KisCanvasController *canvasController = dynamic_cast<KisCanvasController*>(canvas->canvasController()); 0350 if (canvasController) { 0351 canvasController->rotateCanvas(angle - canvas->rotationAngle()); 0352 } 0353 } 0354 0355 void KisStatusBar::slotCanvasRotationChanged() 0356 { 0357 KisCanvas2 *canvas = m_viewManager->canvasBase(); 0358 if (!canvas) return; 0359 0360 KisSignalsBlocker l(m_canvasAngleSelector); 0361 m_canvasAngleSelector->setAngle(canvas->rotationAngle()); 0362 } 0363 0364 void KisStatusBar::updateSelectionToolTip() 0365 { 0366 updateSelectionIcon(); 0367 0368 KisSelectionSP selection = m_viewManager->selection(); 0369 if (selection) { 0370 m_selectionStatus->setEnabled(true); 0371 0372 QRect r = selection->selectedExactRect(); 0373 0374 QString displayMode = 0375 !m_viewManager->selectionManager()->displaySelection() ? 0376 i18n("Hidden") : 0377 (m_viewManager->selectionManager()->showSelectionAsMask() ? 0378 i18n("Mask") : i18n("Ants")); 0379 0380 m_selectionStatus->setToolTip( 0381 i18n("Selection: x = %1 y = %2 width = %3 height = %4\n" 0382 "Display Mode: %5", 0383 r.x(), r.y(), r.width(), r.height(), displayMode)); 0384 } else { 0385 m_selectionStatus->setEnabled(false); 0386 m_selectionStatus->setToolTip(i18n("No Selection")); 0387 } 0388 } 0389 0390 void KisStatusBar::setSelection(KisImageWSP image) 0391 { 0392 Q_UNUSED(image); 0393 updateSelectionToolTip(); 0394 } 0395 0396 void KisStatusBar::setProfile(KisImageWSP image) 0397 { 0398 if (m_statusBarProfileLabel == 0) { 0399 return; 0400 } 0401 0402 if (!image) return; 0403 if (image->profile() == 0) { 0404 m_statusBarProfileLabel->setText(i18n("No profile")); 0405 } else { 0406 m_statusBarProfileLabel->setText(i18nc("<color space> <image profile>", "%1 %2", image->colorSpace()->name(), image->profile()->name())); 0407 } 0408 0409 } 0410 0411 void KisStatusBar::setHelp(const QString &t) 0412 { 0413 Q_UNUSED(t); 0414 } 0415 0416 void KisStatusBar::updateStatusBarProfileLabel() 0417 { 0418 if (!m_imageView) return; 0419 0420 setProfile(m_imageView->image()); 0421 } 0422 0423 KoProgressUpdater *KisStatusBar::progressUpdater() 0424 { 0425 return m_progressUpdater.data(); 0426 } 0427 0428 void KisStatusBar::addExtraWidget(QWidget *widget) 0429 { 0430 m_extraWidgetsLayout->addWidget(widget); 0431 } 0432 0433 void KisStatusBar::removeExtraWidget(QWidget *widget) 0434 { 0435 m_extraWidgetsLayout->removeWidget(widget); 0436 } 0437