| @@ -1,19 +0,0 @@ | |||
| #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 | |||
| @@ -108,7 +108,7 @@ json_t* CableWidget::toJson() { | |||
| void CableWidget::fromJson(json_t* rootJ) { | |||
| json_t* colorJ = json_object_get(rootJ, "color"); | |||
| if (colorJ) { | |||
| // In <=v0.6.0, patches used JSON objects. Just ignore them if so and use the existing cable color. | |||
| // In <v0.6.0, cables used JSON objects instead of hex strings. Just ignore them if so and use the existing cable color. | |||
| if (json_is_string(colorJ)) | |||
| color = color::fromHexString(json_string_value(colorJ)); | |||
| } | |||
| @@ -9,7 +9,6 @@ | |||
| #include <ui/MenuOverlay.hpp> | |||
| #include <ui/ScrollWidget.hpp> | |||
| #include <ui/SequentialLayout.hpp> | |||
| #include <ui/MarginLayout.hpp> | |||
| #include <ui/Label.hpp> | |||
| #include <ui/Slider.hpp> | |||
| #include <ui/TextField.hpp> | |||
| @@ -440,7 +439,7 @@ struct ModuleBrowser : widget::OpaqueWidget { | |||
| ClearButton* clearButton; | |||
| ui::ScrollWidget* modelScroll; | |||
| ui::MarginLayout* modelMargin; | |||
| widget::Widget* modelMargin; | |||
| ui::SequentialLayout* modelContainer; | |||
| std::string search; | |||
| @@ -450,12 +449,12 @@ struct ModuleBrowser : widget::OpaqueWidget { | |||
| std::map<plugin::Model*, float> prefilteredModelScores; | |||
| ModuleBrowser() { | |||
| float margin = 10; | |||
| const float margin = 10; | |||
| // Header | |||
| headerLayout = new ui::SequentialLayout; | |||
| headerLayout->box.pos = math::Vec(0, 0); | |||
| headerLayout->box.size.y = BND_WIDGET_HEIGHT + 2 * margin; | |||
| headerLayout->box.size.y = 0; | |||
| headerLayout->margin = math::Vec(margin, margin); | |||
| headerLayout->spacing = math::Vec(margin, margin); | |||
| addChild(headerLayout); | |||
| @@ -482,9 +481,10 @@ struct ModuleBrowser : widget::OpaqueWidget { | |||
| clearButton->browser = this; | |||
| headerLayout->addChild(clearButton); | |||
| widget::Widget* spacer1 = new widget::Widget; | |||
| spacer1->box.size.x = 20; | |||
| headerLayout->addChild(spacer1); | |||
| // widget::Widget* spacer1 = new widget::Widget; | |||
| // spacer1->box.size.x = 20; | |||
| // spacer1->box.size.y = 0; | |||
| // headerLayout->addChild(spacer1); | |||
| SortButton* sortButton = new SortButton; | |||
| sortButton->box.size.x = 150; | |||
| @@ -507,11 +507,11 @@ struct ModuleBrowser : widget::OpaqueWidget { | |||
| modelScroll->box.pos.y = BND_WIDGET_HEIGHT; | |||
| addChild(modelScroll); | |||
| modelMargin = new ui::MarginLayout; | |||
| modelMargin->margin = math::Vec(margin, 0); | |||
| modelMargin = new widget::Widget; | |||
| modelScroll->container->addChild(modelMargin); | |||
| modelContainer = new ui::SequentialLayout; | |||
| modelContainer->margin = math::Vec(margin, 0); | |||
| modelContainer->spacing = math::Vec(margin, margin); | |||
| modelMargin->addChild(modelContainer); | |||
| @@ -558,10 +558,12 @@ struct ModuleBrowser : widget::OpaqueWidget { | |||
| headerLayout->box.size.x = box.size.x; | |||
| const float margin = 10; | |||
| modelScroll->box.pos = headerLayout->box.getBottomLeft(); | |||
| modelScroll->box.size = box.size.minus(modelScroll->box.pos); | |||
| modelMargin->box.size.x = modelScroll->box.size.x; | |||
| modelMargin->box.size.y = modelContainer->getChildrenBoundingBox().size.y + 2 * modelMargin->margin.y; | |||
| modelMargin->box.size.y = modelContainer->box.size.y + margin; | |||
| modelContainer->box.size.x = modelMargin->box.size.x - margin; | |||
| OpaqueWidget::step(); | |||
| } | |||
| @@ -1,20 +0,0 @@ | |||
| #include <ui/MarginLayout.hpp> | |||
| #include <vector> | |||
| namespace rack { | |||
| namespace ui { | |||
| void MarginLayout::step() { | |||
| Widget::step(); | |||
| math::Rect childBox = box.zeroPos().grow(margin.neg()); | |||
| for (Widget* child : children) { | |||
| child->box = childBox; | |||
| } | |||
| } | |||
| } // namespace ui | |||
| } // namespace rack | |||
| @@ -7,6 +7,8 @@ namespace rack { | |||
| namespace ui { | |||
| /** We assume horizontal orientation in this file, but we can achieve vertical orientation just by swapping the axes. | |||
| */ | |||
| #define X(v) (orientation == HORIZONTAL_ORIENTATION ? (v).x : (v).y) | |||
| #define Y(v) (orientation == HORIZONTAL_ORIENTATION ? (v).y : (v).x) | |||
| @@ -14,16 +16,13 @@ namespace ui { | |||
| void SequentialLayout::step() { | |||
| Widget::step(); | |||
| math::Rect bound; | |||
| bound.pos = margin; | |||
| bound.size = box.size.minus(margin.mult(2)); | |||
| float boundWidth = X(box.size) - 2 * X(margin); | |||
| // Sort widgets into rows (or columns if vertical) | |||
| std::vector<widget::Widget*> row; | |||
| math::Vec cursor = bound.pos; | |||
| math::Vec cursor = margin; | |||
| auto flushRow = [&]() { | |||
| // For center and right alignment, compute offset from the left margin | |||
| float offset = 0.f; | |||
| if (alignment != LEFT_ALIGNMENT) { | |||
| float rowWidth = 0.f; | |||
| for (widget::Widget* child : row) { | |||
| @@ -32,16 +31,15 @@ void SequentialLayout::step() { | |||
| rowWidth -= X(spacing); | |||
| if (alignment == CENTER_ALIGNMENT) | |||
| offset = (X(bound.size) - rowWidth) / 2; | |||
| X(cursor) += (boundWidth - rowWidth) / 2; | |||
| else if (alignment == RIGHT_ALIGNMENT) | |||
| offset = X(bound.size) - rowWidth; | |||
| X(cursor) += boundWidth - rowWidth; | |||
| } | |||
| // Set positions of widgets | |||
| float maxHeight = 0.f; | |||
| for (widget::Widget* child : row) { | |||
| child->box.pos = cursor; | |||
| X(child->box.pos) += offset; | |||
| X(cursor) += X(child->box.size) + X(spacing); | |||
| if (Y(child->box.size) > maxHeight) | |||
| @@ -50,20 +48,21 @@ void SequentialLayout::step() { | |||
| row.clear(); | |||
| // Reset cursor to next line | |||
| X(cursor) = X(bound.pos); | |||
| X(cursor) = X(margin); | |||
| Y(cursor) += maxHeight + Y(spacing); | |||
| }; | |||
| // Iterate through children until row is full | |||
| float rowWidth = 0.0; | |||
| for (widget::Widget* child : children) { | |||
| // Skip invisible children | |||
| if (!child->isVisible()) { | |||
| child->box.pos = math::Vec(); | |||
| continue; | |||
| } | |||
| // Should we wrap the widget now? | |||
| if (!row.empty() && rowWidth + X(child->box.size) > X(bound.size)) { | |||
| if (!row.empty() && rowWidth + X(child->box.size) > boundWidth) { | |||
| flushRow(); | |||
| rowWidth = 0.0; | |||
| } | |||
| @@ -76,6 +75,8 @@ void SequentialLayout::step() { | |||
| if (!row.empty()) { | |||
| flushRow(); | |||
| } | |||
| Y(box.size) = Y(cursor) - Y(spacing) + Y(margin); | |||
| } | |||