Browse Source

ModuleBrowser WIP. Add Widget::show/hide().

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
13dadef857
21 changed files with 355 additions and 120 deletions
  1. +1
    -1
      include/app/ModuleWidget.hpp
  2. +20
    -4
      include/dsp/simd.hpp
  3. +16
    -4
      include/event.hpp
  4. +7
    -7
      include/plugin.hpp
  5. +2
    -2
      include/plugin/Model.hpp
  6. +19
    -0
      include/ui/MarginLayout.hpp
  7. +5
    -0
      include/widget/Widget.hpp
  8. +1
    -0
      src/Core/Blank.cpp
  9. +2
    -2
      src/app/LedDisplay.cpp
  10. +175
    -59
      src/app/ModuleBrowser.cpp
  11. +13
    -9
      src/app/ModuleWidget.cpp
  12. +11
    -6
      src/engine/Engine.cpp
  13. +22
    -11
      src/plugin.cpp
  14. +1
    -1
      src/plugin/Model.cpp
  15. +20
    -0
      src/ui/MarginLayout.cpp
  16. +3
    -1
      src/ui/MenuItem.cpp
  17. +4
    -5
      src/ui/ScrollBar.cpp
  18. +1
    -1
      src/ui/ScrollWidget.cpp
  19. +3
    -2
      src/ui/SequentialLayout.cpp
  20. +7
    -5
      src/ui/TextField.cpp
  21. +22
    -0
      src/widget/Widget.cpp

+ 1
- 1
include/app/ModuleWidget.hpp View File

