Browse Source

Implement file->export, show error message on failure

tags/22.02
falkTX 3 years ago
parent
commit
fb9909e421
6 changed files with 190 additions and 110 deletions
  1. +1
    -1
      dpf
  2. +63
    -29
      src/AsyncDialog.cpp
  3. +1
    -0
      src/AsyncDialog.hpp
  4. +64
    -39
      src/CardinalUI.cpp
  5. +18
    -0
      src/PluginContext.hpp
  6. +43
    -41
      src/override/MenuBar.cpp

+ 1
- 1
dpf

@@ -1 +1 @@
Subproject commit fbbfe11a5bb1a9d02f9fa7a341caae7e7d532e7e
Subproject commit 29709cbe4e1f5d97b7630fd1664e2eb1210bb82f

+ 63
- 29
src/AsyncDialog.cpp View File

@@ -34,42 +34,34 @@ using namespace rack::widget;


struct AsyncDialog : OpaqueWidget struct AsyncDialog : OpaqueWidget
{ {
static const constexpr float margin = 10;
static const constexpr float buttonWidth = 100;

SequentialLayout* layout; SequentialLayout* layout;
SequentialLayout* contentLayout; SequentialLayout* contentLayout;
SequentialLayout* buttonLayout; SequentialLayout* buttonLayout;
Label* label; Label* label;


AsyncDialog(const char* const message, const std::function<void()> action)
AsyncDialog(const char* const message)
{ {
box.size = math::Vec(400, 120);
const float margin = 10;
const float buttonWidth = 100;

layout = new SequentialLayout;
layout->box.pos = math::Vec(0, 0);
layout->box.size = box.size;
layout->orientation = SequentialLayout::VERTICAL_ORIENTATION;
layout->margin = math::Vec(margin, margin);
layout->spacing = math::Vec(margin, margin);
layout->wrap = false;
addChild(layout);
setup(message);


contentLayout = new SequentialLayout;
contentLayout->spacing = math::Vec(margin, margin);
layout->addChild(contentLayout);

buttonLayout = new SequentialLayout;
buttonLayout->alignment = SequentialLayout::CENTER_ALIGNMENT;
buttonLayout->box.size = box.size;
buttonLayout->spacing = math::Vec(margin, margin);
layout->addChild(buttonLayout);
struct AsyncDismissButton : Button {
AsyncDialog* dialog;
void onAction(const ActionEvent& e) override {
dialog->getParent()->requestDelete();
}
};
AsyncDismissButton* const dismissButton = new AsyncDismissButton;
dismissButton->box.size.x = buttonWidth;
dismissButton->text = "Dismiss";
dismissButton->dialog = this;
buttonLayout->addChild(dismissButton);
}


label = new Label;
label->box.size.x = box.size.x - 2*margin;
label->box.size.y = box.size.y - 2*margin - 40;
label->fontSize = 16;
label->text = message;
contentLayout->addChild(label);
AsyncDialog(const char* const message, const std::function<void()> action)
{
setup(message);


struct AsyncCancelButton : Button { struct AsyncCancelButton : Button {
AsyncDialog* dialog; AsyncDialog* dialog;
@@ -99,6 +91,37 @@ struct AsyncDialog : OpaqueWidget
buttonLayout->addChild(okButton); buttonLayout->addChild(okButton);
} }


void setup(const char* const message)
{
box.size = math::Vec(400, 120);

layout = new SequentialLayout;
layout->box.pos = math::Vec(0, 0);
layout->box.size = box.size;
layout->orientation = SequentialLayout::VERTICAL_ORIENTATION;
layout->margin = math::Vec(margin, margin);
layout->spacing = math::Vec(margin, margin);
layout->wrap = false;
addChild(layout);

contentLayout = new SequentialLayout;
contentLayout->spacing = math::Vec(margin, margin);
layout->addChild(contentLayout);

buttonLayout = new SequentialLayout;
buttonLayout->alignment = SequentialLayout::CENTER_ALIGNMENT;
buttonLayout->box.size = box.size;
buttonLayout->spacing = math::Vec(margin, margin);
layout->addChild(buttonLayout);

label = new Label;
label->box.size.x = box.size.x - 2*margin;
label->box.size.y = box.size.y - 2*margin - 40;
label->fontSize = 16;
label->text = message;
contentLayout->addChild(label);
}

void step() override void step() override
{ {
OpaqueWidget::step(); OpaqueWidget::step();
@@ -113,6 +136,17 @@ struct AsyncDialog : OpaqueWidget
} }
}; };


void create(const char* const message)
{
MenuOverlay* const overlay = new MenuOverlay;
overlay->bgColor = nvgRGBAf(0, 0, 0, 0.33);

AsyncDialog* const dialog = new AsyncDialog(message);
overlay->addChild(dialog);

APP->scene->addChild(overlay);
}

void create(const char* const message, const std::function<void()> action) void create(const char* const message, const std::function<void()> action)
{ {
MenuOverlay* const overlay = new MenuOverlay; MenuOverlay* const overlay = new MenuOverlay;
@@ -121,7 +155,7 @@ void create(const char* const message, const std::function<void()> action)
AsyncDialog* const dialog = new AsyncDialog(message, action); AsyncDialog* const dialog = new AsyncDialog(message, action);
overlay->addChild(dialog); overlay->addChild(dialog);


APP->scene->addChild(overlay);
APP->scene->addChild(overlay);
} }


} }

