/* * All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or * its licensors. * * For complete copyright and license terms please see the LICENSE at the root of this * distribution (the "License"). All use of this software is governed by the License, * or, if provided, by the license below or the license accompanying this file. Do not * remove or modify any license notices. This file is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * */ #include "stdafx.h" //QT #include <QSettings> #include <QLabel> #include <QSpinBox> #include <QPushButton> #include <QGridLayout> #include <QSizePolicy> #include <QCheckBox> #include <QScrollArea> //Editor #include <IEditor.h> #include <IEditorParticleUtils.h> #include <Util/Variable.h> #include <Particles/ParticleUIDefinition.h> #include <Particles/ParticleItem.h> #include <BaseLibraryItem.h> //EditorUI_QT #include <../EditorUI_QT/DockWidgetTitleBar.h> #include "../EditorUI_QT/ContextMenu.h" #include <../EditorUI_QT/LibraryTreeViewItem.h> #include <../EditorUI_QT/DockableLibraryPanel.h> #include <../EditorUI_QT/LibraryTreeView.h> #include <../EditorUI_QT/LibraryTreeViewItem.h> #include <../EditorUI_QT/DefaultViewWidget.h> //Local #include "DockableLODPanel.h" #include "LODLevelWidget.h" #include "ParticleEditorPlugin.h" #include <Include/IEditorParticleManager.h> LodWidget::LodWidget(QWidget* parent) : QWidget(parent) , m_BlendInLabel(nullptr) , m_BlendOutLabel(nullptr) , m_OverlapLabel(nullptr) , m_BlendInBox(nullptr) , m_BlendOutBox(nullptr) , m_OverlapBox(nullptr) , m_AddLevelOfDetailButton(nullptr) , m_TopWidget(nullptr) , m_TopLayout(nullptr) , m_LodLevelLayout(nullptr) , m_LodLevelPanel(nullptr) , m_LodLevelScroll(nullptr) , m_Item(nullptr) , m_SelectedLodLevel(-1) { } LodWidget::~LodWidget() { SAFE_DELETE(m_BlendInLabel); SAFE_DELETE(m_BlendOutLabel); SAFE_DELETE(m_OverlapLabel); SAFE_DELETE(m_BlendInBox); SAFE_DELETE(m_BlendOutBox); SAFE_DELETE(m_OverlapBox); SAFE_DELETE(m_AddLevelOfDetailButton); if (m_Item != nullptr) { m_Item->Release(); } } void LodWidget::Init() { m_Layout = new QVBoxLayout(this); m_Layout->setContentsMargins(0, 0, 0, 0); setObjectName("LODPanel"); } void LodWidget::AddLodLevel() { emit SignalAddLod(m_Item); } void LodWidget::AddLodLevelSlot() { AddLodLevel(); } void LodWidget::ClearLODSelection() { for (int i = 0; i < m_LodLevels.size(); i++) { m_LodLevels[i]->ClearSelectionColor(); } } void LodWidget::ClearGUI() { if (m_TopWidget == nullptr) { return; } //Remove top widget m_TopLayout->removeWidget(m_BlendInLabel); m_TopLayout->removeWidget(m_BlendOutLabel); m_TopLayout->removeWidget(m_OverlapLabel); m_TopLayout->removeWidget(m_BlendInBox); m_TopLayout->removeWidget(m_BlendOutBox); m_TopLayout->removeWidget(m_OverlapBox); m_TopLayout->removeWidget(m_AddLevelOfDetailButton); SAFE_DELETE(m_BlendInLabel); SAFE_DELETE(m_BlendOutLabel); SAFE_DELETE(m_OverlapLabel); SAFE_DELETE(m_BlendInBox); SAFE_DELETE(m_BlendOutBox); SAFE_DELETE(m_OverlapBox); SAFE_DELETE(m_AddLevelOfDetailButton); SAFE_DELETE(m_TopLayout); m_Layout->removeWidget(m_TopWidget); SAFE_DELETE(m_TopWidget); //Remove lod scroll area and lod levels if (m_LodLevelScroll == nullptr) { return; } while (m_LodLevels.count() > 0) { delete m_LodLevels.takeLast(); } m_LodLevelLayout->removeWidget(m_LodLevelPanel); SAFE_DELETE(m_LodLevelLayout); SAFE_DELETE(m_LodLevelPanel); m_Layout->removeWidget(m_LodLevelScroll); SAFE_DELETE(m_LodLevelScroll) } void LodWidget::RefreshCurrentGUI() { RefreshGUI(m_Item, m_SelectedLodLevel); } void LodWidget::RefreshGUI(CParticleItem* item, int selectedLevel) { EditorUIPlugin::ScopedSuspendUndoPtr suspendUndo; EBUS_EVENT_RESULT(suspendUndo, EditorLibraryUndoRequestsBus, AddScopedSuspendUndo); if (m_Item != nullptr) { m_Item->Release(); } CParticleItem* top = item; while (top && top->GetParent() != nullptr) { top = top->GetParent(); } ClearGUI(); m_Item = item; if (m_Item == nullptr) { return; } m_Item->AddRef(); //Top Widget m_TopWidget = new QWidget(this); m_Layout->addWidget(m_TopWidget); m_TopLayout = new QGridLayout(m_TopWidget); m_BlendInLabel = new QLabel("Blend In", m_TopWidget); m_BlendOutLabel = new QLabel("Blend Out", m_TopWidget); m_OverlapLabel = new QLabel("Overlap", m_TopWidget); m_BlendInBox = new QDoubleSpinBox(m_TopWidget); m_BlendInBox->setMinimum(0.0); m_BlendInBox->setValue(top->GetEffect()->GetParticleParams().fBlendIn); m_BlendOutBox = new QDoubleSpinBox(m_TopWidget); m_BlendOutBox->setMinimum(0.0); m_BlendOutBox->setValue(top->GetEffect()->GetParticleParams().fBlendOut); m_OverlapBox = new QDoubleSpinBox(m_TopWidget); m_OverlapBox->setMinimum(0.0); m_OverlapBox->setValue(top->GetEffect()->GetParticleParams().fOverlap); connect(m_BlendInBox, SIGNAL(valueChanged(double)), this, SLOT(BlendInValueChanged(double))); connect(m_BlendOutBox, SIGNAL(valueChanged(double)), this, SLOT(BlendOutValueChanged(double))); connect(m_OverlapBox, SIGNAL(valueChanged(double)), this, SLOT(OverlapValueChanged(double))); m_AddLevelOfDetailButton = new QPushButton("+ Add Level of Detail", m_TopWidget); connect(m_AddLevelOfDetailButton, SIGNAL(released()), this, SLOT(AddLodLevelSlot())); m_TopLayout->addWidget(m_BlendInLabel, 0, 0); m_TopLayout->addWidget(m_BlendInBox, 0, 1); m_TopLayout->addWidget(m_BlendOutLabel, 1, 0); m_TopLayout->addWidget(m_BlendOutBox, 1, 1); m_TopLayout->addWidget(m_OverlapLabel, 2, 0); m_TopLayout->addWidget(m_OverlapBox, 2, 1); m_TopLayout->addWidget(m_AddLevelOfDetailButton, 3, 0, 1, 2); m_TopWidget->setLayout(m_TopLayout); m_TopWidget->setSizePolicy(QSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum)); //LoD Levels m_LodLevelScroll = new QScrollArea(this); m_LodLevelScroll->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_LodLevelScroll->setWidgetResizable(true); m_LodLevelScroll->setFrameStyle(QFrame::NoFrame); m_LodLevelScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_LodLevelScroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); m_LodLevelPanel = new QWidget(m_LodLevelScroll); m_LodLevelPanel->setObjectName("LODLevelPanel"); m_LodLevelLayout = new QVBoxLayout(m_LodLevelPanel); int dummy = 0; int right = 0; m_LodLevelLayout->getContentsMargins(&dummy, &dummy, &right, &dummy); m_LodLevelLayout->setContentsMargins(0, 0, right, 0); m_LodLevelScroll->setWidget(m_LodLevelPanel); m_LodLevelScroll->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); m_LodLevelPanel->setLayout(m_LodLevelLayout); m_LodLevelPanel->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum)); m_Layout->addWidget(m_LodLevelScroll); for (int i = 0; i < m_Item->GetEffect()->GetLevelOfDetailCount(); i++) { AddLODLevelWidget(m_Item->GetEffect()->GetLevelOfDetail(i)); } SelectLevel(selectedLevel, ""); this->setLayout(m_Layout); this->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding)); } void LodWidget::AddLODLevelWidget(SLodInfo* lod) { LODLevelWidget* newLevel = new LODLevelWidget(m_LodLevelPanel); newLevel->Init(lod); m_LodLevelLayout->addWidget(newLevel); m_LodLevels.push_back(newLevel); connect(newLevel, SIGNAL(RemoveLod(LODLevelWidget*,SLodInfo*)), this, SLOT(RemoveLodLevel(LODLevelWidget*,SLodInfo*))); connect(newLevel, &LODLevelWidget::SignalLodParticleItemSelected, this, &LodWidget::onLodParticleItemSelected); connect(newLevel, &LODLevelWidget::SignalRefreshGUI, this, &LodWidget::RefreshCurrentGUI); connect(newLevel, &LODLevelWidget::SignalDistanceChanged, this, &LodWidget::OnLevelDistanceChanged); connect(newLevel, &LODLevelWidget::SignalUpdateLODIcon, this, &LodWidget::UpdateLODIcon); } void LodWidget::RemoveLODLevelWidget(SLodInfo* lod) { for (int i = 0; i < m_LodLevels.size(); i++) { if (m_LodLevels[i]->GetLod() == lod) { m_LodLevelLayout->removeWidget(m_LodLevels[i]); delete m_LodLevels[i]; m_LodLevels.remove(i); return; } } } void LodWidget::UpdateLODIcon(CLibraryTreeViewItem* item) { emit SignalUpdateLODIcon(); } void LodWidget::updateTreeItemHighlight(bool ishighlight, SLodInfo* lod, QString fullname) { for (LODLevelWidget* treewidget : m_LodLevels) { treewidget->updateTreeItemStyle(ishighlight, lod, fullname); } } void LodWidget::RemoveLodLevel(LODLevelWidget* widget, SLodInfo* lod) { m_Item->GetEffect()->RemoveLevelOfDetail(lod); QString fullname = m_Item->GetFullName(); if (!m_Item->GetEffect()->HasLevelOfDetail()) { emit SignalLodIconRemoved(fullname); } RefreshLodPanels(); emit SignalLodUndoPoint(); } void LodWidget::BlendInValueChanged(double value) { CParticleItem* top = m_Item; while (top->GetParent() != nullptr) { top = m_Item->GetParent(); } ParticleParams params = top->GetEffect()->GetParticleParams(); params.fBlendIn = value; top->GetEffect()->SetParticleParams(params); emit SignalLodUndoPoint(); } void LodWidget::BlendOutValueChanged(double value) { CParticleItem* top = m_Item; while (top->GetParent() != nullptr) { top = m_Item->GetParent(); } ParticleParams params = top->GetEffect()->GetParticleParams(); params.fBlendOut = value; top->GetEffect()->SetParticleParams(params); emit SignalLodUndoPoint(); } void LodWidget::OverlapValueChanged(double value) { CParticleItem* top = m_Item; while (top->GetParent() != nullptr) { top = m_Item->GetParent(); } ParticleParams params = top->GetEffect()->GetParticleParams(); params.fOverlap = value; top->GetEffect()->SetParticleParams(params); emit SignalLodUndoPoint(); } void LodWidget::SelectLevel(int index, const QString& itemName) { if (m_LodLevels.size() == 0) { return; } if (index >= m_LodLevels.size()) { index = m_LodLevels.size() - 1; } //if a level is selected if (index >= 0) { m_LodLevels[index]->SetSelected(itemName); } m_SelectedLodLevel = index; } void LodWidget::RemoveSelectedLevel() { if (m_SelectedLodLevel < 0 || m_SelectedLodLevel >= m_LodLevels.size()) { return; } m_Item->GetEffect()->RemoveLevelOfDetail(m_LodLevels[m_SelectedLodLevel]->GetLod()); RefreshLodPanels(); emit SignalUpdateLODIcon(); emit SignalLodUndoPoint(); } void LodWidget::RemoveAllLevels() { if (m_Item == nullptr) { return; } m_Item->GetEffect()->RemoveAllLevelOfDetails(); RefreshGUI(m_Item, m_SelectedLodLevel); emit SignalUpdateLODIcon(); emit SignalLodUndoPoint(); } void LodWidget::MoveSelectedLevelUp() { if (m_SelectedLodLevel < 0 || m_SelectedLodLevel >= m_LodLevels.size()) { return; } auto selectedLod = m_LodLevels[m_SelectedLodLevel]->GetLod(); SLodInfo* aboveLod = nullptr; for (int i = 0; i < m_Item->GetEffect()->GetLevelOfDetailCount(); i++) { if (m_Item->GetEffect()->GetLevelOfDetail(i)->GetDistance() < selectedLod->GetDistance()) { aboveLod = m_Item->GetEffect()->GetLevelOfDetail(i); } } if (aboveLod == nullptr) { return; } selectedLod->SetDistance(aboveLod->GetDistance() - 1); //Move it up one level m_LodLevels[m_SelectedLodLevel]->RefreshDistance(); } void LodWidget::RefreshLodPanels() { EditorUIPlugin::ScopedSuspendUndoPtr suspendUndo; EBUS_EVENT_RESULT(suspendUndo, EditorLibraryUndoRequestsBus, AddScopedSuspendUndo); IParticleEffect* effect = m_Item->GetEffect(); for (int i = 0; i < m_LodLevels.size(); i++) { bool found = false; for (int l = 0; l < effect->GetLevelOfDetailCount(); l++) { if (effect->GetLevelOfDetail(l) == m_LodLevels[i]->GetLod()) { found = true; break; } } if (!found) { RemoveLODLevelWidget(m_LodLevels[i]->GetLod()); } } for (int i = 0; i < effect->GetLevelOfDetailCount(); i++) { bool found = false; for (int l = 0; l < m_LodLevels.size(); l++) { if (effect->GetLevelOfDetail(i) == m_LodLevels[l]->GetLod()) { found = true; break; } } if (!found) { AddLODLevelWidget(effect->GetLevelOfDetail(i)); } } OnLevelDistanceChanged(); } void LodWidget::MoveSelectedLevelDown() { if (m_SelectedLodLevel < 0 || m_SelectedLodLevel >= m_LodLevels.size()) { return; } auto selectedLod = m_LodLevels[m_SelectedLodLevel]->GetLod(); SLodInfo* belowLod = nullptr; for (int i = 0; i < m_Item->GetEffect()->GetLevelOfDetailCount(); i++) { if (m_Item->GetEffect()->GetLevelOfDetail(i)->GetDistance() > selectedLod->GetDistance()) { belowLod = m_Item->GetEffect()->GetLevelOfDetail(i); break; } } if (belowLod == nullptr) { return; } selectedLod->SetDistance(belowLod->GetDistance() + 1); //Move it up one level m_LodLevels[m_SelectedLodLevel]->RefreshDistance(); } void LodWidget::MoveSelectedToTop() { if (m_SelectedLodLevel < 0 || m_SelectedLodLevel >= m_LodLevels.size()) { return; } auto selectedLod = m_LodLevels[m_SelectedLodLevel]->GetLod(); auto currentTopLod = m_Item->GetEffect()->GetLevelOfDetail(0); if (selectedLod->GetDistance() == currentTopLod->GetDistance()) { return; } selectedLod->SetDistance(currentTopLod->GetDistance() - 1); m_LodLevels[m_SelectedLodLevel]->RefreshDistance(); } void LodWidget::MoveSelectedToBottom() { if (m_SelectedLodLevel < 0 || m_SelectedLodLevel >= m_LodLevels.size()) { return; } auto selectedLod = m_LodLevels[m_SelectedLodLevel]->GetLod(); auto currentBottomLod = m_Item->GetEffect()->GetLevelOfDetail(m_LodLevels.size() - 1); if (selectedLod->GetDistance() == currentBottomLod->GetDistance()) { return; } selectedLod->SetDistance(currentBottomLod->GetDistance() + 1); m_LodLevels[m_SelectedLodLevel]->RefreshDistance(); } void LodWidget::SelectFirstLevel() { if (m_LodLevels.size() == 0) { return; } m_LodLevels[0]->SelectTopItem(); } void LodWidget::SelectLastLevel() { if (m_LodLevels.size() == 0) { return; } int sel = max(0, m_Item->GetEffect()->GetLevelOfDetailCount() - 1); m_LodLevels[sel]->SelectTopItem(); } void LodWidget::onLodParticleItemSelected(LODLevelWidget* lodLevel, IParticleEffect* baseParticle, SLodInfo* lod) { for (unsigned int i = 0, _e = m_LodLevels.count(); i < _e; i++) { if (m_LodLevels[i] != lodLevel) { m_LodLevels[i]->ClearSelectionColor(); } else { m_SelectedLodLevel = i; } } emit SignalLodItemSelected(baseParticle, lod); } void LodWidget::OnLevelDistanceChanged() { //Sort level widgets int outer, inner; for (outer = m_LodLevelLayout->count() - 1; outer > 0; outer--) { for (inner = 0; inner < outer; inner++) { LODLevelWidget* first = static_cast<LODLevelWidget*>(m_LodLevelLayout->itemAt(inner)->widget()); LODLevelWidget* second = static_cast<LODLevelWidget*>(m_LodLevelLayout->itemAt(inner + 1)->widget()); if (first->GetLod()->GetDistance() > second->GetLod()->GetDistance()) { m_LodLevelLayout->removeWidget(first); m_LodLevelLayout->insertWidget(inner + 1, first); } } } emit SignalLodUndoPoint(); } DockableLODPanel::DockableLODPanel(QWidget* parent) : FloatableDockPanel("", parent, Qt::WindowFlags(), false) , m_titleBar(nullptr) , m_titleBarMenu(nullptr) , m_IgnoreAttributeRefresh(false) , m_LodWidget(nullptr) , m_selectedParticle(nullptr) , m_defaultView(nullptr) , m_centralWidget(nullptr) , m_currentSelectedItem(nullptr) { } DockableLODPanel::~DockableLODPanel() { SAFE_DELETE(m_titleBar); SAFE_DELETE(m_titleBarMenu); SAFE_DELETE(m_LodWidget); ClearParticle(); } void DockableLODPanel::Init(const QString& panelName) { //Setup titlebar m_titleBar = new DockWidgetTitleBar(this); m_centralWidget = new QWidget(this); m_LodWidget = new LodWidget(m_centralWidget); m_layout = new QVBoxLayout(m_centralWidget); m_defaultView = new DefaultViewWidget(m_centralWidget); m_titleBarMenu = new QMenu; DecorateDefaultView(); m_titleBar->SetupLabel(panelName); m_titleBar->SetShowMenuContextMenuCallback([&] {return GetTitleBarMenu(); }); setTitleBarWidget(m_titleBar); setWidget(m_centralWidget); m_centralWidget->setLayout(m_layout); BuildGUI(); //Build menu setWindowTitle("Level of detail"); ShowDefaultView(); } void DockableLODPanel::OnAttributeViewItemDeleted(const QString& name) { if (m_currentSelectedItem) { QString fullname = m_currentSelectedItem->GetLibrary()->GetName() + name; emit SignalAttributeViewItemDeleted(fullname); } } void DockableLODPanel::CollectItemRecursive(CBaseLibraryItem* rootItem, AZStd::list<AZStd::string>& itemIds) { itemIds.push_back(rootItem->GetFullName().toUtf8().data()); for (int i = 0; i < rootItem->GetChildCount(); i++) { CollectItemRecursive(rootItem->GetChild(i), itemIds); } } void DockableLODPanel::OnLodUndoPoint() { AddLodUndoPoint(m_selectedParticle); } void DockableLODPanel::AddLodUndoPoint(CParticleItem* item) { bool isSuspend = false; EBUS_EVENT_RESULT(isSuspend, EditorLibraryUndoRequestsBus, IsSuspend); if (isSuspend) { return; } CParticleItem* parent = item; if (!parent) { return; } while (parent->GetParent()) { parent = parent->GetParent(); } AZStd::list<AZStd::string> itemIds; CollectItemRecursive(parent, itemIds); EBUS_EVENT(EditorLibraryUndoRequestsBus, AddItemGroupUndo, itemIds); } void DockableLODPanel::LoadSessionState() { QSettings settings("Amazon", "Lumberyard"); if (settings.value(PARTICLE_EDITOR_LAYOUT_SETTINGS_LOD).isNull() == false) { restoreGeometry(settings.value(PARTICLE_EDITOR_LAYOUT_SETTINGS_LOD).toByteArray()); } } void DockableLODPanel::SaveSessionState() { QSettings settings("Amazon", "Lumberyard"); settings.setValue(PARTICLE_EDITOR_LAYOUT_SETTINGS_LOD, saveGeometry()); settings.sync(); } void DockableLODPanel::UpdateColors(const QMap<QString, QColor>& colorMap) { m_enabledTextColor = Qt::red; m_disabledTextColor = Qt::red; if (colorMap.contains("CDockWidgetTitleBarColor")) { m_enabledTextColor = colorMap["CDockWidgetTitleBarColor"]; } if (colorMap.contains("CTextEditDisabledText")) { m_disabledTextColor = colorMap["CTextEditDisabledText"]; } } QMenu* DockableLODPanel::GetTitleBarMenu() { CRY_ASSERT(m_titleBarMenu); m_titleBarMenu->clear(); emit SignalPopulateTitleBarMenu(m_titleBarMenu); return m_titleBarMenu; } void DockableLODPanel::OnAddLod(CLibraryTreeViewItem* item) { //Add Level of detail for particle CRY_ASSERT(item); CParticleItem* pParticle = static_cast<CParticleItem*>(item->GetItem()); CRY_ASSERT(pParticle); CRY_ASSERT(pParticle->GetEffect()); OnAddLod(pParticle); EmitIconChangeRecursive(item); } void DockableLODPanel::EmitIconChangeRecursive(CLibraryTreeViewItem* item) { emit SignalChangeLODIcon(item->GetLibraryName(), item->GetFullPath()); for (int i = 0; i < item->childCount(); i++) { EmitIconChangeRecursive(static_cast<CLibraryTreeViewItem*>(item->child(i))); } } void DockableLODPanel::EmitIconChangeRecursive(CParticleItem* item) { emit SignalChangeLODIcon(item->GetLibrary()->GetName(), item->GetFullName()); for (int i = 0; i < item->GetChildCount(); i++) { EmitIconChangeRecursive(static_cast<CParticleItem*>(item->GetChild(i))); } } void DockableLODPanel::UpdateLODIcon() { if (m_selectedParticle) { CParticleItem* top = m_selectedParticle; if (m_selectedParticle->GetParent()) { while (top && top->GetParent()) { top = top->GetParent(); } } EmitIconChangeRecursive(top); } } void DockableLODPanel::EmitIconChangeRecursive(QString library, IParticleEffect* item) { QString fullname = item->GetName(); IParticleEffect* parent = item->GetParent(); while (parent != nullptr) { fullname = parent->GetName() + ('.' + fullname); parent = parent->GetParent(); } emit SignalChangeLODIcon(library, fullname); for (int i = 0; i < item->GetChildCount(); i++) { EmitIconChangeRecursive(library, item->GetChild(i)); } } void DockableLODPanel::OnAddLod(CParticleItem* item) { IParticleEffect* effect = item->GetEffect(); if (effect) { effect->AddLevelOfDetail(); item->GetLibrary()->SetModified(); } //Add level of detail on UI if (item != m_selectedParticle) { RefreshGUI(item); } else { m_LodWidget->RefreshLodPanels(); } show(); IParticleEffect* top = item->GetEffect(); while (top->GetParent() != nullptr) { top = top->GetParent(); } EmitIconChangeRecursive(QString(item->GetLibrary()->GetName()), top); AddLodUndoPoint(item); } void DockableLODPanel::ItemSelectionChanged(CBaseLibraryItem* item) { m_currentSelectedItem = item; if (item && item->IsParticleItem) { RefreshGUI(static_cast<CParticleItem*>(item)); } else { m_LodWidget->RefreshGUI(nullptr); m_selectedParticle = nullptr; } } void DockableLODPanel::LibraryItemReselected(CBaseLibraryItem* item) { m_LodWidget->ClearLODSelection(); } void DockableLODPanel::SelectLod(const SLodInfo* lod) { CParticleItem* parItem = static_cast<CParticleItem*>(m_currentSelectedItem); if (parItem) { int idx = parItem->GetEffect()->GetLevelOfDetailIndex(lod); if (idx >= 0) { m_LodWidget->SelectLevel(idx, parItem->GetFullName().toUtf8().data()); } } } void DockableLODPanel::PerformTitleMenuAction(TitleMenuActions action) { switch (action) { case TitleMenuActions::AddLevel: if (m_selectedParticle != nullptr) { OnAddLod(m_selectedParticle); } break; case TitleMenuActions::MoveUp: m_LodWidget->MoveSelectedLevelUp(); break; case TitleMenuActions::MoveDown: m_LodWidget->MoveSelectedLevelDown(); break; case TitleMenuActions::MoveToTop: m_LodWidget->MoveSelectedToTop(); break; case TitleMenuActions::MoveToBottom: m_LodWidget->MoveSelectedToBottom(); break; case TitleMenuActions::JumpToFirst: m_LodWidget->SelectFirstLevel(); break; case TitleMenuActions::JumpToLast: m_LodWidget->SelectLastLevel(); break; case TitleMenuActions::Remove: m_LodWidget->RemoveSelectedLevel(); break; case TitleMenuActions::RemoveAll: m_LodWidget->RemoveAllLevels(); break; } } void DockableLODPanel::SetParticle(CParticleItem* item) { ClearParticle(); m_selectedParticle = item; m_selectedParticle->AddRef(); } void DockableLODPanel::ClearParticle() { if (m_selectedParticle != nullptr) { m_selectedParticle->Release(); m_selectedParticle = nullptr; } } void DockableLODPanel::BuildGUI() { m_LodWidget->Init(); connect(m_LodWidget, SIGNAL(SignalLodItemSelected(IParticleEffect*,SLodInfo*)), this, SLOT(onLodItemSelectionChanged(IParticleEffect*,SLodInfo*))); m_LodWidget->show(); connect(m_LodWidget, SIGNAL(SignalAddLod(CParticleItem*)), this, SLOT(OnAddLod(CParticleItem*))); connect(m_LodWidget, &LodWidget::SignalLodIconRemoved, this, &DockableLODPanel::RemoveLodIcon); connect(m_LodWidget, &LodWidget::SignalUpdateLODIcon, this, &DockableLODPanel::UpdateLODIcon); connect(m_LodWidget, &LodWidget::SignalAttributeViewItemDeleted, this, &DockableLODPanel::OnAttributeViewItemDeleted); connect(m_LodWidget, &LodWidget::SignalLodUndoPoint, this, &DockableLODPanel::OnLodUndoPoint); m_layout->addWidget(m_defaultView, 0, Qt::AlignHCenter | Qt::AlignTop); m_layout->addWidget(m_LodWidget); m_layout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); } void DockableLODPanel::RefreshGUI(CParticleItem* item) { EditorUIPlugin::ScopedSuspendUndoPtr suspendUndo; EBUS_EVENT_RESULT(suspendUndo, EditorLibraryUndoRequestsBus, AddScopedSuspendUndo); HideDefaultView(); SetParticle(item); m_LodWidget->RefreshGUI(item); } void DockableLODPanel::RefreshGUI() { if (!m_selectedParticle) { ShowDefaultView(); return; } RefreshGUI(m_selectedParticle); } void DockableLODPanel::onLodItemSelectionChanged(IParticleEffect* baseParticleEffect, SLodInfo* lod) { IEditorParticleManager* pParticleMgr = GetIEditor()->GetParticleManager(); //Due to inconsistency with the IParticleEffect interface we can not use IParticleEffect::GetFullName(). //GetFullName returns a crystring, the documentation says this is not allowed in abstract interfaces. //When the crystring is destroyed when it goes out of scope the program will cause an error as the program //tries to free data it is not allowed to. string fullname = baseParticleEffect->GetName(); IParticleEffect* parent = baseParticleEffect->GetParent(); while (parent != nullptr) { fullname = parent->GetName() + ('.' + fullname); parent = parent->GetParent(); } IDataBaseItem* baseItem = pParticleMgr->FindItemByName(fullname.c_str()); if (baseItem != nullptr) { CBaseLibraryItem* item = static_cast<CBaseLibraryItem*>(baseItem); if (item != nullptr) { emit SignalLodItemSelectionChanged(item, lod); } } } void DockableLODPanel::updateTreeItemHighLight(bool ishighlight, SLodInfo* lod, QString fullname) { m_LodWidget->updateTreeItemHighlight(ishighlight, lod, fullname); } void DockableLODPanel::RemoveLodIcon(QString fullname) { QStringList namelist = fullname.split("."); QString libname = namelist.takeAt(0); QString itemname = namelist.join("."); emit SignalChangeLODIcon(libname, fullname); } void DockableLODPanel::DecorateDefaultView() { CRY_ASSERT(m_defaultView); m_defaultView->SetLabel(tr("Add an LOD to an item to continue")); } void DockableLODPanel::ShowDefaultView() { CRY_ASSERT(m_defaultView); CRY_ASSERT(m_LodWidget); m_defaultView->show(); m_LodWidget->hide(); } void DockableLODPanel::HideDefaultView() { CRY_ASSERT(m_defaultView); CRY_ASSERT(m_LodWidget); m_defaultView->hide(); m_LodWidget->show(); } #include <QT/DockableLODPanel.moc>