diff --git a/frontend/data/locale/en-US.ini b/frontend/data/locale/en-US.ini index e1a4efa32..536e6926e 100644 --- a/frontend/data/locale/en-US.ini +++ b/frontend/data/locale/en-US.ini @@ -63,6 +63,8 @@ Left="Left" Right="Right" Top="Top" Bottom="Bottom" +Width="Width" +Height="Height" Reset="Reset" Hours="Hours" Minutes="Minutes" @@ -699,24 +701,26 @@ Basic.Filters.AddFilter.Text="Please specify the name of the filter" # transform window Basic.TransformWindow="Scene Item Transform" Basic.TransformWindow.Position="Position" -Basic.TransformWindow.PositionX="Position X" -Basic.TransformWindow.PositionY="Position Y" +Basic.TransformWindow.PositionX="X" +Basic.TransformWindow.PositionY="Y" Basic.TransformWindow.Rotation="Rotation" Basic.TransformWindow.Size="Size" Basic.TransformWindow.Width="Width" Basic.TransformWindow.Height="Height" -Basic.TransformWindow.Alignment="Positional Alignment" -Basic.TransformWindow.BoundsType="Bounding Box Type" -Basic.TransformWindow.BoundsAlignment="Alignment in Bounding Box" -Basic.TransformWindow.Bounds="Bounding Box Size" +Basic.TransformWindow.Alignment="Alignment" +Basic.TransformWindow.BoundsType="Bounds Type" +Basic.TransformWindow.BoundsAlignment="Bounds Alignment" +Basic.TransformWindow.Bounds="Bounds" Basic.TransformWindow.BoundsWidth="Bounding Box Width" Basic.TransformWindow.BoundsHeight="Bounding Box Height" -Basic.TransformWindow.CropToBounds="Crop to Bounding Box" +Basic.TransformWindow.CropToBounds="Crop Bounds" Basic.TransformWindow.Crop="Crop" Basic.TransformWindow.CropLeft="Crop Left" Basic.TransformWindow.CropRight="Crop Right" Basic.TransformWindow.CropTop="Crop Top" Basic.TransformWindow.CropBottom="Crop Bottom" +Basic.TransformWindow.Accessible.PositionX="X Position" +Basic.TransformWindow.Accessible.PositionY="Y Position" Basic.TransformWindow.Alignment.TopLeft="Top Left" Basic.TransformWindow.Alignment.TopCenter="Top Center" @@ -728,13 +732,13 @@ Basic.TransformWindow.Alignment.BottomLeft="Bottom Left" Basic.TransformWindow.Alignment.BottomCenter="Bottom Center" Basic.TransformWindow.Alignment.BottomRight="Bottom Right" -Basic.TransformWindow.BoundsType.None="No bounds" +Basic.TransformWindow.BoundsType.None="Automatic" Basic.TransformWindow.BoundsType.MaxOnly="Maximum size only" -Basic.TransformWindow.BoundsType.ScaleInner="Scale to inner bounds" -Basic.TransformWindow.BoundsType.ScaleOuter="Scale to outer bounds" -Basic.TransformWindow.BoundsType.ScaleToWidth="Scale to width of bounds" -Basic.TransformWindow.BoundsType.ScaleToHeight="Scale to height of bounds" -Basic.TransformWindow.BoundsType.Stretch="Stretch to bounds" +Basic.TransformWindow.BoundsType.ScaleInner="Fit" +Basic.TransformWindow.BoundsType.ScaleOuter="Cover" +Basic.TransformWindow.BoundsType.ScaleToWidth="Fill Width" +Basic.TransformWindow.BoundsType.ScaleToHeight="Fill Height" +Basic.TransformWindow.BoundsType.Stretch="Stretch" Basic.TransformWindow.Title="Edit Transform for '%1'" Basic.TransformWindow.NoSelectedSource="No source selected" @@ -1635,3 +1639,6 @@ PluginManager.Section.Discover="Browse" PluginManager.Section.Manage="Installed" PluginManager.Section.Updates="Updates" PluginManager.Section.Manage.Title="Manage Enabled Plugins" + +# Custom Widget Localization +Accessible.Widget.Name.AlignmentSelector="Alignment Selector" diff --git a/frontend/data/themes/Yami.obt b/frontend/data/themes/Yami.obt index 06fbe968b..752dc069e 100644 --- a/frontend/data/themes/Yami.obt +++ b/frontend/data/themes/Yami.obt @@ -335,6 +335,12 @@ margin: var(--spacing_base) 0; } +.subtitle { + font-size: var(--font_small); + font-weight: bold; + color: var(--text_muted); +} + .button-primary { background-color: var(--primary_dark); border-color: var(--primary); diff --git a/frontend/dialogs/OBSBasicTransform.cpp b/frontend/dialogs/OBSBasicTransform.cpp index 04407a8e0..828aa9acc 100644 --- a/frontend/dialogs/OBSBasicTransform.cpp +++ b/frontend/dialogs/OBSBasicTransform.cpp @@ -4,6 +4,7 @@ #include "moc_OBSBasicTransform.cpp" +namespace { static bool find_sel(obs_scene_t *, obs_sceneitem_t *item, void *param) { OBSSceneItem &dst = *static_cast(param); @@ -28,8 +29,28 @@ static OBSSceneItem FindASelectedItem(obs_scene_t *scene) obs_scene_enum_items(scene, find_sel, &item); return item; } +static vec2 getAlignmentConversion(uint32_t alignment) +{ + vec2 ratio = {0.5f, 0.5f}; + if (alignment & OBS_ALIGN_RIGHT) { + ratio.x = 1.0f; + } + if (alignment & OBS_ALIGN_LEFT) { + ratio.x = 0.0f; + } + if (alignment & OBS_ALIGN_BOTTOM) { + ratio.y = 1.0f; + } + if (alignment & OBS_ALIGN_TOP) { + ratio.y = 0.0f; + } + + return ratio; +} +} // namespace #define COMBO_CHANGED &QComboBox::currentIndexChanged +#define ALIGN_CHANGED &AlignmentSelector::currentIndexChanged #define ISCROLL_CHANGED &QSpinBox::valueChanged #define DSCROLL_CHANGED &QDoubleSpinBox::valueChanged @@ -42,24 +63,38 @@ OBSBasicTransform::OBSBasicTransform(OBSSceneItem item, OBSBasic *parent) ui->setupUi(this); - HookWidget(ui->positionX, DSCROLL_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->positionY, DSCROLL_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->rotation, DSCROLL_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->sizeX, DSCROLL_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->sizeY, DSCROLL_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->align, COMBO_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->boundsType, COMBO_CHANGED, &OBSBasicTransform::OnBoundsType); - HookWidget(ui->boundsAlign, COMBO_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->boundsWidth, DSCROLL_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->boundsHeight, DSCROLL_CHANGED, &OBSBasicTransform::OnControlChanged); - HookWidget(ui->cropLeft, ISCROLL_CHANGED, &OBSBasicTransform::OnCropChanged); - HookWidget(ui->cropRight, ISCROLL_CHANGED, &OBSBasicTransform::OnCropChanged); - HookWidget(ui->cropTop, ISCROLL_CHANGED, &OBSBasicTransform::OnCropChanged); - HookWidget(ui->cropBottom, ISCROLL_CHANGED, &OBSBasicTransform::OnCropChanged); + positionAlignment = new AlignmentSelector(this); + positionAlignment->setAccessibleName(QTStr("Basic.TransformWindow.Alignment")); + ui->alignmentLayout->addWidget(positionAlignment); + positionAlignment->setAlignment(Qt::AlignTop | Qt::AlignLeft); + + boundsAlignment = new AlignmentSelector(this); + boundsAlignment->setAccessibleName(QTStr("Basic.TransformWindow.BoundsAlignment")); + boundsAlignment->setEnabled(false); + ui->boundsAlignmentLayout->addWidget(boundsAlignment); + boundsAlignment->setAlignment(Qt::AlignTop | Qt::AlignLeft); + + setTabOrder(ui->rotation, positionAlignment); + setTabOrder(ui->boundsType, boundsAlignment); + + hookWidget(ui->positionX, DSCROLL_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(ui->positionY, DSCROLL_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(ui->rotation, DSCROLL_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(ui->sizeX, DSCROLL_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(ui->sizeY, DSCROLL_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(positionAlignment.get(), ALIGN_CHANGED, &OBSBasicTransform::onAlignChanged); + hookWidget(ui->boundsType, COMBO_CHANGED, &OBSBasicTransform::onBoundsType); + hookWidget(boundsAlignment.get(), ALIGN_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(ui->boundsWidth, DSCROLL_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(ui->boundsHeight, DSCROLL_CHANGED, &OBSBasicTransform::onControlChanged); + hookWidget(ui->cropLeft, ISCROLL_CHANGED, &OBSBasicTransform::onCropChanged); + hookWidget(ui->cropRight, ISCROLL_CHANGED, &OBSBasicTransform::onCropChanged); + hookWidget(ui->cropTop, ISCROLL_CHANGED, &OBSBasicTransform::onCropChanged); + hookWidget(ui->cropBottom, ISCROLL_CHANGED, &OBSBasicTransform::onCropChanged); #if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) - HookWidget(ui->cropToBounds, &QCheckBox::checkStateChanged, &OBSBasicTransform::OnControlChanged); + hookWidget(ui->cropToBounds, &QCheckBox::checkStateChanged, &OBSBasicTransform::onControlChanged); #else - HookWidget(ui->cropToBounds, &QCheckBox::stateChanged, &OBSBasicTransform::OnControlChanged); + hookWidget(ui->cropToBounds, &QCheckBox::stateChanged, &OBSBasicTransform::onControlChanged); #endif ui->buttonBox->button(QDialogButtonBox::Close)->setDefault(true); @@ -69,14 +104,18 @@ OBSBasicTransform::OBSBasicTransform(OBSSceneItem item, OBSBasic *parent) installEventFilter(CreateShortcutFilter()); OBSScene scene = obs_sceneitem_get_scene(item); - SetScene(scene); - SetItem(item); + setScene(scene); + setItem(item); std::string name = obs_source_get_name(obs_sceneitem_get_source(item)); setWindowTitle(QTStr("Basic.TransformWindow.Title").arg(name.c_str())); OBSDataAutoRelease wrapper = obs_scene_save_transform_states(main->GetCurrentScene(), false); undo_data = std::string(obs_data_get_json(wrapper)); + + adjustSize(); + setMinimumSize(size()); + setMaximumSize(size()); } OBSBasicTransform::~OBSBasicTransform() @@ -97,7 +136,7 @@ OBSBasicTransform::~OBSBasicTransform() undo_redo, undo_redo, undo_data, redo_data); } -void OBSBasicTransform::SetScene(OBSScene scene) +void OBSBasicTransform::setScene(OBSScene scene) { sigs.clear(); @@ -113,25 +152,27 @@ void OBSBasicTransform::SetScene(OBSScene scene) } } -void OBSBasicTransform::SetItem(OBSSceneItem newItem) +void OBSBasicTransform::setItem(OBSSceneItem newItem) { - QMetaObject::invokeMethod(this, "SetItemQt", Q_ARG(OBSSceneItem, OBSSceneItem(newItem))); + QMetaObject::invokeMethod(this, "setItemQt", Q_ARG(OBSSceneItem, OBSSceneItem(newItem))); } -void OBSBasicTransform::SetEnabled(bool enable) +void OBSBasicTransform::setEnabled(bool enable) { - ui->container->setEnabled(enable); + ui->transformSettings->setEnabled(enable); + ui->boundsSettings->setEnabled(enable); + ui->cropSettings->setEnabled(enable); ui->buttonBox->button(QDialogButtonBox::Reset)->setEnabled(enable); } -void OBSBasicTransform::SetItemQt(OBSSceneItem newItem) +void OBSBasicTransform::setItemQt(OBSSceneItem newItem) { item = newItem; if (item) - RefreshControls(); + refreshControls(); bool enable = !!item && !obs_sceneitem_locked(item); - SetEnabled(enable); + setEnabled(enable); } void OBSBasicTransform::OBSSceneItemTransform(void *param, calldata_t *data) @@ -140,7 +181,7 @@ void OBSBasicTransform::OBSSceneItemTransform(void *param, calldata_t *data) OBSSceneItem item = (obs_sceneitem_t *)calldata_ptr(data, "item"); if (item == window->item && !window->ignoreTransformSignal) - QMetaObject::invokeMethod(window, "RefreshControls"); + QMetaObject::invokeMethod(window, "refreshControls"); } void OBSBasicTransform::OBSSceneItemRemoved(void *param, calldata_t *data) @@ -150,7 +191,7 @@ void OBSBasicTransform::OBSSceneItemRemoved(void *param, calldata_t *data) obs_sceneitem_t *item = (obs_sceneitem_t *)calldata_ptr(data, "item"); if (item == window->item) - window->SetItem(FindASelectedItem(scene)); + window->setItem(FindASelectedItem(scene)); } void OBSBasicTransform::OBSSceneItemSelect(void *param, calldata_t *data) @@ -159,7 +200,7 @@ void OBSBasicTransform::OBSSceneItemSelect(void *param, calldata_t *data) OBSSceneItem item = (obs_sceneitem_t *)calldata_ptr(data, "item"); if (item != window->item) - window->SetItem(item); + window->setItem(item); } void OBSBasicTransform::OBSSceneItemDeselect(void *param, calldata_t *data) @@ -170,7 +211,7 @@ void OBSBasicTransform::OBSSceneItemDeselect(void *param, calldata_t *data) if (item == window->item) { window->setWindowTitle(QTStr("Basic.TransformWindow.NoSelectedSource")); - window->SetItem(FindASelectedItem(scene)); + window->setItem(FindASelectedItem(scene)); } } @@ -179,23 +220,23 @@ void OBSBasicTransform::OBSSceneItemLocked(void *param, calldata_t *data) OBSBasicTransform *window = static_cast(param); bool locked = calldata_bool(data, "locked"); - QMetaObject::invokeMethod(window, "SetEnabled", Q_ARG(bool, !locked)); + QMetaObject::invokeMethod(window, "setEnabled", Q_ARG(bool, !locked)); } -static const uint32_t listToAlign[] = {OBS_ALIGN_TOP | OBS_ALIGN_LEFT, - OBS_ALIGN_TOP, - OBS_ALIGN_TOP | OBS_ALIGN_RIGHT, - OBS_ALIGN_LEFT, - OBS_ALIGN_CENTER, - OBS_ALIGN_RIGHT, - OBS_ALIGN_BOTTOM | OBS_ALIGN_LEFT, - OBS_ALIGN_BOTTOM, - OBS_ALIGN_BOTTOM | OBS_ALIGN_RIGHT}; +static const uint32_t indexToAlign[] = {OBS_ALIGN_TOP | OBS_ALIGN_LEFT, + OBS_ALIGN_TOP, + OBS_ALIGN_TOP | OBS_ALIGN_RIGHT, + OBS_ALIGN_LEFT, + OBS_ALIGN_CENTER, + OBS_ALIGN_RIGHT, + OBS_ALIGN_BOTTOM | OBS_ALIGN_LEFT, + OBS_ALIGN_BOTTOM, + OBS_ALIGN_BOTTOM | OBS_ALIGN_RIGHT}; -static int AlignToList(uint32_t align) +static int alignToIndex(uint32_t align) { int index = 0; - for (uint32_t curAlign : listToAlign) { + for (uint32_t curAlign : indexToAlign) { if (curAlign == align) return index; @@ -205,14 +246,14 @@ static int AlignToList(uint32_t align) return 0; } -void OBSBasicTransform::RefreshControls() +void OBSBasicTransform::refreshControls() { if (!item) return; - obs_transform_info osi; + obs_transform_info oti; obs_sceneitem_crop crop; - obs_sceneitem_get_info2(item, &osi); + obs_sceneitem_get_info2(item, &oti); obs_sceneitem_get_crop(item, &crop); obs_source_t *source = obs_sceneitem_get_source(item); @@ -221,26 +262,26 @@ void OBSBasicTransform::RefreshControls() float width = float(source_cx); float height = float(source_cy); - int alignIndex = AlignToList(osi.alignment); - int boundsAlignIndex = AlignToList(osi.bounds_alignment); + int alignIndex = alignToIndex(oti.alignment); + int boundsAlignIndex = alignToIndex(oti.bounds_alignment); ignoreItemChange = true; - ui->positionX->setValue(osi.pos.x); - ui->positionY->setValue(osi.pos.y); - ui->rotation->setValue(osi.rot); - ui->sizeX->setValue(osi.scale.x * width); - ui->sizeY->setValue(osi.scale.y * height); - ui->align->setCurrentIndex(alignIndex); + ui->positionX->setValue(oti.pos.x); + ui->positionY->setValue(oti.pos.y); + ui->rotation->setValue(oti.rot); + ui->sizeX->setValue(oti.scale.x * width); + ui->sizeY->setValue(oti.scale.y * height); + positionAlignment->setCurrentIndex(alignIndex); bool valid_size = source_cx != 0 && source_cy != 0; ui->sizeX->setEnabled(valid_size); ui->sizeY->setEnabled(valid_size); - ui->boundsType->setCurrentIndex(int(osi.bounds_type)); - ui->boundsAlign->setCurrentIndex(boundsAlignIndex); - ui->boundsWidth->setValue(osi.bounds.x); - ui->boundsHeight->setValue(osi.bounds.y); - ui->cropToBounds->setChecked(osi.crop_to_bounds); + ui->boundsType->setCurrentIndex(int(oti.bounds_type)); + boundsAlignment->setCurrentIndex(boundsAlignIndex); + ui->boundsWidth->setValue(oti.bounds.x); + ui->boundsHeight->setValue(oti.bounds.y); + ui->cropToBounds->setChecked(oti.crop_to_bounds); ui->cropLeft->setValue(int(crop.left)); ui->cropRight->setValue(int(crop.right)); @@ -252,7 +293,45 @@ void OBSBasicTransform::RefreshControls() setWindowTitle(QTStr("Basic.TransformWindow.Title").arg(name.c_str())); } -void OBSBasicTransform::OnBoundsType(int index) +void OBSBasicTransform::onAlignChanged(int index) +{ + uint32_t alignment = indexToAlign[index]; + + vec2 flipRatio = getAlignmentConversion(alignment); + + obs_transform_info oti; + obs_sceneitem_crop crop; + obs_sceneitem_get_info2(item, &oti); + obs_sceneitem_get_crop(item, &crop); + + obs_source_t *source = obs_sceneitem_get_source(item); + uint32_t sourceWidth = obs_source_get_width(source); + uint32_t sourceHeight = obs_source_get_height(source); + + uint32_t widthForFlip = sourceWidth - crop.left - crop.right; + uint32_t heightForFlip = sourceHeight - crop.top - crop.bottom; + + if (oti.bounds_type != OBS_BOUNDS_NONE) { + widthForFlip = oti.bounds.x; + heightForFlip = oti.bounds.y; + } + + vec2 currentRatio = getAlignmentConversion(oti.alignment); + + float shiftX = (currentRatio.x - flipRatio.x) * widthForFlip * oti.scale.x; + float shiftY = (currentRatio.y - flipRatio.y) * heightForFlip * oti.scale.y; + + bool previousIgnoreState = ignoreItemChange; + + ignoreItemChange = true; + ui->positionX->setValue(oti.pos.x - shiftX); + ui->positionY->setValue(oti.pos.y - shiftY); + ignoreItemChange = previousIgnoreState; + + onControlChanged(); +} + +void OBSBasicTransform::onBoundsType(int index) { if (index == -1) return; @@ -260,10 +339,13 @@ void OBSBasicTransform::OnBoundsType(int index) obs_bounds_type type = (obs_bounds_type)index; bool enable = (type != OBS_BOUNDS_NONE); - ui->boundsAlign->setEnabled(enable); + boundsAlignment->setEnabled(enable && type != OBS_BOUNDS_STRETCH); ui->boundsWidth->setEnabled(enable); ui->boundsHeight->setEnabled(enable); - ui->cropToBounds->setEnabled(enable); + + bool isCoverBounds = type == OBS_BOUNDS_SCALE_OUTER || type == OBS_BOUNDS_SCALE_TO_WIDTH || + type == OBS_BOUNDS_SCALE_TO_HEIGHT; + ui->cropToBounds->setEnabled(isCoverBounds); if (!ignoreItemChange) { obs_bounds_type lastType = obs_sceneitem_get_bounds_type(item); @@ -272,15 +354,56 @@ void OBSBasicTransform::OnBoundsType(int index) int width = (int)obs_source_get_width(source); int height = (int)obs_source_get_height(source); - ui->boundsWidth->setValue(width); - ui->boundsHeight->setValue(height); + vec2 scale; + obs_sceneitem_get_scale(item, &scale); + + obs_sceneitem_crop crop; + obs_sceneitem_get_crop(item, &crop); + + ui->sizeX->setValue(width); + ui->sizeY->setValue(height); + + ui->boundsWidth->setValue((width - crop.left - crop.right) * scale.x); + ui->boundsHeight->setValue((height - crop.top - crop.bottom) * scale.y); + } else if (type == OBS_BOUNDS_NONE) { + OBSSource source = obs_sceneitem_get_source(item); + int width = (int)obs_source_get_width(source); + int height = (int)obs_source_get_height(source); + + matrix4 draw; + obs_sceneitem_get_draw_transform(item, &draw); + + ui->sizeX->setValue(width * draw.x.x); + ui->sizeY->setValue(height * draw.y.y); + + obs_transform_info oti; + obs_sceneitem_get_info2(item, &oti); + + // We use the draw transform values here which is always a top left coordinate origin. + vec2 currentRatio = getAlignmentConversion(OBS_ALIGN_TOP | OBS_ALIGN_LEFT); + vec2 flipRatio = getAlignmentConversion(oti.alignment); + + float drawX = draw.t.x; + float drawY = draw.t.y; + + obs_sceneitem_crop crop; + obs_sceneitem_get_crop(item, &crop); + + uint32_t widthForFlip = width - crop.left - crop.right; + uint32_t heightForFlip = height - crop.top - crop.bottom; + + float shiftX = (currentRatio.x - flipRatio.x) * (widthForFlip * draw.x.x); + float shiftY = (currentRatio.y - flipRatio.y) * (heightForFlip * draw.y.y); + + ui->positionX->setValue(oti.pos.x - (oti.pos.x - drawX) - shiftX); + ui->positionY->setValue(oti.pos.y - (oti.pos.y - drawY) - shiftY); } } - OnControlChanged(); + onControlChanged(); } -void OBSBasicTransform::OnControlChanged() +void OBSBasicTransform::onControlChanged() { if (ignoreItemChange) return; @@ -303,10 +426,10 @@ void OBSBasicTransform::OnControlChanged() oti.pos.x = float(ui->positionX->value()); oti.pos.y = float(ui->positionY->value()); oti.rot = float(ui->rotation->value()); - oti.alignment = listToAlign[ui->align->currentIndex()]; + oti.alignment = indexToAlign[positionAlignment->currentIndex()]; oti.bounds_type = (obs_bounds_type)ui->boundsType->currentIndex(); - oti.bounds_alignment = listToAlign[ui->boundsAlign->currentIndex()]; + oti.bounds_alignment = indexToAlign[boundsAlignment->currentIndex()]; oti.bounds.x = float(ui->boundsWidth->value()); oti.bounds.y = float(ui->boundsHeight->value()); oti.crop_to_bounds = ui->cropToBounds->isChecked(); @@ -316,7 +439,7 @@ void OBSBasicTransform::OnControlChanged() ignoreTransformSignal = false; } -void OBSBasicTransform::OnCropChanged() +void OBSBasicTransform::onCropChanged() { if (ignoreItemChange) return; @@ -332,11 +455,11 @@ void OBSBasicTransform::OnCropChanged() ignoreTransformSignal = false; } -void OBSBasicTransform::OnSceneChanged(QListWidgetItem *current, QListWidgetItem *) +void OBSBasicTransform::onSceneChanged(QListWidgetItem *current, QListWidgetItem *) { if (!current) return; OBSScene scene = GetOBSRef(current); - this->SetScene(scene); + this->setScene(scene); } diff --git a/frontend/dialogs/OBSBasicTransform.hpp b/frontend/dialogs/OBSBasicTransform.hpp index 22acfe8c5..3d6778a8c 100644 --- a/frontend/dialogs/OBSBasicTransform.hpp +++ b/frontend/dialogs/OBSBasicTransform.hpp @@ -3,8 +3,10 @@ #include "ui_OBSBasicTransform.h" #include +#include #include +#include class OBSBasic; class QListWidgetItem; @@ -15,6 +17,9 @@ class OBSBasicTransform : public QDialog { private: std::unique_ptr ui; + QPointer positionAlignment; + QPointer boundsAlignment; + OBSBasic *main; OBSSceneItem item; std::vector sigs; @@ -25,14 +30,14 @@ private: bool ignoreItemChange = false; template - void HookWidget(Widget *widget, void (WidgetParent::*signal)(SignalArgs...), + void hookWidget(Widget *widget, void (WidgetParent::*signal)(SignalArgs...), void (OBSBasicTransform::*slot)(SlotArgs...)) { QObject::connect(widget, signal, this, slot); } - void SetScene(OBSScene scene); - void SetItem(OBSSceneItem newItem); + void setScene(OBSScene scene); + void setItem(OBSSceneItem newItem); static void OBSSceneItemTransform(void *param, calldata_t *data); static void OBSSceneItemRemoved(void *param, calldata_t *data); @@ -41,17 +46,18 @@ private: static void OBSSceneItemLocked(void *param, calldata_t *data); private slots: - void RefreshControls(); - void SetItemQt(OBSSceneItem newItem); - void OnBoundsType(int index); - void OnControlChanged(); - void OnCropChanged(); - void SetEnabled(bool enable); + void refreshControls(); + void setItemQt(OBSSceneItem newItem); + void onAlignChanged(int index); + void onBoundsType(int index); + void onControlChanged(); + void onCropChanged(); + void setEnabled(bool enable); public: OBSBasicTransform(OBSSceneItem item, OBSBasic *parent); ~OBSBasicTransform(); public slots: - void OnSceneChanged(QListWidgetItem *current, QListWidgetItem *prev); + void onSceneChanged(QListWidgetItem *current, QListWidgetItem *prev); }; diff --git a/frontend/forms/OBSBasicTransform.ui b/frontend/forms/OBSBasicTransform.ui index 6fb029bbb..9f27bc5d9 100644 --- a/frontend/forms/OBSBasicTransform.ui +++ b/frontend/forms/OBSBasicTransform.ui @@ -6,28 +6,49 @@ 0 0 - 564 - 320 + 900 + 280 + + + 0 + 0 + + Basic.TransformWindow - + + + 0 + + + 0 + + + 0 + + + 0 + - - - - QFormLayout::AllNonFixedFieldsGrow - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 4 - - - 4 + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + dialog-container + + + + 0 0 @@ -41,40 +62,21 @@ 0 - - - - - 0 - 0 - + + + + QFrame::NoFrame - - - 170 - 0 - + + QFrame::Plain - - Basic.TransformWindow.Position + + 0 - - Basic.TransformWindow.Position + + dialog-container dialog-frame - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - + 0 @@ -87,7 +89,86 @@ 0 - + + 8 + + + 2 + + + + + Width + + + Basic.TransformWindow.Width + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Basic.TransformWindow.Accessible.PositionX + + + X + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Width + + + px + + + 2 + + + -90001.000000000000000 + + + 90001.000000000000000 + + + 1.000000000000000 + + + + + + + Basic.TransformWindow.Rotation + + + Basic.TransformWindow.Rotation + + + subtitle + + + + @@ -97,7 +178,7 @@ - 100 + 120 16777215 @@ -108,7 +189,7 @@ px - 4 + 2 -90001.000000000000000 @@ -118,7 +199,102 @@ - + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Basic.TransformWindow.Rotation + + + ° + + + -360.000000000000000 + + + 360.000000000000000 + + + 0.100000000000000 + + + + + + + Basic.TransformWindow.Size + + + Basic.TransformWindow.Size + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + subtitle + + + + + + + Basic.TransformWindow.Position + + + Basic.TransformWindow.Position + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + subtitle + + + + + + + Qt::Horizontal + + + + 0 + 10 + + + + + + + + Basic.TransformWindow.Accessible.PositionY + + + Y + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + @@ -128,7 +304,7 @@ - 100 + 120 16777215 @@ -139,7 +315,7 @@ px - 4 + 2 -90001.000000000000000 @@ -149,122 +325,7 @@ - - - - - - - Basic.TransformWindow.Rotation - - - Basic.TransformWindow.Rotation - - - - - - - - 0 - 0 - - - - - 120 - 0 - - - - - 100 - 16777215 - - - - Basic.TransformWindow.Rotation - - - ° - - - -360.000000000000000 - - - 360.000000000000000 - - - 0.100000000000000 - - - - - - - Basic.TransformWindow.Size - - - Basic.TransformWindow.Size - - - - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - 120 - 0 - - - - - 100 - 16777215 - - - - Basic.TransformWindow.Width - - - px - - - 4 - - - -90001.000000000000000 - - - 90001.000000000000000 - - - 1.000000000000000 - - - - + @@ -274,7 +335,7 @@ - 100 + 120 16777215 @@ -285,7 +346,7 @@ px - 4 + 2 -90001.000000000000000 @@ -298,226 +359,80 @@ + + + + Height + + + Basic.TransformWindow.Height + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Basic.TransformWindow.Alignment + + + Basic.TransformWindow.Alignment + + + subtitle + + + - - - - Basic.TransformWindow.Alignment + + + + QFrame::NoFrame - - Basic.TransformWindow.Alignment + + QFrame::Plain - - - - - - Basic.TransformWindow.Alignment + + 0 - - Basic.TransformWindow.Alignment.TopLeft + + dialog-container dialog-frame - - - Basic.TransformWindow.Alignment.TopLeft - - - - - Basic.TransformWindow.Alignment.TopCenter - - - - - Basic.TransformWindow.Alignment.TopRight - - - - - Basic.TransformWindow.Alignment.CenterLeft - - - - - Basic.TransformWindow.Alignment.Center - - - - - Basic.TransformWindow.Alignment.CenterRight - - - - - Basic.TransformWindow.Alignment.BottomLeft - - - - - Basic.TransformWindow.Alignment.BottomCenter - - - - - Basic.TransformWindow.Alignment.BottomRight - - - - - - - - Qt::Vertical - - - - 10 - 10 - - - - - - - - Basic.TransformWindow.BoundsType - - - Basic.TransformWindow.BoundsType - - - - - - - Basic.TransformWindow.BoundsType - - - - Basic.TransformWindow.BoundsType.None - - - - - Basic.TransformWindow.BoundsType.Stretch - - - - - Basic.TransformWindow.BoundsType.ScaleInner - - - - - Basic.TransformWindow.BoundsType.ScaleOuter - - - - - Basic.TransformWindow.BoundsType.ScaleToWidth - - - - - Basic.TransformWindow.BoundsType.ScaleToHeight - - - - - Basic.TransformWindow.BoundsType.MaxOnly - - - - - - - - Basic.TransformWindow.BoundsAlignment - - - Basic.TransformWindow.BoundsAlignment - - - - - - - false - - - Basic.TransformWindow.BoundsAlignment - - - Basic.TransformWindow.Alignment.TopLeft - - - - Basic.TransformWindow.Alignment.TopLeft - - - - - Basic.TransformWindow.Alignment.TopCenter - - - - - Basic.TransformWindow.Alignment.TopRight - - - - - Basic.TransformWindow.Alignment.CenterLeft - - - - - Basic.TransformWindow.Alignment.Center - - - - - Basic.TransformWindow.Alignment.CenterRight - - - - - Basic.TransformWindow.Alignment.BottomLeft - - - - - Basic.TransformWindow.Alignment.BottomCenter - - - - - Basic.TransformWindow.Alignment.BottomRight - - - - - - - - Basic.TransformWindow.Bounds - - - Basic.TransformWindow.Bounds - - - - - - - - 0 - 0 - - - + 0 @@ -530,7 +445,147 @@ 0 - + + 8 + + + 2 + + + + + Basic.TransformWindow.BoundsType + + + + Basic.TransformWindow.BoundsType.None + + + + + Basic.TransformWindow.BoundsType.Stretch + + + + + Basic.TransformWindow.BoundsType.ScaleInner + + + + + Basic.TransformWindow.BoundsType.ScaleOuter + + + + + Basic.TransformWindow.BoundsType.ScaleToWidth + + + + + Basic.TransformWindow.BoundsType.ScaleToHeight + + + + + Basic.TransformWindow.BoundsType.MaxOnly + + + + + + + + Qt::Horizontal + + + + 0 + 10 + + + + + + + + Basic.TransformWindow.Bounds + + + Basic.TransformWindow.Bounds + + + subtitle + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + 0 + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Basic.TransformWindow.Alignment + + + Basic.TransformWindow.Alignment + + + subtitle + + + + + + + Basic.TransformWindow.BoundsWidth + + + Basic.TransformWindow.Width + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Basic.TransformWindow.BoundsHeight + + + Basic.TransformWindow.Height + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + false @@ -543,7 +598,7 @@ - 100 + 120 16777215 @@ -554,7 +609,7 @@ px - 4 + 2 1.000000000000000 @@ -564,7 +619,7 @@ - + false @@ -577,7 +632,7 @@ - 100 + 120 16777215 @@ -588,7 +643,7 @@ px - 4 + 2 1.000000000000000 @@ -598,260 +653,281 @@ + + + + false + + + + 100 + 16777215 + + + + Basic.TransformWindow.BoundsAlignment + + + Basic.TransformWindow.CropToBounds + + + + + + - - - - Basic.TransformWindow.BoundsAlignment + + + + 0 - - Basic.TransformWindow.CropToBounds + + dialog-container dialog-frame + + + 0 + + + 0 + + + 0 + + + 0 + + + 8 + + + 2 + + + + + Basic.TransformWindow.CropLeft + + + Left + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Right + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Basic.TransformWindow.CropBottom + + + px + + + 100000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Basic.TransformWindow.CropRight + + + px + + + 100000 + + + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Basic.TransformWindow.CropLeft + + + px + + + 100000 + + + + + + + Top + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 120 + 0 + + + + + 120 + 16777215 + + + + Basic.TransformWindow.CropTop + + + px + + + 100000 + + + + + + + Basic.TransformWindow.Crop + + + Basic.TransformWindow.Crop + + + subtitle + + + + + + + Bottom + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + - - - - Qt::Vertical - - - - 10 - 10 - - - - - - - - Basic.TransformWindow.Crop - - - Basic.TransformWindow.Crop + + + + QDialogButtonBox::Close|QDialogButtonBox::Reset - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Basic.TransformWindow.CropLeft - - - px - - - 100000 - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Basic.TransformWindow.CropRight - - - px - - - 100000 - - - - - - - Left - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - cropLeft - - - - - - - Bottom - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - cropBottom - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Basic.TransformWindow.CropTop - - - px - - - 100000 - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Basic.TransformWindow.CropBottom - - - px - - - 100000 - - - - - - - Top - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - cropTop - - - - - - - Right - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - cropRight - - - - - - - Qt::Horizontal - - - - 0 - 0 - - - - - - - - - - Qt::Vertical - - - - 0 - 10 - - - - - - - - QDialogButtonBox::Close|QDialogButtonBox::Reset - - - + + positionX + positionY + sizeX + sizeY + rotation + boundsType + boundsWidth + boundsHeight + cropToBounds + cropLeft + cropRight + cropTop + cropBottom + @@ -862,7 +938,7 @@ 20 - 20 + 358 20 diff --git a/frontend/widgets/OBSBasic_MainControls.cpp b/frontend/widgets/OBSBasic_MainControls.cpp index 25bc79c65..397f0de76 100644 --- a/frontend/widgets/OBSBasic_MainControls.cpp +++ b/frontend/widgets/OBSBasic_MainControls.cpp @@ -489,7 +489,7 @@ void OBSBasic::CreateEditTransformWindow(obs_sceneitem_t *item) if (transformWindow) transformWindow->close(); transformWindow = new OBSBasicTransform(item, this); - connect(ui->scenes, &QListWidget::currentItemChanged, transformWindow, &OBSBasicTransform::OnSceneChanged); + connect(ui->scenes, &QListWidget::currentItemChanged, transformWindow, &OBSBasicTransform::onSceneChanged); transformWindow->show(); transformWindow->setAttribute(Qt::WA_DeleteOnClose, true); }