Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions crates/bevy_input_focus/src/tab_navigation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ pub struct TabNavigation<'w, 's> {
}

impl TabNavigation<'_, '_> {
/// Navigate to the desired focusable entity.
/// Navigate to the desired focusable entity, relative to the current focused entity.
///
/// Change the [`NavAction`] to navigate in a different direction.
/// Focusable entities are determined by the presence of the [`TabIndex`] component.
///
/// If no focusable entities are found, then this function will return either the first
/// If there is no currently focused entity, then this function will return either the first
/// or last focusable entity, depending on the direction of navigation. For example, if
/// `action` is `Next` and no focusable entities are found, then this function will return
/// the first focusable entity.
Expand All @@ -199,13 +199,46 @@ impl TabNavigation<'_, '_> {
})
});

self.navigate_internal(focus.0, action, tabgroup)
}

/// Initialize focus to a focusable child of a container, either the first or last
/// depending on [`NavAction`]. This assumes that the parent entity has a [`TabGroup`]
/// component.
///
/// Focusable entities are determined by the presence of the [`TabIndex`] component.
pub fn initialize(
&self,
parent: Entity,
action: NavAction,
) -> Result<Entity, TabNavigationError> {
// If there are no tab groups, then there are no focusable entities.
if self.tabgroup_query.is_empty() {
return Err(TabNavigationError::NoTabGroups);
}

// Look for the tab group on the parent entity.
match self.tabgroup_query.get(parent) {
Ok(tabgroup) => self.navigate_internal(None, action, Some((parent, tabgroup.1))),
Err(_) => Err(TabNavigationError::NoTabGroups),
}
}

pub fn navigate_internal(
&self,
focus: Option<Entity>,
action: NavAction,
tabgroup: Option<(Entity, &TabGroup)>,
) -> Result<Entity, TabNavigationError> {
let navigation_result = self.navigate_in_group(tabgroup, focus, action);

match navigation_result {
Ok(entity) => {
if focus.0.is_some() && tabgroup.is_none() {
if let Some(previous_focus) = focus
&& tabgroup.is_none()
{
Err(TabNavigationError::NoTabGroupForCurrentFocus {
previous_focus: focus.0.unwrap(),
previous_focus,
new_focus: entity,
})
} else {
Expand All @@ -219,7 +252,7 @@ impl TabNavigation<'_, '_> {
fn navigate_in_group(
&self,
tabgroup: Option<(Entity, &TabGroup)>,
focus: &InputFocus,
focus: Option<Entity>,
action: NavAction,
) -> Result<Entity, TabNavigationError> {
// List of all focusable entities found.
Expand Down Expand Up @@ -269,7 +302,7 @@ impl TabNavigation<'_, '_> {
}
});

let index = focusable.iter().position(|e| Some(e.0) == focus.0);
let index = focusable.iter().position(|e| Some(e.0) == focus);
let count = focusable.len();
let next = match (index, action) {
(Some(idx), NavAction::Next) => (idx + 1).rem_euclid(count),
Expand Down
32 changes: 32 additions & 0 deletions crates/bevy_math/src/rects/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,38 @@ impl Rect {
}
}

/// Return the area of this rectangle.
///
/// # Examples
///
/// ```
/// # use bevy_math::Rect;
/// let r = Rect::new(0., 0., 10., 10.); // w=10 h=10
/// assert_eq!(r.area(), 100.0);
/// ```
#[inline]
pub fn area(&self) -> f32 {
self.width() * self.height()
}

/// Scale this rect by a multiplicative factor
///
/// # Examples
///
/// ```
/// # use bevy_math::Rect;
/// let r = Rect::new(1., 1., 2., 2.); // w=10 h=10
/// assert_eq!(r.scale(2.).min.x, 2.0);
/// assert_eq!(r.scale(2.).max.x, 4.0);
/// ```
#[inline]
pub fn scale(&self, factor: f32) -> Rect {
Self {
min: self.min * factor,
max: self.max * factor,
}
}

/// Returns self as [`IRect`] (i32)
#[inline]
pub fn as_irect(&self) -> IRect {
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_ui_widgets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ keywords = ["bevy"]
# bevy
bevy_app = { path = "../bevy_app", version = "0.18.0-dev" }
bevy_a11y = { path = "../bevy_a11y", version = "0.18.0-dev" }
bevy_camera = { path = "../bevy_camera", version = "0.18.0-dev" }
bevy_ecs = { path = "../bevy_ecs", version = "0.18.0-dev" }
bevy_input = { path = "../bevy_input", version = "0.18.0-dev" }
bevy_input_focus = { path = "../bevy_input_focus", version = "0.18.0-dev" }
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_ui_widgets/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@

mod button;
mod checkbox;
mod menu;
mod observe;
pub mod popover;
mod radio;
mod scrollbar;
mod slider;

pub use button::*;
pub use checkbox::*;
pub use menu::*;
pub use observe::*;
pub use radio::*;
pub use scrollbar::*;
Expand All @@ -35,15 +38,19 @@ pub use slider::*;
use bevy_app::{PluginGroup, PluginGroupBuilder};
use bevy_ecs::{entity::Entity, event::EntityEvent};

use crate::popover::PopoverPlugin;

/// A plugin group that registers the observers for all of the widgets in this crate. If you don't want to
/// use all of the widgets, you can import the individual widget plugins instead.
pub struct UiWidgetsPlugins;

impl PluginGroup for UiWidgetsPlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(PopoverPlugin)
.add(ButtonPlugin)
.add(CheckboxPlugin)
.add(MenuPlugin)
.add(RadioGroupPlugin)
.add(ScrollbarPlugin)
.add(SliderPlugin)
Expand Down
Loading