From 3a1d67784097e870e159c1be262466abf9048023 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 10 May 2020 08:55:41 +0200 Subject: [PATCH] refactor interact style --- emigui/src/color.rs | 13 +- emigui/src/containers/collapsing_header.rs | 12 +- emigui/src/containers/resize.rs | 4 +- emigui/src/containers/scroll_area.rs | 4 +- emigui/src/style.rs | 151 ++++++++++++--------- emigui/src/types.rs | 6 +- emigui/src/ui.rs | 4 + emigui/src/widgets.rs | 20 +-- emigui/src/widgets/slider.rs | 6 +- emigui/src/widgets/text_edit.rs | 2 +- 10 files changed, 135 insertions(+), 87 deletions(-) diff --git a/emigui/src/color.rs b/emigui/src/color.rs index 4697d1ee..e123a918 100644 --- a/emigui/src/color.rs +++ b/emigui/src/color.rs @@ -1,5 +1,7 @@ +use serde_derive::{Deserialize, Serialize}; + /// 0-255 `sRGBA`. TODO: rename `sRGBA` for clarity. -#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, serde_derive::Serialize)] +#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd, Deserialize, Serialize)] pub struct Color { pub r: u8, pub g: u8, @@ -31,6 +33,15 @@ pub const fn gray(l: u8, a: u8) -> Color { } } +pub const fn white(a: u8) -> Color { + Color { + r: 255, + g: 255, + b: 255, + a, + } +} + pub const BLACK: Color = srgba(0, 0, 0, 255); pub const LIGHT_GRAY: Color = srgba(220, 220, 220, 255); pub const WHITE: Color = srgba(255, 255, 255, 255); diff --git a/emigui/src/containers/collapsing_header.rs b/emigui/src/containers/collapsing_header.rs index 68b8601e..87d1e63d 100644 --- a/emigui/src/containers/collapsing_header.rs +++ b/emigui/src/containers/collapsing_header.rs @@ -93,15 +93,15 @@ impl CollapsingHeader { text_pos, label.text_style, title, - Some(ui.style().interact_stroke_color(&interact)), + Some(ui.style().interact(&interact).stroke_color), ); ui.insert_paint_cmd( where_to_put_background, PaintCmd::Rect { - corner_radius: ui.style().interact_corner_radius(&interact), - fill_color: ui.style().interact_fill_color(&interact), - outline: ui.style().interact_outline(&interact), + corner_radius: ui.style().interact(&interact).corner_radius, + fill_color: ui.style().interact(&interact).fill_color, + outline: ui.style().interact(&interact).outline, rect: interact.rect, }, ); @@ -147,8 +147,8 @@ impl CollapsingHeader { } fn paint_icon(ui: &mut Ui, state: &State, interact: &InteractInfo) { - let stroke_color = ui.style().interact_stroke_color(interact); - let stroke_width = ui.style().interact_stroke_width(interact); + let stroke_color = ui.style().interact(interact).stroke_color; + let stroke_width = ui.style().interact(interact).stroke_width; let (mut small_icon_rect, _) = ui.style().icon_rectangles(interact.rect); small_icon_rect.set_center(pos2( diff --git a/emigui/src/containers/resize.rs b/emigui/src/containers/resize.rs index 8348c7e2..0a577340 100644 --- a/emigui/src/containers/resize.rs +++ b/emigui/src/containers/resize.rs @@ -235,8 +235,8 @@ impl Resize { } fn paint_resize_corner(ui: &mut Ui, interact: &InteractInfo) { - let color = ui.style().interact_stroke_color(interact); - let width = ui.style().interact_stroke_width(interact); + let color = ui.style().interact(interact).stroke_color; + let width = ui.style().interact(interact).stroke_width; let corner = interact.rect.right_bottom().round(); // TODO: round to pixels let mut w = 2.0; diff --git a/emigui/src/containers/scroll_area.rs b/emigui/src/containers/scroll_area.rs index ef443391..2d3f9b78 100644 --- a/emigui/src/containers/scroll_area.rs +++ b/emigui/src/containers/scroll_area.rs @@ -164,8 +164,8 @@ impl ScrollArea { ); let style = outer_ui.style(); - let handle_fill_color = style.interact_fill_color(&handle_interact); - let handle_outline = style.interact_outline(&handle_interact); + let handle_fill_color = style.interact(&handle_interact).fill_color; + let handle_outline = style.interact(&handle_interact).outline; outer_ui.add_paint_cmd(PaintCmd::Rect { rect: outer_scroll_rect, diff --git a/emigui/src/style.rs b/emigui/src/style.rs index bf03556d..d38d59a9 100644 --- a/emigui/src/style.rs +++ b/emigui/src/style.rs @@ -25,6 +25,8 @@ pub struct Style { /// The text starts after this many pixels. pub start_icon_width: f32, + pub interact: Interact, + // ----------------------------------------------- // Purely visual: /// For stuff like check marks in check boxes. @@ -39,6 +41,8 @@ pub struct Style { pub window: Window, + pub menu_bar: MenuBar, + /// Allow child widgets to be just on the border and still have an outline with some thickness pub clip_rect_margin: f32, @@ -47,11 +51,6 @@ pub struct Style { pub debug_widget_rects: bool, } -#[derive(Clone, Copy, Debug, Deserialize, Serialize)] -pub struct Window { - pub corner_radius: f32, -} - impl Default for Style { fn default() -> Self { Self { @@ -61,17 +60,89 @@ impl Default for Style { indent: 21.0, clickable_diameter: 22.0, start_icon_width: 16.0, + interact: Default::default(), line_width: 1.0, cursor_blink_hz: 1.0, text_cursor_width: 2.0, animation_time: 1.0 / 20.0, window: Window::default(), + menu_bar: MenuBar::default(), clip_rect_margin: 3.0, debug_widget_rects: false, } } } +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct Interact { + pub active: WidgetStyle, + pub hovered: WidgetStyle, + pub inactive: WidgetStyle, +} + +impl Default for Interact { + fn default() -> Self { + Self { + active: WidgetStyle { + fill_color: Some(srgba(120, 120, 200, 255)), + stroke_color: WHITE, + stroke_width: 2.0, + outline: Some(Outline::new(2.0, WHITE)), + corner_radius: 5.0, + }, + hovered: WidgetStyle { + fill_color: Some(srgba(100, 100, 150, 255)), + stroke_color: WHITE, + stroke_width: 1.5, + outline: None, + corner_radius: 5.0, + }, + inactive: WidgetStyle { + fill_color: Some(srgba(60, 60, 80, 255)), + stroke_color: gray(220, 255), // Mustn't look grayed out! + stroke_width: 1.0, + outline: None, + corner_radius: 0.0, + }, + } + } +} + +impl Interact { + pub fn style(&self, interact: &InteractInfo) -> &WidgetStyle { + if interact.active { + &self.active + } else if interact.hovered { + &self.hovered + } else { + &self.inactive + } + } +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct WidgetStyle { + /// Fill color of the interactive part of a component (button, slider grab, checkbox, ...) + pub fill_color: Option, + + /// Stroke and text color of the interactive part of a component (button, slider grab, checkbox, ...) + pub stroke_color: Color, + + /// For lines etc + pub stroke_width: f32, + + /// For rectangles + pub outline: Option, + + /// Button frames etdc + pub corner_radius: f32, +} + +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct Window { + pub corner_radius: f32, +} + impl Default for Window { fn default() -> Self { Self { @@ -80,6 +151,17 @@ impl Default for Window { } } +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct MenuBar { + pub height: f32, +} + +impl Default for MenuBar { + fn default() -> Self { + Self { height: 16.0 } + } +} + impl Style { /// e.g. the background of the slider pub fn background_fill_color(&self) -> Color { @@ -90,62 +172,9 @@ impl Style { gray(255, 200) } - /// Fill color of the interactive part of a component (button, slider grab, checkbox, ...) - pub fn interact_fill_color(&self, interact: &InteractInfo) -> Option { - if interact.active { - Some(srgba(120, 120, 200, 255)) - } else if interact.hovered { - Some(srgba(100, 100, 150, 255)) - } else { - Some(srgba(60, 60, 80, 255)) - } - } - - /// Stroke and text color of the interactive part of a component (button, slider grab, checkbox, ...) - pub fn interact_stroke_color(&self, interact: &InteractInfo) -> Color { - if interact.active { - gray(255, 255) - } else if interact.hovered { - gray(255, 255) - } else { - gray(220, 255) // Mustn't look grayed out! - } - } - - /// For lines etc - pub fn interact_stroke_width(&self, interact: &InteractInfo) -> f32 { - if interact.active { - 2.0 - } else if interact.hovered { - 1.5 - } else { - 1.0 - } - } - - /// For rectangles - pub fn interact_outline(&self, interact: &InteractInfo) -> Option { - if interact.active { - Some(Outline::new( - self.interact_stroke_width(interact), - self.interact_stroke_color(interact), - )) - } else if interact.hovered { - None - } else { - None - } - } - - /// Buttons etc - pub fn interact_corner_radius(&self, interact: &InteractInfo) -> f32 { - if interact.active { - 5.0 - } else if interact.hovered { - 5.0 - } else { - 0.0 - } + /// Use this style for interactive things + pub fn interact(&self, interact: &InteractInfo) -> &WidgetStyle { + self.interact.style(interact) } /// Returns small icon rectangle and big icon rectangle diff --git a/emigui/src/types.rs b/emigui/src/types.rs index e9c0a5b2..1978e069 100644 --- a/emigui/src/types.rs +++ b/emigui/src/types.rs @@ -1,4 +1,4 @@ -use serde_derive::Serialize; +use serde_derive::{Deserialize, Serialize}; use crate::{ color::Color, @@ -55,7 +55,7 @@ pub struct InteractInfo { // ---------------------------------------------------------------------------- -#[derive(Clone, Debug, Serialize)] +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] pub struct Outline { pub width: f32, pub color: Color, @@ -101,7 +101,7 @@ pub enum PaintCmd { /// Top left corner of the first character. pos: Pos2, text: String, - text_style: TextStyle, + text_style: TextStyle, // TODO: Font /// Start each character in the text, as offset from pos. x_offsets: Vec, // TODO: font info diff --git a/emigui/src/ui.rs b/emigui/src/ui.rs index bdae0ffc..15557861 100644 --- a/emigui/src/ui.rs +++ b/emigui/src/ui.rs @@ -115,6 +115,10 @@ impl Ui { &self.style } + pub fn set_style(&mut self, style: Style) { + self.style = style + } + pub fn ctx(&self) -> &Arc { &self.ctx } diff --git a/emigui/src/widgets.rs b/emigui/src/widgets.rs index e4b67135..ecf79b58 100644 --- a/emigui/src/widgets.rs +++ b/emigui/src/widgets.rs @@ -37,6 +37,10 @@ impl Label { } } + pub fn text(&self) -> &str { + &self.text + } + pub fn multiline(mut self, multiline: bool) -> Self { self.multiline = multiline; self @@ -189,12 +193,12 @@ impl Widget for Button { let mut text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * text_size.y); text_cursor.y += 2.0; // TODO: why is this needed? ui.add_paint_cmd(PaintCmd::Rect { - corner_radius: ui.style().interact_corner_radius(&interact), - fill_color: ui.style().interact_fill_color(&interact), - outline: ui.style().interact_outline(&interact), + corner_radius: ui.style().interact(&interact).corner_radius, + fill_color: ui.style().interact(&interact).fill_color, + outline: ui.style().interact(&interact).outline, rect: interact.rect, }); - let stroke_color = ui.style().interact_stroke_color(&interact); + let stroke_color = ui.style().interact(&interact).stroke_color; let text_color = self.text_color.unwrap_or(stroke_color); ui.add_text(text_cursor, text_style, text, Some(text_color)); ui.response(interact) @@ -246,12 +250,12 @@ impl<'a> Widget for Checkbox<'a> { let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect); ui.add_paint_cmd(PaintCmd::Rect { corner_radius: 3.0, - fill_color: ui.style().interact_fill_color(&interact), + fill_color: ui.style().interact(&interact).fill_color, outline: None, rect: big_icon_rect, }); - let stroke_color = ui.style().interact_stroke_color(&interact); + let stroke_color = ui.style().interact(&interact).stroke_color; if *self.checked { ui.add_paint_cmd(PaintCmd::Line { @@ -315,8 +319,8 @@ impl Widget for RadioButton { let text_cursor = interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0); - let fill_color = ui.style().interact_fill_color(&interact); - let stroke_color = ui.style().interact_stroke_color(&interact); + let fill_color = ui.style().interact(&interact).fill_color; + let stroke_color = ui.style().interact(&interact).stroke_color; let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect); diff --git a/emigui/src/widgets/slider.rs b/emigui/src/widgets/slider.rs index 623f925d..75c791b2 100644 --- a/emigui/src/widgets/slider.rs +++ b/emigui/src/widgets/slider.rs @@ -184,10 +184,10 @@ impl<'a> Widget for Slider<'a> { ui.add_paint_cmd(PaintCmd::Circle { center: pos2(marker_center_x, rail_rect.center().y), radius: handle_radius, - fill_color: ui.style().interact_fill_color(&interact), + fill_color: ui.style().interact(&interact).fill_color, outline: Some(Outline::new( - ui.style().interact_stroke_width(&interact), - ui.style().interact_stroke_color(&interact), + ui.style().interact(&interact).stroke_width, + ui.style().interact(&interact).stroke_color, )), }); } diff --git a/emigui/src/widgets/text_edit.rs b/emigui/src/widgets/text_edit.rs index f8e62a24..8ce2002e 100644 --- a/emigui/src/widgets/text_edit.rs +++ b/emigui/src/widgets/text_edit.rs @@ -80,7 +80,7 @@ impl<'t> Widget for TextEdit<'t> { rect: interact.rect, corner_radius: 0.0, // fill_color: Some(color::BLACK), - fill_color: ui.style().interact_fill_color(&interact), + fill_color: ui.style().interact(&interact).fill_color, // fill_color: Some(ui.style().background_fill_color()), outline: None, //Some(Outline::new(1.0, color::WHITE)), });