1 #include <memory>
2
3 #include "timestretchpopup.h"
4
5 // Tnz6 includes
6 #include "filmstripcommand.h"
7 #include "cellselection.h"
8 #include "tapp.h"
9 #include "menubarcommandids.h"
10
11 // TnzQt includes
12 #include "toonzqt/tselectionhandle.h"
13 #include "historytypes.h"
14
15 // TnzLib includes
16 #include "toonz/tscenehandle.h"
17 #include "toonz/txsheet.h"
18 #include "toonz/txsheethandle.h"
19 #include "toonz/txshcell.h"
20 #include "toonz/txshcolumn.h"
21
22 // TnzCore includes
23 #include "tundo.h"
24
25 // Qt includes
26 #include <QPushButton>
27 #include <QLabel>
28 #include <QHBoxLayout>
29 #include <QComboBox>
30 #include <QMainWindow>
31
32 //=============================================================================
33 // TimeStretch
34 //-----------------------------------------------------------------------------
35
36 //-----------------------------------------------------------------------------
37 namespace {
38 //-----------------------------------------------------------------------------
39
40 class TimeStretchUndo final : public TUndo {
41 int m_r0, m_r1;
42 int m_c0, m_c1;
43 int m_newRange;
44 std::unique_ptr<TXshCell[]> m_cells;
45
46 // servono per modificare la selezione
47 TimeStretchPopup::STRETCH_TYPE m_type;
48 int m_c0Old;
49 int m_c1Old;
50
51 public:
TimeStretchUndo(int r0,int c0,int r1,int c1,int newRange,TimeStretchPopup::STRETCH_TYPE type)52 TimeStretchUndo(int r0, int c0, int r1, int c1, int newRange,
53 TimeStretchPopup::STRETCH_TYPE type)
54 : m_r0(r0)
55 , m_c0(c0)
56 , m_r1(r1)
57 , m_c1(c1)
58 , m_newRange(newRange)
59 , m_type(type)
60 , m_c0Old(0)
61 , m_c1Old(0) {
62 int nr = m_r1 - m_r0 + 1;
63 int nc = m_c1 - m_c0 + 1;
64 assert(nr > 0 && nc > 0);
65 m_cells.reset(new TXshCell[nr * nc]);
66 assert(m_cells);
67 int k = 0;
68 for (int c = c0; c <= c1; c++)
69 for (int r = r0; r <= r1; r++)
70 m_cells[k++] =
71 TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(r, c);
72 }
73
~TimeStretchUndo()74 ~TimeStretchUndo() {}
75
setOldColumnRange(int c0,int c1)76 void setOldColumnRange(int c0, int c1) {
77 m_c0Old = c0;
78 m_c1Old = c1;
79 }
80
undo() const81 void undo() const override {
82 TApp *app = TApp::instance();
83 TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
84 int oldNr = m_newRange;
85 int nr = m_r1 - m_r0 + 1;
86
87 if (nr > oldNr) // Se avevo cancellato delle celle devo reinserirle
88 {
89 int c;
90 for (c = m_c0; c <= m_c1; c++) {
91 int dn = nr - oldNr;
92 xsh->insertCells(m_r0, c, dn);
93 int i;
94 for (i = 0; i < nr; i++)
95 xsh->setCell(i + m_r0, c, m_cells[i + nr * (c - m_c0)]);
96 }
97 } else // Altrimenti devo rimuoverle
98 {
99 int c;
100 for (c = m_c0; c <= m_c1; c++) {
101 int i;
102 for (i = 0; i < nr; i++)
103 xsh->setCell(i + m_r0, c, m_cells[i + nr * (c - m_c0)]);
104 int dn = oldNr - nr;
105 xsh->removeCells(m_r1, c, dn);
106 }
107 }
108
109 TCellSelection *selection = dynamic_cast<TCellSelection *>(
110 app->getCurrentSelection()->getSelection());
111 if (selection) {
112 if (m_type == TimeStretchPopup::eRegion)
113 selection->selectCells(m_r0, m_c0, m_r1, m_c1);
114 else if (m_type == TimeStretchPopup::eFrameRange)
115 selection->selectCells(m_r0, m_c0Old, m_r1, m_c1Old);
116 }
117
118 app->getCurrentXsheet()->notifyXsheetChanged();
119 app->getCurrentXsheet()->notifyXsheetSoundChanged();
120 }
121
redo() const122 void redo() const override {
123 if (m_r1 - m_r0 < 0 || m_c1 - m_c0 < 0) return;
124 TApp *app = TApp::instance();
125 app->getCurrentXsheet()->getXsheet()->timeStretch(m_r0, m_c0, m_r1, m_c1,
126 m_newRange);
127
128 TCellSelection *selection = dynamic_cast<TCellSelection *>(
129 app->getCurrentSelection()->getSelection());
130 if (selection) {
131 if (m_type == TimeStretchPopup::eRegion)
132 selection->selectCells(m_r0, m_c0, m_r0 + m_newRange - 1, m_c1);
133 else if (m_type == TimeStretchPopup::eFrameRange)
134 selection->selectCells(m_r0, m_c0Old, m_r0 + m_newRange - 1, m_c1Old);
135 }
136 app->getCurrentXsheet()->notifyXsheetChanged();
137 app->getCurrentXsheet()->notifyXsheetSoundChanged();
138 }
139
getSize() const140 int getSize() const override { return sizeof(*this); }
141
getHistoryString()142 QString getHistoryString() override { return QObject::tr("Time Stretch"); }
getHistoryType()143 int getHistoryType() override { return HistoryType::Xsheet; }
144 };
145
146 //-----------------------------------------------------------------------------
147
timeStretch(int newRange,TimeStretchPopup::STRETCH_TYPE type)148 void timeStretch(int newRange, TimeStretchPopup::STRETCH_TYPE type) {
149 TCellSelection::Range range;
150 TCellSelection *selection = dynamic_cast<TCellSelection *>(
151 TApp::instance()->getCurrentSelection()->getSelection());
152 if (type != TimeStretchPopup::eWholeXsheet) {
153 if (!selection) {
154 DVGui::error(QObject::tr("The current selection is invalid."));
155 return;
156 }
157 range = selection->getSelectedCells();
158 }
159 int r0 = range.m_r0;
160 int r1 = range.m_r1;
161 int c0 = 0, c1 = 0;
162 TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
163 if (type == TimeStretchPopup::eRegion) {
164 c0 = range.m_c0;
165 c1 = range.m_c1;
166 } else {
167 if (type == TimeStretchPopup::eWholeXsheet) {
168 r0 = 0;
169 r1 = xsheet->getFrameCount() - 1;
170 }
171 c1 = xsheet->getColumnCount() - 1;
172 int c;
173 for (c = c1; c >= c0; c--)
174 if (!xsheet->getColumn(c) && !xsheet->getColumn(c)->isEmpty()) break;
175 }
176 assert(r1 >= r0 && c1 >= c0);
177 if (r1 - r0 + 1 == newRange) return;
178
179 TimeStretchUndo *undo = new TimeStretchUndo(r0, c0, r1, c1, newRange, type);
180
181 xsheet->timeStretch(r0, c0, r1, c1, newRange);
182
183 if (type == TimeStretchPopup::eFrameRange)
184 undo->setOldColumnRange(range.m_c0, range.m_c1);
185 TUndoManager::manager()->add(undo);
186
187 // Modifico la selezione in base al tipo di comando effettuato
188 if (type != TimeStretchPopup::eWholeXsheet) {
189 assert(selection);
190 selection->selectCells(r0, range.m_c0, r0 + newRange - 1, range.m_c1);
191 }
192
193 TApp::instance()->getCurrentScene()->setDirtyFlag(true);
194 TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
195 TApp::instance()->getCurrentXsheet()->notifyXsheetSoundChanged();
196 }
197
198 //-----------------------------------------------------------------------------
199 } // namespace
200 //-----------------------------------------------------------------------------
201
202 //=============================================================================
203 // TimeStretchPopup
204 //-----------------------------------------------------------------------------
205
TimeStretchPopup()206 TimeStretchPopup::TimeStretchPopup()
207 : Dialog(TApp::instance()->getMainWindow(), true, true, "TimeStretch")
208 , m_currentStretchType(eRegion) {
209 setModal(false);
210 setWindowTitle(tr("Time Stretch"));
211
212 beginVLayout();
213
214 m_stretchType = new QComboBox(this);
215 m_stretchType->setFixedHeight(DVGui::WidgetHeight);
216 QStringList viewType;
217 viewType << tr("Selected Cells") << tr("Selected Frame Range")
218 << tr("Whole Xsheet");
219 m_stretchType->addItems(viewType);
220 connect(m_stretchType, SIGNAL(currentIndexChanged(int)),
221 SLOT(setCurrentStretchType(int)));
222 addWidget(tr("Stretch:"), m_stretchType);
223
224 QHBoxLayout *rangeLayout = new QHBoxLayout(this);
225 m_oldRange = new QLabel("0", this);
226 m_oldRange->setFixedSize(43, DVGui::WidgetHeight);
227 rangeLayout->addWidget(m_oldRange);
228 rangeLayout->addSpacing(10);
229 m_newRangeFld = new DVGui::IntLineEdit(this);
230 rangeLayout->addWidget(new QLabel(tr("New Range:")), 1, Qt::AlignRight);
231 rangeLayout->addWidget(m_newRangeFld, 0, Qt::AlignRight);
232 addLayout(tr("Old Range:"), rangeLayout);
233
234 endVLayout();
235
236 m_okBtn = new QPushButton(tr("Stretch"), this);
237 m_okBtn->setDefault(true);
238 m_cancelBtn = new QPushButton(tr("Cancel"), this);
239 bool ret = connect(m_okBtn, SIGNAL(clicked()), this, SLOT(stretch()));
240 ret = ret && connect(m_cancelBtn, SIGNAL(clicked()), this, SLOT(reject()));
241 assert(ret);
242
243 addButtonBarWidget(m_okBtn, m_cancelBtn);
244 }
245
246 //-------------------------------------------------------------------
247
showEvent(QShowEvent *)248 void TimeStretchPopup::showEvent(QShowEvent *) {
249 TSelectionHandle *selectionHandle = TApp::instance()->getCurrentSelection();
250 bool ret = connect(selectionHandle, SIGNAL(selectionChanged(TSelection *)),
251 this, SLOT(updateValues(TSelection *)));
252 ret = ret && connect(selectionHandle,
253 SIGNAL(selectionSwitched(TSelection *, TSelection *)),
254 this, SLOT(updateValues(TSelection *, TSelection *)));
255 TXsheetHandle *xsheetHandle = TApp::instance()->getCurrentXsheet();
256 ret = ret && connect(xsheetHandle, SIGNAL(xsheetChanged()), this,
257 SLOT(updateValues()));
258 assert(ret);
259 updateValues(selectionHandle->getSelection());
260 }
261
262 //-------------------------------------------------------------------
263
hideEvent(QHideEvent * e)264 void TimeStretchPopup::hideEvent(QHideEvent *e) {
265 TSelectionHandle *selectionHandle = TApp::instance()->getCurrentSelection();
266 bool ret = disconnect(selectionHandle, SIGNAL(selectionChanged(TSelection *)),
267 this, SLOT(updateValues(TSelection *)));
268 ret = ret && connect(selectionHandle,
269 SIGNAL(selectionSwitched(TSelection *, TSelection *)),
270 this, SLOT(updateValues(TSelection *, TSelection *)));
271 TXsheetHandle *xsheetHandle = TApp::instance()->getCurrentXsheet();
272 ret = ret && disconnect(xsheetHandle, SIGNAL(xsheetChanged()), this,
273 SLOT(updateValues()));
274 assert(ret);
275 Dialog::hideEvent(e);
276 }
277 //-------------------------------------------------------------------
278
updateValues()279 void TimeStretchPopup::updateValues() {
280 updateValues(TApp::instance()->getCurrentSelection()->getSelection());
281 }
282
283 //-------------------------------------------------------------------
284
updateValues(TSelection * selection)285 void TimeStretchPopup::updateValues(TSelection *selection) {
286 int from = 0, to = 0, newRange = 0;
287 if (m_currentStretchType == eWholeXsheet) {
288 TXsheet *xsheet = TApp::instance()->getCurrentXsheet()->getXsheet();
289 newRange = xsheet->getFrameCount();
290 } else {
291 TCellSelection *cellCelection = dynamic_cast<TCellSelection *>(selection);
292 if (cellCelection) {
293 int c0, c1;
294 cellCelection->getSelectedCells(from, c0, to, c1);
295 newRange = to - from + 1;
296 }
297 }
298
299 m_newRangeFld->setText(QString::number(newRange));
300 m_oldRange->setText(QString::number(newRange));
301 }
302
303 //-------------------------------------------------------------------
304
setCurrentStretchType(int index)305 void TimeStretchPopup::setCurrentStretchType(int index) {
306 if (m_currentStretchType == STRETCH_TYPE(index)) return;
307 m_currentStretchType = STRETCH_TYPE(index);
308 updateValues();
309 }
310
311 //-------------------------------------------------------------------
312
stretch()313 void TimeStretchPopup::stretch() {
314 timeStretch(m_newRangeFld->text().toInt(), m_currentStretchType);
315 accept();
316 }
317