| @@ -22,10 +22,8 @@ struct SequentialLayout : virtual Widget { | |||
| RIGHT_ALIGNMENT, | |||
| }; | |||
| Alignment alignment = LEFT_ALIGNMENT; | |||
| /** Space outside elements */ | |||
| float margin = 0.0; | |||
| /** Space between adjacent elements */ | |||
| float padding = 0.0; | |||
| float spacing = 0.0; | |||
| 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 { | |||
| bool selected = false; | |||
| @@ -78,11 +92,13 @@ struct BrowserListItem : OpaqueWidget { | |||
| }; | |||
| struct ModelItem : BrowserListItem { | |||
| Model *model; | |||
| Label *manufacturerLabel; | |||
| void setModel(Model *model) { | |||
| clearChildren(); | |||
| assert(model); | |||
| this->model = model; | |||
| @@ -95,9 +111,8 @@ struct ModelItem : BrowserListItem { | |||
| manufacturerLabel->text = model->manufacturer; | |||
| 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); | |||
| FavoriteRadioButton *favoriteButton = new FavoriteRadioButton(); | |||
| @@ -138,14 +153,17 @@ struct ManufacturerItem : BrowserListItem { | |||
| Label *manufacturerLabel; | |||
| ManufacturerItem() { | |||
| manufacturerLabel = Widget::create<Label>(Vec(0, 0)); | |||
| manufacturerLabel->text = "Show all modules"; | |||
| addChild(manufacturerLabel); | |||
| } | |||
| void setManufacturer(std::string manufacturer) { | |||
| clearChildren(); | |||
| 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 { | |||
| @@ -163,34 +181,40 @@ struct BrowserList : List { | |||
| // If we have zero children, this result doesn't matter anyway. | |||
| selected = clamp(selected, 0, children.size() - 1); | |||
| 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) { | |||
| item->selected = (i == selected); | |||
| i++; | |||
| } | |||
| i++; | |||
| } | |||
| List::step(); | |||
| } | |||
| void selectChild(Widget *child) { | |||
| void selectItem(Widget *w) { | |||
| 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; | |||
| 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; | |||
| } | |||
| @@ -241,6 +265,11 @@ struct ModuleBrowser : OpaqueWidget { | |||
| moduleList->selected = 0; | |||
| // Favorites | |||
| { | |||
| SeparatorItem *item = new SeparatorItem(); | |||
| item->setText("Favorites"); | |||
| moduleList->addChild(item); | |||
| } | |||
| for (Model *model : sFavoriteModels) { | |||
| if ((manufacturerFilter.empty() || manufacturerFilter == model->manufacturer) && isModelMatch(model, search)) { | |||
| ModelItem *item = new ModelItem(); | |||
| @@ -250,6 +279,11 @@ struct ModuleBrowser : OpaqueWidget { | |||
| } | |||
| // Manufacturers | |||
| { | |||
| SeparatorItem *item = new SeparatorItem(); | |||
| item->setText("Manufacturers"); | |||
| moduleList->addChild(item); | |||
| } | |||
| if (manufacturerFilter.empty()) { | |||
| // Collect all manufacturers | |||
| std::set<std::string> manufacturers; | |||
| @@ -272,10 +306,16 @@ struct ModuleBrowser : OpaqueWidget { | |||
| else { | |||
| // Dummy manufacturer for clearing manufacturer filter | |||
| ManufacturerItem *item = new ManufacturerItem(); | |||
| item->setManufacturer(""); | |||
| moduleList->addChild(item); | |||
| } | |||
| // Models | |||
| { | |||
| SeparatorItem *item = new SeparatorItem(); | |||
| item->setText("Modules"); | |||
| moduleList->addChild(item); | |||
| } | |||
| for (Plugin *plugin : gPlugins) { | |||
| for (Model *model : plugin->models) { | |||
| if ((manufacturerFilter.empty() || manufacturerFilter == model->manufacturer) && isModelMatch(model, search)) { | |||
| @@ -327,7 +367,7 @@ void FavoriteRadioButton::onAction(EventAction &e) { | |||
| void BrowserListItem::onMouseEnter(EventMouseEnter &e) { | |||
| BrowserList *list = getAncestorOfType<BrowserList>(); | |||
| list->selectChild(this); | |||
| list->selectItem(this); | |||
| } | |||
| void SearchModuleField::onTextChange() { | |||
| @@ -350,8 +390,7 @@ void SearchModuleField::onKey(EventKey &e) { | |||
| e.consumed = true; | |||
| } break; | |||
| case GLFW_KEY_ENTER: { | |||
| Widget *w = moduleBrowser->moduleList->getSelectedChild(); | |||
| BrowserListItem *item = dynamic_cast<BrowserListItem*>(w); | |||
| BrowserListItem *item = moduleBrowser->moduleList->getSelectedItem(); | |||
| if (item) { | |||
| item->doAction(); | |||
| e.consumed = true; | |||
| @@ -118,12 +118,6 @@ void RackScene::onHoverKey(EventHoverKey &e) { | |||
| e.consumed = true; | |||
| } | |||
| } break; | |||
| case GLFW_KEY_R: { | |||
| if (windowIsModPressed() && !windowIsShiftPressed()) { | |||
| gRackWidget->revert(); | |||
| e.consumed = true; | |||
| } | |||
| } break; | |||
| case GLFW_KEY_ENTER: { | |||
| appModuleBrowserCreate(); | |||
| e.consumed = true; | |||
| @@ -100,96 +100,64 @@ struct EngineSampleRateChoice : ChoiceButton { | |||
| 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) | |||
| { | |||
| 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 | |||
| } | |||
| @@ -7,7 +7,7 @@ namespace rack { | |||
| void SequentialLayout::step() { | |||
| Widget::step(); | |||
| float offset = margin; | |||
| float offset = 0.0; | |||
| for (Widget *child : children) { | |||
| if (!child->visible) | |||
| continue; | |||
| @@ -15,7 +15,7 @@ void SequentialLayout::step() { | |||
| (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 += padding; | |||
| offset += spacing; | |||
| } | |||
| // We're done if left aligned | |||
| @@ -23,8 +23,7 @@ void SequentialLayout::step() { | |||
| return; | |||
| // Adjust positions based on width of the layout itself | |||
| offset -= padding; | |||
| offset += margin; | |||
| offset -= spacing; | |||
| if (alignment == RIGHT_ALIGNMENT) | |||
| offset -= (orientation == HORIZONTAL_ORIENTATION ? box.size.x : box.size.y); | |||
| else if (alignment == CENTER_ALIGNMENT) | |||