+ 1
- 0
src/AsyncDialog.hpp View File

@@ -22,6 +22,7 @@
namespace asyncDialog namespace asyncDialog
{ {


void create(const char* message);
void create(const char* message, std::function<void()> action); void create(const char* message, std::function<void()> action);


} }

+ 64
- 39
src/CardinalUI.cpp View File

@@ -20,6 +20,8 @@
#include <helpers.hpp> #include <helpers.hpp>
#include <patch.hpp> #include <patch.hpp>
#include <settings.hpp> #include <settings.hpp>
#include <string.hpp>
#include <system.hpp>
#include <ui/Button.hpp> #include <ui/Button.hpp>
#include <ui/MenuItem.hpp> #include <ui/MenuItem.hpp>
#include <ui/MenuSeparator.hpp> #include <ui/MenuSeparator.hpp>
@@ -30,7 +32,7 @@
#endif #endif


#include <Application.hpp> #include <Application.hpp>
#include "DistrhoUI.hpp"
#include "AsyncDialog.hpp"
#include "PluginContext.hpp" #include "PluginContext.hpp"
#include "WindowParameters.hpp" #include "WindowParameters.hpp"
#include "ResizeHandle.hpp" #include "ResizeHandle.hpp"
@@ -42,7 +44,7 @@ GLFWAPI int glfwGetKeyScancode(int key) { return 0; }


