| @@ -11,6 +11,9 @@ namespace app { | |||
| struct Scene : widget::OpaqueWidget { | |||
| struct Internal; | |||
| Internal* internal; | |||
| // Convenience variables for accessing important widgets | |||
| RackScrollWidget* rackScroll; | |||
| RackWidget* rack; | |||
| @@ -19,16 +22,15 @@ struct Scene : widget::OpaqueWidget { | |||
| widget::Widget* frameRateWidget; | |||
| 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(); | |||
| void step() 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 onPathDrop(const event::PathDrop& e) override; | |||
| @@ -11,7 +11,6 @@ | |||
| #include <engine/Module.hpp> | |||
| #include <engine/ParamQuantity.hpp> | |||
| #include <app.hpp> | |||
| #include <window.hpp> | |||
| namespace rack { | |||
| @@ -156,7 +155,7 @@ TMenuItem * createMenuItem(std::string text, std::string rightText = "") { | |||
| template <class TMenu = ui::Menu> | |||
| TMenu * createMenu() { | |||
| TMenu* o = new TMenu; | |||
| o->box.pos = APP->window->mousePos; | |||
| o->box.pos = APP->scene->mousePos; | |||
| ui::MenuOverlay* menuOverlay = new ui::MenuOverlay; | |||
| menuOverlay->addChild(o); | |||
| @@ -53,6 +53,9 @@ DEPRECATED typedef Svg SVG; | |||
| struct Window { | |||
| struct Internal; | |||
| Internal* internal; | |||
| GLFWwindow* win = NULL; | |||
| NVGcontext* vg = NULL; | |||
| /** The scaling ratio */ | |||
| @@ -62,8 +65,6 @@ struct Window { | |||
| */ | |||
| float windowRatio = 1.f; | |||
| int frame = 0; | |||
| /** The last known absolute mouse position in the window */ | |||
| math::Vec mousePos; | |||
| std::shared_ptr<Font> uiFont; | |||
| 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<Svg>> svgCache; | |||
| struct Internal; | |||
| Internal* internal; | |||
| Window(); | |||
| ~Window(); | |||
| void run(); | |||
| @@ -56,7 +56,7 @@ void RackScrollWidget::step() { | |||
| rackWidget->box.pos = scrollBox.pos.div(zoom).neg(); | |||
| // 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()); | |||
| if (rackWidget->incompleteCable) { | |||
| float margin = 20.0; | |||
| @@ -15,6 +15,10 @@ namespace rack { | |||
| namespace app { | |||
| struct Scene::Internal { | |||
| }; | |||
| struct FrameRateWidget : widget::TransparentWidget { | |||
| void draw(const DrawArgs& args) override { | |||
| std::string text = string::f("%.2f Hz", APP->window->getLastFrameRate()); | |||
| @@ -24,6 +28,8 @@ struct FrameRateWidget : widget::TransparentWidget { | |||
| Scene::Scene() { | |||
| internal = new Internal; | |||
| rackScroll = new RackScrollWidget; | |||
| addChild(rackScroll); | |||
| @@ -43,6 +49,7 @@ Scene::Scene() { | |||
| } | |||
| Scene::~Scene() { | |||
| delete internal; | |||
| } | |||
| void Scene::step() { | |||
| @@ -72,6 +79,16 @@ void Scene::draw(const DrawArgs& 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) { | |||
| OpaqueWidget::onHoverKey(e); | |||
| if (e.isConsumed()) | |||
| @@ -1,6 +1,6 @@ | |||
| #include <ui/Tooltip.hpp> | |||
| #include <app.hpp> | |||
| #include <window.hpp> | |||
| #include <app/Scene.hpp> | |||
| namespace rack { | |||
| @@ -12,7 +12,7 @@ void Tooltip::step() { | |||
| 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); | |||
| // 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 | |||
| assert(parent); | |||
| box = box.nudge(parent->box.zeroPos()); | |||
| @@ -98,6 +98,8 @@ struct Window::Internal { | |||
| int frameSwapInterval = -1; | |||
| float monitorRefreshRate = 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 | |||
| 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) { | |||
| Window* window = (Window*) glfwGetWindowUserPointer(win); | |||
| 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. | |||
| 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. | |||
| if (cursorMode == GLFW_CURSOR_HIDDEN) { | |||
| // CGSetLocalEventsSuppressionInterval(0.0); | |||
| glfwSetCursorPos(win, window->mousePos.x, window->mousePos.y); | |||
| glfwSetCursorPos(win, window->internal->lastMousePos.x, window->internal->lastMousePos.y); | |||
| 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 | |||
| glfwSetCursor(win, NULL); | |||
| #endif | |||
| window->mousePos = mousePos; | |||
| window->internal->lastMousePos = mousePos; | |||
| APP->event->handleHover(mousePos, mouseDelta); | |||
| } | |||
| @@ -170,18 +172,18 @@ static void scrollCallback(GLFWwindow* win, double x, double y) { | |||
| scrollDelta = scrollDelta.mult(50.0); | |||
| #endif | |||
| APP->event->handleScroll(window->mousePos, scrollDelta); | |||
| APP->event->handleScroll(window->internal->lastMousePos, scrollDelta); | |||
| } | |||
| static void charCallback(GLFWwindow* win, unsigned int codepoint) { | |||
| Window* window = (Window*) glfwGetWindowUserPointer(win); | |||
| if (APP->event->handleText(window->mousePos, codepoint)) | |||
| if (APP->event->handleText(window->internal->lastMousePos, codepoint)) | |||
| return; | |||
| } | |||
| static void keyCallback(GLFWwindow* win, int key, int scancode, int action, int mods) { | |||
| 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; | |||
| // Keyboard MIDI driver | |||
| @@ -199,7 +201,7 @@ static void dropCallback(GLFWwindow* win, int count, const char** paths) { | |||
| for (int i = 0; i < count; 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) { | |||