1 // Copyright (C) 2012-2019 The VPaint Developers.
2 // See the COPYRIGHT file at the top-level directory of this distribution
3 // and at https://github.com/dalboris/vpaint/blob/master/COPYRIGHT
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #include "ExportPngDialog.h"
18 
19 #include "Scene.h"
20 
21 #include <cmath>
22 
23 #include <QDoubleSpinBox>
24 #include <QVBoxLayout>
25 #include <QDialogButtonBox>
26 #include <QFormLayout>
27 #include <QCheckBox>
28 #include <QLabel>
29 
ExportPngDialog(Scene * scene)30 ExportPngDialog::ExportPngDialog(Scene * scene) :
31     scene_(scene),
32     ignoreSceneChanged_(false),
33     ignoreWidthHeightChanged_(false)
34 {
35     // Set window title
36     setWindowTitle(tr("Export as PNG"));
37 
38     // Edit Canvas
39     QFormLayout * formLayoutCanvas = new QFormLayout();
40 
41     leftSpinBox_ = new QDoubleSpinBox();
42     leftSpinBox_->setRange(-100000,100000);
43     formLayoutCanvas->addRow(tr("Left"), leftSpinBox_);
44 
45     topSpinBox_ = new QDoubleSpinBox();
46     topSpinBox_->setRange(-100000,100000);
47     formLayoutCanvas->addRow(tr("Top"), topSpinBox_);
48 
49     widthSpinBox_ = new QDoubleSpinBox();
50     widthSpinBox_->setRange(0,100000);
51     formLayoutCanvas->addRow(tr("Width"), widthSpinBox_);
52 
53     heightSpinBox_ = new QDoubleSpinBox();
54     heightSpinBox_->setRange(0,100000);
55     formLayoutCanvas->addRow(tr("Height"), heightSpinBox_);
56 
57     // PNG Export options
58     QFormLayout * formLayoutPng = new QFormLayout();
59 
60     pngWidthSpinBox_ = new QSpinBox();
61     pngWidthSpinBox_->setRange(1,100000);
62     pngWidthSpinBox_->setValue(1280);
63     formLayoutPng->addRow(tr("PNG Width"), pngWidthSpinBox_);
64 
65     pngHeightSpinBox_ = new QSpinBox();
66     pngHeightSpinBox_->setRange(1,100000);
67     pngHeightSpinBox_->setValue(720);
68     formLayoutPng->addRow(tr("PNG Height"), pngHeightSpinBox_);
69 
70     preserveAspectRatioCheckBox_ = new QCheckBox();
71     preserveAspectRatioCheckBox_->setChecked(true);
72     formLayoutPng->addRow(tr("Preserve Aspect Ratio"), preserveAspectRatioCheckBox_);
73 
74     exportSequenceCheckBox_ = new QCheckBox();
75     exportSequenceCheckBox_->setChecked(false);
76     formLayoutPng->addRow(tr("Export Sequence"), exportSequenceCheckBox_);
77 
78     useViewSettings_ = new QCheckBox();
79     useViewSettings_->setChecked(false);
80     formLayoutPng->addRow(tr("Use View Settings"), useViewSettings_);
81 
82     // Export/Cancel dialog buttons
83     QDialogButtonBox * buttonBox = new QDialogButtonBox(QDialogButtonBox::Cancel);
84     buttonBox->addButton(tr("Export"), QDialogButtonBox::AcceptRole);
85 
86     // Main layout
87     QVBoxLayout * layout = new QVBoxLayout();
88     //layout->addWidget(new QLabel(tr("<b>Canvas Size</b>")));
89     //layout->addLayout(formLayoutCanvas);
90     //layout->addWidget(new QLabel(tr("<b>PNG Export Options</b>")));
91     layout->addLayout(formLayoutPng);
92     layout->addStretch();
93     layout->addWidget(buttonBox);
94     setLayout(layout);
95 
96     // Set initial widget values
97     updateDialogFromScene();
98 
99     // Store initial values to allow Cancel
100     backupCurrentCanvasSize_();
101 
102     // Create connections
103     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
104     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
105 
106     connect(scene_, SIGNAL(changed()), this, SLOT(updateDialogFromScene()));
107 
108     connect(topSpinBox_, SIGNAL(valueChanged(double)), this, SLOT(processCanvasSizeChanged_()));
109     connect(leftSpinBox_, SIGNAL(valueChanged(double)), this, SLOT(processCanvasSizeChanged_()));
110     connect(widthSpinBox_, SIGNAL(valueChanged(double)), this, SLOT(processCanvasSizeChanged_()));
111     connect(heightSpinBox_, SIGNAL(valueChanged(double)), this, SLOT(processCanvasSizeChanged_()));
112 
113     connect(pngWidthSpinBox_, SIGNAL(valueChanged(int)), this, SLOT(processPngWidthChanged_(int)));
114     connect(pngHeightSpinBox_, SIGNAL(valueChanged(int)), this, SLOT(processPngHeightChanged_(int)));
115     connect(preserveAspectRatioCheckBox_, SIGNAL(toggled(bool)), this, SLOT(processPreserveAspectRatioChanged_(bool)));
116 }
117 
left() const118 double ExportPngDialog::left() const
119 {
120     return leftSpinBox_->value();
121 }
122 
top() const123 double ExportPngDialog::top() const
124 {
125     return topSpinBox_->value();
126 }
127 
width() const128 double ExportPngDialog::width() const
129 {
130     return widthSpinBox_->value();
131 }
132 
height() const133 double ExportPngDialog::height() const
134 {
135     return heightSpinBox_->value();
136 }
137 
pngWidth() const138 int ExportPngDialog::pngWidth() const
139 {
140     return pngWidthSpinBox_->value();
141 }
142 
pngHeight() const143 int ExportPngDialog::pngHeight() const
144 {
145     return pngHeightSpinBox_->value();
146 }
147 
preserveAspectRatio() const148 bool ExportPngDialog::preserveAspectRatio() const
149 {
150     return preserveAspectRatioCheckBox_->isChecked();
151 }
152 
exportSequence() const153 bool ExportPngDialog::exportSequence() const
154 {
155     return exportSequenceCheckBox_->isChecked();
156 }
157 
useViewSettings() const158 bool ExportPngDialog::useViewSettings() const
159 {
160     return useViewSettings_->isChecked();
161 }
162 
setPngWidthForHeight_()163 void ExportPngDialog::setPngWidthForHeight_()
164 {
165     ignoreWidthHeightChanged_ = true; // prevent infinite recursion with pngWidthChanged()
166     if(height() > 0)
167         pngWidthSpinBox_->setValue(floor(0.5+width() * pngHeight() / height()));
168     ignoreWidthHeightChanged_ = false;
169 }
170 
setPngHeightForWidth_()171 void ExportPngDialog::setPngHeightForWidth_()
172 {
173     ignoreWidthHeightChanged_ = true; // prevent infinite recursion with pngHeightChanged()
174     if(width() > 0)
175         pngHeightSpinBox_->setValue(floor(0.5+height() * pngWidth() / width()));
176     ignoreWidthHeightChanged_ = false;
177 }
178 
enforcePngAspectRatio_()179 void ExportPngDialog::enforcePngAspectRatio_()
180 {
181     if(preserveAspectRatio())
182     {
183         if(width() > height())
184             setPngHeightForWidth_();
185         else
186             setPngWidthForHeight_();
187     }
188 
189 }
190 
processPngWidthChanged_(int)191 void ExportPngDialog::processPngWidthChanged_(int )
192 {
193     if(!ignoreWidthHeightChanged_ && preserveAspectRatio())
194     {
195         setPngHeightForWidth_();
196     }
197 }
198 
processPngHeightChanged_(int)199 void ExportPngDialog::processPngHeightChanged_(int )
200 {
201     if(!ignoreWidthHeightChanged_ && preserveAspectRatio())
202     {
203             setPngWidthForHeight_();
204     }
205 }
206 
processPreserveAspectRatioChanged_(bool)207 void ExportPngDialog::processPreserveAspectRatioChanged_(bool )
208 {
209     enforcePngAspectRatio_();
210 }
211 
backupCurrentCanvasSize_()212 void ExportPngDialog::backupCurrentCanvasSize_()
213 {
214     oldTop_ = scene_->top();
215     oldLeft_ = scene_->left();
216     oldWidth_ = scene_->width();
217     oldHeight_ = scene_->height();
218 }
219 
setVisible(bool visible)220 void ExportPngDialog::setVisible(bool visible)
221 {
222     if(visible)
223     {
224         backupCurrentCanvasSize_();
225         enforcePngAspectRatio_();
226     }
227 
228     QDialog::setVisible(visible);
229 }
230 
scene() const231 Scene * ExportPngDialog::scene() const
232 {
233     return scene_;
234 }
235 
accept()236 void ExportPngDialog::accept()
237 {
238     QDialog::accept();
239 }
240 
reject()241 void ExportPngDialog::reject()
242 {
243     scene_->setTop(oldTop_);
244     scene_->setLeft(oldLeft_);
245     scene_->setWidth(oldWidth_);
246     scene_->setHeight(oldHeight_);
247 
248     QDialog::reject();
249 }
250 
processCanvasSizeChanged_()251 void ExportPngDialog::processCanvasSizeChanged_()
252 {
253     enforcePngAspectRatio_();
254     updateSceneFromDialog();
255 }
256 
updateDialogFromScene()257 void ExportPngDialog::updateDialogFromScene()
258 {
259     if(!ignoreSceneChanged_)
260     {
261         topSpinBox_->setValue(scene()->top());
262         leftSpinBox_->setValue(scene()->left());
263         widthSpinBox_->setValue(scene()->width());
264         heightSpinBox_->setValue(scene()->height());
265     }
266 }
267 
updateSceneFromDialog()268 void ExportPngDialog::updateSceneFromDialog()
269 {
270     ignoreSceneChanged_ = true;
271 
272     scene()->setTop(topSpinBox_->value());
273     scene()->setLeft(leftSpinBox_->value());
274     scene()->setWidth(widthSpinBox_->value());
275     scene()->setHeight(heightSpinBox_->value());
276 
277     ignoreSceneChanged_ = false;
278 }
279