Browse Source

UI: Add ability to crop scene items via the alt key

jp9000 9 years ago
parent
commit
27310f8b2c
2 changed files with 166 additions and 5 deletions
  1. 161 5
      obs/window-basic-preview.cpp
  2. 5 0
      obs/window-basic-preview.hpp

+ 161 - 5
obs/window-basic-preview.cpp

@@ -284,11 +284,15 @@ static vec2 GetItemSize(obs_sceneitem_t *item)
 		obs_sceneitem_get_bounds(item, &size);
 	} else {
 		obs_source_t *source = obs_sceneitem_get_source(item);
+		obs_sceneitem_crop crop;
 		vec2 scale;
 
 		obs_sceneitem_get_scale(item, &scale);
-		size.x = float(obs_source_get_width(source))  * scale.x;
-		size.y = float(obs_source_get_height(source)) * scale.y;
+		obs_sceneitem_get_crop(item, &crop);
+		size.x = float(obs_source_get_width(source) -
+				crop.left - crop.right) * scale.x;
+		size.y = float(obs_source_get_height(source) -
+				crop.top - crop.bottom) * scale.y;
 	}
 
 	return size;
@@ -331,6 +335,15 @@ void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
 				-itemUL.x, -itemUL.y, 0.0f);
 		matrix4_rotate_aa4f(&screenToItem, &screenToItem,
 				0.0f, 0.0f, 1.0f, RAD(-itemRot));
+
+		obs_sceneitem_get_crop(stretchItem, &startCrop);
+		obs_sceneitem_get_pos(stretchItem, &startItemPos);
+
+		obs_source_t *source = obs_sceneitem_get_source(stretchItem);
+		cropSize.x = float(obs_source_get_width(source) -
+				startCrop.left - startCrop.right);
+		cropSize.y = float(obs_source_get_height(source) -
+				startCrop.top - startCrop.bottom);
 	}
 }
 
@@ -340,6 +353,8 @@ void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
 	float pixelRatio = main->devicePixelRatio();
 	float x = float(event->x()) - main->previewX / pixelRatio;
 	float y = float(event->y()) - main->previewY / pixelRatio;
+	Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
+	bool altDown = (modifiers & Qt::AltModifier);
 
 	OBSQTDisplay::mousePressEvent(event);
 
@@ -350,6 +365,9 @@ void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
 	if (event->button() == Qt::LeftButton)
 		mouseDown = true;
 
+	if (altDown)
+		cropping = true;
+
 	vec2_set(&startPos, x, y);
 	GetStretchHandleData(startPos);
 
@@ -412,6 +430,7 @@ void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event)
 		stretchItem = nullptr;
 		mouseDown   = false;
 		mouseMoved  = false;
+		cropping    = false;
 	}
 }
 
@@ -603,6 +622,121 @@ void OBSBasicPreview::SnapStretchingToScreen(vec3 &tl, vec3 &br)
 		br.y += offset.y;
 }
 
