| @@ -322,7 +322,7 @@ struct MomentarySwitch : virtual Switch { | |||
| // IO widgets | |||
| //////////////////// | |||
| struct LedDisplay : Widget { | |||
| struct LedDisplay : VirtualWidget { | |||
| void draw(NVGcontext *vg) override; | |||
| }; | |||
| @@ -484,7 +484,7 @@ struct Toolbar : OpaqueWidget { | |||
| void draw(NVGcontext *vg) override; | |||
| }; | |||
| struct PluginManagerWidget : Widget { | |||
| struct PluginManagerWidget : VirtualWidget { | |||
| Widget *loginWidget; | |||
| Widget *manageWidget; | |||
| Widget *downloadWidget; | |||
| @@ -5,15 +5,39 @@ | |||
| namespace rack { | |||
| //////////////////// | |||
| // Layouts | |||
| //////////////////// | |||
| /** Positions children in a row/column based on their widths/heights */ | |||
| struct SequentialLayout : virtual Widget { | |||
| enum Orientation { | |||
| HORIZONTAL_ORIENTATION, | |||
| VERTICAL_ORIENTATION, | |||
| }; | |||
| Orientation orientation = HORIZONTAL_ORIENTATION; | |||
| enum Alignment { | |||
| LEFT_ALIGNMENT, | |||
| CENTER_ALIGNMENT, | |||
| RIGHT_ALIGNMENT, | |||
| }; | |||
| Alignment alignment = LEFT_ALIGNMENT; | |||
| float margin = 0.0; | |||
| void step() override; | |||
| }; | |||
| //////////////////// | |||
| // Blendish UI elements | |||
| //////////////////// | |||
| struct Label : Widget { | |||
| struct Label : VirtualWidget { | |||
| std::string text; | |||
| enum Align { | |||
| LEFT_ALIGN, | |||
| CENTER_ALIGN, | |||
| RIGHT_ALIGN | |||
| enum Alignment { | |||
| LEFT_ALIGNMENT, | |||
| CENTER_ALIGNMENT, | |||
| RIGHT_ALIGNMENT, | |||
| }; | |||
| Align align = LEFT_ALIGN; | |||
| Alignment alignment = LEFT_ALIGNMENT; | |||
| Label() { | |||
| box.size.y = BND_WIDGET_HEIGHT; | |||
| } | |||
| @@ -200,7 +224,7 @@ struct ProgressBar : QuantityWidget { | |||
| void draw(NVGcontext *vg) override; | |||
| }; | |||
| struct Tooltip : Widget { | |||
| struct Tooltip : VirtualWidget { | |||
| void step() override; | |||
| void draw(NVGcontext *vg) override; | |||
| }; | |||
| @@ -44,7 +44,9 @@ struct SVG { | |||
| // Base widget | |||
| //////////////////// | |||
| /** A node in the 2D scene graph */ | |||
| /** A node in the 2D scene graph | |||
| Never inherit from Widget directly. Instead, inherit from VirtualWidget declared below. | |||
| */ | |||
| struct Widget { | |||
| /** Stores position and size */ | |||
| Rect box = Rect(Vec(), Vec(INFINITY, INFINITY)); | |||
| @@ -152,7 +154,11 @@ struct Widget { | |||
| } | |||
| }; | |||
| struct TransformWidget : Widget { | |||
| /** Instead of inheriting from Widget directly, inherit from VirtualWidget to guarantee that only one copy of Widget's member variables are used by each instance of the Widget hierarchy. | |||
| */ | |||
| struct VirtualWidget : virtual Widget {}; | |||
| struct TransformWidget : VirtualWidget { | |||
| /** The transformation matrix */ | |||
| float transform[6]; | |||
| TransformWidget(); | |||
| @@ -164,7 +170,7 @@ struct TransformWidget : Widget { | |||
| void draw(NVGcontext *vg) override; | |||
| }; | |||
| struct ZoomWidget : Widget { | |||
| struct ZoomWidget : VirtualWidget { | |||
| float zoom = 1.0; | |||
| Vec getRelativeOffset(Vec v, Widget *relative) override; | |||
| Rect getViewport(Rect r) override; | |||
| @@ -183,7 +189,7 @@ struct ZoomWidget : Widget { | |||
| //////////////////// | |||
| /** Widget that does not respond to events */ | |||
| struct TransparentWidget : virtual Widget { | |||
| struct TransparentWidget : VirtualWidget { | |||
| void onMouseDown(EventMouseDown &e) override {} | |||
| void onMouseUp(EventMouseUp &e) override {} | |||
| void onMouseMove(EventMouseMove &e) override {} | |||
| @@ -191,7 +197,7 @@ struct TransparentWidget : virtual Widget { | |||
| }; | |||
| /** Widget that automatically responds to all mouse events but gives a chance for children to respond instead */ | |||
| struct OpaqueWidget : virtual Widget { | |||
| struct OpaqueWidget : VirtualWidget { | |||
| void onMouseDown(EventMouseDown &e) override { | |||
| Widget::onMouseDown(e); | |||
| if (!e.target) | |||
| @@ -216,7 +222,7 @@ struct OpaqueWidget : virtual Widget { | |||
| } | |||
| }; | |||
| struct SpriteWidget : virtual Widget { | |||
| struct SpriteWidget : VirtualWidget { | |||
| Vec spriteOffset; | |||
| Vec spriteSize; | |||
| std::shared_ptr<Image> spriteImage; | |||
| @@ -224,7 +230,7 @@ struct SpriteWidget : virtual Widget { | |||
| void draw(NVGcontext *vg) override; | |||
| }; | |||
| struct SVGWidget : virtual Widget { | |||
| struct SVGWidget : VirtualWidget { | |||
| std::shared_ptr<SVG> svg; | |||
| /** Sets the box size to the svg image size */ | |||
| void wrap(); | |||
| @@ -237,7 +243,7 @@ struct SVGWidget : virtual Widget { | |||
| When `dirty` is true, its children will be re-rendered on the next call to step() override. | |||
| Events are not passed to the underlying scene. | |||
| */ | |||
| struct FramebufferWidget : virtual Widget { | |||
| struct FramebufferWidget : VirtualWidget { | |||
| /** Set this to true to re-render the children to the framebuffer the next time it is drawn */ | |||
| bool dirty = true; | |||
| /** A margin in pixels around the children in the framebuffer | |||
| @@ -258,7 +264,7 @@ struct FramebufferWidget : virtual Widget { | |||
| }; | |||
| /** A Widget representing a float value */ | |||
| struct QuantityWidget : virtual Widget { | |||
| struct QuantityWidget : VirtualWidget { | |||
| float value = 0.0; | |||
| float minValue = 0.0; | |||
| float maxValue = 1.0; | |||
| @@ -95,7 +95,7 @@ struct ModelItem : BrowserListItem { | |||
| nameLabel = Widget::create<Label>(Vec(0, 0)); | |||
| addChild(nameLabel); | |||
| manufacturerLabel = Widget::create<Label>(Vec(0, 0)); | |||
| manufacturerLabel->align = Label::RIGHT_ALIGN; | |||
| manufacturerLabel->alignment = Label::RIGHT_ALIGNMENT; | |||
| addChild(manufacturerLabel); | |||
| tagsLabel = Widget::create<Label>(Vec(26, BND_WIDGET_HEIGHT)); | |||
| addChild(tagsLabel); | |||
| @@ -7,10 +7,10 @@ namespace rack { | |||
| void Label::draw(NVGcontext *vg) { | |||
| float x = 0.0; | |||
| if (align == RIGHT_ALIGN) { | |||
| if (alignment == RIGHT_ALIGNMENT) { | |||
| x = box.size.x - bndLabelWidth(vg, -1, text.c_str()); | |||
| } | |||
| else if (align == CENTER_ALIGN) { | |||
| else if (alignment == CENTER_ALIGNMENT) { | |||
| x = (box.size.x - bndLabelWidth(vg, -1, text.c_str())) / 2.0; | |||
| } | |||
| @@ -0,0 +1,39 @@ | |||
| #include "ui.hpp" | |||
| namespace rack { | |||
| void SequentialLayout::step() { | |||
| 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 += margin; | |||
| } | |||
| // We're done if left aligned | |||
| if (alignment == LEFT_ALIGNMENT) | |||
| return; | |||
| // Adjust positions based on width of the layout itself | |||
| offset -= margin; | |||
| 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; | |||
| } | |||
| } | |||
| } // namespace rack | |||