1 /*
2 * dlg_imagesize.cc - part of KimageShop^WKrayon^WKrita
3 *
4 * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
5 * Copyright (c) 2009 C. Boemann <cbo@boemann.dk>
6 * Copyright (c) 2013 Juan Palacios <jpalaciosdev@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23 #include "dlg_imagesize.h"
24
25 #include <QLocale>
26 #include <kis_config.h>
27
28 #include <KoUnit.h>
29 #include <kis_size_group.h>
30 #include <klocalizedstring.h>
31
32 #include <kis_filter_strategy.h>
33
34 #include "kis_aspect_ratio_locker.h"
35 #include "kis_acyclic_signal_connector.h"
36 #include "kis_signals_blocker.h"
37
38 #include "kis_double_parse_unit_spin_box.h"
39 #include "kis_document_aware_spin_box_unit_manager.h"
40
41 static const int maxImagePixelSize = 100000000;
42
43 static const QString pixelStr(KoUnit::unitDescription(KoUnit::Pixel));
44 static const QString percentStr(i18n("Percent (%)"));
45 static const QString pixelsInchStr(i18n("Pixels/Inch"));
46 static const QString pixelsCentimeterStr(i18n("Pixels/Centimeter"));
47
48 const QString DlgImageSize::PARAM_PREFIX = "imagesizedlg";
49 const QString DlgImageSize::PARAM_IMSIZE_UNIT = DlgImageSize::PARAM_PREFIX + "_imsizeunit";
50 const QString DlgImageSize::PARAM_SIZE_UNIT = DlgImageSize::PARAM_PREFIX + "_sizeunit";
51 const QString DlgImageSize::PARAM_RES_UNIT = DlgImageSize::PARAM_PREFIX + "_resunit";
52 const QString DlgImageSize::PARAM_RATIO_LOCK = DlgImageSize::PARAM_PREFIX + "_ratioLock";
53 const QString DlgImageSize::PARAM_PRINT_SIZE_SEPARATE = DlgImageSize::PARAM_PREFIX + "_printSizeSeparatly";
54
DlgImageSize(QWidget * parent,int width,int height,double resolution)55 DlgImageSize::DlgImageSize(QWidget *parent, int width, int height, double resolution)
56 : KoDialog(parent)
57 {
58 setCaption(i18n("Scale To New Size"));
59 setButtons(Ok | Cancel);
60 setDefaultButton(Ok);
61
62 m_page = new WdgImageSize(this);
63
64 Q_CHECK_PTR(m_page);
65 m_page->layout()->setMargin(0);
66 m_page->setObjectName("image_size");
67
68 m_page->pixelFilterCmb->setIDList(KisFilterStrategyRegistry::instance()->listKeys());
69 m_page->pixelFilterCmb->setToolTip(KisFilterStrategyRegistry::instance()->formattedDescriptions());
70 m_page->pixelFilterCmb->setCurrent("Bicubic");
71
72 /**
73 * Initialize Pixel Width and Height fields
74 */
75
76 m_widthUnitManager = new KisDocumentAwareSpinBoxUnitManager(this);
77 m_heightUnitManager = new KisDocumentAwareSpinBoxUnitManager(this, KisDocumentAwareSpinBoxUnitManager::PIX_DIR_Y);
78
79 KisConfig cfg(true);
80
81 /// configure the unit to image length, default unit is pixel and printing units are forbidden.
82 m_widthUnitManager->setUnitDimension(KisSpinBoxUnitManager::IMLENGTH);
83 m_heightUnitManager->setUnitDimension(KisSpinBoxUnitManager::IMLENGTH);
84
85 m_widthUnitManager->syncWithOtherUnitManager(m_heightUnitManager); //sync the two managers, so that the units will be the same, but each manager will know a different reference for percents.
86
87 m_widthUnitManager->setApparentUnitFromSymbol("px"); //set unit to pixel.
88
89 m_page->pixelWidthDouble->setUnitManager(m_widthUnitManager);
90 m_page->pixelHeightDouble->setUnitManager(m_heightUnitManager);
91 m_page->pixelWidthDouble->setMaximum(maxImagePixelSize);
92 m_page->pixelHeightDouble->setMaximum(maxImagePixelSize);
93 m_page->pixelWidthDouble->changeValue(width);
94 m_page->pixelHeightDouble->changeValue(height);
95 m_page->pixelWidthDouble->setDisplayUnit(false);
96 m_page->pixelHeightDouble->setDisplayUnit(false);
97
98 /// add custom units
99
100 int unitId = m_widthUnitManager->getApparentUnitId();
101
102 m_page->pixelSizeUnit->setModel(m_widthUnitManager);
103 m_page->pixelSizeUnit->setCurrentIndex(unitId);
104
105 /**
106 * Connect Pixel Unit switching controls
107 */
108
109 KisAcyclicSignalConnector *pixelUnitConnector = new KisAcyclicSignalConnector(this);
110 pixelUnitConnector->connectForwardInt(m_page->pixelSizeUnit, SIGNAL(currentIndexChanged(int)),
111 m_widthUnitManager, SLOT(selectApparentUnitFromIndex(int)));
112 pixelUnitConnector->connectBackwardInt(m_widthUnitManager, SIGNAL(unitChanged(int)),
113 m_page->pixelSizeUnit, SLOT(setCurrentIndex(int)));
114
115 QString imSizeUnit = cfg.readEntry<QString>(PARAM_IMSIZE_UNIT, "px");
116
117 m_widthUnitManager->setApparentUnitFromSymbol(imSizeUnit);
118
119 /**
120 * Initialize Print Width, Height and Resolution fields
121 */
122
123 m_printSizeUnitManager = new KisSpinBoxUnitManager(this);
124
125 m_page->printWidth->setUnitManager(m_printSizeUnitManager);
126 m_page->printHeight->setUnitManager(m_printSizeUnitManager);
127 m_page->printWidth->setDecimals(2);
128 m_page->printHeight->setDecimals(2);
129 m_page->printWidth->setDisplayUnit(false);
130 m_page->printHeight->setDisplayUnit(false);
131 m_page->printResolution->setDecimals(2);
132 m_page->printResolution->setAlignment(Qt::AlignRight);
133
134 m_page->printWidthUnit->setModel(m_printSizeUnitManager);
135
136 //TODO: create a resolution dimension in the unit manager.
137 m_page->printResolutionUnit->addItem(pixelsInchStr);
138 m_page->printResolutionUnit->addItem(pixelsCentimeterStr);
139
140
141 /**
142 * Initialize labels and layout
143 */
144 KisSizeGroup *labelsGroup = new KisSizeGroup(this);
145 labelsGroup->addWidget(m_page->lblPixelWidth);
146 labelsGroup->addWidget(m_page->lblPixelHeight);
147 labelsGroup->addWidget(m_page->lblPixelFilter);
148 labelsGroup->addWidget(m_page->lblPrintWidth);
149 labelsGroup->addWidget(m_page->lblPrintHeight);
150 labelsGroup->addWidget(m_page->lblResolution);
151
152 KisSizeGroup *spinboxesGroup = new KisSizeGroup(this);
153 spinboxesGroup->addWidget(m_page->pixelWidthDouble);
154 spinboxesGroup->addWidget(m_page->pixelHeightDouble);
155 spinboxesGroup->addWidget(m_page->printWidth);
156 spinboxesGroup->addWidget(m_page->printHeight);
157 spinboxesGroup->addWidget(m_page->printResolution);
158
159 KisSizeGroup *comboboxesGroup = new KisSizeGroup(this);
160 comboboxesGroup->addWidget(m_page->pixelSizeUnit);
161 comboboxesGroup->addWidget(m_page->printWidthUnit);
162 comboboxesGroup->addWidget(m_page->printResolutionUnit);
163 connect(this, SIGNAL(okClicked()), this, SLOT(accept()));
164
165 /**
166 * Initialize aspect ratio buttons and lockers
167 */
168
169 m_page->pixelAspectRatioBtn->setKeepAspectRatio(true);
170 m_page->printAspectRatioBtn->setKeepAspectRatio(true);
171 m_page->constrainProportionsCkb->setChecked(true);
172
173 m_pixelSizeLocker = new KisAspectRatioLocker(this);
174 m_pixelSizeLocker->connectSpinBoxes(m_page->pixelWidthDouble, m_page->pixelHeightDouble, m_page->pixelAspectRatioBtn);
175
176 m_printSizeLocker = new KisAspectRatioLocker(this);
177 m_printSizeLocker->connectSpinBoxes(m_page->printWidth, m_page->printHeight, m_page->printAspectRatioBtn);
178
179 /**
180 * Connect Keep Aspect Lock buttons
181 */
182
183 KisAcyclicSignalConnector *constrainsConnector = new KisAcyclicSignalConnector(this);
184 constrainsConnector->connectBackwardBool(
185 m_page->constrainProportionsCkb, SIGNAL(toggled(bool)),
186 this, SLOT(slotLockAllRatioSwitched(bool)));
187
188 constrainsConnector->connectForwardBool(
189 m_pixelSizeLocker, SIGNAL(aspectButtonToggled(bool)),
190 this, SLOT(slotLockPixelRatioSwitched(bool)));
191
192 constrainsConnector->createCoordinatedConnector()->connectBackwardBool(
193 m_printSizeLocker, SIGNAL(aspectButtonToggled(bool)),
194 this, SLOT(slotLockPrintRatioSwitched(bool)));
195
196 constrainsConnector->createCoordinatedConnector()->connectBackwardBool(
197 m_page->adjustPrintSizeSeparatelyCkb, SIGNAL(toggled(bool)),
198 this, SLOT(slotAdjustSeparatelySwitched(bool)));
199
200 /**
201 * Connect Print Unit switching controls
202 */
203
204 KisAcyclicSignalConnector *printUnitConnector = new KisAcyclicSignalConnector(this);
205 printUnitConnector->connectForwardInt(
206 m_page->printWidthUnit, SIGNAL(currentIndexChanged(int)),
207 m_printSizeUnitManager, SLOT(selectApparentUnitFromIndex(int)));
208
209 printUnitConnector->connectBackwardInt(
210 m_printSizeUnitManager, SIGNAL(unitChanged(int)),
211 m_page->printWidthUnit, SLOT(setCurrentIndex(int)));
212
213 /// connect resolution
214 connect(m_page->printResolutionUnit, SIGNAL(currentIndexChanged(int)),
215 this, SLOT(slotPrintResolutionUnitChanged()));
216
217 /**
218 * Create syncing connections between Pixel and Print values
219 */
220 KisAcyclicSignalConnector *syncConnector = new KisAcyclicSignalConnector(this);
221 syncConnector->connectForwardVoid(
222 m_pixelSizeLocker, SIGNAL(sliderValueChanged()),
223 this, SLOT(slotSyncPixelToPrintSize()));
224
225 syncConnector->connectBackwardVoid(
226 m_printSizeLocker, SIGNAL(sliderValueChanged()),
227 this, SLOT(slotSyncPrintToPixelSize()));
228
229 syncConnector->createCoordinatedConnector()->connectBackwardVoid(
230 m_page->printResolution, SIGNAL(valueChanged(double)),
231 this, SLOT(slotPrintResolutionChanged()));
232
233
234 /**
235 * Initialize printing values from the predefined image values
236 */
237 QString printSizeUnit;
238
239 if (QLocale().measurementSystem() == QLocale::MetricSystem) {
240 printSizeUnit = "cm";
241 } else { // Imperial
242 printSizeUnit = "in";
243 }
244
245 printSizeUnit = cfg.readEntry<QString>(PARAM_SIZE_UNIT, printSizeUnit);
246
247 m_printSizeUnitManager->setApparentUnitFromSymbol(printSizeUnit);
248
249 setCurrentResolutionPPI(resolution);
250 slotSyncPixelToPrintSize();
251
252 /**
253 * Initialize aspect ratio lockers with the current proportion.
254 */
255 m_pixelSizeLocker->updateAspect();
256 m_printSizeLocker->updateAspect();
257
258 QString printResUnit = cfg.readEntry<QString>(PARAM_RES_UNIT, "");
259 m_page->printResolutionUnit->setCurrentText(printResUnit);
260
261 m_page->constrainProportionsCkb->setChecked(cfg.readEntry<bool>(PARAM_RATIO_LOCK, true));
262 m_page->adjustPrintSizeSeparatelyCkb->setChecked(cfg.readEntry<bool>(PARAM_PRINT_SIZE_SEPARATE, false));
263
264 setMainWidget(m_page);
265 }
266
~DlgImageSize()267 DlgImageSize::~DlgImageSize()
268 {
269 KisConfig cfg(false);
270 cfg.writeEntry<bool>(PARAM_PRINT_SIZE_SEPARATE, m_page->adjustPrintSizeSeparatelyCkb->isChecked());
271 cfg.writeEntry<bool>(PARAM_RATIO_LOCK, m_page->constrainProportionsCkb->isChecked());
272
273 cfg.writeEntry<QString>(PARAM_IMSIZE_UNIT, m_widthUnitManager->getApparentUnitSymbol());
274 cfg.writeEntry<QString>(PARAM_SIZE_UNIT, m_printSizeUnitManager->getApparentUnitSymbol());
275 cfg.writeEntry<QString>(PARAM_RES_UNIT, m_page->printResolutionUnit->currentText());
276
277 delete m_page;
278 }
279
width()280 qint32 DlgImageSize::width()
281 {
282 return int(m_page->pixelWidthDouble->value());
283 }
284
height()285 qint32 DlgImageSize::height()
286 {
287 return int(m_page->pixelHeightDouble->value());
288 }
289
resolution()290 double DlgImageSize::resolution()
291 {
292 return currentResolutionPPI();
293 }
294
filterType()295 KisFilterStrategy *DlgImageSize::filterType()
296 {
297 KoID filterID = m_page->pixelFilterCmb->currentItem();
298 KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value(filterID.id());
299 return filter;
300 }
301
slotSyncPrintToPixelSize()302 void DlgImageSize::slotSyncPrintToPixelSize()
303 {
304 const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked();
305
306 if (!printIsSeparate) {
307 KisSignalsBlocker b(m_page->pixelWidthDouble, m_page->pixelHeightDouble);
308 m_page->pixelWidthDouble->changeValue(m_page->printWidth->value() * currentResolutionPPI());
309 m_page->pixelHeightDouble->changeValue(m_page->printHeight->value() * currentResolutionPPI());
310 } else if (m_page->pixelWidthDouble->value() != 0.0) {
311 const qreal resolution = qMax(0.001, m_page->pixelWidthDouble->value() / m_page->printWidth->value());
312 setCurrentResolutionPPI(resolution);
313 }
314 }
315
slotSyncPixelToPrintSize()316 void DlgImageSize::slotSyncPixelToPrintSize()
317 {
318 const qreal resolution = currentResolutionPPI();
319 if (resolution != 0.0) {
320 KisSignalsBlocker b(m_page->printWidth, m_page->printHeight);
321 m_page->printWidth->changeValue(m_page->pixelWidthDouble->value() / resolution);
322 m_page->printHeight->changeValue(m_page->pixelHeightDouble->value() / resolution);
323 }
324 }
325
slotPrintResolutionChanged()326 void DlgImageSize::slotPrintResolutionChanged()
327 {
328 const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked();
329
330 if (printIsSeparate) {
331 slotSyncPixelToPrintSize();
332 } else {
333 slotSyncPrintToPixelSize();
334 }
335
336 updatePrintSizeMaximum();
337 }
338
slotPrintResolutionUnitChanged()339 void DlgImageSize::slotPrintResolutionUnitChanged()
340 {
341 qreal resolution = m_page->printResolution->value();
342
343 if (m_page->printResolutionUnit->currentText() == pixelsInchStr) {
344 resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Inch), KoUnit(KoUnit::Centimeter));
345 } else {
346 resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Centimeter), KoUnit(KoUnit::Inch));
347 }
348
349 {
350 KisSignalsBlocker b(m_page->printResolution);
351 m_page->printResolution->setValue(resolution);
352 }
353 }
354
slotLockPixelRatioSwitched(bool value)355 void DlgImageSize::slotLockPixelRatioSwitched(bool value)
356 {
357 const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked();
358
359 if (!printIsSeparate) {
360 m_page->printAspectRatioBtn->setKeepAspectRatio(value);
361 }
362 m_page->constrainProportionsCkb->setChecked(value);
363 }
364
slotLockPrintRatioSwitched(bool value)365 void DlgImageSize::slotLockPrintRatioSwitched(bool value)
366 {
367 m_page->pixelAspectRatioBtn->setKeepAspectRatio(value);
368 m_page->constrainProportionsCkb->setChecked(value);
369 }
370
slotLockAllRatioSwitched(bool value)371 void DlgImageSize::slotLockAllRatioSwitched(bool value)
372 {
373 const bool printIsSeparate = m_page->adjustPrintSizeSeparatelyCkb->isChecked();
374
375 m_page->pixelAspectRatioBtn->setKeepAspectRatio(value);
376
377 if (!printIsSeparate) {
378 m_page->printAspectRatioBtn->setKeepAspectRatio(value);
379 }
380 }
381
slotAdjustSeparatelySwitched(bool value)382 void DlgImageSize::slotAdjustSeparatelySwitched(bool value)
383 {
384 m_page->printAspectRatioBtn->setEnabled(!value);
385 m_page->printAspectRatioBtn->setKeepAspectRatio(!value ? m_page->constrainProportionsCkb->isChecked() : true);
386 }
387
currentResolutionPPI() const388 qreal DlgImageSize::currentResolutionPPI() const
389 {
390 qreal resolution = m_page->printResolution->value();
391
392 if (m_page->printResolutionUnit->currentText() == pixelsInchStr) {
393 resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Point), KoUnit(KoUnit::Inch));
394 } else {
395 resolution = KoUnit::convertFromUnitToUnit(resolution, KoUnit(KoUnit::Point), KoUnit(KoUnit::Centimeter));
396 }
397
398 return resolution;
399 }
400
setCurrentResolutionPPI(qreal value)401 void DlgImageSize::setCurrentResolutionPPI(qreal value)
402 {
403 qreal newValue = value;
404
405 if (m_page->printResolutionUnit->currentText() == pixelsInchStr) {
406 newValue = KoUnit::convertFromUnitToUnit(value, KoUnit(KoUnit::Inch), KoUnit(KoUnit::Point));
407 } else {
408 newValue = KoUnit::convertFromUnitToUnit(value, KoUnit(KoUnit::Centimeter), KoUnit(KoUnit::Point));
409 }
410
411 {
412 KisSignalsBlocker b(m_page->printResolution);
413 m_page->printResolution->setValue(newValue);
414 }
415
416 updatePrintSizeMaximum();
417 }
418
updatePrintSizeMaximum()419 void DlgImageSize::updatePrintSizeMaximum()
420 {
421 const qreal value = currentResolutionPPI();
422 if (value == 0.0) return;
423
424 m_page->printWidth->setMaximum(maxImagePixelSize / value);
425 m_page->printHeight->setMaximum(maxImagePixelSize / value);
426 }
427