@@ -43,7 +43,18 @@ namespace widget { | |||||
struct Widget; | struct Widget; | ||||
/** Returns the name of a GLFW key macro. | |||||
Printable keys return the key string such as "Q", "=", "\t", etc. | |||||
Letters are capitalized. | |||||
Does not remap keys based on keyboard layout, so GLFW_KEY_Q always returns "Q". | |||||
GLFW_KEY_SPACE returns "Space" translated to the current language. | |||||
Non-printable characters return the name of the key in the current language. | |||||
Key 0 returns "". | |||||
*/ | |||||
std::string getKeyName(int key); | std::string getKeyName(int key); | ||||
/** Returns the name of a key command/chord/combo. | |||||
For example, getKeyCommandName(GLFW_KEY_Q, GLFW_MOD_CONTROL) == "Ctrl+Q" translated to the current language. | |||||
*/ | |||||
std::string getKeyCommandName(int key, int mods = 0); | std::string getKeyCommandName(int key, int mods = 0); | ||||
@@ -82,7 +82,7 @@ static ModuleWidget* chooseModel(plugin::Model* model) { | |||||
mi.lastAdded = system::getUnixTime(); | mi.lastAdded = system::getUnixTime(); | ||||
history::ComplexAction* h = new history::ComplexAction; | history::ComplexAction* h = new history::ComplexAction; | ||||
h->name = "add module"; | |||||
h->name = string::translate("Browser.history.addModule"); | |||||
// Create Module and ModuleWidget | // Create Module and ModuleWidget | ||||
INFO("Creating module %s", model->getFullName().c_str()); | INFO("Creating module %s", model->getFullName().c_str()); | ||||
@@ -306,7 +306,8 @@ struct ModelBox : widget::OpaqueWidget { | |||||
text += "\n" + model->description; | text += "\n" + model->description; | ||||
} | } | ||||
// Tags | // Tags | ||||
text += "\n\nTags: "; | |||||
text += "\n\n"; | |||||
text += string::translate("Browser.tooltipTags"); | |||||
std::vector<std::string> tags; | std::vector<std::string> tags; | ||||
for (int tagId : model->tagIds) { | for (int tagId : model->tagIds) { | ||||
tags.push_back(tag::getTag(tagId)); | tags.push_back(tag::getTag(tagId)); | ||||
@@ -411,13 +412,15 @@ struct TagButton : ui::ChoiceButton { | |||||
}; | }; | ||||
static const std::string sortNames[] = { | |||||
"Last updated", | |||||
"Last used", | |||||
"Most used", | |||||
"Brand", | |||||
"Module name", | |||||
"Random", | |||||
static std::vector<std::string> getSortNames() { | |||||
return { | |||||
string::translate("Browser.sort.lastUpdated"), | |||||
string::translate("Browser.sort.lastUsed"), | |||||
string::translate("Browser.sort.mostUsed"), | |||||
string::translate("Browser.sort.brand"), | |||||
string::translate("Browser.sort.moduleName"), | |||||
string::translate("Browser.sort.random"), | |||||
}; | |||||
}; | }; | ||||
@@ -427,8 +430,8 @@ struct SortButton : ui::ChoiceButton { | |||||
void onAction(const ActionEvent& e) override; | void onAction(const ActionEvent& e) override; | ||||
void step() override { | void step() override { | ||||
text = "Sort: "; | |||||
text += sortNames[settings::browserSort]; | |||||
text = string::translate("Browser.sort"); | |||||
text += getSortNames()[settings::browserSort]; | |||||
ChoiceButton::step(); | ChoiceButton::step(); | ||||
} | } | ||||
}; | }; | ||||
@@ -440,7 +443,7 @@ struct ZoomButton : ui::ChoiceButton { | |||||
void onAction(const ActionEvent& e) override; | void onAction(const ActionEvent& e) override; | ||||
void step() override { | void step() override { | ||||
text = "Zoom: "; | |||||
text = string::translate("Browser.zoom"); | |||||
text += string::f("%.0f%%", std::pow(2.f, settings::browserZoom) * 100.f); | text += string::f("%.0f%%", std::pow(2.f, settings::browserZoom) * 100.f); | ||||
ChoiceButton::step(); | ChoiceButton::step(); | ||||
} | } | ||||
@@ -492,7 +495,7 @@ struct Browser : widget::OpaqueWidget { | |||||
searchField = new BrowserSearchField; | searchField = new BrowserSearchField; | ||||
searchField->box.size.x = 150; | searchField->box.size.x = 150; | ||||
searchField->placeholder = "Search modules"; | |||||
searchField->placeholder = string::translate("Browser.searchModules"); | |||||
searchField->browser = this; | searchField->browser = this; | ||||
headerLayout->addChild(searchField); | headerLayout->addChild(searchField); | ||||
@@ -511,13 +514,13 @@ struct Browser : widget::OpaqueWidget { | |||||
favoriteButton = new ui::OptionButton; | favoriteButton = new ui::OptionButton; | ||||
favoriteButton->quantity = favoriteQuantity; | favoriteButton->quantity = favoriteQuantity; | ||||
favoriteButton->text = "Favorites"; | |||||
favoriteButton->text = string::translate("Browser.favorites"); | |||||
favoriteButton->box.size.x = 70; | favoriteButton->box.size.x = 70; | ||||
headerLayout->addChild(favoriteButton); | headerLayout->addChild(favoriteButton); | ||||
clearButton = new ClearButton; | clearButton = new ClearButton; | ||||
clearButton->box.size.x = 100; | clearButton->box.size.x = 100; | ||||
clearButton->text = "Reset filters"; | |||||
clearButton->text = string::translate("Browser.resetFilters"); | |||||
clearButton->browser = this; | clearButton->browser = this; | ||||
headerLayout->addChild(clearButton); | headerLayout->addChild(clearButton); | ||||
@@ -537,7 +540,7 @@ struct Browser : widget::OpaqueWidget { | |||||
UrlButton* libraryButton = new UrlButton; | UrlButton* libraryButton = new UrlButton; | ||||
libraryButton->box.size.x = 150; | libraryButton->box.size.x = 150; | ||||
libraryButton->text = "Browse VCV Library"; | |||||
libraryButton->text = string::translate("Browser.browseLibrary"); | |||||
libraryButton->url = "https://library.vcvrack.com/"; | libraryButton->url = "https://library.vcvrack.com/"; | ||||
headerLayout->addChild(libraryButton); | headerLayout->addChild(libraryButton); | ||||
@@ -776,7 +779,7 @@ struct Browser : widget::OpaqueWidget { | |||||
if (w->isVisible()) | if (w->isVisible()) | ||||
count++; | count++; | ||||
} | } | ||||
countLabel->text = string::f("%d %s", count, (count == 1) ? "module" : "modules"); | |||||
countLabel->text = (count == 1) ? string::translate("Browser.modulesOne") : string::f(string::translate("Browser.modulesMany"), count); | |||||
} | } | ||||
void clear() { | void clear() { | ||||
@@ -892,7 +895,7 @@ inline void BrandButton::onAction(const ActionEvent& e) { | |||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
BrandItem* noneItem = new BrandItem; | BrandItem* noneItem = new BrandItem; | ||||
noneItem->text = "All brands"; | |||||
noneItem->text = string::translate("Browser.allBrands"); | |||||
noneItem->brand = ""; | noneItem->brand = ""; | ||||
noneItem->browser = browser; | noneItem->browser = browser; | ||||
menu->addChild(noneItem); | menu->addChild(noneItem); | ||||
@@ -916,7 +919,7 @@ inline void BrandButton::onAction(const ActionEvent& e) { | |||||
} | } | ||||
inline void BrandButton::step() { | inline void BrandButton::step() { | ||||
text = "Brand"; | |||||
text = string::translate("Browser.brand"); | |||||
if (!browser->brand.empty()) { | if (!browser->brand.empty()) { | ||||
text += ": "; | text += ": "; | ||||
text += browser->brand; | text += browser->brand; | ||||
@@ -975,12 +978,12 @@ inline void TagButton::onAction(const ActionEvent& e) { | |||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
TagItem* noneItem = new TagItem; | TagItem* noneItem = new TagItem; | ||||
noneItem->text = "All tags"; | |||||
noneItem->text = string::translate("Browser.allTags"); | |||||
noneItem->tagId = -1; | noneItem->tagId = -1; | ||||
noneItem->browser = browser; | noneItem->browser = browser; | ||||
menu->addChild(noneItem); | menu->addChild(noneItem); | ||||
menu->addChild(createMenuLabel(RACK_MOD_CTRL_NAME "+click to select multiple")); | |||||
menu->addChild(createMenuLabel(widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("Browser.tagsSelectMultiple"))); | |||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
for (int tagId = 0; tagId < (int) tag::tagAliases.size(); tagId++) { | for (int tagId = 0; tagId < (int) tag::tagAliases.size(); tagId++) { | ||||
@@ -994,7 +997,7 @@ inline void TagButton::onAction(const ActionEvent& e) { | |||||
} | } | ||||
inline void TagButton::step() { | inline void TagButton::step() { | ||||
text = "Tags"; | |||||
text = string::translate("Browser.tags"); | |||||
if (!browser->tagIds.empty()) { | if (!browser->tagIds.empty()) { | ||||
text += ": "; | text += ": "; | ||||
bool firstTag = true; | bool firstTag = true; | ||||
@@ -1015,7 +1018,7 @@ inline void SortButton::onAction(const ActionEvent& e) { | |||||
menu->box.size.x = box.size.x; | menu->box.size.x = box.size.x; | ||||
for (int sortId = 0; sortId <= settings::BROWSER_SORT_RANDOM; sortId++) { | for (int sortId = 0; sortId <= settings::BROWSER_SORT_RANDOM; sortId++) { | ||||
menu->addChild(createCheckMenuItem(sortNames[sortId], "", | |||||
menu->addChild(createCheckMenuItem(getSortNames()[sortId], "", | |||||
[=]() {return settings::browserSort == sortId;}, | [=]() {return settings::browserSort == sortId;}, | ||||
[=]() { | [=]() { | ||||
settings::browserSort = (settings::BrowserSort) sortId; | settings::browserSort = (settings::BrowserSort) sortId; | ||||
@@ -1094,7 +1094,7 @@ struct InfoLabel : ui::Label { | |||||
double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0; | double fps = std::isfinite(frameDurationAvg) ? 1.0 / frameDurationAvg : 0.0; | ||||
double meterAverage = APP->engine->getMeterAverage(); | double meterAverage = APP->engine->getMeterAverage(); | ||||
double meterMax = APP->engine->getMeterMax(); | double meterMax = APP->engine->getMeterMax(); | ||||
text += string::f("%.1f fps %.1f%% avg %.1f%% max", fps, meterAverage * 100, meterMax * 100); | |||||
text += string::f(string::translate("MenuBar.infoLabel"), fps, meterAverage * 100, meterMax * 100); | |||||
text += " "; | text += " "; | ||||
} | } | ||||
@@ -76,7 +76,7 @@ struct ParamValueItem : ui::MenuItem { | |||||
if (oldValue != newValue) { | if (oldValue != newValue) { | ||||
// Push ParamChange history action | // Push ParamChange history action | ||||
history::ParamChange* h = new history::ParamChange; | history::ParamChange* h = new history::ParamChange; | ||||
h->name = "set parameter"; | |||||
h->name = string::translate("ParamWidget.history.setParam"); | |||||
h->moduleId = paramWidget->module->id; | h->moduleId = paramWidget->module->id; | ||||
h->paramId = paramWidget->paramId; | h->paramId = paramWidget->paramId; | ||||
h->oldValue = oldValue; | h->oldValue = oldValue; | ||||
@@ -274,20 +274,20 @@ void ParamWidget::createContextMenu() { | |||||
// Initialize | // Initialize | ||||
if (pq && pq->resetEnabled && pq->isBounded()) { | if (pq && pq->resetEnabled && pq->isBounded()) { | ||||
menu->addChild(createMenuItem("Initialize", switchQuantity ? "" : "Double-click", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("ParamWidget.initialize"), switchQuantity ? "" : string::translate("ParamWidget.doubleClick"), [=]() { | |||||
this->resetAction(); | this->resetAction(); | ||||
})); | })); | ||||
} | } | ||||
// Fine | // Fine | ||||
if (!switchQuantity) { | if (!switchQuantity) { | ||||
menu->addChild(createMenuItem("Fine adjust", RACK_MOD_CTRL_NAME "+drag", NULL, true)); | |||||
menu->addChild(createMenuItem(string::translate("ParamWidget.fine"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("ParamWidget.fineDrag"), NULL, true)); | |||||
} | } | ||||
// Unmap | // Unmap | ||||
engine::ParamHandle* paramHandle = module ? APP->engine->getParamHandle(module->id, paramId) : NULL; | engine::ParamHandle* paramHandle = module ? APP->engine->getParamHandle(module->id, paramId) : NULL; | ||||
if (paramHandle) { | if (paramHandle) { | ||||
menu->addChild(createMenuItem("Unmap", paramHandle->text, [=]() { | |||||
menu->addChild(createMenuItem(string::translate("ParamWidget.unmap"), paramHandle->text, [=]() { | |||||
APP->engine->updateParamHandle(paramHandle, -1, 0); | APP->engine->updateParamHandle(paramHandle, -1, 0); | ||||
})); | })); | ||||
} | } | ||||
@@ -306,7 +306,7 @@ void ParamWidget::resetAction() { | |||||
if (oldValue != newValue) { | if (oldValue != newValue) { | ||||
// Push ParamChange history action | // Push ParamChange history action | ||||
history::ParamChange* h = new history::ParamChange; | history::ParamChange* h = new history::ParamChange; | ||||
h->name = "reset parameter"; | |||||
h->name = string::translate("ParamWidget.history.reset"); | |||||
h->moduleId = module->id; | h->moduleId = module->id; | ||||
h->paramId = paramId; | h->paramId = paramId; | ||||
h->oldValue = oldValue; | h->oldValue = oldValue; | ||||
@@ -61,14 +61,14 @@ struct PortTooltip : ui::Tooltip { | |||||
continue; | continue; | ||||
text += "\n"; | text += "\n"; | ||||
if (portWidget->type == engine::Port::INPUT) | if (portWidget->type == engine::Port::INPUT) | ||||
text += "From "; | |||||
text += string::translate("PortWidget.from"); | |||||
else | else | ||||
text += "To "; | |||||
text += string::translate("PortWidget.to"); | |||||
text += otherPw->module->model->getFullName(); | text += otherPw->module->model->getFullName(); | ||||
text += ": "; | text += ": "; | ||||
text += otherPw->getPortInfo()->getName(); | text += otherPw->getPortInfo()->getName(); | ||||
text += " "; | text += " "; | ||||
text += (otherPw->type == engine::Port::INPUT) ? "input" : "output"; | |||||
text += (otherPw->type == engine::Port::INPUT) ? string::translate("PortWidget.input") : string::translate("PortWidget.output"); | |||||
} | } | ||||
} | } | ||||
Tooltip::step(); | Tooltip::step(); | ||||
@@ -140,11 +140,11 @@ struct PortCableItem : ui::ColorDotMenuItem { | |||||
ui::Menu* createChildMenu() override { | ui::Menu* createChildMenu() override { | ||||
ui::Menu* menu = new ui::Menu; | ui::Menu* menu = new ui::Menu; | ||||
// menu->addChild(createMenuLabel(string::f("ID: %ld", cw->cable->id))); | |||||
// menu->addChild(createMenuLabel(string::f(string::translate("PortWidget.cableId"), cw->cable->id))); | |||||
for (NVGcolor color : settings::cableColors) { | for (NVGcolor color : settings::cableColors) { | ||||
// Include extra leading spaces for the color circle | // Include extra leading spaces for the color circle | ||||
CableColorItem* item = createMenuItem<CableColorItem>("Set color"); | |||||
CableColorItem* item = createMenuItem<CableColorItem>(string::translate("PortWidget.setColor")); | |||||
item->disabled = color::isEqual(color, cw->color); | item->disabled = color::isEqual(color, cw->color); | ||||
item->cw = cw; | item->cw = cw; | ||||
item->color = color; | item->color = color; | ||||
@@ -286,7 +286,7 @@ void PortWidget::createContextMenu() { | |||||
std::vector<CableWidget*> cws = APP->scene->rack->getCompleteCablesOnPort(this); | std::vector<CableWidget*> cws = APP->scene->rack->getCompleteCablesOnPort(this); | ||||
CableWidget* topCw = cws.empty() ? NULL : cws.back(); | CableWidget* topCw = cws.empty() ? NULL : cws.back(); | ||||
menu->addChild(createMenuItem("Delete top cable", RACK_MOD_SHIFT_NAME "+click", | |||||
menu->addChild(createMenuItem(string::translate("PortWidget.deleteTopCable"), widget::getKeyCommandName(0, RACK_MOD_SHIFT) + string::translate("PortWidget.click"), | |||||
[=]() { | [=]() { | ||||
if (!weakThis) | if (!weakThis) | ||||
return; | return; | ||||
@@ -296,7 +296,7 @@ void PortWidget::createContextMenu() { | |||||
)); | )); | ||||
{ | { | ||||
PortCloneCableItem* item = createMenuItem<PortCloneCableItem>("Duplicate top cable", RACK_MOD_CTRL_NAME "+Shift+drag"); | |||||
PortCloneCableItem* item = createMenuItem<PortCloneCableItem>(string::translate("PortWidget.cloneTopCable"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("PortWidget.drag")); | |||||
item->disabled = !topCw; | item->disabled = !topCw; | ||||
item->pw = this; | item->pw = this; | ||||
item->cw = topCw; | item->cw = topCw; | ||||
@@ -304,7 +304,7 @@ void PortWidget::createContextMenu() { | |||||
} | } | ||||
{ | { | ||||
PortCreateCableItem* item = createMenuItem<PortCreateCableItem>("Create cable on top", RACK_MOD_CTRL_NAME "+drag"); | |||||
PortCreateCableItem* item = createMenuItem<PortCreateCableItem>(string::translate("PortWidget.createCableTop"), widget::getKeyCommandName(0, RACK_MOD_CTRL) + string::translate("PortWidget.drag")); | |||||
item->pw = this; | item->pw = this; | ||||
menu->addChild(item); | menu->addChild(item); | ||||
} | } | ||||
@@ -317,7 +317,7 @@ void PortWidget::createContextMenu() { | |||||
std::string label = get(settings::cableLabels, colorId); | std::string label = get(settings::cableLabels, colorId); | ||||
if (label == "") | if (label == "") | ||||
label = string::f("#%lld", (long long) (colorId + 1)); | label = string::f("#%lld", (long long) (colorId + 1)); | ||||
PortCreateCableColorItem* item = createMenuItem<PortCreateCableColorItem>("Create cable: " + label); | |||||
PortCreateCableColorItem* item = createMenuItem<PortCreateCableColorItem>(string::translate("PortWidget.createCable") + label); | |||||
item->pw = this; | item->pw = this; | ||||
item->color = color; | item->color = color; | ||||
item->colorId = colorId; | item->colorId = colorId; | ||||
@@ -326,7 +326,7 @@ void PortWidget::createContextMenu() { | |||||
if (!cws.empty()) { | if (!cws.empty()) { | ||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
menu->addChild(createMenuLabel("Click+drag to grab cable")); | |||||
menu->addChild(createMenuLabel(string::translate("PortWidget.clickDrag") + string::translate("PortWidget.grabCable"))); | |||||
// Cable items | // Cable items | ||||
for (auto it = cws.rbegin(); it != cws.rend(); it++) { | for (auto it = cws.rbegin(); it != cws.rend(); it++) { | ||||
@@ -342,7 +342,7 @@ void PortWidget::createContextMenu() { | |||||
} | } | ||||
if (cws.size() > 1) { | if (cws.size() > 1) { | ||||
PortAllCablesItem* item = createMenuItem<PortAllCablesItem>("All cables"); | |||||
PortAllCablesItem* item = createMenuItem<PortAllCablesItem>(string::translate("PortWidget.allCables")); | |||||
item->pw = this; | item->pw = this; | ||||
item->cws = cws; | item->cws = cws; | ||||
menu->addChild(item); | menu->addChild(item); | ||||
@@ -431,7 +431,7 @@ void PortWidget::onDragStart(const DragStartEvent& e) { | |||||
internal->history = NULL; | internal->history = NULL; | ||||
} | } | ||||
internal->history = new history::ComplexAction; | internal->history = new history::ComplexAction; | ||||
internal->history->name = "move cable"; | |||||
internal->history->name = string::translate("PortWidget.history.moveCable"); | |||||
std::vector<CableWidget*> cws; | std::vector<CableWidget*> cws; | ||||
int mods = APP->window->getMods(); | int mods = APP->window->getMods(); | ||||
@@ -106,16 +106,16 @@ std::string Model::getManualUrl() { | |||||
void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | ||||
// plugin | // plugin | ||||
menu->addChild(createMenuItem("Plugin: " + plugin->name, "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.plugin") + plugin->name, "", [=]() { | |||||
system::openBrowser(plugin->pluginUrl); | system::openBrowser(plugin->pluginUrl); | ||||
}, plugin->pluginUrl == "")); | }, plugin->pluginUrl == "")); | ||||
// version | // version | ||||
menu->addChild(createMenuLabel("Version: " + plugin->version)); | |||||
menu->addChild(createMenuLabel(string::translate("Model.version") + plugin->version)); | |||||
// author | // author | ||||
if (plugin->author != "") { | if (plugin->author != "") { | ||||
menu->addChild(createMenuItem("Author: " + plugin->author, "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.author") + plugin->author, "", [=]() { | |||||
system::openBrowser(plugin->authorUrl); | system::openBrowser(plugin->authorUrl); | ||||
}, plugin->authorUrl.empty())); | }, plugin->authorUrl.empty())); | ||||
} | } | ||||
@@ -123,17 +123,17 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | |||||
// license | // license | ||||
std::string license = plugin->license; | std::string license = plugin->license; | ||||
if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) { | if (string::startsWith(license, "https://") || string::startsWith(license, "http://")) { | ||||
menu->addChild(createMenuItem("License: Open in browser", "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.licenseBrowser"), "", [=]() { | |||||
system::openBrowser(license); | system::openBrowser(license); | ||||
})); | })); | ||||
} | } | ||||
else if (license != "") { | else if (license != "") { | ||||
menu->addChild(createMenuLabel("License: " + license)); | |||||
menu->addChild(createMenuLabel(string::translate("Model.license") + license)); | |||||
} | } | ||||
// tags | // tags | ||||
if (!tagIds.empty()) { | if (!tagIds.empty()) { | ||||
menu->addChild(createMenuLabel("Tags:")); | |||||
menu->addChild(createMenuLabel(string::translate("Model.tags"))); | |||||
for (int tagId : tagIds) { | for (int tagId : tagIds) { | ||||
menu->addChild(createMenuLabel("• " + tag::getTag(tagId))); | menu->addChild(createMenuLabel("• " + tag::getTag(tagId))); | ||||
} | } | ||||
@@ -142,13 +142,13 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | |||||
menu->addChild(new ui::MenuSeparator); | menu->addChild(new ui::MenuSeparator); | ||||
// VCV Library page | // VCV Library page | ||||
menu->addChild(createMenuItem("VCV Library page", "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.library"), "", [=]() { | |||||
system::openBrowser("https://library.vcvrack.com/" + plugin->slug + "/" + slug); | system::openBrowser("https://library.vcvrack.com/" + plugin->slug + "/" + slug); | ||||
})); | })); | ||||
// modularGridUrl | // modularGridUrl | ||||
if (modularGridUrl != "") { | if (modularGridUrl != "") { | ||||
menu->addChild(createMenuItem("ModularGrid page", "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.modularGrid"), "", [=]() { | |||||
system::openBrowser(modularGridUrl); | system::openBrowser(modularGridUrl); | ||||
})); | })); | ||||
} | } | ||||
@@ -156,42 +156,42 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | |||||
// manual | // manual | ||||
std::string manualUrl = getManualUrl(); | std::string manualUrl = getManualUrl(); | ||||
if (manualUrl != "") { | if (manualUrl != "") { | ||||
menu->addChild(createMenuItem("User manual", widget::getKeyCommandName(GLFW_KEY_F1, RACK_MOD_CTRL), [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.manual"), widget::getKeyCommandName(GLFW_KEY_F1, RACK_MOD_CTRL), [=]() { | |||||
system::openBrowser(manualUrl); | system::openBrowser(manualUrl); | ||||
})); | })); | ||||
} | } | ||||
// donate | // donate | ||||
if (plugin->donateUrl != "") { | if (plugin->donateUrl != "") { | ||||
menu->addChild(createMenuItem("Donate", "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.donate"), "", [=]() { | |||||
system::openBrowser(plugin->donateUrl); | system::openBrowser(plugin->donateUrl); | ||||
})); | })); | ||||
} | } | ||||
// source code | // source code | ||||
if (plugin->sourceUrl != "") { | if (plugin->sourceUrl != "") { | ||||
menu->addChild(createMenuItem("Source code", "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.source"), "", [=]() { | |||||
system::openBrowser(plugin->sourceUrl); | system::openBrowser(plugin->sourceUrl); | ||||
})); | })); | ||||
} | } | ||||
// changelog | // changelog | ||||
if (plugin->changelogUrl != "") { | if (plugin->changelogUrl != "") { | ||||
menu->addChild(createMenuItem("Changelog", "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.changelog"), "", [=]() { | |||||
system::openBrowser(plugin->changelogUrl); | system::openBrowser(plugin->changelogUrl); | ||||
})); | })); | ||||
} | } | ||||
// author email | // author email | ||||
if (plugin->authorEmail != "") { | if (plugin->authorEmail != "") { | ||||
menu->addChild(createMenuItem("Author email", "Copy to clipboard", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.authorEmail"), string::translate("Model.authorEmailCopy"), [=]() { | |||||
glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str()); | glfwSetClipboardString(APP->window->win, plugin->authorEmail.c_str()); | ||||
})); | })); | ||||
} | } | ||||
// plugin folder | // plugin folder | ||||
if (plugin->path != "") { | if (plugin->path != "") { | ||||
menu->addChild(createMenuItem("Open plugin folder", "", [=]() { | |||||
menu->addChild(createMenuItem(string::translate("Model.pluginDir"), "", [=]() { | |||||
system::openDirectory(plugin->path); | system::openDirectory(plugin->path); | ||||
})); | })); | ||||
} | } | ||||
@@ -200,7 +200,7 @@ void Model::appendContextMenu(ui::Menu* menu, bool inBrowser) { | |||||
std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; | std::string favoriteRightText = inBrowser ? (RACK_MOD_CTRL_NAME "+click") : ""; | ||||
if (isFavorite()) | if (isFavorite()) | ||||
favoriteRightText += " " CHECKMARK_STRING; | favoriteRightText += " " CHECKMARK_STRING; | ||||
menu->addChild(createMenuItem("Favorite", favoriteRightText, | |||||
menu->addChild(createMenuItem(string::translate("Model.favorite"), favoriteRightText, | |||||
[=]() { | [=]() { | ||||
setFavorite(!isFavorite()); | setFavorite(!isFavorite()); | ||||
} | } | ||||
@@ -3,6 +3,7 @@ | |||||
#include <context.hpp> | #include <context.hpp> | ||||
#include <window/Window.hpp> | #include <window/Window.hpp> | ||||
#include <system.hpp> | #include <system.hpp> | ||||
#include <string.hpp> | |||||
namespace rack { | namespace rack { | ||||
@@ -10,9 +11,12 @@ namespace widget { | |||||
std::string getKeyName(int key) { | std::string getKeyName(int key) { | ||||
if (key < 32) | |||||
return ""; | |||||
// glfwGetKeyName overrides | // glfwGetKeyName overrides | ||||
switch (key) { | switch (key) { | ||||
case GLFW_KEY_SPACE: return "Space"; | |||||
case GLFW_KEY_SPACE: return string::translate("key.space"); | |||||
} | } | ||||
// Printable characters | // Printable characters | ||||
@@ -22,21 +26,21 @@ std::string getKeyName(int key) { | |||||
// Unprintable keys with names | // Unprintable keys with names | ||||
switch (key) { | switch (key) { | ||||
case GLFW_KEY_ESCAPE: return "Escape"; | |||||
case GLFW_KEY_ENTER: return "Enter"; | |||||
case GLFW_KEY_TAB: return "Tab"; | |||||
case GLFW_KEY_BACKSPACE: return "Backspace"; | |||||
case GLFW_KEY_INSERT: return "Insert"; | |||||
case GLFW_KEY_DELETE: return "Delete"; | |||||
case GLFW_KEY_RIGHT: return "Right"; | |||||
case GLFW_KEY_LEFT: return "Left"; | |||||
case GLFW_KEY_DOWN: return "Down"; | |||||
case GLFW_KEY_UP: return "Up"; | |||||
case GLFW_KEY_PAGE_UP: return "Page Up"; | |||||
case GLFW_KEY_PAGE_DOWN: return "Page Down"; | |||||
case GLFW_KEY_HOME: return "Home"; | |||||
case GLFW_KEY_END: return "End"; | |||||
case GLFW_KEY_KP_ENTER: return "Enter"; | |||||
case GLFW_KEY_ESCAPE: return string::translate("key.escape"); | |||||
case GLFW_KEY_ENTER: return string::translate("key.enter"); | |||||
case GLFW_KEY_TAB: return string::translate("key.tab"); | |||||
case GLFW_KEY_BACKSPACE: return string::translate("key.backspace"); | |||||
case GLFW_KEY_INSERT: return string::translate("key.insert"); | |||||
case GLFW_KEY_DELETE: return string::translate("key.delete"); | |||||
case GLFW_KEY_RIGHT: return string::translate("key.right"); | |||||
case GLFW_KEY_LEFT: return string::translate("key.left"); | |||||
case GLFW_KEY_DOWN: return string::translate("key.down"); | |||||
case GLFW_KEY_UP: return string::translate("key.up"); | |||||
case GLFW_KEY_PAGE_UP: return string::translate("key.pageUp"); | |||||
case GLFW_KEY_PAGE_DOWN: return string::translate("key.pageDown"); | |||||
case GLFW_KEY_HOME: return string::translate("key.home"); | |||||
case GLFW_KEY_END: return string::translate("key.end"); | |||||
case GLFW_KEY_KP_ENTER: return string::translate("key.enter"); | |||||
} | } | ||||
if (GLFW_KEY_F1 <= key && key <= GLFW_KEY_F25) | if (GLFW_KEY_F1 <= key && key <= GLFW_KEY_F25) | ||||
@@ -49,13 +53,20 @@ std::string getKeyName(int key) { | |||||
std::string getKeyCommandName(int key, int mods) { | std::string getKeyCommandName(int key, int mods) { | ||||
std::string modsName; | std::string modsName; | ||||
if (mods & RACK_MOD_CTRL) { | if (mods & RACK_MOD_CTRL) { | ||||
modsName += RACK_MOD_CTRL_NAME "+"; | |||||
#if defined ARCH_MAC | |||||
modsName += "⌘"; | |||||
#else | |||||
modsName += string::translate("key.ctrl"); | |||||
#endif | |||||
modsName += "+"; | |||||
} | } | ||||
if (mods & GLFW_MOD_SHIFT) { | if (mods & GLFW_MOD_SHIFT) { | ||||
modsName += RACK_MOD_SHIFT_NAME "+"; | |||||
modsName += string::translate("key.shift"); | |||||
modsName += "+"; | |||||
} | } | ||||
if (mods & GLFW_MOD_ALT) { | if (mods & GLFW_MOD_ALT) { | ||||
modsName += RACK_MOD_ALT_NAME "+"; | |||||
modsName += string::translate("key.alt"); | |||||
modsName += "+"; | |||||
} | } | ||||
return modsName + getKeyName(key); | return modsName + getKeyName(key); | ||||
} | } | ||||
@@ -1,5 +1,25 @@ | |||||
{ | { | ||||
"language": "English", | "language": "English", | ||||
"translators": "", | |||||
"key.space": "Space", | |||||
"key.escape": "Escape", | |||||
"key.enter": "Enter", | |||||
"key.tab": "Tab", | |||||
"key.backspace": "Backspace", | |||||
"key.insert": "Insert", | |||||
"key.delete": "Delete", | |||||
"key.right": "Right", | |||||
"key.left": "Left", | |||||
"key.down": "Down", | |||||
"key.up": "Up", | |||||
"key.pageUp": "Page Up", | |||||
"key.pageDown": "Page Down", | |||||
"key.home": "Home", | |||||
"key.end": "End", | |||||
"key.ctrl": "Ctrl", | |||||
"key.shift": "Shift", | |||||
"key.alt": "Alt", | |||||
"MenuBar.infoLabel": "%.1f fps %.1f%% avg %.1f%% max", | |||||
"MenuBar.file": "File", | "MenuBar.file": "File", | ||||
"MenuBar.file.new": "New", | "MenuBar.file.new": "New", | ||||
"MenuBar.file.open": "Open", | "MenuBar.file.open": "Open", | ||||
@@ -146,5 +166,65 @@ | |||||
"RackWidget.duplicate": "Duplicate", | "RackWidget.duplicate": "Duplicate", | ||||
"RackWidget.duplicateWithCables": "with cables", | "RackWidget.duplicateWithCables": "with cables", | ||||
"RackWidget.delete": "Delete", | "RackWidget.delete": "Delete", | ||||
"RackWidget.history.clearCables": "clear cables" | |||||
"RackWidget.history.clearCables": "clear cables", | |||||
"Model.plugin": "Plugin: ", | |||||
"Model.version": "Version: ", | |||||
"Model.author": "Author: ", | |||||
"Model.licenseBrowser": "License: Open in browser", | |||||
"Model.license": "License: ", | |||||
"Model.tags": "Tags:", | |||||
"Model.library": "VCV Library page", | |||||
"Model.modularGrid": "ModularGrid page", | |||||
"Model.manual": "User manual", | |||||
"Model.donate": "Donate", | |||||
"Model.source": "Source code", | |||||
"Model.changelog": "Changelog", | |||||
"Model.authorEmail": "Author email", | |||||
"Model.authorEmailCopy": "Copy to clipboard", | |||||
"Model.pluginDir": "Open plugin folder", | |||||
"Model.favorite": "Favorite", | |||||
"Browser.history.addModule": "add module", | |||||
"Browser.tooltipTags": "Tags: ", | |||||
"Browser.sort.lastUpdated": "Last updated", | |||||
"Browser.sort.lastUsed": "Last used", | |||||
"Browser.sort.mostUsed": "Most used", | |||||
"Browser.sort.brand": "Brand", | |||||
"Browser.sort.moduleName": "Module name", | |||||
"Browser.sort.random": "Random", | |||||
"Browser.sort": "Sort: ", | |||||
"Browser.zoom": "Zoom: ", | |||||
"Browser.searchModules": "Search modules", | |||||
"Browser.favorites": "Favorites", | |||||
"Browser.resetFilters": "Reset filters", | |||||
"Browser.browseLibrary": "Browse VCV Library", | |||||
"Browser.modulesOne": "1 module", | |||||
"Browser.modulesMany": "%d modules", | |||||
"Browser.allBrands": "All brands", | |||||
"Browser.brand": "Brand", | |||||
"Browser.allTags": "All tags", | |||||
"Browser.tagsSelectMultiple": "click to select multiple", | |||||
"Browser.tags": "Tags", | |||||
"ParamWidget.history.setParam": "set parameter", | |||||
"ParamWidget.initialize": "Initialize", | |||||
"ParamWidget.doubleClick": "Double-click", | |||||
"ParamWidget.fine": "Fine adjust", | |||||
"ParamWidget.fineDrag": "drag", | |||||
"ParamWidget.unmap": "Unmap", | |||||
"ParamWidget.history.reset": "reset parameter", | |||||
"PortWidget.from": "From ", | |||||
"PortWidget.to": "To ", | |||||
"PortWidget.input": "input", | |||||
"PortWidget.output": "output", | |||||
"PortWidget.cableId": "ID: %ld", | |||||
"PortWidget.setColor": "Set color", | |||||
"PortWidget.deleteTopCable": "Delete top cable", | |||||
"PortWidget.click": "click", | |||||
"PortWidget.cloneTopCable": "Duplicate top cable", | |||||
"PortWidget.createCableTop": "Create cable on top", | |||||
"PortWidget.drag": "drag", | |||||
"PortWidget.createCable": "Create cable: ", | |||||
"PortWidget.clickDrag": "Click+drag", | |||||
"PortWidget.grabCable": " to grab cable", | |||||
"PortWidget.allCables": "All cables", | |||||
"PortWidget.history.moveCable": "move cable" | |||||
} | } |