Browse Source

Tear down old Module Browser, make app widgets and Core plugins compatible with NULL Module

tags/v1.0.0
Andrew Belt 5 years ago
parent
commit
a6961d6626
14 changed files with 166 additions and 532 deletions
  1. +3
    -6
      include/math.hpp
  2. +35
    -0
      include/widgets/ObstructWidget.hpp
  3. +5
    -4
      include/widgets/ZoomWidget.hpp
  4. +2
    -1
      src/Core/AudioInterface.cpp
  5. +11
    -2
      src/Core/MIDICCToCVInterface.cpp
  6. +2
    -1
      src/Core/MIDIToCVInterface.cpp
  7. +8
    -1
      src/Core/MIDITriggerToCVInterface.cpp
  8. +2
    -1
      src/Core/QuadMIDIToCVInterface.cpp
  9. +28
    -3
      src/app/AudioWidget.cpp
  10. +21
    -1
      src/app/MidiWidget.cpp
  11. +23
    -511
      src/app/ModuleBrowser.cpp
  12. +3
    -1
      src/app/ModuleLightWidget.cpp
  13. +20
    -0
      src/app/ParamQuantity.cpp
  14. +3
    -0
      src/app/PortWidget.cpp

+ 3
- 6
include/math.hpp View File

@@ -296,18 +296,15 @@ struct Rect {
Rect zeroPos() const {
return Rect(Vec(), size);
}
/** Expands each corner
Use a negative delta to shrink.
*/
Rect grow(Vec delta) const {
Rect r;
r.pos = pos.minus(delta);
r.size = size.plus(delta.mult(2.f));
return r;
}
Rect shrink(Vec delta) const {
Rect r;
r.pos = pos.plus(delta);
r.size = size.minus(delta.mult(2.f));
return r;
}
};




+ 35
- 0
include/widgets/ObstructWidget.hpp View File

@@ -0,0 +1,35 @@
#pragma once
#include "widgets/Widget.hpp"


namespace rack {


/** Widget that consumes recursing events without giving a chance for children to consume.
*/
struct ObstructWidget : virtual Widget {
void onHover(const event::Hover &e) override {
e.consume(this);
}
void onButton(const event::Button &e) override {
e.consume(this);
}
void onHoverKey(const event::HoverKey &e) override {
e.consume(this);
}
void onHoverText(const event::HoverText &e) override {
e.consume(this);
}
void onHoverScroll(const event::HoverScroll &e) override {
e.consume(this);
}
void onDragHover(const event::DragHover &e) override {
e.consume(this);
}
void onPathDrop(const event::PathDrop &e) override {
e.consume(this);
}
};


} // namespace rack

+ 5
- 4
include/widgets/ZoomWidget.hpp View File

@@ -22,11 +22,12 @@ struct ZoomWidget : virtual Widget {
}

void setZoom(float zoom) {
if (zoom != this->zoom) {
event::Zoom eZoom;
Widget::onZoom(eZoom);
}
this->zoom = zoom;

event::Context eZoomContext;
event::Zoom eZoom;
eZoom.context = &eZoomContext;
Widget::onZoom(eZoom);
}

void draw(NVGcontext *vg) override {


+ 2
- 1
src/Core/AudioInterface.cpp View File

@@ -276,7 +276,8 @@ struct AudioInterfaceWidget : ModuleWidget {

AudioWidget *audioWidget = createWidget<AudioWidget>(mm2px(Vec(3.2122073, 14.837339)));
audioWidget->box.size = mm2px(Vec(44, 28));
audioWidget->audioIO = &module->audioIO;
if (module)
audioWidget->audioIO = &module->audioIO;
addChild(audioWidget);
}
};


+ 11
- 2
src/Core/MIDICCToCVInterface.cpp View File

@@ -119,6 +119,10 @@ struct MidiCcChoice : GridChoice {
}

