@@ -13,6 +13,8 @@ struct PatchManager { | |||
int legacy; | |||
std::string warningLog; | |||
PatchManager(); | |||
~PatchManager(); | |||
void init(std::string path); | |||
void reset(); | |||
void resetDialog(); | |||
@@ -26,7 +26,6 @@ bool isSlugValid(std::string slug); | |||
extern std::list<Plugin*> plugins; | |||
extern std::string token; | |||
extern bool isDownloading; | |||
extern float downloadProgress; | |||
extern std::string downloadName; | |||
@@ -1,26 +1,39 @@ | |||
#pragma once | |||
#include "common.hpp" | |||
#include "math.hpp" | |||
#include <jansson.h> | |||
namespace rack { | |||
namespace settings { | |||
void save(std::string filename); | |||
void load(std::string filename); | |||
struct Settings { | |||
std::string token; | |||
math::Vec windowSize; | |||
math::Vec windowPos; | |||
float zoom = 1.0; | |||
float cableOpacity = 0.5; | |||
float cableTension = 0.5; | |||
bool allowCursorLock = true; | |||
float sampleRate = 44100.0; | |||
int threadCount = 1; | |||
bool paramTooltip = false; | |||
bool cpuMeter = false; | |||
bool lockModules = false; | |||
bool checkVersion = true; | |||
float frameRateLimit = 0.0; | |||
bool frameRateSync = true; | |||
bool skipLoadOnLaunch = false; | |||
std::string patchPath; | |||
json_t *toJson(); | |||
void fromJson(json_t *rootJ); | |||
void save(std::string filename); | |||
void load(std::string filename); | |||
}; | |||
extern float zoom; | |||
extern float cableOpacity; | |||
extern float cableTension; | |||
extern bool paramTooltip; | |||
extern bool powerMeter; | |||
extern bool lockModules; | |||
extern bool checkVersion; | |||
extern bool skipLoadOnLaunch; | |||
extern float frameRateLimit; | |||
extern bool frameRateSync; | |||
extern Settings settings; | |||
} // namespace settings | |||
} // namespace rack |
@@ -71,7 +71,6 @@ struct Window { | |||
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 */ | |||
math::Vec mousePos; | |||
@@ -90,11 +89,6 @@ struct Window { | |||
Don't call this from a Key event. Simply use `e.mods` instead. | |||
*/ | |||
int getMods(); | |||
math::Vec getWindowSize(); | |||
void setWindowSize(math::Vec size); | |||
math::Vec getWindowPos(); | |||
void setWindowPos(math::Vec pos); | |||
bool isMaximized(); | |||
void setFullScreen(bool fullScreen); | |||
bool isFullScreen(); | |||
}; | |||
@@ -207,8 +207,8 @@ void CableWidget::fromJson(json_t *rootJ, const std::map<int, ModuleWidget*> &mo | |||
} | |||
void CableWidget::draw(const widget::DrawContext &ctx) { | |||
float opacity = settings::cableOpacity; | |||
float tension = settings::cableTension; | |||
float opacity = settings.cableOpacity; | |||
float tension = settings.cableTension; | |||
float thickness = 5; | |||
if (isComplete()) { | |||
@@ -145,7 +145,7 @@ void ModuleWidget::draw(const widget::DrawContext &ctx) { | |||
widget::Widget::draw(ctx); | |||
// Power meter | |||
if (module && settings::powerMeter) { | |||
if (module && settings.cpuMeter) { | |||
nvgBeginPath(ctx.vg); | |||
nvgRect(ctx.vg, | |||
0, box.size.y - 20, | |||
@@ -285,7 +285,7 @@ void ModuleWidget::onDragEnd(const event::DragEnd &e) { | |||
} | |||
void ModuleWidget::onDragMove(const event::DragMove &e) { | |||
if (!settings::lockModules) { | |||
if (!settings.lockModules) { | |||
math::Rect newBox = box; | |||
newBox.pos = APP->scene->rackWidget->mousePos.minus(dragPos); | |||
APP->scene->rackWidget->requestModuleBoxNearest(this, newBox); | |||
@@ -158,7 +158,7 @@ void ParamWidget::onDoubleClick(const event::DoubleClick &e) { | |||
} | |||
void ParamWidget::onEnter(const event::Enter &e) { | |||
if (settings::paramTooltip && !tooltip && paramQuantity) { | |||
if (settings.paramTooltip && !tooltip && paramQuantity) { | |||
ParamTooltip *paramTooltip = new ParamTooltip; | |||
paramTooltip->paramWidget = this; | |||
APP->scene->addChild(paramTooltip); | |||
@@ -59,12 +59,12 @@ void Scene::step() { | |||
int frame = APP->window->frame; | |||
if (frame > 0 && frame % (60 * 15) == 0) { | |||
APP->patch->save(asset::user("autosave.vcv")); | |||
settings::save(asset::user("settings.json")); | |||
settings.save(asset::user("settings.json")); | |||
} | |||
// Set zoom every few frames | |||
if (APP->window->frame % 10 == 0) | |||
zoomWidget->setZoom(std::round(settings::zoom * 100) / 100); | |||
zoomWidget->setZoom(std::round(settings.zoom * 100) / 100); | |||
// Request latest version from server | |||
if (!devMode && checkVersion && !checkedVersion) { | |||
@@ -180,10 +180,10 @@ struct EditButton : MenuButton { | |||
struct ZoomQuantity : ui::Quantity { | |||
void setValue(float value) override { | |||
settings::zoom = math::clamp(value, getMinValue(), getMaxValue()); | |||
settings.zoom = math::clamp(value, getMinValue(), getMaxValue()); | |||
} | |||
float getValue() override { | |||
return settings::zoom; | |||
return settings.zoom; | |||
} | |||
float getMinValue() override {return 0.25;} | |||
float getMaxValue() override {return 2.0;} | |||
@@ -197,10 +197,10 @@ struct ZoomQuantity : ui::Quantity { | |||
struct CableOpacityQuantity : ui::Quantity { | |||
void setValue(float value) override { | |||
settings::cableOpacity = math::clamp(value, getMinValue(), getMaxValue()); | |||
settings.cableOpacity = math::clamp(value, getMinValue(), getMaxValue()); | |||
} | |||
float getValue() override { | |||
return settings::cableOpacity; | |||
return settings.cableOpacity; | |||
} | |||
float getDefaultValue() override {return 0.5;} | |||
float getDisplayValue() override {return getValue() * 100;} | |||
@@ -213,10 +213,10 @@ struct CableOpacityQuantity : ui::Quantity { | |||
struct CableTensionQuantity : ui::Quantity { | |||
void setValue(float value) override { | |||
settings::cableTension = math::clamp(value, getMinValue(), getMaxValue()); | |||
settings.cableTension = math::clamp(value, getMinValue(), getMaxValue()); | |||
} | |||
float getValue() override { | |||
return settings::cableTension; | |||
return settings.cableTension; | |||
} | |||
float getDefaultValue() override {return 0.5;} | |||
std::string getLabel() override {return "Cable tension";} | |||
@@ -224,13 +224,13 @@ struct CableTensionQuantity : ui::Quantity { | |||
}; | |||
struct PowerMeterItem : ui::MenuItem { | |||
PowerMeterItem() { | |||
struct CpuMeterItem : ui::MenuItem { | |||
CpuMeterItem() { | |||
text = "CPU meter"; | |||
rightText = CHECKMARK(settings::powerMeter); | |||
rightText = CHECKMARK(settings.cpuMeter); | |||
} | |||
void onAction(const event::Action &e) override { | |||
settings::powerMeter ^= true; | |||
settings.cpuMeter ^= true; | |||
} | |||
}; | |||
@@ -238,10 +238,10 @@ struct PowerMeterItem : ui::MenuItem { | |||
struct ParamTooltipItem : ui::MenuItem { | |||
ParamTooltipItem() { | |||
text = "Parameter tooltips"; | |||
rightText = CHECKMARK(settings::paramTooltip); | |||
rightText = CHECKMARK(settings.paramTooltip); | |||
} | |||
void onAction(const event::Action &e) override { | |||
settings::paramTooltip ^= true; | |||
settings.paramTooltip ^= true; | |||
} | |||
}; | |||
@@ -249,10 +249,10 @@ struct ParamTooltipItem : ui::MenuItem { | |||
struct LockModulesItem : ui::MenuItem { | |||
LockModulesItem() { | |||
text = "Lock modules"; | |||
rightText = CHECKMARK(settings::lockModules); | |||
rightText = CHECKMARK(settings.lockModules); | |||
} | |||
void onAction(const event::Action &e) override { | |||
settings::lockModules ^= true; | |||
settings.lockModules ^= true; | |||
} | |||
}; | |||
@@ -369,7 +369,7 @@ struct SettingsButton : MenuButton { | |||
menu->box.size.x = box.size.x; | |||
menu->addChild(new ParamTooltipItem); | |||
menu->addChild(new PowerMeterItem); | |||
menu->addChild(new CpuMeterItem); | |||
menu->addChild(new LockModulesItem); | |||
menu->addChild(new SampleRateItem); | |||
menu->addChild(new ThreadCount); | |||
@@ -627,10 +627,10 @@ struct WebsiteItem : ui::MenuItem { | |||
struct CheckVersionItem : ui::MenuItem { | |||
CheckVersionItem() { | |||
text = "Check version on launch"; | |||
rightText = CHECKMARK(settings::checkVersion); | |||
rightText = CHECKMARK(settings.checkVersion); | |||
} | |||
void onAction(const event::Action &e) override { | |||
settings::checkVersion ^= true; | |||
settings.checkVersion ^= true; | |||
} | |||
}; | |||
@@ -155,16 +155,20 @@ struct Engine::Internal { | |||
Engine::Engine() { | |||
internal = new Internal; | |||
float sampleRate = 44100.f; | |||
float sampleRate = settings.sampleRate; | |||
internal->sampleRate = sampleRate; | |||
internal->sampleTime = 1 / sampleRate; | |||
internal->sampleRateRequested = sampleRate; | |||
internal->threadCount = settings.threadCount; | |||
internal->engineBarrier.total = 1; | |||
internal->workerBarrier.total = 1; | |||
} | |||
Engine::~Engine() { | |||
settings.sampleRate = internal->sampleRate; | |||
settings.threadCount = internal->threadCount; | |||
// Make sure there are no cables or modules in the rack on destruction. This suggests that a module failed to remove itself before the RackWidget was destroyed. | |||
assert(internal->cables.empty()); | |||
assert(internal->modules.empty()); | |||
@@ -173,6 +177,7 @@ Engine::~Engine() { | |||
} | |||
static void Engine_setWorkerCount(Engine *engine, int workerCount) { | |||
assert(0 <= workerCount && workerCount <= 32); | |||
Engine::Internal *internal = engine->internal; | |||
// Stop all workers | |||
@@ -213,7 +218,7 @@ static void Engine_stepModules(Engine *engine, int id) { | |||
Module *module = internal->modules[i]; | |||
if (!module->bypass) { | |||
// Step module | |||
if (settings::powerMeter) { | |||
if (settings.cpuMeter) { | |||
auto startTime = std::chrono::high_resolution_clock::now(); | |||
module->step(); | |||
@@ -83,9 +83,9 @@ int main(int argc, char *argv[]) { | |||
INFO("Initialized environment"); | |||
// Initialize app | |||
settings.load(asset::user("settings.json")); | |||
app::init(); | |||
APP->scene->devMode = devMode; | |||
settings::load(asset::user("settings.json")); | |||
APP->patch->init(patchPath); | |||
INFO("Initialized app"); | |||
@@ -97,8 +97,8 @@ int main(int argc, char *argv[]) { | |||
// Destroy app | |||
APP->patch->save(asset::user("autosave.vcv")); | |||
settings::save(asset::user("settings.json")); | |||
app::destroy(); | |||
settings.save(asset::user("settings.json")); | |||
INFO("Cleaned up app"); | |||
// Destroy environment | |||
@@ -16,6 +16,14 @@ namespace rack { | |||
static const char PATCH_FILTERS[] = "VCV Rack patch (.vcv):vcv"; | |||
PatchManager::PatchManager() { | |||
path = settings.patchPath; | |||
} | |||
PatchManager::~PatchManager() { | |||
settings.patchPath = path; | |||
} | |||
void PatchManager::init(std::string path) { | |||
if (!path.empty()) { | |||
// Load patch | |||
@@ -25,10 +33,10 @@ void PatchManager::init(std::string path) { | |||
} | |||
// 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 oldSkipLoadOnLaunch = settings::skipLoadOnLaunch; | |||
settings::skipLoadOnLaunch = true; | |||
settings::save(asset::user("settings.json")); | |||
settings::skipLoadOnLaunch = false; | |||
bool oldSkipLoadOnLaunch = settings.skipLoadOnLaunch; | |||
settings.skipLoadOnLaunch = true; | |||
settings.save(asset::user("settings.json")); | |||
settings.skipLoadOnLaunch = false; | |||
if (oldSkipLoadOnLaunch && 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?")) { | |||
this->path = ""; | |||
return; | |||
@@ -6,6 +6,7 @@ | |||
#include "app.hpp" | |||
#include "app/common.hpp" | |||
#include "plugin/callbacks.hpp" | |||
#include "settings.hpp" | |||
#include <unistd.h> | |||
#include <sys/types.h> | |||
@@ -184,7 +185,7 @@ static bool syncPlugin(std::string slug, json_t *manifestJ, bool dryRun) { | |||
if (dryRun) { | |||
downloadUrl += "/available"; | |||
} | |||
downloadUrl += "?token=" + network::encodeUrl(token); | |||
downloadUrl += "?token=" + network::encodeUrl(settings.token); | |||
downloadUrl += "&slug=" + network::encodeUrl(slug); | |||
downloadUrl += "&version=" + network::encodeUrl(latestVersion); | |||
downloadUrl += "&arch=" + network::encodeUrl(arch); | |||
@@ -393,7 +394,7 @@ void logIn(std::string email, std::string password) { | |||
json_t *tokenJ = json_object_get(resJ, "token"); | |||
if (tokenJ) { | |||
const char *tokenStr = json_string_value(tokenJ); | |||
token = tokenStr; | |||
settings.token = tokenStr; | |||
loginStatus = ""; | |||
} | |||
} | |||
@@ -402,11 +403,11 @@ void logIn(std::string email, std::string password) { | |||
} | |||
void logOut() { | |||
token = ""; | |||
settings.token = ""; | |||
} | |||
bool sync(bool dryRun) { | |||
if (token.empty()) | |||
if (settings.token.empty()) | |||
return false; | |||
bool available = false; | |||
@@ -422,7 +423,7 @@ bool sync(bool dryRun) { | |||
// Get user's plugins list | |||
json_t *pluginsReqJ = json_object(); | |||
json_object_set(pluginsReqJ, "token", json_string(token.c_str())); | |||
json_object_set(pluginsReqJ, "token", json_string(settings.token.c_str())); | |||
std::string pluginsUrl = app::API_URL; | |||
pluginsUrl += "/plugins"; | |||
json_t *pluginsResJ = network::requestJson(network::METHOD_GET, pluginsUrl, pluginsReqJ); | |||
@@ -493,7 +494,7 @@ void cancelDownload() { | |||
} | |||
bool isLoggedIn() { | |||
return token != ""; | |||
return settings.token != ""; | |||
} | |||
Plugin *getPlugin(std::string pluginSlug) { | |||
@@ -534,7 +535,6 @@ bool isSlugValid(std::string slug) { | |||
std::list<Plugin*> plugins; | |||
std::string token; | |||
bool isDownloading = false; | |||
float downloadProgress = 0.f; | |||
std::string downloadName; | |||
@@ -10,181 +10,137 @@ | |||
namespace rack { | |||
namespace settings { | |||
static json_t *settingsToJson() { | |||
// root | |||
json_t *Settings::toJson() { | |||
json_t *rootJ = json_object(); | |||
// token | |||
json_t *tokenJ = json_string(plugin::token.c_str()); | |||
json_object_set_new(rootJ, "token", tokenJ); | |||
json_object_set_new(rootJ, "token", json_string(token.c_str())); | |||
if (!APP->window->isMaximized()) { | |||
// windowSize | |||
math::Vec windowSize = APP->window->getWindowSize(); | |||
json_t *windowSizeJ = json_pack("[f, f]", windowSize.x, windowSize.y); | |||
json_object_set_new(rootJ, "windowSize", windowSizeJ); | |||
json_t *windowSizeJ = json_pack("[f, f]", windowSize.x, windowSize.y); | |||
json_object_set_new(rootJ, "windowSize", windowSizeJ); | |||
// windowPos | |||
math::Vec windowPos = APP->window->getWindowPos(); | |||
json_t *windowPosJ = json_pack("[f, f]", windowPos.x, windowPos.y); | |||
json_object_set_new(rootJ, "windowPos", windowPosJ); | |||
} | |||
// cableOpacity | |||
json_t *cableOpacityJ = json_real(cableOpacity); | |||
json_object_set_new(rootJ, "cableOpacity", cableOpacityJ); | |||
json_t *windowPosJ = json_pack("[f, f]", windowPos.x, windowPos.y); | |||
json_object_set_new(rootJ, "windowPos", windowPosJ); | |||
// cableTension | |||
json_t *cableTensionJ = json_real(cableTension); | |||
json_object_set_new(rootJ, "cableTension", cableTensionJ); | |||
json_object_set_new(rootJ, "zoom", json_real(zoom)); | |||
// zoom | |||
json_t *zoomJ = json_real(zoom); | |||
json_object_set_new(rootJ, "zoom", zoomJ); | |||
json_object_set_new(rootJ, "cableOpacity", json_real(cableOpacity)); | |||
// allowCursorLock | |||
json_t *allowCursorLockJ = json_boolean(APP->window->allowCursorLock); | |||
json_object_set_new(rootJ, "allowCursorLock", allowCursorLockJ); | |||
json_object_set_new(rootJ, "cableTension", json_real(cableTension)); | |||
// sampleRate | |||
json_t *sampleRateJ = json_real(APP->engine->getSampleRate()); | |||
json_object_set_new(rootJ, "sampleRate", sampleRateJ); | |||
json_object_set_new(rootJ, "allowCursorLock", json_boolean(allowCursorLock)); | |||
// patchPath | |||
json_t *patchPathJ = json_string(APP->patch->path.c_str()); | |||
json_object_set_new(rootJ, "patchPath", patchPathJ); | |||
json_object_set_new(rootJ, "sampleRate", json_real(sampleRate)); | |||
// skipLoadOnLaunch | |||
if (skipLoadOnLaunch) { | |||
json_object_set_new(rootJ, "skipLoadOnLaunch", json_true()); | |||
} | |||
json_object_set_new(rootJ, "threadCount", json_integer(threadCount)); | |||
// moduleBrowser | |||
json_object_set_new(rootJ, "moduleBrowser", app::moduleBrowserToJson()); | |||
json_object_set_new(rootJ, "paramTooltip", json_boolean(paramTooltip)); | |||
// powerMeter | |||
json_object_set_new(rootJ, "powerMeter", json_boolean(powerMeter)); | |||
json_object_set_new(rootJ, "cpuMeter", json_boolean(cpuMeter)); | |||
// threadCount | |||
json_object_set_new(rootJ, "threadCount", json_integer(APP->engine->getThreadCount())); | |||
json_object_set_new(rootJ, "lockModules", json_boolean(lockModules)); | |||
// checkVersion | |||
json_object_set_new(rootJ, "checkVersion", json_boolean(checkVersion)); | |||
// paramTooltip | |||
json_object_set_new(rootJ, "paramTooltip", json_boolean(paramTooltip)); | |||
// frameRateLimit | |||
json_object_set_new(rootJ, "frameRateLimit", json_real(frameRateLimit)); | |||
// frameRateSync | |||
json_object_set_new(rootJ, "frameRateSync", json_boolean(frameRateSync)); | |||
if (skipLoadOnLaunch) { | |||
json_object_set_new(rootJ, "skipLoadOnLaunch", json_true()); | |||
} | |||
json_object_set_new(rootJ, "patchPath", json_string(patchPath.c_str())); | |||
json_object_set_new(rootJ, "moduleBrowser", app::moduleBrowserToJson()); | |||
return rootJ; | |||
} | |||
static void settingsFromJson(json_t *rootJ) { | |||
// token | |||
void Settings::fromJson(json_t *rootJ) { | |||
json_t *tokenJ = json_object_get(rootJ, "token"); | |||
if (tokenJ) | |||
plugin::token = json_string_value(tokenJ); | |||
token = json_string_value(tokenJ); | |||
// windowSize | |||
json_t *windowSizeJ = json_object_get(rootJ, "windowSize"); | |||
if (windowSizeJ) { | |||
double width, height; | |||
json_unpack(windowSizeJ, "[F, F]", &width, &height); | |||
APP->window->setWindowSize(math::Vec(width, height)); | |||
double x, y; | |||
json_unpack(windowSizeJ, "[F, F]", &x, &y); | |||
windowSize = math::Vec(x, y); | |||
} | |||
// windowPos | |||
json_t *windowPosJ = json_object_get(rootJ, "windowPos"); | |||
if (windowPosJ) { | |||
double x, y; | |||
json_unpack(windowPosJ, "[F, F]", &x, &y); | |||
APP->window->setWindowPos(math::Vec(x, y)); | |||
windowPos = math::Vec(x, y); | |||
} | |||
// cableOpacity | |||
json_t *zoomJ = json_object_get(rootJ, "zoom"); | |||
if (zoomJ) | |||
zoom = json_number_value(zoomJ); | |||
json_t *cableOpacityJ = json_object_get(rootJ, "cableOpacity"); | |||
if (cableOpacityJ) | |||
cableOpacity = json_number_value(cableOpacityJ); | |||
// tension | |||
json_t *tensionJ = json_object_get(rootJ, "cableTension"); | |||
if (tensionJ) | |||
cableTension = json_number_value(tensionJ); | |||
// zoom | |||
json_t *zoomJ = json_object_get(rootJ, "zoom"); | |||
if (zoomJ) | |||
zoom = json_number_value(zoomJ); | |||
// allowCursorLock | |||
json_t *allowCursorLockJ = json_object_get(rootJ, "allowCursorLock"); | |||
if (allowCursorLockJ) | |||
APP->window->allowCursorLock = json_is_true(allowCursorLockJ); | |||
allowCursorLock = json_is_true(allowCursorLockJ); | |||
// sampleRate | |||
json_t *sampleRateJ = json_object_get(rootJ, "sampleRate"); | |||
if (sampleRateJ) { | |||
float sampleRate = json_number_value(sampleRateJ); | |||
APP->engine->setSampleRate(sampleRate); | |||
} | |||
// patchPath | |||
json_t *patchPathJ = json_object_get(rootJ, "patchPath"); | |||
if (patchPathJ) | |||
APP->patch->path = json_string_value(patchPathJ); | |||
if (sampleRateJ) | |||
sampleRate = json_number_value(sampleRateJ); | |||
// skipLoadOnLaunch | |||
json_t *skipLoadOnLaunchJ = json_object_get(rootJ, "skipLoadOnLaunch"); | |||
if (skipLoadOnLaunchJ) | |||
skipLoadOnLaunch = json_boolean_value(skipLoadOnLaunchJ); | |||
json_t *threadCountJ = json_object_get(rootJ, "threadCount"); | |||
if (threadCountJ) | |||
threadCount = json_integer_value(threadCountJ); | |||
// moduleBrowser | |||
json_t *moduleBrowserJ = json_object_get(rootJ, "moduleBrowser"); | |||
if (moduleBrowserJ) | |||
app::moduleBrowserFromJson(moduleBrowserJ); | |||
json_t *paramTooltipJ = json_object_get(rootJ, "paramTooltip"); | |||
if (paramTooltipJ) | |||
paramTooltip = json_boolean_value(paramTooltipJ); | |||
// powerMeter | |||
json_t *powerMeterJ = json_object_get(rootJ, "powerMeter"); | |||
if (powerMeterJ) | |||
powerMeter = json_boolean_value(powerMeterJ); | |||
json_t *cpuMeterJ = json_object_get(rootJ, "cpuMeter"); | |||
if (cpuMeterJ) | |||
cpuMeter = json_boolean_value(cpuMeterJ); | |||
// threadCount | |||
json_t *threadCountJ = json_object_get(rootJ, "threadCount"); | |||
if (threadCountJ) | |||
APP->engine->setThreadCount(json_integer_value(threadCountJ)); | |||
json_t *lockModulesJ = json_object_get(rootJ, "lockModules"); | |||
if (lockModulesJ) | |||
lockModules = json_boolean_value(lockModulesJ); | |||
// checkVersion | |||
json_t *checkVersionJ = json_object_get(rootJ, "checkVersion"); | |||
if (checkVersionJ) | |||
checkVersion = json_boolean_value(checkVersionJ); | |||
// paramTooltip | |||
json_t *paramTooltipJ = json_object_get(rootJ, "paramTooltip"); | |||
if (paramTooltipJ) | |||
paramTooltip = json_boolean_value(paramTooltipJ); | |||
// frameRateLimit | |||
json_t *frameRateLimitJ = json_object_get(rootJ, "frameRateLimit"); | |||
if (frameRateLimitJ) | |||
frameRateLimit = json_number_value(frameRateLimitJ); | |||
// frameRateSync | |||
json_t *frameRateSyncJ = json_object_get(rootJ, "frameRateSync"); | |||
if (frameRateSyncJ) | |||
frameRateSync = json_boolean_value(frameRateSyncJ); | |||
} | |||
json_t *skipLoadOnLaunchJ = json_object_get(rootJ, "skipLoadOnLaunch"); | |||
if (skipLoadOnLaunchJ) | |||
skipLoadOnLaunch = json_boolean_value(skipLoadOnLaunchJ); | |||
json_t *patchPathJ = json_object_get(rootJ, "patchPath"); | |||
if (patchPathJ) | |||
patchPath = json_string_value(patchPathJ); | |||
json_t *moduleBrowserJ = json_object_get(rootJ, "moduleBrowser"); | |||
if (moduleBrowserJ) | |||
app::moduleBrowserFromJson(moduleBrowserJ); | |||
} | |||
void save(std::string filename) { | |||
void Settings::save(std::string filename) { | |||
INFO("Saving settings %s", filename.c_str()); | |||
json_t *rootJ = settingsToJson(); | |||
json_t *rootJ = toJson(); | |||
if (rootJ) { | |||
FILE *file = fopen(filename.c_str(), "w"); | |||
if (!file) | |||
@@ -196,7 +152,7 @@ void save(std::string filename) { | |||
} | |||
} | |||
void load(std::string filename) { | |||
void Settings::load(std::string filename) { | |||
INFO("Loading settings %s", filename.c_str()); | |||
FILE *file = fopen(filename.c_str(), "r"); | |||
if (!file) | |||
@@ -205,7 +161,7 @@ void load(std::string filename) { | |||
json_error_t error; | |||
json_t *rootJ = json_loadf(file, 0, &error); | |||
if (rootJ) { | |||
settingsFromJson(rootJ); | |||
fromJson(rootJ); | |||
json_decref(rootJ); | |||
} | |||
else { | |||
@@ -216,17 +172,7 @@ void load(std::string filename) { | |||
} | |||
float zoom = 1.0; | |||
float cableOpacity = 0.5; | |||
float cableTension = 0.5; | |||
bool paramTooltip = false; | |||
bool powerMeter = false; | |||
bool lockModules = false; | |||
bool checkVersion = true; | |||
bool skipLoadOnLaunch = false; | |||
float frameRateLimit = 0.0; | |||
bool frameRateSync = true; | |||
Settings settings; | |||
} // namespace settings | |||
} // namespace rack |
@@ -12,7 +12,7 @@ | |||
#include <queue> | |||
#include <thread> | |||
#ifdef ARCH_MAC | |||
#if defined ARCH_MAC | |||
// For CGAssociateMouseAndMouseCursorPosition | |||
#include <ApplicationServices/ApplicationServices.h> | |||
#endif | |||
@@ -109,7 +109,7 @@ static void windowSizeCallback(GLFWwindow *win, int width, int height) { | |||
static void mouseButtonCallback(GLFWwindow *win, int button, int action, int mods) { | |||
Window *window = (Window*) glfwGetWindowUserPointer(win); | |||
#ifdef ARCH_MAC | |||
#if defined ARCH_MAC | |||
// Remap Ctrl-left click to right click on Mac | |||
if (button == GLFW_MOUSE_BUTTON_LEFT) { | |||
if (mods & GLFW_MOD_CONTROL) { | |||
@@ -130,7 +130,7 @@ static void cursorPosCallback(GLFWwindow *win, double xpos, double ypos) { | |||
int cursorMode = glfwGetInputMode(win, GLFW_CURSOR); | |||
(void) cursorMode; | |||
#ifdef ARCH_MAC | |||
#if defined ARCH_MAC | |||
// Workaround for Mac. We can't use GLFW_CURSOR_DISABLED because it's buggy, so implement it on our own. | |||
// 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) { | |||
@@ -223,7 +223,7 @@ Window::Window() { | |||
glfwMakeContextCurrent(win); | |||
// Enable v-sync | |||
glfwSwapInterval(settings::frameRateSync ? 1 : 0); | |||
glfwSwapInterval(settings.frameRateSync ? 1 : 0); | |||
glfwSetWindowSizeCallback(win, windowSizeCallback); | |||
glfwSetMouseButtonCallback(win, mouseButtonCallback); | |||
@@ -253,6 +253,14 @@ Window::Window() { | |||
glfwSetWindowSizeLimits(win, 800, 600, GLFW_DONT_CARE, GLFW_DONT_CARE); | |||
if (settings.windowSize.isZero()) { | |||
glfwMaximizeWindow(win); | |||
} | |||
else { | |||
glfwSetWindowSize(win, settings.windowSize.x, settings.windowSize.y); | |||
glfwSetWindowPos(win, settings.windowPos.x, settings.windowPos.y); | |||
} | |||
// Set up NanoVG | |||
int nvgFlags = NVG_ANTIALIAS; | |||
#if defined NANOVG_GL2 | |||
@@ -275,6 +283,19 @@ Window::Window() { | |||
} | |||
Window::~Window() { | |||
if (glfwGetWindowAttrib(win, GLFW_MAXIMIZED)) { | |||
settings.windowSize = math::Vec(); | |||
settings.windowPos = math::Vec(); | |||
} | |||
else { | |||
int winWidth, winHeight; | |||
glfwGetWindowSize(win, &winWidth, &winHeight); | |||
int winX, winY; | |||
glfwGetWindowPos(win, &winX, &winY); | |||
settings.windowSize = math::Vec(winWidth, winHeight); | |||
settings.windowPos = math::Vec(winX, winY); | |||
} | |||
#if defined NANOVG_GL2 | |||
nvgDeleteGL2(vg); | |||
#elif defined NANOVG_GL3 | |||
@@ -375,9 +396,9 @@ void Window::run() { | |||
// Limit frame rate | |||
double endTime = glfwGetTime(); | |||
if (settings::frameRateLimit > 0.0) { | |||
if (settings.frameRateLimit > 0.0) { | |||
double frameDuration = endTime - startTime; | |||
double waitDuration = 1.0 / settings::frameRateLimit - frameDuration; | |||
double waitDuration = 1.0 / settings.frameRateLimit - frameDuration; | |||
if (waitDuration > 0.0) { | |||
std::this_thread::sleep_for(std::chrono::duration<double>(waitDuration)); | |||
} | |||
@@ -394,8 +415,8 @@ void Window::close() { | |||
} | |||
void Window::cursorLock() { | |||
if (allowCursorLock) { | |||
#ifdef ARCH_MAC | |||
if (settings.allowCursorLock) { | |||
#if defined ARCH_MAC | |||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); | |||
#else | |||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_DISABLED); | |||
@@ -404,7 +425,7 @@ void Window::cursorLock() { | |||
} | |||
void Window::cursorUnlock() { | |||
if (allowCursorLock) { | |||
if (settings.allowCursorLock) { | |||
glfwSetInputMode(win, GLFW_CURSOR, GLFW_CURSOR_NORMAL); | |||
} | |||
} | |||
@@ -422,34 +443,6 @@ int Window::getMods() { | |||
return mods; | |||
} | |||
math::Vec Window::getWindowSize() { | |||
int width, height; | |||
glfwGetWindowSize(win, &width, &height); | |||
return math::Vec(width, height); | |||
} | |||
void Window::setWindowSize(math::Vec size) { | |||
int width = size.x; | |||
int height = size.y; | |||
glfwSetWindowSize(win, width, height); | |||
} | |||
math::Vec Window::getWindowPos() { | |||
int x, y; | |||
glfwGetWindowPos(win, &x, &y); | |||
return math::Vec(x, y); | |||
} | |||
void Window::setWindowPos(math::Vec pos) { | |||
int x = pos.x; | |||
int y = pos.y; | |||
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); | |||