feat(renaser): Fase 8d — manipulación de ventanas
El escritorio se podía recorrer con el foco, pero no reordenar. La 8d lo hace manipulable: el orden de teselado se separa de la identidad. - Escritorio gana `orden: Vec<usize>` — una permutacion que dice que ventana ocupa cada celda. Mover una ventana cambia su celda, no su indice_app: conserva su canal de teclado y su ranura de estado. - aplicar_teselado reparte los marcos segun el orden. - Alt+Enter promueve la ventana enfocada a la celda maestra; Alt+H/Alt+L la reordenan. mover_foco recorre ahora el orden, no los indices crudos. Verificado en QEMU (sendkey): con memoriosa enfocada, Alt+Enter la promueve a maestra y hola baja a la pila; Alt+L la devuelve a la pila. El foco —el borde indigo— viaja siempre con la ventana, no con la celda. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -731,3 +731,32 @@ asume la persistencia visual con una caché de fotogramas.
|
|||||||
mueve con él.
|
mueve con él.
|
||||||
- **Enrutamiento** — con `memoriosa` enfocada, cuatro pulsaciones llegan sólo
|
- **Enrutamiento** — con `memoriosa` enfocada, cuatro pulsaciones llegan sólo
|
||||||
a ella —cuatro celdas violetas—; las demás apps, intactas.
|
a ella —cuatro celdas violetas—; las demás apps, intactas.
|
||||||
|
|
||||||
|
## Fase 8d — Manipulación de ventanas — 2026-05-22
|
||||||
|
|
||||||
|
El escritorio de la 8c se podía recorrer con la vista —el foco— pero no
|
||||||
|
reordenar. La 8d lo hace MANIPULABLE: el orden de teselado se separa de la
|
||||||
|
identidad de las ventanas, y el teclado promueve y reordena.
|
||||||
|
|
||||||
|
### Añadido
|
||||||
|
- `Escritorio` gana `orden: Vec<usize>` — una permutación que dice qué ventana
|
||||||
|
ocupa cada celda del teselado. Separar el orden de la identidad
|
||||||
|
(`indice_app`) permite mover una ventana sin tocar su canal de teclado ni su
|
||||||
|
ranura de estado: cambia de pared, no de identidad.
|
||||||
|
- `aplicar_teselado` — recalcula los marcos y los reparte según el orden.
|
||||||
|
- Mandos `Promover`, `MoverAdelante`, `MoverAtras`:
|
||||||
|
- `Alt+Enter` — promueve la ventana enfocada a la celda maestra; las demás
|
||||||
|
se desplazan una posición.
|
||||||
|
- `Alt+L` / `Alt+H` — mueven la ventana enfocada adelante / atrás en el
|
||||||
|
orden, intercambiándola con su vecina.
|
||||||
|
|
||||||
|
### Cambiado
|
||||||
|
- `mover_foco` recorre ahora el ORDEN de teselado —no los índices crudos—: el
|
||||||
|
foco salta entre ventanas visualmente contiguas.
|
||||||
|
- `ciclar_layout` y `fundar` delegan en `aplicar_teselado`.
|
||||||
|
|
||||||
|
### Verificado
|
||||||
|
- QEMU (`sendkey`): con `memoriosa` enfocada, `Alt+Enter` la promueve a la
|
||||||
|
ventana maestra y `hola` baja a la pila; `Alt+L` la devuelve a la pila y
|
||||||
|
`hola` recupera la maestra. El foco —el borde índigo— viaja siempre con la
|
||||||
|
ventana, no con la celda.
|
||||||
|
|||||||
+3
-3
@@ -75,9 +75,9 @@ QEMU 11, OVMF en `/usr/share/edk2/x64/OVMF.4m.fd` (sin módulo KVM → TCG).
|
|||||||
|
|
||||||
Fases 1 a 5, 6.0, 6.1, 6.2, la Fase 7 COMPLETA —el userspace nace del grafo de
|
Fases 1 a 5, 6.0, 6.1, 6.2, la Fase 7 COMPLETA —el userspace nace del grafo de
|
||||||
objetos— y la Fase 8 COMPLETA —el compositor teselante e interactivo: teselado
|
objetos— y la Fase 8 COMPLETA —el compositor teselante e interactivo: teselado
|
||||||
con `mirada-layout` (8a), `Alt+Espacio` cicla el layout (8b), foco con
|
con `mirada-layout` (8a), ciclado de layout (8b), foco y enrutamiento selectivo
|
||||||
`Alt+J`/`Alt+K` y enrutamiento selectivo del teclado (8c)—. Todo verificado en
|
del teclado (8c), promoción y reordenación de ventanas (8d)—. Todo verificado
|
||||||
QEMU. Ver `ROADMAP.md`.
|
en QEMU. Ver `ROADMAP.md`.
|
||||||
|
|
||||||
## Flujo de trabajo
|
## Flujo de trabajo
|
||||||
|
|
||||||
|
|||||||
@@ -372,6 +372,24 @@ los libros de la casa. Sólo deja una nota breve en un casillero a prueba de
|
|||||||
prisas, y sigue su camino. Es el arquitecto quien, más tarde y con calma, lee
|
prisas, y sigue su camino. Es el arquitecto quien, más tarde y con calma, lee
|
||||||
la nota y mueve los tabiques. Nadie se pisa; nada se traba.
|
la nota y mueve los tabiques. Nadie se pisa; nada se traba.
|
||||||
|
|
||||||
|
## El cuarto se muda, el inquilino se queda
|
||||||
|
|
||||||
|
Hasta ayer, la casa sabía mirar a un inquilino —darle el foco—, pero no
|
||||||
|
moverlo. Su sitio era el que el arquitecto le había dado, y allí se quedaba.
|
||||||
|
|
||||||
|
Hoy la casa aprendió a reacomodar. Con una tecla, quien la habita puede decir
|
||||||
|
«este inquilino merece el cuarto grande», y el arquitecto lo asciende a la
|
||||||
|
pieza maestra; los demás se corren un sitio. Con otras dos, puede adelantar o
|
||||||
|
atrasar un cuarto en la fila, como quien reordena los libros de un estante.
|
||||||
|
|
||||||
|
Y aquí hubo una distinción fina, casi filosófica. Una cosa es el INQUILINO —su
|
||||||
|
nombre, su cajón de recuerdos, su buzón de cartas— y otra es el CUARTO que
|
||||||
|
ocupa. La casa aprendió a no confundirlos. Cuando un inquilino cambia de
|
||||||
|
habitación no cambia de identidad: sigue recibiendo su correo, sigue siendo el
|
||||||
|
dueño de su cajón; sólo se mudó de pared. Por eso, cuando la mirada de la casa
|
||||||
|
estaba puesta en él, lo sigue al cuarto nuevo — el foco viaja con la persona,
|
||||||
|
nunca se queda mirando una pared vacía.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
*El diario continúa. La próxima página la escribirá la próxima jornada.*
|
*El diario continúa. La próxima página la escribirá la próxima jornada.*
|
||||||
|
|||||||
+8
-1
@@ -48,10 +48,17 @@ bare-metal.
|
|||||||
`mirada-layout` —ventanas, marcos, foco— sin adoptar su tipo: el kernel
|
`mirada-layout` —ventanas, marcos, foco— sin adoptar su tipo: el kernel
|
||||||
necesita además la caché de respaldo, que el `Workspace` no contempla.
|
necesita además la caché de respaldo, que el `Workspace` no contempla.
|
||||||
|
|
||||||
|
### 8d — Manipulación de ventanas — ✅ HECHA
|
||||||
|
|
||||||
|
- `Escritorio` separa el ORDEN de teselado de la IDENTIDAD de las ventanas
|
||||||
|
(`orden: Vec<usize>`): una ventana puede cambiar de celda sin perder su canal
|
||||||
|
de teclado ni su ranura de estado.
|
||||||
|
- `Alt+Enter` promueve la ventana enfocada a la celda maestra; `Alt+H` /
|
||||||
|
`Alt+L` la mueven atrás / adelante en el orden. El foco viaja con la ventana.
|
||||||
|
|
||||||
### Pendiente
|
### Pendiente
|
||||||
|
|
||||||
- Orden-Z y solapamiento (ventanas flotantes); alta y baja de apps en vivo.
|
- Orden-Z y solapamiento (ventanas flotantes); alta y baja de apps en vivo.
|
||||||
- Promover la app enfocada al área maestra (`Alt+Enter`).
|
|
||||||
|
|
||||||
## Estructura de archivos
|
## Estructura de archivos
|
||||||
|
|
||||||
|
|||||||
@@ -139,6 +139,10 @@ en `FASE8.md`.
|
|||||||
- **8c — foco y enrutamiento selectivo (completada).** Una ventana enfocada,
|
- **8c — foco y enrutamiento selectivo (completada).** Una ventana enfocada,
|
||||||
con borde índigo; `Alt+J` / `Alt+K` mueven el foco entre las ventanas vivas.
|
con borde índigo; `Alt+J` / `Alt+K` mueven el foco entre las ventanas vivas.
|
||||||
El teclado deja de difundir: entrega cada tecla sólo a la app enfocada.
|
El teclado deja de difundir: entrega cada tecla sólo a la app enfocada.
|
||||||
|
- **8d — manipulación de ventanas (completada).** El orden de teselado se
|
||||||
|
separa de la identidad de las ventanas. `Alt+Enter` promueve la ventana
|
||||||
|
enfocada a la celda maestra; `Alt+H` / `Alt+L` la reordenan. El foco viaja
|
||||||
|
con la ventana.
|
||||||
|
|
||||||
Líneas abiertas posteriores: orden-Z y ventanas flotantes; más capacidades del
|
Líneas abiertas posteriores: orden-Z y ventanas flotantes; más capacidades del
|
||||||
host (temporización, audio).
|
host (temporización, audio).
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
// FASE 8c :: el teclado deja de DIFUNDIR a ciegas. Ahora discrimina:
|
// FASE 8c :: el teclado deja de DIFUNDIR a ciegas. Ahora discrimina:
|
||||||
//
|
//
|
||||||
// * La tecla Alt es el MODIFICADOR del sistema. Con Alt pulsada, los make
|
// * La tecla Alt es el MODIFICADOR del sistema. Con Alt pulsada, los make
|
||||||
// codes son MANDOS del compositor (ciclar el teselado, mover el foco): se
|
// codes son MANDOS del compositor (ciclar el teselado, mover el foco,
|
||||||
// consumen aqui, jamas llegan a una app.
|
// promover y reordenar ventanas): se consumen aqui, jamas llegan a una app.
|
||||||
// * Una tecla ordinaria se entrega SOLO a la app ENFOCADA — la que el
|
// * Una tecla ordinaria se entrega SOLO a la app ENFOCADA — la que el
|
||||||
// compositor senala. El censo de canales se indexa por el `indice_app`,
|
// compositor senala. El censo de canales se indexa por el `indice_app`,
|
||||||
// de modo que el foco —un atomico— elija el canal exacto.
|
// de modo que el foco —un atomico— elija el canal exacto.
|
||||||
@@ -45,6 +45,12 @@ const ESPACIO: u8 = 0x39;
|
|||||||
const TECLA_J: u8 = 0x24;
|
const TECLA_J: u8 = 0x24;
|
||||||
/// Tecla K — `Alt + K` mueve el foco a la ventana anterior.
|
/// Tecla K — `Alt + K` mueve el foco a la ventana anterior.
|
||||||
const TECLA_K: u8 = 0x25;
|
const TECLA_K: u8 = 0x25;
|
||||||
|
/// Tecla H — `Alt + H` mueve la ventana enfocada atras en el orden.
|
||||||
|
const TECLA_H: u8 = 0x23;
|
||||||
|
/// Tecla L — `Alt + L` mueve la ventana enfocada adelante en el orden.
|
||||||
|
const TECLA_L: u8 = 0x26;
|
||||||
|
/// Tecla Enter — `Alt + Enter` promueve la ventana enfocada a maestra.
|
||||||
|
const ENTER: u8 = 0x1C;
|
||||||
|
|
||||||
/// Un canal de teclado: la cola lock-free de scancodes de UNA aplicacion.
|
/// Un canal de teclado: la cola lock-free de scancodes de UNA aplicacion.
|
||||||
pub type CanalTeclado = Arc<ArrayQueue<u8>>;
|
pub type CanalTeclado = Arc<ArrayQueue<u8>>;
|
||||||
@@ -127,6 +133,9 @@ pub fn recibir_scancode(scancode: u8) {
|
|||||||
ESPACIO => compositor::solicitar(Mando::CiclarLayout),
|
ESPACIO => compositor::solicitar(Mando::CiclarLayout),
|
||||||
TECLA_J => compositor::solicitar(Mando::FocoSiguiente),
|
TECLA_J => compositor::solicitar(Mando::FocoSiguiente),
|
||||||
TECLA_K => compositor::solicitar(Mando::FocoAnterior),
|
TECLA_K => compositor::solicitar(Mando::FocoAnterior),
|
||||||
|
ENTER => compositor::solicitar(Mando::Promover),
|
||||||
|
TECLA_L => compositor::solicitar(Mando::MoverAdelante),
|
||||||
|
TECLA_H => compositor::solicitar(Mando::MoverAtras),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ pub enum Mando {
|
|||||||
FocoSiguiente,
|
FocoSiguiente,
|
||||||
/// Mover el foco a la ventana viva anterior.
|
/// Mover el foco a la ventana viva anterior.
|
||||||
FocoAnterior,
|
FocoAnterior,
|
||||||
|
/// Promover la ventana enfocada a la posicion maestra del teselado.
|
||||||
|
Promover,
|
||||||
|
/// Mover la ventana enfocada una posicion adelante en el orden de teselado.
|
||||||
|
MoverAdelante,
|
||||||
|
/// Mover la ventana enfocada una posicion atras en el orden de teselado.
|
||||||
|
MoverAtras,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Una ventana del escritorio: una app, su geometria y su ultimo fotograma.
|
/// Una ventana del escritorio: una app, su geometria y su ultimo fotograma.
|
||||||
@@ -84,7 +90,13 @@ struct Escritorio {
|
|||||||
modo: LayoutMode,
|
modo: LayoutMode,
|
||||||
ancho: usize,
|
ancho: usize,
|
||||||
alto: usize,
|
alto: usize,
|
||||||
|
/// Las ventanas, indexadas por `indice_app` — su IDENTIDAD, inmutable.
|
||||||
ventanas: Vec<Ventana>,
|
ventanas: Vec<Ventana>,
|
||||||
|
/// El ORDEN de teselado: `orden[slot]` es el `indice_app` de la ventana que
|
||||||
|
/// ocupa esa celda del teselado. Una permutacion de `0..ventanas.len()`.
|
||||||
|
/// Separar el orden de la identidad permite promover y reordenar ventanas
|
||||||
|
/// sin tocar su `indice_app` —su canal de teclado, su ranura de estado—.
|
||||||
|
orden: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// El escritorio global. Se funda una sola vez, en el arranque.
|
/// El escritorio global. Se funda una sola vez, en el arranque.
|
||||||
@@ -110,13 +122,18 @@ static MANDOS: Once<ArrayQueue<Mando>> = Once::new();
|
|||||||
pub fn fundar(ancho: usize, alto: usize, naturales: &[(usize, usize)]) {
|
pub fn fundar(ancho: usize, alto: usize, naturales: &[(usize, usize)]) {
|
||||||
MANDOS.call_once(|| ArrayQueue::new(CAPACIDAD_MANDOS));
|
MANDOS.call_once(|| ArrayQueue::new(CAPACIDAD_MANDOS));
|
||||||
|
|
||||||
let marcos = teselar(naturales.len(), ancho, alto, MODO_INICIAL);
|
|
||||||
let mut ventanas = Vec::with_capacity(naturales.len());
|
let mut ventanas = Vec::with_capacity(naturales.len());
|
||||||
for (i, &(nat_ancho, nat_alto)) in naturales.iter().enumerate() {
|
for &(nat_ancho, nat_alto) in naturales {
|
||||||
ventanas.push(Ventana {
|
ventanas.push(Ventana {
|
||||||
natural_ancho: nat_ancho,
|
natural_ancho: nat_ancho,
|
||||||
natural_alto: nat_alto,
|
natural_alto: nat_alto,
|
||||||
marco: marcos[i],
|
// Marco provisional; `aplicar_teselado` lo fija enseguida.
|
||||||
|
marco: RegionPantalla {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
ancho: 0,
|
||||||
|
alto: 0,
|
||||||
|
},
|
||||||
// La cache: reservada UNA vez, acotada al lienzo natural.
|
// La cache: reservada UNA vez, acotada al lienzo natural.
|
||||||
cache: vec![0u8; nat_ancho.saturating_mul(nat_alto).saturating_mul(4)],
|
cache: vec![0u8; nat_ancho.saturating_mul(nat_alto).saturating_mul(4)],
|
||||||
pintada: false,
|
pintada: false,
|
||||||
@@ -124,14 +141,34 @@ pub fn fundar(ancho: usize, alto: usize, naturales: &[(usize, usize)]) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ESCRITORIO.call_once(|| {
|
// El orden de teselado arranca como la identidad: la ventana `i` ocupa la
|
||||||
Mutex::new(Escritorio {
|
// celda `i`. Los mandos del teclado lo permutaran.
|
||||||
modo: MODO_INICIAL,
|
let orden = (0..ventanas.len()).collect();
|
||||||
ancho,
|
let mut escritorio = Escritorio {
|
||||||
alto,
|
modo: MODO_INICIAL,
|
||||||
ventanas,
|
ancho,
|
||||||
})
|
alto,
|
||||||
});
|
ventanas,
|
||||||
|
orden,
|
||||||
|
};
|
||||||
|
aplicar_teselado(&mut escritorio);
|
||||||
|
|
||||||
|
ESCRITORIO.call_once(|| Mutex::new(escritorio));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Recalcula el teselado y asigna a cada ventana su marco. La celda `slot` del
|
||||||
|
/// teselado va a la ventana `orden[slot]`: manda el orden, no la identidad.
|
||||||
|
fn aplicar_teselado(escritorio: &mut Escritorio) {
|
||||||
|
let marcos = teselar(
|
||||||
|
escritorio.orden.len(),
|
||||||
|
escritorio.ancho,
|
||||||
|
escritorio.alto,
|
||||||
|
escritorio.modo,
|
||||||
|
);
|
||||||
|
for (slot, marco) in marcos.into_iter().enumerate() {
|
||||||
|
let ventana = escritorio.orden[slot];
|
||||||
|
escritorio.ventanas[ventana].marco = marco;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pinta el escenario inicial del compositor: el area de apps y sus marcos
|
/// Pinta el escenario inicial del compositor: el area de apps y sus marcos
|
||||||
@@ -223,6 +260,9 @@ pub fn atender_mandos() {
|
|||||||
Mando::CiclarLayout => ciclar_layout(),
|
Mando::CiclarLayout => ciclar_layout(),
|
||||||
Mando::FocoSiguiente => mover_foco(true),
|
Mando::FocoSiguiente => mover_foco(true),
|
||||||
Mando::FocoAnterior => mover_foco(false),
|
Mando::FocoAnterior => mover_foco(false),
|
||||||
|
Mando::Promover => promover(),
|
||||||
|
Mando::MoverAdelante => mover_ventana(true),
|
||||||
|
Mando::MoverAtras => mover_ventana(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,52 +275,96 @@ fn ciclar_layout() {
|
|||||||
};
|
};
|
||||||
let mut escritorio = escritorio.lock();
|
let mut escritorio = escritorio.lock();
|
||||||
escritorio.modo = escritorio.modo.next();
|
escritorio.modo = escritorio.modo.next();
|
||||||
|
aplicar_teselado(&mut escritorio);
|
||||||
let marcos = teselar(
|
|
||||||
escritorio.ventanas.len(),
|
|
||||||
escritorio.ancho,
|
|
||||||
escritorio.alto,
|
|
||||||
escritorio.modo,
|
|
||||||
);
|
|
||||||
for (ventana, marco) in escritorio.ventanas.iter_mut().zip(marcos) {
|
|
||||||
ventana.marco = marco;
|
|
||||||
}
|
|
||||||
redibujar_todo(&escritorio);
|
redibujar_todo(&escritorio);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mueve el foco a la siguiente ventana VIVA —saltando las desalojadas—; tras
|
/// Mueve el foco a la siguiente ventana VIVA, recorriendo el ORDEN de teselado
|
||||||
/// el salto, redibuja la ventana que pierde el foco y la que lo gana, para que
|
/// —de modo que el foco salte entre ventanas visualmente contiguas— y saltando
|
||||||
/// el borde de cada una cambie de color.
|
/// las desalojadas. Redibuja la ventana que pierde el foco y la que lo gana.
|
||||||
fn mover_foco(adelante: bool) {
|
fn mover_foco(adelante: bool) {
|
||||||
let Some(escritorio) = ESCRITORIO.get() else {
|
let Some(escritorio) = ESCRITORIO.get() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let escritorio = escritorio.lock();
|
let escritorio = escritorio.lock();
|
||||||
let n = escritorio.ventanas.len();
|
let n = escritorio.orden.len();
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let anterior = FOCO.load(Ordering::Relaxed).min(n - 1);
|
let anterior = FOCO.load(Ordering::Relaxed);
|
||||||
|
// La posicion del foco en el orden de teselado — el punto de partida.
|
||||||
|
let pos = escritorio
|
||||||
|
.orden
|
||||||
|
.iter()
|
||||||
|
.position(|&v| v == anterior)
|
||||||
|
.unwrap_or(0);
|
||||||
|
|
||||||
// Avanzar saltando las ventanas desalojadas. Si no hay ninguna viva, tras
|
// Avanzar saltando las ventanas desalojadas. Si no hay ninguna viva, tras
|
||||||
// `n` pasos se vuelve al punto de partida y el foco no cambia.
|
// `n` pasos se vuelve al punto de partida y el foco no cambia.
|
||||||
|
let mut nueva_pos = pos;
|
||||||
let mut nuevo = anterior;
|
let mut nuevo = anterior;
|
||||||
for _ in 0..n {
|
for _ in 0..n {
|
||||||
nuevo = if adelante {
|
nueva_pos = if adelante {
|
||||||
(nuevo + 1) % n
|
(nueva_pos + 1) % n
|
||||||
} else {
|
} else {
|
||||||
(nuevo + n - 1) % n
|
(nueva_pos + n - 1) % n
|
||||||
};
|
};
|
||||||
if escritorio.ventanas[nuevo].baliza.is_none() {
|
let candidata = escritorio.orden[nueva_pos];
|
||||||
|
if escritorio.ventanas[candidata].baliza.is_none() {
|
||||||
|
nuevo = candidata;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FOCO.store(nuevo, Ordering::Relaxed);
|
FOCO.store(nuevo, Ordering::Relaxed);
|
||||||
|
|
||||||
redibujar_ventana(&escritorio.ventanas[anterior], false);
|
if let Some(ventana) = escritorio.ventanas.get(anterior) {
|
||||||
|
redibujar_ventana(ventana, false);
|
||||||
|
}
|
||||||
redibujar_ventana(&escritorio.ventanas[nuevo], true);
|
redibujar_ventana(&escritorio.ventanas[nuevo], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Promueve la ventana enfocada a la posicion maestra —la celda 0— del
|
||||||
|
/// teselado: la saca de su lugar en el orden y la inserta al frente. Las demas
|
||||||
|
/// se desplazan una posicion. El escritorio entero se recompone.
|
||||||
|
fn promover() {
|
||||||
|
let Some(escritorio) = ESCRITORIO.get() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut escritorio = escritorio.lock();
|
||||||
|
let foco = FOCO.load(Ordering::Relaxed);
|
||||||
|
if let Some(pos) = escritorio.orden.iter().position(|&v| v == foco) {
|
||||||
|
let ventana = escritorio.orden.remove(pos);
|
||||||
|
escritorio.orden.insert(0, ventana);
|
||||||
|
aplicar_teselado(&mut escritorio);
|
||||||
|
redibujar_todo(&escritorio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mueve la ventana enfocada una posicion en el orden de teselado,
|
||||||
|
/// intercambiandola con su vecina. El foco viaja con la ventana — el indice no
|
||||||
|
/// cambia, solo su lugar en el orden.
|
||||||
|
fn mover_ventana(adelante: bool) {
|
||||||
|
let Some(escritorio) = ESCRITORIO.get() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut escritorio = escritorio.lock();
|
||||||
|
let n = escritorio.orden.len();
|
||||||
|
if n < 2 {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let foco = FOCO.load(Ordering::Relaxed);
|
||||||
|
if let Some(pos) = escritorio.orden.iter().position(|&v| v == foco) {
|
||||||
|
let destino = if adelante {
|
||||||
|
(pos + 1) % n
|
||||||
|
} else {
|
||||||
|
(pos + n - 1) % n
|
||||||
|
};
|
||||||
|
escritorio.orden.swap(pos, destino);
|
||||||
|
aplicar_teselado(&mut escritorio);
|
||||||
|
redibujar_todo(&escritorio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Recompone el escritorio entero: repinta el escenario —area y paneles— con
|
/// Recompone el escritorio entero: repinta el escenario —area y paneles— con
|
||||||
/// los marcos nuevos y, sobre el, cada ventana desde su cache de respaldo.
|
/// los marcos nuevos y, sobre el, cada ventana desde su cache de respaldo.
|
||||||
fn redibujar_todo(escritorio: &Escritorio) {
|
fn redibujar_todo(escritorio: &Escritorio) {
|
||||||
|
|||||||
Reference in New Issue
Block a user