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