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:
2026-05-15 23:46:56 +02:00
parent 3d237039c6
commit 4aa3480b64
155 changed files with 13832 additions and 13035 deletions

109
src/widget/viewport/mod.rs Normal file
View File

@@ -0,0 +1,109 @@
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
use crate::render::Canvas;
use crate::widget::Element;
/// A non-scrollable clipped viewport for revealing only part of a child tree.
///
/// Unlike `Scroll`, this widget does not own
/// any gesture state. It simply renders its child into an off-screen canvas
/// and blits the result into the allocated rect, clipping anything outside.
pub struct Viewport<Msg: Clone>
{
/// The child element to render inside the viewport.
pub child: Box<Element<Msg>>,
/// Optional fixed width in logical pixels. When omitted the
/// viewport reports `max_width` as its preferred width — i.e. it
/// stretches to fill whatever horizontal slice the parent layout
/// gives it. Set explicitly when the viewport has to coexist with
/// `flex` siblings (the flex would otherwise lose every pixel to
/// the viewport's `max_width` claim) or whenever the inner content
/// has its own intrinsic width and the viewport is just a vertical
/// clip.
pub width: Option<f32>,
/// Optional fixed height in logical pixels. When omitted the viewport
/// reports the child's natural height.
pub height: Option<f32>,
/// Logical pixels at the bottom edge that fade to transparent during the
/// blit. Zero leaves the bottom hard-edged. Useful for slide-in panels so
/// the leading edge of the animation does not knife-cut against the layer
/// below it.
pub fade_bottom: f32,
}
impl<Msg: Clone> Viewport<Msg>
{
pub fn new( child: impl Into<Element<Msg>> ) -> Self
{
Self { child: Box::new( child.into() ), width: None, height: None, fade_bottom: 0.0 }
}
/// Set a fixed viewport width in logical pixels. Mirrors
/// [`Self::height`]: with an explicit value the viewport
/// reports `w` as its preferred width and the child is laid
/// out against `w` rather than the parent-supplied `max_width`.
pub fn width( mut self, w: f32 ) -> Self
{
self.width = Some( w.max( 0.0 ) );
self
}
/// Set a fixed viewport height in logical pixels.
pub fn height( mut self, h: f32 ) -> Self
{
self.height = Some( h.max( 0.0 ) );
self
}
/// Feather the bottom `px` rows of the viewport so its lower edge dissolves
/// to transparent. Drawn by the GLES blit shader as a linear alpha ramp
/// over the bottom band; the software backend currently renders a hard
/// edge regardless.
pub fn fade_bottom( mut self, px: f32 ) -> Self
{
self.fade_bottom = px.max( 0.0 );
self
}
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> ( f32, f32 )
{
let inner_w = self.width.unwrap_or( max_width );
let child_h = self.child.preferred_size( inner_w, canvas ).1;
( self.width.unwrap_or( max_width ), self.height.unwrap_or( child_h ) )
}
/// No-op — rendering is handled by `layout_and_draw` in `draw.rs`.
pub fn draw( &self ) {}
pub( crate ) fn map_msg<U>( self, f: &super::MapFn<Msg, U> ) -> Viewport<U>
where
U: Clone + 'static,
Msg: 'static,
{
Viewport
{
child: Box::new( self.child.map_arc( f ) ),
width: self.width,
height: self.height,
fade_bottom: self.fade_bottom,
}
}
}
impl<Msg: Clone + 'static> From<Viewport<Msg>> for Element<Msg>
{
fn from( v: Viewport<Msg> ) -> Self
{
Element::Viewport( v )
}
}
/// Create a clipped viewport wrapping `child`.
pub fn viewport<Msg: Clone>( child: impl Into<Element<Msg>> ) -> Viewport<Msg>
{
Viewport::new( child )
}
#[ cfg( test ) ]
mod tests;

View File

@@ -0,0 +1,75 @@
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
use super::*;
use crate::layout::spacer::spacer;
use crate::render::Canvas;
fn make_canvas() -> Canvas { Canvas::new( 800, 600 ) }
#[ test ]
fn new_defaults_are_unset_dimensions_and_no_fade()
{
let v = Viewport::<()>::new( spacer() );
assert!( v.width.is_none() );
assert!( v.height.is_none() );
assert_eq!( v.fade_bottom, 0.0 );
}
#[ test ]
fn width_builder_clamps_negative_to_zero()
{
let v = Viewport::<()>::new( spacer() ).width( -50.0 );
assert_eq!( v.width, Some( 0.0 ) );
}
#[ test ]
fn height_builder_clamps_negative_to_zero()
{
let v = Viewport::<()>::new( spacer() ).height( -10.0 );
assert_eq!( v.height, Some( 0.0 ) );
}
#[ test ]
fn fade_bottom_clamps_negative_to_zero()
{
let v = Viewport::<()>::new( spacer() ).fade_bottom( -1.0 );
assert_eq!( v.fade_bottom, 0.0 );
}
#[ test ]
fn fade_bottom_accepts_positive_pixel_count()
{
let v = Viewport::<()>::new( spacer() ).fade_bottom( 16.0 );
assert_eq!( v.fade_bottom, 16.0 );
}
#[ test ]
fn explicit_dimensions_override_child_intrinsic_size()
{
let v = Viewport::<()>::new( spacer().width( 99.0 ).height( 99.0 ) )
.width( 200.0 )
.height( 80.0 );
let canvas = make_canvas();
let ( w, h ) = v.preferred_size( 600.0, &canvas );
assert_eq!( w, 200.0 );
assert_eq!( h, 80.0 );
}
#[ test ]
fn unset_width_falls_through_to_max_width()
{
let v = Viewport::<()>::new( spacer().height( 40.0 ) );
let canvas = make_canvas();
let ( w, _ ) = v.preferred_size( 400.0, &canvas );
assert_eq!( w, 400.0 );
}
#[ test ]
fn unset_height_falls_through_to_child_intrinsic_height()
{
let v = Viewport::<()>::new( spacer().height( 75.0 ) );
let canvas = make_canvas();
let ( _, h ) = v.preferred_size( 400.0, &canvas );
assert_eq!( h, 75.0 );
}