From 3dae4a35a1aa5043fc915e31fa92f94791b20f4a Mon Sep 17 00:00:00 2001 From: Clayton Groeneveld Date: Sun, 24 Oct 2021 13:18:31 -0500 Subject: [PATCH] UI: Relatively center multiple scene items Before the scene items would be centered at the same spot when centering them, now they are moved relatively to each other. --- UI/window-basic-main.cpp | 109 ++++++++++++++++++++++++++------------- UI/window-basic-main.hpp | 8 +++ 2 files changed, 80 insertions(+), 37 deletions(-) diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index a76479e33..b0bd1ea5b 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -8256,62 +8256,97 @@ void OBSBasic::on_actionStretchToScreen_triggered() undo_redo, undo_redo, undo_data, redo_data); } -enum class CenterType { - Scene, - Vertical, - Horizontal, -}; - -static bool center_to_scene(obs_scene_t *, obs_sceneitem_t *item, void *param) +void OBSBasic::CenterSelectedSceneItems(const CenterType ¢erType) { - CenterType centerType = *reinterpret_cast(param); + QModelIndexList selectedItems = GetAllSelectedSourceItems(); - vec3 tl, br, itemCenter, screenCenter, offset; + if (!selectedItems.count()) + return; + + vector items; + + // Filter out items that have no size + for (int x = 0; x < selectedItems.count(); x++) { + OBSSceneItem item = ui->sources->Get(selectedItems[x].row()); + obs_transform_info oti; + obs_sceneitem_get_info(item, &oti); + + obs_source_t *source = obs_sceneitem_get_source(item); + float width = float(obs_source_get_width(source)) * oti.scale.x; + float height = + float(obs_source_get_height(source)) * oti.scale.y; + + if (width == 0.0f || height == 0.0f) + continue; + + items.emplace_back(item); + } + + if (!items.size()) + return; + + // Get center x, y coordinates of items + vec3 center; + + float top = M_INFINITE; + float left = M_INFINITE; + float right = 0.0f; + float bottom = 0.0f; + + for (auto &item : items) { + vec3 tl, br; + + GetItemBox(item, tl, br); + + left = (std::min)(tl.x, left); + top = (std::min)(tl.y, top); + right = (std::max)(br.x, right); + bottom = (std::max)(br.y, bottom); + } + + center.x = (right + left) / 2.0f; + center.y = (top + bottom) / 2.0f; + center.z = 0.0f; + + // Get coordinates of screen center obs_video_info ovi; - obs_transform_info oti; - - if (obs_sceneitem_is_group(item)) - obs_sceneitem_group_enum_items(item, center_to_scene, - ¢erType); - if (!obs_sceneitem_selected(item)) - return true; - if (obs_sceneitem_locked(item)) - return true; - obs_get_video_info(&ovi); - obs_sceneitem_get_info(item, &oti); + vec3 screenCenter; vec3_set(&screenCenter, float(ovi.base_width), float(ovi.base_height), 0.0f); vec3_mulf(&screenCenter, &screenCenter, 0.5f); - GetItemBox(item, tl, br); + // Calculate difference between screen center and item center + vec3 offset; + vec3_sub(&offset, &screenCenter, ¢er); - vec3_sub(&itemCenter, &br, &tl); - vec3_mulf(&itemCenter, &itemCenter, 0.5f); - vec3_add(&itemCenter, &itemCenter, &tl); + // Shift items by offset + for (auto &item : items) { + vec3 tl, br; - vec3_sub(&offset, &screenCenter, &itemCenter); - vec3_add(&tl, &tl, &offset); + GetItemBox(item, tl, br); - vec3 itemTL = GetItemTL(item); + vec3_add(&tl, &tl, &offset); - if (centerType == CenterType::Vertical) - tl.x = itemTL.x; - else if (centerType == CenterType::Horizontal) - tl.y = itemTL.y; + vec3 itemTL = GetItemTL(item); - SetItemTL(item, tl); - return true; -}; + if (centerType == CenterType::Vertical) + tl.x = itemTL.x; + else if (centerType == CenterType::Horizontal) + tl.y = itemTL.y; + + SetItemTL(item, tl); + } +} void OBSBasic::on_actionCenterToScreen_triggered() { CenterType centerType = CenterType::Scene; OBSDataAutoRelease wrapper = obs_scene_save_transform_states(GetCurrentScene(), false); - obs_scene_enum_items(GetCurrentScene(), center_to_scene, ¢erType); + CenterSelectedSceneItems(centerType); OBSDataAutoRelease rwrapper = obs_scene_save_transform_states(GetCurrentScene(), false); @@ -8328,7 +8363,7 @@ void OBSBasic::on_actionVerticalCenter_triggered() CenterType centerType = CenterType::Vertical; OBSDataAutoRelease wrapper = obs_scene_save_transform_states(GetCurrentScene(), false); - obs_scene_enum_items(GetCurrentScene(), center_to_scene, ¢erType); + CenterSelectedSceneItems(centerType); OBSDataAutoRelease rwrapper = obs_scene_save_transform_states(GetCurrentScene(), false); @@ -8345,7 +8380,7 @@ void OBSBasic::on_actionHorizontalCenter_triggered() CenterType centerType = CenterType::Horizontal; OBSDataAutoRelease wrapper = obs_scene_save_transform_states(GetCurrentScene(), false); - obs_scene_enum_items(GetCurrentScene(), center_to_scene, ¢erType); + CenterSelectedSceneItems(centerType); OBSDataAutoRelease rwrapper = obs_scene_save_transform_states(GetCurrentScene(), false); diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index c342dcd4a..0221bcab1 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -205,6 +205,12 @@ class OBSBasic : public OBSMainWindow { ContextBarSize_Normal }; + enum class CenterType { + Scene, + Vertical, + Horizontal, + }; + private: obs_frontend_callbacks *api = nullptr; @@ -614,6 +620,8 @@ private: void UpdatePreviewSafeAreas(); bool drawSafeAreas = false; + void CenterSelectedSceneItems(const CenterType ¢erType); + public slots: void DeferSaveBegin(); void DeferSaveEnd();