@@ -24,7 +24,9 @@ use std::{collections::BTreeMap, process::ExitStatus, sync::Arc};
24
24
use tokio:: sync:: oneshot;
25
25
use tracing:: error;
26
26
27
- static DPI_SCALES : & [ u32 ] = & [ 50 , 75 , 100 , 125 , 150 , 175 , 200 , 225 , 250 , 275 , 300 ] ;
27
+ static DPI_SCALES : & [ f64 ] = & [
28
+ 50.0 , 75.0 , 100.0 , 125.0 , 150.0 , 175.0 , 200.0 , 225.0 , 250.0 , 275.0 , 300.0 ,
29
+ ] ;
28
30
static DPI_SCALE_LABELS : Lazy < Vec < String > > =
29
31
Lazy :: new ( || DPI_SCALES . iter ( ) . map ( |scale| format ! ( "{scale}%" ) ) . collect ( ) ) ;
30
32
@@ -100,6 +102,8 @@ pub enum Message {
100
102
Resolution ( usize ) ,
101
103
/// Set the preferred scale for a display.
102
104
Scale ( usize ) ,
105
+ SliderChangeScale ( f64 ) ,
106
+ SliderApplyScale ,
103
107
/// Refreshes display outputs.
104
108
Update {
105
109
/// Available outputs from cosmic-randr.
@@ -148,6 +152,7 @@ pub struct Page {
148
152
show_display_options : bool ,
149
153
comp_config : cosmic_config:: Config ,
150
154
comp_config_descale_xwayland : bool ,
155
+ slider_scale : Option < f64 > ,
151
156
}
152
157
153
158
impl Default for Page {
@@ -177,6 +182,7 @@ impl Default for Page {
177
182
dialog : None ,
178
183
dialog_countdown : 0 ,
179
184
show_display_options : true ,
185
+ slider_scale : None ,
180
186
comp_config,
181
187
comp_config_descale_xwayland,
182
188
}
@@ -193,6 +199,13 @@ struct Config {
193
199
scale : u32 ,
194
200
}
195
201
202
+ #[ derive( Default ) ]
203
+ struct ScaleOptionsViewCache {
204
+ scale_selected : Option < usize > ,
205
+ scale_values : Vec < f64 > ,
206
+ scale_labels : Vec < String > ,
207
+ }
208
+
196
209
/// Cached view content for widgets.
197
210
#[ derive( Default ) ]
198
211
struct ViewCache {
@@ -205,7 +218,18 @@ struct ViewCache {
205
218
refresh_rate_selected : Option < usize > ,
206
219
vrr_selected : Option < usize > ,
207
220
resolution_selected : Option < usize > ,
208
- scale_selected : Option < usize > ,
221
+ scale_options : ScaleOptionsViewCache ,
222
+ }
223
+
224
+ impl ScaleOptionsViewCache {
225
+ fn scale_selected_as_value ( & self ) -> f64 {
226
+ let selected = self . scale_selected ;
227
+ if let Some ( selected) = selected {
228
+ return * self . scale_values . get ( selected) . unwrap_or ( DPI_SCALES . last ( ) . unwrap ( ) ) ;
229
+ }
230
+
231
+ * DPI_SCALES . last ( ) . unwrap ( )
232
+ }
209
233
}
210
234
211
235
impl page:: AutoBind < crate :: pages:: Message > for Page { }
@@ -515,8 +539,15 @@ impl Page {
515
539
516
540
Message :: Resolution ( option) => return self . set_resolution ( option) ,
517
541
518
- Message :: Scale ( scale) => return self . set_scale ( scale) ,
519
-
542
+ Message :: Scale ( option) => return self . set_scale_option ( option) ,
543
+ Message :: SliderChangeScale ( scale) => {
544
+ self . slider_scale = Some ( scale) ;
545
+ }
546
+ Message :: SliderApplyScale => {
547
+ if let Some ( value) = self . slider_scale {
548
+ return self . set_scale_value ( value) ;
549
+ }
550
+ }
520
551
Message :: Update { randr } => {
521
552
match Arc :: into_inner ( randr) {
522
553
Some ( Ok ( outputs) ) => self . update_displays ( outputs) ,
@@ -664,10 +695,14 @@ impl Page {
664
695
self . cache . refresh_rate_selected = None ;
665
696
self . cache . vrr_selected = None ;
666
697
667
- self . cache . scale_selected = Some (
668
- DPI_SCALES
698
+ self . cache . scale_options . scale_labels = get_sorted_scale_labels ( self . config . scale . try_into ( ) . unwrap ( ) ) ;
699
+ self . cache . scale_options . scale_values = get_sorted_scales ( self . config . scale . try_into ( ) . unwrap ( ) ) ;
700
+ self . cache . scale_options . scale_selected = Some (
701
+ self . cache
702
+ . scale_options
703
+ . scale_values
669
704
. iter ( )
670
- . position ( |scale| self . config . scale <= * scale)
705
+ . position ( |scale| self . config . scale <= scale. floor ( ) as u32 )
671
706
. unwrap_or ( DPI_SCALES . len ( ) - 1 ) ,
672
707
) ;
673
708
@@ -913,20 +948,40 @@ impl Page {
913
948
Task :: batch ( tasks)
914
949
}
915
950
951
+ pub fn set_scale_option ( & mut self , option : usize ) -> Task < app:: Message > {
952
+ let value = self . cache
953
+ . scale_options
954
+ . scale_values
955
+ . get ( option)
956
+ . unwrap_or ( self . cache . scale_options . scale_values . last ( ) . unwrap ( ) ) ;
957
+
958
+ self . set_scale_value ( * value)
959
+ }
960
+
916
961
/// Set the scale of the active display.
917
- pub fn set_scale ( & mut self , option : usize ) -> Task < app:: Message > {
962
+ pub fn set_scale_value ( & mut self , value : f64 ) -> Task < app:: Message > {
918
963
let mut tasks = Vec :: with_capacity ( 2 ) ;
919
964
920
965
let Some ( output) = self . list . outputs . get ( self . active_display ) else {
921
966
return Task :: none ( ) ;
922
967
} ;
923
968
924
- let scale = ( option * 25 + 50 ) as u32 ;
969
+ let scale = value . floor ( ) as u32 ;
925
970
926
971
let request = Randr :: Scale ( scale) ;
927
972
let revert_request = Randr :: Scale ( self . config . scale ) ;
928
973
929
- self . cache . scale_selected = Some ( option) ;
974
+ self . cache . scale_options . scale_labels = get_sorted_scale_labels ( value) ;
975
+ self . cache . scale_options . scale_values = get_sorted_scales ( value) ;
976
+ self . cache . scale_options . scale_selected = Some (
977
+ self . cache
978
+ . scale_options
979
+ . scale_values
980
+ . iter ( )
981
+ . position ( |scale| value <= * scale)
982
+ . unwrap_or ( self . cache . scale_options . scale_values . len ( ) - 1 ) ,
983
+ ) ;
984
+
930
985
self . config . scale = scale;
931
986
tasks. push ( self . exec_randr ( output, Randr :: Scale ( scale) ) ) ;
932
987
tasks. push ( self . set_dialog ( revert_request, & request) ) ;
@@ -1078,6 +1133,29 @@ impl Page {
1078
1133
}
1079
1134
}
1080
1135
1136
+ fn get_sorted_scales ( current_value : f64 ) -> Vec < f64 > {
1137
+ if DPI_SCALES . contains ( & current_value ) {
1138
+ return DPI_SCALES . to_vec ( ) ;
1139
+ }
1140
+
1141
+ let mut scales: Vec < f64 > = DPI_SCALES . iter ( ) . copied ( ) . collect ( ) ;
1142
+ scales. push ( current_value) ;
1143
+ scales. sort_by ( |a, b| a. partial_cmp ( b) . unwrap ( ) ) ;
1144
+
1145
+ scales
1146
+ }
1147
+
1148
+ fn get_sorted_scale_labels ( current_value : f64 ) -> Vec < String > {
1149
+ if DPI_SCALES . contains ( & current_value) {
1150
+ return DPI_SCALE_LABELS . to_vec ( ) ;
1151
+ }
1152
+
1153
+ return get_sorted_scales ( current_value)
1154
+ . iter ( )
1155
+ . map ( |v| format ! ( "{v}%" ) )
1156
+ . collect ( ) ;
1157
+ }
1158
+
1081
1159
/// View for the display arrangement section.
1082
1160
pub fn display_arrangement ( ) -> Section < crate :: pages:: Message > {
1083
1161
let mut descriptions = Slab :: new ( ) ;
@@ -1132,6 +1210,7 @@ pub fn display_configuration() -> Section<crate::pages::Message> {
1132
1210
let vrr = descriptions. insert ( fl ! ( "vrr" ) ) ;
1133
1211
let resolution = descriptions. insert ( fl ! ( "display" , "resolution" ) ) ;
1134
1212
let scale = descriptions. insert ( fl ! ( "display" , "scale" ) ) ;
1213
+ let additional_scale_options = descriptions. insert ( fl ! ( "display" , "additional-scale-options" ) ) ;
1135
1214
let orientation = descriptions. insert ( fl ! ( "orientation" ) ) ;
1136
1215
let enable_label = descriptions. insert ( fl ! ( "display" , "enable" ) ) ;
1137
1216
let options_label = descriptions. insert ( fl ! ( "display" , "options" ) ) ;
@@ -1183,7 +1262,23 @@ pub fn display_configuration() -> Section<crate::pages::Message> {
1183
1262
items. extend ( vec ! [
1184
1263
widget:: settings:: item(
1185
1264
& descriptions[ scale] ,
1186
- dropdown( & DPI_SCALE_LABELS , page. cache. scale_selected, Message :: Scale ) ,
1265
+ dropdown(
1266
+ & page. cache. scale_options. scale_labels,
1267
+ page. cache. scale_options. scale_selected,
1268
+ Message :: Scale ,
1269
+ ) ,
1270
+ ) ,
1271
+ widget:: settings:: item(
1272
+ & descriptions[ additional_scale_options] ,
1273
+ widget:: slider(
1274
+ 50.0 ..=300.0 ,
1275
+ page. slider_scale. unwrap_or(
1276
+ page. cache. scale_options. scale_selected_as_value( )
1277
+ ) ,
1278
+ Message :: SliderChangeScale ,
1279
+ )
1280
+ . on_release( Message :: SliderApplyScale )
1281
+ . breakpoints( DPI_SCALES ) ,
1187
1282
) ,
1188
1283
widget:: settings:: item(
1189
1284
& descriptions[ orientation] ,
0 commit comments