From 68bd62f57f59d00356f9bddfdefbd7ac08c532aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Forment?= Date: Wed, 18 Mar 2026 02:28:57 +0100 Subject: [PATCH] Fix: clean ratatui > egui interaction --- Cargo.toml | 3 +- plugins/cagire-plugins/src/editor.rs | 110 +------------------- src/bin/desktop/main.rs | 145 +++------------------------ src/block_renderer.rs | 2 +- src/lib.rs | 3 + src/terminal.rs | 110 ++++++++++++++++++++ 6 files changed, 133 insertions(+), 240 deletions(-) create mode 100644 src/terminal.rs diff --git a/Cargo.toml b/Cargo.toml index eb4922f..2d7f1bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,13 +36,12 @@ required-features = ["desktop"] [features] default = ["cli"] cli = ["dep:cpal", "dep:midir", "dep:confy", "dep:clap", "dep:thread-priority"] -block-renderer = ["dep:soft_ratatui", "dep:rustc-hash", "dep:egui"] +block-renderer = ["dep:soft_ratatui", "dep:rustc-hash", "dep:egui", "dep:egui_ratatui"] desktop = [ "cli", "block-renderer", "cagire-forth/desktop", "dep:eframe", - "dep:egui_ratatui", "dep:image", ] asio = ["doux/asio", "cpal/asio"] diff --git a/plugins/cagire-plugins/src/editor.rs b/plugins/cagire-plugins/src/editor.rs index 0c9e760..58c5396 100644 --- a/plugins/cagire-plugins/src/editor.rs +++ b/plugins/cagire-plugins/src/editor.rs @@ -6,128 +6,22 @@ use std::time::Instant; use arc_swap::ArcSwap; use crossbeam_channel::Sender; -use egui_ratatui::RataguiBackend; use nih_plug::prelude::*; use nih_plug_egui::egui; use nih_plug_egui::{create_egui_editor, EguiState}; -use ratatui::Terminal; -use soft_ratatui::embedded_graphics_unicodefonts::{ - mono_10x20_atlas, mono_6x13_atlas, mono_6x13_bold_atlas, mono_6x13_italic_atlas, - mono_7x13_atlas, mono_7x13_bold_atlas, mono_7x13_italic_atlas, mono_8x13_atlas, - mono_8x13_bold_atlas, mono_8x13_italic_atlas, mono_9x15_atlas, mono_9x15_bold_atlas, - mono_9x18_atlas, mono_9x18_bold_atlas, -}; -use soft_ratatui::{EmbeddedGraphics, SoftBackend}; -use cagire::block_renderer::BlockCharBackend; use cagire::app::App; use cagire::engine::{AudioCommand, LinkState, SequencerSnapshot}; use cagire::input::{handle_key, handle_mouse, InputContext}; +use cagire::input_egui::{convert_egui_events, convert_egui_mouse, EguiMouseState}; use cagire::model::{Dictionary, Rng, Variables}; +use cagire::terminal::{create_terminal, FontChoice, TerminalType}; use cagire::theme; use cagire::views; -use cagire::input_egui::{convert_egui_events, convert_egui_mouse, EguiMouseState}; use crate::params::CagireParams; use crate::PluginBridge; -type TerminalType = Terminal>; - -#[derive(Clone, Copy, PartialEq)] -enum FontChoice { - Size6x13, - Size7x13, - Size8x13, - Size9x15, - Size9x18, - Size10x20, -} - -impl FontChoice { - fn from_setting(s: &str) -> Self { - match s { - "6x13" => Self::Size6x13, - "7x13" => Self::Size7x13, - "9x15" => Self::Size9x15, - "9x18" => Self::Size9x18, - "10x20" => Self::Size10x20, - _ => Self::Size8x13, - } - } - - fn to_setting(self) -> &'static str { - match self { - Self::Size6x13 => "6x13", - Self::Size7x13 => "7x13", - Self::Size8x13 => "8x13", - Self::Size9x15 => "9x15", - Self::Size9x18 => "9x18", - Self::Size10x20 => "10x20", - } - } - - fn label(self) -> &'static str { - match self { - Self::Size6x13 => "6x13 (Compact)", - Self::Size7x13 => "7x13", - Self::Size8x13 => "8x13 (Default)", - Self::Size9x15 => "9x15", - Self::Size9x18 => "9x18", - Self::Size10x20 => "10x20 (Large)", - } - } - - const ALL: [Self; 6] = [ - Self::Size6x13, - Self::Size7x13, - Self::Size8x13, - Self::Size9x15, - Self::Size9x18, - Self::Size10x20, - ]; -} - -fn create_terminal(font: FontChoice) -> TerminalType { - let (regular, bold, italic) = match font { - FontChoice::Size6x13 => ( - mono_6x13_atlas(), - Some(mono_6x13_bold_atlas()), - Some(mono_6x13_italic_atlas()), - ), - FontChoice::Size7x13 => ( - mono_7x13_atlas(), - Some(mono_7x13_bold_atlas()), - Some(mono_7x13_italic_atlas()), - ), - FontChoice::Size8x13 => ( - mono_8x13_atlas(), - Some(mono_8x13_bold_atlas()), - Some(mono_8x13_italic_atlas()), - ), - FontChoice::Size9x15 => (mono_9x15_atlas(), Some(mono_9x15_bold_atlas()), None), - FontChoice::Size9x18 => (mono_9x18_atlas(), Some(mono_9x18_bold_atlas()), None), - FontChoice::Size10x20 => (mono_10x20_atlas(), None, None), - }; - - let eg = SoftBackend::::new(80, 24, regular, bold, italic); - let soft = SoftBackend { - buffer: eg.buffer, - cursor: eg.cursor, - cursor_pos: eg.cursor_pos, - char_width: eg.char_width, - char_height: eg.char_height, - blink_counter: eg.blink_counter, - blinking_fast: eg.blinking_fast, - blinking_slow: eg.blinking_slow, - rgb_pixmap: eg.rgb_pixmap, - always_redraw_list: eg.always_redraw_list, - raster_backend: BlockCharBackend { - inner: eg.raster_backend, - }, - }; - Terminal::new(RataguiBackend::new("cagire", soft)).expect("terminal") -} - struct EditorState { app: App, terminal: TerminalType, diff --git a/src/bin/desktop/main.rs b/src/bin/desktop/main.rs index 92712d1..e2509eb 100644 --- a/src/bin/desktop/main.rs +++ b/src/bin/desktop/main.rs @@ -4,24 +4,15 @@ use std::sync::atomic::{AtomicBool, AtomicI64, AtomicU32, AtomicU64, Ordering}; use std::sync::Arc; use std::time::Duration; -use cagire::block_renderer::BlockCharBackend; use clap::Parser; use doux::EngineMetrics; use eframe::NativeOptions; -use egui_ratatui::RataguiBackend; -use ratatui::Terminal; -use soft_ratatui::embedded_graphics_unicodefonts::{ - mono_10x20_atlas, mono_6x13_atlas, mono_6x13_bold_atlas, mono_6x13_italic_atlas, - mono_7x13_atlas, mono_7x13_bold_atlas, mono_7x13_italic_atlas, mono_8x13_atlas, - mono_8x13_bold_atlas, mono_8x13_italic_atlas, mono_9x15_atlas, mono_9x15_bold_atlas, - mono_9x18_atlas, mono_9x18_bold_atlas, -}; -use soft_ratatui::{EmbeddedGraphics, SoftBackend}; use cagire::engine::{ build_stream, AnalysisHandle, AudioStreamConfig, LinkState, ScopeBuffer, SequencerHandle, SpectrumBuffer, }; +use cagire::terminal::{create_terminal, FontChoice, TerminalType}; use cagire::init::{init, InitArgs}; use cagire::input::{handle_key, handle_mouse, InputContext, InputResult}; use cagire::input_egui::{convert_egui_events, convert_egui_mouse, EguiMouseState}; @@ -47,103 +38,6 @@ struct Args { buffer: Option, } -#[derive(Clone, Copy, PartialEq)] -enum FontChoice { - Size6x13, - Size7x13, - Size8x13, - Size9x15, - Size9x18, - Size10x20, -} - -impl FontChoice { - fn from_setting(s: &str) -> Self { - match s { - "6x13" => Self::Size6x13, - "7x13" => Self::Size7x13, - "9x15" => Self::Size9x15, - "9x18" => Self::Size9x18, - "10x20" => Self::Size10x20, - _ => Self::Size8x13, - } - } - - fn to_setting(self) -> &'static str { - match self { - Self::Size6x13 => "6x13", - Self::Size7x13 => "7x13", - Self::Size8x13 => "8x13", - Self::Size9x15 => "9x15", - Self::Size9x18 => "9x18", - Self::Size10x20 => "10x20", - } - } - - fn label(self) -> &'static str { - match self { - Self::Size6x13 => "6x13 (Compact)", - Self::Size7x13 => "7x13", - Self::Size8x13 => "8x13 (Default)", - Self::Size9x15 => "9x15", - Self::Size9x18 => "9x18", - Self::Size10x20 => "10x20 (Large)", - } - } - - const ALL: [Self; 6] = [ - Self::Size6x13, - Self::Size7x13, - Self::Size8x13, - Self::Size9x15, - Self::Size9x18, - Self::Size10x20, - ]; -} - -type TerminalType = Terminal>; - -fn create_terminal(font: FontChoice) -> TerminalType { - let (regular, bold, italic) = match font { - FontChoice::Size6x13 => ( - mono_6x13_atlas(), - Some(mono_6x13_bold_atlas()), - Some(mono_6x13_italic_atlas()), - ), - FontChoice::Size7x13 => ( - mono_7x13_atlas(), - Some(mono_7x13_bold_atlas()), - Some(mono_7x13_italic_atlas()), - ), - FontChoice::Size8x13 => ( - mono_8x13_atlas(), - Some(mono_8x13_bold_atlas()), - Some(mono_8x13_italic_atlas()), - ), - FontChoice::Size9x15 => (mono_9x15_atlas(), Some(mono_9x15_bold_atlas()), None), - FontChoice::Size9x18 => (mono_9x18_atlas(), Some(mono_9x18_bold_atlas()), None), - FontChoice::Size10x20 => (mono_10x20_atlas(), None, None), - }; - - let eg = SoftBackend::::new(80, 24, regular, bold, italic); - let soft = SoftBackend { - buffer: eg.buffer, - cursor: eg.cursor, - cursor_pos: eg.cursor_pos, - char_width: eg.char_width, - char_height: eg.char_height, - blink_counter: eg.blink_counter, - blinking_fast: eg.blinking_fast, - blinking_slow: eg.blinking_slow, - rgb_pixmap: eg.rgb_pixmap, - always_redraw_list: eg.always_redraw_list, - raster_backend: BlockCharBackend { - inner: eg.raster_backend, - }, - }; - Terminal::new(RataguiBackend::new("cagire", soft)).expect("terminal") -} - struct CagireDesktop { app: cagire::app::App, terminal: TerminalType, @@ -336,30 +230,23 @@ impl CagireDesktop { let term = self.terminal.get_frame().area(); let widget_rect = ctx.content_rect(); - for mouse in convert_egui_mouse(ctx, widget_rect, term, &mut self.egui_mouse) { - let mut input_ctx = InputContext { - app: &mut self.app, - link: &self.link, - snapshot: &seq_snapshot, - playing: &self.playing, - audio_tx: &sequencer.audio_tx, - seq_cmd_tx: &sequencer.cmd_tx, - nudge_us: &self.nudge_us, - }; + let mouse_events = convert_egui_mouse(ctx, widget_rect, term, &mut self.egui_mouse); + let key_events = convert_egui_events(ctx); + + let mut input_ctx = InputContext { + app: &mut self.app, + link: &self.link, + snapshot: &seq_snapshot, + playing: &self.playing, + audio_tx: &sequencer.audio_tx, + seq_cmd_tx: &sequencer.cmd_tx, + nudge_us: &self.nudge_us, + }; + + for mouse in mouse_events { handle_mouse(&mut input_ctx, mouse, term); } - - for key in convert_egui_events(ctx) { - let mut input_ctx = InputContext { - app: &mut self.app, - link: &self.link, - snapshot: &seq_snapshot, - playing: &self.playing, - audio_tx: &sequencer.audio_tx, - seq_cmd_tx: &sequencer.cmd_tx, - nudge_us: &self.nudge_us, - }; - + for key in key_events { if let InputResult::Quit = handle_key(&mut input_ctx, key) { return true; } diff --git a/src/block_renderer.rs b/src/block_renderer.rs index cc19331..4e79d64 100644 --- a/src/block_renderer.rs +++ b/src/block_renderer.rs @@ -242,7 +242,7 @@ fn color_to_rgb(color: &Color, is_fg: bool) -> [u8; 3] { Color::Yellow => [255, 215, 0], Color::Blue => [0, 0, 139], Color::Magenta => [255, 0, 255], - Color::Cyan => [0, 0, 255], + Color::Cyan => [0, 255, 255], Color::Gray => [128, 128, 128], Color::DarkGray => [64, 64, 64], Color::LightRed => [255, 0, 0], diff --git a/src/lib.rs b/src/lib.rs index 06a3ed0..4e6bf41 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,3 +21,6 @@ pub mod block_renderer; #[cfg(feature = "block-renderer")] pub mod input_egui; + +#[cfg(feature = "block-renderer")] +pub mod terminal; diff --git a/src/terminal.rs b/src/terminal.rs new file mode 100644 index 0000000..668a5d2 --- /dev/null +++ b/src/terminal.rs @@ -0,0 +1,110 @@ +use egui_ratatui::RataguiBackend; +use ratatui::Terminal; +use soft_ratatui::embedded_graphics_unicodefonts::{ + mono_10x20_atlas, mono_6x13_atlas, mono_6x13_bold_atlas, mono_6x13_italic_atlas, + mono_7x13_atlas, mono_7x13_bold_atlas, mono_7x13_italic_atlas, mono_8x13_atlas, + mono_8x13_bold_atlas, mono_8x13_italic_atlas, mono_9x15_atlas, mono_9x15_bold_atlas, + mono_9x18_atlas, mono_9x18_bold_atlas, +}; +use soft_ratatui::{EmbeddedGraphics, SoftBackend}; + +use crate::block_renderer::BlockCharBackend; + +pub type TerminalType = Terminal>; + +#[derive(Clone, Copy, PartialEq)] +pub enum FontChoice { + Size6x13, + Size7x13, + Size8x13, + Size9x15, + Size9x18, + Size10x20, +} + +impl FontChoice { + pub fn from_setting(s: &str) -> Self { + match s { + "6x13" => Self::Size6x13, + "7x13" => Self::Size7x13, + "9x15" => Self::Size9x15, + "9x18" => Self::Size9x18, + "10x20" => Self::Size10x20, + _ => Self::Size8x13, + } + } + + pub fn to_setting(self) -> &'static str { + match self { + Self::Size6x13 => "6x13", + Self::Size7x13 => "7x13", + Self::Size8x13 => "8x13", + Self::Size9x15 => "9x15", + Self::Size9x18 => "9x18", + Self::Size10x20 => "10x20", + } + } + + pub fn label(self) -> &'static str { + match self { + Self::Size6x13 => "6x13 (Compact)", + Self::Size7x13 => "7x13", + Self::Size8x13 => "8x13 (Default)", + Self::Size9x15 => "9x15", + Self::Size9x18 => "9x18", + Self::Size10x20 => "10x20 (Large)", + } + } + + pub const ALL: [Self; 6] = [ + Self::Size6x13, + Self::Size7x13, + Self::Size8x13, + Self::Size9x15, + Self::Size9x18, + Self::Size10x20, + ]; +} + +pub fn create_terminal(font: FontChoice) -> TerminalType { + let (regular, bold, italic) = match font { + FontChoice::Size6x13 => ( + mono_6x13_atlas(), + Some(mono_6x13_bold_atlas()), + Some(mono_6x13_italic_atlas()), + ), + FontChoice::Size7x13 => ( + mono_7x13_atlas(), + Some(mono_7x13_bold_atlas()), + Some(mono_7x13_italic_atlas()), + ), + FontChoice::Size8x13 => ( + mono_8x13_atlas(), + Some(mono_8x13_bold_atlas()), + Some(mono_8x13_italic_atlas()), + ), + FontChoice::Size9x15 => (mono_9x15_atlas(), Some(mono_9x15_bold_atlas()), None), + FontChoice::Size9x18 => (mono_9x18_atlas(), Some(mono_9x18_bold_atlas()), None), + FontChoice::Size10x20 => (mono_10x20_atlas(), None, None), + }; + + // SoftBackend fields are copied individually to wrap raster_backend in BlockCharBackend. + // If soft_ratatui changes its field layout, this will fail to compile — that's intentional. + let eg = SoftBackend::::new(80, 24, regular, bold, italic); + let soft = SoftBackend { + buffer: eg.buffer, + cursor: eg.cursor, + cursor_pos: eg.cursor_pos, + char_width: eg.char_width, + char_height: eg.char_height, + blink_counter: eg.blink_counter, + blinking_fast: eg.blinking_fast, + blinking_slow: eg.blinking_slow, + rgb_pixmap: eg.rgb_pixmap, + always_redraw_list: eg.always_redraw_list, + raster_backend: BlockCharBackend { + inner: eg.raster_backend, + }, + }; + Terminal::new(RataguiBackend::new("cagire", soft)).expect("terminal") +}