From 27310f8b2cb91734083e73ccb8f6825c88fb32ca Mon Sep 17 00:00:00 2001 From: jp9000 Date: Wed, 30 Mar 2016 18:46:02 -0700 Subject: [PATCH] UI: Add ability to crop scene items via the alt key --- obs/window-basic-preview.cpp | 166 +++++++++++++++++++++++++++++++++-- obs/window-basic-preview.hpp | 5 ++ 2 files changed, 166 insertions(+), 5 deletions(-) diff --git a/obs/window-basic-preview.cpp b/obs/window-basic-preview.cpp index 5a6ea6f8a..5d3017698 100644 --- a/obs/window-basic-preview.cpp +++ b/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); diff --git a/obs/window-basic-preview.hpp b/obs/window-basic-preview.hpp index aaa8bddc2..4507f61b2 100644 --- a/obs/window-basic-preview.hpp +++ b/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);