diff --git a/src/WSRequestHandler.cpp b/src/WSRequestHandler.cpp index 77411461..cb3eabe0 100644 --- a/src/WSRequestHandler.cpp +++ b/src/WSRequestHandler.cpp @@ -60,6 +60,7 @@ const QHash WSRequestHandler::messageMap { { "SetSceneItemProperties", &WSRequestHandler::SetSceneItemProperties }, { "ResetSceneItem", &WSRequestHandler::ResetSceneItem }, { "DeleteSceneItem", &WSRequestHandler::DeleteSceneItem }, + { "AddSceneItem", &WSRequestHandler::AddSceneItem }, { "DuplicateSceneItem", &WSRequestHandler::DuplicateSceneItem }, { "ReorderSceneItems", &WSRequestHandler::ReorderSceneItems }, diff --git a/src/WSRequestHandler.h b/src/WSRequestHandler.h index 2a33c8f4..a334a1a9 100644 --- a/src/WSRequestHandler.h +++ b/src/WSRequestHandler.h @@ -78,6 +78,7 @@ class WSRequestHandler { RpcResponse ResetSceneItem(const RpcRequest&); RpcResponse DuplicateSceneItem(const RpcRequest&); RpcResponse DeleteSceneItem(const RpcRequest&); + RpcResponse AddSceneItem(const RpcRequest&); RpcResponse ReorderSceneItems(const RpcRequest&); RpcResponse GetStreamingStatus(const RpcRequest&); diff --git a/src/WSRequestHandler_SceneItems.cpp b/src/WSRequestHandler_SceneItems.cpp index c1fd8522..abff904f 100644 --- a/src/WSRequestHandler_SceneItems.cpp +++ b/src/WSRequestHandler_SceneItems.cpp @@ -2,6 +2,18 @@ #include "WSRequestHandler.h" +struct AddSourceData { + obs_source_t *source; + obs_sceneitem_t *sceneItem; + bool setVisible; +}; + +void AddSourceHelper(void *_data, obs_scene_t *scene) { + auto *data = reinterpret_cast(_data); + data->sceneItem = obs_scene_add(scene, data->source); + obs_sceneitem_set_visible(data->sceneItem, data->setVisible); +} + /** * 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). @@ -37,7 +49,7 @@ * @return {int} `alignment` The point on the source that the item is manipulated from. The sum of 1=Left or 2=Right, and 4=Top or 8=Bottom, or omit to center on that axis. * @return {String (optional)} `parentGroupName` Name of the item's parent (if this item belongs to a group) * @return {Array (optional)} `groupChildren` List of children (if this item is a group) -* +* * @api requests * @name GetSceneItemProperties * @category scene items @@ -164,7 +176,7 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) 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"); } @@ -252,7 +264,7 @@ RpcResponse WSRequestHandler::SetSceneItemProperties(const RpcRequest& request) } 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)) { @@ -455,7 +467,7 @@ RpcResponse WSRequestHandler::SetSceneItemTransform(const RpcRequest& request) { obs_sceneitem_set_scale(sceneItem, &scale); obs_sceneitem_set_rot(sceneItem, rotation); - + obs_sceneitem_defer_update_end(sceneItem); return request.success(); @@ -544,6 +556,59 @@ RpcResponse WSRequestHandler::DeleteSceneItem(const RpcRequest& request) { return request.success(); } +/** + * Creates a scene item in a scene. In other words, this is how you add a source into a scene. + * + * @param {String} `sceneName` Name of the scene to create the scene item in + * @param {String} `sourceName` Name of the source to be added + * @param {boolean} `setVisible` Whether to make the sceneitem visible on creation or not. Default `true` + * + * @return {int} `itemId` Numerical ID of the created scene item + * + * @api requests + * @name AddSceneItem + * @category scene items + * @since unreleased + */ +RpcResponse WSRequestHandler::AddSceneItem(const RpcRequest& request) { + if (!request.hasField("sceneName") || !request.hasField("sourceName")) { + return request.failed("missing request parameters"); + } + + const char* sceneName = obs_data_get_string(request.parameters(), "sceneName"); + OBSSourceAutoRelease sceneSource = obs_get_source_by_name(sceneName); + OBSScene scene = obs_scene_from_source(sceneSource); + if (!scene) { + return request.failed("requested scene is invalid or doesnt exist"); + } + + const char* sourceName = obs_data_get_string(request.parameters(), "sourceName"); + OBSSourceAutoRelease source = obs_get_source_by_name(sourceName); + if (!source) { + return request.failed("requested source does not exist"); + } + + if (source == sceneSource) { + return request.failed("you cannot add a scene as a sceneitem to itself"); + } + + AddSourceData data; + data.source = source; + data.setVisible = true; + if (request.hasField("setVisible")) { + data.setVisible = obs_data_get_bool(request.parameters(), "setVisible"); + } + + obs_enter_graphics(); + obs_scene_atomic_update(scene, AddSourceHelper, &data); + obs_leave_graphics(); + + OBSDataAutoRelease responseData = obs_data_create(); + obs_data_set_int(responseData, "itemID", obs_sceneitem_get_id(data.sceneItem)); + + return request.success(responseData); +} + /** * Duplicates a scene item. *