namespace rack { namespace rack {
namespace app { namespace app {
widget::Widget* createMenuBar(Window& window, bool isStandalone);
widget::Widget* createMenuBar(CardinalBaseUI* const ui, bool isStandalone);
} }
namespace window { namespace window {
void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui); void WindowSetPluginUI(Window* window, DISTRHO_NAMESPACE::UI* ui);
@@ -54,14 +56,9 @@ START_NAMESPACE_DISTRHO


// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------


CardinalPluginContext* getRackContextFromPlugin(void* ptr);

// -----------------------------------------------------------------------------------------------------------

class CardinalUI : public UI,
class CardinalUI : public CardinalBaseUI,
public WindowParametersCallback public WindowParametersCallback
{ {
CardinalPluginContext* const fContext;
rack::math::Vec fLastMousePos; rack::math::Vec fLastMousePos;
ResizeHandle fResizeHandle; ResizeHandle fResizeHandle;
WindowParameters fWindowParameters; WindowParameters fWindowParameters;
@@ -70,14 +67,14 @@ class CardinalUI : public UI,
CardinalPluginContext* const context; CardinalPluginContext* const context;


ScopedContext(CardinalUI* const ui) ScopedContext(CardinalUI* const ui)
: context(ui->fContext)
: context(ui->context)
{ {
rack::contextSet(context); rack::contextSet(context);
WindowParametersRestore(context->window); WindowParametersRestore(context->window);
} }


ScopedContext(CardinalUI* const ui, const int mods) ScopedContext(CardinalUI* const ui, const int mods)
: context(ui->fContext)
: context(ui->context)
{ {
rack::contextSet(context); rack::contextSet(context);
rack::window::WindowSetMods(context->window, mods); rack::window::WindowSetMods(context->window, mods);
@@ -94,14 +91,13 @@ class CardinalUI : public UI,


public: public:
CardinalUI() CardinalUI()
: UI(1228, 666),
fContext(getRackContextFromPlugin(getPluginInstancePointer())),
: CardinalBaseUI(1228, 666),
fResizeHandle(this) fResizeHandle(this)
{ {
Window& window(getWindow()); Window& window(getWindow());


window.setIgnoringKeyRepeat(true); window.setIgnoringKeyRepeat(true);
fContext->nativeWindowId = window.getNativeWindowHandle();
context->nativeWindowId = window.getNativeWindowHandle();


if (isResizable()) if (isResizable())
fResizeHandle.hide(); fResizeHandle.hide();
@@ -111,32 +107,32 @@ public:
if (scaleFactor != 1) if (scaleFactor != 1)
setSize(1228 * scaleFactor, 666 * scaleFactor); setSize(1228 * scaleFactor, 666 * scaleFactor);


rack::contextSet(fContext);
rack::contextSet(context);


rack::window::WindowSetPluginUI(fContext->window, this);
rack::window::WindowSetPluginUI(context->window, this);


if (fContext->scene->menuBar != nullptr)
fContext->scene->removeChild(fContext->scene->menuBar);
if (context->scene->menuBar != nullptr)
context->scene->removeChild(context->scene->menuBar);


fContext->scene->menuBar = rack::app::createMenuBar(window, getApp().isStandalone());
fContext->scene->addChildBelow(fContext->scene->menuBar, fContext->scene->rackScroll);
context->scene->menuBar = rack::app::createMenuBar(this, getApp().isStandalone());
context->scene->addChildBelow(context->scene->menuBar, context->scene->rackScroll);


fContext->window->step();
context->window->step();


rack::contextSet(nullptr); rack::contextSet(nullptr);


WindowParametersSetCallback(fContext->window, this);
WindowParametersSetCallback(context->window, this);
} }


~CardinalUI() override ~CardinalUI() override
{ {
rack::contextSet(fContext);
rack::contextSet(context);


rack::widget::Widget* const menuBar = fContext->scene->menuBar;
fContext->scene->menuBar = nullptr;
fContext->scene->removeChild(menuBar);
rack::widget::Widget* const menuBar = context->scene->menuBar;
context->scene->menuBar = nullptr;
context->scene->removeChild(menuBar);


rack::window::WindowSetPluginUI(fContext->window, nullptr);
rack::window::WindowSetPluginUI(context->window, nullptr);


rack::contextSet(nullptr); rack::contextSet(nullptr);
} }
@@ -144,7 +140,7 @@ public:
void onNanoDisplay() override void onNanoDisplay() override
{ {
const ScopedContext sc(this); const ScopedContext sc(this);
fContext->window->step();
context->window->step();
} }


void uiIdle() override void uiIdle() override
@@ -268,7 +264,7 @@ protected:
return; return;
} }


WindowParametersSetValues(fContext->window, fWindowParameters);
WindowParametersSetValues(context->window, fWindowParameters);
} }


void stateChanged(const char* key, const char* value) override void stateChanged(const char* key, const char* value) override
@@ -378,7 +374,7 @@ protected:
*/ */


const ScopedContext sc(this, mods); const ScopedContext sc(this, mods);
return fContext->event->handleButton(fLastMousePos, button, action, mods);
return context->event->handleButton(fLastMousePos, button, action, mods);
} }


bool onMotion(const MotionEvent& ev) override bool onMotion(const MotionEvent& ev) override
@@ -389,7 +385,7 @@ protected:
fLastMousePos = mousePos; fLastMousePos = mousePos;


const ScopedContext sc(this, glfwMods(ev.mod)); const ScopedContext sc(this, glfwMods(ev.mod));
return fContext->event->handleHover(mousePos, mouseDelta);
return context->event->handleHover(mousePos, mouseDelta);
} }


bool onScroll(const ScrollEvent& ev) override bool onScroll(const ScrollEvent& ev) override
@@ -402,7 +398,7 @@ protected:
#endif #endif


const ScopedContext sc(this, glfwMods(ev.mod)); const ScopedContext sc(this, glfwMods(ev.mod));
return fContext->event->handleScroll(fLastMousePos, scrollDelta);
return context->event->handleScroll(fLastMousePos, scrollDelta);
} }


bool onCharacterInput(const CharacterInputEvent& ev) override bool onCharacterInput(const CharacterInputEvent& ev) override
@@ -411,7 +407,7 @@ protected:
return false; return false;


const ScopedContext sc(this, glfwMods(ev.mod)); const ScopedContext sc(this, glfwMods(ev.mod));
return fContext->event->handleText(fLastMousePos, ev.character);
return context->event->handleText(fLastMousePos, ev.character);
} }


