11/// A udp client which receives visualization data from a corresponding udp server and renders
22/// visualizations in a graphical window.
33use 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;
99use clap:: { Parser , Subcommand , ValueEnum } ;
10- use lazy_static:: lazy_static;
1110use line_2d:: Coord ;
1211use 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 } ;
2321use 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) ,
0 commit comments