@@ -1,6 +1,6 @@ | |||||
#pragma once | #pragma once | ||||
#include "util/math.hpp" | |||||
#include "math.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -23,7 +23,7 @@ struct VUMeter { | |||||
return (dBScaled >= 0.0) ? 1.0 : 0.0; | return (dBScaled >= 0.0) ? 1.0 : 0.0; | ||||
} | } | ||||
else { | else { | ||||
return clamp(dBScaled + i, 0.0, 1.0); | |||||
return math::clamp(dBScaled + i, 0.0, 1.0); | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||
@@ -4,9 +4,10 @@ | |||||
namespace rack { | namespace rack { | ||||
namespace gamepad { | |||||
struct GamepadInputDevice : MidiInputDevice { | |||||
struct InputDevice : MidiInputDevice { | |||||
int deviceId; | int deviceId; | ||||
std::vector<uint8_t> ccs; | std::vector<uint8_t> ccs; | ||||
std::vector<bool> states; | std::vector<bool> states; | ||||
@@ -14,10 +15,10 @@ struct GamepadInputDevice : MidiInputDevice { | |||||
}; | }; | ||||
struct GamepadDriver : MidiDriver { | |||||
GamepadInputDevice devices[16]; | |||||
struct Driver : MidiDriver { | |||||
InputDevice devices[16]; | |||||
GamepadDriver(); | |||||
Driver(); | |||||
std::string getName() override {return "Gamepad";} | std::string getName() override {return "Gamepad";} | ||||
std::vector<int> getInputDeviceIds() override; | std::vector<int> getInputDeviceIds() override; | ||||
std::string getInputDeviceName(int deviceId) override; | std::string getInputDeviceName(int deviceId) override; | ||||
@@ -26,8 +27,9 @@ struct GamepadDriver : MidiDriver { | |||||
}; | }; | ||||
void gamepadInit(); | |||||
void gamepadStep(); | |||||
void init(); | |||||
void step(); | |||||
} // namespace gamepad | |||||
} // namespace rack | } // namespace rack |
@@ -40,12 +40,6 @@ TWidget *createWidget(math::Vec pos) { | |||||
return w; | return w; | ||||
} | } | ||||
/** Deprecated. Use createWidget<TScrew>() instead */ | |||||
template <class TScrew> | |||||
DEPRECATED TScrew *createScrew(math::Vec pos) { | |||||
return createWidget<TScrew>(pos); | |||||
} | |||||
template <class TParamWidget> | template <class TParamWidget> | ||||
TParamWidget *createParam(math::Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { | TParamWidget *createParam(math::Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { | ||||
TParamWidget *param = new TParamWidget(); | TParamWidget *param = new TParamWidget(); | ||||
@@ -5,9 +5,10 @@ | |||||
namespace rack { | namespace rack { | ||||
namespace keyboard { | |||||
struct KeyboardInputDevice : MidiInputDevice { | |||||
struct InputDevice : MidiInputDevice { | |||||
int octave = 5; | int octave = 5; | ||||
std::map<int, int> pressedNotes; | std::map<int, int> pressedNotes; | ||||
void onKeyPress(int key); | void onKeyPress(int key); | ||||
@@ -15,8 +16,8 @@ struct KeyboardInputDevice : MidiInputDevice { | |||||
}; | }; | ||||
struct KeyboardDriver : MidiDriver { | |||||
KeyboardInputDevice device; | |||||
struct Driver : MidiDriver { | |||||
InputDevice device; | |||||
std::string getName() override {return "Computer keyboard";} | std::string getName() override {return "Computer keyboard";} | ||||
std::vector<int> getInputDeviceIds() override; | std::vector<int> getInputDeviceIds() override; | ||||
@@ -26,9 +27,10 @@ struct KeyboardDriver : MidiDriver { | |||||
}; | }; | ||||
void keyboardInit(); | |||||
void keyboardPress(int key); | |||||
void keyboardRelease(int key); | |||||
void init(); | |||||
void press(int key); | |||||
void release(int key); | |||||
} // namespace keyboard | |||||
} // namespace rack | } // namespace rack |
@@ -39,16 +39,31 @@ b must be positive. | |||||
*/ | */ | ||||
inline int eucMod(int a, int b) { | inline int eucMod(int a, int b) { | ||||
int mod = a % b; | int mod = a % b; | ||||
return (mod >= 0) ? mod : mod + b; | |||||
if (mod < 0) { | |||||
mod += b; | |||||
} | |||||
return mod; | |||||
} | } | ||||
/** Euclidean division. | /** Euclidean division. | ||||
b must be positive. | b must be positive. | ||||
*/ | */ | ||||
inline int eucDiv(int a, int b) { | inline int eucDiv(int a, int b) { | ||||
int mod = a % b; | |||||
int div = a / b; | int div = a / b; | ||||
return (mod >= 0) ? div : div - 1; | |||||
int mod = a % b; | |||||
if (mod < 0) { | |||||
div -= 1; | |||||
} | |||||
return div; | |||||
} | |||||
inline void eucDivMod(int a, int b, int *div, int *mod) { | |||||
*div = a / b; | |||||
*mod = a % b; | |||||
if (*mod < 0) { | |||||
*div -= 1; | |||||
*mod += b; | |||||
} | |||||
} | } | ||||
/** Returns floor(log_2(n)), or 0 if n == 1. | /** Returns floor(log_2(n)), or 0 if n == 1. | ||||
@@ -21,6 +21,7 @@ | |||||
namespace rack { | namespace rack { | ||||
// Adopt some sub-namespaces into the main namespace for convenience | |||||
using namespace math; | using namespace math; | ||||
using namespace string; | using namespace string; | ||||
@@ -1,6 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include "rack.hpp" | #include "rack.hpp" | ||||
#include "componentlibrary.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -71,5 +72,53 @@ using string::stringf; | |||||
#define warn(...) WARN(__VA_ARGS__) | #define warn(...) WARN(__VA_ARGS__) | ||||
#define fatal(...) FATAL(__VA_ARGS__) | #define fatal(...) FATAL(__VA_ARGS__) | ||||
//////////////////// | |||||
// asset | |||||
//////////////////// | |||||
DEPRECATED inline std::string assetGlobal(std::string filename) {return asset::global(filename);} | |||||
DEPRECATED inline std::string assetLocal(std::string filename) {return asset::local(filename);} | |||||
DEPRECATED inline std::string assetPlugin(Plugin *plugin, std::string filename) {return asset::plugin(plugin, filename);} | |||||
//////////////////// | |||||
// color | |||||
//////////////////// | |||||
DEPRECATED inline NVGcolor colorClip(NVGcolor a) {return color::clip(a);} | |||||
DEPRECATED inline NVGcolor colorMinus(NVGcolor a, NVGcolor b) {return color::minus(a, b);} | |||||
DEPRECATED inline NVGcolor colorPlus(NVGcolor a, NVGcolor b) {return color::plus(a, b);} | |||||
DEPRECATED inline NVGcolor colorMult(NVGcolor a, NVGcolor b) {return color::mult(a, b);} | |||||
DEPRECATED inline NVGcolor colorMult(NVGcolor a, float x) {return color::mult(a, x);} | |||||
DEPRECATED inline NVGcolor colorScreen(NVGcolor a, NVGcolor b) {return color::screen(a, b);} | |||||
DEPRECATED inline NVGcolor colorAlpha(NVGcolor a, float alpha) {return color::alpha(a, alpha);} | |||||
DEPRECATED inline NVGcolor colorFromHexString(std::string s) {return color::fromHexString(s);} | |||||
DEPRECATED inline std::string colorToHexString(NVGcolor c) {return color::toHexString(c);} | |||||
//////////////////// | |||||
// componentlibrary | |||||
//////////////////// | |||||
DEPRECATED static const NVGcolor COLOR_BLACK_TRANSPARENT = SCHEME_BLACK_TRANSPARENT; | |||||
DEPRECATED static const NVGcolor COLOR_BLACK = SCHEME_BLACK; | |||||
DEPRECATED static const NVGcolor COLOR_WHITE = SCHEME_WHITE; | |||||
DEPRECATED static const NVGcolor COLOR_RED = SCHEME_RED; | |||||
DEPRECATED static const NVGcolor COLOR_ORANGE = SCHEME_ORANGE; | |||||
DEPRECATED static const NVGcolor COLOR_YELLOW = SCHEME_YELLOW; | |||||
DEPRECATED static const NVGcolor COLOR_GREEN = SCHEME_GREEN; | |||||
DEPRECATED static const NVGcolor COLOR_CYAN = SCHEME_CYAN; | |||||
DEPRECATED static const NVGcolor COLOR_BLUE = SCHEME_BLUE; | |||||
DEPRECATED static const NVGcolor COLOR_PURPLE = SCHEME_PURPLE; | |||||
DEPRECATED static const NVGcolor COLOR_LIGHT_PANEL = SCHEME_LIGHT_PANEL; | |||||
DEPRECATED static const NVGcolor COLOR_DARK_PANEL = SCHEME_DARK_PANEL; | |||||
//////////////////// | |||||
// helpers | |||||
//////////////////// | |||||
template <class TScrew> | |||||
DEPRECATED TScrew *createScrew(math::Vec pos) { | |||||
return createWidget<TScrew>(pos); | |||||
} | |||||
} // namespace rack | } // namespace rack |
@@ -3,12 +3,14 @@ | |||||
namespace rack { | namespace rack { | ||||
namespace settings { | |||||
extern bool gSkipAutosaveOnLaunch; | extern bool gSkipAutosaveOnLaunch; | ||||
void settingsSave(std::string filename); | |||||
void settingsLoad(std::string filename); | |||||
void save(std::string filename); | |||||
void load(std::string filename); | |||||
} // namespace settings | |||||
} // namespace rack | } // namespace rack |
@@ -1,168 +1,20 @@ | |||||
#pragma once | #pragma once | ||||
#include <list> | #include <list> | ||||
#include <memory> | |||||
#include "nanovg.h" | |||||
#include "nanosvg.h" | |||||
#include "common.hpp" | #include "common.hpp" | ||||
#include "events.hpp" | #include "events.hpp" | ||||
#include "color.hpp" | #include "color.hpp" | ||||
#include "widgets/Widget.hpp" | |||||
namespace rack { | |||||
//////////////////// | |||||
// resources | |||||
//////////////////// | |||||
// Constructing these directly will load from the disk each time. Use the load() functions to load from disk and cache them as long as the shared_ptr is held. | |||||
// Implemented in window.cpp | |||||
struct Font { | |||||
int handle; | |||||
Font(const std::string &filename); | |||||
~Font(); | |||||
static std::shared_ptr<Font> load(const std::string &filename); | |||||
}; | |||||
struct Image { | |||||
int handle; | |||||
Image(const std::string &filename); | |||||
~Image(); | |||||
static std::shared_ptr<Image> load(const std::string &filename); | |||||
}; | |||||
struct SVG { | |||||
NSVGimage *handle; | |||||
SVG(const std::string &filename); | |||||
~SVG(); | |||||
static std::shared_ptr<SVG> load(const std::string &filename); | |||||
}; | |||||
namespace rack { | |||||
//////////////////// | //////////////////// | ||||
// Base widget | // Base widget | ||||
//////////////////// | //////////////////// | ||||
/** A node in the 2D scene graph | |||||
Never inherit from Widget directly. Instead, inherit from VirtualWidget declared below. | |||||
*/ | |||||
struct Widget { | |||||
/** Stores position and size */ | |||||
math::Rect box = math::Rect(math::Vec(), math::Vec(INFINITY, INFINITY)); | |||||
Widget *parent = NULL; | |||||
std::list<Widget*> children; | |||||
bool visible = true; | |||||
virtual ~Widget(); | |||||
virtual math::Rect getChildrenBoundingBox(); | |||||
/** Returns `v` transformed into the coordinate system of `relative` */ | |||||
virtual math::Vec getRelativeOffset(math::Vec v, Widget *relative); | |||||
/** Returns `v` transformed into world coordinates */ | |||||
math::Vec getAbsoluteOffset(math::Vec v) { | |||||
return getRelativeOffset(v, NULL); | |||||
} | |||||
/** Returns a subset of the given math::Rect bounded by the box of this widget and all ancestors */ | |||||
virtual math::Rect getViewport(math::Rect r); | |||||
template <class T> | |||||
T *getAncestorOfType() { | |||||
if (!parent) return NULL; | |||||
T *p = dynamic_cast<T*>(parent); | |||||
if (p) return p; | |||||
return parent->getAncestorOfType<T>(); | |||||
} | |||||
template <class T> | |||||
T *getFirstDescendantOfType() { | |||||
for (Widget *child : children) { | |||||
T *c = dynamic_cast<T*>(child); | |||||
if (c) return c; | |||||
c = child->getFirstDescendantOfType<T>(); | |||||
if (c) return c; | |||||
} | |||||
return NULL; | |||||
} | |||||
/** Adds widget to list of children. | |||||
Gives ownership of widget to this widget instance. | |||||
*/ | |||||
void addChild(Widget *widget); | |||||
/** Removes widget from list of children if it exists. | |||||
Does not delete widget but transfers ownership to caller | |||||
*/ | |||||
void removeChild(Widget *widget); | |||||
/** Removes and deletes all children */ | |||||
void clearChildren(); | |||||
/** Recursively finalizes event start/end pairs as needed */ | |||||
void finalizeEvents(); | |||||
/** Advances the module by one frame */ | |||||
virtual void step(); | |||||
/** Draws to NanoVG context */ | |||||
virtual void draw(NVGcontext *vg); | |||||
// Events | |||||
/** Called when a mouse button is pressed over this widget */ | |||||
virtual void onMouseDown(EventMouseDown &e); | |||||
/** Called when a mouse button is released over this widget */ | |||||
virtual void onMouseUp(EventMouseUp &e); | |||||
/** Called when the mouse moves over this widget. | |||||
Called on every frame, even if `mouseRel = math::Vec(0, 0)`. | |||||
*/ | |||||
virtual void onMouseMove(EventMouseMove &e); | |||||
/** Called when a key is pressed while hovering over this widget */ | |||||
virtual void onHoverKey(EventHoverKey &e); | |||||
/** Called when this widget begins responding to `onMouseMove` events */ | |||||
virtual void onMouseEnter(EventMouseEnter &e) {} | |||||
/** Called when this widget no longer responds to `onMouseMove` events */ | |||||
virtual void onMouseLeave(EventMouseLeave &e) {} | |||||
/** Called when this widget gains focus by responding to the `onMouseDown` event */ | |||||
virtual void onFocus(EventFocus &e) {} | |||||
virtual void onDefocus(EventDefocus &e) {} | |||||
/** Called when a printable character is received while this widget is focused */ | |||||
virtual void onText(EventText &e) {} | |||||
/** Called when a key is pressed while this widget is focused */ | |||||
virtual void onKey(EventKey &e) {} | |||||
/** Called when the scroll wheel is moved while the mouse is hovering over this widget */ | |||||
virtual void onScroll(EventScroll &e); | |||||
/** Called when a widget responds to `onMouseDown` for a left button press */ | |||||
virtual void onDragStart(EventDragStart &e) {} | |||||
/** Called when the left button is released and this widget is being dragged */ | |||||
virtual void onDragEnd(EventDragEnd &e) {} | |||||
/** Called when a widget responds to `onMouseMove` and is being dragged */ | |||||
virtual void onDragMove(EventDragMove &e) {} | |||||
/** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */ | |||||
virtual void onDragEnter(EventDragEnter &e) {} | |||||
virtual void onDragLeave(EventDragEnter &e) {} | |||||
/** Called when a drag action ends while hovering this widget */ | |||||
virtual void onDragDrop(EventDragDrop &e) {} | |||||
/** Called when an OS selection of files is dragged-and-dropped on this widget */ | |||||
virtual void onPathDrop(EventPathDrop &e); | |||||
/** Called when an event triggers an action */ | |||||
virtual void onAction(EventAction &e) {} | |||||
/** For widgets with some concept of values, called when the value is changed */ | |||||
virtual void onChange(EventChange &e) {} | |||||
/** Called when the zoom level is changed of this widget */ | |||||
virtual void onZoom(EventZoom &e); | |||||
/** Helper function for creating and initializing a Widget with certain arguments (in this case just the position). | |||||
In this project, you will find this idiom everywhere, as an easier alternative to constructor arguments, for building a Widget (or a subclass) with a one-liner. | |||||
Example: | |||||
addChild(Widget::create<SVGWidget>(math::Vec(10, 10))) | |||||
*/ | |||||
template <typename T = Widget> | |||||
static T *create(math::Vec pos = math::Vec()) { | |||||
T *o = new T(); | |||||
o->box.pos = pos; | |||||
return o; | |||||
} | |||||
}; | |||||
/** Instead of inheriting from Widget directly, inherit from VirtualWidget to guarantee that only one copy of Widget's member variables are used by each instance of the Widget hierarchy. | /** Instead of inheriting from Widget directly, inherit from VirtualWidget to guarantee that only one copy of Widget's member variables are used by each instance of the Widget hierarchy. | ||||
*/ | */ | ||||
@@ -0,0 +1,128 @@ | |||||
#pragma once | |||||
#include "window.hpp" | |||||
namespace rack { | |||||
/** A node in the 2D scene graph | |||||
Never inherit from Widget directly. Instead, inherit from VirtualWidget declared below. | |||||
*/ | |||||
struct Widget { | |||||
/** Stores position and size */ | |||||
math::Rect box = math::Rect(math::Vec(), math::Vec(INFINITY, INFINITY)); | |||||
Widget *parent = NULL; | |||||
std::list<Widget*> children; | |||||
bool visible = true; | |||||
virtual ~Widget(); | |||||
virtual math::Rect getChildrenBoundingBox(); | |||||
/** Returns `v` transformed into the coordinate system of `relative` */ | |||||
virtual math::Vec getRelativeOffset(math::Vec v, Widget *relative); | |||||
/** Returns `v` transformed into world coordinates */ | |||||
math::Vec getAbsoluteOffset(math::Vec v) { | |||||
return getRelativeOffset(v, NULL); | |||||
} | |||||
/** Returns a subset of the given math::Rect bounded by the box of this widget and all ancestors */ | |||||
virtual math::Rect getViewport(math::Rect r); | |||||
template <class T> | |||||
T *getAncestorOfType() { | |||||
if (!parent) return NULL; | |||||
T *p = dynamic_cast<T*>(parent); | |||||
if (p) return p; | |||||
return parent->getAncestorOfType<T>(); | |||||
} | |||||
template <class T> | |||||
T *getFirstDescendantOfType() { | |||||
for (Widget *child : children) { | |||||
T *c = dynamic_cast<T*>(child); | |||||
if (c) return c; | |||||
c = child->getFirstDescendantOfType<T>(); | |||||
if (c) return c; | |||||
} | |||||
return NULL; | |||||
} | |||||
/** Adds widget to list of children. | |||||
Gives ownership of widget to this widget instance. | |||||
*/ | |||||
void addChild(Widget *widget); | |||||
/** Removes widget from list of children if it exists. | |||||
Does not delete widget but transfers ownership to caller | |||||
*/ | |||||
void removeChild(Widget *widget); | |||||
/** Removes and deletes all children */ | |||||
void clearChildren(); | |||||
/** Recursively finalizes event start/end pairs as needed */ | |||||
void finalizeEvents(); | |||||
/** Advances the module by one frame */ | |||||
virtual void step(); | |||||
/** Draws to NanoVG context */ | |||||
virtual void draw(NVGcontext *vg); | |||||
// Events | |||||
/** Called when a mouse button is pressed over this widget */ | |||||
virtual void onMouseDown(EventMouseDown &e); | |||||
/** Called when a mouse button is released over this widget */ | |||||
virtual void onMouseUp(EventMouseUp &e); | |||||
/** Called when the mouse moves over this widget. | |||||
Called on every frame, even if `mouseRel = math::Vec(0, 0)`. | |||||
*/ | |||||
virtual void onMouseMove(EventMouseMove &e); | |||||
/** Called when a key is pressed while hovering over this widget */ | |||||
virtual void onHoverKey(EventHoverKey &e); | |||||
/** Called when this widget begins responding to `onMouseMove` events */ | |||||
virtual void onMouseEnter(EventMouseEnter &e) {} | |||||
/** Called when this widget no longer responds to `onMouseMove` events */ | |||||
virtual void onMouseLeave(EventMouseLeave &e) {} | |||||
/** Called when this widget gains focus by responding to the `onMouseDown` event */ | |||||
virtual void onFocus(EventFocus &e) {} | |||||
virtual void onDefocus(EventDefocus &e) {} | |||||
/** Called when a printable character is received while this widget is focused */ | |||||
virtual void onText(EventText &e) {} | |||||
/** Called when a key is pressed while this widget is focused */ | |||||
virtual void onKey(EventKey &e) {} | |||||
/** Called when the scroll wheel is moved while the mouse is hovering over this widget */ | |||||
virtual void onScroll(EventScroll &e); | |||||
/** Called when a widget responds to `onMouseDown` for a left button press */ | |||||
virtual void onDragStart(EventDragStart &e) {} | |||||
/** Called when the left button is released and this widget is being dragged */ | |||||
virtual void onDragEnd(EventDragEnd &e) {} | |||||
/** Called when a widget responds to `onMouseMove` and is being dragged */ | |||||
virtual void onDragMove(EventDragMove &e) {} | |||||
/** Called when a widget responds to `onMouseUp` for a left button release and a widget is being dragged */ | |||||
virtual void onDragEnter(EventDragEnter &e) {} | |||||
virtual void onDragLeave(EventDragEnter &e) {} | |||||
/** Called when a drag action ends while hovering this widget */ | |||||
virtual void onDragDrop(EventDragDrop &e) {} | |||||
/** Called when an OS selection of files is dragged-and-dropped on this widget */ | |||||
virtual void onPathDrop(EventPathDrop &e); | |||||
/** Called when an event triggers an action */ | |||||
virtual void onAction(EventAction &e) {} | |||||
/** For widgets with some concept of values, called when the value is changed */ | |||||
virtual void onChange(EventChange &e) {} | |||||
/** Called when the zoom level is changed of this widget */ | |||||
virtual void onZoom(EventZoom &e); | |||||
/** Helper function for creating and initializing a Widget with certain arguments (in this case just the position). | |||||
In this project, you will find this idiom everywhere, as an easier alternative to constructor arguments, for building a Widget (or a subclass) with a one-liner. | |||||
Example: | |||||
addChild(Widget::create<SVGWidget>(math::Vec(10, 10))) | |||||
*/ | |||||
template <typename T = Widget> | |||||
static T *create(math::Vec pos = math::Vec()) { | |||||
T *o = new T(); | |||||
o->box.pos = pos; | |||||
return o; | |||||
} | |||||
}; | |||||
} // namespace rack |
@@ -1,10 +1,12 @@ | |||||
#pragma once | #pragma once | ||||
#include <memory> | |||||
#define GLEW_STATIC | #define GLEW_STATIC | ||||
#include <GL/glew.h> | #include <GL/glew.h> | ||||
#include <GLFW/glfw3.h> | #include <GLFW/glfw3.h> | ||||
#include "nanovg.h" | |||||
#include "nanosvg.h" | |||||
#include "common.hpp" | #include "common.hpp" | ||||
#include "widgets.hpp" | |||||
#ifdef ARCH_MAC | #ifdef ARCH_MAC | ||||
@@ -17,6 +19,30 @@ | |||||
namespace rack { | namespace rack { | ||||
// Constructing these directly will load from the disk each time. Use the load() functions to load from disk and cache them as long as the shared_ptr is held. | |||||
struct Font { | |||||
int handle; | |||||
Font(const std::string &filename); | |||||
~Font(); | |||||
static std::shared_ptr<Font> load(const std::string &filename); | |||||
}; | |||||
struct Image { | |||||
int handle; | |||||
Image(const std::string &filename); | |||||
~Image(); | |||||
static std::shared_ptr<Image> load(const std::string &filename); | |||||
}; | |||||
struct SVG { | |||||
NSVGimage *handle; | |||||
SVG(const std::string &filename); | |||||
~SVG(); | |||||
static std::shared_ptr<SVG> load(const std::string &filename); | |||||
}; | |||||
extern GLFWwindow *gWindow; | extern GLFWwindow *gWindow; | ||||
extern NVGcontext *gVg; | extern NVGcontext *gVg; | ||||
extern NVGcontext *gFramebufferVg; | extern NVGcontext *gFramebufferVg; | ||||
@@ -487,7 +487,7 @@ void RackWidget::step() { | |||||
// Autosave every 15 seconds | // Autosave every 15 seconds | ||||
if (gGuiFrame % (60 * 15) == 0) { | if (gGuiFrame % (60 * 15) == 0) { | ||||
save(asset::local("autosave.vcv")); | save(asset::local("autosave.vcv")); | ||||
settingsSave(asset::local("settings.json")); | |||||
settings::save(asset::local("settings.json")); | |||||
} | } | ||||
Widget::step(); | Widget::step(); | ||||
@@ -3,13 +3,14 @@ | |||||
namespace rack { | namespace rack { | ||||
namespace gamepad { | |||||
static const int GAMEPAD_DRIVER = -10; | |||||
static GamepadDriver *driver = NULL; | |||||
static const int DRIVER = -10; | |||||
static Driver *driver = NULL; | |||||
void GamepadInputDevice::step() { | |||||
void InputDevice::step() { | |||||
if (!glfwJoystickPresent(deviceId)) | if (!glfwJoystickPresent(deviceId)) | ||||
return; | return; | ||||
// Get gamepad state | // Get gamepad state | ||||
@@ -53,13 +54,13 @@ void GamepadInputDevice::step() { | |||||
} | } | ||||
GamepadDriver::GamepadDriver() { | |||||
Driver::Driver() { | |||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
devices[i].deviceId = i; | devices[i].deviceId = i; | ||||
} | } | ||||
} | } | ||||
std::vector<int> GamepadDriver::getInputDeviceIds() { | |||||
std::vector<int> Driver::getInputDeviceIds() { | |||||
std::vector<int> deviceIds; | std::vector<int> deviceIds; | ||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
if (glfwJoystickPresent(i)) { | if (glfwJoystickPresent(i)) { | ||||
@@ -69,7 +70,7 @@ std::vector<int> GamepadDriver::getInputDeviceIds() { | |||||
return deviceIds; | return deviceIds; | ||||
} | } | ||||
std::string GamepadDriver::getInputDeviceName(int deviceId) { | |||||
std::string Driver::getInputDeviceName(int deviceId) { | |||||
if (!(0 <= deviceId && deviceId < 16)) | if (!(0 <= deviceId && deviceId < 16)) | ||||
return ""; | return ""; | ||||
@@ -77,10 +78,10 @@ std::string GamepadDriver::getInputDeviceName(int deviceId) { | |||||
if (name) { | if (name) { | ||||
return name; | return name; | ||||
} | } | ||||
return string::stringf("Gamepad %d (unavailable)", deviceId + 1); | |||||
return string::stringf(" %d (unavailable)", deviceId + 1); | |||||
} | } | ||||
MidiInputDevice *GamepadDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
MidiInputDevice *Driver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
if (!(0 <= deviceId && deviceId < 16)) | if (!(0 <= deviceId && deviceId < 16)) | ||||
return NULL; | return NULL; | ||||
@@ -88,7 +89,7 @@ MidiInputDevice *GamepadDriver::subscribeInputDevice(int deviceId, MidiInput *mi | |||||
return &devices[deviceId]; | return &devices[deviceId]; | ||||
} | } | ||||
void GamepadDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
void Driver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
if (!(0 <= deviceId && deviceId < 16)) | if (!(0 <= deviceId && deviceId < 16)) | ||||
return; | return; | ||||
@@ -96,12 +97,12 @@ void GamepadDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
} | } | ||||
void gamepadInit() { | |||||
driver = new GamepadDriver(); | |||||
midiDriverAdd(GAMEPAD_DRIVER, driver); | |||||
void init() { | |||||
driver = new Driver(); | |||||
midiDriverAdd(DRIVER, driver); | |||||
} | } | ||||
void gamepadStep() { | |||||
void step() { | |||||
if (!driver) | if (!driver) | ||||
return; | return; | ||||
for (int i = 0; i < 16; i++) { | for (int i = 0; i < 16; i++) { | ||||
@@ -112,4 +113,5 @@ void gamepadStep() { | |||||
} | } | ||||
} // namespace gamepad | |||||
} // namespace rack | } // namespace rack |
@@ -3,13 +3,14 @@ | |||||
namespace rack { | namespace rack { | ||||
namespace keyboard { | |||||
static const int KEYBOARD_DRIVER = -11; | |||||
static KeyboardDriver *driver = NULL; | |||||
static const int DRIVER = -11; | |||||
static Driver *driver = NULL; | |||||
void KeyboardInputDevice::onKeyPress(int key) { | |||||
void InputDevice::onKeyPress(int key) { | |||||
int note = -1; | int note = -1; | ||||
switch (key) { | switch (key) { | ||||
case GLFW_KEY_Z: note = 0; break; | case GLFW_KEY_Z: note = 0; break; | ||||
@@ -77,7 +78,7 @@ void KeyboardInputDevice::onKeyPress(int key) { | |||||
pressedNotes[key] = note; | pressedNotes[key] = note; | ||||
} | } | ||||
void KeyboardInputDevice::onKeyRelease(int key) { | |||||
void InputDevice::onKeyRelease(int key) { | |||||
auto it = pressedNotes.find(key); | auto it = pressedNotes.find(key); | ||||
if (it != pressedNotes.end()) { | if (it != pressedNotes.end()) { | ||||
int note = it->second; | int note = it->second; | ||||
@@ -92,17 +93,17 @@ void KeyboardInputDevice::onKeyRelease(int key) { | |||||
} | } | ||||
std::vector<int> KeyboardDriver::getInputDeviceIds() { | |||||
std::vector<int> Driver::getInputDeviceIds() { | |||||
return {0}; | return {0}; | ||||
} | } | ||||
std::string KeyboardDriver::getInputDeviceName(int deviceId) { | |||||
std::string Driver::getInputDeviceName(int deviceId) { | |||||
if (deviceId == 0) | if (deviceId == 0) | ||||
return "QWERTY keyboard (US)"; | return "QWERTY keyboard (US)"; | ||||
return ""; | return ""; | ||||
} | } | ||||
MidiInputDevice *KeyboardDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
MidiInputDevice *Driver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
if (deviceId != 0) | if (deviceId != 0) | ||||
return NULL; | return NULL; | ||||
@@ -110,7 +111,7 @@ MidiInputDevice *KeyboardDriver::subscribeInputDevice(int deviceId, MidiInput *m | |||||
return &device; | return &device; | ||||
} | } | ||||
void KeyboardDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
void Driver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||||
if (deviceId != 0) | if (deviceId != 0) | ||||
return; | return; | ||||
@@ -118,22 +119,23 @@ void KeyboardDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) | |||||
} | } | ||||
void keyboardInit() { | |||||
driver = new KeyboardDriver(); | |||||
midiDriverAdd(KEYBOARD_DRIVER, driver); | |||||
void init() { | |||||
driver = new Driver(); | |||||
midiDriverAdd(DRIVER, driver); | |||||
} | } | ||||
void keyboardPress(int key) { | |||||
void press(int key) { | |||||
if (!driver) | if (!driver) | ||||
return; | return; | ||||
driver->device.onKeyPress(key); | driver->device.onKeyPress(key); | ||||
} | } | ||||
void keyboardRelease(int key) { | |||||
void release(int key) { | |||||
if (!driver) | if (!driver) | ||||
return; | return; | ||||
driver->device.onKeyRelease(key); | driver->device.onKeyRelease(key); | ||||
} | } | ||||
} // namespace keyboard | |||||
} // namespace rack | } // namespace rack |
@@ -67,18 +67,18 @@ int main(int argc, char* argv[]) { | |||||
engineInit(); | engineInit(); | ||||
rtmidiInit(); | rtmidiInit(); | ||||
bridgeInit(); | bridgeInit(); | ||||
keyboardInit(); | |||||
gamepadInit(); | |||||
keyboard::init(); | |||||
gamepad::init(); | |||||
windowInit(); | windowInit(); | ||||
appInit(devMode); | appInit(devMode); | ||||
settingsLoad(asset::local("settings.json")); | |||||
settings::load(asset::local("settings.json")); | |||||
if (patchFile.empty()) { | if (patchFile.empty()) { | ||||
// To prevent launch crashes, if Rack crashes between now and 15 seconds from now, the "skipAutosaveOnLaunch" property will remain in settings.json, so that in the next launch, the broken autosave will not be loaded. | // To prevent launch crashes, if Rack crashes between now and 15 seconds from now, the "skipAutosaveOnLaunch" property will remain in settings.json, so that in the next launch, the broken autosave will not be loaded. | ||||
bool oldSkipAutosaveOnLaunch = gSkipAutosaveOnLaunch; | |||||
gSkipAutosaveOnLaunch = true; | |||||
settingsSave(asset::local("settings.json")); | |||||
gSkipAutosaveOnLaunch = false; | |||||
bool oldSkipAutosaveOnLaunch = settings::gSkipAutosaveOnLaunch; | |||||
settings::gSkipAutosaveOnLaunch = true; | |||||
settings::save(asset::local("settings.json")); | |||||
settings::gSkipAutosaveOnLaunch = false; | |||||
if (oldSkipAutosaveOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, possibly caused by a faulty module in your patch. Clear your patch and start over?")) { | if (oldSkipAutosaveOnLaunch && osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, "Rack has recovered from a crash, possibly caused by a faulty module in your patch. Clear your patch and start over?")) { | ||||
gRackWidget->lastPath = ""; | gRackWidget->lastPath = ""; | ||||
} | } | ||||
@@ -101,7 +101,7 @@ int main(int argc, char* argv[]) { | |||||
// Destroy namespaces | // Destroy namespaces | ||||
gRackWidget->save(asset::local("autosave.vcv")); | gRackWidget->save(asset::local("autosave.vcv")); | ||||
settingsSave(asset::local("settings.json")); | |||||
settings::save(asset::local("settings.json")); | |||||
appDestroy(); | appDestroy(); | ||||
windowDestroy(); | windowDestroy(); | ||||
bridgeDestroy(); | bridgeDestroy(); | ||||
@@ -4,6 +4,7 @@ | |||||
namespace rack { | namespace rack { | ||||
namespace settings { | |||||
bool gSkipAutosaveOnLaunch = false; | bool gSkipAutosaveOnLaunch = false; | ||||
@@ -151,7 +152,7 @@ static void settingsFromJson(json_t *rootJ) { | |||||
} | } | ||||
void settingsSave(std::string filename) { | |||||
void save(std::string filename) { | |||||
INFO("Saving settings %s", filename.c_str()); | INFO("Saving settings %s", filename.c_str()); | ||||
json_t *rootJ = settingsToJson(); | json_t *rootJ = settingsToJson(); | ||||
if (rootJ) { | if (rootJ) { | ||||
@@ -165,7 +166,7 @@ void settingsSave(std::string filename) { | |||||
} | } | ||||
} | } | ||||
void settingsLoad(std::string filename) { | |||||
void load(std::string filename) { | |||||
INFO("Loading settings %s", filename.c_str()); | INFO("Loading settings %s", filename.c_str()); | ||||
FILE *file = fopen(filename.c_str(), "r"); | FILE *file = fopen(filename.c_str(), "r"); | ||||
if (!file) | if (!file) | ||||
@@ -185,4 +186,5 @@ void settingsLoad(std::string filename) { | |||||
} | } | ||||
} // namespace settings | |||||
} // namespace rack | } // namespace rack |
@@ -11,7 +11,6 @@ | |||||
#include "osdialog.h" | #include "osdialog.h" | ||||
#include "rack.hpp" | #include "rack.hpp" | ||||
#include "window.hpp" | |||||
#include "keyboard.hpp" | #include "keyboard.hpp" | ||||
#include "gamepad.hpp" | #include "gamepad.hpp" | ||||
@@ -281,10 +280,10 @@ void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods | |||||
// Keyboard MIDI driver | // Keyboard MIDI driver | ||||
if (!(mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER))) { | if (!(mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER))) { | ||||
if (action == GLFW_PRESS) { | if (action == GLFW_PRESS) { | ||||
keyboardPress(key); | |||||
keyboard::press(key); | |||||
} | } | ||||
else if (action == GLFW_RELEASE) { | else if (action == GLFW_RELEASE) { | ||||
keyboardRelease(key); | |||||
keyboard::release(key); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -444,7 +443,7 @@ void windowRun() { | |||||
cursorPosCallback(gWindow, xpos, ypos); | cursorPosCallback(gWindow, xpos, ypos); | ||||
} | } | ||||
mouseButtonStickyPop(); | mouseButtonStickyPop(); | ||||
gamepadStep(); | |||||
gamepad::step(); | |||||
// Set window title | // Set window title | ||||
std::string windowTitle; | std::string windowTitle; | ||||