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

148
src/widget/external/mod.rs vendored Normal file
View File

@@ -0,0 +1,148 @@
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
//! Widget that hosts content rendered by an external GL producer.
//!
//! Reserves layout space and, at draw time, samples a caller-provided GL
//! texture into the LTK canvas via [`Canvas::draw_external_texture`]. The
//! producer (a web engine, a video decoder, …) keeps ownership of the
//! texture and updates it on its own cadence; LTK only composites.
//!
//! # Source closure contract
//!
//! [`ExternalSource::Texture`] carries an
//! `Arc<dyn Fn(&glow::Context, Rect) -> Option<glow::Texture>>` that LTK
//! invokes once per frame, with its GLES context current. The producer:
//!
//! 1. Reads `Rect` (in physical pixels of the host surface) — useful for
//! sizing the inner viewport (e.g. resizing a `WPEToplevel` to match)
//! and for translating input coordinates by `rect.origin`.
//! 2. May allocate / update GL textures against the supplied
//! `glow::Context`.
//! 3. May bind extension-imported EGLImages onto a persistent texture.
//! 4. Returns the `glow::Texture` to sample, or `None` to paint
//! transparent (e.g. while the first frame is still being produced).
//!
//! Returning `None` for one frame and `Some` for the next is fine; LTK
//! re-invokes on every redraw.
//!
//! # Use cases
//!
//! * `ltk-webkit` hosting a `WPEView`-rendered page.
//! * Video / media playback widgets that decode into a GL texture.
//! * Any embedding that already has a GLES producer and wants its output
//! in-line with the rest of the LTK widget tree.
//!
//! # Example
//!
//! ```rust,no_run
//! # use std::sync::{ Arc, Mutex };
//! # use ltk::{ External, ExternalSource, Element };
//! # #[ derive( Clone ) ] enum Msg {}
//! # fn _ex() -> Element<Msg> {
//! let cached_texture: Arc<Mutex<Option<glow::Texture>>> = Arc::new( Mutex::new( None ) );
//! let cached = Arc::clone( &cached_texture );
//! External::new(
//! 800.0, 600.0,
//! ExternalSource::Texture( Arc::new( move | _gl, _rect | -> Option<glow::Texture>
//! {
//! *cached.lock().ok()?
//! } ) ),
//! ).into()
//! # }
//! ```
use std::sync::Arc;
use crate::render::Canvas;
use crate::types::Rect;
/// A widget that defers its pixels to an external GL texture producer.
///
/// The widget itself is non-interactive and produces no messages. Wrap it
/// in a [`crate::widget::pressable::Pressable`] (or similar) when input
/// capture is needed.
pub struct External
{
/// Reserved width in logical pixels.
pub width: f32,
/// Reserved height in logical pixels.
pub height: f32,
/// Source of the GL texture sampled at draw time.
pub source: ExternalSource,
/// Opacity multiplier in `[0.0, 1.0]`.
pub opacity: f32,
}
/// Backends an [`External`] widget can pull pixels from.
///
/// The only variant today is [`ExternalSource::Texture`], a closure
/// returning the current GL texture name. Future variants (DMA-BUF
/// imports, software pixmaps for the CPU backend, …) can be added
/// without changing call sites.
#[ derive( Clone ) ]
pub enum ExternalSource
{
/// Closure invoked once per frame with LTK's [`glow::Context`] current
/// and the widget's laid-out rect (in physical pixels of the host
/// surface). The producer can allocate textures, bind extension-
/// imported EGLImages, etc., and returns the texture name to sample.
/// Returning `None` paints transparent — useful while the producer
/// is still warming up its first frame. The rect is exposed so
/// embedders can size their inner viewport to match LTK's actual
/// allocation (e.g. resize a WPEToplevel on layout change) and
/// translate input coordinates by `rect.origin`.
Texture( Arc<dyn Fn( &glow::Context, Rect ) -> Option<glow::Texture> + Send + Sync> ),
}
impl External
{
/// Build a new external-content widget reserving `width × height`
/// logical pixels.
pub fn new( width: f32, height: f32, source: ExternalSource ) -> Self
{
Self { width, height, source, opacity: 1.0 }
}
/// Override the opacity multiplier. Default: `1.0`.
pub fn opacity( mut self, opacity: f32 ) -> Self
{
self.opacity = opacity.clamp( 0.0, 1.0 );
self
}
pub fn preferred_size( &self, _max_width: f32 ) -> ( f32, f32 )
{
( self.width, self.height )
}
pub fn draw( &self, canvas: &mut Canvas, rect: Rect )
{
// SAFETY-ish: this is the only call site of the source closure;
// LTK's draw pass guarantees the GLES context is current and
// the canvas is bound to its FBO. The rect we pass is the
// widget's laid-out rect in physical pixels — the same
// coordinate space pointer events arrive in, so the producer
// can use `rect.origin` to translate input.
// External content only renders against the GLES backend — the
// software backend has no GL texture to sample. Skip silently.
let gl = match canvas
{
Canvas::Software( _ ) => return,
Canvas::Gles( c ) => c.gl.clone(),
};
match &self.source
{
ExternalSource::Texture( get ) =>
{
if let Some( tex ) = get( &gl, rect )
{
canvas.draw_external_texture( tex, rect, self.opacity );
}
}
}
}
}
#[ cfg( test ) ]
mod tests;