@@ -8,7 +8,7 @@ run: doxygen | |||||
http-server html | http-server html | ||||
upload: doxygen | upload: doxygen | ||||
rsync html/ vcvrack.com:vcvrack.com/docs/ -ruvz --delete | |||||
rsync html/ vcvrack.com:vcvrack.com/docs/ -ruz --info=progress2 --delete | |||||
clean: | clean: | ||||
rm -rfv html | rm -rfv html |
@@ -1,5 +1,11 @@ | |||||
#pragma once | #pragma once | ||||
#include "rack.hpp" | |||||
#include "app/SvgKnob.hpp" | |||||
#include "app/SvgSlider.hpp" | |||||
#include "app/SvgPort.hpp" | |||||
#include "app/ModuleLightWidget.hpp" | |||||
#include "app/SvgSwitch.hpp" | |||||
#include "app/SvgScrew.hpp" | |||||
#include "asset.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -294,7 +300,7 @@ struct SynthTechAlco : app::SvgKnob { | |||||
minAngle = -0.82*M_PI; | minAngle = -0.82*M_PI; | ||||
maxAngle = 0.82*M_PI; | maxAngle = 0.82*M_PI; | ||||
setSvg(APP->window->loadSvg(asset::system("res/ComponentLibrary/SynthTechAlco.svg"))); | setSvg(APP->window->loadSvg(asset::system("res/ComponentLibrary/SynthTechAlco.svg"))); | ||||
SvgWidget *cap = new SvgWidget; | |||||
widget::SvgWidget *cap = new widget::SvgWidget; | |||||
cap->setSvg(APP->window->loadSvg(asset::system("res/ComponentLibrary/SynthTechAlco_cap.svg"))); | cap->setSvg(APP->window->loadSvg(asset::system("res/ComponentLibrary/SynthTechAlco_cap.svg"))); | ||||
addChild(cap); | addChild(cap); | ||||
} | } | ||||
@@ -344,8 +350,8 @@ struct BefacoSlidePot : app::SvgSlider { | |||||
struct LEDSlider : app::SvgSlider { | struct LEDSlider : app::SvgSlider { | ||||
LEDSlider() { | LEDSlider() { | ||||
maxHandlePos = mm2px(math::Vec(0.738, 0.738).plus(math::Vec(2, 0))); | |||||
minHandlePos = mm2px(math::Vec(0.738, 22.078).plus(math::Vec(2, 0))); | |||||
maxHandlePos = app::mm2px(math::Vec(0.738, 0.738).plus(math::Vec(2, 0))); | |||||
minHandlePos = app::mm2px(math::Vec(0.738, 22.078).plus(math::Vec(2, 0))); | |||||
setBackgroundSvg(APP->window->loadSvg(asset::system("res/ComponentLibrary/LEDSlider.svg"))); | setBackgroundSvg(APP->window->loadSvg(asset::system("res/ComponentLibrary/LEDSlider.svg"))); | ||||
} | } | ||||
}; | }; | ||||
@@ -467,7 +473,7 @@ struct RGBLight : app::ModuleLightWidget { | |||||
template <typename BASE> | template <typename BASE> | ||||
struct LargeLight : BASE { | struct LargeLight : BASE { | ||||
LargeLight() { | LargeLight() { | ||||
this->box.size = mm2px(math::Vec(5.179, 5.179)); | |||||
this->box.size = app::mm2px(math::Vec(5.179, 5.179)); | |||||
} | } | ||||
}; | }; | ||||
@@ -475,7 +481,7 @@ struct LargeLight : BASE { | |||||
template <typename BASE> | template <typename BASE> | ||||
struct MediumLight : BASE { | struct MediumLight : BASE { | ||||
MediumLight() { | MediumLight() { | ||||
this->box.size = mm2px(math::Vec(3.176, 3.176)); | |||||
this->box.size = app::mm2px(math::Vec(3.176, 3.176)); | |||||
} | } | ||||
}; | }; | ||||
@@ -483,7 +489,7 @@ struct MediumLight : BASE { | |||||
template <typename BASE> | template <typename BASE> | ||||
struct SmallLight : BASE { | struct SmallLight : BASE { | ||||
SmallLight() { | SmallLight() { | ||||
this->box.size = mm2px(math::Vec(2.176, 2.176)); | |||||
this->box.size = app::mm2px(math::Vec(2.176, 2.176)); | |||||
} | } | ||||
}; | }; | ||||
@@ -491,7 +497,7 @@ struct SmallLight : BASE { | |||||
template <typename BASE> | template <typename BASE> | ||||
struct TinyLight : BASE { | struct TinyLight : BASE { | ||||
TinyLight() { | TinyLight() { | ||||
this->box.size = mm2px(math::Vec(1.088, 1.088)); | |||||
this->box.size = app::mm2px(math::Vec(1.088, 1.088)); | |||||
} | } | ||||
}; | }; | ||||
@@ -500,18 +506,18 @@ template <typename BASE> | |||||
struct LEDBezelLight : BASE { | struct LEDBezelLight : BASE { | ||||
LEDBezelLight() { | LEDBezelLight() { | ||||
this->bgColor = color::BLACK_TRANSPARENT; | this->bgColor = color::BLACK_TRANSPARENT; | ||||
this->box.size = mm2px(math::Vec(6.0, 6.0)); | |||||
this->box.size = app::mm2px(math::Vec(6.0, 6.0)); | |||||
} | } | ||||
}; | }; | ||||
/** A light to displayed over PB61303. Must add a color by subclassing or templating. | /** A light to displayed over PB61303. Must add a color by subclassing or templating. | ||||
Don't add this as a child of the PB61303 itself. Instead, just place it over it as a sibling in the scene graph, offset by mm2px(math::Vec(0.5, 0.5)). | |||||
Don't add this as a child of the PB61303 itself. Instead, just place it over it as a sibling in the scene graph, offset by app::mm2px(math::Vec(0.5, 0.5)). | |||||
*/ | */ | ||||
template <typename BASE> | template <typename BASE> | ||||
struct PB61303Light : BASE { | struct PB61303Light : BASE { | ||||
PB61303Light() { | PB61303Light() { | ||||
this->bgColor = color::BLACK_TRANSPARENT; | this->bgColor = color::BLACK_TRANSPARENT; | ||||
this->box.size = mm2px(math::Vec(9.0, 9.0)); | |||||
this->box.size = app::mm2px(math::Vec(9.0, 9.0)); | |||||
} | } | ||||
}; | }; | ||||
@@ -18,8 +18,8 @@ void alignedDelete(T *p) { | |||||
} | } | ||||
/** Real-valued FFT context | |||||
Wrapper for PFFFT (https://bitbucket.org/jpommier/pffft/) | |||||
/** Real-valued FFT context. | |||||
Wrapper for [PFFFT](https://bitbucket.org/jpommier/pffft/) | |||||
`length` must be a multiple of 32. | `length` must be a multiple of 32. | ||||
*/ | */ | ||||
struct RealFFT { | struct RealFFT { | ||||
@@ -72,8 +72,7 @@ struct RealFFT { | |||||
pffft_transform_ordered(setup, input, output, NULL, PFFFT_BACKWARD); | pffft_transform_ordered(setup, input, output, NULL, PFFFT_BACKWARD); | ||||
} | } | ||||
/** Scales the RFFT so that | |||||
scale(IFFT(FFT(x))) = x | |||||
/** Scales the RFFT so that `scale(IFFT(FFT(x))) = x`. | |||||
*/ | */ | ||||
void scale(float *x) { | void scale(float *x) { | ||||
float a = 1.f / length; | float a = 1.f / length; | ||||
@@ -84,7 +83,7 @@ struct RealFFT { | |||||
}; | }; | ||||
/** Complex-valued FFT context | |||||
/** Complex-valued FFT context. | |||||
`length` must be a multiple of 16. | `length` must be a multiple of 16. | ||||
*/ | */ | ||||
struct ComplexFFT { | struct ComplexFFT { | ||||
@@ -6,7 +6,7 @@ namespace rack { | |||||
namespace dsp { | namespace dsp { | ||||
/** Deprecated. Use VuMeter2. */ | |||||
/** Deprecated. Use VuMeter2 instead. */ | |||||
struct VuMeter { | struct VuMeter { | ||||
/** Decibel level difference between adjacent meter lights */ | /** Decibel level difference between adjacent meter lights */ | ||||
float dBInterval = 3.0; | float dBInterval = 3.0; | ||||
@@ -34,17 +34,18 @@ DEPRECATED typedef VuMeter VUMeter; | |||||
/** Models a VU meter with smoothing. | /** Models a VU meter with smoothing. | ||||
Supports peak and RMS (root-mean-square) metering | |||||
Supports peak and RMS (root-mean-square) metering. | |||||
Usage example for a strip of lights with 3dB increments: | Usage example for a strip of lights with 3dB increments: | ||||
// Update VuMeter state every frame. | |||||
vuMeter.process(deltaTime, output); | |||||
// Iterate lights every ~512 frames (less than a screen refresh). | |||||
for (int i = 0; i < 6; i++) { | |||||
float b = vuMeter.getBrightness(-3.f * (i + 1), -3.f * i); | |||||
// No need to use setSmoothBrightness() since VuMeter2 smooths the value for you. | |||||
lights[i].setBrightness(b); | |||||
} | |||||
``` | |||||
// Update VuMeter state every frame. | |||||
vuMeter.process(deltaTime, output); | |||||
// Iterate lights every ~512 frames (less than a screen refresh). | |||||
for (int i = 0; i < 6; i++) { | |||||
float b = vuMeter.getBrightness(-3.f * (i + 1), -3.f * i); | |||||
// No need to use setSmoothBrightness() since VuMeter2 smooths the value for you. | |||||
lights[i].setBrightness(b); | |||||
} | |||||
``` | |||||
*/ | */ | ||||
struct VuMeter2 { | struct VuMeter2 { | ||||
enum Mode { | enum Mode { | ||||
@@ -1,7 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include "common.hpp" | #include "common.hpp" | ||||
#include <jansson.h> | #include <jansson.h> | ||||
#include <list> | |||||
#include <vector> | |||||
namespace rack { | namespace rack { | ||||
@@ -14,7 +14,7 @@ struct Model; | |||||
// Subclass this and return a pointer to a new one when init() is called | // Subclass this and return a pointer to a new one when init() is called | ||||
struct Plugin { | struct Plugin { | ||||
/** A list of the models available by this plugin, add with addModel() */ | /** A list of the models available by this plugin, add with addModel() */ | ||||
std::list<Model*> models; | |||||
std::vector<Model*> models; | |||||
/** The file path of the plugin's directory */ | /** The file path of the plugin's directory */ | ||||
std::string path; | std::string path; | ||||
/** OS-dependent library handle */ | /** OS-dependent library handle */ | ||||
@@ -1,4 +1,5 @@ | |||||
#pragma once | #pragma once | ||||
// Include most Rack headers for convenience | // Include most Rack headers for convenience | ||||
#include "common.hpp" | #include "common.hpp" | ||||
#include "math.hpp" | #include "math.hpp" | ||||
@@ -11,6 +12,7 @@ | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "midi.hpp" | #include "midi.hpp" | ||||
#include "helpers.hpp" | #include "helpers.hpp" | ||||
#include "component.hpp" | |||||
#include "widget/Widget.hpp" | #include "widget/Widget.hpp" | ||||
#include "widget/TransparentWidget.hpp" | #include "widget/TransparentWidget.hpp" | ||||
@@ -90,9 +92,12 @@ | |||||
#include "dsp/vumeter.hpp" | #include "dsp/vumeter.hpp" | ||||
#include "dsp/window.hpp" | #include "dsp/window.hpp" | ||||
namespace rack { | namespace rack { | ||||
/** Define this macro before including this header to prevent common namespaces from being included in the main `rack::` namespace. */ | |||||
#ifndef RACK_FLATTEN_NAMESPACES | |||||
// Import some namespaces for convenience | // Import some namespaces for convenience | ||||
using namespace math; | using namespace math; | ||||
using namespace widget; | using namespace widget; | ||||
@@ -101,9 +106,8 @@ using namespace app; | |||||
using plugin::Plugin; | using plugin::Plugin; | ||||
using plugin::Model; | using plugin::Model; | ||||
using namespace engine; | using namespace engine; | ||||
namespace component {} | |||||
using namespace component; | using namespace component; | ||||
#endif | |||||
} // namespace rack | } // namespace rack |
@@ -6,6 +6,7 @@ | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "patch.hpp" | #include "patch.hpp" | ||||
#include "settings.hpp" | #include "settings.hpp" | ||||
#include "engine/Port.hpp" | |||||
namespace rack { | namespace rack { | ||||
@@ -219,7 +220,7 @@ void CableWidget::draw(const DrawArgs &args) { | |||||
float thickness = 5; | float thickness = 5; | ||||
if (isComplete()) { | if (isComplete()) { | ||||
Output *output = &cable->outputModule->outputs[cable->outputId]; | |||||
engine::Output *output = &cable->outputModule->outputs[cable->outputId]; | |||||
// Draw opaque if mouse is hovering over a connected port | // Draw opaque if mouse is hovering over a connected port | ||||
if (output->channels > 1) { | if (output->channels > 1) { | ||||
// Increase thickness if output port is polyphonic | // Increase thickness if output port is polyphonic | ||||
@@ -79,7 +79,7 @@ struct BrowserOverlay : widget::OpaqueWidget { | |||||
}; | }; | ||||
static const float MODEL_BOX_ZOOM = 0.5f; | |||||
static const float MODEL_BOX_ZOOM = 1.0f; | |||||
struct ModelBox : widget::OpaqueWidget { | struct ModelBox : widget::OpaqueWidget { | ||||
@@ -92,20 +92,23 @@ struct ModelBox : widget::OpaqueWidget { | |||||
bool selected = false; | bool selected = false; | ||||
ModelBox() { | ModelBox() { | ||||
box.size.x = 0.f; | |||||
box.size.y = std::ceil(RACK_GRID_HEIGHT * MODEL_BOX_ZOOM); | |||||
// 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(); | |||||
} | } | ||||
void setModel(plugin::Model *model) { | void setModel(plugin::Model *model) { | ||||
this->model = model; | this->model = model; | ||||
infoWidget = new widget::Widget; | infoWidget = new widget::Widget; | ||||
infoWidget->box.size.x = 140; | |||||
infoWidget->box.size.y = box.size.y; | |||||
infoWidget->hide(); | |||||
addChild(infoWidget); | addChild(infoWidget); | ||||
math::Vec pos; | math::Vec pos; | ||||
// Name label | |||||
ui::Label *nameLabel = new ui::Label; | ui::Label *nameLabel = new ui::Label; | ||||
// nameLabel->box.size.x = infoWidget->box.size.x; | // nameLabel->box.size.x = infoWidget->box.size.x; | ||||
nameLabel->box.pos = pos; | nameLabel->box.pos = pos; | ||||
@@ -113,6 +116,7 @@ struct ModelBox : widget::OpaqueWidget { | |||||
infoWidget->addChild(nameLabel); | infoWidget->addChild(nameLabel); | ||||
pos = nameLabel->box.getBottomLeft(); | pos = nameLabel->box.getBottomLeft(); | ||||
// Plugin label | |||||
ui::Label *pluginLabel = new ui::Label; | ui::Label *pluginLabel = new ui::Label; | ||||
// pluginLabel->box.size.x = infoWidget->box.size.x; | // pluginLabel->box.size.x = infoWidget->box.size.x; | ||||
pluginLabel->box.pos = pos; | pluginLabel->box.pos = pos; | ||||
@@ -127,24 +131,23 @@ struct ModelBox : widget::OpaqueWidget { | |||||
infoWidget->addChild(descriptionLabel); | infoWidget->addChild(descriptionLabel); | ||||
pos = descriptionLabel->box.getBottomLeft(); | 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(); | |||||
// 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->text = tag; | |||||
// infoWidget->addChild(tagButton); | |||||
// pos = tagButton->box.getTopLeft(); | |||||
// } | |||||
// // Favorite button | |||||
// ui::Button *favoriteButton = new ui::Button; | |||||
// favoriteButton->box.size.x = box.size.x; | |||||
// favoriteButton->box.pos = pos; | |||||
// favoriteButton->box.pos.y -= favoriteButton->box.size.y; | |||||
// favoriteButton->text = "★"; | |||||
// addChild(favoriteButton); | |||||
// pos = favoriteButton->box.getTopLeft(); | |||||
} | } | ||||
void createPreview() { | void createPreview() { | ||||
@@ -171,9 +174,8 @@ struct ModelBox : widget::OpaqueWidget { | |||||
zoomWidget->box.size.y = RACK_GRID_HEIGHT * MODEL_BOX_ZOOM; | zoomWidget->box.size.y = RACK_GRID_HEIGHT * MODEL_BOX_ZOOM; | ||||
previewWidget->box.size.x = std::ceil(zoomWidget->box.size.x); | 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; | |||||
infoWidget->box.size = previewWidget->box.size; | |||||
box.size.x = previewWidget->box.size.x; | |||||
} | } | ||||
void deletePreview() { | void deletePreview() { | ||||
@@ -197,6 +199,16 @@ struct ModelBox : widget::OpaqueWidget { | |||||
createPreview(); | createPreview(); | ||||
} | } | ||||
// Draw shadow | |||||
nvgBeginPath(args.vg); | |||||
float r = 10; // Blur radius | |||||
float c = 10; // Corner radius | |||||
nvgRect(args.vg, -r, -r, box.size.x + 2*r, box.size.y + 2*r); | |||||
NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.5); | |||||
NVGcolor transparentColor = nvgRGBAf(0, 0, 0, 0); | |||||
nvgFillPaint(args.vg, nvgBoxGradient(args.vg, 0, 0, box.size.x, box.size.y, c, r, shadowColor, transparentColor)); | |||||
nvgFill(args.vg); | |||||
nvgScissor(args.vg, RECT_ARGS(args.clipBox)); | nvgScissor(args.vg, RECT_ARGS(args.clipBox)); | ||||
widget::OpaqueWidget::draw(args); | widget::OpaqueWidget::draw(args); | ||||
nvgResetScissor(args.vg); | nvgResetScissor(args.vg); | ||||
@@ -261,17 +273,18 @@ struct BrowserSidebar : widget::Widget { | |||||
searchField = new BrowserSearchField; | searchField = new BrowserSearchField; | ||||
addChild(searchField); | addChild(searchField); | ||||
// Plugin list | |||||
pluginScroll = new ui::ScrollWidget; | pluginScroll = new ui::ScrollWidget; | ||||
pluginScroll->box.pos = searchField->box.getBottomLeft(); | |||||
addChild(pluginScroll); | addChild(pluginScroll); | ||||
pluginList = new ui::List; | pluginList = new ui::List; | ||||
pluginScroll->container->addChild(pluginList); | pluginScroll->container->addChild(pluginList); | ||||
std::set<std::string> pluginNames; | |||||
std::vector<std::string> pluginNames; | |||||
for (plugin::Plugin *plugin : plugin::plugins) { | for (plugin::Plugin *plugin : plugin::plugins) { | ||||
pluginNames.insert(plugin->name); | |||||
pluginNames.push_back(plugin->name); | |||||
} | } | ||||
std::sort(pluginNames.begin(), pluginNames.end(), string::CaseInsensitiveCompare()); | |||||
for (const std::string &pluginName : pluginNames) { | for (const std::string &pluginName : pluginNames) { | ||||
ui::MenuItem *item = new ui::MenuItem; | ui::MenuItem *item = new ui::MenuItem; | ||||
@@ -279,8 +292,8 @@ struct BrowserSidebar : widget::Widget { | |||||
pluginList->addChild(item); | pluginList->addChild(item); | ||||
} | } | ||||
// Tag list | |||||
tagScroll = new ui::ScrollWidget; | tagScroll = new ui::ScrollWidget; | ||||
tagScroll->box.pos = searchField->box.getBottomLeft(); | |||||
addChild(tagScroll); | addChild(tagScroll); | ||||
tagList = new ui::List; | tagList = new ui::List; | ||||
@@ -295,11 +308,14 @@ struct BrowserSidebar : widget::Widget { | |||||
void step() override { | void step() override { | ||||
searchField->box.size.x = box.size.x; | 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; | |||||
pluginScroll->box.pos = searchField->box.getBottomLeft(); | |||||
pluginScroll->box.size.y = (box.size.y - searchField->box.size.y) / 2; | |||||
pluginScroll->box.size.x = box.size.x; | |||||
pluginList->box.size.x = pluginScroll->box.size.x; | |||||
tagScroll->box.pos = pluginScroll->box.getBottomLeft().floor(); | |||||
tagScroll->box.size.y = (box.size.y - searchField->box.size.y) / 2; | |||||
tagScroll->box.size.x = box.size.x; | |||||
tagList->box.size.x = tagScroll->box.size.x; | |||||
widget::Widget::step(); | widget::Widget::step(); | ||||
} | } | ||||
}; | }; | ||||
@@ -313,18 +329,18 @@ struct ModuleBrowser : widget::OpaqueWidget { | |||||
ModuleBrowser() { | ModuleBrowser() { | ||||
sidebar = new BrowserSidebar; | sidebar = new BrowserSidebar; | ||||
sidebar->box.size.x = 300; | |||||
sidebar->box.size.x = 200; | |||||
addChild(sidebar); | addChild(sidebar); | ||||
modelScroll = new ui::ScrollWidget; | modelScroll = new ui::ScrollWidget; | ||||
addChild(modelScroll); | addChild(modelScroll); | ||||
modelMargin = new ui::MarginLayout; | modelMargin = new ui::MarginLayout; | ||||
modelMargin->margin = math::Vec(20, 20); | |||||
modelMargin->margin = math::Vec(10, 10); | |||||
modelScroll->container->addChild(modelMargin); | modelScroll->container->addChild(modelMargin); | ||||
modelContainer = new ui::SequentialLayout; | modelContainer = new ui::SequentialLayout; | ||||
modelContainer->spacing = math::Vec(20, 20); | |||||
modelContainer->spacing = math::Vec(10, 10); | |||||
modelMargin->addChild(modelContainer); | modelMargin->addChild(modelContainer); | ||||
for (plugin::Plugin *plugin : plugin::plugins) { | for (plugin::Plugin *plugin : plugin::plugins) { | ||||
@@ -527,7 +527,7 @@ Model *getModel(const std::string &pluginSlug, const std::string &modelSlug) { | |||||
} | } | ||||
/** List of allowed tags in human display form. | |||||
/** List of allowed tags in human display form, alphabetized. | |||||
All tags here should be in sentence caps for display consistency. | All tags here should be in sentence caps for display consistency. | ||||
However, tags are case-insensitive in plugin metadata. | However, tags are case-insensitive in plugin metadata. | ||||
*/ | */ | ||||
@@ -13,8 +13,9 @@ void List::step() { | |||||
for (widget::Widget *child : children) { | for (widget::Widget *child : children) { | ||||
if (!child->visible) | if (!child->visible) | ||||
continue; | continue; | ||||
// Increment height, set position of child | |||||
// Set position of child | |||||
child->box.pos = math::Vec(0.0, box.size.y); | child->box.pos = math::Vec(0.0, box.size.y); | ||||
// Increment height | |||||
box.size.y += child->box.size.y; | box.size.y += child->box.size.y; | ||||
// Resize width of child | // Resize width of child | ||||
child->box.size.x = box.size.x; | child->box.size.x = box.size.x; | ||||