bool onKeyboard(const KeyboardEvent& ev) override bool onKeyboard(const KeyboardEvent& ev) override
@@ -486,15 +482,15 @@ protected:
} }


const ScopedContext sc(this, mods); const ScopedContext sc(this, mods);
return fContext->event->handleKey(fLastMousePos, key, ev.keycode, action, mods);
return context->event->handleKey(fLastMousePos, key, ev.keycode, action, mods);
} }


void onResize(const ResizeEvent& ev) override void onResize(const ResizeEvent& ev) override
{ {
UI::onResize(ev); UI::onResize(ev);


if (fContext->window != nullptr)
fContext->window->setSize(rack::math::Vec(ev.size.getWidth(), ev.size.getHeight()));
if (context->window != nullptr)
context->window->setSize(rack::math::Vec(ev.size.getWidth(), ev.size.getHeight()));


const double scaleFactor = getScaleFactor(); const double scaleFactor = getScaleFactor();
char sizeString[64]; char sizeString[64];
@@ -509,7 +505,7 @@ protected:
return; return;


const ScopedContext sc(this, 0); const ScopedContext sc(this, 0);
fContext->event->handleLeave();
context->event->handleLeave();
} }


void uiFileBrowserSelected(const char* const filename) override void uiFileBrowserSelected(const char* const filename) override
@@ -517,9 +513,38 @@ protected:
if (filename == nullptr) if (filename == nullptr)
return; return;


rack::contextSet(fContext);
WindowParametersRestore(fContext->window);
fContext->patch->loadAction(filename);
rack::contextSet(context);
WindowParametersRestore(context->window);

std::string sfilename = filename;

if (saving)
{
if (rack::system::getExtension(sfilename) != ".vcv")
sfilename += ".vcv";

try {
context->patch->save(sfilename);
}
catch (rack::Exception& e) {
std::string message = rack::string::f("Could not save patch: %s", e.what());
asyncDialog::create(message.c_str());
return;
}
}
else
{
try {
context->patch->load(sfilename);
} catch (rack::Exception& e) {
std::string message = rack::string::f("Could not load patch: %s", e.what());
asyncDialog::create(message.c_str());
return;
}
}

context->patch->path = sfilename;
context->history->setSaved();
} }


#if 0 #if 0


+ 18
- 0
src/PluginContext.hpp View File

@@ -28,6 +28,10 @@
#include "DistrhoPlugin.hpp" #include "DistrhoPlugin.hpp"
#include "extra/Mutex.hpp" #include "extra/Mutex.hpp"


#ifndef HEADLESS
# include "DistrhoUI.hpp"
#endif

START_NAMESPACE_DISTRHO START_NAMESPACE_DISTRHO


// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------
@@ -86,6 +90,8 @@ struct CardinalAudioDevice;
struct CardinalMidiInputDevice; struct CardinalMidiInputDevice;
struct CardinalMidiOutputDevice; struct CardinalMidiOutputDevice;


CardinalPluginContext* getRackContextFromPlugin(void* ptr);

class CardinalBasePlugin : public Plugin { class CardinalBasePlugin : public Plugin {
public: public:
CardinalPluginContext* const context; CardinalPluginContext* const context;
@@ -106,6 +112,18 @@ public:
virtual bool clearMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0; virtual bool clearMidiOutputDevice(CardinalMidiOutputDevice* dev) noexcept = 0;
}; };


class CardinalBaseUI : public UI {
public:
CardinalPluginContext* const context;
bool saving;

CardinalBaseUI(const uint width, const uint height)
: UI(width, height),
context(getRackContextFromPlugin(getPluginInstancePointer())),
saving(false) {}
~CardinalBaseUI() override {}
};

// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------


END_NAMESPACE_DISTRHO END_NAMESPACE_DISTRHO

+ 43
- 41
src/override/MenuBar.cpp View File

@@ -108,8 +108,29 @@ static void promptClear(const char* const message, const std::function<void()> a
asyncDialog::create(message, action); asyncDialog::create(message, action);
} }


static std::string homeDir()
{
#ifdef ARCH_WIN
if (const char* const userprofile = getenv("USERPROFILE"))
{
return userprofile;
}
else if (const char* const homedrive = getenv("HOMEDRIVE"))
{
if (const char* const homepath = getenv("HOMEPATH"))
return system::join(homedrive, homepath);
}
#else
if (struct passwd* const pwd = getpwuid(getuid()))
return pwd->pw_dir;
else if (const char* const home = getenv("HOME"))
return home;
#endif
return {};
}

