From 6c880fb3c8628ea54b182f36a23f55e2ffd60f43 Mon Sep 17 00:00:00 2001 From: VodBox Date: Fri, 8 Feb 2019 20:58:40 +1300 Subject: [PATCH] UI: Change preview handles/outline and add hover --- UI/source-tree.cpp | 12 +++ UI/source-tree.hpp | 11 +++ UI/window-basic-preview.cpp | 169 ++++++++++++++++++++++++++++-------- UI/window-basic-preview.hpp | 2 + 4 files changed, 159 insertions(+), 35 deletions(-) diff --git a/UI/source-tree.cpp b/UI/source-tree.cpp index 4fa84e681..fc31f80eb 100644 --- a/UI/source-tree.cpp +++ b/UI/source-tree.cpp @@ -35,6 +35,7 @@ SourceTreeItem::SourceTreeItem(SourceTree *tree_, OBSSceneItem sceneitem_) sceneitem (sceneitem_) { setAttribute(Qt::WA_TranslucentBackground); + setMouseTracking(true); obs_source_t *source = obs_sceneitem_get_source(sceneitem); const char *name = obs_source_get_name(source); @@ -911,6 +912,8 @@ SourceTree::SourceTree(QWidget *parent_) : QListView(parent_) "*[bgColor=\"6\"]{background-color:rgba(255,68,255,33%);}" \ "*[bgColor=\"7\"]{background-color:rgba(68,68,68,33%);}" \ "*[bgColor=\"8\"]{background-color:rgba(255,255,255,33%);}")); + + setMouseTracking(true); } void SourceTree::ResetWidgets() @@ -1264,6 +1267,15 @@ void SourceTree::dropEvent(QDropEvent *event) QListView::dropEvent(event); } +void SourceTree::mouseMoveEvent(QMouseEvent *event) +{ + QPoint pos = event->pos(); + SourceTreeItem *item = qobject_cast + (childAt(pos)); + + currentHover = item; +} + void SourceTree::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected) diff --git a/UI/source-tree.hpp b/UI/source-tree.hpp index 5893fafa8..0d7dff79f 100644 --- a/UI/source-tree.hpp +++ b/UI/source-tree.hpp @@ -142,6 +142,8 @@ class SourceTree : public QListView { return reinterpret_cast(model()); } + SourceTreeItem *currentHover; + public: inline SourceTreeItem *GetItemWidget(int idx) { @@ -149,6 +151,14 @@ public: return reinterpret_cast(widget); } + inline SourceTreeItem *GetHoveredItem() + { + if (underMouse()) { + return currentHover; + } + return nullptr; + } + explicit SourceTree(QWidget *parent = nullptr); inline bool IgnoreReorder() const {return ignoreReorder;} @@ -175,6 +185,7 @@ public slots: protected: virtual void mouseDoubleClickEvent(QMouseEvent *event) override; virtual void dropEvent(QDropEvent *event) override; + virtual void mouseMoveEvent(QMouseEvent *event) override; virtual void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected) override; }; diff --git a/UI/window-basic-preview.cpp b/UI/window-basic-preview.cpp index e75a384ea..34dbf9186 100644 --- a/UI/window-basic-preview.cpp +++ b/UI/window-basic-preview.cpp @@ -612,6 +612,9 @@ void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event) mouseDown = false; mouseMoved = false; cropping = false; + + OBSSceneItem item = GetItemAtPos(pos, true); + hovered = item; } } @@ -1158,6 +1161,8 @@ void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event) return; if (mouseDown) { + hovered = nullptr; + vec2 pos = GetMouseEventPos(event); if (!mouseMoved && !mouseOverItems && @@ -1194,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); @@ -1209,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 || @@ -1327,10 +1406,17 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene, gs_matrix_pop(); } - if (!obs_sceneitem_selected(item)) - return true; - OBSBasic *main = reinterpret_cast(App()->GetMainWindow()); + OBSBasicPreview *prev = reinterpret_cast(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; @@ -1344,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) { @@ -1359,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, 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); -#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); + 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(); diff --git a/UI/window-basic-preview.hpp b/UI/window-basic-preview.hpp index be075fd7f..707328da2 100644 --- a/UI/window-basic-preview.hpp +++ b/UI/window-basic-preview.hpp @@ -56,6 +56,7 @@ private: bool locked = false; bool scrollMode = false; bool fixedScaling = false; + OBSSceneItem hovered = nullptr; int32_t scalingLevel = 0; float scalingAmount = 1.0f; @@ -98,6 +99,7 @@ public: virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseReleaseEvent(QMouseEvent *event) override; virtual void mouseMoveEvent(QMouseEvent *event) override; + virtual void leaveEvent(QEvent *event) override; void DrawOverflow(); void DrawSceneEditing();