1 #include "lc_global.h"
2 #include "lc_timelinewidget.h"
3 #include "lc_model.h"
4 #include "piece.h"
5 #include "pieceinf.h"
6 #include "lc_mainwindow.h"
7 #include "lc_viewwidget.h"
8 #include "lc_previewwidget.h"
9
lcTimelineWidget(QWidget * Parent)10 lcTimelineWidget::lcTimelineWidget(QWidget* Parent)
11 : QTreeWidget(Parent)
12 {
13 mCurrentStepItem = nullptr;
14 mIgnoreUpdates = false;
15
16 setSelectionMode(QAbstractItemView::ExtendedSelection);
17 setDragEnabled(true);
18 setDragDropMode(QAbstractItemView::InternalMove);
19 setUniformRowHeights(true);
20 setHeaderHidden(true);
21 setContextMenuPolicy(Qt::CustomContextMenu);
22
23 invisibleRootItem()->setFlags(invisibleRootItem()->flags() & ~Qt::ItemIsDropEnabled);
24
25 connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)), SLOT(CurrentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)));
26 connect(this, SIGNAL(itemSelectionChanged()), SLOT(ItemSelectionChanged()));
27 connect(this, SIGNAL(customContextMenuRequested(QPoint)), SLOT(CustomMenuRequested(QPoint)));
28 }
29
~lcTimelineWidget()30 lcTimelineWidget::~lcTimelineWidget()
31 {
32 }
33
CustomMenuRequested(QPoint Pos)34 void lcTimelineWidget::CustomMenuRequested(QPoint Pos)
35 {
36 QMenu* Menu = new QMenu(this);
37
38 lcObject* FocusObject = gMainWindow->GetActiveModel()->GetFocusObject();
39
40 if (FocusObject && FocusObject->IsPiece())
41 {
42 lcPiece* Piece = (lcPiece*)FocusObject;
43
44 if (Piece->mPieceInfo->IsModel())
45 {
46 Menu->addAction(gMainWindow->mActions[LC_PIECE_EDIT_SELECTED_SUBMODEL]);
47 Menu->addAction(gMainWindow->mActions[LC_PIECE_VIEW_SELECTED_MODEL]);
48 Menu->addAction(gMainWindow->mActions[LC_PIECE_INLINE_SELECTED_MODELS]);
49 Menu->addSeparator();
50 }
51 }
52
53 Menu->addAction(gMainWindow->mActions[LC_TIMELINE_SET_CURRENT]);
54 Menu->addAction(gMainWindow->mActions[LC_TIMELINE_INSERT_BEFORE]);
55 Menu->addAction(gMainWindow->mActions[LC_TIMELINE_INSERT_AFTER]);
56 Menu->addAction(gMainWindow->mActions[LC_TIMELINE_DELETE]);
57 Menu->addAction(gMainWindow->mActions[LC_TIMELINE_MOVE_SELECTION]);
58
59 Menu->addSeparator();
60
61 Menu->addAction(gMainWindow->mActions[LC_PIECE_HIDE_SELECTED]);
62 Menu->addAction(gMainWindow->mActions[LC_PIECE_HIDE_UNSELECTED]);
63 Menu->addAction(gMainWindow->mActions[LC_PIECE_UNHIDE_SELECTED]);
64 Menu->addAction(gMainWindow->mActions[LC_PIECE_UNHIDE_ALL]);
65
66 Menu->exec(viewport()->mapToGlobal(Pos));
67 delete Menu;
68 }
69
Update(bool Clear,bool UpdateItems)70 void lcTimelineWidget::Update(bool Clear, bool UpdateItems)
71 {
72 if (mIgnoreUpdates)
73 return;
74
75 lcModel* Model = gMainWindow->GetActiveModel();
76
77 bool Blocked = blockSignals(true);
78
79 if (!Model)
80 {
81 mCurrentStepItem = nullptr;
82 mItems.clear();
83 clear();
84 blockSignals(Blocked);
85 return;
86 }
87
88 if (Clear)
89 {
90 mCurrentStepItem = nullptr;
91 mItems.clear();
92 clear();
93 }
94
95 lcStep LastStep = Model->GetLastStep();
96 if (Model->HasPieces())
97 LastStep++;
98 LastStep = lcMax(LastStep, Model->GetCurrentStep());
99
100 for (int TopLevelItemIdx = LastStep; TopLevelItemIdx < topLevelItemCount(); )
101 {
102 QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx);
103
104 while (StepItem->childCount())
105 {
106 QTreeWidgetItem* PieceItem = StepItem->child(0);
107 lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value<uintptr_t>();
108 mItems.remove(Piece);
109 delete PieceItem;
110 }
111
112 if (mCurrentStepItem == StepItem)
113 mCurrentStepItem = nullptr;
114
115 delete StepItem;
116 }
117
118 for (unsigned int TopLevelItemIdx = topLevelItemCount(); TopLevelItemIdx < LastStep; TopLevelItemIdx++)
119 {
120 QTreeWidgetItem* StepItem = new QTreeWidgetItem(this, QStringList(tr("Step %1").arg(TopLevelItemIdx + 1)));
121 StepItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsDropEnabled);
122 addTopLevelItem(StepItem);
123 StepItem->setExpanded(true);
124 }
125
126 const lcArray<lcPiece*>& Pieces = Model->GetPieces();
127 QTreeWidgetItem* StepItem = nullptr;
128 int PieceItemIndex = 0;
129 lcStep Step = 0;
130
131 for (lcPiece* Piece : Pieces)
132 {
133 while (Step != Piece->GetStepShow())
134 {
135 if (StepItem)
136 {
137 while (PieceItemIndex < StepItem->childCount())
138 {
139 QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIndex);
140 lcPiece* RemovePiece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value<uintptr_t>();
141
142 if (Pieces.FindIndex(RemovePiece) == -1)
143 {
144 mItems.remove(RemovePiece);
145 delete PieceItem;
146 }
147 else
148 {
149 PieceItem->parent()->removeChild(PieceItem);
150 topLevelItem(RemovePiece->GetStepShow() - 1)->addChild(PieceItem);
151 }
152 }
153 }
154
155 Step++;
156 StepItem = topLevelItem(Step - 1);
157 PieceItemIndex = 0;
158 }
159
160 QTreeWidgetItem* PieceItem = mItems.value(Piece);
161 bool UpdateItem = UpdateItems;
162
163 if (StepItem)
164 {
165 if (!PieceItem)
166 {
167 PieceItem = new QTreeWidgetItem();
168 PieceItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
169 PieceItem->setData(0, Qt::UserRole, QVariant::fromValue<uintptr_t>((uintptr_t)Piece));
170 StepItem->insertChild(PieceItemIndex, PieceItem);
171 mItems[Piece] = PieceItem;
172
173 UpdateItem = true;
174 }
175 else
176 {
177 if (PieceItemIndex >= StepItem->childCount() || PieceItem != StepItem->child(PieceItemIndex))
178 {
179 QTreeWidgetItem* PieceParent = PieceItem->parent();
180
181 if (PieceParent)
182 PieceParent->removeChild(PieceItem);
183
184 StepItem->insertChild(PieceItemIndex, PieceItem);
185 }
186 }
187 }
188
189 if (UpdateItem)
190 {
191 PieceItem->setText(0, Piece->mPieceInfo->m_strDescription);
192
193 int ColorIndex = Piece->GetColorIndex();
194 if (!mIcons.contains(ColorIndex))
195 {
196 int Size = rowHeight(indexFromItem(PieceItem));
197
198 QImage Image(Size, Size, QImage::Format_ARGB32);
199 Image.fill(0);
200 float* Color = gColorList[ColorIndex].Value;
201 QPainter Painter(&Image);
202 Painter.setPen(Qt::darkGray);
203 Painter.setBrush(QColor::fromRgbF(Color[0], Color[1], Color[2]));
204 Painter.drawEllipse(0, 0, Size - 1, Size - 1);
205
206 mIcons[ColorIndex] = QIcon(QPixmap::fromImage(Image));
207 }
208
209 PieceItem->setIcon(0, mIcons[ColorIndex]);
210
211 QColor Color = palette().text().color();
212
213 if (Piece->mPieceInfo->IsPlaceholder())
214 Color = QColor(208, 0, 0);
215 else if (Piece->IsHidden())
216 Color.setAlpha(128);
217
218 PieceItem->setForeground(0, Color);
219 }
220
221 PieceItem->setSelected(Piece->IsSelected());
222 PieceItemIndex++;
223 }
224
225 if (Step == 0)
226 {
227 Step = 1;
228 StepItem = topLevelItem(0);
229 }
230
231 while (Step <= LastStep && StepItem)
232 {
233 while (PieceItemIndex < StepItem->childCount())
234 {
235 QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIndex);
236 lcPiece* RemovePiece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value<uintptr_t>();
237
238 mItems.remove(RemovePiece);
239 delete PieceItem;
240 }
241
242 Step++;
243 StepItem = topLevelItem(Step - 1);
244 PieceItemIndex = 0;
245 }
246
247 UpdateCurrentStepItem();
248
249 blockSignals(Blocked);
250 }
251
UpdateCurrentStepItem()252 void lcTimelineWidget::UpdateCurrentStepItem()
253 {
254 lcModel* Model = gMainWindow->GetActiveModel();
255 lcStep CurrentStep = Model->GetCurrentStep();
256 QTreeWidgetItem* CurrentStepItem = topLevelItem(CurrentStep - 1);
257
258 if (CurrentStepItem != mCurrentStepItem)
259 {
260 if (mCurrentStepItem)
261 {
262 QFont Font = mCurrentStepItem->font(0);
263 Font.setBold(false);
264 mCurrentStepItem->setFont(0, Font);
265 }
266
267 if (CurrentStepItem)
268 {
269 QFont Font = CurrentStepItem->font(0);
270 Font.setBold(true);
271 CurrentStepItem->setFont(0, Font);
272 setCurrentItem(CurrentStepItem);
273 }
274
275 mCurrentStepItem = CurrentStepItem;
276 }
277 }
278
UpdateSelection()279 void lcTimelineWidget::UpdateSelection()
280 {
281 if (mIgnoreUpdates)
282 return;
283
284 QItemSelection ItemSelection;
285
286 for (int TopLevelItemIdx = 0; TopLevelItemIdx < topLevelItemCount(); TopLevelItemIdx++)
287 {
288 QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx);
289
290 for (int PieceItemIdx = 0; PieceItemIdx < StepItem->childCount(); PieceItemIdx++)
291 {
292 QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIdx);
293 lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value<uintptr_t>();
294
295 if (Piece && Piece->IsSelected())
296 {
297 QModelIndex Index = indexFromItem(PieceItem);
298 ItemSelection.select(Index, Index);
299 }
300 }
301 }
302
303 bool Blocked = blockSignals(true);
304
305 selectionModel()->select(ItemSelection, QItemSelectionModel::ClearAndSelect);
306
307 blockSignals(Blocked);
308 }
309
InsertStepBefore()310 void lcTimelineWidget::InsertStepBefore()
311 {
312 QTreeWidgetItem* CurrentItem = currentItem();
313
314 if (!CurrentItem)
315 return;
316
317 if (CurrentItem->parent())
318 CurrentItem = CurrentItem->parent();
319
320 int Step = indexOfTopLevelItem(CurrentItem);
321
322 if (Step == -1)
323 return;
324
325 gMainWindow->GetActiveModel()->InsertStep(Step + 1);
326 }
327
InsertStepAfter()328 void lcTimelineWidget::InsertStepAfter()
329 {
330 QTreeWidgetItem* CurrentItem = currentItem();
331
332 if (!CurrentItem)
333 return;
334
335 if (CurrentItem->parent())
336 CurrentItem = CurrentItem->parent();
337
338 int Step = indexOfTopLevelItem(CurrentItem);
339
340 if (Step == -1)
341 return;
342
343 gMainWindow->GetActiveModel()->InsertStep(Step + 2);
344 }
345
RemoveStep()346 void lcTimelineWidget::RemoveStep()
347 {
348 QTreeWidgetItem* CurrentItem = currentItem();
349
350 if (!CurrentItem)
351 return;
352
353 if (CurrentItem->parent())
354 CurrentItem = CurrentItem->parent();
355
356 int Step = indexOfTopLevelItem(CurrentItem);
357
358 if (Step == -1)
359 return;
360
361 gMainWindow->GetActiveModel()->RemoveStep(Step + 1);
362 }
363
MoveSelection()364 void lcTimelineWidget::MoveSelection()
365 {
366 QTreeWidgetItem* CurrentItem = currentItem();
367
368 if (!CurrentItem)
369 return;
370
371 if (CurrentItem->parent())
372 CurrentItem = CurrentItem->parent();
373
374 int Step = indexOfTopLevelItem(CurrentItem);
375
376 if (Step == -1)
377 return;
378 Step++;
379
380 QList<QTreeWidgetItem*> SelectedItems = selectedItems();
381
382 for (QTreeWidgetItem* PieceItem : SelectedItems)
383 {
384 QTreeWidgetItem* Parent = PieceItem->parent();
385
386 if (!Parent)
387 continue;
388
389 int ChildIndex = Parent->indexOfChild(PieceItem);
390 CurrentItem->addChild(Parent->takeChild(ChildIndex));
391 }
392
393 UpdateModel();
394
395 lcModel* Model = gMainWindow->GetActiveModel();
396
397 if (Step > static_cast<int>(Model->GetCurrentStep()))
398 Model->SetCurrentStep(Step);
399 }
400
SetCurrentStep()401 void lcTimelineWidget::SetCurrentStep()
402 {
403 QTreeWidgetItem* CurrentItem = currentItem();
404
405 if (!CurrentItem)
406 return;
407
408 if (CurrentItem->parent())
409 CurrentItem = CurrentItem->parent();
410
411 int Step = indexOfTopLevelItem(CurrentItem);
412
413 if (Step == -1)
414 return;
415
416 gMainWindow->GetActiveModel()->SetCurrentStep(Step + 1);
417 }
418
CurrentItemChanged(QTreeWidgetItem * Current,QTreeWidgetItem * Previous)419 void lcTimelineWidget::CurrentItemChanged(QTreeWidgetItem* Current, QTreeWidgetItem* Previous)
420 {
421 Q_UNUSED(Previous);
422
423 if (Current && !Current->parent())
424 SetCurrentStep();
425 }
426
ItemSelectionChanged()427 void lcTimelineWidget::ItemSelectionChanged()
428 {
429 lcArray<lcObject*> Selection;
430 lcStep LastStep = 1;
431 QList<QTreeWidgetItem*> SelectedItems = selectedItems();
432
433 for (QTreeWidgetItem* PieceItem : SelectedItems)
434 {
435 lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value<uintptr_t>();
436 if (Piece)
437 {
438 LastStep = lcMax(LastStep, Piece->GetStepShow());
439 Selection.Add(Piece);
440 }
441 }
442
443 lcPiece* CurrentPiece = nullptr;
444 QTreeWidgetItem* CurrentItem = currentItem();
445 if (CurrentItem && CurrentItem->isSelected())
446 CurrentPiece = (lcPiece*)CurrentItem->data(0, Qt::UserRole).value<uintptr_t>();
447
448 bool Blocked = blockSignals(true);
449 mIgnoreUpdates = true;
450 lcModel* Model = gMainWindow->GetActiveModel();
451 if (LastStep > Model->GetCurrentStep())
452 {
453 Model->SetCurrentStep(LastStep);
454 UpdateCurrentStepItem();
455 }
456 Model->SetSelectionAndFocus(Selection, CurrentPiece, LC_PIECE_SECTION_POSITION, false);
457 mIgnoreUpdates = false;
458 blockSignals(Blocked);
459 }
460
dropEvent(QDropEvent * Event)461 void lcTimelineWidget::dropEvent(QDropEvent* Event)
462 {
463 QTreeWidgetItem* DropItem = itemAt(Event->pos());
464 lcModel* Model = gMainWindow->GetActiveModel();
465
466 if (DropItem)
467 {
468 QTreeWidgetItem* ParentItem = DropItem->parent();
469 lcStep Step = indexOfTopLevelItem(ParentItem ? ParentItem : DropItem) + 1;
470
471 if (Step > Model->GetCurrentStep())
472 Model->SetCurrentStep(Step);
473 }
474
475 QList<QTreeWidgetItem*> SelectedItems = selectedItems();
476 clearSelection();
477
478 auto SortItems = [this](QTreeWidgetItem* Item1, QTreeWidgetItem* Item2)
479 {
480 QTreeWidgetItem* StepItem1 = Item1->parent();
481 QTreeWidgetItem* StepItem2 = Item2->parent();
482
483 if (StepItem1 == StepItem2)
484 return StepItem1->indexOfChild(Item1) < StepItem1->indexOfChild(Item2);
485
486 return indexOfTopLevelItem(StepItem1) < indexOfTopLevelItem(StepItem2);
487 };
488
489 std::sort(SelectedItems.begin(), SelectedItems.end(), SortItems);
490
491 for (QTreeWidgetItem* SelectedItem : SelectedItems)
492 SelectedItem->setSelected(true);
493
494 QTreeWidget::dropEvent(Event);
495
496 UpdateModel();
497 Update(false, false);
498 }
499
mousePressEvent(QMouseEvent * Event)500 void lcTimelineWidget::mousePressEvent(QMouseEvent* Event)
501 {
502 if (Event->button() == Qt::RightButton)
503 {
504 QItemSelection Selection = selectionModel()->selection();
505
506 bool Blocked = blockSignals(true);
507 QTreeWidget::mousePressEvent(Event);
508 blockSignals(Blocked);
509
510 selectionModel()->select(Selection, QItemSelectionModel::ClearAndSelect);
511 }
512 else
513 QTreeWidget::mousePressEvent(Event);
514 }
515
mouseDoubleClickEvent(QMouseEvent * MouseEvent)516 void lcTimelineWidget::mouseDoubleClickEvent(QMouseEvent* MouseEvent)
517 {
518 if (MouseEvent->button() == Qt::LeftButton)
519 {
520 QTreeWidgetItem* CurrentItem = currentItem();
521 PreviewSelection(CurrentItem);
522 }
523
524 QTreeWidget::mouseDoubleClickEvent(MouseEvent);
525 }
526
PreviewSelection(QTreeWidgetItem * CurrentItem)527 void lcTimelineWidget::PreviewSelection(QTreeWidgetItem* CurrentItem)
528 {
529 if (!CurrentItem)
530 return;
531
532 lcPiece* Piece = (lcPiece*)CurrentItem->data(0, Qt::UserRole).value<uintptr_t>();
533
534 if (!Piece)
535 return;
536
537 PieceInfo* Info = Piece->mPieceInfo;
538
539 if (!Info)
540 return;
541
542 gMainWindow->PreviewPiece(Info->mFileName, Piece->GetColorCode(), false);
543 }
544
UpdateModel()545 void lcTimelineWidget::UpdateModel()
546 {
547 QList<QPair<lcPiece*, lcStep>> PieceSteps;
548
549 for (int TopLevelItemIdx = 0; TopLevelItemIdx < topLevelItemCount(); TopLevelItemIdx++)
550 {
551 QTreeWidgetItem* StepItem = topLevelItem(TopLevelItemIdx);
552
553 for (int PieceItemIdx = 0; PieceItemIdx < StepItem->childCount(); PieceItemIdx++)
554 {
555 QTreeWidgetItem* PieceItem = StepItem->child(PieceItemIdx);
556 lcPiece* Piece = (lcPiece*)PieceItem->data(0, Qt::UserRole).value<uintptr_t>();
557
558 PieceSteps.append(QPair<lcPiece*, lcStep>(Piece, TopLevelItemIdx + 1));
559 }
560 }
561
562 mIgnoreUpdates = true;
563 gMainWindow->GetActiveModel()->SetPieceSteps(PieceSteps);
564 mIgnoreUpdates = false;
565 }
566