11//! Display a widget over another.
22use crate :: container;
3- use crate :: core;
43use crate :: core:: event:: { self , Event } ;
54use crate :: core:: layout:: { self , Layout } ;
65use crate :: core:: mouse;
76use crate :: core:: overlay;
87use crate :: core:: renderer;
98use crate :: core:: text;
10- use crate :: core:: widget:: Tree ;
9+ use crate :: core:: widget:: { self , Widget } ;
1110use crate :: core:: {
12- Clipboard , Element , Length , Padding , Pixels , Rectangle , Shell , Size ,
13- Vector , Widget ,
11+ Clipboard , Element , Length , Padding , Pixels , Point , Rectangle , Shell , Size ,
12+ Vector ,
1413} ;
1514use crate :: Text ;
1615
@@ -107,14 +106,22 @@ where
107106 Renderer : text:: Renderer ,
108107 Renderer :: Theme : container:: StyleSheet + crate :: text:: StyleSheet ,
109108{
110- fn children ( & self ) -> Vec < Tree > {
111- vec ! [ Tree :: new( & self . content) ]
109+ fn children ( & self ) -> Vec < widget :: Tree > {
110+ vec ! [ widget :: Tree :: new( & self . content) ]
112111 }
113112
114- fn diff ( & self , tree : & mut Tree ) {
113+ fn diff ( & self , tree : & mut widget :: Tree ) {
115114 tree. diff_children ( std:: slice:: from_ref ( & self . content ) )
116115 }
117116
117+ fn state ( & self ) -> widget:: tree:: State {
118+ widget:: tree:: State :: new ( State :: default ( ) )
119+ }
120+
121+ fn tag ( & self ) -> widget:: tree:: Tag {
122+ widget:: tree:: Tag :: of :: < State > ( )
123+ }
124+
118125 fn width ( & self ) -> Length {
119126 self . content . as_widget ( ) . width ( )
120127 }
@@ -133,14 +140,21 @@ where
133140
134141 fn on_event (
135142 & mut self ,
136- tree : & mut Tree ,
143+ tree : & mut widget :: Tree ,
137144 event : Event ,
138145 layout : Layout < ' _ > ,
139146 cursor : mouse:: Cursor ,
140147 renderer : & Renderer ,
141148 clipboard : & mut dyn Clipboard ,
142149 shell : & mut Shell < ' _ , Message > ,
143150 ) -> event:: Status {
151+ let state = tree. state . downcast_mut :: < State > ( ) ;
152+
153+ * state = cursor
154+ . position_over ( layout. bounds ( ) )
155+ . map ( |cursor_position| State :: Hovered { cursor_position } )
156+ . unwrap_or_default ( ) ;
157+
144158 self . content . as_widget_mut ( ) . on_event (
145159 & mut tree. children [ 0 ] ,
146160 event,
@@ -154,7 +168,7 @@ where
154168
155169 fn mouse_interaction (
156170 & self ,
157- tree : & Tree ,
171+ tree : & widget :: Tree ,
158172 layout : Layout < ' _ > ,
159173 cursor : mouse:: Cursor ,
160174 viewport : & Rectangle ,
@@ -171,7 +185,7 @@ where
171185
172186 fn draw (
173187 & self ,
174- tree : & Tree ,
188+ tree : & widget :: Tree ,
175189 renderer : & mut Renderer ,
176190 theme : & Renderer :: Theme ,
177191 inherited_style : & renderer:: Style ,
@@ -188,50 +202,50 @@ where
188202 cursor,
189203 viewport,
190204 ) ;
191-
192- let tooltip = & self . tooltip ;
193-
194- draw (
195- renderer,
196- theme,
197- inherited_style,
198- layout,
199- cursor,
200- viewport,
201- self . position ,
202- self . gap ,
203- self . padding ,
204- self . snap_within_viewport ,
205- & self . style ,
206- |renderer, limits| {
207- Widget :: < ( ) , Renderer > :: layout ( tooltip, renderer, limits)
208- } ,
209- |renderer, defaults, layout, viewport| {
210- Widget :: < ( ) , Renderer > :: draw (
211- tooltip,
212- & Tree :: empty ( ) ,
213- renderer,
214- theme,
215- defaults,
216- layout,
217- cursor,
218- viewport,
219- ) ;
220- } ,
221- ) ;
222205 }
223206
224207 fn overlay < ' b > (
225208 & ' b mut self ,
226- tree : & ' b mut Tree ,
209+ tree : & ' b mut widget :: Tree ,
227210 layout : Layout < ' _ > ,
228211 renderer : & Renderer ,
229212 ) -> Option < overlay:: Element < ' b , Message , Renderer > > {
230- self . content . as_widget_mut ( ) . overlay (
213+ let state = tree. state . downcast_ref :: < State > ( ) ;
214+
215+ let content = self . content . as_widget_mut ( ) . overlay (
231216 & mut tree. children [ 0 ] ,
232217 layout,
233218 renderer,
234- )
219+ ) ;
220+
221+ let tooltip = if let State :: Hovered { cursor_position } = * state {
222+ Some ( overlay:: Element :: new (
223+ layout. position ( ) ,
224+ Box :: new ( Overlay {
225+ tooltip : & self . tooltip ,
226+ cursor_position,
227+ content_bounds : layout. bounds ( ) ,
228+ snap_within_viewport : self . snap_within_viewport ,
229+ position : self . position ,
230+ gap : self . gap ,
231+ padding : self . padding ,
232+ style : & self . style ,
233+ } ) ,
234+ ) )
235+ } else {
236+ None
237+ } ;
238+
239+ if content. is_some ( ) || tooltip. is_some ( ) {
240+ Some (
241+ overlay:: Group :: with_children (
242+ content. into_iter ( ) . chain ( tooltip) . collect ( ) ,
243+ )
244+ . overlay ( ) ,
245+ )
246+ } else {
247+ None
248+ }
235249 }
236250}
237251
@@ -264,84 +278,107 @@ pub enum Position {
264278 Right ,
265279}
266280
267- /// Draws a [`Tooltip`].
268- pub fn draw < Renderer > (
269- renderer : & mut Renderer ,
270- theme : & Renderer :: Theme ,
271- inherited_style : & renderer:: Style ,
272- layout : Layout < ' _ > ,
273- cursor : mouse:: Cursor ,
274- viewport : & Rectangle ,
281+ #[ derive( Debug , Clone , Copy , Default ) ]
282+ enum State {
283+ #[ default]
284+ Idle ,
285+ Hovered {
286+ cursor_position : Point ,
287+ } ,
288+ }
289+
290+ struct Overlay < ' a , ' b , Renderer >
291+ where
292+ Renderer : text:: Renderer ,
293+ Renderer :: Theme : container:: StyleSheet + widget:: text:: StyleSheet ,
294+ {
295+ tooltip : & ' b Text < ' a , Renderer > ,
296+ cursor_position : Point ,
297+ content_bounds : Rectangle ,
298+ snap_within_viewport : bool ,
275299 position : Position ,
276300 gap : f32 ,
277301 padding : f32 ,
278- snap_within_viewport : bool ,
279- style : & <Renderer :: Theme as container:: StyleSheet >:: Style ,
280- layout_text : impl FnOnce ( & Renderer , & layout:: Limits ) -> layout:: Node ,
281- draw_text : impl FnOnce ( & mut Renderer , & renderer:: Style , Layout < ' _ > , & Rectangle ) ,
282- ) where
283- Renderer : core:: Renderer ,
284- Renderer :: Theme : container:: StyleSheet ,
285- {
286- use container:: StyleSheet ;
287-
288- let bounds = layout. bounds ( ) ;
289-
290- if let Some ( cursor_position) = cursor. position_over ( bounds) {
291- let style = theme. appearance ( style) ;
302+ style : & ' b <Renderer :: Theme as container:: StyleSheet >:: Style ,
303+ }
292304
293- let defaults = renderer:: Style {
294- text_color : style. text_color . unwrap_or ( inherited_style. text_color ) ,
295- } ;
305+ impl < ' a , ' b , Message , Renderer > overlay:: Overlay < Message , Renderer >
306+ for Overlay < ' a , ' b , Renderer >
307+ where
308+ Renderer : text:: Renderer ,
309+ Renderer :: Theme : container:: StyleSheet + widget:: text:: StyleSheet ,
310+ {
311+ fn layout (
312+ & self ,
313+ renderer : & Renderer ,
314+ bounds : Size ,
315+ _position : Point ,
316+ ) -> layout:: Node {
317+ let viewport = Rectangle :: with_size ( bounds) ;
296318
297- let text_layout = layout_text (
319+ let text_layout = Widget :: < ( ) , Renderer > :: layout (
320+ self . tooltip ,
298321 renderer,
299322 & layout:: Limits :: new (
300323 Size :: ZERO ,
301- snap_within_viewport
324+ self . snap_within_viewport
302325 . then ( || viewport. size ( ) )
303326 . unwrap_or ( Size :: INFINITY ) ,
304327 )
305- . pad ( Padding :: new ( padding) ) ,
328+ . pad ( Padding :: new ( self . padding ) ) ,
306329 ) ;
307330
308331 let text_bounds = text_layout. bounds ( ) ;
309- let x_center = bounds. x + ( bounds. width - text_bounds. width ) / 2.0 ;
310- let y_center = bounds. y + ( bounds. height - text_bounds. height ) / 2.0 ;
332+ let x_center = self . content_bounds . x
333+ + ( self . content_bounds . width - text_bounds. width ) / 2.0 ;
334+ let y_center = self . content_bounds . y
335+ + ( self . content_bounds . height - text_bounds. height ) / 2.0 ;
311336
312337 let mut tooltip_bounds = {
313- let offset = match position {
338+ let offset = match self . position {
314339 Position :: Top => Vector :: new (
315340 x_center,
316- bounds. y - text_bounds. height - gap - padding,
341+ self . content_bounds . y
342+ - text_bounds. height
343+ - self . gap
344+ - self . padding ,
317345 ) ,
318346 Position :: Bottom => Vector :: new (
319347 x_center,
320- bounds. y + bounds. height + gap + padding,
348+ self . content_bounds . y
349+ + self . content_bounds . height
350+ + self . gap
351+ + self . padding ,
321352 ) ,
322353 Position :: Left => Vector :: new (
323- bounds. x - text_bounds. width - gap - padding,
354+ self . content_bounds . x
355+ - text_bounds. width
356+ - self . gap
357+ - self . padding ,
324358 y_center,
325359 ) ,
326360 Position :: Right => Vector :: new (
327- bounds. x + bounds. width + gap + padding,
361+ self . content_bounds . x
362+ + self . content_bounds . width
363+ + self . gap
364+ + self . padding ,
328365 y_center,
329366 ) ,
330367 Position :: FollowCursor => Vector :: new (
331- cursor_position. x ,
332- cursor_position. y - text_bounds. height ,
368+ self . cursor_position . x ,
369+ self . cursor_position . y - text_bounds. height ,
333370 ) ,
334371 } ;
335372
336373 Rectangle {
337- x : offset. x - padding,
338- y : offset. y - padding,
339- width : text_bounds. width + padding * 2.0 ,
340- height : text_bounds. height + padding * 2.0 ,
374+ x : offset. x - self . padding ,
375+ y : offset. y - self . padding ,
376+ width : text_bounds. width + self . padding * 2.0 ,
377+ height : text_bounds. height + self . padding * 2.0 ,
341378 }
342379 } ;
343380
344- if snap_within_viewport {
381+ if self . snap_within_viewport {
345382 if tooltip_bounds. x < viewport. x {
346383 tooltip_bounds. x = viewport. x ;
347384 } else if viewport. x + viewport. width
@@ -361,21 +398,49 @@ pub fn draw<Renderer>(
361398 }
362399 }
363400
364- renderer. with_layer ( Rectangle :: with_size ( Size :: INFINITY ) , |renderer| {
365- container:: draw_background ( renderer, & style, tooltip_bounds) ;
366-
367- draw_text (
368- renderer,
369- & defaults,
370- Layout :: with_offset (
371- Vector :: new (
372- tooltip_bounds. x + padding,
373- tooltip_bounds. y + padding,
374- ) ,
375- & text_layout,
376- ) ,
377- viewport,
378- )
379- } ) ;
401+ layout:: Node :: with_children (
402+ tooltip_bounds. size ( ) ,
403+ vec ! [ text_layout. translate( Vector :: new( self . padding, self . padding) ) ] ,
404+ )
405+ . translate ( Vector :: new ( tooltip_bounds. x , tooltip_bounds. y ) )
406+ }
407+
408+ fn draw (
409+ & self ,
410+ renderer : & mut Renderer ,
411+ theme : & <Renderer as renderer:: Renderer >:: Theme ,
412+ inherited_style : & renderer:: Style ,
413+ layout : Layout < ' _ > ,
414+ cursor_position : mouse:: Cursor ,
415+ ) {
416+ let style = <Renderer :: Theme as container:: StyleSheet >:: appearance (
417+ theme, self . style ,
418+ ) ;
419+
420+ container:: draw_background ( renderer, & style, layout. bounds ( ) ) ;
421+
422+ let defaults = renderer:: Style {
423+ text_color : style. text_color . unwrap_or ( inherited_style. text_color ) ,
424+ } ;
425+
426+ Widget :: < ( ) , Renderer > :: draw (
427+ self . tooltip ,
428+ & widget:: Tree :: empty ( ) ,
429+ renderer,
430+ theme,
431+ & defaults,
432+ layout. children ( ) . next ( ) . unwrap ( ) ,
433+ cursor_position,
434+ & Rectangle :: with_size ( Size :: INFINITY ) ,
435+ ) ;
436+ }
437+
438+ fn is_over (
439+ & self ,
440+ _layout : Layout < ' _ > ,
441+ _renderer : & Renderer ,
442+ _cursor_position : Point ,
443+ ) -> bool {
444+ false
380445 }
381446}
0 commit comments