diff --git a/src/Utils.cpp b/src/Utils.cpp
index 3f3013cc..ecd6039f 100644
--- a/src/Utils.cpp
+++ b/src/Utils.cpp
@@ -28,6 +28,25 @@ with this program. If not, see
Q_DECLARE_METATYPE(OBSScene);
+const QHash 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) {
if (!strings)
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") &&
(QString)obs_source_get_name(obs_sceneitem_get_source(sceneItem)) !=
(QString)obs_data_get_string(item, "name")) {
- return nullptr;
+ return nullptr;
}
}
else if (obs_data_has_user_value(item, "name")) {
@@ -554,75 +573,70 @@ bool Utils::SetFilenameFormatting(const char* filenameFormatting) {
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) {
- obs_data_t* data = obs_data_create();
+ 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();
- 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));
+ obs_data_set_int(posData, "alignment", alignment);
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_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;
diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp
index 99d5cf31..ca3d496d 100644
--- a/src/WSEvents.cpp
+++ b/src/WSEvents.cpp
@@ -920,6 +920,7 @@ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) {
*
* @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
@@ -940,9 +941,12 @@ void WSEvents::OnSceneItemTransform(void* param, calldata_t* data) {
const char* sceneItemName =
obs_source_get_name(obs_sceneitem_get_source(sceneItem));
- OBSDataAutoRelease fields = Utils::GetSceneItemPropertiesData(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);
}
diff --git a/src/WSRequestHandler_SceneItems.cpp b/src/WSRequestHandler_SceneItems.cpp
index edd8e74a..6b19ae97 100644
--- a/src/WSRequestHandler_SceneItems.cpp
+++ b/src/WSRequestHandler_SceneItems.cpp
@@ -21,7 +21,7 @@
* @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 {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 {double} `bounds.x` Width of the bounding box.
* @return {double} `bounds.y` Height of the bounding box.
@@ -75,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.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 {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 {double} `bounds.x` The new width of the bounding box.
* @param {double} `bounds.y` The new height of the bounding box.
@@ -238,7 +238,7 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemProperties(WSRequestHandler*
if (badRequest) {
return req->SendErrorResponse(errorMessage);
}
-
+
return req->SendOKResponse();
}
@@ -363,7 +363,7 @@ HandlerResponse WSRequestHandler::HandleSetSceneItemPosition(WSRequestHandler* r
if (!sceneItem) {
return req->SendErrorResponse("specified scene item doesn't exist");
}
-
+
vec2 item_position = { 0 };
item_position.x = obs_data_get_double(req->data, "x");
item_position.y = obs_data_get_double(req->data, "y");
@@ -530,7 +530,7 @@ static void DuplicateSceneItem(void *_data, obs_scene_t *scene) {
* @return {Object} `item` New item info
* @return {int} `̀€item.id` New item ID
* @return {String} `item.name` New item name
- *
+ *
* @api requests
* @name DuplicateSceneItem
* @category scene items