--- ../Rack/src/app/ModuleWidget.cpp 2022-11-23 23:11:38.000000000 +0000 +++ ModuleWidget.cpp 2022-11-30 20:10:06.000000000 +0000 @@ -1,3 +1,32 @@ +/* + * 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 ModuleWidget.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 "../../CardinalCommon.hpp" + #include #include @@ -368,71 +397,71 @@ } void ModuleWidget::onButton(const ButtonEvent& e) { - bool selected = APP->scene->rack->isSelected(this); - - if (selected) { - if (e.button == GLFW_MOUSE_BUTTON_RIGHT) { - if (e.action == GLFW_PRESS) { - // Open selection context menu on right-click - ui::Menu* menu = createMenu(); - APP->scene->rack->appendSelectionContextMenu(menu); - } - e.consume(this); - } - - if (e.button == GLFW_MOUSE_BUTTON_LEFT) { - if (e.action == GLFW_PRESS) { - // Toggle selection on Shift-click - if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { - APP->scene->rack->select(this, false); - e.consume(NULL); - return; - } - - // If module positions are locked, don't consume left-click - if (settings::lockModules) { - return; - } + const bool selected = APP->scene->rack->isSelected(this); - internal->dragOffset = e.pos; - } - - e.consume(this); - } - - return; - } - - // Dispatch event to children - Widget::onButton(e); - e.stopPropagating(); - if (e.isConsumed()) - return; - - if (e.button == GLFW_MOUSE_BUTTON_LEFT) { - if (e.action == GLFW_PRESS) { - // Toggle selection on Shift-click - if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { - APP->scene->rack->select(this, true); - e.consume(NULL); - return; - } - - // If module positions are locked, don't consume left-click - if (settings::lockModules) { - return; - } - - internal->dragOffset = e.pos; - } - e.consume(this); - } - - // Open context menu on right-click - if (e.button == GLFW_MOUSE_BUTTON_RIGHT && e.action == GLFW_PRESS) { - createContextMenu(); - e.consume(this); - } + if (selected) { + if (e.button == GLFW_MOUSE_BUTTON_RIGHT) { + if (e.action == GLFW_PRESS) { + // Open selection context menu on right-click + ui::Menu* menu = createMenu(); + patchUtils::appendSelectionContextMenu(menu); + } + e.consume(this); + } + + if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + if (e.action == GLFW_PRESS) { + // Toggle selection on Shift-click + if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { + APP->scene->rack->select(this, false); + e.consume(NULL); + return; + } + + // If module positions are locked, don't consume left-click + if (settings::lockModules) { + return; + } + + internal->dragOffset = e.pos; + } + + e.consume(this); + } + + return; + } + + // Dispatch event to children + Widget::onButton(e); + e.stopPropagating(); + if (e.isConsumed()) + return; + + if (e.button == GLFW_MOUSE_BUTTON_LEFT) { + if (e.action == GLFW_PRESS) { + // Toggle selection on Shift-click + if ((e.mods & RACK_MOD_MASK) == GLFW_MOD_SHIFT) { + APP->scene->rack->select(this, true); + e.consume(NULL); + return; + } + + // If module positions are locked, don't consume left-click + if (settings::lockModules) { + return; + } + + internal->dragOffset = e.pos; + } + e.consume(this); + } + + // Open context menu on right-click + if (e.button == GLFW_MOUSE_BUTTON_RIGHT && e.action == GLFW_PRESS) { + createContextMenu(); + e.consume(this); + } } void ModuleWidget::onDragStart(const DragStartEvent& e) { @@ -624,36 +653,37 @@ } void ModuleWidget::loadDialog() { - std::string presetDir = model->getUserPresetDirectory(); - system::createDirectories(presetDir); + std::string presetDir = model->getUserPresetDirectory(); + system::createDirectories(presetDir); - // Delete directories if empty - DEFER({ - try { - system::remove(presetDir); - system::remove(system::getDirectory(presetDir)); - } - catch (Exception& e) { - // Ignore exceptions if directory cannot be removed. - } - }); + WeakPtr weakThis = this; - osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS); - DEFER({osdialog_filters_free(filters);}); + async_dialog_filebrowser(false, nullptr, presetDir.c_str(), "Load preset", [=](char* pathC) { + // Delete directories if empty + DEFER({ + try { + system::remove(presetDir); + system::remove(system::getDirectory(presetDir)); + } + catch (Exception& e) { + // Ignore exceptions if directory cannot be removed. + } + }); + + if (!weakThis) + return; + if (!pathC) + return; + + try { + weakThis->loadAction(pathC); + } + catch (Exception& e) { + async_dialog_message(e.what()); + } - char* pathC = osdialog_file(OSDIALOG_OPEN, presetDir.c_str(), NULL, filters); - if (!pathC) { - // No path selected - return; - } - DEFER({std::free(pathC);}); - - try { - loadAction(pathC); - } - catch (Exception& e) { - osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, e.what()); - } + std::free(pathC); + }); } void ModuleWidget::save(std::string filename) { @@ -712,36 +742,37 @@ } void ModuleWidget::saveDialog() { - std::string presetDir = model->getUserPresetDirectory(); - system::createDirectories(presetDir); + const std::string presetDir = model->getUserPresetDirectory(); + system::createDirectories(presetDir); - // Delete directories if empty - DEFER({ - try { - system::remove(presetDir); - system::remove(system::getDirectory(presetDir)); - } - catch (Exception& e) { - // Ignore exceptions if directory cannot be removed. - } - }); - - osdialog_filters* filters = osdialog_filters_parse(PRESET_FILTERS); - DEFER({osdialog_filters_free(filters);}); - - char* pathC = osdialog_file(OSDIALOG_SAVE, presetDir.c_str(), "Untitled.vcvm", filters); - if (!pathC) { - // No path selected - return; - } - DEFER({std::free(pathC);}); + WeakPtr weakThis = this; - std::string path = pathC; - // Automatically append .vcvm extension - if (system::getExtension(path) != ".vcvm") - path += ".vcvm"; + async_dialog_filebrowser(true, "preset.vcvm", presetDir.c_str(), "Save preset", [=](char* pathC) { + // Delete directories if empty + DEFER({ + try { + system::remove(presetDir); + system::remove(system::getDirectory(presetDir)); + } + catch (Exception& e) { + // Ignore exceptions if directory cannot be removed. + } + }); + + if (!weakThis) + return; + if (!pathC) + return; + + std::string path = pathC; + std::free(pathC); + + // Automatically append .vcvm extension + if (system::getExtension(path) != ".vcvm") + path += ".vcvm"; - save(path); + weakThis->save(path); + }); } void ModuleWidget::disconnect() { @@ -981,118 +1012,108 @@ WeakPtr weakThis = this; - // Brand and module name - menu->addChild(createMenuLabel(model->name)); - menu->addChild(createMenuLabel(model->plugin->brand)); - - // Info - menu->addChild(createSubmenuItem("Info", "", [=](ui::Menu* menu) { - model->appendContextMenu(menu); - })); - - // Preset - menu->addChild(createSubmenuItem("Preset", "", [=](ui::Menu* menu) { - menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [=]() { - if (!weakThis) - return; - weakThis->copyClipboard(); - })); - - menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [=]() { - if (!weakThis) - return; - weakThis->pasteClipboardAction(); - })); - - menu->addChild(createMenuItem("Open", "", [=]() { - if (!weakThis) - return; - weakThis->loadDialog(); - })); - - menu->addChild(createMenuItem("Save as", "", [=]() { - if (!weakThis) - return; - weakThis->saveDialog(); - })); - - menu->addChild(createMenuItem("Save default", "", [=]() { - if (!weakThis) - return; - weakThis->saveTemplateDialog(); - })); - - menu->addChild(createMenuItem("Clear default", "", [=]() { - if (!weakThis) - return; - weakThis->clearTemplateDialog(); - }, !weakThis->hasTemplate())); - - // Scan `/presets//` for presets. - menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("User presets")); - appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); - - // Scan `/presets/` for presets. - menu->addChild(new ui::MenuSeparator); - menu->addChild(createMenuLabel("Factory presets")); - appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); - })); + // Brand and module name + menu->addChild(createMenuLabel(model->name)); + menu->addChild(createMenuLabel(model->plugin->brand)); - // Initialize - menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [=]() { + // Info + menu->addChild(createSubmenuItem("Info", "", [weakThis](ui::Menu* menu) { if (!weakThis) return; - weakThis->resetAction(); - })); + weakThis->model->appendContextMenu(menu); + })); - // Randomize - menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [=]() { - if (!weakThis) - return; - weakThis->randomizeAction(); - })); - - // Disconnect cables - menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [=]() { - if (!weakThis) - return; - weakThis->disconnectAction(); - })); - - // Bypass - std::string bypassText = RACK_MOD_CTRL_NAME "+E"; - bool bypassed = module && module->isBypassed(); - if (bypassed) - bypassText += " " CHECKMARK_STRING; - menu->addChild(createMenuItem("Bypass", bypassText, [=]() { - if (!weakThis) - return; - weakThis->bypassAction(!bypassed); - })); - - // Duplicate - menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [=]() { - if (!weakThis) - return; - weakThis->cloneAction(false); - })); - - // Duplicate with cables - menu->addChild(createMenuItem("└ with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [=]() { - if (!weakThis) - return; - weakThis->cloneAction(true); - })); - - // Delete - menu->addChild(createMenuItem("Delete", "Backspace/Delete", [=]() { - if (!weakThis) - return; - weakThis->removeAction(); - }, false, true)); + // Preset + menu->addChild(createSubmenuItem("Preset", "", [weakThis](ui::Menu* menu) { + menu->addChild(createMenuItem("Copy", RACK_MOD_CTRL_NAME "+C", [weakThis]() { + if (!weakThis) + return; + weakThis->copyClipboard(); + })); + + menu->addChild(createMenuItem("Paste", RACK_MOD_CTRL_NAME "+V", [weakThis]() { + if (!weakThis) + return; + weakThis->pasteClipboardAction(); + })); + + menu->addChild(createMenuItem("Open", "", [weakThis]() { + if (!weakThis) + return; + weakThis->loadDialog(); + })); + + /* TODO requires setting up user dir + menu->addChild(createMenuItem("Save as", "", [weakThis]() { + if (!weakThis) + return; + CardinalModuleWidget__saveDialog(weakThis); + })); + + // Scan `/presets//` for presets. + menu->addChild(new ui::MenuSeparator); + menu->addChild(createMenuLabel("User presets")); + appendPresetItems(menu, weakThis, weakThis->model->getUserPresetDirectory()); + */ + + // Scan `/presets/` for presets. + appendPresetItems(menu, weakThis, weakThis->model->getFactoryPresetDirectory()); + })); + + // Initialize + menu->addChild(createMenuItem("Initialize", RACK_MOD_CTRL_NAME "+I", [weakThis]() { + if (!weakThis) + return; + weakThis->resetAction(); + })); + + // Randomize + menu->addChild(createMenuItem("Randomize", RACK_MOD_CTRL_NAME "+R", [weakThis]() { + if (!weakThis) + return; + weakThis->randomizeAction(); + })); + + // Disconnect cables + menu->addChild(createMenuItem("Disconnect cables", RACK_MOD_CTRL_NAME "+U", [weakThis]() { + if (!weakThis) + return; + weakThis->disconnectAction(); + })); + + // Bypass + std::string bypassText = RACK_MOD_CTRL_NAME "+E"; + bool bypassed = module && module->isBypassed(); + if (bypassed) + bypassText += " " CHECKMARK_STRING; + menu->addChild(createMenuItem("Bypass", bypassText, [weakThis, bypassed]() { + if (!weakThis) + return; + weakThis->bypassAction(!bypassed); + })); + + // Duplicate + menu->addChild(createMenuItem("Duplicate", RACK_MOD_CTRL_NAME "+D", [weakThis]() { + if (!weakThis) + return; + weakThis->cloneAction(false); + })); + + // Duplicate with cables + menu->addChild(createMenuItem("└ with cables", RACK_MOD_SHIFT_NAME "+" RACK_MOD_CTRL_NAME "+D", [weakThis]() { + if (!weakThis) + return; + weakThis->cloneAction(true); + })); + + // Delete + menu->addChild(createMenuItem("Delete", "Backspace/Delete", [weakThis]() { + if (!weakThis) + return; + weakThis->removeAction(); + }, false, true)); - appendContextMenu(menu); + appendContextMenu(menu); } math::Vec ModuleWidget::getGridPosition() {