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:
183
src/input/keyboard/text_keys.rs
Normal file
183
src/input/keyboard/text_keys.rs
Normal file
@@ -0,0 +1,183 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-only
|
||||
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>
|
||||
|
||||
use smithay_client_toolkit::seat::keyboard::{ KeyEvent, Keysym };
|
||||
|
||||
use crate::app::App;
|
||||
use crate::event_loop::{ AppData, SurfaceFocus };
|
||||
use crate::tree::find_handlers;
|
||||
|
||||
impl<A: App> AppData<A>
|
||||
{
|
||||
pub( super ) fn handle_key_backspace( &mut self, focus: SurfaceFocus, event: &KeyEvent )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
if focused.is_some() { self.handle_backspace( focus ); }
|
||||
else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_delete( &mut self, focus: SurfaceFocus, event: &KeyEvent )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
// Supr / Forward-Delete: same shape as Backspace but
|
||||
// removes the char *after* the cursor. When no widget
|
||||
// is focused, the keysym bubbles to the app.
|
||||
if focused.is_some() { self.handle_delete_forward( focus ); }
|
||||
else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_return( &mut self, focus: SurfaceFocus, event: &KeyEvent )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
// Enter targets, in order: (a) the focused widget's submit
|
||||
// message (TextEdit), (b) its press message (Button etc),
|
||||
// (c) the press message of the keyboard-hovered list item
|
||||
// in the topmost scroll. The hovered fallback lets users
|
||||
// confirm a combo / list choice with the keyboard after
|
||||
// arrow-navigating to it without ever taking widget focus.
|
||||
//
|
||||
// Multiline text-input override: when the focused widget
|
||||
// is a `text_edit().multiline( true )`, Enter inserts a
|
||||
// literal `\n` into the buffer instead of submitting, so
|
||||
// the user can compose paragraphs.
|
||||
let is_multi = focused.and_then( |idx|
|
||||
find_handlers( &self.surface( focus ).widget_rects, idx )
|
||||
.map( |h| h.is_multiline_text_input() ) ).unwrap_or( false );
|
||||
if is_multi
|
||||
{
|
||||
self.handle_text_insert( focus, "\n" );
|
||||
} else {
|
||||
let target = focused.or( self.surface( focus ).hovered_idx );
|
||||
if let Some( idx ) = target
|
||||
{
|
||||
let msg = find_handlers( &self.surface( focus ).widget_rects, idx )
|
||||
.and_then( |h| h.submit_msg().or_else( || h.press_msg() ) );
|
||||
if let Some( m ) = msg
|
||||
{
|
||||
self.pending_msgs.push( m );
|
||||
}
|
||||
} else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_arrow_vertical( &mut self, focus: SurfaceFocus, event: &KeyEvent )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
let is_text = focused.and_then( |idx|
|
||||
find_handlers( &self.surface( focus ).widget_rects, idx )
|
||||
.map( |h| h.is_text_input() ) ).unwrap_or( false );
|
||||
let reverse = event.keysym == Keysym::Up;
|
||||
let extend = self.shift_pressed;
|
||||
let intercepted = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed );
|
||||
if let Some( msg ) = intercepted
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
else
|
||||
{
|
||||
let consumed = if is_text
|
||||
{
|
||||
if reverse { self.handle_cursor_up( focus, extend ) }
|
||||
else { self.handle_cursor_down( focus, extend ) }
|
||||
} else { false };
|
||||
if !consumed && !self.move_keyboard_hover( focus, reverse )
|
||||
{
|
||||
// already None, no extra fire
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_arrow_horizontal( &mut self, focus: SurfaceFocus, event: &KeyEvent )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
let is_text = focused.and_then( |idx|
|
||||
find_handlers( &self.surface( focus ).widget_rects, idx )
|
||||
.map( |h| h.is_text_input() ) ).unwrap_or( false );
|
||||
let extend = self.shift_pressed;
|
||||
let intercepted = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed );
|
||||
if let Some( msg ) = intercepted
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
else if is_text
|
||||
{
|
||||
if event.keysym == Keysym::Left
|
||||
{
|
||||
self.handle_cursor_left( focus, extend );
|
||||
} else {
|
||||
self.handle_cursor_right( focus, extend );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_home( &mut self, focus: SurfaceFocus )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
let is_text = focused.and_then( |idx|
|
||||
find_handlers( &self.surface( focus ).widget_rects, idx )
|
||||
.map( |h| h.is_text_input() ) ).unwrap_or( false );
|
||||
if is_text { self.handle_cursor_home( focus, self.shift_pressed ); }
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_end( &mut self, focus: SurfaceFocus )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
let is_text = focused.and_then( |idx|
|
||||
find_handlers( &self.surface( focus ).widget_rects, idx )
|
||||
.map( |h| h.is_text_input() ) ).unwrap_or( false );
|
||||
if is_text { self.handle_cursor_end( focus, self.shift_pressed ); }
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_space( &mut self, focus: SurfaceFocus, event: &KeyEvent )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
if let Some( idx ) = focused
|
||||
{
|
||||
let press = find_handlers( &self.surface( focus ).widget_rects, idx )
|
||||
.and_then( |h| h.press_msg() );
|
||||
if let Some( msg ) = press
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
} else {
|
||||
// Focused widget is a TextEdit (or has no on_press) — insert space as text
|
||||
self.handle_text_insert( focus, " " );
|
||||
}
|
||||
} else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
}
|
||||
|
||||
pub( super ) fn handle_key_default( &mut self, focus: SurfaceFocus, event: &KeyEvent )
|
||||
{
|
||||
let focused = self.surface( focus ).focused_idx;
|
||||
if self.ctrl_pressed
|
||||
{
|
||||
if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, true, self.shift_pressed )
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
} else if focused.is_some()
|
||||
{
|
||||
if let Some( txt ) = event.utf8.clone()
|
||||
{
|
||||
if !txt.is_empty() && txt.chars().all( |c| !c.is_control() )
|
||||
{
|
||||
self.handle_text_insert( focus, &txt );
|
||||
}
|
||||
}
|
||||
} else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, false, self.shift_pressed )
|
||||
{
|
||||
self.pending_msgs.push( msg );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user