@@ -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 |