struct FileButton : MenuButton { struct FileButton : MenuButton {
Window& window;
CardinalBaseUI* const ui;
const bool isStandalone; const bool isStandalone;


#ifdef HAVE_LIBLO #ifdef HAVE_LIBLO
@@ -133,8 +154,8 @@ struct FileButton : MenuButton {
} }
#endif #endif


FileButton(Window& win, const bool standalone)
: MenuButton(), window(win), isStandalone(standalone) {}
FileButton(CardinalBaseUI* const ui2, const bool standalone)
: MenuButton(), ui(ui2), isStandalone(standalone) {}


void onAction(const ActionEvent& e) override { void onAction(const ActionEvent& e) override {
ui::Menu* menu = createMenu(); ui::Menu* menu = createMenu();
@@ -153,49 +174,30 @@ struct FileButton : MenuButton {
promptClear("The current patch is unsaved. Clear it and open a new patch?", [this]() { promptClear("The current patch is unsaved. Clear it and open a new patch?", [this]() {
std::string dir; std::string dir;
if (! APP->patch->path.empty()) if (! APP->patch->path.empty())
{
dir = system::getDirectory(APP->patch->path); dir = system::getDirectory(APP->patch->path);
}
else else
{
// find home directory
#ifdef ARCH_WIN
if (const char* const userprofile = getenv("USERPROFILE"))
{
dir = userprofile;
}
else if (const char* const homedrive = getenv("HOMEDRIVE"))
{
if (const char* const homepath = getenv("HOMEPATH"))
dir = system::join(homedrive, homepath);
}
#else
if (struct passwd* const pwd = getpwuid(getuid()))
dir = pwd->pw_dir;
else if (const char* const home = getenv("HOME"))
dir = home;
#endif
}
dir = homeDir();


Window::FileBrowserOptions opts; Window::FileBrowserOptions opts;
opts.startDir = dir.c_str(); opts.startDir = dir.c_str();
window.openFileBrowser(opts);
opts.saving = ui->saving = false;
ui->openFileBrowser(opts);
}); });
})); }));


/*
menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() {
APP->patch->saveDialog();
}));

menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() {
APP->patch->saveAsDialog();
}));

menu->addChild(createMenuItem("Save template", "", []() {
APP->patch->saveTemplateDialog();
menu->addChild(createMenuItem("Export...", RACK_MOD_CTRL_NAME "+Shift+S", [this]() {
// see APP->patch->saveAsDialog();
std::string dir;
if (! APP->patch->path.empty())
dir = system::getDirectory(APP->patch->path);
else
dir = homeDir();

Window::FileBrowserOptions opts;
opts.startDir = dir.c_str();
opts.saving = ui->saving = true;
ui->openFileBrowser(opts);
})); }));
*/


#ifdef HAVE_LIBLO #ifdef HAVE_LIBLO
if (oscServer == nullptr || !oscConnected) { if (oscServer == nullptr || !oscConnected) {
@@ -680,7 +682,7 @@ struct MenuBar : widget::OpaqueWidget {
// CardinalPluginContext* const context; // CardinalPluginContext* const context;
MeterLabel* meterLabel; MeterLabel* meterLabel;


MenuBar(Window& window, const bool isStandalone)
MenuBar(CardinalBaseUI* const ui, const bool isStandalone)
: widget::OpaqueWidget() : widget::OpaqueWidget()
// : context(ctx) // : context(ctx)
{ {
@@ -692,7 +694,7 @@ struct MenuBar : widget::OpaqueWidget {
layout->spacing = math::Vec(0, 0); layout->spacing = math::Vec(0, 0);
addChild(layout); addChild(layout);


FileButton* fileButton = new FileButton(window, isStandalone);
FileButton* fileButton = new FileButton(ui, isStandalone);
fileButton->text = "File"; fileButton->text = "File";
layout->addChild(fileButton); layout->addChild(fileButton);


@@ -745,8 +747,8 @@ widget::Widget* createMenuBar() {
return new widget::Widget; return new widget::Widget;
} }


widget::Widget* createMenuBar(Window& window, const bool isStandalone) {
menuBar::MenuBar* menuBar = new menuBar::MenuBar(window, isStandalone);
widget::Widget* createMenuBar(CardinalBaseUI* const ui, const bool isStandalone) {
menuBar::MenuBar* menuBar = new menuBar::MenuBar(ui, isStandalone);
return menuBar; return menuBar;
} }




Loading…
Cancel
Save