@@ -11,6 +11,9 @@ namespace app { | |||||
struct Scene : widget::OpaqueWidget { | struct Scene : widget::OpaqueWidget { | ||||
struct Internal; | |||||
Internal* internal; | |||||
// Convenience variables for accessing important widgets | // Convenience variables for accessing important widgets | ||||
RackScrollWidget* rackScroll; | RackScrollWidget* rackScroll; | ||||
RackWidget* rack; | RackWidget* rack; | ||||
@@ -19,16 +22,15 @@ struct Scene : widget::OpaqueWidget { | |||||
widget::Widget* frameRateWidget; | widget::Widget* frameRateWidget; | ||||
double lastAutosaveTime = 0.0; | double lastAutosaveTime = 0.0; | ||||
// Version checking | |||||
bool checkVersion = true; | |||||
bool checkedVersion = false; | |||||
std::string latestVersion; | |||||
/** The last mouse position in the Scene */ | |||||
math::Vec mousePos; | |||||
Scene(); | Scene(); | ||||
~Scene(); | ~Scene(); | ||||
void step() override; | void step() override; | ||||
void draw(const DrawArgs& args) override; | void draw(const DrawArgs& args) override; | ||||
void onHover(const event::Hover& e) override; | |||||
void onDragHover(const event::DragHover& e) override; | |||||
void onHoverKey(const event::HoverKey& e) override; | void onHoverKey(const event::HoverKey& e) override; | ||||
void onPathDrop(const event::PathDrop& e) override; | void onPathDrop(const event::PathDrop& e) override; | ||||
@@ -11,7 +11,6 @@ | |||||
#include <engine/Module.hpp> | #include <engine/Module.hpp> | ||||
#include <engine/ParamQuantity.hpp> | #include <engine/ParamQuantity.hpp> | ||||
#include <app.hpp> | #include <app.hpp> | ||||
#include <window.hpp> | |||||
namespace rack { | namespace rack { | ||||
@@ -156,7 +155,7 @@ TMenuItem * createMenuItem(std::string text, std::string rightText = "") { | |||||
template <class TMenu = ui::Menu> | template <class TMenu = ui::Menu> | ||||
TMenu * createMenu() { | TMenu * createMenu() { | ||||
TMenu* o = new TMenu; | TMenu* o = new TMenu; | ||||
o->box.pos = APP->window->mousePos; | |||||
o->box.pos = APP->scene->mousePos; | |||||
ui::MenuOverlay* menuOverlay = new ui::MenuOverlay; | ui::MenuOverlay* menuOverlay = new ui::MenuOverlay; | ||||
menuOverlay->addChild(o); | menuOverlay->addChild(o); | ||||
@@ -53,6 +53,9 @@ DEPRECATED typedef Svg SVG; | |||||
struct Window { | struct Window { | ||||
struct Internal; | |||||
Internal* internal; | |||||
GLFWwindow* win = NULL; | GLFWwindow* win = NULL; | ||||
NVGcontext* vg = NULL; | NVGcontext* vg = NULL; | ||||
/** The scaling ratio */ | /** The scaling ratio */ | ||||
@@ -62,8 +65,6 @@ struct Window { | |||||
*/ | */ | ||||
float windowRatio = 1.f; | float windowRatio = 1.f; | ||||
int frame = 0; | int frame = 0; | ||||
/** The last known absolute mouse position in the window */ | |||||
math::Vec mousePos; | |||||
std::shared_ptr<Font> uiFont; | std::shared_ptr<Font> uiFont; | ||||
double frameTimeStart = 0.f; | double frameTimeStart = 0.f; | ||||
@@ -72,9 +73,6 @@ struct Window { | |||||
std::map<std::string, std::weak_ptr<Image>> imageCache; | std::map<std::string, std::weak_ptr<Image>> imageCache; | ||||
std::map<std::string, std::weak_ptr<Svg>> svgCache; | std::map<std::string, std::weak_ptr<Svg>> svgCache; | ||||
struct Internal; | |||||
Internal* internal; | |||||
Window(); | Window(); | ||||
~Window(); | ~Window(); | ||||
void run(); | void run(); | ||||
@@ -56,7 +56,7 @@ void RackScrollWidget::step() { | |||||
rackWidget->box.pos = scrollBox.pos.div(zoom).neg(); | rackWidget->box.pos = scrollBox.pos.div(zoom).neg(); | ||||
// Scroll rack if dragging cable near the edge of the screen | // Scroll rack if dragging cable near the edge of the screen | ||||
math::Vec pos = APP->window->mousePos; | |||||
math::Vec pos = APP->scene->mousePos; | |||||
math::Rect viewport = getViewport(box.zeroPos()); | math::Rect viewport = getViewport(box.zeroPos()); | ||||
if (rackWidget->incompleteCable) { | if (rackWidget->incompleteCable) { | ||||
float margin = 20.0; | float margin = 20.0; | ||||
@@ -15,6 +15,10 @@ namespace rack { | |||||
namespace app { | namespace app { | ||||
struct Scene::Internal { | |||||
}; | |||||
struct FrameRateWidget : widget::TransparentWidget { | struct FrameRateWidget : widget::TransparentWidget { | ||||
void draw(const DrawArgs& args) override { | void draw(const DrawArgs& args) override { | ||||
std::string text = string::f("%.2f Hz", APP->window->getLastFrameRate()); | std::string text = string::f("%.2f Hz", APP->window->getLastFrameRate()); | ||||
@@ -24,6 +28,8 @@ struct FrameRateWidget : widget::TransparentWidget { | |||||
Scene::Scene() { | Scene::Scene() { | ||||
internal = new Internal; | |||||
rackScroll = new RackScrollWidget; | rackScroll = new RackScrollWidget; | ||||
addChild(rackScroll); | addChild(rackScroll); | ||||
@@ -43,6 +49,7 @@ Scene::Scene() { | |||||
} | } | ||||
Scene::~Scene() { | Scene::~Scene() { | ||||
delete internal; | |||||
} | } | ||||
void Scene::step() { | void Scene::step() { | ||||
@@ -72,6 +79,16 @@ void Scene::draw(const DrawArgs& args) { | |||||
Widget::draw(args); | Widget::draw(args); | ||||
} | } | ||||
void Scene::onHover(const event::Hover& e) { | |||||
mousePos = e.pos; | |||||
OpaqueWidget::onHover(e); | |||||
} | |||||
void Scene::onDragHover(const event::DragHover& e) { | |||||
mousePos = e.pos; | |||||
OpaqueWidget::onDragHover(e); | |||||
} | |||||
void Scene::onHoverKey(const event::HoverKey& e) { | void Scene::onHoverKey(const event::HoverKey& e) { | ||||
OpaqueWidget::onHoverKey(e); | OpaqueWidget::onHoverKey(e); | ||||
if (e.isConsumed()) | if (e.isConsumed()) | ||||
@@ -1,6 +1,6 @@ | |||||
#include <ui/Tooltip.hpp> | #include <ui/Tooltip.hpp> | ||||
#include <app.hpp> | #include <app.hpp> | ||||
#include <window.hpp> | |||||
#include <app/Scene.hpp> | |||||
namespace rack { | namespace rack { | ||||
@@ -12,7 +12,7 @@ void Tooltip::step() { | |||||
box.size.x = bndLabelWidth(APP->window->vg, -1, text.c_str()) + 10.0; | box.size.x = bndLabelWidth(APP->window->vg, -1, text.c_str()) + 10.0; | ||||
box.size.y = bndLabelHeight(APP->window->vg, -1, text.c_str(), INFINITY); | box.size.y = bndLabelHeight(APP->window->vg, -1, text.c_str(), INFINITY); | ||||
// Position near cursor. This assumes that `this` is added to the root widget. | // Position near cursor. This assumes that `this` is added to the root widget. | ||||
box.pos = APP->window->mousePos.plus(math::Vec(15, 15)); | |||||
box.pos = APP->scene->mousePos.plus(math::Vec(15, 15)); | |||||
// Fit inside parent | // Fit inside parent | ||||
assert(parent); | assert(parent); | ||||
box = box.nudge(parent->box.zeroPos()); | box = box.nudge(parent->box.zeroPos()); | ||||
@@ -98,6 +98,8 @@ struct Window::Internal { | |||||
int frameSwapInterval = -1; | int frameSwapInterval = -1; | ||||
float monitorRefreshRate = 0.f; | float monitorRefreshRate = 0.f; | ||||
float lastFrameRate = 0.f; | float lastFrameRate = 0.f; | ||||
math::Vec lastMousePos; | |||||
}; | }; | ||||
@@ -120,13 +122,13 @@ static void mouseButtonCallback(GLFWwindow* win, int button, int action, int mod | |||||
} | } | ||||
#endif | #endif | ||||
APP->event->handleButton(window->mousePos, button, action, mods); | |||||
APP->event->handleButton(window->internal->lastMousePos, button, action, mods); | |||||
} | } | ||||
static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos) { | static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos) { | ||||
Window* window = (Window*) glfwGetWindowUserPointer(win); | Window* window = (Window*) glfwGetWindowUserPointer(win); | ||||
math::Vec mousePos = math::Vec(xpos, ypos).div(window->pixelRatio / window->windowRatio).round(); | math::Vec mousePos = math::Vec(xpos, ypos).div(window->pixelRatio / window->windowRatio).round(); | ||||
math::Vec mouseDelta = mousePos.minus(window->mousePos); | |||||
math::Vec mouseDelta = mousePos.minus(window->internal->lastMousePos); | |||||
// Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked. | // Workaround for GLFW warping mouse to a different position when the cursor is locked or unlocked. | ||||
if (window->internal->ignoreNextMouseDelta) { | if (window->internal->ignoreNextMouseDelta) { | ||||
@@ -142,15 +144,15 @@ static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos) { | |||||
// This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped. | // This is not an ideal implementation. For example, if the user drags off the screen, the new mouse position will be clamped. | ||||
if (cursorMode == GLFW_CURSOR_HIDDEN) { | if (cursorMode == GLFW_CURSOR_HIDDEN) { | ||||
// CGSetLocalEventsSuppressionInterval(0.0); | // CGSetLocalEventsSuppressionInterval(0.0); | ||||
glfwSetCursorPos(win, window->mousePos.x, window->mousePos.y); | |||||
glfwSetCursorPos(win, window->internal->lastMousePos.x, window->internal->lastMousePos.y); | |||||
CGAssociateMouseAndMouseCursorPosition(true); | CGAssociateMouseAndMouseCursorPosition(true); | ||||
mousePos = window->mousePos; | |||||
mousePos = window->internal->lastMousePos; | |||||
} | } | ||||
// Because sometimes the cursor turns into an arrow when its position is on the boundary of the window | // Because sometimes the cursor turns into an arrow when its position is on the boundary of the window | ||||
glfwSetCursor(win, NULL); | glfwSetCursor(win, NULL); | ||||
#endif | #endif | ||||
window->mousePos = mousePos; | |||||
window->internal->lastMousePos = mousePos; | |||||
APP->event->handleHover(mousePos, mouseDelta); | APP->event->handleHover(mousePos, mouseDelta); | ||||
} | } | ||||
@@ -170,18 +172,18 @@ static void scrollCallback(GLFWwindow* win, double x, double y) { | |||||
scrollDelta = scrollDelta.mult(50.0); | scrollDelta = scrollDelta.mult(50.0); | ||||
#endif | #endif | ||||
APP->event->handleScroll(window->mousePos, scrollDelta); | |||||
APP->event->handleScroll(window->internal->lastMousePos, scrollDelta); | |||||
} | } | ||||
static void charCallback(GLFWwindow* win, unsigned int codepoint) { | static void charCallback(GLFWwindow* win, unsigned int codepoint) { | ||||
Window* window = (Window*) glfwGetWindowUserPointer(win); | Window* window = (Window*) glfwGetWindowUserPointer(win); | ||||
if (APP->event->handleText(window->mousePos, codepoint)) | |||||
if (APP->event->handleText(window->internal->lastMousePos, codepoint)) | |||||
return; | return; | ||||
} | } | ||||
static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { | static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { | ||||
Window* window = (Window*) glfwGetWindowUserPointer(win); | Window* window = (Window*) glfwGetWindowUserPointer(win); | ||||
if (APP->event->handleKey(window->mousePos, key, scancode, action, mods)) | |||||
if (APP->event->handleKey(window->internal->lastMousePos, key, scancode, action, mods)) | |||||
return; | return; | ||||
// Keyboard MIDI driver | // Keyboard MIDI driver | ||||
@@ -199,7 +201,7 @@ static void dropCallback(GLFWwindow* win, int count, const char** paths) { | |||||
for (int i = 0; i < count; i++) { | for (int i = 0; i < count; i++) { | ||||
pathsVec.push_back(paths[i]); | pathsVec.push_back(paths[i]); | ||||
} | } | ||||
APP->event->handleDrop(window->mousePos, pathsVec); | |||||
APP->event->handleDrop(window->internal->lastMousePos, pathsVec); | |||||
} | } | ||||
static void errorCallback(int error, const char* description) { | static void errorCallback(int error, const char* description) { | ||||