@@ -8,7 +8,11 @@ use cosmic::{
88 alignment, event,
99 layout:: { Layout , Limits , Node } ,
1010 mouse, overlay, renderer,
11- widget:: { operation:: Operation , tree:: Tree , Id , Widget } ,
11+ widget:: {
12+ operation:: Operation ,
13+ tree:: { self , Tree } ,
14+ Id , Widget ,
15+ } ,
1216 Border , Clipboard , Color , Length , Rectangle , Shell , Size ,
1317 } ,
1418 iced_widget:: scrollable:: AbsoluteOffset ,
@@ -53,46 +57,52 @@ impl From<TabRuleTheme> for theme::Rule {
5357
5458#[ derive( Clone , Copy ) ]
5559pub ( super ) enum TabBackgroundTheme {
60+ /// Selected active stack
5661 ActiveActivated ,
62+ /// Selected inactive stack
5763 ActiveDeactivated ,
64+ /// Not selected
5865 Default ,
5966}
6067
61- impl From < TabBackgroundTheme > for theme:: Container < ' _ > {
62- fn from ( background_theme : TabBackgroundTheme ) -> Self {
63- match background_theme {
64- TabBackgroundTheme :: ActiveActivated => {
65- Self :: custom ( move |theme| widget:: container:: Style {
66- icon_color : Some ( Color :: from ( theme. cosmic ( ) . accent_text_color ( ) ) ) ,
67- text_color : Some ( Color :: from ( theme. cosmic ( ) . accent_text_color ( ) ) ) ,
68- background : Some ( Background :: Color (
69- theme. cosmic ( ) . primary . component . selected . into ( ) ,
70- ) ) ,
71- border : Border {
72- radius : 0.0 . into ( ) ,
73- width : 0.0 ,
74- color : Color :: TRANSPARENT ,
75- } ,
76- shadow : Default :: default ( ) ,
77- } )
78- }
79- TabBackgroundTheme :: ActiveDeactivated => {
80- Self :: custom ( move |theme| widget:: container:: Style {
81- icon_color : None ,
82- text_color : None ,
83- background : Some ( Background :: Color (
84- theme. cosmic ( ) . primary . component . base . into ( ) ,
85- ) ) ,
86- border : Border {
87- radius : 0.0 . into ( ) ,
88- width : 0.0 ,
89- color : Color :: TRANSPARENT ,
90- } ,
91- shadow : Default :: default ( ) ,
92- } )
68+ impl TabBackgroundTheme {
69+ pub fn into_container_theme ( self , hovered : bool ) -> theme:: Container < ' static > {
70+ let ( selected, active_stack) = match self {
71+ Self :: ActiveActivated => ( true , true ) ,
72+ Self :: ActiveDeactivated => ( true , false ) ,
73+ Self :: Default => ( false , false ) ,
74+ } ;
75+
76+ theme:: Container :: custom ( move |theme| {
77+ let cosmic_theme = theme. cosmic ( ) ;
78+
79+ let text_color = if selected && active_stack {
80+ Some ( Color :: from ( cosmic_theme. accent_text_color ( ) ) )
81+ } else {
82+ None
83+ } ;
84+
85+ widget:: container:: Style {
86+ icon_color : text_color,
87+ text_color,
88+ background : Some ( Background :: Color (
89+ if hovered {
90+ cosmic_theme. primary . component . hover_state_color ( )
91+ } else if selected {
92+ cosmic_theme. primary . component . selected_state_color ( )
93+ } else {
94+ cosmic_theme. primary . component . base
95+ }
96+ . into ( ) ,
97+ ) ) ,
98+ border : Border {
99+ radius : 0.0 . into ( ) ,
100+ width : 0.0 ,
101+ color : Color :: TRANSPARENT ,
102+ } ,
103+ shadow : Default :: default ( ) ,
93104 }
94- TabBackgroundTheme :: Default => Self :: Transparent ,
95- }
105+ } )
96106 }
97107}
98108
@@ -105,6 +115,10 @@ pub trait TabMessage: Clone {
105115 fn scrolled ( ) -> Self ;
106116}
107117
118+ struct LocalState {
119+ hovered : bool ,
120+ }
121+
108122pub struct Tab < Message : TabMessage > {
109123 id : Id ,
110124 app_icon : Icon ,
@@ -209,7 +223,7 @@ impl<Message: TabMessage + 'static> Tab<Message> {
209223 id : self . id ,
210224 idx,
211225 active : self . active ,
212- background : self . background_theme . into ( ) ,
226+ background : self . background_theme ,
213227 elements : items,
214228 press_message : self . press_message ,
215229 right_click_message : self . right_click_message ,
@@ -228,7 +242,7 @@ pub(super) struct TabInternal<'a, Message: TabMessage> {
228242 id : Id ,
229243 idx : usize ,
230244 active : bool ,
231- background : theme :: Container < ' a > ,
245+ background : TabBackgroundTheme ,
232246 elements : Vec < cosmic:: Element < ' a , Message > > ,
233247 press_message : Option < Message > ,
234248 right_click_message : Option < Message > ,
@@ -258,6 +272,10 @@ where
258272 Size :: new ( Length :: Fill , Length :: Fill )
259273 }
260274
275+ fn state ( & self ) -> tree:: State {
276+ tree:: State :: new ( LocalState { hovered : false } )
277+ }
278+
261279 fn layout ( & self , tree : & mut Tree , renderer : & cosmic:: Renderer , limits : & Limits ) -> Node {
262280 let min_size = Size {
263281 height : TAB_HEIGHT as f32 ,
@@ -332,6 +350,9 @@ where
332350 shell : & mut Shell < ' _ , Message > ,
333351 viewport : & Rectangle ,
334352 ) -> event:: Status {
353+ let state = tree. state . downcast_mut :: < LocalState > ( ) ;
354+ state. hovered = cursor. is_over ( layout. bounds ( ) ) ;
355+
335356 let status = self
336357 . elements
337358 . iter_mut ( )
@@ -351,7 +372,7 @@ where
351372 } )
352373 . fold ( event:: Status :: Ignored , event:: Status :: merge) ;
353374
354- if status == event:: Status :: Ignored && cursor . is_over ( layout . bounds ( ) ) {
375+ if status == event:: Status :: Ignored && state . hovered {
355376 if matches ! (
356377 event,
357378 event:: Event :: Mouse ( mouse:: Event :: ButtonPressed ( mouse:: Button :: Left ) )
@@ -414,7 +435,10 @@ where
414435 viewport : & Rectangle ,
415436 ) {
416437 use cosmic:: widget:: container:: Catalog ;
417- let style = theme. style ( & self . background ) ;
438+ let state = tree. state . downcast_ref :: < LocalState > ( ) ;
439+
440+ let style = theme. style ( & self . background . into_container_theme ( state. hovered ) ) ;
441+ let text_color = style. text_color . unwrap_or ( renderer_style. text_color ) ;
418442
419443 draw_background ( renderer, & style, layout. bounds ( ) ) ;
420444
@@ -429,8 +453,8 @@ where
429453 renderer,
430454 theme,
431455 & renderer:: Style {
432- icon_color : style . text_color . unwrap_or ( renderer_style . text_color ) ,
433- text_color : style . text_color . unwrap_or ( renderer_style . text_color ) ,
456+ icon_color : text_color,
457+ text_color,
434458 scale_factor : renderer_style. scale_factor ,
435459 } ,
436460 layout,
0 commit comments