11use crate :: injector:: { self , WindowInfo } ;
22use eframe:: {
33 Renderer ,
4- egui:: { self , ColorImage , Direction , IconData , Layout } ,
4+ egui:: {
5+ self , Color32 , ColorImage , Direction , FontData , FontDefinitions , FontFamily , FontId ,
6+ IconData , Layout , Margin , RichText , TextStyle ,
7+ } ,
58} ;
69use image:: { GenericImageView , ImageFormat , ImageReader } ;
710use std:: sync:: { Arc , Mutex } ;
@@ -159,6 +162,16 @@ impl Gui {
159162 active_monitor : 0 ,
160163 }
161164 }
165+
166+ fn add_section_header ( ui : & mut egui:: Ui , header : impl Into < String > , desc : impl Into < String > ) {
167+ ui. label (
168+ RichText :: new ( header)
169+ . heading ( )
170+ . color ( Color32 :: from_rgb ( 242 , 242 , 242 ) ) ,
171+ ) ;
172+ ui. label ( RichText :: new ( desc) . color ( Color32 :: from_rgb ( 148 , 148 , 148 ) ) ) ;
173+ ui. add_space ( 8.0 ) ;
174+ }
162175}
163176
164177impl eframe:: App for Gui {
@@ -181,99 +194,101 @@ impl eframe::App for Gui {
181194 }
182195 }
183196
184- egui:: CentralPanel :: default ( ) . show ( ctx, |ui| {
185- if !focused {
186- ui. with_layout (
187- Layout :: centered_and_justified ( Direction :: LeftToRight ) ,
188- |ui| {
189- ui. label ( ":)" ) ;
190- } ,
191- ) ;
192- return ;
193- }
197+ egui:: CentralPanel :: default ( )
198+ . frame ( egui:: Frame :: central_panel ( & ctx. style ( ) ) . inner_margin ( Margin :: same ( 14 ) ) )
199+ . show ( ctx, |ui| {
200+ if !focused {
201+ ui. with_layout (
202+ Layout :: centered_and_justified ( Direction :: LeftToRight ) ,
203+ |ui| {
204+ ui. label ( ":)" ) ;
205+ } ,
206+ ) ;
207+ return ;
208+ }
194209
195- egui:: ScrollArea :: vertical ( ) . show ( ui, |ui| {
196- if self . show_desktop_preview {
197- ui. heading ( "Desktop Preview" ) ;
198- ui. add_space ( 4.0 ) ;
199-
200- if self . monitors . len ( ) > 1 {
201- ui. horizontal_wrapped ( |ui| {
202- for ( i, monitor) in self . monitors . iter ( ) . enumerate ( ) {
203- let monitor_label = ui. selectable_label (
204- i == self . active_monitor ,
205- format ! ( "Screen {}" , i + 1 ) ,
206- ) ;
207- if monitor_label. clicked ( ) && self . active_monitor != i {
208- self . active_monitor = i;
209- let _ = self
210- . capture_event_send
211- . send ( CaptureWorkerEvent :: CAPTURE ( * monitor) ) ;
212- }
210+ egui:: ScrollArea :: vertical ( ) . show ( ui, |ui| {
211+ if self . show_desktop_preview {
212+ Self :: add_section_header ( ui, "Preview" , "How others will see your screen" ) ;
213+
214+ if let Ok ( img) = self . capture_recv . try_recv ( ) {
215+ if let Some ( texture_handle) = & mut self . capture_tex {
216+ texture_handle. set ( img, egui:: TextureOptions :: LINEAR ) ;
217+ } else {
218+ self . capture_tex = Some ( ctx. load_texture (
219+ "screen_capture" ,
220+ img,
221+ egui:: TextureOptions :: LINEAR ,
222+ ) ) ;
213223 }
214- } ) ;
215- ui. add_space ( 4.0 ) ;
216- }
224+ ctx. request_repaint ( ) ;
225+ }
217226
218- if let Ok ( img) = self . capture_recv . try_recv ( ) {
219- if let Some ( texture_handle) = & mut self . capture_tex {
220- texture_handle. set ( img, egui:: TextureOptions :: LINEAR ) ;
221- } else {
222- self . capture_tex = Some ( ctx. load_texture (
223- "screen_capture" ,
224- img,
225- egui:: TextureOptions :: LINEAR ,
226- ) ) ;
227+ if let Some ( tex) = & self . capture_tex {
228+ ui. add ( egui:: Image :: from_texture ( tex) . shrink_to_fit ( ) ) ;
227229 }
228- ctx. request_repaint ( ) ;
229- }
230230
231- if let Some ( tex) = & self . capture_tex {
232- ui. add ( egui:: Image :: from_texture ( tex) . shrink_to_fit ( ) ) ;
233- }
234- ui. add_space ( 8.0 ) ;
235- }
231+ if self . monitors . len ( ) > 1 {
232+ ui. add_space ( 8.0 ) ;
233+ ui. horizontal_wrapped ( |ui| {
234+ for ( i, monitor) in self . monitors . iter ( ) . enumerate ( ) {
235+ let monitor_label = ui. selectable_label (
236+ i == self . active_monitor ,
237+ format ! ( "Screen {}" , i + 1 ) ,
238+ ) ;
239+ if monitor_label. clicked ( ) && self . active_monitor != i {
240+ self . active_monitor = i;
241+ let _ = self
242+ . capture_event_send
243+ . send ( CaptureWorkerEvent :: CAPTURE ( * monitor) ) ;
244+ }
245+ }
246+ } ) ;
247+ }
236248
237- ui. heading ( "Hide applications" ) ;
238- ui. add_space ( 4.0 ) ;
239- for window_info in self . windows . lock ( ) . unwrap ( ) . iter_mut ( ) {
240- ui. style_mut ( ) . wrap_mode = Some ( egui:: TextWrapMode :: Truncate ) ; // elide with "…"
241- let checkbox_response =
242- ui. checkbox ( & mut window_info. hidden , & window_info. title ) ;
243- if checkbox_response. changed ( ) {
244- let event = if window_info. hidden {
245- InjectorWorkerEvent :: HIDE (
246- window_info. pid ,
247- window_info. hwnd ,
248- self . hide_from_taskbar ,
249- )
250- } else {
251- InjectorWorkerEvent :: SHOW (
252- window_info. pid ,
253- window_info. hwnd ,
254- self . hide_from_taskbar ,
255- )
256- } ;
257- self . event_sender . send ( event) . unwrap ( ) ;
249+ ui. add_space ( 14.0 ) ;
258250 }
259- }
260- ui. add_space ( 10.0 ) ;
261- ui. collapsing ( "Advanced settings" , |ui| {
262- ui. checkbox ( & mut self . hide_from_taskbar , "Hide from Alt+Tab and Taskbar" ) ;
263- let preview_checkbox_response =
264- ui. checkbox ( & mut self . show_desktop_preview , "Show desktop preview" ) ;
265- if preview_checkbox_response. changed ( ) {
266- let event = if self . show_desktop_preview {
267- CaptureWorkerEvent :: CAPTURE ( self . monitors [ self . active_monitor ] )
268- } else {
269- self . capture_tex = None ;
270- CaptureWorkerEvent :: NONE
271- } ;
272- self . capture_event_send . send ( event) . unwrap ( ) ;
251+
252+ Self :: add_section_header ( ui, "Hide applications" , "Select the windows to hide" ) ;
253+
254+ for window_info in self . windows . lock ( ) . unwrap ( ) . iter_mut ( ) {
255+ ui. style_mut ( ) . wrap_mode = Some ( egui:: TextWrapMode :: Truncate ) ; // elide with "…"
256+ let checkbox_response =
257+ ui. checkbox ( & mut window_info. hidden , & window_info. title ) ;
258+ if checkbox_response. changed ( ) {
259+ let event = if window_info. hidden {
260+ InjectorWorkerEvent :: HIDE (
261+ window_info. pid ,
262+ window_info. hwnd ,
263+ self . hide_from_taskbar ,
264+ )
265+ } else {
266+ InjectorWorkerEvent :: SHOW (
267+ window_info. pid ,
268+ window_info. hwnd ,
269+ self . hide_from_taskbar ,
270+ )
271+ } ;
272+ self . event_sender . send ( event) . unwrap ( ) ;
273+ }
273274 }
275+ ui. add_space ( 10.0 ) ;
276+ ui. collapsing ( "Advanced settings" , |ui| {
277+ ui. checkbox ( & mut self . hide_from_taskbar , "Hide from Alt+Tab and Taskbar" ) ;
278+ let preview_checkbox_response =
279+ ui. checkbox ( & mut self . show_desktop_preview , "Show desktop preview" ) ;
280+ if preview_checkbox_response. changed ( ) {
281+ let event = if self . show_desktop_preview {
282+ CaptureWorkerEvent :: CAPTURE ( self . monitors [ self . active_monitor ] )
283+ } else {
284+ self . capture_tex = None ;
285+ CaptureWorkerEvent :: NONE
286+ } ;
287+ self . capture_event_send . send ( event) . unwrap ( ) ;
288+ }
289+ } ) ;
274290 } ) ;
275291 } ) ;
276- } ) ;
277292 }
278293}
279294
@@ -306,6 +321,70 @@ pub fn start() {
306321 // This gives us image support:
307322 egui_extras:: install_image_loaders ( & cc. egui_ctx ) ;
308323
324+ let mut fonts = FontDefinitions :: default ( ) ;
325+
326+ fonts. font_data . insert (
327+ "Inter_18pt-Regular" . to_owned ( ) ,
328+ Arc :: new ( FontData :: from_static ( include_bytes ! (
329+ "../../Misc/fonts/Inter_18pt-Regular.ttf"
330+ ) ) ) ,
331+ ) ;
332+
333+ fonts. families . insert (
334+ FontFamily :: Name ( "Inter_18pt-Regular" . into ( ) ) ,
335+ vec ! [ "Inter_18pt-Regular" . to_owned( ) ] ,
336+ ) ;
337+
338+ fonts. font_data . insert (
339+ "Inter_18pt-Bold" . to_owned ( ) ,
340+ Arc :: new ( FontData :: from_static ( include_bytes ! (
341+ "../../Misc/fonts/Inter_18pt-Bold.ttf"
342+ ) ) ) ,
343+ ) ;
344+
345+ fonts. families . insert (
346+ FontFamily :: Name ( "Inter_18pt-Bold" . into ( ) ) ,
347+ vec ! [ "Inter_18pt-Bold" . to_owned( ) ] ,
348+ ) ;
349+
350+ cc. egui_ctx . set_fonts ( fonts) ;
351+
352+ cc. egui_ctx . all_styles_mut ( |style| {
353+ // no rounded checkboxes
354+ style. visuals . widgets . inactive . corner_radius = Default :: default ( ) ;
355+ style. visuals . widgets . hovered . corner_radius = Default :: default ( ) ;
356+ style. visuals . widgets . active . corner_radius = Default :: default ( ) ;
357+
358+ // we don't want strokes around checkboxes
359+ style. visuals . widgets . hovered . bg_stroke = Default :: default ( ) ;
360+ style. visuals . widgets . active . bg_stroke = Default :: default ( ) ;
361+
362+ // we don't want checkboxes or collapsibles to expand on hover/active state
363+ style. visuals . widgets . hovered . expansion = 0.0 ;
364+ style. visuals . widgets . active . expansion = 0.0 ;
365+
366+ // do not allow text to be selected
367+ style. interaction . selectable_labels = false ;
368+
369+ let mut text_styles = style. text_styles . clone ( ) ;
370+ text_styles. insert (
371+ TextStyle :: Body ,
372+ FontId {
373+ size : 12.0 ,
374+ family : egui:: FontFamily :: Name ( "Inter_18pt-Regular" . into ( ) ) ,
375+ } ,
376+ ) ;
377+
378+ text_styles. insert (
379+ TextStyle :: Heading ,
380+ FontId {
381+ size : 16.0 ,
382+ family : egui:: FontFamily :: Name ( "Inter_18pt-Bold" . into ( ) ) ,
383+ } ,
384+ ) ;
385+ style. text_styles = text_styles;
386+ } ) ;
387+
309388 Ok ( Box :: new ( Gui :: new ( ) ) )
310389 } ) ,
311390 )
0 commit comments