|
@@ -3,11 +3,13 @@
|
|
|
|
|
|
#include <algorithm>
|
|
|
#include <cmath>
|
|
|
+#include <string>
|
|
|
#include <graphics/vec4.h>
|
|
|
#include <graphics/matrix4.h>
|
|
|
#include "window-basic-preview.hpp"
|
|
|
#include "window-basic-main.hpp"
|
|
|
#include "obs-app.hpp"
|
|
|
+#include "platform.hpp"
|
|
|
|
|
|
#define HANDLE_RADIUS 4.0f
|
|
|
#define HANDLE_SEL_RADIUS (HANDLE_RADIUS * 1.5f)
|
|
@@ -24,6 +26,13 @@ OBSBasicPreview::OBSBasicPreview(QWidget *parent, Qt::WindowFlags flags)
|
|
|
setMouseTracking(true);
|
|
|
}
|
|
|
|
|
|
+OBSBasicPreview::~OBSBasicPreview()
|
|
|
+{
|
|
|
+ if (overflow) {
|
|
|
+ gs_texture_destroy(overflow);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
vec2 OBSBasicPreview::GetMouseEventPos(QMouseEvent *event)
|
|
|
{
|
|
|
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
|
@@ -603,6 +612,9 @@ void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event)
|
|
|
mouseDown = false;
|
|
|
mouseMoved = false;
|
|
|
cropping = false;
|
|
|
+
|
|
|
+ OBSSceneItem item = GetItemAtPos(pos, true);
|
|
|
+ hovered = item;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1149,6 +1161,8 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
|
|
|
return;
|
|
|
|
|
|
if (mouseDown) {
|
|
|
+ hovered = nullptr;
|
|
|
+
|
|
|
vec2 pos = GetMouseEventPos(event);
|
|
|
|
|
|
if (!mouseMoved && !mouseOverItems &&
|
|
@@ -1185,10 +1199,22 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
|
|
|
}
|
|
|
|
|
|
mouseMoved = true;
|
|
|
+ } else {
|
|
|
+ vec2 pos = GetMouseEventPos(event);
|
|
|
+ OBSSceneItem item = GetItemAtPos(pos, true);
|
|
|
+
|
|
|
+ hovered = item;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void DrawCircleAtPos(float x, float y)
|
|
|
+void OBSBasicPreview::leaveEvent(QEvent *event)
|
|
|
+{
|
|
|
+ hovered = nullptr;
|
|
|
+
|
|
|
+ UNUSED_PARAMETER(event);
|
|
|
+}
|
|
|
+
|
|
|
+static void DrawSquareAtPos(float x, float y)
|
|
|
{
|
|
|
struct vec3 pos;
|
|
|
vec3_set(&pos, x, y, 0.0f);
|
|
@@ -1200,11 +1226,73 @@ static void DrawCircleAtPos(float x, float y)
|
|
|
gs_matrix_push();
|
|
|
gs_matrix_identity();
|
|
|
gs_matrix_translate(&pos);
|
|
|
- gs_matrix_scale3f(HANDLE_RADIUS, HANDLE_RADIUS, 1.0f);
|
|
|
- gs_draw(GS_LINESTRIP, 0, 0);
|
|
|
+
|
|
|
+ gs_matrix_translate3f(-HANDLE_RADIUS, -HANDLE_RADIUS, 0.0f);
|
|
|
+ gs_matrix_scale3f(HANDLE_RADIUS*2, HANDLE_RADIUS*2, 1.0f);
|
|
|
+ gs_draw(GS_TRISTRIP, 0, 0);
|
|
|
gs_matrix_pop();
|
|
|
}
|
|
|
|
|
|
+static void DrawLine(float x1, float y1, float x2, float y2, float thickness)
|
|
|
+{
|
|
|
+ struct matrix4 matrix;
|
|
|
+ gs_matrix_get(&matrix);
|
|
|
+
|
|
|
+ float ySide = (y1 == y2) ? (y1 < 0.5f ? 1.0f : -1.0f) : 0.0f;
|
|
|
+ float xSide = (x1 == x2) ? (x1 < 0.5f ? 1.0f : -1.0f) : 0.0f;
|
|
|
+
|
|
|
+ gs_render_start(true);
|
|
|
+
|
|
|
+ gs_vertex2f(x1, y1);
|
|
|
+ gs_vertex2f(x1 + (xSide * (thickness / matrix.x.x)),
|
|
|
+ y1 + (ySide * (thickness / matrix.y.y)));
|
|
|
+ gs_vertex2f(x2 + (xSide * (thickness / matrix.x.x)),
|
|
|
+ y2 + (ySide * (thickness / matrix.y.y)));
|
|
|
+ gs_vertex2f(x2, y2);
|
|
|
+ gs_vertex2f(x1, y1);
|
|
|
+
|
|
|
+ gs_vertbuffer_t *line = gs_render_save();
|
|
|
+
|
|
|
+ gs_load_vertexbuffer(line);
|
|
|
+ gs_draw(GS_TRISTRIP, 0, 0);
|
|
|
+ gs_vertexbuffer_destroy(line);
|
|
|
+}
|
|
|
+
|
|
|
+static void DrawRect(float thickness)
|
|
|
+{
|
|
|
+ struct matrix4 matrix;
|
|
|
+ gs_matrix_get(&matrix);
|
|
|
+
|
|
|
+ gs_render_start(true);
|
|
|
+
|
|
|
+ gs_vertex2f(0.0f, 0.0f);
|
|
|
+ gs_vertex2f(0.0f + (thickness / matrix.x.x), 0.0f);
|
|
|
+ gs_vertex2f(0.0f + (thickness / matrix.x.x), 1.0f);
|
|
|
+ gs_vertex2f(0.0f, 1.0f);
|
|
|
+ gs_vertex2f(0.0f, 0.0f);
|
|
|
+ gs_vertex2f(0.0f, 1.0f);
|
|
|
+ gs_vertex2f(0.0f, 1.0f - (thickness / matrix.y.y));
|
|
|
+ gs_vertex2f(1.0f, 1.0f - (thickness / matrix.y.y));
|
|
|
+ gs_vertex2f(1.0f, 1.0f);
|
|
|
+ gs_vertex2f(0.0f, 1.0f);
|
|
|
+ gs_vertex2f(1.0f, 1.0f);
|
|
|
+ gs_vertex2f(1.0f - (thickness / matrix.x.x), 1.0f);
|
|
|
+ gs_vertex2f(1.0f - (thickness / matrix.x.x), 0.0f);
|
|
|
+ gs_vertex2f(1.0f, 0.0f);
|
|
|
+ gs_vertex2f(1.0f, 1.0f);
|
|
|
+ gs_vertex2f(1.0f, 0.0f);
|
|
|
+ gs_vertex2f(1.0f, 0.0f + (thickness / matrix.y.y));
|
|
|
+ gs_vertex2f(0.0f, 0.0f + (thickness / matrix.y.y));
|
|
|
+ gs_vertex2f(0.0f, 0.0f);
|
|
|
+ gs_vertex2f(1.0f, 0.0f);
|
|
|
+
|
|
|
+ gs_vertbuffer_t *rect = gs_render_save();
|
|
|
+
|
|
|
+ gs_load_vertexbuffer(rect);
|
|
|
+ gs_draw(GS_TRISTRIP, 0, 0);
|
|
|
+ gs_vertexbuffer_destroy(rect);
|
|
|
+}
|
|
|
+
|
|
|
static inline bool crop_enabled(const obs_sceneitem_crop *crop)
|
|
|
{
|
|
|
return crop->left > 0 ||
|
|
@@ -1213,6 +1301,92 @@ static inline bool crop_enabled(const obs_sceneitem_crop *crop)
|
|
|
crop->bottom > 0;
|
|
|
}
|
|
|
|
|
|
+bool OBSBasicPreview::DrawSelectedOverflow(obs_scene_t *scene,
|
|
|
+ obs_sceneitem_t *item, void *param)
|
|
|
+{
|
|
|
+ if (obs_sceneitem_locked(item))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (!SceneItemHasVideo(item))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ bool select = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
|
|
+ "OverflowSelectionHidden");
|
|
|
+
|
|
|
+ if (!select && !obs_sceneitem_visible(item))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ if (obs_sceneitem_is_group(item)) {
|
|
|
+ matrix4 mat;
|
|
|
+ obs_sceneitem_get_draw_transform(item, &mat);
|
|
|
+
|
|
|
+ gs_matrix_push();
|
|
|
+ gs_matrix_mul(&mat);
|
|
|
+ obs_sceneitem_group_enum_items(item, DrawSelectedOverflow, param);
|
|
|
+ gs_matrix_pop();
|
|
|
+ }
|
|
|
+
|
|
|
+ bool always = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
|
|
+ "OverflowAlwaysVisible");
|
|
|
+
|
|
|
+ if (!always && !obs_sceneitem_selected(item))
|
|
|
+ return true;
|
|
|
+
|
|
|
+ OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview*>(param);
|
|
|
+
|
|
|
+ matrix4 boxTransform;
|
|
|
+ matrix4 invBoxTransform;
|
|
|
+ obs_sceneitem_get_box_transform(item, &boxTransform);
|
|
|
+ matrix4_inv(&invBoxTransform, &boxTransform);
|
|
|
+
|
|
|
+ vec3 bounds[] = {
|
|
|
+ {{{0.f, 0.f, 0.f}}},
|
|
|
+ {{{1.f, 0.f, 0.f}}},
|
|
|
+ {{{0.f, 1.f, 0.f}}},
|
|
|
+ {{{1.f, 1.f, 0.f}}},
|
|
|
+ };
|
|
|
+
|
|
|
+ bool visible = std::all_of(std::begin(bounds), std::end(bounds),
|
|
|
+ [&](const vec3 &b)
|
|
|
+ {
|
|
|
+ vec3 pos;
|
|
|
+ vec3_transform(&pos, &b, &boxTransform);
|
|
|
+ vec3_transform(&pos, &pos, &invBoxTransform);
|
|
|
+ return CloseFloat(pos.x, b.x) && CloseFloat(pos.y, b.y);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!visible)
|
|
|
+ return true;
|
|
|
+
|
|
|
+ obs_transform_info info;
|
|
|
+ obs_sceneitem_get_info(item, &info);
|
|
|
+
|
|
|
+ gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_REPEAT);
|
|
|
+ gs_eparam_t *image = gs_effect_get_param_by_name(solid, "image");
|
|
|
+ gs_eparam_t *scale = gs_effect_get_param_by_name(solid, "scale");
|
|
|
+
|
|
|
+ vec2 s;
|
|
|
+ vec2_set(&s, boxTransform.x.x / 96, boxTransform.y.y / 96);
|
|
|
+
|
|
|
+ gs_effect_set_vec2(scale, &s);
|
|
|
+ gs_effect_set_texture(image, prev->overflow);
|
|
|
+
|
|
|
+ gs_matrix_push();
|
|
|
+ gs_matrix_mul(&boxTransform);
|
|
|
+
|
|
|
+ obs_sceneitem_crop crop;
|
|
|
+ obs_sceneitem_get_crop(item, &crop);
|
|
|
+
|
|
|
+ while (gs_effect_loop(solid, "Draw")) {
|
|
|
+ gs_draw_sprite(prev->overflow, 0, 1, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ gs_matrix_pop();
|
|
|
+
|
|
|
+ UNUSED_PARAMETER(scene);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|
|
obs_sceneitem_t *item, void *param)
|
|
|
{
|
|
@@ -1232,10 +1406,17 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|
|
gs_matrix_pop();
|
|
|
}
|
|
|
|
|
|
- if (!obs_sceneitem_selected(item))
|
|
|
- return true;
|
|
|
-
|
|
|
OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
|
|
+ OBSBasicPreview *prev = reinterpret_cast<OBSBasicPreview*>(param);
|
|
|
+
|
|
|
+ SourceTreeItem *hovItem = main->ui->sources->GetHoveredItem();
|
|
|
+ SourceTreeItem *curItem = main->GetItemWidgetFromSceneItem(item);
|
|
|
+
|
|
|
+ bool hover = (curItem && hovItem == curItem) || prev->hovered == item;
|
|
|
+ bool selected = obs_sceneitem_selected(item);
|
|
|
+
|
|
|
+ if (!selected && !hover)
|
|
|
+ return true;
|
|
|
|
|
|
matrix4 boxTransform;
|
|
|
matrix4 invBoxTransform;
|
|
@@ -1249,6 +1430,14 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|
|
{{{1.f, 1.f, 0.f}}},
|
|
|
};
|
|
|
|
|
|
+ vec4 red;
|
|
|
+ vec4 green;
|
|
|
+ vec4 blue;
|
|
|
+
|
|
|
+ vec4_set(&red, 1.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+ vec4_set(&green, 0.0f, 1.0f, 0.0f, 1.0f);
|
|
|
+ vec4_set(&blue, 0.0f, 0.5f, 1.0f, 1.0f);
|
|
|
+
|
|
|
bool visible = std::all_of(std::begin(bounds), std::end(bounds),
|
|
|
[&](const vec3 &b)
|
|
|
{
|
|
@@ -1264,45 +1453,50 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|
|
obs_transform_info info;
|
|
|
obs_sceneitem_get_info(item, &info);
|
|
|
|
|
|
- gs_load_vertexbuffer(main->circle);
|
|
|
-
|
|
|
gs_matrix_push();
|
|
|
gs_matrix_mul(&boxTransform);
|
|
|
|
|
|
- DrawCircleAtPos(0.0f, 0.0f);
|
|
|
- DrawCircleAtPos(0.0f, 1.0f);
|
|
|
- DrawCircleAtPos(1.0f, 0.0f);
|
|
|
- DrawCircleAtPos(1.0f, 1.0f);
|
|
|
- DrawCircleAtPos(0.5f, 0.0f);
|
|
|
- DrawCircleAtPos(0.0f, 0.5f);
|
|
|
- DrawCircleAtPos(0.5f, 1.0f);
|
|
|
- DrawCircleAtPos(1.0f, 0.5f);
|
|
|
-
|
|
|
obs_sceneitem_crop crop;
|
|
|
obs_sceneitem_get_crop(item, &crop);
|
|
|
|
|
|
+ gs_effect_t *eff = gs_get_effect();
|
|
|
+ gs_eparam_t *colParam = gs_effect_get_param_by_name(eff, "color");
|
|
|
+
|
|
|
if (info.bounds_type == OBS_BOUNDS_NONE && crop_enabled(&crop)) {
|
|
|
- vec4 color;
|
|
|
- gs_effect_t *eff = gs_get_effect();
|
|
|
- gs_eparam_t *param = gs_effect_get_param_by_name(eff, "color");
|
|
|
-
|
|
|
-#define DRAW_SIDE(side, vb) \
|
|
|
- if (crop.side > 0) \
|
|
|
- vec4_set(&color, 0.0f, 1.0f, 0.0f, 1.0f); \
|
|
|
- else \
|
|
|
- vec4_set(&color, 1.0f, 0.0f, 0.0f, 1.0f); \
|
|
|
- gs_effect_set_vec4(param, &color); \
|
|
|
- gs_load_vertexbuffer(main->vb); \
|
|
|
- gs_draw(GS_LINESTRIP, 0, 0);
|
|
|
-
|
|
|
- DRAW_SIDE(left, boxLeft);
|
|
|
- DRAW_SIDE(top, boxTop);
|
|
|
- DRAW_SIDE(right, boxRight);
|
|
|
- DRAW_SIDE(bottom, boxBottom);
|
|
|
+#define DRAW_SIDE(side, x1, y1, x2, y2) \
|
|
|
+ if (hover && !selected) \
|
|
|
+ gs_effect_set_vec4(colParam, &blue); \
|
|
|
+ else if (crop.side > 0) \
|
|
|
+ gs_effect_set_vec4(colParam, &green); \
|
|
|
+ DrawLine(x1, y1, x2, y2, HANDLE_RADIUS / 2); \
|
|
|
+ gs_effect_set_vec4(colParam, &red);
|
|
|
+
|
|
|
+ DRAW_SIDE(left, 0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
+ DRAW_SIDE(top, 0.0f, 0.0f, 1.0f, 0.0f);
|
|
|
+ DRAW_SIDE(right, 1.0f, 0.0f, 1.0f, 1.0f);
|
|
|
+ DRAW_SIDE(bottom, 0.0f, 1.0f, 1.0f, 1.0f);
|
|
|
#undef DRAW_SIDE
|
|
|
} else {
|
|
|
- gs_load_vertexbuffer(main->box);
|
|
|
- gs_draw(GS_LINESTRIP, 0, 0);
|
|
|
+ if (!selected) {
|
|
|
+ gs_effect_set_vec4(colParam, &blue);
|
|
|
+ DrawRect(HANDLE_RADIUS / 2);
|
|
|
+ } else {
|
|
|
+ DrawRect(HANDLE_RADIUS / 2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ gs_load_vertexbuffer(main->box);
|
|
|
+ gs_effect_set_vec4(colParam, &red);
|
|
|
+
|
|
|
+ if (selected) {
|
|
|
+ DrawSquareAtPos(0.0f, 0.0f);
|
|
|
+ DrawSquareAtPos(0.0f, 1.0f);
|
|
|
+ DrawSquareAtPos(1.0f, 0.0f);
|
|
|
+ DrawSquareAtPos(1.0f, 1.0f);
|
|
|
+ DrawSquareAtPos(0.5f, 0.0f);
|
|
|
+ DrawSquareAtPos(0.0f, 0.5f);
|
|
|
+ DrawSquareAtPos(0.5f, 1.0f);
|
|
|
+ DrawSquareAtPos(1.0f, 0.5f);
|
|
|
}
|
|
|
|
|
|
gs_matrix_pop();
|
|
@@ -1312,6 +1506,37 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+void OBSBasicPreview::DrawOverflow()
|
|
|
+{
|
|
|
+ if (locked)
|
|
|
+ return;
|
|
|
+
|
|
|
+ bool hidden = config_get_bool(GetGlobalConfig(), "BasicWindow",
|
|
|
+ "OverflowHidden");
|
|
|
+
|
|
|
+ if (hidden)
|
|
|
+ return;
|
|
|
+
|
|
|
+ if (!overflow) {
|
|
|
+ std::string path;
|
|
|
+ GetDataFilePath("images/overflow.png", path);
|
|
|
+ overflow = gs_texture_create_from_file(path.c_str());
|
|
|
+ }
|
|
|
+
|
|
|
+ OBSBasic *main = reinterpret_cast<OBSBasic*>(App()->GetMainWindow());
|
|
|
+
|
|
|
+ OBSScene scene = main->GetCurrentScene();
|
|
|
+
|
|
|
+ if (scene) {
|
|
|
+ gs_matrix_push();
|
|
|
+ gs_matrix_scale3f(main->previewScale, main->previewScale, 1.0f);
|
|
|
+ obs_scene_enum_items(scene, DrawSelectedOverflow, this);
|
|
|
+ gs_matrix_pop();
|
|
|
+ }
|
|
|
+
|
|
|
+ gs_load_vertexbuffer(nullptr);
|
|
|
+}
|
|
|
+
|
|
|
void OBSBasicPreview::DrawSceneEditing()
|
|
|
{
|
|
|
if (locked)
|