void step() override {
if (!module) {
text = "";
return;
}
if (module->learningId == id) {
if (0 <= focusCc)
text = string::f("%d", focusCc);
@@ -136,11 +140,15 @@ struct MidiCcChoice : GridChoice {

void onSelect(const event::Select &e) override {
e.consume(this);
if (!module)
return;
module->learningId = id;
focusCc = -1;
}

void onDeselect(const event::Deselect &e) override {
if (!module)
return;
if (0 <= focusCc && focusCc < 128) {
module->learnedCcs[id] = focusCc;
}
@@ -159,7 +167,7 @@ struct MidiCcChoice : GridChoice {

void onSelectKey(const event::SelectKey &e) override {
if (context()->event->selectedWidget == this) {
if (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER) {
if (e.action == GLFW_PRESS && (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER)) {
event::Deselect eDeselect;
onDeselect(eDeselect);
context()->event->selectedWidget = NULL;
@@ -209,7 +217,8 @@ struct MIDICCToCVInterfaceWidget : ModuleWidget {
MidiCcWidget *midiWidget = createWidget<MidiCcWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->module = module;
midiWidget->box.size = mm2px(Vec(44, 54.667));
midiWidget->midiIO = &module->midiInput;
if (module)
midiWidget->midiIO = &module->midiInput;
midiWidget->createGridChoices();
addChild(midiWidget);
}


+ 2
- 1
src/Core/MIDIToCVInterface.cpp View File

@@ -283,7 +283,8 @@ struct MIDIToCVInterfaceWidget : ModuleWidget {

MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.41891, 14.8373)));
midiWidget->box.size = mm2px(Vec(33.840, 28));
midiWidget->midiIO = &module->midiInput;
if (module)
midiWidget->midiIO = &module->midiInput;
addChild(midiWidget);
}



+ 8
- 1
src/Core/MIDITriggerToCVInterface.cpp View File

@@ -159,6 +159,8 @@ struct MidiTrigChoice : GridChoice {
}

void step() override {
if (!module)
return;
if (module->learningId == id) {
text = "LRN";
color.a = 0.5;
@@ -180,10 +182,14 @@ struct MidiTrigChoice : GridChoice {

void onSelect(const event::Select &e) override {
e.consume(this);
if (!module)
return;
module->learningId = id;
}

void onDeselect(const event::Deselect &e) override {
if (!module)
return;
module->learningId = -1;
}
};
@@ -228,7 +234,8 @@ struct MIDITriggerToCVInterfaceWidget : ModuleWidget {
MidiTrigWidget *midiWidget = createWidget<MidiTrigWidget>(mm2px(Vec(3.399621, 14.837339)));
midiWidget->module = module;
midiWidget->box.size = mm2px(Vec(44, 54.667));
midiWidget->midiIO = &module->midiInput;
if (module)
midiWidget->midiIO = &module->midiInput;
midiWidget->createGridChoices();
addChild(midiWidget);
}


+ 2
- 1
src/Core/QuadMIDIToCVInterface.cpp View File

@@ -329,7 +329,8 @@ struct QuadMIDIToCVInterfaceWidget : ModuleWidget {

MidiWidget *midiWidget = createWidget<MidiWidget>(mm2px(Vec(3.4009969, 14.837336)));
midiWidget->box.size = mm2px(Vec(44, 28));
midiWidget->midiIO = &module->midiInput;
if (module)
midiWidget->midiIO = &module->midiInput;
addChild(midiWidget);
}



+ 28
- 3
src/app/AudioWidget.cpp View File

@@ -17,6 +17,9 @@ struct AudioDriverItem : MenuItem {
struct AudioDriverChoice : LedDisplayChoice {
AudioWidget *audioWidget;
void onAction(const event::Action &e) override {
if (!audioWidget->audioIO)
return;

Menu *menu = createMenu();
menu->addChild(createMenuLabel("Audio driver"));
for (int driver : audioWidget->audioIO->getDrivers()) {
@@ -29,7 +32,10 @@ struct AudioDriverChoice : LedDisplayChoice {
}
}
void step() override {
text = audioWidget->audioIO->getDriverName(audioWidget->audioIO->driver);
if (audioWidget->audioIO)
text = audioWidget->audioIO->getDriverName(audioWidget->audioIO->driver);
else
text = "";
}
};

@@ -49,6 +55,9 @@ struct AudioDeviceChoice : LedDisplayChoice {
int maxTotalChannels = 128;

void onAction(const event::Action &e) override {
if (!audioWidget->audioIO)
return;

Menu *menu = createMenu();
menu->addChild(createMenuLabel("Audio device"));
int deviceCount = audioWidget->audioIO->getDeviceCount();
@@ -74,6 +83,10 @@ struct AudioDeviceChoice : LedDisplayChoice {
}
}
void step() override {
if (!audioWidget->audioIO) {
text = "";
return;
}
text = audioWidget->audioIO->getDeviceDetail(audioWidget->audioIO->device, audioWidget->audioIO->offset);
if (text.empty()) {
text = "(No device)";
@@ -97,6 +110,9 @@ struct AudioSampleRateItem : MenuItem {
struct AudioSampleRateChoice : LedDisplayChoice {
AudioWidget *audioWidget;
void onAction(const event::Action &e) override {
if (!audioWidget->audioIO)
return;

Menu *menu = createMenu();
menu->addChild(createMenuLabel("Sample rate"));
std::vector<int> sampleRates = audioWidget->audioIO->getSampleRates();
@@ -113,7 +129,10 @@ struct AudioSampleRateChoice : LedDisplayChoice {
}
}
void step() override {
text = string::f("%g kHz", audioWidget->audioIO->sampleRate / 1000.f);
if (audioWidget->audioIO)
text = string::f("%g kHz", audioWidget->audioIO->sampleRate / 1000.f);
else
text = "";
}
};

@@ -129,6 +148,9 @@ struct AudioBlockSizeItem : MenuItem {
struct AudioBlockSizeChoice : LedDisplayChoice {
AudioWidget *audioWidget;
void onAction(const event::Action &e) override {
if (!audioWidget->audioIO)
return;

Menu *menu = createMenu();
menu->addChild(createMenuLabel("Block size"));
std::vector<int> blockSizes = audioWidget->audioIO->getBlockSizes();
@@ -146,7 +168,10 @@ struct AudioBlockSizeChoice : LedDisplayChoice {
}
}
void step() override {
text = string::f("%d", audioWidget->audioIO->blockSize);
if (audioWidget->audioIO)
text = string::f("%d", audioWidget->audioIO->blockSize);
else
text = "";
}
};



+ 21
- 1
src/app/MidiWidget.cpp View File

@@ -17,6 +17,9 @@ struct MidiDriverItem : MenuItem {
struct MidiDriverChoice : LedDisplayChoice {
MidiWidget *midiWidget;
void onAction(const event::Action &e) override {
if (!midiWidget->midiIO)
return;

Menu *menu = createMenu();
menu->addChild(createMenuLabel("MIDI driver"));
for (int driverId : midiWidget->midiIO->getDriverIds()) {
@@ -29,6 +32,10 @@ struct MidiDriverChoice : LedDisplayChoice {
}
}
void step() override {
if (!midiWidget->midiIO) {
text = "";
return;
}
text = midiWidget->midiIO->getDriverName(midiWidget->midiIO->driverId);
if (text.empty()) {
text = "(No driver)";
@@ -51,6 +58,9 @@ struct MidiDeviceItem : MenuItem {
struct MidiDeviceChoice : LedDisplayChoice {
MidiWidget *midiWidget;
void onAction(const event::Action &e) override {
if (!midiWidget->midiIO)
return;

Menu *menu = createMenu();
menu->addChild(createMenuLabel("MIDI device"));
{
@@ -71,6 +81,10 @@ struct MidiDeviceChoice : LedDisplayChoice {
}
}
void step() override {
if (!midiWidget->midiIO) {
text = "";
return;
}
text = midiWidget->midiIO->getDeviceName(midiWidget->midiIO->deviceId);
if (text.empty()) {
text = "(No device)";
@@ -93,6 +107,9 @@ struct MidiChannelItem : MenuItem {
struct MidiChannelChoice : LedDisplayChoice {
MidiWidget *midiWidget;
void onAction(const event::Action &e) override {
if (!midiWidget->midiIO)
return;

Menu *menu = createMenu();
menu->addChild(createMenuLabel("MIDI channel"));
for (int channel = -1; channel < 16; channel++) {
@@ -105,7 +122,10 @@ struct MidiChannelChoice : LedDisplayChoice {
}
}
void step() override {
text = midiWidget->midiIO->getChannelName(midiWidget->midiIO->channel);
if (midiWidget->midiIO)
text = midiWidget->midiIO->getChannelName(midiWidget->midiIO->channel);
else
text = "";
}
};



+ 23
- 511
src/app/ModuleBrowser.cpp View File

@@ -10,13 +10,12 @@
#include "app/Scene.hpp"
#include "ui/List.hpp"
#include "ui/TextField.hpp"
#include "widgets/ObstructWidget.hpp"
#include "widgets/ZoomWidget.hpp"
#include "plugin.hpp"
#include "context.hpp"


static const float itemMargin = 2.0;


namespace rack {


@@ -26,533 +25,46 @@ static std::string sTagFilter;



bool isMatch(std::string s, std::string search) {
s = string::lowercase(s);
search = string::lowercase(search);
return (s.find(search) != std::string::npos);
}

static bool isModelMatch(Model *model, std::string search) {
if (search.empty())
return true;
std::string s;
s += model->plugin->slug;
s += " ";
s += model->plugin->author;
s += " ";
s += model->name;
s += " ";
s += model->slug;
for (std::string tag : model->tags) {
std::string allowedTag = plugin::getAllowedTag(tag);
if (!allowedTag.empty()) {
s += " ";
s += allowedTag;
}
}
return isMatch(s, search);
}


struct FavoriteQuantity : Quantity {
std::string getString() override {
return "★";
}
};


struct FavoriteRadioButton : RadioButton {
Model *model = NULL;

FavoriteRadioButton() {
quantity = new FavoriteQuantity;
}

void onAction(const event::Action &e) override;
};


struct SeparatorItem : OpaqueWidget {
SeparatorItem() {
box.size.y = 2*BND_WIDGET_HEIGHT + 2*itemMargin;
}

void setText(std::string text) {
clearChildren();
Label *label = createWidget<Label>(math::Vec(0, 12 + itemMargin));
label->text = text;
label->fontSize = 20;
label->color.a *= 0.5;
addChild(label);
}
};


struct BrowserListItem : OpaqueWidget {
bool selected = false;

BrowserListItem() {
box.size.y = BND_WIDGET_HEIGHT + 2*itemMargin;
}

void draw(NVGcontext *vg) override {
BNDwidgetState state = selected ? BND_HOVER : BND_DEFAULT;
bndMenuItem(vg, 0.0, 0.0, box.size.x, box.size.y, state, -1, "");
Widget::draw(vg);
}

void onDragStart(const event::DragStart &e) override;

void onDragDrop(const event::DragDrop &e) override {
if (e.origin != this)
return;
doAction();
}

void doAction() {
event::Context eActionContext;
event::Action eAction;
eAction.context = &eActionContext;
eAction.consume(this);
onAction(eAction);
if (eActionContext.consumed) {
MenuOverlay *overlay = getAncestorOfType<MenuOverlay>();
overlay->requestedDelete = true;
}
}
};


struct ModelItem : BrowserListItem {
Model *model;
Label *pluginLabel = NULL;

void setModel(Model *model) {
clearChildren();
assert(model);
this->model = model;

FavoriteRadioButton *favoriteButton = createWidget<FavoriteRadioButton>(math::Vec(8, itemMargin));
favoriteButton->box.size.x = 20;
addChild(favoriteButton);

// Set favorite button initial state
auto it = sFavoriteModels.find(model);
if (it != sFavoriteModels.end())
favoriteButton->quantity->setValue(1);
favoriteButton->model = model;

Label *nameLabel = createWidget<Label>(favoriteButton->box.getTopRight());
nameLabel->text = model->name;
addChild(nameLabel);

pluginLabel = createWidget<Label>(math::Vec(0, itemMargin));
pluginLabel->alignment = Label::RIGHT_ALIGNMENT;
pluginLabel->text = model->plugin->slug + " " + model->plugin->version;
pluginLabel->color.a = 0.5;
addChild(pluginLabel);
}

void step() override {
BrowserListItem::step();
if (pluginLabel)
pluginLabel->box.size.x = box.size.x - BND_SCROLLBAR_WIDTH;
}

void onAction(const event::Action &e) override {
ModuleWidget *moduleWidget = model->createModuleWidget();
if (!moduleWidget)
return;
context()->scene->rackWidget->addModule(moduleWidget);
// Move module nearest to the mouse position
moduleWidget->box.pos = context()->scene->rackWidget->lastMousePos.minus(moduleWidget->box.size.div(2));
context()->scene->rackWidget->requestModuleBoxNearest(moduleWidget, moduleWidget->box);
}
};


struct AuthorItem : BrowserListItem {
std::string author;

void setAuthor(std::string author) {
clearChildren();
this->author = author;
Label *authorLabel = createWidget<Label>(math::Vec(0, 0 + itemMargin));
if (author.empty())
authorLabel->text = "Show all modules";
else
authorLabel->text = author;
addChild(authorLabel);
}

void onAction(const event::Action &e) override;
};


struct TagItem : BrowserListItem {
std::string tag;

void setTag(std::string tag) {
clearChildren();
this->tag = tag;
Label *tagLabel = createWidget<Label>(math::Vec(0, 0 + itemMargin));
if (tag.empty())
tagLabel->text = "Show all tags";
else
tagLabel->text = tag;
addChild(tagLabel);
}

void onAction(const event::Action &e) override;
};


struct ClearFilterItem : BrowserListItem {
ClearFilterItem() {
Label *label = createWidget<Label>(math::Vec(0, 0 + itemMargin));
label->text = "Back";
addChild(label);
}

void onAction(const event::Action &e) override;
};


struct BrowserList : List {
int selected = 0;

void step() override {
incrementSelection(0);
// Find and select item
int i = 0;
for (Widget *child : children) {
BrowserListItem *item = dynamic_cast<BrowserListItem*>(child);
if (item) {
item->selected = (i == selected);
i++;
}
}
List::step();
}

void incrementSelection(int delta) {
selected += delta;
selected = math::clamp(selected, 0, countItems() - 1);
}

int countItems() {
int n = 0;
for (Widget *child : children) {
BrowserListItem *item = dynamic_cast<BrowserListItem*>(child);
if (item) {
n++;
}
}
return n;
}

void selectItem(Widget *w) {
int i = 0;
for (Widget *child : children) {
BrowserListItem *item = dynamic_cast<BrowserListItem*>(child);
if (item) {
if (child == w) {
selected = i;
break;
}
i++;
}
}
}

BrowserListItem *getSelectedItem() {
int i = 0;
for (Widget *child : children) {
BrowserListItem *item = dynamic_cast<BrowserListItem*>(child);
if (item) {
if (i == selected) {
return item;
}
i++;
}
}
return NULL;
}

void scrollSelected() {
BrowserListItem *item = getSelectedItem();
if (item) {
ScrollWidget *parentScroll = dynamic_cast<ScrollWidget*>(parent->parent);
if (parentScroll)
parentScroll->scrollTo(item->box);
}
}
};


struct ModuleBrowser;

struct SearchModuleField : TextField {
ModuleBrowser *moduleBrowser;
void onChange(const event::Change &e) override;
void onSelectKey(const event::SelectKey &e) override;
struct ModuleWidgetWrapper : ObstructWidget {
};


struct ModuleBrowser : OpaqueWidget {
SearchModuleField *searchField;
ScrollWidget *moduleScroll;
BrowserList *moduleList;
std::set<std::string, string::CaseInsensitiveCompare> availableAuthors;
std::set<std::string> availableTags;

ModuleBrowser() {
box.size.x = 450;
sAuthorFilter = "";
sTagFilter = "";

// Search
searchField = new SearchModuleField;
searchField->box.size.x = box.size.x;
searchField->moduleBrowser = this;
addChild(searchField);

moduleList = new BrowserList;
moduleList->box.size = math::Vec(box.size.x, 0.0);

// Module Scroll
moduleScroll = new ScrollWidget;
moduleScroll->box.pos.y = searchField->box.size.y;
moduleScroll->box.size.x = box.size.x;
moduleScroll->container->addChild(moduleList);
addChild(moduleScroll);

// Collect authors
math::Vec p;
for (Plugin *plugin : plugin::plugins) {
// Insert author
if (!plugin->author.empty())
availableAuthors.insert(plugin->author);
for (Model *model : plugin->models) {
// Insert tag
for (std::string tag : model->tags) {
std::string allowedTag = plugin::getAllowedTag(tag);
if (!allowedTag.empty())
availableTags.insert(tag);
}
}
}

// Trigger search update
clearSearch();
}

void draw(NVGcontext *vg) override {
bndMenuBackground(vg, 0.0, 0.0, box.size.x, box.size.y, BND_CORNER_NONE);
Widget::draw(vg);
}

void clearSearch() {
searchField->setText("");
}

bool isModelFiltered(Model *model) {
if (!sAuthorFilter.empty() && model->plugin->author != sAuthorFilter)
return false;
if (!sTagFilter.empty()) {
// TODO filter tags
}
return true;
}

void refreshSearch() {
std::string search = searchField->text;
moduleList->clearChildren();
moduleList->selected = 0;
bool filterPage = !(sAuthorFilter.empty() && sTagFilter.empty());

if (!filterPage) {
// Favorites
if (!sFavoriteModels.empty()) {
SeparatorItem *item = new SeparatorItem;
item->setText("Favorites");
moduleList->addChild(item);
}
for (Model *model : sFavoriteModels) {
if (isModelFiltered(model) && isModelMatch(model, search)) {
ModelItem *item = new ModelItem;
item->setModel(model);
moduleList->addChild(item);
}
}
// Author items
{
SeparatorItem *item = new SeparatorItem;
item->setText("Authors");
moduleList->addChild(item);
}
for (std::string author : availableAuthors) {
if (isMatch(author, search)) {
AuthorItem *item = new AuthorItem;
item->setAuthor(author);
moduleList->addChild(item);
}
}
// Tag items
{
SeparatorItem *item = new SeparatorItem;
item->setText("Tags");
moduleList->addChild(item);
}
for (std::string tag : availableTags) {
if (isMatch(tag, search)) {
TagItem *item = new TagItem;
item->setTag(tag);
moduleList->addChild(item);
}
}
}
else {
// Clear filter
ClearFilterItem *item = new ClearFilterItem;
moduleList->addChild(item);
}

if (filterPage || !search.empty()) {
if (!search.empty()) {
SeparatorItem *item = new SeparatorItem;
item->setText("Modules");
moduleList->addChild(item);
}
else if (filterPage) {
SeparatorItem *item = new SeparatorItem;
if (!sAuthorFilter.empty())
item->setText(sAuthorFilter);
else if (!sTagFilter.empty())
item->setText("Tag: " + sTagFilter);
moduleList->addChild(item);
}
// Modules
for (Plugin *plugin : plugin::plugins) {
for (Model *model : plugin->models) {
if (isModelFiltered(model) && isModelMatch(model, search)) {
ModelItem *item = new ModelItem;
item->setModel(model);
moduleList->addChild(item);
}
}
ModuleWidgetWrapper *wrapper = new ModuleWidgetWrapper;
wrapper->box.pos = p;
addChild(wrapper);

ZoomWidget *zoomWidget = new ZoomWidget;
zoomWidget->setZoom(0.5);
wrapper->addChild(zoomWidget);

ModuleWidget *moduleWidget = model->createModuleWidgetNull();
zoomWidget->addChild(moduleWidget);
wrapper->box.size = moduleWidget->box.size.mult(zoomWidget->zoom);
p = wrapper->box.getTopRight();
}
}
}

void step() override {
box.pos = parent->box.size.minus(box.size).div(2).round();
box.pos.y = 60;
box.size.y = parent->box.size.y - 2 * box.pos.y;
moduleScroll->box.size.y = std::min(box.size.y - moduleScroll->box.pos.y, moduleList->box.size.y);
box.size.y = std::min(box.size.y, moduleScroll->box.getBottomRight().y);

context()->event->selectedWidget = searchField;
Widget::step();
}
};

assert(parent);

// Implementations of inline methods above
box = parent->box.zeroPos().grow(math::Vec(-100, -100));

void AuthorItem::onAction(const event::Action &e) {
ModuleBrowser *moduleBrowser = getAncestorOfType<ModuleBrowser>();
sAuthorFilter = author;
moduleBrowser->clearSearch();
moduleBrowser->refreshSearch();
e.consume(this);
}

void TagItem::onAction(const event::Action &e) {
ModuleBrowser *moduleBrowser = getAncestorOfType<ModuleBrowser>();
sTagFilter = tag;
moduleBrowser->clearSearch();
moduleBrowser->refreshSearch();
e.consume(this);
}

void ClearFilterItem::onAction(const event::Action &e) {
ModuleBrowser *moduleBrowser = getAncestorOfType<ModuleBrowser>();
sAuthorFilter = "";
sTagFilter = "";
moduleBrowser->refreshSearch();
e.consume(this);
}

void FavoriteRadioButton::onAction(const event::Action &e) {
if (!model)
return;
if (quantity->isMax()) {
sFavoriteModels.insert(model);
}
else {
auto it = sFavoriteModels.find(model);
if (it != sFavoriteModels.end())
sFavoriteModels.erase(it);
OpaqueWidget::step();
}

ModuleBrowser *moduleBrowser = getAncestorOfType<ModuleBrowser>();
if (moduleBrowser)
moduleBrowser->refreshSearch();
}

void BrowserListItem::onDragStart(const event::DragStart &e) {
BrowserList *list = dynamic_cast<BrowserList*>(parent);
if (list) {
list->selectItem(this);
void draw(NVGcontext *vg) override {
bndTooltipBackground(vg, 0.0, 0.0, box.size.x, box.size.y);
Widget::draw(vg);
}
}

void SearchModuleField::onChange(const event::Change &e) {
moduleBrowser->refreshSearch();
}
};

void SearchModuleField::onSelectKey(const event::SelectKey &e) {
if (e.action == GLFW_PRESS) {
switch (e.key) {
case GLFW_KEY_ESCAPE: {
MenuOverlay *overlay = getAncestorOfType<MenuOverlay>();
overlay->requestedDelete = true;
e.consume(this);
return;
} break;
case GLFW_KEY_UP: {
moduleBrowser->moduleList->incrementSelection(-1);
moduleBrowser->moduleList->scrollSelected();
e.consume(this);
} break;
case GLFW_KEY_DOWN: {
moduleBrowser->moduleList->incrementSelection(1);
moduleBrowser->moduleList->scrollSelected();
e.consume(this);
} break;
case GLFW_KEY_PAGE_UP: {
moduleBrowser->moduleList->incrementSelection(-5);
moduleBrowser->moduleList->scrollSelected();
e.consume(this);
} break;
case GLFW_KEY_PAGE_DOWN: {
moduleBrowser->moduleList->incrementSelection(5);
moduleBrowser->moduleList->scrollSelected();
e.consume(this);
} break;
case GLFW_KEY_ENTER: {
BrowserListItem *item = moduleBrowser->moduleList->getSelectedItem();
if (item) {
item->doAction();
e.consume(this);
}
} break;
}
}

if (!e.getConsumed())
TextField::onSelectKey(e);
}

// Global functions



+ 3
- 1
src/app/ModuleLightWidget.cpp View File

@@ -5,7 +5,9 @@ namespace rack {


void ModuleLightWidget::step() {
assert(module);
if (!module)
return;

assert(module->lights.size() >= firstLightId + baseColors.size());
std::vector<float> values(baseColors.size());



+ 20
- 0
src/app/ParamQuantity.cpp View File

@@ -14,6 +14,8 @@ void ParamQuantity::commitSnap() {
}

void ParamQuantity::setValue(float value) {
if (!module)
return;
value = math::clamp(value, getMinValue(), getMaxValue());
// TODO Smooth
// TODO Snap
@@ -21,22 +23,32 @@ void ParamQuantity::setValue(float value) {
}

float ParamQuantity::getValue() {
if (!module)
return Quantity::getValue();
return getParam()->value;
}

float ParamQuantity::getMinValue() {
if (!module)
return Quantity::getMinValue();
return getParam()->minValue;
}

float ParamQuantity::getMaxValue() {
if (!module)
return Quantity::getMaxValue();
return getParam()->maxValue;
}

float ParamQuantity::getDefaultValue() {
if (!module)
return Quantity::getDefaultValue();
return getParam()->defaultValue;
}

float ParamQuantity::getDisplayValue() {
if (!module)
return Quantity::getDisplayValue();
if (getParam()->displayBase == 0.f) {
// Linear
return getParam()->value * getParam()->displayMultiplier;
@@ -52,6 +64,8 @@ float ParamQuantity::getDisplayValue() {
}

void ParamQuantity::setDisplayValue(float displayValue) {
if (!module)
return;
if (getParam()->displayBase == 0.f) {
// Linear
getParam()->value = displayValue / getParam()->displayMultiplier;
@@ -67,14 +81,20 @@ void ParamQuantity::setDisplayValue(float displayValue) {
}

int ParamQuantity::getDisplayPrecision() {
if (!module)
return Quantity::getDisplayPrecision();
return getParam()->displayPrecision;
}

std::string ParamQuantity::getLabel() {
if (!module)
return Quantity::getLabel();
return getParam()->label;
}

std::string ParamQuantity::getUnit() {
if (!module)
return Quantity::getUnit();
return getParam()->unit;
}



+ 3
- 0
src/app/PortWidget.cpp View File

@@ -29,6 +29,9 @@ PortWidget::~PortWidget() {
}

void PortWidget::step() {
if (!module)
return;

std::vector<float> values(2);
if (type == INPUT) {
values[0] = module->inputs[portId].plugLights[0].getBrightness();


Loading…
Cancel
Save