@@ -1,6 +1,6 @@ | |||
#pragma once | |||
#include "util/math.hpp" | |||
#include "math.hpp" | |||
namespace rack { | |||
@@ -23,7 +23,7 @@ struct VUMeter { | |||
return (dBScaled >= 0.0) ? 1.0 : 0.0; | |||
} | |||
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 gamepad { | |||
struct GamepadInputDevice : MidiInputDevice { | |||
struct InputDevice : MidiInputDevice { | |||
int deviceId; | |||
std::vector<uint8_t> ccs; | |||
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::vector<int> getInputDeviceIds() 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 |
@@ -40,12 +40,6 @@ TWidget *createWidget(math::Vec pos) { | |||
return w; | |||
} | |||
/** Deprecated. Use createWidget<TScrew>() instead */ | |||
template <class TScrew> | |||
DEPRECATED TScrew *createScrew(math::Vec pos) { | |||
return createWidget<TScrew>(pos); | |||
} | |||
template <class TParamWidget> | |||
TParamWidget *createParam(math::Vec pos, Module *module, int paramId, float minValue, float maxValue, float defaultValue) { | |||
TParamWidget *param = new TParamWidget(); | |||
@@ -5,9 +5,10 @@ | |||
namespace rack { | |||
namespace keyboard { | |||
struct KeyboardInputDevice : MidiInputDevice { | |||
struct InputDevice : MidiInputDevice { | |||
int octave = 5; | |||
std::map<int, int> pressedNotes; | |||
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::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 |
@@ -39,16 +39,31 @@ b must be positive. | |||
*/ | |||
inline int eucMod(int a, int b) { | |||
int mod = a % b; | |||
return (mod >= 0) ? mod : mod + b; | |||
if (mod < 0) { | |||
mod += b; | |||
} | |||
return mod; | |||
} | |||
/** Euclidean division. | |||
b must be positive. | |||
*/ | |||
inline int eucDiv(int a, int b) { | |||
int mod = 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. | |||
@@ -21,6 +21,7 @@ | |||
namespace rack { | |||
// Adopt some sub-namespaces into the main namespace for convenience | |||
using namespace math; | |||
using namespace string; | |||
@@ -1,6 +1,7 @@ | |||
#pragma once | |||
#include "rack.hpp" | |||
#include "componentlibrary.hpp" | |||
namespace rack { | |||
@@ -71,5 +72,53 @@ using string::stringf; | |||
#define warn(...) WARN(__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 |
@@ -3,12 +3,14 @@ | |||
namespace rack { | |||
namespace settings { | |||
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 |
@@ -1,168 +1,20 @@ | |||
#pragma once | |||
#include <list> | |||
#include <memory> | |||
#include "nanovg.h" | |||
#include "nanosvg.h" | |||
#include "common.hpp" | |||
#include "events.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 | |||
//////////////////// | |||
/** 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. | |||
*/ | |||
@@ -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 | |||
#include <memory> | |||
#define GLEW_STATIC | |||
#include <GL/glew.h> | |||
#include <GLFW/glfw3.h> | |||
#include "nanovg.h" | |||
#include "nanosvg.h" | |||
#include "common.hpp" | |||
#include "widgets.hpp" | |||
#ifdef ARCH_MAC | |||
@@ -17,6 +19,30 @@ | |||
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 NVGcontext *gVg; | |||
extern NVGcontext *gFramebufferVg; | |||
@@ -487,7 +487,7 @@ void RackWidget::step() { | |||
// Autosave every 15 seconds | |||
if (gGuiFrame % (60 * 15) == 0) { | |||
save(asset::local("autosave.vcv")); | |||
settingsSave(asset::local("settings.json")); | |||
settings::save(asset::local("settings.json")); | |||
} | |||
Widget::step(); | |||
@@ -3,13 +3,14 @@ | |||
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)) | |||
return; | |||
// Get gamepad state | |||
@@ -53,13 +54,13 @@ void GamepadInputDevice::step() { | |||
} | |||
GamepadDriver::GamepadDriver() { | |||
Driver::Driver() { | |||
for (int i = 0; i < 16; i++) { | |||
devices[i].deviceId = i; | |||
} | |||
} | |||
std::vector<int> GamepadDriver::getInputDeviceIds() { | |||
std::vector<int> Driver::getInputDeviceIds() { | |||
std::vector<int> deviceIds; | |||
for (int i = 0; i < 16; i++) { | |||
if (glfwJoystickPresent(i)) { | |||
@@ -69,7 +70,7 @@ std::vector<int> GamepadDriver::getInputDeviceIds() { | |||
return deviceIds; | |||
} | |||
std::string GamepadDriver::getInputDeviceName(int deviceId) { | |||
std::string Driver::getInputDeviceName(int deviceId) { | |||
if (!(0 <= deviceId && deviceId < 16)) | |||
return ""; | |||
@@ -77,10 +78,10 @@ std::string GamepadDriver::getInputDeviceName(int deviceId) { | |||
if (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)) | |||
return NULL; | |||
@@ -88,7 +89,7 @@ MidiInputDevice *GamepadDriver::subscribeInputDevice(int deviceId, MidiInput *mi | |||
return &devices[deviceId]; | |||
} | |||
void GamepadDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
void Driver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
if (!(0 <= deviceId && deviceId < 16)) | |||
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) | |||
return; | |||
for (int i = 0; i < 16; i++) { | |||
@@ -112,4 +113,5 @@ void gamepadStep() { | |||
} | |||
} // namespace gamepad | |||
} // namespace rack |
@@ -3,13 +3,14 @@ | |||
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; | |||
switch (key) { | |||
case GLFW_KEY_Z: note = 0; break; | |||
@@ -77,7 +78,7 @@ void KeyboardInputDevice::onKeyPress(int key) { | |||
pressedNotes[key] = note; | |||
} | |||
void KeyboardInputDevice::onKeyRelease(int key) { | |||
void InputDevice::onKeyRelease(int key) { | |||
auto it = pressedNotes.find(key); | |||
if (it != pressedNotes.end()) { | |||
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}; | |||
} | |||
std::string KeyboardDriver::getInputDeviceName(int deviceId) { | |||
std::string Driver::getInputDeviceName(int deviceId) { | |||
if (deviceId == 0) | |||
return "QWERTY keyboard (US)"; | |||
return ""; | |||
} | |||
MidiInputDevice *KeyboardDriver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
MidiInputDevice *Driver::subscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
if (deviceId != 0) | |||
return NULL; | |||
@@ -110,7 +111,7 @@ MidiInputDevice *KeyboardDriver::subscribeInputDevice(int deviceId, MidiInput *m | |||
return &device; | |||
} | |||
void KeyboardDriver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
void Driver::unsubscribeInputDevice(int deviceId, MidiInput *midiInput) { | |||
if (deviceId != 0) | |||
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) | |||
return; | |||
driver->device.onKeyPress(key); | |||
} | |||
void keyboardRelease(int key) { | |||
void release(int key) { | |||
if (!driver) | |||
return; | |||
driver->device.onKeyRelease(key); | |||
} | |||
} // namespace keyboard | |||
} // namespace rack |
@@ -67,18 +67,18 @@ int main(int argc, char* argv[]) { | |||
engineInit(); | |||
rtmidiInit(); | |||
bridgeInit(); | |||
keyboardInit(); | |||
gamepadInit(); | |||
keyboard::init(); | |||
gamepad::init(); | |||
windowInit(); | |||
appInit(devMode); | |||
settingsLoad(asset::local("settings.json")); | |||
settings::load(asset::local("settings.json")); | |||
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. | |||
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?")) { | |||
gRackWidget->lastPath = ""; | |||
} | |||
@@ -101,7 +101,7 @@ int main(int argc, char* argv[]) { | |||
// Destroy namespaces | |||
gRackWidget->save(asset::local("autosave.vcv")); | |||
settingsSave(asset::local("settings.json")); | |||
settings::save(asset::local("settings.json")); | |||
appDestroy(); | |||
windowDestroy(); | |||
bridgeDestroy(); | |||
@@ -4,6 +4,7 @@ | |||
namespace rack { | |||
namespace settings { | |||
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()); | |||
json_t *rootJ = settingsToJson(); | |||
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()); | |||
FILE *file = fopen(filename.c_str(), "r"); | |||
if (!file) | |||
@@ -185,4 +186,5 @@ void settingsLoad(std::string filename) { | |||
} | |||
} // namespace settings | |||
} // namespace rack |
@@ -11,7 +11,6 @@ | |||
#include "osdialog.h" | |||
#include "rack.hpp" | |||
#include "window.hpp" | |||
#include "keyboard.hpp" | |||
#include "gamepad.hpp" | |||
@@ -281,10 +280,10 @@ void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods | |||
// Keyboard MIDI driver | |||
if (!(mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER))) { | |||
if (action == GLFW_PRESS) { | |||
keyboardPress(key); | |||
keyboard::press(key); | |||
} | |||
else if (action == GLFW_RELEASE) { | |||
keyboardRelease(key); | |||
keyboard::release(key); | |||
} | |||
} | |||
} | |||
@@ -444,7 +443,7 @@ void windowRun() { | |||
cursorPosCallback(gWindow, xpos, ypos); | |||
} | |||
mouseButtonStickyPop(); | |||
gamepadStep(); | |||
gamepad::step(); | |||
// Set window title | |||
std::string windowTitle; | |||