Feat: add icon and reorganize desktop.rs
Some checks failed
Deploy Website / deploy (push) Failing after 7s
Some checks failed
Deploy Website / deploy (push) Failing after 7s
This commit is contained in:
@@ -26,6 +26,7 @@ desktop = [
|
||||
"eframe",
|
||||
"egui_ratatui",
|
||||
"soft_ratatui",
|
||||
"image",
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
@@ -56,6 +57,7 @@ egui = { version = "0.33", optional = true }
|
||||
eframe = { version = "0.33", optional = true }
|
||||
egui_ratatui = { version = "2.1", optional = true }
|
||||
soft_ratatui = { version = "0.1.3", features = ["unicodefonts"], optional = true }
|
||||
image = { version = "0.25", default-features = false, features = ["png"], optional = true }
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<p align="center">
|
||||
<img src="cagire_pixel.png" alt="Cagire" width="256">
|
||||
</p>
|
||||
|
||||
# Cagire
|
||||
|
||||
A Forth Music Sequencer.
|
||||
|
||||
BIN
cagire_pixel.png
Normal file
BIN
cagire_pixel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -145,7 +145,6 @@ struct CagireDesktop {
|
||||
_stream: Option<cpal::Stream>,
|
||||
_analysis_handle: Option<AnalysisHandle>,
|
||||
current_font: FontChoice,
|
||||
pending_font: Option<FontChoice>,
|
||||
}
|
||||
|
||||
impl CagireDesktop {
|
||||
@@ -270,7 +269,6 @@ impl CagireDesktop {
|
||||
_stream: stream,
|
||||
_analysis_handle: analysis_handle,
|
||||
current_font,
|
||||
pending_font: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +300,7 @@ impl CagireDesktop {
|
||||
}
|
||||
self.app.audio.config.sample_count = restart_samples.len();
|
||||
|
||||
self.audio_sample_pos.store(0, Ordering::Relaxed);
|
||||
self.audio_sample_pos.store(0, Ordering::Release);
|
||||
|
||||
match build_stream(
|
||||
&new_config,
|
||||
@@ -372,14 +370,6 @@ impl CagireDesktop {
|
||||
|
||||
impl eframe::App for CagireDesktop {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
if let Some(font) = self.pending_font.take() {
|
||||
self.terminal = create_terminal(font);
|
||||
self.current_font = font;
|
||||
let mut settings = Settings::load();
|
||||
settings.display.font = font.to_setting().to_string();
|
||||
settings.save();
|
||||
}
|
||||
|
||||
self.handle_audio_restart();
|
||||
self.update_metrics();
|
||||
|
||||
@@ -412,7 +402,7 @@ impl eframe::App for CagireDesktop {
|
||||
}
|
||||
|
||||
let current_font = self.current_font;
|
||||
let mut pending_font = None;
|
||||
let mut new_font = None;
|
||||
|
||||
egui::CentralPanel::default()
|
||||
.frame(egui::Frame::NONE.fill(egui::Color32::BLACK))
|
||||
@@ -429,7 +419,6 @@ impl eframe::App for CagireDesktop {
|
||||
|
||||
ui.add(self.terminal.backend_mut());
|
||||
|
||||
// Create a click-sensing overlay for context menu
|
||||
let response = ui.interact(
|
||||
ui.max_rect(),
|
||||
egui::Id::new("terminal_context"),
|
||||
@@ -440,7 +429,7 @@ impl eframe::App for CagireDesktop {
|
||||
for choice in FontChoice::ALL {
|
||||
let selected = current_font == choice;
|
||||
if ui.selectable_label(selected, choice.label()).clicked() {
|
||||
pending_font = Some(choice);
|
||||
new_font = Some(choice);
|
||||
ui.close();
|
||||
}
|
||||
}
|
||||
@@ -448,8 +437,12 @@ impl eframe::App for CagireDesktop {
|
||||
});
|
||||
});
|
||||
|
||||
if pending_font.is_some() {
|
||||
self.pending_font = pending_font;
|
||||
if let Some(font) = new_font {
|
||||
self.terminal = create_terminal(font);
|
||||
self.current_font = font;
|
||||
let mut settings = Settings::load();
|
||||
settings.display.font = font.to_setting().to_string();
|
||||
settings.save();
|
||||
}
|
||||
|
||||
ctx.request_repaint_after(Duration::from_millis(
|
||||
@@ -465,50 +458,19 @@ impl eframe::App for CagireDesktop {
|
||||
}
|
||||
|
||||
fn load_icon() -> egui::IconData {
|
||||
let size = 64u32;
|
||||
let mut rgba = vec![0u8; (size * size * 4) as usize];
|
||||
const ICON_BYTES: &[u8] = include_bytes!("../../cagire_pixel.png");
|
||||
|
||||
for y in 0..size {
|
||||
for x in 0..size {
|
||||
let idx = ((y * size + x) * 4) as usize;
|
||||
let cx = x as f32 - size as f32 / 2.0;
|
||||
let cy = y as f32 - size as f32 / 2.0;
|
||||
let dist = (cx * cx + cy * cy).sqrt();
|
||||
let radius = size as f32 / 2.0 - 2.0;
|
||||
let img = image::load_from_memory(ICON_BYTES)
|
||||
.expect("Failed to load embedded icon")
|
||||
.resize(64, 64, image::imageops::FilterType::Lanczos3)
|
||||
.into_rgba8();
|
||||
|
||||
if dist < radius {
|
||||
let angle = cy.atan2(cx);
|
||||
let normalized = (angle + std::f32::consts::PI) / (2.0 * std::f32::consts::PI);
|
||||
|
||||
if normalized > 0.1 && normalized < 0.9 {
|
||||
let inner_radius = radius * 0.5;
|
||||
if dist > inner_radius {
|
||||
rgba[idx] = 80;
|
||||
rgba[idx + 1] = 160;
|
||||
rgba[idx + 2] = 200;
|
||||
rgba[idx + 3] = 255;
|
||||
} else {
|
||||
rgba[idx] = 30;
|
||||
rgba[idx + 1] = 60;
|
||||
rgba[idx + 2] = 80;
|
||||
rgba[idx + 3] = 255;
|
||||
}
|
||||
} else {
|
||||
rgba[idx] = 30;
|
||||
rgba[idx + 1] = 30;
|
||||
rgba[idx + 2] = 40;
|
||||
rgba[idx + 3] = 255;
|
||||
}
|
||||
} else {
|
||||
rgba[idx + 3] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
let (width, height) = img.dimensions();
|
||||
|
||||
egui::IconData {
|
||||
rgba,
|
||||
width: size,
|
||||
height: size,
|
||||
rgba: img.into_raw(),
|
||||
width,
|
||||
height,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,9 @@ impl SequencerHandle {
|
||||
|
||||
pub fn shutdown(self) {
|
||||
let _ = self.cmd_tx.send(SeqCommand::Shutdown);
|
||||
let _ = self.thread.join();
|
||||
if let Err(e) = self.thread.join() {
|
||||
eprintln!("Sequencer thread panicked: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -873,7 +875,7 @@ fn sequencer_loop(
|
||||
let tempo = state.tempo();
|
||||
|
||||
let sr = sample_rate.load(Ordering::Relaxed) as f64;
|
||||
let audio_samples = audio_sample_pos.load(Ordering::Relaxed);
|
||||
let audio_samples = audio_sample_pos.load(Ordering::Acquire);
|
||||
let engine_time = if sr > 0.0 {
|
||||
audio_samples as f64 / sr
|
||||
} else {
|
||||
|
||||
@@ -101,7 +101,9 @@ impl Settings {
|
||||
}
|
||||
|
||||
pub fn save(&self) {
|
||||
let _ = confy::store(APP_NAME, None, self);
|
||||
if let Err(e) = confy::store(APP_NAME, None, self) {
|
||||
eprintln!("Failed to save settings: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user