feat: an open box zoom draws the frame the release will apply

The controller has always tracked its selection; nothing drew it, so a Ctrl or
Shift drag framed a range with no feedback until the release.

The preview is the area the release will change, not what the pointer swept:
Ctrl frames the x range only, so a band across the plot is what it will zoom,
where the sliver a straight horizontal drag sweeps is only the gesture. The
plot carries the rect a host hands it -- it learns nothing about pointers --
and the renderer draws a low-alpha fill under a light border over everything
else inside the axes.
This commit is contained in:
Martino Ferrari committed 2026-10-11 11:07:55 +02:00
1 parent 1fc97d818f
commit be1f31a04f
14 files changed
+276 -1

No files matched your search

+18
View File
@@ -344,6 +344,21 @@ u32 PlotArea::pointer_row() const noexcept {
return row_in(row_rects_, pointer_.y);
}
void PlotArea::sync_selection_frames() noexcept {
const auto frame_for = [](input::Controller& c) -> Rect {
return c.drag_mode() == input::DragMode::BoxZoom ? c.selection_preview() : Rect{};
};
if (figure_ != nullptr) {
for (u32 i = 0; i < row_controllers_.size(); ++i) {
// An empty rect on the rows that are not choosing: `Rect` has no equality to compare
// with, and a store of the same value is what keeps this path free of anything else.
figure_->plot(i).set_selection_rect(frame_for(*row_controllers_[i]));
}
return;
}
plot_->set_selection_rect(frame_for(controller_));
}
void PlotArea::sync_figure_crosshair() noexcept {
if (row_rects_.empty() || row_controllers_.empty()) return;
const u32 row_count = static_cast<u32>(row_rects_.size());
@@ -534,6 +549,9 @@ void PlotArea::render() noexcept {
// `::resize` ratio, not `gtk_widget_get_scale_factor()` -- the latter is the
// ceiling under fractional scaling and would over-scale the chrome by up to 60%.
renderer_->style().ui_scale = mapping_.factor;
// After the scale and before the draw: the preview reads the row's layout, and a layout measured
// with the previous frame's scale is not the one being drawn.
sync_selection_frames();
renderer_->begin_frame(static_cast<u32>(viewport.w), static_cast<u32>(viewport.h), viewport);
if (figure_ != nullptr) {
renderer_->draw(*figure_);