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,72 +278,93 @@ 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 ( ) ;
302+ style : & ' b <Renderer :: Theme as container:: StyleSheet >:: Style ,
303+ }
289304
290- if let Some ( cursor_position) = cursor. position_over ( bounds) {
291- let style = theme. appearance ( style) ;
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) ;
292318
293- let defaults = renderer:: Style {
294- text_color : style. text_color . unwrap_or ( inherited_style. text_color ) ,
295- } ;
319+ let gap = f32:: from ( self . gap ) ;
296320
297- let text_layout = layout_text (
321+ let text_layout = Widget :: < ( ) , Renderer > :: layout (
322+ self . tooltip ,
298323 renderer,
299324 & layout:: Limits :: new (
300325 Size :: ZERO ,
301- snap_within_viewport
326+ self . snap_within_viewport
302327 . then ( || viewport. size ( ) )
303328 . unwrap_or ( Size :: INFINITY ) ,
304329 )
305- . pad ( Padding :: new ( padding) ) ,
330+ . pad ( Padding :: new ( self . padding ) ) ,
306331 ) ;
307332
333+ let padding = f32:: from ( self . padding ) ;
334+
308335 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 ;
336+ let x_center = self . content_bounds . x
337+ + ( self . content_bounds . width - text_bounds. width ) / 2.0 ;
338+ let y_center = self . content_bounds . y
339+ + ( self . content_bounds . height - text_bounds. height ) / 2.0 ;
311340
312341 let mut tooltip_bounds = {
313- let offset = match position {
342+ let offset = match self . position {
314343 Position :: Top => Vector :: new (
315344 x_center,
316- bounds . y - text_bounds. height - gap - padding,
345+ self . content_bounds . y - text_bounds. height - gap - padding,
317346 ) ,
318347 Position :: Bottom => Vector :: new (
319348 x_center,
320- bounds. y + bounds. height + gap + padding,
349+ self . content_bounds . y
350+ + self . content_bounds . height
351+ + gap
352+ + padding,
321353 ) ,
322354 Position :: Left => Vector :: new (
323- bounds . x - text_bounds. width - gap - padding,
355+ self . content_bounds . x - text_bounds. width - gap - padding,
324356 y_center,
325357 ) ,
326358 Position :: Right => Vector :: new (
327- bounds. x + bounds. width + gap + padding,
359+ self . content_bounds . x
360+ + self . content_bounds . width
361+ + gap
362+ + padding,
328363 y_center,
329364 ) ,
330365 Position :: FollowCursor => Vector :: new (
331- cursor_position. x ,
332- cursor_position. y - text_bounds. height ,
366+ self . cursor_position . x ,
367+ self . cursor_position . y - text_bounds. height ,
333368 ) ,
334369 } ;
335370
@@ -341,7 +376,7 @@ pub fn draw<Renderer>(
341376 }
342377 } ;
343378
344- if snap_within_viewport {
379+ if self . snap_within_viewport {
345380 if tooltip_bounds. x < viewport. x {
346381 tooltip_bounds. x = viewport. x ;
347382 } else if viewport. x + viewport. width
@@ -361,21 +396,49 @@ pub fn draw<Renderer>(
361396 }
362397 }
363398
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- } ) ;
399+ layout:: Node :: with_children (
400+ tooltip_bounds. size ( ) ,
401+ vec ! [ text_layout. translate( Vector :: new( padding, padding) ) ] ,
402+ )
403+ . translate ( Vector :: new ( tooltip_bounds. x , tooltip_bounds. y ) )
404+ }
405+
406+ fn draw (
407+ & self ,
408+ renderer : & mut Renderer ,
409+ theme : & <Renderer as renderer:: Renderer >:: Theme ,
410+ inherited_style : & renderer:: Style ,
411+ layout : Layout < ' _ > ,
412+ cursor_position : mouse:: Cursor ,
413+ ) {
414+ let style = <Renderer :: Theme as container:: StyleSheet >:: appearance (
415+ theme, self . style ,
416+ ) ;
417+
418+ container:: draw_background ( renderer, & style, layout. bounds ( ) ) ;
419+
420+ let defaults = renderer:: Style {
421+ text_color : style. text_color . unwrap_or ( inherited_style. text_color ) ,
422+ } ;
423+
424+ Widget :: < ( ) , Renderer > :: draw (
425+ self . tooltip ,
426+ & widget:: Tree :: empty ( ) ,
427+ renderer,
428+ theme,
429+ & defaults,
430+ layout. children ( ) . next ( ) . unwrap ( ) ,
431+ cursor_position,
432+ & Rectangle :: with_size ( Size :: INFINITY ) ,
433+ ) ;
434+ }
435+
436+ fn is_over (
437+ & self ,
438+ _layout : Layout < ' _ > ,
439+ _renderer : & Renderer ,
440+ _cursor_position : Point ,
441+ ) -> bool {
442+ false
380443 }
381444}
0 commit comments