diff --git a/lib/macro/macro-action-edit.cpp b/lib/macro/macro-action-edit.cpp index 53cbd4c2..949f9c10 100644 --- a/lib/macro/macro-action-edit.cpp +++ b/lib/macro/macro-action-edit.cpp @@ -61,12 +61,40 @@ MacroActionEdit::MacroActionEdit(QWidget *parent, setLayout(mainLayout); _entryData = entryData; - UpdateEntryData(id); + SetupWidgets(true); _actionStateTimer.start(300); _loading = false; } +void MacroActionEdit::SetupWidgets(bool basicSetup) +{ + if (_allWidgetsAreSetup) { + return; + } + + const auto id = (*_entryData)->GetId(); + _actionSelection->setCurrentText( + obs_module_text(MacroActionFactory::GetActionName(id).c_str())); + const bool enabled = (*_entryData)->Enabled(); + _enable->setChecked(enabled); + SetDisableEffect(!enabled); + HeaderInfoChanged( + QString::fromStdString((*_entryData)->GetShortDesc())); + + if (basicSetup) { + return; + } + + auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData); + QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), + this, SLOT(HeaderInfoChanged(const QString &))); + _section->SetContent(widget, (*_entryData)->GetCollapsed()); + SetFocusPolicyOfWidgets(); + + _allWidgetsAreSetup = true; +} + void MacroActionEdit::ActionSelectionChanged(const QString &text) { if (_loading || !_entryData) { @@ -96,22 +124,6 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text) SetFocusPolicyOfWidgets(); } -void MacroActionEdit::UpdateEntryData(const std::string &id) -{ - _actionSelection->setCurrentText( - obs_module_text(MacroActionFactory::GetActionName(id).c_str())); - const bool enabled = (*_entryData)->Enabled(); - _enable->setChecked(enabled); - SetDisableEffect(!enabled); - auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData); - QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), - this, SLOT(HeaderInfoChanged(const QString &))); - HeaderInfoChanged( - QString::fromStdString((*_entryData)->GetShortDesc())); - _section->SetContent(widget, (*_entryData)->GetCollapsed()); - SetFocusPolicyOfWidgets(); -} - void MacroActionEdit::SetEntryData(std::shared_ptr *data) { _entryData = data; diff --git a/lib/macro/macro-action-edit.hpp b/lib/macro/macro-action-edit.hpp index cd775b39..93eeb731 100644 --- a/lib/macro/macro-action-edit.hpp +++ b/lib/macro/macro-action-edit.hpp @@ -17,7 +17,7 @@ public: QWidget *parent = nullptr, std::shared_ptr * = nullptr, const std::string &id = MacroAction::GetDefaultID().data()); - void UpdateEntryData(const std::string &id); + void SetupWidgets(bool basicSetup = false); void SetEntryData(std::shared_ptr *); private slots: diff --git a/lib/macro/macro-condition-edit.cpp b/lib/macro/macro-condition-edit.cpp index 903181f8..756aaa4a 100644 --- a/lib/macro/macro-condition-edit.cpp +++ b/lib/macro/macro-condition-edit.cpp @@ -138,7 +138,7 @@ MacroConditionEdit::MacroConditionEdit( mainLayout->addWidget(_frame); setLayout(mainLayout); - UpdateEntryData(id); + SetupWidgets(true); _loading = false; } @@ -178,23 +178,36 @@ void MacroConditionEdit::SetRootNode(bool root) SetLogicSelection(); } -void MacroConditionEdit::UpdateEntryData(const std::string &id) +void MacroConditionEdit::SetupWidgets(bool basicSetup) { + if (_allWidgetsAreSetup) { + return; + } + + const auto id = (*_entryData)->GetId(); _conditionSelection->setCurrentText(obs_module_text( MacroConditionFactory::GetConditionName(id).c_str())); - auto widget = - MacroConditionFactory::CreateWidget(id, this, *_entryData); - QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), - this, SLOT(HeaderInfoChanged(const QString &))); + HeaderInfoChanged( QString::fromStdString((*_entryData)->GetShortDesc())); SetLogicSelection(); - _section->SetContent(widget, (*_entryData)->GetCollapsed()); _dur->setVisible(MacroConditionFactory::UsesDurationModifier(id)); auto modifier = (*_entryData)->GetDurationModifier(); _dur->SetValue(modifier); + + if (basicSetup) { + return; + } + + auto widget = + MacroConditionFactory::CreateWidget(id, this, *_entryData); + QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), + this, SLOT(HeaderInfoChanged(const QString &))); + _section->SetContent(widget, (*_entryData)->GetCollapsed()); SetFocusPolicyOfWidgets(); + + _allWidgetsAreSetup = true; } void MacroConditionEdit::SetEntryData(std::shared_ptr *data) diff --git a/lib/macro/macro-condition-edit.hpp b/lib/macro/macro-condition-edit.hpp index a3591af0..ec588159 100644 --- a/lib/macro/macro-condition-edit.hpp +++ b/lib/macro/macro-condition-edit.hpp @@ -41,7 +41,7 @@ public: bool root = true); bool IsRootNode() const; void SetRootNode(bool); - void UpdateEntryData(const std::string &id); + void SetupWidgets(bool basicSetup = false); void SetEntryData(std::shared_ptr *); private slots: diff --git a/lib/macro/macro-segment-list.cpp b/lib/macro/macro-segment-list.cpp index ee46ee45..cdbbc371 100644 --- a/lib/macro/macro-segment-list.cpp +++ b/lib/macro/macro-segment-list.cpp @@ -35,6 +35,9 @@ MacroSegmentList::MacroSegmentList(QWidget *parent) setWidget(wrapper); setWidgetResizable(true); setAcceptDrops(true); + + connect(verticalScrollBar(), &QScrollBar::valueChanged, this, + [this]() { SetupVisibleMacroSegmentWidgets(); }); } MacroSegmentList::~MacroSegmentList() @@ -98,16 +101,18 @@ void MacroSegmentList::SetHelpMsgVisible(bool visible) const _helpMsg->setVisible(visible); } -void MacroSegmentList::Insert(int idx, MacroSegmentEdit *widget) +void MacroSegmentList::Insert(int idx, QWidget *widget) { widget->installEventFilter(this); _contentLayout->insertWidget(idx, widget); + SetupVisibleMacroSegmentWidgets(); } void MacroSegmentList::Add(QWidget *widget) { widget->installEventFilter(this); _contentLayout->addWidget(widget); + SetupVisibleMacroSegmentWidgets(); } void MacroSegmentList::Remove(int idx) const @@ -322,6 +327,36 @@ QRect MacroSegmentList::GetContentItemRectWithPadding(int idx) const return rect; } +void MacroSegmentList::SetVisibilityCheckEnable(bool enable) +{ + _checkVisibility = enable; + + if (_checkVisibility) { + QTimer::singleShot(0, this, [this]() { + SetupVisibleMacroSegmentWidgets(); + }); + } +} + +void MacroSegmentList::SetupVisibleMacroSegmentWidgets() +{ + if (!_checkVisibility) { + return; + } + + const auto viewportRect = viewport()->rect(); + + for (auto segment : widget()->findChildren()) { + const auto pos = segment->mapTo(viewport(), QPoint(0, 0)); + const QRect rect(pos, segment->size()); + if (!viewportRect.intersects(rect)) { + continue; + } + + segment->SetupWidgets(); + } +} + int MacroSegmentList::GetSegmentIndexFromPos(const QPoint &pos) const { int idx = -1; @@ -455,4 +490,10 @@ void MacroSegmentList::dropEvent(QDropEvent *event) _dragPosition = -1; } +void MacroSegmentList::resizeEvent(QResizeEvent *event) +{ + QWidget::resizeEvent(event); + SetupVisibleMacroSegmentWidgets(); +} + } // namespace advss diff --git a/lib/macro/macro-segment-list.hpp b/lib/macro/macro-segment-list.hpp index 000fc84a..3c7c8e91 100644 --- a/lib/macro/macro-segment-list.hpp +++ b/lib/macro/macro-segment-list.hpp @@ -20,7 +20,7 @@ public: MacroSegmentEdit *WidgetAt(int idx) const; MacroSegmentEdit *WidgetAt(const QPoint &) const; int IndexAt(const QPoint &) const; - void Insert(int idx, MacroSegmentEdit *widget); + void Insert(int idx, QWidget *widget); void Add(QWidget *widget); void Remove(int idx) const; void Clear(int idx = 0) const; // Clear all elements >= idx @@ -28,6 +28,7 @@ public: void SetCollapsed(bool) const; void SetSelection(int idx) const; QVBoxLayout *ContentLayout() const { return _contentLayout; } + void SetVisibilityCheckEnable(bool enable); signals: void SelectionChanged(int idx); @@ -42,8 +43,10 @@ protected: void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); + void resizeEvent(QResizeEvent *event); private: + void SetupVisibleMacroSegmentWidgets(); int GetSegmentIndexFromPos(const QPoint &) const; int GetDragIndex(const QPoint &) const; int GetDropIndex(const QPoint &) const; @@ -62,6 +65,8 @@ private: QVBoxLayout *_layout; QVBoxLayout *_contentLayout; QLabel *_helpMsg; + + bool _checkVisibility = true; }; } // namespace advss diff --git a/lib/macro/macro-segment.hpp b/lib/macro/macro-segment.hpp index 2d0e5d2d..138e27c0 100644 --- a/lib/macro/macro-segment.hpp +++ b/lib/macro/macro-segment.hpp @@ -106,6 +106,7 @@ public: void SetCollapsed(bool collapsed); void SetSelected(bool); virtual std::shared_ptr Data() const = 0; + virtual void SetupWidgets(bool basicSetup = false) = 0; public slots: void HeaderInfoChanged(const QString &); @@ -130,6 +131,7 @@ protected: QLabel *_headerInfo; QWidget *_frame; QVBoxLayout *_contentLayout; + bool _allWidgetsAreSetup = false; private: enum class DropLineState { diff --git a/lib/macro/macro-tab.cpp b/lib/macro/macro-tab.cpp index ce9e2ff3..d155fb69 100644 --- a/lib/macro/macro-tab.cpp +++ b/lib/macro/macro-tab.cpp @@ -531,29 +531,56 @@ void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value) const void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx) { auto &actions = m.Actions(); + + // The layout system has not completed geometry propagation yet, so we + // can skip those checks for now + ui->actionsList->SetVisibilityCheckEnable(false); + for (; afterIdx < actions.size(); afterIdx++) { auto newEntry = new MacroActionEdit(this, &actions[afterIdx], actions[afterIdx]->GetId()); ui->actionsList->Add(newEntry); } ui->actionsList->SetHelpMsgVisible(actions.size() == 0); + + // Give the layout system time before enabling the visibility checks and + // fully constructing the visible macro segments + QTimer::singleShot(0, this, [this]() { + ui->actionsList->SetVisibilityCheckEnable(true); + }); } void AdvSceneSwitcher::PopulateMacroElseActions(Macro &m, uint32_t afterIdx) { auto &actions = m.ElseActions(); + + // The layout system has not completed geometry propagation yet, so we + // can skip those checks for now + ui->elseActionsList->SetVisibilityCheckEnable(false); + for (; afterIdx < actions.size(); afterIdx++) { auto newEntry = new MacroActionEdit(this, &actions[afterIdx], actions[afterIdx]->GetId()); ui->elseActionsList->Add(newEntry); } ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0); + + // Give the layout system time before enabling the visibility checks and + // fully constructing the visible macro segments + QTimer::singleShot(0, this, [this]() { + ui->elseActionsList->SetVisibilityCheckEnable(true); + }); } void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx) { bool root = afterIdx == 0; auto &conditions = m.Conditions(); + + // The layout system has not completed geometry propagation yet, so we + // can skip those checks for now + ui->conditionsList->SetVisibilityCheckEnable(false); + for (; afterIdx < conditions.size(); afterIdx++) { auto newEntry = new MacroConditionEdit( this, &conditions[afterIdx], @@ -562,6 +589,12 @@ void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx) root = false; } ui->conditionsList->SetHelpMsgVisible(conditions.size() == 0); + + // Give the layout system time before enabling the visibility checks and + // fully constructing the visible macro segments + QTimer::singleShot(0, this, [this]() { + ui->conditionsList->SetVisibilityCheckEnable(true); + }); } void AdvSceneSwitcher::SetActionData(Macro &m) const diff --git a/lib/utils/section.cpp b/lib/utils/section.cpp index d949800d..df1fd79c 100644 --- a/lib/utils/section.cpp +++ b/lib/utils/section.cpp @@ -47,6 +47,12 @@ void Section::Collapse(bool collapse) _toggleButton->setChecked(collapse); _toggleButton->setArrowType(collapse ? Qt::ArrowType::RightArrow : Qt::ArrowType::DownArrow); + if (!_toggleAnimation) { + _collapsed = collapse; + emit Collapsed(collapse); + return; + } + _toggleAnimation->setDirection(collapse ? QAbstractAnimation::Backward : QAbstractAnimation::Forward); _transitioning = true;