mirror of
https://github.com/Palakis/obs-websocket.git
synced 2024-08-30 18:12:16 +00:00
Merge pull request #272 from BarryCarlyon/scene_item_transform
Support item_transform signal
This commit is contained in:
commit
2eb6463ab0
@ -28,6 +28,25 @@ with this program. If not, see <https://www.gnu.org/licenses/>
|
|||||||
|
|
||||||
Q_DECLARE_METATYPE(OBSScene);
|
Q_DECLARE_METATYPE(OBSScene);
|
||||||
|
|
||||||
|
const QHash<obs_bounds_type, QString> boundTypeNames = {
|
||||||
|
{ OBS_BOUNDS_STRETCH, "OBS_BOUNDS_STRETCH" },
|
||||||
|
{ OBS_BOUNDS_SCALE_INNER, "OBS_BOUNDS_SCALE_INNER" },
|
||||||
|
{ OBS_BOUNDS_SCALE_OUTER, "OBS_BOUNDS_SCALE_OUTER" },
|
||||||
|
{ OBS_BOUNDS_SCALE_TO_WIDTH, "OBS_BOUNDS_SCALE_TO_WIDTH" },
|
||||||
|
{ OBS_BOUNDS_SCALE_TO_HEIGHT, "OBS_BOUNDS_SCALE_TO_HEIGHT" },
|
||||||
|
{ OBS_BOUNDS_MAX_ONLY, "OBS_BOUNDS_MAX_ONLY" },
|
||||||
|
{ OBS_BOUNDS_NONE, "OBS_BOUNDS_NONE" },
|
||||||
|
};
|
||||||
|
|
||||||
|
QString getBoundsNameFromType(obs_bounds_type type) {
|
||||||
|
QString fallback = boundTypeNames.value(OBS_BOUNDS_NONE);
|
||||||
|
return boundTypeNames.value(type, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_bounds_type getBoundsTypeFromName(QString name) {
|
||||||
|
return boundTypeNames.key(name);
|
||||||
|
}
|
||||||
|
|
||||||
obs_data_array_t* Utils::StringListToArray(char** strings, char* key) {
|
obs_data_array_t* Utils::StringListToArray(char** strings, char* key) {
|
||||||
if (!strings)
|
if (!strings)
|
||||||
return obs_data_array_create();
|
return obs_data_array_create();
|
||||||
@ -110,7 +129,7 @@ obs_sceneitem_t* Utils::GetSceneItemFromItem(obs_source_t* source, obs_data_t* i
|
|||||||
if (obs_data_has_user_value(item, "name") &&
|
if (obs_data_has_user_value(item, "name") &&
|
||||||
(QString)obs_source_get_name(obs_sceneitem_get_source(sceneItem)) !=
|
(QString)obs_source_get_name(obs_sceneitem_get_source(sceneItem)) !=
|
||||||
(QString)obs_data_get_string(item, "name")) {
|
(QString)obs_data_get_string(item, "name")) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (obs_data_has_user_value(item, "name")) {
|
else if (obs_data_has_user_value(item, "name")) {
|
||||||
@ -553,3 +572,72 @@ bool Utils::SetFilenameFormatting(const char* filenameFormatting) {
|
|||||||
config_save(profile);
|
config_save(profile);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Transform properties copy-pasted from WSRequestHandler_SceneItems.cpp because typedefs can't be extended yet
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {Object} `SceneItemTransform`
|
||||||
|
* @property {int} `position.x` The x position of the scene item from the left.
|
||||||
|
* @property {int} `position.y` The y position of the scene item from the top.
|
||||||
|
* @property {int} `position.alignment` The point on the scene item that the item is manipulated from.
|
||||||
|
* @property {double} `rotation` The clockwise rotation of the scene item in degrees around the point of alignment.
|
||||||
|
* @property {double} `scale.x` The x-scale factor of the scene item.
|
||||||
|
* @property {double} `scale.y` The y-scale factor of the scene item.
|
||||||
|
* @property {int} `crop.top` The number of pixels cropped off the top of the scene item before scaling.
|
||||||
|
* @property {int} `crop.right` The number of pixels cropped off the right of the scene item before scaling.
|
||||||
|
* @property {int} `crop.bottom` The number of pixels cropped off the bottom of the scene item before scaling.
|
||||||
|
* @property {int} `crop.left` The number of pixels cropped off the left of the scene item before scaling.
|
||||||
|
* @property {bool} `visible` If the scene item is visible.
|
||||||
|
* @property {String} `bounds.type` Type of bounding box. Can be "OBS_BOUNDS_STRETCH", "OBS_BOUNDS_SCALE_INNER", "OBS_BOUNDS_SCALE_OUTER", "OBS_BOUNDS_SCALE_TO_WIDTH", "OBS_BOUNDS_SCALE_TO_HEIGHT", "OBS_BOUNDS_MAX_ONLY" or "OBS_BOUNDS_NONE".
|
||||||
|
* @property {int} `bounds.alignment` Alignment of the bounding box.
|
||||||
|
* @property {double} `bounds.x` Width of the bounding box.
|
||||||
|
* @property {double} `bounds.y` Height of the bounding box.
|
||||||
|
*/
|
||||||
|
obs_data_t* Utils::GetSceneItemPropertiesData(obs_sceneitem_t* sceneItem) {
|
||||||
|
vec2 pos, scale, bounds;
|
||||||
|
obs_sceneitem_crop crop;
|
||||||
|
|
||||||
|
obs_sceneitem_get_pos(sceneItem, &pos);
|
||||||
|
obs_sceneitem_get_scale(sceneItem, &scale);
|
||||||
|
obs_sceneitem_get_crop(sceneItem, &crop);
|
||||||
|
obs_sceneitem_get_bounds(sceneItem, &bounds);
|
||||||
|
|
||||||
|
uint32_t alignment = obs_sceneitem_get_alignment(sceneItem);
|
||||||
|
float rotation = obs_sceneitem_get_rot(sceneItem);
|
||||||
|
bool isVisible = obs_sceneitem_visible(sceneItem);
|
||||||
|
|
||||||
|
obs_bounds_type boundsType = obs_sceneitem_get_bounds_type(sceneItem);
|
||||||
|
uint32_t boundsAlignment = obs_sceneitem_get_bounds_alignment(sceneItem);
|
||||||
|
QString boundsTypeName = getBoundsNameFromType(boundsType);
|
||||||
|
|
||||||
|
OBSDataAutoRelease posData = obs_data_create();
|
||||||
|
obs_data_set_double(posData, "x", pos.x);
|
||||||
|
obs_data_set_double(posData, "y", pos.y);
|
||||||
|
obs_data_set_int(posData, "alignment", alignment);
|
||||||
|
|
||||||
|
OBSDataAutoRelease scaleData = obs_data_create();
|
||||||
|
obs_data_set_double(scaleData, "x", scale.x);
|
||||||
|
obs_data_set_double(scaleData, "y", scale.y);
|
||||||
|
|
||||||
|
OBSDataAutoRelease cropData = obs_data_create();
|
||||||
|
obs_data_set_int(cropData, "left", crop.left);
|
||||||
|
obs_data_set_int(cropData, "top", crop.top);
|
||||||
|
obs_data_set_int(cropData, "right", crop.right);
|
||||||
|
obs_data_set_int(cropData, "bottom", crop.bottom);
|
||||||
|
|
||||||
|
OBSDataAutoRelease boundsData = obs_data_create();
|
||||||
|
obs_data_set_string(boundsData, "type", boundsTypeName.toUtf8());
|
||||||
|
obs_data_set_int(boundsData, "alignment", boundsAlignment);
|
||||||
|
obs_data_set_double(boundsData, "x", bounds.x);
|
||||||
|
obs_data_set_double(boundsData, "y", bounds.y);
|
||||||
|
|
||||||
|
obs_data_t* data = obs_data_create();
|
||||||
|
obs_data_set_obj(data, "position", posData);
|
||||||
|
obs_data_set_double(data, "rotation", rotation);
|
||||||
|
obs_data_set_obj(data, "scale", scaleData);
|
||||||
|
obs_data_set_obj(data, "crop", cropData);
|
||||||
|
obs_data_set_bool(data, "visible", isVisible);
|
||||||
|
obs_data_set_obj(data, "bounds", boundsData);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
@ -41,6 +41,7 @@ class Utils {
|
|||||||
static obs_sceneitem_t* GetSceneItemFromItem(obs_source_t* source, obs_data_t* item);
|
static obs_sceneitem_t* GetSceneItemFromItem(obs_source_t* source, obs_data_t* item);
|
||||||
static obs_source_t* GetTransitionFromName(QString transitionName);
|
static obs_source_t* GetTransitionFromName(QString transitionName);
|
||||||
static obs_source_t* GetSceneFromNameOrCurrent(QString sceneName);
|
static obs_source_t* GetSceneFromNameOrCurrent(QString sceneName);
|
||||||
|
static obs_data_t* GetSceneItemPropertiesData(obs_sceneitem_t* item);
|
||||||
|
|
||||||
static bool IsValidAlignment(const uint32_t alignment);
|
static bool IsValidAlignment(const uint32_t alignment);
|
||||||
|
|
||||||
|
@ -256,6 +256,8 @@ void WSEvents::connectSceneSignals(obs_source_t* scene) {
|
|||||||
"item_remove", OnSceneItemDelete, this);
|
"item_remove", OnSceneItemDelete, this);
|
||||||
signal_handler_disconnect(sh,
|
signal_handler_disconnect(sh,
|
||||||
"item_visible", OnSceneItemVisibilityChanged, this);
|
"item_visible", OnSceneItemVisibilityChanged, this);
|
||||||
|
signal_handler_disconnect(sh,
|
||||||
|
"item_transform", OnSceneItemTransform, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentScene = scene;
|
currentScene = scene;
|
||||||
@ -271,6 +273,8 @@ void WSEvents::connectSceneSignals(obs_source_t* scene) {
|
|||||||
"item_remove", OnSceneItemDelete, this);
|
"item_remove", OnSceneItemDelete, this);
|
||||||
signal_handler_connect(sh,
|
signal_handler_connect(sh,
|
||||||
"item_visible", OnSceneItemVisibilityChanged, this);
|
"item_visible", OnSceneItemVisibilityChanged, this);
|
||||||
|
signal_handler_connect(sh,
|
||||||
|
"item_transform", OnSceneItemTransform, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,6 +915,42 @@ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
|
|||||||
instance->broadcastUpdate("SceneItemVisibilityChanged", fields);
|
instance->broadcastUpdate("SceneItemVisibilityChanged", fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An item's transfrom has been changed.
|
||||||
|
*
|
||||||
|
* @return {String} `scene-name` Name of the scene.
|
||||||
|
* @return {String} `item-name` Name of the item in the scene.
|
||||||
|
* @return {SceneItemProperties} `transform` Scene item transform properties
|
||||||
|
*
|
||||||
|
* @api events
|
||||||
|
* @name SceneItemTransformChanged
|
||||||
|
* @category sources
|
||||||
|
* @since unreleased
|
||||||
|
*/
|
||||||
|
void WSEvents::OnSceneItemTransform(void* param, calldata_t* data) {
|
||||||
|
WSEvents* instance = static_cast<WSEvents*>(param);
|
||||||
|
|
||||||
|
obs_scene_t* scene = nullptr;
|
||||||
|
calldata_get_ptr(data, "scene", &scene);
|
||||||
|
|
||||||
|
obs_sceneitem_t* sceneItem = nullptr;
|
||||||
|
calldata_get_ptr(data, "item", &sceneItem);
|
||||||
|
|
||||||
|
const char* sceneName =
|
||||||
|
obs_source_get_name(obs_scene_get_source(scene));
|
||||||
|
const char* sceneItemName =
|
||||||
|
obs_source_get_name(obs_sceneitem_get_source(sceneItem));
|
||||||
|
|
||||||
|
OBSDataAutoRelease transform = Utils::GetSceneItemPropertiesData(sceneItem);
|
||||||
|
|
||||||
|
OBSDataAutoRelease fields = obs_data_create();
|
||||||
|
obs_data_set_string(fields, "scene-name", sceneName);
|
||||||
|
obs_data_set_string(fields, "item-name", sceneItemName);
|
||||||
|
obs_data_set_obj(fields, "transform", transform);
|
||||||
|
|
||||||
|
instance->broadcastUpdate("SceneItemTransformChanged", fields);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The selected preview scene has changed (only available in Studio Mode).
|
* The selected preview scene has changed (only available in Studio Mode).
|
||||||
*
|
*
|
||||||
|
@ -116,4 +116,5 @@ private:
|
|||||||
static void OnSceneItemAdd(void* param, calldata_t* data);
|
static void OnSceneItemAdd(void* param, calldata_t* data);
|
||||||
static void OnSceneItemDelete(void* param, calldata_t* data);
|
static void OnSceneItemDelete(void* param, calldata_t* data);
|
||||||
static void OnSceneItemVisibilityChanged(void* param, calldata_t* data);
|
static void OnSceneItemVisibilityChanged(void* param, calldata_t* data);
|
||||||
|
static void OnSceneItemTransform(void* param, calldata_t* data);
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
* @return {int} `crop.bottom` The number of pixels cropped off the bottom of the source before scaling.
|
* @return {int} `crop.bottom` The number of pixels cropped off the bottom of the source before scaling.
|
||||||
* @return {int} `crop.left` The number of pixels cropped off the left of the source before scaling.
|
* @return {int} `crop.left` The number of pixels cropped off the left of the source before scaling.
|
||||||
* @return {bool} `visible` If the source is visible.
|
* @return {bool} `visible` If the source is visible.
|
||||||
* @return {String} `bounds.type` Type of bounding box.
|
* @return {String} `bounds.type` Type of bounding box. Can be "OBS_BOUNDS_STRETCH", "OBS_BOUNDS_SCALE_INNER", "OBS_BOUNDS_SCALE_OUTER", "OBS_BOUNDS_SCALE_TO_WIDTH", "OBS_BOUNDS_SCALE_TO_HEIGHT", "OBS_BOUNDS_MAX_ONLY" or "OBS_BOUNDS_NONE".
|
||||||
* @return {int} `bounds.alignment` Alignment of the bounding box.
|
* @return {int} `bounds.alignment` Alignment of the bounding box.
|
||||||
* @return {double} `bounds.x` Width of the bounding box.
|
* @return {double} `bounds.x` Width of the bounding box.
|
||||||
* @return {double} `bounds.y` Height of the bounding box.
|
* @return {double} `bounds.y` Height of the bounding box.
|
||||||
@ -53,77 +53,9 @@ HandlerResponse WSRequestHandler::HandleGetSceneItemProperties(WSRequestHandler*
|
|||||||
return req->SendErrorResponse("specified scene item doesn't exist");
|
return req->SendErrorResponse("specified scene item doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSDataAutoRelease data = obs_data_create();
|
OBSDataAutoRelease data = Utils::GetSceneItemPropertiesData(sceneItem);
|
||||||
obs_data_set_string(data, "name", itemName.toUtf8());
|
obs_data_set_string(data, "name", itemName.toUtf8());
|
||||||
|
|
||||||
OBSDataAutoRelease posData = obs_data_create();
|
|
||||||
vec2 pos;
|
|
||||||
obs_sceneitem_get_pos(sceneItem, &pos);
|
|
||||||
obs_data_set_double(posData, "x", pos.x);
|
|
||||||
obs_data_set_double(posData, "y", pos.y);
|
|
||||||
obs_data_set_int(posData, "alignment", obs_sceneitem_get_alignment(sceneItem));
|
|
||||||
obs_data_set_obj(data, "position", posData);
|
|
||||||
|
|
||||||
obs_data_set_double(data, "rotation", obs_sceneitem_get_rot(sceneItem));
|
|
||||||
|
|
||||||
OBSDataAutoRelease scaleData = obs_data_create();
|
|
||||||
vec2 scale;
|
|
||||||
obs_sceneitem_get_scale(sceneItem, &scale);
|
|
||||||
obs_data_set_double(scaleData, "x", scale.x);
|
|
||||||
obs_data_set_double(scaleData, "y", scale.y);
|
|
||||||
obs_data_set_obj(data, "scale", scaleData);
|
|
||||||
|
|
||||||
OBSDataAutoRelease cropData = obs_data_create();
|
|
||||||
obs_sceneitem_crop crop;
|
|
||||||
obs_sceneitem_get_crop(sceneItem, &crop);
|
|
||||||
obs_data_set_int(cropData, "left", crop.left);
|
|
||||||
obs_data_set_int(cropData, "top", crop.top);
|
|
||||||
obs_data_set_int(cropData, "right", crop.right);
|
|
||||||
obs_data_set_int(cropData, "bottom", crop.bottom);
|
|
||||||
obs_data_set_obj(data, "crop", cropData);
|
|
||||||
|
|
||||||
obs_data_set_bool(data, "visible", obs_sceneitem_visible(sceneItem));
|
|
||||||
|
|
||||||
OBSDataAutoRelease boundsData = obs_data_create();
|
|
||||||
obs_bounds_type boundsType = obs_sceneitem_get_bounds_type(sceneItem);
|
|
||||||
if (boundsType == OBS_BOUNDS_NONE) {
|
|
||||||
obs_data_set_string(boundsData, "type", "OBS_BOUNDS_NONE");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
switch (boundsType) {
|
|
||||||
case OBS_BOUNDS_STRETCH: {
|
|
||||||
obs_data_set_string(boundsData, "type", "OBS_BOUNDS_STRETCH");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OBS_BOUNDS_SCALE_INNER: {
|
|
||||||
obs_data_set_string(boundsData, "type", "OBS_BOUNDS_SCALE_INNER");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OBS_BOUNDS_SCALE_OUTER: {
|
|
||||||
obs_data_set_string(boundsData, "type", "OBS_BOUNDS_SCALE_OUTER");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OBS_BOUNDS_SCALE_TO_WIDTH: {
|
|
||||||
obs_data_set_string(boundsData, "type", "OBS_BOUNDS_SCALE_TO_WIDTH");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OBS_BOUNDS_SCALE_TO_HEIGHT: {
|
|
||||||
obs_data_set_string(boundsData, "type", "OBS_BOUNDS_SCALE_TO_HEIGHT");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case OBS_BOUNDS_MAX_ONLY: {
|
|
||||||
obs_data_set_string(boundsData, "type", "OBS_BOUNDS_MAX_ONLY");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
obs_data_set_int(boundsData, "alignment", obs_sceneitem_get_bounds_alignment(sceneItem));
|
|
||||||
vec2 bounds;
|
|
||||||
obs_sceneitem_get_bounds(sceneItem, &bounds);
|
|
||||||
obs_data_set_double(boundsData, "x", bounds.x);
|
|
||||||
obs_data_set_double(boundsData, "y", bounds.y);
|
|
||||||
}
|
|
||||||
obs_data_set_obj(data, "bounds", boundsData);
|
|
||||||
|
|
||||||
return req->SendOKResponse(data);
|
return req->SendOKResponse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +75,7 @@ HandlerResponse WSRequestHandler::HandleGetSceneItemProperties(WSRequestHandler*
|
|||||||
* @param {int} `crop.left` The new amount of pixels cropped off the left of the source before scaling.
|
* @param {int} `crop.left` The new amount of pixels cropped off the left of the source before scaling.
|
||||||
* @param {int} `crop.right` The new amount of pixels cropped off the right of the source before scaling.
|
* @param {int} `crop.right` The new amount of pixels cropped off the right of the source before scaling.
|
||||||
* @param {bool} `visible` The new visibility of the source. 'true' shows source, 'false' hides source.
|
* @param {bool} `visible` The new visibility of the source. 'true' shows source, 'false' hides source.
|
||||||
* @param {String} `bounds.type` The new bounds type of the source.
|
* @param {String} `bounds.type` The new bounds type of the source. Can be "OBS_BOUNDS_STRETCH", "OBS_BOUNDS_SCALE_INNER", "OBS_BOUNDS_SCALE_OUTER", "OBS_BOUNDS_SCALE_TO_WIDTH", "OBS_BOUNDS_SCALE_TO_HEIGHT", "OBS_BOUNDS_MAX_ONLY" or "OBS_BOUNDS_NONE".
|
||||||
* @param {int} `bounds.alignment` The new alignment of the bounding box. (0-2, 4-6, 8-10)
|
* @param {int} `bounds.alignment` The new alignment of the bounding box. (0-2, 4-6, 8-10)
|
||||||
* @param {double} `bounds.x` The new width of the bounding box.
|
* @param {double} `bounds.x` The new width of the bounding box.
|
||||||
* @param {double} `bounds.y` The new height of the bounding box.
|
* @param {double} `bounds.y` The new height of the bounding box.
|
||||||
@ -306,7 +238,7 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler*
|
|||||||
if (badRequest) {
|
if (badRequest) {
|
||||||
return req->SendErrorResponse(errorMessage);
|
return req->SendErrorResponse(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return req->SendOKResponse();
|
return req->SendOKResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +363,7 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemPosition(WSRequestHandler* r
|
|||||||
if (!sceneItem) {
|
if (!sceneItem) {
|
||||||
return req->SendErrorResponse("specified scene item doesn't exist");
|
return req->SendErrorResponse("specified scene item doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 item_position = { 0 };
|
vec2 item_position = { 0 };
|
||||||
item_position.x = obs_data_get_double(req->data, "x");
|
item_position.x = obs_data_get_double(req->data, "x");
|
||||||
item_position.y = obs_data_get_double(req->data, "y");
|
item_position.y = obs_data_get_double(req->data, "y");
|
||||||
@ -598,7 +530,7 @@ static void DuplicateSceneItem(void *_data, obs_scene_t *scene) {
|
|||||||
* @return {Object} `item` New item info
|
* @return {Object} `item` New item info
|
||||||
* @return {int} `̀item.id` New item ID
|
* @return {int} `̀item.id` New item ID
|
||||||
* @return {String} `item.name` New item name
|
* @return {String} `item.name` New item name
|
||||||
*
|
*
|
||||||
* @api requests
|
* @api requests
|
||||||
* @name DuplicateSceneItem
|
* @name DuplicateSceneItem
|
||||||
* @category scene items
|
* @category scene items
|
||||||
|
Loading…
x
Reference in New Issue
Block a user