mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-03-16 13:37:05 -04:00
@@ -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"
|
||||
|
||||
@@ -34,14 +34,14 @@
|
||||
*
|
||||
* Reset to zero each major version
|
||||
*/
|
||||
#define LIBOBS_API_MINOR_VER 2
|
||||
#define LIBOBS_API_MINOR_VER 3
|
||||
|
||||
/*
|
||||
* Increment if backward-compatible bug fix
|
||||
*
|
||||
* Reset to zero each major or minor version
|
||||
*/
|
||||
#define LIBOBS_API_PATCH_VER 4
|
||||
#define LIBOBS_API_PATCH_VER 0
|
||||
|
||||
#define LIBOBS_API_VER ((LIBOBS_API_MAJOR_VER << 24) | \
|
||||
(LIBOBS_API_MINOR_VER << 16) | \
|
||||
|
||||
@@ -20,6 +20,12 @@
|
||||
/** Maximum number of source channels for output and per display */
|
||||
#define MAX_CHANNELS 64
|
||||
|
||||
#define OBS_ALIGN_CENTER (0)
|
||||
#define OBS_ALIGN_LEFT (1<<0)
|
||||
#define OBS_ALIGN_RIGHT (1<<1)
|
||||
#define OBS_ALIGN_TOP (1<<2)
|
||||
#define OBS_ALIGN_BOTTOM (1<<3)
|
||||
|
||||
#define MODULE_SUCCESS 0
|
||||
#define MODULE_ERROR -1
|
||||
#define MODULE_FILE_NOT_FOUND -2
|
||||
|
||||
@@ -26,6 +26,9 @@ static const char *obs_scene_signals[] = {
|
||||
"void item_move_down(ptr scene, ptr item)",
|
||||
"void item_move_top(ptr scene, ptr item)",
|
||||
"void item_move_bottom(ptr scene, ptr item)",
|
||||
"void item_select(ptr scene, ptr item)",
|
||||
"void item_deselect(ptr scene, ptr item)",
|
||||
"void item_transform(ptr scene, ptr item)",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -155,6 +158,143 @@ static inline void attach_sceneitem(struct obs_scene *parent,
|
||||
}
|
||||
}
|
||||
|
||||
static void add_alignment(struct vec2 *v, uint32_t align, int cx, int cy)
|
||||
{
|
||||
if (align & OBS_ALIGN_RIGHT)
|
||||
v->x += (float)cx;
|
||||
else if ((align & OBS_ALIGN_LEFT) == 0)
|
||||
v->x += (float)(cx / 2);
|
||||
|
||||
if (align & OBS_ALIGN_BOTTOM)
|
||||
v->y += (float)cy;
|
||||
else if ((align & OBS_ALIGN_TOP) == 0)
|
||||
v->y += (float)(cy / 2);
|
||||
}
|
||||
|
||||
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;
|
||||
uint32_t bounds_type = item->bounds_type;
|
||||
float width_diff, height_diff;
|
||||
|
||||
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;
|
||||
|
||||
if (item->bounds_type == OBS_BOUNDS_SCALE_OUTER)
|
||||
use_width = !use_width;
|
||||
|
||||
mul = use_width ?
|
||||
item->bounds.x / width :
|
||||
item->bounds.y / height;
|
||||
|
||||
vec2_mulf(scale, scale, mul);
|
||||
|
||||
} else if (bounds_type == OBS_BOUNDS_SCALE_TO_WIDTH) {
|
||||
vec2_mulf(scale, scale, item->bounds.x / width);
|
||||
|
||||
} else if (bounds_type == OBS_BOUNDS_SCALE_TO_HEIGHT) {
|
||||
vec2_mulf(scale, scale, item->bounds.y / height);
|
||||
|
||||
} else if (bounds_type == OBS_BOUNDS_STRETCH) {
|
||||
scale->x = item->bounds.x / (float)(*cx);
|
||||
scale->y = item->bounds.y / (float)(*cy);
|
||||
}
|
||||
|
||||
width = (float)(*cx) * scale->x;
|
||||
height = (float)(*cy) * scale->y;
|
||||
width_diff = item->bounds.x - width;
|
||||
height_diff = item->bounds.y - height;
|
||||
*cx = (uint32_t)item->bounds.x;
|
||||
*cy = (uint32_t)item->bounds.y;
|
||||
|
||||
add_alignment(origin, item->bounds_align,
|
||||
(int)-width_diff, (int)-height_diff);
|
||||
}
|
||||
|
||||
static void update_item_transform(struct obs_scene_item *item)
|
||||
{
|
||||
uint32_t width = obs_source_getwidth(item->source);
|
||||
uint32_t height = obs_source_getheight(item->source);
|
||||
uint32_t cx = width;
|
||||
uint32_t cy = height;
|
||||
struct vec2 base_origin = {0.0f, 0.0f};
|
||||
struct vec2 origin = {0.0f, 0.0f};
|
||||
struct vec2 scale = item->scale;
|
||||
struct calldata params = {0};
|
||||
|
||||
/* ----------------------- */
|
||||
|
||||
if (item->bounds_type != OBS_BOUNDS_NONE) {
|
||||
calculate_bounds_data(item, &origin, &scale, &cx, &cy);
|
||||
} else {
|
||||
cx = (uint32_t)((float)cx * scale.x);
|
||||
cy = (uint32_t)((float)cy * scale.y);
|
||||
}
|
||||
|
||||
add_alignment(&origin, item->align, (int)cx, (int)cy);
|
||||
|
||||
matrix4_identity(&item->draw_transform);
|
||||
matrix4_scale3f(&item->draw_transform, &item->draw_transform,
|
||||
scale.x, scale.y, 1.0f);
|
||||
matrix4_translate3f(&item->draw_transform, &item->draw_transform,
|
||||
-origin.x, -origin.y, 0.0f);
|
||||
matrix4_rotate_aa4f(&item->draw_transform, &item->draw_transform,
|
||||
0.0f, 0.0f, 1.0f, RAD(item->rot));
|
||||
matrix4_translate3f(&item->draw_transform, &item->draw_transform,
|
||||
item->pos.x, item->pos.y, 0.0f);
|
||||
|
||||
/* ----------------------- */
|
||||
|
||||
if (item->bounds_type != OBS_BOUNDS_NONE) {
|
||||
vec2_copy(&scale, &item->bounds);
|
||||
} else {
|
||||
scale.x = (float)width * item->scale.x;
|
||||
scale.y = (float)height * item->scale.y;
|
||||
}
|
||||
|
||||
add_alignment(&base_origin, item->align, (int)scale.x, (int)scale.y);
|
||||
|
||||
matrix4_identity(&item->box_transform);
|
||||
matrix4_scale3f(&item->box_transform, &item->box_transform,
|
||||
scale.x, scale.y, 1.0f);
|
||||
matrix4_translate3f(&item->box_transform, &item->box_transform,
|
||||
-base_origin.x, -base_origin.y, 0.0f);
|
||||
matrix4_rotate_aa4f(&item->box_transform, &item->box_transform,
|
||||
0.0f, 0.0f, 1.0f, RAD(item->rot));
|
||||
matrix4_translate3f(&item->box_transform, &item->box_transform,
|
||||
item->pos.x, item->pos.y, 0.0f);
|
||||
|
||||
/* ----------------------- */
|
||||
|
||||
item->last_width = width;
|
||||
item->last_height = height;
|
||||
|
||||
calldata_setptr(¶ms, "scene", item->parent);
|
||||
calldata_setptr(¶ms, "item", item);
|
||||
signal_handler_signal(item->parent->source->context.signals,
|
||||
"item_transform", ¶ms);
|
||||
calldata_free(¶ms);
|
||||
}
|
||||
|
||||
static inline bool source_size_changed(struct obs_scene_item *item)
|
||||
{
|
||||
uint32_t width = obs_source_getwidth(item->source);
|
||||
uint32_t height = obs_source_getheight(item->source);
|
||||
|
||||
return item->last_width != width || item->last_height != height;
|
||||
}
|
||||
|
||||
static void scene_video_render(void *data, effect_t effect)
|
||||
{
|
||||
struct obs_scene *scene = data;
|
||||
@@ -173,14 +313,12 @@ static void scene_video_render(void *data, effect_t effect)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (source_size_changed(item))
|
||||
update_item_transform(item);
|
||||
|
||||
gs_matrix_push();
|
||||
gs_matrix_translate3f(item->origin.x, item->origin.y, 0.0f);
|
||||
gs_matrix_scale3f(item->scale.x, item->scale.y, 1.0f);
|
||||
gs_matrix_rotaa4f(0.0f, 0.0f, 1.0f, RAD(-item->rot));
|
||||
gs_matrix_translate3f(-item->pos.x, -item->pos.y, 0.0f);
|
||||
|
||||
gs_matrix_mul(&item->draw_transform);
|
||||
obs_source_video_render(item->source);
|
||||
|
||||
gs_matrix_pop();
|
||||
|
||||
item = item->next;
|
||||
@@ -205,12 +343,24 @@ static void scene_load_item(struct obs_scene *scene, obs_data_t item_data)
|
||||
|
||||
item = obs_scene_add(scene, source);
|
||||
|
||||
obs_data_set_default_int(item_data, "align",
|
||||
OBS_ALIGN_TOP | OBS_ALIGN_LEFT);
|
||||
|
||||
item->rot = (float)obs_data_getdouble(item_data, "rot");
|
||||
item->align = (uint32_t)obs_data_getint(item_data, "align");
|
||||
item->visible = obs_data_getbool(item_data, "visible");
|
||||
obs_data_get_vec2(item_data, "origin", &item->origin);
|
||||
obs_data_get_vec2(item_data, "pos", &item->pos);
|
||||
obs_data_get_vec2(item_data, "scale", &item->scale);
|
||||
|
||||
item->bounds_type =
|
||||
(enum obs_bounds_type)obs_data_getint(item_data, "bounds_type");
|
||||
item->bounds_align =
|
||||
(uint32_t)obs_data_getint(item_data, "bounds_align");
|
||||
obs_data_get_vec2(item_data, "bounds", &item->bounds);
|
||||
|
||||
obs_source_release(source);
|
||||
|
||||
update_item_transform(item);
|
||||
}
|
||||
|
||||
static void scene_load(void *scene, obs_data_t settings)
|
||||
@@ -238,12 +388,15 @@ static void scene_save_item(obs_data_array_t array, struct obs_scene_item *item)
|
||||
obs_data_t item_data = obs_data_create();
|
||||
const char *name = obs_source_getname(item->source);
|
||||
|
||||
obs_data_setstring(item_data, "name", name);
|
||||
obs_data_setbool (item_data, "visible", item->visible);
|
||||
obs_data_setdouble(item_data, "rot", item->rot);
|
||||
obs_data_set_vec2 (item_data, "origin", &item->origin);
|
||||
obs_data_set_vec2 (item_data, "pos", &item->pos);
|
||||
obs_data_set_vec2 (item_data, "scale", &item->scale);
|
||||
obs_data_setstring(item_data, "name", name);
|
||||
obs_data_setbool (item_data, "visible", item->visible);
|
||||
obs_data_setdouble(item_data, "rot", item->rot);
|
||||
obs_data_set_vec2 (item_data, "pos", &item->pos);
|
||||
obs_data_set_vec2 (item_data, "scale", &item->scale);
|
||||
obs_data_setint (item_data, "align", (int)item->align);
|
||||
obs_data_setint (item_data, "bounds_type", (int)item->bounds_type);
|
||||
obs_data_setint (item_data, "bounds_align", (int)item->bounds_align);
|
||||
obs_data_set_vec2 (item_data, "bounds", &item->bounds);
|
||||
|
||||
obs_data_array_push_back(array, item_data);
|
||||
obs_data_release(item_data);
|
||||
@@ -400,7 +553,10 @@ obs_sceneitem_t obs_scene_add(obs_scene_t scene, obs_source_t source)
|
||||
item->visible = true;
|
||||
item->parent = scene;
|
||||
item->ref = 1;
|
||||
item->align = OBS_ALIGN_TOP | OBS_ALIGN_LEFT;
|
||||
vec2_set(&item->scale, 1.0f, 1.0f);
|
||||
matrix4_identity(&item->draw_transform);
|
||||
matrix4_identity(&item->box_transform);
|
||||
|
||||
obs_source_addref(source);
|
||||
obs_source_add_child(scene->source, source);
|
||||
@@ -495,28 +651,59 @@ obs_source_t obs_sceneitem_getsource(obs_sceneitem_t item)
|
||||
return item ? item->source : NULL;
|
||||
}
|
||||
|
||||
void obs_sceneitem_select(obs_sceneitem_t item, bool select)
|
||||
{
|
||||
struct calldata params = {0};
|
||||
const char *command = select ? "item_select" : "item_deselect";
|
||||
|
||||
if (!item || item->selected == select)
|
||||
return;
|
||||
|
||||
item->selected = select;
|
||||
|
||||
calldata_setptr(¶ms, "scene", item->parent);
|
||||
calldata_setptr(¶ms, "item", item);
|
||||
signal_handler_signal(item->parent->source->context.signals,
|
||||
command, ¶ms);
|
||||
|
||||
calldata_free(¶ms);
|
||||
}
|
||||
|
||||
bool obs_sceneitem_selected(obs_sceneitem_t item)
|
||||
{
|
||||
return item ? item->selected : false;
|
||||
}
|
||||
|
||||
void obs_sceneitem_setpos(obs_sceneitem_t item, const struct vec2 *pos)
|
||||
{
|
||||
if (item)
|
||||
if (item) {
|
||||
vec2_copy(&item->pos, pos);
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_setrot(obs_sceneitem_t item, float rot)
|
||||
{
|
||||
if (item)
|
||||
if (item) {
|
||||
item->rot = rot;
|
||||
}
|
||||
|
||||
void obs_sceneitem_setorigin(obs_sceneitem_t item, const struct vec2 *origin)
|
||||
{
|
||||
if (item)
|
||||
vec2_copy(&item->origin, origin);
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_setscale(obs_sceneitem_t item, const struct vec2 *scale)
|
||||
{
|
||||
if (item)
|
||||
if (item) {
|
||||
vec2_copy(&item->scale, scale);
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_setalignment(obs_sceneitem_t item, uint32_t alignment)
|
||||
{
|
||||
if (item) {
|
||||
item->align = alignment;
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void signal_move_dir(struct obs_scene_item *item,
|
||||
@@ -583,6 +770,32 @@ void obs_sceneitem_setorder(obs_sceneitem_t item, enum order_movement movement)
|
||||
obs_scene_release(scene);
|
||||
}
|
||||
|
||||
void obs_sceneitem_set_bounds_type(obs_sceneitem_t item,
|
||||
enum obs_bounds_type type)
|
||||
{
|
||||
if (item) {
|
||||
item->bounds_type = type;
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_set_bounds_alignment(obs_sceneitem_t item,
|
||||
uint32_t alignment)
|
||||
{
|
||||
if (item) {
|
||||
item->bounds_align = alignment;
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_set_bounds(obs_sceneitem_t item, const struct vec2 *bounds)
|
||||
{
|
||||
if (item) {
|
||||
item->bounds = *bounds;
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_getpos(obs_sceneitem_t item, struct vec2 *pos)
|
||||
{
|
||||
if (item)
|
||||
@@ -594,14 +807,72 @@ float obs_sceneitem_getrot(obs_sceneitem_t item)
|
||||
return item ? item->rot : 0.0f;
|
||||
}
|
||||
|
||||
void obs_sceneitem_getorigin(obs_sceneitem_t item, struct vec2 *origin)
|
||||
{
|
||||
if (item)
|
||||
vec2_copy(origin, &item->origin);
|
||||
}
|
||||
|
||||
void obs_sceneitem_getscale(obs_sceneitem_t item, struct vec2 *scale)
|
||||
{
|
||||
if (item)
|
||||
vec2_copy(scale, &item->scale);
|
||||
}
|
||||
|
||||
uint32_t obs_sceneitem_getalignment(obs_sceneitem_t item)
|
||||
{
|
||||
return item ? item->align : 0;
|
||||
}
|
||||
|
||||
enum obs_bounds_type obs_sceneitem_get_bounds_type(obs_sceneitem_t item)
|
||||
{
|
||||
return item ? item->bounds_type : OBS_BOUNDS_NONE;
|
||||
}
|
||||
|
||||
uint32_t obs_sceneitem_get_bounds_alignment(obs_sceneitem_t item)
|
||||
{
|
||||
return item ? item->bounds_align : 0;
|
||||
}
|
||||
|
||||
void obs_sceneitem_get_bounds(obs_sceneitem_t item, struct vec2 *bounds)
|
||||
{
|
||||
if (item)
|
||||
*bounds = item->bounds;
|
||||
}
|
||||
|
||||
void obs_sceneitem_get_info(obs_sceneitem_t item,
|
||||
struct obs_sceneitem_info *info)
|
||||
{
|
||||
if (item && info) {
|
||||
info->pos = item->pos;
|
||||
info->rot = item->rot;
|
||||
info->scale = item->scale;
|
||||
info->alignment = item->align;
|
||||
info->bounds_type = item->bounds_type;
|
||||
info->bounds_alignment = item->bounds_align;
|
||||
info->bounds = item->bounds;
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_set_info(obs_sceneitem_t item,
|
||||
const struct obs_sceneitem_info *info)
|
||||
{
|
||||
if (item && info) {
|
||||
item->pos = info->pos;
|
||||
item->rot = info->rot;
|
||||
item->scale = info->scale;
|
||||
item->align = info->alignment;
|
||||
item->bounds_type = info->bounds_type;
|
||||
item->bounds_align = info->bounds_alignment;
|
||||
item->bounds = info->bounds;
|
||||
update_item_transform(item);
|
||||
}
|
||||
}
|
||||
|
||||
void obs_sceneitem_get_draw_transform(obs_sceneitem_t item,
|
||||
struct matrix4 *transform)
|
||||
{
|
||||
if (item)
|
||||
matrix4_copy(transform, &item->draw_transform);
|
||||
}
|
||||
|
||||
void obs_sceneitem_get_box_transform(obs_sceneitem_t item,
|
||||
struct matrix4 *transform)
|
||||
{
|
||||
if (item)
|
||||
matrix4_copy(transform, &item->box_transform);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "obs.h"
|
||||
#include "obs-internal.h"
|
||||
#include "graphics/matrix4.h"
|
||||
|
||||
/* how obs scene! */
|
||||
|
||||
@@ -29,11 +30,24 @@ struct obs_scene_item {
|
||||
struct obs_scene *parent;
|
||||
struct obs_source *source;
|
||||
bool visible;
|
||||
bool selected;
|
||||
|
||||
struct vec2 origin;
|
||||
struct vec2 pos;
|
||||
struct vec2 scale;
|
||||
float rot;
|
||||
uint32_t align;
|
||||
|
||||
/* last width/height of the source, this is used to check whether
|
||||
* ths transform needs updating */
|
||||
uint32_t last_width;
|
||||
uint32_t last_height;
|
||||
|
||||
struct matrix4 box_transform;
|
||||
struct matrix4 draw_transform;
|
||||
|
||||
enum obs_bounds_type bounds_type;
|
||||
uint32_t bounds_align;
|
||||
struct vec2 bounds;
|
||||
|
||||
/* would do **prev_next, but not really great for reordering */
|
||||
struct obs_scene_item *prev;
|
||||
|
||||
66
libobs/obs.h
66
libobs/obs.h
@@ -21,6 +21,7 @@
|
||||
#include "util/bmem.h"
|
||||
#include "graphics/graphics.h"
|
||||
#include "graphics/vec2.h"
|
||||
#include "graphics/vec3.h"
|
||||
#include "media-io/audio-io.h"
|
||||
#include "media-io/video-io.h"
|
||||
#include "callback/signal.h"
|
||||
@@ -32,6 +33,8 @@
|
||||
#include "obs-ui.h"
|
||||
#include "obs-properties.h"
|
||||
|
||||
struct matrix4;
|
||||
|
||||
/* opaque types */
|
||||
struct obs_display;
|
||||
struct obs_view;
|
||||
@@ -85,13 +88,38 @@ enum allow_direct_render {
|
||||
ALLOW_DIRECT_RENDERING,
|
||||
};
|
||||
|
||||
/**
|
||||
* Used with scene items to indicate the type of bounds to use for scene items.
|
||||
* Mostly determines how the image will be scaled within those bounds, or
|
||||
* whether to use bounds at all.
|
||||
*/
|
||||
enum obs_bounds_type {
|
||||
OBS_BOUNDS_NONE, /**< no bounds */
|
||||
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_MAX_ONLY, /**< no scaling, maximum size only */
|
||||
};
|
||||
|
||||
struct obs_sceneitem_info {
|
||||
struct vec2 pos;
|
||||
float rot;
|
||||
struct vec2 scale;
|
||||
uint32_t alignment;
|
||||
|
||||
enum obs_bounds_type bounds_type;
|
||||
uint32_t bounds_alignment;
|
||||
struct vec2 bounds;
|
||||
};
|
||||
|
||||
/**
|
||||
* Video initialization structure
|
||||
*/
|
||||
struct obs_video_info {
|
||||
/**
|
||||
* Graphics module to use (usually "libobs-opengl" or
|
||||
* "libobs-d3d11")
|
||||
* Graphics module to use (usually "libobs-opengl" or "libobs-d3d11")
|
||||
*/
|
||||
const char *graphics_module;
|
||||
|
||||
@@ -669,20 +697,44 @@ EXPORT obs_scene_t obs_sceneitem_getscene(obs_sceneitem_t item);
|
||||
/** Gets the source of a scene item. */
|
||||
EXPORT obs_source_t obs_sceneitem_getsource(obs_sceneitem_t item);
|
||||
|
||||
/* Functions for gettings/setting specific oriantation of a scene item */
|
||||
EXPORT void obs_sceneitem_select(obs_sceneitem_t item, bool select);
|
||||
EXPORT bool obs_sceneitem_selected(obs_sceneitem_t item);
|
||||
|
||||
/* Functions for gettings/setting specific orientation of a scene item */
|
||||
EXPORT void obs_sceneitem_setpos(obs_sceneitem_t item, const struct vec2 *pos);
|
||||
EXPORT void obs_sceneitem_setrot(obs_sceneitem_t item, float rot);
|
||||
EXPORT void obs_sceneitem_setorigin(obs_sceneitem_t item,
|
||||
const struct vec2 *origin);
|
||||
EXPORT void obs_sceneitem_setrot(obs_sceneitem_t item, float rot_deg);
|
||||
EXPORT void obs_sceneitem_setscale(obs_sceneitem_t item,
|
||||
const struct vec2 *scale);
|
||||
EXPORT void obs_sceneitem_setalignment(obs_sceneitem_t item,
|
||||
uint32_t alignment);
|
||||
EXPORT void obs_sceneitem_setorder(obs_sceneitem_t item,
|
||||
enum order_movement movement);
|
||||
|
||||
EXPORT void obs_sceneitem_set_bounds_type(obs_sceneitem_t item,
|
||||
enum obs_bounds_type type);
|
||||
EXPORT void obs_sceneitem_set_bounds_alignment(obs_sceneitem_t item,
|
||||
uint32_t alignment);
|
||||
EXPORT void obs_sceneitem_set_bounds(obs_sceneitem_t item,
|
||||
const struct vec2 *bounds);
|
||||
|
||||
EXPORT void obs_sceneitem_getpos(obs_sceneitem_t item, struct vec2 *pos);
|
||||
EXPORT float obs_sceneitem_getrot(obs_sceneitem_t item);
|
||||
EXPORT void obs_sceneitem_getorigin(obs_sceneitem_t item, struct vec2 *center);
|
||||
EXPORT void obs_sceneitem_getscale(obs_sceneitem_t item, struct vec2 *scale);
|
||||
EXPORT uint32_t obs_sceneitem_getalignment(obs_sceneitem_t item);
|
||||
|
||||
EXPORT enum obs_bounds_type obs_sceneitem_get_bounds_type(obs_sceneitem_t item);
|
||||
EXPORT uint32_t obs_sceneitem_get_bounds_alignment(obs_sceneitem_t item);
|
||||
EXPORT void obs_sceneitem_get_bounds(obs_sceneitem_t item, struct vec2 *bounds);
|
||||
|
||||
EXPORT void obs_sceneitem_get_info(obs_sceneitem_t item,
|
||||
struct obs_sceneitem_info *info);
|
||||
EXPORT void obs_sceneitem_set_info(obs_sceneitem_t item,
|
||||
const struct obs_sceneitem_info *info);
|
||||
|
||||
EXPORT void obs_sceneitem_get_draw_transform(obs_sceneitem_t item,
|
||||
struct matrix4 *transform);
|
||||
EXPORT void obs_sceneitem_get_box_transform(obs_sceneitem_t item,
|
||||
struct matrix4 *transform);
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -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"
|
||||
@@ -47,6 +48,8 @@
|
||||
#include <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
#define PREVIEW_EDGE_SIZE 10
|
||||
|
||||
using namespace std;
|
||||
|
||||
Q_DECLARE_METATYPE(OBSScene);
|
||||
@@ -55,15 +58,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 +438,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 +507,8 @@ void OBSBasic::OBSInit()
|
||||
if (!InitService())
|
||||
throw "Failed to initialize service";
|
||||
|
||||
InitPrimitives();
|
||||
|
||||
Load(savePath);
|
||||
ResetAudioDevices();
|
||||
}
|
||||
@@ -501,14 +519,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();
|
||||
}
|
||||
|
||||
@@ -788,24 +818,73 @@ void OBSBasic::ChannelChanged(void *data, calldata_t params)
|
||||
Q_ARG(OBSSource, OBSSource(source)));
|
||||
}
|
||||
|
||||
void OBSBasic::DrawBackdrop(float cx, float cy)
|
||||
{
|
||||
if (!box)
|
||||
return;
|
||||
|
||||
effect_t solid = obs_get_solid_effect();
|
||||
eparam_t color = effect_getparambyname(solid, "color");
|
||||
technique_t tech = effect_gettechnique(solid, "Solid");
|
||||
|
||||
vec4 colorVal;
|
||||
vec4_set(&colorVal, 0.0f, 0.0f, 0.0f, 1.0f);
|
||||
effect_setvec4(solid, color, &colorVal);
|
||||
|
||||
technique_begin(tech);
|
||||
technique_beginpass(tech, 0);
|
||||
gs_matrix_push();
|
||||
gs_matrix_identity();
|
||||
gs_matrix_scale3f(float(cx), float(cy), 1.0f);
|
||||
|
||||
gs_load_vertexbuffer(box);
|
||||
gs_draw(GS_TRISTRIP, 0, 0);
|
||||
|
||||
gs_matrix_pop();
|
||||
technique_endpass(tech);
|
||||
technique_end(tech);
|
||||
|
||||
gs_load_vertexbuffer(nullptr);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
window->DrawBackdrop(float(ovi.base_width), float(ovi.base_height));
|
||||
|
||||
obs_render_main_view();
|
||||
gs_load_vertexbuffer(nullptr);
|
||||
|
||||
/* --------------------------------------- */
|
||||
|
||||
float right = float(window->ui->preview->width()) - window->previewX;
|
||||
float bottom = float(window->ui->preview->height()) - window->previewY;
|
||||
|
||||
gs_ortho(-window->previewX, right,
|
||||
-window->previewY, bottom,
|
||||
-100.0f, 100.0f);
|
||||
gs_resetviewport();
|
||||
|
||||
window->ui->preview->DrawSceneEditing();
|
||||
|
||||
/* --------------------------------------- */
|
||||
|
||||
gs_projection_pop();
|
||||
gs_viewport_pop();
|
||||
@@ -981,9 +1060,13 @@ void OBSBasic::ResizePreview(uint32_t cx, uint32_t cy)
|
||||
/* resize preview panel to fix to the top section of the window */
|
||||
targetSize = GetPixelSize(ui->preview);
|
||||
GetScaleAndCenterPos(int(cx), int(cy),
|
||||
targetSize.width(), targetSize.height(),
|
||||
targetSize.width() - PREVIEW_EDGE_SIZE * 2,
|
||||
targetSize.height() - PREVIEW_EDGE_SIZE * 2,
|
||||
previewX, previewY, previewScale);
|
||||
|
||||
previewX += float(PREVIEW_EDGE_SIZE);
|
||||
previewY += float(PREVIEW_EDGE_SIZE);
|
||||
|
||||
if (isVisible()) {
|
||||
if (resizeTimer)
|
||||
killTimer(resizeTimer);
|
||||
@@ -1155,8 +1238,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 +1667,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,43 @@ 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 DrawBackdrop(float cx, float cy);
|
||||
|
||||
void SetupEncoders();
|
||||
|
||||
@@ -97,7 +107,8 @@ private:
|
||||
|
||||
void InitOBSCallbacks();
|
||||
|
||||
OBSScene GetCurrentScene();
|
||||
void InitPrimitives();
|
||||
|
||||
OBSSceneItem GetCurrentSceneItem();
|
||||
|
||||
void GetFPSCommon(uint32_t &num, uint32_t &den) const;
|
||||
@@ -153,6 +164,8 @@ private:
|
||||
void AddSourcePopupMenu(const QPoint &pos);
|
||||
|
||||
public:
|
||||
OBSScene GetCurrentScene();
|
||||
|
||||
obs_service_t GetService();
|
||||
void SetService(obs_service_t service);
|
||||
|
||||
@@ -167,6 +180,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 +199,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 +229,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">
|
||||
|
||||
Reference in New Issue
Block a user