diff --git a/assets/image/entity/1-bit/Creatures.png b/assets/image/entity/1-bit/Creatures.png index 8c66cb8..7904f87 100644 Binary files a/assets/image/entity/1-bit/Creatures.png and b/assets/image/entity/1-bit/Creatures.png differ diff --git a/src/state/editor_screen/outline_panel.rs b/src/state/editor_screen/outline_panel.rs index 8e487be..9e7754a 100644 --- a/src/state/editor_screen/outline_panel.rs +++ b/src/state/editor_screen/outline_panel.rs @@ -9,6 +9,7 @@ use crate::state::editor_screen::EditorScreenTheme; use crate::state::AppState; use crate::ui::FontSize; use crate::ui::InteractionPalette; +use crate::ui::ScrollContent; use crate::ui::Tooltip; use crate::ui::TooltipSide; use crate::ui::BOLD_FONT_HANDLE; @@ -51,14 +52,13 @@ pub fn spawn_outline_panel(commands: &mut Commands, theme: &EditorScreenTheme) - style: Style { min_width: theme.outline_panel_width, height: Percent(100.0), - padding: UiRect::all(Px(12.0)), + padding: UiRect::new(Px(12.0), Px(8.0), Px(12.0), Px(12.0)), flex_direction: FlexDirection::Column, ..default() }, background_color: theme.outline_panel_background_color.into(), ..default() }, - IsOutlineContainer, )) .id(); @@ -75,8 +75,6 @@ pub fn spawn_outline_panel(commands: &mut Commands, theme: &EditorScreenTheme) - }, ), style: Style { - // Hiding this because it looks bad :( - // display: Display::None, margin: UiRect::bottom(Px(10.0)), ..default() }, @@ -87,6 +85,77 @@ pub fn spawn_outline_panel(commands: &mut Commands, theme: &EditorScreenTheme) - )) .set_parent(outline_panel); + let hbox = commands + .spawn(( + Name::new("HBox"), + NodeBundle { + style: Style { + width: Percent(100.0), + justify_content: JustifyContent::End, + flex_grow: 1.0, + column_gap: Px(4.0), + ..default() + }, + ..default() + }, + )) + .set_parent(outline_panel) + .id(); + + let scroll_view = commands + .spawn(( + Name::new("OutlineScrollView"), + NodeBundle { + style: Style { + // TODO: This is a hack.. there seems to be no other way to + // restrict height to available space in the parent node + position_type: PositionType::Absolute, + overflow: Overflow::clip_y(), + width: Percent(100.0), + height: Percent(100.0), + padding: UiRect::right(Px(12.0)), + flex_direction: FlexDirection::Column, + ..default() + }, + ..default() + }, + )) + .set_parent(hbox) + .id(); + + commands + .spawn(( + Name::new("OutlineContainer"), + NodeBundle { + style: Style { + width: Percent(100.0), + flex_direction: FlexDirection::Column, + ..default() + }, + ..default() + }, + ScrollContent::with_sensitivity(2.0), + IsOutlineContainer, + )) + .set_parent(scroll_view); + + commands + .spawn(( + Name::new("OutlineScrollbar"), + NodeBundle { + style: Style { + width: Px(8.0), + height: Percent(100.0), + justify_self: JustifySelf::End, + ..default() + }, + // TODO + background_color: theme.info_bar_background_color.into(), + ..default() + }, + )) + .set_parent(hbox); + outline_panel } @@ -119,7 +188,7 @@ fn spawn_outline_entry( Tooltip { text: upgrade_desc, side: TooltipSide::Right, - offset: vec2(12.0, 0.0), + offset: vec2(20.0, 0.0), }, OutlineEntry(upgrade_kind), )) diff --git a/src/ui.rs b/src/ui.rs index 94f1c8a..dca452c 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,6 +1,7 @@ mod code_typer; mod font; mod interaction_palette; +mod scroll; mod tooltip; use bevy::prelude::*; @@ -11,6 +12,7 @@ pub use crate::ui::font::FontSize; pub use crate::ui::font::BOLD_FONT_HANDLE; pub use crate::ui::font::FONT_HANDLE; pub use crate::ui::interaction_palette::InteractionPalette; +pub use crate::ui::scroll::ScrollContent; pub use crate::ui::tooltip::Tooltip; pub use crate::ui::tooltip::TooltipConfig; pub use crate::ui::tooltip::TooltipSide; @@ -21,9 +23,10 @@ impl Plugin for UiPlugin { fn build(&self, app: &mut App) { app.register_type::().add_plugins(( DefaultPickingPlugins, - interaction_palette::InteractionPalettePlugin, code_typer::CodeTyperPlugin, font::FontPlugin, + interaction_palette::InteractionPalettePlugin, + scroll::ScrollPlugin, tooltip::TooltipPlugin, )); } diff --git a/src/ui/scroll.rs b/src/ui/scroll.rs new file mode 100644 index 0000000..d38ce8b --- /dev/null +++ b/src/ui/scroll.rs @@ -0,0 +1,57 @@ +use bevy::input::mouse::MouseScrollUnit; +use bevy::input::mouse::MouseWheel; +use bevy::prelude::*; + +use crate::AppSet; + +pub struct ScrollPlugin; + +impl Plugin for ScrollPlugin { + fn build(&self, app: &mut App) { + app.register_type::() + .add_systems(Update, mouse_scroll.in_set(AppSet::Input)); + } +} + +#[derive(Component, Reflect, Default)] +pub struct ScrollContent { + position: f32, + sensitivity: f32, +} + +impl ScrollContent { + pub fn with_sensitivity(sensitivity: f32) -> Self { + Self { + sensitivity, + ..default() + } + } +} + +fn mouse_scroll( + mut events: EventReader, + mut scroll_query: Query<(&mut ScrollContent, &mut Style, &Parent, &Node)>, + node_query: Query<&Node>, +) { + let pixels = events + .read() + .map(|event| { + event.y + * match event.unit { + MouseScrollUnit::Line => 20.0, + MouseScrollUnit::Pixel => 1.0, + } + }) + .sum::(); + + for (mut scroll, mut style, parent, node) in &mut scroll_query { + scroll.position += pixels * scroll.sensitivity; + + let height = node.size().y; + let parent_height = node_query.get(parent.get()).unwrap().size().y; + let max_scroll = (height - parent_height).max(0.0); + scroll.position = scroll.position.clamp(-max_scroll, 0.0); + + style.top = Val::Px(scroll.position); + } +}