Browse Source

Refactor ParamWidget and ModuleWidget. Add context menu to ParamWidget on right-click.

tags/v1.0.0
Andrew Belt 6 years ago
parent
commit
f73dae1384
5 changed files with 412 additions and 340 deletions
  1. +25
    -17
      include/app/ModuleWidget.hpp
  2. +3
    -0
      include/app/ParamWidget.hpp
  3. +2
    -0
      include/window.hpp
  4. +273
    -274
      src/app/ModuleWidget.cpp
  5. +109
    -49
      src/app/ParamWidget.cpp

+ 25
- 17
include/app/ModuleWidget.hpp View File

@@ -30,16 +30,34 @@ struct ModuleWidget : OpaqueWidget {
} }
~ModuleWidget(); ~ModuleWidget();


void draw(NVGcontext *vg) override;
void drawShadow(NVGcontext *vg);

void onHover(const event::Hover &e) override;
void onButton(const event::Button &e) override;
void onHoverKey(const event::HoverKey &e) override;
void onDragStart(const event::DragStart &e) override;
void onDragEnd(const event::DragEnd &e) override;
void onDragMove(const event::DragMove &e) override;

/** Associates this ModuleWidget with the Module
Transfers ownership
*/
void setModule(Module *module); void setModule(Module *module);

/** Convenience functions for adding special widgets (calls addChild()) */ /** Convenience functions for adding special widgets (calls addChild()) */
void addInput(PortWidget *input); void addInput(PortWidget *input);
void addOutput(PortWidget *output); void addOutput(PortWidget *output);
void addParam(ParamWidget *param); void addParam(ParamWidget *param);
void setPanel(std::shared_ptr<SVG> svg); void setPanel(std::shared_ptr<SVG> svg);


/** Overriding these is deprecated.
Use Module::dataToJson() and dataFromJson() instead
*/
virtual json_t *toJson(); virtual json_t *toJson();
virtual void fromJson(json_t *rootJ); virtual void fromJson(json_t *rootJ);


/** Serializes/unserializes the module state */
void copyClipboard(); void copyClipboard();
void pasteClipboard(); void pasteClipboard();
void load(std::string filename); void load(std::string filename);
@@ -50,33 +68,23 @@ struct ModuleWidget : OpaqueWidget {
/** Disconnects cables from all ports /** Disconnects cables from all ports
Called when the user clicks Disconnect Cables in the context menu. Called when the user clicks Disconnect Cables in the context menu.
*/ */
virtual void disconnect();
void disconnect();
/** Resets the parameters of the module and calls the Module's randomize(). /** Resets the parameters of the module and calls the Module's randomize().
Called when the user clicks Initialize in the context menu. Called when the user clicks Initialize in the context menu.
*/ */
virtual void reset();
/** Deprecated */
virtual void initialize() final {}
void reset();
/** Randomizes the parameters of the module and calls the Module's randomize(). /** Randomizes the parameters of the module and calls the Module's randomize().
Called when the user clicks Randomize in the context menu. Called when the user clicks Randomize in the context menu.
*/ */
virtual void randomize();
/** Do not subclass this to add context menu entries. Use appendContextMenu() instead */
virtual Menu *createContextMenu();
void randomize();

void removeAction();
void bypassAction();
void createContextMenu();
/** Override to add context menu entries to your subclass. /** Override to add context menu entries to your subclass.
It is recommended to add a blank MenuEntry first for spacing. It is recommended to add a blank MenuEntry first for spacing.
*/ */
virtual void appendContextMenu(Menu *menu) {} virtual void appendContextMenu(Menu *menu) {}

void draw(NVGcontext *vg) override;
void drawShadow(NVGcontext *vg);

void onHover(const event::Hover &e) override;
void onButton(const event::Button &e) override;
void onHoverKey(const event::HoverKey &e) override;
void onDragStart(const event::DragStart &e) override;
void onDragEnd(const event::DragEnd &e) override;
void onDragMove(const event::DragMove &e) override;
}; };






+ 3
- 0
include/app/ParamWidget.hpp View File