+void OBSBasicPreview::CropItem(const vec2 &pos)
+{
+	obs_bounds_type boundsType = obs_sceneitem_get_bounds_type(stretchItem);
+	uint32_t stretchFlags = (uint32_t)stretchHandle;
+	uint32_t align = obs_sceneitem_get_alignment(stretchItem);
+	vec3 tl, br, pos3;
+
+	if (boundsType != OBS_BOUNDS_NONE) /* TODO */
+		return;
+
+	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);
+
+	obs_sceneitem_crop crop = startCrop;
+	vec2 scale;
+
+	obs_sceneitem_get_scale(stretchItem, &scale);
+
+	vec2 max_tl;
+	vec2 max_br;
+
+	vec2_set(&max_tl,
+		float(-crop.left) * scale.x,
+		float(-crop.top) * scale.y);
+	vec2_set(&max_br,
+		stretchItemSize.x + crop.right * scale.x,
+		stretchItemSize.y + crop.bottom * scale.y);
+
+	vec2_max((vec2*)&pos3, (vec2*)&pos3, &max_br);
+	vec2_min((vec2*)&pos3, (vec2*)&pos3, &max_tl);
+
+	if (stretchFlags & ITEM_LEFT) {
+		tl.x = pos3.x;
+
+		float maxX = stretchItemSize.x - (2.0 * scale.x);
+		if (tl.x > maxX) pos3.x = tl.x = maxX;
+	} else if (stretchFlags & ITEM_RIGHT) {
+		br.x = pos3.x;
+
+		float minX = (2.0 * scale.x);
+		if (br.x < minX) pos3.x = br.x = minX;
+	}
+
+	if (stretchFlags & ITEM_TOP) {
+		tl.y = pos3.y;
+
+		float maxY = stretchItemSize.y - (2.0 * scale.y);
+		if (tl.y > maxY) pos3.y = tl.y = maxY;
+	} else if (stretchFlags & ITEM_BOTTOM) {
+		br.y = pos3.y;
+
+		float minY = (2.0 * scale.y);
+		if (br.y < minY) pos3.y = br.y = minY;
+	}
+
+#define ALIGN_X (ITEM_LEFT|ITEM_RIGHT)
+#define ALIGN_Y (ITEM_TOP|ITEM_BOTTOM)
+	vec3 newPos;
+	vec3_zero(&newPos);
+
+	uint32_t align_x = (align & ALIGN_X);
+	uint32_t align_y = (align & ALIGN_Y);
+	if (align_x == (stretchFlags & ALIGN_X) && align_x != 0)
+		newPos.x = pos3.x;
+	else if (align & ITEM_RIGHT)
+		newPos.x = stretchItemSize.x;
+	else if (!(align & ITEM_LEFT))
+		newPos.x = stretchItemSize.x * 0.5f;
+
+	if (align_y == (stretchFlags & ALIGN_Y) && align_y != 0)
+		newPos.y = pos3.y;
+	else if (align & ITEM_BOTTOM)
+		newPos.y = stretchItemSize.y;
+	else if (!(align & ITEM_TOP))
+		newPos.y = stretchItemSize.y * 0.5f;
+#undef ALIGN_X
+#undef ALIGN_Y
+
+	crop = startCrop;
+
+	if (stretchFlags & ITEM_LEFT)
+		crop.left += int(std::round(tl.x / scale.x));
+	else if (stretchFlags & ITEM_RIGHT)
+		crop.right += int(std::round((stretchItemSize.x - br.x) / scale.x));
+
+	if (stretchFlags & ITEM_TOP)
+		crop.top += int(std::round(tl.y / scale.y));
+	else if (stretchFlags & ITEM_BOTTOM)
+		crop.bottom += int(std::round((stretchItemSize.y - br.y) / scale.y));
+
+	vec3_transform(&newPos, &newPos, &itemToScreen);
+	newPos.x = std::round(newPos.x);
+	newPos.y = std::round(newPos.y);
+
+#if 0
+	vec3 curPos;
+	vec3_zero(&curPos);
+	obs_sceneitem_get_pos(stretchItem, (vec2*)&curPos);
+	blog(LOG_DEBUG, "curPos {%d, %d} - newPos {%d, %d}",
+			int(curPos.x), int(curPos.y),
+			int(newPos.x), int(newPos.y));
+	blog(LOG_DEBUG, "crop {%d, %d, %d, %d}",
+			crop.left, crop.top,
+			crop.right, crop.bottom);
+#endif
+
+	obs_sceneitem_defer_update_begin(stretchItem);
+	obs_sceneitem_set_crop(stretchItem, &crop);
+	obs_sceneitem_set_pos(stretchItem, (vec2*)&newPos);
+	obs_sceneitem_defer_update_end(stretchItem);
+}
+
 void OBSBasicPreview::StretchItem(const vec2 &pos)
 {
 	Qt::KeyboardModifiers modifiers = QGuiApplication::keyboardModifiers();
@@ -651,6 +785,12 @@ void OBSBasicPreview::StretchItem(const vec2 &pos)
 
 		obs_sceneitem_set_bounds(stretchItem, &size);
 	} else {
+		obs_sceneitem_crop crop;
+		obs_sceneitem_get_crop(stretchItem, &crop);
+
+		baseSize.x -= float(crop.left + crop.right);
+		baseSize.y -= float(crop.top + crop.bottom);
+
 		if (!shiftDown)
 			ClampAspect(tl, br, size, baseSize);
 
@@ -680,10 +820,15 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
 		pos.x = std::round(pos.x);
 		pos.y = std::round(pos.y);
 
-		if (stretchHandle != ItemHandle::None)
-			StretchItem(pos);
-		else if (mouseOverItems)
+		if (stretchHandle != ItemHandle::None) {
+			if (cropping)
+				CropItem(pos);
+			else
+				StretchItem(pos);
+
+		} else if (mouseOverItems) {
 			MoveItems(pos);
+		}
 
 		mouseMoved = true;
 	}
@@ -704,6 +849,14 @@ static void DrawCircleAtPos(float x, float y, matrix4 &matrix,
 	gs_matrix_pop();
 }
 
+static inline bool crop_enabled(const obs_sceneitem_crop *crop)
+{
+	return crop->left > 0  ||
+	       crop->top > 0   ||
+	       crop->right > 0 ||
+	       crop->bottom > 0;
+}
+
 bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
 		obs_sceneitem_t *item, void *param)
 {
@@ -736,6 +889,9 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
 	if (!visible)
 		return true;
 
+	obs_transform_info info;
+	obs_sceneitem_get_info(item, &info);
+
 	gs_load_vertexbuffer(main->circle);
 
 	DrawCircleAtPos(0.0f, 0.0f, boxTransform, main->previewScale);

+ 5 - 0
obs/window-basic-preview.hpp

@@ -30,6 +30,9 @@ class OBSBasicPreview : public OBSQTDisplay {
 	Q_OBJECT
 
 private:
+	obs_sceneitem_crop startCrop;
+	vec2         startItemPos;
+	vec2         cropSize;
 	OBSSceneItem stretchItem;
 	ItemHandle   stretchHandle = ItemHandle::None;
 	vec2         stretchItemSize;
@@ -41,6 +44,7 @@ private:
 	bool         mouseDown      = false;
 	bool         mouseMoved     = false;
 	bool         mouseOverItems = false;
+	bool         cropping       = false;
 
 	static vec2 GetMouseEventPos(QMouseEvent *event);
 	static bool DrawSelectedItem(obs_scene_t *scene, obs_sceneitem_t *item,
@@ -59,6 +63,7 @@ private:
 	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 CropItem(const vec2 &pos);
 	void StretchItem(const vec2 &pos);
 
 	static void SnapItemMovement(vec2 &offset);