@@ -1,7 +1,7 @@ | |||||
#pragma once | #pragma once | ||||
#include "app/common.hpp" | #include "app/common.hpp" | ||||
#include "widget/Widget.hpp" | |||||
#include "widget/OpaqueWidget.hpp" | #include "widget/OpaqueWidget.hpp" | ||||
#include "widget/TransparentWidget.hpp" | |||||
#include "ui/TextField.hpp" | #include "ui/TextField.hpp" | ||||
@@ -13,12 +13,12 @@ struct LedDisplay : widget::OpaqueWidget { | |||||
void draw(const DrawArgs &args) override; | void draw(const DrawArgs &args) override; | ||||
}; | }; | ||||
struct LedDisplaySeparator : widget::TransparentWidget { | |||||
struct LedDisplaySeparator : widget::Widget { | |||||
LedDisplaySeparator(); | LedDisplaySeparator(); | ||||
void draw(const DrawArgs &args) override; | void draw(const DrawArgs &args) override; | ||||
}; | }; | ||||
struct LedDisplayChoice : widget::TransparentWidget { | |||||
struct LedDisplayChoice : widget::OpaqueWidget { | |||||
std::string text; | std::string text; | ||||
std::shared_ptr<Font> font; | std::shared_ptr<Font> font; | ||||
math::Vec textOffset; | math::Vec textOffset; | ||||
@@ -32,7 +32,6 @@ struct RackWidget : widget::OpaqueWidget { | |||||
void onHoverKey(const event::HoverKey &e) override; | void onHoverKey(const event::HoverKey &e) override; | ||||
void onDragHover(const event::DragHover &e) override; | void onDragHover(const event::DragHover &e) override; | ||||
void onButton(const event::Button &e) override; | void onButton(const event::Button &e) override; | ||||
void onZoom(const event::Zoom &e) override; | |||||
/** Completely clear the rack's modules and cables */ | /** Completely clear the rack's modules and cables */ | ||||
void clear(); | void clear(); | ||||
@@ -1,6 +1,6 @@ | |||||
#pragma once | #pragma once | ||||
#include "ui/common.hpp" | #include "ui/common.hpp" | ||||
#include "widget/Widget.hpp" | |||||
#include "widget/OpaqueWidget.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::Widget { | |||||
struct ScrollWidget : widget::OpaqueWidget { | |||||
widget::Widget *container; | widget::Widget *container; | ||||
ScrollBar *horizontalScrollBar; | ScrollBar *horizontalScrollBar; | ||||
ScrollBar *verticalScrollBar; | ScrollBar *verticalScrollBar; | ||||
@@ -19,7 +19,9 @@ struct ScrollWidget : widget::Widget { | |||||
void scrollTo(math::Rect r); | void scrollTo(math::Rect r); | ||||
void draw(const DrawArgs &args) override; | void draw(const DrawArgs &args) override; | ||||
void step() override; | void step() override; | ||||
void onHover(const event::Hover &e) override; | |||||
void onButton(const event::Button &e) override; | |||||
void onDragStart(const event::DragStart &e) override; | |||||
void onDragMove(const event::DragMove &e) override; | |||||
void onHoverScroll(const event::HoverScroll &e) override; | void onHoverScroll(const event::HoverScroll &e) override; | ||||
}; | }; | ||||
@@ -8,7 +8,6 @@ namespace widget { | |||||
/** A Widget that stops propagation of all recursive PositionEvents but gives a chance for children to consume first. | /** A Widget that stops propagation of all recursive PositionEvents but gives a chance for children to consume first. | ||||
Also consumes Hover and Button for left-clicks. | Also consumes Hover and Button for left-clicks. | ||||
Remember to call these methods in your subclass if you wish to preserve default OpaqueWidget behavior. | |||||
*/ | */ | ||||
struct OpaqueWidget : Widget { | struct OpaqueWidget : Widget { | ||||
void onHover(const event::Hover &e) override { | void onHover(const event::Hover &e) override { | ||||
@@ -36,13 +36,10 @@ struct ModuleResizeHandle : OpaqueWidget { | |||||
box.size = Vec(RACK_GRID_WIDTH * 1, RACK_GRID_HEIGHT); | 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 { | void onDragStart(const event::DragStart &e) override { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
dragX = APP->scene->rack->mousePos.x; | dragX = APP->scene->rack->mousePos.x; | ||||
ModuleWidget *m = getAncestorOfType<ModuleWidget>(); | ModuleWidget *m = getAncestorOfType<ModuleWidget>(); | ||||
originalBox = m->box; | originalBox = m->box; | ||||
@@ -247,6 +247,7 @@ struct MIDI_MapChoice : LedDisplayChoice { | |||||
} | } | ||||
void onButton(const event::Button &e) override { | void onButton(const event::Button &e) override { | ||||
e.stopPropagating(); | |||||
if (!module) | if (!module) | ||||
return; | return; | ||||
@@ -29,6 +29,9 @@ void Knob::onButton(const event::Button &e) { | |||||
} | } | ||||
void Knob::onDragStart(const event::DragStart &e) { | void Knob::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
if (paramQuantity) { | if (paramQuantity) { | ||||
oldValue = paramQuantity->getSmoothValue(); | oldValue = paramQuantity->getSmoothValue(); | ||||
if (snap) { | if (snap) { | ||||
@@ -62,6 +62,8 @@ void LedDisplayChoice::draw(const DrawArgs &args) { | |||||
} | } | ||||
void LedDisplayChoice::onButton(const event::Button &e) { | void LedDisplayChoice::onButton(const event::Button &e) { | ||||
OpaqueWidget::onButton(e); | |||||
if (e.action == GLFW_PRESS && (e.button == GLFW_MOUSE_BUTTON_LEFT || e.button == GLFW_MOUSE_BUTTON_RIGHT)) { | if (e.action == GLFW_PRESS && (e.button == GLFW_MOUSE_BUTTON_LEFT || e.button == GLFW_MOUSE_BUTTON_RIGHT)) { | ||||
event::Action eAction; | event::Action eAction; | ||||
onAction(eAction); | onAction(eAction); | ||||
@@ -305,8 +305,6 @@ void ModuleWidget::drawShadow(const DrawArgs &args) { | |||||
} | } | ||||
void ModuleWidget::onHover(const event::Hover &e) { | void ModuleWidget::onHover(const event::Hover &e) { | ||||
widget::OpaqueWidget::onHover(e); | |||||
if (!APP->event->selectedWidget) { | 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. | // 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 | if ((glfwGetKey(APP->window->win, GLFW_KEY_DELETE) == GLFW_PRESS | ||||
@@ -317,11 +315,13 @@ void ModuleWidget::onHover(const event::Hover &e) { | |||||
return; | return; | ||||
} | } | ||||
} | } | ||||
OpaqueWidget::onHover(e); | |||||
} | } | ||||
void ModuleWidget::onButton(const event::Button &e) { | void ModuleWidget::onButton(const event::Button &e) { | ||||
widget::OpaqueWidget::onButton(e); | |||||
if (e.getTarget() != this) | |||||
OpaqueWidget::onButton(e); | |||||
if (e.isConsumed()) | |||||
return; | return; | ||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { | if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { | ||||
@@ -331,8 +331,8 @@ void ModuleWidget::onButton(const event::Button &e) { | |||||
} | } | ||||
void ModuleWidget::onHoverKey(const event::HoverKey &e) { | void ModuleWidget::onHoverKey(const event::HoverKey &e) { | ||||
widget::OpaqueWidget::onHoverKey(e); | |||||
if (e.getTarget() != this) | |||||
OpaqueWidget::onHoverKey(e); | |||||
if (e.isConsumed()) | |||||
return; | return; | ||||
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | ||||
@@ -384,6 +384,9 @@ void ModuleWidget::onHoverKey(const event::HoverKey &e) { | |||||
} | } | ||||
void ModuleWidget::onDragStart(const event::DragStart &e) { | void ModuleWidget::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
oldPos = box.pos; | oldPos = box.pos; | ||||
dragPos = APP->scene->rack->mousePos.minus(box.pos); | dragPos = APP->scene->rack->mousePos.minus(box.pos); | ||||
e.consume(this); | e.consume(this); | ||||
@@ -119,7 +119,7 @@ void ParamWidget::step() { | |||||
} | } | ||||
} | } | ||||
OpaqueWidget::step(); | |||||
Widget::step(); | |||||
} | } | ||||
void ParamWidget::draw(const DrawArgs &args) { | void ParamWidget::draw(const DrawArgs &args) { | ||||
@@ -141,14 +141,13 @@ void ParamWidget::draw(const DrawArgs &args) { | |||||
void ParamWidget::onButton(const event::Button &e) { | void ParamWidget::onButton(const event::Button &e) { | ||||
OpaqueWidget::onButton(e); | OpaqueWidget::onButton(e); | ||||
if (e.getTarget() != this) | |||||
return; | |||||
// Touch parameter | // Touch parameter | ||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == 0) { | if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT && (e.mods & WINDOW_MOD_MASK) == 0) { | ||||
if (paramQuantity) { | if (paramQuantity) { | ||||
APP->scene->rack->touchedParam = this; | APP->scene->rack->touchedParam = this; | ||||
} | } | ||||
e.consume(this); | |||||
} | } | ||||
// Right click to open context menu | // Right click to open context menu | ||||
@@ -46,7 +46,7 @@ void PortWidget::step() { | |||||
} | } | ||||
plugLight->setBrightnesses(values); | plugLight->setBrightnesses(values); | ||||
OpaqueWidget::step(); | |||||
Widget::step(); | |||||
} | } | ||||
void PortWidget::draw(const DrawArgs &args) { | void PortWidget::draw(const DrawArgs &args) { | ||||
@@ -73,6 +73,8 @@ void PortWidget::onButton(const event::Button &e) { | |||||
APP->scene->rack->removeCable(cw); | APP->scene->rack->removeCable(cw); | ||||
delete cw; | delete cw; | ||||
} | } | ||||
e.consume(this); | |||||
} | } | ||||
} | } | ||||
@@ -86,6 +88,9 @@ void PortWidget::onLeave(const event::Leave &e) { | |||||
} | } | ||||
void PortWidget::onDragStart(const event::DragStart &e) { | void PortWidget::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
CableWidget *cw = NULL; | CableWidget *cw = NULL; | ||||
if ((APP->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | if ((APP->window->getMods() & WINDOW_MOD_MASK) == WINDOW_MOD_CTRL) { | ||||
if (type == OUTPUT) { | if (type == OUTPUT) { | ||||
@@ -109,21 +109,22 @@ void RackWidget::step() { | |||||
rail->box.size = railFb->box.size; | rail->box.size = railFb->box.size; | ||||
} | } | ||||
OpaqueWidget::step(); | |||||
Widget::step(); | |||||
} | } | ||||
void RackWidget::draw(const DrawArgs &args) { | void RackWidget::draw(const DrawArgs &args) { | ||||
OpaqueWidget::draw(args); | |||||
Widget::draw(args); | |||||
} | } | ||||
void RackWidget::onHover(const event::Hover &e) { | void RackWidget::onHover(const event::Hover &e) { | ||||
// Set before calling children's onHover() | |||||
mousePos = e.pos; | mousePos = e.pos; | ||||
OpaqueWidget::onHover(e); | OpaqueWidget::onHover(e); | ||||
} | } | ||||
void RackWidget::onHoverKey(const event::HoverKey &e) { | void RackWidget::onHoverKey(const event::HoverKey &e) { | ||||
OpaqueWidget::onHoverKey(e); | OpaqueWidget::onHoverKey(e); | ||||
if (e.getTarget() != this) | |||||
if (e.isConsumed()) | |||||
return; | return; | ||||
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | ||||
@@ -139,13 +140,14 @@ void RackWidget::onHoverKey(const event::HoverKey &e) { | |||||
} | } | ||||
void RackWidget::onDragHover(const event::DragHover &e) { | void RackWidget::onDragHover(const event::DragHover &e) { | ||||
OpaqueWidget::onDragHover(e); | |||||
mousePos = e.pos; | mousePos = e.pos; | ||||
OpaqueWidget::onDragHover(e); | |||||
} | } | ||||
void RackWidget::onButton(const event::Button &e) { | void RackWidget::onButton(const event::Button &e) { | ||||
OpaqueWidget::onButton(e); | |||||
if (e.getTarget() != this) | |||||
Widget::onButton(e); | |||||
e.stopPropagating(); | |||||
if (e.isConsumed()) | |||||
return; | return; | ||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { | if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_RIGHT) { | ||||
@@ -154,10 +156,6 @@ void RackWidget::onButton(const event::Button &e) { | |||||
} | } | ||||
} | } | ||||
void RackWidget::onZoom(const event::Zoom &e) { | |||||
OpaqueWidget::onZoom(e); | |||||
} | |||||
void RackWidget::clear() { | void RackWidget::clear() { | ||||
// This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case. | // This isn't required because removing all ModuleWidgets should remove all cables, but do it just in case. | ||||
clearCables(); | clearCables(); | ||||
@@ -64,16 +64,16 @@ void Scene::step() { | |||||
latestVersion = ""; | latestVersion = ""; | ||||
} | } | ||||
OpaqueWidget::step(); | |||||
Widget::step(); | |||||
} | } | ||||
void Scene::draw(const DrawArgs &args) { | void Scene::draw(const DrawArgs &args) { | ||||
OpaqueWidget::draw(args); | |||||
Widget::draw(args); | |||||
} | } | ||||
void Scene::onHoverKey(const event::HoverKey &e) { | void Scene::onHoverKey(const event::HoverKey &e) { | ||||
OpaqueWidget::onHoverKey(e); | OpaqueWidget::onHoverKey(e); | ||||
if (e.getTarget() != this) | |||||
if (e.isConsumed()) | |||||
return; | return; | ||||
if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { | ||||
@@ -135,7 +135,7 @@ void Scene::onHoverKey(const event::HoverKey &e) { | |||||
void Scene::onPathDrop(const event::PathDrop &e) { | void Scene::onPathDrop(const event::PathDrop &e) { | ||||
OpaqueWidget::onPathDrop(e); | OpaqueWidget::onPathDrop(e); | ||||
if (e.getTarget() != this) | |||||
if (e.isConsumed()) | |||||
return; | return; | ||||
if (e.paths.size() >= 1) { | if (e.paths.size() >= 1) { | ||||
@@ -31,6 +31,9 @@ void SvgButton::addFrame(std::shared_ptr<Svg> svg) { | |||||
} | } | ||||
void SvgButton::onDragStart(const event::DragStart &e) { | void SvgButton::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
if (frames.size() >= 2) { | if (frames.size() >= 2) { | ||||
sw->setSvg(frames[1]); | sw->setSvg(frames[1]); | ||||
fb->dirty = true; | fb->dirty = true; | ||||
@@ -29,6 +29,9 @@ void Switch::onDoubleClick(const event::DoubleClick &e) { | |||||
} | } | ||||
void Switch::onDragStart(const event::DragStart &e) { | void Switch::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
if (momentary) { | if (momentary) { | ||||
if (paramQuantity) { | if (paramQuantity) { | ||||
// Set to maximum value | // Set to maximum value | ||||
@@ -23,6 +23,9 @@ void Button::onLeave(const event::Leave &e) { | |||||
} | } | ||||
void Button::onDragStart(const event::DragStart &e) { | void Button::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
state = BND_ACTIVE; | state = BND_ACTIVE; | ||||
if (quantity) | if (quantity) | ||||
quantity->setMax(); | quantity->setMax(); | ||||
@@ -59,6 +59,9 @@ void MenuItem::onEnter(const event::Enter &e) { | |||||
} | } | ||||
void MenuItem::onDragStart(const event::DragStart &e) { | void MenuItem::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
@@ -18,7 +18,7 @@ void MenuOverlay::step() { | |||||
} | } | ||||
void MenuOverlay::onButton(const event::Button &e) { | void MenuOverlay::onButton(const event::Button &e) { | ||||
widget::OpaqueWidget::onButton(e); | |||||
OpaqueWidget::onButton(e); | |||||
if (e.getTarget() != this) | if (e.getTarget() != this) | ||||
return; | return; | ||||
@@ -28,8 +28,8 @@ void MenuOverlay::onButton(const event::Button &e) { | |||||
} | } | ||||
void MenuOverlay::onHoverKey(const event::HoverKey &e) { | void MenuOverlay::onHoverKey(const event::HoverKey &e) { | ||||
widget::OpaqueWidget::onHoverKey(e); | |||||
if (e.getTarget() != this) | |||||
OpaqueWidget::onHoverKey(e); | |||||
if (e.isConsumed()) | |||||
return; | return; | ||||
if (e.action == GLFW_PRESS && e.key == GLFW_KEY_ESCAPE) { | if (e.action == GLFW_PRESS && e.key == GLFW_KEY_ESCAPE) { | ||||
@@ -30,6 +30,9 @@ void RadioButton::onLeave(const event::Leave &e) { | |||||
} | } | ||||
void RadioButton::onDragStart(const event::DragStart &e) { | void RadioButton::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
e.consume(this); | e.consume(this); | ||||
} | } | ||||
@@ -17,6 +17,9 @@ void ScrollBar::draw(const DrawArgs &args) { | |||||
} | } | ||||
void ScrollBar::onDragStart(const event::DragStart &e) { | void ScrollBar::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
state = BND_ACTIVE; | state = BND_ACTIVE; | ||||
APP->window->cursorLock(); | APP->window->cursorLock(); | ||||
e.consume(this); | e.consume(this); | ||||
@@ -63,19 +63,39 @@ void ScrollWidget::step() { | |||||
verticalScrollBar->box.size.y = horizontalScrollBar->visible ? inner.y : box.size.y; | verticalScrollBar->box.size.y = horizontalScrollBar->visible ? inner.y : box.size.y; | ||||
} | } | ||||
void ScrollWidget::onHover(const event::Hover &e) { | |||||
widget::Widget::onHover(e); | |||||
} | |||||
void ScrollWidget::onButton(const event::Button &e) { | |||||
Widget::onButton(e); | |||||
if (e.isConsumed()) | |||||
return; | |||||
void ScrollWidget::onHoverScroll(const event::HoverScroll &e) { | |||||
widget::Widget::onHoverScroll(e); | |||||
if (e.getTarget() != this) | |||||
// Consume right button only if the scrollbars are visible | |||||
if (!(horizontalScrollBar->visible || verticalScrollBar->visible)) | |||||
return; | return; | ||||
if (e.button == GLFW_MOUSE_BUTTON_MIDDLE) { | |||||
e.consume(this); | |||||
} | |||||
} | |||||
void ScrollWidget::onDragStart(const event::DragStart &e) { | |||||
if (e.button == GLFW_MOUSE_BUTTON_MIDDLE) { | |||||
e.consume(this); | |||||
} | |||||
} | |||||
void ScrollWidget::onDragMove(const event::DragMove &e) { | |||||
// Scroll only if the scrollbars are visible | // Scroll only if the scrollbars are visible | ||||
if (!(horizontalScrollBar->visible || verticalScrollBar->visible)) | if (!(horizontalScrollBar->visible || verticalScrollBar->visible)) | ||||
return; | return; | ||||
offset = offset.minus(e.mouseDelta); | |||||
} | |||||
void ScrollWidget::onHoverScroll(const event::HoverScroll &e) { | |||||
OpaqueWidget::onHoverScroll(e); | |||||
if (e.isConsumed()) | |||||
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) | ||||
@@ -19,6 +19,9 @@ void Slider::draw(const DrawArgs &args) { | |||||
} | } | ||||
void Slider::onDragStart(const event::DragStart &e) { | void Slider::onDragStart(const event::DragStart &e) { | ||||
if (e.button != GLFW_MOUSE_BUTTON_LEFT) | |||||
return; | |||||
state = BND_ACTIVE; | state = BND_ACTIVE; | ||||
APP->window->cursorLock(); | APP->window->cursorLock(); | ||||
e.consume(this); | e.consume(this); | ||||
@@ -31,7 +31,7 @@ void TextField::draw(const DrawArgs &args) { | |||||
} | } | ||||
void TextField::onHover(const event::Hover &e) { | void TextField::onHover(const event::Hover &e) { | ||||
widget::OpaqueWidget::onHover(e); | |||||
OpaqueWidget::onHover(e); | |||||
if (this == APP->event->draggedWidget) { | if (this == APP->event->draggedWidget) { | ||||
int pos = getTextPosition(e.pos); | int pos = getTextPosition(e.pos); | ||||
@@ -42,7 +42,7 @@ void TextField::onHover(const event::Hover &e) { | |||||
} | } | ||||
void TextField::onButton(const event::Button &e) { | void TextField::onButton(const event::Button &e) { | ||||
widget::OpaqueWidget::onButton(e); | |||||
OpaqueWidget::onButton(e); | |||||
if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) { | if (e.action == GLFW_PRESS && e.button == GLFW_MOUSE_BUTTON_LEFT) { | ||||
cursor = selection = getTextPosition(e.pos); | cursor = selection = getTextPosition(e.pos); | ||||