1use egui::{ecolor::*, CornerRadius, Margin, Stroke};
2
3#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
5#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
6#[allow(missing_docs)]
7pub enum TabAddAlign {
8 Left,
9 Right,
10}
11
12#[derive(Clone, Debug)]
49#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
50#[allow(missing_docs)]
51pub struct Style {
52 pub dock_area_padding: Option<Margin>,
54
55 pub main_surface_border_stroke: Stroke,
56 pub main_surface_border_rounding: CornerRadius,
57
58 pub buttons: ButtonsStyle,
59 pub separator: SeparatorStyle,
60 pub tab_bar: TabBarStyle,
61 pub tab: TabStyle,
62 pub overlay: OverlayStyle,
63}
64
65#[derive(Clone, Debug)]
67#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
68pub struct ButtonsStyle {
69 pub close_tab_color: Color32,
71
72 pub close_tab_active_color: Color32,
74
75 pub close_tab_bg_fill: Color32,
77
78 pub add_tab_align: TabAddAlign,
80
81 pub add_tab_color: Color32,
83
84 pub add_tab_active_color: Color32,
86
87 pub add_tab_bg_fill: Color32,
89
90 pub add_tab_border_color: Color32,
92
93 pub close_all_tabs_color: Color32,
95
96 pub close_all_tabs_active_color: Color32,
98
99 pub close_all_tabs_bg_fill: Color32,
101
102 pub close_all_tabs_border_color: Color32,
104
105 pub close_all_tabs_disabled_color: Color32,
107
108 pub collapse_tabs_color: Color32,
110
111 pub collapse_tabs_active_color: Color32,
113
114 pub collapse_tabs_bg_fill: Color32,
116
117 pub collapse_tabs_border_color: Color32,
119
120 pub minimize_window_color: Color32,
122
123 pub minimize_window_active_color: Color32,
125
126 pub minimize_window_bg_fill: Color32,
128
129 pub minimize_window_border_color: Color32,
131}
132
133#[derive(Clone, Debug)]
135#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
136pub struct SeparatorStyle {
137 pub width: f32,
139
140 pub extra_interact_width: f32,
143
144 pub extra: f32,
147
148 pub color_idle: Color32,
150
151 pub color_hovered: Color32,
153
154 pub color_dragged: Color32,
156}
157
158#[derive(Clone, Debug)]
160#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
161pub struct TabBarStyle {
162 pub bg_fill: Color32,
164
165 pub height: f32,
167
168 pub inner_margin: Margin,
170
171 pub show_scroll_bar_on_overflow: bool,
173
174 pub corner_radius: CornerRadius,
176
177 pub hline_color: Color32,
180
181 pub fill_tab_bar: bool,
184}
185
186#[derive(Clone, Debug)]
188#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
189pub struct TabStyle {
190 pub active: TabInteractionStyle,
192
193 pub inactive: TabInteractionStyle,
195
196 pub focused: TabInteractionStyle,
198
199 pub hovered: TabInteractionStyle,
201
202 pub inactive_with_kb_focus: TabInteractionStyle,
204
205 pub active_with_kb_focus: TabInteractionStyle,
207
208 pub focused_with_kb_focus: TabInteractionStyle,
210
211 pub tab_body: TabBodyStyle,
213
214 pub hline_below_active_tab_name: bool,
218
219 pub spacing: f32,
221
222 pub minimum_width: Option<f32>,
227}
228
229#[derive(Clone, Debug)]
231#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
232pub struct TabInteractionStyle {
233 pub outline_color: Color32,
235
236 pub corner_radius: CornerRadius,
238
239 pub bg_fill: Color32,
241
242 pub text_color: Color32,
244}
245
246#[derive(Clone, Debug)]
248#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
249pub struct TabBodyStyle {
250 pub inner_margin: Margin,
252
253 pub stroke: Stroke,
255
256 pub corner_radius: CornerRadius,
258
259 pub bg_fill: Color32,
261}
262
263#[derive(Clone, Debug)]
265#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
266pub struct OverlayStyle {
267 pub selection_color: Color32,
270
271 pub selection_stroke_width: f32,
273
274 pub button_spacing: f32,
276
277 pub max_button_size: f32,
279
280 pub hovered_leaf_highlight: LeafHighlighting,
284
285 pub surface_fade_opacity: f32,
287
288 pub button_color: Color32,
290
291 pub button_border_stroke: Stroke,
293
294 pub overlay_type: OverlayType,
296
297 pub feel: OverlayFeel,
299}
300
301#[derive(Clone, Debug)]
303#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
304pub struct OverlayFeel {
305 pub window_drop_coverage: f32,
307
308 pub center_drop_coverage: f32,
310
311 pub fade_hold_time: f32,
313
314 pub max_preference_time: f32,
316
317 pub interact_expansion: f32,
319}
320
321#[derive(Copy, Clone, Debug, PartialEq)]
323#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
324pub enum OverlayType {
325 HighlightedAreas,
329
330 Widgets,
334}
335
336#[derive(Clone, Debug)]
338#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
339pub struct LeafHighlighting {
340 pub color: Color32,
342
343 pub corner_radius: CornerRadius,
345
346 pub stroke: Stroke,
348
349 pub expansion: f32,
351}
352
353impl Default for Style {
354 fn default() -> Self {
355 Self {
356 dock_area_padding: None,
357 main_surface_border_stroke: Stroke::new(f32::default(), Color32::BLACK),
358 main_surface_border_rounding: CornerRadius::default(),
359 buttons: ButtonsStyle::default(),
360 separator: SeparatorStyle::default(),
361 tab_bar: TabBarStyle::default(),
362 tab: TabStyle::default(),
363 overlay: OverlayStyle::default(),
364 }
365 }
366}
367
368impl Default for ButtonsStyle {
369 fn default() -> Self {
370 Self {
371 close_tab_color: Color32::WHITE,
372 close_tab_active_color: Color32::WHITE,
373 close_tab_bg_fill: Color32::GRAY,
374
375 add_tab_align: TabAddAlign::Right,
376 add_tab_color: Color32::WHITE,
377 add_tab_active_color: Color32::WHITE,
378 add_tab_bg_fill: Color32::GRAY,
379 add_tab_border_color: Color32::BLACK,
380
381 close_all_tabs_color: Color32::WHITE,
382 close_all_tabs_active_color: Color32::WHITE,
383 close_all_tabs_bg_fill: Color32::GRAY,
384 close_all_tabs_border_color: Color32::BLACK,
385 close_all_tabs_disabled_color: Color32::LIGHT_GRAY,
386
387 collapse_tabs_color: Color32::WHITE,
388 collapse_tabs_active_color: Color32::WHITE,
389 collapse_tabs_bg_fill: Color32::GRAY,
390 collapse_tabs_border_color: Color32::BLACK,
391
392 minimize_window_color: Color32::WHITE,
393 minimize_window_active_color: Color32::WHITE,
394 minimize_window_bg_fill: Color32::GRAY,
395 minimize_window_border_color: Color32::BLACK,
396 }
397 }
398}
399
400impl Default for SeparatorStyle {
401 fn default() -> Self {
402 Self {
403 width: 1.0,
404 extra_interact_width: 2.0,
405 extra: 175.0,
406 color_idle: Color32::BLACK,
407 color_hovered: Color32::GRAY,
408 color_dragged: Color32::WHITE,
409 }
410 }
411}
412
413impl Default for TabBarStyle {
414 fn default() -> Self {
415 Self {
416 bg_fill: Color32::WHITE,
417 height: 24.0,
418 inner_margin: Margin::ZERO,
419 show_scroll_bar_on_overflow: true,
420 corner_radius: CornerRadius::default(),
421 hline_color: Color32::BLACK,
422 fill_tab_bar: false,
423 }
424 }
425}
426
427impl Default for TabStyle {
428 fn default() -> Self {
429 Self {
430 active: TabInteractionStyle::default(),
431 inactive: TabInteractionStyle {
432 text_color: Color32::DARK_GRAY,
433 ..Default::default()
434 },
435 focused: TabInteractionStyle {
436 text_color: Color32::BLACK,
437 ..Default::default()
438 },
439 hovered: TabInteractionStyle {
440 text_color: Color32::BLACK,
441 ..Default::default()
442 },
443 active_with_kb_focus: TabInteractionStyle::default(),
444 inactive_with_kb_focus: TabInteractionStyle {
445 text_color: Color32::DARK_GRAY,
446 ..Default::default()
447 },
448 focused_with_kb_focus: TabInteractionStyle {
449 text_color: Color32::BLACK,
450 ..Default::default()
451 },
452 spacing: 0.0,
453 tab_body: TabBodyStyle::default(),
454 hline_below_active_tab_name: false,
455 minimum_width: None,
456 }
457 }
458}
459
460impl Default for TabInteractionStyle {
461 fn default() -> Self {
462 Self {
463 bg_fill: Color32::WHITE,
464 outline_color: Color32::BLACK,
465 corner_radius: CornerRadius::default(),
466 text_color: Color32::DARK_GRAY,
467 }
468 }
469}
470
471impl Default for TabBodyStyle {
472 fn default() -> Self {
473 Self {
474 inner_margin: Margin::same(4),
475 stroke: Stroke::default(),
476 corner_radius: CornerRadius::default(),
477 bg_fill: Color32::WHITE,
478 }
479 }
480}
481
482impl Default for OverlayStyle {
483 fn default() -> Self {
484 Self {
485 selection_color: Color32::from_rgb(0, 191, 255).linear_multiply(0.5),
486 selection_stroke_width: 1.0,
487 button_spacing: 10.0,
488 max_button_size: 100.0,
489
490 surface_fade_opacity: 0.1,
491
492 hovered_leaf_highlight: Default::default(),
493 button_color: Color32::from_gray(140),
494 button_border_stroke: Stroke::new(1.0, Color32::from_gray(60)),
495 overlay_type: OverlayType::Widgets,
496 feel: Default::default(),
497 }
498 }
499}
500
501impl Default for OverlayFeel {
502 fn default() -> Self {
503 Self {
504 max_preference_time: 0.3,
505 window_drop_coverage: 0.5,
506 center_drop_coverage: 0.25,
507 fade_hold_time: 0.2,
508 interact_expansion: 20.0,
509 }
510 }
511}
512
513impl Default for LeafHighlighting {
514 fn default() -> Self {
515 Self {
516 color: Color32::TRANSPARENT,
517 corner_radius: CornerRadius::same(0),
518 stroke: Stroke::NONE,
519 expansion: 0.0,
520 }
521 }
522}
523
524impl Style {
525 pub(crate) const TAB_ADD_BUTTON_SIZE: f32 = 24.0;
526 pub(crate) const TAB_ADD_PLUS_SIZE: f32 = 12.0;
527 pub(crate) const TAB_CLOSE_BUTTON_SIZE: f32 = 24.0;
528 pub(crate) const TAB_CLOSE_X_SIZE: f32 = 9.0;
529 pub(crate) const TAB_CLOSE_ALL_BUTTON_SIZE: f32 = 24.0;
530 pub(crate) const TAB_CLOSE_ALL_SIZE: f32 = 10.0;
531 pub(crate) const TAB_COLLAPSE_BUTTON_SIZE: f32 = 24.0;
532 pub(crate) const TAB_COLLAPSE_ARROW_SIZE: f32 = 10.0;
533 pub(crate) const TAB_EXPAND_BUTTON_SIZE: f32 = 24.0;
534 pub(crate) const TAB_EXPAND_ARROW_SIZE: f32 = 10.0;
535}
536
537impl Style {
538 pub fn from_egui(style: &egui::Style) -> Self {
546 Self {
547 main_surface_border_stroke: Stroke::NONE,
548 main_surface_border_rounding: CornerRadius::ZERO,
549 buttons: ButtonsStyle::from_egui(style),
550 separator: SeparatorStyle::from_egui(style),
551 tab_bar: TabBarStyle::from_egui(style),
552 tab: TabStyle::from_egui(style),
553 overlay: OverlayStyle::from_egui(style),
554 ..Self::default()
555 }
556 }
557}
558
559impl ButtonsStyle {
560 pub fn from_egui(style: &egui::Style) -> Self {
579 Self {
580 close_tab_bg_fill: style.visuals.widgets.hovered.bg_fill,
581 close_tab_color: style.visuals.text_color(),
582 close_tab_active_color: style.visuals.strong_text_color(),
583 add_tab_bg_fill: style.visuals.widgets.hovered.bg_fill,
584 add_tab_color: style.visuals.text_color(),
585 add_tab_active_color: style.visuals.strong_text_color(),
586 add_tab_border_color: style.visuals.widgets.noninteractive.bg_fill,
587 close_all_tabs_bg_fill: style.visuals.widgets.hovered.bg_fill,
588 close_all_tabs_color: style.visuals.text_color(),
589 close_all_tabs_active_color: style.visuals.strong_text_color(),
590 close_all_tabs_border_color: style.visuals.widgets.noninteractive.bg_fill,
591 close_all_tabs_disabled_color: style.visuals.widgets.inactive.bg_fill,
592 collapse_tabs_bg_fill: style.visuals.widgets.hovered.bg_fill,
593 collapse_tabs_color: style.visuals.text_color(),
594 collapse_tabs_active_color: style.visuals.strong_text_color(),
595 collapse_tabs_border_color: style.visuals.widgets.noninteractive.bg_fill,
596 minimize_window_bg_fill: style.visuals.widgets.hovered.bg_fill,
597 minimize_window_color: style.visuals.text_color(),
598 minimize_window_active_color: style.visuals.strong_text_color(),
599 minimize_window_border_color: style.visuals.widgets.noninteractive.bg_fill,
600 ..ButtonsStyle::default()
601 }
602 }
603}
604
605impl SeparatorStyle {
606 pub fn from_egui(style: &egui::Style) -> Self {
613 Self {
614 color_idle: style.visuals.widgets.noninteractive.bg_stroke.color, color_hovered: style.visuals.widgets.hovered.fg_stroke.color, color_dragged: style.visuals.widgets.active.fg_stroke.color, ..SeparatorStyle::default()
619 }
620 }
621}
622
623impl TabBarStyle {
624 pub fn from_egui(style: &egui::Style) -> Self {
630 Self {
631 bg_fill: style.visuals.extreme_bg_color,
632 corner_radius: CornerRadius {
633 nw: style.visuals.widgets.inactive.corner_radius.nw + 2,
634 ne: style.visuals.widgets.inactive.corner_radius.ne + 2,
635 sw: 0,
636 se: 0,
637 },
638 hline_color: style.visuals.widgets.noninteractive.bg_stroke.color,
639 ..TabBarStyle::default()
640 }
641 }
642}
643
644impl TabStyle {
645 pub fn from_egui(style: &egui::Style) -> TabStyle {
650 Self {
651 active: TabInteractionStyle::from_egui_active(style),
652 inactive: TabInteractionStyle::from_egui_inactive(style),
653 focused: TabInteractionStyle::from_egui_focused(style),
654 hovered: TabInteractionStyle::from_egui_hovered(style),
655 active_with_kb_focus: TabInteractionStyle::from_egui_active_with_kb_focus(style),
656 inactive_with_kb_focus: TabInteractionStyle::from_egui_inactive_with_kb_focus(style),
657 focused_with_kb_focus: TabInteractionStyle::from_egui_focused_with_kb_focus(style),
658 tab_body: TabBodyStyle::from_egui(style),
659 ..Default::default()
660 }
661 }
662}
663
664impl TabInteractionStyle {
665 pub fn from_egui_active(style: &egui::Style) -> Self {
672 Self {
673 outline_color: style.visuals.widgets.noninteractive.bg_stroke.color,
674 bg_fill: style.visuals.window_fill(),
675 text_color: style.visuals.text_color(),
676 corner_radius: CornerRadius {
677 sw: 0,
678 se: 0,
679 ..style.visuals.widgets.active.corner_radius
680 },
681 }
682 }
683
684 pub fn from_egui_inactive(style: &egui::Style) -> Self {
691 Self {
692 text_color: style.visuals.text_color(),
693 bg_fill: tint_color_towards(style.visuals.window_fill, style.visuals.extreme_bg_color),
694 outline_color: tint_color_towards(
695 style.visuals.widgets.noninteractive.bg_stroke.color,
696 style.visuals.extreme_bg_color,
697 ),
698 ..TabInteractionStyle::from_egui_active(style)
699 }
700 }
701
702 pub fn from_egui_focused(style: &egui::Style) -> Self {
709 Self {
710 text_color: style.visuals.strong_text_color(),
711 ..TabInteractionStyle::from_egui_active(style)
712 }
713 }
714
715 pub fn from_egui_hovered(style: &egui::Style) -> Self {
722 Self {
723 text_color: style.visuals.strong_text_color(),
724 outline_color: style.visuals.widgets.hovered.bg_stroke.color,
725 ..TabInteractionStyle::from_egui_inactive(style)
726 }
727 }
728
729 pub fn from_egui_active_with_kb_focus(style: &egui::Style) -> Self {
736 Self {
737 text_color: style.visuals.strong_text_color(),
738 outline_color: style.visuals.widgets.hovered.bg_stroke.color,
739 ..TabInteractionStyle::from_egui_active(style)
740 }
741 }
742
743 pub fn from_egui_inactive_with_kb_focus(style: &egui::Style) -> Self {
750 Self {
751 text_color: style.visuals.strong_text_color(),
752 outline_color: style.visuals.widgets.hovered.bg_stroke.color,
753 ..TabInteractionStyle::from_egui_inactive(style)
754 }
755 }
756
757 pub fn from_egui_focused_with_kb_focus(style: &egui::Style) -> Self {
764 Self {
765 text_color: style.visuals.strong_text_color(),
766 outline_color: style.visuals.widgets.hovered.bg_stroke.color,
767 ..TabInteractionStyle::from_egui_focused(style)
768 }
769 }
770}
771
772impl TabBodyStyle {
773 pub fn from_egui(style: &egui::Style) -> Self {
780 Self {
781 inner_margin: style.spacing.window_margin,
782 stroke: style.visuals.widgets.noninteractive.bg_stroke,
783 corner_radius: style.visuals.widgets.active.corner_radius,
784 bg_fill: style.visuals.window_fill(),
785 }
786 }
787}
788
789impl OverlayStyle {
790 pub fn from_egui(style: &egui::Style) -> Self {
798 Self {
799 selection_color: style.visuals.selection.bg_fill.linear_multiply(0.5),
800 button_spacing: style.spacing.icon_spacing,
801 button_color: style.visuals.widgets.noninteractive.fg_stroke.color,
802 button_border_stroke: style.visuals.widgets.noninteractive.bg_stroke,
803 ..Default::default()
804 }
805 }
806}