Skip to main content

BorderColor

Struct BorderColor 

Source
pub struct BorderColor {
    pub top: Color,
    pub right: Color,
    pub bottom: Color,
    pub left: Color,
}
Available on crate feature bevy_ui only.
Expand description

The border color of the UI node.

Fields§

§top: Color§right: Color§bottom: Color§left: Color

Implementations§

Source§

impl BorderColor

Source

pub const DEFAULT: BorderColor

Border color is transparent by default.

Source

pub fn all(color: impl Into<Color>) -> BorderColor

Helper to create a BorderColor struct with all borders set to the given color

Examples found in repository?
examples/ui/navigation/directional_navigation.rs (line 452)
445fn highlight_focused_element(
446    input_focus: Res<InputFocus>,
447    input_focus_visible: Res<InputFocusVisible>,
448    mut query: Query<(Entity, &mut BorderColor)>,
449) {
450    for (entity, mut border_color) in query.iter_mut() {
451        if input_focus.get() == Some(entity) && input_focus_visible.0 {
452            *border_color = BorderColor::all(FOCUSED_BORDER);
453        } else {
454            *border_color = BorderColor::DEFAULT;
455        }
456    }
457}
More examples
Hide additional examples
examples/ui/navigation/directional_navigation_overrides.rs (line 795)
788fn highlight_focused_element(
789    input_focus: Res<InputFocus>,
790    input_focus_visible: Res<InputFocusVisible>,
791    mut query: Query<(Entity, &mut BorderColor, &Page)>,
792) {
793    for (entity, mut border_color, page) in query.iter_mut() {
794        if input_focus.get() == Some(entity) && input_focus_visible.0 {
795            *border_color = BorderColor::all(FOCUSED_BORDER_COLORS[page.0]);
796        } else {
797            *border_color = BorderColor::DEFAULT;
798        }
799    }
800}
examples/showcase/mines.rs (line 199)
189fn text_button(label: &'static str, action: ButtonAction) -> impl Bundle {
190    (
191        action,
192        Node {
193            min_width: px(144),
194            border: px(3).all(),
195            border_radius: px(8).into(),
196            box_sizing: BoxSizing::ContentBox,
197            ..default()
198        },
199        BorderColor::all(TILE_BORDER_COLOR),
200        BackgroundColor(BACKGROUND_COLOR),
201        Text::new(label),
202        TextFont::from_font_size(24.0),
203        TextLayout::justify(Justify::Center),
204        LineHeight::Px(40.),
205    )
206}
207
208fn setup(mut commands: Commands) {
209    commands.spawn(Camera2d);
210}
211
212fn setup_menu(mut commands: Commands) {
213    commands.spawn((
214        DespawnOnExit(GameState::Menu),
215        Node {
216            width: percent(100),
217            height: percent(100),
218            flex_direction: FlexDirection::Column,
219            justify_content: JustifyContent::Center,
220            align_items: AlignItems::Center,
221            row_gap: px(20),
222            ..default()
223        },
224        children![
225            (Text::new("Bevy Mines"), TextFont::from_font_size(35.0)),
226            (
227                Node {
228                    flex_direction: FlexDirection::Column,
229                    row_gap: px(10),
230                    ..default()
231                },
232                children![
233                    text_button("easy", ButtonAction::NewGame(Difficulty::Easy)),
234                    text_button("normal", ButtonAction::NewGame(Difficulty::Normal)),
235                    text_button("hard", ButtonAction::NewGame(Difficulty::Hard)),
236                ],
237            ),
238        ],
239    ));
240}
241
242fn setup_game(mut commands: Commands, game: Res<Game>, assets: Res<AssetServer>) {
243    let root = commands
244        .spawn((
245            GameRoot,
246            DespawnOnExit(GameState::Playing),
247            Node {
248                margin: auto().all(),
249                ..default()
250            },
251        ))
252        .id();
253
254    rebuild_game_ui(&mut commands, root, &game, &assets);
255}
256
257fn rebuild_game_ui(commands: &mut Commands, root: Entity, game: &Game, assets: &AssetServer) {
258    commands.entity(root).despawn_related::<Children>();
259
260    commands.entity(root).with_children(|parent| {
261        parent
262            .spawn(Node {
263                flex_direction: FlexDirection::Column,
264                row_gap: px(20),
265                ..default()
266            })
267            .with_children(|parent| {
268                parent
269                    .spawn((
270                        Node {
271                            display: Display::Grid,
272                            padding: UiRect::all(px(BOARD_PADDING)),
273                            border_radius: BorderRadius::all(px(25)),
274                            row_gap: px(TILE_GAP),
275                            column_gap: px(TILE_GAP),
276                            grid_template_columns: RepeatedGridTrack::px(
277                                game.field.width,
278                                TILE_SIZE,
279                            ),
280                            grid_template_rows: RepeatedGridTrack::px(game.field.height, TILE_SIZE),
281                            ..default()
282                        },
283                        BackgroundColor(BACKGROUND_COLOR),
284                    ))
285                    .with_children(|parent| {
286                        for (position, tile) in game.field.iter() {
287                            let tile_node = Node {
288                                grid_column: GridPlacement::start((position.x + 1) as i16),
289                                grid_row: GridPlacement::start((position.y + 1) as i16),
290                                border: px(4).all(),
291                                border_radius: px(8).into(),
292                                justify_content: JustifyContent::Center,
293                                align_items: AlignItems::Center,
294                                ..default()
295                            };
296
297                            if game.game_over && tile.mined {
298                                parent.spawn((
299                                    tile_node,
300                                    BackgroundColor(BACKGROUND_COLOR),
301                                    BorderColor::all(Color::NONE),
302                                    Pickable::IGNORE,
303                                    children![(
304                                        Text::new("*"),
305                                        TextFont::from_font_size(24.0),
306                                        TextColor(MOST_DANGER_COLOR),
307                                    )],
308                                ));
309                            } else if game.game_over || tile.revealed {
310                                let mine_count = game.field.count_adjacent_mines(position);
311                                let color = match mine_count {
312                                    0 => continue,
313                                    1 => MILD_DANGER_COLOR,
314                                    2 => SOME_DANGER_COLOR,
315                                    3 => VERY_DANGER_COLOR,
316                                    _ => MOST_DANGER_COLOR,
317                                };
318                                parent.spawn((
319                                    tile_node,
320                                    BackgroundColor(BACKGROUND_COLOR),
321                                    BorderColor::all(color),
322                                    Pickable::IGNORE,
323                                    children![(
324                                        Text::new(mine_count.to_string()),
325                                        TextFont::from_font_size(20.0),
326                                        TextColor(color),
327                                    )],
328                                ));
329                            } else {
330                                parent
331                                    .spawn((
332                                        tile_node,
333                                        TileCell(position),
334                                        BackgroundColor(BACKGROUND_COLOR),
335                                        BorderColor::all(TILE_BORDER_COLOR),
336                                    ))
337                                    .with_children(|parent| {
338                                        if tile.flagged {
339                                            parent.spawn((
340                                                ImageNode::new(assets.load("textures/flag.png")),
341                                                Node {
342                                                    width: px(20),
343                                                    height: px(20),
344                                                    ..default()
345                                                },
346                                                Pickable::IGNORE,
347                                            ));
348                                        }
349                                    });
350                            }
351                        }
352                    });
353
354                parent
355                    .spawn(Node {
356                        width: percent(100),
357                        height: px(50),
358                        margin: px(15).vertical(),
359                        justify_content: JustifyContent::SpaceBetween,
360                        align_items: AlignItems::Center,
361                        ..default()
362                    })
363                    .with_children(|parent| {
364                        parent.spawn((
365                            Node {
366                                align_items: AlignItems::Center,
367                                column_gap: px(3),
368                                ..default()
369                            },
370                            children![
371                                (
372                                    ImageNode::new(assets.load("textures/flag.png")),
373                                    Node {
374                                        width: px(28),
375                                        height: px(28),
376                                        ..default()
377                                    },
378                                    Pickable::IGNORE,
379                                ),
380                                (
381                                    Text::new(
382                                        (game.field.mine_count() - game.field.flag_count())
383                                            .to_string()
384                                    ),
385                                    TextFont::from_font_size(24.0),
386                                )
387                            ],
388                        ));
389
390                        if game.field.is_cleared() || game.game_over {
391                            parent.spawn((
392                                Node {
393                                    width: percent(100),
394                                    height: percent(100),
395                                    position_type: PositionType::Absolute,
396                                    justify_content: JustifyContent::Center,
397                                    align_items: AlignItems::Center,
398                                    ..default()
399                                },
400                                Pickable::IGNORE,
401                                children![(
402                                    Text::new(if game.field.is_cleared() {
403                                        "mines cleared!"
404                                    } else {
405                                        "boom!"
406                                    }),
407                                    TextFont::from_font_size(24.0),
408                                )],
409                            ));
410
411                            parent.spawn(text_button("new game", ButtonAction::Menu));
412                        }
413                    });
414            });
415    });
416}
examples/ui/widgets/standard_widgets.rs (line 207)
192fn button(asset_server: &AssetServer) -> impl Bundle {
193    (
194        Node {
195            width: px(150),
196            height: px(65),
197            border: UiRect::all(px(5)),
198            border_radius: BorderRadius::MAX,
199            justify_content: JustifyContent::Center,
200            align_items: AlignItems::Center,
201            ..default()
202        },
203        DemoButton,
204        Button,
205        Hovered::default(),
206        TabIndex(0),
207        BorderColor::all(Color::BLACK),
208        BackgroundColor(NORMAL_BUTTON),
209        children![(
210            Text::new("Button"),
211            TextFont {
212                font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
213                font_size: FontSize::Px(33.0),
214                ..default()
215            },
216            TextColor(Color::srgb(0.9, 0.9, 0.9)),
217            TextShadow::default(),
218        )],
219    )
220}
221
222fn menu_button(asset_server: &AssetServer) -> impl Bundle {
223    (
224        Node { ..default() },
225        DemoMenuAnchor,
226        observe(on_menu_event),
227        children![(
228            Node {
229                width: px(200),
230                height: px(65),
231                border: UiRect::all(px(5)),
232                box_sizing: BoxSizing::BorderBox,
233                justify_content: JustifyContent::SpaceBetween,
234                align_items: AlignItems::Center,
235                padding: UiRect::axes(px(16), px(0)),
236                border_radius: BorderRadius::all(px(5)),
237                ..default()
238            },
239            DemoMenuButton,
240            Button,
241            MenuButton,
242            Hovered::default(),
243            TabIndex(0),
244            BorderColor::all(Color::BLACK),
245            BackgroundColor(NORMAL_BUTTON),
246            children![
247                (
248                    Text::new("Menu"),
249                    TextFont {
250                        font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
251                        font_size: FontSize::Px(33.0),
252                        ..default()
253                    },
254                    TextColor(Color::srgb(0.9, 0.9, 0.9)),
255                    TextShadow::default(),
256                ),
257                (
258                    Node {
259                        width: px(12),
260                        height: px(12),
261                        ..default()
262                    },
263                    BackgroundColor(GRAY.into()),
264                )
265            ],
266        )],
267    )
268}
269
270fn update_button_style(
271    mut buttons: Query<
272        (
273            Has<Pressed>,
274            &Hovered,
275            Has<InteractionDisabled>,
276            &mut BackgroundColor,
277            &mut BorderColor,
278            &Children,
279        ),
280        (
281            Or<(
282                Changed<Pressed>,
283                Changed<Hovered>,
284                Added<InteractionDisabled>,
285            )>,
286            With<DemoButton>,
287        ),
288    >,
289    mut text_query: Query<&mut Text>,
290) {
291    for (pressed, hovered, disabled, mut color, mut border_color, children) in &mut buttons {
292        let mut text = text_query.get_mut(children[0]).unwrap();
293        set_button_style(
294            disabled,
295            hovered.get(),
296            pressed,
297            &mut color,
298            &mut border_color,
299            &mut text,
300        );
301    }
302}
303
304/// Supplementary system to detect removed marker components
305fn update_button_style2(
306    mut buttons: Query<
307        (
308            Has<Pressed>,
309            &Hovered,
310            Has<InteractionDisabled>,
311            &mut BackgroundColor,
312            &mut BorderColor,
313            &Children,
314        ),
315        With<DemoButton>,
316    >,
317    mut removed_depressed: RemovedComponents<Pressed>,
318    mut removed_disabled: RemovedComponents<InteractionDisabled>,
319    mut text_query: Query<&mut Text>,
320) {
321    removed_depressed
322        .read()
323        .chain(removed_disabled.read())
324        .for_each(|entity| {
325            if let Ok((pressed, hovered, disabled, mut color, mut border_color, children)) =
326                buttons.get_mut(entity)
327            {
328                let mut text = text_query.get_mut(children[0]).unwrap();
329                set_button_style(
330                    disabled,
331                    hovered.get(),
332                    pressed,
333                    &mut color,
334                    &mut border_color,
335                    &mut text,
336                );
337            }
338        });
339}
340
341fn set_button_style(
342    disabled: bool,
343    hovered: bool,
344    pressed: bool,
345    color: &mut BackgroundColor,
346    border_color: &mut BorderColor,
347    text: &mut Text,
348) {
349    match (disabled, hovered, pressed) {
350        // Disabled button
351        (true, _, _) => {
352            **text = "Disabled".to_string();
353            *color = NORMAL_BUTTON.into();
354            border_color.set_all(GRAY);
355        }
356
357        // Pressed and hovered button
358        (false, true, true) => {
359            **text = "Press".to_string();
360            *color = PRESSED_BUTTON.into();
361            border_color.set_all(RED);
362        }
363
364        // Hovered, unpressed button
365        (false, true, false) => {
366            **text = "Hover".to_string();
367            *color = HOVERED_BUTTON.into();
368            border_color.set_all(WHITE);
369        }
370
371        // Unhovered button (either pressed or not).
372        (false, false, _) => {
373            **text = "Button".to_string();
374            *color = NORMAL_BUTTON.into();
375            border_color.set_all(BLACK);
376        }
377    }
378}
379
380/// Create a demo slider
381fn slider(min: f32, max: f32, value: f32) -> impl Bundle {
382    (
383        Node {
384            display: Display::Flex,
385            flex_direction: FlexDirection::Column,
386            justify_content: JustifyContent::Center,
387            align_items: AlignItems::Stretch,
388            justify_items: JustifyItems::Center,
389            column_gap: px(4),
390            height: px(12),
391            width: percent(30),
392            ..default()
393        },
394        Name::new("Slider"),
395        Hovered::default(),
396        DemoSlider,
397        Slider {
398            track_click: TrackClick::Snap,
399            ..Default::default()
400        },
401        SliderValue(value),
402        SliderRange::new(min, max),
403        TabIndex(0),
404        Children::spawn((
405            // Slider background rail
406            Spawn((
407                Node {
408                    height: px(6),
409                    border_radius: BorderRadius::all(px(3)),
410                    ..default()
411                },
412                BackgroundColor(SLIDER_TRACK), // Border color for the slider
413            )),
414            // Invisible track to allow absolute placement of thumb entity. This is narrower than
415            // the actual slider, which allows us to position the thumb entity using simple
416            // percentages, without having to measure the actual width of the slider thumb.
417            Spawn((
418                Node {
419                    display: Display::Flex,
420                    position_type: PositionType::Absolute,
421                    left: px(0),
422                    // Track is short by 12px to accommodate the thumb.
423                    right: px(12),
424                    top: px(0),
425                    bottom: px(0),
426                    ..default()
427                },
428                children![(
429                    // Thumb
430                    DemoSliderThumb,
431                    SliderThumb,
432                    Node {
433                        display: Display::Flex,
434                        width: px(12),
435                        height: px(12),
436                        position_type: PositionType::Absolute,
437                        left: percent(0), // This will be updated by the slider's value
438                        border_radius: BorderRadius::MAX,
439                        ..default()
440                    },
441                    BackgroundColor(SLIDER_THUMB),
442                )],
443            )),
444        )),
445    )
446}
447
448/// Update the visuals of the slider based on the slider state.
449fn update_slider_style(
450    sliders: Query<
451        (
452            Entity,
453            &SliderValue,
454            &SliderRange,
455            &Hovered,
456            &SliderDragState,
457            Has<InteractionDisabled>,
458        ),
459        (
460            Or<(
461                Changed<SliderValue>,
462                Changed<SliderRange>,
463                Changed<Hovered>,
464                Changed<SliderDragState>,
465                Added<InteractionDisabled>,
466            )>,
467            With<DemoSlider>,
468        ),
469    >,
470    children: Query<&Children>,
471    mut thumbs: Query<(&mut Node, &mut BackgroundColor, Has<DemoSliderThumb>), Without<DemoSlider>>,
472) {
473    for (slider_ent, value, range, hovered, drag_state, disabled) in sliders.iter() {
474        for child in children.iter_descendants(slider_ent) {
475            if let Ok((mut thumb_node, mut thumb_bg, is_thumb)) = thumbs.get_mut(child)
476                && is_thumb
477            {
478                thumb_node.left = percent(range.thumb_position(value.0) * 100.0);
479                thumb_bg.0 = thumb_color(disabled, hovered.0 | drag_state.dragging);
480            }
481        }
482    }
483}
484
485fn update_slider_style2(
486    sliders: Query<
487        (Entity, &Hovered, &SliderDragState, Has<InteractionDisabled>),
488        With<DemoSlider>,
489    >,
490    children: Query<&Children>,
491    mut thumbs: Query<(&mut BackgroundColor, Has<DemoSliderThumb>), Without<DemoSlider>>,
492    mut removed_disabled: RemovedComponents<InteractionDisabled>,
493) {
494    removed_disabled.read().for_each(|entity| {
495        if let Ok((slider_ent, hovered, drag_state, disabled)) = sliders.get(entity) {
496            for child in children.iter_descendants(slider_ent) {
497                if let Ok((mut thumb_bg, is_thumb)) = thumbs.get_mut(child)
498                    && is_thumb
499                {
500                    thumb_bg.0 = thumb_color(disabled, hovered.0 | drag_state.dragging);
501                }
502            }
503        }
504    });
505}
506
507fn thumb_color(disabled: bool, hovered: bool) -> Color {
508    match (disabled, hovered) {
509        (true, _) => ELEMENT_FILL_DISABLED,
510
511        (false, true) => SLIDER_THUMB.lighter(0.3),
512
513        _ => SLIDER_THUMB,
514    }
515}
516
517/// Create a demo checkbox
518fn checkbox(asset_server: &AssetServer, caption: &str) -> impl Bundle {
519    (
520        Node {
521            display: Display::Flex,
522            flex_direction: FlexDirection::Row,
523            justify_content: JustifyContent::FlexStart,
524            align_items: AlignItems::Center,
525            align_content: AlignContent::Center,
526            column_gap: px(4),
527            ..default()
528        },
529        Name::new("Checkbox"),
530        Hovered::default(),
531        DemoCheckbox,
532        Checkbox,
533        TabIndex(0),
534        Children::spawn((
535            Spawn((
536                // Checkbox outer
537                Node {
538                    display: Display::Flex,
539                    width: px(16),
540                    height: px(16),
541                    border: UiRect::all(px(2)),
542                    border_radius: BorderRadius::all(px(3)),
543                    ..default()
544                },
545                BorderColor::all(ELEMENT_OUTLINE), // Border color for the checkbox
546                children![
547                    // Checkbox inner
548                    (
549                        Node {
550                            display: Display::Flex,
551                            width: px(8),
552                            height: px(8),
553                            position_type: PositionType::Absolute,
554                            left: px(2),
555                            top: px(2),
556                            ..default()
557                        },
558                        BackgroundColor(ELEMENT_FILL),
559                    ),
560                ],
561            )),
562            Spawn((
563                Text::new(caption),
564                TextFont {
565                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
566                    font_size: FontSize::Px(20.0),
567                    ..default()
568                },
569            )),
570        )),
571    )
572}
573
574// Update the element's styles.
575fn update_checkbox_or_radio_style(
576    mut q_checkbox: Query<
577        (Has<Checked>, &Hovered, Has<InteractionDisabled>, &Children),
578        (
579            Or<(With<DemoCheckbox>, With<DemoRadio>)>,
580            Or<(
581                Added<DemoCheckbox>,
582                Changed<Hovered>,
583                Added<Checked>,
584                Added<InteractionDisabled>,
585            )>,
586        ),
587    >,
588    mut q_border_color: Query<
589        (&mut BorderColor, &mut Children),
590        (Without<DemoCheckbox>, Without<DemoRadio>),
591    >,
592    mut q_bg_color: Query<&mut BackgroundColor, (Without<DemoCheckbox>, Without<Children>)>,
593) {
594    for (checked, Hovered(is_hovering), is_disabled, children) in q_checkbox.iter_mut() {
595        let Some(border_id) = children.first() else {
596            continue;
597        };
598
599        let Ok((mut border_color, border_children)) = q_border_color.get_mut(*border_id) else {
600            continue;
601        };
602
603        let Some(mark_id) = border_children.first() else {
604            warn!("Checkbox does not have a mark entity.");
605            continue;
606        };
607
608        let Ok(mut mark_bg) = q_bg_color.get_mut(*mark_id) else {
609            warn!("Checkbox mark entity lacking a background color.");
610            continue;
611        };
612
613        set_checkbox_or_radio_style(
614            is_disabled,
615            *is_hovering,
616            checked,
617            &mut border_color,
618            &mut mark_bg,
619        );
620    }
621}
622
623fn update_checkbox_or_radio_style2(
624    mut q_checkbox: Query<
625        (Has<Checked>, &Hovered, Has<InteractionDisabled>, &Children),
626        Or<(With<DemoCheckbox>, With<DemoRadio>)>,
627    >,
628    mut q_border_color: Query<
629        (&mut BorderColor, &mut Children),
630        (Without<DemoCheckbox>, Without<DemoRadio>),
631    >,
632    mut q_bg_color: Query<
633        &mut BackgroundColor,
634        (Without<DemoCheckbox>, Without<DemoRadio>, Without<Children>),
635    >,
636    mut removed_checked: RemovedComponents<Checked>,
637    mut removed_disabled: RemovedComponents<InteractionDisabled>,
638) {
639    removed_checked
640        .read()
641        .chain(removed_disabled.read())
642        .for_each(|entity| {
643            if let Ok((checked, Hovered(is_hovering), is_disabled, children)) =
644                q_checkbox.get_mut(entity)
645            {
646                let Some(border_id) = children.first() else {
647                    return;
648                };
649
650                let Ok((mut border_color, border_children)) = q_border_color.get_mut(*border_id)
651                else {
652                    return;
653                };
654
655                let Some(mark_id) = border_children.first() else {
656                    warn!("Checkbox does not have a mark entity.");
657                    return;
658                };
659
660                let Ok(mut mark_bg) = q_bg_color.get_mut(*mark_id) else {
661                    warn!("Checkbox mark entity lacking a background color.");
662                    return;
663                };
664
665                set_checkbox_or_radio_style(
666                    is_disabled,
667                    *is_hovering,
668                    checked,
669                    &mut border_color,
670                    &mut mark_bg,
671                );
672            }
673        });
674}
675
676fn set_checkbox_or_radio_style(
677    disabled: bool,
678    hovering: bool,
679    checked: bool,
680    border_color: &mut BorderColor,
681    mark_bg: &mut BackgroundColor,
682) {
683    let color: Color = if disabled {
684        // If the element is disabled, use a lighter color
685        ELEMENT_OUTLINE.with_alpha(0.2)
686    } else if hovering {
687        // If hovering, use a lighter color
688        ELEMENT_OUTLINE.lighter(0.2)
689    } else {
690        // Default color for the element
691        ELEMENT_OUTLINE
692    };
693
694    // Update the background color of the element
695    border_color.set_all(color);
696
697    let mark_color: Color = match (disabled, checked) {
698        (true, true) => ELEMENT_FILL_DISABLED,
699        (false, true) => ELEMENT_FILL,
700        (_, false) => Srgba::NONE.into(),
701    };
702
703    if mark_bg.0 != mark_color {
704        // Update the color of the element
705        mark_bg.0 = mark_color;
706    }
707}
708
709/// Create a demo radio group
710fn radio_group(asset_server: &AssetServer) -> impl Bundle {
711    (
712        Node {
713            display: Display::Flex,
714            flex_direction: FlexDirection::Column,
715            align_items: AlignItems::Start,
716            column_gap: px(4),
717            ..default()
718        },
719        Name::new("RadioGroup"),
720        RadioGroup,
721        TabIndex::default(),
722        children![
723            (radio(asset_server, TrackClick::Drag, "Slider Drag"),),
724            (radio(asset_server, TrackClick::Step, "Slider Step"),),
725            (radio(asset_server, TrackClick::Snap, "Slider Snap"),)
726        ],
727    )
728}
729
730/// Create a demo radio button
731fn radio(asset_server: &AssetServer, value: TrackClick, caption: &str) -> impl Bundle {
732    (
733        Node {
734            display: Display::Flex,
735            flex_direction: FlexDirection::Row,
736            justify_content: JustifyContent::FlexStart,
737            align_items: AlignItems::Center,
738            align_content: AlignContent::Center,
739            column_gap: px(4),
740            ..default()
741        },
742        Name::new("RadioButton"),
743        Hovered::default(),
744        DemoRadio(value),
745        RadioButton,
746        Children::spawn((
747            Spawn((
748                // Radio outer
749                Node {
750                    display: Display::Flex,
751                    width: px(16),
752                    height: px(16),
753                    border: UiRect::all(px(2)),
754                    border_radius: BorderRadius::MAX,
755                    ..default()
756                },
757                BorderColor::all(ELEMENT_OUTLINE), // Border color for the radio button
758                children![
759                    // Radio inner
760                    (
761                        Node {
762                            display: Display::Flex,
763                            width: px(8),
764                            height: px(8),
765                            position_type: PositionType::Absolute,
766                            left: px(2),
767                            top: px(2),
768                            border_radius: BorderRadius::MAX,
769                            ..default()
770                        },
771                        BackgroundColor(ELEMENT_FILL),
772                    ),
773                ],
774            )),
775            Spawn((
776                Text::new(caption),
777                TextFont {
778                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
779                    font_size: FontSize::Px(20.0),
780                    ..default()
781                },
782            )),
783        )),
784    )
785}
786
787fn on_menu_event(
788    menu_event: On<MenuEvent>,
789    q_anchor: Single<(Entity, &Children), With<DemoMenuAnchor>>,
790    q_popup: Query<Entity, With<MenuPopup>>,
791    assets: Res<AssetServer>,
792    mut focus: ResMut<InputFocus>,
793    mut commands: Commands,
794) {
795    let (anchor, children) = q_anchor.into_inner();
796    let popup = children.iter().find_map(|c| q_popup.get(c).ok());
797    info!("Menu action: {:?}", menu_event.action);
798    match menu_event.action {
799        MenuAction::Open(_) => {
800            if popup.is_none() {
801                spawn_menu(anchor, assets, commands);
802            }
803        }
804        MenuAction::Toggle => match popup {
805            Some(popup) => commands.entity(popup).despawn(),
806            None => spawn_menu(anchor, assets, commands),
807        },
808        MenuAction::CloseAll => {
809            if let Some(popup) = popup {
810                commands.entity(popup).despawn();
811            }
812        }
813        MenuAction::FocusRoot => {
814            focus.set(anchor, FocusCause::Navigated);
815        }
816    }
817}
818
819fn spawn_menu(anchor: Entity, assets: Res<AssetServer>, mut commands: Commands) {
820    let menu = commands
821        .spawn((
822            Node {
823                display: Display::Flex,
824                flex_direction: FlexDirection::Column,
825                min_height: px(10.),
826                min_width: percent(100),
827                border: UiRect::all(px(1)),
828                position_type: PositionType::Absolute,
829                ..default()
830            },
831            MenuPopup::default(),
832            BorderColor::all(GREEN),
833            BackgroundColor(GRAY.into()),
834            BoxShadow::new(
835                Srgba::BLACK.with_alpha(0.9).into(),
836                px(0),
837                px(0),
838                px(1),
839                px(4),
840            ),
841            GlobalZIndex(100),
842            Popover {
843                positions: vec![
844                    PopoverPlacement {
845                        side: PopoverSide::Bottom,
846                        align: PopoverAlign::Start,
847                        gap: 2.0,
848                    },
849                    PopoverPlacement {
850                        side: PopoverSide::Top,
851                        align: PopoverAlign::Start,
852                        gap: 2.0,
853                    },
854                ],
855                window_margin: 10.0,
856            },
857            OverrideClip,
858            children![
859                menu_item(&assets),
860                menu_item(&assets),
861                menu_item(&assets),
862                menu_item(&assets)
863            ],
864        ))
865        .id();
866    commands.entity(anchor).add_child(menu);
867}
examples/ui/widgets/standard_widgets_observers.rs (line 139)
124fn button(asset_server: &AssetServer) -> impl Bundle {
125    (
126        Node {
127            width: px(150),
128            height: px(65),
129            border: UiRect::all(px(5)),
130            justify_content: JustifyContent::Center,
131            align_items: AlignItems::Center,
132            border_radius: BorderRadius::MAX,
133            ..default()
134        },
135        DemoButton,
136        Button,
137        Hovered::default(),
138        TabIndex(0),
139        BorderColor::all(Color::BLACK),
140        BackgroundColor(NORMAL_BUTTON),
141        children![(
142            Text::new("Button"),
143            TextFont {
144                font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
145                font_size: FontSize::Px(33.0),
146                ..default()
147            },
148            TextColor(Color::srgb(0.9, 0.9, 0.9)),
149            TextShadow::default(),
150        )],
151    )
152}
153
154fn button_on_interaction<E: EventPattern<Event: EntityEvent>>(
155    event: On<E>,
156    mut buttons: Query<
157        (
158            &Hovered,
159            Has<InteractionDisabled>,
160            Has<Pressed>,
161            &mut BackgroundColor,
162            &mut BorderColor,
163            &Children,
164        ),
165        With<DemoButton>,
166    >,
167    mut text_query: Query<&mut Text>,
168) {
169    if let Ok((hovered, disabled, pressed, mut color, mut border_color, children)) =
170        buttons.get_mut(event.event_target())
171    {
172        if children.is_empty() {
173            return;
174        }
175        let Ok(mut text) = text_query.get_mut(children[0]) else {
176            return;
177        };
178        let hovered = hovered.get();
179        // These "removal event checks" exist because the `Remove` event is triggered _before_ the component is actually
180        // removed, meaning it still shows up in the query. We're investigating the best way to improve this scenario.
181        let pressed = pressed && !(E::Event::is::<RemoveEvent>() && E::Components::is::<Pressed>());
182        let disabled = disabled
183            && !(E::Event::is::<RemoveEvent>() && E::Components::is::<InteractionDisabled>());
184        match (disabled, hovered, pressed) {
185            // Disabled button
186            (true, _, _) => {
187                **text = "Disabled".to_string();
188                *color = NORMAL_BUTTON.into();
189                border_color.set_all(GRAY);
190            }
191
192            // Pressed and hovered button
193            (false, true, true) => {
194                **text = "Press".to_string();
195                *color = PRESSED_BUTTON.into();
196                border_color.set_all(RED);
197            }
198
199            // Hovered, unpressed button
200            (false, true, false) => {
201                **text = "Hover".to_string();
202                *color = HOVERED_BUTTON.into();
203                border_color.set_all(WHITE);
204            }
205
206            // Unhovered button (either pressed or not).
207            (false, false, _) => {
208                **text = "Button".to_string();
209                *color = NORMAL_BUTTON.into();
210                border_color.set_all(BLACK);
211            }
212        }
213    }
214}
215
216/// Create a demo slider
217fn slider(min: f32, max: f32, value: f32) -> impl Bundle {
218    (
219        Node {
220            display: Display::Flex,
221            flex_direction: FlexDirection::Column,
222            justify_content: JustifyContent::Center,
223            align_items: AlignItems::Stretch,
224            justify_items: JustifyItems::Center,
225            column_gap: px(4),
226            height: px(12),
227            width: percent(30),
228            ..default()
229        },
230        Name::new("Slider"),
231        Hovered::default(),
232        DemoSlider,
233        Slider::default(),
234        SliderValue(value),
235        SliderRange::new(min, max),
236        TabIndex(0),
237        Children::spawn((
238            // Slider background rail
239            Spawn((
240                Node {
241                    height: px(6),
242                    border_radius: BorderRadius::all(px(3)),
243                    ..default()
244                },
245                BackgroundColor(SLIDER_TRACK), // Border color for the checkbox
246            )),
247            // Invisible track to allow absolute placement of thumb entity. This is narrower than
248            // the actual slider, which allows us to position the thumb entity using simple
249            // percentages, without having to measure the actual width of the slider thumb.
250            Spawn((
251                Node {
252                    display: Display::Flex,
253                    position_type: PositionType::Absolute,
254                    left: px(0),
255                    // Track is short by 12px to accommodate the thumb.
256                    right: px(12),
257                    top: px(0),
258                    bottom: px(0),
259                    ..default()
260                },
261                children![(
262                    // Thumb
263                    DemoSliderThumb,
264                    SliderThumb,
265                    Node {
266                        display: Display::Flex,
267                        width: px(12),
268                        height: px(12),
269                        position_type: PositionType::Absolute,
270                        left: percent(0), // This will be updated by the slider's value
271                        border_radius: BorderRadius::MAX,
272                        ..default()
273                    },
274                    BackgroundColor(SLIDER_THUMB),
275                )],
276            )),
277        )),
278    )
279}
280
281fn slider_on_interaction<E: EventPattern<Event: EntityEvent>>(
282    event: On<E>,
283    sliders: Query<(Entity, &Hovered, Has<InteractionDisabled>), With<DemoSlider>>,
284    children: Query<&Children>,
285    mut thumbs: Query<(&mut BackgroundColor, Has<DemoSliderThumb>), Without<DemoSlider>>,
286) {
287    if let Ok((slider_ent, hovered, disabled)) = sliders.get(event.event_target()) {
288        // These "removal event checks" exist because the `Remove` event is triggered _before_ the component is actually
289        // removed, meaning it still shows up in the query. We're investigating the best way to improve this scenario.
290        let disabled = disabled
291            && !(E::Event::is::<RemoveEvent>() && E::Components::is::<InteractionDisabled>());
292        for child in children.iter_descendants(slider_ent) {
293            if let Ok((mut thumb_bg, is_thumb)) = thumbs.get_mut(child)
294                && is_thumb
295            {
296                thumb_bg.0 = thumb_color(disabled, hovered.0);
297            }
298        }
299    }
300}
301
302fn slider_on_change_value<C: Component>(
303    insert: On<Insert<C>>,
304    sliders: Query<(Entity, &SliderValue, &SliderRange), With<DemoSlider>>,
305    children: Query<&Children>,
306    mut thumbs: Query<(&mut Node, Has<DemoSliderThumb>), Without<DemoSlider>>,
307) {
308    if let Ok((slider_ent, value, range)) = sliders.get(insert.entity) {
309        for child in children.iter_descendants(slider_ent) {
310            if let Ok((mut thumb_node, is_thumb)) = thumbs.get_mut(child)
311                && is_thumb
312            {
313                thumb_node.left = percent(range.thumb_position(value.0) * 100.0);
314            }
315        }
316    }
317}
318
319fn thumb_color(disabled: bool, hovered: bool) -> Color {
320    match (disabled, hovered) {
321        (true, _) => GRAY.into(),
322
323        (false, true) => SLIDER_THUMB.lighter(0.3),
324
325        _ => SLIDER_THUMB,
326    }
327}
328
329/// Create a demo checkbox
330fn checkbox(asset_server: &AssetServer, caption: &str) -> impl Bundle {
331    (
332        Node {
333            display: Display::Flex,
334            flex_direction: FlexDirection::Row,
335            justify_content: JustifyContent::FlexStart,
336            align_items: AlignItems::Center,
337            align_content: AlignContent::Center,
338            column_gap: px(4),
339            ..default()
340        },
341        Name::new("Checkbox"),
342        Hovered::default(),
343        DemoCheckbox,
344        Checkbox,
345        TabIndex(0),
346        Children::spawn((
347            Spawn((
348                // Checkbox outer
349                Node {
350                    display: Display::Flex,
351                    width: px(16),
352                    height: px(16),
353                    border: UiRect::all(px(2)),
354                    border_radius: BorderRadius::all(px(3)),
355                    ..default()
356                },
357                BorderColor::all(CHECKBOX_OUTLINE), // Border color for the checkbox
358                children![
359                    // Checkbox inner
360                    (
361                        Node {
362                            display: Display::Flex,
363                            width: px(8),
364                            height: px(8),
365                            position_type: PositionType::Absolute,
366                            left: px(2),
367                            top: px(2),
368                            ..default()
369                        },
370                        BackgroundColor(Srgba::NONE.into()),
371                    ),
372                ],
373            )),
374            Spawn((
375                Text::new(caption),
376                TextFont {
377                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
378                    font_size: FontSize::Px(20.0),
379                    ..default()
380                },
381            )),
382        )),
383    )
384}
examples/animation/animation_graph.rs (line 357)
345fn setup_node_lines(commands: &mut Commands) {
346    for line in &HORIZONTAL_LINES {
347        commands.spawn((
348            Node {
349                position_type: PositionType::Absolute,
350                bottom: px(line.bottom),
351                left: px(line.left),
352                height: px(0),
353                width: px(line.length),
354                border: UiRect::bottom(px(1)),
355                ..default()
356            },
357            BorderColor::all(WHITE),
358        ));
359    }
360
361    for line in &VERTICAL_LINES {
362        commands.spawn((
363            Node {
364                position_type: PositionType::Absolute,
365                bottom: px(line.bottom),
366                left: px(line.left),
367                height: px(line.length),
368                width: px(0),
369                border: UiRect::left(px(1)),
370                ..default()
371            },
372            BorderColor::all(WHITE),
373        ));
374    }
375}
Source

