Browse Source

Add scrolling to MIDI-Map with up to 128 mappings. Add onAdd and onRemove events. Fix minor ScrollWidget behavior.

tags/v1.0.0
Andrew Belt 6 years ago
parent
commit
578dd8aed2
14 changed files with 206 additions and 135 deletions
  1. +2
    -2
      include/app/LedDisplay.hpp
  2. +19
    -7
      include/event.hpp
  3. +2
    -2
      include/ui/ScrollWidget.hpp
  4. +1
    -1
      include/ui/Slider.hpp
  5. +0
    -10
      include/widget/OpaqueWidget.hpp
  6. +2
    -0
      include/widget/Widget.hpp
  7. +143
    -84
      src/Core/MIDI_Map.cpp
  8. +3
    -4
      src/app/LedDisplay.cpp
  9. +1
    -0
      src/engine/Engine.cpp
  10. +0
    -18
      src/event.cpp
  11. +9
    -1
      src/ui/ScrollWidget.cpp
  12. +3
    -6
      src/ui/Slider.cpp
  13. +16
    -0
      src/widget/Widget.cpp
  14. +5
    -0
      src/window.cpp

+ 2
- 2
include/app/LedDisplay.hpp View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "app/common.hpp" #include "app/common.hpp"
#include "widget/Widget.hpp"
#include "widget/OpaqueWidget.hpp"
#include "widget/TransparentWidget.hpp" #include "widget/TransparentWidget.hpp"
#include "ui/TextField.hpp" #include "ui/TextField.hpp"


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




struct LedDisplay : widget::Widget {
struct LedDisplay : widget::OpaqueWidget {
void draw(const widget::DrawContext &ctx) override; void draw(const widget::DrawContext &ctx) override;
}; };




+ 19
- 7
include/event.hpp View File

@@ -222,37 +222,51 @@ struct PathDrop : Event, Position {
}; };




/** Occurs when an certain action is triggered on a Widget.
/** Occurs after a certain action is triggered on a Widget.
The concept of an "action" is dependent on the type of Widget.
*/ */
struct Action : Event { struct Action : Event {
}; };




/** Occurs when the value of a Widget changes.
/** Occurs after the value of a Widget changes.
The concept of a "value" is dependent on the type of Widget.
*/ */
struct Change : Event { struct Change : Event {
}; };




/** Occurs when the zoom level of a Widget is changed.
/** Occurs after the zoom level of a Widget is changed.
Recurses until consumed. Recurses until consumed.
*/ */
struct Zoom : Event { struct Zoom : Event {
}; };




/** Occurs when Widget::setPos() is called.
/** Occurs after the Widget's position is set by setPos();
*/ */
struct Reposition : Event { struct Reposition : Event {
}; };




/** Occurs when Widget::setSize() is called.
/** Occurs after the Widget's size is set by setSize();
*/ */
struct Resize : Event { struct Resize : Event {
}; };




/** Occurs after the Widget is added to a parent.
*/
struct Add : Event {
};


/** Occurs before the Widget is remove from its parent.
*/
struct Remove : Event {
};


