--- ../Rack/src/app/MenuBar.cpp 2022-09-21 19:49:12.198540676 +0100 +++ MenuBar.cpp 2022-12-30 14:50:06.801891005 +0000 @@ -1,8 +1,33 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For a full copy of the GNU General Public License see the LICENSE file. + */ + +/** + * This file is an edited version of VCVRack's app/MenuBar.cpp + * Copyright (C) 2016-2021 VCV. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of + * the License, or (at your option) any later version. + */ + #include #include -#include - #include #include #include @@ -15,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -25,8 +51,28 @@ #include #include +#include "../CardinalCommon.hpp" +#include "../CardinalRemote.hpp" +#include "DistrhoPlugin.hpp" +#include "DistrhoStandaloneUtils.hpp" + +#ifdef HAVE_LIBLO +# include +#endif + +void switchDarkMode(bool darkMode); namespace rack { +namespace asset { +std::string patchesPath(); +} +namespace engine { +void Engine_setRemoteDetails(Engine*, remoteUtils::RemoteDetails*); +} +namespace plugin { +void updateStaticPluginsDarkMode(); +} + namespace app { namespace menuBar { @@ -48,79 +94,160 @@ }; -struct NotificationIcon : widget::Widget { - void draw(const DrawArgs& args) override { - nvgBeginPath(args.vg); - float radius = 4; - nvgCircle(args.vg, radius, radius, radius); - nvgFillColor(args.vg, nvgRGBf(1.0, 0.0, 0.0)); - nvgFill(args.vg); - nvgStrokeColor(args.vg, nvgRGBf(0.5, 0.0, 0.0)); - nvgStroke(args.vg); - } -}; - - //////////////////// // File //////////////////// struct FileButton : MenuButton { + const bool isStandalone; +#if ! CARDINAL_VARIANT_MINI + std::vector demoPatches; +#endif + + FileButton(const bool standalone) + : MenuButton(), isStandalone(standalone) + { +#if ! CARDINAL_VARIANT_MINI + const std::string patchesDir = asset::patchesPath() + DISTRHO_OS_SEP_STR "examples"; + + if (system::isDirectory(patchesDir)) + { + demoPatches = system::getEntries(patchesDir); + std::sort(demoPatches.begin(), demoPatches.end(), [](const std::string& a, const std::string& b){ + return string::lowercase(a) < string::lowercase(b); + }); + } +#endif + } + void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); - menu->addChild(createMenuItem("New", RACK_MOD_CTRL_NAME "+N", []() { - APP->patch->loadTemplateDialog(); +#ifndef DISTRHO_OS_WASM + const char* const NewShortcut = RACK_MOD_CTRL_NAME "+N"; +#else + const char* const NewShortcut = ""; +#endif + menu->addChild(createMenuItem("New", NewShortcut, []() { + patchUtils::loadTemplateDialog(); })); - menu->addChild(createMenuItem("Open", RACK_MOD_CTRL_NAME "+O", []() { - APP->patch->loadDialog(); +#if ! CARDINAL_VARIANT_MINI +#ifndef DISTRHO_OS_WASM + menu->addChild(createMenuItem("Open / Import...", RACK_MOD_CTRL_NAME "+O", []() { + patchUtils::loadDialog(); })); - menu->addChild(createSubmenuItem("Open recent", "", [](ui::Menu* menu) { - for (const std::string& path : settings::recentPatchPaths) { - std::string name = system::getStem(path); - menu->addChild(createMenuItem(name, "", [=]() { - APP->patch->loadPathDialog(path); - })); - } - }, settings::recentPatchPaths.empty())); - menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { - APP->patch->saveDialog(); + // NOTE: will do nothing if path is empty, intentionally + patchUtils::saveDialog(APP->patch->path); + }, APP->patch->path.empty())); + + menu->addChild(createMenuItem("Save as / Export...", RACK_MOD_CTRL_NAME "+Shift+S", []() { + patchUtils::saveAsDialog(); + })); +#else + menu->addChild(createMenuItem("Import patch...", RACK_MOD_CTRL_NAME "+O", []() { + patchUtils::loadDialog(); })); - menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() { - APP->patch->saveAsDialog(); + menu->addChild(createMenuItem("Import selection...", "", [=]() { + patchUtils::loadSelectionDialog(); + }, false, true)); + + menu->addChild(createMenuItem("Save and download compressed", RACK_MOD_CTRL_NAME "+Shift+S", []() { + patchUtils::saveAsDialog(); })); - menu->addChild(createMenuItem("Save a copy", "", []() { - APP->patch->saveAsDialog(false); + menu->addChild(createMenuItem("Save and download uncompressed", "", []() { + patchUtils::saveAsDialogUncompressed(); })); +#endif +#endif menu->addChild(createMenuItem("Revert", RACK_MOD_CTRL_NAME "+" RACK_MOD_SHIFT_NAME "+O", []() { - APP->patch->revertDialog(); - }, APP->patch->path == "")); + patchUtils::revertDialog(); + }, APP->patch->path.empty())); - menu->addChild(createMenuItem("Overwrite template", "", []() { - APP->patch->saveTemplateDialog(); - })); +#if defined(HAVE_LIBLO) && ! CARDINAL_VARIANT_MINI + menu->addChild(new ui::MenuSeparator); + + remoteUtils::RemoteDetails* const remoteDetails = remoteUtils::getRemote(); + + if (remoteDetails != nullptr && remoteDetails->connected) { + menu->addChild(createMenuItem("Deploy to MOD", "F7", [remoteDetails]() { + remoteUtils::sendFullPatchToRemote(remoteDetails); + })); + menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", + [remoteDetails]() {return remoteDetails->autoDeploy;}, + [remoteDetails]() { + remoteDetails->autoDeploy = !remoteDetails->autoDeploy; + Engine_setRemoteDetails(APP->engine, remoteDetails->autoDeploy ? remoteDetails : nullptr); + } + )); + } else { + menu->addChild(createMenuItem("Connect to MOD", "", []() { + DISTRHO_SAFE_ASSERT(remoteUtils::connectToRemote()); + })); + } +#endif + +#if ! CARDINAL_VARIANT_MINI +#ifndef DISTRHO_OS_WASM menu->addChild(new ui::MenuSeparator); // Load selection - menu->addChild(createMenuItem("Import selection", "", [=]() { - APP->scene->rack->loadSelectionDialog(); + menu->addChild(createMenuItem("Import selection...", "", [=]() { + patchUtils::loadSelectionDialog(); }, false, true)); - menu->addChild(new ui::MenuSeparator); - - menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() { - APP->window->close(); + menu->addChild(createMenuItem("Export uncompressed json...", "", []() { + patchUtils::saveAsDialogUncompressed(); })); +#endif +#endif + +#if ! CARDINAL_VARIANT_MINI + if (!demoPatches.empty()) + { + menu->addChild(new ui::MenuSeparator); + + menu->addChild(createSubmenuItem("Open Demo / Example project", "", [=](ui::Menu* const menu) { + for (std::string path : demoPatches) { + std::string label = system::getStem(path); + + for (size_t i=0, len=label.size(); iaddChild(createMenuItem(label, "", [path]() { + patchUtils::loadPathDialog(path, true); + })); + } + + menu->addChild(new ui::MenuSeparator); + + menu->addChild(createMenuItem("Open PatchStorage.com for more patches", "", []() { + patchUtils::openBrowser("https://patchstorage.com/platform/cardinal/"); + })); + })); + } +#endif + +#ifndef DISTRHO_OS_WASM + if (isStandalone) { + menu->addChild(new ui::MenuSeparator); + + menu->addChild(createMenuItem("Quit", RACK_MOD_CTRL_NAME "+Q", []() { + APP->window->close(); + })); + } +#endif } }; @@ -166,7 +293,7 @@ menu->addChild(new ui::MenuSeparator); - APP->scene->rack->appendSelectionContextMenu(menu); + patchUtils::appendSelectionContextMenu(menu); } }; @@ -256,7 +383,7 @@ return settings::cableTension; } float getDefaultValue() override { - return 0.5; + return 0.75; } float getDisplayValue() override { return getValue() * 100; @@ -393,36 +520,37 @@ }; +static void setAllFramebufferWidgetsDirty(widget::Widget* const widget) +{ + for (widget::Widget* child : widget->children) + { + if (widget::FramebufferWidget* const fbw = dynamic_cast(child)) + { + fbw->setDirty(); + break; + } + setAllFramebufferWidgetsDirty(child); + } +} + + struct ViewButton : MenuButton { void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); - menu->addChild(createMenuLabel("Window")); - - bool fullscreen = APP->window->isFullScreen(); - std::string fullscreenText = "F11"; - if (fullscreen) - fullscreenText += " " CHECKMARK_STRING; - menu->addChild(createMenuItem("Fullscreen", fullscreenText, [=]() { - APP->window->setFullScreen(!fullscreen); - })); + menu->addChild(createMenuLabel("Appearance")); - double frameRate = APP->window->getMonitorRefreshRate() / settings::frameSwapInterval; - menu->addChild(createSubmenuItem("Frame rate", string::f("%.0f Hz", frameRate), [=](ui::Menu* menu) { - for (int i = 1; i <= 6; i++) { - double frameRate = APP->window->getMonitorRefreshRate() / i; - menu->addChild(createCheckMenuItem(string::f("%.0f Hz", frameRate), "", - [=]() {return settings::frameSwapInterval == i;}, - [=]() {settings::frameSwapInterval = i;} - )); - } + std::string darkModeText; + if (settings::darkMode) + darkModeText = CHECKMARK_STRING; + menu->addChild(createMenuItem("Dark Mode", darkModeText, []() { + switchDarkMode(!settings::darkMode); + plugin::updateStaticPluginsDarkMode(); + setAllFramebufferWidgetsDirty(APP->scene); })); - menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("Appearance")); - menu->addChild(createBoolPtrMenuItem("Show tooltips", "", &settings::tooltips)); ZoomSlider* zoomSlider = new ZoomSlider; @@ -446,9 +574,18 @@ menu->addChild(haloBrightnessSlider); menu->addChild(new ui::MenuSeparator); + menu->addChild(createMenuLabel("Module dragging")); + + menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules)); + + menu->addChild(createBoolPtrMenuItem("Auto-squeeze modules when dragging", "", &settings::squeezeModules)); + + menu->addChild(new ui::MenuSeparator); menu->addChild(createMenuLabel("Parameters")); +#ifdef DISTRHO_OS_WASM menu->addChild(createBoolPtrMenuItem("Lock cursor while dragging", "", &settings::allowCursorLock)); +#endif static const std::vector knobModeLabels = { "Linear", @@ -473,11 +610,34 @@ menu->addChild(knobScrollSensitivitySlider); menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("Module dragging")); + menu->addChild(createMenuLabel("Window")); + +#ifdef DISTRHO_OS_WASM + const bool fullscreen = APP->window->isFullScreen(); + std::string rightText = "F11"; + if (fullscreen) + rightText += " " CHECKMARK_STRING; + menu->addChild(createMenuItem("Fullscreen", rightText, [=]() { + APP->window->setFullScreen(!fullscreen); + })); +#endif - menu->addChild(createBoolPtrMenuItem("Lock positions", "", &settings::lockModules)); + menu->addChild(createBoolPtrMenuItem("Invert zoom", "", &settings::invertZoom)); - menu->addChild(createBoolPtrMenuItem("Auto-squeeze algorithm (experimental)", "", &settings::squeezeModules)); + static const std::vector rateLimitLabels = { + "None", + "2x", + "4x", + }; + static const std::vector rateLimits = {0, 1, 2}; + menu->addChild(createSubmenuItem("Update rate limit", rateLimitLabels[settings::rateLimit], [=](ui::Menu* menu) { + for (int rateLimit : rateLimits) { + menu->addChild(createCheckMenuItem(rateLimitLabels[rateLimit], "", + [=]() {return settings::rateLimit == rateLimit;}, + [=]() {settings::rateLimit = rateLimit;} + )); + } + })); } }; @@ -487,47 +647,6 @@ //////////////////// -struct SampleRateItem : ui::MenuItem { - ui::Menu* createChildMenu() override { - ui::Menu* menu = new ui::Menu; - - // Auto sample rate - std::string rightText; - if (settings::sampleRate == 0) { - float sampleRate = APP->engine->getSampleRate(); - rightText += string::f("(%g kHz) ", sampleRate / 1000.f); - } - menu->addChild(createCheckMenuItem("Auto", rightText, - [=]() {return settings::sampleRate == 0;}, - [=]() {settings::sampleRate = 0;} - )); - - // Power-of-2 oversample times 44.1kHz or 48kHz - for (int i = -2; i <= 4; i++) { - for (int j = 0; j < 2; j++) { - float oversample = std::pow(2.f, i); - float sampleRate = (j == 0) ? 44100.f : 48000.f; - sampleRate *= oversample; - - std::string text = string::f("%g kHz", sampleRate / 1000.f); - std::string rightText; - if (oversample > 1.f) { - rightText += string::f("(%.0fx)", oversample); - } - else if (oversample < 1.f) { - rightText += string::f("(1/%.0fx)", 1.f / oversample); - } - menu->addChild(createCheckMenuItem(text, rightText, - [=]() {return settings::sampleRate == sampleRate;}, - [=]() {settings::sampleRate = sampleRate;} - )); - } - } - return menu; - } -}; - - struct EngineButton : MenuButton { void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); @@ -541,268 +660,46 @@ settings::cpuMeter ^= true; })); - menu->addChild(createMenuItem("Sample rate", RIGHT_ARROW)); - - menu->addChild(createSubmenuItem("Threads", string::f("%d", settings::threadCount), [=](ui::Menu* menu) { - // BUG This assumes SMT is enabled. - int cores = system::getLogicalCoreCount() / 2; - - for (int i = 1; i <= 2 * cores; i++) { + if (isUsingNativeAudio()) { + if (supportsAudioInput()) { + const bool enabled = isAudioInputEnabled(); std::string rightText; - if (i == cores) - rightText += "(most modules)"; - else if (i == 1) - rightText += "(lowest CPU usage)"; - menu->addChild(createCheckMenuItem(string::f("%d", i), rightText, - [=]() {return settings::threadCount == i;}, - [=]() {settings::threadCount = i;} - )); - } - })); - } -}; - - -//////////////////// -// Plugins -//////////////////// - - -struct AccountPasswordField : ui::PasswordField { - ui::MenuItem* logInItem; - void onAction(const ActionEvent& e) override { - logInItem->doAction(); - } -}; - - -struct LogInItem : ui::MenuItem { - ui::TextField* emailField; - ui::TextField* passwordField; - - void onAction(const ActionEvent& e) override { - std::string email = emailField->text; - std::string password = passwordField->text; - std::thread t([=] { - library::logIn(email, password); - library::checkUpdates(); - }); - t.detach(); - e.unconsume(); - } - - void step() override { - text = "Log in"; - rightText = library::loginStatus; - MenuItem::step(); - } -}; - - -struct SyncUpdatesItem : ui::MenuItem { - void step() override { - if (library::updateStatus != "") { - text = library::updateStatus; - } - else if (library::isSyncing) { - text = "Updating..."; - } - else if (!library::hasUpdates()) { - text = "Up-to-date"; - } - else { - text = "Update all"; - } - - disabled = library::isSyncing || !library::hasUpdates(); - MenuItem::step(); - } - - void onAction(const ActionEvent& e) override { - std::thread t([=] { - library::syncUpdates(); - }); - t.detach(); - e.unconsume(); - } -}; - - -struct SyncUpdateItem : ui::MenuItem { - std::string slug; - - void setUpdate(const std::string& slug) { - this->slug = slug; - - auto it = library::updateInfos.find(slug); - if (it == library::updateInfos.end()) - return; - library::UpdateInfo update = it->second; - - text = update.name; - } - - ui::Menu* createChildMenu() override { - auto it = library::updateInfos.find(slug); - if (it == library::updateInfos.end()) - return NULL; - library::UpdateInfo update = it->second; - - if (update.changelogUrl == "") - return NULL; - - ui::Menu* menu = new ui::Menu; - - std::string changelogUrl = update.changelogUrl; - menu->addChild(createMenuItem("Changelog", "", [=]() { - system::openBrowser(changelogUrl); - })); - - return menu; - } - - void step() override { - disabled = library::isSyncing; - - auto it = library::updateInfos.find(slug); - if (it != library::updateInfos.end()) { - library::UpdateInfo update = it->second; - - if (update.downloaded) { - rightText = CHECKMARK_STRING; - disabled = true; - } - else if (slug == library::updateSlug) { - rightText = string::f("%.0f%%", library::updateProgress * 100.f); - } - else { - rightText = ""; - plugin::Plugin* p = plugin::getPlugin(slug); - if (p) { - rightText += p->version + " → "; - } - rightText += update.version; + if (enabled) + rightText = CHECKMARK_STRING; + menu->addChild(createMenuItem("Enable Audio Input", rightText, [enabled]() { + if (!enabled) + requestAudioInput(); + })); } - } - MenuItem::step(); - } - - void onAction(const ActionEvent& e) override { - std::thread t([=] { - library::syncUpdate(slug); - }); - t.detach(); - e.unconsume(); - } -}; - - -struct LibraryMenu : ui::Menu { - LibraryMenu() { - refresh(); - } - - void step() override { - // Refresh menu when appropriate - if (library::refreshRequested) { - library::refreshRequested = false; - refresh(); - } - Menu::step(); - } - - void refresh() { - setChildMenu(NULL); - clearChildren(); - - if (settings::devMode) { - addChild(createMenuLabel("Disabled in development mode")); - } - else if (!library::isLoggedIn()) { - addChild(createMenuItem("Register VCV account", "", [=]() { - system::openBrowser("https://vcvrack.com/login"); - })); - - ui::TextField* emailField = new ui::TextField; - emailField->placeholder = "Email"; - emailField->box.size.x = 240.0; - addChild(emailField); - - AccountPasswordField* passwordField = new AccountPasswordField; - passwordField->placeholder = "Password"; - passwordField->box.size.x = 240.0; - passwordField->nextField = emailField; - emailField->nextField = passwordField; - addChild(passwordField); - - LogInItem* logInItem = new LogInItem; - logInItem->emailField = emailField; - logInItem->passwordField = passwordField; - passwordField->logInItem = logInItem; - addChild(logInItem); - } - else { - addChild(createMenuItem("Log out", "", [=]() { - library::logOut(); - })); - - addChild(createMenuItem("Browse VCV Library", "", [=]() { - system::openBrowser("https://library.vcvrack.com/"); - })); - - SyncUpdatesItem* syncItem = new SyncUpdatesItem; - syncItem->text = "Update all"; - addChild(syncItem); - - if (!library::updateInfos.empty()) { - addChild(new ui::MenuSeparator); - addChild(createMenuLabel("Updates")); - - for (auto& pair : library::updateInfos) { - SyncUpdateItem* updateItem = new SyncUpdateItem; - updateItem->setUpdate(pair.first); - addChild(updateItem); - } + if (supportsMIDI()) { + std::string rightText; + if (isMIDIEnabled()) + rightText = CHECKMARK_STRING; + menu->addChild(createMenuItem("Enable/Reconnect MIDI", rightText, []() { + requestMIDI(); + })); } - } - } -}; - - -struct LibraryButton : MenuButton { - NotificationIcon* notification; - - LibraryButton() { - notification = new NotificationIcon; - addChild(notification); - } - - void onAction(const ActionEvent& e) override { - ui::Menu* menu = createMenu(); - menu->cornerFlags = BND_CORNER_TOP; - menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); - // Check for updates when menu is opened - std::thread t([&]() { - system::setThreadName("Library"); - library::checkUpdates(); - }); - t.detach(); - } - - void step() override { - notification->box.pos = math::Vec(0, 0); - notification->visible = library::hasUpdates(); - // Popup when updates finish downloading - if (library::restartRequested) { - library::restartRequested = false; - if (osdialog_message(OSDIALOG_INFO, OSDIALOG_OK_CANCEL, "All plugins have been downloaded. Close and re-launch Rack to load new updates.")) { - APP->window->close(); + if (supportsBufferSizeChanges()) { + static const std::vector bufferSizes = { + #ifdef DISTRHO_OS_WASM + 256, 512, 1024, 2048, 4096, 8192, 16384 + #else + 128, 256, 512, 1024, 2048, 4096, 8192 + #endif + }; + const uint32_t currentBufferSize = getBufferSize(); + menu->addChild(createSubmenuItem("Buffer Size", std::to_string(currentBufferSize), [=](ui::Menu* menu) { + for (uint32_t bufferSize : bufferSizes) { + menu->addChild(createCheckMenuItem(std::to_string(bufferSize), "", + [=]() {return currentBufferSize == bufferSize;}, + [=]() {requestBufferSizeChange(bufferSize);} + )); + } + })); } } - - MenuButton::step(); } }; @@ -813,65 +710,23 @@ struct HelpButton : MenuButton { - NotificationIcon* notification; - - HelpButton() { - notification = new NotificationIcon; - addChild(notification); - } - void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); menu->cornerFlags = BND_CORNER_TOP; menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); - menu->addChild(createMenuItem("Tips", "", [=]() { - APP->scene->addChild(tipWindowCreate()); - })); - - menu->addChild(createMenuItem("User manual", "F1", [=]() { - system::openBrowser("https://vcvrack.com/manual"); - })); - - menu->addChild(createMenuItem("Support", "", [=]() { - system::openBrowser("https://vcvrack.com/support"); + menu->addChild(createMenuItem("Rack User manual", "F1", [=]() { + patchUtils::openBrowser("https://vcvrack.com/manual"); })); - menu->addChild(createMenuItem("VCVRack.com", "", [=]() { - system::openBrowser("https://vcvrack.com/"); + menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { + patchUtils::openBrowser("https://github.com/DISTRHO/Cardinal/"); })); menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel(APP_NAME + " " + APP_EDITION_NAME + " " + APP_VERSION)); - - menu->addChild(createMenuItem("Open user folder", "", [=]() { - system::openDirectory(asset::user("")); - })); - - menu->addChild(createMenuItem("Changelog", "", [=]() { - system::openBrowser("https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md"); - })); - - if (library::isAppUpdateAvailable()) { - menu->addChild(createMenuItem("Update " + APP_NAME, APP_VERSION + " → " + library::appVersion, [=]() { - system::openBrowser(library::appDownloadUrl); - })); - } - else if (!settings::autoCheckUpdates && !settings::devMode) { - menu->addChild(createMenuItem("Check for " + APP_NAME + " update", "", [=]() { - std::thread t([&]() { - library::checkAppUpdate(); - }); - t.detach(); - }, false, true)); - } - } - - void step() override { - notification->box.pos = math::Vec(0, 0); - notification->visible = library::isAppUpdateAvailable(); - MenuButton::step(); + menu->addChild(createMenuLabel("Cardinal " + APP_EDITION + " " + CARDINAL_VERSION)); + menu->addChild(createMenuLabel("Rack " + APP_VERSION + " Compatible")); } }; @@ -910,9 +765,14 @@ // uiLastTime = time; // } +#if CARDINAL_VARIANT_MINI + text = string::f("%.1f fps", 1.0 / frameDurationAvg); +#else double meterAverage = APP->engine->getMeterAverage(); double meterMax = APP->engine->getMeterMax(); text = string::f("%.1f fps %.1f%% avg %.1f%% max", 1.0 / frameDurationAvg, meterAverage * 100, meterMax * 100); +#endif + Label::step(); } }; @@ -921,7 +781,9 @@ struct MenuBar : widget::OpaqueWidget { MeterLabel* meterLabel; - MenuBar() { + MenuBar(const bool isStandalone) + : widget::OpaqueWidget() + { const float margin = 5; box.size.y = BND_WIDGET_HEIGHT + 2 * margin; @@ -930,7 +792,7 @@ layout->spacing = math::Vec(0, 0); addChild(layout); - FileButton* fileButton = new FileButton; + FileButton* fileButton = new FileButton(isStandalone); fileButton->text = "File"; layout->addChild(fileButton); @@ -942,13 +804,11 @@ viewButton->text = "View"; layout->addChild(viewButton); +#if ! CARDINAL_VARIANT_MINI EngineButton* engineButton = new EngineButton; engineButton->text = "Engine"; layout->addChild(engineButton); - - LibraryButton* libraryButton = new LibraryButton; - libraryButton->text = "Library"; - layout->addChild(libraryButton); +#endif HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; @@ -984,7 +844,7 @@ widget::Widget* createMenuBar() { - menuBar::MenuBar* menuBar = new menuBar::MenuBar; + menuBar::MenuBar* menuBar = new menuBar::MenuBar(isStandalone()); return menuBar; }