diff --git a/src/widgets.rs b/src/widgets.rs index 4a435a3..e02961a 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -189,6 +189,70 @@ impl Widget for RectButton { } } +pub struct ScrollBarStyle { + pub margin: Vec2, + pub body_radius: f32, + pub body_width: f32, + pub body_idle_color: Color, + pub body_hover_color: Color, + pub body_active_color: Color, + pub rail_width: f32, + pub rail_color: Color, +} + +impl Default for ScrollBarStyle { + fn default() -> Self { + Self { + margin: Vec2::new(0.01, 0.01), + body_radius: 0.005, + body_width: 0.015, + body_idle_color: Color::new(0.5, 0.5, 0.5, 1.0), + body_hover_color: Color::new(0.8, 0.8, 0.8, 1.0), + body_active_color: Color::new(1.0, 1.0, 0.0, 1.0), + rail_width: 0.005, + rail_color: Color::new(0.7, 0.7, 0.7, 0.5), + } + } +} + +pub struct ScrollBar { + height: f32, + style: ScrollBarStyle, + scroll: f32, + content_height: f32, +} + +impl ScrollBar { + pub fn new(height: f32, content_height: f32, style: ScrollBarStyle) -> Self { + Self { + height, + style, + scroll: height, + content_height, + } + } +} + +impl Widget for ScrollBar { + fn update(&mut self, dt: f32) {} + + fn draw(&mut self, ctx: &DrawContext) { + let style = &self.style; + let center_x = style.body_width / 2.0 + style.margin.x; + let rail_xy = Vec2::new(center_x - style.rail_width / 2.0, self.style.margin.y); + let rail_size = Vec2::new(style.rail_width, self.height - style.margin.y * 2.0); + let body_height = (self.height / self.content_height) * rail_size.y; + let body_y = rail_size.y - (self.scroll / self.content_height) * rail_size.y - body_height; + let body_xy = Vec2::new(style.margin.x, body_y + style.margin.y); + let body_size = Vec2::new(style.body_width, body_height); + + ctx.draw_rect(rail_xy, rail_size, style.rail_color); + ctx.draw_rounded_rect(body_xy, body_size, style.body_radius, style.body_idle_color); + } + + fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) {} +} + #[derive(Eq, PartialEq)] pub enum ScrollMenuState { Opening, @@ -544,6 +608,7 @@ impl Widget for MainMenu { pub struct TabMenu { tabs: Vec, + scroll_bar: Offset, } impl TabMenu { @@ -554,10 +619,7 @@ impl TabMenu { const TAB_NUM: usize = 6; const SEPARATOR_WIDTH: f32 = 0.015; const INNER_RADIUS: f32 = 0.005; - const BOX_SIZE: f32 = 0.05; - const BOX_MARGIN: f32 = 0.01; - const BOX_PADDING: f32 = 0.005; - const BOX_GRID_WIDTH: usize = 8; + const CONTENT_WIDTH: f32 = 0.4; pub fn new() -> Self { let tab_size = Vec2::new(Self::TAB_WIDTH, Self::TAB_HEIGHT); @@ -577,7 +639,12 @@ impl TabMenu { tabs.push(RectButton::new(pos, tab_size, corners, radius)); } - Self { tabs } + let scroll_height = Self::TAB_NUM as f32 * Self::TAB_HEIGHT; + let scroll_bar = ScrollBar::new(scroll_height, scroll_height * 3.0, Default::default()); + let scroll_x = Self::TAB_WIDTH + Self::SEPARATOR_WIDTH + Self::CONTENT_WIDTH; + let scroll_bar = Offset::new(scroll_bar, Vec2::new(scroll_x, -scroll_height)); + + Self { tabs, scroll_bar } } } @@ -586,6 +653,8 @@ impl Widget for TabMenu { for tab in self.tabs.iter_mut() { tab.update(dt); } + + self.scroll_bar.update(dt); } fn draw(&mut self, ctx: &DrawContext) { @@ -604,10 +673,11 @@ impl Widget for TabMenu { let tab_list_height = Self::TAB_NUM as f32 * Self::TAB_HEIGHT; let separator_xy = Vec2::new(Self::TAB_WIDTH, -tab_list_height); let separator_size = Vec2::new(Self::SEPARATOR_WIDTH, tab_list_height); - let body_width = Self::BOX_GRID_WIDTH as f32 * (Self::BOX_SIZE + Self::BOX_PADDING) - + Self::BOX_MARGIN * 2.0; - let body_height = tab_list_height - Self::BOX_MARGIN * 2.0; - let head_width = Self::TAB_WIDTH + Self::SEPARATOR_WIDTH + body_width; + let head_width = Self::TAB_WIDTH + + Self::SEPARATOR_WIDTH + + Self::CONTENT_WIDTH + + self.scroll_bar.inner.style.body_width + + self.scroll_bar.inner.style.margin.x * 2.0; let head_inner_xy = Vec2::ZERO; let head_inner_size = Vec2::new(head_width, Self::HEAD_HEIGHT - Self::HEAD_RADIUS); let head_edge_xy = Vec2::new(Self::HEAD_RADIUS, Self::HEAD_HEIGHT - Self::HEAD_RADIUS); @@ -629,27 +699,14 @@ impl Widget for TabMenu { ctx.draw_quarter_circle(Corner::TopLeft, head_tl_xy, Self::HEAD_RADIUS, head_color); ctx.draw_quarter_circle(Corner::TopRight, head_tr_xy, Self::HEAD_RADIUS, head_color); - // placeholder inventory item boxes - let box_grid_stride = Self::BOX_SIZE + Self::BOX_PADDING; - let box_grid_height = (body_height / box_grid_stride).floor() as usize; - let box_rect_size = Vec2::new(Self::BOX_SIZE, Self::BOX_SIZE); - let box_grid_xy = Vec2::new( - Self::TAB_WIDTH + Self::SEPARATOR_WIDTH + Self::BOX_MARGIN, - -Self::BOX_MARGIN - Self::BOX_SIZE, - ); - let box_radius = 0.005; - - for x in 0..Self::BOX_GRID_WIDTH { - for y in 0..box_grid_height { - let box_rect_xy = Vec2::new(x as f32, -(y as f32)) * box_grid_stride + box_grid_xy; - ctx.draw_rounded_rect(box_rect_xy, box_rect_size, box_radius, head_color); - } - } + self.scroll_bar.draw(ctx); } fn on_cursor_event(&mut self, kind: CursorEventKind, at: Vec2) { for tab in self.tabs.iter_mut() { tab.on_cursor_event(kind, at); } + + self.scroll_bar.on_cursor_event(kind, at); } }