pub fn set_all(&mut self, color: impl Into<Color>) -> &mut BorderColor

Helper to set all border colors to a given color.

Examples found in repository?
examples/showcase/mines.rs (line 449)
444fn on_button_over(
445    over: On<PointerOver>,
446    mut buttons: Query<(&mut BorderColor, &mut BackgroundColor), With<ButtonAction>>,
447) {
448    if let Ok((mut border, mut background)) = buttons.get_mut(over.event_target()) {
449        border.set_all(HOVERED_TILE_BORDER_COLOR);
450        background.0 = BACKGROUND_COLOR;
451    }
452}
453
454fn on_button_out(
455    out: On<PointerOut>,
456    mut buttons: Query<(&mut BorderColor, &mut BackgroundColor), With<ButtonAction>>,
457) {
458    if let Ok((mut border, mut background)) = buttons.get_mut(out.event_target()) {
459        border.set_all(TILE_BORDER_COLOR);
460        background.0 = BACKGROUND_COLOR;
461    }
462}
463
464fn on_tile_over(over: On<PointerOver>, mut tiles: Query<&mut BorderColor, With<TileCell>>) {
465    if let Ok(mut border) = tiles.get_mut(over.event_target()) {
466        border.set_all(HOVERED_TILE_BORDER_COLOR);
467    }
468}
469
470fn on_tile_out(out: On<PointerOut>, mut tiles: Query<&mut BorderColor, With<TileCell>>) {
471    if let Ok(mut border) = tiles.get_mut(out.event_target()) {
472        border.set_all(TILE_BORDER_COLOR);
473    }
474}
More examples
Hide additional examples
examples/ui/text/multiple_text_inputs.rs (line 374)
351fn update_row_border_colors(
352    input_focus: Res<InputFocus>,
353    input_rows: Query<&TextInputRow, With<EditableText>>,
354    mut row_borders: Query<(&TextInputRow, &mut BorderColor, Has<EditableText>)>,
355) {
356    if !input_focus.is_changed() {
357        return;
358    }
359
360    let focused_row = input_focus
361        .get()
362        .and_then(|focused_entity| input_rows.get(focused_entity).ok())
363        .map(|row| row.0);
364
365    for (row, mut border_color, is_input) in &mut row_borders {
366        let mut color = if is_input {
367            SLATE_300.into()
368        } else {
369            Color::WHITE
370        };
371        if Some(row.0) != focused_row {
372            color = color.darker(0.75);
373        }
374        border_color.set_all(color);
375    }
376}
examples/ui/widgets/headless_tabs.rs (lines 204-208)
182fn update_tab_styles(
183    focus: Res<InputFocus>,
184    focus_visible: Res<InputFocusVisible>,
185    mut tabs: Query<
186        (
187            Entity,
188            &Hovered,
189            Has<Selected>,
190            Has<InteractionDisabled>,
191            &mut BackgroundColor,
192            &mut BorderColor,
193        ),
194        With<ShowcaseTab>,
195    >,
196) {
197    for (entity, hovered, selected, disabled, mut background, mut border) in &mut tabs {
198        background.0 = match (disabled, selected, hovered.get()) {
199            (true, _, _) => Color::srgb(0.10, 0.10, 0.11),
200            (false, true, _) => Color::srgb(0.18, 0.34, 0.52),
201            (false, false, true) => Color::srgb(0.20, 0.21, 0.26),
202            _ => Color::srgb(0.13, 0.14, 0.18),
203        };
204        border.set_all(if focus_visible.0 && focus.get() == Some(entity) {
205            Color::srgb(0.45, 0.78, 1.0)
206        } else {
207            Color::srgb(0.24, 0.25, 0.30)
208        });
209    }
210}
examples/ui/widgets/standard_widgets.rs (line 354)
341fn set_button_style(
342    disabled: bool,
343    hovered: bool,
344    pressed: bool,
345    color: &mut BackgroundColor,
346    border_color: &mut BorderColor,
347    text: &mut Text,
348) {
349    match (disabled, hovered, pressed) {
350        // Disabled button
351        (true, _, _) => {
352            **text = "Disabled".to_string();
353            *color = NORMAL_BUTTON.into();
354            border_color.set_all(GRAY);
355        }
356
357        // Pressed and hovered button
358        (false, true, true) => {
359            **text = "Press".to_string();
360            *color = PRESSED_BUTTON.into();
361            border_color.set_all(RED);
362        }
363
364        // Hovered, unpressed button
365        (false, true, false) => {
366            **text = "Hover".to_string();
367            *color = HOVERED_BUTTON.into();
368            border_color.set_all(WHITE);
369        }
370
371        // Unhovered button (either pressed or not).
372        (false, false, _) => {
373            **text = "Button".to_string();
374            *color = NORMAL_BUTTON.into();
375            border_color.set_all(BLACK);
376        }
377    }
378}
379
380/// Create a demo slider
381fn slider(min: f32, max: f32, value: f32) -> impl Bundle {
382    (
383        Node {
384            display: Display::Flex,
385            flex_direction: FlexDirection::Column,
386            justify_content: JustifyContent::Center,
387            align_items: AlignItems::Stretch,
388            justify_items: JustifyItems::Center,
389            column_gap: px(4),
390            height: px(12),
391            width: percent(30),
392            ..default()
393        },
394        Name::new("Slider"),
395        Hovered::default(),
396        DemoSlider,
397        Slider {
398            track_click: TrackClick::Snap,
399            ..Default::default()
400        },
401        SliderValue(value),
402        SliderRange::new(min, max),
403        TabIndex(0),
404        Children::spawn((
405            // Slider background rail
406            Spawn((
407                Node {
408                    height: px(6),
409                    border_radius: BorderRadius::all(px(3)),
410                    ..default()
411                },
412                BackgroundColor(SLIDER_TRACK), // Border color for the slider
413            )),
414            // Invisible track to allow absolute placement of thumb entity. This is narrower than
415            // the actual slider, which allows us to position the thumb entity using simple
416            // percentages, without having to measure the actual width of the slider thumb.
417            Spawn((
418                Node {
419                    display: Display::Flex,
420                    position_type: PositionType::Absolute,
421                    left: px(0),
422                    // Track is short by 12px to accommodate the thumb.
423                    right: px(12),
424                    top: px(0),
425                    bottom: px(0),
426                    ..default()
427                },
428                children![(
429                    // Thumb
430                    DemoSliderThumb,
431                    SliderThumb,
432                    Node {
433                        display: Display::Flex,
434                        width: px(12),
435                        height: px(12),
436                        position_type: PositionType::Absolute,
437                        left: percent(0), // This will be updated by the slider's value
438                        border_radius: BorderRadius::MAX,
439                        ..default()
440                    },
441                    BackgroundColor(SLIDER_THUMB),
442                )],
443            )),
444        )),
445    )
446}
447
448/// Update the visuals of the slider based on the slider state.
449fn update_slider_style(
450    sliders: Query<
451        (
452            Entity,
453            &SliderValue,
454            &SliderRange,
455            &Hovered,
456            &SliderDragState,
457            Has<InteractionDisabled>,
458        ),
459        (
460            Or<(
461                Changed<SliderValue>,
462                Changed<SliderRange>,
463                Changed<Hovered>,
464                Changed<SliderDragState>,
465                Added<InteractionDisabled>,
466            )>,
467            With<DemoSlider>,
468        ),
469    >,
470    children: Query<&Children>,
471    mut thumbs: Query<(&mut Node, &mut BackgroundColor, Has<DemoSliderThumb>), Without<DemoSlider>>,
472) {
473    for (slider_ent, value, range, hovered, drag_state, disabled) in sliders.iter() {
474        for child in children.iter_descendants(slider_ent) {
475            if let Ok((mut thumb_node, mut thumb_bg, is_thumb)) = thumbs.get_mut(child)
476                && is_thumb
477            {
478                thumb_node.left = percent(range.thumb_position(value.0) * 100.0);
479                thumb_bg.0 = thumb_color(disabled, hovered.0 | drag_state.dragging);
480            }
481        }
482    }
483}
484
485fn update_slider_style2(
486    sliders: Query<
487        (Entity, &Hovered, &SliderDragState, Has<InteractionDisabled>),
488        With<DemoSlider>,
489    >,
490    children: Query<&Children>,
491    mut thumbs: Query<(&mut BackgroundColor, Has<DemoSliderThumb>), Without<DemoSlider>>,
492    mut removed_disabled: RemovedComponents<InteractionDisabled>,
493) {
494    removed_disabled.read().for_each(|entity| {
495        if let Ok((slider_ent, hovered, drag_state, disabled)) = sliders.get(entity) {
496            for child in children.iter_descendants(slider_ent) {
497                if let Ok((mut thumb_bg, is_thumb)) = thumbs.get_mut(child)
498                    && is_thumb
499                {
500                    thumb_bg.0 = thumb_color(disabled, hovered.0 | drag_state.dragging);
501                }
502            }
503        }
504    });
505}
506
507fn thumb_color(disabled: bool, hovered: bool) -> Color {
508    match (disabled, hovered) {
509        (true, _) => ELEMENT_FILL_DISABLED,
510
511        (false, true) => SLIDER_THUMB.lighter(0.3),
512
513        _ => SLIDER_THUMB,
514    }
515}
516
517/// Create a demo checkbox
518fn checkbox(asset_server: &AssetServer, caption: &str) -> impl Bundle {
519    (
520        Node {
521            display: Display::Flex,
522            flex_direction: FlexDirection::Row,
523            justify_content: JustifyContent::FlexStart,
524            align_items: AlignItems::Center,
525            align_content: AlignContent::Center,
526            column_gap: px(4),
527            ..default()
528        },
529        Name::new("Checkbox"),
530        Hovered::default(),
531        DemoCheckbox,
532        Checkbox,
533        TabIndex(0),
534        Children::spawn((
535            Spawn((
536                // Checkbox outer
537                Node {
538                    display: Display::Flex,
539                    width: px(16),
540                    height: px(16),
541                    border: UiRect::all(px(2)),
542                    border_radius: BorderRadius::all(px(3)),
543                    ..default()
544                },
545                BorderColor::all(ELEMENT_OUTLINE), // Border color for the checkbox
546                children![
547                    // Checkbox inner
548                    (
549                        Node {
550                            display: Display::Flex,
551                            width: px(8),
552                            height: px(8),
553                            position_type: PositionType::Absolute,
554                            left: px(2),
555                            top: px(2),
556                            ..default()
557                        },
558                        BackgroundColor(ELEMENT_FILL),
559                    ),
560                ],
561            )),
562            Spawn((
563                Text::new(caption),
564                TextFont {
565                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
566                    font_size: FontSize::Px(20.0),
567                    ..default()
568                },
569            )),
570        )),
571    )
572}
573
574// Update the element's styles.
575fn update_checkbox_or_radio_style(
576    mut q_checkbox: Query<
577        (Has<Checked>, &Hovered, Has<InteractionDisabled>, &Children),
578        (
579            Or<(With<DemoCheckbox>, With<DemoRadio>)>,
580            Or<(
581                Added<DemoCheckbox>,
582                Changed<Hovered>,
583                Added<Checked>,
584                Added<InteractionDisabled>,
585            )>,
586        ),
587    >,
588    mut q_border_color: Query<
589        (&mut BorderColor, &mut Children),
590        (Without<DemoCheckbox>, Without<DemoRadio>),
591    >,
592    mut q_bg_color: Query<&mut BackgroundColor, (Without<DemoCheckbox>, Without<Children>)>,
593) {
594    for (checked, Hovered(is_hovering), is_disabled, children) in q_checkbox.iter_mut() {
595        let Some(border_id) = children.first() else {
596            continue;
597        };
598
599        let Ok((mut border_color, border_children)) = q_border_color.get_mut(*border_id) else {
600            continue;
601        };
602
603        let Some(mark_id) = border_children.first() else {
604            warn!("Checkbox does not have a mark entity.");
605            continue;
606        };
607
608        let Ok(mut mark_bg) = q_bg_color.get_mut(*mark_id) else {
609            warn!("Checkbox mark entity lacking a background color.");
610            continue;
611        };
612
613        set_checkbox_or_radio_style(
614            is_disabled,
615            *is_hovering,
616            checked,
617            &mut border_color,
618            &mut mark_bg,
619        );
620    }
621}
622
623fn update_checkbox_or_radio_style2(
624    mut q_checkbox: Query<
625        (Has<Checked>, &Hovered, Has<InteractionDisabled>, &Children),
626        Or<(With<DemoCheckbox>, With<DemoRadio>)>,
627    >,
628    mut q_border_color: Query<
629        (&mut BorderColor, &mut Children),
630        (Without<DemoCheckbox>, Without<DemoRadio>),
631    >,
632    mut q_bg_color: Query<
633        &mut BackgroundColor,
634        (Without<DemoCheckbox>, Without<DemoRadio>, Without<Children>),
635    >,
636    mut removed_checked: RemovedComponents<Checked>,
637    mut removed_disabled: RemovedComponents<InteractionDisabled>,
638) {
639    removed_checked
640        .read()
641        .chain(removed_disabled.read())
642        .for_each(|entity| {
643            if let Ok((checked, Hovered(is_hovering), is_disabled, children)) =
644                q_checkbox.get_mut(entity)
645            {
646                let Some(border_id) = children.first() else {
647                    return;
648                };
649
650                let Ok((mut border_color, border_children)) = q_border_color.get_mut(*border_id)
651                else {
652                    return;
653                };
654
655                let Some(mark_id) = border_children.first() else {
656                    warn!("Checkbox does not have a mark entity.");
657                    return;
658                };
659
660                let Ok(mut mark_bg) = q_bg_color.get_mut(*mark_id) else {
661                    warn!("Checkbox mark entity lacking a background color.");
662                    return;
663                };
664
665                set_checkbox_or_radio_style(
666                    is_disabled,
667                    *is_hovering,
668                    checked,
669                    &mut border_color,
670                    &mut mark_bg,
671                );
672            }
673        });
674}
675
676fn set_checkbox_or_radio_style(
677    disabled: bool,
678    hovering: bool,
679    checked: bool,
680    border_color: &mut BorderColor,
681    mark_bg: &mut BackgroundColor,
682) {
683    let color: Color = if disabled {
684        // If the element is disabled, use a lighter color
685        ELEMENT_OUTLINE.with_alpha(0.2)
686    } else if hovering {
687        // If hovering, use a lighter color
688        ELEMENT_OUTLINE.lighter(0.2)
689    } else {
690        // Default color for the element
691        ELEMENT_OUTLINE
692    };
693
694    // Update the background color of the element
695    border_color.set_all(color);
696
697    let mark_color: Color = match (disabled, checked) {
698        (true, true) => ELEMENT_FILL_DISABLED,
699        (false, true) => ELEMENT_FILL,
700        (_, false) => Srgba::NONE.into(),
701    };
702
703    if mark_bg.0 != mark_color {
704        // Update the color of the element
705        mark_bg.0 = mark_color;
706    }
707}
examples/ui/widgets/button.rs (line 134)
111fn update_button_appearance(
112    mut buttons: Query<
113        (
114            &Hovered,
115            Has<Pressed>,
116            &mut BackgroundColor,
117            &mut BorderColor,
118            &Children,
119        ),
120        With<Button>,
121    >,
122    mut text_query: Query<&mut Text>,
123) {
124    for (hovered, pressed, mut color, mut border_color, children) in &mut buttons {
125        let Ok(mut text) = text_query.get_mut(children[0]) else {
126            continue;
127        };
128
129        match (hovered.get(), pressed) {
130            // Pressed (and, since you can only press what you're hovering, also hovered).
131            (_, true) => {
132                **text = "Press".to_string();
133                *color = PRESSED_BUTTON.into();
134                border_color.set_all(RED);
135            }
136            // Hovered but not pressed.
137            (true, false) => {
138                **text = "Hover".to_string();
139                *color = HOVERED_BUTTON.into();
140                border_color.set_all(WHITE);
141            }
142            // Neither hovered nor pressed.
143            (false, false) => {
144                **text = "Button".to_string();
145                *color = NORMAL_BUTTON.into();
146                border_color.set_all(BLACK);
147            }
148        }
149    }
150}
examples/ui/widgets/standard_widgets_observers.rs (line 189)
154fn button_on_interaction<E: EventPattern<Event: EntityEvent>>(
155    event: On<E>,
156    mut buttons: Query<
157        (
158            &Hovered,
159            Has<InteractionDisabled>,
160            Has<Pressed>,
161            &mut BackgroundColor,
162            &mut BorderColor,
163            &Children,
164        ),
165        With<DemoButton>,
166    >,
167    mut text_query: Query<&mut Text>,
168) {
169    if let Ok((hovered, disabled, pressed, mut color, mut border_color, children)) =
170        buttons.get_mut(event.event_target())
171    {
172        if children.is_empty() {
173            return;
174        }
175        let Ok(mut text) = text_query.get_mut(children[0]) else {
176            return;
177        };
178        let hovered = hovered.get();
179        // These "removal event checks" exist because the `Remove` event is triggered _before_ the component is actually
180        // removed, meaning it still shows up in the query. We're investigating the best way to improve this scenario.
181        let pressed = pressed && !(E::Event::is::<RemoveEvent>() && E::Components::is::<Pressed>());
182        let disabled = disabled
183            && !(E::Event::is::<RemoveEvent>() && E::Components::is::<InteractionDisabled>());
184        match (disabled, hovered, pressed) {
185            // Disabled button
186            (true, _, _) => {
187                **text = "Disabled".to_string();
188                *color = NORMAL_BUTTON.into();
189                border_color.set_all(GRAY);
190            }
191
192            // Pressed and hovered button
193            (false, true, true) => {
194                **text = "Press".to_string();
195                *color = PRESSED_BUTTON.into();
196                border_color.set_all(RED);
197            }
198
199            // Hovered, unpressed button
200            (false, true, false) => {
201                **text = "Hover".to_string();
202                *color = HOVERED_BUTTON.into();
203                border_color.set_all(WHITE);
204            }
205
206            // Unhovered button (either pressed or not).
207            (false, false, _) => {
208                **text = "Button".to_string();
209                *color = NORMAL_BUTTON.into();
210                border_color.set_all(BLACK);
211            }
212        }
213    }
214}
215
216/// Create a demo slider
217fn slider(min: f32, max: f32, value: f32) -> impl Bundle {
218    (
219        Node {
220            display: Display::Flex,
221            flex_direction: FlexDirection::Column,
222            justify_content: JustifyContent::Center,
223            align_items: AlignItems::Stretch,
224            justify_items: JustifyItems::Center,
225            column_gap: px(4),
226            height: px(12),
227            width: percent(30),
228            ..default()
229        },
230        Name::new("Slider"),
231        Hovered::default(),
232        DemoSlider,
233        Slider::default(),
234        SliderValue(value),
235        SliderRange::new(min, max),
236        TabIndex(0),
237        Children::spawn((
238            // Slider background rail
239            Spawn((
240                Node {
241                    height: px(6),
242                    border_radius: BorderRadius::all(px(3)),
243                    ..default()
244                },
245                BackgroundColor(SLIDER_TRACK), // Border color for the checkbox
246            )),
247            // Invisible track to allow absolute placement of thumb entity. This is narrower than
248            // the actual slider, which allows us to position the thumb entity using simple
249            // percentages, without having to measure the actual width of the slider thumb.
250            Spawn((
251                Node {
252                    display: Display::Flex,
253                    position_type: PositionType::Absolute,
254                    left: px(0),
255                    // Track is short by 12px to accommodate the thumb.
256                    right: px(12),
257                    top: px(0),
258                    bottom: px(0),
259                    ..default()
260                },
261                children![(
262                    // Thumb
263                    DemoSliderThumb,
264                    SliderThumb,
265                    Node {
266                        display: Display::Flex,
267                        width: px(12),
268                        height: px(12),
269                        position_type: PositionType::Absolute,
270                        left: percent(0), // This will be updated by the slider's value
271                        border_radius: BorderRadius::MAX,
272                        ..default()
273                    },
274                    BackgroundColor(SLIDER_THUMB),
275                )],
276            )),
277        )),
278    )
279}
280
281fn slider_on_interaction<E: EventPattern<Event: EntityEvent>>(
282    event: On<E>,
283    sliders: Query<(Entity, &Hovered, Has<InteractionDisabled>), With<DemoSlider>>,
284    children: Query<&Children>,
285    mut thumbs: Query<(&mut BackgroundColor, Has<DemoSliderThumb>), Without<DemoSlider>>,
286) {
287    if let Ok((slider_ent, hovered, disabled)) = sliders.get(event.event_target()) {
288        // These "removal event checks" exist because the `Remove` event is triggered _before_ the component is actually
289        // removed, meaning it still shows up in the query. We're investigating the best way to improve this scenario.
290        let disabled = disabled
291            && !(E::Event::is::<RemoveEvent>() && E::Components::is::<InteractionDisabled>());
292        for child in children.iter_descendants(slider_ent) {
293            if let Ok((mut thumb_bg, is_thumb)) = thumbs.get_mut(child)
294                && is_thumb
295            {
296                thumb_bg.0 = thumb_color(disabled, hovered.0);
297            }
298        }
299    }
300}
301
302fn slider_on_change_value<C: Component>(
303    insert: On<Insert<C>>,
304    sliders: Query<(Entity, &SliderValue, &SliderRange), With<DemoSlider>>,
305    children: Query<&Children>,
306    mut thumbs: Query<(&mut Node, Has<DemoSliderThumb>), Without<DemoSlider>>,
307) {
308    if let Ok((slider_ent, value, range)) = sliders.get(insert.entity) {
309        for child in children.iter_descendants(slider_ent) {
310            if let Ok((mut thumb_node, is_thumb)) = thumbs.get_mut(child)
311                && is_thumb
312            {
313                thumb_node.left = percent(range.thumb_position(value.0) * 100.0);
314            }
315        }
316    }
317}
318
319fn thumb_color(disabled: bool, hovered: bool) -> Color {
320    match (disabled, hovered) {
321        (true, _) => GRAY.into(),
322
323        (false, true) => SLIDER_THUMB.lighter(0.3),
324
325        _ => SLIDER_THUMB,
326    }
327}
328
329/// Create a demo checkbox
330fn checkbox(asset_server: &AssetServer, caption: &str) -> impl Bundle {
331    (
332        Node {
333            display: Display::Flex,
334            flex_direction: FlexDirection::Row,
335            justify_content: JustifyContent::FlexStart,
336            align_items: AlignItems::Center,
337            align_content: AlignContent::Center,
338            column_gap: px(4),
339            ..default()
340        },
341        Name::new("Checkbox"),
342        Hovered::default(),
343        DemoCheckbox,
344        Checkbox,
345        TabIndex(0),
346        Children::spawn((
347            Spawn((
348                // Checkbox outer
349                Node {
350                    display: Display::Flex,
351                    width: px(16),
352                    height: px(16),
353                    border: UiRect::all(px(2)),
354                    border_radius: BorderRadius::all(px(3)),
355                    ..default()
356                },
357                BorderColor::all(CHECKBOX_OUTLINE), // Border color for the checkbox
358                children![
359                    // Checkbox inner
360                    (
361                        Node {
362                            display: Display::Flex,
363                            width: px(8),
364                            height: px(8),
365                            position_type: PositionType::Absolute,
366                            left: px(2),
367                            top: px(2),
368                            ..default()
369                        },
370                        BackgroundColor(Srgba::NONE.into()),
371                    ),
372                ],
373            )),
374            Spawn((
375                Text::new(caption),
376                TextFont {
377                    font: asset_server.load("fonts/FiraSans-Bold.ttf").into(),
378                    font_size: FontSize::Px(20.0),
379                    ..default()
380                },
381            )),
382        )),
383    )
384}
385
386fn checkbox_on_interaction<E: EventPattern<Event: EntityEvent>>(
387    event: On<E>,
388    checkboxes: Query<
389        (&Hovered, Has<InteractionDisabled>, Has<Checked>, &Children),
390        With<DemoCheckbox>,
391    >,
392    mut borders: Query<(&mut BorderColor, &mut Children), Without<DemoCheckbox>>,
393    mut marks: Query<&mut BackgroundColor, (Without<DemoCheckbox>, Without<Children>)>,
394) {
395    if let Ok((hovered, disabled, checked, children)) = checkboxes.get(event.event_target()) {
396        let hovered = hovered.get();
397        // These "removal event checks" exist because the `Remove` event is triggered _before_ the component is actually
398        // removed, meaning it still shows up in the query. We're investigating the best way to improve this scenario.
399        let checked = checked && !(E::Event::is::<RemoveEvent>() && E::Components::is::<Checked>());
400        let disabled = disabled
401            && !(E::Event::is::<RemoveEvent>() && E::Components::is::<InteractionDisabled>());
402
403        let Some(border_id) = children.first() else {
404            return;
405        };
406
407        let Ok((mut border_color, border_children)) = borders.get_mut(*border_id) else {
408            return;
409        };
410
411        let Some(mark_id) = border_children.first() else {
412            warn!("Checkbox does not have a mark entity.");
413            return;
414        };
415
416        let Ok(mut mark_bg) = marks.get_mut(*mark_id) else {
417            warn!("Checkbox mark entity lacking a background color.");
418            return;
419        };
420
421        let color: Color = if disabled {
422            // If the checkbox is disabled, use a lighter color
423            CHECKBOX_OUTLINE.with_alpha(0.2)
424        } else if hovered {
425            // If hovering, use a lighter color
426            CHECKBOX_OUTLINE.lighter(0.2)
427        } else {
428            // Default color for the checkbox
429            CHECKBOX_OUTLINE
430        };
431
432        // Update the background color of the check mark
433        border_color.set_all(color);
434
435        let mark_color: Color = match (disabled, checked) {
436            (true, true) => CHECKBOX_CHECK.with_alpha(0.5),
437            (false, true) => CHECKBOX_CHECK,
438            (_, false) => Srgba::NONE.into(),
439        };
440
441        if mark_bg.0 != mark_color {
442            // Update the color of the check mark
443            mark_bg.0 = mark_color;
444        }
445    }
446}
Source

