Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_custom_image_widget.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 Thomas Zander <zander@kde.org>
3 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
4 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
10
11#include <QMimeData>
12#include <QSlider>
13#include <QApplication>
14#include <QScreen>
15#include <QDialogButtonBox>
16#include <QFile>
17#include <QSpacerItem>
18
19#include <QMessageBox>
20#include <KoResourcePaths.h>
21
22#include <KFormat>
23#include <kstandardguiitem.h>
24
25#include <kis_debug.h>
26
27#include <kis_icon.h>
28#include <KoCompositeOp.h>
29#include <KoColorProfile.h>
30#include <KoColorSpace.h>
31#include <KoID.h>
32#include <KoColor.h>
33#include <KoUnit.h>
35
36#include <kis_fill_painter.h>
37#include <kis_image.h>
38#include <kis_layer.h>
39#include <kis_group_layer.h>
40#include <kis_paint_layer.h>
41#include <kis_paint_device.h>
42#include <kis_painter.h>
43
44#include "kis_config.h"
45#include "KisPart.h"
46#include "KisDocument.h"
48#include <KisSqueezedComboBox.h>
49#include "kis_signals_blocker.h"
50
51static QString pixelsInchStr()
52{
53 static QString str = i18n("Pixels/Inch");
54 return str;
55}
56
57static const QString pixelsCentimeterStr()
58{
59 static QString str = i18n("Pixels/Centimeter");
60 return str;
61}
62
63KisCustomImageWidget::KisCustomImageWidget(QWidget* parent, const QString& imageName, const QLatin1String &dialogType)
64 : WdgNewImage(parent)
65 , m_dialogType(dialogType)
66{
67 setObjectName("KisCustomImageWidget");
68 m_openPane = qobject_cast<KisOpenPane*>(parent);
69 Q_ASSERT(m_openPane);
70
71 KisConfig cfg(true);
72
73 const qint32 defWidth = cfg.defImageWidth();
74 const qint32 defHeight = cfg.defImageHeight();
75 const double resolution = cfg.defImageResolution();
76 const QString& defColorModel = cfg.defColorModel();
77 const QString& defColorDepth = cfg.defaultColorDepth();
78 const QString& defColorProfile = cfg.defColorProfile();
79
80 txtName->setText(imageName);
81 m_widthUnit = KoUnit(KoUnit::Pixel, resolution);
82 doubleWidth->setValue(defWidth);
83 doubleWidth->setDecimals(0);
85 cmbWidthUnit->addItems(KoUnit::listOfUnitNameForUi(KoUnit::ListAll));
86 cmbWidthUnit->setCurrentIndex(m_widthUnit.indexInListForUi(KoUnit::ListAll));
87
88 m_heightUnit = KoUnit(KoUnit::Pixel, resolution);
89 doubleHeight->setValue(defHeight);
90 doubleHeight->setDecimals(0);
92 cmbHeightUnit->addItems(KoUnit::listOfUnitNameForUi(KoUnit::ListAll));
93 cmbHeightUnit->setCurrentIndex(m_heightUnit.indexInListForUi(KoUnit::ListAll));
94
95 cmbResolutionUnit->addItem(pixelsInchStr());
96 cmbResolutionUnit->addItem(pixelsCentimeterStr());
97
98 doubleResolution->setValue(72.0 * resolution);
99 doubleResolution->setDecimals(2);
100
101 grpClipboard->hide();
102
103 sliderOpacity->setRange(0, 100, 0);
104 sliderOpacity->setValue(100);
105 KisSpinBoxI18nHelper::setText(sliderOpacity, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
106
107 connect(cmbPredefined, SIGNAL(activated(int)), SLOT(predefinedClicked(int)));
108 connect(doubleResolution, SIGNAL(valueChanged(double)),
109 this, SLOT(resolutionChanged(double)));
110 connect(cmbWidthUnit, SIGNAL(activated(int)),
111 this, SLOT(widthUnitChanged(int)));
112 connect(doubleWidth, SIGNAL(valueChanged(double)),
113 this, SLOT(widthChanged(double)));
114 connect(cmbHeightUnit, SIGNAL(activated(int)),
115 this, SLOT(heightUnitChanged(int)));
116 connect(doubleHeight, SIGNAL(valueChanged(double)),
117 this, SLOT(heightChanged(double)));
118 connect(cmbResolutionUnit, SIGNAL(currentIndexChanged(int)),
119 this, SLOT(resolutionUnitChanged()));
120
121
122 // Create image
123 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setText(i18n("&Create"));
124 KGuiItem::assign(newDialogConfirmationButtonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
125 connect(newDialogConfirmationButtonBox, SIGNAL(accepted()), this, SLOT(createImage()));
126
127
128 // Cancel Create image button
129 connect(newDialogConfirmationButtonBox, SIGNAL(rejected()), m_openPane, SLOT(reject()));
130
131
132
133 bnPortrait->setIcon(KisIconUtils::loadIcon("portrait"));
134 connect(bnPortrait, SIGNAL(clicked()), SLOT(setPortrait()));
135 connect(bnLandscape, SIGNAL(clicked()), SLOT(setLandscape()));
136 bnLandscape->setIcon(KisIconUtils::loadIcon("landscape"));
137
138 connect(doubleWidth, SIGNAL(valueChanged(double)), this, SLOT(switchPortraitLandscape()));
139 connect(doubleHeight, SIGNAL(valueChanged(double)), this, SLOT(switchPortraitLandscape()));
140 connect(bnSaveAsPredefined, SIGNAL(clicked()), this, SLOT(saveAsPredefined()));
141
142 colorSpaceSelector->setCurrentColorModel(KoID(defColorModel));
143 colorSpaceSelector->setCurrentColorDepth(KoID(defColorDepth));
144 colorSpaceSelector->setCurrentProfile(defColorProfile);
145 connect(colorSpaceSelector, SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(changeDocumentInfoLabel()));
146
147 connect(colorSpaceSelector, SIGNAL(selectionChanged(bool)), newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok), SLOT(setEnabled(bool)));
148
149 intNumLayers->setValue(cfg.numDefaultLayers(m_dialogType));
152 cmbColor->setColor(bcol);
154
156
157 if (bgStyle == KisConfig::RASTER_LAYER) {
158 radioBackgroundAsRaster->setChecked(true);
159 } else if (bgStyle == KisConfig::FILL_LAYER) {
160 radioBackgroundAsFill->setChecked(true);
161 } else {
162 radioBackgroundAsProjection->setChecked(true);
163 }
164
167
168 // this makes the portrait and landscape buttons more
169 // obvious what is selected by changing the highlight color
170 QPalette p = QApplication::palette();
171 QPalette palette_highlight(p );
172 QColor c = p.color(QPalette::Highlight);
173 palette_highlight.setColor(QPalette::Button, c);
174 bnLandscape->setPalette(palette_highlight);
175 bnPortrait->setPalette(palette_highlight);
177}
178
180{
182 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setFocus();
183 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
184}
185
190
192{
193 if (m_widthUnit.type() == KoUnit::Pixel) {
194 m_widthUnit.setFactor(res / 72.0);
195 m_width = m_widthUnit.fromUserValue(doubleWidth->value());
196 }
197
199 m_heightUnit.setFactor(res / 72.0);
200 m_height = m_heightUnit.fromUserValue(doubleHeight->value());
201 }
203}
204
206{
207 qreal resolution = doubleResolution->value();
208
209 if (cmbResolutionUnit->currentText() == pixelsInchStr()) {
211 } else {
213 }
214
215 {
216 KisSignalsBlocker b(doubleResolution);
217 doubleResolution->setValue(resolution);
218 }
219}
220
222{
223 doubleWidth->blockSignals(true);
224
226 if (m_widthUnit.type() == KoUnit::Pixel) {
227 doubleWidth->setDecimals(0);
228 m_widthUnit.setFactor(doubleResolution->value() / 72.0);
229 } else {
230 doubleWidth->setDecimals(2);
231 }
232
233 doubleWidth->setValue(m_widthUnit.toUserValuePrecise(m_width));
234
235 doubleWidth->blockSignals(false);
237}
238
244
246{
247 doubleHeight->blockSignals(true);
248
251 doubleHeight->setDecimals(0);
252 m_heightUnit.setFactor(doubleResolution->value() / 72.0);
253 } else {
254 doubleHeight->setDecimals(2);
255 }
256
257 doubleHeight->setValue(m_heightUnit.toUserValuePrecise(m_height));
258
259 doubleHeight->blockSignals(false);
261}
262
268
270{
271 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
273 if (doc) {
274 doc->setModified(false);
275 Q_EMIT m_openPane->documentSelected(doc);
276 m_openPane->accept();
277 } else {
278 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
279 }
280}
281
283{
284 const KoColorSpace * cs = colorSpaceSelector->currentColorSpace();
285
286 if (cs->colorModelId() == RGBAColorModelID &&
288
289 const KoColorProfile *profile = cs->profile();
290
291 if (profile->name().contains("linear") ||
292 profile->name().contains("scRGB") ||
293 profile->info().contains("linear") ||
294 profile->info().contains("scRGB")) {
295
296 int result =
297 QMessageBox::warning(this,
298 i18nc("@title:window", "Krita"),
299 i18n("Linear gamma RGB color spaces are not supposed to be used "
300 "in 8-bit integer modes. It is suggested to use 16-bit integer "
301 "or any floating point colorspace for linear profiles.\n\n"
302 "Press \"Ok\" to create a 8-bit integer linear RGB color space "
303 "or \"Cancel\" to return to the settings dialog."),
304 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
305
306 if (result == QMessageBox::Cancel) {
307 dbgKrita << "Model RGB8" << "NOT SUPPORTED";
308 dbgKrita << ppVar(cs->name());
309 dbgKrita << ppVar(cs->profile()->name());
310 dbgKrita << ppVar(cs->profile()->info());
311 return 0;
312 }
313 }
314 }
315 KisDocument *doc = static_cast<KisDocument*>(KisPart::instance()->createDocument());
316
317 qint32 width, height;
318 double resolution ;
319 KIS_SAFE_ASSERT_RECOVER(cmbResolutionUnit->currentText() == pixelsInchStr() || cmbResolutionUnit->currentText() == pixelsCentimeterStr()) { resolution = 1.0; }
320 if (cmbResolutionUnit->currentText() == pixelsInchStr()) {
321 resolution = doubleResolution->value() / 72.0; // internal resolution is in pixels per pt
322 } else if (cmbResolutionUnit->currentText() == pixelsCentimeterStr()) {
323 resolution = doubleResolution->value() / 28.34;
324 } else {
325 resolution = 1.0;
326 }
327 width = static_cast<qint32>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_width));
328 height = static_cast<qint32>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_height));
329
330 QColor qc = cmbColor->color().toQColor();
331 qc.setAlpha(backgroundOpacity());
332 KoColor bgColor(qc, cs);
333
335 if( radioBackgroundAsRaster->isChecked() ){
336 bgStyle = KisConfig::RASTER_LAYER;
337 } else if( radioBackgroundAsFill->isChecked() ){
338 bgStyle = KisConfig::FILL_LAYER;
339 }
340
341 doc->newImage(txtName->text(), width, height, cs, bgColor, bgStyle, intNumLayers->value(), txtDescription->toPlainText(), resolution);
342
343 KisConfig cfg(false);
344 cfg.setNumDefaultLayers(m_dialogType, intNumLayers->value());
346 cfg.setDefaultBackgroundColor(m_dialogType, cmbColor->color().toQColor());
348
350 cfg.defImageWidth(width);
351 cfg.defImageHeight(height);
352 cfg.defImageResolution(resolution);
353 if (!cfg.useDefaultColorSpace()) {
354 cfg.defColorModel(cs->colorModelId().id());
356 cfg.defColorProfile(cs->profile() ? cs->profile()->name() : "");
357 }
358 }
359
360 return doc;
361}
362
364{
365 return true;
366}
367
369{
370 intNumLayers->setValue(layers);
371}
372
374{
375 qint32 opacity = sliderOpacity->value();
376
377 if (!opacity)
378 return 0;
379
380 return (opacity * 255) / 100;
381}
382
384 sliderOpacity->setValue((value * 100) / 255);
385}
386
388{
389 cmbPredefined->clear();
390 m_predefined.clear();
391
392 cmbPredefined->addItem("");
393
394 QStringList definitions = KoResourcePaths::findAllAssets("data", "predefined_image_sizes/*.predefinedimage", KoResourcePaths::Recursive);
395 definitions.sort();
396
397 if (!definitions.empty()) {
398
399 Q_FOREACH (const QString &definition, definitions) {
400 QFile f(definition);
401 if (f.open(QIODevice::ReadOnly)) {
402 QString xml = QString::fromUtf8(f.readAll());
404 predefined->fromXML(xml);
405 if (predefined->hasProperty("name")
406 && predefined->hasProperty("width")
407 && predefined->hasProperty("height")
408 && predefined->hasProperty("resolution")
409 && predefined->hasProperty("x-unit")
410 && predefined->hasProperty("y-unit")) {
411 m_predefined << predefined;
412 cmbPredefined->addItem(predefined->getString("name"));
413 }
414 }
415 }
416 }
417
418 cmbPredefined->setCurrentIndex(0);
419
420}
421
422
424{
425 if (index < 1 || index > m_predefined.size()) return;
426
427 KisPropertiesConfigurationSP predefined = m_predefined[index - 1];
428 txtPredefinedName->setText(predefined->getString("name"));
429 if (cmbResolutionUnit->currentText() == pixelsInchStr()) {
430 doubleResolution->setValue(predefined->getDouble("resolution"));
431 } else {
432 doubleResolution->setValue(KoUnit::convertFromUnitToUnit(predefined->getDouble("resolution"), KoUnit(KoUnit::Centimeter), KoUnit(KoUnit::Inch)));
433 }
434 cmbWidthUnit->setCurrentIndex(predefined->getInt("x-unit"));
435 cmbHeightUnit->setCurrentIndex(predefined->getInt("y-unit"));
436
437 widthUnitChanged(cmbWidthUnit->currentIndex());
438 heightUnitChanged(cmbHeightUnit->currentIndex());
439
440 doubleWidth->setValue(predefined->getDouble("width"));
441 doubleHeight->setValue(predefined->getDouble("height"));
443
444}
445
447{
448 QString fileName = txtPredefinedName->text();
449 if (fileName.isEmpty()) {
450 return;
451 }
452 QString saveLocation = KoResourcePaths::saveLocation("data", "predefined_image_sizes/", true);
453 QFile f(saveLocation + '/' + fileName.replace(' ', '_').replace('(', '_').replace(')', '_').replace(':', '_') + ".predefinedimage");
454
455 if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
456 QMessageBox::warning(this, i18nc("@title:window", "Krita"),
457 i18n("Could not save %1.\nReason: %2.", f.fileName(), f.errorString()));
458 return;
459 }
461 predefined->setProperty("name", txtPredefinedName->text());
462 predefined->setProperty("width", doubleWidth->value());
463 predefined->setProperty("height", doubleHeight->value());
464 predefined->setProperty("resolution", doubleResolution->value());
465 predefined->setProperty("x-unit", cmbWidthUnit->currentIndex());
466 predefined->setProperty("y-unit", cmbHeightUnit->currentIndex());
467
468 QString xml = predefined->toXML();
469
470 f.write(xml.toUtf8());
471 f.flush();
472 f.close();
473
474 int i = 0;
475 bool found = false;
477 if (pr->getString("name") == txtPredefinedName->text()) {
478 found = true;
479 break;
480 }
481 ++i;
482 }
483 if (found) {
484 m_predefined[i] = predefined;
485 }
486 else {
487 m_predefined.append(predefined);
488 cmbPredefined->addItem(txtPredefinedName->text());
489 }
490
491}
492
494{
495 if (doubleWidth->value() < doubleHeight->value()) {
497 }
498}
499
501{
502 if (doubleWidth->value() > doubleHeight->value()) {
504 }
505}
506
508{
509 double width = doubleWidth->value();
510 double height = doubleHeight->value();
511
512 doubleHeight->clearFocus();
513 doubleWidth->clearFocus();
514
515 doubleHeight->blockSignals(true);
516 doubleWidth->blockSignals(true);
517 cmbWidthUnit->blockSignals(true);
518 cmbHeightUnit->blockSignals(true);
519
520 doubleWidth->setValue(height);
521 doubleHeight->setValue(width);
522 cmbWidthUnit->setCurrentIndex(m_heightUnit.indexInListForUi(KoUnit::ListAll));
523 cmbHeightUnit->setCurrentIndex(m_widthUnit.indexInListForUi(KoUnit::ListAll));
524
525 doubleHeight->blockSignals(false);
526 doubleWidth->blockSignals(false);
527 cmbWidthUnit->blockSignals(false);
528 cmbHeightUnit->blockSignals(false);
530
531 widthChanged(doubleWidth->value());
532 heightChanged(doubleHeight->value());
534}
535
537{
538 if(doubleWidth->value() > doubleHeight->value())
539 bnLandscape->setChecked(true);
540 else
541 bnPortrait->setChecked(true);
542}
543
545{
546
547 qint64 width, height;
548 double resolution;
549 resolution = doubleResolution->value() / 72.0; // internal resolution is in pixels per pt
550
551 width = static_cast<qint64>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_width));
552 height = static_cast<qint64>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_height));
553
554 qint64 layerSize = width * height;
555 const KoColorSpace *cs = colorSpaceSelector->currentColorSpace();
556 int bitSize = 8 * cs->pixelSize(); //pixelsize is in bytes.
557 layerSize = layerSize * cs->pixelSize();
558 QString text = i18nc("arg1: width. arg2: height. arg3: colorspace name. arg4: size of a channel in bits. arg5: image size",
559 "This document will be %1 pixels by %2 pixels in %3. The pixel size is %4 bit. A single paint layer will use %5 of RAM.",
560 width,
561 height,
562 cs->name(),
563 bitSize,
564 KFormat().formatByteSize(layerSize));
565 lblDocumentInfo->setText(text);
566}
567
float value(const T *src, size_t ch)
const Params2D p
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
void setDefaultBackgroundOpacity(const QLatin1String &dialogType, quint8 value)
qint32 defImageHeight(bool defaultValue=false) const
void setDefaultBackgroundStyle(const QLatin1String &dialogType, BackgroundStyle value)
qint32 defImageWidth(bool defaultValue=false) const
BackgroundStyle defaultBackgroundStyle(const QLatin1String &dialogType, bool defaultValue=false) const
QColor defaultBackgroundColor(const QLatin1String &dialogType, bool defaultValue=false) const
void setDefaultBackgroundColor(const QLatin1String &dialogType, const QColor &value)
bool useDefaultColorSpace(bool defaultvalue=false) const
quint8 defaultBackgroundOpacity(const QLatin1String &dialogType, bool defaultValue=false) const
void setDefaultColorDepth(const QString &depth) const
qreal defImageResolution(bool defaultValue=false) const
int numDefaultLayers(const QLatin1String &dialogType, bool defaultValue=false) const
void setNumDefaultLayers(const QLatin1String &dialogType, int num)
QString defColorProfile(bool defaultValue=false) const
QString defColorModel(bool defaultValue=false) const
QString defaultColorDepth(bool defaultValue=false) const
void resolutionChanged(double value)
QList< KisPropertiesConfigurationSP > m_predefined
void showEvent(QShowEvent *) override
KisCustomImageWidget(QWidget *parent, const QString &imageName, const QLatin1String &dialogType)
void setNumberOfLayers(int layers)
Set the number of layers that will be created.
void setBackgroundOpacity(quint8 value)
virtual bool shouldSaveImageDimensions() const
void setModified(bool _mod)
bool newImage(const QString &name, qint32 width, qint32 height, const KoColorSpace *cs, const KoColor &bgColor, KisConfig::BackgroundStyle bgStyle, int numberOfLayers, const QString &imageDescription, const double imageResolution)
void documentSelected(KisDocument *)
this signal is emitted (as defined by KisDocument) the moment the document is 'ready'
static KisPart * instance()
Definition KisPart.cpp:130
KisDocument * createDocument() const
Definition KisPart.cpp:228
virtual quint32 pixelSize() const =0
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
static QStringList findAllAssets(const QString &type, const QString &filter=QString(), SearchOptions options=NoSearchOptions)
static QString saveLocation(const QString &type, const QString &suffix=QString(), bool create=true)
static qreal convertFromUnitToUnit(const qreal value, const KoUnit &fromUnit, const KoUnit &toUnit, qreal factor=1.0)
Definition KoUnit.cpp:295
qreal fromUserValue(qreal value) const
Definition KoUnit.cpp:201
@ ListAll
Definition KoUnit.h:88
KoUnit::Type type() const
Definition KoUnit.h:118
qreal toUserValuePrecise(const qreal ptValue) const
Definition KoUnit.cpp:161
static KoUnit fromListForUi(int index, ListOptions listOptions=ListAll, qreal factor=1.0)
Definition KoUnit.cpp:80
@ Centimeter
Definition KoUnit.h:78
@ Inch
Definition KoUnit.h:77
@ Pixel
Definition KoUnit.h:82
static QStringList listOfUnitNameForUi(ListOptions listOptions=ListAll)
Returns the list of unit types for the UI, controlled with the given listOptions.
Definition KoUnit.cpp:69
int indexInListForUi(ListOptions listOptions=ListAll) const
Definition KoUnit.cpp:101
void setFactor(qreal factor)
Definition KoUnit.h:122
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
static const QString pixelsCentimeterStr()
static QString pixelsInchStr()
#define dbgKrita
Definition kis_debug.h:49
#define ppVar(var)
Definition kis_debug.h:163
QIcon loadIcon(const QString &name)
void setText(QSpinBox *spinBox, const QStringView textTemplate)
static KoColorSpaceRegistry * instance()
static const QString pixelsCentimeterStr()
static QString pixelsInchStr()