ccab39f140
Re-sincroniza las fuentes desde el monorepo (estaba en vello 0.5/wgpu 24 y con la estructura vieja de eventloop) y suma el 3D: - bump del workspace a vello 0.7 / wgpu 27 / parley 0.6, + accesskit 0.24 / accesskit_winit 0.33 / vello_hybrid 0.0.9. - nuevos crates: llimphi-3d (voxels ray-march + mallas en un depth compartido, montable dentro de un View 2D vía set_viewport+scissor) y llimphi-voxel (world-gen, personajes, director de escenas) + shared/foreign-vox (puente .vox). - README: sección "Not just 2D — a 3D voxel engine" + GIF (docs/llimphi_voxel.gif). - excluido modules/allichay (arrastra deps fuera del alcance del front-door). - cargo check --workspace: verde. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
82 lines
4.1 KiB
Rust
82 lines
4.1 KiB
Rust
// a11y_rt.rs — Integración con AccessKit en tiempo de ejecución.
|
|
// Empuja el árbol de accesibilidad al SO y atiende las acciones del lector
|
|
// de pantalla (focus, click). Separado para no contaminar el flujo de input
|
|
// con detalles de la API de accesskit_winit.
|
|
|
|
use super::super::*;
|
|
use super::push_a11y_tree;
|
|
|
|
impl<A: App> Runtime<A> {
|
|
/// Recibe un `accesskit_winit::Event` (ruteado vía `EventLoopProxy` como
|
|
/// `UserEvent::A11y(...)`) y reacciona:
|
|
/// - `InitialTreeRequested`: el lector pidió el árbol inicial → empujamos
|
|
/// uno desde `last_render` si lo hay, o pedimos un redraw que lo creará.
|
|
/// - `ActionRequested(req)`: el lector quiere ejecutar una acción sobre un
|
|
/// `NodeId`. v1 soporta `Action::Focus` (mueve `state.focused` + dispara
|
|
/// `App::on_focus`) y `Action::Click` (ejecuta el `on_click` del nodo).
|
|
/// - `AccessibilityDeactivated`: nada que hacer; el siguiente paint dejará
|
|
/// de construir trees (el `update_if_active` se autoinhibe).
|
|
pub(super) fn handle_a11y_event(&mut self, ev: accesskit_winit::Event) {
|
|
use accesskit_winit::WindowEvent as AkWinEvent;
|
|
let Some(state) = self.state.as_mut() else { return };
|
|
match ev.window_event {
|
|
AkWinEvent::InitialTreeRequested => {
|
|
// Si ya pintamos un frame, ese mounted sirve para el árbol
|
|
// inicial. Si no, forzamos un redraw — el path normal llamará
|
|
// a `push_a11y_tree::<A>` al final.
|
|
if state.last_render.is_some() {
|
|
push_a11y_tree::<A>(state);
|
|
} else {
|
|
state.window.request_redraw();
|
|
}
|
|
}
|
|
AkWinEvent::ActionRequested(req) => {
|
|
let Some(idx) = crate::a11y::mounted_idx_for(req.target_node) else {
|
|
return;
|
|
};
|
|
let Some(cache) = state.last_render.as_ref() else {
|
|
return;
|
|
};
|
|
let Some(node) = cache.mounted.nodes.get(idx) else {
|
|
return;
|
|
};
|
|
match req.action {
|
|
accesskit::Action::Focus => {
|
|
// Si el nodo es focusable, movemos el foco a su id
|
|
// opaco; si no, lo limpiamos. La app recibe la
|
|
// transición vía `App::on_focus`.
|
|
let new_focus = node.focusable;
|
|
state.focused = new_focus;
|
|
let model = state.model.as_ref().expect("model");
|
|
if let Some(msg) = A::on_focus(model, new_focus) {
|
|
let m = state.model.take().expect("model");
|
|
state.model = Some(A::update(m, msg, &self.handle));
|
|
}
|
|
state.last_render = None;
|
|
state.window.request_redraw();
|
|
}
|
|
accesskit::Action::Click => {
|
|
// Sólo soportamos `on_click` (Msg directo) en v1. Los
|
|
// handlers `*_at` necesitan una posición sintética
|
|
// coherente que no tenemos — los ignoramos.
|
|
if let Some(msg) = node.on_click.clone() {
|
|
let m = state.model.take().expect("model");
|
|
state.model = Some(A::update(m, msg, &self.handle));
|
|
state.last_render = None;
|
|
state.window.request_redraw();
|
|
}
|
|
}
|
|
_ => {
|
|
// Otras acciones (Expand/Collapse/Increment/Decrement/
|
|
// SetValue/ScrollIntoView/etc.) se sumarán cuando un
|
|
// widget concreto lo pida — el modelo `SemanticsSpec`
|
|
// ya tiene los flags relevantes; solo falta cablear el
|
|
// efecto inverso (acción → mutación de Model).
|
|
}
|
|
}
|
|
}
|
|
AkWinEvent::AccessibilityDeactivated => {}
|
|
}
|
|
}
|
|
}
|