@@ -98,6 +98,7 @@ struct CosmicBatteryApplet {
9898 zbus_connection : Option < zbus:: Connection > ,
9999 dragging_screen_brightness : bool ,
100100 dragging_kbd_brightness : bool ,
101+ last_coarse_k : Option < i32 > ,
101102}
102103
103104impl CosmicBatteryApplet {
@@ -135,18 +136,62 @@ impl CosmicBatteryApplet {
135136 format ! ( "cosmic-applet-battery-level-{battery_percent}-{limited}{charging}symbolic" , ) ;
136137 }
137138
139+ #[ inline]
140+ fn raw_from_step_index ( k : i32 , max_raw : i32 ) -> i32 {
141+ // round(k * max / 20) using integer math
142+ ( ( k * max_raw + 10 ) / 20 )
143+ }
144+
145+ /// Resolve rung k for a given raw on coarse panels (max<=20) in a tie-aware way.
146+ /// If multiple rungs map to the same raw, use the last displayed rung to keep
147+ /// GUI steps monotonic in 5% increments (no 10% jumps).
148+ fn resolve_rung_tie_aware ( & self , raw : i32 , max_raw : i32 ) -> i32 {
149+ // Exact matches: all k s.t. forward map equals this raw
150+ let mut ks: Vec < i32 > = ( 0 ..=20 )
151+ . filter ( |& k| Self :: raw_from_step_index ( k, max_raw) == raw)
152+ . collect ( ) ;
153+
154+ if ks. is_empty ( ) {
155+ // Fallback to nearest k
156+ let mut best_k = 0 ;
157+ let mut best_d = i32:: MAX ;
158+ for k in 0 ..=20 {
159+ let d = ( Self :: raw_from_step_index ( k, max_raw) - raw) . abs ( ) ;
160+ if d < best_d {
161+ best_d = d;
162+ best_k = k;
163+ }
164+ }
165+ return best_k;
166+ }
167+ if ks. len ( ) == 1 || self . last_coarse_k . is_none ( ) {
168+ return ks[ 0 ] ;
169+ }
170+
171+ let prev = self . last_coarse_k . unwrap ( ) ;
172+ let k_lo = ks[ 0 ] ;
173+ let k_hi = * ks. last ( ) . unwrap ( ) ;
174+ // Entering tie from below -> lower first; from above -> higher first
175+ if prev < k_lo { return k_lo; }
176+ if prev == k_lo { return k_hi; } // stuck raw, next upward step
177+ if prev > k_hi { return k_hi; }
178+ if prev == k_hi { return k_lo; } // stuck raw, next downward step
179+ k_lo
180+ }
181+
182+
138183 fn screen_brightness_percent ( & self ) -> Option < f64 > {
139- let raw = self . screen_brightness ? as i64 ;
140- let max = self . max_screen_brightness ?. max ( 1 ) as i64 ;
184+ let raw = self . screen_brightness ? as i32 ;
185+ let max = self . max_screen_brightness ?. max ( 1 ) as i32 ;
141186 if max <= 20 {
142- // Matching brightness calculation logic from cosmic-osd and cosmic-settings-daemon
143- let mut k = ( raw * 20 + max / 2 ) / max;
144- if k < 0 { k = 0 ; }
145- if k > 20 { k = 20 ; }
187+ // TIE-AWARE: invert daemon setpoints with prev-k memory
188+ let k = self . resolve_rung_tie_aware ( raw. max ( 0 ) , max) ;
146189 let p = if k == 0 { 1 } else { 5 * k } ;
147- Some ( ( p as f64 ) / 100.0 )
190+ Some ( p as f64 / 100.0 )
148191 } else {
149- let p = ( ( raw * 100 + max / 2 ) / max) . clamp ( 1 , 100 ) as f64 ;
192+ // Fine panels: exact integer percent with 1% floor
193+ let p = ( ( ( raw as i64 ) * 100 + ( max as i64 ) / 2 ) / ( max as i64 ) )
194+ . clamp ( 1 , 100 ) as f64 ;
150195 Some ( p / 100.0 )
151196 }
152197 }
@@ -265,6 +310,15 @@ impl cosmic::Application for CosmicBatteryApplet {
265310 brightness
266311 } ;
267312 self . screen_brightness = Some ( snapped) ;
313+ // Maintain tie-aware rung memory so GUI steps are 5% even if raw repeats
314+ if let Some ( max) = self . max_screen_brightness {
315+ if max > 0 && max <= 20 {
316+ let k = self . resolve_rung_tie_aware ( snapped. max ( 0 ) , max. max ( 1 ) ) ;
317+ self . last_coarse_k = Some ( k) ;
318+ } else {
319+ self . last_coarse_k = None ;
320+ }
321+ }
268322 if !self . dragging_screen_brightness {
269323 self . dragging_screen_brightness = true ;
270324 self . update_display ( ) ;
@@ -484,11 +538,24 @@ impl cosmic::Application for CosmicBatteryApplet {
484538 }
485539 settings_daemon:: Event :: MaxDisplayBrightness ( max_brightness) => {
486540 self . max_screen_brightness = Some ( max_brightness) ;
541+ if max_brightness > 20 {
542+ // Fine panel: no tie memory needed
543+ self . last_coarse_k = None ;
544+ }
487545 }
488546 settings_daemon:: Event :: DisplayBrightness ( brightness) => {
489547 if !self . dragging_screen_brightness {
490548 self . screen_brightness = Some ( brightness) ;
491549 }
550+ // Keep tie-aware rung memory in sync with daemon reports
551+ if let Some ( max) = self . max_screen_brightness {
552+ if max <= 20 {
553+ let k = self . resolve_rung_tie_aware ( brightness. max ( 0 ) , max. max ( 1 ) ) ;
554+ self . last_coarse_k = Some ( k) ;
555+ } else {
556+ self . last_coarse_k = None ;
557+ }
558+ }
492559 }
493560 } ,
494561 Message :: Surface ( a) => {
0 commit comments