Add detection code for legacy1 mode for patch files. Initialize patch on launch if the last launch crashed after 15 seconds.tags/v0.6.0
@@ -1,7 +1,13 @@ | |||||
VERSION = 0.6.0dev | |||||
FLAGS += \ | FLAGS += \ | ||||
-Iinclude \ | -Iinclude \ | ||||
-Idep/include -Idep/lib/libzip/include | -Idep/include -Idep/lib/libzip/include | ||||
ifdef RELEASE | |||||
FLAGS += -DRELEASE=$(RELEASE) | |||||
endif | |||||
SOURCES = $(wildcard src/*.cpp src/*/*.cpp) \ | SOURCES = $(wildcard src/*.cpp src/*/*.cpp) \ | ||||
ext/nanovg/src/nanovg.c | ext/nanovg/src/nanovg.c | ||||
@@ -87,9 +93,6 @@ include compile.mk | |||||
dist: all | dist: all | ||||
ifndef VERSION | |||||
$(error VERSION must be defined when making distributables) | |||||
endif | |||||
rm -rf dist | rm -rf dist | ||||
$(MAKE) -C plugins/Fundamental dist | $(MAKE) -C plugins/Fundamental dist | ||||
@@ -70,13 +70,24 @@ struct Module { | |||||
/** Called when user explicitly deletes the module, not when Rack is closed or a new patch is loaded */ | /** Called when user explicitly deletes the module, not when Rack is closed or a new patch is loaded */ | ||||
virtual void onDelete() {} | virtual void onDelete() {} | ||||
/** Called when user clicks Initialize in the module context menu */ | /** Called when user clicks Initialize in the module context menu */ | ||||
virtual void onReset() {} | |||||
virtual void onReset() { | |||||
// Call deprecated method | |||||
reset(); | |||||
} | |||||
/** Called when user clicks Randomize in the module context menu */ | /** Called when user clicks Randomize in the module context menu */ | ||||
virtual void onRandomize() {} | |||||
virtual void onRandomize() { | |||||
// Call deprecated method | |||||
randomize(); | |||||
} | |||||
/** Override these to store extra internal data in the "data" property */ | /** Override these to store extra internal data in the "data" property */ | ||||
virtual json_t *toJson() { return NULL; } | virtual json_t *toJson() { return NULL; } | ||||
virtual void fromJson(json_t *root) {} | virtual void fromJson(json_t *root) {} | ||||
/** Deprecated */ | |||||
virtual void reset() {} | |||||
/** Deprecated */ | |||||
virtual void randomize() {} | |||||
}; | }; | ||||
struct Wire { | struct Wire { | ||||
@@ -10,4 +10,7 @@ void settingsSave(std::string filename); | |||||
void settingsLoad(std::string filename); | void settingsLoad(std::string filename); | ||||
extern bool skipAutosaveOnLaunch; | |||||
} // namespace rack | } // namespace rack |
@@ -83,11 +83,12 @@ float randomNormal(); | |||||
/** Converts a printf format string and optional arguments into a std::string */ | /** Converts a printf format string and optional arguments into a std::string */ | ||||
std::string stringf(const char *format, ...); | std::string stringf(const char *format, ...); | ||||
std::string tolower(std::string s); | |||||
std::string toupper(std::string s); | |||||
std::string lowercase(std::string s); | |||||
std::string uppercase(std::string s); | |||||
/** Truncates and adds "..." to a string, not exceeding `len` characters */ | /** Truncates and adds "..." to a string, not exceeding `len` characters */ | ||||
std::string ellipsize(std::string s, size_t len); | std::string ellipsize(std::string s, size_t len); | ||||
bool startsWith(std::string str, std::string prefix); | |||||
std::string extractDirectory(std::string path); | std::string extractDirectory(std::string path); | ||||
std::string extractFilename(std::string path); | std::string extractFilename(std::string path); | ||||
@@ -4,12 +4,7 @@ | |||||
namespace rack { | namespace rack { | ||||
std::string gApplicationName = "VCV Rack"; | std::string gApplicationName = "VCV Rack"; | ||||
std::string gApplicationVersion = | |||||
#ifdef VERSION | |||||
TOSTRING(VERSION); | |||||
#else | |||||
""; | |||||
#endif | |||||
std::string gApplicationVersion = TOSTRING(VERSION); | |||||
std::string gApiHost = "https://api.vcvrack.com"; | std::string gApiHost = "https://api.vcvrack.com"; | ||||
// std::string gApiHost = "http://localhost:8081"; | // std::string gApiHost = "http://localhost:8081"; | ||||
@@ -98,8 +98,8 @@ static bool isModelMatch(Model *model, std::string search) { | |||||
str += " "; | str += " "; | ||||
str += gTagNames[tag]; | str += gTagNames[tag]; | ||||
} | } | ||||
str = tolower(str); | |||||
search = tolower(search); | |||||
str = lowercase(str); | |||||
search = lowercase(search); | |||||
return (str.find(search) != std::string::npos); | return (str.find(search) != std::string::npos); | ||||
} | } | ||||
@@ -45,10 +45,10 @@ RackScene::RackScene() { | |||||
scrollWidget->box.pos.y = gToolbar->box.size.y; | scrollWidget->box.pos.y = gToolbar->box.size.y; | ||||
// Check for new version | // Check for new version | ||||
if (!gApplicationVersion.empty()) { | |||||
std::thread versionThread(checkVersion); | |||||
versionThread.detach(); | |||||
} | |||||
#if defined(RELEASE) | |||||
std::thread versionThread(checkVersion); | |||||
versionThread.detach(); | |||||
#endif | |||||
} | } | ||||
void RackScene::step() { | void RackScene::step() { | ||||
@@ -68,7 +68,7 @@ void RackScene::step() { | |||||
// Version popup message | // Version popup message | ||||
if (!newVersion.empty()) { | if (!newVersion.empty()) { | ||||
std::string versionMessage = stringf("Rack %s is available.\n\nYou have Rack %s.\n\nWould you like to download the new version on the website?", newVersion.c_str(), gApplicationVersion.c_str()); | |||||
std::string versionMessage = stringf("Rack v%s is available.\n\nYou have Rack v%s.\n\nWould you like to download the new version on the website?", newVersion.c_str(), gApplicationVersion.c_str()); | |||||
if (osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, versionMessage.c_str())) { | if (osdialog_message(OSDIALOG_INFO, OSDIALOG_YES_NO, versionMessage.c_str())) { | ||||
std::thread t(openBrowser, "https://vcvrack.com/"); | std::thread t(openBrowser, "https://vcvrack.com/"); | ||||
t.detach(); | t.detach(); | ||||
@@ -145,10 +145,8 @@ json_t *RackWidget::toJson() { | |||||
json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
// version | // version | ||||
if (!gApplicationVersion.empty()) { | |||||
json_t *versionJ = json_string(gApplicationVersion.c_str()); | |||||
json_object_set_new(rootJ, "version", versionJ); | |||||
} | |||||
json_t *versionJ = json_string(gApplicationVersion.c_str()); | |||||
json_object_set_new(rootJ, "version", versionJ); | |||||
// modules | // modules | ||||
json_t *modulesJ = json_array(); | json_t *modulesJ = json_array(); | ||||
@@ -210,11 +208,19 @@ void RackWidget::fromJson(json_t *rootJ) { | |||||
std::string message; | std::string message; | ||||
// version | // version | ||||
std::string version; | |||||
json_t *versionJ = json_object_get(rootJ, "version"); | json_t *versionJ = json_object_get(rootJ, "version"); | ||||
if (versionJ) { | if (versionJ) { | ||||
std::string version = json_string_value(versionJ); | |||||
version = json_string_value(versionJ); | |||||
if (!version.empty() && gApplicationVersion != version) | if (!version.empty() && gApplicationVersion != version) | ||||
message += stringf("This patch was created with Rack %s. Saving it will convert it to a Rack %s patch.\n\n", version.c_str(), gApplicationVersion.empty() ? "dev" : gApplicationVersion.c_str()); | |||||
message += stringf("This patch was created with Rack %s. Saving it will convert it to a Rack %s patch.\n\n", version.c_str(), gApplicationVersion.c_str()); | |||||
} | |||||
// Detect old patches with ModuleWidget::params/inputs/outputs indices. | |||||
// (We now use Module::params/inputs/outputs indices.) | |||||
bool legacy1 = (startsWith(version, "0.3.") || startsWith(version, "0.4.") || startsWith(version, "0.5.") || version == "" || version == "dev"); | |||||
if (legacy1) { | |||||
info("Converting patch using legacy1 loader"); | |||||
} | } | ||||
// modules | // modules | ||||
@@ -178,7 +178,7 @@ Toolbar::Toolbar() { | |||||
xPos += margin; | xPos += margin; | ||||
*/ | */ | ||||
#ifdef VERSION | |||||
#if defined(RELEASE) | |||||
{ | { | ||||
Widget *pluginManager = new PluginManagerWidget(); | Widget *pluginManager = new PluginManagerWidget(); | ||||
pluginManager->box.pos = Vec(xPos, margin); | pluginManager->box.pos = Vec(xPos, margin); | ||||
@@ -26,7 +26,7 @@ namespace rack { | |||||
std::string assetGlobal(std::string filename) { | std::string assetGlobal(std::string filename) { | ||||
std::string dir; | std::string dir; | ||||
#ifdef VERSION | |||||
#if defined(RELEASE) | |||||
#if ARCH_MAC | #if ARCH_MAC | ||||
CFBundleRef bundle = CFBundleGetMainBundle(); | CFBundleRef bundle = CFBundleGetMainBundle(); | ||||
assert(bundle); | assert(bundle); | ||||
@@ -45,16 +45,16 @@ std::string assetGlobal(std::string filename) { | |||||
// TODO For now, users should launch Rack from their terminal in the global directory | // TODO For now, users should launch Rack from their terminal in the global directory | ||||
dir = "."; | dir = "."; | ||||
#endif | #endif | ||||
#else // VERSION | |||||
#else // RELEASE | |||||
dir = "."; | dir = "."; | ||||
#endif // VERSION | |||||
#endif // RELEASE | |||||
return dir + "/" + filename; | return dir + "/" + filename; | ||||
} | } | ||||
std::string assetLocal(std::string filename) { | std::string assetLocal(std::string filename) { | ||||
std::string dir; | std::string dir; | ||||
#ifdef VERSION | |||||
#if defined(RELEASE) | |||||
#if ARCH_MAC | #if ARCH_MAC | ||||
// Get home directory | // Get home directory | ||||
struct passwd *pw = getpwuid(getuid()); | struct passwd *pw = getpwuid(getuid()); | ||||
@@ -83,9 +83,9 @@ std::string assetLocal(std::string filename) { | |||||
dir += "/.Rack"; | dir += "/.Rack"; | ||||
mkdir(dir.c_str(), 0755); | mkdir(dir.c_str(), 0755); | ||||
#endif | #endif | ||||
#else // VERSION | |||||
#else // RELEASE | |||||
dir = "."; | dir = "."; | ||||
#endif // VERSION | |||||
#endif // RELEASE | |||||
return dir + "/" + filename; | return dir + "/" + filename; | ||||
} | } | ||||
@@ -2,7 +2,7 @@ | |||||
#include <list> | #include <list> | ||||
#include <algorithm> | #include <algorithm> | ||||
#include "core.hpp" | #include "core.hpp" | ||||
#include "MidiIO.hpp" | |||||
#include "midi.hpp" | |||||
#include "dsp/digital.hpp" | #include "dsp/digital.hpp" | ||||
@@ -16,7 +16,7 @@ struct MidiValue { | |||||
bool changed = false; // Value has been changed by midi message (only if it is in sync!) | bool changed = false; // Value has been changed by midi message (only if it is in sync!) | ||||
}; | }; | ||||
struct MIDIToCVInterface : MidiIO, Module { | |||||
struct MIDIToCVInterface : Module { | |||||
enum ParamIds { | enum ParamIds { | ||||
RESET_PARAM, | RESET_PARAM, | ||||
NUM_PARAMS | NUM_PARAMS | ||||
@@ -49,7 +49,7 @@ struct MIDIToCVInterface : MidiIO, Module { | |||||
SchmittTrigger resetTrigger; | SchmittTrigger resetTrigger; | ||||
MIDIToCVInterface() : MidiIO(), Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
MIDIToCVInterface() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) { | |||||
pitchWheel.val = 64; | pitchWheel.val = 64; | ||||
pitchWheel.tSmooth.set(0, 0); | pitchWheel.tSmooth.set(0, 0); | ||||
} | } | ||||
@@ -253,8 +253,7 @@ MidiToCVWidget::MidiToCVWidget() { | |||||
} | } | ||||
addParam(createParam<LEDButton>(Vec(7 * 15, labelHeight), module, MIDIToCVInterface::RESET_PARAM, 0.0, 1.0, 0.0)); | addParam(createParam<LEDButton>(Vec(7 * 15, labelHeight), module, MIDIToCVInterface::RESET_PARAM, 0.0, 1.0, 0.0)); | ||||
addChild(createLight<SmallLight<RedLight>>(Vec(7 * 15 + 5, labelHeight + 5), module, | |||||
MIDIToCVInterface::RESET_LIGHT)); | |||||
addChild(createLight<SmallLight<RedLight>>(Vec(7 * 15 + 5, labelHeight + 5), module, MIDIToCVInterface::RESET_LIGHT)); | |||||
{ | { | ||||
Label *label = new Label(); | Label *label = new Label(); | ||||
label->box.pos = Vec(margin, yPos); | label->box.pos = Vec(margin, yPos); | ||||
@@ -285,8 +284,7 @@ MidiToCVWidget::MidiToCVWidget() { | |||||
yPos += channelChoice->box.size.y + margin + 15; | yPos += channelChoice->box.size.y + margin + 15; | ||||
} | } | ||||
std::string labels[MIDIToCVInterface::NUM_OUTPUTS] = {"1V/oct", "Gate", "Velocity", "Mod Wheel", "Pitch Wheel", | |||||
"Aftertouch"}; | |||||
std::string labels[MIDIToCVInterface::NUM_OUTPUTS] = {"1V/oct", "Gate", "Velocity", "Mod Wheel", "Pitch Wheel", "Aftertouch"}; | |||||
for (int i = 0; i < MIDIToCVInterface::NUM_OUTPUTS; i++) { | for (int i = 0; i < MIDIToCVInterface::NUM_OUTPUTS; i++) { | ||||
Label *label = new Label(); | Label *label = new Label(); | ||||
@@ -299,9 +297,4 @@ MidiToCVWidget::MidiToCVWidget() { | |||||
yPos += yGap + margin; | yPos += yGap + margin; | ||||
} | } | ||||
} | } | ||||
void MidiToCVWidget::step() { | |||||
ModuleWidget::step(); | |||||
} | |||||
#endif | #endif |
@@ -8,8 +8,8 @@ void init(rack::Plugin *p) { | |||||
#endif | #endif | ||||
p->addModel(createModel<AudioInterfaceWidget>("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); | p->addModel(createModel<AudioInterfaceWidget>("Core", "AudioInterface", "Audio Interface", EXTERNAL_TAG)); | ||||
// p->addModel(createModel<MidiToCVWidget>("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
// p->addModel(createModel<MidiToCVWidget>("Core", "MIDIToCVInterface", "MIDI-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | |||||
// p->addModel(createModel<MIDICCToCVWidget>("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | // p->addModel(createModel<MIDICCToCVWidget>("Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | ||||
// p->addModel(createModel<MIDIClockToCVWidget>("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); | // p->addModel(createModel<MIDIClockToCVWidget>("Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface", MIDI_TAG, EXTERNAL_TAG, CLOCK_TAG)); | ||||
// p->addModel(createModel<MIDITriggerToCVWidget>("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | // p->addModel(createModel<MIDITriggerToCVWidget>("Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface", MIDI_TAG, EXTERNAL_TAG)); | ||||
@@ -14,29 +14,27 @@ struct AudioInterfaceWidget : ModuleWidget { | |||||
struct MidiToCVWidget : ModuleWidget { | struct MidiToCVWidget : ModuleWidget { | ||||
MidiToCVWidget(); | MidiToCVWidget(); | ||||
void step() override; | |||||
}; | }; | ||||
struct MIDICCToCVWidget : ModuleWidget { | |||||
MIDICCToCVWidget(); | |||||
void step() override; | |||||
}; | |||||
struct MIDIClockToCVWidget : ModuleWidget { | |||||
MIDIClockToCVWidget(); | |||||
void step() override; | |||||
}; | |||||
// struct MIDICCToCVWidget : ModuleWidget { | |||||
// MIDICCToCVWidget(); | |||||
// void step() override; | |||||
// }; | |||||
struct MIDITriggerToCVWidget : ModuleWidget { | |||||
MIDITriggerToCVWidget(); | |||||
void step() override; | |||||
}; | |||||
// struct MIDIClockToCVWidget : ModuleWidget { | |||||
// MIDIClockToCVWidget(); | |||||
// void step() override; | |||||
// }; | |||||
struct QuadMidiToCVWidget : ModuleWidget { | |||||
QuadMidiToCVWidget(); | |||||
void step() override; | |||||
}; | |||||
// struct MIDITriggerToCVWidget : ModuleWidget { | |||||
// MIDITriggerToCVWidget(); | |||||
// void step() override; | |||||
// }; | |||||
// struct QuadMidiToCVWidget : ModuleWidget { | |||||
// QuadMidiToCVWidget(); | |||||
// void step() override; | |||||
// }; | |||||
struct BridgeWidget : ModuleWidget { | struct BridgeWidget : ModuleWidget { | ||||
BridgeWidget(); | BridgeWidget(); | ||||
@@ -432,10 +432,7 @@ void guiRun() { | |||||
mouseButtonStickyPop(); | mouseButtonStickyPop(); | ||||
// Set window title | // Set window title | ||||
std::string windowTitle = gApplicationName; | |||||
if (!gApplicationVersion.empty()) { | |||||
windowTitle += " v" + gApplicationVersion; | |||||
} | |||||
std::string windowTitle = gApplicationName + " v" + gApplicationVersion; | |||||
if (!gRackWidget->lastPath.empty()) { | if (!gRackWidget->lastPath.empty()) { | ||||
windowTitle += " - "; | windowTitle += " - "; | ||||
windowTitle += extractFilename(gRackWidget->lastPath); | windowTitle += extractFilename(gRackWidget->lastPath); | ||||
@@ -12,14 +12,12 @@ using namespace rack; | |||||
int main(int argc, char* argv[]) { | int main(int argc, char* argv[]) { | ||||
randomSeedTime(); | randomSeedTime(); | ||||
#ifdef VERSION | |||||
#ifdef RELEASE | |||||
std::string logFilename = assetLocal("log.txt"); | std::string logFilename = assetLocal("log.txt"); | ||||
gLogFile = fopen(logFilename.c_str(), "w"); | gLogFile = fopen(logFilename.c_str(), "w"); | ||||
#endif | #endif | ||||
if (!gApplicationVersion.empty()) { | |||||
info("Rack v%s", gApplicationVersion.c_str()); | |||||
} | |||||
info("Rack v%s", gApplicationVersion.c_str()); | |||||
{ | { | ||||
char *cwd = getcwd(NULL, 0); | char *cwd = getcwd(NULL, 0); | ||||
@@ -35,21 +33,28 @@ int main(int argc, char* argv[]) { | |||||
engineInit(); | engineInit(); | ||||
guiInit(); | guiInit(); | ||||
sceneInit(); | sceneInit(); | ||||
gRackWidget->loadPatch(assetLocal("autosave.vcv")); | |||||
settingsLoad(assetLocal("settings.json")); | settingsLoad(assetLocal("settings.json")); | ||||
// 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 = skipAutosaveOnLaunch; | |||||
skipAutosaveOnLaunch = true; | |||||
settingsSave(assetLocal("settings.json")); | |||||
skipAutosaveOnLaunch = false; | |||||
if (!oldSkipAutosaveOnLaunch) | |||||
gRackWidget->loadPatch(assetLocal("autosave.vcv")); | |||||
engineStart(); | engineStart(); | ||||
guiRun(); | guiRun(); | ||||
engineStop(); | engineStop(); | ||||
settingsSave(assetLocal("settings.json")); | |||||
gRackWidget->savePatch(assetLocal("autosave.vcv")); | gRackWidget->savePatch(assetLocal("autosave.vcv")); | ||||
settingsSave(assetLocal("settings.json")); | |||||
sceneDestroy(); | sceneDestroy(); | ||||
guiDestroy(); | guiDestroy(); | ||||
engineDestroy(); | engineDestroy(); | ||||
pluginDestroy(); | pluginDestroy(); | ||||
#ifdef VERSION | |||||
#ifdef RELEASE | |||||
fclose(gLogFile); | fclose(gLogFile); | ||||
#endif | #endif | ||||
@@ -9,6 +9,9 @@ | |||||
namespace rack { | namespace rack { | ||||
bool skipAutosaveOnLaunch = false; | |||||
static json_t *settingsToJson() { | static json_t *settingsToJson() { | ||||
// root | // root | ||||
json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
@@ -56,6 +59,11 @@ static json_t *settingsToJson() { | |||||
json_t *lastPathJ = json_string(gRackWidget->lastPath.c_str()); | json_t *lastPathJ = json_string(gRackWidget->lastPath.c_str()); | ||||
json_object_set_new(rootJ, "lastPath", lastPathJ); | json_object_set_new(rootJ, "lastPath", lastPathJ); | ||||
// skipAutosaveOnLaunch | |||||
if (skipAutosaveOnLaunch) { | |||||
json_object_set_new(rootJ, "skipAutosaveOnLaunch", json_true()); | |||||
} | |||||
return rootJ; | return rootJ; | ||||
} | } | ||||
@@ -114,22 +122,25 @@ static void settingsFromJson(json_t *rootJ) { | |||||
json_t *lastPathJ = json_object_get(rootJ, "lastPath"); | json_t *lastPathJ = json_object_get(rootJ, "lastPath"); | ||||
if (lastPathJ) | if (lastPathJ) | ||||
gRackWidget->lastPath = json_string_value(lastPathJ); | gRackWidget->lastPath = json_string_value(lastPathJ); | ||||
json_t *skipAutosaveOnLaunchJ = json_object_get(rootJ, "skipAutosaveOnLaunch"); | |||||
if (skipAutosaveOnLaunchJ) | |||||
skipAutosaveOnLaunch = json_boolean_value(skipAutosaveOnLaunchJ); | |||||
} | } | ||||
void settingsSave(std::string filename) { | void settingsSave(std::string filename) { | ||||
info("Saving settings %s", filename.c_str()); | info("Saving settings %s", filename.c_str()); | ||||
FILE *file = fopen(filename.c_str(), "w"); | |||||
if (!file) | |||||
return; | |||||
json_t *rootJ = settingsToJson(); | json_t *rootJ = settingsToJson(); | ||||
if (rootJ) { | if (rootJ) { | ||||
FILE *file = fopen(filename.c_str(), "w"); | |||||
if (!file) | |||||
return; | |||||
json_dumpf(rootJ, file, JSON_INDENT(2)); | json_dumpf(rootJ, file, JSON_INDENT(2)); | ||||
json_decref(rootJ); | json_decref(rootJ); | ||||
fclose(file); | |||||
} | } | ||||
fclose(file); | |||||
} | } | ||||
void settingsLoad(std::string filename) { | void settingsLoad(std::string filename) { | ||||
@@ -99,12 +99,12 @@ std::string stringf(const char *format, ...) { | |||||
return s; | return s; | ||||
} | } | ||||
std::string tolower(std::string s) { | |||||
std::string lowercase(std::string s) { | |||||
std::transform(s.begin(), s.end(), s.begin(), ::tolower); | std::transform(s.begin(), s.end(), s.begin(), ::tolower); | ||||
return s; | return s; | ||||
} | } | ||||
std::string toupper(std::string s) { | |||||
std::string uppercase(std::string s) { | |||||
std::transform(s.begin(), s.end(), s.begin(), ::toupper); | std::transform(s.begin(), s.end(), s.begin(), ::toupper); | ||||
return s; | return s; | ||||
} | } | ||||
@@ -116,6 +116,10 @@ std::string ellipsize(std::string s, size_t len) { | |||||
return s.substr(0, len - 3) + "..."; | return s.substr(0, len - 3) + "..."; | ||||
} | } | ||||
bool startsWith(std::string str, std::string prefix) { | |||||
return str.substr(0, prefix.size()) == prefix; | |||||
} | |||||
std::string extractDirectory(std::string path) { | std::string extractDirectory(std::string path) { | ||||
char *pathDup = strdup(path.c_str()); | char *pathDup = strdup(path.c_str()); | ||||
std::string directory = dirname(pathDup); | std::string directory = dirname(pathDup); | ||||