Fit the split on a double-click only once the handle's drag ends
The split's own drag is still going during the second press of a double-click, so the least movement before the release put the handle back under the pointer right after it was fitted. The fit now waits for that drag to end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+26
-7
@@ -227,10 +227,30 @@ Gtk::Widget& EffectorWindow::buildChainTab() {
|
|||||||
auto click = Gtk::GestureClick::create();
|
auto click = Gtk::GestureClick::create();
|
||||||
click->set_propagation_phase(Gtk::PropagationPhase::CAPTURE);
|
click->set_propagation_phase(Gtk::PropagationPhase::CAPTURE);
|
||||||
// The split's drag ends every press on the handle, which starts the
|
// The split's drag ends every press on the handle, which starts the
|
||||||
// click's count over, so the second press is counted here.
|
// click's count over, so the second press is counted here. And that
|
||||||
|
// drag is still going on during the second press -- the least jitter
|
||||||
|
// puts the handle back under the pointer -- so the fit waits for it
|
||||||
|
// to end.
|
||||||
|
std::vector<Glib::RefPtr<Gtk::GestureDrag>> drags;
|
||||||
|
const auto controllers = split->observe_controllers();
|
||||||
|
for (guint i = 0; i < controllers->get_n_items(); ++i) {
|
||||||
|
auto other = std::dynamic_pointer_cast<Gtk::Gesture>(controllers->get_object(i));
|
||||||
|
if (other) click->group(other);
|
||||||
|
if (auto drag = std::dynamic_pointer_cast<Gtk::GestureDrag>(other)) drags.push_back(drag);
|
||||||
|
}
|
||||||
auto lastPress = std::make_shared<guint32>(0);
|
auto lastPress = std::make_shared<guint32>(0);
|
||||||
|
auto refitPending = std::make_shared<bool>(false);
|
||||||
|
for (const auto& drag : drags) {
|
||||||
|
drag->signal_drag_end().connect([this, refitPending](double, double) {
|
||||||
|
if (!*refitPending) return;
|
||||||
|
*refitPending = false;
|
||||||
|
refitChainSplit();
|
||||||
|
});
|
||||||
|
}
|
||||||
auto* gesture = click.get(); // not the RefPtr: the gesture owns this slot
|
auto* gesture = click.get(); // not the RefPtr: the gesture owns this slot
|
||||||
click->signal_pressed().connect([this, split, handle, gesture, lastPress](int, double x, double y) {
|
const bool waitForDrag = !drags.empty();
|
||||||
|
click->signal_pressed().connect(
|
||||||
|
[this, split, handle, gesture, lastPress, refitPending, waitForDrag](int, double x, double y) {
|
||||||
// The handle is thin, and the drag takes presses a little past it.
|
// The handle is thin, and the drag takes presses a little past it.
|
||||||
const auto bounds = handle->compute_bounds(*split);
|
const auto bounds = handle->compute_bounds(*split);
|
||||||
constexpr double slack = 6.0;
|
constexpr double slack = 6.0;
|
||||||
@@ -244,16 +264,15 @@ Gtk::Widget& EffectorWindow::buildChainTab() {
|
|||||||
const int doubleClick = Gtk::Settings::get_default()->property_gtk_double_click_time();
|
const int doubleClick = Gtk::Settings::get_default()->property_gtk_double_click_time();
|
||||||
if (*lastPress != 0 && now - *lastPress <= static_cast<guint32>(doubleClick)) {
|
if (*lastPress != 0 && now - *lastPress <= static_cast<guint32>(doubleClick)) {
|
||||||
*lastPress = 0;
|
*lastPress = 0;
|
||||||
|
if (waitForDrag) {
|
||||||
|
*refitPending = true;
|
||||||
|
} else {
|
||||||
refitChainSplit();
|
refitChainSplit();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
*lastPress = now;
|
*lastPress = now;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const auto controllers = split->observe_controllers();
|
|
||||||
for (guint i = 0; i < controllers->get_n_items(); ++i) {
|
|
||||||
auto drag = std::dynamic_pointer_cast<Gtk::Gesture>(controllers->get_object(i));
|
|
||||||
if (drag) click->group(drag);
|
|
||||||
}
|
|
||||||
split->add_controller(click);
|
split->add_controller(click);
|
||||||
}
|
}
|
||||||
rebuildChainRows();
|
rebuildChainRows();
|
||||||
|
|||||||
Reference in New Issue
Block a user