New MousePointer to change behavior of mouse

Initial implementation, mostly replicating GLMixer features. 5 Modes; default, linear, spring, wiggly and metronome. Save in Settings. Selection in Navigation panel.
This commit is contained in:
Bruno Herbelin
2023-08-19 23:39:41 +02:00
parent d743307e59
commit a8bb4ae6d1
10 changed files with 528 additions and 37 deletions

Binary file not shown.

View File

@@ -96,6 +96,7 @@ set(VMIX_SRCS
MultiFileRecorder.cpp
DisplaysView.cpp
ScreenCaptureSource.cpp
MousePointer.cpp
)
#####

View File

@@ -437,6 +437,41 @@ bool ImGuiToolkit::IconToggle(int i, int j, int i_toggle, int j_toggle, bool* to
}
bool ImGuiToolkit::IconToggle(int i, int j, bool* toggle, const char *tooltip, const char* shortcut)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
ImGui::PushID( i * 20 + j + ( tooltip ? window->GetID(tooltip) : 0) );
float frame_height = ImGui::GetFrameHeight();
ImVec2 draw_pos = ImGui::GetCursorScreenPos();
// toggle action : operate on the whole area
bool ret = false;
ImGui::InvisibleButton("##iconijtogglebutton", ImVec2(frame_height, frame_height));
if (ImGui::IsItemClicked()) {
*toggle = !*toggle;
ret = true;
}
if (tooltip != nullptr && ImGui::IsItemHovered())
ImGuiToolkit::ToolTip(tooltip, shortcut);
ImGui::SetCursorScreenPos(draw_pos);
// draw with hovered color
const ImVec4* colors = ImGui::GetStyle().Colors;
ImGui::PushStyleColor( ImGuiCol_Text, *toggle ? colors[ImGuiCol_DragDropTarget] : colors[ImGuiCol_Text] );
ImGui::PushStyleColor( ImGuiCol_Text, ImGui::IsItemHovered() ? colors[ImGuiCol_NavHighlight] : colors[ImGuiCol_Text] );
// ImGui::Text("%s", icon);
Icon(i, j, !ret);
ImGui::PopStyleColor(2);
ImGui::PopID();
return ret;
}
bool ImGuiToolkit::IconToggle(const char* icon, bool* toggle, const char *tooltip, const char* shortcut)
{
bool ret = false;

View File

@@ -20,6 +20,7 @@ namespace ImGuiToolkit
bool IconButton (const char* icon, const char *tooltips = nullptr, const char *shortcut = nullptr);
bool IconMultistate (std::vector<std::pair<int, int> > icons, int* state, std::vector<std::string> tooltips);
bool IconToggle (int i, int j, int i_toggle, int j_toggle, bool* toggle, const char *tooltips[] = nullptr);
bool IconToggle (int i, int j, bool* toggle, const char *tooltip = nullptr, const char *shortcut = nullptr);
bool IconToggle (const char* icon, bool* toggle, const char *tooltip = nullptr, const char *shortcut = nullptr);
void ShowIconsWindow(bool* p_open);

247
src/MousePointer.cpp Normal file
View File

@@ -0,0 +1,247 @@
/*
* This file is part of vimix - video live mixer
*
* **Copyright** (C) 2019-2023 Bruno Herbelin <bruno.herbelin@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
**/
#include <glm/gtc/random.hpp> // for diskRand
#include "imgui.h"
#include "Metronome.h"
#include "MousePointer.h"
std::vector< std::tuple<int, int, std::string> > Pointer::Modes = {
{ ICON_POINTER_DEFAULT, std::string("Default") },
{ ICON_POINTER_LINEAR, std::string("Linear") },
{ ICON_POINTER_SPRING, std::string("Spring") },
{ ICON_POINTER_WIGGLY, std::string("Wiggly") },
{ ICON_POINTER_METRONOME, std::string("Metronome") }
};
#define POINTER_LINEAR_MIN_SPEED 40.f
#define POINTER_LINEAR_MAX_SPEED 800.f
#define POINTER_LINEAR_THICKNESS 4.f
#define POINTER_LINEAR_ARROW 40.f
void PointerLinear::update(glm::vec2 pos, float dt)
{
float speed = POINTER_LINEAR_MIN_SPEED + (POINTER_LINEAR_MAX_SPEED - POINTER_LINEAR_MIN_SPEED) * strength_;
glm::vec2 delta = pos - pos_ ;
if (glm::length(delta) > 10.f )
pos_ += glm::normalize(delta) * (speed * dt);
}
void PointerLinear::draw()
{
ImGuiIO& io = ImGui::GetIO();
const glm::vec2 start = glm::vec2( io.MousePos.x, io.MousePos.y);
const glm::vec2 end = glm::vec2( pos_.x / io.DisplayFramebufferScale.x, pos_.y / io.DisplayFramebufferScale.y );
const ImVec2 _end = ImVec2( end.x, end.y );
// draw line
ImGui::GetBackgroundDrawList()->AddLine(io.MousePos, _end, ImGui::GetColorU32(ImGuiCol_HeaderActive), POINTER_LINEAR_THICKNESS);
ImGui::GetBackgroundDrawList()->AddCircleFilled(_end, 6.0, ImGui::GetColorU32(ImGuiCol_HeaderActive));
// direction vector
glm::vec2 delta = start - end;
float l = glm::length(delta);
delta = glm::normalize( delta );
// draw dots regularly to show speed
for (float p = 0.f; p < l; p += 200.f * (strength_ + 0.1f)) {
glm::vec2 point = start - delta * p;
ImGui::GetBackgroundDrawList()->AddCircleFilled(ImVec2(point.x,point.y), 4.0, ImGui::GetColorU32(ImGuiCol_HeaderActive));
}
// draw arrow head
if ( l > POINTER_LINEAR_ARROW * 1.5f) {
glm::vec2 ortho = glm::normalize( glm::vec2( glm::cross( glm::vec3(delta, 0.f), glm::vec3(0.f, 0.f, 1.f)) ));
ortho *= POINTER_LINEAR_ARROW;
delta *= POINTER_LINEAR_ARROW;
const glm::vec2 pointA = start - delta + ortho * 0.5f;
const glm::vec2 pointB = start - delta - ortho * 0.5f;
ImGui::GetBackgroundDrawList()->AddTriangleFilled(io.MousePos, ImVec2(pointA.x, pointA.y),
ImVec2(pointB.x, pointB.y), ImGui::GetColorU32(ImGuiCol_HeaderActive));
}
}
#define POINTER_WIGGLY_MIN_RADIUS 30.f
#define POINTER_WIGGLY_MAX_RADIUS 300.f
#define POINTER_WIGGLY_SMOOTHING 10
void PointerWiggly::update(glm::vec2 pos, float)
{
float radius = POINTER_WIGGLY_MIN_RADIUS + (POINTER_WIGGLY_MAX_RADIUS - POINTER_WIGGLY_MIN_RADIUS) * strength_;
// change pos to a random point in a close radius
pos += glm::diskRand( radius );
// smooth a little and apply
const float emaexp = 2.0 / float( POINTER_WIGGLY_SMOOTHING + 1);
pos_ = emaexp * pos + (1.f - emaexp) * pos_;
}
void PointerWiggly::draw()
{
ImGuiIO& io = ImGui::GetIO();
const ImVec2 _end = ImVec2( pos_.x / io.DisplayFramebufferScale.x, pos_.y / io.DisplayFramebufferScale.y );
ImGui::GetBackgroundDrawList()->AddLine(io.MousePos, _end, ImGui::GetColorU32(ImGuiCol_HeaderActive), 5.f);
const float radius = POINTER_WIGGLY_MIN_RADIUS + (POINTER_WIGGLY_MAX_RADIUS - POINTER_WIGGLY_MIN_RADIUS) * strength_;
ImGui::GetBackgroundDrawList()->AddCircle(io.MousePos, radius * 0.5f,
ImGui::GetColorU32(ImGuiCol_HeaderActive), 0, 2.f + 4.f * strength_);
}
#define POINTER_METRONOME_RADIUS 30.f
void PointerMetronome::update(glm::vec2 pos, float dt)
{
if ( Metronome::manager().timeToBeat() < std::chrono::milliseconds( (uint)floor(dt * 1000.f) )) {
pos_ = pos;
}
}
void PointerMetronome::draw()
{
ImGuiIO& io = ImGui::GetIO();
const ImVec2 end = ImVec2(pos_.x / io.DisplayFramebufferScale.x, pos_.y / io.DisplayFramebufferScale.y);
ImGui::GetBackgroundDrawList()->AddLine(io.MousePos, end, ImGui::GetColorU32(ImGuiCol_HeaderActive), 4.f);
ImGui::GetBackgroundDrawList()->AddCircle(io.MousePos, POINTER_METRONOME_RADIUS, ImGui::GetColorU32(ImGuiCol_HeaderActive), 0, 3.f);
ImGui::GetBackgroundDrawList()->AddCircleFilled(end, 6.0, ImGui::GetColorU32(ImGuiCol_HeaderActive));
double t = Metronome::manager().phase();
t -= floor(t);
ImGui::GetBackgroundDrawList()->AddCircleFilled(io.MousePos, t * POINTER_METRONOME_RADIUS, ImGui::GetColorU32(ImGuiCol_HeaderActive), 0);
}
#define POINTER_SPRING_MIN_MASS 6.f
#define POINTER_SPRING_MAX_MASS 40.f
void PointerSpring::initiate(glm::vec2 pos)
{
Pointer::initiate(pos);
velocity_ = glm::vec2(0.f);
}
void PointerSpring::update(glm::vec2 pos, float dt)
{
// percentage of loss of energy at every update
const float viscousness = 0.75;
// force applied on the mass, as percent of the Maximum mass
const float stiffness = 0.8;
// damping : opposite direction of force, non proportional to mass
const float damping = 60.0;
// mass as a percentage of min to max
const float mass = POINTER_SPRING_MAX_MASS - (POINTER_SPRING_MAX_MASS - POINTER_SPRING_MIN_MASS) * strength_;
// compute delta betwen initial and current position
glm::vec2 delta = pos - pos_;
// apply force on velocity : spring stiffness / mass
velocity_ += delta * ( (POINTER_SPRING_MAX_MASS * stiffness) / mass );
// apply damping dynamics
velocity_ -= damping * dt * glm::normalize(delta);
// compute new position : add velocity x time
pos_ += dt * velocity_;
// diminish velocity by viscousness of substrate
// (loss of energy between updates)
velocity_ *= viscousness;
}
void PointerSpring::draw()
{
ImGuiIO& io = ImGui::GetIO();
glm::vec2 _start = glm::vec2( io.MousePos.x * io.DisplayFramebufferScale.x, io.MousePos.y * io.DisplayFramebufferScale.y );
const glm::vec2 delta = pos_ - _start;
glm::vec2 ortho = glm::normalize( glm::vec2( glm::cross( glm::vec3(delta, 0.f), glm::vec3(0.f, 0.f, 1.f)) ));
ortho *= 0.05f * glm::length( velocity_ );
// draw a wave with 3 bezier
glm::vec2 _third = _start + delta * 1.f / 9.f + ortho;
glm::vec2 _twothird = _start + delta * 2.f / 9.f - ortho;
glm::vec2 _end = _start + delta * 3.f / 9.f;
ImVec2 start = ImVec2(_start.x / io.DisplayFramebufferScale.x, _start.y / io.DisplayFramebufferScale.y);
ImVec2 third = ImVec2(_third.x / io.DisplayFramebufferScale.x, _third.y / io.DisplayFramebufferScale.y);
ImVec2 twothird = ImVec2(_twothird.x / io.DisplayFramebufferScale.x, _twothird.y / io.DisplayFramebufferScale.y);
ImVec2 end = ImVec2(_end.x / io.DisplayFramebufferScale.x, _end.y / io.DisplayFramebufferScale.y);
ImGui::GetBackgroundDrawList()->AddBezierCurve(start, third, twothird, end,
ImGui::GetColorU32(ImGuiCol_HeaderActive), 5.f);
_start = _end;
_third = _start + delta * 1.f / 9.f + ortho;
_twothird = _start + delta * 2.f / 9.f - ortho;
_end = _start + delta * 3.f / 9.f;
start = ImVec2(_start.x / io.DisplayFramebufferScale.x, _start.y / io.DisplayFramebufferScale.y);
third = ImVec2(_third.x / io.DisplayFramebufferScale.x, _third.y / io.DisplayFramebufferScale.y);
twothird = ImVec2(_twothird.x / io.DisplayFramebufferScale.x, _twothird.y / io.DisplayFramebufferScale.y);
end = ImVec2(_end.x / io.DisplayFramebufferScale.x, _end.y / io.DisplayFramebufferScale.y);
ImGui::GetBackgroundDrawList()->AddBezierCurve(start, third, twothird, end,
ImGui::GetColorU32(ImGuiCol_HeaderActive), 5.f);
_start = _end;
_third = _start + delta * 1.f / 9.f + ortho;
_twothird = _start + delta * 2.f / 9.f - ortho;
start = ImVec2(_start.x / io.DisplayFramebufferScale.x, _start.y / io.DisplayFramebufferScale.y);
third = ImVec2(_third.x / io.DisplayFramebufferScale.x, _third.y / io.DisplayFramebufferScale.y);
twothird = ImVec2(_twothird.x / io.DisplayFramebufferScale.x, _twothird.y / io.DisplayFramebufferScale.y);
end = ImVec2(pos_.x / io.DisplayFramebufferScale.x, pos_.y / io.DisplayFramebufferScale.y);
ImGui::GetBackgroundDrawList()->AddBezierCurve(start, third, twothird, end,
ImGui::GetColorU32(ImGuiCol_HeaderActive), 5.f);
// represent the weight with a filled circle
float mass = POINTER_SPRING_MAX_MASS - (POINTER_SPRING_MAX_MASS - POINTER_SPRING_MIN_MASS) * strength_;
ImGui::GetBackgroundDrawList()->AddCircleFilled(end, mass, ImGui::GetColorU32(ImGuiCol_HeaderActive));
}
MousePointer::MousePointer() : mode_(Pointer::POINTER_DEFAULT), active_(nullptr)
{
active_ = new Pointer;
}
void MousePointer::setActiveMode(Pointer::Mode m)
{
if (mode_ != m) {
mode_ = m;
if (active_)
delete active_;
switch (mode_) {
case Pointer::POINTER_SPRING:
active_ = new PointerSpring;
break;
case Pointer::POINTER_METRONOME:
active_ = new PointerMetronome;
break;
case Pointer::POINTER_LINEAR:
active_ = new PointerLinear;
break;
case Pointer::POINTER_WIGGLY:
active_ = new PointerWiggly;
break;
default:
case Pointer::POINTER_DEFAULT:
active_ = new Pointer;
break;
}
}
}

106
src/MousePointer.h Normal file
View File

@@ -0,0 +1,106 @@
#ifndef POINTER_H
#define POINTER_H
#include <string>
#include <vector>
#include <glm/glm.hpp>
#define ICON_POINTER_DEFAULT 7, 3
#define ICON_POINTER_OPTION 12, 9
#define ICON_POINTER_SPRING 13, 9
#define ICON_POINTER_LINEAR 14, 9
#define ICON_POINTER_WIGGLY 10, 3
#define ICON_POINTER_METRONOME 6, 13
class Pointer
{
public:
typedef enum {
POINTER_DEFAULT = 0,
POINTER_LINEAR,
POINTER_SPRING,
POINTER_WIGGLY,
POINTER_METRONOME,
POINTER_INVALID
} Mode;
static std::vector< std::tuple<int, int, std::string> > Modes;
Pointer() : strength_(0.5) {}
virtual ~Pointer() {}
inline glm::vec2 pos() { return pos_; }
virtual void initiate(glm::vec2 pos) { pos_ = pos; }
virtual void update(glm::vec2 pos, float) { pos_ = pos; }
virtual void draw() {}
inline void setStrength(float percent) { strength_ = glm::clamp(percent, 0.f, 1.f); }
inline float strength() const { return strength_; }
protected:
glm::vec2 pos_;
float strength_;
};
class PointerLinear : public Pointer
{
public:
PointerLinear() {}
void update(glm::vec2 pos, float dt) override;
void draw() override;
};
class PointerSpring : public Pointer
{
glm::vec2 velocity_;
public:
PointerSpring() {}
void initiate(glm::vec2 pos) override;
void update(glm::vec2 pos, float dt) override;
void draw() override;
};
class PointerWiggly : public Pointer
{
public:
PointerWiggly() {}
void update(glm::vec2 pos, float) override;
void draw() override;
};
class PointerMetronome : public Pointer
{
public:
PointerMetronome() {}
void update(glm::vec2 pos, float dt) override;
void draw() override;
};
class MousePointer
{
// Private Constructor
MousePointer();
MousePointer(MousePointer const& copy) = delete;
MousePointer& operator=(MousePointer const& copy) = delete;
public:
static MousePointer& manager ()
{
// The only instance
static MousePointer _instance;
return _instance;
}
inline Pointer *active() { return active_; }
inline Pointer::Mode activeMode() { return mode_; }
void setActiveMode(Pointer::Mode m);
private:
Pointer::Mode mode_;
Pointer *active_;
};
#endif // POINTER_H

View File

@@ -132,7 +132,6 @@ void Settings::Save(uint64_t runtime)
applicationNode->SetAttribute("accent_color", application.accent_color);
applicationNode->SetAttribute("smooth_transition", application.smooth_transition);
applicationNode->SetAttribute("save_snapshot", application.save_version_snapshot);
applicationNode->SetAttribute("smooth_cursor", application.smooth_cursor);
applicationNode->SetAttribute("action_history_follow_view", application.action_history_follow_view);
applicationNode->SetAttribute("show_tooptips", application.show_tooptips);
applicationNode->SetAttribute("accept_connections", application.accept_connections);
@@ -214,6 +213,15 @@ void Settings::Save(uint64_t runtime)
BrushNode->InsertEndChild( XMLElementFromGLM(&xmlDoc, application.brush) );
pRoot->InsertEndChild(BrushNode);
// Pointer
XMLElement *PointerNode = xmlDoc.NewElement( "MousePointer" );
PointerNode->SetAttribute("mode", application.mouse_pointer);
for (size_t i = 0; i < application.mouse_pointer_strength.size(); ++i ) {
float v = application.mouse_pointer_strength[i];
PointerNode->InsertEndChild( XMLElementFromGLM(&xmlDoc, glm::vec2((float)i, v)) );
}
pRoot->InsertEndChild(PointerNode);
// bloc views
{
XMLElement *viewsNode = xmlDoc.NewElement( "Views" );
@@ -284,8 +292,6 @@ void Settings::Save(uint64_t runtime)
// recent SRT hosts
knownhosts->InsertEndChild( save_knownhost(application.recentSRT, "SRT", xmlDoc));
pRoot->InsertEndChild(knownhosts);
}
@@ -410,7 +416,6 @@ void Settings::Load()
applicationNode->QueryIntAttribute("accent_color", &application.accent_color);
applicationNode->QueryBoolAttribute("smooth_transition", &application.smooth_transition);
applicationNode->QueryBoolAttribute("save_snapshot", &application.save_version_snapshot);
applicationNode->QueryBoolAttribute("smooth_cursor", &application.smooth_cursor);
applicationNode->QueryBoolAttribute("action_history_follow_view", &application.action_history_follow_view);
applicationNode->QueryBoolAttribute("show_tooptips", &application.show_tooptips);
applicationNode->QueryBoolAttribute("accept_connections", &application.accept_connections);
@@ -556,6 +561,20 @@ void Settings::Load()
tinyxml2::XMLElementToGLM( brushnode->FirstChildElement("vec3"), application.brush);
}
// Pointer
XMLElement * pointernode = pRoot->FirstChildElement("MousePointer");
if (pointernode != nullptr) {
pointernode->QueryIntAttribute("mode", &application.mouse_pointer);
XMLElement* strengthNode = pointernode->FirstChildElement("vec2");
for( ; strengthNode ; strengthNode = strengthNode->NextSiblingElement())
{
glm::vec2 val;
tinyxml2::XMLElementToGLM( strengthNode, val);
application.mouse_pointer_strength[ (size_t) ceil(val.x) ] = val.y;
}
}
// bloc views
{
XMLElement * pElement = pRoot->FirstChildElement("Views");

View File

@@ -271,7 +271,8 @@ struct Application
int accent_color;
bool save_version_snapshot;
bool smooth_transition;
bool smooth_cursor;
int mouse_pointer;
std::vector<float> mouse_pointer_strength;
bool action_history_follow_view;
bool show_tooptips;
@@ -336,7 +337,8 @@ struct Application
accent_color = 0;
smooth_transition = false;
save_version_snapshot = false;
smooth_cursor = false;
mouse_pointer = 0;
mouse_pointer_strength = {0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f};
action_history_follow_view = false;
show_tooptips = true;
accept_connections = false;

View File

@@ -76,6 +76,7 @@
#include "ShmdataBroadcast.h"
#include "VideoBroadcast.h"
#include "MultiFileRecorder.h"
#include "MousePointer.h"
#include "UserInterfaceManager.h"
@@ -442,13 +443,10 @@ void UserInterface::handleKeyboard()
void UserInterface::handleMouse()
{
ImGuiIO& io = ImGui::GetIO();
glm::vec2 mousepos(io.MousePos.x * io.DisplayFramebufferScale.x, io.MousePos.y * io.DisplayFramebufferScale.y);
mousepos = glm::clamp(mousepos, glm::vec2(0.f), glm::vec2(io.DisplaySize.x * io.DisplayFramebufferScale.x, io.DisplaySize.y * io.DisplayFramebufferScale.y));
static glm::vec2 mouse_smooth = mousepos;
static glm::vec2 mouseclic[2];
mouseclic[ImGuiMouseButton_Left] = glm::vec2(io.MouseClickedPos[ImGuiMouseButton_Left].x * io.DisplayFramebufferScale.y, io.MouseClickedPos[ImGuiMouseButton_Left].y* io.DisplayFramebufferScale.x);
mouseclic[ImGuiMouseButton_Right] = glm::vec2(io.MouseClickedPos[ImGuiMouseButton_Right].x * io.DisplayFramebufferScale.y, io.MouseClickedPos[ImGuiMouseButton_Right].y* io.DisplayFramebufferScale.x);
@@ -474,15 +472,6 @@ void UserInterface::handleMouse()
// if not on any window
if ( !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow) && !ImGui::IsWindowFocused(ImGuiHoveredFlags_AnyWindow) )
{
//
// Mouse wheel over background
//
if ( io.MouseWheel != 0) {
// scroll => zoom current view
Mixer::manager().view()->zoom( io.MouseWheel );
}
// TODO : zoom with center on source if over current
//
// RIGHT Mouse button
//
@@ -512,7 +501,11 @@ void UserInterface::handleMouse()
if ( !mousedown )
{
mousedown = true;
mouse_smooth = mousepos;
// initiate Mouse pointer from position at mouse down event
MousePointer::manager().setActiveMode( (Pointer::Mode) Settings::application.mouse_pointer );
MousePointer::manager().active()->setStrength( Settings::application.mouse_pointer_strength[Settings::application.mouse_pointer] );
MousePointer::manager().active()->initiate(mousepos);
// ask the view what was picked
picked = Mixer::manager().view()->pick(mousepos);
@@ -592,17 +585,8 @@ void UserInterface::handleMouse()
if (view_drag == Mixer::manager().view()) {
if ( picked.first != nullptr ) {
// Smooth cursor
if (Settings::application.smooth_cursor) {
// TODO : physics implementation
float smoothing = 10.f / ( MAX(io.Framerate, 1.f) );
glm::vec2 d = mousepos - mouse_smooth;
mouse_smooth += smoothing * d;
ImVec2 start = ImVec2(mouse_smooth.x / io.DisplayFramebufferScale.x, mouse_smooth.y / io.DisplayFramebufferScale.y);
ImGui::GetBackgroundDrawList()->AddLine(io.MousePos, start, ImGui::GetColorU32(ImGuiCol_HeaderActive), 5.f);
}
else
mouse_smooth = mousepos;
// Apply Mouse pointer filter
MousePointer::manager().active()->update(mousepos, 1.f / ( MAX(io.Framerate, 1.f) ));
// action on current source
Source *current = Mixer::manager().currentSource();
@@ -612,19 +596,32 @@ void UserInterface::handleMouse()
// grab others from selection
for (auto it = Mixer::selection().begin(); it != Mixer::selection().end(); ++it) {
if ( *it != current && !(*it)->locked() )
Mixer::manager().view()->grab(*it, mouseclic[ImGuiMouseButton_Left], mouse_smooth, picked);
Mixer::manager().view()->grab(*it, mouseclic[ImGuiMouseButton_Left],
MousePointer::manager().active()->pos(), picked);
}
}
// grab current sources
View::Cursor c = Mixer::manager().view()->grab(current, mouseclic[ImGuiMouseButton_Left], mouse_smooth, picked);
View::Cursor c = Mixer::manager().view()->grab(current, mouseclic[ImGuiMouseButton_Left],
MousePointer::manager().active()->pos(), picked);
SetMouseCursor(io.MousePos, c);
// scrollwheel changes strength of Mouse Pointer
if ( io.MouseWheel != 0) {
MousePointer::manager().active()->setStrength( MousePointer::manager().active()->strength() + 0.1 * io.MouseWheel);
Settings::application.mouse_pointer_strength[Settings::application.mouse_pointer] = MousePointer::manager().active()->strength();
}
// Draw Mouse pointer effect
MousePointer::manager().active()->draw();
}
// action on other (non-source) elements in the view
else
{
View::Cursor c = Mixer::manager().view()->grab(nullptr, mouseclic[ImGuiMouseButton_Left], mouse_smooth, picked);
View::Cursor c = Mixer::manager().view()->grab(nullptr, mouseclic[ImGuiMouseButton_Left], mousepos, picked);
SetMouseCursor(io.MousePos, c);
}
}
// Selection area
else {
@@ -640,6 +637,13 @@ void UserInterface::handleMouse()
}
}
//
// Mouse wheel over background without source action
//
else if ( !mousedown && io.MouseWheel != 0) {
// scroll => zoom current view
Mixer::manager().view()->zoom( io.MouseWheel );
}
}
else {
// cancel all operations on view when interacting on GUI
@@ -2770,7 +2774,7 @@ void Navigator::Render()
height_ = ImGui::GetIO().DisplaySize.y; // cover vertically
const float icon_width = width_ - 2.f * style.WindowPadding.x; // icons keep padding
const ImVec2 iconsize(icon_width, icon_width);
const float sourcelist_height = height_ - 5.5f * icon_width - 5.f * style.WindowPadding.y; // space for 4 icons of view
const float sourcelist_height = height_ - 6.5f * icon_width - 6.f * style.WindowPadding.y; // space for 4 icons of view
// hack to show more sources if not enough space; make source icons smaller...
ImVec2 sourceiconsize(icon_width, icon_width);
@@ -2886,6 +2890,10 @@ void Navigator::Render()
if (ImGui::Begin("##navigatorViews", NULL, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration |
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoScrollWithMouse))
{
// Mouse pointer selector
RenderMousePointerSelector(iconsize);
// List of icons for View selection
bool selected_view[View::INVALID] = { };
selected_view[ Settings::application.current_view ] = true;
int previous_view = Settings::application.current_view;
@@ -4606,6 +4614,80 @@ void Navigator::RenderMainPannelVimix()
ImGui::EndPopup();
}
}
void Navigator::RenderMousePointerSelector(const ImVec2 &size)
{
ImGuiContext& g = *GImGui;
ImVec2 top = ImGui::GetCursorPos();
///
/// interactive button of the given size: show menu if clic or mouse over
///
static uint counter_menu_timeout = 0;
if ( ImGui::InvisibleButton("##MenuMousePointerButton", size) || ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) ) {
counter_menu_timeout=0;
ImGui::OpenPopup( "MenuMousePointer" );
}
ImVec2 bottom = ImGui::GetCursorScreenPos();
// Change color of icons depending on context menu status
const ImVec4* colors = ImGui::GetStyle().Colors;
ImGui::PushStyleColor( ImGuiCol_Text, ImGui::IsPopupOpen("MenuMousePointer") ? colors[ImGuiCol_DragDropTarget] : colors[ImGuiCol_Text] );
// Draw centered icon of Mouse pointer
ImVec2 margin = (size - ImVec2(g.FontSize, g.FontSize)) * 0.42f;
ImGui::SetCursorPos( top + margin );
if ( Settings::application.mouse_pointer > 0 ) {
// icon with corner erased
ImGuiToolkit::Icon(ICON_POINTER_OPTION);
// Draw sub-icon of Mouse pointer type
ImGuiToolkit::PushFont(ImGuiToolkit::FONT_DEFAULT);
ImVec2 t = top + size - ImVec2(g.FontSize, g.FontSize) - ImVec2(g.Style.FramePadding.y, g.Style.FramePadding.y);
ImGui::SetCursorPos( t );
std::tuple<int, int, std::string> mode = Pointer::Modes.at( (size_t) Settings::application.mouse_pointer);
ImGuiToolkit::Icon(std::get<0>(mode), std::get<1>(mode));
ImGui::PopFont();
}
else
// standard icon
ImGuiToolkit::Icon(ICON_POINTER_DEFAULT);
// Revert
ImGui::PopStyleColor(1);
ImGui::SetCursorScreenPos(bottom);
///
/// Render the Popup menu selector
///
ImGui::SetNextWindowPos( bottom + ImVec2(size.x + g.Style.WindowPadding.x, -size.y), ImGuiCond_Always );
if (ImGui::BeginPopup( "MenuMousePointer" ))
{
// loop over all mouse pointer modes
for ( size_t m = Pointer::POINTER_DEFAULT; m < Pointer::POINTER_INVALID; ++m) {
bool on = m == (size_t) Settings::application.mouse_pointer;
std::tuple<int, int, std::string> mode = Pointer::Modes.at(m);
// show icon of mouse mode and set mouse pointer if selected
if (ImGuiToolkit::IconToggle( std::get<0>(mode), std::get<1>(mode), &on, std::get<2>(mode).c_str()) )
Settings::application.mouse_pointer = (int) m;
// space between icons
ImGui::SameLine(0, IMGUI_SAME_LINE);
}
// timer to close menu like a tooltip
if (ImGui::IsWindowHovered())
counter_menu_timeout=0;
else if (++counter_menu_timeout > 10)
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
}
void Navigator::RenderMainPannelSettings()
@@ -4637,9 +4719,6 @@ void Navigator::RenderMainPannelSettings()
Settings::application.scale = CLAMP(Settings::application.scale, 0.5f, 2.f);
ImGui::GetIO().FontGlobalScale = Settings::application.scale;
}
ImGuiToolkit::HelpToolTip("Cursor filter that makes movement smoother when manipulating a source.");
ImGui::SameLine();
ImGuiToolkit::ButtonSwitch( ICON_FA_MOUSE_POINTER " Smooth cursor", &Settings::application.smooth_cursor);
//
// Recording preferences

View File

@@ -70,6 +70,7 @@ class Navigator
void RenderTransitionPannel();
void RenderNewPannel();
void RenderViewPannel(ImVec2 draw_pos, ImVec2 draw_size);
void RenderMousePointerSelector(const ImVec2 &size);
public: