From 549376500eeffb8c4b5c42d04466d66e6bb2f1cf Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Mon, 14 Oct 2024 20:03:56 +0200 Subject: [PATCH] Add option to move scene item above / below specified scene item --- data/locale/de-DE.ini | 2 +- data/locale/en-US.ini | 4 +- data/locale/es-ES.ini | 2 +- data/locale/fr-FR.ini | 2 +- data/locale/ja-JP.ini | 2 +- data/locale/pt-BR.ini | 2 +- data/locale/tr-TR.ini | 2 +- data/locale/zh-CN.ini | 2 +- plugins/base/macro-action-scene-order.cpp | 220 ++++++++++++++++------ plugins/base/macro-action-scene-order.hpp | 30 +-- 10 files changed, 194 insertions(+), 74 deletions(-) diff --git a/data/locale/de-DE.ini b/data/locale/de-DE.ini index 245a0a719..71c7e9409 100644 --- a/data/locale/de-DE.ini +++ b/data/locale/de-DE.ini @@ -490,7 +490,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Nach unten verschieben" AdvSceneSwitcher.action.sceneOrder.type.moveTop="An erste Stelle verschieben" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="An letzte Stelle verschieben" AdvSceneSwitcher.action.sceneOrder.type.movePosition="An Position verschieben" -AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{position}}" +AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}" AdvSceneSwitcher.action.sceneTransform="Szenenelement transformieren" AdvSceneSwitcher.action.sceneTransform.getTransform="Transformation erhalten" AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}" diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index c88f4dab5..4188158a0 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -956,7 +956,9 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Move down" AdvSceneSwitcher.action.sceneOrder.type.moveTop="Move to top" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Move to bottom" AdvSceneSwitcher.action.sceneOrder.type.movePosition="Move to position" -AdvSceneSwitcher.action.sceneOrder.entry="On{{scenes}}{{actions}}{{sources}}{{position}}" +AdvSceneSwitcher.action.sceneOrder.type.above="Move above" +AdvSceneSwitcher.action.sceneOrder.type.below="Move below" +AdvSceneSwitcher.action.sceneOrder.entry="On{{scenes}}{{actions}}{{sources}}{{position}}{{sources2}}" AdvSceneSwitcher.action.sceneTransform="Scene item transform" AdvSceneSwitcher.action.sceneTransform.type.manual="Set transform string" AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="Set transform setting" diff --git a/data/locale/es-ES.ini b/data/locale/es-ES.ini index 7df020160..958deff9e 100644 --- a/data/locale/es-ES.ini +++ b/data/locale/es-ES.ini @@ -407,7 +407,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover hacia abajo" AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover al principio" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover al final" AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover a la posición" -AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{position}}" +AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}" AdvSceneSwitcher.action.sceneTransform="Transformar elemento de escena" AdvSceneSwitcher.action.sceneTransform.getTransform="Obtener transformación" AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}" diff --git a/data/locale/fr-FR.ini b/data/locale/fr-FR.ini index 93c8c20b7..e7de6e4d1 100644 --- a/data/locale/fr-FR.ini +++ b/data/locale/fr-FR.ini @@ -597,7 +597,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Déplacer vers le bas" AdvSceneSwitcher.action.sceneOrder.type.moveTop="Déplacer en haut" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Déplacer en bas" AdvSceneSwitcher.action.sceneOrder.type.movePosition="Déplacer à la position" -AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{position}}" +AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}" AdvSceneSwitcher.action.sceneTransform="Transformation de l'élément de la scène" AdvSceneSwitcher.action.sceneTransform.type.manual="Transform" AdvSceneSwitcher.action.sceneTransform.type.reset="Réinitialiser la transformation" diff --git a/data/locale/ja-JP.ini b/data/locale/ja-JP.ini index 36ce3269e..5bbf2f053 100644 --- a/data/locale/ja-JP.ini +++ b/data/locale/ja-JP.ini @@ -925,7 +925,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="下へ移動" AdvSceneSwitcher.action.sceneOrder.type.moveTop="トップへ移動" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="一番下へ移動" AdvSceneSwitcher.action.sceneOrder.type.movePosition="ポジションへの移動" -AdvSceneSwitcher.action.sceneOrder.entry="オン{{scenes}}{{actions}}{{sources}}{{position}}" +AdvSceneSwitcher.action.sceneOrder.entry="オン{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}" AdvSceneSwitcher.action.sceneTransform="シーンアイテムの変形" AdvSceneSwitcher.action.sceneTransform.type.manual="変形" AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="トランスフォーム設定を行う" diff --git a/data/locale/pt-BR.ini b/data/locale/pt-BR.ini index 517cf067b..a5f7fcd56 100644 --- a/data/locale/pt-BR.ini +++ b/data/locale/pt-BR.ini @@ -907,7 +907,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover para baixo" AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover para o topo" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover para o fundo" AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover para posição" -AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{position}}" +AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}" AdvSceneSwitcher.action.sceneTransform="Transformação de item de cena" AdvSceneSwitcher.action.sceneTransform.type.manual="Definir string de transformação" AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="Definir configuração de transformação" diff --git a/data/locale/tr-TR.ini b/data/locale/tr-TR.ini index ee5adc064..3d8af1a97 100644 --- a/data/locale/tr-TR.ini +++ b/data/locale/tr-TR.ini @@ -336,7 +336,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Aşağı indir" AdvSceneSwitcher.action.sceneOrder.type.moveTop="En üste taşı" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Aşağıya taşı" AdvSceneSwitcher.action.sceneOrder.type.movePosition="Konuma taşı" -AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{position}}" +AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}" AdvSceneSwitcher.action.sceneTransform="Sahne öğesi dönüşümü" AdvSceneSwitcher.action.sceneTransform.getTransform="Dönüşümü al" AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini index 48fffbaa8..aa643f62c 100644 --- a/data/locale/zh-CN.ini +++ b/data/locale/zh-CN.ini @@ -547,7 +547,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="下移" AdvSceneSwitcher.action.sceneOrder.type.moveTop="顶部" AdvSceneSwitcher.action.sceneOrder.type.moveBottom="底部" AdvSceneSwitcher.action.sceneOrder.type.movePosition="移动到数值位置" -AdvSceneSwitcher.action.sceneOrder.entry="在 {{scenes}} {{actions}} {{sources}} {{position}}" +AdvSceneSwitcher.action.sceneOrder.entry="在{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}" AdvSceneSwitcher.action.sceneTransform="场景项目转换" AdvSceneSwitcher.action.sceneTransform.getTransform="获得转换" AdvSceneSwitcher.action.sceneTransform.entry="在{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}" diff --git a/plugins/base/macro-action-scene-order.cpp b/plugins/base/macro-action-scene-order.cpp index 279173cb4..5c2a40a0a 100644 --- a/plugins/base/macro-action-scene-order.cpp +++ b/plugins/base/macro-action-scene-order.cpp @@ -10,17 +10,21 @@ bool MacroActionSceneOrder::_registered = MacroActionFactory::Register( {MacroActionSceneOrder::Create, MacroActionSceneOrderEdit::Create, "AdvSceneSwitcher.action.sceneOrder"}); -const static std::map actionTypes = { - {SceneOrderAction::MOVE_UP, +const static std::map actionTypes = { + {MacroActionSceneOrder::Action::MOVE_UP, "AdvSceneSwitcher.action.sceneOrder.type.moveUp"}, - {SceneOrderAction::MOVE_DOWN, + {MacroActionSceneOrder::Action::MOVE_DOWN, "AdvSceneSwitcher.action.sceneOrder.type.moveDown"}, - {SceneOrderAction::MOVE_TOP, + {MacroActionSceneOrder::Action::MOVE_TOP, "AdvSceneSwitcher.action.sceneOrder.type.moveTop"}, - {SceneOrderAction::MOVE_BOTTOM, + {MacroActionSceneOrder::Action::MOVE_BOTTOM, "AdvSceneSwitcher.action.sceneOrder.type.moveBottom"}, - {SceneOrderAction::POSITION, + {MacroActionSceneOrder::Action::POSITION, "AdvSceneSwitcher.action.sceneOrder.type.movePosition"}, + {MacroActionSceneOrder::Action::ABOVE, + "AdvSceneSwitcher.action.sceneOrder.type.above"}, + {MacroActionSceneOrder::Action::BELOW, + "AdvSceneSwitcher.action.sceneOrder.type.below"}, }; static void moveSceneItemsUp(std::vector &items) @@ -66,26 +70,128 @@ static void moveSceneItemsPos(std::vector &items, int pos) } } +namespace { + +struct PositionData { + obs_scene_item *item = nullptr; + bool found = false; + int position = 0; +}; + +} // namespace + +static bool getSceneItemPositionHelper(obs_scene_t *, obs_sceneitem_t *item, + void *data) +{ + auto positionData = reinterpret_cast(data); + if (obs_sceneitem_is_group(item)) { + obs_scene_t *scene = obs_sceneitem_group_get_scene(item); + obs_scene_enum_items(scene, getSceneItemPositionHelper, data); + } + if (positionData->item == item) { + positionData->found = true; + return false; + } + + positionData->position += 1; + return true; +} + +static std::optional getSceneItemPosition(const OBSSceneItem &item, + const SceneSelection &scene) +{ + auto sceneSource = OBSGetStrongRef(scene.GetScene()); + auto obsScene = obs_scene_from_source(sceneSource); + PositionData data{item}; + obs_scene_enum_items(obsScene, getSceneItemPositionHelper, &data); + + if (!data.found) { + return {}; + } + + return data.position; +} + +static void moveItemFromToHelper(MacroActionSceneOrder::Action action, + const OBSSceneItem &itemToMove, + int currentPosition, int targetPosition) +{ + if (action == MacroActionSceneOrder::Action::ABOVE) { + if (currentPosition > targetPosition) { + obs_sceneitem_set_order_position(itemToMove, + targetPosition + 1); + } else { + obs_sceneitem_set_order_position(itemToMove, + targetPosition); + } + } else if (action == MacroActionSceneOrder::Action::BELOW) { + if (currentPosition > targetPosition) { + obs_sceneitem_set_order_position(itemToMove, + targetPosition); + } else { + obs_sceneitem_set_order_position(itemToMove, + targetPosition - 1); + } + } +} + +static void moveItemToItemHelper(MacroActionSceneOrder::Action action, + const std::vector &itemsToMove, + const SceneItemSelection &target, + const SceneSelection &scene) +{ + auto targetItems = target.GetSceneItems(scene); + if (targetItems.empty()) { + return; + } + + auto targetItem = targetItems.at(0); + + for (const auto &item : itemsToMove) { + if (item == targetItem) { + continue; + } + + auto targetPosition = getSceneItemPosition(targetItem, scene); + if (!targetPosition) { + continue; + } + + auto currentPosition = getSceneItemPosition(item, scene); + if (!currentPosition) { + continue; + } + + moveItemFromToHelper(action, item, *currentPosition, + *targetPosition); + } +} + bool MacroActionSceneOrder::PerformAction() { auto items = _source.GetSceneItems(_scene); switch (_action) { - case SceneOrderAction::MOVE_UP: + case Action::MOVE_UP: moveSceneItemsUp(items); break; - case SceneOrderAction::MOVE_DOWN: + case Action::MOVE_DOWN: moveSceneItemsDown(items); break; - case SceneOrderAction::MOVE_TOP: + case Action::MOVE_TOP: moveSceneItemsTop(items); break; - case SceneOrderAction::MOVE_BOTTOM: + case Action::MOVE_BOTTOM: moveSceneItemsBottom(items); break; - case SceneOrderAction::POSITION: + case Action::POSITION: moveSceneItemsPos(items, _position); break; + case Action::ABOVE: + case Action::BELOW: { + moveItemToItemHelper(_action, items, _source2, _scene); + break; + } default: break; } @@ -111,6 +217,7 @@ bool MacroActionSceneOrder::Save(obs_data_t *obj) const MacroAction::Save(obj); _scene.Save(obj); _source.Save(obj); + _source2.Save(obj, "sceneItemSelection2"); obs_data_set_int(obj, "action", static_cast(_action)); obs_data_set_int(obj, "position", _position); return true; @@ -128,8 +235,8 @@ bool MacroActionSceneOrder::Load(obs_data_t *obj) MacroAction::Load(obj); _scene.Load(obj); _source.Load(obj); - _action = - static_cast(obs_data_get_int(obj, "action")); + _source2.Load(obj, "sceneItemSelection2"); + _action = static_cast(obs_data_get_int(obj, "action")); _position = obs_data_get_int(obj, "position"); return true; } @@ -167,13 +274,13 @@ static inline void populateActionSelection(QComboBox *list) MacroActionSceneOrderEdit::MacroActionSceneOrderEdit( QWidget *parent, std::shared_ptr entryData) - : QWidget(parent) + : QWidget(parent), + _scenes(new SceneSelectionWidget(this, true, false, false, true)), + _sources(new SceneItemSelectionWidget(this)), + _sources2(new SceneItemSelectionWidget(this)), + _actions(new QComboBox(this)), + _position(new QSpinBox(this)) { - _scenes = new SceneSelectionWidget(window(), true, false, false, true); - _sources = new SceneItemSelectionWidget(parent); - _actions = new QComboBox(); - _position = new QSpinBox(); - populateActionSelection(_actions); QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, @@ -182,23 +289,28 @@ MacroActionSceneOrderEdit::MacroActionSceneOrderEdit( this, SLOT(SceneChanged(const SceneSelection &))); QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), _sources, SLOT(SceneChanged(const SceneSelection &))); + QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), + _sources2, SLOT(SceneChanged(const SceneSelection &))); QWidget::connect(_sources, SIGNAL(SceneItemChanged(const SceneItemSelection &)), this, SLOT(SourceChanged(const SceneItemSelection &))); + QWidget::connect(_sources2, + SIGNAL(SceneItemChanged(const SceneItemSelection &)), + this, + SLOT(Source2Changed(const SceneItemSelection &))); QWidget::connect(_position, SIGNAL(valueChanged(int)), this, SLOT(PositionChanged(int))); - QHBoxLayout *mainLayout = new QHBoxLayout; - std::unordered_map widgetPlaceholders = { - {"{{scenes}}", _scenes}, - {"{{sources}}", _sources}, - {"{{actions}}", _actions}, - {"{{position}}", _position}, - }; + auto layout = new QHBoxLayout; PlaceWidgets( obs_module_text("AdvSceneSwitcher.action.sceneOrder.entry"), - mainLayout, widgetPlaceholders); - setLayout(mainLayout); + layout, + {{"{{scenes}}", _scenes}, + {"{{sources}}", _sources}, + {"{{sources2}}", _sources2}, + {"{{actions}}", _actions}, + {"{{position}}", _position}}); + setLayout(layout); _entryData = entryData; UpdateEntryData(); @@ -214,28 +326,20 @@ void MacroActionSceneOrderEdit::UpdateEntryData() _actions->setCurrentIndex(static_cast(_entryData->_action)); _scenes->SetScene(_entryData->_scene); _sources->SetSceneItem(_entryData->_source); + _sources2->SetSceneItem(_entryData->_source2); _position->setValue(_entryData->_position); - _position->setVisible(_entryData->_action == - SceneOrderAction::POSITION); + SetWidgetVisibility(); } void MacroActionSceneOrderEdit::SceneChanged(const SceneSelection &s) { - if (_loading || !_entryData) { - return; - } - - auto lock = LockContext(); + GUARD_LOADING_AND_LOCK(); _entryData->_scene = s; } void MacroActionSceneOrderEdit::SourceChanged(const SceneItemSelection &item) { - if (_loading || !_entryData) { - return; - } - - auto lock = LockContext(); + GUARD_LOADING_AND_LOCK(); _entryData->_source = item; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); @@ -243,26 +347,36 @@ void MacroActionSceneOrderEdit::SourceChanged(const SceneItemSelection &item) updateGeometry(); } -void MacroActionSceneOrderEdit::ActionChanged(int value) +void MacroActionSceneOrderEdit::Source2Changed(const SceneItemSelection &item) { - if (_loading || !_entryData) { - return; - } + GUARD_LOADING_AND_LOCK(); + _entryData->_source2 = item; + adjustSize(); + updateGeometry(); +} - auto lock = LockContext(); - _entryData->_action = static_cast(value); - _position->setVisible(_entryData->_action == - SceneOrderAction::POSITION); +void MacroActionSceneOrderEdit::ActionChanged(int value) +{ + GUARD_LOADING_AND_LOCK(); + _entryData->_action = static_cast(value); + SetWidgetVisibility(); } void MacroActionSceneOrderEdit::PositionChanged(int value) { - if (_loading || !_entryData) { - return; - } - - auto lock = LockContext(); + GUARD_LOADING_AND_LOCK(); _entryData->_position = value; } +void MacroActionSceneOrderEdit::SetWidgetVisibility() +{ + _position->setVisible(_entryData->_action == + MacroActionSceneOrder::Action::POSITION); + _sources2->setVisible( + _entryData->_action == MacroActionSceneOrder::Action::ABOVE || + _entryData->_action == MacroActionSceneOrder::Action::BELOW); + adjustSize(); + updateGeometry(); +} + } // namespace advss diff --git a/plugins/base/macro-action-scene-order.hpp b/plugins/base/macro-action-scene-order.hpp index f214de07b..f8e346b3b 100644 --- a/plugins/base/macro-action-scene-order.hpp +++ b/plugins/base/macro-action-scene-order.hpp @@ -7,14 +7,6 @@ namespace advss { -enum class SceneOrderAction { - MOVE_UP, - MOVE_DOWN, - MOVE_TOP, - MOVE_BOTTOM, - POSITION, -}; - class MacroActionSceneOrder : public MacroAction { public: MacroActionSceneOrder(Macro *m) : MacroAction(m) {} @@ -30,7 +22,17 @@ class MacroActionSceneOrder : public MacroAction { SceneSelection _scene; SceneItemSelection _source; - SceneOrderAction _action = SceneOrderAction::MOVE_UP; + SceneItemSelection _source2; + enum class Action { + MOVE_UP, + MOVE_DOWN, + MOVE_TOP, + MOVE_BOTTOM, + POSITION, + ABOVE, + BELOW, + }; + Action _action = Action::MOVE_UP; int _position = 0; private: @@ -58,20 +60,22 @@ class MacroActionSceneOrderEdit : public QWidget { private slots: void SceneChanged(const SceneSelection &); void SourceChanged(const SceneItemSelection &); + void Source2Changed(const SceneItemSelection &); void ActionChanged(int value); void PositionChanged(int value); signals: void HeaderInfoChanged(const QString &); -protected: +private: + void SetWidgetVisibility(); + SceneSelectionWidget *_scenes; SceneItemSelectionWidget *_sources; + SceneItemSelectionWidget *_sources2; QComboBox *_actions; QSpinBox *_position; - std::shared_ptr _entryData; -private: - QHBoxLayout *_mainLayout; + std::shared_ptr _entryData; bool _loading = true; };