pub fn is_fully_transparent(&self) -> bool

Check if all contained border colors are transparent

Trait Implementations§

Source§

impl Clone for BorderColor

Source§

fn clone(&self) -> BorderColor

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Component for BorderColor
where BorderColor: Send + Sync + 'static,

Source§

const STORAGE_TYPE: StorageType = bevy_ecs::component::StorageType::Table

A constant indicating the storage type used for this component.
Source§

type Mutability = Mutable

A marker type to assist Bevy with determining if this component is mutable, or immutable. Mutable components will have Component<Mutability = Mutable>, while immutable components will instead have Component<Mutability = Immutable>. Read more
Source§

fn register_required_components( _requiree: ComponentId, required_components: &mut RequiredComponentsRegistrator<'_, '_>, )

Registers required components. Read more
Source§

fn clone_behavior() -> ComponentCloneBehavior

Called when registering this component, allowing to override clone function (or disable cloning altogether) for this component. Read more
Source§

fn relationship_accessor() -> Option<ComponentRelationshipAccessor<BorderColor>>

Returns ComponentRelationshipAccessor required for working with relationships in dynamic contexts. Read more
Source§

fn on_add() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_add ComponentHook for this Component if one is defined.
Source§

fn on_insert() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_insert ComponentHook for this Component if one is defined.
Source§

