Let the mouse wheel scroll past spin buttons that do not have the focus
A GtkSpinButton grabs the focus and spins its value on any wheel turn over it, so scrolling through the params stopped at the first spin under the pointer and changed it. A capture-phase scroll controller now scrolls the enclosing view instead, unless the spin already has the focus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -43,6 +43,40 @@ Gtk::Label* sectionLabel(const char* text) {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A GtkSpinButton takes every wheel turn over it: it grabs the focus and
|
||||||
|
// spins its value, so scrolling down a column of params stops dead at the
|
||||||
|
// first spin under the pointer and quietly changes it. This hands the wheel to
|
||||||
|
// the view instead unless the spin already has the focus -- the user clicked
|
||||||
|
// into it and means to adjust it. It runs in the capture phase, ahead of the
|
||||||
|
// spin's own controller, and so has to scroll the enclosing ScrolledWindow
|
||||||
|
// itself: stopping the event there stops it for the window as well.
|
||||||
|
void scrollPastUnlessFocused(Gtk::SpinButton& spin) {
|
||||||
|
auto scroll = Gtk::EventControllerScroll::create();
|
||||||
|
scroll->set_propagation_phase(Gtk::PropagationPhase::CAPTURE);
|
||||||
|
scroll->set_flags(Gtk::EventControllerScroll::Flags::VERTICAL);
|
||||||
|
auto* controller = scroll.get();
|
||||||
|
scroll->signal_scroll().connect(
|
||||||
|
[&spin, controller](double, double dy) {
|
||||||
|
if ((spin.get_state_flags() & Gtk::StateFlags::FOCUS_WITHIN) == Gtk::StateFlags::FOCUS_WITHIN) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto* scroller = spin.get_ancestor(GTK_TYPE_SCROLLED_WINDOW);
|
||||||
|
if (scroller == nullptr) return true;
|
||||||
|
auto adjustment = static_cast<Gtk::ScrolledWindow*>(scroller)->get_vadjustment();
|
||||||
|
// The step a ScrolledWindow itself takes for one notch of a wheel;
|
||||||
|
// a touchpad already reports its deltas in pixels.
|
||||||
|
double step = dy;
|
||||||
|
if (controller->get_unit() == Gdk::ScrollUnit::WHEEL) {
|
||||||
|
step *= std::pow(adjustment->get_page_size(), 2.0 / 3.0);
|
||||||
|
}
|
||||||
|
adjustment->set_value(std::clamp(adjustment->get_value() + step, adjustment->get_lower(),
|
||||||
|
adjustment->get_upper() - adjustment->get_page_size()));
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
false);
|
||||||
|
spin.add_controller(scroll);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
EffectorWindow::EffectorWindow(const Options& initial) {
|
EffectorWindow::EffectorWindow(const Options& initial) {
|
||||||
@@ -281,6 +315,7 @@ Gtk::Widget& EffectorWindow::buildCanvasSection() {
|
|||||||
dpiSpin_.set_value(kDefaultDpi);
|
dpiSpin_.set_value(kDefaultDpi);
|
||||||
for (auto* spin : {&widthSpin_, &heightSpin_, &dpiSpin_}) {
|
for (auto* spin : {&widthSpin_, &heightSpin_, &dpiSpin_}) {
|
||||||
spin->set_hexpand(true);
|
spin->set_hexpand(true);
|
||||||
|
scrollPastUnlessFocused(*spin);
|
||||||
}
|
}
|
||||||
for (auto* spin : {&widthSpin_, &heightSpin_}) {
|
for (auto* spin : {&widthSpin_, &heightSpin_}) {
|
||||||
spin->signal_value_changed().connect([this] {
|
spin->signal_value_changed().connect([this] {
|
||||||
@@ -477,6 +512,7 @@ void EffectorWindow::buildParamWidgets() {
|
|||||||
: paramDouble(values, spec.key, spec.defaultValue));
|
: paramDouble(values, spec.key, spec.defaultValue));
|
||||||
spin->signal_value_changed().connect(
|
spin->signal_value_changed().connect(
|
||||||
sigc::mem_fun(*this, &EffectorWindow::onParamChanged));
|
sigc::mem_fun(*this, &EffectorWindow::onParamChanged));
|
||||||
|
scrollPastUnlessFocused(*spin);
|
||||||
widget = std::move(spin);
|
widget = std::move(spin);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user