struct State { struct State {
widget::Widget *rootWidget = NULL; widget::Widget *rootWidget = NULL;
/** State widgets /** State widgets
@@ -262,8 +276,6 @@ struct State {
widget::Widget *draggedWidget = NULL; widget::Widget *draggedWidget = NULL;
widget::Widget *dragHoveredWidget = NULL; widget::Widget *dragHoveredWidget = NULL;
widget::Widget *selectedWidget = NULL; widget::Widget *selectedWidget = NULL;
/** For middle-click dragging */
widget::Widget *scrollWidget = NULL;
/** For double-clicking */ /** For double-clicking */
double lastClickTime = -INFINITY; double lastClickTime = -INFINITY;
widget::Widget *lastClickedWidget = NULL; widget::Widget *lastClickedWidget = NULL;


+ 2
- 2
include/ui/ScrollWidget.hpp View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "ui/common.hpp" #include "ui/common.hpp"
#include "widget/OpaqueWidget.hpp"
#include "widget/Widget.hpp"
#include "ui/ScrollBar.hpp" #include "ui/ScrollBar.hpp"




@@ -9,7 +9,7 @@ namespace ui {




/** Handles a container with ScrollBar */ /** Handles a container with ScrollBar */
struct ScrollWidget : widget::OpaqueWidget {
struct ScrollWidget : widget::Widget {
widget::Widget *container; widget::Widget *container;
ScrollBar *horizontalScrollBar; ScrollBar *horizontalScrollBar;
ScrollBar *verticalScrollBar; ScrollBar *verticalScrollBar;


+ 1
- 1
include/ui/Slider.hpp View File

@@ -19,7 +19,7 @@ struct Slider : widget::OpaqueWidget {
void onDragStart(const event::DragStart &e) override; void onDragStart(const event::DragStart &e) override;
void onDragMove(const event::DragMove &e) override; void onDragMove(const event::DragMove &e) override;
void onDragEnd(const event::DragEnd &e) override; void onDragEnd(const event::DragEnd &e) override;
void onButton(const event::Button &e) override;
void onDoubleClick(const event::DoubleClick &e) override;
}; };






+ 0
- 10
include/widget/OpaqueWidget.hpp View File

@@ -31,21 +31,11 @@ struct OpaqueWidget : Widget {
if (!e.getConsumed()) if (!e.getConsumed())
e.consume(this); e.consume(this);
} }
void onHoverScroll(const event::HoverScroll &e) override {
Widget::onHoverScroll(e);
if (!e.getConsumed())
e.consume(this);
}
void onDragHover(const event::DragHover &e) override { void onDragHover(const event::DragHover &e) override {
Widget::onDragHover(e); Widget::onDragHover(e);
if (!e.getConsumed()) if (!e.getConsumed())
e.consume(this); e.consume(this);
} }
void onPathDrop(const event::PathDrop &e) override {
Widget::onPathDrop(e);
if (!e.getConsumed())
e.consume(this);
}
}; };






+ 2
- 0
include/widget/Widget.hpp View File

@@ -148,6 +148,8 @@ struct Widget {
virtual void onZoom(const event::Zoom &e) {recurseEvent(&Widget::onZoom, e);} virtual void onZoom(const event::Zoom &e) {recurseEvent(&Widget::onZoom, e);}
virtual void onReposition(const event::Reposition &e) {} virtual void onReposition(const event::Reposition &e) {}
virtual void onResize(const event::Resize &e) {} virtual void onResize(const event::Resize &e) {}
virtual void onAdd(const event::Add &e) {}
virtual void onRemove(const event::Remove &e) {}
}; };






+ 143
- 84
src/Core/MIDI_Map.cpp View File

@@ -1,7 +1,7 @@
#include "plugin.hpp" #include "plugin.hpp"




static const int CHANNELS = 8;
static const int MAX_CHANNELS = 128;




struct MIDI_Map : Module { struct MIDI_Map : Module {
@@ -19,33 +19,37 @@ struct MIDI_Map : Module {
}; };


midi::InputQueue midiInput; midi::InputQueue midiInput;

/** Number of maps */
int mapLen = 0;
/** The mapped CC number of each channel */
int ccs[MAX_CHANNELS];
/** The mapped param handle of each channel */
ParamHandle paramHandles[MAX_CHANNELS];

/** Channel ID of the learning session */ /** Channel ID of the learning session */
int learningId; int learningId;
/** Whether the CC has been set during the learning session */ /** Whether the CC has been set during the learning session */
bool learnedCc; bool learnedCc;
/** Whether the param has been set during the learning session */ /** Whether the param has been set during the learning session */
bool learnedParam; bool learnedParam;
/** The learned CC number of each channel */
int learnedCcs[CHANNELS];
/** The learned param handle of each channel */
ParamHandle learnedParamHandles[CHANNELS];

/** The value of each CC number */ /** The value of each CC number */
int8_t values[128]; int8_t values[128];
/** The smoothing processor (normalized between 0 and 1) of each channel */ /** The smoothing processor (normalized between 0 and 1) of each channel */
dsp::ExponentialFilter valueFilters[CHANNELS];
dsp::ExponentialFilter valueFilters[MAX_CHANNELS];


MIDI_Map() { MIDI_Map() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
for (int i = 0; i < CHANNELS; i++) {
APP->engine->addParamHandle(&learnedParamHandles[i]);
valueFilters[i].lambda = 60.f;
for (int id = 0; id < MAX_CHANNELS; id++) {
APP->engine->addParamHandle(&paramHandles[id]);
} }
onReset(); onReset();
} }


