mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 23:34:08 +00:00
UI: Add scene editing
So, scene editing was interesting (and by interesting I mean excruciating). I almost implemented 'manipulator' visuals (ala 3dsmax for example), and used 3 modes for controlling position/rotation/size, but in a 2D editing, it felt clunky, so I defaulted back to simply click-and-drag for movement, and then took a similar though slightly different looking approach for handling scaling and reszing. I also added a number of menu item helpers related to positioning, scaling, rotating, flipping, and resetting the transform back to default. There is also a new 'transform' dialog (accessible via menu) which will allow you to manually edit every single transform variable of a scene item directly if desired. If a scene item does not have bounds active, pulling on the sides of a source will cause it to resize it via base scale rather than by the bounding box system (if the source resizes that scale will apply). If bounds are active, it will modify the bounding box only instead. How a source scales when a bounding box is active depends on the type of bounds being used. You can set it to scale to the inner bounds, the outer bounds, scale to bounds width only, scale to bounds height only, and a setting to stretch to bounds (which forces a source to always draw at the bounding box size rather than be affected by its internal size). You can also set it to be used as a 'maximum' size, so that the source doesn't necessarily get scaled unless it extends beyond the bounds. Like in OBS1, objects will snap to the edges unless the control key is pressed. However, this will now happen even if the object is rotated or oriented in any strange way. Snapping will also occur when stretching or changing the bounding box size.
This commit is contained in:
parent
b23f8cc6e1
commit
452e0695f4
|
@ -15,7 +15,7 @@ MoveUp="Move Up"
|
|||
MoveDown="Move Down"
|
||||
Settings="Settings"
|
||||
Exit="Exit"
|
||||
Volume="Volume"
|
||||
Mixer="Mixer"
|
||||
Browse="Browse"
|
||||
Mono="Mono"
|
||||
Stereo="Stereo"
|
||||
|
@ -66,6 +66,34 @@ Basic.Main.DefaultSceneName.Text="Scene %1"
|
|||
Basic.SourceSelect.CreateNew="Create new"
|
||||
Basic.SourceSelect.AddExisting="Add Existing"
|
||||
|
||||
# transform window
|
||||
Basic.TransformWindow="Scene Item Transform"
|
||||
Basic.TransformWindow.Position="Position"
|
||||
Basic.TransformWindow.Rotation="Rotation"
|
||||
Basic.TransformWindow.Scale="Scale"
|
||||
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.TopLeft="Top Left"
|
||||
Basic.TransformWindow.Alignment.TopCenter="Top Center"
|
||||
Basic.TransformWindow.Alignment.TopRight="Top Right"
|
||||
Basic.TransformWindow.Alignment.CenterLeft="Center Left"
|
||||
Basic.TransformWindow.Alignment.Center="Center"
|
||||
Basic.TransformWindow.Alignment.CenterRight="Center Right"
|
||||
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.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"
|
||||
|
||||
# no scene warning
|
||||
Basic.Main.AddSourceHelp.Title="Cannot Add Source"
|
||||
Basic.Main.AddSourceHelp.Text="You need to have at least 1 scene to add a source."
|
||||
|
@ -86,6 +114,24 @@ Basic.MainMenu.File.Import="&Import"
|
|||
Basic.MainMenu.File.Settings="&Settings"
|
||||
Basic.MainMenu.File.Exit="E&xit"
|
||||
|
||||
# basic mode edit menu
|
||||
Basic.MainMenu.Edit="&Edit"
|
||||
Basic.MainMenu.Edit.Undo="&Undo"
|
||||
Basic.MainMenu.Edit.Redo="&Redo"
|
||||
Basic.MainMenu.Edit.UndoAction="&Undo $1"
|
||||
Basic.MainMenu.Edit.RedoAction="&Redo $1"
|
||||
Basic.MainMenu.Edit.Transform="&Transform"
|
||||
Basic.MainMenu.Edit.Transform.EditTransform="&Edit Transform..."
|
||||
Basic.MainMenu.Edit.Transform.ResetTransform="&Reset Transform"
|
||||
Basic.MainMenu.Edit.Transform.Rotate90CW="Rotate 90 degrees CW"
|
||||
Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotate 90 degrees CCW"
|
||||
Basic.MainMenu.Edit.Transform.Rotate180="Rotate 180 degrees"
|
||||
Basic.MainMenu.Edit.Transform.FlipHorizontal="Flip &Horizontal"
|
||||
Basic.MainMenu.Edit.Transform.FlipVertical="Flip &Vertical"
|
||||
Basic.MainMenu.Edit.Transform.FitToScreen="&Fit to screen"
|
||||
Basic.MainMenu.Edit.Transform.StretchToScreen="&Stretch to screen"
|
||||
Basic.MainMenu.Edit.Transform.CenterToScreen="&Center to screen"
|
||||
|
||||
# basic mode help menu
|
||||
Basic.MainMenu.Help="&Help"
|
||||
Basic.MainMenu.Help.Logs="&Log Files"
|
||||
|
|
|
@ -175,14 +175,19 @@ static void calculate_bounds_data(struct obs_scene_item *item,
|
|||
struct vec2 *origin, struct vec2 *scale,
|
||||
uint32_t *cx, uint32_t *cy)
|
||||
{
|
||||
float width = (float)(*cx) * fabsf(scale->x);
|
||||
float height = (float)(*cy) * fabsf(scale->y);
|
||||
float item_aspect = width / height;
|
||||
float bounds_aspect = item->bounds.x / item->bounds.y;
|
||||
float width_diff, height_diff;
|
||||
float width = (float)(*cx) * fabsf(scale->x);
|
||||
float height = (float)(*cy) * fabsf(scale->y);
|
||||
float item_aspect = width / height;
|
||||
float bounds_aspect = item->bounds.x / item->bounds.y;
|
||||
uint32_t bounds_type = item->bounds_type;
|
||||
float width_diff, height_diff;
|
||||
|
||||
if (item->bounds_type == OBS_BOUNDS_SCALE_INNER ||
|
||||
item->bounds_type == OBS_BOUNDS_SCALE_OUTER) {
|
||||
if (item->bounds_type == OBS_BOUNDS_MAX_ONLY)
|
||||
if (width > item->bounds.x || height > item->bounds.y)
|
||||
bounds_type = OBS_BOUNDS_SCALE_INNER;
|
||||
|
||||
if (bounds_type == OBS_BOUNDS_SCALE_INNER ||
|
||||
bounds_type == OBS_BOUNDS_SCALE_OUTER) {
|
||||
bool use_width = (bounds_aspect < item_aspect);
|
||||
float mul;
|
||||
|
||||
|
@ -195,13 +200,13 @@ static void calculate_bounds_data(struct obs_scene_item *item,
|
|||
|
||||
vec2_mulf(scale, scale, mul);
|
||||
|
||||
} else if (item->bounds_type == OBS_BOUNDS_SCALE_TO_WIDTH) {
|
||||
} else if (bounds_type == OBS_BOUNDS_SCALE_TO_WIDTH) {
|
||||
vec2_mulf(scale, scale, item->bounds.x / width);
|
||||
|
||||
} else if (item->bounds_type == OBS_BOUNDS_SCALE_TO_HEIGHT) {
|
||||
} else if (bounds_type == OBS_BOUNDS_SCALE_TO_HEIGHT) {
|
||||
vec2_mulf(scale, scale, item->bounds.y / height);
|
||||
|
||||
} else if (item->bounds_type == OBS_BOUNDS_STRETCH) {
|
||||
} else if (bounds_type == OBS_BOUNDS_STRETCH) {
|
||||
scale->x = item->bounds.x / (float)(*cx);
|
||||
scale->y = item->bounds.y / (float)(*cy);
|
||||
}
|
||||
|
|
|
@ -95,12 +95,12 @@ enum allow_direct_render {
|
|||
*/
|
||||
enum obs_bounds_type {
|
||||
OBS_BOUNDS_NONE, /**< no bounds */
|
||||
OBS_BOUNDS_ALIGN_ONLY, /**< no scaling to bounds, align only */
|
||||
OBS_BOUNDS_STRETCH, /**< stretch (ignores base scale) */
|
||||
OBS_BOUNDS_SCALE_INNER, /**< scales to inner rectangle */
|
||||
OBS_BOUNDS_SCALE_OUTER, /**< scales to outer rectangle */
|
||||
OBS_BOUNDS_SCALE_TO_WIDTH, /**< scales to the width */
|
||||
OBS_BOUNDS_SCALE_TO_HEIGHT, /**< scales to the height */
|
||||
OBS_BOUNDS_STRETCH /**< stretch (ignores base scale) */
|
||||
OBS_BOUNDS_MAX_ONLY, /**< no scaling, maximum size only */
|
||||
};
|
||||
|
||||
struct obs_sceneitem_info {
|
||||
|
|
|
@ -57,6 +57,8 @@ set(obs_SOURCES
|
|||
window-basic-settings.cpp
|
||||
window-basic-properties.cpp
|
||||
window-basic-source-select.cpp
|
||||
window-basic-transform.cpp
|
||||
window-basic-preview.cpp
|
||||
window-namedialog.cpp
|
||||
window-log-reply.cpp
|
||||
properties-view.cpp
|
||||
|
@ -71,6 +73,8 @@ set(obs_HEADERS
|
|||
window-basic-settings.hpp
|
||||
window-basic-properties.hpp
|
||||
window-basic-source-select.hpp
|
||||
window-basic-transform.hpp
|
||||
window-basic-preview.hpp
|
||||
window-namedialog.hpp
|
||||
window-log-reply.hpp
|
||||
properties-view.hpp
|
||||
|
@ -83,6 +87,7 @@ set(obs_UI
|
|||
forms/NameDialog.ui
|
||||
forms/OBSLogReply.ui
|
||||
forms/OBSBasic.ui
|
||||
forms/OBSBasicTransform.ui
|
||||
forms/OBSBasicSettings.ui
|
||||
forms/OBSBasicSourceSelect.ui
|
||||
forms/OBSBasicProperties.ui)
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="OBSQTDisplay" name="preview" native="true">
|
||||
<widget class="OBSBasicPreview" name="preview" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -305,7 +305,7 @@
|
|||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Volume</string>
|
||||
<string>Mixer</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -463,7 +463,35 @@
|
|||
</widget>
|
||||
<addaction name="menuLogFiles"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuBasic_MainMenu_Edit">
|
||||
<property name="title">
|
||||
<string>Basic.MainMenu.Edit</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuBasic_MainMenu_Edit_Transform">
|
||||
<property name="title">
|
||||
<string>Basic.MainMenu.Edit.Transform</string>
|
||||
</property>
|
||||
<addaction name="actionEditTransform"/>
|
||||
<addaction name="actionResetTransform"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionRotate90CW"/>
|
||||
<addaction name="actionRotate90CCW"/>
|
||||
<addaction name="actionRotate180"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionFlipHorizontal"/>
|
||||
<addaction name="actionFlipVertical"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionFitToScreen"/>
|
||||
<addaction name="actionStretchToScreen"/>
|
||||
<addaction name="actionCenterToScreen"/>
|
||||
</widget>
|
||||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="menuBasic_MainMenu_Edit_Transform"/>
|
||||
</widget>
|
||||
<addaction name="menu_File"/>
|
||||
<addaction name="menuBasic_MainMenu_Edit"/>
|
||||
<addaction name="menuBasic_MainMenu_Help"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
|
@ -610,12 +638,90 @@
|
|||
<string>Basic.MainMenu.Help.Logs.UploadCurrentLog</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUndo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Undo</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRedo">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Redo</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEditTransform">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.EditTransform</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRotate90CW">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.Rotate90CW</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRotate90CCW">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.Rotate90CCW</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRotate180">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.Rotate180</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFitToScreen">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.FitToScreen</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+F</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStretchToScreen">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.StretchToScreen</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResetTransform">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.ResetTransform</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCenterToScreen">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.CenterToScreen</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+C</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFlipHorizontal">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.FlipHorizontal</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFlipVertical">
|
||||
<property name="text">
|
||||
<string>Basic.MainMenu.Edit.Transform.FlipVertical</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>OBSQTDisplay</class>
|
||||
<class>OBSBasicPreview</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qt-display.hpp</header>
|
||||
<header>window-basic-preview.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
|
|
462
obs/forms/OBSBasicTransform.ui
Normal file
462
obs/forms/OBSBasicTransform.ui
Normal file
|
@ -0,0 +1,462 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>OBSBasicTransform</class>
|
||||
<widget class="QDialog" name="OBSBasicTransform">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>564</width>
|
||||
<height>241</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Basic.TransformWindow</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="fieldGrowthPolicy">
|
||||
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
|
||||
</property>
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>170</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Position</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="positionX">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-9001.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9001.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="positionY">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-9001.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9001.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Rotation</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QDoubleSpinBox" name="rotation">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-360.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>360.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.100000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Scale</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QWidget" name="widget_2" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="scaleX">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-9001.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9001.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="scaleY">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>-9001.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9001.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.010000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="align">
|
||||
<property name="currentText">
|
||||
<string>Basic.TransformWindow.Alignment.TopLeft</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.TopLeft</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.TopCenter</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.TopRight</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.CenterLeft</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.Center</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.CenterRight</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.BottomLeft</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.BottomCenter</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.BottomRight</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="boundsType">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType.None</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType.Stretch</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType.ScaleInner</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType.ScaleOuter</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType.ScaleToWidth</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType.ScaleToHeight</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsType.MaxOnly</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.BoundsAlignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Bounds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QWidget" name="widget_3" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="boundsWidth">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9001.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="boundsHeight">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<double>9001.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="boundsAlign">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string>Basic.TransformWindow.Alignment.TopLeft</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.TopLeft</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.TopCenter</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.TopRight</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.CenterLeft</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.Center</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.CenterRight</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.BottomLeft</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.BottomCenter</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Basic.TransformWindow.Alignment.BottomRight</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -26,6 +26,7 @@
|
|||
#include <util/dstr.h>
|
||||
#include <util/util.hpp>
|
||||
#include <util/platform.h>
|
||||
#include <graphics/math-defs.h>
|
||||
|
||||
#include "obs-app.hpp"
|
||||
#include "platform.hpp"
|
||||
|
@ -55,15 +56,6 @@ Q_DECLARE_METATYPE(order_movement);
|
|||
|
||||
OBSBasic::OBSBasic(QWidget *parent)
|
||||
: OBSMainWindow (parent),
|
||||
properties (nullptr),
|
||||
fileOutput (nullptr),
|
||||
streamOutput (nullptr),
|
||||
service (nullptr),
|
||||
aac (nullptr),
|
||||
x264 (nullptr),
|
||||
sceneChanging (false),
|
||||
resizeTimer (0),
|
||||
activeRefs (0),
|
||||
ui (new Ui::OBSBasic)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
@ -444,6 +436,28 @@ void OBSBasic::InitOBSCallbacks()
|
|||
OBSBasic::SourceDeactivated, this);
|
||||
}
|
||||
|
||||
void OBSBasic::InitPrimitives()
|
||||
{
|
||||
gs_entercontext(obs_graphics());
|
||||
|
||||
gs_renderstart(true);
|
||||
gs_vertex2f(0.0f, 0.0f);
|
||||
gs_vertex2f(0.0f, 1.0f);
|
||||
gs_vertex2f(1.0f, 1.0f);
|
||||
gs_vertex2f(1.0f, 0.0f);
|
||||
gs_vertex2f(0.0f, 0.0f);
|
||||
box = gs_rendersave();
|
||||
|
||||
gs_renderstart(true);
|
||||
for (int i = 0; i <= 360; i += (360/20)) {
|
||||
float pos = RAD(float(i));
|
||||
gs_vertex2f(cosf(pos), sinf(pos));
|
||||
}
|
||||
circle = gs_rendersave();
|
||||
|
||||
gs_leavecontext();
|
||||
}
|
||||
|
||||
void OBSBasic::OBSInit()
|
||||
{
|
||||
BPtr<char> savePath(os_get_config_path("obs-studio/basic/scenes.json"));
|
||||
|
@ -491,6 +505,8 @@ void OBSBasic::OBSInit()
|
|||
if (!InitService())
|
||||
throw "Failed to initialize service";
|
||||
|
||||
InitPrimitives();
|
||||
|
||||
Load(savePath);
|
||||
ResetAudioDevices();
|
||||
}
|
||||
|
@ -501,14 +517,26 @@ OBSBasic::~OBSBasic()
|
|||
SaveService();
|
||||
Save(savePath);
|
||||
|
||||
/* XXX: any obs data must be released before calling obs_shutdown.
|
||||
* currently, we can't automate this with C++ RAII because of the
|
||||
* delicate nature of obs_shutdown needing to be freed before the UI
|
||||
* can be freed, and we have no control over the destruction order of
|
||||
* the Qt UI stuff, so we have to manually clear any references to
|
||||
* libobs. */
|
||||
if (properties)
|
||||
delete properties;
|
||||
if (transformWindow)
|
||||
delete transformWindow;
|
||||
|
||||
/* free the lists before shutting down to remove the scene/item
|
||||
* references */
|
||||
ClearVolumeControls();
|
||||
ui->sources->clear();
|
||||
ui->scenes->clear();
|
||||
|
||||
gs_entercontext(obs_graphics());
|
||||
vertexbuffer_destroy(box);
|
||||
vertexbuffer_destroy(circle);
|
||||
gs_leavecontext();
|
||||
|
||||
obs_shutdown();
|
||||
}
|
||||
|
||||
|
@ -792,21 +820,26 @@ void OBSBasic::RenderMain(void *data, uint32_t cx, uint32_t cy)
|
|||
{
|
||||
OBSBasic *window = static_cast<OBSBasic*>(data);
|
||||
obs_video_info ovi;
|
||||
int newCX, newCY;
|
||||
|
||||
obs_get_video_info(&ovi);
|
||||
|
||||
newCX = int(window->previewScale * float(ovi.base_width));
|
||||
newCY = int(window->previewScale * float(ovi.base_height));
|
||||
window->previewCX = int(window->previewScale * float(ovi.base_width));
|
||||
window->previewCY = int(window->previewScale * float(ovi.base_height));
|
||||
|
||||
gs_viewport_push();
|
||||
gs_projection_push();
|
||||
gs_ortho(0.0f, float(ovi.base_width), 0.0f, float(ovi.base_height),
|
||||
-100.0f, 100.0f);
|
||||
gs_setviewport(window->previewX, window->previewY, newCX, newCY);
|
||||
gs_setviewport(window->previewX, window->previewY,
|
||||
window->previewCX, window->previewCY);
|
||||
|
||||
obs_render_main_view();
|
||||
|
||||
gs_ortho(0.0f, float(window->previewCX), 0.0f, float(window->previewCY),
|
||||
-100.0f, 100.0f);
|
||||
|
||||
window->ui->preview->DrawSceneEditing();
|
||||
|
||||
gs_projection_pop();
|
||||
gs_viewport_pop();
|
||||
|
||||
|
@ -1155,8 +1188,23 @@ void OBSBasic::on_actionSceneDown_triggered()
|
|||
void OBSBasic::on_sources_currentItemChanged(QListWidgetItem *current,
|
||||
QListWidgetItem *prev)
|
||||
{
|
||||
/* TODO */
|
||||
UNUSED_PARAMETER(current);
|
||||
auto select_one = [] (obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
obs_sceneitem_t selectedItem =
|
||||
*reinterpret_cast<OBSSceneItem*>(param);
|
||||
obs_sceneitem_select(item, (selectedItem == item));
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!current)
|
||||
return;
|
||||
|
||||
OBSSceneItem item = current->data(Qt::UserRole).value<OBSSceneItem>();
|
||||
obs_scene_enum_items(GetCurrentScene(), select_one, &item);
|
||||
|
||||
UNUSED_PARAMETER(prev);
|
||||
}
|
||||
|
||||
|
@ -1569,3 +1617,192 @@ config_t OBSBasic::Config() const
|
|||
{
|
||||
return basicConfig;
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionEditTransform_triggered()
|
||||
{
|
||||
delete transformWindow;
|
||||
transformWindow = new OBSBasicTransform(this);
|
||||
transformWindow->show();
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionResetTransform_triggered()
|
||||
{
|
||||
auto func = [] (obs_scene_t scene, obs_sceneitem_t item, void *param)
|
||||
{
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
obs_sceneitem_info info;
|
||||
vec2_set(&info.pos, 0.0f, 0.0f);
|
||||
vec2_set(&info.scale, 1.0f, 1.0f);
|
||||
info.rot = 0.0f;
|
||||
info.alignment = OBS_ALIGN_TOP | OBS_ALIGN_LEFT;
|
||||
info.bounds_type = OBS_BOUNDS_NONE;
|
||||
info.bounds_alignment = OBS_ALIGN_CENTER;
|
||||
vec2_set(&info.bounds, 0.0f, 0.0f);
|
||||
obs_sceneitem_set_info(item, &info);
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
UNUSED_PARAMETER(param);
|
||||
return true;
|
||||
};
|
||||
|
||||
obs_scene_enum_items(GetCurrentScene(), func, nullptr);
|
||||
}
|
||||
|
||||
static vec3 GetItemTL(obs_sceneitem_t item)
|
||||
{
|
||||
matrix4 boxTransform;
|
||||
obs_sceneitem_get_box_transform(item, &boxTransform);
|
||||
|
||||
vec3 tl;
|
||||
vec3_set(&tl, M_INFINITE, M_INFINITE, 0.0f);
|
||||
|
||||
auto GetMinPos = [&] (vec3 &val, float x, float y)
|
||||
{
|
||||
vec3 pos;
|
||||
vec3_set(&pos, x, y, 0.0f);
|
||||
vec3_transform(&pos, &pos, &boxTransform);
|
||||
vec3_min(&val, &val, &pos);
|
||||
};
|
||||
|
||||
GetMinPos(tl, 0.0f, 0.0f);
|
||||
GetMinPos(tl, 1.0f, 0.0f);
|
||||
GetMinPos(tl, 0.0f, 1.0f);
|
||||
GetMinPos(tl, 1.0f, 1.0f);
|
||||
return tl;
|
||||
}
|
||||
|
||||
static void SetItemTL(obs_sceneitem_t item, const vec3 &tl)
|
||||
{
|
||||
vec3 newTL;
|
||||
vec2 pos;
|
||||
|
||||
obs_sceneitem_getpos(item, &pos);
|
||||
newTL = GetItemTL(item);
|
||||
pos.x += tl.x - newTL.x;
|
||||
pos.y += tl.y - newTL.y;
|
||||
obs_sceneitem_setpos(item, &pos);
|
||||
}
|
||||
|
||||
static bool RotateSelectedSources(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
float rot = *reinterpret_cast<float*>(param);
|
||||
|
||||
vec3 tl = GetItemTL(item);
|
||||
|
||||
rot += obs_sceneitem_getrot(item);
|
||||
if (rot >= 360.0f) rot -= 360.0f;
|
||||
else if (rot <= -360.0f) rot += 360.0f;
|
||||
obs_sceneitem_setrot(item, rot);
|
||||
|
||||
SetItemTL(item, tl);
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
UNUSED_PARAMETER(param);
|
||||
return true;
|
||||
};
|
||||
|
||||
void OBSBasic::on_actionRotate90CW_triggered()
|
||||
{
|
||||
float f90CW = 90.0f;
|
||||
obs_scene_enum_items(GetCurrentScene(), RotateSelectedSources, &f90CW);
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionRotate90CCW_triggered()
|
||||
{
|
||||
float f90CCW = -90.0f;
|
||||
obs_scene_enum_items(GetCurrentScene(), RotateSelectedSources, &f90CCW);
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionRotate180_triggered()
|
||||
{
|
||||
float f180 = 180.0f;
|
||||
obs_scene_enum_items(GetCurrentScene(), RotateSelectedSources, &f180);
|
||||
}
|
||||
|
||||
static bool MultiplySelectedItemScale(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
vec2 &mul = *reinterpret_cast<vec2*>(param);
|
||||
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
vec3 tl = GetItemTL(item);
|
||||
|
||||
vec2 scale;
|
||||
obs_sceneitem_getscale(item, &scale);
|
||||
vec2_mul(&scale, &scale, &mul);
|
||||
obs_sceneitem_setscale(item, &scale);
|
||||
|
||||
SetItemTL(item, tl);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionFlipHorizontal_triggered()
|
||||
{
|
||||
vec2 scale = {-1.0f, 1.0f};
|
||||
obs_scene_enum_items(GetCurrentScene(), MultiplySelectedItemScale,
|
||||
&scale);
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionFlipVertical_triggered()
|
||||
{
|
||||
vec2 scale = {1.0f, -1.0f};
|
||||
obs_scene_enum_items(GetCurrentScene(), MultiplySelectedItemScale,
|
||||
&scale);
|
||||
}
|
||||
|
||||
static bool CenterAlignSelectedItems(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
obs_bounds_type boundsType = *reinterpret_cast<obs_bounds_type*>(param);
|
||||
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
obs_video_info ovi;
|
||||
obs_get_video_info(&ovi);
|
||||
|
||||
obs_sceneitem_info itemInfo;
|
||||
vec2_set(&itemInfo.pos, 0.0f, 0.0f);
|
||||
vec2_set(&itemInfo.scale, 1.0f, 1.0f);
|
||||
itemInfo.alignment = OBS_ALIGN_LEFT | OBS_ALIGN_TOP;
|
||||
itemInfo.rot = 0.0f;
|
||||
|
||||
vec2_set(&itemInfo.bounds,
|
||||
float(ovi.base_width), float(ovi.base_height));
|
||||
itemInfo.bounds_type = boundsType;
|
||||
itemInfo.bounds_alignment = OBS_ALIGN_CENTER;
|
||||
|
||||
obs_sceneitem_set_info(item, &itemInfo);
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionFitToScreen_triggered()
|
||||
{
|
||||
obs_bounds_type boundsType = OBS_BOUNDS_SCALE_INNER;
|
||||
obs_scene_enum_items(GetCurrentScene(), CenterAlignSelectedItems,
|
||||
&boundsType);
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionStretchToScreen_triggered()
|
||||
{
|
||||
obs_bounds_type boundsType = OBS_BOUNDS_STRETCH;
|
||||
obs_scene_enum_items(GetCurrentScene(), CenterAlignSelectedItems,
|
||||
&boundsType);
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionCenterToScreen_triggered()
|
||||
{
|
||||
obs_bounds_type boundsType = OBS_BOUNDS_MAX_ONLY;
|
||||
obs_scene_enum_items(GetCurrentScene(), CenterAlignSelectedItems,
|
||||
&boundsType);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <memory>
|
||||
#include "window-main.hpp"
|
||||
#include "window-basic-properties.hpp"
|
||||
#include "window-basic-transform.hpp"
|
||||
|
||||
#include <util/util.hpp>
|
||||
|
||||
|
@ -45,34 +46,41 @@ class QNetworkReply;
|
|||
class OBSBasic : public OBSMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
friend class OBSBasicPreview;
|
||||
|
||||
private:
|
||||
std::unordered_map<obs_source_t, int> sourceSceneRefs;
|
||||
|
||||
std::vector<VolControl*> volumes;
|
||||
|
||||
QPointer<OBSBasicProperties> properties;
|
||||
QPointer<OBSBasicTransform> transformWindow;
|
||||
|
||||
QNetworkAccessManager networkManager;
|
||||
|
||||
QBuffer logUploadPostData;
|
||||
QNetworkReply *logUploadReply;
|
||||
QNetworkReply *logUploadReply = nullptr;
|
||||
QByteArray logUploadReturnData;
|
||||
|
||||
obs_output_t fileOutput;
|
||||
obs_output_t streamOutput;
|
||||
obs_service_t service;
|
||||
obs_encoder_t aac;
|
||||
obs_encoder_t x264;
|
||||
obs_output_t fileOutput = nullptr;
|
||||
obs_output_t streamOutput = nullptr;
|
||||
obs_service_t service = nullptr;
|
||||
obs_encoder_t aac = nullptr;
|
||||
obs_encoder_t x264 = nullptr;
|
||||
|
||||
bool sceneChanging;
|
||||
vertbuffer_t box = nullptr;
|
||||
vertbuffer_t circle = nullptr;
|
||||
|
||||
int previewX, previewY;
|
||||
float previewScale;
|
||||
int resizeTimer;
|
||||
bool sceneChanging = false;
|
||||
|
||||
int previewX = 0, previewY = 0;
|
||||
int previewCX = 0, previewCY = 0;
|
||||
float previewScale = 0.0f;
|
||||
int resizeTimer = 0;
|
||||
|
||||
ConfigFile basicConfig;
|
||||
|
||||
int activeRefs;
|
||||
int activeRefs = 0;
|
||||
|
||||
void SetupEncoders();
|
||||
|
||||
|
@ -97,7 +105,8 @@ private:
|
|||
|
||||
void InitOBSCallbacks();
|
||||
|
||||
OBSScene GetCurrentScene();
|
||||
void InitPrimitives();
|
||||
|
||||
OBSSceneItem GetCurrentSceneItem();
|
||||
|
||||
void GetFPSCommon(uint32_t &num, uint32_t &den) const;
|
||||
|
@ -153,6 +162,8 @@ private:
|
|||
void AddSourcePopupMenu(const QPoint &pos);
|
||||
|
||||
public:
|
||||
OBSScene GetCurrentScene();
|
||||
|
||||
obs_service_t GetService();
|
||||
void SetService(obs_service_t service);
|
||||
|
||||
|
@ -167,6 +178,14 @@ public:
|
|||
void SaveProject();
|
||||
void LoadProject();
|
||||
|
||||
inline void GetDisplayRect(int &x, int &y, int &cx, int &cy)
|
||||
{
|
||||
x = previewX;
|
||||
y = previewY;
|
||||
cx = previewCX;
|
||||
cy = previewCY;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent *event) override;
|
||||
virtual void changeEvent(QEvent *event) override;
|
||||
|
@ -178,6 +197,20 @@ private slots:
|
|||
void on_action_Open_triggered();
|
||||
void on_action_Save_triggered();
|
||||
void on_action_Settings_triggered();
|
||||
void on_actionUploadCurrentLog_triggered();
|
||||
void on_actionUploadLastLog_triggered();
|
||||
|
||||
void on_actionEditTransform_triggered();
|
||||
void on_actionResetTransform_triggered();
|
||||
void on_actionRotate90CW_triggered();
|
||||
void on_actionRotate90CCW_triggered();
|
||||
void on_actionRotate180_triggered();
|
||||
void on_actionFlipHorizontal_triggered();
|
||||
void on_actionFlipVertical_triggered();
|
||||
void on_actionFitToScreen_triggered();
|
||||
void on_actionStretchToScreen_triggered();
|
||||
void on_actionCenterToScreen_triggered();
|
||||
|
||||
void on_scenes_currentItemChanged(QListWidgetItem *current,
|
||||
QListWidgetItem *prev);
|
||||
void on_scenes_customContextMenuRequested(const QPoint &pos);
|
||||
|
@ -194,8 +227,7 @@ private slots:
|
|||
void on_actionSourceProperties_triggered();
|
||||
void on_actionSourceUp_triggered();
|
||||
void on_actionSourceDown_triggered();
|
||||
void on_actionUploadCurrentLog_triggered();
|
||||
void on_actionUploadLastLog_triggered();
|
||||
|
||||
void on_streamButton_clicked();
|
||||
void on_recordButton_clicked();
|
||||
void on_settingsButton_clicked();
|
||||
|
|
718
obs/window-basic-preview.cpp
Normal file
718
obs/window-basic-preview.cpp
Normal file
|
@ -0,0 +1,718 @@
|
|||
#include <QGuiApplication>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include <cmath>
|
||||
#include <graphics/vec4.h>
|
||||
#include <graphics/matrix4.h>
|
||||
#include "window-basic-preview.hpp"
|
||||
#include "window-basic-main.hpp"
|
||||
#include "obs-app.hpp"
|
||||
|
||||
#define HANDLE_RADIUS 4.0f
|
||||
#define HANDLE_SEL_RADIUS (HANDLE_RADIUS * 1.5f)
|
||||
#define CLAMP_DISTANCE 10.0f
|
||||
|
||||
/* TODO: make C++ math classes and clean up code here later */
|
||||
|
||||
OBSBasicPreview::OBSBasicPreview(QWidget *parent, Qt::WindowFlags flags)
|
||||
: OBSQTDisplay(parent, flags)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
vec2 OBSBasicPreview::GetMouseEventPos(QMouseEvent *event)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
vec2 pos = {
|
||||
(float(event->x()) - main->previewX) / main->previewScale,
|
||||
(float(event->y()) - main->previewY) / main->previewScale
|
||||
};
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
struct SceneFindData {
|
||||
const vec2 &pos;
|
||||
OBSSceneItem item;
|
||||
bool selectBelow;
|
||||
|
||||
inline SceneFindData(const vec2 &pos_, bool selectBelow_)
|
||||
: pos (pos_),
|
||||
selectBelow (selectBelow_)
|
||||
{}
|
||||
};
|
||||
|
||||
static bool FindItemAtPos(obs_scene_t scene, obs_sceneitem_t item, void *param)
|
||||
{
|
||||
SceneFindData *data = reinterpret_cast<SceneFindData*>(param);
|
||||
matrix4 transform;
|
||||
vec3 transformedPos;
|
||||
vec3 pos3 = {data->pos.x, data->pos.y, 0.0f};
|
||||
|
||||
obs_sceneitem_get_box_transform(item, &transform);
|
||||
|
||||
matrix4_inv(&transform, &transform);
|
||||
vec3_transform(&transformedPos, &pos3, &transform);
|
||||
|
||||
if (transformedPos.x >= 0.0f && transformedPos.x <= 1.0f &&
|
||||
transformedPos.y >= 0.0f && transformedPos.y <= 1.0f) {
|
||||
if (data->selectBelow && obs_sceneitem_selected(item)) {
|
||||
if (data->item)
|
||||
return false;
|
||||
else
|
||||
data->selectBelow = false;
|
||||
}
|
||||
|
||||
data->item = item;
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
static vec3 GetTransformedPos(float x, float y, const matrix4 &mat)
|
||||
{
|
||||
vec3 result;
|
||||
vec3_set(&result, x, y, 0.0f);
|
||||
vec3_transform(&result, &result, &mat);
|
||||
return result;
|
||||
}
|
||||
|
||||
static vec3 GetTransformedPosScaled(float x, float y, const matrix4 &mat,
|
||||
float scale)
|
||||
{
|
||||
vec3 result;
|
||||
vec3_set(&result, x, y, 0.0f);
|
||||
vec3_transform(&result, &result, &mat);
|
||||
vec3_mulf(&result, &result, scale);
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline vec2 GetOBSScreenSize()
|
||||
{
|
||||
obs_video_info ovi;
|
||||
vec2 size = {0.0f, 0.0f};
|
||||
|
||||
if (obs_get_video_info(&ovi)) {
|
||||
size.x = float(ovi.base_width);
|
||||
size.y = float(ovi.base_height);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
vec3 OBSBasicPreview::GetScreenSnapOffset(const vec3 &tl, const vec3 &br)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
vec2 screenSize = GetOBSScreenSize();
|
||||
vec3 clampOffset;
|
||||
|
||||
vec3_zero(&clampOffset);
|
||||
|
||||
const float clampDist = CLAMP_DISTANCE / main->previewScale;
|
||||
|
||||
if (fabsf(tl.x) < clampDist)
|
||||
clampOffset.x = -tl.x;
|
||||
if (fabsf(clampOffset.x) < EPSILON &&
|
||||
fabsf(screenSize.x - br.x) < clampDist)
|
||||
clampOffset.x = screenSize.x - br.x;
|
||||
|
||||
if (fabsf(tl.y) < clampDist)
|
||||
clampOffset.y = -tl.y;
|
||||
if (fabsf(clampOffset.y) < EPSILON &&
|
||||
fabsf(screenSize.y - br.y) < clampDist)
|
||||
clampOffset.y = screenSize.y - br.y;
|
||||
|
||||
return clampOffset;
|
||||
}
|
||||
|
||||
OBSSceneItem OBSBasicPreview::GetItemAtPos(const vec2 &pos, bool selectBelow)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (!scene)
|
||||
return OBSSceneItem();
|
||||
|
||||
SceneFindData data(pos, selectBelow);
|
||||
obs_scene_enum_items(scene, FindItemAtPos, &data);
|
||||
return data.item;
|
||||
}
|
||||
|
||||
static bool CheckItemSelected(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
SceneFindData *data = reinterpret_cast<SceneFindData*>(param);
|
||||
matrix4 transform;
|
||||
vec3 transformedPos;
|
||||
vec3 pos3 = {data->pos.x, data->pos.y, 0.0f};
|
||||
|
||||
obs_sceneitem_get_box_transform(item, &transform);
|
||||
|
||||
matrix4_inv(&transform, &transform);
|
||||
vec3_transform(&transformedPos, &pos3, &transform);
|
||||
|
||||
if (transformedPos.x >= 0.0f && transformedPos.x <= 1.0f &&
|
||||
transformedPos.y >= 0.0f && transformedPos.y <= 1.0f) {
|
||||
if (obs_sceneitem_selected(item)) {
|
||||
data->item = item;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OBSBasicPreview::SelectedAtPos(const vec2 &pos)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (!scene)
|
||||
return false;
|
||||
|
||||
SceneFindData data(pos, false);
|
||||
obs_scene_enum_items(scene, CheckItemSelected, &data);
|
||||
return !!data.item;
|
||||
}
|
||||
|
||||
struct HandleFindData {
|
||||
const vec2 &pos;
|
||||
const float scale;
|
||||
|
||||
OBSSceneItem item;
|
||||
ItemHandle handle = ItemHandle::None;
|
||||
|
||||
inline HandleFindData(const vec2 &pos_, float scale_)
|
||||
: pos (pos_),
|
||||
scale (scale_)
|
||||
{}
|
||||
};
|
||||
|
||||
static bool FindHandleAtPos(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
HandleFindData *data = reinterpret_cast<HandleFindData*>(param);
|
||||
matrix4 transform;
|
||||
vec3 pos3 = {data->pos.x, data->pos.y, 0.0f};
|
||||
float closestHandle = HANDLE_SEL_RADIUS;
|
||||
|
||||
obs_sceneitem_get_box_transform(item, &transform);
|
||||
|
||||
auto TestHandle = [&] (float x, float y, ItemHandle handle)
|
||||
{
|
||||
vec3 handlePos = GetTransformedPosScaled(x, y, transform,
|
||||
data->scale);
|
||||
|
||||
float dist = vec3_dist(&handlePos, &pos3);
|
||||
if (dist < HANDLE_SEL_RADIUS) {
|
||||
if (dist < closestHandle) {
|
||||
closestHandle = dist;
|
||||
data->handle = handle;
|
||||
data->item = item;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TestHandle(0.0f, 0.0f, ItemHandle::TopLeft);
|
||||
TestHandle(0.5f, 0.0f, ItemHandle::TopCenter);
|
||||
TestHandle(1.0f, 0.0f, ItemHandle::TopRight);
|
||||
TestHandle(0.0f, 0.5f, ItemHandle::CenterLeft);
|
||||
TestHandle(1.0f, 0.5f, ItemHandle::CenterRight);
|
||||
TestHandle(0.0f, 1.0f, ItemHandle::BottomLeft);
|
||||
TestHandle(0.5f, 1.0f, ItemHandle::BottomCenter);
|
||||
TestHandle(1.0f, 1.0f, ItemHandle::BottomRight);
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
static vec2 GetItemSize(obs_sceneitem_t item)
|
||||
{
|
||||
obs_bounds_type boundsType = obs_sceneitem_get_bounds_type(item);
|
||||
vec2 size;
|
||||
|
||||
if (boundsType != OBS_BOUNDS_NONE) {
|
||||
obs_sceneitem_get_bounds(item, &size);
|
||||
} else {
|
||||
obs_source_t source = obs_sceneitem_getsource(item);
|
||||
vec2 scale;
|
||||
|
||||
obs_sceneitem_getscale(item, &scale);
|
||||
size.x = float(obs_source_getwidth(source)) * scale.x;
|
||||
size.y = float(obs_source_getheight(source)) * scale.y;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (!scene)
|
||||
return;
|
||||
|
||||
HandleFindData data(pos, main->previewScale);
|
||||
obs_scene_enum_items(scene, FindHandleAtPos, &data);
|
||||
|
||||
stretchItem = std::move(data.item);
|
||||
stretchHandle = data.handle;
|
||||
|
||||
if (stretchHandle != ItemHandle::None) {
|
||||
matrix4 boxTransform;
|
||||
vec3 itemUL;
|
||||
float itemRot;
|
||||
|
||||
stretchItemSize = GetItemSize(stretchItem);
|
||||
|
||||
obs_sceneitem_get_box_transform(stretchItem, &boxTransform);
|
||||
itemRot = obs_sceneitem_getrot(stretchItem);
|
||||
vec3_from_vec4(&itemUL, &boxTransform.t);
|
||||
|
||||
/* build the item space conversion matrices */
|
||||
matrix4_identity(&itemToScreen);
|
||||
matrix4_rotate_aa4f(&itemToScreen, &itemToScreen,
|
||||
0.0f, 0.0f, 1.0f, RAD(itemRot));
|
||||
matrix4_translate3f(&itemToScreen, &itemToScreen,
|
||||
itemUL.x, itemUL.y, 0.0f);
|
||||
|
||||
matrix4_identity(&screenToItem);
|
||||
matrix4_translate3f(&screenToItem, &screenToItem,
|
||||
-itemUL.x, -itemUL.y, 0.0f);
|
||||
matrix4_rotate_aa4f(&screenToItem, &screenToItem,
|
||||
0.0f, 0.0f, 1.0f, RAD(-itemRot));
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
float x = float(event->x()) - main->previewX;
|
||||
float y = float(event->y()) - main->previewY;
|
||||
|
||||
if (event->button() != Qt::LeftButton ||
|
||||
x < 0.0f || y < 0.0f || x > main->previewCX || y > main->previewCY)
|
||||
return;
|
||||
|
||||
mouseDown = true;
|
||||
|
||||
vec2_set(&startPos, x, y);
|
||||
GetStretchHandleData(startPos);
|
||||
|
||||
vec2_divf(&startPos, &startPos, main->previewScale);
|
||||
startPos.x = std::round(startPos.x);
|
||||
startPos.y = std::round(startPos.y);
|
||||
|
||||
mouseOverItems = SelectedAtPos(startPos);
|
||||
vec2_zero(&lastMoveOffset);
|
||||
}
|
||||
|
||||
static bool select_one(obs_scene_t scene, obs_sceneitem_t item, void *param)
|
||||
{
|
||||
obs_sceneitem_t selectedItem = reinterpret_cast<obs_sceneitem_t>(param);
|
||||
obs_sceneitem_select(item, (selectedItem == item));
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::DoSelect(const vec2 &pos)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
OBSSceneItem item = GetItemAtPos(pos, true);
|
||||
|
||||
obs_scene_enum_items(scene, select_one, (obs_sceneitem_t)item);
|
||||
}
|
||||
|
||||
void OBSBasicPreview::DoCtrlSelect(const vec2 &pos)
|
||||
{
|
||||
OBSSceneItem item = GetItemAtPos(pos, false);
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
bool selected = obs_sceneitem_selected(item);
|
||||
obs_sceneitem_select(item, !selected);
|
||||
}
|
||||
|
||||
void OBSBasicPreview::ProcessClick(const vec2 &pos)
|
||||
{
|
||||
Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
|
||||
|
||||
if (modifiers & Qt::ControlModifier)
|
||||
DoCtrlSelect(pos);
|
||||
else
|
||||
DoSelect(pos);
|
||||
}
|
||||
|
||||
void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (mouseDown) {
|
||||
vec2 pos = GetMouseEventPos(event);
|
||||
|
||||
if (!mouseMoved)
|
||||
ProcessClick(pos);
|
||||
|
||||
stretchItem = nullptr;
|
||||
mouseDown = false;
|
||||
mouseMoved = false;
|
||||
}
|
||||
}
|
||||
|
||||
struct SelectedItemBounds {
|
||||
bool first = true;
|
||||
vec3 tl, br;
|
||||
};
|
||||
|
||||
static bool AddItemBounds(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
SelectedItemBounds *data = reinterpret_cast<SelectedItemBounds*>(param);
|
||||
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
matrix4 boxTransform;
|
||||
obs_sceneitem_get_box_transform(item, &boxTransform);
|
||||
|
||||
vec3 t[4] = {
|
||||
GetTransformedPos(0.0f, 0.0f, boxTransform),
|
||||
GetTransformedPos(1.0f, 0.0f, boxTransform),
|
||||
GetTransformedPos(0.0f, 1.0f, boxTransform),
|
||||
GetTransformedPos(1.0f, 1.0f, boxTransform)
|
||||
};
|
||||
|
||||
for (const vec3 &v : t) {
|
||||
if (data->first) {
|
||||
vec3_copy(&data->tl, &v);
|
||||
vec3_copy(&data->br, &v);
|
||||
data->first = false;
|
||||
} else {
|
||||
vec3_min(&data->tl, &data->tl, &v);
|
||||
vec3_max(&data->br, &data->br, &v);
|
||||
}
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::SnapItemMovement(vec2 &offset)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
|
||||
SelectedItemBounds data;
|
||||
obs_scene_enum_items(scene, AddItemBounds, &data);
|
||||
|
||||
data.tl.x += offset.x;
|
||||
data.tl.y += offset.y;
|
||||
data.br.x += offset.x;
|
||||
data.br.y += offset.y;
|
||||
|
||||
vec3 snapOffset = GetScreenSnapOffset(data.tl, data.br);
|
||||
offset.x += snapOffset.x;
|
||||
offset.y += snapOffset.y;
|
||||
}
|
||||
|
||||
static bool move_items(obs_scene_t scene, obs_sceneitem_t item, void *param)
|
||||
{
|
||||
vec2 *offset = reinterpret_cast<vec2*>(param);
|
||||
|
||||
if (obs_sceneitem_selected(item)) {
|
||||
vec2 pos;
|
||||
obs_sceneitem_getpos(item, &pos);
|
||||
vec2_add(&pos, &pos, offset);
|
||||
obs_sceneitem_setpos(item, &pos);
|
||||
}
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::MoveItems(const vec2 &pos)
|
||||
{
|
||||
Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
|
||||
vec2 offset, moveOffset;
|
||||
vec2_sub(&offset, &pos, &startPos);
|
||||
vec2_sub(&moveOffset, &offset, &lastMoveOffset);
|
||||
|
||||
if (!(modifiers & Qt::ControlModifier))
|
||||
SnapItemMovement(moveOffset);
|
||||
|
||||
vec2_add(&lastMoveOffset, &lastMoveOffset, &moveOffset);
|
||||
|
||||
obs_scene_enum_items(scene, move_items, &moveOffset);
|
||||
}
|
||||
|
||||
vec3 OBSBasicPreview::CalculateStretchPos(const vec3 &tl, const vec3 &br)
|
||||
{
|
||||
uint32_t alignment = obs_sceneitem_getalignment(stretchItem);
|
||||
vec3 pos;
|
||||
|
||||
vec3_zero(&pos);
|
||||
|
||||
if (alignment & OBS_ALIGN_LEFT)
|
||||
pos.x = tl.x;
|
||||
else if (alignment & OBS_ALIGN_RIGHT)
|
||||
pos.x = br.x;
|
||||
else
|
||||
pos.x = (br.x - tl.x) * 0.5f + tl.x;
|
||||
|
||||
if (alignment & OBS_ALIGN_TOP)
|
||||
pos.y = tl.y;
|
||||
else if (alignment & OBS_ALIGN_BOTTOM)
|
||||
pos.y = br.y;
|
||||
else
|
||||
pos.y = (br.y - tl.y) * 0.5f + tl.y;
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::ClampAspect(vec3 &tl, vec3 &br, vec2 &size,
|
||||
const vec2 &baseSize)
|
||||
{
|
||||
float baseAspect = baseSize.x / baseSize.y;
|
||||
float aspect = size.x / size.y;
|
||||
uint32_t stretchFlags = (uint32_t)stretchHandle;
|
||||
|
||||
if (stretchHandle == ItemHandle::TopLeft ||
|
||||
stretchHandle == ItemHandle::TopRight ||
|
||||
stretchHandle == ItemHandle::BottomLeft ||
|
||||
stretchHandle == ItemHandle::BottomRight) {
|
||||
if (aspect < baseAspect)
|
||||
size.x = size.y * baseAspect;
|
||||
else
|
||||
size.y = size.x / baseAspect;
|
||||
|
||||
} else if (stretchHandle == ItemHandle::TopCenter ||
|
||||
stretchHandle == ItemHandle::BottomCenter) {
|
||||
size.x = size.y * baseAspect;
|
||||
|
||||
} else if (stretchHandle == ItemHandle::CenterLeft ||
|
||||
stretchHandle == ItemHandle::CenterRight) {
|
||||
size.y = size.x / baseAspect;
|
||||
}
|
||||
|
||||
size.x = std::round(size.x);
|
||||
size.y = std::round(size.y);
|
||||
|
||||
if (stretchFlags & ITEM_LEFT)
|
||||
tl.x = br.x - size.x;
|
||||
else if (stretchFlags & ITEM_RIGHT)
|
||||
br.x = tl.x + size.x;
|
||||
|
||||
if (stretchFlags & ITEM_TOP)
|
||||
tl.y = br.y - size.y;
|
||||
else if (stretchFlags & ITEM_BOTTOM)
|
||||
br.y = tl.y + size.y;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::SnapStretchingToScreen(vec3 &tl, vec3 &br)
|
||||
{
|
||||
uint32_t stretchFlags = (uint32_t)stretchHandle;
|
||||
vec3 newTL = GetTransformedPos(tl.x, tl.y, itemToScreen);
|
||||
vec3 newTR = GetTransformedPos(br.x, tl.y, itemToScreen);
|
||||
vec3 newBL = GetTransformedPos(tl.x, br.y, itemToScreen);
|
||||
vec3 newBR = GetTransformedPos(br.x, br.y, itemToScreen);
|
||||
vec3 boundingTL;
|
||||
vec3 boundingBR;
|
||||
|
||||
vec3_copy(&boundingTL, &newTL);
|
||||
vec3_min(&boundingTL, &boundingTL, &newTR);
|
||||
vec3_min(&boundingTL, &boundingTL, &newBL);
|
||||
vec3_min(&boundingTL, &boundingTL, &newBR);
|
||||
|
||||
vec3_copy(&boundingBR, &newTL);
|
||||
vec3_max(&boundingBR, &boundingBR, &newTR);
|
||||
vec3_max(&boundingBR, &boundingBR, &newBL);
|
||||
vec3_max(&boundingBR, &boundingBR, &newBR);
|
||||
|
||||
vec3 offset = GetScreenSnapOffset(boundingTL, boundingBR);
|
||||
vec3_add(&offset, &offset, &newTL);
|
||||
vec3_transform(&offset, &offset, &screenToItem);
|
||||
vec3_sub(&offset, &offset, &tl);
|
||||
|
||||
if (stretchFlags & ITEM_LEFT)
|
||||
tl.x += offset.x;
|
||||
else if (stretchFlags & ITEM_RIGHT)
|
||||
br.x += offset.x;
|
||||
|
||||
if (stretchFlags & ITEM_TOP)
|
||||
tl.y += offset.y;
|
||||
else if (stretchFlags & ITEM_BOTTOM)
|
||||
br.y += offset.y;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::StretchItem(const vec2 &pos)
|
||||
{
|
||||
Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
|
||||
obs_bounds_type boundsType = obs_sceneitem_get_bounds_type(stretchItem);
|
||||
uint32_t stretchFlags = (uint32_t)stretchHandle;
|
||||
bool shiftDown = (modifiers & Qt::ShiftModifier);
|
||||
vec3 tl, br, pos3;
|
||||
|
||||
vec3_zero(&tl);
|
||||
vec3_set(&br, stretchItemSize.x, stretchItemSize.y, 0.0f);
|
||||
|
||||
vec3_set(&pos3, pos.x, pos.y, 0.0f);
|
||||
vec3_transform(&pos3, &pos3, &screenToItem);
|
||||
|
||||
if (stretchFlags & ITEM_LEFT)
|
||||
tl.x = pos3.x;
|
||||
else if (stretchFlags & ITEM_RIGHT)
|
||||
br.x = pos3.x;
|
||||
|
||||
if (stretchFlags & ITEM_TOP)
|
||||
tl.y = pos3.y;
|
||||
else if (stretchFlags & ITEM_BOTTOM)
|
||||
br.y = pos3.y;
|
||||
|
||||
if (!(modifiers & Qt::ControlModifier))
|
||||
SnapStretchingToScreen(tl, br);
|
||||
|
||||
obs_source_t source = obs_sceneitem_getsource(stretchItem);
|
||||
vec2 baseSize = {
|
||||
float(obs_source_getwidth(source)),
|
||||
float(obs_source_getheight(source))
|
||||
};
|
||||
|
||||
vec2 size = {br.x - tl.x, br.y - tl.y};
|
||||
|
||||
if (boundsType != OBS_BOUNDS_NONE) {
|
||||
if (boundsType == OBS_BOUNDS_STRETCH && !shiftDown)
|
||||
ClampAspect(tl, br, size, baseSize);
|
||||
|
||||
if (tl.x > br.x) std::swap(tl.x, br.x);
|
||||
if (tl.y > br.y) std::swap(tl.y, br.y);
|
||||
|
||||
vec2_abs(&size, &size);
|
||||
|
||||
obs_sceneitem_set_bounds(stretchItem, &size);
|
||||
} else {
|
||||
if (!shiftDown)
|
||||
ClampAspect(tl, br, size, baseSize);
|
||||
|
||||
vec2_div(&size, &size, &baseSize);
|
||||
obs_sceneitem_setscale(stretchItem, &size);
|
||||
}
|
||||
|
||||
pos3 = CalculateStretchPos(tl, br);
|
||||
vec3_transform(&pos3, &pos3, &itemToScreen);
|
||||
vec2 newPos = {pos3.x, pos3.y};
|
||||
|
||||
newPos.x = std::round(newPos.x);
|
||||
newPos.y = std::round(newPos.y);
|
||||
|
||||
obs_sceneitem_setpos(stretchItem, &newPos);
|
||||
}
|
||||
|
||||
void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (mouseDown) {
|
||||
vec2 pos = GetMouseEventPos(event);
|
||||
|
||||
if (!mouseMoved && !mouseOverItems &&
|
||||
stretchHandle == ItemHandle::None) {
|
||||
ProcessClick(startPos);
|
||||
mouseOverItems = SelectedAtPos(startPos);
|
||||
}
|
||||
|
||||
pos.x = std::round(pos.x);
|
||||
pos.y = std::round(pos.y);
|
||||
|
||||
if (stretchHandle != ItemHandle::None)
|
||||
StretchItem(pos);
|
||||
else if (mouseOverItems)
|
||||
MoveItems(pos);
|
||||
|
||||
mouseMoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawCircleAtPos(float x, float y, matrix4 &matrix,
|
||||
float previewScale)
|
||||
{
|
||||
struct vec3 pos;
|
||||
vec3_set(&pos, x, y, 0.0f);
|
||||
vec3_transform(&pos, &pos, &matrix);
|
||||
vec3_mulf(&pos, &pos, previewScale);
|
||||
|
||||
gs_matrix_push();
|
||||
gs_matrix_translate(&pos);
|
||||
gs_draw(GS_LINESTRIP, 0, 0);
|
||||
gs_matrix_pop();
|
||||
}
|
||||
|
||||
bool OBSBasicPreview::DrawSelectedItem(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param)
|
||||
{
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
OBSBasicPreview *preview = reinterpret_cast<OBSBasicPreview*>(param);
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
|
||||
gs_load_vertexbuffer(main->circle);
|
||||
|
||||
matrix4 boxTransform;
|
||||
obs_sceneitem_get_box_transform(item, &boxTransform);
|
||||
|
||||
gs_matrix_push();
|
||||
gs_matrix_scale3f(HANDLE_RADIUS, HANDLE_RADIUS, 1.0f);
|
||||
DrawCircleAtPos(0.0f, 0.0f, boxTransform, main->previewScale);
|
||||
DrawCircleAtPos(0.0f, 1.0f, boxTransform, main->previewScale);
|
||||
DrawCircleAtPos(1.0f, 0.0f, boxTransform, main->previewScale);
|
||||
DrawCircleAtPos(1.0f, 1.0f, boxTransform, main->previewScale);
|
||||
DrawCircleAtPos(0.5f, 0.0f, boxTransform, main->previewScale);
|
||||
DrawCircleAtPos(0.0f, 0.5f, boxTransform, main->previewScale);
|
||||
DrawCircleAtPos(0.5f, 1.0f, boxTransform, main->previewScale);
|
||||
DrawCircleAtPos(1.0f, 0.5f, boxTransform, main->previewScale);
|
||||
gs_matrix_pop();
|
||||
|
||||
gs_load_vertexbuffer(main->box);
|
||||
|
||||
gs_matrix_push();
|
||||
gs_matrix_set(&boxTransform);
|
||||
gs_matrix_scale3f(main->previewScale, main->previewScale, 1.0f);
|
||||
gs_draw(GS_LINESTRIP, 0, 0);
|
||||
|
||||
gs_matrix_pop();
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
return true;
|
||||
}
|
||||
|
||||
void OBSBasicPreview::DrawSceneEditing()
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
||||
|
||||
effect_t solid = obs_get_solid_effect();
|
||||
technique_t tech = effect_gettechnique(solid, "Solid");
|
||||
|
||||
vec4 color;
|
||||
vec4_set(&color, 1.0f, 0.0f, 0.0f, 1.0f);
|
||||
effect_setvec4(solid, effect_getparambyname(solid, "color"), &color);
|
||||
|
||||
technique_begin(tech);
|
||||
technique_beginpass(tech, 0);
|
||||
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (scene)
|
||||
obs_scene_enum_items(scene, DrawSelectedItem, this);
|
||||
|
||||
gs_load_vertexbuffer(nullptr);
|
||||
|
||||
technique_endpass(tech);
|
||||
technique_end(tech);
|
||||
}
|
84
obs/window-basic-preview.hpp
Normal file
84
obs/window-basic-preview.hpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#pragma once
|
||||
|
||||
#include <obs.hpp>
|
||||
#include <graphics/vec2.h>
|
||||
#include <graphics/matrix4.h>
|
||||
#include "qt-display.hpp"
|
||||
#include "obs-app.hpp"
|
||||
|
||||
class OBSBasic;
|
||||
class QMouseEvent;
|
||||
|
||||
#define ITEM_LEFT (1<<0)
|
||||
#define ITEM_RIGHT (1<<1)
|
||||
#define ITEM_TOP (1<<2)
|
||||
#define ITEM_BOTTOM (1<<3)
|
||||
|
||||
enum class ItemHandle : uint32_t {
|
||||
None = 0,
|
||||
TopLeft = ITEM_TOP | ITEM_LEFT,
|
||||
TopCenter = ITEM_TOP,
|
||||
TopRight = ITEM_TOP | ITEM_RIGHT,
|
||||
CenterLeft = ITEM_LEFT,
|
||||
CenterRight = ITEM_RIGHT,
|
||||
BottomLeft = ITEM_BOTTOM | ITEM_LEFT,
|
||||
BottomCenter = ITEM_BOTTOM,
|
||||
BottomRight = ITEM_BOTTOM | ITEM_RIGHT
|
||||
};
|
||||
|
||||
class OBSBasicPreview : public OBSQTDisplay {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
OBSSceneItem stretchItem;
|
||||
ItemHandle stretchHandle = ItemHandle::None;
|
||||
vec2 stretchItemSize;
|
||||
matrix4 screenToItem;
|
||||
matrix4 itemToScreen;
|
||||
|
||||
vec2 startPos;
|
||||
vec2 lastMoveOffset;
|
||||
bool mouseDown = false;
|
||||
bool mouseMoved = false;
|
||||
bool mouseOverItems = false;
|
||||
|
||||
static vec2 GetMouseEventPos(QMouseEvent *event);
|
||||
static bool DrawSelectedItem(obs_scene_t scene, obs_sceneitem_t item,
|
||||
void *param);
|
||||
|
||||
static OBSSceneItem GetItemAtPos(const vec2 &pos, bool selectBelow);
|
||||
static bool SelectedAtPos(const vec2 &pos);
|
||||
|
||||
static void DoSelect(const vec2 &pos);
|
||||
static void DoCtrlSelect(const vec2 &pos);
|
||||
|
||||
static vec3 GetScreenSnapOffset(const vec3 &tl, const vec3 &br);
|
||||
|
||||
void GetStretchHandleData(const vec2 &pos);
|
||||
|
||||
void SnapStretchingToScreen(vec3 &tl, vec3 &br);
|
||||
void ClampAspect(vec3 &tl, vec3 &br, vec2 &size, const vec2 &baseSize);
|
||||
vec3 CalculateStretchPos(const vec3 &tl, const vec3 &br);
|
||||
void StretchItem(const vec2 &pos);
|
||||
|
||||
static void SnapItemMovement(vec2 &offset);
|
||||
void MoveItems(const vec2 &pos);
|
||||
|
||||
void ProcessClick(const vec2 &pos);
|
||||
|
||||
public:
|
||||
OBSBasicPreview(QWidget *parent, Qt::WindowFlags flags = 0);
|
||||
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
void DrawSceneEditing();
|
||||
|
||||
/* use libobs allocator for alignment because the matrices itemToScreen
|
||||
* and screenToItem may contain SSE data, which will cause SSE
|
||||
* instructions to crash if the data is not aligned to at least a 16
|
||||
* byte boundry. */
|
||||
static inline void* operator new(size_t size) {return bmalloc(size);}
|
||||
static inline void operator delete(void* ptr) {bfree(ptr);}
|
||||
};
|
|
@ -92,7 +92,6 @@ void OBSBasicSettings::HookWidget(QWidget *widget, const char *signal,
|
|||
QObject::connect(widget, signal, this, slot);
|
||||
}
|
||||
|
||||
#define COMBO_CHANGED SIGNAL(currentIndexChanged(int))
|
||||
#define COMBO_CHANGED SIGNAL(currentIndexChanged(int))
|
||||
#define EDIT_CHANGED SIGNAL(textChanged(const QString &))
|
||||
#define CBEDIT_CHANGED SIGNAL(editTextChanged(const QString &))
|
||||
|
|
253
obs/window-basic-transform.cpp
Normal file
253
obs/window-basic-transform.cpp
Normal file
|
@ -0,0 +1,253 @@
|
|||
#include "window-basic-transform.hpp"
|
||||
#include "window-basic-main.hpp"
|
||||
|
||||
Q_DECLARE_METATYPE(OBSSceneItem);
|
||||
|
||||
static OBSSceneItem FindASelectedItem(OBSScene scene)
|
||||
{
|
||||
auto func = [] (obs_scene_t scene, obs_sceneitem_t item, void *param)
|
||||
{
|
||||
OBSSceneItem &dst = *reinterpret_cast<OBSSceneItem*>(param);
|
||||
|
||||
if (obs_sceneitem_selected(item)) {
|
||||
dst = item;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
OBSSceneItem item;
|
||||
obs_scene_enum_items(scene, func, &item);
|
||||
return item;
|
||||
}
|
||||
|
||||
void OBSBasicTransform::HookWidget(QWidget *widget, const char *signal,
|
||||
const char *slot)
|
||||
{
|
||||
QObject::connect(widget, signal, this, slot);
|
||||
}
|
||||
|
||||
#define COMBO_CHANGED SIGNAL(currentIndexChanged(int))
|
||||
#define DSCROLL_CHANGED SIGNAL(valueChanged(double))
|
||||
|
||||
OBSBasicTransform::OBSBasicTransform(OBSBasic *parent)
|
||||
: QDialog (parent),
|
||||
ui (new Ui::OBSBasicTransform),
|
||||
main (parent)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
HookWidget(ui->positionX, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->positionY, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->rotation, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->scaleX, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->scaleY, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->align, COMBO_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->boundsType, COMBO_CHANGED, SLOT(OnBoundsType(int)));
|
||||
HookWidget(ui->boundsAlign, COMBO_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->boundsWidth, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
HookWidget(ui->boundsHeight, DSCROLL_CHANGED, SLOT(OnControlChanged()));
|
||||
|
||||
OBSScene curScene = main->GetCurrentScene();
|
||||
SetScene(curScene);
|
||||
SetItem(FindASelectedItem(curScene));
|
||||
|
||||
channelChangedSignal.Connect(obs_signalhandler(), "channel_change",
|
||||
OBSChannelChanged, this);
|
||||
}
|
||||
|
||||
void OBSBasicTransform::SetScene(OBSScene scene)
|
||||
{
|
||||
transformSignal.Disconnect();
|
||||
selectSignal.Disconnect();
|
||||
deselectSignal.Disconnect();
|
||||
removeSignal.Disconnect();
|
||||
|
||||
if (scene) {
|
||||
OBSSource source = obs_scene_getsource(scene);
|
||||
signal_handler_t signal = obs_source_signalhandler(source);
|
||||
|
||||
transformSignal.Connect(signal, "item_transform",
|
||||
OBSSceneItemTransform, this);
|
||||
removeSignal.Connect(signal, "item_remove",
|
||||
OBSSceneItemRemoved, this);
|
||||
selectSignal.Connect(signal, "item_select",
|
||||
OBSSceneItemSelect, this);
|
||||
deselectSignal.Connect(signal, "item_deselect",
|
||||
OBSSceneItemDeselect, this);
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicTransform::SetItem(OBSSceneItem newItem)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "SetItemQt",
|
||||
Q_ARG(OBSSceneItem, OBSSceneItem(newItem)));
|
||||
}
|
||||
|
||||
void OBSBasicTransform::SetItemQt(OBSSceneItem newItem)
|
||||
{
|
||||
item = newItem;
|
||||
if (item)
|
||||
RefreshControls();
|
||||
|
||||
setEnabled(!!item);
|
||||
}
|
||||
|
||||
void OBSBasicTransform::OBSChannelChanged(void *param, calldata_t data)
|
||||
{
|
||||
OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
|
||||
uint32_t channel = (uint32_t)calldata_int(data, "channel");
|
||||
OBSSource source = (obs_source_t)calldata_ptr(data, "source");
|
||||
|
||||
if (channel == 0) {
|
||||
OBSScene scene = obs_scene_fromsource(source);
|
||||
window->SetScene(scene);
|
||||
|
||||
if (!scene)
|
||||
window->SetItem(nullptr);
|
||||
else
|
||||
window->SetItem(FindASelectedItem(scene));
|
||||
}
|
||||
}
|
||||
|
||||
void OBSBasicTransform::OBSSceneItemTransform(void *param, calldata_t data)
|
||||
{
|
||||
OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
|
||||
OBSSceneItem item = (obs_sceneitem_t)calldata_ptr(data, "item");
|
||||
|
||||
if (item == window->item && !window->ignoreTransformSignal)
|
||||
QMetaObject::invokeMethod(window, "RefreshControls");
|
||||
}
|
||||
|
||||
void OBSBasicTransform::OBSSceneItemRemoved(void *param, calldata_t data)
|
||||
{
|
||||
OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
|
||||
OBSScene scene = (obs_scene_t)calldata_ptr(data, "scene");
|
||||
OBSSceneItem item = (obs_sceneitem_t)calldata_ptr(data, "item");
|
||||
|
||||
if (item == window->item)
|
||||
window->SetItem(FindASelectedItem(scene));
|
||||
}
|
||||
|
||||
void OBSBasicTransform::OBSSceneItemSelect(void *param, calldata_t data)
|
||||
{
|
||||
OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
|
||||
OBSSceneItem item = (obs_sceneitem_t)calldata_ptr(data, "item");
|
||||
|
||||
if (item != window->item)
|
||||
window->SetItem(item);
|
||||
}
|
||||
|
||||
void OBSBasicTransform::OBSSceneItemDeselect(void *param, calldata_t data)
|
||||
{
|
||||
OBSBasicTransform *window = reinterpret_cast<OBSBasicTransform*>(param);
|
||||
OBSScene scene = (obs_scene_t)calldata_ptr(data, "scene");
|
||||
OBSSceneItem item = (obs_sceneitem_t)calldata_ptr(data, "item");
|
||||
|
||||
if (item == window->item)
|
||||
window->SetItem(FindASelectedItem(scene));
|
||||
}
|
||||
|
||||
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 int AlignToList(uint32_t align)
|
||||
{
|
||||
int index = 0;
|
||||
for (uint32_t curAlign : listToAlign) {
|
||||
if (curAlign == align)
|
||||
return index;
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OBSBasicTransform::RefreshControls()
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
obs_sceneitem_info osi;
|
||||
obs_sceneitem_get_info(item, &osi);
|
||||
|
||||
int alignIndex = AlignToList(osi.alignment);
|
||||
int boundsAlignIndex = AlignToList(osi.bounds_alignment);
|
||||
|
||||
ignoreItemChange = true;
|
||||
ui->positionX->setValue(osi.pos.x);
|
||||
ui->positionY->setValue(osi.pos.y);
|
||||
ui->rotation->setValue(osi.rot);
|
||||
ui->scaleX->setValue(osi.scale.x);
|
||||
ui->scaleY->setValue(osi.scale.y);
|
||||
ui->align->setCurrentIndex(alignIndex);
|
||||
|
||||
ui->boundsType->setCurrentIndex(int(osi.bounds_type));
|
||||
ui->boundsAlign->setCurrentIndex(boundsAlignIndex);
|
||||
ui->boundsWidth->setValue(osi.bounds.x);
|
||||
ui->boundsHeight->setValue(osi.bounds.y);
|
||||
ignoreItemChange = false;
|
||||
}
|
||||
|
||||
void OBSBasicTransform::OnBoundsType(int index)
|
||||
{
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
obs_bounds_type type = (obs_bounds_type)index;
|
||||
bool enable = (type != OBS_BOUNDS_NONE);
|
||||
|
||||
ui->boundsAlign->setEnabled(enable);
|
||||
ui->boundsWidth->setEnabled(enable);
|
||||
ui->boundsHeight->setEnabled(enable);
|
||||
|
||||
if (!ignoreItemChange) {
|
||||
obs_bounds_type lastType = obs_sceneitem_get_bounds_type(item);
|
||||
if (lastType == OBS_BOUNDS_NONE) {
|
||||
OBSSource source = obs_sceneitem_getsource(item);
|
||||
int width = (int)obs_source_getwidth(source);
|
||||
int height = (int)obs_source_getheight(source);
|
||||
|
||||
ui->boundsWidth->setValue(width);
|
||||
ui->boundsHeight->setValue(height);
|
||||
}
|
||||
}
|
||||
|
||||
OnControlChanged();
|
||||
}
|
||||
|
||||
void OBSBasicTransform::OnControlChanged()
|
||||
{
|
||||
if (ignoreItemChange)
|
||||
return;
|
||||
|
||||
obs_sceneitem_info osi;
|
||||
osi.pos.x = float(ui->positionX->value());
|
||||
osi.pos.y = float(ui->positionY->value());
|
||||
osi.rot = float(ui->rotation->value());
|
||||
osi.scale.x = float(ui->scaleX->value());
|
||||
osi.scale.y = float(ui->scaleY->value());
|
||||
osi.alignment = listToAlign[ui->align->currentIndex()];
|
||||
|
||||
osi.bounds_type = (obs_bounds_type)ui->boundsType->currentIndex();
|
||||
osi.bounds_alignment = listToAlign[ui->boundsAlign->currentIndex()];
|
||||
osi.bounds.x = float(ui->boundsWidth->value());
|
||||
osi.bounds.y = float(ui->boundsHeight->value());
|
||||
|
||||
ignoreTransformSignal = true;
|
||||
obs_sceneitem_set_info(item, &osi);
|
||||
ignoreTransformSignal = false;
|
||||
}
|
47
obs/window-basic-transform.hpp
Normal file
47
obs/window-basic-transform.hpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
|
||||
#include <obs.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "ui_OBSBasicTransform.h"
|
||||
|
||||
class OBSBasic;
|
||||
|
||||
class OBSBasicTransform : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
std::unique_ptr<Ui::OBSBasicTransform> ui;
|
||||
|
||||
OBSBasic *main;
|
||||
OBSSceneItem item;
|
||||
OBSSignal channelChangedSignal;
|
||||
OBSSignal transformSignal;
|
||||
OBSSignal removeSignal;
|
||||
OBSSignal selectSignal;
|
||||
OBSSignal deselectSignal;
|
||||
|
||||
bool ignoreTransformSignal = false;
|
||||
bool ignoreItemChange = false;
|
||||
|
||||
void HookWidget(QWidget *widget, const char *signal, const char *slot);
|
||||
|
||||
void SetScene(OBSScene scene);
|
||||
void SetItem(OBSSceneItem newItem);
|
||||
|
||||
static void OBSChannelChanged(void *param, calldata_t data);
|
||||
|
||||
static void OBSSceneItemTransform(void *param, calldata_t data);
|
||||
static void OBSSceneItemRemoved(void *param, calldata_t data);
|
||||
static void OBSSceneItemSelect(void *param, calldata_t data);
|
||||
static void OBSSceneItemDeselect(void *param, calldata_t data);
|
||||
|
||||
private slots:
|
||||
void RefreshControls();
|
||||
void SetItemQt(OBSSceneItem newItem);
|
||||
void OnBoundsType(int index);
|
||||
void OnControlChanged();
|
||||
|
||||
public:
|
||||
OBSBasicTransform(OBSBasic *parent);
|
||||
};
|
|
@ -22,6 +22,43 @@
|
|||
<ClInclude Include="..\..\..\libobs\obs-ui.h" />
|
||||
<ClInclude Include="..\..\..\obs\display-helpers.hpp" />
|
||||
<ClInclude Include="..\..\..\obs\platform.hpp" />
|
||||
<CustomBuild Include="..\..\..\obs\window-basic-preview.hpp">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing window-basic-preview.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing window-basic-preview.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing window-basic-preview.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing window-basic-preview.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\..\obs\window-basic-transform.hpp">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing window-basic-transform.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing window-basic-transform.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing window-basic-transform.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Moc%27ing window-basic-transform.hpp...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_NETWORK_LIB "-I.\..\..\..\libobs" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I.\..\..\..\obs" "-I$(QTDIR)\include\QtNetwork"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="GeneratedFiles\ui_OBSBasicTransform.h" />
|
||||
<ClInclude Include="GeneratedFiles\ui_OBSLogReply.h" />
|
||||
<CustomBuild Include="..\..\..\obs\window-basic-source-select.hpp">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
|
@ -235,9 +272,11 @@
|
|||
<ClCompile Include="..\..\..\obs\qt-wrappers.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\volume-control.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-basic-main.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-basic-preview.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-basic-properties.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-basic-settings.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-basic-source-select.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-basic-transform.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-log-reply.cpp" />
|
||||
<ClCompile Include="..\..\..\obs\window-namedialog.cpp" />
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_obs-app.cpp">
|
||||
|
@ -260,6 +299,10 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_window-basic-preview.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_window-basic-properties.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
|
@ -272,6 +315,10 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_window-basic-transform.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_window-log-reply.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
|
@ -314,6 +361,10 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_window-basic-preview.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_window-basic-properties.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
|
@ -326,6 +377,10 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_window-basic-transform.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_window-log-reply.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
|
@ -553,6 +608,26 @@
|
|||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include="..\..\..\obs\forms\OBSBasicTransform.ui">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{B12702AD-ABFB-343A-A199-8E24837244A3}</ProjectGuid>
|
||||
<Keyword>Qt4VSv1.0</Keyword>
|
||||
|
|
|
@ -89,6 +89,15 @@
|
|||
<CustomBuild Include="..\..\..\obs\forms\OBSLogReply.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\..\obs\window-basic-preview.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\..\obs\forms\OBSBasicTransform.ui">
|
||||
<Filter>Form Files</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="..\..\..\obs\window-basic-transform.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\obs\platform.hpp">
|
||||
|
@ -121,6 +130,9 @@
|
|||
<ClInclude Include="GeneratedFiles\ui_OBSLogReply.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GeneratedFiles\ui_OBSBasicTransform.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\obs\obs-app.cpp">
|
||||
|
@ -225,6 +237,24 @@
|
|||
<ClCompile Include="..\..\..\obs\window-log-reply.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_window-basic-preview.cpp">
|
||||
<Filter>Generated Files\Debug</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_window-basic-preview.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\obs\window-basic-preview.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_window-basic-transform.cpp">
|
||||
<Filter>Generated Files\Debug</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_window-basic-transform.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\obs\window-basic-transform.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\..\obs\forms\images\add.ico">
|
||||
|
|
Loading…
Reference in a new issue