Pencil2D Animation
Download Community News Docs Contribute
  • Overview
  • Articles
  • Code
  •  
  • Class List
  • Class Index
  • Class Hierarchy
  • Class Members
  • File List
Loading...
Searching...
No Matches
  • app
  • src
layeropacitydialog.cpp
1#include "layeropacitydialog.h"
2#include "ui_layeropacitydialog.h"
3
4#include "layermanager.h"
5#include "playbackmanager.h"
6#include "layer.h"
7#include "layerbitmap.h"
8#include "bitmapimage.h"
9#include "layervector.h"
10#include "vectorimage.h"
11
12
13LayerOpacityDialog::LayerOpacityDialog(QWidget *parent) :
14 QDialog(parent, Qt::Tool),
15 ui(new Ui::LayerOpacityDialog)
16{
17 ui->setupUi(this);
18}
19
20LayerOpacityDialog::~LayerOpacityDialog()
21{
22 delete ui;
23}
24
25void LayerOpacityDialog::setCore(Editor *editor)
26{
27 mEditor = editor;
28 mLayerManager = mEditor->layers();
29 mPlayBack = mEditor->playback();
30}
31
32void LayerOpacityDialog::initUI()
33{
34
35 connect(ui->chooseOpacitySlider, &QSlider::valueChanged, this, &LayerOpacityDialog::opacitySliderChanged);
36 auto spinboxValueChanged = static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged);
37 connect(ui->chooseOpacitySpinBox, spinboxValueChanged, this, &LayerOpacityDialog::opacitySpinboxChanged);
38 connect(ui->btnFadeIn, &QPushButton::pressed, this, &LayerOpacityDialog::fadeInPressed);
39 connect(ui->btnFadeOut, &QPushButton::pressed, this, &LayerOpacityDialog::fadeOutPressed);
40 connect(ui->btnClose, &QPushButton::pressed, this, &LayerOpacityDialog::close);
41 connect(ui->rbActiveKeyframe, &QRadioButton::toggled, this, &LayerOpacityDialog::updateUI);
42 connect(ui->rbSelectedKeyframes, &QRadioButton::toggled, this, &LayerOpacityDialog::updateUI);
43 connect(ui->rbActiveLayer, &QRadioButton::toggled, this, &LayerOpacityDialog::updateUI);
44
45 connect(this, &QDialog::finished, this, &LayerOpacityDialog::close);
46
47 connect(mEditor, &Editor::objectLoaded, this, &LayerOpacityDialog::onObjectLoaded);
48 connect(mEditor, &Editor::scrubbed, this, &LayerOpacityDialog::onCurrentFrameChanged);
49 connect(mPlayBack, &PlaybackManager::playStateChanged, this, &LayerOpacityDialog::onPlayStateChanged);
50 connect(mLayerManager, &LayerManager::currentLayerChanged, this, &LayerOpacityDialog::onCurrentLayerChanged);
51 connect(mEditor, &Editor::selectedFramesChanged, this, &LayerOpacityDialog::onSelectedFramesChanged);
52
53 onObjectLoaded();
54}
55
56void LayerOpacityDialog::updateUI()
57{
58 Layer* currentLayer = mLayerManager->currentLayer();
59 if (currentLayer == nullptr) { return; }
60
61 ui->labLayerInfo->setText(tr("Layer: %1").arg(currentLayer->name()));
62 if (currentLayer->type() != Layer::BITMAP && currentLayer->type() != Layer::VECTOR) {
63 setCanAdjust(false, false);
64 return;
65 }
66
67 bool canAdjust = false;
68 if (ui->rbActiveKeyframe->isChecked()) {
69 KeyFrame* keyframe = currentLayer->getLastKeyFrameAtPosition(mEditor->currentFrame());
70 canAdjust = keyframe != nullptr;
71 } else if (ui->rbSelectedKeyframes->isChecked()) {
72 canAdjust = !currentLayer->getSelectedFramesByPos().isEmpty();
73 } else if (ui->rbActiveLayer->isChecked()) {
74 canAdjust = true;
75 }
76
77 updateSelectedFramesUI();
78
79 ui->chooseOpacitySlider->setEnabled(canAdjust);
80 ui->chooseOpacitySpinBox->setEnabled(canAdjust);
81}
82
83void LayerOpacityDialog::onObjectLoaded()
84{
85 Layer* currentLayer = mLayerManager->currentLayer();
86 if (currentLayer == nullptr) { return; }
87
88 if (currentLayer->type() != Layer::BITMAP && currentLayer->type() != Layer::VECTOR) { return; }
89
90 KeyFrame* keyframe = currentLayer->getLastKeyFrameAtPosition(mEditor->currentFrame());
91
92 if (keyframe) {
93 updateValues(getOpacityForKeyFrame(currentLayer, keyframe));
94 } else {
95 updateValues(100);
96 }
97
98 updateUI();
99}
100
101qreal LayerOpacityDialog::getOpacityForKeyFrame(Layer* layer, const KeyFrame* keyframe) const
102{
103 if (layer->type() == Layer::BITMAP) {
104 const BitmapImage* bitmap = static_cast<const BitmapImage*>(keyframe);
105 return bitmap->getOpacity();
106 } else if (layer->type() == Layer::VECTOR) {
107 const VectorImage* vector = static_cast<const VectorImage*>(keyframe);
108 return vector->getOpacity();
109 } else {
110 return -1;
111 }
112}
113
114void LayerOpacityDialog::setOpacityForKeyFrame(Layer* layer, KeyFrame* keyframe, qreal opacity)
115{
116 if (layer->type() == Layer::BITMAP) {
117 BitmapImage* bitmap = static_cast<BitmapImage*>(keyframe);
118 bitmap->setOpacity(opacity);
119 layer->markFrameAsDirty(bitmap->pos());
120 } else if (layer->type() == Layer::VECTOR) {
121 VectorImage* vector = static_cast<VectorImage*>(keyframe);
122 vector->setOpacity(opacity);
123 layer->markFrameAsDirty(vector->pos());
124 }
125}
126
127void LayerOpacityDialog::opacitySliderChanged(int value)
128{
129 ui->chooseOpacitySpinBox->setValue(value * mSpinBoxMultiplier);
130 opacityValueChanged();
131}
132
133void LayerOpacityDialog::opacitySpinboxChanged(double value)
134{
135 ui->chooseOpacitySlider->setValue(static_cast<int>(value * 5.0));
136 opacityValueChanged();
137}
138
139void LayerOpacityDialog::fade(OpacityFadeType fadeType)
140{
141 QSignalBlocker b1(ui->chooseOpacitySlider);
142 QSignalBlocker b2(ui->chooseOpacitySpinBox);
143
144 Layer* currentLayer = mLayerManager->currentLayer();
145 if (currentLayer == nullptr) { return; }
146
147 if (currentLayer->type() != Layer::BITMAP && currentLayer->type() != Layer::VECTOR) { return; }
148
149 QList<int> selectedKeys = currentLayer->getSelectedFramesByPos();
150
151 if (selectedKeys.count() < mMinSelectedFrames) { return; }
152
153 int fadeFromPos = selectedKeys.first();
154 KeyFrame* keyframe = currentLayer->getLastKeyFrameAtPosition(fadeFromPos);
155 if (keyframe == nullptr) { return; }
156
157 qreal initialOpacity = getOpacityForKeyFrame(currentLayer, keyframe);
158
159 qreal imageCount = static_cast<qreal>(selectedKeys.count() - 1);
160
161 qreal opacityStepper = 0.0;
162 switch (fadeType) {
163 case OpacityFadeType::IN:
164 {
165 // When the opacity is 100% act as we're doing a full fade in from 0-100%
166 if (initialOpacity >= 1.0) {
167 initialOpacity = 0.0;
168 }
169 opacityStepper = (1.0 - initialOpacity) / imageCount;
170 break;
171 }
172 case OpacityFadeType::OUT:
173 {
174 // When the opacity is 0%, act as we're doing a full fade out from 100-0%
175 if (initialOpacity <= 0) {
176 initialOpacity = 1.0;
177 }
178 opacityStepper = initialOpacity / imageCount;
179 break;
180 }
181 }
182
183 for (int i = 0; i < selectedKeys.count(); i++) {
184 keyframe = currentLayer->getLastKeyFrameAtPosition(selectedKeys.at(i));
185 if (keyframe == nullptr) { continue; }
186
187 qreal newOpacity = 0;
188 switch (fadeType)
189 {
190 case OpacityFadeType::IN: {
191 newOpacity = initialOpacity + (i * opacityStepper);
192 break;
193 }
194 case OpacityFadeType::OUT: {
195 newOpacity = initialOpacity - (i * opacityStepper);
196 break;
197 }
198 }
199 setOpacityForKeyFrame(currentLayer, keyframe, newOpacity);
200 }
201
202 keyframe = currentLayer->getLastKeyFrameAtPosition(mEditor->currentFrame());
203
204 if (keyframe) {
205 qreal imageOpacity = getOpacityForKeyFrame(currentLayer, keyframe);
206 updateValues(imageOpacity);
207 }
208
209 emit mEditor->framesModified();
210}
211
212void LayerOpacityDialog::fadeInPressed()
213{
214 fade(OpacityFadeType::IN);
215}
216
217void LayerOpacityDialog::fadeOutPressed()
218{
219 fade(OpacityFadeType::OUT);
220}
221
222void LayerOpacityDialog::onCurrentLayerChanged(int)
223{
224 onCurrentFrameChanged(mEditor->currentFrame());
225 updateUI();
226}
227
228void LayerOpacityDialog::onCurrentFrameChanged(int frame)
229{
230 if (mPlayerIsPlaying) { return; }
231
232 Layer* currentLayer = mLayerManager->currentLayer();
233 if (currentLayer == nullptr) { return; }
234
235 if (currentLayer->type() != Layer::BITMAP && currentLayer->type() != Layer::VECTOR) {
236 setCanAdjust(false, false);
237 return;
238 }
239
240 KeyFrame* keyframe = currentLayer->getLastKeyFrameAtPosition(frame);
241 if (keyframe) {
242 updateValues(getOpacityForKeyFrame(currentLayer, keyframe));
243 }
244 updateUI();
245}
246
247void LayerOpacityDialog::onSelectedFramesChanged()
248{
249 updateUI();
250}
251
252void LayerOpacityDialog::updateSelectedFramesUI()
253{
254 Layer* currentLayer = mLayerManager->currentLayer();
255 if (currentLayer == nullptr) { return; }
256
257 QList<int> frames = currentLayer->getSelectedFramesByPos();
258
259 int minSelectedFrames = frames.count() >= mMinSelectedFrames;
260 ui->groupBoxFade->setEnabled(minSelectedFrames);
261 ui->rbSelectedKeyframes->setEnabled(minSelectedFrames);
262}
263
264void LayerOpacityDialog::onPlayStateChanged(bool isPlaying)
265{
266 mPlayerIsPlaying = isPlaying;
267
268 if (!mPlayerIsPlaying) {
269 onCurrentFrameChanged(mEditor->currentFrame());
270 }
271 updateUI();
272}
273
274void LayerOpacityDialog::updateValues(qreal opacity)
275{
276 QSignalBlocker b1(ui->chooseOpacitySlider);
277 QSignalBlocker b2(ui->chooseOpacitySpinBox);
278
279 int newOpacity = static_cast<int>(opacity * mMultiplier);
280 ui->chooseOpacitySlider->setValue(newOpacity);
281 ui->chooseOpacitySpinBox->setValue(newOpacity * mSpinBoxMultiplier);
282}
283
284void LayerOpacityDialog::opacityValueChanged()
285{
286 if (ui->rbActiveKeyframe->isChecked()) {
287 setOpacityForCurrentKeyframe();
288 } else if (ui->rbActiveLayer->isChecked()) {
289 setOpacityForLayer();
290 } else if (ui->rbSelectedKeyframes->isChecked()) {
291 setOpacityForSelectedKeyframes();
292 }
293}
294
295void LayerOpacityDialog::setOpacityForCurrentKeyframe()
296{
297 Layer* currentLayer = mLayerManager->currentLayer();
298 if (currentLayer == nullptr) { return; }
299
300 if (currentLayer->type() != Layer::BITMAP && currentLayer->type() != Layer::VECTOR) { return; }
301
302 KeyFrame* keyframe = currentLayer->getLastKeyFrameAtPosition(mEditor->currentFrame());
303 if (keyframe == nullptr) { return; }
304
305 qreal opacity = ui->chooseOpacitySlider->value() / mMultiplier;
306 setOpacityForKeyFrame(currentLayer, keyframe, opacity);
307
308 emit mEditor->framesModified();
309}
310
311void LayerOpacityDialog::setOpacityForSelectedKeyframes()
312{
313 Layer* currentLayer = mLayerManager->currentLayer();
314 if (currentLayer == nullptr) { return; }
315
316 QList<int> frames = currentLayer->getSelectedFramesByPos();
317
318 if (frames.isEmpty()) { return; }
319
320 qreal opacity = static_cast<qreal>(ui->chooseOpacitySlider->value()) / mMultiplier;
321
322 for (int pos : frames)
323 {
324 KeyFrame* keyframe = currentLayer->getKeyFrameAt(pos);
325 Q_ASSERT(keyframe);
326
327 setOpacityForKeyFrame(currentLayer, keyframe, opacity);
328 }
329
330 emit mEditor->framesModified();
331}
332
333void LayerOpacityDialog::setOpacityForLayer()
334{
335 Layer* currentLayer = mLayerManager->currentLayer();
336 if (currentLayer == nullptr) { return; }
337
338 qreal opacity = static_cast<qreal>(ui->chooseOpacitySlider->value()) / mMultiplier;
339
340 currentLayer->foreachKeyFrame([this, currentLayer, opacity](KeyFrame* keyframe) {
341 Q_ASSERT(keyframe);
342
343 setOpacityForKeyFrame(currentLayer, keyframe, opacity);
344 });
345
346 emit mEditor->framesModified();
347}
348
349void LayerOpacityDialog::setCanAdjust(bool opacity, bool fade)
350{
351 ui->groupBoxFade->setEnabled(fade);
352 ui->chooseOpacitySlider->setEnabled(opacity);
353 ui->chooseOpacitySpinBox->setEnabled(opacity);
354}
BitmapImage
Definition: bitmapimage.h:28
Editor
Definition: editor.h:71
Editor::framesModified
void framesModified()
This should be emitted after modifying multiple frames.
Editor::scrubbed
void scrubbed(int frameNumber)
This should be emitted after scrubbing.
KeyFrame
Definition: keyframe.h:30
Layer
Definition: layer.h:33
Layer::markFrameAsDirty
void markFrameAsDirty(const int frameNumber)
Mark the frame position as dirty.
Definition: layer.h:170
LayerOpacityDialog
Definition: layeropacitydialog.h:22
VectorImage
Definition: vectorimage.h:32
QAbstractButton::pressed
void pressed()
QAbstractButton::toggled
void toggled(bool checked)
QAbstractSlider::valueChanged
void valueChanged(int value)
QDialog
QDialog::finished
void finished(int result)
QDoubleSpinBox
QDoubleSpinBox::valueChanged
void valueChanged(double d)
QList
QList::at
const T & at(int i) const const
QList::count
int count(const T &value) const const
QList::first
T & first()
QList::isEmpty
bool isEmpty() const const
QObject::connect
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject::tr
QString tr(const char *sourceText, const char *disambiguation, int n)
QSignalBlocker
Qt
Qt::Tool
Tool
QWidget
QWidget::close
bool close()
QWidget::pos
pos
QWidget::setupUi
void setupUi(QWidget *widget)
Generated on Thu May 8 2025 04:47:53 for Pencil2D by doxygen 1.9.6 based on revision 4513250b1d5b1a3676ec0e67b06b7a885ceaae39