override Scene.cpp; Move common menu/scene to new file; Cleanup
Closes #50 Signed-off-by: falkTX <falktx@falktx.com>
This commit is contained in:
parent
18a88ded9a
commit
5a652907c7
13 changed files with 515 additions and 95 deletions
1
src/Cardinal/CardinalCommon.cpp
Symbolic link
1
src/Cardinal/CardinalCommon.cpp
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../CardinalCommon.cpp
|
|
@ -1 +0,0 @@
|
||||||
../override/MenuBar.cpp
|
|
157
src/CardinalCommon.cpp
Normal file
157
src/CardinalCommon.cpp
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* DISTRHO Cardinal Plugin
|
||||||
|
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.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 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.
|
||||||
|
*
|
||||||
|
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CardinalCommon.hpp"
|
||||||
|
|
||||||
|
#include "AsyncDialog.hpp"
|
||||||
|
#include "PluginContext.hpp"
|
||||||
|
|
||||||
|
#include <context.hpp>
|
||||||
|
#include <history.hpp>
|
||||||
|
#include <patch.hpp>
|
||||||
|
#include <string.hpp>
|
||||||
|
#include <system.hpp>
|
||||||
|
#include <app/Scene.hpp>
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
# undef DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// for finding home dir
|
||||||
|
#ifndef ARCH_WIN
|
||||||
|
# include <pwd.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace patchUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
static void promptClear(const char* const message, const std::function<void()> action)
|
||||||
|
{
|
||||||
|
if (APP->history->isSaved() || APP->scene->rack->hasModules())
|
||||||
|
return action();
|
||||||
|
|
||||||
|
asyncDialog::create(message, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string homeDir()
|
||||||
|
{
|
||||||
|
#ifdef ARCH_WIN
|
||||||
|
if (const char* const userprofile = getenv("USERPROFILE"))
|
||||||
|
{
|
||||||
|
return userprofile;
|
||||||
|
}
|
||||||
|
else if (const char* const homedrive = getenv("HOMEDRIVE"))
|
||||||
|
{
|
||||||
|
if (const char* const homepath = getenv("HOMEPATH"))
|
||||||
|
return system::join(homedrive, homepath);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (const char* const home = getenv("HOME"))
|
||||||
|
return home;
|
||||||
|
else if (struct passwd* const pwd = getpwuid(getuid()))
|
||||||
|
return pwd->pw_dir;
|
||||||
|
#endif
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace rack;
|
||||||
|
|
||||||
|
void loadDialog()
|
||||||
|
{
|
||||||
|
promptClear("The current patch is unsaved. Clear it and open a new patch?", []() {
|
||||||
|
std::string dir;
|
||||||
|
if (! APP->patch->path.empty())
|
||||||
|
dir = system::getDirectory(APP->patch->path);
|
||||||
|
else
|
||||||
|
dir = homeDir();
|
||||||
|
|
||||||
|
CardinalPluginContext* const pcontext = static_cast<CardinalPluginContext*>(APP);
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(pcontext != nullptr,);
|
||||||
|
|
||||||
|
CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(pcontext->ui);
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
|
||||||
|
|
||||||
|
FileBrowserOptions opts;
|
||||||
|
opts.startDir = dir.c_str();
|
||||||
|
opts.saving = ui->saving = false;
|
||||||
|
ui->openFileBrowser(opts);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadPathDialog(const std::string& path)
|
||||||
|
{
|
||||||
|
promptClear("The current patch is unsaved. Clear it and open the new patch?", [path]() {
|
||||||
|
APP->patch->loadAction(path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadTemplateDialog()
|
||||||
|
{
|
||||||
|
promptClear("The current patch is unsaved. Clear it and start a new patch?", []() {
|
||||||
|
APP->patch->loadTemplate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void revertDialog()
|
||||||
|
{
|
||||||
|
if (APP->patch->path.empty())
|
||||||
|
return;
|
||||||
|
promptClear("Revert patch to the last saved state?", []{
|
||||||
|
APP->patch->loadAction(APP->patch->path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveDialog(const std::string& path)
|
||||||
|
{
|
||||||
|
if (path.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: If save() fails below, this should probably be reset. But we need it so toJson() doesn't set the "unsaved" property.
|
||||||
|
APP->history->setSaved();
|
||||||
|
|
||||||
|
try {
|
||||||
|
APP->patch->save(path);
|
||||||
|
}
|
||||||
|
catch (Exception& e) {
|
||||||
|
asyncDialog::create(string::f("Could not save patch: %s", e.what()).c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveAsDialog()
|
||||||
|
{
|
||||||
|
std::string dir;
|
||||||
|
if (! APP->patch->path.empty())
|
||||||
|
dir = system::getDirectory(APP->patch->path);
|
||||||
|
else
|
||||||
|
dir = homeDir();
|
||||||
|
|
||||||
|
CardinalPluginContext* const pcontext = static_cast<CardinalPluginContext*>(APP);
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(pcontext != nullptr,);
|
||||||
|
|
||||||
|
CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(pcontext->ui);
|
||||||
|
DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
|
||||||
|
|
||||||
|
FileBrowserOptions opts;
|
||||||
|
opts.startDir = dir.c_str();
|
||||||
|
opts.saving = ui->saving = true;
|
||||||
|
ui->openFileBrowser(opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
32
src/CardinalCommon.hpp
Normal file
32
src/CardinalCommon.hpp
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* DISTRHO Cardinal Plugin
|
||||||
|
* Copyright (C) 2021 Filipe Coelho <falktx@falktx.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 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.
|
||||||
|
*
|
||||||
|
* For a full copy of the GNU General Public License see the LICENSE file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace patchUtils
|
||||||
|
{
|
||||||
|
|
||||||
|
void loadDialog();
|
||||||
|
void loadPathDialog(const std::string& path);
|
||||||
|
void loadTemplateDialog();
|
||||||
|
void revertDialog();
|
||||||
|
void saveDialog(const std::string& path);
|
||||||
|
void saveAsDialog();
|
||||||
|
|
||||||
|
}
|
1
src/CardinalFX/CardinalCommon.cpp
Symbolic link
1
src/CardinalFX/CardinalCommon.cpp
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../CardinalCommon.cpp
|
|
@ -1 +0,0 @@
|
||||||
../override/MenuBar.cpp
|
|
1
src/CardinalSynth/CardinalCommon.cpp
Symbolic link
1
src/CardinalSynth/CardinalCommon.cpp
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../CardinalCommon.cpp
|
|
@ -1 +0,0 @@
|
||||||
../override/MenuBar.cpp
|
|
|
@ -179,7 +179,7 @@ GLFWAPI const char* glfwGetKeyName(const int key, int)
|
||||||
|
|
||||||
namespace rack {
|
namespace rack {
|
||||||
namespace app {
|
namespace app {
|
||||||
widget::Widget* createMenuBar(CardinalBaseUI* const ui, bool isStandalone);
|
widget::Widget* createMenuBar(bool isStandalone);
|
||||||
}
|
}
|
||||||
namespace window {
|
namespace window {
|
||||||
void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui);
|
void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui);
|
||||||
|
@ -283,7 +283,7 @@ public:
|
||||||
if (context->scene->menuBar != nullptr)
|
if (context->scene->menuBar != nullptr)
|
||||||
context->scene->removeChild(context->scene->menuBar);
|
context->scene->removeChild(context->scene->menuBar);
|
||||||
|
|
||||||
context->scene->menuBar = rack::app::createMenuBar(this, getApp().isStandalone());
|
context->scene->menuBar = rack::app::createMenuBar(getApp().isStandalone());
|
||||||
context->scene->addChildBelow(context->scene->menuBar, context->scene->rackScroll);
|
context->scene->addChildBelow(context->scene->menuBar, context->scene->rackScroll);
|
||||||
|
|
||||||
// hide "Browse VCV Library" button
|
// hide "Browse VCV Library" button
|
||||||
|
|
|
@ -88,6 +88,8 @@ BUILD_CXX_FLAGS += -DnsvgParseFromFile=nsvgParseFromFileCardinal
|
||||||
|
|
||||||
RACK_FILES += AsyncDialog.cpp
|
RACK_FILES += AsyncDialog.cpp
|
||||||
RACK_FILES += override/Engine.cpp
|
RACK_FILES += override/Engine.cpp
|
||||||
|
RACK_FILES += override/MenuBar.cpp
|
||||||
|
RACK_FILES += override/Scene.cpp
|
||||||
RACK_FILES += override/asset.cpp
|
RACK_FILES += override/asset.cpp
|
||||||
RACK_FILES += override/context.cpp
|
RACK_FILES += override/context.cpp
|
||||||
RACK_FILES += override/dep.cpp
|
RACK_FILES += override/dep.cpp
|
||||||
|
@ -112,6 +114,7 @@ IGNORED_FILES += Rack/src/network.cpp
|
||||||
IGNORED_FILES += Rack/src/rtaudio.cpp
|
IGNORED_FILES += Rack/src/rtaudio.cpp
|
||||||
IGNORED_FILES += Rack/src/rtmidi.cpp
|
IGNORED_FILES += Rack/src/rtmidi.cpp
|
||||||
IGNORED_FILES += Rack/src/app/MenuBar.cpp
|
IGNORED_FILES += Rack/src/app/MenuBar.cpp
|
||||||
|
IGNORED_FILES += Rack/src/app/Scene.cpp
|
||||||
IGNORED_FILES += Rack/src/engine/Engine.cpp
|
IGNORED_FILES += Rack/src/engine/Engine.cpp
|
||||||
IGNORED_FILES += Rack/src/window/Window.cpp
|
IGNORED_FILES += Rack/src/window/Window.cpp
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ include ../../dpf/Makefile.base.mk
|
||||||
# Files to build (DPF stuff)
|
# Files to build (DPF stuff)
|
||||||
|
|
||||||
FILES_DSP = CardinalPlugin.cpp
|
FILES_DSP = CardinalPlugin.cpp
|
||||||
|
FILES_DSP += CardinalCommon.cpp
|
||||||
FILES_DSP += common.cpp
|
FILES_DSP += common.cpp
|
||||||
|
|
||||||
ifeq ($(HEADLESS),true)
|
ifeq ($(HEADLESS),true)
|
||||||
|
@ -87,7 +88,6 @@ FILES_DSP += RemoteNanoVG.cpp
|
||||||
FILES_DSP += RemoteWindow.cpp
|
FILES_DSP += RemoteWindow.cpp
|
||||||
else
|
else
|
||||||
FILES_UI = CardinalUI.cpp
|
FILES_UI = CardinalUI.cpp
|
||||||
FILES_UI += MenuBar.cpp
|
|
||||||
FILES_UI += Window.cpp
|
FILES_UI += Window.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -50,23 +50,11 @@
|
||||||
#include <patch.hpp>
|
#include <patch.hpp>
|
||||||
#include <library.hpp>
|
#include <library.hpp>
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
# undef DEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// for finding home dir
|
|
||||||
#ifndef ARCH_WIN
|
|
||||||
# include <pwd.h>
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_LIBLO
|
#ifdef HAVE_LIBLO
|
||||||
# include <lo/lo.h>
|
# include <lo/lo.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <Window.hpp>
|
#include "../CardinalCommon.hpp"
|
||||||
#include "../AsyncDialog.hpp"
|
|
||||||
#include "../PluginContext.hpp"
|
|
||||||
|
|
||||||
// #define REMOTE_HOST "localhost"
|
// #define REMOTE_HOST "localhost"
|
||||||
#define REMOTE_HOST "192.168.51.1"
|
#define REMOTE_HOST "192.168.51.1"
|
||||||
|
@ -99,37 +87,7 @@ struct MenuButton : ui::Button {
|
||||||
////////////////////
|
////////////////////
|
||||||
|
|
||||||
|
|
||||||
static void promptClear(const char* const message, const std::function<void()> action)
|
|
||||||
{
|
|
||||||
if (APP->history->isSaved() || APP->scene->rack->hasModules())
|
|
||||||
return action();
|
|
||||||
|
|
||||||
asyncDialog::create(message, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string homeDir()
|
|
||||||
{
|
|
||||||
#ifdef ARCH_WIN
|
|
||||||
if (const char* const userprofile = getenv("USERPROFILE"))
|
|
||||||
{
|
|
||||||
return userprofile;
|
|
||||||
}
|
|
||||||
else if (const char* const homedrive = getenv("HOMEDRIVE"))
|
|
||||||
{
|
|
||||||
if (const char* const homepath = getenv("HOMEPATH"))
|
|
||||||
return system::join(homedrive, homepath);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (const char* const home = getenv("HOME"))
|
|
||||||
return home;
|
|
||||||
else if (struct passwd* const pwd = getpwuid(getuid()))
|
|
||||||
return pwd->pw_dir;
|
|
||||||
#endif
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FileButton : MenuButton {
|
struct FileButton : MenuButton {
|
||||||
CardinalBaseUI* const ui;
|
|
||||||
const bool isStandalone;
|
const bool isStandalone;
|
||||||
|
|
||||||
#ifdef HAVE_LIBLO
|
#ifdef HAVE_LIBLO
|
||||||
|
@ -153,53 +111,29 @@ struct FileButton : MenuButton {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FileButton(CardinalBaseUI* const ui2, const bool standalone)
|
FileButton(const bool standalone)
|
||||||
: MenuButton(), ui(ui2), isStandalone(standalone) {}
|
: MenuButton(), isStandalone(standalone) {}
|
||||||
|
|
||||||
void onAction(const ActionEvent& e) override {
|
void onAction(const ActionEvent& e) override {
|
||||||
ui::Menu* menu = createMenu();
|
ui::Menu* menu = createMenu();
|
||||||
menu->cornerFlags = BND_CORNER_TOP;
|
menu->cornerFlags = BND_CORNER_TOP;
|
||||||
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
|
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
|
||||||
|
|
||||||
menu->addChild(createMenuItem("New", ""/*RACK_MOD_CTRL_NAME "+N"*/, []() {
|
menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() {
|
||||||
// see APP->patch->loadTemplateDialog();
|
patchUtils::loadTemplateDialog();
|
||||||
promptClear("The current patch is unsaved. Clear it and start a new patch?", []() {
|
|
||||||
APP->patch->loadTemplate();
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
menu->addChild(createMenuItem("Open / Import...", ""/*RACK_MOD_CTRL_NAME "+O"*/, [this]() {
|
menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() {
|
||||||
// see APP->patch->loadDialog();
|
patchUtils::loadDialog();
|
||||||
promptClear("The current patch is unsaved. Clear it and open a new patch?", [this]() {
|
|
||||||
std::string dir;
|
|
||||||
if (! APP->patch->path.empty())
|
|
||||||
dir = system::getDirectory(APP->patch->path);
|
|
||||||
else
|
|
||||||
dir = homeDir();
|
|
||||||
|
|
||||||
Window::FileBrowserOptions opts;
|
|
||||||
opts.startDir = dir.c_str();
|
|
||||||
opts.saving = ui->saving = false;
|
|
||||||
ui->openFileBrowser(opts);
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() {
|
menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() {
|
||||||
APP->patch->saveDialog();
|
// NOTE: will do nothing if path is empty, intentionally
|
||||||
|
patchUtils::saveDialog(APP->patch->path);
|
||||||
}, APP->patch->path.empty()));
|
}, APP->patch->path.empty()));
|
||||||
|
|
||||||
menu->addChild(createMenuItem("Save as / Export...", ""/*RACK_MOD_CTRL_NAME "+Shift+S"*/, [this]() {
|
menu->addChild(createMenuItem("Save as / Export...", RACK_MOD_CTRL_NAME "+Shift+S", []() {
|
||||||
// see APP->patch->saveAsDialog();
|
patchUtils::saveAsDialog();
|
||||||
std::string dir;
|
|
||||||
if (! APP->patch->path.empty())
|
|
||||||
dir = system::getDirectory(APP->patch->path);
|
|
||||||
else
|
|
||||||
dir = homeDir();
|
|
||||||
|
|
||||||
Window::FileBrowserOptions opts;
|
|
||||||
opts.startDir = dir.c_str();
|
|
||||||
opts.saving = ui->saving = true;
|
|
||||||
ui->openFileBrowser(opts);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
#ifdef HAVE_LIBLO
|
#ifdef HAVE_LIBLO
|
||||||
|
@ -236,13 +170,8 @@ struct FileButton : MenuButton {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
menu->addChild(createMenuItem("Revert", ""/*RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O"*/, []() {
|
menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() {
|
||||||
// APP->patch->revertDialog();
|
patchUtils::revertDialog();
|
||||||
if (APP->patch->path.empty())
|
|
||||||
return;
|
|
||||||
promptClear("Revert patch to the last saved state?", []{
|
|
||||||
APP->patch->loadAction(APP->patch->path);
|
|
||||||
});
|
|
||||||
}, APP->patch->path.empty()));
|
}, APP->patch->path.empty()));
|
||||||
|
|
||||||
if (isStandalone) {
|
if (isStandalone) {
|
||||||
|
@ -678,10 +607,9 @@ struct MeterLabel : ui::Label {
|
||||||
|
|
||||||
|
|
||||||
struct MenuBar : widget::OpaqueWidget {
|
struct MenuBar : widget::OpaqueWidget {
|
||||||
// CardinalPluginContext* const context;
|
|
||||||
MeterLabel* meterLabel;
|
MeterLabel* meterLabel;
|
||||||
|
|
||||||
MenuBar(CardinalBaseUI* const ui, const bool isStandalone)
|
MenuBar(const bool isStandalone)
|
||||||
: widget::OpaqueWidget()
|
: widget::OpaqueWidget()
|
||||||
// : context(ctx)
|
// : context(ctx)
|
||||||
{
|
{
|
||||||
|
@ -693,7 +621,7 @@ struct MenuBar : widget::OpaqueWidget {
|
||||||
layout->spacing = math::Vec(0, 0);
|
layout->spacing = math::Vec(0, 0);
|
||||||
addChild(layout);
|
addChild(layout);
|
||||||
|
|
||||||
FileButton* fileButton = new FileButton(ui, isStandalone);
|
FileButton* fileButton = new FileButton(isStandalone);
|
||||||
fileButton->text = "File";
|
fileButton->text = "File";
|
||||||
layout->addChild(fileButton);
|
layout->addChild(fileButton);
|
||||||
|
|
||||||
|
@ -746,8 +674,8 @@ widget::Widget* createMenuBar() {
|
||||||
return new widget::Widget;
|
return new widget::Widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
widget::Widget* createMenuBar(CardinalBaseUI* const ui, const bool isStandalone) {
|
widget::Widget* createMenuBar(const bool isStandalone) {
|
||||||
menuBar::MenuBar* menuBar = new menuBar::MenuBar(ui, isStandalone);
|
menuBar::MenuBar* menuBar = new menuBar::MenuBar(isStandalone);
|
||||||
return menuBar;
|
return menuBar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
300
src/override/Scene.cpp
Normal file
300
src/override/Scene.cpp
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <app/Scene.hpp>
|
||||||
|
#include <app/Browser.hpp>
|
||||||
|
#include <app/TipWindow.hpp>
|
||||||
|
#include <app/MenuBar.hpp>
|
||||||
|
#include <context.hpp>
|
||||||
|
#include <system.hpp>
|
||||||
|
#include <network.hpp>
|
||||||
|
#include <history.hpp>
|
||||||
|
#include <settings.hpp>
|
||||||
|
#include <patch.hpp>
|
||||||
|
#include <asset.hpp>
|
||||||
|
|
||||||
|
#include "../CardinalCommon.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace rack {
|
||||||
|
namespace app {
|
||||||
|
|
||||||
|
|
||||||
|
struct Scene::Internal {
|
||||||
|
bool heldArrowKeys[4] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Scene::Scene() {
|
||||||
|
internal = new Internal;
|
||||||
|
|
||||||
|
rackScroll = new RackScrollWidget;
|
||||||
|
addChild(rackScroll);
|
||||||
|
|
||||||
|
rack = rackScroll->rackWidget;
|
||||||
|
|
||||||
|
menuBar = createMenuBar();
|
||||||
|
addChild(menuBar);
|
||||||
|
|
||||||
|
browser = browserCreate();
|
||||||
|
browser->hide();
|
||||||
|
addChild(browser);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Scene::~Scene() {
|
||||||
|
delete internal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
math::Vec Scene::getMousePos() {
|
||||||
|
return mousePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::step() {
|
||||||
|
// Resize owned descendants
|
||||||
|
menuBar->box.size.x = box.size.x;
|
||||||
|
rackScroll->box.pos.y = menuBar->box.size.y;
|
||||||
|
rackScroll->box.size = box.size.minus(rackScroll->box.pos);
|
||||||
|
|
||||||
|
// Scroll RackScrollWidget with arrow keys
|
||||||
|
math::Vec arrowDelta;
|
||||||
|
if (internal->heldArrowKeys[0]) {
|
||||||
|
arrowDelta.x -= 1;
|
||||||
|
}
|
||||||
|
if (internal->heldArrowKeys[1]) {
|
||||||
|
arrowDelta.x += 1;
|
||||||
|
}
|
||||||
|
if (internal->heldArrowKeys[2]) {
|
||||||
|
arrowDelta.y -= 1;
|
||||||
|
}
|
||||||
|
if (internal->heldArrowKeys[3]) {
|
||||||
|
arrowDelta.y += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!arrowDelta.isZero()) {
|
||||||
|
int mods = APP->window->getMods();
|
||||||
|
float arrowSpeed = 32.f;
|
||||||
|
if ((mods & RACK_MOD_MASK) == RACK_MOD_CTRL)
|
||||||
|
arrowSpeed /= 4.f;
|
||||||
|
if ((mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT)
|
||||||
|
arrowSpeed *= 4.f;
|
||||||
|
if ((mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT))
|
||||||
|
arrowSpeed /= 16.f;
|
||||||
|
|
||||||
|
rackScroll->offset += arrowDelta * arrowSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::step();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::draw(const DrawArgs& args) {
|
||||||
|
Widget::draw(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::onHover(const HoverEvent& e) {
|
||||||
|
mousePos = e.pos;
|
||||||
|
if (mousePos.y < menuBar->box.size.y) {
|
||||||
|
menuBar->show();
|
||||||
|
}
|
||||||
|
OpaqueWidget::onHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::onDragHover(const DragHoverEvent& e) {
|
||||||
|
mousePos = e.pos;
|
||||||
|
OpaqueWidget::onDragHover(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::onHoverKey(const HoverKeyEvent& e) {
|
||||||
|
// Key commands that override children
|
||||||
|
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
|
||||||
|
// DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str());
|
||||||
|
if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
patchUtils::loadTemplateDialog();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
APP->window->close();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
patchUtils::loadDialog();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
|
||||||
|
patchUtils::revertDialog();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
// NOTE: will do nothing if path is empty, intentionally
|
||||||
|
patchUtils::saveDialog(APP->patch->path);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "s" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
|
||||||
|
patchUtils::saveAsDialog();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
APP->history->undo();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
|
||||||
|
APP->history->redo();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "-" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
float zoom = std::log2(APP->scene->rackScroll->getZoom());
|
||||||
|
zoom *= 2;
|
||||||
|
zoom = std::ceil(zoom - 0.01f) - 1;
|
||||||
|
zoom /= 2;
|
||||||
|
APP->scene->rackScroll->setZoom(std::pow(2.f, zoom));
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
// Numpad has a "+" key, but the main keyboard section hides it under "="
|
||||||
|
if ((e.keyName == "=" || e.keyName == "+") && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
float zoom = std::log2(APP->scene->rackScroll->getZoom());
|
||||||
|
zoom *= 2;
|
||||||
|
zoom = std::floor(zoom + 0.01f) + 1;
|
||||||
|
zoom /= 2;
|
||||||
|
APP->scene->rackScroll->setZoom(std::pow(2.f, zoom));
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if ((e.keyName == "0") && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
APP->scene->rackScroll->setZoom(1.f);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.key == GLFW_KEY_F1 && (e.mods & RACK_MOD_MASK) == 0) {
|
||||||
|
system::openBrowser("https://vcvrack.com/manual/");
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.key == GLFW_KEY_F3 && (e.mods & RACK_MOD_MASK) == 0) {
|
||||||
|
settings::cpuMeter ^= true;
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Module selections
|
||||||
|
if (e.keyName == "a" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
rack->selectAll();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "a" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
|
||||||
|
rack->deselectAll();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.keyName == "c" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->copyClipboardSelection();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.keyName == "i" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->resetSelectionAction();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.keyName == "r" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->randomizeSelectionAction();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.keyName == "u" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->disconnectSelectionAction();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.keyName == "e" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->bypassSelectionAction(!rack->isSelectionBypassed());
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.keyName == "d" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->cloneSelectionAction(false);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (e.keyName == "d" && (e.mods & RACK_MOD_MASK) == (RACK_MOD_CTRL | GLFW_MOD_SHIFT)) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->cloneSelectionAction(true);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((e.key == GLFW_KEY_DELETE || e.key == GLFW_KEY_BACKSPACE) && (e.mods & RACK_MOD_MASK) == 0) {
|
||||||
|
if (rack->hasSelection()) {
|
||||||
|
rack->deleteSelectionAction();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll RackScrollWidget with arrow keys
|
||||||
|
if (e.action == GLFW_PRESS || e.action == GLFW_RELEASE) {
|
||||||
|
if (e.key == GLFW_KEY_LEFT) {
|
||||||
|
internal->heldArrowKeys[0] = (e.action == GLFW_PRESS);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.key == GLFW_KEY_RIGHT) {
|
||||||
|
internal->heldArrowKeys[1] = (e.action == GLFW_PRESS);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.key == GLFW_KEY_UP) {
|
||||||
|
internal->heldArrowKeys[2] = (e.action == GLFW_PRESS);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if (e.key == GLFW_KEY_DOWN) {
|
||||||
|
internal->heldArrowKeys[3] = (e.action == GLFW_PRESS);
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.isConsumed())
|
||||||
|
return;
|
||||||
|
OpaqueWidget::onHoverKey(e);
|
||||||
|
if (e.isConsumed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Key commands that can be overridden by children
|
||||||
|
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
|
||||||
|
if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) {
|
||||||
|
rack->pasteClipboardAction();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
if ((e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) && (e.mods & RACK_MOD_MASK) == 0) {
|
||||||
|
browser->show();
|
||||||
|
e.consume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::onPathDrop(const PathDropEvent& e) {
|
||||||
|
if (e.paths.size() >= 1) {
|
||||||
|
const std::string& path = e.paths[0];
|
||||||
|
std::string extension = system::getExtension(path);
|
||||||
|
|
||||||
|
if (extension == ".vcv") {
|
||||||
|
patchUtils::loadPathDialog(path);
|
||||||
|
e.consume(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (extension == ".vcvs") {
|
||||||
|
APP->scene->rack->loadSelection(path);
|
||||||
|
e.consume(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpaqueWidget::onPathDrop(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace app
|
||||||
|
} // namespace rack
|
Loading…
Add table
Add a link
Reference in a new issue