| @@ -12,6 +12,7 @@ namespace app { | |||
| struct PortWidget : widget::OpaqueWidget { | |||
| engine::Module *module = NULL; | |||
| int portId; | |||
| bool hovered = false; | |||
| enum Type { | |||
| OUTPUT, | |||
| @@ -27,6 +28,8 @@ struct PortWidget : widget::OpaqueWidget { | |||
| void draw(const widget::DrawContext &ctx) override; | |||
| void onButton(const event::Button &e) override; | |||
| void onEnter(const event::Enter &e) override; | |||
| void onLeave(const event::Leave &e) override; | |||
| void onDragStart(const event::DragStart &e) override; | |||
| void onDragEnd(const event::DragEnd &e) override; | |||
| void onDragDrop(const event::DragDrop &e) override; | |||
| @@ -110,6 +110,7 @@ struct HoverScroll : Event, Position { | |||
| /** Occurs when a Widget begins consuming the Hover event. | |||
| Must consume to set the widget as hovered. | |||
| */ | |||
| struct Enter : Event { | |||
| }; | |||
| @@ -122,6 +123,7 @@ struct Leave : Event { | |||
| /** Occurs when a Widget begins consuming the Button press event. | |||
| Must consume to set the widget as selected. | |||
| */ | |||
| struct Select : Event { | |||
| }; | |||
| @@ -141,12 +143,14 @@ struct SelectKey : Event, Key { | |||
| /** Occurs when text is typed while a Widget is selected. | |||
| If consumed, a HoverText event will not be triggered. | |||
| */ | |||
| struct SelectText : Event, Text { | |||
| }; | |||
| /** Occurs when a Widget begins being dragged. | |||
| Must consume to set the widget as dragged. | |||
| */ | |||
| struct DragStart : Event { | |||
| }; | |||
| @@ -177,6 +181,7 @@ struct DragHover : Event, Position { | |||
| }; | |||
| /** Occurs when the mouse enters a Widget while dragging. | |||
| Must consume to set the widget as drag-hovered. | |||
| */ | |||
| struct DragEnter : Event { | |||
| /** The dragged widget */ | |||
| @@ -21,6 +21,7 @@ struct MenuItem : MenuEntry { | |||
| void draw(const widget::DrawContext &ctx) override; | |||
| void step() override; | |||
| void onEnter(const event::Enter &e) override; | |||
| void onDragStart(const event::DragStart &e) override; | |||
| void onDragDrop(const event::DragDrop &e) override; | |||
| void doAction(); | |||
| virtual Menu *createChildMenu() {return NULL;} | |||
| @@ -25,6 +25,7 @@ struct TextField : widget::OpaqueWidget { | |||
| void onButton(const event::Button &e) override; | |||
| void onHover(const event::Hover &e) override; | |||
| void onEnter(const event::Enter &e) override; | |||
| void onSelect(const event::Select &e) override; | |||
| void onSelectText(const event::SelectText &e) override; | |||
| void onSelectKey(const event::SelectKey &e) override; | |||
| @@ -30,19 +30,24 @@ struct ModuleResizeHandle : Widget { | |||
| bool right = false; | |||
| float dragX; | |||
| Rect originalBox; | |||
| ModuleResizeHandle() { | |||
| box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT); | |||
| } | |||
| void onButton(const event::Button &e) override { | |||
| if (e.button == GLFW_MOUSE_BUTTON_LEFT) { | |||
| e.consume(this); | |||
| } | |||
| } | |||
| void onDragStart(const event::DragStart &e) override { | |||
| dragX = APP->scene->rackWidget->mousePos.x; | |||
| ModuleWidget *m = getAncestorOfType<ModuleWidget>(); | |||
| originalBox = m->box; | |||
| e.consume(this); | |||
| } | |||
| void onDragMove(const event::DragMove &e) override { | |||
| ModuleWidget *m = getAncestorOfType<ModuleWidget>(); | |||
| @@ -64,6 +69,7 @@ struct ModuleResizeHandle : Widget { | |||
| } | |||
| APP->scene->rackWidget->requestModuleBox(m, newBox); | |||
| } | |||
| void draw(const DrawContext &ctx) override { | |||
| for (float x = 5.0; x <= 10.0; x += 5.0) { | |||
| nvgBeginPath(ctx.vg); | |||
| @@ -88,10 +88,8 @@ struct CcChoice : LedDisplayChoice { | |||
| } | |||
| void step() override { | |||
| if (!module) { | |||
| text = ""; | |||
| if (!module) | |||
| return; | |||
| } | |||
| if (module->learningId == id) { | |||
| if (0 <= focusCc) | |||
| text = string::f("%d", focusCc); | |||
| @@ -103,25 +101,27 @@ struct CcChoice : LedDisplayChoice { | |||
| text = string::f("%d", module->learnedCcs[id]); | |||
| color.a = 1.0; | |||
| if (APP->event->selectedWidget == this) | |||
| APP->event->selectedWidget = NULL; | |||
| APP->event->setSelected(NULL); | |||
| } | |||
| } | |||
| void onSelect(const event::Select &e) override { | |||
| e.consume(this); | |||
| if (!module) | |||
| return; | |||
| module->learningId = id; | |||
| focusCc = -1; | |||
| e.consume(this); | |||
| } | |||
| void onDeselect(const event::Deselect &e) override { | |||
| if (!module) | |||
| return; | |||
| if (0 <= focusCc && focusCc < 128) { | |||
| module->learnedCcs[id] = focusCc; | |||
| if (module->learningId == id) { | |||
| if (0 <= focusCc && focusCc < 128) { | |||
| module->learnedCcs[id] = focusCc; | |||
| } | |||
| module->learningId = -1; | |||
| } | |||
| module->learningId = -1; | |||
| } | |||
| void onSelectText(const event::SelectText &e) override { | |||
| @@ -180,20 +180,22 @@ struct NoteChoice : LedDisplayChoice { | |||
| color.a = 1.0; | |||
| if (APP->event->selectedWidget == this) | |||
| APP->event->selectedWidget = NULL; | |||
| APP->event->setSelected(NULL); | |||
| } | |||
| } | |||
| void onSelect(const event::Select &e) override { | |||
| e.consume(this); | |||
| if (!module) | |||
| return; | |||
| module->learningId = id; | |||
| e.consume(this); | |||
| } | |||
| void onDeselect(const event::Deselect &e) override { | |||
| if (!module) | |||
| return; | |||
| module->learningId = -1; | |||
| if (module->learningId == id) { | |||
| module->learningId = -1; | |||
| } | |||
| } | |||
| }; | |||
| @@ -216,8 +216,7 @@ void CableWidget::draw(const widget::DrawContext &ctx) { | |||
| } | |||
| else { | |||
| // Draw opaque if mouse is hovering over a connected port | |||
| PortWidget *hoveredPort = dynamic_cast<PortWidget*>(APP->event->hoveredWidget); | |||
| if (hoveredPort && (hoveredPort == outputPort || hoveredPort == inputPort)) | |||
| if (outputPort->hovered || inputPort->hovered) | |||
| opacity = 1.0; | |||
| } | |||
| @@ -36,6 +36,7 @@ void Knob::onDragStart(const event::DragStart &e) { | |||
| } | |||
| APP->window->cursorLock(); | |||
| e.consume(this); | |||
| } | |||
| void Knob::onDragEnd(const event::DragEnd &e) { | |||
| @@ -62,6 +62,7 @@ struct ModuleBox : widget::OpaqueWidget { | |||
| widget::Widget *previewWidget = NULL; | |||
| /** Number of frames since draw() has been called */ | |||
| int visibleFrames = 0; | |||
| bool selected = false; | |||
| void setModel(plugin::Model *model) { | |||
| this->model = model; | |||
| @@ -125,7 +126,7 @@ struct ModuleBox : widget::OpaqueWidget { | |||
| } | |||
| widget::OpaqueWidget::draw(ctx); | |||
| if (APP->event->hoveredWidget == this) { | |||
| if (selected) { | |||
| nvgBeginPath(ctx.vg); | |||
| nvgRect(ctx.vg, 0.0, 0.0, box.size.x, box.size.y); | |||
| nvgFillColor(ctx.vg, nvgRGBAf(1, 1, 1, 0.25)); | |||
| @@ -134,6 +135,15 @@ struct ModuleBox : widget::OpaqueWidget { | |||
| } | |||
| void onButton(const event::Button &e) override; | |||
| void onEnter(const event::Enter &e) override { | |||
| e.consume(this); | |||
| selected = true; | |||
| } | |||
| void onLeave(const event::Leave &e) override { | |||
| selected = false; | |||
| } | |||
| }; | |||
| @@ -193,13 +193,15 @@ void ModuleWidget::drawShadow(const widget::DrawContext &ctx) { | |||
| void ModuleWidget::onHover(const event::Hover &e) { | |||
| widget::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) | |||
| && (APP->window->getMods() & WINDOW_MOD_MASK) == 0) { | |||
| removeAction(); | |||
| e.consume(NULL); | |||
| return; | |||
| if (!APP->event->selectedWidget) { | |||
| // 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) | |||
| && (APP->window->getMods() & WINDOW_MOD_MASK) == 0) { | |||
| removeAction(); | |||
| e.consume(NULL); | |||
| return; | |||
| } | |||
| } | |||
| } | |||
| @@ -268,6 +270,7 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) { | |||
| void ModuleWidget::onDragStart(const event::DragStart &e) { | |||
| oldPos = box.pos; | |||
| dragPos = APP->scene->rackWidget->mousePos.minus(box.pos); | |||
| e.consume(this); | |||
| } | |||
| void ModuleWidget::onDragEnd(const event::DragEnd &e) { | |||
| @@ -167,6 +167,7 @@ void ParamWidget::onEnter(const event::Enter &e) { | |||
| paramTooltip->paramWidget = this; | |||
| APP->scene->addChild(paramTooltip); | |||
| tooltip = paramTooltip; | |||
| e.consume(this); | |||
| } | |||
| } | |||
| @@ -78,6 +78,15 @@ void PortWidget::onButton(const event::Button &e) { | |||
| e.consume(this); | |||
| } | |||
| void PortWidget::onEnter(const event::Enter &e) { | |||
| hovered = true; | |||
| e.consume(this); | |||
| } | |||
| void PortWidget::onLeave(const event::Leave &e) { | |||
| hovered = false; | |||
| } | |||
| void PortWidget::onDragStart(const event::DragStart &e) { | |||
| CableWidget *cw = NULL; | |||
| if (type == OUTPUT && (APP->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | |||
| @@ -110,6 +119,7 @@ void PortWidget::onDragStart(const event::DragStart &e) { | |||
| cw->setInput(this); | |||
| } | |||
| APP->scene->rackWidget->setIncompleteCable(cw); | |||
| e.consume(this); | |||
| } | |||
| void PortWidget::onDragEnd(const event::DragEnd &e) { | |||
| @@ -158,6 +168,7 @@ void PortWidget::onDragEnter(const event::DragEnter &e) { | |||
| else | |||
| cw->hoveredInputPort = this; | |||
| } | |||
| e.consume(this); | |||
| } | |||
| void PortWidget::onDragLeave(const event::DragLeave &e) { | |||
| @@ -28,6 +28,7 @@ void SVGButton::onDragStart(const event::DragStart &e) { | |||
| sw->setSVG(frames[1]); | |||
| fb->dirty = true; | |||
| } | |||
| e.consume(this); | |||
| } | |||
| void SVGButton::onDragEnd(const event::DragEnd &e) { | |||
| @@ -55,6 +55,7 @@ void Switch::onDragStart(const event::DragStart &e) { | |||
| } | |||
| } | |||
| } | |||
| e.consume(this); | |||
| } | |||
| void Switch::onDragEnd(const event::DragEnd &e) { | |||
| @@ -415,9 +415,10 @@ struct AccountEmailField : ui::TextField { | |||
| if (e.action == GLFW_PRESS && e.key == GLFW_KEY_TAB) { | |||
| APP->event->selectedWidget = passwordField; | |||
| e.consume(this); | |||
| return; | |||
| } | |||
| ui::TextField::onSelectKey(e); | |||
| if (!e.getConsumed()) | |||
| ui::TextField::onSelectKey(e); | |||
| } | |||
| }; | |||
| @@ -431,9 +432,10 @@ struct AccountPasswordField : ui::PasswordField { | |||
| if (e.action == GLFW_PRESS && (e.key == GLFW_KEY_ENTER || e.key == GLFW_KEY_KP_ENTER)) { | |||
| logInItem->doAction(); | |||
| e.consume(this); | |||
| return; | |||
| } | |||
| ui::PasswordField::onSelectKey(e); | |||
| if (!e.getConsumed()) | |||
| ui::PasswordField::onSelectKey(e); | |||
| } | |||
| }; | |||
| @@ -14,14 +14,16 @@ void State::setHovered(widget::Widget *w) { | |||
| // event::Leave | |||
| event::Leave eLeave; | |||
| hoveredWidget->onLeave(eLeave); | |||
| hoveredWidget = NULL; | |||
| } | |||
| hoveredWidget = w; | |||
| if (hoveredWidget) { | |||
| if (w) { | |||
| // event::Enter | |||
| event::Context eEnterContext; | |||
| event::Enter eEnter; | |||
| hoveredWidget->onEnter(eEnter); | |||
| eEnter.context = &eEnterContext; | |||
| w->onEnter(eEnter); | |||
| hoveredWidget = eEnterContext.consumed; | |||
| } | |||
| } | |||
| @@ -33,14 +35,16 @@ void State::setDragged(widget::Widget *w) { | |||
| // event::DragEnd | |||
| event::DragEnd eDragEnd; | |||
| draggedWidget->onDragEnd(eDragEnd); | |||
| draggedWidget = NULL; | |||
| } | |||
| draggedWidget = w; | |||
| if (draggedWidget) { | |||
| if (w) { | |||
| // event::DragStart | |||
| event::Context eDragStartContext; | |||
| event::DragStart eDragStart; | |||
| draggedWidget->onDragStart(eDragStart); | |||
| eDragStart.context = &eDragStartContext; | |||
| w->onDragStart(eDragStart); | |||
| draggedWidget = eDragStartContext.consumed; | |||
| } | |||
| } | |||
| @@ -53,15 +57,17 @@ void State::setDragHovered(widget::Widget *w) { | |||
| event::DragLeave eDragLeave; | |||
| eDragLeave.origin = draggedWidget; | |||
| dragHoveredWidget->onDragLeave(eDragLeave); | |||
| dragHoveredWidget = NULL; | |||
| } | |||
| dragHoveredWidget = w; | |||
| if (dragHoveredWidget) { | |||
| if (w) { | |||
| // event::DragEnter | |||
| event::Context eDragEnterContext; | |||
| event::DragEnter eDragEnter; | |||
| eDragEnter.context = &eDragEnterContext; | |||
| eDragEnter.origin = draggedWidget; | |||
| dragHoveredWidget->onDragEnter(eDragEnter); | |||
| w->onDragEnter(eDragEnter); | |||
| dragHoveredWidget = eDragEnterContext.consumed; | |||
| } | |||
| } | |||
| @@ -73,14 +79,16 @@ void State::setSelected(widget::Widget *w) { | |||
| // event::Deselect | |||
| event::Deselect eDeselect; | |||
| selectedWidget->onDeselect(eDeselect); | |||
| selectedWidget = NULL; | |||
| } | |||
| selectedWidget = w; | |||
| if (selectedWidget) { | |||
| if (w) { | |||
| // event::Select | |||
| event::Context eSelectContext; | |||
| event::Select eSelect; | |||
| selectedWidget->onSelect(eSelect); | |||
| eSelect.context = &eSelectContext; | |||
| w->onSelect(eSelect); | |||
| selectedWidget = eSelectContext.consumed; | |||
| } | |||
| } | |||
| @@ -20,6 +20,7 @@ void Button::draw(const widget::DrawContext &ctx) { | |||
| void Button::onEnter(const event::Enter &e) { | |||
| state = BND_HOVER; | |||
| e.consume(this); | |||
| } | |||
| void Button::onLeave(const event::Leave &e) { | |||
| @@ -30,6 +31,7 @@ void Button::onDragStart(const event::DragStart &e) { | |||
| state = BND_ACTIVE; | |||
| if (quantity) | |||
| quantity->setMax(); | |||
| e.consume(this); | |||
| } | |||
| void Button::onDragEnd(const event::DragEnd &e) { | |||
| @@ -38,6 +38,7 @@ void MenuItem::step() { | |||
| } | |||
| void MenuItem::onEnter(const event::Enter &e) { | |||
| e.consume(this); | |||
| Menu *parentMenu = dynamic_cast<Menu*>(parent); | |||
| if (!parentMenu) | |||
| return; | |||
| @@ -53,6 +54,10 @@ void MenuItem::onEnter(const event::Enter &e) { | |||
| parentMenu->setChildMenu(childMenu); | |||
| } | |||
| void MenuItem::onDragStart(const event::DragStart &e) { | |||
| e.consume(this); | |||
| } | |||
| void MenuItem::onDragDrop(const event::DragDrop &e) { | |||
| if (e.origin != this) | |||
| return; | |||
| @@ -24,6 +24,7 @@ void RadioButton::draw(const widget::DrawContext &ctx) { | |||
| void RadioButton::onEnter(const event::Enter &e) { | |||
| if (state != BND_ACTIVE) | |||
| state = BND_HOVER; | |||
| e.consume(this); | |||
| } | |||
| void RadioButton::onLeave(const event::Leave &e) { | |||
| @@ -22,6 +22,7 @@ void ScrollBar::draw(const widget::DrawContext &ctx) { | |||
| void ScrollBar::onDragStart(const event::DragStart &e) { | |||
| state = BND_ACTIVE; | |||
| APP->window->cursorLock(); | |||
| e.consume(this); | |||
| } | |||
| void ScrollBar::onDragMove(const event::DragMove &e) { | |||
| @@ -26,6 +26,7 @@ void Slider::draw(const widget::DrawContext &ctx) { | |||
| void Slider::onDragStart(const event::DragStart &e) { | |||
| state = BND_ACTIVE; | |||
| APP->window->cursorLock(); | |||
| e.consume(this); | |||
| } | |||
| void Slider::onDragMove(const event::DragMove &e) { | |||
| @@ -51,6 +51,10 @@ void TextField::onEnter(const event::Enter &e) { | |||
| e.consume(this); | |||
| } | |||
| void TextField::onSelect(const event::Select &e) { | |||
| e.consume(this); | |||
| } | |||
| void TextField::onSelectText(const event::SelectText &e) { | |||
| if (e.codepoint < 128) { | |||
| std::string newText(1, (char) e.codepoint); | |||
| @@ -120,14 +120,6 @@ void Widget::draw(const DrawContext &ctx) { | |||
| child->draw(childCtx); | |||
| // Draw red hitboxes | |||
| // if (APP->event->hoveredWidget == child) { | |||
| // nvgBeginPath(ctx.vg); | |||
| // nvgRect(ctx.vg, 0, 0, child->box.size.x, child->box.size.y); | |||
| // nvgFillColor(ctx.vg, nvgRGBAf(1, 0, 0, 0.5)); | |||
| // nvgFill(ctx.vg); | |||
| // } | |||
| nvgRestore(ctx.vg); | |||
| } | |||
| } | |||