refactor interact style

This commit is contained in:
Emil Ernerfeldt 2020-05-10 08:55:41 +02:00
parent 2bd610cb5b
commit 3a1d677840
10 changed files with 135 additions and 87 deletions

View file

@ -1,5 +1,7 @@
use serde_derive::{Deserialize, Serialize};
/// 0-255 `sRGBA`. TODO: rename `sRGBA` for clarity. /// 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 struct Color {
pub r: u8, pub r: u8,
pub g: 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 BLACK: Color = srgba(0, 0, 0, 255);
pub const LIGHT_GRAY: Color = srgba(220, 220, 220, 255); pub const LIGHT_GRAY: Color = srgba(220, 220, 220, 255);
pub const WHITE: Color = srgba(255, 255, 255, 255); pub const WHITE: Color = srgba(255, 255, 255, 255);

View file

@ -93,15 +93,15 @@ impl CollapsingHeader {
text_pos, text_pos,
label.text_style, label.text_style,
title, title,
Some(ui.style().interact_stroke_color(&interact)), Some(ui.style().interact(&interact).stroke_color),
); );
ui.insert_paint_cmd( ui.insert_paint_cmd(
where_to_put_background, where_to_put_background,
PaintCmd::Rect { PaintCmd::Rect {
corner_radius: ui.style().interact_corner_radius(&interact), corner_radius: ui.style().interact(&interact).corner_radius,
fill_color: ui.style().interact_fill_color(&interact), fill_color: ui.style().interact(&interact).fill_color,
outline: ui.style().interact_outline(&interact), outline: ui.style().interact(&interact).outline,
rect: interact.rect, rect: interact.rect,
}, },
); );
@ -147,8 +147,8 @@ impl CollapsingHeader {
} }
fn paint_icon(ui: &mut Ui, state: &State, interact: &InteractInfo) { fn paint_icon(ui: &mut Ui, state: &State, interact: &InteractInfo) {
let stroke_color = ui.style().interact_stroke_color(interact); let stroke_color = ui.style().interact(interact).stroke_color;
let stroke_width = ui.style().interact_stroke_width(interact); let stroke_width = ui.style().interact(interact).stroke_width;
let (mut small_icon_rect, _) = ui.style().icon_rectangles(interact.rect); let (mut small_icon_rect, _) = ui.style().icon_rectangles(interact.rect);
small_icon_rect.set_center(pos2( small_icon_rect.set_center(pos2(

View file

@ -235,8 +235,8 @@ impl Resize {
} }
fn paint_resize_corner(ui: &mut Ui, interact: &InteractInfo) { fn paint_resize_corner(ui: &mut Ui, interact: &InteractInfo) {
let color = ui.style().interact_stroke_color(interact); let color = ui.style().interact(interact).stroke_color;
let width = ui.style().interact_stroke_width(interact); let width = ui.style().interact(interact).stroke_width;
let corner = interact.rect.right_bottom().round(); // TODO: round to pixels let corner = interact.rect.right_bottom().round(); // TODO: round to pixels
let mut w = 2.0; let mut w = 2.0;

View file

@ -164,8 +164,8 @@ impl ScrollArea {
); );
let style = outer_ui.style(); let style = outer_ui.style();
let handle_fill_color = style.interact_fill_color(&handle_interact); let handle_fill_color = style.interact(&handle_interact).fill_color;
let handle_outline = style.interact_outline(&handle_interact); let handle_outline = style.interact(&handle_interact).outline;
outer_ui.add_paint_cmd(PaintCmd::Rect { outer_ui.add_paint_cmd(PaintCmd::Rect {
rect: outer_scroll_rect, rect: outer_scroll_rect,

View file

@ -25,6 +25,8 @@ pub struct Style {
/// The text starts after this many pixels. /// The text starts after this many pixels.
pub start_icon_width: f32, pub start_icon_width: f32,
pub interact: Interact,
// ----------------------------------------------- // -----------------------------------------------
// Purely visual: // Purely visual:
/// For stuff like check marks in check boxes. /// For stuff like check marks in check boxes.
@ -39,6 +41,8 @@ pub struct Style {
pub window: Window, pub window: Window,
pub menu_bar: MenuBar,
/// Allow child widgets to be just on the border and still have an outline with some thickness /// Allow child widgets to be just on the border and still have an outline with some thickness
pub clip_rect_margin: f32, pub clip_rect_margin: f32,
@ -47,11 +51,6 @@ pub struct Style {
pub debug_widget_rects: bool, pub debug_widget_rects: bool,
} }
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Window {
pub corner_radius: f32,
}
impl Default for Style { impl Default for Style {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -61,17 +60,89 @@ impl Default for Style {
indent: 21.0, indent: 21.0,
clickable_diameter: 22.0, clickable_diameter: 22.0,
start_icon_width: 16.0, start_icon_width: 16.0,
interact: Default::default(),
line_width: 1.0, line_width: 1.0,
cursor_blink_hz: 1.0, cursor_blink_hz: 1.0,
text_cursor_width: 2.0, text_cursor_width: 2.0,
animation_time: 1.0 / 20.0, animation_time: 1.0 / 20.0,
window: Window::default(), window: Window::default(),
menu_bar: MenuBar::default(),
clip_rect_margin: 3.0, clip_rect_margin: 3.0,
debug_widget_rects: false, 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<Color>,
/// 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<Outline>,
/// Button frames etdc
pub corner_radius: f32,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Window {
pub corner_radius: f32,
}
impl Default for Window { impl Default for Window {
fn default() -> Self { fn default() -> Self {
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 { impl Style {
/// e.g. the background of the slider /// e.g. the background of the slider
pub fn background_fill_color(&self) -> Color { pub fn background_fill_color(&self) -> Color {
@ -90,62 +172,9 @@ impl Style {
gray(255, 200) gray(255, 200)
} }
/// Fill color of the interactive part of a component (button, slider grab, checkbox, ...) /// Use this style for interactive things
pub fn interact_fill_color(&self, interact: &InteractInfo) -> Option<Color> { pub fn interact(&self, interact: &InteractInfo) -> &WidgetStyle {
if interact.active { self.interact.style(interact)
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<Outline> {
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
}
} }
/// Returns small icon rectangle and big icon rectangle /// Returns small icon rectangle and big icon rectangle

View file

@ -1,4 +1,4 @@
use serde_derive::Serialize; use serde_derive::{Deserialize, Serialize};
use crate::{ use crate::{
color::Color, color::Color,
@ -55,7 +55,7 @@ pub struct InteractInfo {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Outline { pub struct Outline {
pub width: f32, pub width: f32,
pub color: Color, pub color: Color,
@ -101,7 +101,7 @@ pub enum PaintCmd {
/// Top left corner of the first character. /// Top left corner of the first character.
pos: Pos2, pos: Pos2,
text: String, text: String,
text_style: TextStyle, text_style: TextStyle, // TODO: Font
/// Start each character in the text, as offset from pos. /// Start each character in the text, as offset from pos.
x_offsets: Vec<f32>, x_offsets: Vec<f32>,
// TODO: font info // TODO: font info

View file

@ -115,6 +115,10 @@ impl Ui {
&self.style &self.style
} }
pub fn set_style(&mut self, style: Style) {
self.style = style
}
pub fn ctx(&self) -> &Arc<Context> { pub fn ctx(&self) -> &Arc<Context> {
&self.ctx &self.ctx
} }

View file

@ -37,6 +37,10 @@ impl Label {
} }
} }
pub fn text(&self) -> &str {
&self.text
}
pub fn multiline(mut self, multiline: bool) -> Self { pub fn multiline(mut self, multiline: bool) -> Self {
self.multiline = multiline; self.multiline = multiline;
self 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); 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? text_cursor.y += 2.0; // TODO: why is this needed?
ui.add_paint_cmd(PaintCmd::Rect { ui.add_paint_cmd(PaintCmd::Rect {
corner_radius: ui.style().interact_corner_radius(&interact), corner_radius: ui.style().interact(&interact).corner_radius,
fill_color: ui.style().interact_fill_color(&interact), fill_color: ui.style().interact(&interact).fill_color,
outline: ui.style().interact_outline(&interact), outline: ui.style().interact(&interact).outline,
rect: interact.rect, 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); let text_color = self.text_color.unwrap_or(stroke_color);
ui.add_text(text_cursor, text_style, text, Some(text_color)); ui.add_text(text_cursor, text_style, text, Some(text_color));
ui.response(interact) 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); let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);
ui.add_paint_cmd(PaintCmd::Rect { ui.add_paint_cmd(PaintCmd::Rect {
corner_radius: 3.0, corner_radius: 3.0,
fill_color: ui.style().interact_fill_color(&interact), fill_color: ui.style().interact(&interact).fill_color,
outline: None, outline: None,
rect: big_icon_rect, 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 { if *self.checked {
ui.add_paint_cmd(PaintCmd::Line { ui.add_paint_cmd(PaintCmd::Line {
@ -315,8 +319,8 @@ impl Widget for RadioButton {
let text_cursor = let text_cursor =
interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0); 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 fill_color = ui.style().interact(&interact).fill_color;
let stroke_color = ui.style().interact_stroke_color(&interact); let stroke_color = ui.style().interact(&interact).stroke_color;
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect); let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);

View file

@ -184,10 +184,10 @@ impl<'a> Widget for Slider<'a> {
ui.add_paint_cmd(PaintCmd::Circle { ui.add_paint_cmd(PaintCmd::Circle {
center: pos2(marker_center_x, rail_rect.center().y), center: pos2(marker_center_x, rail_rect.center().y),
radius: handle_radius, radius: handle_radius,
fill_color: ui.style().interact_fill_color(&interact), fill_color: ui.style().interact(&interact).fill_color,
outline: Some(Outline::new( outline: Some(Outline::new(
ui.style().interact_stroke_width(&interact), ui.style().interact(&interact).stroke_width,
ui.style().interact_stroke_color(&interact), ui.style().interact(&interact).stroke_color,
)), )),
}); });
} }

View file

@ -80,7 +80,7 @@ impl<'t> Widget for TextEdit<'t> {
rect: interact.rect, rect: interact.rect,
corner_radius: 0.0, corner_radius: 0.0,
// fill_color: Some(color::BLACK), // 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()), // fill_color: Some(ui.style().background_fill_color()),
outline: None, //Some(Outline::new(1.0, color::WHITE)), outline: None, //Some(Outline::new(1.0, color::WHITE)),
}); });