Browse Source

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

tags/v2.0.0
Andrew Belt 4 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 { namespace settings {




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

extern bool devMode; extern bool devMode;
extern bool headless; extern bool headless;


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

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


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

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


FramebufferWidget(); FramebufferWidget();
~FramebufferWidget(); ~FramebufferWidget();
void setDirty(bool dirty = true);
void onDirty(const event::Dirty& e) override; void onDirty(const event::Dirty& e) override;
void step() override; void step() override;
void draw(const DrawArgs& args) 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 { struct ModelBox : widget::OpaqueWidget {
plugin::Model* model; plugin::Model* model;
widget::Widget* previewWidget;
ui::Tooltip* tooltip = NULL; 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() { 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) { void setModel(plugin::Model* model) {
this->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() { 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)) { if (math::isNear(APP->window->pixelRatio, 1.0)) {
// Small details draw poorly at low DPI, so oversample when drawing to the framebuffer // 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 { void draw(const DrawArgs& args) override {
// Lazily create preview when drawn // Lazily create preview when drawn
if (!previewFb) {
createPreview();
}
createPreview();


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


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

void setTooltip(ui::Tooltip* tooltip) { void setTooltip(ui::Tooltip* tooltip) {
if (this->tooltip) { if (this->tooltip) {
this->tooltip->requestDelete(); this->tooltip->requestDelete();
@@ -433,9 +444,9 @@ struct ZoomButton : ui::ChoiceButton {
menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y)); menu->box.pos = getAbsoluteOffset(math::Vec(0, box.size.y));
menu->box.size.x = box.size.x; 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; 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->zoom = zoom;
sortItem->browser = browser; sortItem->browser = browser;
menu->addChild(sortItem); menu->addChild(sortItem);
@@ -444,7 +455,7 @@ struct ZoomButton : ui::ChoiceButton {


void step() override { void step() override {
text = "Zoom: "; 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(); ChoiceButton::step();
} }
}; };
@@ -549,6 +560,7 @@ struct ModuleBrowser : widget::OpaqueWidget {
void resetModelBoxes() { void resetModelBoxes() {
modelContainer->clearChildren(); modelContainer->clearChildren();
// Iterate plugins // Iterate plugins
for (int i = 0; i < 100; i++)
for (plugin::Plugin* plugin : plugin::plugins) { for (plugin::Plugin* plugin : plugin::plugins) {
// Get module slugs from module whitelist // Get module slugs from module whitelist
const auto& pluginIt = settings::moduleWhitelist.find(plugin->slug); 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 { void step() override {
box = parent->box.zeroPos().grow(math::Vec(-40, -40)); 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) { 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; bool showTipsOnLaunch = true;
int tipIndex = -1; int tipIndex = -1;
ModuleBrowserSort moduleBrowserSort = MODULE_BROWSER_SORT_UPDATED; 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::set<std::string>> moduleWhitelist = {};
std::map<std::string, std::map<std::string, ModuleUsage>> moduleUsages = {}; 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() { 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(); auto duration = std::chrono::system_clock::now().time_since_epoch();
return std::chrono::duration<double>(duration).count(); 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) { void FramebufferWidget::onDirty(const event::Dirty& e) {
dirty = true; dirty = true;
Widget::onDirty(e); Widget::onDirty(e);


Loading…
Cancel
Save