refactor: split every monolithic module into focused submodules
Each source file that had grown beyond a single concern is replaced by an identically-named directory containing focused submodules. `src/event_loop/mod.rs` (878 lines) becomes a directory with clipboard, context_menu, cursor_shape, drag, focus, handlers, invalidation, overlays_reconcile, repeat, run, surface, text_editing, and tooltip. Every widget, input handler, and theme component follows the same split. Public interfaces are unchanged — only the internal file layout moves. image bumped from 0.25.2 to 0.25.9.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
|
||||
|
||||
use crate::app::App;
|
||||
use crate::event_loop::{ AppData, SurfaceFocus };
|
||||
|
||||
impl<A: App> AppData<A>
|
||||
{
|
||||
/// Step the topmost scroll's `hovered_idx` one item up or down with
|
||||
/// the keyboard. Returns `true` when the move was applied (a scroll
|
||||
/// with at least one navigable item was on screen and the new item
|
||||
/// is different from the current hover) so the caller can fall
|
||||
/// through to the application's own `on_key` only on a no-op.
|
||||
///
|
||||
/// The "topmost scroll" is the last entry in `scroll_rects`, which
|
||||
/// matches Stack-overlay layout order: a popup pushed after the
|
||||
/// main content sits above it. Auto-scrolls the new item into view
|
||||
/// by adjusting `scroll_offsets[scroll_idx]`.
|
||||
pub( crate ) fn move_keyboard_hover( &mut self, focus: SurfaceFocus, reverse: bool ) -> bool
|
||||
{
|
||||
// Find the topmost scroll that has a navigable item list.
|
||||
let scroll_meta = {
|
||||
let ss = self.surface( focus );
|
||||
ss.scroll_rects.iter().rev()
|
||||
.find_map( |( rect, idx )|
|
||||
{
|
||||
ss.scroll_navigable_items.get( idx )
|
||||
.filter( |list| !list.is_empty() )
|
||||
.map( |list| ( *rect, *idx, list.clone() ) )
|
||||
} )
|
||||
};
|
||||
let Some( ( scroll_rect, scroll_idx, items ) ) = scroll_meta else { return false; };
|
||||
|
||||
let current = self.surface( focus ).hovered_idx;
|
||||
let pos = current.and_then( |h| items.iter().position( |( i, _, _ )| *i == h ) );
|
||||
let next_pos = match ( reverse, pos )
|
||||
{
|
||||
( false, None ) => 0,
|
||||
( false, Some( p ) ) => ( p + 1 ).min( items.len() - 1 ),
|
||||
( true, None ) => items.len() - 1,
|
||||
( true, Some( p ) ) => p.saturating_sub( 1 ),
|
||||
};
|
||||
let ( new_idx, content_y, content_h ) = items[ next_pos ];
|
||||
|
||||
// Auto-scroll to bring the new item fully into view. Item Y is
|
||||
// in pre-offset content coordinates, so the offset that places
|
||||
// the item flush with the top of the viewport is `content_y`,
|
||||
// and flush with the bottom is `content_y + content_h - viewport_h`.
|
||||
let viewport_h = scroll_rect.height;
|
||||
let current_offset = self.surface( focus )
|
||||
.scroll_offsets.get( &scroll_idx )
|
||||
.copied().unwrap_or( 0.0 );
|
||||
let new_offset = if content_y < current_offset
|
||||
{
|
||||
content_y
|
||||
}
|
||||
else if content_y + content_h > current_offset + viewport_h
|
||||
{
|
||||
( content_y + content_h - viewport_h ).max( 0.0 )
|
||||
}
|
||||
else
|
||||
{
|
||||
current_offset
|
||||
};
|
||||
|
||||
let ss = self.surface_mut( focus );
|
||||
ss.hovered_idx = Some( new_idx );
|
||||
ss.scroll_offsets.insert( scroll_idx, new_offset );
|
||||
ss.request_redraw();
|
||||
true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user