Browse Source

[style] tweak style, and refactor struct Style

pull/22/head
Emil Ernerfeldt 4 years ago
parent
commit
9578773613
  1. 27
      egui/src/containers/frame.rs
  2. 2
      egui/src/containers/resize.rs
  3. 10
      egui/src/containers/scroll_area.rs
  4. 6
      egui/src/containers/window.rs
  5. 42
      egui/src/menu.rs
  6. 74
      egui/src/style.rs
  7. 2
      egui/src/ui.rs
  8. 61
      egui/src/widgets.rs
  9. 23
      egui/src/widgets/slider.rs
  10. 13
      egui/src/widgets/text_edit.rs

27
egui/src/containers/frame.rs

@ -3,7 +3,7 @@
use crate::{layers::PaintCmdIdx, paint::*, *};
/// Adds a rectangular frame and background to some `Ui`.
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug)]
pub struct Frame {
// On each side
pub margin: Vec2,
@ -13,12 +13,21 @@ pub struct Frame {
}
impl Frame {
pub fn none() -> Self {
Self {
margin: Vec2::zero(),
corner_radius: 0.0,
fill: Default::default(),
stroke: Stroke::none(),
}
}
pub fn window(style: &Style) -> Self {
Self {
margin: style.spacing.window_padding,
corner_radius: style.visuals.window_corner_radius,
fill: style.visuals.background_fill,
stroke: style.visuals.interacted.inactive.bg_stroke, // because we can resize windows
fill: style.visuals.widgets.noninteractive.bg_fill,
stroke: style.visuals.widgets.inactive.bg_stroke, // because we can resize windows
}
}
@ -26,8 +35,8 @@ impl Frame {
Self {
margin: Vec2::splat(1.0),
corner_radius: 0.0,
fill: style.visuals.background_fill,
stroke: Stroke::new(0.5, Srgba::gray(128)),
fill: style.visuals.widgets.noninteractive.bg_fill,
stroke: style.visuals.widgets.noninteractive.bg_stroke,
}
}
@ -35,8 +44,8 @@ impl Frame {
Self {
margin: Vec2::splat(1.0),
corner_radius: 2.0,
fill: style.visuals.background_fill,
stroke: Stroke::new(1.0, Srgba::gray(128)),
fill: style.visuals.widgets.noninteractive.bg_fill,
stroke: style.visuals.widgets.noninteractive.bg_stroke,
}
}
@ -44,8 +53,8 @@ impl Frame {
Self {
margin: style.spacing.window_padding,
corner_radius: 5.0,
fill: style.visuals.background_fill,
stroke: Stroke::new(1.0, Srgba::gray(128)),
fill: style.visuals.widgets.noninteractive.bg_fill,
stroke: style.visuals.widgets.noninteractive.bg_stroke,
}
}

2
egui/src/containers/resize.rs

@ -238,7 +238,7 @@ impl Resize {
rect,
corner_radius: 3.0,
fill: Default::default(),
stroke: ui.style().visuals.thin_stroke,
stroke: ui.style().visuals.widgets.noninteractive.bg_stroke,
});
}

10
egui/src/containers/scroll_area.rs

@ -259,22 +259,22 @@ impl Prepared {
);
}
let style = ui.style();
let handle_fill = style.interact(&response).fg_fill;
let handle_stroke = style.interact(&response).bg_stroke;
let visuals = ui.style().interact(&response);
ui.painter().add(paint::PaintCmd::Rect {
rect: outer_scroll_rect,
corner_radius,
fill: ui.style().visuals.dark_bg_color,
stroke: Default::default(),
// fill: visuals.bg_fill,
// stroke: visuals.bg_stroke,
});
ui.painter().add(paint::PaintCmd::Rect {
rect: handle_rect.expand(-2.0),
corner_radius,
fill: handle_fill,
stroke: handle_stroke,
fill: visuals.fg_fill,
stroke: visuals.fg_stroke,
});
}

6
egui/src/containers/window.rs

@ -294,14 +294,14 @@ impl<'open> Window<'open> {
&mut area_content_ui,
outer_rect,
interaction,
ctx.style().visuals.interacted.active,
ctx.style().visuals.widgets.active,
);
} else if let Some(hover_interaction) = hover_interaction {
paint_frame_interaction(
&mut area_content_ui,
outer_rect,
hover_interaction,
ctx.style().visuals.interacted.hovered,
ctx.style().visuals.widgets.hovered,
);
}
}
@ -678,7 +678,7 @@ impl TitleBar {
let y = content_rect.top() + ui.style().spacing.item_spacing.y * 0.5;
ui.painter().line_segment(
[pos2(left, y), pos2(right, y)],
ui.style().visuals.interacted.inactive.bg_stroke,
ui.style().visuals.widgets.inactive.bg_stroke,
);
}

