@@ -1,25 +0,0 @@ | |||
#pragma once | |||
#include "common.hpp" | |||
namespace rack { | |||
struct Plugin; | |||
struct AssetManager { | |||
std::string systemDir; | |||
std::string userDir; | |||
AssetManager(); | |||
/** Returns the path of a system resource. Should only read files from this location. */ | |||
std::string system(std::string filename); | |||
/** Returns the path of a user resource. Can read and write files to this location. */ | |||
std::string user(std::string filename); | |||
/** Returns the path of a resource in the plugin's folder. Should only read files from this location. */ | |||
std::string plugin(Plugin *plugin, std::string filename); | |||
}; | |||
} // namespace rack |
@@ -1,6 +1,7 @@ | |||
#pragma once | |||
#include "app/common.hpp" | |||
#include "app/ParamWidget.hpp" | |||
#include "context.hpp" | |||
namespace rack { | |||
@@ -15,11 +16,11 @@ struct Knob : ParamWidget { | |||
float speed = 1.0; | |||
void onDragStart(event::DragStart &e) override { | |||
windowCursorLock(); | |||
context()->window->cursorLock(); | |||
} | |||
void onDragEnd(event::DragEnd &e) override { | |||
windowCursorUnlock(); | |||
context()->window->cursorUnlock(); | |||
} | |||
void onDragMove(event::DragMove &e) override { | |||
@@ -35,7 +36,7 @@ struct Knob : ParamWidget { | |||
float delta = KNOB_SENSITIVITY * -e.mouseDelta.y * speed * range; | |||
// Drag slower if Mod is held | |||
if (windowIsModPressed()) | |||
if (context()->window->isModPressed()) | |||
delta /= 16.f; | |||
quantity->moveValue(delta); | |||
} | |||
@@ -3,6 +3,7 @@ | |||
#include "widgets/TransparentWidget.hpp" | |||
#include "widgets/FramebufferWidget.hpp" | |||
#include "widgets/SVGWidget.hpp" | |||
#include "context.hpp" | |||
namespace rack { | |||
@@ -22,7 +23,7 @@ struct PanelBorder : TransparentWidget { | |||
struct SVGPanel : FramebufferWidget { | |||
void step() override { | |||
if (isNear(gPixelRatio, 1.0)) { | |||
if (isNear(context()->window->pixelRatio, 1.0)) { | |||
// Small details draw poorly at low DPI, so oversample when drawing to the framebuffer | |||
oversample = 2.0; | |||
} | |||
@@ -19,6 +19,7 @@ struct Scene : OpaqueWidget { | |||
Toolbar *toolbar; | |||
// Version checking | |||
bool devMode = false; | |||
bool checkVersion = true; | |||
bool checkedVersion = false; | |||
std::string latestVersion; | |||
@@ -0,0 +1,26 @@ | |||
#pragma once | |||
#include "common.hpp" | |||
namespace rack { | |||
struct Plugin; | |||
namespace asset { | |||
void init(bool devMode); | |||
/** Returns the path of a system resource. Should only read files from this location. */ | |||
std::string system(std::string filename); | |||
/** Returns the path of a user resource. Can read and write files to this location. */ | |||
std::string user(std::string filename); | |||
/** Returns the path of a resource in the plugin's folder. Should only read files from this location. */ | |||
std::string plugin(Plugin *plugin, std::string filename); | |||
extern std::string gSystemDir; | |||
extern std::string gUserDir; | |||
} // namespace asset | |||
} // namespace rack |
@@ -35,25 +35,25 @@ struct RoundKnob : SVGKnob { | |||
struct RoundBlackKnob : RoundKnob { | |||
RoundBlackKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/RoundBlackKnob.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/RoundBlackKnob.svg"))); | |||
} | |||
}; | |||
struct RoundSmallBlackKnob : RoundKnob { | |||
RoundSmallBlackKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/RoundSmallBlackKnob.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/RoundSmallBlackKnob.svg"))); | |||
} | |||
}; | |||
struct RoundLargeBlackKnob : RoundKnob { | |||
RoundLargeBlackKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/RoundLargeBlackKnob.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/RoundLargeBlackKnob.svg"))); | |||
} | |||
}; | |||
struct RoundHugeBlackKnob : RoundKnob { | |||
RoundHugeBlackKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/RoundHugeBlackKnob.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/RoundHugeBlackKnob.svg"))); | |||
} | |||
}; | |||
@@ -75,37 +75,37 @@ struct Davies1900hKnob : SVGKnob { | |||
struct Davies1900hWhiteKnob : Davies1900hKnob { | |||
Davies1900hWhiteKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Davies1900hWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Davies1900hWhite.svg"))); | |||
} | |||
}; | |||
struct Davies1900hBlackKnob : Davies1900hKnob { | |||
Davies1900hBlackKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Davies1900hBlack.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Davies1900hBlack.svg"))); | |||
} | |||
}; | |||
struct Davies1900hRedKnob : Davies1900hKnob { | |||
Davies1900hRedKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Davies1900hRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Davies1900hRed.svg"))); | |||
} | |||
}; | |||
struct Davies1900hLargeWhiteKnob : Davies1900hKnob { | |||
Davies1900hLargeWhiteKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Davies1900hLargeWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Davies1900hLargeWhite.svg"))); | |||
} | |||
}; | |||
struct Davies1900hLargeBlackKnob : Davies1900hKnob { | |||
Davies1900hLargeBlackKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Davies1900hLargeBlack.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Davies1900hLargeBlack.svg"))); | |||
} | |||
}; | |||
struct Davies1900hLargeRedKnob : Davies1900hKnob { | |||
Davies1900hLargeRedKnob() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Davies1900hLargeRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Davies1900hLargeRed.svg"))); | |||
} | |||
}; | |||
@@ -119,163 +119,163 @@ struct Rogan : SVGKnob { | |||
struct Rogan6PSWhite : Rogan { | |||
Rogan6PSWhite() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan6PSWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan6PSWhite.svg"))); | |||
} | |||
}; | |||
struct Rogan5PSGray : Rogan { | |||
Rogan5PSGray() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan5PSGray.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan5PSGray.svg"))); | |||
} | |||
}; | |||
struct Rogan3PSBlue : Rogan { | |||
Rogan3PSBlue() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PSBlue.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PSBlue.svg"))); | |||
} | |||
}; | |||
struct Rogan3PSRed : Rogan { | |||
Rogan3PSRed() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PSRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PSRed.svg"))); | |||
} | |||
}; | |||
struct Rogan3PSGreen : Rogan { | |||
Rogan3PSGreen() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PSGreen.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PSGreen.svg"))); | |||
} | |||
}; | |||
struct Rogan3PSWhite : Rogan { | |||
Rogan3PSWhite() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PSWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PSWhite.svg"))); | |||
} | |||
}; | |||
struct Rogan3PBlue : Rogan { | |||
Rogan3PBlue() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PBlue.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PBlue.svg"))); | |||
} | |||
}; | |||
struct Rogan3PRed : Rogan { | |||
Rogan3PRed() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PRed.svg"))); | |||
} | |||
}; | |||
struct Rogan3PGreen : Rogan { | |||
Rogan3PGreen() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PGreen.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PGreen.svg"))); | |||
} | |||
}; | |||
struct Rogan3PWhite : Rogan { | |||
Rogan3PWhite() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan3PWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan3PWhite.svg"))); | |||
} | |||
}; | |||
struct Rogan2SGray : Rogan { | |||
Rogan2SGray() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2SGray.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2SGray.svg"))); | |||
} | |||
}; | |||
struct Rogan2PSBlue : Rogan { | |||
Rogan2PSBlue() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PSBlue.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PSBlue.svg"))); | |||
} | |||
}; | |||
struct Rogan2PSRed : Rogan { | |||
Rogan2PSRed() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PSRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PSRed.svg"))); | |||
} | |||
}; | |||
struct Rogan2PSGreen : Rogan { | |||
Rogan2PSGreen() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PSGreen.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PSGreen.svg"))); | |||
} | |||
}; | |||
struct Rogan2PSWhite : Rogan { | |||
Rogan2PSWhite() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PSWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PSWhite.svg"))); | |||
} | |||
}; | |||
struct Rogan2PBlue : Rogan { | |||
Rogan2PBlue() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PBlue.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PBlue.svg"))); | |||
} | |||
}; | |||
struct Rogan2PRed : Rogan { | |||
Rogan2PRed() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PRed.svg"))); | |||
} | |||
}; | |||
struct Rogan2PGreen : Rogan { | |||
Rogan2PGreen() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PGreen.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PGreen.svg"))); | |||
} | |||
}; | |||
struct Rogan2PWhite : Rogan { | |||
Rogan2PWhite() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan2PWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan2PWhite.svg"))); | |||
} | |||
}; | |||
struct Rogan1PSBlue : Rogan { | |||
Rogan1PSBlue() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PSBlue.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PSBlue.svg"))); | |||
} | |||
}; | |||
struct Rogan1PSRed : Rogan { | |||
Rogan1PSRed() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PSRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PSRed.svg"))); | |||
} | |||
}; | |||
struct Rogan1PSGreen : Rogan { | |||
Rogan1PSGreen() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PSGreen.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PSGreen.svg"))); | |||
} | |||
}; | |||
struct Rogan1PSWhite : Rogan { | |||
Rogan1PSWhite() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PSWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PSWhite.svg"))); | |||
} | |||
}; | |||
struct Rogan1PBlue : Rogan { | |||
Rogan1PBlue() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PBlue.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PBlue.svg"))); | |||
} | |||
}; | |||
struct Rogan1PRed : Rogan { | |||
Rogan1PRed() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PRed.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PRed.svg"))); | |||
} | |||
}; | |||
struct Rogan1PGreen : Rogan { | |||
Rogan1PGreen() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PGreen.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PGreen.svg"))); | |||
} | |||
}; | |||
struct Rogan1PWhite : Rogan { | |||
Rogan1PWhite() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Rogan1PWhite.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Rogan1PWhite.svg"))); | |||
} | |||
}; | |||
@@ -284,9 +284,9 @@ struct SynthTechAlco : SVGKnob { | |||
SynthTechAlco() { | |||
minAngle = -0.82*M_PI; | |||
maxAngle = 0.82*M_PI; | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/SynthTechAlco.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/SynthTechAlco.svg"))); | |||
SVGWidget *cap = new SVGWidget; | |||
cap->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/SynthTechAlco_cap.svg"))); | |||
cap->setSVG(SVG::load(asset::system("res/ComponentLibrary/SynthTechAlco_cap.svg"))); | |||
addChild(cap); | |||
} | |||
}; | |||
@@ -295,7 +295,7 @@ struct Trimpot : SVGKnob { | |||
Trimpot() { | |||
minAngle = -0.75*M_PI; | |||
maxAngle = 0.75*M_PI; | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/Trimpot.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/Trimpot.svg"))); | |||
} | |||
}; | |||
@@ -303,7 +303,7 @@ struct BefacoBigKnob : SVGKnob { | |||
BefacoBigKnob() { | |||
minAngle = -0.75*M_PI; | |||
maxAngle = 0.75*M_PI; | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoBigKnob.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/BefacoBigKnob.svg"))); | |||
} | |||
}; | |||
@@ -319,7 +319,7 @@ struct BefacoTinyKnob : SVGKnob { | |||
BefacoTinyKnob() { | |||
minAngle = -0.75*M_PI; | |||
maxAngle = 0.75*M_PI; | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoTinyKnob.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/BefacoTinyKnob.svg"))); | |||
} | |||
}; | |||
@@ -328,7 +328,7 @@ struct BefacoSlidePot : SVGSlider { | |||
Vec margin = Vec(3.5, 3.5); | |||
maxHandlePos = Vec(-1, -2).plus(margin); | |||
minHandlePos = Vec(-1, 87).plus(margin); | |||
setSVGs(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoSlidePot.svg")), SVG::load(context()->asset->system("res/ComponentLibrary/BefacoSlidePotHandle.svg"))); | |||
setSVGs(SVG::load(asset::system("res/ComponentLibrary/BefacoSlidePot.svg")), SVG::load(asset::system("res/ComponentLibrary/BefacoSlidePotHandle.svg"))); | |||
background->box.pos = margin; | |||
box.size = background->box.size.plus(margin.mult(2)); | |||
} | |||
@@ -338,38 +338,38 @@ struct LEDSlider : SVGSlider { | |||
LEDSlider() { | |||
maxHandlePos = mm2px(Vec(0.738, 0.738).plus(Vec(2, 0))); | |||
minHandlePos = mm2px(Vec(0.738, 22.078).plus(Vec(2, 0))); | |||
setSVGs(SVG::load(context()->asset->system("res/ComponentLibrary/LEDSlider.svg")), NULL); | |||
setSVGs(SVG::load(asset::system("res/ComponentLibrary/LEDSlider.svg")), NULL); | |||
} | |||
}; | |||
/** API is unstable for LEDSlider. Will add a LightWidget later. */ | |||
struct LEDSliderGreen : LEDSlider { | |||
LEDSliderGreen() { | |||
handle->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/LEDSliderGreenHandle.svg"))); | |||
handle->setSVG(SVG::load(asset::system("res/ComponentLibrary/LEDSliderGreenHandle.svg"))); | |||
} | |||
}; | |||
struct LEDSliderRed : LEDSlider { | |||
LEDSliderRed() { | |||
handle->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/LEDSliderRedHandle.svg"))); | |||
handle->setSVG(SVG::load(asset::system("res/ComponentLibrary/LEDSliderRedHandle.svg"))); | |||
} | |||
}; | |||
struct LEDSliderYellow : LEDSlider { | |||
LEDSliderYellow() { | |||
handle->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/LEDSliderYellowHandle.svg"))); | |||
handle->setSVG(SVG::load(asset::system("res/ComponentLibrary/LEDSliderYellowHandle.svg"))); | |||
} | |||
}; | |||
struct LEDSliderBlue : LEDSlider { | |||
LEDSliderBlue() { | |||
handle->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/LEDSliderBlueHandle.svg"))); | |||
handle->setSVG(SVG::load(asset::system("res/ComponentLibrary/LEDSliderBlueHandle.svg"))); | |||
} | |||
}; | |||
struct LEDSliderWhite : LEDSlider { | |||
LEDSliderWhite() { | |||
handle->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/LEDSliderWhiteHandle.svg"))); | |||
handle->setSVG(SVG::load(asset::system("res/ComponentLibrary/LEDSliderWhiteHandle.svg"))); | |||
} | |||
}; | |||
@@ -379,19 +379,19 @@ struct LEDSliderWhite : LEDSlider { | |||
struct PJ301MPort : SVGPort { | |||
PJ301MPort() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/PJ301M.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/PJ301M.svg"))); | |||
} | |||
}; | |||
struct PJ3410Port : SVGPort { | |||
PJ3410Port() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/PJ3410.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/PJ3410.svg"))); | |||
} | |||
}; | |||
struct CL1362Port : SVGPort { | |||
CL1362Port() { | |||
setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/CL1362.svg"))); | |||
setSVG(SVG::load(asset::system("res/ComponentLibrary/CL1362.svg"))); | |||
} | |||
}; | |||
@@ -514,83 +514,83 @@ struct PB61303Light : BASE { | |||
struct NKK : SVGSwitch, ToggleSwitch { | |||
NKK() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/NKK_0.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/NKK_1.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/NKK_2.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/NKK_0.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/NKK_1.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/NKK_2.svg"))); | |||
} | |||
}; | |||
struct CKSS : SVGSwitch, ToggleSwitch { | |||
CKSS() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/CKSS_0.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/CKSS_1.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/CKSS_0.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/CKSS_1.svg"))); | |||
} | |||
}; | |||
struct CKSSThree : SVGSwitch, ToggleSwitch { | |||
CKSSThree() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/CKSSThree_0.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/CKSSThree_1.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/CKSSThree_2.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/CKSSThree_0.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/CKSSThree_1.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/CKSSThree_2.svg"))); | |||
} | |||
}; | |||
struct CKD6 : SVGSwitch, MomentarySwitch { | |||
CKD6() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/CKD6_0.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/CKD6_1.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/CKD6_0.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/CKD6_1.svg"))); | |||
} | |||
}; | |||
struct TL1105 : SVGSwitch, MomentarySwitch { | |||
TL1105() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/TL1105_0.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/TL1105_1.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/TL1105_0.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/TL1105_1.svg"))); | |||
} | |||
}; | |||
struct LEDButton : SVGSwitch, MomentarySwitch { | |||
LEDButton() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/LEDButton.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/LEDButton.svg"))); | |||
} | |||
}; | |||
struct BefacoSwitch : SVGSwitch, ToggleSwitch { | |||
BefacoSwitch() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoSwitch_0.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoSwitch_1.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoSwitch_2.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/BefacoSwitch_0.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/BefacoSwitch_1.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/BefacoSwitch_2.svg"))); | |||
} | |||
}; | |||
struct BefacoPush : SVGSwitch, MomentarySwitch { | |||
BefacoPush() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoPush_0.svg"))); | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/BefacoPush_1.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/BefacoPush_0.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/BefacoPush_1.svg"))); | |||
} | |||
}; | |||
struct LEDBezel : SVGSwitch, MomentarySwitch { | |||
LEDBezel() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/LEDBezel.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/LEDBezel.svg"))); | |||
} | |||
}; | |||
struct PB61303 : SVGSwitch, MomentarySwitch { | |||
PB61303() { | |||
addFrame(SVG::load(context()->asset->system("res/ComponentLibrary/PB61303.svg"))); | |||
addFrame(SVG::load(asset::system("res/ComponentLibrary/PB61303.svg"))); | |||
} | |||
}; | |||
struct PB61303Button : SVGButton { | |||
PB61303Button() { | |||
setSVGs(SVG::load(context()->asset->system("res/ComponentLibrary/PB61303.svg")), NULL); | |||
setSVGs(SVG::load(asset::system("res/ComponentLibrary/PB61303.svg")), NULL); | |||
} | |||
}; | |||
struct LEDBezelButton : SVGButton { | |||
LEDBezelButton() { | |||
setSVGs(SVG::load(context()->asset->system("res/ComponentLibrary/LEDBezel.svg")), NULL); | |||
setSVGs(SVG::load(asset::system("res/ComponentLibrary/LEDBezel.svg")), NULL); | |||
} | |||
}; | |||
@@ -600,14 +600,14 @@ struct LEDBezelButton : SVGButton { | |||
struct ScrewSilver : SVGScrew { | |||
ScrewSilver() { | |||
sw->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/ScrewSilver.svg"))); | |||
sw->setSVG(SVG::load(asset::system("res/ComponentLibrary/ScrewSilver.svg"))); | |||
box.size = sw->box.size; | |||
} | |||
}; | |||
struct ScrewBlack : SVGScrew { | |||
ScrewBlack() { | |||
sw->setSVG(SVG::load(context()->asset->system("res/ComponentLibrary/ScrewBlack.svg"))); | |||
sw->setSVG(SVG::load(asset::system("res/ComponentLibrary/ScrewBlack.svg"))); | |||
box.size = sw->box.size; | |||
} | |||
}; | |||
@@ -12,17 +12,15 @@ namespace event { | |||
struct Scene; | |||
struct Engine; | |||
struct PluginManager; | |||
struct AssetManager; | |||
struct Window; | |||
struct Context { | |||
bool devMode = false; | |||
event::Context *event = NULL; | |||
Scene *scene = NULL; | |||
Engine *engine = NULL; | |||
PluginManager *plugin = NULL; | |||
AssetManager *asset = NULL; | |||
Window *window = NULL; | |||
}; | |||
@@ -144,7 +144,7 @@ TMenuItem *createMenuItem(std::string text, std::string rightText = "") { | |||
// TODO Reevaluate this. Does it belong here? | |||
inline Menu *createMenu() { | |||
Menu *o = new Menu; | |||
o->box.pos = gMousePos; | |||
o->box.pos = context()->window->mousePos; | |||
MenuOverlay *menuOverlay = new MenuOverlay; | |||
menuOverlay->addChild(o); | |||
@@ -24,7 +24,7 @@ enum Level { | |||
FATAL_LEVEL | |||
}; | |||
void init(); | |||
void init(bool devMode); | |||
void destroy(); | |||
/** Do not use this function directly. Use the macros below. */ | |||
void log(Level level, const char *filename, int line, const char *format, ...); | |||
@@ -17,7 +17,7 @@ struct PluginManager { | |||
std::string downloadName; | |||
std::string loginStatus; | |||
PluginManager(); | |||
PluginManager(bool devMode); | |||
~PluginManager(); | |||
void logIn(std::string email, std::string password); | |||
void logOut(); | |||
@@ -7,7 +7,7 @@ | |||
#include "system.hpp" | |||
#include "random.hpp" | |||
#include "network.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "window.hpp" | |||
#include "context.hpp" | |||
#include "helpers.hpp" | |||
@@ -69,9 +69,9 @@ DEPRECATED inline float randomf() {return random::uniform();} | |||
// asset | |||
//////////////////// | |||
DEPRECATED inline std::string assetGlobal(std::string filename) {return context()->asset->system(filename);} | |||
DEPRECATED inline std::string assetLocal(std::string filename) {return context()->asset->user(filename);} | |||
DEPRECATED inline std::string assetPlugin(Plugin *plugin, std::string filename) {return context()->asset->plugin(plugin, filename);} | |||
DEPRECATED inline std::string assetGlobal(std::string filename) {return asset::system(filename);} | |||
DEPRECATED inline std::string assetLocal(std::string filename) {return asset::user(filename);} | |||
DEPRECATED inline std::string assetPlugin(Plugin *plugin, std::string filename) {return asset::plugin(plugin, filename);} | |||
//////////////////// | |||
// color | |||
@@ -0,0 +1,13 @@ | |||
#pragma once | |||
#include "common.hpp" | |||
#include <nanovg.h> | |||
#include <nanosvg.h> | |||
namespace rack { | |||
void svgDraw(NVGcontext *vg, NSVGimage *svg); | |||
} // namespace rack |
@@ -0,0 +1,15 @@ | |||
#pragma once | |||
#include "ui/common.hpp" | |||
#include "color.hpp" | |||
#include "window.hpp" | |||
namespace rack { | |||
void uiInit(); | |||
void uiDestroy(); | |||
void uiSetTheme(NVGcolor bg, NVGcolor fg); | |||
} // namespace rack |
@@ -34,9 +34,9 @@ struct MenuItem : MenuEntry { | |||
void step() override { | |||
// Add 10 more pixels because measurements on high-DPI screens are sometimes too small for some reason | |||
const float rightPadding = 10.0; | |||
// HACK use gVg from the window. | |||
// All this does is inspect the font, so it shouldn't modify gVg and should work when called from a FramebufferWidget for example. | |||
box.size.x = bndLabelWidth(gVg, -1, text.c_str()) + bndLabelWidth(gVg, -1, rightText.c_str()) + rightPadding; | |||
// HACK use context()->window->vg from the window. | |||
// All this does is inspect the font, so it shouldn't modify context()->window->vg and should work when called from a FramebufferWidget for example. | |||
box.size.x = bndLabelWidth(context()->window->vg, -1, text.c_str()) + bndLabelWidth(context()->window->vg, -1, rightText.c_str()) + rightPadding; | |||
Widget::step(); | |||
} | |||
@@ -1,6 +1,7 @@ | |||
#pragma once | |||
#include "ui/common.hpp" | |||
#include "ui/MenuEntry.hpp" | |||
#include "context.hpp" | |||
namespace rack { | |||
@@ -16,8 +17,8 @@ struct MenuLabel : MenuEntry { | |||
void step() override { | |||
// Add 10 more pixels because Retina measurements are sometimes too small | |||
const float rightPadding = 10.0; | |||
// HACK use gVg from the window. | |||
box.size.x = bndLabelWidth(gVg, -1, text.c_str()) + rightPadding; | |||
// HACK use context()->window->vg from the window. | |||
box.size.x = bndLabelWidth(context()->window->vg, -1, text.c_str()) + rightPadding; | |||
Widget::step(); | |||
} | |||
}; | |||
@@ -29,14 +29,14 @@ struct ScrollBar : OpaqueWidget { | |||
void onDragStart(event::DragStart &e) override { | |||
state = BND_ACTIVE; | |||
windowCursorLock(); | |||
context()->window->cursorLock(); | |||
} | |||
void onDragMove(event::DragMove &e) override; | |||
void onDragEnd(event::DragEnd &e) override { | |||
state = BND_DEFAULT; | |||
windowCursorUnlock(); | |||
context()->window->cursorUnlock(); | |||
} | |||
}; | |||
@@ -114,23 +114,23 @@ struct ScrollWidget : OpaqueWidget { | |||
// Scroll with arrow keys | |||
if (!context()->event->selectedWidget) { | |||
float arrowSpeed = 30.0; | |||
if (windowIsShiftPressed() && windowIsModPressed()) | |||
if (context()->window->isShiftPressed() && context()->window->isModPressed()) | |||
arrowSpeed /= 16.0; | |||
else if (windowIsShiftPressed()) | |||
else if (context()->window->isShiftPressed()) | |||
arrowSpeed *= 4.0; | |||
else if (windowIsModPressed()) | |||
else if (context()->window->isModPressed()) | |||
arrowSpeed /= 4.0; | |||
if (glfwGetKey(gWindow, GLFW_KEY_LEFT) == GLFW_PRESS) { | |||
if (glfwGetKey(context()->window->win, GLFW_KEY_LEFT) == GLFW_PRESS) { | |||
offset.x -= arrowSpeed; | |||
} | |||
if (glfwGetKey(gWindow, GLFW_KEY_RIGHT) == GLFW_PRESS) { | |||
if (glfwGetKey(context()->window->win, GLFW_KEY_RIGHT) == GLFW_PRESS) { | |||
offset.x += arrowSpeed; | |||
} | |||
if (glfwGetKey(gWindow, GLFW_KEY_UP) == GLFW_PRESS) { | |||
if (glfwGetKey(context()->window->win, GLFW_KEY_UP) == GLFW_PRESS) { | |||
offset.y -= arrowSpeed; | |||
} | |||
if (glfwGetKey(gWindow, GLFW_KEY_DOWN) == GLFW_PRESS) { | |||
if (glfwGetKey(context()->window->win, GLFW_KEY_DOWN) == GLFW_PRESS) { | |||
offset.y += arrowSpeed; | |||
} | |||
} | |||
@@ -2,6 +2,7 @@ | |||
#include "widgets/OpaqueWidget.hpp" | |||
#include "ui/Quantity.hpp" | |||
#include "ui/common.hpp" | |||
#include "context.hpp" | |||
namespace rack { | |||
@@ -31,7 +32,7 @@ struct Slider : OpaqueWidget { | |||
void onDragStart(event::DragStart &e) override { | |||
state = BND_ACTIVE; | |||
windowCursorLock(); | |||
context()->window->cursorLock(); | |||
} | |||
void onDragMove(event::DragMove &e) override { | |||
@@ -42,7 +43,7 @@ struct Slider : OpaqueWidget { | |||
void onDragEnd(event::DragEnd &e) override { | |||
state = BND_DEFAULT; | |||
windowCursorUnlock(); | |||
context()->window->cursorUnlock(); | |||
} | |||
void onButton(event::Button &e) override { | |||
@@ -109,7 +109,7 @@ struct TextField : OpaqueWidget { | |||
} | |||
} break; | |||
case GLFW_KEY_LEFT: { | |||
if (windowIsModPressed()) { | |||
if (context()->window->isModPressed()) { | |||
while (--cursor > 0) { | |||
if (text[cursor] == ' ') | |||
break; | |||
@@ -118,12 +118,12 @@ struct TextField : OpaqueWidget { | |||
else { | |||
cursor--; | |||
} | |||
if (!windowIsShiftPressed()) { | |||
if (!context()->window->isShiftPressed()) { | |||
selection = cursor; | |||
} | |||
} break; | |||
case GLFW_KEY_RIGHT: { | |||
if (windowIsModPressed()) { | |||
if (context()->window->isModPressed()) { | |||
while (++cursor < (int) text.size()) { | |||
if (text[cursor] == ' ') | |||
break; | |||
@@ -132,7 +132,7 @@ struct TextField : OpaqueWidget { | |||
else { | |||
cursor++; | |||
} | |||
if (!windowIsShiftPressed()) { | |||
if (!context()->window->isShiftPressed()) { | |||
selection = cursor; | |||
} | |||
} break; | |||
@@ -143,33 +143,33 @@ struct TextField : OpaqueWidget { | |||
selection = cursor = text.size(); | |||
} break; | |||
case GLFW_KEY_V: { | |||
if (windowIsModPressed()) { | |||
const char *newText = glfwGetClipboardString(gWindow); | |||
if (context()->window->isModPressed()) { | |||
const char *newText = glfwGetClipboardString(context()->window->win); | |||
if (newText) | |||
insertText(newText); | |||
} | |||
} break; | |||
case GLFW_KEY_X: { | |||
if (windowIsModPressed()) { | |||
if (context()->window->isModPressed()) { | |||
if (cursor != selection) { | |||
int begin = std::min(cursor, selection); | |||
std::string selectedText = text.substr(begin, std::abs(selection - cursor)); | |||
glfwSetClipboardString(gWindow, selectedText.c_str()); | |||
glfwSetClipboardString(context()->window->win, selectedText.c_str()); | |||
insertText(""); | |||
} | |||
} | |||
} break; | |||
case GLFW_KEY_C: { | |||
if (windowIsModPressed()) { | |||
if (context()->window->isModPressed()) { | |||
if (cursor != selection) { | |||
int begin = std::min(cursor, selection); | |||
std::string selectedText = text.substr(begin, std::abs(selection - cursor)); | |||
glfwSetClipboardString(gWindow, selectedText.c_str()); | |||
glfwSetClipboardString(context()->window->win, selectedText.c_str()); | |||
} | |||
} | |||
} break; | |||
case GLFW_KEY_A: { | |||
if (windowIsModPressed()) { | |||
if (context()->window->isModPressed()) { | |||
selection = 0; | |||
cursor = text.size(); | |||
} | |||
@@ -213,7 +213,7 @@ struct TextField : OpaqueWidget { | |||
} | |||
virtual int getTextPosition(Vec mousePos) { | |||
return bndTextFieldTextPosition(gVg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), mousePos.x, mousePos.y); | |||
return bndTextFieldTextPosition(context()->window->vg, 0.0, 0.0, box.size.x, box.size.y, -1, text.c_str(), mousePos.x, mousePos.y); | |||
} | |||
}; | |||
@@ -1,5 +1,6 @@ | |||
#pragma once | |||
#include "../common.hpp" | |||
#include <nanovg.h> | |||
#include <blendish.h> | |||
#define CHECKMARK_STRING "âś”" | |||
@@ -1,5 +1,6 @@ | |||
#pragma once | |||
#include "widgets/Widget.hpp" | |||
#include "svg.hpp" | |||
namespace rack { | |||
@@ -43,42 +43,41 @@ struct SVG { | |||
static std::shared_ptr<SVG> load(const std::string &filename); | |||
}; | |||
extern GLFWwindow *gWindow; | |||
extern NVGcontext *gVg; | |||
extern NVGcontext *gFramebufferVg; | |||
/** The default font to use for GUI elements */ | |||
extern std::shared_ptr<Font> gGuiFont; | |||
/** The scaling ratio */ | |||
extern float gPixelRatio; | |||
/* The ratio between the framebuffer size and the window size reported by the OS. | |||
This is not equal to gPixelRatio in general. | |||
*/ | |||
extern float gWindowRatio; | |||
extern bool gAllowCursorLock; | |||
extern int gGuiFrame; | |||
extern Vec gMousePos; | |||
void windowInit(); | |||
void windowDestroy(); | |||
void windowRun(); | |||
void windowClose(); | |||
void windowCursorLock(); | |||
void windowCursorUnlock(); | |||
bool windowIsModPressed(); | |||
bool windowIsShiftPressed(); | |||
Vec windowGetWindowSize(); | |||
void windowSetWindowSize(Vec size); | |||
Vec windowGetWindowPos(); | |||
void windowSetWindowPos(Vec pos); | |||
bool windowIsMaximized(); | |||
void windowSetTheme(NVGcolor bg, NVGcolor fg); | |||
void windowSetFullScreen(bool fullScreen); | |||
bool windowGetFullScreen(); | |||
// In svg.cpp | |||
void svgDraw(NVGcontext *vg, NSVGimage *svg); | |||
struct Window { | |||
GLFWwindow *win = NULL; | |||
NVGcontext *vg = NULL; | |||
NVGcontext *framebufferVg = NULL; | |||
/** The scaling ratio */ | |||
float pixelRatio = 1.f; | |||
/* The ratio between the framebuffer size and the window size reported by the OS. | |||
This is not equal to gPixelRatio in general. | |||
*/ | |||
float windowRatio = 1.f; | |||
bool allowCursorLock = true; | |||
int frame = 0; | |||
/** The last known absolute mouse position in the window */ | |||
Vec mousePos; | |||
std::shared_ptr<Font> uiFont; | |||
struct Internal; | |||
Internal *internal; | |||
Window(); | |||
~Window(); | |||
void run(); | |||
void close(); | |||
void cursorLock(); | |||
void cursorUnlock(); | |||
bool isModPressed(); | |||
bool isShiftPressed(); | |||
Vec getWindowSize(); | |||
void setWindowSize(Vec size); | |||
Vec getWindowPos(); | |||
void setWindowPos(Vec pos); | |||
bool isMaximized(); | |||
void setFullScreen(bool fullScreen); | |||
bool isFullScreen(); | |||
}; | |||
} // namespace rack |
@@ -240,7 +240,7 @@ void AudioInterface::step() { | |||
struct AudioInterfaceWidget : ModuleWidget { | |||
AudioInterfaceWidget(AudioInterface *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(context()->asset->system("res/Core/AudioInterface.svg"))); | |||
setPanel(SVG::load(asset::system("res/Core/AudioInterface.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||
@@ -182,7 +182,7 @@ struct MidiCcWidget : Grid16MidiWidget { | |||
struct MIDICCToCVInterfaceWidget : ModuleWidget { | |||
MIDICCToCVInterfaceWidget(MIDICCToCVInterface *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(context()->asset->system("res/Core/MIDICCToCVInterface.svg"))); | |||
setPanel(SVG::load(asset::system("res/Core/MIDICCToCVInterface.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||
@@ -261,7 +261,7 @@ struct MIDIToCVInterface : Module { | |||
struct MIDIToCVInterfaceWidget : ModuleWidget { | |||
MIDIToCVInterfaceWidget(MIDIToCVInterface *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(context()->asset->system("res/Core/MIDIToCVInterface.svg"))); | |||
setPanel(SVG::load(asset::system("res/Core/MIDIToCVInterface.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||
@@ -201,7 +201,7 @@ struct MidiTrigWidget : Grid16MidiWidget { | |||
struct MIDITriggerToCVInterfaceWidget : ModuleWidget { | |||
MIDITriggerToCVInterfaceWidget(MIDITriggerToCVInterface *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(context()->asset->system("res/Core/MIDITriggerToCVInterface.svg"))); | |||
setPanel(SVG::load(asset::system("res/Core/MIDITriggerToCVInterface.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||
@@ -8,7 +8,7 @@ struct NotesWidget : ModuleWidget { | |||
TextField *textField; | |||
NotesWidget(Module *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(context()->asset->system("res/Core/Notes.svg"))); | |||
setPanel(SVG::load(asset::system("res/Core/Notes.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||
@@ -303,7 +303,7 @@ struct QuadMIDIToCVInterface : Module { | |||
struct QuadMIDIToCVInterfaceWidget : ModuleWidget { | |||
QuadMIDIToCVInterfaceWidget(QuadMIDIToCVInterface *module) : ModuleWidget(module) { | |||
setPanel(SVG::load(context()->asset->system("res/Core/QuadMIDIToCVInterface.svg"))); | |||
setPanel(SVG::load(asset::system("res/Core/QuadMIDIToCVInterface.svg"))); | |||
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, 0))); | |||
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, 0))); | |||
@@ -1,8 +1,9 @@ | |||
#include "app/LedDisplay.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "window.hpp" | |||
#include "event.hpp" | |||
#include "context.hpp" | |||
#include "ui.hpp" | |||
namespace rack { | |||
@@ -34,7 +35,7 @@ void LedDisplaySeparator::draw(NVGcontext *vg) { | |||
LedDisplayChoice::LedDisplayChoice() { | |||
box.size = mm2px(Vec(0, 28.0 / 3)); | |||
font = Font::load(context()->asset->system("res/fonts/ShareTechMono-Regular.ttf")); | |||
font = Font::load(asset::system("res/fonts/ShareTechMono-Regular.ttf")); | |||
color = nvgRGB(0xff, 0xd7, 0x14); | |||
textOffset = Vec(10, 18); | |||
} | |||
@@ -64,7 +65,7 @@ void LedDisplayChoice::onButton(event::Button &e) { | |||
LedDisplayTextField::LedDisplayTextField() { | |||
font = Font::load(context()->asset->system("res/fonts/ShareTechMono-Regular.ttf")); | |||
font = Font::load(asset::system("res/fonts/ShareTechMono-Regular.ttf")); | |||
color = nvgRGB(0xff, 0xd7, 0x14); | |||
textOffset = Vec(5, 5); | |||
} | |||
@@ -91,7 +92,7 @@ void LedDisplayTextField::draw(NVGcontext *vg) { | |||
box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, | |||
-1, color, 12, text.c_str(), highlightColor, begin, end); | |||
bndSetFont(gGuiFont->handle); | |||
bndSetFont(context()->window->uiFont->handle); | |||
} | |||
nvgResetScissor(vg); | |||
@@ -99,10 +100,10 @@ void LedDisplayTextField::draw(NVGcontext *vg) { | |||
int LedDisplayTextField::getTextPosition(Vec mousePos) { | |||
bndSetFont(font->handle); | |||
int textPos = bndIconLabelTextPosition(gVg, textOffset.x, textOffset.y, | |||
int textPos = bndIconLabelTextPosition(context()->window->vg, textOffset.x, textOffset.y, | |||
box.size.x - 2*textOffset.x, box.size.y - 2*textOffset.y, | |||
-1, 12, text.c_str(), mousePos.x, mousePos.y); | |||
bndSetFont(gGuiFont->handle); | |||
bndSetFont(context()->window->uiFont->handle); | |||
return textPos; | |||
} | |||
@@ -2,10 +2,11 @@ | |||
#include "engine/Engine.hpp" | |||
#include "logger.hpp" | |||
#include "system.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "app/Scene.hpp" | |||
#include "helpers.hpp" | |||
#include "context.hpp" | |||
#include "ui.hpp" | |||
#include "osdialog.h" | |||
@@ -124,13 +125,13 @@ void ModuleWidget::fromJson(json_t *rootJ) { | |||
void ModuleWidget::copyClipboard() { | |||
json_t *moduleJ = toJson(); | |||
char *moduleJson = json_dumps(moduleJ, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); | |||
glfwSetClipboardString(gWindow, moduleJson); | |||
glfwSetClipboardString(context()->window->win, moduleJson); | |||
free(moduleJson); | |||
json_decref(moduleJ); | |||
} | |||
void ModuleWidget::pasteClipboard() { | |||
const char *moduleJson = glfwGetClipboardString(gWindow); | |||
const char *moduleJson = glfwGetClipboardString(context()->window->win); | |||
if (!moduleJson) { | |||
WARN("Could not get text from clipboard."); | |||
return; | |||
@@ -185,7 +186,7 @@ void ModuleWidget::save(std::string filename) { | |||
} | |||
void ModuleWidget::loadDialog() { | |||
std::string dir = context()->asset->user("presets"); | |||
std::string dir = asset::user("presets"); | |||
system::createDirectory(dir); | |||
osdialog_filters *filters = osdialog_filters_parse(PRESET_FILTERS.c_str()); | |||
@@ -198,7 +199,7 @@ void ModuleWidget::loadDialog() { | |||
} | |||
void ModuleWidget::saveDialog() { | |||
std::string dir = context()->asset->user("presets"); | |||
std::string dir = asset::user("presets"); | |||
system::createDirectory(dir); | |||
osdialog_filters *filters = osdialog_filters_parse(PRESET_FILTERS.c_str()); | |||
@@ -264,7 +265,8 @@ void ModuleWidget::draw(NVGcontext *vg) { | |||
nvgFill(vg); | |||
std::string cpuText = string::f("%.0f mS", module->cpuTime * 1000.f); | |||
nvgFontFaceId(vg, gGuiFont->handle); | |||
// TODO Use blendish text function | |||
nvgFontFaceId(vg, context()->window->uiFont->handle); | |||
nvgFontSize(vg, 12); | |||
nvgFillColor(vg, nvgRGBf(1, 1, 1)); | |||
nvgText(vg, 10.0, box.size.y - 6.0, cpuText.c_str(), NULL); | |||
@@ -297,8 +299,8 @@ void ModuleWidget::onHover(event::Hover &e) { | |||
OpaqueWidget::onHover(e); | |||
// Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget. | |||
if (glfwGetKey(gWindow, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_BACKSPACE) == GLFW_PRESS) { | |||
if (!windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (glfwGetKey(context()->window->win, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(context()->window->win, GLFW_KEY_BACKSPACE) == GLFW_PRESS) { | |||
if (!context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
context()->scene->rackWidget->deleteModule(this); | |||
delete this; | |||
// e.target = this; | |||
@@ -319,42 +321,42 @@ void ModuleWidget::onButton(event::Button &e) { | |||
void ModuleWidget::onHoverKey(event::HoverKey &e) { | |||
switch (e.key) { | |||
case GLFW_KEY_I: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
reset(); | |||
e.target = this; | |||
return; | |||
} | |||
} break; | |||
case GLFW_KEY_R: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
randomize(); | |||
e.target = this; | |||
return; | |||
} | |||
} break; | |||
case GLFW_KEY_C: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
copyClipboard(); | |||
e.target = this; | |||
return; | |||
} | |||
} break; | |||
case GLFW_KEY_V: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
pasteClipboard(); | |||
e.target = this; | |||
return; | |||
} | |||
} break; | |||
case GLFW_KEY_D: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
context()->scene->rackWidget->cloneModule(this); | |||
e.target = this; | |||
return; | |||
} | |||
} break; | |||
case GLFW_KEY_U: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
disconnect(); | |||
e.target = this; | |||
return; | |||
@@ -77,7 +77,7 @@ struct SyncButton : Button { | |||
// Display message if we've completed updates | |||
if (completed) { | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "All plugins have been updated. Close Rack and re-launch it to load new updates.")) { | |||
windowClose(); | |||
context()->window->close(); | |||
} | |||
completed = false; | |||
} | |||
@@ -65,7 +65,7 @@ void Port::onButton(event::Button &e) { | |||
void Port::onDragStart(event::DragStart &e) { | |||
// Try to grab wire on top of stack | |||
WireWidget *wire = context()->scene->rackWidget->wireContainer->getTopWire(this); | |||
if (type == OUTPUT && windowIsModPressed()) { | |||
if (type == OUTPUT && context()->window->isModPressed()) { | |||
wire = NULL; | |||
} | |||
@@ -8,7 +8,7 @@ namespace rack { | |||
void RackScrollWidget::step() { | |||
Vec pos = gMousePos; | |||
Vec pos = context()->window->mousePos; | |||
Rect viewport = getViewport(box.zeroPos()); | |||
// Scroll rack if dragging cable near the edge of the screen | |||
if (context()->scene->rackWidget->wireContainer->activeWire) { | |||
@@ -6,7 +6,7 @@ | |||
#include "app/ModuleBrowser.hpp" | |||
#include "osdialog.h" | |||
#include "settings.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "system.hpp" | |||
#include "logger.hpp" | |||
#include "plugin/PluginManager.hpp" | |||
@@ -67,7 +67,7 @@ void RackWidget::reset() { | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "Clear patch and start over?")) { | |||
clear(); | |||
// Fails silently if file does not exist | |||
load(context()->asset->user("template.vcv")); | |||
load(asset::user("template.vcv")); | |||
lastPath = ""; | |||
} | |||
} | |||
@@ -75,7 +75,7 @@ void RackWidget::reset() { | |||
void RackWidget::loadDialog() { | |||
std::string dir; | |||
if (lastPath.empty()) { | |||
dir = context()->asset->user("patches"); | |||
dir = asset::user("patches"); | |||
system::createDirectory(dir); | |||
} | |||
else { | |||
@@ -104,7 +104,7 @@ void RackWidget::saveAsDialog() { | |||
std::string dir; | |||
std::string filename; | |||
if (lastPath.empty()) { | |||
dir = context()->asset->user("patches"); | |||
dir = asset::user("patches"); | |||
system::createDirectory(dir); | |||
} | |||
else { | |||
@@ -392,7 +392,7 @@ ModuleWidget *RackWidget::moduleFromJson(json_t *moduleJ) { | |||
} | |||
void RackWidget::pastePresetClipboard() { | |||
const char *moduleJson = glfwGetClipboardString(gWindow); | |||
const char *moduleJson = glfwGetClipboardString(context()->window->win); | |||
if (!moduleJson) { | |||
WARN("Could not get text from clipboard."); | |||
return; | |||
@@ -493,9 +493,9 @@ void RackWidget::step() { | |||
} | |||
// Autosave every 15 seconds | |||
if (gGuiFrame % (60 * 15) == 0) { | |||
save(context()->asset->user("autosave.vcv")); | |||
settings::save(context()->asset->user("settings.json")); | |||
if (context()->window->frame % (60 * 15) == 0) { | |||
save(asset::user("autosave.vcv")); | |||
settings::save(asset::user("settings.json")); | |||
} | |||
Widget::step(); | |||
@@ -44,7 +44,7 @@ void Scene::step() { | |||
zoomWidget->box.size = rackWidget->box.size.mult(zoomWidget->zoom); | |||
// Request latest version from server | |||
if (!context()->devMode && checkVersion && !checkedVersion) { | |||
if (!devMode && checkVersion && !checkedVersion) { | |||
std::thread t(&Scene::runCheckVersion, this); | |||
t.detach(); | |||
checkedVersion = true; | |||
@@ -56,7 +56,7 @@ void Scene::step() { | |||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, versionMessage.c_str())) { | |||
std::thread t(system::openBrowser, "https://vcvrack.com/"); | |||
t.detach(); | |||
windowClose(); | |||
context()->window->close(); | |||
} | |||
latestVersion = ""; | |||
} | |||
@@ -72,39 +72,39 @@ void Scene::onHoverKey(event::HoverKey &e) { | |||
if (!e.target) { | |||
switch (e.key) { | |||
case GLFW_KEY_N: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
rackWidget->reset(); | |||
e.target = this; | |||
} | |||
} break; | |||
case GLFW_KEY_Q: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
windowClose(); | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
context()->window->close(); | |||
e.target = this; | |||
} | |||
} break; | |||
case GLFW_KEY_O: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
rackWidget->loadDialog(); | |||
e.target = this; | |||
} | |||
if (windowIsModPressed() && windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && context()->window->isShiftPressed()) { | |||
rackWidget->revert(); | |||
e.target = this; | |||
} | |||
} break; | |||
case GLFW_KEY_S: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
rackWidget->saveDialog(); | |||
e.target = this; | |||
} | |||
if (windowIsModPressed() && windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && context()->window->isShiftPressed()) { | |||
rackWidget->saveAsDialog(); | |||
e.target = this; | |||
} | |||
} break; | |||
case GLFW_KEY_V: { | |||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
if (context()->window->isModPressed() && !context()->window->isShiftPressed()) { | |||
rackWidget->pastePresetClipboard(); | |||
e.target = this; | |||
} | |||
@@ -115,7 +115,7 @@ void Scene::onHoverKey(event::HoverKey &e) { | |||
e.target = this; | |||
} break; | |||
case GLFW_KEY_F11: { | |||
windowSetFullScreen(!windowGetFullScreen()); | |||
context()->window->setFullScreen(!context()->window->isFullScreen()); | |||
} | |||
} | |||
} | |||
@@ -1,7 +1,7 @@ | |||
#include "app/Toolbar.hpp" | |||
#include "window.hpp" | |||
#include "engine/Engine.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "ui/Tooltip.hpp" | |||
#include "ui/IconButton.hpp" | |||
#include "ui/SequentialLayout.hpp" | |||
@@ -39,7 +39,7 @@ struct TooltipIconButton : IconButton { | |||
struct NewButton : TooltipIconButton { | |||
NewButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_146097_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_146097_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "New patch (" WINDOW_MOD_KEY_NAME "+N)";} | |||
void onAction(event::Action &e) override { | |||
@@ -49,7 +49,7 @@ struct NewButton : TooltipIconButton { | |||
struct OpenButton : TooltipIconButton { | |||
OpenButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_31859_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_31859_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Open patch (" WINDOW_MOD_KEY_NAME "+O)";} | |||
void onAction(event::Action &e) override { | |||
@@ -59,7 +59,7 @@ struct OpenButton : TooltipIconButton { | |||
struct SaveButton : TooltipIconButton { | |||
SaveButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_1343816_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_1343816_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Save patch (" WINDOW_MOD_KEY_NAME "+S)";} | |||
void onAction(event::Action &e) override { | |||
@@ -69,7 +69,7 @@ struct SaveButton : TooltipIconButton { | |||
struct SaveAsButton : TooltipIconButton { | |||
SaveAsButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_1343811_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_1343811_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Save patch as (" WINDOW_MOD_KEY_NAME "+Shift+S)";} | |||
void onAction(event::Action &e) override { | |||
@@ -79,7 +79,7 @@ struct SaveAsButton : TooltipIconButton { | |||
struct RevertButton : TooltipIconButton { | |||
RevertButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_1084369_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_1084369_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Revert patch";} | |||
void onAction(event::Action &e) override { | |||
@@ -89,7 +89,7 @@ struct RevertButton : TooltipIconButton { | |||
struct DisconnectCablesButton : TooltipIconButton { | |||
DisconnectCablesButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_1745061_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_1745061_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Disconnect cables";} | |||
void onAction(event::Action &e) override { | |||
@@ -99,7 +99,7 @@ struct DisconnectCablesButton : TooltipIconButton { | |||
struct PowerMeterButton : TooltipIconButton { | |||
PowerMeterButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_305536_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_305536_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Toggle power meter (see manual for explanation)";} | |||
void onAction(event::Action &e) override { | |||
@@ -123,7 +123,7 @@ struct SampleRateItem : MenuItem { | |||
struct SampleRateButton : TooltipIconButton { | |||
SampleRateButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_1240789_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_1240789_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Engine sample rate";} | |||
void onAction(event::Action &e) override { | |||
@@ -150,7 +150,7 @@ struct SampleRateButton : TooltipIconButton { | |||
struct RackLockButton : TooltipIconButton { | |||
RackLockButton() { | |||
setSVG(SVG::load(context()->asset->system("res/icons/noun_468341_cc.svg"))); | |||
setSVG(SVG::load(asset::system("res/icons/noun_468341_cc.svg"))); | |||
} | |||
std::string getTooltipText() override {return "Lock modules";} | |||
void onAction(event::Action &e) override { | |||
@@ -238,7 +238,7 @@ Toolbar::Toolbar() { | |||
layout->addChild(zoomSlider); | |||
// Kind of hacky, but display the PluginManagerWidget only if the user directory is not the development directory | |||
if (context()->asset->user("") != "./") { | |||
if (asset::user("") != "./") { | |||
Widget *pluginManager = new PluginManagerWidget; | |||
layout->addChild(pluginManager); | |||
} | |||
@@ -1,6 +1,5 @@ | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "system.hpp" | |||
#include "context.hpp" | |||
#include "plugin/Plugin.hpp" | |||
#if ARCH_MAC | |||
@@ -22,13 +21,14 @@ | |||
namespace rack { | |||
namespace asset { | |||
AssetManager::AssetManager() { | |||
void init(bool devMode) { | |||
// Get system dir | |||
if (systemDir.empty()) { | |||
if (context()->devMode) { | |||
systemDir = "."; | |||
if (gSystemDir.empty()) { | |||
if (devMode) { | |||
gSystemDir = "."; | |||
} | |||
else { | |||
#if ARCH_MAC | |||
@@ -39,26 +39,26 @@ AssetManager::AssetManager() { | |||
Boolean success = CFURLGetFileSystemRepresentation(resourcesUrl, TRUE, (UInt8*) resourcesBuf, sizeof(resourcesBuf)); | |||
assert(success); | |||
CFRelease(resourcesUrl); | |||
systemDir = resourcesBuf; | |||
gSystemDir = resourcesBuf; | |||
#endif | |||
#if ARCH_WIN | |||
char moduleBuf[MAX_PATH]; | |||
DWORD length = GetModuleFileName(NULL, moduleBuf, sizeof(moduleBuf)); | |||
assert(length > 0); | |||
PathRemoveFileSpec(moduleBuf); | |||
systemDir = moduleBuf; | |||
gSystemDir = moduleBuf; | |||
#endif | |||
#if ARCH_LIN | |||
// TODO For now, users should launch Rack from their terminal in the system directory | |||
systemDir = "."; | |||
gSystemDir = "."; | |||
#endif | |||
} | |||
} | |||
// Get user dir | |||
if (userDir.empty()) { | |||
if (context()->devMode) { | |||
userDir = "."; | |||
if (gUserDir.empty()) { | |||
if (devMode) { | |||
gUserDir = "."; | |||
} | |||
else { | |||
#if ARCH_WIN | |||
@@ -66,15 +66,15 @@ AssetManager::AssetManager() { | |||
char documentsBuf[MAX_PATH]; | |||
HRESULT result = SHGetFolderPath(NULL, CSIDL_MYDOCUMENTS, NULL, SHGFP_TYPE_CURRENT, documentsBuf); | |||
assert(result == S_OK); | |||
userDir = documentsBuf; | |||
userDir += "/Rack"; | |||
gUserDir = documentsBuf; | |||
gUserDir += "/Rack"; | |||
#endif | |||
#if ARCH_MAC | |||
// Get home directory | |||
struct passwd *pw = getpwuid(getuid()); | |||
assert(pw); | |||
userDir = pw->pw_dir; | |||
userDir += "/Documents/Rack"; | |||
gUserDir = pw->pw_dir; | |||
gUserDir += "/Documents/Rack"; | |||
#endif | |||
#if ARCH_LIN | |||
// Get home directory | |||
@@ -84,31 +84,36 @@ AssetManager::AssetManager() { | |||
assert(pw); | |||
homeBuf = pw->pw_dir; | |||
} | |||
userDir = homeBuf; | |||
userDir += "/.Rack"; | |||
gUserDir = homeBuf; | |||
gUserDir += "/.Rack"; | |||
#endif | |||
} | |||
} | |||
system::createDirectory(systemDir); | |||
system::createDirectory(userDir); | |||
system::createDirectory(gSystemDir); | |||
system::createDirectory(gUserDir); | |||
} | |||
std::string AssetManager::system(std::string filename) { | |||
return systemDir + "/" + filename; | |||
std::string system(std::string filename) { | |||
return gSystemDir + "/" + filename; | |||
} | |||
std::string AssetManager::user(std::string filename) { | |||
return userDir + "/" + filename; | |||
std::string user(std::string filename) { | |||
return gUserDir + "/" + filename; | |||
} | |||
std::string AssetManager::plugin(Plugin *plugin, std::string filename) { | |||
std::string plugin(Plugin *plugin, std::string filename) { | |||
assert(plugin); | |||
return plugin->path + "/" + filename; | |||
} | |||
std::string gSystemDir; | |||
std::string gUserDir; | |||
} // namespace asset | |||
} // namespace rack |
@@ -219,9 +219,5 @@ void Context::handleZoom() { | |||
} | |||
// TODO Move this elsewhere | |||
Context *gContext = NULL; | |||
} // namespace event | |||
} // namespace rack |
@@ -1,6 +1,5 @@ | |||
#include "logger.hpp" | |||
#include "AssetManager.hpp" | |||
#include "context.hpp" | |||
#include "asset.hpp" | |||
#include <chrono> | |||
@@ -12,13 +11,13 @@ static FILE *outputFile = NULL; | |||
static std::chrono::high_resolution_clock::time_point startTime; | |||
void init() { | |||
void init(bool devMode) { | |||
startTime = std::chrono::high_resolution_clock::now(); | |||
if (context()->devMode) { | |||
if (devMode) { | |||
outputFile = stderr; | |||
} | |||
else { | |||
std::string logFilename = context()->asset->user("log.txt"); | |||
std::string logFilename = asset::user("log.txt"); | |||
outputFile = fopen(logFilename.c_str(), "w"); | |||
} | |||
} | |||
@@ -1,7 +1,7 @@ | |||
#include "common.hpp" | |||
#include "random.hpp" | |||
#include "logger.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "rtmidi.hpp" | |||
#include "keyboard.hpp" | |||
#include "gamepad.hpp" | |||
@@ -12,6 +12,7 @@ | |||
#include "tags.hpp" | |||
#include "plugin/PluginManager.hpp" | |||
#include "context.hpp" | |||
#include "ui.hpp" | |||
#include <unistd.h> | |||
#include <osdialog.h> | |||
@@ -35,6 +36,7 @@ int main(int argc, char *argv[]) { | |||
(void) instanceMutex; | |||
#endif | |||
bool devMode = false; | |||
std::string patchFile; | |||
// Parse command line arguments | |||
@@ -43,13 +45,13 @@ int main(int argc, char *argv[]) { | |||
while ((c = getopt(argc, argv, "ds:u:")) != -1) { | |||
switch (c) { | |||
case 'd': { | |||
context()->devMode = true; | |||
devMode = true; | |||
} break; | |||
case 's': { | |||
context()->asset->systemDir = optarg; | |||
asset::gSystemDir = optarg; | |||
} break; | |||
case 'u': { | |||
context()->asset->userDir = optarg; | |||
asset::gUserDir = optarg; | |||
} break; | |||
default: break; | |||
} | |||
@@ -60,35 +62,37 @@ int main(int argc, char *argv[]) { | |||
// Initialize environment | |||
random::init(); | |||
context()->asset = new AssetManager; | |||
logger::init(); | |||
asset::init(devMode); | |||
logger::init(devMode); | |||
tagsInit(); | |||
rtmidiInit(); | |||
bridgeInit(); | |||
keyboard::init(); | |||
gamepad::init(); | |||
uiInit(); | |||
// Log environment | |||
INFO("%s %s", APP_NAME.c_str(), APP_VERSION.c_str()); | |||
if (context()->devMode) | |||
if (devMode) | |||
INFO("Development mode"); | |||
INFO("System directory: %s", context()->asset->system("").c_str()); | |||
INFO("User directory: %s", context()->asset->user("").c_str()); | |||
INFO("System directory: %s", asset::gSystemDir.c_str()); | |||
INFO("User directory: %s", asset::gUserDir.c_str()); | |||
// Initialize app | |||
tagsInit(); | |||
context()->plugin = new PluginManager; | |||
context()->plugin = new PluginManager(devMode); | |||
context()->engine = new Engine; | |||
rtmidiInit(); | |||
bridgeInit(); | |||
keyboard::init(); | |||
gamepad::init(); | |||
context()->event = new event::Context; | |||
context()->scene = new Scene; | |||
context()->scene->devMode = devMode; | |||
context()->event->rootWidget = context()->scene; | |||
windowInit(); | |||
settings::load(context()->asset->user("settings.json")); | |||
context()->window = new Window; | |||
settings::load(asset::user("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 = settings::gSkipAutosaveOnLaunch; | |||
settings::gSkipAutosaveOnLaunch = true; | |||
settings::save(context()->asset->user("settings.json")); | |||
settings::save(asset::user("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?")) { | |||
context()->scene->rackWidget->lastPath = ""; | |||
@@ -96,7 +100,7 @@ int main(int argc, char *argv[]) { | |||
else { | |||
// Load autosave | |||
std::string oldLastPath = context()->scene->rackWidget->lastPath; | |||
context()->scene->rackWidget->load(context()->asset->user("autosave.vcv")); | |||
context()->scene->rackWidget->load(asset::user("autosave.vcv")); | |||
context()->scene->rackWidget->lastPath = oldLastPath; | |||
} | |||
} | |||
@@ -107,25 +111,27 @@ int main(int argc, char *argv[]) { | |||
} | |||
context()->engine->start(); | |||
windowRun(); | |||
context()->window->run(); | |||
context()->engine->stop(); | |||
// Destroy namespaces | |||
context()->scene->rackWidget->save(context()->asset->user("autosave.vcv")); | |||
settings::save(context()->asset->user("settings.json")); | |||
// Destroy app | |||
context()->scene->rackWidget->save(asset::user("autosave.vcv")); | |||
settings::save(asset::user("settings.json")); | |||
delete context()->scene; | |||
context()->scene = NULL; | |||
delete context()->event; | |||
context()->event = NULL; | |||
windowDestroy(); | |||
bridgeDestroy(); | |||
delete context()->window; | |||
context()->window = NULL; | |||
delete context()->engine; | |||
context()->engine = NULL; | |||
midiDestroy(); | |||
delete context()->plugin; | |||
context()->plugin = NULL; | |||
delete context()->asset; | |||
context()->asset = NULL; | |||
// Destroy environment | |||
uiDestroy(); | |||
bridgeDestroy(); | |||
midiDestroy(); | |||
logger::destroy(); | |||
return 0; | |||
@@ -2,7 +2,7 @@ | |||
#include "system.hpp" | |||
#include "logger.hpp" | |||
#include "network.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "string.hpp" | |||
#include "context.hpp" | |||
#include "app/common.hpp" | |||
@@ -178,7 +178,7 @@ static bool PluginManager_syncPlugin(PluginManager *pluginManager, std::string s | |||
INFO("Downloading plugin %s %s %s", slug.c_str(), latestVersion.c_str(), arch.c_str()); | |||
// Download zip | |||
std::string pluginDest = context()->asset->user("plugins/" + slug + ".zip"); | |||
std::string pluginDest = asset::user("plugins/" + slug + ".zip"); | |||
if (!network::requestDownload(downloadUrl, pluginDest, &pluginManager->downloadProgress)) { | |||
WARN("Plugin %s download was unsuccessful", slug.c_str()); | |||
return false; | |||
@@ -300,7 +300,7 @@ static void extractPackages(std::string path) { | |||
// public API | |||
//////////////////// | |||
PluginManager::PluginManager() { | |||
PluginManager::PluginManager(bool devMode) { | |||
// Load core | |||
// This function is defined in core.cpp | |||
Plugin *corePlugin = new Plugin; | |||
@@ -308,14 +308,14 @@ PluginManager::PluginManager() { | |||
plugins.push_back(corePlugin); | |||
// Get user plugins directory | |||
std::string userPlugins = context()->asset->user("plugins"); | |||
std::string userPlugins = asset::user("plugins"); | |||
mkdir(userPlugins.c_str(), 0755); | |||
if (!context()->devMode) { | |||
if (devMode) { | |||
// Copy Fundamental package to plugins directory if folder does not exist | |||
std::string fundamentalSrc = context()->asset->system("Fundamental.zip"); | |||
std::string fundamentalDest = context()->asset->user("plugins/Fundamental.zip"); | |||
std::string fundamentalDir = context()->asset->user("plugins/Fundamental"); | |||
std::string fundamentalSrc = asset::system("Fundamental.zip"); | |||
std::string fundamentalDest = asset::user("plugins/Fundamental.zip"); | |||
std::string fundamentalDir = asset::user("plugins/Fundamental"); | |||
if (system::isFile(fundamentalSrc) && !system::isFile(fundamentalDest) && !system::isDirectory(fundamentalDir)) { | |||
system::copyFile(fundamentalSrc, fundamentalDest); | |||
} | |||
@@ -24,14 +24,14 @@ static json_t *settingsToJson() { | |||
json_t *tokenJ = json_string(context()->plugin->token.c_str()); | |||
json_object_set_new(rootJ, "token", tokenJ); | |||
if (!windowIsMaximized()) { | |||
if (!context()->window->isMaximized()) { | |||
// windowSize | |||
Vec windowSize = windowGetWindowSize(); | |||
Vec windowSize = context()->window->getWindowSize(); | |||
json_t *windowSizeJ = json_pack("[f, f]", windowSize.x, windowSize.y); | |||
json_object_set_new(rootJ, "windowSize", windowSizeJ); | |||
// windowPos | |||
Vec windowPos = windowGetWindowPos(); | |||
Vec windowPos = context()->window->getWindowPos(); | |||
json_t *windowPosJ = json_pack("[f, f]", windowPos.x, windowPos.y); | |||
json_object_set_new(rootJ, "windowPos", windowPosJ); | |||
} | |||
@@ -52,7 +52,7 @@ static json_t *settingsToJson() { | |||
json_object_set_new(rootJ, "zoom", zoomJ); | |||
// allowCursorLock | |||
json_t *allowCursorLockJ = json_boolean(gAllowCursorLock); | |||
json_t *allowCursorLockJ = json_boolean(context()->window->allowCursorLock); | |||
json_object_set_new(rootJ, "allowCursorLock", allowCursorLockJ); | |||
// sampleRate | |||
@@ -91,7 +91,7 @@ static void settingsFromJson(json_t *rootJ) { | |||
if (windowSizeJ) { | |||
double width, height; | |||
json_unpack(windowSizeJ, "[F, F]", &width, &height); | |||
windowSetWindowSize(Vec(width, height)); | |||
context()->window->setWindowSize(Vec(width, height)); | |||
} | |||
// windowPos | |||
@@ -99,7 +99,7 @@ static void settingsFromJson(json_t *rootJ) { | |||
if (windowPosJ) { | |||
double x, y; | |||
json_unpack(windowPosJ, "[F, F]", &x, &y); | |||
windowSetWindowPos(Vec(x, y)); | |||
context()->window->setWindowPos(Vec(x, y)); | |||
} | |||
// opacity | |||
@@ -121,7 +121,7 @@ static void settingsFromJson(json_t *rootJ) { | |||
// allowCursorLock | |||
json_t *allowCursorLockJ = json_object_get(rootJ, "allowCursorLock"); | |||
if (allowCursorLockJ) | |||
gAllowCursorLock = json_is_true(allowCursorLockJ); | |||
context()->window->allowCursorLock = json_is_true(allowCursorLockJ); | |||
// sampleRate | |||
json_t *sampleRateJ = json_object_get(rootJ, "sampleRate"); | |||
@@ -1,4 +1,5 @@ | |||
#include "window.hpp" | |||
#include "svg.hpp" | |||
#include "math.hpp" | |||
// #define DEBUG_ONLY(x) x | |||
@@ -186,9 +187,6 @@ void svgDraw(NVGcontext *vg, NSVGimage *svg) { | |||
} | |||
nvgRestore(vg); | |||
// if (std::string(shape->id) == "rect19347") | |||
// exit(0); | |||
} | |||
DEBUG_ONLY(printf("\n");) | |||
@@ -0,0 +1,64 @@ | |||
#include "ui.hpp" | |||
namespace rack { | |||
void uiInit(){ | |||
uiSetTheme(nvgRGB(0x33, 0x33, 0x33), nvgRGB(0xf0, 0xf0, 0xf0)); | |||
} | |||
void uiDestroy() { | |||
} | |||
void uiSetTheme(NVGcolor bg, NVGcolor fg) { | |||
// Assume dark background and light foreground | |||
BNDwidgetTheme w; | |||
w.outlineColor = bg; | |||
w.itemColor = fg; | |||
w.innerColor = bg; | |||
w.innerSelectedColor = color::plus(bg, nvgRGB(0x30, 0x30, 0x30)); | |||
w.textColor = fg; | |||
w.textSelectedColor = fg; | |||
w.shadeTop = 0; | |||
w.shadeDown = 0; | |||
BNDtheme t; | |||
t.backgroundColor = color::plus(bg, nvgRGB(0x30, 0x30, 0x30)); | |||
t.regularTheme = w; | |||
t.toolTheme = w; | |||
t.radioTheme = w; | |||
t.textFieldTheme = w; | |||
t.optionTheme = w; | |||
t.choiceTheme = w; | |||
t.numberFieldTheme = w; | |||
t.sliderTheme = w; | |||
t.scrollBarTheme = w; | |||
t.tooltipTheme = w; | |||
t.menuTheme = w; | |||
t.menuItemTheme = w; | |||
t.sliderTheme.itemColor = bg; | |||
t.sliderTheme.innerColor = color::plus(bg, nvgRGB(0x50, 0x50, 0x50)); | |||
t.sliderTheme.innerSelectedColor = color::plus(bg, nvgRGB(0x60, 0x60, 0x60)); | |||
t.textFieldTheme = t.sliderTheme; | |||
t.textFieldTheme.textColor = color::minus(bg, nvgRGB(0x20, 0x20, 0x20)); | |||
t.textFieldTheme.textSelectedColor = t.textFieldTheme.textColor; | |||
t.scrollBarTheme.itemColor = color::plus(bg, nvgRGB(0x50, 0x50, 0x50)); | |||
t.scrollBarTheme.innerColor = bg; | |||
t.menuTheme.innerColor = color::minus(bg, nvgRGB(0x10, 0x10, 0x10)); | |||
t.menuTheme.textColor = color::minus(fg, nvgRGB(0x50, 0x50, 0x50)); | |||
t.menuTheme.textSelectedColor = t.menuTheme.textColor; | |||
bndSetTheme(t); | |||
} | |||
std::shared_ptr<Font> gGuiFont; | |||
} // namespace rack |
@@ -1,4 +1,5 @@ | |||
#include "widgets/FramebufferWidget.hpp" | |||
#include "context.hpp" | |||
#include <nanovg_gl.h> | |||
#include <nanovg_gl_utils.h> | |||
@@ -54,7 +55,7 @@ void FramebufferWidget::draw(NVGcontext *vg) { | |||
internal->box.pos = internal->box.pos.mult(s).floor(); | |||
internal->box.size = internal->box.size.mult(s).ceil().plus(Vec(1, 1)); | |||
Vec fbSize = internal->box.size.mult(gPixelRatio * oversample); | |||
Vec fbSize = internal->box.size.mult(context()->window->pixelRatio * oversample); | |||
if (!fbSize.isFinite()) | |||
return; | |||
@@ -65,7 +66,7 @@ void FramebufferWidget::draw(NVGcontext *vg) { | |||
// Delete old one first to free up GPU memory | |||
internal->setFramebuffer(NULL); | |||
// Create a framebuffer from the main nanovg context. We will draw to this in the secondary nanovg context. | |||
NVGLUframebuffer *fb = nvgluCreateFramebuffer(gVg, fbSize.x, fbSize.y, 0); | |||
NVGLUframebuffer *fb = nvgluCreateFramebuffer(context()->window->vg, fbSize.x, fbSize.y, 0); | |||
if (!fb) | |||
return; | |||
internal->setFramebuffer(fb); | |||
@@ -75,16 +76,17 @@ void FramebufferWidget::draw(NVGcontext *vg) { | |||
glClearColor(0.0, 0.0, 0.0, 0.0); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||
nvgBeginFrame(gFramebufferVg, fbSize.x, fbSize.y, gPixelRatio * oversample); | |||
NVGcontext *framebufferVg = context()->window->framebufferVg; | |||
nvgBeginFrame(framebufferVg, fbSize.x, fbSize.y, context()->window->pixelRatio * oversample); | |||
nvgScale(gFramebufferVg, gPixelRatio * oversample, gPixelRatio * oversample); | |||
nvgScale(framebufferVg, context()->window->pixelRatio * oversample, context()->window->pixelRatio * oversample); | |||
// Use local scaling | |||
nvgTranslate(gFramebufferVg, bf.x, bf.y); | |||
nvgTranslate(gFramebufferVg, -internal->box.pos.x, -internal->box.pos.y); | |||
nvgScale(gFramebufferVg, s.x, s.y); | |||
Widget::draw(gFramebufferVg); | |||
nvgTranslate(framebufferVg, bf.x, bf.y); | |||
nvgTranslate(framebufferVg, -internal->box.pos.x, -internal->box.pos.y); | |||
nvgScale(framebufferVg, s.x, s.y); | |||
Widget::draw(framebufferVg); | |||
nvgEndFrame(gFramebufferVg); | |||
nvgEndFrame(framebufferVg); | |||
nvgluBindFramebuffer(NULL); | |||
} | |||
@@ -1,6 +1,6 @@ | |||
#include "window.hpp" | |||
#include "logger.hpp" | |||
#include "AssetManager.hpp" | |||
#include "asset.hpp" | |||
#include "app/Scene.hpp" | |||
#include "keyboard.hpp" | |||
#include "gamepad.hpp" | |||
@@ -36,24 +36,32 @@ | |||
namespace rack { | |||
GLFWwindow *gWindow = NULL; | |||
NVGcontext *gVg = NULL; | |||
NVGcontext *gFramebufferVg = NULL; | |||
std::shared_ptr<Font> gGuiFont; | |||
float gPixelRatio = 1.0; | |||
float gWindowRatio = 1.0; | |||
bool gAllowCursorLock = true; | |||
int gGuiFrame; | |||
Vec gMousePos; | |||
struct MouseButtonArguments { | |||
GLFWwindow *win; | |||
int button; | |||
int action; | |||
int mods; | |||
}; | |||
std::string lastWindowTitle; | |||
struct Window::Internal { | |||
std::string lastWindowTitle; | |||
int lastWindowX = 0; | |||
int lastWindowY = 0; | |||
int lastWindowWidth = 0; | |||
int lastWindowHeight = 0; | |||
static void windowSizeCallback(GLFWwindow* window, int width, int height) { | |||
std::queue<MouseButtonArguments> mouseButtonQueue; | |||
}; | |||
static void windowSizeCallback(GLFWwindow *win, int width, int height) { | |||
// Do nothing. Window size is reset each frame anyway. | |||
} | |||
static void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) { | |||
static void mouseButtonCallback(GLFWwindow *win, int button, int action, int mods) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
#ifdef ARCH_MAC | |||
// Remap Ctrl-left click to right click on Mac | |||
if (button == GLFW_MOUSE_BUTTON_LEFT) { | |||
@@ -63,36 +71,30 @@ static void mouseButtonCallback(GLFWwindow *window, int button, int action, int | |||
} | |||
#endif | |||
context()->event->handleButton(gMousePos, button, action, mods); | |||
context()->event->handleButton(window->mousePos, button, action, mods); | |||
} | |||
struct MouseButtonArguments { | |||
GLFWwindow *window; | |||
int button; | |||
int action; | |||
int mods; | |||
}; | |||
static std::queue<MouseButtonArguments> mouseButtonQueue; | |||
void mouseButtonStickyPop() { | |||
if (!mouseButtonQueue.empty()) { | |||
MouseButtonArguments args = mouseButtonQueue.front(); | |||
mouseButtonQueue.pop(); | |||
mouseButtonCallback(args.window, args.button, args.action, args.mods); | |||
static void Window_mouseButtonStickyPop(Window *window) { | |||
if (!window->internal->mouseButtonQueue.empty()) { | |||
MouseButtonArguments args = window->internal->mouseButtonQueue.front(); | |||
window->internal->mouseButtonQueue.pop(); | |||
mouseButtonCallback(args.win, args.button, args.action, args.mods); | |||
} | |||
} | |||
void mouseButtonStickyCallback(GLFWwindow *window, int button, int action, int mods) { | |||
static void mouseButtonStickyCallback(GLFWwindow *win, int button, int action, int mods) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
// Defer multiple clicks per frame to future frames | |||
MouseButtonArguments args = {window, button, action, mods}; | |||
mouseButtonQueue.push(args); | |||
MouseButtonArguments args = {win, button, action, mods}; | |||
window->internal->mouseButtonQueue.push(args); | |||
} | |||
void cursorPosCallback(GLFWwindow* window, double xpos, double ypos) { | |||
Vec mousePos = Vec(xpos, ypos).div(gPixelRatio / gWindowRatio).round(); | |||
Vec mouseDelta = mousePos.minus(gMousePos); | |||
static void cursorPosCallback(GLFWwindow *win, double xpos, double ypos) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
Vec mousePos = Vec(xpos, ypos).div(window->pixelRatio / window->windowRatio).round(); | |||
Vec mouseDelta = mousePos.minus(window->mousePos); | |||
int cursorMode = glfwGetInputMode(gWindow, GLFW_CURSOR); | |||
int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); | |||
(void) cursorMode; | |||
#ifdef ARCH_MAC | |||
@@ -100,42 +102,45 @@ void cursorPosCallback(GLFWwindow* window, 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(gWindow, gMousePos.x, gMousePos.y); | |||
glfwSetCursorPos(win, window->mousePos.x, window->mousePos.y); | |||
CGAssociateMouseAndMouseCursorPosition(true); | |||
mousePos = gMousePos; | |||
mousePos = window->mousePos; | |||
} | |||
// Because sometimes the cursor turns into an arrow when its position is on the boundary of the window | |||
glfwSetCursor(gWindow, NULL); | |||
glfwSetCursor(win, NULL); | |||
#endif | |||
gMousePos = mousePos; | |||
window->mousePos = mousePos; | |||
context()->event->handleHover(mousePos, mouseDelta); | |||
} | |||
void cursorEnterCallback(GLFWwindow* window, int entered) { | |||
static void cursorEnterCallback(GLFWwindow *win, int entered) { | |||
if (!entered) { | |||
context()->event->handleLeave(); | |||
} | |||
} | |||
void scrollCallback(GLFWwindow *window, double x, double y) { | |||
static void scrollCallback(GLFWwindow *win, double x, double y) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
Vec scrollDelta = Vec(x, y); | |||
#if ARCH_LIN || ARCH_WIN | |||
if (windowIsShiftPressed()) | |||
if (window->isShiftPressed()) | |||
scrollDelta = Vec(y, x); | |||
#endif | |||
scrollDelta = scrollDelta.mult(50.0); | |||
context()->event->handleScroll(gMousePos, scrollDelta); | |||
context()->event->handleScroll(window->mousePos, scrollDelta); | |||
} | |||
void charCallback(GLFWwindow *window, unsigned int codepoint) { | |||
context()->event->handleText(gMousePos, codepoint); | |||
static void charCallback(GLFWwindow *win, unsigned int codepoint) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
context()->event->handleText(window->mousePos, codepoint); | |||
} | |||
void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods) { | |||
context()->event->handleKey(gMousePos, key, scancode, action, mods); | |||
static void keyCallback(GLFWwindow *win, int key, int scancode, int action, int mods) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
context()->event->handleKey(window->mousePos, key, scancode, action, mods); | |||
// Keyboard MIDI driver | |||
if (!(mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER))) { | |||
@@ -148,37 +153,22 @@ void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods | |||
} | |||
} | |||
void dropCallback(GLFWwindow *window, int count, const char **paths) { | |||
static void dropCallback(GLFWwindow *win, int count, const char **paths) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
std::vector<std::string> pathsVec; | |||
for (int i = 0; i < count; i++) { | |||
pathsVec.push_back(paths[i]); | |||
} | |||
context()->event->handleDrop(gMousePos, pathsVec); | |||
context()->event->handleDrop(window->mousePos, pathsVec); | |||
} | |||
void errorCallback(int error, const char *description) { | |||
static void errorCallback(int error, const char *description) { | |||
WARN("GLFW error %d: %s", error, description); | |||
} | |||
void renderGui() { | |||
int width, height; | |||
glfwGetFramebufferSize(gWindow, &width, &height); | |||
// Update and render | |||
nvgBeginFrame(gVg, width, height, gPixelRatio); | |||
Window::Window() { | |||
internal = new Internal; | |||
nvgReset(gVg); | |||
nvgScale(gVg, gPixelRatio, gPixelRatio); | |||
context()->event->rootWidget->draw(gVg); | |||
glViewport(0, 0, width, height); | |||
glClearColor(0.0, 0.0, 0.0, 1.0); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||
nvgEndFrame(gVg); | |||
glfwSwapBuffers(gWindow); | |||
} | |||
void windowInit() { | |||
int err; | |||
// Set up GLFW | |||
@@ -200,28 +190,29 @@ void windowInit() { | |||
#endif | |||
glfwWindowHint(GLFW_MAXIMIZED, GLFW_TRUE); | |||
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); | |||
lastWindowTitle = ""; | |||
gWindow = glfwCreateWindow(640, 480, lastWindowTitle.c_str(), NULL, NULL); | |||
if (!gWindow) { | |||
internal->lastWindowTitle = ""; | |||
win = glfwCreateWindow(640, 480, internal->lastWindowTitle.c_str(), NULL, NULL); | |||
if (!win) { | |||
osdialog_message(OSDIALOG_ERROR, OSDIALOG_OK, "Cannot open window with OpenGL 2.0 renderer. Does your graphics card support OpenGL 2.0 or greater? If so, make sure you have the latest graphics drivers installed."); | |||
exit(1); | |||
} | |||
glfwMakeContextCurrent(gWindow); | |||
glfwSetWindowUserPointer(win, this); | |||
glfwSetInputMode(win, GLFW_LOCK_KEY_MODS, 1); | |||
glfwMakeContextCurrent(win); | |||
glfwSwapInterval(1); | |||
glfwSetInputMode(gWindow, GLFW_LOCK_KEY_MODS, 1); | |||
glfwSetWindowSizeCallback(gWindow, windowSizeCallback); | |||
glfwSetMouseButtonCallback(gWindow, mouseButtonStickyCallback); | |||
glfwSetWindowSizeCallback(win, windowSizeCallback); | |||
glfwSetMouseButtonCallback(win, mouseButtonStickyCallback); | |||
// Call this ourselves, but on every frame instead of only when the mouse moves | |||
// glfwSetCursorPosCallback(gWindow, cursorPosCallback); | |||
glfwSetCursorEnterCallback(gWindow, cursorEnterCallback); | |||
glfwSetScrollCallback(gWindow, scrollCallback); | |||
glfwSetCharCallback(gWindow, charCallback); | |||
glfwSetKeyCallback(gWindow, keyCallback); | |||
glfwSetDropCallback(gWindow, dropCallback); | |||
// glfwSetCursorPosCallback(win, cursorPosCallback); | |||
glfwSetCursorEnterCallback(win, cursorEnterCallback); | |||
glfwSetScrollCallback(win, scrollCallback); | |||
glfwSetCharCallback(win, charCallback); | |||
glfwSetKeyCallback(win, keyCallback); | |||
glfwSetDropCallback(win, dropCallback); | |||
// Set up GLEW | |||
glewExperimental = GL_TRUE; | |||
@@ -234,73 +225,87 @@ void windowInit() { | |||
// GLEW generates GL error because it calls glGetString(GL_EXTENSIONS), we'll consume it here. | |||
glGetError(); | |||
glfwSetWindowSizeLimits(gWindow, 640, 480, GLFW_DONT_CARE, GLFW_DONT_CARE); | |||
glfwSetWindowSizeLimits(win, 640, 480, GLFW_DONT_CARE, GLFW_DONT_CARE); | |||
// Set up NanoVG | |||
int nvgFlags = NVG_ANTIALIAS; | |||
#if defined NANOVG_GL2 | |||
gVg = nvgCreateGL2(nvgFlags); | |||
vg = nvgCreateGL2(nvgFlags); | |||
#elif defined NANOVG_GL3 | |||
gVg = nvgCreateGL3(nvgFlags); | |||
vg = nvgCreateGL3(nvgFlags); | |||
#elif defined NANOVG_GLES2 | |||
gVg = nvgCreateGLES2(nvgFlags); | |||
vg = nvgCreateGLES2(nvgFlags); | |||
#endif | |||
assert(gVg); | |||
assert(vg); | |||
#if defined NANOVG_GL2 | |||
gFramebufferVg = nvgCreateGL2(nvgFlags); | |||
framebufferVg = nvgCreateGL2(nvgFlags); | |||
#elif defined NANOVG_GL3 | |||
gFramebufferVg = nvgCreateGL3(nvgFlags); | |||
framebufferVg = nvgCreateGL3(nvgFlags); | |||
#elif defined NANOVG_GLES2 | |||
gFramebufferVg = nvgCreateGLES2(nvgFlags); | |||
framebufferVg = nvgCreateGLES2(nvgFlags); | |||
#endif | |||
assert(gFramebufferVg); | |||
// Set up Blendish | |||
gGuiFont = Font::load(context()->asset->system("res/fonts/DejaVuSans.ttf")); | |||
bndSetFont(gGuiFont->handle); | |||
windowSetTheme(nvgRGB(0x33, 0x33, 0x33), nvgRGB(0xf0, 0xf0, 0xf0)); | |||
assert(framebufferVg); | |||
} | |||
void windowDestroy() { | |||
gGuiFont.reset(); | |||
Window::~Window() { | |||
#if defined NANOVG_GL2 | |||
nvgDeleteGL2(gVg); | |||
nvgDeleteGL2(vg); | |||
#elif defined NANOVG_GL3 | |||
nvgDeleteGL3(gVg); | |||
nvgDeleteGL3(vg); | |||
#elif defined NANOVG_GLES2 | |||
nvgDeleteGLES2(gVg); | |||
nvgDeleteGLES2(vg); | |||
#endif | |||
#if defined NANOVG_GL2 | |||
nvgDeleteGL2(gFramebufferVg); | |||
nvgDeleteGL2(framebufferVg); | |||
#elif defined NANOVG_GL3 | |||
nvgDeleteGL3(gFramebufferVg); | |||
nvgDeleteGL3(framebufferVg); | |||
#elif defined NANOVG_GLES2 | |||
nvgDeleteGLES2(gFramebufferVg); | |||
nvgDeleteGLES2(framebufferVg); | |||
#endif | |||
glfwDestroyWindow(gWindow); | |||
glfwDestroyWindow(win); | |||
glfwTerminate(); | |||
delete internal; | |||
} | |||
static void Window_renderGui(Window *window) { | |||
int width, height; | |||
glfwGetFramebufferSize(window->win, &width, &height); | |||
bndSetFont(window->uiFont->handle); | |||
// Update and render | |||
nvgBeginFrame(window->vg, width, height, window->pixelRatio); | |||
nvgReset(window->vg); | |||
nvgScale(window->vg, window->pixelRatio, window->pixelRatio); | |||
context()->event->rootWidget->draw(window->vg); | |||
glViewport(0, 0, width, height); | |||
glClearColor(0.0, 0.0, 0.0, 1.0); | |||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); | |||
nvgEndFrame(window->vg); | |||
glfwSwapBuffers(window->win); | |||
} | |||
void windowRun() { | |||
assert(gWindow); | |||
gGuiFrame = 0; | |||
while(!glfwWindowShouldClose(gWindow)) { | |||
void Window::run() { | |||
uiFont = Font::load(asset::system("res/fonts/DejaVuSans.ttf")); | |||
frame = 0; | |||
while(!glfwWindowShouldClose(win)) { | |||
double startTime = glfwGetTime(); | |||
gGuiFrame++; | |||
frame++; | |||
// Poll events | |||
glfwPollEvents(); | |||
{ | |||
double xpos, ypos; | |||
glfwGetCursorPos(gWindow, &xpos, &ypos); | |||
cursorPosCallback(gWindow, xpos, ypos); | |||
glfwGetCursorPos(win, &xpos, &ypos); | |||
cursorPosCallback(win, xpos, ypos); | |||
} | |||
mouseButtonStickyPop(); | |||
Window_mouseButtonStickyPop(this); | |||
gamepad::step(); | |||
// Set window title | |||
@@ -312,36 +317,36 @@ void windowRun() { | |||
windowTitle += " - "; | |||
windowTitle += string::filename(context()->scene->rackWidget->lastPath); | |||
} | |||
if (windowTitle != lastWindowTitle) { | |||
glfwSetWindowTitle(gWindow, windowTitle.c_str()); | |||
lastWindowTitle = windowTitle; | |||
if (windowTitle != internal->lastWindowTitle) { | |||
glfwSetWindowTitle(win, windowTitle.c_str()); | |||
internal->lastWindowTitle = windowTitle; | |||
} | |||
// Get desired scaling | |||
float pixelRatio; | |||
glfwGetWindowContentScale(gWindow, &pixelRatio, NULL); | |||
pixelRatio = roundf(pixelRatio); | |||
if (pixelRatio != gPixelRatio) { | |||
float newPixelRatio; | |||
glfwGetWindowContentScale(win, &newPixelRatio, NULL); | |||
newPixelRatio = std::round(newPixelRatio); | |||
if (newPixelRatio != pixelRatio) { | |||
context()->event->handleZoom(); | |||
gPixelRatio = pixelRatio; | |||
pixelRatio = newPixelRatio; | |||
} | |||
// Get framebuffer/window ratio | |||
int width, height; | |||
glfwGetFramebufferSize(gWindow, &width, &height); | |||
glfwGetFramebufferSize(win, &width, &height); | |||
int windowWidth, windowHeight; | |||
glfwGetWindowSize(gWindow, &windowWidth, &windowHeight); | |||
gWindowRatio = (float)width / windowWidth; | |||
glfwGetWindowSize(win, &windowWidth, &windowHeight); | |||
windowRatio = (float)width / windowWidth; | |||
context()->event->rootWidget->box.size = Vec(width, height).div(gPixelRatio); | |||
context()->event->rootWidget->box.size = Vec(width, height).div(pixelRatio); | |||
// Step scene | |||
context()->event->rootWidget->step(); | |||
// Render | |||
bool visible = glfwGetWindowAttrib(gWindow, GLFW_VISIBLE) && !glfwGetWindowAttrib(gWindow, GLFW_ICONIFIED); | |||
bool visible = glfwGetWindowAttrib(win, GLFW_VISIBLE) && !glfwGetWindowAttrib(win, GLFW_ICONIFIED); | |||
if (visible) { | |||
renderGui(); | |||
Window_renderGui(this); | |||
} | |||
// Limit framerate manually if vsync isn't working | |||
@@ -356,132 +361,81 @@ void windowRun() { | |||
} | |||
} | |||
void windowClose() { | |||
glfwSetWindowShouldClose(gWindow, GLFW_TRUE); | |||
void Window::close() { | |||
glfwSetWindowShouldClose(win, GLFW_TRUE); | |||
} | |||
void windowCursorLock() { | |||
if (gAllowCursorLock) { | |||
void Window::cursorLock() { | |||
if (allowCursorLock) { | |||
#ifdef ARCH_MAC | |||
glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | |||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | |||
#else | |||
glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | |||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | |||
#endif | |||
} | |||
} | |||
void windowCursorUnlock() { | |||
if (gAllowCursorLock) { | |||
glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |||
void Window::cursorUnlock() { | |||
if (allowCursorLock) { | |||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |||
} | |||
} | |||
bool windowIsModPressed() { | |||
bool Window::isModPressed() { | |||
#ifdef ARCH_MAC | |||
return glfwGetKey(gWindow, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS; | |||
return glfwGetKey(win, GLFW_KEY_LEFT_SUPER) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SUPER) == GLFW_PRESS; | |||
#else | |||
return glfwGetKey(gWindow, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS; | |||
return glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS; | |||
#endif | |||
} | |||
bool windowIsShiftPressed() { | |||
return glfwGetKey(gWindow, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(gWindow, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS; | |||
bool Window::isShiftPressed() { | |||
return glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS; | |||
} | |||
Vec windowGetWindowSize() { | |||
Vec Window::getWindowSize() { | |||
int width, height; | |||
glfwGetWindowSize(gWindow, &width, &height); | |||
glfwGetWindowSize(win, &width, &height); | |||
return Vec(width, height); | |||
} | |||
void windowSetWindowSize(Vec size) { | |||
void Window::setWindowSize(Vec size) { | |||
int width = size.x; | |||
int height = size.y; | |||
glfwSetWindowSize(gWindow, width, height); | |||
glfwSetWindowSize(win, width, height); | |||
} | |||
Vec windowGetWindowPos() { | |||
Vec Window::getWindowPos() { | |||
int x, y; | |||
glfwGetWindowPos(gWindow, &x, &y); | |||
glfwGetWindowPos(win, &x, &y); | |||
return Vec(x, y); | |||
} | |||
void windowSetWindowPos(Vec pos) { | |||
void Window::setWindowPos(Vec pos) { | |||
int x = pos.x; | |||
int y = pos.y; | |||
glfwSetWindowPos(gWindow, x, y); | |||
} | |||
bool windowIsMaximized() { | |||
return glfwGetWindowAttrib(gWindow, GLFW_MAXIMIZED); | |||
} | |||
void windowSetTheme(NVGcolor bg, NVGcolor fg) { | |||
// Assume dark background and light foreground | |||
BNDwidgetTheme w; | |||
w.outlineColor = bg; | |||
w.itemColor = fg; | |||
w.innerColor = bg; | |||
w.innerSelectedColor = color::plus(bg, nvgRGB(0x30, 0x30, 0x30)); | |||
w.textColor = fg; | |||
w.textSelectedColor = fg; | |||
w.shadeTop = 0; | |||
w.shadeDown = 0; | |||
BNDtheme t; | |||
t.backgroundColor = color::plus(bg, nvgRGB(0x30, 0x30, 0x30)); | |||
t.regularTheme = w; | |||
t.toolTheme = w; | |||
t.radioTheme = w; | |||
t.textFieldTheme = w; | |||
t.optionTheme = w; | |||
t.choiceTheme = w; | |||
t.numberFieldTheme = w; | |||
t.sliderTheme = w; | |||
t.scrollBarTheme = w; | |||
t.tooltipTheme = w; | |||
t.menuTheme = w; | |||
t.menuItemTheme = w; | |||
t.sliderTheme.itemColor = bg; | |||
t.sliderTheme.innerColor = color::plus(bg, nvgRGB(0x50, 0x50, 0x50)); | |||
t.sliderTheme.innerSelectedColor = color::plus(bg, nvgRGB(0x60, 0x60, 0x60)); | |||
t.textFieldTheme = t.sliderTheme; | |||
t.textFieldTheme.textColor = color::minus(bg, nvgRGB(0x20, 0x20, 0x20)); | |||
t.textFieldTheme.textSelectedColor = t.textFieldTheme.textColor; | |||
t.scrollBarTheme.itemColor = color::plus(bg, nvgRGB(0x50, 0x50, 0x50)); | |||
t.scrollBarTheme.innerColor = bg; | |||
t.menuTheme.innerColor = color::minus(bg, nvgRGB(0x10, 0x10, 0x10)); | |||
t.menuTheme.textColor = color::minus(fg, nvgRGB(0x50, 0x50, 0x50)); | |||
t.menuTheme.textSelectedColor = t.menuTheme.textColor; | |||
bndSetTheme(t); | |||
} | |||
static int windowX = 0; | |||
static int windowY = 0; | |||
static int windowWidth = 0; | |||
static int windowHeight = 0; | |||
void windowSetFullScreen(bool fullScreen) { | |||
if (windowGetFullScreen()) { | |||
glfwSetWindowMonitor(gWindow, NULL, windowX, windowY, windowWidth, windowHeight, GLFW_DONT_CARE); | |||
glfwSetWindowPos(win, x, y); | |||
} | |||
bool Window::isMaximized() { | |||
return glfwGetWindowAttrib(win, GLFW_MAXIMIZED); | |||
} | |||
void Window::setFullScreen(bool fullScreen) { | |||
if (isFullScreen()) { | |||
glfwSetWindowMonitor(win, NULL, internal->lastWindowX, internal->lastWindowY, internal->lastWindowWidth, internal->lastWindowHeight, GLFW_DONT_CARE); | |||
} | |||
else { | |||
glfwGetWindowPos(gWindow, &windowX, &windowY); | |||
glfwGetWindowSize(gWindow, &windowWidth, &windowHeight); | |||
glfwGetWindowPos(win, &internal->lastWindowX, &internal->lastWindowY); | |||
glfwGetWindowSize(win, &internal->lastWindowWidth, &internal->lastWindowHeight); | |||
GLFWmonitor *monitor = glfwGetPrimaryMonitor(); | |||
const GLFWvidmode* mode = glfwGetVideoMode(monitor); | |||
glfwSetWindowMonitor(gWindow, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); | |||
glfwSetWindowMonitor(win, monitor, 0, 0, mode->width, mode->height, mode->refreshRate); | |||
} | |||
} | |||
bool windowGetFullScreen() { | |||
GLFWmonitor *monitor = glfwGetWindowMonitor(gWindow); | |||
bool Window::isFullScreen() { | |||
GLFWmonitor *monitor = glfwGetWindowMonitor(win); | |||
return monitor != NULL; | |||
} | |||
@@ -491,7 +445,7 @@ bool windowGetFullScreen() { | |||
//////////////////// | |||
Font::Font(const std::string &filename) { | |||
handle = nvgCreateFont(gVg, filename.c_str(), filename.c_str()); | |||
handle = nvgCreateFont(context()->window->vg, filename.c_str(), filename.c_str()); | |||
if (handle >= 0) { | |||
INFO("Loaded font %s", filename.c_str()); | |||
} | |||
@@ -517,7 +471,7 @@ std::shared_ptr<Font> Font::load(const std::string &filename) { | |||
//////////////////// | |||
Image::Image(const std::string &filename) { | |||
handle = nvgCreateImage(gVg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||
handle = nvgCreateImage(context()->window->vg, filename.c_str(), NVG_IMAGE_REPEATX | NVG_IMAGE_REPEATY); | |||
if (handle > 0) { | |||
INFO("Loaded image %s", filename.c_str()); | |||
} | |||
@@ -528,7 +482,7 @@ Image::Image(const std::string &filename) { | |||
Image::~Image() { | |||
// TODO What if handle is invalid? | |||
nvgDeleteImage(gVg, handle); | |||
nvgDeleteImage(context()->window->vg, handle); | |||
} | |||
std::shared_ptr<Image> Image::load(const std::string &filename) { | |||