1- use appcui:: prelude:: * ;
21use std:: time:: Duration ;
2+
3+ use appcui:: prelude:: * ;
34use rand;
45
5- #[ derive( Clone ) ]
6+ #[ derive( Copy , Clone , Default ) ]
67struct Bar {
7- height : i32 ,
8- color : Color ,
9- x : i32 , // Add x position to track movement
8+ value : i32 ,
9+ col : Color ,
1010}
1111
12+ const COLORS : [ Color ; 7 ] = [
13+ Color :: Red ,
14+ Color :: Green ,
15+ Color :: Blue ,
16+ Color :: Aqua ,
17+ Color :: Yellow ,
18+ Color :: Pink ,
19+ Color :: Gray ,
20+ ] ;
21+
1222#[ Window ( events = TimerEvents ) ]
13- pub ( crate ) struct Win {
23+ pub ( super ) struct Win {
1424 bars : Vec < Bar > ,
15- last_update : u64 ,
16- canvas : Handle < Canvas > ,
25+ c : Handle < Canvas > ,
1726}
1827
1928impl Win {
20- pub ( crate ) fn new ( ) -> Self {
29+ pub ( super ) fn new ( ) -> Self {
2130 let mut w = Self {
22- base : window ! ( "Animation,d:c,w:50,h:20" ) ,
23- bars : Vec :: new ( ) ,
24- last_update : 0 ,
25- canvas : Handle :: None ,
31+ base : window ! ( "Animation,d:c,w:50,h:10" ) ,
32+ bars : Vec :: with_capacity ( 100 ) ,
33+ c : Handle :: None ,
2634 } ;
27-
28- // Add canvas using the public add method
29- w. canvas = w. add ( canvas ! ( "l:0,t:0,r:0,b:0,size:100x100" ) ) ;
35+ w. c = w. add ( canvas ! ( "d:c,w:100%,h:100%,size:100x50" ) ) ;
3036 if let Some ( timer) = w. timer ( ) {
31- timer. start ( Duration :: from_millis ( 300 ) ) ; // Update every 0.3 seconds
37+ timer. start ( Duration :: from_millis ( 300 ) ) ;
3238 }
3339 w
3440 }
41+ fn repaint_graphic ( & mut self ) {
42+ let h = self . c ;
43+ let line_color = self . theme ( ) . lines . normal ;
44+ let bars_width = self . bars . len ( ) as i32 * 2 ;
45+ let bars_count = self . bars . len ( ) ;
46+ let sz = self . size ( ) . reduce_by ( 2 ) ; // window margins
47+ let mut arr: [ Bar ; 100 ] = [ Bar :: default ( ) ; 100 ] ;
48+ for i in 0 ..bars_count. min ( 100 ) {
49+ arr[ i] = self . bars [ i] ;
50+ }
51+ if let Some ( canvas) = self . control_mut ( h) {
52+ let surface = canvas. get_drawing_surface ( ) ;
53+ surface. clear ( char !( "' ',w,black" ) ) ;
3554
36- fn get_height_change ( & self , current_height : i32 , max_height : i32 ) -> i32 {
37- let quarter_height = max_height / 4 ;
38- let three_quarters_height = ( max_height * 3 ) / 4 ;
39-
40- if current_height < quarter_height {
41- // When height is less than 25%, higher chance to increase
42- match rand:: random :: < u32 > ( ) % 10 {
43- 0 ..=1 => -1 , // 20% chance
44- 2 ..=4 => 0 , // 30% chance
45- 5 ..=9 => 1 , // 50% chance
46- _ => 0 ,
47- }
48- } else if current_height > three_quarters_height {
49- // When height is more than 75%, higher chance to decrease
50- match rand:: random :: < u32 > ( ) % 10 {
51- 0 ..=4 => -1 , // 50% chance
52- 5 ..=7 => 0 , // 30% chance
53- 8 ..=9 => 1 , // 20% chance
54- _ => 0 ,
55+ // draw the lines
56+ surface. draw_horizontal_line ( 0 , ( sz. height / 4 ) as i32 , sz. width as i32 , LineType :: Single , line_color) ;
57+ surface. draw_horizontal_line ( 0 , ( sz. height / 2 ) as i32 , sz. width as i32 , LineType :: Single , line_color) ;
58+ surface. draw_horizontal_line ( 0 , ( sz. height * 3 / 4 ) as i32 , sz. width as i32 , LineType :: Single , line_color) ;
59+
60+ // draw the bars
61+ let mut x = sz. width as i32 - bars_width;
62+ for b in & arr {
63+ surface. fill_vertical_line (
64+ x,
65+ sz. height as i32 - b. value ,
66+ sz. height as i32 ,
67+ Character :: new ( ' ' , Color :: Black , b. col , CharFlags :: None ) ,
68+ ) ;
69+ x += 2 ;
5570 }
56- } else {
57- // Normal case: equal probability
58- rand:: random :: < i32 > ( ) % 3 - 1
5971 }
6072 }
6173}
6274
6375impl TimerEvents for Win {
6476 fn on_update ( & mut self , _ticks : u64 ) -> EventProcessStatus {
65- let canvas_handle = self . canvas ;
66-
67- // Get canvas size first
68- let size = if let Some ( canvas) = self . control ( canvas_handle) {
69- canvas. size ( )
70- } else {
71- return EventProcessStatus :: Processed ;
72- } ;
73-
74- // Move all existing bars to the left
75- for bar in & mut self . bars {
76- bar. x -= 2 ; // Move 2 positions to leave space between columns
77- }
78-
79- // Remove bars that have moved off screen
80- self . bars . retain ( |bar| bar. x >= 0 ) ;
81-
82- // Add a new random bar at the right edge
83- let colors = [
84- Color :: Red ,
85- Color :: Green ,
86- Color :: Blue ,
87- Color :: Aqua ,
88- Color :: Yellow ,
89- Color :: Pink ,
90- Color :: Gray ,
91- ] ;
92- let random_color = colors[ rand:: random :: < usize > ( ) % colors. len ( ) ] ;
93-
94- // Calculate new height based on previous bar or random if first bar
95- let new_height = if let Some ( last_bar) = self . bars . last ( ) {
96- let change = self . get_height_change ( last_bar. height , size. height as i32 ) ;
97- ( last_bar. height + change) . clamp ( 1 , size. height as i32 - 2 )
98- } else {
99- // First bar - random height
100- ( rand:: random :: < u32 > ( ) % ( size. height as u32 - 2 ) ) as i32 + 1
77+ let sz = self . size ( ) . reduce_by ( 2 ) ; // window margins
78+ let h = sz. height as i32 ;
79+ let last_height = self
80+ . bars
81+ . last ( )
82+ . unwrap_or ( & Bar {
83+ value : ( rand:: random :: < i32 > ( ) % h) . clamp ( 1 , h) ,
84+ col : Color :: Black ,
85+ } )
86+ . value ;
87+ let add = match ( ) {
88+ _ if last_height <= ( h / 4 ) => ( ( rand:: random :: < i32 > ( ) % 5 ) - 1 ) . min ( 1 ) ,
89+ _ if last_height >= ( 3 * h / 4 ) => ( ( rand:: random :: < i32 > ( ) % 5 ) - 3 ) . max ( -1 ) ,
90+ _ => ( rand:: random :: < i32 > ( ) % 3 ) - 1 ,
10191 } ;
102-
10392 self . bars . push ( Bar {
104- height : new_height,
105- color : random_color,
106- x : size. width as i32 - 1 ,
93+ value : ( last_height + add) . clamp ( 1 , h) ,
94+ col : COLORS [ rand:: random :: < usize > ( ) % COLORS . len ( ) ] ,
10795 } ) ;
108-
109- // Prepare bar data for drawing
110- let bars_data: Vec < _ > = self . bars . iter ( )
111- . map ( |bar| ( bar. x , bar. height , bar. color ) )
112- . collect ( ) ;
113-
114- // Draw bars
115- if let Some ( canvas) = self . control_mut ( canvas_handle) {
116- let surface = canvas. get_drawing_surface ( ) ;
117- surface. clear ( Character :: with_char ( ' ' ) ) ;
118-
119- // Draw marker lines
120- let quarter_height = size. height as i32 / 4 ;
121- let half_height = size. height as i32 / 2 ;
122- let three_quarters_height = ( size. height as i32 * 3 ) / 4 ;
123-
124- // Draw horizontal lines for each threshold
125- for x in 0 ..size. width as i32 {
126- // 25% line
127- surface. write_char (
128- x,
129- size. height as i32 - 1 - quarter_height,
130- Character :: new ( '─' , Color :: White , Color :: Black , CharFlags :: None ) ,
131- ) ;
132- // 50% line
133- surface. write_char (
134- x,
135- size. height as i32 - 1 - half_height,
136- Character :: new ( '─' , Color :: White , Color :: Black , CharFlags :: None ) ,
137- ) ;
138- // 75% line
139- surface. write_char (
140- x,
141- size. height as i32 - 1 - three_quarters_height,
142- Character :: new ( '─' , Color :: White , Color :: Black , CharFlags :: None ) ,
143- ) ;
144- }
145-
146- // Draw each bar using the prepared data
147- for ( x, height, color) in bars_data {
148- if x >= 0 {
149- for y in 0 ..height {
150- surface. write_char (
151- x,
152- size. height as i32 - 1 - y,
153- Character :: new ( '█' , color, Color :: Black , CharFlags :: None ) ,
154- ) ;
155- }
156- }
157- }
96+ if self . bars . len ( ) > ( sz. width as usize ) * 2 {
97+ self . bars . remove ( 0 ) ;
15898 }
99+ // repaint all
100+ self . repaint_graphic ( ) ;
159101
160102 EventProcessStatus :: Processed
161103 }
162- }
104+ }
0 commit comments