42
egui/src/menu.rs

@ -62,12 +62,12 @@ pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect)
Frame::menu_bar(ui.style()).show(ui, |ui| {
let mut style = ui.style().clone();
style.spacing.button_padding = vec2(2.0, 0.0);
// style.visuals.interacted.active.bg_fill = TRANSPARENT;
style.visuals.interacted.active.bg_stroke = Stroke::none();
// style.visuals.interacted.hovered.bg_fill = TRANSPARENT;
style.visuals.interacted.hovered.bg_stroke = Stroke::none();
style.visuals.interacted.inactive.bg_fill = TRANSPARENT;
style.visuals.interacted.inactive.bg_stroke = Stroke::none();
// style.visuals.widgets.active.bg_fill = TRANSPARENT;
style.visuals.widgets.active.bg_stroke = Stroke::none();
// style.visuals.widgets.hovered.bg_fill = TRANSPARENT;
style.visuals.widgets.hovered.bg_stroke = Stroke::none();
style.visuals.widgets.inactive.bg_fill = TRANSPARENT;
style.visuals.widgets.inactive.bg_stroke = Stroke::none();
ui.set_style(style);
// Take full width and fixed height:
@ -77,7 +77,7 @@ pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect)
let ret = add_contents(ui);
let clicked_outside = !ui.hovered(ui.rect()) && ui.input().mouse.released;
let clicked_outside = !ui.hovered(ui.rect()) && ui.input().mouse.click;
if clicked_outside || ui.input().key_pressed(Key::Escape) {
// TODO: this prevents sub-menus in menus. We should fix that.
let bar_id = ui.id();
@ -108,7 +108,7 @@ fn menu_impl<'c>(
let mut button = Button::new(title);
if bar_state.open_menu == Some(menu_id) {
button = button.fill(Some(ui.style().visuals.interacted.active.fg_fill));
button = button.fill(Some(ui.style().visuals.widgets.active.fg_fill));
}
let button_response = ui.add(button);
@ -121,23 +121,19 @@ fn menu_impl<'c>(
.fixed_pos(button_response.rect.left_bottom());
let frame = Frame::menu(ui.style());
let resize = Resize::default().auto_sized().with_stroke(false);
let menu_response = area.show(ui.ctx(), |ui| {
frame.show(ui, |ui| {
resize.show(ui, |ui| {
let mut style = ui.style().clone();
style.spacing.button_padding = vec2(2.0, 0.0);
// style.visuals.interacted.active.bg_fill = TRANSPARENT;
style.visuals.interacted.active.bg_stroke = Stroke::none();
// style.visuals.interacted.hovered.bg_fill = TRANSPARENT;
style.visuals.interacted.hovered.bg_stroke = Stroke::none();
style.visuals.interacted.inactive.bg_fill = TRANSPARENT;
style.visuals.interacted.inactive.bg_stroke = Stroke::none();
ui.set_style(style);
ui.set_layout(Layout::justified(Direction::Vertical));
add_contents(ui)
})
let mut style = ui.style().clone();
style.spacing.button_padding = vec2(2.0, 0.0);
// style.visuals.widgets.active.bg_fill = TRANSPARENT;
style.visuals.widgets.active.bg_stroke = Stroke::none();
// style.visuals.widgets.hovered.bg_fill = TRANSPARENT;
style.visuals.widgets.hovered.bg_stroke = Stroke::none();
style.visuals.widgets.inactive.bg_fill = TRANSPARENT;
style.visuals.widgets.inactive.bg_stroke = Stroke::none();
ui.set_style(style);
ui.set_layout(Layout::justified(Direction::Vertical));
add_contents(ui)
})
});

74
egui/src/style.rs

@ -26,7 +26,7 @@ impl Style {
// TODO: rename style.interact() to maybe... `style.response_visuals` ?
/// Use this style for interactive things
pub fn interact(&self, response: &Response) -> &WidgetVisuals {
self.visuals.interacted.style(response)
self.visuals.widgets.style(response)
}
}
@ -51,6 +51,7 @@ pub struct Spacing {
pub indent: f32,
/// Anything clickable is (at least) this wide.
/// TODO: rename `button_height` or something?
pub clickable_diameter: f32,
/// Total width of a slider
@ -93,20 +94,11 @@ pub struct Interaction {
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Visuals {
pub interacted: Interacted,
pub widgets: Widgets,
pub text_color: Srgba,
/// For stuff like check marks in check boxes.
pub line_width: f32,
pub thin_stroke: Stroke,
/// e.g. the background of windows
pub background_fill: Srgba,
/// e.g. the background of the slider or text edit
pub dark_bg_color: Srgba,
/// e.g. the background of the slider or text edit,
/// needs to look different from other interactive stuff.
pub dark_bg_color: Srgba, // TODO: remove, rename, or clarify what it is for
pub window_corner_radius: f32,
@ -125,16 +117,28 @@ pub struct Visuals {
pub debug_resize: bool,
}
impl Visuals {
pub fn text_color(&self) -> Srgba {
self.widgets.noninteractive.text_color()
}
}
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct Interacted {
pub struct Widgets {
/// For an interactive widget that is being interacted with
pub active: WidgetVisuals,
/// For an interactive widget that is being hovered
pub hovered: WidgetVisuals,
/// For an interactive widget that is "resting"
pub inactive: WidgetVisuals,
/// For an otherwise interactive widget that has been disabled
pub disabled: WidgetVisuals,
/// For a non-interactive widget
pub noninteractive: WidgetVisuals,
}
impl Interacted {
impl Widgets {
pub fn style(&self, response: &Response) -> &WidgetVisuals {
if response.active || response.has_kb_focus {
&self.active
@ -218,11 +222,7 @@ impl Default for Interaction {
impl Default for Visuals {
fn default() -> Self {
Self {
interacted: Default::default(),
text_color: Srgba::gray(160),
line_width: 0.5,
thin_stroke: Stroke::new(0.5, GRAY),
background_fill: Rgba::luminance_alpha(0.013, 0.95).into(),
widgets: Default::default(),
dark_bg_color: Srgba::black_alpha(140),
window_corner_radius: 10.0,
resize_corner_size: 12.0,
@ -235,7 +235,7 @@ impl Default for Visuals {
}
}
impl Default for Interacted {
impl Default for Widgets {
fn default() -> Self {
Self {
active: WidgetVisuals {
@ -257,14 +257,21 @@ impl Default for Interacted {
bg_stroke: Stroke::new(1.0, Rgba::white_alpha(0.04)),
corner_radius: 4.0,
fg_fill: srgba(60, 60, 80, 255),
fg_stroke: Stroke::new(0.5, Srgba::gray(200)), // Should NOT look grayed out!
fg_stroke: Stroke::new(1.0, Srgba::gray(200)), // Should NOT look grayed out!
},
disabled: WidgetVisuals {
bg_fill: TRANSPARENT,
bg_stroke: Stroke::new(0.5, Srgba::gray(70)),
corner_radius: 4.0,
fg_fill: srgba(50, 50, 50, 255),
fg_stroke: Stroke::new(0.5, Srgba::gray(128)), // Should look grayed out
fg_stroke: Stroke::new(1.0, Srgba::gray(128)), // Should look grayed out
},
noninteractive: WidgetVisuals {
bg_stroke: Stroke::new(1.0, Rgba::white_alpha(0.03)),
bg_fill: Rgba::luminance_alpha(0.013, 0.95).into(),
corner_radius: 4.0,
fg_fill: Default::default(),
fg_stroke: Stroke::new(1.0, Srgba::gray(160)), // text color
},
}
}
@ -348,7 +355,7 @@ impl Interaction {
}
}
impl Interacted {
impl Widgets {
pub fn ui(&mut self, ui: &mut crate::Ui) {
if ui.add(Button::new("Reset")).clicked {
*self = Default::default();
@ -359,8 +366,11 @@ impl Interacted {
hovered,
inactive,
disabled,
noninteractive,
} = self;
ui.collapsing("noninteractive", |ui| noninteractive.ui(ui));
ui.heading("Interactive:");
ui.collapsing("active", |ui| active.ui(ui));
ui.collapsing("hovered", |ui| hovered.ui(ui));
ui.collapsing("inactive", |ui| inactive.ui(ui));
@ -382,7 +392,7 @@ impl WidgetVisuals {
bg_stroke.ui(ui, "bg_stroke");
ui.add(Slider::f32(corner_radius, 0.0..=10.0).text("corner_radius"));
ui_color(ui, fg_fill, "fg_fill");
fg_stroke.ui(ui, "fg_stroke");
fg_stroke.ui(ui, "fg_stroke (text)");
}
}
@ -393,11 +403,7 @@ impl Visuals {
}
let Self {
interacted,
text_color,
line_width,
thin_stroke,
background_fill,
widgets,
dark_bg_color,
window_corner_radius,
resize_corner_size,
@ -408,11 +414,7 @@ impl Visuals {
debug_resize,
} = self;
ui.collapsing("interacted", |ui| interacted.ui(ui));
ui_color(ui, text_color, "text_color");
ui.add(Slider::f32(line_width, 0.0..=10.0).text("line_width"));
thin_stroke.ui(ui, "thin_stroke");
ui_color(ui, background_fill, "background_fill");
ui.collapsing("widgets", |ui| widgets.ui(ui));
ui_color(ui, dark_bg_color, "dark_bg_color");
ui.add(Slider::f32(window_corner_radius, 0.0..=20.0).text("window_corner_radius"));
ui.add(Slider::f32(resize_corner_size, 0.0..=20.0).text("resize_corner_size"));

2
egui/src/ui.rs

@ -556,7 +556,7 @@ impl Ui {
let line_end = pos2(line_start.x, line_start.y + size.y - 2.0);
self.painter.line_segment(
[line_start, line_end],
(self.style().visuals.line_width, Srgba::gray(150)),
self.style().visuals.widgets.noninteractive.bg_stroke,
);
(ret, self.allocate_space(indent + size))

61
egui/src/widgets.rs

@ -116,7 +116,7 @@ impl Label {
let text_style = self.text_style_or_default(ui.style());
let text_color = self
.text_color
.unwrap_or_else(|| ui.style().visuals.text_color);
.unwrap_or_else(|| ui.style().visuals.text_color());
ui.painter().galley(pos, galley, text_style, text_color);
}
@ -201,9 +201,11 @@ impl Widget for Hyperlink {
ui.ctx().output().cursor_icon = CursorIcon::PointingHand;
}
if response.clicked {
ui.ctx().output().open_url = Some(url);
ui.ctx().output().open_url = Some(url.clone());
}
let style = ui.style().interact(&response);
if response.hovered {
// Underline:
for line in &galley.lines {
@ -214,7 +216,7 @@ impl Widget for Hyperlink {
let max_x = pos.x + line.max_x();
ui.painter().line_segment(
[pos2(min_x, y), pos2(max_x, y)],
(ui.style().visuals.line_width, color),
(style.fg_stroke.width, color),
);
}
}
@ -222,7 +224,7 @@ impl Widget for Hyperlink {
ui.painter()
.galley(response.rect.min, galley, text_style, color);
response
response.tooltip_text(url)
}
}
@ -254,6 +256,11 @@ impl Button {
self
}
pub fn text_color_opt(mut self, text_color: Option<Srgba>) -> Self {
self.text_color = text_color;
self
}
pub fn text_style(mut self, text_style: TextStyle) -> Self {
self.text_style = text_style;
self
@ -484,25 +491,12 @@ impl Widget for RadioButton {
/// A visual separator. A horizontal or vertical line (depending on `Layout`).
pub struct Separator {
line_width: Option<f32>,
spacing: f32,
extra: f32,
color: Srgba,
}
impl Separator {
pub fn new() -> Self {
Self {
line_width: None,
spacing: 6.0,
extra: 0.0,
color: Srgba::gray(128), // TODO: from style
}
}
pub fn line_width(mut self, line_width: f32) -> Self {
self.line_width = Some(line_width);
self
Self { spacing: 6.0 }
}
/// How much space we take up. The line is painted in the middle of this.
@ -510,29 +504,11 @@ impl Separator {
self.spacing = spacing;
self
}
/// Draw this much longer on each side
pub fn extra(mut self, extra: f32) -> Self {
self.extra = extra;
self
}
pub fn color(mut self, color: Srgba) -> Self {
self.color = color;
self
}
}
impl Widget for Separator {
fn ui(self, ui: &mut Ui) -> Response {
let Separator {
line_width,
spacing,
extra,
color,
} = self;
let line_width = line_width.unwrap_or_else(|| ui.style().visuals.line_width);
let Separator { spacing } = self;
let available_space = ui.available_finite().size();
@ -541,8 +517,8 @@ impl Widget for Separator {
let rect = ui.allocate_space(vec2(spacing, available_space.y));
(
[
pos2(rect.center().x, rect.top() - extra),
pos2(rect.center().x, rect.bottom() + extra),
pos2(rect.center().x, rect.top()),
pos2(rect.center().x, rect.bottom()),
],
rect,
)
@ -551,14 +527,15 @@ impl Widget for Separator {
let rect = ui.allocate_space(vec2(available_space.x, spacing));
(
[
pos2(rect.left() - extra, rect.center().y),
pos2(rect.right() + extra, rect.center().y),
pos2(rect.left(), rect.center().y),
pos2(rect.right(), rect.center().y),
],
rect,
)
}
};
ui.painter().line_segment(points, (line_width, color));
let stroke = ui.style().visuals.widgets.noninteractive.bg_stroke;
ui.painter().line_segment(points, stroke);
ui.interact_hover(rect)
}
}

23
egui/src/widgets/slider.rs

@ -178,8 +178,8 @@ impl<'a> Slider<'a> {
ui.painter().add(PaintCmd::Rect {
rect: rail_rect,
corner_radius: rail_radius,
fill: ui.style().visuals.interacted.inactive.bg_fill,
stroke: ui.style().visuals.interacted.inactive.bg_stroke,
fill: ui.style().visuals.widgets.inactive.bg_fill,
stroke: ui.style().visuals.widgets.inactive.bg_stroke,
});
ui.painter().add(PaintCmd::Circle {
@ -193,11 +193,11 @@ impl<'a> Slider<'a> {
/// Just the text label
fn text_ui(&mut self, ui: &mut Ui, x_range: RangeInclusive<f32>) {
let text_color = self
.text_color
.unwrap_or_else(|| ui.style().visuals.text_color);
if let Some(label_text) = self.text.as_deref() {
let text_color = self
.text_color
.unwrap_or_else(|| ui.style().visuals.text_color());
ui.style_mut().spacing.item_spacing.x = 0.0;
ui.add(
Label::new(format!("{}: ", label_text))
@ -223,7 +223,7 @@ impl<'a> Slider<'a> {
.id(kb_edit_id)
.multiline(false)
.desired_width(0.0)
.text_color(text_color)
.text_color_opt(self.text_color)
.text_style(TextStyle::Monospace),
);
if let Ok(value) = value_text.parse() {
@ -236,13 +236,12 @@ impl<'a> Slider<'a> {
}
} else {
let response = ui.add(
Label::new(value_text)
.multiline(false)
.text_color(text_color)
.text_style(TextStyle::Monospace),
Button::new(value_text)
.text_style(TextStyle::Monospace)
.text_color_opt(self.text_color),
);
let response = response.tooltip_text("Click to enter a value");
let response = ui.interact(response.rect, kb_edit_id, Sense::click());
// let response = ui.interact(response.rect, kb_edit_id, Sense::click());
if response.clicked {
ui.memory().request_kb_focus(kb_edit_id);
ui.memory().temp_edit_string = None; // Filled in next frame

13
egui/src/widgets/text_edit.rs

@ -55,6 +55,11 @@ impl<'t> TextEdit<'t> {
self
}
pub fn text_color_opt(mut self, text_color: Option<Srgba>) -> Self {
self.text_color = text_color;
self
}
pub fn multiline(mut self, multiline: bool) -> Self {
self.multiline = multiline;
self
@ -178,14 +183,16 @@ impl<'t> Widget for TextEdit<'t> {
}
let painter = ui.painter();
let visuals = ui.style().interact(&response);
{
let bg_rect = response.rect.expand(2.0); // breathing room for content
painter.add(PaintCmd::Rect {
rect: bg_rect,
corner_radius: ui.style().interact(&response).corner_radius,
corner_radius: visuals.corner_radius,
fill: ui.style().visuals.dark_bg_color,
stroke: ui.style().interact(&response).bg_stroke,
// fill: visuals.bg_fill,
stroke: visuals.bg_stroke,
});
}
@ -209,7 +216,7 @@ impl<'t> Widget for TextEdit<'t> {
}
}
let text_color = text_color.unwrap_or_else(|| ui.style().interact(&response).text_color());
let text_color = text_color.unwrap_or_else(|| visuals.text_color());
painter.galley(response.rect.min, galley, text_style, text_color);
ui.memory().text_edit.insert(id, state);
response

Loading…
Cancel
Save