@@ -23,6 +23,9 @@ struct ParamWidget : OpaqueWidget {


/** For legacy patch loading */ /** For legacy patch loading */
void fromJson(json_t *rootJ); void fromJson(json_t *rootJ);
void createParamField();
void createContextMenu();
void resetAction();
}; };






+ 2
- 0
include/window.hpp View File

@@ -20,6 +20,8 @@ Use this instead of GLFW_MOD_CONTROL, since Cmd should be used on Mac in place o
#define WINDOW_MOD_CTRL GLFW_MOD_CONTROL #define WINDOW_MOD_CTRL GLFW_MOD_CONTROL
#define WINDOW_MOD_CTRL_NAME "Ctrl" #define WINDOW_MOD_CTRL_NAME "Ctrl"
#endif #endif
#define WINDOW_MOD_SHIFT_NAME "Shift"
#define WINDOW_MOD_ALT_NAME "Alt"


/** Filters actual mod keys from the mod flags. /** Filters actual mod keys from the mod flags.
Use this if you don't care about GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK. Use this if you don't care about GLFW_MOD_CAPS_LOCK and GLFW_MOD_NUM_LOCK.


+ 273
- 274
src/app/ModuleWidget.cpp View File

@@ -15,10 +15,267 @@
namespace rack { namespace rack {




struct ModuleDisconnectItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleDisconnectItem() {
text = "Disconnect cables";
rightText = WINDOW_MOD_CTRL_NAME "+U";
}
void onAction(const event::Action &e) override {
moduleWidget->disconnect();
}
};

struct ModuleResetItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleResetItem() {
text = "Initialize";
rightText = WINDOW_MOD_CTRL_NAME "+I";
}
void onAction(const event::Action &e) override {
moduleWidget->reset();
}
};

struct ModuleRandomizeItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleRandomizeItem() {
text = "Randomize";
rightText = WINDOW_MOD_CTRL_NAME "+R";
}
void onAction(const event::Action &e) override {
moduleWidget->randomize();
}
};

struct ModuleCopyItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleCopyItem() {
text = "Copy preset";
rightText = WINDOW_MOD_CTRL_NAME "+C";
}
void onAction(const event::Action &e) override {
moduleWidget->copyClipboard();
}
};

struct ModulePasteItem : MenuItem {
ModuleWidget *moduleWidget;
ModulePasteItem() {
text = "Paste preset";
rightText = WINDOW_MOD_CTRL_NAME "+V";
}
void onAction(const event::Action &e) override {
moduleWidget->pasteClipboard();
}
};

struct ModuleSaveItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleSaveItem() {
text = "Save preset as";
}
void onAction(const event::Action &e) override {
moduleWidget->saveDialog();
}
};

struct ModuleLoadItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleLoadItem() {
text = "Load preset";
}
void onAction(const event::Action &e) override {
moduleWidget->loadDialog();
}
};

struct ModuleCloneItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleCloneItem() {
text = "Duplicate";
rightText = WINDOW_MOD_CTRL_NAME "+D";
}
void onAction(const event::Action &e) override {
app()->scene->rackWidget->cloneModule(moduleWidget);
}
};

struct ModuleBypassItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleBypassItem() {
text = "Bypass";
}
void step() override {
rightText = WINDOW_MOD_CTRL_NAME "+E";
if (!moduleWidget->module)
return;
if (moduleWidget->module->bypass)
rightText = CHECKMARK_STRING " " + rightText;
}
void onAction(const event::Action &e) override {
moduleWidget->bypassAction();
}
};

struct ModuleDeleteItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleDeleteItem() {
text = "Delete";
rightText = "Backspace/Delete";
}
void onAction(const event::Action &e) override {
moduleWidget->removeAction();
}
};


ModuleWidget::~ModuleWidget() { ModuleWidget::~ModuleWidget() {
setModule(NULL); setModule(NULL);
} }


void ModuleWidget::draw(NVGcontext *vg) {
if (module && module->bypass) {
nvgGlobalAlpha(vg, 0.5);
}
// nvgScissor(vg, 0, 0, box.size.x, box.size.y);
Widget::draw(vg);

// Power meter
if (module && settings::powerMeter) {
nvgBeginPath(vg);
nvgRect(vg,
0, box.size.y - 20,
65, 20);
nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.75));
nvgFill(vg);

std::string cpuText = string::f("%.2f ÎĽs", module->cpuTime * 1e6f);
bndLabel(vg, 2.0, box.size.y - 20.0, INFINITY, INFINITY, -1, cpuText.c_str());

float p = math::clamp(module->cpuTime / app()->engine->getSampleTime(), 0.f, 1.f);
nvgBeginPath(vg);
nvgRect(vg,
0, (1.f - p) * box.size.y,
5, p * box.size.y);
nvgFillColor(vg, nvgRGBAf(1, 0, 0, 1.0));
nvgFill(vg);
}

// nvgResetScissor(vg);
}

void ModuleWidget::drawShadow(NVGcontext *vg) {
nvgBeginPath(vg);
float r = 20; // Blur radius
float c = 20; // Corner radius
math::Vec b = math::Vec(-10, 30); // Offset from each corner
nvgRect(vg, b.x - r, b.y - r, box.size.x - 2*b.x + 2*r, box.size.y - 2*b.y + 2*r);
NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.2);
NVGcolor transparentColor = nvgRGBAf(0, 0, 0, 0);
nvgFillPaint(vg, nvgBoxGradient(vg, b.x, b.y, box.size.x - 2*b.x, box.size.y - 2*b.y, c, r, shadowColor, transparentColor));
nvgFill(vg);
}

void ModuleWidget::onHover(const event::Hover &e) {
OpaqueWidget::onHover(e);

// Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget.
if (glfwGetKey(app()->window->win, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(app()->window->win, GLFW_KEY_BACKSPACE) == GLFW_PRESS) {
if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
removeAction();
e.consume(NULL);
return;
}
}
}

void ModuleWidget::onButton(const event::Button &e) {
OpaqueWidget::onButton(e);

if (e.getConsumed() == this) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
createContextMenu();
}
}
}

void ModuleWidget::onHoverKey(const event::HoverKey &e) {
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
switch (e.key) {
case GLFW_KEY_I: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
reset();
e.consume(this);
}
} break;
case GLFW_KEY_R: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
randomize();
e.consume(this);
}
} break;
case GLFW_KEY_C: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
copyClipboard();
e.consume(this);
}
} break;
case GLFW_KEY_V: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
pasteClipboard();
e.consume(this);
}
} break;
case GLFW_KEY_D: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
app()->scene->rackWidget->cloneModule(this);
e.consume(this);
}
} break;
case GLFW_KEY_U: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
disconnect();
e.consume(this);
}
} break;
case GLFW_KEY_E: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
bypassAction();
e.consume(this);
}
} break;
}
}

if (!e.getConsumed())
OpaqueWidget::onHoverKey(e);
}

void ModuleWidget::onDragStart(const event::DragStart &e) {
oldPos = box.pos;
dragPos = app()->scene->rackWidget->lastMousePos.minus(box.pos);
}

void ModuleWidget::onDragEnd(const event::DragEnd &e) {
if (!box.pos.isEqual(oldPos)) {
// Push ModuleMove history action
history::ModuleMove *h = new history::ModuleMove;
h->moduleId = module->id;
h->oldPos = oldPos;
h->newPos = box.pos;
app()->history->push(h);
}
}

void ModuleWidget::onDragMove(const event::DragMove &e) {
if (!settings::lockModules) {
math::Rect newBox = box;
newBox.pos = app()->scene->rackWidget->lastMousePos.minus(dragPos);
app()->scene->rackWidget->requestModuleBoxNearest(this, newBox);
}
}

void ModuleWidget::setModule(Module *module) { void ModuleWidget::setModule(Module *module) {
if (this->module) { if (this->module) {
delete this->module; delete this->module;
@@ -244,15 +501,6 @@ void ModuleWidget::saveDialog() {
save(pathStr); save(pathStr);
} }


void ModuleWidget_bypassAction(ModuleWidget *moduleWidget) {
// Push ModuleBypass history action
history::ModuleBypass *h = new history::ModuleBypass;
h->bypass = !moduleWidget->module->bypass;
h->moduleId = moduleWidget->module->id;
app()->history->push(h);
h->redo();
}

void ModuleWidget::disconnect() { void ModuleWidget::disconnect() {
for (PortWidget *input : inputs) { for (PortWidget *input : inputs) {
app()->scene->rackWidget->cableContainer->removeAllCables(input); app()->scene->rackWidget->cableContainer->removeAllCables(input);
@@ -274,282 +522,35 @@ void ModuleWidget::randomize() {
} }
} }


void ModuleWidget::draw(NVGcontext *vg) {
if (module && module->bypass) {
nvgGlobalAlpha(vg, 0.5);
}
// nvgScissor(vg, 0, 0, box.size.x, box.size.y);
Widget::draw(vg);

// Power meter
if (module && settings::powerMeter) {
nvgBeginPath(vg);
nvgRect(vg,
0, box.size.y - 20,
65, 20);
nvgFillColor(vg, nvgRGBAf(0, 0, 0, 0.75));
nvgFill(vg);

std::string cpuText = string::f("%.2f ÎĽs", module->cpuTime * 1e6f);
bndLabel(vg, 2.0, box.size.y - 20.0, INFINITY, INFINITY, -1, cpuText.c_str());

float p = math::clamp(module->cpuTime / app()->engine->getSampleTime(), 0.f, 1.f);
nvgBeginPath(vg);
nvgRect(vg,
0, (1.f - p) * box.size.y,
5, p * box.size.y);
nvgFillColor(vg, nvgRGBAf(1, 0, 0, 1.0));
nvgFill(vg);
}

// nvgResetScissor(vg);
}

void ModuleWidget::drawShadow(NVGcontext *vg) {
nvgBeginPath(vg);
float r = 20; // Blur radius
float c = 20; // Corner radius
math::Vec b = math::Vec(-10, 30); // Offset from each corner
nvgRect(vg, b.x - r, b.y - r, box.size.x - 2*b.x + 2*r, box.size.y - 2*b.y + 2*r);
NVGcolor shadowColor = nvgRGBAf(0, 0, 0, 0.2);
NVGcolor transparentColor = nvgRGBAf(0, 0, 0, 0);
nvgFillPaint(vg, nvgBoxGradient(vg, b.x, b.y, box.size.x - 2*b.x, box.size.y - 2*b.y, c, r, shadowColor, transparentColor));
nvgFill(vg);
}

static void ModuleWidget_removeAction(ModuleWidget *moduleWidget) {
void ModuleWidget::removeAction() {
history::ComplexAction *complexAction = new history::ComplexAction; history::ComplexAction *complexAction = new history::ComplexAction;


// Push ModuleRemove history action // Push ModuleRemove history action
history::ModuleRemove *moduleRemove = new history::ModuleRemove; history::ModuleRemove *moduleRemove = new history::ModuleRemove;
moduleRemove->model = moduleWidget->model;
moduleRemove->moduleId = moduleWidget->module->id;
moduleRemove->pos = moduleWidget->box.pos;
moduleRemove->moduleJ = moduleWidget->toJson();
moduleRemove->model = model;
moduleRemove->moduleId = module->id;
moduleRemove->pos = box.pos;
moduleRemove->moduleJ = toJson();
complexAction->push(moduleRemove); complexAction->push(moduleRemove);


app()->history->push(complexAction); app()->history->push(complexAction);


app()->scene->rackWidget->removeModule(moduleWidget);
delete moduleWidget;
}

void ModuleWidget::onHover(const event::Hover &e) {
OpaqueWidget::onHover(e);

// Instead of checking key-down events, delete the module even if key-repeat hasn't fired yet and the cursor is hovering over the widget.
if (glfwGetKey(app()->window->win, GLFW_KEY_DELETE) == GLFW_PRESS || glfwGetKey(app()->window->win, GLFW_KEY_BACKSPACE) == GLFW_PRESS) {
if ((app()->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
ModuleWidget_removeAction(this);
e.consume(NULL);
return;
}
}
}

void ModuleWidget::onButton(const event::Button &e) {
OpaqueWidget::onButton(e);

if (e.getConsumed() == this) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
createContextMenu();
}
}
}

void ModuleWidget::onHoverKey(const event::HoverKey &e) {
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) {
switch (e.key) {
case GLFW_KEY_I: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
reset();
e.consume(this);
}
} break;
case GLFW_KEY_R: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
randomize();
e.consume(this);
}
} break;
case GLFW_KEY_C: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
copyClipboard();
e.consume(this);
}
} break;
case GLFW_KEY_V: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
pasteClipboard();
e.consume(this);
}
} break;
case GLFW_KEY_D: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
app()->scene->rackWidget->cloneModule(this);
e.consume(this);
}
} break;
case GLFW_KEY_U: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
disconnect();
e.consume(this);
}
} break;
case GLFW_KEY_E: {
if ((e.mods & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) {
ModuleWidget_bypassAction(this);
e.consume(this);
}
} break;
}
}

if (!e.getConsumed())
OpaqueWidget::onHoverKey(e);
}

void ModuleWidget::onDragStart(const event::DragStart &e) {
oldPos = box.pos;
dragPos = app()->scene->rackWidget->lastMousePos.minus(box.pos);
app()->scene->rackWidget->removeModule(this);
delete this;
} }


void ModuleWidget::onDragEnd(const event::DragEnd &e) {
if (!box.pos.isEqual(oldPos)) {
// Push ModuleMove history action
history::ModuleMove *h = new history::ModuleMove;
h->moduleId = module->id;
h->oldPos = oldPos;
h->newPos = box.pos;
app()->history->push(h);
}
}

void ModuleWidget::onDragMove(const event::DragMove &e) {
if (!settings::lockModules) {
math::Rect newBox = box;
newBox.pos = app()->scene->rackWidget->lastMousePos.minus(dragPos);
app()->scene->rackWidget->requestModuleBoxNearest(this, newBox);
}
void ModuleWidget::bypassAction() {
// Push ModuleBypass history action
history::ModuleBypass *h = new history::ModuleBypass;
h->bypass = !module->bypass;
h->moduleId = module->id;
app()->history->push(h);
h->redo();
} }



struct ModuleDisconnectItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleDisconnectItem() {
text = "Disconnect cables";
rightText = WINDOW_MOD_CTRL_NAME "+U";
}
void onAction(const event::Action &e) override {
moduleWidget->disconnect();
}
};

struct ModuleResetItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleResetItem() {
text = "Initialize";
rightText = WINDOW_MOD_CTRL_NAME "+I";
}
void onAction(const event::Action &e) override {
moduleWidget->reset();
}
};

struct ModuleRandomizeItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleRandomizeItem() {
text = "Randomize";
rightText = WINDOW_MOD_CTRL_NAME "+R";
}
void onAction(const event::Action &e) override {
moduleWidget->randomize();
}
};

struct ModuleCopyItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleCopyItem() {
text = "Copy preset";
rightText = WINDOW_MOD_CTRL_NAME "+C";
}
void onAction(const event::Action &e) override {
moduleWidget->copyClipboard();
}
};

struct ModulePasteItem : MenuItem {
ModuleWidget *moduleWidget;
ModulePasteItem() {
text = "Paste preset";
rightText = WINDOW_MOD_CTRL_NAME "+V";
}
void onAction(const event::Action &e) override {
moduleWidget->pasteClipboard();
}
};

struct ModuleSaveItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleSaveItem() {
text = "Save preset as";
}
void onAction(const event::Action &e) override {
moduleWidget->saveDialog();
}
};

struct ModuleLoadItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleLoadItem() {
text = "Load preset";
}
void onAction(const event::Action &e) override {
moduleWidget->loadDialog();
}
};

struct ModuleCloneItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleCloneItem() {
text = "Duplicate";
rightText = WINDOW_MOD_CTRL_NAME "+D";
}
void onAction(const event::Action &e) override {
app()->scene->rackWidget->cloneModule(moduleWidget);
}
};

struct ModuleBypassItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleBypassItem() {
text = "Bypass";
}
void step() override {
rightText = WINDOW_MOD_CTRL_NAME "+E";
if (!moduleWidget->module)
return;
if (moduleWidget->module->bypass)
rightText = CHECKMARK_STRING " " + rightText;
}
void onAction(const event::Action &e) override {
ModuleWidget_bypassAction(moduleWidget);
}
};

struct ModuleDeleteItem : MenuItem {
ModuleWidget *moduleWidget;
ModuleDeleteItem() {
text = "Delete";
rightText = "Backspace/Delete";
}
void onAction(const event::Action &e) override {
ModuleWidget_removeAction(moduleWidget);
}
};

Menu *ModuleWidget::createContextMenu() {
void ModuleWidget::createContextMenu() {
Menu *menu = createMenu(); Menu *menu = createMenu();
assert(model);


MenuLabel *menuLabel = new MenuLabel; MenuLabel *menuLabel = new MenuLabel;
menuLabel->text = model->plugin->name + " " + model->name + " " + model->plugin->version; menuLabel->text = model->plugin->name + " " + model->name + " " + model->plugin->version;
@@ -596,8 +597,6 @@ Menu *ModuleWidget::createContextMenu() {
menu->addChild(deleteItem); menu->addChild(deleteItem);


appendContextMenu(menu); appendContextMenu(menu);

return menu;
} }





+ 109
- 49
src/app/ParamWidget.cpp View File

@@ -7,6 +7,7 @@
#include "settings.hpp" #include "settings.hpp"
#include "random.hpp" #include "random.hpp"
#include "history.hpp" #include "history.hpp"
#include "helpers.hpp"




namespace rack { namespace rack {
@@ -18,6 +19,7 @@ struct ParamField : TextField {
void step() override { void step() override {
// Keep selected // Keep selected
app()->event->setSelected(this); app()->event->setSelected(this);
TextField::step();
} }


void setParamWidget(ParamWidget *paramWidget) { void setParamWidget(ParamWidget *paramWidget) {
@@ -61,6 +63,48 @@ struct ParamField : TextField {
}; };




struct ParamTooltip : Tooltip {
ParamWidget *paramWidget;

void step() override {
if (paramWidget->paramQuantity) {
// Quantity string
text = paramWidget->paramQuantity->getString();
// Param description
std::string description = paramWidget->paramQuantity->getParam()->description;
if (!description.empty())
text += "\n" + description;
}
// Position at bottom-right of parameter
box.pos = paramWidget->getAbsoluteOffset(box.size).round();
}
};


struct ParamResetItem : MenuItem {
ParamWidget *paramWidget;
ParamResetItem() {
text = "Initialize";
rightText = WINDOW_MOD_ALT_NAME "+click";
}
void onAction(const event::Action &e) override {
paramWidget->resetAction();
}
};


struct ParamFieldItem : MenuItem {
ParamWidget *paramWidget;
ParamFieldItem() {
text = "Enter value";
rightText = WINDOW_MOD_SHIFT_NAME "+click";
}
void onAction(const event::Action &e) override {
paramWidget->createParamField();
}
};


ParamWidget::~ParamWidget() { ParamWidget::~ParamWidget() {
if (paramQuantity) if (paramQuantity)
delete paramQuantity; delete paramQuantity;
@@ -77,19 +121,6 @@ void ParamWidget::step() {
} }
} }


if (tooltip) {
if (paramQuantity) {
// Quantity string
tooltip->text = paramQuantity->getString();
// Param description
std::string description = paramQuantity->getParam()->description;
if (!description.empty())
tooltip->text += "\n" + description;
}
// Position at bottom-right of parameter
tooltip->box.pos = getAbsoluteOffset(box.size).round();
}

OpaqueWidget::step(); OpaqueWidget::step();
} }


@@ -109,48 +140,22 @@ void ParamWidget::draw(NVGcontext *vg) {
// } // }
} }


void ParamWidget::fromJson(json_t *rootJ) {
json_t *valueJ = json_object_get(rootJ, "value");
if (valueJ) {
if (paramQuantity)
paramQuantity->setValue(json_number_value(valueJ));
}
}

void ParamWidget::onButton(const event::Button &e) { void ParamWidget::onButton(const event::Button &e) {
// Right click to reset
// Right click to open context menu
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & WINDOW_MOD_MASK) == 0) { if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT && (e.mods & WINDOW_MOD_MASK) == 0) {
if (paramQuantity && paramQuantity->isBounded()) {
float oldValue = paramQuantity->getValue();
paramQuantity->reset();
float newValue = paramQuantity->getValue();
createContextMenu();
e.consume(this);
}


if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange *h = new history::ParamChange;
h->moduleId = paramQuantity->module->id;
h->paramId = paramQuantity->paramId;
h->oldValue = oldValue;
h->newValue = newValue;
app()->history->push(h);
}
}
// Here's another way of doing it, but either works.
// paramQuantity->getParam()->reset();
// Alt-click to reset
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == GLFW_MOD_ALT) {
resetAction();
e.consume(this); e.consume(this);
} }


// Shift-click to open value entry // Shift-click to open value entry
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT) { if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT) {
// Create ParamField
MenuOverlay *overlay = new MenuOverlay;
app()->scene->addChild(overlay);

ParamField *paramField = new ParamField;
paramField->box.size.x = 100;
paramField->box.pos = getAbsoluteOffset(box.size).round();
paramField->setParamWidget(this);
overlay->addChild(paramField);
createParamField();
e.consume(this); e.consume(this);
} }


@@ -160,8 +165,10 @@ void ParamWidget::onButton(const event::Button &e) {


void ParamWidget::onEnter(const event::Enter &e) { void ParamWidget::onEnter(const event::Enter &e) {
if (settings::paramTooltip && !tooltip) { if (settings::paramTooltip && !tooltip) {
tooltip = new Tooltip;
app()->scene->addChild(tooltip);
ParamTooltip *paramTooltip = new ParamTooltip;
paramTooltip->paramWidget = this;
app()->scene->addChild(paramTooltip);
tooltip = paramTooltip;
} }
} }


@@ -173,5 +180,58 @@ void ParamWidget::onLeave(const event::Leave &e) {
} }
} }


void ParamWidget::fromJson(json_t *rootJ) {
json_t *valueJ = json_object_get(rootJ, "value");
if (valueJ) {
if (paramQuantity)
paramQuantity->setValue(json_number_value(valueJ));
}
}

void ParamWidget::createParamField() {
// Create ParamField
MenuOverlay *overlay = new MenuOverlay;
app()->scene->addChild(overlay);

ParamField *paramField = new ParamField;
paramField->box.size.x = 100;
paramField->box.pos = getAbsoluteOffset(box.size).round();
paramField->setParamWidget(this);
overlay->addChild(paramField);
}

void ParamWidget::createContextMenu() {
Menu *menu = createMenu();

ParamResetItem *resetItem = new ParamResetItem;
resetItem->paramWidget = this;
menu->addChild(resetItem);

ParamFieldItem *fieldItem = new ParamFieldItem;
fieldItem->paramWidget = this;
menu->addChild(fieldItem);
}

void ParamWidget::resetAction() {
if (paramQuantity && paramQuantity->isBounded()) {
float oldValue = paramQuantity->getValue();
paramQuantity->reset();
float newValue = paramQuantity->getValue();

if (oldValue != newValue) {
// Push ParamChange history action
history::ParamChange *h = new history::ParamChange;
h->moduleId = paramQuantity->module->id;
h->paramId = paramQuantity->paramId;
h->oldValue = oldValue;
h->newValue = newValue;
app()->history->push(h);
}

// Here's another way of doing it, but either works.
// paramQuantity->getParam()->reset();
}
}



} // namespace rack } // namespace rack

Loading…
Cancel
Save