~MIDI_Map() { ~MIDI_Map() {
for (int i = 0; i < CHANNELS; i++) {
APP->engine->removeParamHandle(&learnedParamHandles[i]);
for (int id = 0; id < MAX_CHANNELS; id++) {
APP->engine->removeParamHandle(&paramHandles[id]);
} }
} }


@@ -53,11 +57,8 @@ struct MIDI_Map : Module {
learningId = -1; learningId = -1;
learnedCc = false; learnedCc = false;
learnedParam = false; learnedParam = false;
for (int i = 0; i < CHANNELS; i++) {
learnedCcs[i] = -1;
APP->engine->updateParamHandle(&learnedParamHandles[i], -1, 0);
valueFilters[i].reset();
}
clearMaps();
mapLen = 1;
for (int i = 0; i < 128; i++) { for (int i = 0; i < 128; i++) {
values[i] = -1; values[i] = -1;
} }
@@ -73,20 +74,19 @@ struct MIDI_Map : Module {
float deltaTime = APP->engine->getSampleTime(); float deltaTime = APP->engine->getSampleTime();


// Step channels // Step channels
for (int id = 0; id < CHANNELS; id++) {
int cc = learnedCcs[id];
for (int id = 0; id < mapLen; id++) {
int cc = ccs[id];
if (cc < 0) if (cc < 0)
continue; continue;
// DEBUG("%d %d %p %d", id, learnedCcs[id], learnedParamHandles[id].module, learnedParamHandles[id].paramId);
// Check if CC value has been set // Check if CC value has been set
if (values[cc] < 0) if (values[cc] < 0)
continue; continue;
// Get module // Get module
Module *module = learnedParamHandles[id].module;
Module *module = paramHandles[id].module;
if (!module) if (!module)
continue; continue;
// Get param // Get param
int paramId = learnedParamHandles[id].paramId;
int paramId = paramHandles[id].paramId;
Param *param = &module->params[paramId]; Param *param = &module->params[paramId];
if (!param->isBounded()) if (!param->isBounded())
continue; continue;
@@ -110,14 +110,47 @@ struct MIDI_Map : Module {


void processCC(midi::Message msg) { void processCC(midi::Message msg) {
uint8_t cc = msg.getNote(); uint8_t cc = msg.getNote();
int8_t value = msg.getValue();
// Learn // Learn
if (learningId >= 0 && values[cc] != msg.getValue()) {
learnedCcs[learningId] = cc;
if (0 <= learningId && values[cc] != value) {
ccs[learningId] = cc;
valueFilters[learningId].reset(); valueFilters[learningId].reset();
learnedCc = true; learnedCc = true;
commitLearn(); commitLearn();
updateMapLen();
} }
values[cc] = msg.getValue();
values[cc] = value;
}

void clearMap(int id) {
learningId = -1;
ccs[id] = -1;
APP->engine->updateParamHandle(&paramHandles[id], -1, 0, true);
valueFilters[id].reset();
updateMapLen();
}

void clearMaps() {
learningId = -1;
for (int id = 0; id < MAX_CHANNELS; id++) {
ccs[id] = -1;
APP->engine->updateParamHandle(&paramHandles[id], -1, 0, true);
valueFilters[id].reset();
}
mapLen = 0;
}

void updateMapLen() {
// Find last nonempty map
int id;
for (id = MAX_CHANNELS - 1; id >= 0; id--) {
if (ccs[id] >= 0 || paramHandles[id].moduleId >= 0)
break;
}
mapLen = id + 1;
// Add an empty "Mapping..." slot
if (mapLen < MAX_CHANNELS)
mapLen++;
} }


void commitLearn() { void commitLearn() {
@@ -130,20 +163,14 @@ struct MIDI_Map : Module {
// Reset learned state // Reset learned state
learnedCc = false; learnedCc = false;
learnedParam = false; learnedParam = false;
// Find next unlearned channel
while (++learningId < CHANNELS) {
if (learnedCcs[learningId] < 0 || learnedParamHandles[learningId].moduleId < 0)
// Find next incomplete map
while (++learningId < MAX_CHANNELS) {
if (ccs[learningId] < 0 || paramHandles[learningId].moduleId < 0)
return; return;
} }
learningId = -1; learningId = -1;
} }


void clearLearn(int id) {
disableLearn(id);
learnedCcs[id] = -1;
APP->engine->updateParamHandle(&learnedParamHandles[id], -1, 0);
}

void enableLearn(int id) { void enableLearn(int id) {
if (learningId != id) { if (learningId != id) {
learningId = id; learningId = id;
@@ -159,53 +186,50 @@ struct MIDI_Map : Module {
} }


void learnParam(int id, int moduleId, int paramId) { void learnParam(int id, int moduleId, int paramId) {
APP->engine->updateParamHandle(&learnedParamHandles[id], moduleId, paramId, true);
APP->engine->updateParamHandle(&paramHandles[id], moduleId, paramId, true);
learnedParam = true; learnedParam = true;
commitLearn(); commitLearn();
updateMapLen();
} }


json_t *dataToJson() override { json_t *dataToJson() override {
json_t *rootJ = json_object(); json_t *rootJ = json_object();


json_t *ccsJ = json_array();
for (int i = 0; i < 8; i++) {
json_array_append_new(ccsJ, json_integer(learnedCcs[i]));
}
json_object_set_new(rootJ, "ccs", ccsJ);

json_t *moduleIdsJ = json_array();
json_t *paramIdsJ = json_array();
for (int i = 0; i < CHANNELS; i++) {
json_array_append_new(moduleIdsJ, json_integer(learnedParamHandles[i].moduleId));
json_array_append_new(paramIdsJ, json_integer(learnedParamHandles[i].paramId));
json_t *mapsJ = json_array();
for (int id = 0; id < mapLen; id++) {
json_t *mapJ = json_object();
json_object_set_new(mapJ, "cc", json_integer(ccs[id]));
json_object_set_new(mapJ, "moduleId", json_integer(paramHandles[id].moduleId));
json_object_set_new(mapJ, "paramId", json_integer(paramHandles[id].paramId));
json_array_append(mapsJ, mapJ);
} }
json_object_set_new(rootJ, "moduleIds", moduleIdsJ);
json_object_set_new(rootJ, "paramIds", paramIdsJ);
json_object_set_new(rootJ, "maps", mapsJ);


json_object_set_new(rootJ, "midi", midiInput.toJson()); json_object_set_new(rootJ, "midi", midiInput.toJson());
return rootJ; return rootJ;
} }


void dataFromJson(json_t *rootJ) override { void dataFromJson(json_t *rootJ) override {
json_t *ccsJ = json_object_get(rootJ, "ccs");
if (ccsJ) {
for (int i = 0; i < CHANNELS; i++) {
json_t *ccJ = json_array_get(ccsJ, i);
if (ccJ)
learnedCcs[i] = json_integer_value(ccJ);
clearMaps();

json_t *mapsJ = json_object_get(rootJ, "maps");
if (mapsJ) {
json_t *mapJ;
size_t mapIndex;
json_array_foreach(mapsJ, mapIndex, mapJ) {
json_t *ccJ = json_object_get(mapJ, "cc");
json_t *moduleIdJ = json_object_get(mapJ, "moduleId");
json_t *paramIdJ = json_object_get(mapJ, "paramId");
if (!(ccJ && moduleIdJ && paramIdJ))
continue;
if (mapIndex >= MAX_CHANNELS)
continue;
ccs[mapIndex] = json_integer_value(ccJ);
APP->engine->updateParamHandle(&paramHandles[mapIndex], json_integer_value(moduleIdJ), json_integer_value(paramIdJ), false);
} }
} }


json_t *moduleIdsJ = json_object_get(rootJ, "moduleIds");
json_t *paramIdsJ = json_object_get(rootJ, "paramIds");
if (moduleIdsJ && paramIdsJ) {
for (int i = 0; i < CHANNELS; i++) {
json_t *moduleIdJ = json_array_get(moduleIdsJ, i);
json_t *paramIdJ = json_array_get(paramIdsJ, i);
if (moduleIdJ && paramIdsJ)
APP->engine->updateParamHandle(&learnedParamHandles[i], json_integer_value(moduleIdJ), json_integer_value(paramIdJ), false);
}
}
updateMapLen();


json_t *midiJ = json_object_get(rootJ, "midi"); json_t *midiJ = json_object_get(rootJ, "midi");
if (midiJ) if (midiJ)
@@ -232,7 +256,7 @@ struct MIDI_MapChoice : LedDisplayChoice {
} }


if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
module->clearLearn(id);
module->clearMap(id);
e.consume(this); e.consume(this);
} }
} }
@@ -240,6 +264,10 @@ struct MIDI_MapChoice : LedDisplayChoice {
void onSelect(const event::Select &e) override { void onSelect(const event::Select &e) override {
if (!module) if (!module)
return; return;

ScrollWidget *scroll = getAncestorOfType<ScrollWidget>();
scroll->scrollTo(box);

// Reset touchedParam // Reset touchedParam
APP->scene->rackWidget->touchedParam = NULL; APP->scene->rackWidget->touchedParam = NULL;
module->enableLearn(id); module->enableLearn(id);
@@ -285,13 +313,13 @@ struct MIDI_MapChoice : LedDisplayChoice {


// Set text // Set text
text = ""; text = "";
if (module->learnedCcs[id] >= 0) {
text += string::f("CC%d ", module->learnedCcs[id]);
if (module->ccs[id] >= 0) {
text += string::f("CC%d ", module->ccs[id]);
} }
if (module->learnedParamHandles[id].moduleId >= 0) {
if (module->paramHandles[id].moduleId >= 0) {
text += getParamName(); text += getParamName();
} }
if (module->learnedCcs[id] < 0 && module->learnedParamHandles[id].moduleId < 0) {
if (module->ccs[id] < 0 && module->paramHandles[id].moduleId < 0) {
if (module->learningId == id) { if (module->learningId == id) {
text = "Mapping..."; text = "Mapping...";
} }
@@ -301,7 +329,7 @@ struct MIDI_MapChoice : LedDisplayChoice {
} }


// Set text color // Set text color
if ((module->learnedCcs[id] >= 0 && module->learnedParamHandles[id].moduleId >= 0) || module->learningId == id) {
if ((module->ccs[id] >= 0 && module->paramHandles[id].moduleId >= 0) || module->learningId == id) {
color.a = 1.0; color.a = 1.0;
} }
else { else {
@@ -312,7 +340,9 @@ struct MIDI_MapChoice : LedDisplayChoice {
std::string getParamName() { std::string getParamName() {
if (!module) if (!module)
return ""; return "";
ParamHandle *paramHandle = &module->learnedParamHandles[id];
if (id >= module->mapLen)
return "";
ParamHandle *paramHandle = &module->paramHandles[id];
if (paramHandle->moduleId < 0) if (paramHandle->moduleId < 0)
return ""; return "";
ModuleWidget *mw = APP->scene->rackWidget->getModule(paramHandle->moduleId); ModuleWidget *mw = APP->scene->rackWidget->getModule(paramHandle->moduleId);
@@ -337,28 +367,57 @@ struct MIDI_MapChoice : LedDisplayChoice {




struct MIDI_MapDisplay : MidiWidget { struct MIDI_MapDisplay : MidiWidget {
void setModule(MIDI_Map *module) {
// ScrollWidget *scroll = new ScrollWidget;
// scroll->box.pos = channelChoice->box.getBottomLeft();
// scroll->box.size.x = box.size.x;
// scroll->box.size.y = box.size.y - scroll->box.pos.y;
// addChild(scroll);
MIDI_Map *module;
ScrollWidget *scroll;
MIDI_MapChoice *choices[MAX_CHANNELS];
LedDisplaySeparator *separators[MAX_CHANNELS];


Vec pos = channelChoice->box.getBottomLeft();
void setModule(MIDI_Map *module) {
this->module = module;


for (int i = 0; i < CHANNELS; i++) {
LedDisplaySeparator *separator = createWidget<LedDisplaySeparator>(pos);
separator->box.size.x = box.size.x;
addChild(separator);
scroll = new ScrollWidget;
scroll->box.pos = channelChoice->box.getBottomLeft();
scroll->box.size.x = box.size.x;
scroll->box.size.y = box.size.y - scroll->box.pos.y;
addChild(scroll);

LedDisplaySeparator *separator = createWidget<LedDisplaySeparator>(scroll->box.pos);
separator->box.size.x = box.size.x;
addChild(separator);
separators[0] = separator;

Vec pos;
for (int id = 0; id < MAX_CHANNELS; id++) {
if (id > 0) {
LedDisplaySeparator *separator = createWidget<LedDisplaySeparator>(pos);
separator->box.size.x = box.size.x;
scroll->container->addChild(separator);
separators[id] = separator;
}


MIDI_MapChoice *choice = createWidget<MIDI_MapChoice>(pos); MIDI_MapChoice *choice = createWidget<MIDI_MapChoice>(pos);
choice->box.size.x = box.size.x; choice->box.size.x = box.size.x;
choice->id = i;
choice->id = id;
choice->setModule(module); choice->setModule(module);
addChild(choice);
scroll->container->addChild(choice);
choices[id] = choice;

pos = choice->box.getBottomLeft(); pos = choice->box.getBottomLeft();
} }
} }

void step() override {
if (!module)
return;

int mapLen = module->mapLen;
for (int id = 0; id < MAX_CHANNELS; id++) {
choices[id]->visible = (id < mapLen);
separators[id]->visible = (id < mapLen);
}

MidiWidget::step();
}
}; };




@@ -372,7 +431,7 @@ struct MIDI_MapWidget : ModuleWidget {
addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH))); addChild(createWidget<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));


MIDI_MapDisplay *midiWidget = createWidget<MIDI_MapDisplay>(mm2px(Vec(3.4, 14.839)));
MIDI_MapDisplay *midiWidget = createWidget<MIDI_MapDisplay>(mm2px(Vec(3.41891, 14.8373)));
midiWidget->box.size = mm2px(Vec(43.999, 102.664)); midiWidget->box.size = mm2px(Vec(43.999, 102.664));
midiWidget->setMidiIO(module ? &module->midiInput : NULL); midiWidget->setMidiIO(module ? &module->midiInput : NULL);
midiWidget->setModule(module); midiWidget->setModule(module);


+ 3
- 4
src/app/LedDisplay.cpp View File

@@ -10,12 +10,15 @@ namespace app {




void LedDisplay::draw(const widget::DrawContext &ctx) { void LedDisplay::draw(const widget::DrawContext &ctx) {

nvgBeginPath(ctx.vg); nvgBeginPath(ctx.vg);
nvgRoundedRect(ctx.vg, 0, 0, box.size.x, box.size.y, 5.0); nvgRoundedRect(ctx.vg, 0, 0, box.size.x, box.size.y, 5.0);
nvgFillColor(ctx.vg, nvgRGB(0x00, 0x00, 0x00)); nvgFillColor(ctx.vg, nvgRGB(0x00, 0x00, 0x00));
nvgFill(ctx.vg); nvgFill(ctx.vg);


nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y);
widget::Widget::draw(ctx); widget::Widget::draw(ctx);
nvgResetScissor(ctx.vg);
} }




@@ -42,8 +45,6 @@ LedDisplayChoice::LedDisplayChoice() {
} }


void LedDisplayChoice::draw(const widget::DrawContext &ctx) { void LedDisplayChoice::draw(const widget::DrawContext &ctx) {
nvgScissor(ctx.vg, 0, 0, box.size.x, box.size.y);

if (bgColor.a > 0.0) { if (bgColor.a > 0.0) {
nvgBeginPath(ctx.vg); nvgBeginPath(ctx.vg);
nvgRect(ctx.vg, 0, 0, box.size.x, box.size.y); nvgRect(ctx.vg, 0, 0, box.size.x, box.size.y);
@@ -59,8 +60,6 @@ void LedDisplayChoice::draw(const widget::DrawContext &ctx) {
nvgFontSize(ctx.vg, 12); nvgFontSize(ctx.vg, 12);
nvgText(ctx.vg, textOffset.x, textOffset.y, text.c_str(), NULL); nvgText(ctx.vg, textOffset.x, textOffset.y, text.c_str(), NULL);
} }

nvgResetScissor(ctx.vg);
} }


void LedDisplayChoice::onButton(const event::Button &e) { void LedDisplayChoice::onButton(const event::Button &e) {


+ 1
- 0
src/engine/Engine.cpp View File

@@ -589,6 +589,7 @@ void Engine::addParamHandle(ParamHandle *paramHandle) {
auto it = std::find(internal->paramHandles.begin(), internal->paramHandles.end(), paramHandle); auto it = std::find(internal->paramHandles.begin(), internal->paramHandles.end(), paramHandle);
assert(it == internal->paramHandles.end()); assert(it == internal->paramHandles.end());


// New ParamHandles must be blank
assert(paramHandle->moduleId < 0); assert(paramHandle->moduleId < 0);
internal->paramHandles.push_back(paramHandle); internal->paramHandles.push_back(paramHandle);
} }


+ 0
- 18
src/event.cpp View File

@@ -97,7 +97,6 @@ void State::finalizeWidget(widget::Widget *w) {
if (draggedWidget == w) setDragged(NULL); if (draggedWidget == w) setDragged(NULL);
if (dragHoveredWidget == w) setDragHovered(NULL); if (dragHoveredWidget == w) setDragHovered(NULL);
if (selectedWidget == w) setSelected(NULL); if (selectedWidget == w) setSelected(NULL);
if (scrollWidget == w) scrollWidget = NULL;
if (lastClickedWidget == w) lastClickedWidget = NULL; if (lastClickedWidget == w) lastClickedWidget = NULL;
} }


@@ -149,15 +148,6 @@ void State::handleButton(math::Vec pos, int button, int action, int mods) {
lastClickedWidget = clickedWidget; lastClickedWidget = clickedWidget;
} }
} }

// if (button == GLFW_MOUSE_BUTTON_MIDDLE) {
// if (action == GLFW_PRESS) {
// scrollWidget = clickedWidget;
// }
// if (action == GLFW_RELEASE) {
// scrollWidget = NULL;
// }
// }
} }


void State::handleHover(math::Vec pos, math::Vec mouseDelta) { void State::handleHover(math::Vec pos, math::Vec mouseDelta) {
@@ -181,14 +171,6 @@ void State::handleHover(math::Vec pos, math::Vec mouseDelta) {
return; return;
} }


// if (scrollWidget) {
// event::HoverScroll
// event::HoverScroll eHoverScroll;
// eHoverScroll.pos = pos;
// eHoverScroll.scrollDelta = scrollDelta;
// rootWidget->onHoverScroll(eHoverScroll);
// }

// event::Hover // event::Hover
event::Context eHoverContext; event::Context eHoverContext;
event::Hover eHover; event::Hover eHover;


+ 9
- 1
src/ui/ScrollWidget.cpp View File

@@ -70,10 +70,18 @@ void ScrollWidget::step() {
} }


void ScrollWidget::onHover(const event::Hover &e) { void ScrollWidget::onHover(const event::Hover &e) {
widget::OpaqueWidget::onHover(e);
widget::Widget::onHover(e);
} }


void ScrollWidget::onHoverScroll(const event::HoverScroll &e) { void ScrollWidget::onHoverScroll(const event::HoverScroll &e) {
widget::Widget::onHoverScroll(e);
if (e.getConsumed())
return;

// Scroll only if the scrollbars are visible
if (!(horizontalScrollBar->visible || verticalScrollBar->visible))
return;

math::Vec scrollDelta = e.scrollDelta; math::Vec scrollDelta = e.scrollDelta;
// Flip coordinates if shift is held // Flip coordinates if shift is held
if ((APP->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT) if ((APP->window->getMods() & WINDOW_MOD_MASK) == GLFW_MOD_SHIFT)


+ 3
- 6
src/ui/Slider.cpp View File

@@ -40,12 +40,9 @@ void Slider::onDragEnd(const event::DragEnd &e) {
APP->window->cursorUnlock(); APP->window->cursorUnlock();
} }


void Slider::onButton(const event::Button &e) {
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) {
if (quantity)
quantity->reset();
}
e.consume(this);
void Slider::onDoubleClick(const event::DoubleClick &e) {
if (quantity)
quantity->reset();
} }






+ 16
- 0
src/widget/Widget.cpp View File

@@ -16,12 +16,14 @@ Widget::~Widget() {


void Widget::setPos(math::Vec pos) { void Widget::setPos(math::Vec pos) {
box.pos = pos; box.pos = pos;
// event::Reposition
event::Reposition eReposition; event::Reposition eReposition;
onReposition(eReposition); onReposition(eReposition);
} }


void Widget::setSize(math::Vec size) { void Widget::setSize(math::Vec size) {
box.size = size; box.size = size;
// event::Resize
event::Resize eResize; event::Resize eResize;
onResize(eResize); onResize(eResize);
} }
@@ -30,6 +32,8 @@ math::Rect Widget::getChildrenBoundingBox() {
math::Vec min = math::Vec(INFINITY, INFINITY); math::Vec min = math::Vec(INFINITY, INFINITY);
math::Vec max = math::Vec(-INFINITY, -INFINITY); math::Vec max = math::Vec(-INFINITY, -INFINITY);
for (Widget *child : children) { for (Widget *child : children) {
if (!child->visible)
continue;
min = min.min(child->box.getTopLeft()); min = min.min(child->box.getTopLeft());
max = max.max(child->box.getBottomRight()); max = max.max(child->box.getBottomRight());
} }
@@ -64,12 +68,18 @@ void Widget::addChild(Widget *child) {
assert(!child->parent); assert(!child->parent);
child->parent = this; child->parent = this;
children.push_back(child); children.push_back(child);
// event::Add
event::Add eAdd;
child->onAdd(eAdd);
} }


void Widget::removeChild(Widget *child) { void Widget::removeChild(Widget *child) {
assert(child); assert(child);
// Make sure `this` is the child's parent // Make sure `this` is the child's parent
assert(child->parent == this); assert(child->parent == this);
// event::Remove
event::Remove eRemove;
child->onRemove(eRemove);
// Prepare to remove widget from the event state // Prepare to remove widget from the event state
APP->event->finalizeWidget(child); APP->event->finalizeWidget(child);
// Delete child from children list // Delete child from children list
@@ -82,6 +92,9 @@ void Widget::removeChild(Widget *child) {


void Widget::clearChildren() { void Widget::clearChildren() {
for (Widget *child : children) { for (Widget *child : children) {
// event::Remove
event::Remove eRemove;
child->onRemove(eRemove);
APP->event->finalizeWidget(child); APP->event->finalizeWidget(child);
child->parent = NULL; child->parent = NULL;
delete child; delete child;
@@ -94,6 +107,9 @@ void Widget::step() {
Widget *child = *it; Widget *child = *it;
// Delete children if a delete is requested // Delete children if a delete is requested
if (child->requestedDelete) { if (child->requestedDelete) {
// event::Remove
event::Remove eRemove;
child->onRemove(eRemove);
APP->event->finalizeWidget(child); APP->event->finalizeWidget(child);
it = children.erase(it); it = children.erase(it);
child->parent = NULL; child->parent = NULL;


+ 5
- 0
src/window.cpp View File

@@ -136,6 +136,11 @@ static void cursorPosCallback(GLFWwindow *win, double xpos, double ypos) {
window->mousePos = mousePos; window->mousePos = mousePos;


APP->event->handleHover(mousePos, mouseDelta); APP->event->handleHover(mousePos, mouseDelta);

// Scroll if middle button is held
if (glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE)) {
APP->event->handleScroll(mousePos, mouseDelta);
}
} }


static void cursorEnterCallback(GLFWwindow *win, int entered) { static void cursorEnterCallback(GLFWwindow *win, int entered) {


Loading…
Cancel
Save