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"
49#include <KisSqueezedComboBox.h>
50#include "kis_signals_blocker.h"
51
52static QString pixelsInchStr()
53{
54 static QString str = i18n("Pixels/Inch");
55 return str;
56}
57
58static const QString pixelsCentimeterStr()
59{
60 static QString str = i18n("Pixels/Centimeter");
61 return str;
62}
63
64KisCustomImageWidget::KisCustomImageWidget(QWidget* parent, qint32 defWidth, qint32 defHeight, double resolution, const QString& defColorModel, const QString& defColorDepth, const QString& defColorProfile, const QString& imageName)
65 : WdgNewImage(parent)
66{
67 setObjectName("KisCustomImageWidget");
68 m_openPane = qobject_cast<KisOpenPane*>(parent);
69 Q_ASSERT(m_openPane);
70
71 txtName->setText(imageName);
72 m_widthUnit = KoUnit(KoUnit::Pixel, resolution);
73 doubleWidth->setValue(defWidth);
74 doubleWidth->setDecimals(0);
76 cmbWidthUnit->addItems(KoUnit::listOfUnitNameForUi(KoUnit::ListAll));
77 cmbWidthUnit->setCurrentIndex(m_widthUnit.indexInListForUi(KoUnit::ListAll));
78
79 m_heightUnit = KoUnit(KoUnit::Pixel, resolution);
80 doubleHeight->setValue(defHeight);
81 doubleHeight->setDecimals(0);
83 cmbHeightUnit->addItems(KoUnit::listOfUnitNameForUi(KoUnit::ListAll));
84 cmbHeightUnit->setCurrentIndex(m_heightUnit.indexInListForUi(KoUnit::ListAll));
85
86 cmbResolutionUnit->addItem(pixelsInchStr());
87 cmbResolutionUnit->addItem(pixelsCentimeterStr());
88
89 doubleResolution->setValue(72.0 * resolution);
90 doubleResolution->setDecimals(2);
91
92 grpClipboard->hide();
93
94 sliderOpacity->setRange(0, 100, 0);
95 sliderOpacity->setValue(100);
96 KisSpinBoxI18nHelper::setText(sliderOpacity, i18nc("{n} is the number value, % is the percent sign", "{n}%"));
97
98 connect(cmbPredefined, SIGNAL(activated(int)), SLOT(predefinedClicked(int)));
99 connect(doubleResolution, SIGNAL(valueChanged(double)),
100 this, SLOT(resolutionChanged(double)));
101 connect(cmbWidthUnit, SIGNAL(activated(int)),
102 this, SLOT(widthUnitChanged(int)));
103 connect(doubleWidth, SIGNAL(valueChanged(double)),
104 this, SLOT(widthChanged(double)));
105 connect(cmbHeightUnit, SIGNAL(activated(int)),
106 this, SLOT(heightUnitChanged(int)));
107 connect(doubleHeight, SIGNAL(valueChanged(double)),
108 this, SLOT(heightChanged(double)));
109 connect(cmbResolutionUnit, SIGNAL(currentIndexChanged(int)),
110 this, SLOT(resolutionUnitChanged()));
111
112
113 // Create image
114 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setText(i18n("&Create"));
115 KGuiItem::assign(newDialogConfirmationButtonBox->button(QDialogButtonBox::Cancel), KStandardGuiItem::cancel());
116 connect(newDialogConfirmationButtonBox, SIGNAL(accepted()), this, SLOT(createImage()));
117
118
119 // Cancel Create image button
120 connect(newDialogConfirmationButtonBox, SIGNAL(rejected()), m_openPane, SLOT(reject()));
121
122
123
124 bnPortrait->setIcon(KisIconUtils::loadIcon("portrait"));
125 connect(bnPortrait, SIGNAL(clicked()), SLOT(setPortrait()));
126 connect(bnLandscape, SIGNAL(clicked()), SLOT(setLandscape()));
127 bnLandscape->setIcon(KisIconUtils::loadIcon("landscape"));
128
129 connect(doubleWidth, SIGNAL(valueChanged(double)), this, SLOT(switchPortraitLandscape()));
130 connect(doubleHeight, SIGNAL(valueChanged(double)), this, SLOT(switchPortraitLandscape()));
131 connect(bnSaveAsPredefined, SIGNAL(clicked()), this, SLOT(saveAsPredefined()));
132
133 colorSpaceSelector->setCurrentColorModel(KoID(defColorModel));
134 colorSpaceSelector->setCurrentColorDepth(KoID(defColorDepth));
135 colorSpaceSelector->setCurrentProfile(defColorProfile);
136 connect(colorSpaceSelector, SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(changeDocumentInfoLabel()));
137
138 connect(colorSpaceSelector, SIGNAL(selectionChanged(bool)), newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok), SLOT(setEnabled(bool)));
139
140
141 KisConfig cfg(true);
142 intNumLayers->setValue(cfg.numDefaultLayers());
145 cmbColor->setColor(bcol);
147
149
150 if (bgStyle == KisConfig::RASTER_LAYER) {
151 radioBackgroundAsRaster->setChecked(true);
152 } else if (bgStyle == KisConfig::FILL_LAYER) {
153 radioBackgroundAsFill->setChecked(true);
154 } else {
155 radioBackgroundAsProjection->setChecked(true);
156 }
157
160
161 // this makes the portrait and landscape buttons more
162 // obvious what is selected by changing the highlight color
163 QPalette p = QApplication::palette();
164 QPalette palette_highlight(p );
165 QColor c = p.color(QPalette::Highlight);
166 palette_highlight.setColor(QPalette::Button, c);
167 bnLandscape->setPalette(palette_highlight);
168 bnPortrait->setPalette(palette_highlight);
170}
171
173{
175 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setFocus();
176 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
177}
178
183
185{
186 if (m_widthUnit.type() == KoUnit::Pixel) {
187 m_widthUnit.setFactor(res / 72.0);
188 m_width = m_widthUnit.fromUserValue(doubleWidth->value());
189 }
190
192 m_heightUnit.setFactor(res / 72.0);
193 m_height = m_heightUnit.fromUserValue(doubleHeight->value());
194 }
196}
197
199{
200 qreal resolution = doubleResolution->value();
201
202 if (cmbResolutionUnit->currentText() == pixelsInchStr()) {
204 } else {
206 }
207
208 {
209 KisSignalsBlocker b(doubleResolution);
210 doubleResolution->setValue(resolution);
211 }
212}
213
215{
216 doubleWidth->blockSignals(true);
217
219 if (m_widthUnit.type() == KoUnit::Pixel) {
220 doubleWidth->setDecimals(0);
221 m_widthUnit.setFactor(doubleResolution->value() / 72.0);
222 } else {
223 doubleWidth->setDecimals(2);
224 }
225
226 doubleWidth->setValue(m_widthUnit.toUserValuePrecise(m_width));
227
228 doubleWidth->blockSignals(false);
230}
231
237
239{
240 doubleHeight->blockSignals(true);
241
244 doubleHeight->setDecimals(0);
245 m_heightUnit.setFactor(doubleResolution->value() / 72.0);
246 } else {
247 doubleHeight->setDecimals(2);
248 }
249
250 doubleHeight->setValue(m_heightUnit.toUserValuePrecise(m_height));
251
252 doubleHeight->blockSignals(false);
254}
255
261
263{
264 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
266 if (doc) {
267 doc->setModified(false);
268 Q_EMIT m_openPane->documentSelected(doc);
269 m_openPane->accept();
270 } else {
271 newDialogConfirmationButtonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
272 }
273}
274
276{
277 const KoColorSpace * cs = colorSpaceSelector->currentColorSpace();
278
279 if (cs->colorModelId() == RGBAColorModelID &&
281
282 const KoColorProfile *profile = cs->profile();
283
284 if (profile->name().contains("linear") ||
285 profile->name().contains("scRGB") ||
286 profile->info().contains("linear") ||
287 profile->info().contains("scRGB")) {
288
289 int result =
290 QMessageBox::warning(this,
291 i18nc("@title:window", "Krita"),
292 i18n("Linear gamma RGB color spaces are not supposed to be used "
293 "in 8-bit integer modes. It is suggested to use 16-bit integer "
294 "or any floating point colorspace for linear profiles.\n\n"
295 "Press \"Ok\" to create a 8-bit integer linear RGB color space "
296 "or \"Cancel\" to return to the settings dialog."),
297 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
298
299 if (result == QMessageBox::Cancel) {
300 dbgKrita << "Model RGB8" << "NOT SUPPORTED";
301 dbgKrita << ppVar(cs->name());
302 dbgKrita << ppVar(cs->profile()->name());
303 dbgKrita << ppVar(cs->profile()->info());
304 return 0;
305 }
306 }
307 }
308 KisDocument *doc = static_cast<KisDocument*>(KisPart::instance()->createDocument());
309
310 qint32 width, height;
311 double resolution ;
312 KIS_SAFE_ASSERT_RECOVER(cmbResolutionUnit->currentText() == pixelsInchStr() || cmbResolutionUnit->currentText() == pixelsCentimeterStr()) { resolution = 1.0; }
313 if (cmbResolutionUnit->currentText() == pixelsInchStr()) {
314 resolution = doubleResolution->value() / 72.0; // internal resolution is in pixels per pt
315 } else if (cmbResolutionUnit->currentText() == pixelsCentimeterStr()) {
316 resolution = doubleResolution->value() / 28.34;
317 } else {
318 resolution = 1.0;
319 }
320 width = static_cast<qint32>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_width));
321 height = static_cast<qint32>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_height));
322
323 QColor qc = cmbColor->color().toQColor();
324 qc.setAlpha(backgroundOpacity());
325 KoColor bgColor(qc, cs);
326
328 if( radioBackgroundAsRaster->isChecked() ){
329 bgStyle = KisConfig::RASTER_LAYER;
330 } else if( radioBackgroundAsFill->isChecked() ){
331 bgStyle = KisConfig::FILL_LAYER;
332 }
333
334 doc->newImage(txtName->text(), width, height, cs, bgColor, bgStyle, intNumLayers->value(), txtDescription->toPlainText(), resolution);
335
336 KisConfig cfg(true);
337 cfg.setNumDefaultLayers(intNumLayers->value());
339 cfg.setDefaultBackgroundColor(cmbColor->color().toQColor());
340 cfg.setDefaultBackgroundStyle(bgStyle);
341
342 return doc;
343}
344
346{
347 intNumLayers->setValue(layers);
348}
349
351{
352 qint32 opacity = sliderOpacity->value();
353
354 if (!opacity)
355 return 0;
356
357 return (opacity * 255) / 100;
358}
359
361 sliderOpacity->setValue((value * 100) / 255);
362}
363
365{
366 cmbPredefined->clear();
367 m_predefined.clear();
368
369 cmbPredefined->addItem("");
370
371 QStringList definitions = KoResourcePaths::findAllAssets("data", "predefined_image_sizes/*.predefinedimage", KoResourcePaths::Recursive);
372 definitions.sort();
373
374 if (!definitions.empty()) {
375
376 Q_FOREACH (const QString &definition, definitions) {
377 QFile f(definition);
378 if (f.open(QIODevice::ReadOnly)) {
379 QString xml = QString::fromUtf8(f.readAll());
381 predefined->fromXML(xml);
382 if (predefined->hasProperty("name")
383 && predefined->hasProperty("width")
384 && predefined->hasProperty("height")
385 && predefined->hasProperty("resolution")
386 && predefined->hasProperty("x-unit")
387 && predefined->hasProperty("y-unit")) {
388 m_predefined << predefined;
389 cmbPredefined->addItem(predefined->getString("name"));
390 }
391 }
392 }
393 }
394
395 cmbPredefined->setCurrentIndex(0);
396
397}
398
399
401{
402 if (index < 1 || index > m_predefined.size()) return;
403
404 KisPropertiesConfigurationSP predefined = m_predefined[index - 1];
405 txtPredefinedName->setText(predefined->getString("name"));
406 if (cmbResolutionUnit->currentText() == pixelsInchStr()) {
407 doubleResolution->setValue(predefined->getDouble("resolution"));
408 } else {
409 doubleResolution->setValue(KoUnit::convertFromUnitToUnit(predefined->getDouble("resolution"), KoUnit(KoUnit::Centimeter), KoUnit(KoUnit::Inch)));
410 }
411 cmbWidthUnit->setCurrentIndex(predefined->getInt("x-unit"));
412 cmbHeightUnit->setCurrentIndex(predefined->getInt("y-unit"));
413
414 widthUnitChanged(cmbWidthUnit->currentIndex());
415 heightUnitChanged(cmbHeightUnit->currentIndex());
416
417 doubleWidth->setValue(predefined->getDouble("width"));
418 doubleHeight->setValue(predefined->getDouble("height"));
420
421}
422
424{
425 QString fileName = txtPredefinedName->text();
426 if (fileName.isEmpty()) {
427 return;
428 }
429 QString saveLocation = KoResourcePaths::saveLocation("data", "predefined_image_sizes/", true);
430 QFile f(saveLocation + '/' + fileName.replace(' ', '_').replace('(', '_').replace(')', '_').replace(':', '_') + ".predefinedimage");
431
432 if (!f.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
433 QMessageBox::warning(this, i18nc("@title:window", "Krita"),
434 i18n("Could not save %1.\nReason: %2.", f.fileName(), f.errorString()));
435 return;
436 }
438 predefined->setProperty("name", txtPredefinedName->text());
439 predefined->setProperty("width", doubleWidth->value());
440 predefined->setProperty("height", doubleHeight->value());
441 predefined->setProperty("resolution", doubleResolution->value());
442 predefined->setProperty("x-unit", cmbWidthUnit->currentIndex());
443 predefined->setProperty("y-unit", cmbHeightUnit->currentIndex());
444
445 QString xml = predefined->toXML();
446
447 f.write(xml.toUtf8());
448 f.flush();
449 f.close();
450
451 int i = 0;
452 bool found = false;
454 if (pr->getString("name") == txtPredefinedName->text()) {
455 found = true;
456 break;
457 }
458 ++i;
459 }
460 if (found) {
461 m_predefined[i] = predefined;
462 }
463 else {
464 m_predefined.append(predefined);
465 cmbPredefined->addItem(txtPredefinedName->text());
466 }
467
468}
469
471{
472 if (doubleWidth->value() < doubleHeight->value()) {
474 }
475}
476
478{
479 if (doubleWidth->value() > doubleHeight->value()) {
481 }
482}
483
485{
486 double width = doubleWidth->value();
487 double height = doubleHeight->value();
488
489 doubleHeight->clearFocus();
490 doubleWidth->clearFocus();
491
492 doubleHeight->blockSignals(true);
493 doubleWidth->blockSignals(true);
494 cmbWidthUnit->blockSignals(true);
495 cmbHeightUnit->blockSignals(true);
496
497 doubleWidth->setValue(height);
498 doubleHeight->setValue(width);
499 cmbWidthUnit->setCurrentIndex(m_heightUnit.indexInListForUi(KoUnit::ListAll));
500 cmbHeightUnit->setCurrentIndex(m_widthUnit.indexInListForUi(KoUnit::ListAll));
501
502 doubleHeight->blockSignals(false);
503 doubleWidth->blockSignals(false);
504 cmbWidthUnit->blockSignals(false);
505 cmbHeightUnit->blockSignals(false);
507
508 widthChanged(doubleWidth->value());
509 heightChanged(doubleHeight->value());
511}
512
514{
515 if(doubleWidth->value() > doubleHeight->value())
516 bnLandscape->setChecked(true);
517 else
518 bnPortrait->setChecked(true);
519}
520
522{
523
524 qint64 width, height;
525 double resolution;
526 resolution = doubleResolution->value() / 72.0; // internal resolution is in pixels per pt
527
528 width = static_cast<qint64>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_width));
529 height = static_cast<qint64>(0.5 + KoUnit(KoUnit::Pixel, resolution).toUserValuePrecise(m_height));
530
531 qint64 layerSize = width * height;
532 const KoColorSpace *cs = colorSpaceSelector->currentColorSpace();
533 int bitSize = 8 * cs->pixelSize(); //pixelsize is in bytes.
534 layerSize = layerSize * cs->pixelSize();
535 QString text = i18nc("arg1: width. arg2: height. arg3: colorspace name. arg4: size of a channel in bits. arg5: image size",
536 "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.",
537 width,
538 height,
539 cs->name(),
540 bitSize,
541 KFormat().formatByteSize(layerSize));
542 lblDocumentInfo->setText(text);
543}
544
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"))
BackgroundStyle defaultBackgroundStyle(bool defaultValue=false) const
void setNumDefaultLayers(int num)
void setDefaultBackgroundOpacity(quint8 value)
QColor defaultBackgroundColor(bool defaultValue=false) const
void setDefaultBackgroundStyle(BackgroundStyle value)
void setDefaultBackgroundColor(const QColor &value)
int numDefaultLayers(bool defaultValue=false) const
quint8 defaultBackgroundOpacity(bool defaultValue=false) const
void resolutionChanged(double value)
QList< KisPropertiesConfigurationSP > m_predefined
void showEvent(QShowEvent *) override
KisCustomImageWidget(QWidget *parent, qint32 defWidth, qint32 defHeight, double resolution, const QString &defColorModel, const QString &defColorDepth, const QString &defColorProfile, const QString &imageName)
void setNumberOfLayers(int layers)
Set the number of layers that will be created.
void setBackgroundOpacity(quint8 value)
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:131
KisDocument * createDocument() const
Definition KisPart.cpp:230
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
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:45
#define ppVar(var)
Definition kis_debug.h:155
QIcon loadIcon(const QString &name)
void setText(QSpinBox *spinBox, const QStringView textTemplate)
static KoColorSpaceRegistry * instance()
static const QString pixelsCentimeterStr()
static QString pixelsInchStr()