Compare commits
2 Commits
a2a5884a2a
...
05081a7662
Author | SHA1 | Date |
---|---|---|
|
05081a7662 | |
|
68a91c4af1 |
|
@ -43,6 +43,13 @@ impl SimId {
|
||||||
Self::Player2 => 1,
|
Self::Player2 => 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub const fn from_index(index: usize) -> Option<Self> {
|
||||||
|
match index {
|
||||||
|
0 => Some(Self::Player1),
|
||||||
|
1 => Some(Self::Player2),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Display for SimId {
|
impl Display for SimId {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
@ -230,8 +237,15 @@ impl Emulator {
|
||||||
|
|
||||||
let index = sim_id.to_index();
|
let index = sim_id.to_index();
|
||||||
while self.sims.len() <= index {
|
while self.sims.len() <= index {
|
||||||
|
let new_index = self.sims.len();
|
||||||
self.sims.push(Sim::new());
|
self.sims.push(Sim::new());
|
||||||
self.sim_state[index].store(SimState::NoGame, Ordering::Release);
|
if self
|
||||||
|
.stdouts
|
||||||
|
.contains_key(&SimId::from_index(new_index).unwrap())
|
||||||
|
{
|
||||||
|
self.sims[new_index].watch_stdout(true);
|
||||||
|
}
|
||||||
|
self.sim_state[new_index].store(SimState::NoGame, Ordering::Release);
|
||||||
}
|
}
|
||||||
let sim = &mut self.sims[index];
|
let sim = &mut self.sims[index];
|
||||||
sim.reset();
|
sim.reset();
|
||||||
|
@ -476,7 +490,7 @@ impl Emulator {
|
||||||
// stdout
|
// stdout
|
||||||
self.stdouts.retain(|sim_id, stdout| {
|
self.stdouts.retain(|sim_id, stdout| {
|
||||||
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
|
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
|
||||||
return false;
|
return true;
|
||||||
};
|
};
|
||||||
if let Some(text) = sim.take_stdout() {
|
if let Some(text) = sim.take_stdout() {
|
||||||
if stdout.send(text).is_err() {
|
if stdout.send(text).is_err() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::mpsc;
|
use std::{collections::VecDeque, sync::mpsc};
|
||||||
|
|
||||||
use egui::{
|
use egui::{
|
||||||
Align, CentralPanel, Context, FontFamily, Label, RichText, ScrollArea, ViewportBuilder,
|
Align, CentralPanel, Context, FontFamily, Label, RichText, ScrollArea, ViewportBuilder,
|
||||||
|
@ -9,20 +9,24 @@ use crate::emulator::{EmulatorClient, EmulatorCommand, SimId};
|
||||||
|
|
||||||
use super::AppWindow;
|
use super::AppWindow;
|
||||||
|
|
||||||
|
const SCROLLBACK: usize = 1000;
|
||||||
|
|
||||||
pub struct TerminalWindow {
|
pub struct TerminalWindow {
|
||||||
sim_id: SimId,
|
sim_id: SimId,
|
||||||
receiver: mpsc::Receiver<String>,
|
receiver: mpsc::Receiver<String>,
|
||||||
text: String,
|
lines: VecDeque<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TerminalWindow {
|
impl TerminalWindow {
|
||||||
pub fn new(sim_id: SimId, client: &EmulatorClient) -> Self {
|
pub fn new(sim_id: SimId, client: &EmulatorClient) -> Self {
|
||||||
let (sender, receiver) = mpsc::channel();
|
let (sender, receiver) = mpsc::channel();
|
||||||
client.send_command(EmulatorCommand::WatchStdout(sim_id, sender));
|
client.send_command(EmulatorCommand::WatchStdout(sim_id, sender));
|
||||||
|
let mut lines = VecDeque::new();
|
||||||
|
lines.push_back(String::new());
|
||||||
Self {
|
Self {
|
||||||
sim_id,
|
sim_id,
|
||||||
receiver,
|
receiver,
|
||||||
text: String::new(),
|
lines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,17 +48,31 @@ impl AppWindow for TerminalWindow {
|
||||||
|
|
||||||
fn show(&mut self, ctx: &Context) {
|
fn show(&mut self, ctx: &Context) {
|
||||||
if let Ok(text) = self.receiver.try_recv() {
|
if let Ok(text) = self.receiver.try_recv() {
|
||||||
self.text.push_str(&text);
|
let mut rest = text.as_str();
|
||||||
|
while let Some(index) = rest.find('\n') {
|
||||||
|
let (line, lines) = rest.split_at(index);
|
||||||
|
let current = self.lines.back_mut().unwrap();
|
||||||
|
current.push_str(line);
|
||||||
|
self.lines.push_back(String::new());
|
||||||
|
if self.lines.len() > SCROLLBACK {
|
||||||
|
self.lines.pop_front();
|
||||||
|
}
|
||||||
|
rest = &lines[1..];
|
||||||
|
}
|
||||||
|
self.lines.back_mut().unwrap().push_str(rest);
|
||||||
}
|
}
|
||||||
CentralPanel::default().show(ctx, |ui| {
|
CentralPanel::default().show(ctx, |ui| {
|
||||||
ScrollArea::vertical()
|
ScrollArea::vertical()
|
||||||
.stick_to_bottom(true)
|
.stick_to_bottom(true)
|
||||||
.auto_shrink([false, false])
|
.auto_shrink([false, false])
|
||||||
|
.animated(false)
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
let label = Label::new(RichText::new(&self.text).family(FontFamily::Monospace))
|
for line in &self.lines {
|
||||||
.halign(Align::LEFT)
|
let label = Label::new(RichText::new(line).family(FontFamily::Monospace))
|
||||||
.wrap();
|
.halign(Align::LEFT)
|
||||||
ui.add(label);
|
.wrap();
|
||||||
|
ui.add(label);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue