@@ -10,7 +10,7 @@ OBJCOPY ?= objcopy | |||||
FLAGS += -MMD -MP | FLAGS += -MMD -MP | ||||
FLAGS += -g | FLAGS += -g | ||||
# Optimization | # Optimization | ||||
FLAGS += -O0 -march=nocona -ffast-math -fno-finite-math-only | |||||
FLAGS += -O3 -march=nocona -ffast-math -fno-finite-math-only | |||||
FLAGS += -Wall -Wextra -Wno-unused-parameter | FLAGS += -Wall -Wextra -Wno-unused-parameter | ||||
ifneq ($(ARCH), mac) | ifneq ($(ARCH), mac) | ||||
@@ -12,47 +12,18 @@ struct SequentialLayout : virtual Widget { | |||||
HORIZONTAL_ORIENTATION, | HORIZONTAL_ORIENTATION, | ||||
VERTICAL_ORIENTATION, | VERTICAL_ORIENTATION, | ||||
}; | }; | ||||
Orientation orientation = HORIZONTAL_ORIENTATION; | |||||
enum Alignment { | enum Alignment { | ||||
LEFT_ALIGNMENT, | LEFT_ALIGNMENT, | ||||
CENTER_ALIGNMENT, | CENTER_ALIGNMENT, | ||||
RIGHT_ALIGNMENT, | RIGHT_ALIGNMENT, | ||||
}; | }; | ||||
Orientation orientation = HORIZONTAL_ORIENTATION; | |||||
Alignment alignment = LEFT_ALIGNMENT; | Alignment alignment = LEFT_ALIGNMENT; | ||||
/** Space between adjacent elements */ | /** Space between adjacent elements */ | ||||
float spacing = 0.0; | |||||
void step() override { | |||||
Widget::step(); | |||||
float offset = 0.0; | |||||
for (Widget *child : children) { | |||||
if (!child->visible) | |||||
continue; | |||||
// Set position | |||||
(orientation == HORIZONTAL_ORIENTATION ? child->box.pos.x : child->box.pos.y) = offset; | |||||
// Increment by size | |||||
offset += (orientation == HORIZONTAL_ORIENTATION ? child->box.size.x : child->box.size.y); | |||||
offset += spacing; | |||||
} | |||||
// We're done if left aligned | |||||
if (alignment == LEFT_ALIGNMENT) | |||||
return; | |||||
// Adjust positions based on width of the layout itself | |||||
offset -= spacing; | |||||
if (alignment == RIGHT_ALIGNMENT) | |||||
offset -= (orientation == HORIZONTAL_ORIENTATION ? box.size.x : box.size.y); | |||||
else if (alignment == CENTER_ALIGNMENT) | |||||
offset -= (orientation == HORIZONTAL_ORIENTATION ? box.size.x : box.size.y) / 2.0; | |||||
for (Widget *child : children) { | |||||
if (!child->visible) | |||||
continue; | |||||
(orientation == HORIZONTAL_ORIENTATION ? child->box.pos.x : child->box.pos.y) += offset; | |||||
} | |||||
} | |||||
math::Vec spacing; | |||||
void step() override; | |||||
}; | }; | ||||
@@ -1,20 +1,23 @@ | |||||
#include <set> | |||||
#include <algorithm> | |||||
#include "app/ModuleBrowser.hpp" | |||||
// TODO clean up | |||||
#include "window.hpp" | #include "window.hpp" | ||||
#include "helpers.hpp" | #include "helpers.hpp" | ||||
#include "event.hpp" | #include "event.hpp" | ||||
#include "ui/Quantity.hpp" | #include "ui/Quantity.hpp" | ||||
#include "ui/RadioButton.hpp" | #include "ui/RadioButton.hpp" | ||||
#include "ui/Label.hpp" | #include "ui/Label.hpp" | ||||
#include "app/ModuleBrowser.hpp" | |||||
#include "app/Scene.hpp" | #include "app/Scene.hpp" | ||||
#include "ui/List.hpp" | #include "ui/List.hpp" | ||||
#include "ui/TextField.hpp" | #include "ui/TextField.hpp" | ||||
#include "ui/SequentialLayout.hpp" | |||||
#include "widgets/ObstructWidget.hpp" | #include "widgets/ObstructWidget.hpp" | ||||
#include "widgets/ZoomWidget.hpp" | #include "widgets/ZoomWidget.hpp" | ||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "context.hpp" | #include "context.hpp" | ||||
#include <set> | |||||
#include <algorithm> | |||||
namespace rack { | namespace rack { | ||||
@@ -43,14 +46,17 @@ struct ModuleWidgetWrapper : ObstructWidget { | |||||
struct ModuleBrowser : OpaqueWidget { | struct ModuleBrowser : OpaqueWidget { | ||||
SequentialLayout *moduleLayout; | |||||
ModuleBrowser() { | ModuleBrowser() { | ||||
math::Vec p; | |||||
moduleLayout = new SequentialLayout; | |||||
moduleLayout->spacing = math::Vec(10, 10); | |||||
addChild(moduleLayout); | |||||
for (Plugin *plugin : plugin::plugins) { | for (Plugin *plugin : plugin::plugins) { | ||||
for (Model *model : plugin->models) { | for (Model *model : plugin->models) { | ||||
ModuleWidgetWrapper *wrapper = new ModuleWidgetWrapper; | ModuleWidgetWrapper *wrapper = new ModuleWidgetWrapper; | ||||
wrapper->box.pos = p; | |||||
wrapper->model = model; | wrapper->model = model; | ||||
addChild(wrapper); | |||||
moduleLayout->addChild(wrapper); | |||||
ZoomWidget *zoomWidget = new ZoomWidget; | ZoomWidget *zoomWidget = new ZoomWidget; | ||||
zoomWidget->setZoom(0.5); | zoomWidget->setZoom(0.5); | ||||
@@ -59,7 +65,6 @@ struct ModuleBrowser : OpaqueWidget { | |||||
ModuleWidget *moduleWidget = model->createModuleWidgetNull(); | ModuleWidget *moduleWidget = model->createModuleWidgetNull(); | ||||
zoomWidget->addChild(moduleWidget); | zoomWidget->addChild(moduleWidget); | ||||
wrapper->box.size = moduleWidget->box.size.mult(zoomWidget->zoom); | wrapper->box.size = moduleWidget->box.size.mult(zoomWidget->zoom); | ||||
p = wrapper->box.getTopRight().plus(math::Vec(20, 0)); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -67,7 +72,8 @@ struct ModuleBrowser : OpaqueWidget { | |||||
void step() override { | void step() override { | ||||
assert(parent); | assert(parent); | ||||
box = parent->box.zeroPos().grow(math::Vec(-100, -100)); | |||||
box = parent->box.zeroPos().grow(math::Vec(-50, -50)); | |||||
moduleLayout->box.size = box.size; | |||||
OpaqueWidget::step(); | OpaqueWidget::step(); | ||||
} | } | ||||
@@ -543,7 +543,7 @@ Toolbar::Toolbar() { | |||||
SequentialLayout *layout = new SequentialLayout; | SequentialLayout *layout = new SequentialLayout; | ||||
layout->box.pos = math::Vec(margin, margin); | layout->box.pos = math::Vec(margin, margin); | ||||
layout->spacing = 0.0; | |||||
layout->spacing = math::Vec(0, 0); | |||||
addChild(layout); | addChild(layout); | ||||
FileButton *fileButton = new FileButton; | FileButton *fileButton = new FileButton; | ||||
@@ -146,7 +146,8 @@ static void Engine_step(Engine *engine) { | |||||
auto stopTime = std::chrono::high_resolution_clock::now(); | auto stopTime = std::chrono::high_resolution_clock::now(); | ||||
float cpuTime = std::chrono::duration<float>(stopTime - startTime).count() * engine->internal->sampleRate; | float cpuTime = std::chrono::duration<float>(stopTime - startTime).count() * engine->internal->sampleRate; | ||||
// Smooth cpu time | // Smooth cpu time | ||||
module->cpuTime += (cpuTime - module->cpuTime) * engine->internal->sampleTime / 0.5f; | |||||
float powerLambda = 2.f / 10.f; | |||||
module->cpuTime += (cpuTime - module->cpuTime) * engine->internal->sampleTime * powerLambda; | |||||
} | } | ||||
else { | else { | ||||
module->step(); | module->step(); | ||||
@@ -1,5 +1,6 @@ | |||||
#include "ui/MenuItem.hpp" | #include "ui/MenuItem.hpp" | ||||
namespace rack { | namespace rack { | ||||
@@ -0,0 +1,65 @@ | |||||
#include "ui/SequentialLayout.hpp" | |||||
#include <vector> | |||||
namespace rack { | |||||
#define X(_v) (orientation == HORIZONTAL_ORIENTATION ? (_v).x : (_v).y) | |||||
#define Y(_v) (orientation == HORIZONTAL_ORIENTATION ? (_v).y : (_v).x) | |||||
void SequentialLayout::step() { | |||||
Widget::step(); | |||||
// Sort widgets into rows (or columns if vertical) | |||||
std::vector<std::vector<Widget*>> rows; | |||||
rows.resize(1); | |||||
float rowWidth = 0.0; | |||||
for (Widget *child : children) { | |||||
if (!child->visible) | |||||
continue; | |||||
// Should we wrap the widget now? | |||||
if (!rows.back().empty() && rowWidth + X(child->box.size) >= X(box.size)) { | |||||
rowWidth = 0.0; | |||||
rows.resize(rows.size() + 1); | |||||
} | |||||
rows.back().push_back(child); | |||||
rowWidth += X(child->box.size) + X(spacing); | |||||
} | |||||
// Position widgets | |||||
math::Vec p; | |||||
for (auto &row : rows) { | |||||
// For center and right alignment, compute offset from the left margin | |||||
float offset = 0.0; | |||||
if (alignment != LEFT_ALIGNMENT) { | |||||
float rowWidth = 0.0; | |||||
for (Widget *child : row) { | |||||
rowWidth += X(child->box.size) + X(spacing); | |||||
} | |||||
rowWidth -= X(spacing); | |||||
if (alignment == CENTER_ALIGNMENT) | |||||
offset = (X(box.size) - rowWidth) / 2; | |||||
else if (alignment == RIGHT_ALIGNMENT) | |||||
offset = X(box.size) - rowWidth; | |||||
} | |||||
float maxHeight = 0.0; | |||||
for (Widget *child : row) { | |||||
child->box.pos = p; | |||||
X(child->box.pos) += offset; | |||||
X(p) += X(child->box.size) + X(spacing); | |||||
if (Y(child->box.size) > maxHeight) | |||||
maxHeight = Y(child->box.size); | |||||
} | |||||
X(p) = 0.0; | |||||
Y(p) += maxHeight + Y(spacing); | |||||
} | |||||
} | |||||
} // namespace rack |