diff --git a/src/Utils.cpp b/src/Utils.cpp index 978162be..dd5ad14a 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -180,34 +180,6 @@ obs_data_t* Utils::GetSceneItemData(obs_sceneitem_t* item) { return data; } -obs_sceneitem_t* Utils::GetSceneItemFromItem(obs_scene_t* scene, obs_data_t* itemInfo) { - if (!scene) { - return nullptr; - } - - OBSDataItemAutoRelease idInfoItem = obs_data_item_byname(itemInfo, "id"); - int id = obs_data_item_get_int(idInfoItem); - - OBSDataItemAutoRelease nameInfoItem = obs_data_item_byname(itemInfo, "name"); - const char* name = obs_data_item_get_string(nameInfoItem); - - if (idInfoItem) { - obs_sceneitem_t* sceneItem = GetSceneItemFromId(scene, id); - obs_source_t* sceneItemSource = obs_sceneitem_get_source(sceneItem); - - QString sceneItemName = obs_source_get_name(sceneItemSource); - if (nameInfoItem && (QString(name) != sceneItemName)) { - return nullptr; - } - - return sceneItem; - } else if (nameInfoItem) { - return GetSceneItemFromName(scene, name); - } - - return nullptr; -} - obs_sceneitem_t* Utils::GetSceneItemFromName(obs_scene_t* scene, QString name) { if (!scene) { return nullptr; @@ -297,6 +269,49 @@ obs_sceneitem_t* Utils::GetSceneItemFromId(obs_scene_t* scene, int64_t id) { return search.result; } +obs_sceneitem_t* Utils::GetSceneItemFromItem(obs_scene_t* scene, obs_data_t* itemInfo) { + if (!scene) { + return nullptr; + } + + OBSDataItemAutoRelease idInfoItem = obs_data_item_byname(itemInfo, "id"); + int id = obs_data_item_get_int(idInfoItem); + + OBSDataItemAutoRelease nameInfoItem = obs_data_item_byname(itemInfo, "name"); + const char* name = obs_data_item_get_string(nameInfoItem); + + if (idInfoItem) { + obs_sceneitem_t* sceneItem = GetSceneItemFromId(scene, id); + obs_source_t* sceneItemSource = obs_sceneitem_get_source(sceneItem); + + QString sceneItemName = obs_source_get_name(sceneItemSource); + if (nameInfoItem && (QString(name) != sceneItemName)) { + return nullptr; + } + + return sceneItem; + } else if (nameInfoItem) { + return GetSceneItemFromName(scene, name); + } + + return nullptr; +} + +obs_sceneitem_t* Utils::GetSceneItemFromRequestField(obs_scene_t* scene, obs_data_item_t* dataItem) +{ + enum obs_data_type dataType = obs_data_item_gettype(dataItem); + + if (dataType == OBS_DATA_OBJECT) { + OBSDataAutoRelease itemData = obs_data_item_get_obj(dataItem); + return GetSceneItemFromItem(scene, itemData); + } else if (dataType == OBS_DATA_STRING) { + QString name = obs_data_item_get_string(dataItem); + return GetSceneItemFromName(scene, name); + } + + return nullptr; +} + bool Utils::IsValidAlignment(const uint32_t alignment) { switch (alignment) { case OBS_ALIGN_CENTER: diff --git a/src/Utils.h b/src/Utils.h index 5934ad4e..dbe2481f 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -39,11 +39,12 @@ namespace Utils { obs_data_array_t* GetSceneItems(obs_source_t* source); obs_data_t* GetSceneItemData(obs_sceneitem_t* item); - // These two functions support nested lookup into groups + // These functions support nested lookup into groups obs_sceneitem_t* GetSceneItemFromName(obs_scene_t* scene, QString name); obs_sceneitem_t* GetSceneItemFromId(obs_scene_t* scene, int64_t id); - obs_sceneitem_t* GetSceneItemFromItem(obs_scene_t* scene, obs_data_t* item); + obs_sceneitem_t* GetSceneItemFromRequestField(obs_scene_t* scene, obs_data_item_t* dataItem); + obs_scene_t* GetSceneFromNameOrCurrent(QString sceneName); obs_data_t* GetSceneItemPropertiesData(obs_sceneitem_t* item); diff --git a/src/WSEvents.cpp b/src/WSEvents.cpp index e2c0684f..37ada8ee 100644 --- a/src/WSEvents.cpp +++ b/src/WSEvents.cpp @@ -1345,7 +1345,7 @@ void WSEvents::OnSourceFilterOrderChanged(void* param, calldata_t* data) { * * @api events * @name SourceOrderChanged - * @category sources + * @category scene items * @since 4.0.0 */ void WSEvents::OnSceneReordered(void* param, calldata_t* data) { @@ -1387,7 +1387,7 @@ void WSEvents::OnSceneReordered(void* param, calldata_t* data) { * * @api events * @name SceneItemAdded - * @category sources + * @category scene items * @since 4.0.0 */ void WSEvents::OnSceneItemAdd(void* param, calldata_t* data) { @@ -1420,7 +1420,7 @@ void WSEvents::OnSceneItemAdd(void* param, calldata_t* data) { * * @api events * @name SceneItemRemoved - * @category sources + * @category scene items * @since 4.0.0 */ void WSEvents::OnSceneItemDelete(void* param, calldata_t* data) { @@ -1454,7 +1454,7 @@ void WSEvents::OnSceneItemDelete(void* param, calldata_t* data) { * * @api events * @name SceneItemVisibilityChanged - * @category sources + * @category scene items * @since 4.0.0 */ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) { @@ -1492,7 +1492,7 @@ void WSEvents::OnSceneItemVisibilityChanged(void* param, calldata_t* data) { * * @api events * @name SceneItemLockChanged - * @category sources + * @category scene items * @since 4.8.0 */ void WSEvents::OnSceneItemLockChanged(void* param, calldata_t* data) { @@ -1530,7 +1530,7 @@ void WSEvents::OnSceneItemLockChanged(void* param, calldata_t* data) { * * @api events * @name SceneItemTransformChanged - * @category sources + * @category scene items * @since 4.6.0 */ void WSEvents::OnSceneItemTransform(void* param, calldata_t* data) { @@ -1566,7 +1566,7 @@ void WSEvents::OnSceneItemTransform(void* param, calldata_t* data) { * * @api events * @name SceneItemSelected - * @category sources + * @category scene items * @since 4.6.0 */ void WSEvents::OnSceneItemSelected(void* param, calldata_t* data) { @@ -1601,7 +1601,7 @@ void WSEvents::OnSceneItemSelected(void* param, calldata_t* data) { * * @api events * @name SceneItemDeselected - * @category sources + * @category scene items * @since 4.6.0 */ void WSEvents::OnSceneItemDeselected(void* param, calldata_t* data) { diff --git a/src/WSRequestHandler_SceneItems.cpp b/src/WSRequestHandler_SceneItems.cpp index 5e736802..c1fd8522 100644 --- a/src/WSRequestHandler_SceneItems.cpp +++ b/src/WSRequestHandler_SceneItems.cpp @@ -6,10 +6,13 @@ * Gets the scene specific properties of the specified source item. * Coordinates are relative to the item's parent (the scene or group it belongs to). * -* @param {String (optional)} `scene-name` the name of the scene that the source item belongs to. Defaults to the current scene. -* @param {String} `item` The name of the source. +* @param {String (optional)} `scene-name` Name of the scene the scene item belongs to. Defaults to the current scene. +* @param {String | Object} `item` Scene Item name (if this field is a string) or specification (if it is an object). +* @param {String (optional)} `item.name` Scene Item name (if the `item` field is an object) +* @param {int (optional)} `item.id` Scene Item ID (if the `item` field is an object) * -* @return {String} `name` The name of the source. +* @return {String} `name` Scene Item name. +* @return {int} `itemId` Scene Item ID. * @return {int} `position.x` The x position of the source from the left. * @return {int} `position.y` The y position of the source from the top. * @return {int} `position.alignment` The point on the source that the item is manipulated from. @@ -45,24 +48,25 @@ RpcResponse WSRequestHandler::GetSceneItemProperties(const RpcRequest& request) return request.failed("missing request parameters"); } - QString itemName = obs_data_get_string(request.parameters(), "item"); - if (itemName.isEmpty()) { - return request.failed("invalid request parameters"); - } + OBSData params = request.parameters(); - QString sceneName = obs_data_get_string(request.parameters(), "scene-name"); + QString sceneName = obs_data_get_string(params, "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { return request.failed("requested scene doesn't exist"); } - OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); + OBSDataItemAutoRelease itemField = obs_data_item_byname(params, "item"); + OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromRequestField(scene, itemField); if (!sceneItem) { return request.failed("specified scene item doesn't exist"); } OBSDataAutoRelease data = Utils::GetSceneItemPropertiesData(sceneItem); - obs_data_set_string(data, "name", itemName.toUtf8()); + + OBSSource sceneItemSource = obs_sceneitem_get_source(sceneItem); + obs_data_set_string(data, "name", obs_source_get_name(sceneItemSource)); + obs_data_set_int(data, "itemId", obs_sceneitem_get_id(sceneItem)); return request.success(data); } @@ -71,8 +75,10 @@ RpcResponse WSRequestHandler::GetSceneItemProperties(const RpcRequest& request) * Sets the scene specific properties of a source. Unspecified properties will remain unchanged. * Coordinates are relative to the item's parent (the scene or group it belongs to). * -* @param {String (optional)} `scene-name` the name of the scene that the source item belongs to. Defaults to the current scene. -* @param {String} `item` The name of the source. +* @param {String (optional)} `scene-name` Name of the scene the source item belongs to. Defaults to the current scene. +* @param {String | Object} `item` Scene Item name (if this field is a string) or specification (if it is an object). +* @param {String (optional)} `item.name` Scene Item name (if the `item` field is an object) +* @param {int (optional)} `item.id` Scene Item ID (if the `item` field is an object) * @param {int (optional)} `position.x` The new x position of the source. * @param {int (optional)} `position.y` The new y position of the source. * @param {int (optional)} `position.alignment` The new alignment of the source. @@ -100,19 +106,16 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) return request.failed("missing request parameters"); } - QString itemName = obs_data_get_string(request.parameters(), "item"); - if (itemName.isEmpty()) { - return request.failed("invalid request parameters"); - } + OBSData params = request.parameters(); - QString sceneName = obs_data_get_string(request.parameters(), "scene-name"); + QString sceneName = obs_data_get_string(params, "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { return request.failed("requested scene doesn't exist"); } - OBSSceneItemAutoRelease sceneItem = - Utils::GetSceneItemFromName(scene, itemName); + OBSDataItemAutoRelease itemField = obs_data_item_byname(params, "item"); + OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromRequestField(scene, itemField); if (!sceneItem) { return request.failed("specified scene item doesn't exist"); } @@ -126,51 +129,59 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) vec2 oldPosition; OBSDataAutoRelease positionError = obs_data_create(); obs_sceneitem_get_pos(sceneItem, &oldPosition); - OBSDataAutoRelease reqPosition = obs_data_get_obj(request.parameters(), "position"); + + OBSDataAutoRelease reqPosition = obs_data_get_obj(params, "position"); vec2 newPosition = oldPosition; + if (obs_data_has_user_value(reqPosition, "x")) { newPosition.x = obs_data_get_int(reqPosition, "x"); } if (obs_data_has_user_value(reqPosition, "y")) { newPosition.y = obs_data_get_int(reqPosition, "y"); } + if (obs_data_has_user_value(reqPosition, "alignment")) { const uint32_t alignment = obs_data_get_int(reqPosition, "alignment"); if (Utils::IsValidAlignment(alignment)) { obs_sceneitem_set_alignment(sceneItem, alignment); - } - else { + } else { badRequest = true; obs_data_set_string(positionError, "alignment", "invalid"); obs_data_set_obj(errorData, "position", positionError); } } + obs_sceneitem_set_pos(sceneItem, &newPosition); } if (request.hasField("rotation")) { - obs_sceneitem_set_rot(sceneItem, (float)obs_data_get_double(request.parameters(), "rotation")); + obs_sceneitem_set_rot(sceneItem, (float)obs_data_get_double(params, "rotation")); } if (request.hasField("scale")) { vec2 oldScale; obs_sceneitem_get_scale(sceneItem, &oldScale); - OBSDataAutoRelease reqScale = obs_data_get_obj(request.parameters(), "scale"); vec2 newScale = oldScale; + + OBSDataAutoRelease reqScale = obs_data_get_obj(params, "scale"); + if (obs_data_has_user_value(reqScale, "x")) { newScale.x = obs_data_get_double(reqScale, "x"); } if (obs_data_has_user_value(reqScale, "y")) { newScale.y = obs_data_get_double(reqScale, "y"); } + obs_sceneitem_set_scale(sceneItem, &newScale); } if (request.hasField("crop")) { obs_sceneitem_crop oldCrop; obs_sceneitem_get_crop(sceneItem, &oldCrop); - OBSDataAutoRelease reqCrop = obs_data_get_obj(request.parameters(), "crop"); + + OBSDataAutoRelease reqCrop = obs_data_get_obj(params, "crop"); obs_sceneitem_crop newCrop = oldCrop; + if (obs_data_has_user_value(reqCrop, "top")) { newCrop.top = obs_data_get_int(reqCrop, "top"); } @@ -183,21 +194,23 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) if (obs_data_has_user_value(reqCrop, "left")) { newCrop.left = obs_data_get_int(reqCrop, "left"); } + obs_sceneitem_set_crop(sceneItem, &newCrop); } if (request.hasField("visible")) { - obs_sceneitem_set_visible(sceneItem, obs_data_get_bool(request.parameters(), "visible")); + obs_sceneitem_set_visible(sceneItem, obs_data_get_bool(params, "visible")); } if (request.hasField("locked")) { - obs_sceneitem_set_locked(sceneItem, obs_data_get_bool(request.parameters(), "locked")); + obs_sceneitem_set_locked(sceneItem, obs_data_get_bool(params, "locked")); } if (request.hasField("bounds")) { bool badBounds = false; OBSDataAutoRelease boundsError = obs_data_create(); - OBSDataAutoRelease reqBounds = obs_data_get_obj(request.parameters(), "bounds"); + OBSDataAutoRelease reqBounds = obs_data_get_obj(params, "bounds"); + if (obs_data_has_user_value(reqBounds, "type")) { QString newBoundsType = obs_data_get_string(reqBounds, "type"); if (newBoundsType == "OBS_BOUNDS_NONE") { @@ -226,16 +239,20 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) obs_data_set_string(boundsError, "type", "invalid"); } } + vec2 oldBounds; obs_sceneitem_get_bounds(sceneItem, &oldBounds); vec2 newBounds = oldBounds; + if (obs_data_has_user_value(reqBounds, "x")) { newBounds.x = obs_data_get_double(reqBounds, "x"); } if (obs_data_has_user_value(reqBounds, "y")) { newBounds.y = obs_data_get_double(reqBounds, "y"); } + obs_sceneitem_set_bounds(sceneItem, &newBounds); + if (obs_data_has_user_value(reqBounds, "alignment")) { const uint32_t bounds_alignment = obs_data_get_int(reqBounds, "alignment"); if (Utils::IsValidAlignment(bounds_alignment)) { @@ -246,6 +263,7 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) obs_data_set_string(boundsError, "alignment", "invalid"); } } + if (badBounds) { obs_data_set_obj(errorData, "bounds", boundsError); } @@ -263,8 +281,10 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) /** * Reset a scene item. * -* @param {String (optional)} `scene-name` Name of the scene the source belongs to. Defaults to the current scene. -* @param {String} `item` Name of the source item. +* @param {String (optional)} `scene-name` Name of the scene the scene item belongs to. Defaults to the current scene. +* @param {String | Object} `item` Scene Item name (if this field is a string) or specification (if it is an object). +* @param {String (optional)} `item.name` Scene Item name (if the `item` field is an object) +* @param {int (optional)} `item.id` Scene Item ID (if the `item` field is an object) * * @api requests * @name ResetSceneItem @@ -272,24 +292,20 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) * @since 4.2.0 */ RpcResponse WSRequestHandler::ResetSceneItem(const RpcRequest& request) { - // TODO: remove this request, or refactor it to ResetSource - if (!request.hasField("item")) { return request.failed("missing request parameters"); } - const char* itemName = obs_data_get_string(request.parameters(), "item"); - if (!itemName) { - return request.failed("invalid request parameters"); - } + OBSData params = request.parameters(); - const char* sceneName = obs_data_get_string(request.parameters(), "scene-name"); + const char* sceneName = obs_data_get_string(params, "scene-name"); OBSScene scene = Utils::GetSceneFromNameOrCurrent(sceneName); if (!scene) { return request.failed("requested scene doesn't exist"); } - OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromName(scene, itemName); + OBSDataItemAutoRelease itemField = obs_data_item_byname(params, "item"); + OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromRequestField(scene, itemField); if (!sceneItem) { return request.failed("specified scene item doesn't exist"); } @@ -305,9 +321,9 @@ RpcResponse WSRequestHandler::ResetSceneItem(const RpcRequest& request) { /** * Show or hide a specified source item in a specified scene. * -* @param {String} `source` Scene item name in the specified scene. +* @param {String (optional)} `scene-name` Name of the scene the scene item belongs to. Defaults to the currently active scene. +* @param {String} `source` Scene Item name. * @param {boolean} `render` true = shown ; false = hidden -* @param {String (optional)} `scene-name` Name of the scene where the source resides. Defaults to the currently active scene. * * @api requests * @name SetSceneItemRender @@ -348,8 +364,8 @@ RpcResponse WSRequestHandler::SetSceneItemRender(const RpcRequest& request) { /** * Sets the coordinates of a specified source item. * -* @param {String (optional)} `scene-name` The name of the scene that the source item belongs to. Defaults to the current scene. -* @param {String} `item` The name of the source item. +* @param {String (optional)} `scene-name` Name of the scene the scene item belongs to. Defaults to the current scene. +* @param {String} `item` Scene Item name. * @param {double} `x` X coordinate. * @param {double} `y` Y coordinate. @@ -393,8 +409,8 @@ RpcResponse WSRequestHandler::SetSceneItemPosition(const RpcRequest& request) { /** * Set the transform of the specified source item. * -* @param {String (optional)} `scene-name` The name of the scene that the source item belongs to. Defaults to the current scene. -* @param {String} `item` The name of the source item. +* @param {String (optional)} `scene-name` Name of the scene the scene item belongs to. Defaults to the current scene. +* @param {String} `item` Scene Item name. * @param {double} `x-scale` Width scale factor. * @param {double} `y-scale` Height scale factor. * @param {double} `rotation` Source item rotation (in degrees). @@ -448,8 +464,8 @@ RpcResponse WSRequestHandler::SetSceneItemTransform(const RpcRequest& request) { /** * Sets the crop coordinates of the specified source item. * -* @param {String (optional)} `scene-name` the name of the scene that the source item belongs to. Defaults to the current scene. -* @param {String} `item` The name of the source. +* @param {String (optional)} `scene-name` Name of the scene the scene item belongs to. Defaults to the current scene. +* @param {String} `item` Scene Item name. * @param {int} `top` Pixel position of the top of the source item. * @param {int} `bottom` Pixel position of the bottom of the source item. * @param {int} `left` Pixel position of the left of the source item. @@ -496,10 +512,10 @@ RpcResponse WSRequestHandler::SetSceneItemCrop(const RpcRequest& request) { /** * Deletes a scene item. * - * @param {String (optional)} `scene` Name of the scene the source belongs to. Defaults to the current scene. - * @param {Object} `item` item to delete (required) - * @param {String} `item.name` name of the scene item (prefer `id`, including both is acceptable). - * @param {int} `item.id` id of the scene item. + * @param {String (optional)} `scene` Name of the scene the scene item belongs to. Defaults to the current scene. + * @param {Object} `item` Scene item to delete (required) + * @param {String} `item.name` Scene Item name (prefer `id`, including both is acceptable). + * @param {int} `item.id` Scene Item ID. * * @api requests * @name DeleteSceneItem @@ -517,8 +533,8 @@ RpcResponse WSRequestHandler::DeleteSceneItem(const RpcRequest& request) { return request.failed("requested scene doesn't exist"); } - OBSDataAutoRelease item = obs_data_get_obj(request.parameters(), "item"); - OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromItem(scene, item); + OBSDataItemAutoRelease itemField = obs_data_item_byname(request.parameters(), "item"); + OBSSceneItemAutoRelease sceneItem = Utils::GetSceneItemFromRequestField(scene, itemField); if (!sceneItem) { return request.failed("item with id/name combination not found in specified scene"); } @@ -533,9 +549,9 @@ RpcResponse WSRequestHandler::DeleteSceneItem(const RpcRequest& request) { * * @param {String (optional)} `fromScene` Name of the scene to copy the item from. Defaults to the current scene. * @param {String (optional)} `toScene` Name of the scene to create the item in. Defaults to the current scene. - * @param {Object} `item` item to duplicate (required) - * @param {String} `item.name` name of the scene item (prefer `id`, including both is acceptable). - * @param {int} `item.id` id of the scene item. + * @param {Object} `item` Scene Item to duplicate from the source scene (required) + * @param {String} `item.name` Scene Item name (prefer `id`, including both is acceptable). + * @param {int} `item.id` Scene Item ID. * * @return {String} `scene` Name of the scene where the new item was created * @return {Object} `item` New item info @@ -570,8 +586,8 @@ RpcResponse WSRequestHandler::DuplicateSceneItem(const RpcRequest& request) { return request.failed("requested toScene doesn't exist"); } - OBSDataAutoRelease item = obs_data_get_obj(request.parameters(), "item"); - OBSSceneItemAutoRelease referenceItem = Utils::GetSceneItemFromItem(fromScene, item); + OBSDataItemAutoRelease itemField = obs_data_item_byname(request.parameters(), "item"); + OBSSceneItemAutoRelease referenceItem = Utils::GetSceneItemFromRequestField(fromScene, itemField); if (!referenceItem) { return request.failed("item with id/name combination not found in specified scene"); }