Skip to content

Commit ce76125

Browse files
committed
More things can be persisted
1 parent 92087b7 commit ce76125

File tree

12 files changed

+210
-145
lines changed

12 files changed

+210
-145
lines changed

viz-udp-app/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ documentation = "https://docs.rs/caw_viz_udp_app"
1111

1212
[dependencies]
1313
anyhow = "1.0"
14-
sdl2 = { version = "0.38", features = ["ttf"] }
14+
sdl2 = { version = "0.38" }
1515
line_2d = "0.5"
1616
clap = { version = "4", features = ["derive"] }
1717
caw_viz_udp_app_lib = { version = "0.1", path = "../viz-udp-app-lib" }
18-
lazy_static = "1.5"
1918
log = "0.4"
2019
caw_window_utils = { version = "0.1", path = "../window-utils" }
20+
serde = { version = "1.0", features = ["serde_derive"] }

viz-udp-app/src/main.rs

Lines changed: 46 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
/// A udp client which receives visualization data from a corresponding udp server and renders
22
/// visualizations in a graphical window.
33
use anyhow::anyhow;
4-
use caw_viz_udp_app_lib::{
5-
blink,
6-
oscilloscope::{self, OscilloscopeStyle},
4+
use caw_viz_udp_app_lib::{blink, oscilloscope};
5+
use caw_window_utils::{
6+
font::load_font,
7+
persistent::{PersistentData, WindowPosition, WindowSize},
78
};
8-
use caw_window_utils::persisten_window_position;
99
use clap::{Parser, Subcommand, ValueEnum};
10-
use lazy_static::lazy_static;
1110
use line_2d::Coord;
1211
use sdl2::{
1312
EventPump,
@@ -16,44 +15,20 @@ use sdl2::{
1615
pixels::Color,
1716
rect::Rect,
1817
render::Canvas,
19-
rwops::RWops,
20-
ttf::{Font, Sdl2TtfContext},
2118
video::Window,
2219
};
20+
use serde::{Deserialize, Serialize};
2321
use std::collections::VecDeque;
2422

25-
lazy_static! {
26-
static ref TTF_CONTEXT: Result<Sdl2TtfContext, String> = sdl2::ttf::init();
27-
}
28-
29-
// TODO: unify font loading across libraries
30-
fn load_font() -> anyhow::Result<Font<'static, 'static>> {
31-
let font_data = include_bytes!("inconsolata.regular.ttf");
32-
let pt_size = 16;
33-
let rwops = RWops::from_bytes(font_data).map_err(|e| anyhow!("{e}"))?;
34-
let ttf_context = TTF_CONTEXT.as_ref().map_err(|e| anyhow!("{e}"))?;
35-
ttf_context
36-
.load_font_from_rwops(rwops, pt_size)
37-
.map_err(|e| anyhow!(e))
38-
}
39-
40-
#[derive(ValueEnum, Clone, Copy)]
41-
enum OscilloscopeStyle_ {
23+
#[derive(Serialize, Deserialize, ValueEnum, Clone, Copy, Debug)]
24+
pub enum OscilloscopeStyle {
4225
Xy,
4326
TimeDomain,
4427
TimeDomainStereo,
4528
}
4629

47-
impl From<OscilloscopeStyle_> for OscilloscopeStyle {
48-
fn from(value: OscilloscopeStyle_) -> Self {
49-
match value {
50-
OscilloscopeStyle_::Xy => OscilloscopeStyle::Xy,
51-
OscilloscopeStyle_::TimeDomain => OscilloscopeStyle::TimeDomain,
52-
OscilloscopeStyle_::TimeDomainStereo => {
53-
OscilloscopeStyle::TimeDomainStereo
54-
}
55-
}
56-
}
30+
impl PersistentData for OscilloscopeStyle {
31+
const NAME: &'static str = "oscilloscope_style";
5732
}
5833

5934
#[derive(Parser)]
@@ -77,7 +52,7 @@ struct OscilloscopeCommand {
7752
#[arg(long, short, default_value_t = 0)]
7853
blue: u8,
7954
#[arg(long, default_value = "time-domain")]
80-
style: OscilloscopeStyle_,
55+
style: OscilloscopeStyle,
8156
}
8257

8358
#[derive(Parser)]
@@ -153,9 +128,7 @@ impl App {
153128
win_event: WindowEvent::Moved(x, y),
154129
..
155130
} => {
156-
if let Err(e) = persisten_window_position::save(title, x, y) {
157-
log::warn!("{}", e);
158-
}
131+
(WindowPosition { x, y }).save_(title);
159132
}
160133
_ => (),
161134
}
@@ -165,8 +138,12 @@ impl App {
165138
mut self,
166139
mut args: OscilloscopeCommand,
167140
) -> anyhow::Result<()> {
141+
self.canvas.window_mut().set_resizable(true);
168142
let mut viz_udp_client = oscilloscope::Client::new(self.server)?;
169143
let mut scope_state = ScopeState::default();
144+
if let Some(style) = OscilloscopeStyle::load_(&self.title) {
145+
args.style = style;
146+
}
170147
loop {
171148
for event in self.event_pump.poll_iter() {
172149
Self::handle_event_common(event.clone(), self.title.as_str());
@@ -190,16 +167,19 @@ impl App {
190167
Scancode::Left => (-1, 0),
191168
Scancode::Right => (1, 0),
192169
Scancode::Num1 => {
193-
args.style = OscilloscopeStyle_::TimeDomain;
170+
args.style = OscilloscopeStyle::TimeDomain;
171+
args.style.save_(&self.title);
194172
continue;
195173
}
196174
Scancode::Num2 => {
197175
args.style =
198-
OscilloscopeStyle_::TimeDomainStereo;
176+
OscilloscopeStyle::TimeDomainStereo;
177+
args.style.save_(&self.title);
199178
continue;
200179
}
201180
Scancode::Num3 => {
202-
args.style = OscilloscopeStyle_::Xy;
181+
args.style = OscilloscopeStyle::Xy;
182+
args.style.save_(&self.title);
203183
continue;
204184
}
205185
_ => (0, 0),
@@ -219,6 +199,11 @@ impl App {
219199
} => {
220200
args.width = width as u32;
221201
args.height = height as u32;
202+
(WindowSize {
203+
width: args.width,
204+
height: args.height,
205+
})
206+
.save_(&self.title);
222207
}
223208
_ => (),
224209
}
@@ -238,7 +223,7 @@ impl App {
238223
y: args.height as i32,
239224
};
240225
match args.style {
241-
OscilloscopeStyle_::TimeDomain => {
226+
OscilloscopeStyle::TimeDomain => {
242227
let num_samples_to_draw = screen_size.x as usize;
243228
let sample_mean_iter = scope_state
244229
.samples
@@ -273,7 +258,7 @@ impl App {
273258
prev = Some(coord);
274259
}
275260
}
276-
OscilloscopeStyle_::TimeDomainStereo => {
261+
OscilloscopeStyle::TimeDomainStereo => {
277262
let num_samples_to_draw = screen_size.x as usize;
278263
let make_sample_pair_iter = || {
279264
scope_state
@@ -335,7 +320,7 @@ impl App {
335320
prev = Some(coord);
336321
}
337322
}
338-
OscilloscopeStyle_::Xy => {
323+
OscilloscopeStyle::Xy => {
339324
let mut coord_iter =
340325
scope_state.samples.iter().map(|(left, right)| {
341326
Coord {
@@ -380,7 +365,7 @@ impl App {
380365
title: String,
381366
) -> anyhow::Result<()> {
382367
let mut viz_udp_client = blink::Client::new(self.server)?;
383-
let font = load_font()?;
368+
let font = load_font(16)?;
384369
let text_surface = font
385370
.render(title.as_str())
386371
.blended(Color::WHITE)
@@ -447,28 +432,28 @@ fn main() -> anyhow::Result<()> {
447432
} = Cli::parse();
448433
let sdl_context = sdl2::init().map_err(|e| anyhow!(e))?;
449434
let video_subsystem = sdl_context.video().map_err(|e| anyhow!(e))?;
435+
let (width, height) = match WindowSize::load(&title) {
436+
Err(_) => (command.width(), command.height()),
437+
Ok(WindowSize { width, height }) => (width, height),
438+
};
439+
let window_position = match WindowPosition::load(&title) {
440+
Err(_) => None,
441+
Ok(window_position) => Some(window_position),
442+
};
443+
450444
let mut window_builder = match command {
451445
Command::Oscilloscope(_) => {
452-
let mut wb = video_subsystem.window(
453-
title.as_str(),
454-
command.width(),
455-
command.height(),
456-
);
457-
wb.resizable();
446+
let wb = video_subsystem.window(title.as_str(), width, height);
458447
wb
459448
}
460449
Command::Blink(_) => {
461-
let mut wb =
462-
video_subsystem.window("", command.width(), command.height());
450+
let mut wb = video_subsystem.window("", width, height);
463451
wb.always_on_top();
464452
wb
465453
}
466454
};
467-
match persisten_window_position::load(&title) {
468-
Err(e) => log::warn!("{}", e),
469-
Ok((x, y)) => {
470-
window_builder.position(x, y);
471-
}
455+
if let Some(WindowPosition { x, y }) = window_position {
456+
window_builder.position(x, y);
472457
}
473458
let window = window_builder.build()?;
474459
let mut canvas = window
@@ -485,7 +470,9 @@ fn main() -> anyhow::Result<()> {
485470
title: title.clone(),
486471
};
487472
match command {
488-
Command::Oscilloscope(oscilloscope_command) => {
473+
Command::Oscilloscope(mut oscilloscope_command) => {
474+
oscilloscope_command.width = width;
475+
oscilloscope_command.height = height;
489476
app.run_oscilloscope(oscilloscope_command)
490477
}
491478
Command::Blink(blink_command) => app.run_blink(blink_command, title),

widgets/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ documentation = "https://docs.rs/caw_widgets"
1111

1212
[dependencies]
1313
anyhow = "1.0"
14-
sdl2 = { version = "0.38", features = ["ttf"] }
14+
sdl2 = { version = "0.38" }
1515
line_2d = "0.5"
16-
lazy_static = "1.5"
1716
midly = "0.5"
1817
caw_computer_keyboard = { version = "0.4", path = "../computer-keyboard" }
1918
caw_keyboard = { version = "0.4", path = "../keyboard" }
2019
caw_sdl2 = { version = "0.1", path = "../sdl2" }
2120
caw_window_utils = { version = "0.1", path = "../window-utils" }
2221
itertools = "0.14"
2322
log = "0.4"
23+
serde = { version = "1.0", features = ["serde_derive"] }
2424

2525
[dev-dependencies]
2626
env_logger = "0.11"

widgets/src/computer_keyboard.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ use crate::window::Window;
22
use anyhow::anyhow;
33
use caw_computer_keyboard::Key;
44
use caw_keyboard::Note;
5+
use caw_window_utils::font::{Font, load_font};
56
use midly::{MidiMessage, num::u7};
6-
use sdl2::{keyboard::Scancode, pixels::Color, rect::Rect, ttf::Font};
7+
use sdl2::{keyboard::Scancode, pixels::Color, rect::Rect};
78
use std::{collections::HashMap, time::Instant};
89

910
const WIDTH_PX: u32 = 128;
@@ -65,7 +66,7 @@ impl ComputerKeyboard {
6566
window,
6667
key_mappings,
6768
pressed_keys: Default::default(),
68-
font: crate::window::load_font(48)?,
69+
font: load_font(48)?,
6970
})
7071
}
7172

-80.4 KB
Binary file not shown.

widgets/src/knob.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
use crate::window::Window;
22
use anyhow::anyhow;
3+
use caw_window_utils::persistent::PersistentData;
34
use line_2d::Coord;
45
use midly::num::u7;
56
use sdl2::{
67
event::Event, keyboard::Scancode, mouse::MouseButton, pixels::Color,
78
rect::Rect,
89
};
10+
use serde::{Deserialize, Serialize};
911
use std::time::Instant;
1012

1113
const WIDTH_PX: u32 = 128;
1214
const HEIGHT_PX: u32 = 128;
1315

1416
const RANGE_RADS: f32 = (std::f32::consts::PI * 3.0) / 2.0;
1517

18+
#[derive(Serialize, Deserialize)]
19+
struct State {
20+
value_01: f32,
21+
}
22+
23+
impl PersistentData for State {
24+
const NAME: &'static str = "knob_state";
25+
}
26+
1627
pub struct Knob {
28+
title: Option<String>,
1729
window: Window,
18-
value_01: f32,
30+
state: State,
1931
sensitivity: f32,
2032
}
2133

@@ -26,9 +38,17 @@ impl Knob {
2638
sensitivity: f32,
2739
) -> anyhow::Result<Self> {
2840
let window = Window::new(title, WIDTH_PX, HEIGHT_PX)?;
41+
let state = if let Some(state) = title.and_then(|t| State::load_(t)) {
42+
state
43+
} else {
44+
State {
45+
value_01: initial_value_01.clamp(0., 1.),
46+
}
47+
};
2948
Ok(Self {
49+
title: title.map(|s| s.to_string()),
3050
window,
31-
value_01: initial_value_01.clamp(0., 1.),
51+
state,
3252
sensitivity,
3353
})
3454
}
@@ -55,11 +75,11 @@ impl Knob {
5575
Some(Scancode::Num0) => 1.0,
5676
_ => continue,
5777
};
58-
self.value_01 = value_01;
78+
self.state.value_01 = value_01;
5979
}
6080
Event::MouseWheel { precise_y, .. } => {
6181
let multiplier = 0.1;
62-
self.value_01 = (self.value_01
82+
self.state.value_01 = (self.state.value_01
6383
+ (precise_y * multiplier * self.sensitivity))
6484
.clamp(0., 1.);
6585
}
@@ -68,21 +88,24 @@ impl Knob {
6888
} => {
6989
if mousestate.is_mouse_button_pressed(MouseButton::Left) {
7090
let multiplier = -0.05;
71-
self.value_01 = (self.value_01
91+
self.state.value_01 = (self.state.value_01
7292
+ (yrel as f32 * multiplier * self.sensitivity))
7393
.clamp(0., 1.);
7494
}
7595
}
7696
_ => (),
7797
}
7898
}
99+
if let Some(title) = self.title.as_ref() {
100+
self.state.save_(title);
101+
}
79102
}
80103

81104
fn render_value(&mut self) -> anyhow::Result<()> {
82105
let text_surface = self
83106
.window
84107
.font
85-
.render(format!("{}", self.value_01).as_str())
108+
.render(format!("{}", self.state.value_01).as_str())
86109
.blended(Color::WHITE)
87110
.map_err(|e| anyhow!("{e}"))?;
88111
let text_texture =
@@ -122,7 +145,7 @@ impl Knob {
122145
let absolute_rotation_rads =
123146
(((std::f32::consts::PI * 2.0) - RANGE_RADS) / 2.0)
124147
+ std::f32::consts::FRAC_PI_2;
125-
let relative_angle_rads = RANGE_RADS * self.value_01;
148+
let relative_angle_rads = RANGE_RADS * self.state.value_01;
126149
let line_length_px =
127150
((available_width.min(available_height) / 2) - 10) as f32;
128151
let angle_rads = absolute_rotation_rads + relative_angle_rads;
@@ -175,7 +198,7 @@ impl Knob {
175198
}
176199

177200
pub fn value_01(&self) -> f32 {
178-
self.value_01
201+
self.state.value_01
179202
}
180203

181204
pub fn value_midi(&self) -> u7 {

0 commit comments

Comments
 (0)