@@ -26,7 +26,7 @@ struct ModuleWidget : widget::OpaqueWidget {
math::Vec dragPos;
math::Vec oldPos;

ModuleWidget() {}
ModuleWidget();
DEPRECATED ModuleWidget(engine::Module *module) {
setModule(module);
}


+ 20
- 4
include/dsp/simd.hpp View File

@@ -1,5 +1,5 @@
#include "common.hpp"
#include "sse_mathfun.h"
#include <cstring>
#include <emmintrin.h>


@@ -7,7 +7,10 @@ namespace rack {
namespace dsp {


/** Casts an int to float, bitwise without conversion. */
inline float cast_i32_f32(int i) {
static_assert(sizeof(int) == sizeof(float), "int and float must be the same size");
// Should be optimized to two `mov` instructions
float f;
std::memcpy(&f, &i, sizeof(f));
return f;
@@ -21,6 +24,17 @@ inline int cast_f32_i32(float f) {
}


/** Generic class for vector float types.

This class is designed to be used just like `float` scalars, with extra features for handling bitwise logic, conditions, loading, and storing.

Usage example:
float a[4], b[4];
f32_4 a = f32_4::load(in);
f32_4 b = 2.f * a / (1 - a);
b *= sin(2 * M_PI * a);
b.store(out);
*/
template <int N>
struct f32;

@@ -65,7 +79,7 @@ typedef f32<4> f32_4;
// Operator overloads


/** `a operator b` */
/** `a @ b` */
#define DECLARE_F32_4_OPERATOR_INFIX(operator, func) \
inline f32_4 operator(const f32_4 &a, const f32_4 &b) { \
return f32_4(func(a.v, b.v)); \
@@ -79,7 +93,7 @@ typedef f32<4> f32_4;
return operator(a, f32_4(b)); \
}

/** `a operator b` */
/** `a @= b` */
#define DECLARE_F32_4_OPERATOR_INCREMENT(operator, opfunc) \
inline f32_4 &operator(f32_4 &a, const f32_4 &b) { \
a = opfunc(a, b); \
@@ -95,7 +109,7 @@ DECLARE_F32_4_OPERATOR_INFIX(operator-, _mm_sub_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator*, _mm_mul_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator/, _mm_div_ps)

/** Boolean operators on vectors give 0x00000000 for false and 0xffffffff for true, for each vector element.
/**
Use these to apply logic, bit masks, and conditions to elements.
Examples:

@@ -106,6 +120,8 @@ DECLARE_F32_4_OPERATOR_INFIX(operator^, _mm_xor_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator&, _mm_and_ps)
DECLARE_F32_4_OPERATOR_INFIX(operator|, _mm_mul_ps)

/** Boolean operators on vectors give 0x00000000 for false and 0xffffffff for true, for each vector element.
*/
DECLARE_F32_4_OPERATOR_INCREMENT(operator+=, operator+);
DECLARE_F32_4_OPERATOR_INCREMENT(operator-=, operator-);
DECLARE_F32_4_OPERATOR_INCREMENT(operator*=, operator*);


+ 16
- 4
include/event.hpp View File

@@ -245,30 +245,42 @@ struct Zoom : Event {
};


/** Occurs after the Widget's position is set by setPos();
/** Occurs after a Widget's position is set by Widget::setPos().
*/
struct Reposition : Event {
};


/** Occurs after the Widget's size is set by setSize();
/** Occurs after a Widget's size is set by Widget::setSize().
*/
struct Resize : Event {
};


/** Occurs after the Widget is added to a parent.
/** Occurs after a Widget is added to a parent.
*/
struct Add : Event {
};


/** Occurs before the Widget is remove from its parent.
/** Occurs before a Widget is removed from its parent.
*/
struct Remove : Event {
};


/** Occurs after a Widget is shown with Widget::show().
*/
struct Show : Event {
};


/** Occurs after a Widget is hidden with Widget::hide().
*/
struct Hide : Event {
};


struct State {
widget::Widget *rootWidget = NULL;
/** State widgets


+ 7
- 7
include/plugin.hpp View File

@@ -3,7 +3,7 @@
#include "plugin/Plugin.hpp"
#include "plugin/Model.hpp"
#include <vector>
#include <list>
#include <set>


namespace rack {
@@ -16,21 +16,21 @@ namespace plugin {

void init(bool devMode);
void destroy();
void logIn(std::string email, std::string password);
void logIn(const std::string &email, const std::string &password);
void logOut();
/** Returns whether a new plugin is available, and downloads it unless doing a dry run */
bool sync(bool dryRun);
void cancelDownload();
bool isLoggedIn();
Plugin *getPlugin(std::string pluginSlug);
Model *getModel(std::string pluginSlug, std::string modelSlug);
std::string getAllowedTag(std::string tag);
Plugin *getPlugin(const std::string &pluginSlug);
Model *getModel(const std::string &pluginSlug, const std::string &modelSlug);
std::string normalizeTag(const std::string &tag);
/** Checks that the slug contains only alphanumeric characters, "-", and "_" */
bool isSlugValid(std::string slug);
bool isSlugValid(const std::string &slug);


extern const std::vector<std::string> allowedTags;
extern std::list<Plugin*> plugins;
extern std::vector<Plugin*> plugins;
extern bool isDownloading;
extern float downloadProgress;
extern std::string downloadName;


+ 2
- 2
include/plugin/Model.hpp View File

@@ -2,7 +2,7 @@
#include "common.hpp"
#include "plugin/Plugin.hpp"
#include <jansson.h>
#include <list>
#include <set>


namespace rack {
@@ -31,7 +31,7 @@ struct Model {
/** Human readable name for your model, e.g. "Voltage Controlled Oscillator" */
std::string name;
/** List of tags representing the function(s) of the module */
std::list<std::string> tags;
std::set<std::string> tags;
/** A one-line summary of the module's purpose */
std::string description;



+ 19
- 0
include/ui/MarginLayout.hpp View File

@@ -0,0 +1,19 @@
#pragma once
#include "widget/Widget.hpp"
#include "ui/common.hpp"


namespace rack {
namespace ui {


/** Positions children with a margin between the layout's box. */
struct MarginLayout : widget::Widget {
math::Vec margin;

void step() override;
};


} // namespace ui
} // namespace rack

+ 5
- 0
include/widget/Widget.hpp View File

@@ -40,6 +40,9 @@ struct Widget {

void setPos(math::Vec pos);
void setSize(math::Vec size);
void show();
void hide();
void requestDelete();

virtual math::Rect getChildrenBoundingBox();
/** Returns `v` transformed into the coordinate system of `relative` */
@@ -156,6 +159,8 @@ struct Widget {
virtual void onResize(const event::Resize &e) {}
virtual void onAdd(const event::Add &e) {}
virtual void onRemove(const event::Remove &e) {}
virtual void onShow(const event::Show &e) {recurseEvent(&Widget::onShow, e);}
virtual void onHide(const event::Hide &e) {recurseEvent(&Widget::onHide, e);}
};




+ 1
- 0
src/Core/Blank.cpp View File

@@ -14,6 +14,7 @@ struct BlankPanel : Widget {

void step() override {
panelBorder->box.size = box.size;
Widget::step();
}

void draw(const DrawContext &ctx) override {


+ 2
- 2
src/app/LedDisplay.cpp View File

@@ -16,7 +16,7 @@ void LedDisplay::draw(const widget::DrawContext &ctx) {
nvgFillColor(ctx.vg, nvgRGB(0x00, 0x00, 0x00));
nvgFill(ctx.vg);

nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y);
nvgScissor(ctx.vg, RECT_ARGS(ctx.clipBox));
widget::Widget::draw(ctx);
nvgResetScissor(ctx.vg);
}
@@ -79,7 +79,7 @@ LedDisplayTextField::LedDisplayTextField() {


void LedDisplayTextField::draw(const widget::DrawContext &ctx) {
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y);
nvgScissor(ctx.vg, RECT_ARGS(ctx.clipBox));

// Background
nvgBeginPath(ctx.vg);


+ 175
- 59
src/app/ModuleBrowser.cpp View File

@@ -4,9 +4,14 @@
#include "widget/ZoomWidget.hpp"
#include "ui/ScrollWidget.hpp"
#include "ui/SequentialLayout.hpp"
#include "ui/MarginLayout.hpp"
#include "ui/Label.hpp"
#include "ui/TextField.hpp"
#include "ui/MenuOverlay.hpp"
#include "ui/List.hpp"
#include "ui/MenuItem.hpp"
#include "ui/Button.hpp"
#include "ui/ChoiceButton.hpp"
#include "app/ModuleWidget.hpp"
#include "app/Scene.hpp"
#include "plugin.hpp"
@@ -68,96 +73,135 @@ struct BrowserOverlay : widget::OpaqueWidget {
return;

if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) {
this->visible = false;
hide();
}
}
};

void onHoverKey(const event::HoverKey &e) override {
if (e.action == GLFW_PRESS) {
switch (e.key) {
case GLFW_KEY_ESCAPE: {
this->visible = false;
e.consume(this);
} break;
}
}

if (!e.getConsumed())
widget::OpaqueWidget::onHoverKey(e);
}
};
static const float MODEL_BOX_ZOOM = 0.5f;


struct ModelBox : widget::OpaqueWidget {
plugin::Model *model;
widget::Widget *infoWidget;
/** Lazily created */
widget::Widget *previewWidget = NULL;
/** Number of frames since draw() has been called */
int visibleFrames = 0;
bool selected = false;

ModelBox() {
box.size.x = 0.f;
box.size.y = std::ceil(RACK_GRID_HEIGHT * MODEL_BOX_ZOOM);
}

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

box.size.x = 70.f;
box.size.y = std::ceil(RACK_GRID_SIZE.y * 0.5f);
infoWidget = new widget::Widget;
infoWidget->box.size.x = 140;
infoWidget->box.size.y = box.size.y;
addChild(infoWidget);

math::Vec p;
p.y = box.size.y;
box.size.y += 40.0;
math::Vec pos;

ui::Label *nameLabel = new ui::Label;
// nameLabel->box.size.x = infoWidget->box.size.x;
nameLabel->box.pos = pos;
nameLabel->text = model->name;
nameLabel->box.pos = p;
p.y += nameLabel->box.size.y;
addChild(nameLabel);
infoWidget->addChild(nameLabel);
pos = nameLabel->box.getBottomLeft();

ui::Label *pluginLabel = new ui::Label;
// pluginLabel->box.size.x = infoWidget->box.size.x;
pluginLabel->box.pos = pos;
pluginLabel->text = model->plugin->name;
pluginLabel->box.pos = p;
p.y += pluginLabel->box.size.y;
addChild(pluginLabel);
infoWidget->addChild(pluginLabel);
pos = pluginLabel->box.getBottomLeft();

ui::Label *descriptionLabel = new ui::Label;
descriptionLabel->box.size.x = infoWidget->box.size.x;
descriptionLabel->box.pos = pos;
descriptionLabel->text = model->description;
infoWidget->addChild(descriptionLabel);
pos = descriptionLabel->box.getBottomLeft();

pos.y = infoWidget->box.size.y;
for (const std::string &tag : model->tags) {
ui::Button *tagButton = new ui::Button;
tagButton->box.size.x = infoWidget->box.size.x;
tagButton->box.pos = pos;
tagButton->box.pos.y -= tagButton->box.size.y;
tagButton->text = tag;
infoWidget->addChild(tagButton);
pos = tagButton->box.getTopLeft();
}

ui::Button *favoriteButton = new ui::Button;
favoriteButton->box.size.x = infoWidget->box.size.x;
favoriteButton->box.pos = pos;
favoriteButton->box.pos.y -= favoriteButton->box.size.y;
favoriteButton->text = "★";
infoWidget->addChild(favoriteButton);
pos = favoriteButton->box.getTopLeft();
}

void createPreview() {
assert(!previewWidget);
previewWidget = new widget::TransparentWidget;
previewWidget->box.size.y = std::ceil(RACK_GRID_HEIGHT * MODEL_BOX_ZOOM);
addChild(previewWidget);

widget::FramebufferWidget *fbWidget = 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
fbWidget->oversample = 2.0;
}
previewWidget->addChild(fbWidget);

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

ModuleWidget *moduleWidget = model->createModuleWidgetNull();
zoomWidget->addChild(moduleWidget);

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);

// Reposition infoWidget
infoWidget->box.pos.x = previewWidget->box.size.x;
box.size.x = previewWidget->box.size.x + infoWidget->box.size.x;
}

void deletePreview() {
assert(previewWidget);
removeChild(previewWidget);
delete previewWidget;
previewWidget = NULL;
}

void step() override {
if (previewWidget && ++visibleFrames >= 60) {
removeChild(previewWidget);
delete previewWidget;
previewWidget = NULL;
deletePreview();
}
}

void draw(const widget::DrawContext &ctx) override {
visibleFrames = 0;

// Lazily create ModuleWidget when drawn
// Lazily create preview when drawn
if (!previewWidget) {
widget::Widget *transparentWidget = new widget::TransparentWidget;
addChild(transparentWidget);

widget::FramebufferWidget *fbWidget = 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
fbWidget->oversample = 2.0;
}
transparentWidget->addChild(fbWidget);

widget::ZoomWidget *zoomWidget = new widget::ZoomWidget;
zoomWidget->setZoom(0.5f);
fbWidget->addChild(zoomWidget);

ModuleWidget *moduleWidget = model->createModuleWidgetNull();
zoomWidget->addChild(moduleWidget);

zoomWidget->box.size.x = moduleWidget->box.size.x * zoomWidget->zoom;
zoomWidget->box.size.y = RACK_GRID_HEIGHT;
float width = std::ceil(zoomWidget->box.size.x);
box.size.x = std::max(box.size.x, width);

previewWidget = transparentWidget;
createPreview();
}

nvgScissor(ctx.vg, RECT_ARGS(ctx.clipBox));
widget::OpaqueWidget::draw(ctx);
nvgResetScissor(ctx.vg);

// Translucent overlay when selected
if (selected) {
nvgBeginPath(ctx.vg);
nvgRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y);
@@ -180,20 +224,82 @@ struct ModelBox : widget::OpaqueWidget {


struct BrowserSearchField : ui::TextField {
void step() override {
// Steal focus when step is called
APP->event->setSelected(this);
ui::TextField::step();
}
void onSelectKey(const event::SelectKey &e) override {
if (e.action == GLFW_PRESS) {
if (e.key == GLFW_KEY_ESCAPE) {
BrowserOverlay *overlay = getAncestorOfType<BrowserOverlay>();
overlay->hide();
e.consume(this);
}
}

if (!e.getConsumed())
ui::TextField::onSelectKey(e);
}
void onChange(const event::Change &e) override;
void onHide(const event::Hide &e) override {
setText("");
APP->event->setSelected(NULL);
ui::TextField::onHide(e);
}
};


struct BrowserSidebar : widget::Widget {
BrowserSearchField *searchField;
ui::List *pluginList;
ui::ScrollWidget *pluginScroll;
ui::List *tagList;
ui::ScrollWidget *tagScroll;

BrowserSidebar() {
searchField = new BrowserSearchField;
addChild(searchField);

pluginScroll = new ui::ScrollWidget;
pluginScroll->box.pos = searchField->box.getBottomLeft();
addChild(pluginScroll);

pluginList = new ui::List;
pluginScroll->container->addChild(pluginList);

std::set<std::string> pluginNames;
for (plugin::Plugin *plugin : plugin::plugins) {
pluginNames.insert(plugin->name);
}

for (const std::string &pluginName : pluginNames) {
ui::MenuItem *item = new ui::MenuItem;
item->text = pluginName;
pluginList->addChild(item);
}

tagScroll = new ui::ScrollWidget;
tagScroll->box.pos = searchField->box.getBottomLeft();
addChild(tagScroll);

tagList = new ui::List;
tagScroll->container->addChild(tagList);

for (const std::string &tag : plugin::allowedTags) {
ui::MenuItem *item = new ui::MenuItem;
item->text = tag;
tagList->addChild(item);
}
}

void step() override {
searchField->box.size.x = box.size.x;
pluginScroll->box.size.y = box.size.y - searchField->box.size.y;
pluginList->box.size.x = pluginScroll->box.size.x = box.size.x / 2;
tagScroll->box.pos.x = box.size.x / 2;
tagScroll->box.size.y = box.size.y - searchField->box.size.y;
tagList->box.size.x = tagScroll->box.size.x = box.size.x / 2;
widget::Widget::step();
}
};
@@ -202,6 +308,7 @@ struct BrowserSidebar : widget::Widget {
struct ModuleBrowser : widget::OpaqueWidget {
BrowserSidebar *sidebar;
ui::ScrollWidget *modelScroll;
ui::MarginLayout *modelMargin;
ui::SequentialLayout *modelContainer;

ModuleBrowser() {
@@ -212,9 +319,13 @@ struct ModuleBrowser : widget::OpaqueWidget {
modelScroll = new ui::ScrollWidget;
addChild(modelScroll);

modelMargin = new ui::MarginLayout;
modelMargin->margin = math::Vec(20, 20);
modelScroll->container->addChild(modelMargin);

modelContainer = new ui::SequentialLayout;
modelContainer->spacing = math::Vec(10, 10);
modelScroll->container->addChild(modelContainer);
modelContainer->spacing = math::Vec(20, 20);
modelMargin->addChild(modelContainer);

for (plugin::Plugin *plugin : plugin::plugins) {
for (plugin::Model *model : plugin->models) {
@@ -233,8 +344,8 @@ struct ModuleBrowser : widget::OpaqueWidget {
modelScroll->box.pos.x = sidebar->box.size.x;
modelScroll->box.size.x = box.size.x - sidebar->box.size.x;
modelScroll->box.size.y = box.size.y;
modelContainer->box.size.x = modelScroll->box.size.x;
modelContainer->box.size.y = modelContainer->getChildrenBoundingBox().getBottomRight().y;
modelMargin->box.size.x = modelScroll->box.size.x;
modelMargin->box.size.y = modelContainer->getChildrenBoundingBox().size.y + 2 * modelMargin->margin.y;

widget::OpaqueWidget::step();
}
@@ -251,6 +362,8 @@ struct ModuleBrowser : widget::OpaqueWidget {
bool match = isModelMatch(modelBox->model, search);
modelBox->visible = match;
}
// Reset scroll position
modelScroll->offset = math::Vec();
}
};

@@ -259,6 +372,10 @@ struct ModuleBrowser : widget::OpaqueWidget {


void ModelBox::onButton(const event::Button &e) {
widget::OpaqueWidget::onButton(e);
if (e.getConsumed() != this)
return;

if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) {
// Create module
ModuleWidget *moduleWidget = model->createModuleWidget();
@@ -268,9 +385,9 @@ void ModelBox::onButton(const event::Button &e) {
// Pretend the moduleWidget was clicked so it can be dragged in the RackWidget
e.consume(moduleWidget);

// Close Module Browser
// Hide Module Browser
BrowserOverlay *overlay = getAncestorOfType<BrowserOverlay>();
overlay->visible = false;
overlay->hide();

// Push ModuleAdd history action
history::ModuleAdd *h = new history::ModuleAdd;
@@ -278,7 +395,6 @@ void ModelBox::onButton(const event::Button &e) {
h->setModule(moduleWidget);
APP->history->push(h);
}
widget::OpaqueWidget::onButton(e);
}

void BrowserSearchField::onChange(const event::Change &e) {


+ 13
- 9
src/app/ModuleWidget.cpp View File

@@ -133,15 +133,21 @@ struct ModuleDeleteItem : ui::MenuItem {
};


ModuleWidget::ModuleWidget() {
box.size = math::Vec(0, RACK_GRID_HEIGHT);
}

ModuleWidget::~ModuleWidget() {
setModule(NULL);
}

void ModuleWidget::draw(const widget::DrawContext &ctx) {
nvgScissor(ctx.vg, RECT_ARGS(ctx.clipBox));

if (module && module->bypass) {
nvgGlobalAlpha(ctx.vg, 0.25);
}
// nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y);
widget::Widget::draw(ctx);

// Power meter
@@ -175,7 +181,7 @@ void ModuleWidget::draw(const widget::DrawContext &ctx) {
// bndLabel(ctx.vg, 0, 0, INFINITY, INFINITY, -1, debugText.c_str());
// }

// nvgResetScissor(ctx.vg);
nvgResetScissor(ctx.vg);
}

void ModuleWidget::drawShadow(const widget::DrawContext &ctx) {
@@ -307,13 +313,11 @@ void ModuleWidget::setPanel(std::shared_ptr<Svg> svg) {
panel = NULL;
}

{
SvgPanel *panel = new SvgPanel;
panel->setBackground(svg);
addChild(panel);
box.size = panel->box.size;
this->panel = panel;
}
SvgPanel *svgPanel = new SvgPanel;
svgPanel->setBackground(svg);
addChild(svgPanel);
box.size.x = svgPanel->box.size.x;
panel = svgPanel;
}

void ModuleWidget::addParam(ParamWidget *param) {


+ 11
- 6
src/engine/Engine.cpp View File

@@ -17,6 +17,14 @@ namespace rack {
namespace engine {


void disableDenormals() {
// Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode
// https://software.intel.com/en-us/node/682949
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
}


/** Threads which obtain a VIPLock will cause wait() to block for other less important threads.
This does not provide the VIPs with an exclusive lock. That should be left up to another mutex shared between the less important thread.
*/
@@ -111,6 +119,7 @@ struct EngineWorker {
void run() {
system::setThreadName("Engine worker");
system::setThreadRealTime();
disableDenormals();
while (running) {
step();
}
@@ -179,7 +188,7 @@ Engine::~Engine() {
static void Engine_stepModules(Engine *engine, int threadId) {
Engine::Internal *internal = engine->internal;

int threadCount = internal->threadCount;
// int threadCount = internal->threadCount;
int modulesLen = internal->modules.size();

// Step each module
@@ -259,11 +268,7 @@ static void Engine_run(Engine *engine) {
// Set up thread
system::setThreadName("Engine");
system::setThreadRealTime();

// Set CPU to flush-to-zero (FTZ) and denormals-are-zero (DAZ) mode
// https://software.intel.com/en-us/node/682949
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
_MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
disableDenormals();

// Every time the engine waits and locks a mutex, it steps this many frames
const int mutexSteps = 64;


+ 22
- 11
src/plugin.cpp View File

@@ -116,6 +116,17 @@ static bool loadPlugin(std::string path) {
initCallback(plugin);
plugin->fromJson(rootJ);

// Normalize tags
for (Model *model : plugin->models) {
std::set<std::string> normalizedTags;
for (const std::string &tag : model->tags) {
std::string normalizedTag = normalizeTag(tag);
if (!normalizedTag.empty())
normalizedTags.insert(normalizedTag);
}
model->tags = normalizedTags;
}

// Check slug
if (!isSlugValid(plugin->slug)) {
WARN("Plugin slug \"%s\" is invalid", plugin->slug.c_str());
@@ -305,7 +316,7 @@ static int extractZip(const char *filename, const char *path) {
return err;
}

static void extractPackages(std::string path) {
static void extractPackages(const std::string &path) {
std::string message;

for (std::string packagePath : system::listEntries(path)) {
@@ -374,7 +385,7 @@ void destroy() {
plugins.clear();
}

void logIn(std::string email, std::string password) {
void logIn(const std::string &email, const std::string &password) {
json_t *reqJ = json_object();
json_object_set(reqJ, "email", json_string(email.c_str()));
json_object_set(reqJ, "password", json_string(password.c_str()));
@@ -496,7 +507,7 @@ bool isLoggedIn() {
return settings.token != "";
}

Plugin *getPlugin(std::string pluginSlug) {
Plugin *getPlugin(const std::string &pluginSlug) {
for (Plugin *plugin : plugins) {
if (plugin->slug == pluginSlug) {
return plugin;
@@ -505,7 +516,7 @@ Plugin *getPlugin(std::string pluginSlug) {
return NULL;
}

Model *getModel(std::string pluginSlug, std::string modelSlug) {
Model *getModel(const std::string &pluginSlug, const std::string &modelSlug) {
Plugin *plugin = getPlugin(pluginSlug);
if (!plugin)
return NULL;
@@ -599,21 +610,21 @@ const std::map<std::string, std::string> tagAliases = {
};


std::string getAllowedTag(std::string tag) {
tag = string::lowercase(tag);
std::string normalizeTag(const std::string &tag) {
std::string lowercaseTag = string::lowercase(tag);
// Transform aliases
auto it = tagAliases.find(tag);
auto it = tagAliases.find(lowercaseTag);
if (it != tagAliases.end())
tag = it->second;
lowercaseTag = it->second;
// Find allowed tag
for (std::string allowedTag : allowedTags) {
if (tag == string::lowercase(allowedTag))
if (lowercaseTag == string::lowercase(allowedTag))
return allowedTag;
}
return "";
}

bool isSlugValid(std::string slug) {
bool isSlugValid(const std::string &slug) {
for (char c : slug) {
if (!(std::isalnum(c) || c == '-' || c == '_'))
return false;
@@ -622,7 +633,7 @@ bool isSlugValid(std::string slug) {
}


std::list<Plugin*> plugins;
std::vector<Plugin*> plugins;
bool isDownloading = false;
float downloadProgress = 0.f;
std::string downloadName;


+ 1
- 1
src/plugin/Model.cpp View File

@@ -20,7 +20,7 @@ void Model::fromJson(json_t *rootJ) {
json_t *tagJ;
json_array_foreach(tagsJ, i, tagJ) {
std::string tag = json_string_value(tagJ);
tags.push_back(tag);
tags.insert(tag);
}
}
}


+ 20
- 0
src/ui/MarginLayout.cpp View File

@@ -0,0 +1,20 @@
#include "ui/MarginLayout.hpp"
#include <vector>


namespace rack {
namespace ui {


void MarginLayout::step() {
widget::Widget::step();

math::Rect childBox = box.zeroPos().grow(margin.neg());
for (Widget *child : children) {
child->box = childBox;
}
}


} // namespace ui
} // namespace rack

+ 3
- 1
src/ui/MenuItem.cpp View File

@@ -78,7 +78,9 @@ void MenuItem::doAction() {
return;

widget::Widget *overlay = getAncestorOfType<MenuOverlay>();
overlay->requestedDelete = true;
if (overlay) {
overlay->requestedDelete = true;
}
}




+ 4
- 5
src/ui/ScrollBar.cpp View File

@@ -8,9 +8,6 @@ namespace rack {
namespace ui {


static const float SCROLLBAR_SENSITIVITY = 2.f;


ScrollBar::ScrollBar() {
box.size = math::Vec(BND_SCROLLBAR_WIDTH, BND_SCROLLBAR_HEIGHT);
}
@@ -26,12 +23,14 @@ void ScrollBar::onDragStart(const event::DragStart &e) {
}

void ScrollBar::onDragMove(const event::DragMove &e) {
const float sensitivity = 1.f;

ScrollWidget *scrollWidget = dynamic_cast<ScrollWidget*>(parent);
assert(scrollWidget);
if (orientation == HORIZONTAL)
scrollWidget->offset.x += SCROLLBAR_SENSITIVITY * e.mouseDelta.x;
scrollWidget->offset.x += sensitivity * e.mouseDelta.x;
else
scrollWidget->offset.y += SCROLLBAR_SENSITIVITY * e.mouseDelta.y;
scrollWidget->offset.y += sensitivity * e.mouseDelta.y;
}

void ScrollBar::onDragEnd(const event::DragEnd &e) {


+ 1
- 1
src/ui/ScrollWidget.cpp View File

@@ -28,7 +28,7 @@ void ScrollWidget::scrollTo(math::Rect r) {
}

void ScrollWidget::draw(const widget::DrawContext &ctx) {
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y);
nvgScissor(ctx.vg, RECT_ARGS(ctx.clipBox));
widget::Widget::draw(ctx);
nvgResetScissor(ctx.vg);
}


+ 3
- 2
src/ui/SequentialLayout.cpp View File

@@ -6,8 +6,9 @@ namespace rack {
namespace ui {


#define X(_v) (orientation == HORIZONTAL_ORIENTATION ? (_v).x : (_v).y)
#define Y(_v) (orientation == HORIZONTAL_ORIENTATION ? (_v).y : (_v).x)
#define X(v) (orientation == HORIZONTAL_ORIENTATION ? (v).x : (v).y)
#define Y(v) (orientation == HORIZONTAL_ORIENTATION ? (v).y : (v).x)


void SequentialLayout::step() {
widget::Widget::step();


+ 7
- 5
src/ui/TextField.cpp View File

@@ -9,7 +9,7 @@ TextField::TextField() {
}

void TextField::draw(const widget::DrawContext &ctx) {
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y);
nvgScissor(ctx.vg, RECT_ARGS(ctx.clipBox));

BNDwidgetState state;
if (this == APP->event->selectedWidget)
@@ -180,7 +180,6 @@ void TextField::onSelectKey(const event::SelectKey &e) {
}
}

/** Inserts text at the cursor, replacing the selection if necessary */
void TextField::insertText(std::string text) {
if (cursor != selection) {
int begin = std::min(cursor, selection);
@@ -194,12 +193,15 @@ void TextField::insertText(std::string text) {
onChange(eChange);
}

/** Replaces the entire text */
void TextField::setText(std::string text) {
bool changed = (text != this->text);
this->text = text;
selection = cursor = text.size();
event::Change eChange;
onChange(eChange);
if (changed) {
// event::Change
event::Change eChange;
onChange(eChange);
}
}

void TextField::selectAll() {


+ 22
- 0
src/widget/Widget.cpp View File

@@ -28,6 +28,28 @@ void Widget::setSize(math::Vec size) {
onResize(eResize);
}

void Widget::show() {
if (visible)
return;
visible = true;
// event::Show
event::Show eShow;
onShow(eShow);
}

void Widget::hide() {
if (!visible)
return;
visible = false;
// event::Hide
event::Hide eHide;
onHide(eHide);
}

void Widget::requestDelete() {
requestedDelete = true;
}

math::Rect Widget::getChildrenBoundingBox() {
math::Vec min = math::Vec(INFINITY, INFINITY);
math::Vec max = math::Vec(-INFINITY, -INFINITY);


Loading…
Cancel
Save