@@ -22,10 +22,8 @@ struct SequentialLayout : virtual Widget { | |||||
RIGHT_ALIGNMENT, | RIGHT_ALIGNMENT, | ||||
}; | }; | ||||
Alignment alignment = LEFT_ALIGNMENT; | Alignment alignment = LEFT_ALIGNMENT; | ||||
/** Space outside elements */ | |||||
float margin = 0.0; | |||||
/** Space between adjacent elements */ | /** Space between adjacent elements */ | ||||
float padding = 0.0; | |||||
float spacing = 0.0; | |||||
void step() override; | void step() override; | ||||
}; | }; | ||||
@@ -45,6 +45,20 @@ struct FavoriteRadioButton : RadioButton { | |||||
}; | }; | ||||
struct SeparatorItem : OpaqueWidget { | |||||
SeparatorItem() { | |||||
box.size.y = BND_WIDGET_HEIGHT; | |||||
} | |||||
void setText(std::string text) { | |||||
clearChildren(); | |||||
Label *label = Widget::create<Label>(Vec(0, 0)); | |||||
label->text = text; | |||||
addChild(label); | |||||
} | |||||
}; | |||||
struct BrowserListItem : OpaqueWidget { | struct BrowserListItem : OpaqueWidget { | ||||
bool selected = false; | bool selected = false; | ||||
@@ -78,11 +92,13 @@ struct BrowserListItem : OpaqueWidget { | |||||
}; | }; | ||||
struct ModelItem : BrowserListItem { | struct ModelItem : BrowserListItem { | ||||
Model *model; | Model *model; | ||||
Label *manufacturerLabel; | Label *manufacturerLabel; | ||||
void setModel(Model *model) { | void setModel(Model *model) { | ||||
clearChildren(); | |||||
assert(model); | assert(model); | ||||
this->model = model; | this->model = model; | ||||
@@ -95,9 +111,8 @@ struct ModelItem : BrowserListItem { | |||||
manufacturerLabel->text = model->manufacturer; | manufacturerLabel->text = model->manufacturer; | ||||
addChild(manufacturerLabel); | addChild(manufacturerLabel); | ||||
SequentialLayout *layout2 = Widget::create<SequentialLayout>(Vec(0, BND_WIDGET_HEIGHT)); | |||||
layout2->margin = 7; | |||||
layout2->padding = 10; | |||||
SequentialLayout *layout2 = Widget::create<SequentialLayout>(Vec(7, BND_WIDGET_HEIGHT)); | |||||
layout2->spacing = 10; | |||||
addChild(layout2); | addChild(layout2); | ||||
FavoriteRadioButton *favoriteButton = new FavoriteRadioButton(); | FavoriteRadioButton *favoriteButton = new FavoriteRadioButton(); | ||||
@@ -138,14 +153,17 @@ struct ManufacturerItem : BrowserListItem { | |||||
Label *manufacturerLabel; | Label *manufacturerLabel; | ||||
ManufacturerItem() { | ManufacturerItem() { | ||||
manufacturerLabel = Widget::create<Label>(Vec(0, 0)); | |||||
manufacturerLabel->text = "Show all modules"; | |||||
addChild(manufacturerLabel); | |||||
} | } | ||||
void setManufacturer(std::string manufacturer) { | void setManufacturer(std::string manufacturer) { | ||||
clearChildren(); | |||||
this->manufacturer = manufacturer; | this->manufacturer = manufacturer; | ||||
manufacturerLabel->text = manufacturer; | |||||
manufacturerLabel = Widget::create<Label>(Vec(0, 0)); | |||||
if (manufacturer.empty()) | |||||
manufacturerLabel->text = "Show all modules"; | |||||
else | |||||
manufacturerLabel->text = manufacturer; | |||||
addChild(manufacturerLabel); | |||||
} | } | ||||
void step() override { | void step() override { | ||||
@@ -163,34 +181,40 @@ struct BrowserList : List { | |||||
// If we have zero children, this result doesn't matter anyway. | // If we have zero children, this result doesn't matter anyway. | ||||
selected = clamp(selected, 0, children.size() - 1); | selected = clamp(selected, 0, children.size() - 1); | ||||
int i = 0; | int i = 0; | ||||
for (Widget *w : children) { | |||||
BrowserListItem *item = dynamic_cast<BrowserListItem*>(w); | |||||
for (Widget *child : children) { | |||||
BrowserListItem *item = dynamic_cast<BrowserListItem*>(child); | |||||
if (item) { | if (item) { | ||||
item->selected = (i == selected); | item->selected = (i == selected); | ||||
i++; | |||||
} | } | ||||
i++; | |||||
} | } | ||||
List::step(); | List::step(); | ||||
} | } | ||||
void selectChild(Widget *child) { | |||||
void selectItem(Widget *w) { | |||||
int i = 0; | int i = 0; | ||||
for (Widget *w : children) { | |||||
if (w == child) { | |||||
selected = i; | |||||
break; | |||||
for (Widget *child : children) { | |||||
BrowserListItem *item = dynamic_cast<BrowserListItem*>(child); | |||||
if (item) { | |||||
if (child == w) { | |||||
selected = i; | |||||
break; | |||||
} | |||||
i++; | |||||
} | } | ||||
i++; | |||||
} | } | ||||
} | } | ||||
Widget *getSelectedChild() { | |||||
BrowserListItem *getSelectedItem() { | |||||
int i = 0; | int i = 0; | ||||
for (Widget *w : children) { | |||||
if (i == selected) { | |||||
return w; | |||||
for (Widget *child : children) { | |||||
BrowserListItem *item = dynamic_cast<BrowserListItem*>(child); | |||||
if (item) { | |||||
if (i == selected) { | |||||
return item; | |||||
} | |||||
i++; | |||||
} | } | ||||
i++; | |||||
} | } | ||||
return NULL; | return NULL; | ||||
} | } | ||||
@@ -241,6 +265,11 @@ struct ModuleBrowser : OpaqueWidget { | |||||
moduleList->selected = 0; | moduleList->selected = 0; | ||||
// Favorites | // Favorites | ||||
{ | |||||
SeparatorItem *item = new SeparatorItem(); | |||||
item->setText("Favorites"); | |||||
moduleList->addChild(item); | |||||
} | |||||
for (Model *model : sFavoriteModels) { | for (Model *model : sFavoriteModels) { | ||||
if ((manufacturerFilter.empty() || manufacturerFilter == model->manufacturer) && isModelMatch(model, search)) { | if ((manufacturerFilter.empty() || manufacturerFilter == model->manufacturer) && isModelMatch(model, search)) { | ||||
ModelItem *item = new ModelItem(); | ModelItem *item = new ModelItem(); | ||||
@@ -250,6 +279,11 @@ struct ModuleBrowser : OpaqueWidget { | |||||
} | } | ||||
// Manufacturers | // Manufacturers | ||||
{ | |||||
SeparatorItem *item = new SeparatorItem(); | |||||
item->setText("Manufacturers"); | |||||
moduleList->addChild(item); | |||||
} | |||||
if (manufacturerFilter.empty()) { | if (manufacturerFilter.empty()) { | ||||
// Collect all manufacturers | // Collect all manufacturers | ||||
std::set<std::string> manufacturers; | std::set<std::string> manufacturers; | ||||
@@ -272,10 +306,16 @@ struct ModuleBrowser : OpaqueWidget { | |||||
else { | else { | ||||
// Dummy manufacturer for clearing manufacturer filter | // Dummy manufacturer for clearing manufacturer filter | ||||
ManufacturerItem *item = new ManufacturerItem(); | ManufacturerItem *item = new ManufacturerItem(); | ||||
item->setManufacturer(""); | |||||
moduleList->addChild(item); | moduleList->addChild(item); | ||||
} | } | ||||
// Models | // Models | ||||
{ | |||||
SeparatorItem *item = new SeparatorItem(); | |||||
item->setText("Modules"); | |||||
moduleList->addChild(item); | |||||
} | |||||
for (Plugin *plugin : gPlugins) { | for (Plugin *plugin : gPlugins) { | ||||
for (Model *model : plugin->models) { | for (Model *model : plugin->models) { | ||||
if ((manufacturerFilter.empty() || manufacturerFilter == model->manufacturer) && isModelMatch(model, search)) { | if ((manufacturerFilter.empty() || manufacturerFilter == model->manufacturer) && isModelMatch(model, search)) { | ||||
@@ -327,7 +367,7 @@ void FavoriteRadioButton::onAction(EventAction &e) { | |||||
void BrowserListItem::onMouseEnter(EventMouseEnter &e) { | void BrowserListItem::onMouseEnter(EventMouseEnter &e) { | ||||
BrowserList *list = getAncestorOfType<BrowserList>(); | BrowserList *list = getAncestorOfType<BrowserList>(); | ||||
list->selectChild(this); | |||||
list->selectItem(this); | |||||
} | } | ||||
void SearchModuleField::onTextChange() { | void SearchModuleField::onTextChange() { | ||||
@@ -350,8 +390,7 @@ void SearchModuleField::onKey(EventKey &e) { | |||||
e.consumed = true; | e.consumed = true; | ||||
} break; | } break; | ||||
case GLFW_KEY_ENTER: { | case GLFW_KEY_ENTER: { | ||||
Widget *w = moduleBrowser->moduleList->getSelectedChild(); | |||||
BrowserListItem *item = dynamic_cast<BrowserListItem*>(w); | |||||
BrowserListItem *item = moduleBrowser->moduleList->getSelectedItem(); | |||||
if (item) { | if (item) { | ||||
item->doAction(); | item->doAction(); | ||||
e.consumed = true; | e.consumed = true; | ||||
@@ -118,12 +118,6 @@ void RackScene::onHoverKey(EventHoverKey &e) { | |||||
e.consumed = true; | e.consumed = true; | ||||
} | } | ||||
} break; | } break; | ||||
case GLFW_KEY_R: { | |||||
if (windowIsModPressed() && !windowIsShiftPressed()) { | |||||
gRackWidget->revert(); | |||||
e.consumed = true; | |||||
} | |||||
} break; | |||||
case GLFW_KEY_ENTER: { | case GLFW_KEY_ENTER: { | ||||
appModuleBrowserCreate(); | appModuleBrowserCreate(); | ||||
e.consumed = true; | e.consumed = true; | ||||
@@ -100,96 +100,64 @@ struct EngineSampleRateChoice : ChoiceButton { | |||||
Toolbar::Toolbar() { | Toolbar::Toolbar() { | ||||
float margin = 5; | |||||
box.size.y = BND_WIDGET_HEIGHT + 2*margin; | |||||
float xPos = 0; | |||||
xPos += margin; | |||||
{ | |||||
ChoiceButton *fileChoice = new FileChoice(); | |||||
fileChoice->box.pos = Vec(xPos, margin); | |||||
fileChoice->box.size.x = 100; | |||||
fileChoice->text = "File"; | |||||
addChild(fileChoice); | |||||
xPos += fileChoice->box.size.x; | |||||
} | |||||
xPos += margin; | |||||
{ | |||||
EngineSampleRateChoice *srChoice = new EngineSampleRateChoice(); | |||||
srChoice->box.pos = Vec(xPos, margin); | |||||
srChoice->box.size.x = 100; | |||||
addChild(srChoice); | |||||
xPos += srChoice->box.size.x; | |||||
} | |||||
xPos += margin; | |||||
{ | |||||
wireOpacitySlider = new Slider(); | |||||
wireOpacitySlider->box.pos = Vec(xPos, margin); | |||||
wireOpacitySlider->box.size.x = 150; | |||||
wireOpacitySlider->label = "Cable opacity"; | |||||
wireOpacitySlider->precision = 0; | |||||
wireOpacitySlider->unit = "%"; | |||||
wireOpacitySlider->setLimits(0.0, 100.0); | |||||
wireOpacitySlider->setDefaultValue(50.0); | |||||
addChild(wireOpacitySlider); | |||||
xPos += wireOpacitySlider->box.size.x; | |||||
} | |||||
xPos += margin; | |||||
{ | |||||
wireTensionSlider = new Slider(); | |||||
wireTensionSlider->box.pos = Vec(xPos, margin); | |||||
wireTensionSlider->box.size.x = 150; | |||||
wireTensionSlider->label = "Cable tension"; | |||||
wireTensionSlider->unit = ""; | |||||
wireTensionSlider->setLimits(0.0, 1.0); | |||||
wireTensionSlider->setDefaultValue(0.5); | |||||
addChild(wireTensionSlider); | |||||
xPos += wireTensionSlider->box.size.x; | |||||
} | |||||
xPos += margin; | |||||
{ | |||||
struct ZoomSlider : Slider { | |||||
void onAction(EventAction &e) override { | |||||
Slider::onAction(e); | |||||
gRackScene->zoomWidget->setZoom(roundf(value) / 100.0); | |||||
} | |||||
}; | |||||
zoomSlider = new ZoomSlider(); | |||||
zoomSlider->box.pos = Vec(xPos, margin); | |||||
zoomSlider->box.size.x = 150; | |||||
zoomSlider->precision = 0; | |||||
zoomSlider->label = "Zoom"; | |||||
zoomSlider->unit = "%"; | |||||
zoomSlider->setLimits(25.0, 200.0); | |||||
zoomSlider->setDefaultValue(100.0); | |||||
addChild(zoomSlider); | |||||
xPos += zoomSlider->box.size.x; | |||||
} | |||||
xPos += margin; | |||||
/* | |||||
{ | |||||
cpuUsageButton = new RadioButton(); | |||||
cpuUsageButton->box.pos = Vec(xPos, margin); | |||||
cpuUsageButton->box.size.x = 100; | |||||
cpuUsageButton->label = "CPU usage"; | |||||
addChild(cpuUsageButton); | |||||
xPos += cpuUsageButton->box.size.x; | |||||
} | |||||
xPos += margin; | |||||
*/ | |||||
box.size.y = BND_WIDGET_HEIGHT + 2*5; | |||||
SequentialLayout *layout = new SequentialLayout(); | |||||
layout->box.pos = Vec(5, 5); | |||||
layout->spacing = 5; | |||||
addChild(layout); | |||||
ChoiceButton *fileChoice = new FileChoice(); | |||||
fileChoice->box.size.x = 100; | |||||
fileChoice->text = "File"; | |||||
layout->addChild(fileChoice); | |||||
EngineSampleRateChoice *srChoice = new EngineSampleRateChoice(); | |||||
srChoice->box.size.x = 100; | |||||
layout->addChild(srChoice); | |||||
wireOpacitySlider = new Slider(); | |||||
wireOpacitySlider->box.size.x = 150; | |||||
wireOpacitySlider->label = "Cable opacity"; | |||||
wireOpacitySlider->precision = 0; | |||||
wireOpacitySlider->unit = "%"; | |||||
wireOpacitySlider->setLimits(0.0, 100.0); | |||||
wireOpacitySlider->setDefaultValue(50.0); | |||||
layout->addChild(wireOpacitySlider); | |||||
wireTensionSlider = new Slider(); | |||||
wireTensionSlider->box.size.x = 150; | |||||
wireTensionSlider->label = "Cable tension"; | |||||
wireTensionSlider->unit = ""; | |||||
wireTensionSlider->setLimits(0.0, 1.0); | |||||
wireTensionSlider->setDefaultValue(0.5); | |||||
layout->addChild(wireTensionSlider); | |||||
struct ZoomSlider : Slider { | |||||
void onAction(EventAction &e) override { | |||||
Slider::onAction(e); | |||||
gRackScene->zoomWidget->setZoom(roundf(value) / 100.0); | |||||
} | |||||
}; | |||||
zoomSlider = new ZoomSlider(); | |||||
zoomSlider->box.size.x = 150; | |||||
zoomSlider->precision = 0; | |||||
zoomSlider->label = "Zoom"; | |||||
zoomSlider->unit = "%"; | |||||
zoomSlider->setLimits(25.0, 200.0); | |||||
zoomSlider->setDefaultValue(100.0); | |||||
layout->addChild(zoomSlider); | |||||
/* | |||||
cpuUsageButton = new RadioButton(); | |||||
cpuUsageButton->box.size.x = 100; | |||||
cpuUsageButton->label = "CPU usage"; | |||||
layout->addChild(cpuUsageButton); | |||||
*/ | |||||
#if defined(RELEASE) | #if defined(RELEASE) | ||||
{ | |||||
Widget *pluginManager = new PluginManagerWidget(); | |||||
pluginManager->box.pos = Vec(xPos, margin); | |||||
addChild(pluginManager); | |||||
xPos += pluginManager->box.size.x; | |||||
} | |||||
Widget *pluginManager = new PluginManagerWidget(); | |||||
layout->addChild(pluginManager); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -7,7 +7,7 @@ namespace rack { | |||||
void SequentialLayout::step() { | void SequentialLayout::step() { | ||||
Widget::step(); | Widget::step(); | ||||
float offset = margin; | |||||
float offset = 0.0; | |||||
for (Widget *child : children) { | for (Widget *child : children) { | ||||
if (!child->visible) | if (!child->visible) | ||||
continue; | continue; | ||||
@@ -15,7 +15,7 @@ void SequentialLayout::step() { | |||||
(orientation == HORIZONTAL_ORIENTATION ? child->box.pos.x : child->box.pos.y) = offset; | (orientation == HORIZONTAL_ORIENTATION ? child->box.pos.x : child->box.pos.y) = offset; | ||||
// Increment by size | // Increment by size | ||||
offset += (orientation == HORIZONTAL_ORIENTATION ? child->box.size.x : child->box.size.y); | offset += (orientation == HORIZONTAL_ORIENTATION ? child->box.size.x : child->box.size.y); | ||||
offset += padding; | |||||
offset += spacing; | |||||
} | } | ||||
// We're done if left aligned | // We're done if left aligned | ||||
@@ -23,8 +23,7 @@ void SequentialLayout::step() { | |||||
return; | return; | ||||
// Adjust positions based on width of the layout itself | // Adjust positions based on width of the layout itself | ||||
offset -= padding; | |||||
offset += margin; | |||||
offset -= spacing; | |||||
if (alignment == RIGHT_ALIGNMENT) | if (alignment == RIGHT_ALIGNMENT) | ||||
offset -= (orientation == HORIZONTAL_ORIENTATION ? box.size.x : box.size.y); | offset -= (orientation == HORIZONTAL_ORIENTATION ? box.size.x : box.size.y); | ||||
else if (alignment == CENTER_ALIGNMENT) | else if (alignment == CENTER_ALIGNMENT) | ||||