diff --git a/assets_gui/src/yakui_gui.rs b/assets_gui/src/yakui_gui.rs index b909d1af..e28a7d9d 100644 --- a/assets_gui/src/yakui_gui.rs +++ b/assets_gui/src/yakui_gui.rs @@ -1,4 +1,3 @@ -use yakui::shapes::RoundedRectangle; use yakui::widgets::{List, Pad, StateResponse, TextBox}; use yakui::{ align, center, colored_box_container, column, constrained, pad, row, use_state, Alignment, @@ -11,12 +10,11 @@ use engine::wgpu::RenderPass; use engine::{set_cursor_icon, CursorIcon, Drawable, GfxContext, Mesh, SpriteBatch}; use geom::Matrix4; use goryak::{ - background, button_primary, center_width, checkbox_value, combo_box, dragvalue, icon, - interact_box, is_hovered, labelc, on_background, on_primary_container, on_secondary, - on_secondary_container, on_surface, outline, outline_variant, primary_container, round_rect, - scroll_vertical, secondary, secondary_container, set_theme, stretch_width, surface, - surface_variant, tertiary, use_changed, CountGrid, Draggable, MainAxisAlignItems, RoundRect, - Theme, + background, button_primary, center_width, checkbox_value, combo_box, divider, dragvalue, icon, + interact_box_radius, is_hovered, labelc, on_background, on_secondary, on_secondary_container, + on_surface, outline, outline_variant, round_rect, scroll_vertical, secondary, + secondary_container, set_theme, stretch_width, surface, surface_variant, use_changed, + CountGrid, Draggable, MainAxisAlignItems, RoundRect, Theme, }; use crate::companies::Companies; @@ -130,7 +128,8 @@ impl State { folder: Option, on_click: impl FnOnce(), ) { - let r = interact_box( + divider(outline_variant(), 3.0, 1.0); + let r = interact_box_radius( if selected { surface_variant() } else { @@ -138,6 +137,7 @@ impl State { }, surface_variant(), surface_variant(), + 0.0, || { let mut p = Pad::ZERO; p.left = 4.0; @@ -161,7 +161,7 @@ impl State { }); }, ); - if r.just_clicked { + if r.clicked { on_click(); } } diff --git a/goryak/src/decoration.rs b/goryak/src/decoration.rs deleted file mode 100644 index eb03cdaa..00000000 --- a/goryak/src/decoration.rs +++ /dev/null @@ -1,18 +0,0 @@ -use yakui_core::geometry::{Color, Vec2}; -use yakui_core::paint::PaintRect; -use yakui_core::WidgetId; -use yakui_widgets::canvas; - -pub fn horiz_line(width_id: WidgetId) { - canvas(move |ctx| { - let w = ctx.layout.get(width_id).unwrap().rect.size().x; - let layout = ctx.layout.get(ctx.dom.current()).unwrap(); - - let mut r = layout.rect; - r.set_size(Vec2::new(w, 3.0)); - r.set_pos(Vec2::new(r.pos().x, r.pos().y - 3.0 / 2.0)); - let mut pr = PaintRect::new(r); - pr.color = Color::GRAY.adjust(0.8); - pr.add(ctx.paint); - }); -} diff --git a/goryak/src/divider.rs b/goryak/src/divider.rs new file mode 100644 index 00000000..be34a3e2 --- /dev/null +++ b/goryak/src/divider.rs @@ -0,0 +1,97 @@ +use yakui_core::geometry::{Color, Constraints, Rect, Vec2}; +use yakui_core::paint::PaintRect; +use yakui_core::widget::{LayoutContext, PaintContext, Widget}; +use yakui_core::Response; + +pub fn divider(color: Color, height: f32, thickness: f32) -> Response { + Divider::new(color, height, thickness).show() +} + +/// A horizontal divider line. Will take up the whole width of the parent. +/// +/// The line width is determined by the parent's width after the layout phase. +/// +/// Responds with [DividerResponse]. +#[derive(Debug)] +#[non_exhaustive] +pub struct Divider { + /// The color of the divider. + pub color: Color, + /// The thickness of the divider. + pub thickness: f32, + /// The height of the divider. + /// How much vertical space it takes up. + pub height: f32, + /// The indent of the divider from the left. + pub indent: f32, + /// The indent of the divider from the right. + pub end_indent: f32, +} + +impl Divider { + pub fn new(color: Color, height: f32, thickness: f32) -> Self { + Self { + color, + thickness, + height, + indent: 0.0, + end_indent: 0.0, + } + } + + pub fn show(self) -> Response { + yakui_widgets::util::widget::(self) + } +} + +#[derive(Debug)] +pub struct DividerWidget { + props: Divider, +} + +pub type DividerResponse = (); + +impl Widget for DividerWidget { + type Props<'a> = Divider; + type Response = DividerResponse; + + fn new() -> Self { + Self { + props: Divider::new(Color::WHITE, 0.0, 0.0), + } + } + + fn update(&mut self, props: Self::Props<'_>) -> Self::Response { + self.props = props; + } + + fn layout(&self, _ctx: LayoutContext<'_>, input: Constraints) -> Vec2 { + // We say we dont take horizontal space to avoid the divider making + // the parent wider than it should be. + Vec2::new(0.0, self.props.height.clamp(input.min.y, input.max.y)) + } + + fn paint(&self, ctx: PaintContext<'_>) { + let id = ctx.dom.current(); + let Some(parent) = ctx.dom.get(id).unwrap().parent else { + return; + }; + let line_width = ctx.layout.get(parent).unwrap().rect.size().x; + + let outer_rect = ctx.layout.get(id).unwrap().rect; + + let line_pos = outer_rect.pos() + + Vec2::new( + self.props.indent, + (outer_rect.size().y - self.props.thickness) / 2.0, + ); + let line_size = Vec2::new( + line_width - self.props.indent - self.props.end_indent, + self.props.thickness, + ); + + let mut line_rect = PaintRect::new(Rect::from_pos_size(line_pos, line_size)); + line_rect.color = self.props.color; + line_rect.add(ctx.paint); + } +} diff --git a/goryak/src/interact_box.rs b/goryak/src/interact_box.rs index 6ac5663a..36619604 100644 --- a/goryak/src/interact_box.rs +++ b/goryak/src/interact_box.rs @@ -5,6 +5,7 @@ use yakui_core::paint::PaintRect; use yakui_core::widget::{EventContext, LayoutContext, PaintContext, Widget}; use yakui_core::Response; use yakui_widgets::shapes::RoundedRectangle; +use yakui_widgets::widgets::{Pad, PadWidget}; /** A colored box that can contain children. @@ -15,8 +16,9 @@ Responds with [InteractBoxResponse]. pub struct InteractBox { pub color: Color, pub hover_color: Color, - pub click_color: Color, + pub active_color: Color, pub border_radius: f32, + pub padding: Pad, } impl InteractBox { @@ -24,8 +26,9 @@ impl InteractBox { Self { color: Color::WHITE, hover_color: Color::WHITE, - click_color: Color::WHITE, + active_color: Color::WHITE, border_radius: 0.0, + padding: Pad::ZERO, } } @@ -41,15 +44,16 @@ impl InteractBox { pub fn interact_box_radius( color: Color, hover_color: Color, - click_color: Color, + active_color: Color, border_radius: f32, children: impl FnOnce(), ) -> Response { InteractBox { color, hover_color, - click_color, + active_color, border_radius, + padding: Pad::ZERO, } .show_children(children) } @@ -57,14 +61,15 @@ pub fn interact_box_radius( pub fn interact_box( color: Color, hover_color: Color, - click_color: Color, + active_color: Color, children: impl FnOnce(), ) -> Response { InteractBox { color, hover_color, - click_color, + active_color, border_radius: 0.0, + padding: Pad::ZERO, } .show_children(children) } @@ -77,10 +82,10 @@ pub struct InteractBoxWidget { #[derive(Copy, Clone, Debug, Default)] pub struct InteractBoxResponse { - pub hovered: bool, - pub mousedown: bool, - pub just_hovered: bool, - pub just_clicked: bool, + pub hovering: bool, + pub mouse_down: bool, + pub mouse_entered: bool, + pub clicked: bool, } impl Widget for InteractBoxWidget { @@ -97,8 +102,8 @@ impl Widget for InteractBoxWidget { fn update(&mut self, props: Self::Props<'_>) -> Self::Response { self.props = props; let resp = self.resp; - self.resp.just_hovered = false; - self.resp.just_clicked = false; + self.resp.mouse_entered = false; + self.resp.clicked = false; resp } @@ -106,9 +111,9 @@ impl Widget for InteractBoxWidget { let node = ctx.dom.get_current(); let layout_node = ctx.layout.get(ctx.dom.current()).unwrap(); - let curcolor = if self.resp.mousedown { - self.props.click_color - } else if self.resp.hovered { + let curcolor = if self.resp.mouse_down { + self.props.active_color + } else if self.resp.hovering { self.props.hover_color } else { self.props.color @@ -133,15 +138,21 @@ impl Widget for InteractBoxWidget { EventInterest::MOUSE_ALL } + fn layout(&self, ctx: LayoutContext<'_>, constraints: Constraints) -> Vec2 { + let mut p = PadWidget::new(); + p.update(self.props.padding); + p.layout(ctx, constraints) + } + fn event(&mut self, _: EventContext<'_>, event: &WidgetEvent) -> EventResponse { match event { WidgetEvent::MouseEnter => { - self.resp.just_hovered = true; - self.resp.hovered = true; + self.resp.mouse_entered = true; + self.resp.hovering = true; EventResponse::Bubble } WidgetEvent::MouseLeave => { - self.resp.hovered = false; + self.resp.hovering = false; EventResponse::Bubble } WidgetEvent::MouseButtonChanged { @@ -151,10 +162,10 @@ impl Widget for InteractBoxWidget { .. } => { if *down && *inside { - self.resp.just_clicked = true; - self.resp.mousedown = true; + self.resp.clicked = true; + self.resp.mouse_down = true; } else { - self.resp.mousedown = false; + self.resp.mouse_down = false; } EventResponse::Bubble } diff --git a/goryak/src/lib.rs b/goryak/src/lib.rs index 56791ee0..28c34a0c 100644 --- a/goryak/src/lib.rs +++ b/goryak/src/lib.rs @@ -1,6 +1,6 @@ mod combo_box; mod count_grid; -mod decoration; +mod divider; mod dragvalue; mod hovered; mod icon; @@ -13,7 +13,7 @@ mod util; pub use combo_box::*; pub use count_grid::*; -pub use decoration::*; +pub use divider::*; pub use dragvalue::*; pub use hovered::*; pub use icon::icon; diff --git a/goryak/src/roundrect.rs b/goryak/src/roundrect.rs index 98f8eb17..3193a2cd 100644 --- a/goryak/src/roundrect.rs +++ b/goryak/src/roundrect.rs @@ -114,7 +114,8 @@ impl Widget for RoundRectWidget { inner_rect.set_pos(inner_rect.pos() + Vec2::splat(thickness)); if self.props.radius > 0.0 { - let mut inner_rect = shapes::RoundedRectangle::new(inner_rect, self.props.radius); + let mut inner_rect = + shapes::RoundedRectangle::new(inner_rect, self.props.radius - thickness); inner_rect.color = self.props.color; inner_rect.add(ctx.paint); } else { diff --git a/goryak/src/util.rs b/goryak/src/util.rs index 0aaa33c4..6e575e42 100644 --- a/goryak/src/util.rs +++ b/goryak/src/util.rs @@ -4,12 +4,9 @@ use std::panic::Location; use yakui_core::geometry::{Color, Constraints, Vec2}; use yakui_core::widget::{LayoutContext, PaintContext, Widget}; use yakui_core::{Response, WidgetId}; -use yakui_widgets::font::FontName; use yakui_widgets::util::widget; use yakui_widgets::widgets::{Button, ButtonResponse, Text}; -use yakui_widgets::{center, constrained, max_width}; -use crate::icon::ICON_NAME_MAPPING; use crate::{on_primary, on_secondary, primary, secondary, Scrollable, ScrollableResponse}; pub fn scroll_vertical(children: impl FnOnce()) -> Response {