fn on_discard() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_discard ComponentHook for this Component if one is defined.
Source§

fn on_remove() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_remove ComponentHook for this Component if one is defined.
Source§

fn on_despawn() -> Option<for<'w> fn(DeferredWorld<'w>, HookContext)>

Gets the on_despawn ComponentHook for this Component if one is defined.
Source§

fn map_entities<E>(_this: &mut Self, _mapper: &mut E)
where E: EntityMapper,

Maps the entities on this component using the given EntityMapper. This is used to remap entities in contexts like scenes and entity cloning. When deriving Component, this is populated by annotating fields containing entities with #[entities] Read more
Source§

const HAS_SUMMARY_TICK: bool = false

Set this constant to true if the component should track a summary tick. Read more
Source§

impl Copy for BorderColor

Source§

impl Debug for BorderColor

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Default for BorderColor

Source§

fn default() -> BorderColor

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for BorderColor

Source§

fn deserialize<__D>( __deserializer: __D, ) -> Result<BorderColor, <__D as Deserializer<'de>>::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<T> From<T> for BorderColor
where T: Into<Color>,

Source§

fn from(color: T) -> BorderColor

Converts to this type from the input type.
Source§

impl FromArg for BorderColor

Source§

type This<'from_arg> = BorderColor

The type to convert into. Read more
Source§

