Browse Source

Rewrite module browser's ModelBox to support changing zoom. Add FramebufferWidget::setDirty().

tags/v2.0.0
Andrew Belt 3 years ago
parent
commit
ac0588c0f8
6 changed files with 79 additions and 38 deletions
  1. +12
    -2
      include/settings.hpp
  2. +1
    -0
      include/widget/FramebufferWidget.hpp
  3. +58
    -35
      src/app/ModuleBrowser.cpp
  4. +1
    -1
      src/settings.cpp
  5. +2
    -0
      src/system.cpp
  6. +5
    -0
      src/widget/FramebufferWidget.cpp

+ 12
- 2
include/settings.hpp View File

@@ -19,18 +19,28 @@ namespace rack {
namespace settings {


/** Runtime state, not serialized. */
// Runtime state, not serialized.

extern bool devMode;
extern bool headless;

/** Persistent state, serialized to settings.json. */
// Persistent state, serialized to settings.json.

/** vcvrack.com user token */
extern std::string token;
/** Size of window in pixels */
extern math::Vec windowSize;
/** Position in window in pixels */
extern math::Vec windowPos;
/** Rack zoom level, log2. E.g. 100% = 0, 200% = 1, 50% = -1. */
extern float zoom;
/** Reverse the zoom scroll direction */
extern bool invertZoom;
/** Opacity of cables in the range [0, 1] */
extern float cableOpacity;
/** Straightness of cables in the range [0, 1]. Unitless and arbitrary. */
extern float cableTension;
/** Allows rack to hide and lock the cursor position when dragging knobs etc. */
extern bool allowCursorLock;
enum KnobMode {
KNOB_MODE_LINEAR,


+ 1
- 0
include/widget/FramebufferWidget.hpp View File

@@ -23,6 +23,7 @@ struct FramebufferWidget : Widget {

FramebufferWidget();
~FramebufferWidget();
void setDirty(bool dirty = true);
void onDirty(const event::Dirty& e) override;
void step() override;
void draw(const DrawArgs& args) override;


+ 58
- 35
src/app/ModuleBrowser.cpp View File

@@ -127,59 +127,66 @@ struct BrowserOverlay : ui::MenuOverlay {
};


static const float MODEL_BOX_ZOOM = 0.5f;


struct ModelBox : widget::OpaqueWidget {
plugin::Model* model;
widget::Widget* previewWidget;
ui::Tooltip* tooltip = NULL;
/** Lazily created */
widget::FramebufferWidget* previewFb = NULL;
// Lazily created widgets
widget::Widget* previewWidget = NULL;
widget::ZoomWidget* zoomWidget = NULL;
widget::FramebufferWidget* fb = NULL;
ModuleWidget* moduleWidget = NULL;

ModelBox() {
// Approximate size as 10HP before we know the actual size.
// We need a nonzero size, otherwise the parent widget will consider it not in the draw bounds, so its preview will not be lazily created.
box.size.x = 10 * RACK_GRID_WIDTH * MODEL_BOX_ZOOM;
box.size.y = RACK_GRID_HEIGHT * MODEL_BOX_ZOOM;
box.size = box.size.ceil();
updateZoom();
}

void setModel(plugin::Model* model) {
this->model = model;
}

previewWidget = new widget::TransparentWidget;
previewWidget->box.size.y = std::ceil(RACK_GRID_HEIGHT * MODEL_BOX_ZOOM);
addChild(previewWidget);
void updateZoom() {
float zoom = std::pow(2.f, settings::moduleBrowserZoom);

if (previewWidget) {
fb->setDirty();
zoomWidget->setZoom(zoom);
box.size.x = moduleWidget->box.size.x * zoom;
}
else {
// Approximate size as 12HP before we know the actual size.
// We need a nonzero size, otherwise too many ModelBoxes will lazily render in the same frame.
box.size.x = 12 * RACK_GRID_WIDTH * zoom;
}
box.size.y = RACK_GRID_HEIGHT * zoom;
box.size = box.size.ceil();
}

void createPreview() {
previewFb = new widget::FramebufferWidget;
if (previewWidget)
return;

previewWidget = new widget::TransparentWidget;
addChild(previewWidget);

zoomWidget = new widget::ZoomWidget;
previewWidget->addChild(zoomWidget);

fb = new widget::FramebufferWidget;
if (math::isNear(APP->window->pixelRatio, 1.0)) {
// Small details draw poorly at low DPI, so oversample when drawing to the framebuffer
previewFb->oversample = 2.0;
fb->oversample = 2.0;
}
previewWidget->addChild(previewFb);

widget::ZoomWidget* zoomWidget = new widget::ZoomWidget;
zoomWidget->setZoom(MODEL_BOX_ZOOM);
previewFb->addChild(zoomWidget);

ModuleWidget* moduleWidget = model->createModuleWidget(NULL);
zoomWidget->addChild(moduleWidget);
zoomWidget->addChild(fb);

zoomWidget->box.size.x = moduleWidget->box.size.x * MODEL_BOX_ZOOM;
zoomWidget->box.size.y = RACK_GRID_HEIGHT * MODEL_BOX_ZOOM;
previewWidget->box.size.x = std::ceil(zoomWidget->box.size.x);
moduleWidget = model->createModuleWidget(NULL);
fb->addChild(moduleWidget);

box.size.x = previewWidget->box.size.x;
updateZoom();
}

void draw(const DrawArgs& args) override {
// Lazily create preview when drawn
if (!previewFb) {
createPreview();
}
createPreview();

// Draw shadow
nvgBeginPath(args.vg);
@@ -194,6 +201,10 @@ struct ModelBox : widget::OpaqueWidget {
OpaqueWidget::draw(args);
}

void step() override {
OpaqueWidget::step();
}

void setTooltip(ui::Tooltip* tooltip) {
if (this->tooltip) {
this->tooltip->requestDelete();
@@ -433,9 +444,9 @@ struct ZoomButton : ui::ChoiceButton {
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
menu->box.size.x = box.size.x;

for (int zoom = 0; zoom >= -3; zoom--) {
for (float zoom = 0.f; zoom >= -2.f; zoom -= 0.5f) {
ZoomItem* sortItem = new ZoomItem;
sortItem->text = string::f("%g%%", std::pow(2.f, zoom) * 100.f);
sortItem->text = string::f("%.3g%%", std::pow(2.f, zoom) * 100.f);
sortItem->zoom = zoom;
sortItem->browser = browser;
menu->addChild(sortItem);
@@ -444,7 +455,7 @@ struct ZoomButton : ui::ChoiceButton {

void step() override {
text = "Zoom: ";
text += string::f("%g%%", std::pow(2.f, settings::moduleBrowserZoom) * 100.f);
text += string::f("%.3g%%", std::pow(2.f, settings::moduleBrowserZoom) * 100.f);
ChoiceButton::step();
}
};
@@ -549,6 +560,7 @@ struct ModuleBrowser : widget::OpaqueWidget {
void resetModelBoxes() {
modelContainer->clearChildren();
// Iterate plugins
for (int i = 0; i < 100; i++)
for (plugin::Plugin* plugin : plugin::plugins) {
// Get module slugs from module whitelist
const auto& pluginIt = settings::moduleWhitelist.find(plugin->slug);
@@ -569,6 +581,14 @@ struct ModuleBrowser : widget::OpaqueWidget {
}
}

void updateZoom() {
for (Widget* w : modelContainer->children) {
ModelBox* mb = reinterpret_cast<ModelBox*>(w);
assert(mb);
mb->updateZoom();
}
}

void step() override {
box = parent->box.zeroPos().grow(math::Vec(-40, -40));

@@ -850,7 +870,10 @@ inline void SortItem::onAction(const event::Action& e) {
}

inline void ZoomItem::onAction(const event::Action& e) {
settings::moduleBrowserZoom = zoom;
if (zoom != settings::moduleBrowserZoom) {
settings::moduleBrowserZoom = zoom;
browser->updateZoom();
}
}




+ 1
- 1
src/settings.cpp View File

@@ -53,7 +53,7 @@ bool autoCheckUpdates = true;
bool showTipsOnLaunch = true;
int tipIndex = -1;
ModuleBrowserSort moduleBrowserSort = MODULE_BROWSER_SORT_UPDATED;
float moduleBrowserZoom = -2.f;
float moduleBrowserZoom = -1.f;
std::map<std::string, std::set<std::string>> moduleWhitelist = {};
std::map<std::string, std::map<std::string, ModuleUsage>> moduleUsages = {};



+ 2
- 0
src/system.cpp View File

@@ -589,6 +589,8 @@ double getRuntime() {


double getUnixTime() {
// This is not guaranteed to return the time since 1970 in C++11. (It only does in C++20).
// However, it does on all platforms I care about.
auto duration = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration<double>(duration).count();
}


+ 5
- 0
src/widget/FramebufferWidget.cpp View File

@@ -44,6 +44,11 @@ FramebufferWidget::~FramebufferWidget() {
}


void FramebufferWidget::setDirty(bool dirty) {
this->dirty = dirty;
}


void FramebufferWidget::onDirty(const event::Dirty& e) {
dirty = true;
Widget::onDirty(e);


Loading…
Cancel
Save