fn from_arg( arg: Arg<'_>, ) -> Result<<BorderColor as FromArg>::This<'_>, ArgError>

Creates an item from an argument. Read more
Source§

impl FromReflect for BorderColor

Source§

fn from_reflect(reflect: &(dyn PartialReflect + 'static)) -> Option<BorderColor>

Constructs a concrete instance of Self from a reflected value.
Source§

fn take_from_reflect( reflect: Box<dyn PartialReflect>, ) -> Result<Self, Box<dyn PartialReflect>>

Attempts to downcast the given value to Self using, constructing the value using from_reflect if that fails. Read more
Source§

impl GetOwnership for BorderColor

Source§

fn ownership() -> Ownership

Returns the ownership of Self.
Source§

impl GetTypeRegistration for BorderColor

Source§

fn get_type_registration() -> TypeRegistration

Returns the default TypeRegistration for this type.
Source§

fn register_type_dependencies(registry: &mut TypeRegistry)

Registers other types needed by this type. Read more
Source§

impl IntoReturn for BorderColor

Source§

fn into_return<'into_return>(self) -> Return<'into_return>
where BorderColor: 'into_return,

Converts Self into a Return value.
Source§

impl PartialEq for BorderColor

Source§

fn eq(&self, other: &BorderColor) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl PartialReflect for BorderColor

Source§

fn get_represented_type_info(&self) -> Option<&'static TypeInfo>

Returns the TypeInfo of the type represented by this value. Read more
Source§

fn try_apply( &mut self, value: &(dyn PartialReflect + 'static), ) -> Result<(), ApplyError>

Tries to apply a reflected value to this value. Read more
Source§

fn reflect_kind(&self) -> ReflectKind

Returns a zero-sized enumeration of “kinds” of type. Read more
Source§

fn reflect_ref(&self) -> ReflectRef<'_>

Returns an immutable enumeration of “kinds” of type. Read more
Source§

fn reflect_mut(&mut self) -> ReflectMut<'_>

Returns a mutable enumeration of “kinds” of type. Read more
Source§

fn reflect_owned(self: Box<BorderColor>) -> ReflectOwned

Returns an owned enumeration of “kinds” of type. Read more
Source§

fn try_into_reflect( self: Box<BorderColor>, ) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>

Attempts to cast this type to a boxed, fully-reflected value.
Source§

fn try_as_reflect(&self) -> Option<&(dyn Reflect + 'static)>

Attempts to cast this type to a fully-reflected value.
Source§

fn try_as_reflect_mut(&mut self) -> Option<&mut (dyn Reflect + 'static)>

Attempts to cast this type to a mutable, fully-reflected value.
Source§

fn into_partial_reflect(self: Box<BorderColor>) -> Box<dyn PartialReflect>

Casts this type to a boxed, reflected value. Read more
Source§

fn as_partial_reflect(&self) -> &(dyn PartialReflect + 'static)

Casts this type to a reflected value. Read more
Source§

fn as_partial_reflect_mut(&mut self) -> &mut (dyn PartialReflect + 'static)

Casts this type to a mutable, reflected value. Read more
Source§

fn reflect_partial_eq( &self, value: &(dyn PartialReflect + 'static), ) -> Option<bool>

Returns a “partial equality” comparison result. Read more
Source§

fn reflect_partial_cmp( &self, value: &(dyn PartialReflect + 'static), ) -> Option<Ordering>

Returns a “partial comparison” result. Read more
Source§

fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Debug formatter for the value. Read more
Source§

fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError>

Attempts to clone Self using reflection. Read more
Source§

fn apply(&mut self, value: &(dyn PartialReflect + 'static))

Applies a reflected value to this value. Read more
Source§

fn to_dynamic(&self) -> Result<Box<dyn PartialReflect>, ReflectCloneError>

Converts this reflected value into its dynamic representation based on its kind. Read more
Source§

fn reflect_clone_and_take<T>(&self) -> Result<T, ReflectCloneError>
where T: 'static, Self: Sized + TypePath,

For a type implementing PartialReflect, combines reflect_clone and take in a useful fashion, automatically constructing an appropriate ReflectCloneError if the downcast fails.
Source§

fn reflect_hash(&self) -> Option<u64>

Returns a hash of the value (which includes the type). Read more
Source§

fn is_dynamic(&self) -> bool

Indicates whether or not this type is a dynamic type. Read more
Source§

impl Reflect for BorderColor

Source§

fn into_any(self: Box<BorderColor>) -> Box<dyn Any>

Returns the value as a Box<dyn Any>. Read more
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Returns the value as a &dyn Any. Read more
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Returns the value as a &mut dyn Any. Read more
Source§

fn into_reflect(self: Box<BorderColor>) -> Box<dyn Reflect>

Casts this type to a boxed, fully-reflected value.
Source§

fn as_reflect(&self) -> &(dyn Reflect + 'static)

Casts this type to a fully-reflected value.
Source§

fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)

Casts this type to a mutable, fully-reflected value.
Source§

fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>

Performs a type-checked assignment of a reflected value to this value. Read more
Source§

impl Serialize for BorderColor

Source§

fn serialize<__S>( &self, __serializer: __S, ) -> Result<<__S as Serializer>::Ok, <__S as Serializer>::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl Struct for BorderColor

Source§

fn field(&self, name: &str) -> Option<&(dyn PartialReflect + 'static)>

Gets a reference to the value of the field named name as a &dyn PartialReflect.
Source§

fn field_mut( &mut self, name: &str, ) -> Option<&mut (dyn PartialReflect + 'static)>

Gets a mutable reference to the value of the field named name as a &mut dyn PartialReflect.
Source§

fn field_at(&self, index: usize) -> Option<&(dyn PartialReflect + 'static)>

Gets a reference to the value of the field with index index as a &dyn PartialReflect.
Source§

fn field_at_mut( &mut self, index: usize, ) -> Option<&mut (dyn PartialReflect + 'static)>

Gets a mutable reference to the value of the field with index index as a &mut dyn PartialReflect.
Source§

fn name_at(&self, index: usize) -> Option<&str>

Gets the name of the field with index index.
Source§

fn index_of_name(&self, name: &str) -> Option<usize>

Gets the index of the field with the given name.
Source§

fn field_len(&self) -> usize

Returns the number of fields in the struct.
Source§

fn iter_fields(&self) -> FieldIter<'_> ⓘ

Returns an iterator over the values of the reflectable fields for this struct.
Source§

fn to_dynamic_struct(&self) -> Result<DynamicStruct, ReflectCloneError>

Creates a new DynamicStruct from this struct. Read more
Source§

fn get_represented_struct_info(&self) -> Option<&'static StructInfo>

Will return None if TypeInfo is not available.
Source§

impl StructuralPartialEq for BorderColor

Source§

impl TypePath for BorderColor

Source§

fn type_path() -> &'static str

Returns the fully qualified path of the underlying type. Read more
Source§

fn short_type_path() -> &'static str

Returns a short, pretty-print enabled path to the type. Read more
Source§

fn type_ident() -> Option<&'static str>

Returns the name of the type, or None if it is anonymous. Read more
Source§

fn crate_name() -> Option<&'static str>

Returns the name of the crate the type is in, or None if it is anonymous. Read more
Source§

fn module_path() -> Option<&'static str>

Returns the path to the module the type is in, or None if it is anonymous. Read more
Source§

impl Typed for BorderColor

Source§

fn type_info() -> &'static TypeInfo

Returns the compile-time info for the underlying type.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

Source§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Brush for T
where T: Clone + PartialEq + Default + Debug,

Source§

impl<C> Bundle for C
where C: Component,

Source§

fn component_ids( components: &mut ComponentsRegistrator<'_>, ) -> impl Iterator<Item = ComponentId> + use<C>

Source§

fn get_component_ids( components: &Components, ) -> impl Iterator<Item = Option<ComponentId>>

Returns an iterator over this Bundle’s component ids. This will be None if the component has not been registered.
Source§

impl<C> BundleFromComponents for C
where C: Component,

Source§

unsafe fn from_components<T, F>(ctx: &mut T, func: &mut F) -> C
where F: for<'a> FnMut(&'a mut T) -> OwningPtr<'a>, C: Sized,

Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> ConditionalSend for T
where T: Send,

Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<C> DynamicBundle for C
where C: Component,

Source§

type Effect = ()

An operation on the entity that happens after inserting this bundle.
Source§

unsafe fn get_components( ptr: MovingPtr<'_, C>, func: &mut impl FnMut(StorageType, OwningPtr<'_>), ) -> <C as DynamicBundle>::Effect

Moves the components out of the bundle. Read more
Source§

unsafe fn apply_effect( _ptr: MovingPtr<'_, MaybeUninit<C>>, _entity: &mut EntityWorldMut<'_>, )

Applies the after-effects of spawning this bundle. Read more
Source§

impl<T> DynamicTypePath for T
where T: TypePath,

Source§

impl<T> DynamicTyped for T
where T: Typed,

Source§

impl<T> ErasedBundleTemplate for T
where T: Template + Send + Sync + 'static, <T as Template>::Output: Bundle,

Source§

unsafe fn apply( &self, context: &mut TemplateContext<'_, '_>, ) -> Result<(), BevyError>

Applies this template to the given entity. Read more
Source§

fn clone_template(&self) -> Box<dyn ErasedBundleTemplate>

Clones this template. See Clone.
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> ErasedTemplate for T
where T: Template + Send + Sync + 'static, <T as Template>::Output: SceneEffect,

Source§

unsafe fn apply( &self, context: &mut TemplateContext<'_, '_>, bundle_writer: &mut BundleWriter<'_>, ) -> Result<(), BevyError>

Applies this template to the given entity. Read more
Source§

fn clone_template(&self) -> Box<dyn ErasedTemplate>

Clones this template. See Clone.
Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> FromTemplate for T
where T: Clone + Default + Unpin,

Source§

type Template = T

The Template for this type.
Source§

impl<T> FromWorld for T
where T: Default,

Source§

fn from_world(_world: &mut World) -> T

Creates Self using default().

Source§

impl<S> GetField for S
where S: Struct,

Source§

fn get_field<T>(&self, name: &str) -> Option<&T>
where T: Reflect,

Gets a reference to the value of the field named name, downcast to T.
Source§

fn get_field_mut<T>(&mut self, name: &str) -> Option<&mut T>
where T: Reflect,

Gets a mutable reference to the value of the field named name, downcast to T.
Source§

impl<T> GetPath for T
where T: Reflect + ?Sized,

Source§

fn reflect_path<'p>( &self, path: impl ReflectPath<'p>, ) -> Result<&(dyn PartialReflect + 'static), ReflectPathError<'p>>

Returns a reference to the value specified by path. Read more
Source§

fn reflect_path_mut<'p>( &mut self, path: impl ReflectPath<'p>, ) -> Result<&mut (dyn PartialReflect + 'static), ReflectPathError<'p>>

Returns a mutable reference to the value specified by path. Read more
Source§

fn path<'p, T>( &self, path: impl ReflectPath<'p>, ) -> Result<&T, ReflectPathError<'p>>
where T: Reflect,

Returns a statically typed reference to the value specified by path. Read more
Source§

fn path_mut<'p, T>( &mut self, path: impl ReflectPath<'p>, ) -> Result<&mut T, ReflectPathError<'p>>
where T: Reflect,

Returns a statically typed mutable reference to the value specified by path. Read more
Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

impl<T> HitDataExtra for T
where T: Send + Sync + Debug + Any + 'static,

Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> InitializeFromFunction<T> for T

Source§

fn initialize_from_function(f: fn() -> T) -> T

Create an instance of this type from an initialization function
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
Source§

impl<T> NoneValue for T
where T: Default,

Source§

type NoneType = T

Source§

fn null_value() -> T

The none-equivalent value.
Source§

impl<G> PatchFromTemplate for G
where G: FromTemplate,

Source§

type Template = <G as FromTemplate>::Template

The Template that will be patched.
Source§

fn patch<F>(func: F) -> TemplatePatch<F, <G as PatchFromTemplate>::Template>
where F: FnOnce(&mut <G as PatchFromTemplate>::Template, &mut ResolveContext<'_>),

Takes a “patch function” func, and turns it into a TemplatePatch.
Source§

impl<T> PatchTemplate for T
where T: Template,

Source§

fn patch_template<F>(func: F) -> TemplatePatch<F, T>
where F: FnOnce(&mut T, &mut ResolveContext<'_>),

Takes a “patch function” func that patches this Template, and turns it into a TemplatePatch.
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<R, P> ReadPrimitive<R> for P
where R: Read + ReadEndian<P>, P: Default,

Source§

fn read_from_little_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_little_endian().
Source§

fn read_from_big_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_big_endian().
Source§

fn read_from_native_endian(read: &mut R) -> Result<Self, Error>

Read this value from the supplied reader. Same as ReadEndian::read_from_native_endian().
Source§

impl<T> Reflectable for T

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<C> SceneEffect for C
where C: Component,

Source§

fn apply( self, context: &mut TemplateContext<'_, '_>, bundle_writer: &mut BundleWriter<'_>, )

Applies the scene effect to the current context.
Source§

impl<T> Serialize for T
where T: Serialize + ?Sized,

Source§

fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>

Source§

fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>

Source§

impl<T> Settings for T
where T: 'static + Send + Sync,

Source§

impl<Ret> SpawnIfAsync<(), Ret> for Ret

Source§

fn spawn(self) -> Ret

Spawn the value into the dioxus runtime if it is an async block
Source§

impl<T, O> SuperFrom<T> for O
where O: From<T>,

Source§

fn super_from(input: T) -> O

Convert from a type to another type.
Source§

impl<T, O, M> SuperInto<O, M> for T
where O: SuperFrom<T, M>,

Source§

fn super_into(self) -> O

Convert from a type to another type.
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> Template for T
where T: Clone + Unpin,

Source§

type Output = T

The type of value produced by this Template.
Source§

fn build_template( &self, _context: &mut TemplateContext<'_, '_>, ) -> Result<<T as Template>::Output, BevyError>

Uses this template and the given entity context to produce a Template::Output.
Source§

fn clone_template(&self) -> T

Clones this template. See Clone.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> TypeData for T
where T: 'static + Send + Sync + Clone,

Source§

fn clone_type_data(&self) -> Box<dyn TypeData>

Creates a type-erased clone of self.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more