[style] make the default style a lot more compact and sleek

This commit is contained in:
Emil Ernerfeldt 2020-09-01 20:40:54 +02:00
parent 2129a87575
commit e7b098ac56
8 changed files with 89 additions and 64 deletions

View file

@ -45,11 +45,11 @@ TODO-list for the Egui project. If you looking for something to do, look here.
* [x] Pixel-perfect painting (round positions to nearest pixel).
* [x] Fix `aa_size`: should be 1, currently fudged at 1.5
* [x] Fix thin rounded corners rendering bug (too bright)
* [x] Smoother animation (e.g. ease-out)? NO: animation are too brief for subtelty
* [ ] Veriy alpha and sRGB correctness
* [x] sRGBA decode in fragment shader
* [ ] Thin circles look bad
* [ ] Color picker
* [ ] Smoother animation (e.g. ease-out)?
* Math
* [ ] Change `width.min(max_width)` to `width.at_most(max_width)`

View file

@ -2,7 +2,7 @@ use std::hash::Hash;
use crate::{
layout::Direction,
paint::{LineStyle, PaintCmd, TextStyle},
paint::{PaintCmd, TextStyle},
widgets::Label,
*,
};
@ -105,8 +105,7 @@ impl State {
/// Paint the arrow icon that indicated if the region is open or not
pub fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) {
let stroke_color = ui.style().interact(response).stroke_color;
let stroke_width = ui.style().interact(response).stroke_width;
let line_style = ui.style().interact(response).line_style();
let rect = response.rect;
@ -124,7 +123,7 @@ pub fn paint_icon(ui: &mut Ui, openness: f32, response: &Response) {
points,
closed: true,
fill: Default::default(),
outline: LineStyle::new(stroke_width, stroke_color),
outline: line_style,
});
}
@ -183,17 +182,19 @@ impl CollapsingHeader {
let available = ui.available_finite();
let text_pos = available.min + vec2(ui.style().spacing.indent, 0.0);
let galley = label.layout_width(ui, available.width() - ui.style().spacing.indent);
let galley = label.layout_width(ui, available.right() - text_pos.x);
let text_max_x = text_pos.x + galley.size.x;
let desired_width = text_max_x - available.left();
let desired_width = desired_width.max(available.width());
let size = vec2(
let mut desired_size = vec2(
desired_width,
galley.size.y + 2.0 * ui.style().spacing.button_padding.y,
);
desired_size.y = desired_size.y.max(ui.style().spacing.clickable_diameter);
let rect = ui.allocate_space(desired_size);
let rect = rect.expand2(ui.style().spacing.button_expand);
let rect = ui.allocate_space(size);
let response = ui.interact(rect, id, Sense::click());
let text_pos = pos2(text_pos.x, response.rect.center().y - galley.size.y / 2.0);

View file

@ -280,7 +280,7 @@ pub fn paint_resize_corner_with_style(ui: &mut Ui, rect: &Rect, style: LineStyle
let corner = painter.round_pos_to_pixels(rect.right_bottom());
let mut w = 2.0;
while w < 12.0 {
while w <= rect.width() && w <= rect.height() {
painter.line_segment(
[pos2(corner.x - w, corner.y), pos2(corner.x, corner.y - w)],
style,

View file

@ -504,9 +504,8 @@ impl Context {
use crate::containers::*;
CollapsingHeader::new("Style")
.default_open(false)
.default_open(true)
.show(ui, |ui| {
self.paint_options.lock().ui(ui);
self.style_ui(ui);
});
@ -518,6 +517,12 @@ impl Context {
self.fonts().texture().ui(ui);
self.set_fonts(font_definitions);
});
CollapsingHeader::new("Painting")
.default_open(true)
.show(ui, |ui| {
self.paint_options.lock().ui(ui);
});
}
pub fn inspection_ui(&self, ui: &mut Ui) {

View file

@ -34,6 +34,11 @@ pub struct Spacing {
/// Button size is text size plus this on each side
pub button_padding: Vec2,
/// Expand buttons by this much *after* allocating them.
/// This is then mostly a visual change (but also makes them easier to hit with the mouse).
/// This allows for compact layout where buttons actually eat into item_spacing a bit
pub button_expand: Vec2,
/// Indent collapsing regions etc by this much.
pub indent: f32,
@ -99,8 +104,8 @@ pub struct Visuals {
pub resize_corner_size: f32,
/// Blink text cursor by this frequency. If None, always show the cursor.
pub cursor_blink_hz: Option<f32>,
/// Blink text cursor by this frequency. If 0, always show the cursor.
pub cursor_blink_hz: f32,
pub text_cursor_width: f32,
/// Allow child widgets to be just on the border and still have an outline with some thickness
@ -152,7 +157,7 @@ pub struct WidgetVisuals {
/// When you need a fill.
pub main_fill: Srgba,
/// Stroke and text color of the interactive part of a component (button, slider grab, checkbox, ...)
/// Stroke and text color of the interactive part of a component (button text, slider grab, check-mark, ...)
pub stroke_color: Srgba,
/// For lines etc
@ -181,11 +186,12 @@ impl Default for Style {
impl Default for Spacing {
fn default() -> Self {
Self {
item_spacing: vec2(8.0, 4.0),
item_spacing: vec2(8.0, 6.0),
window_padding: vec2(6.0, 6.0),
button_padding: vec2(4.0, 1.0),
button_padding: vec2(2.0, 0.0),
button_expand: vec2(1.0, 1.0),
indent: 21.0,
clickable_diameter: 22.0,
clickable_diameter: 14.0, // TODO: automatically higher on touch screens
slider_width: 140.0,
icon_width: 14.0,
menu_bar_height: 16.0,
@ -207,13 +213,13 @@ impl Default for Visuals {
Self {
interacted: Default::default(),
text_color: Srgba::gray(160),
line_width: 1.0,
line_width: 0.5,
thin_outline: LineStyle::new(0.5, GRAY),
background_fill: Rgba::luminance_alpha(0.013, 0.95).into(),
dark_bg_color: Srgba::black_alpha(140),
window_corner_radius: 10.0,
resize_corner_size: 16.0,
cursor_blink_hz: None, // Some(1.0)
resize_corner_size: 12.0,
cursor_blink_hz: 0.0, // 1.0 looks good
text_cursor_width: 2.0,
clip_rect_margin: 3.0,
debug_widget_rects: false,
@ -228,30 +234,30 @@ impl Default for Interacted {
active: WidgetVisuals {
bg_fill: Srgba::black_alpha(128),
bg_outline: LineStyle::new(2.0, WHITE),
corner_radius: 0.0,
corner_radius: 4.0,
main_fill: srgba(120, 120, 200, 255),
stroke_color: WHITE,
stroke_width: 2.0,
},
hovered: WidgetVisuals {
bg_fill: TRANSPARENT,
bg_outline: LineStyle::new(1.0, WHITE),
corner_radius: 2.0,
bg_fill: Rgba::luminance_alpha(0.06, 0.5).into(),
bg_outline: LineStyle::new(1.0, Rgba::white_alpha(0.5)),
corner_radius: 4.0,
main_fill: srgba(100, 100, 150, 255),
stroke_color: Srgba::gray(240),
stroke_width: 1.5,
},
inactive: WidgetVisuals {
bg_fill: TRANSPARENT,
bg_outline: LineStyle::new(1.0, Srgba::gray(128)),
bg_fill: Rgba::luminance_alpha(0.04, 0.5).into(),
bg_outline: LineStyle::new(1.0, Rgba::white_alpha(0.04)),
corner_radius: 4.0,
main_fill: srgba(60, 60, 80, 255),
stroke_color: Srgba::gray(200), // Mustn't look grayed out!
stroke_width: 1.0,
stroke_color: Srgba::gray(200), // Should NOT look grayed out!
stroke_width: 0.5,
},
disabled: WidgetVisuals {
bg_fill: TRANSPARENT,
bg_outline: LineStyle::new(0.5, Srgba::gray(128)),
bg_outline: LineStyle::new(0.5, Srgba::gray(70)),
corner_radius: 4.0,
main_fill: srgba(50, 50, 50, 255),
stroke_color: Srgba::gray(128), // Should look grayed out
@ -294,6 +300,7 @@ impl Spacing {
item_spacing,
window_padding,
button_padding,
button_expand,
indent,
clickable_diameter,
slider_width,
@ -301,9 +308,10 @@ impl Spacing {
menu_bar_height,
} = self;
ui_slider_vec2(ui, item_spacing, 0.0..=20.0, "item_spacing");
ui_slider_vec2(ui, window_padding, 0.0..=20.0, "window_padding");
ui_slider_vec2(ui, button_padding, 0.0..=20.0, "button_padding");
ui_slider_vec2(ui, item_spacing, 0.0..=10.0, "item_spacing");
ui_slider_vec2(ui, window_padding, 0.0..=10.0, "window_padding");
ui_slider_vec2(ui, button_padding, 0.0..=10.0, "button_padding");
ui_slider_vec2(ui, button_expand, 0.0..=10.0, "button_expand");
ui.add(Slider::f32(indent, 0.0..=100.0).text("indent"));
ui.add(Slider::f32(clickable_diameter, 0.0..=40.0).text("clickable_diameter"));
ui.add(Slider::f32(slider_width, 0.0..=1000.0).text("slider_width"));
@ -400,7 +408,7 @@ impl Visuals {
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"));
let _ = cursor_blink_hz; // TODO
ui.add(Slider::f32(cursor_blink_hz, 0.0..=4.0).text("cursor_blink_hz"));
ui.add(Slider::f32(text_cursor_width, 0.0..=2.0).text("text_cursor_width"));
ui.add(Slider::f32(clip_rect_margin, 0.0..=20.0).text("clip_rect_margin"));
@ -416,8 +424,9 @@ impl LineStyle {
pub fn ui(&mut self, ui: &mut crate::Ui, text: &str) {
let Self { width, color } = self;
ui.horizontal_centered(|ui| {
ui.style_mut().spacing.slider_width /= 2.0;
ui.label(format!("{}: ", text));
ui.add(Slider::f32(width, 0.0..=10.0).text("width"));
ui.add(Slider::f32(width, 0.0..=5.0).text("width"));
ui_color(ui, color, "color");
});
}
@ -427,9 +436,8 @@ impl LineStyle {
fn ui_slider_vec2(ui: &mut Ui, value: &mut Vec2, range: std::ops::RangeInclusive<f32>, text: &str) {
ui.horizontal_centered(|ui| {
ui.label(format!("{}: ", text));
ui.add(Slider::f32(&mut value.x, range.clone()))
.tooltip_text("x");
ui.add(Slider::f32(&mut value.y, range)).tooltip_text("y");
ui.add(Slider::f32(&mut value.x, range.clone()).text("w"));
ui.add(Slider::f32(&mut value.y, range.clone()).text("h"));
});
}

View file

@ -283,12 +283,13 @@ impl Widget for Button {
let id = ui.make_position_id();
let font = &ui.fonts()[text_style];
let galley = font.layout_multiline(text, ui.available().width());
let padding = ui.style().spacing.button_padding;
let mut size = galley.size + 2.0 * padding;
size.y = size.y.max(ui.style().spacing.clickable_diameter);
let rect = ui.allocate_space(size);
let mut desired_size = galley.size + 2.0 * ui.style().spacing.button_padding;
desired_size.y = desired_size.y.max(ui.style().spacing.clickable_diameter);
let rect = ui.allocate_space(desired_size);
let rect = rect.expand2(ui.style().spacing.button_expand);
let response = ui.interact(rect, id, sense);
let text_cursor = response.rect.left_center() + vec2(padding.x, -0.5 * galley.size.y);
let text_cursor = response.rect.center() - 0.5 * galley.size;
let fill = fill.unwrap_or(ui.style().interact(&response).bg_fill);
ui.painter().add(PaintCmd::Rect {
rect: response.rect,
@ -342,18 +343,23 @@ impl<'a> Widget for Checkbox<'a> {
let text_style = TextStyle::Button;
let font = &ui.fonts()[text_style];
let galley = font.layout_single_line(text);
let size = ui.style().spacing.button_padding
+ vec2(ui.style().spacing.icon_width, 0.0)
+ galley.size
+ ui.style().spacing.button_padding;
let rect = ui.allocate_space(size);
let icon_width = ui.style().spacing.icon_width;
let button_padding = ui.style().spacing.button_padding;
let mut desired_size =
button_padding + vec2(icon_width, 0.0) + galley.size + button_padding;
desired_size.y = desired_size.y.max(ui.style().spacing.clickable_diameter);
let rect = ui.allocate_space(desired_size);
let response = ui.interact(rect, id, Sense::click());
let text_cursor = response.rect.min
+ ui.style().spacing.button_padding
+ vec2(ui.style().spacing.icon_width, 0.0);
if response.clicked {
*checked = !*checked;
}
let text_cursor = pos2(
response.rect.min.x + button_padding.x + icon_width,
response.rect.center().y - 0.5 * galley.size.y,
);
let (small_icon_rect, big_icon_rect) = ui.style().spacing.icon_rectangles(response.rect);
ui.painter().add(PaintCmd::Rect {
rect: big_icon_rect,
@ -362,7 +368,7 @@ impl<'a> Widget for Checkbox<'a> {
outline: ui.style().interact(&response).bg_outline,
});
let stroke_color = ui.style().interact(&response).stroke_color;
let line_style = ui.style().interact(&response).line_style();
if *checked {
ui.painter().add(PaintCmd::Path {
@ -372,12 +378,12 @@ impl<'a> Widget for Checkbox<'a> {
pos2(small_icon_rect.right(), small_icon_rect.top()),
],
closed: false,
outline: LineStyle::new(ui.style().visuals.line_width, stroke_color),
outline: line_style,
fill: Default::default(),
});
}
let text_color = text_color.unwrap_or(stroke_color);
let text_color = text_color.unwrap_or(line_style.color);
ui.painter()
.galley(text_cursor, galley, text_style, text_color);
response
@ -420,15 +426,20 @@ impl Widget for RadioButton {
let text_style = TextStyle::Button;
let font = &ui.fonts()[text_style];
let galley = font.layout_multiline(text, ui.available().width());
let size = ui.style().spacing.button_padding
+ vec2(ui.style().spacing.icon_width, 0.0)
+ galley.size
+ ui.style().spacing.button_padding;
let rect = ui.allocate_space(size);
let icon_width = ui.style().spacing.icon_width;
let button_padding = ui.style().spacing.button_padding;
let mut desired_size =
button_padding + vec2(icon_width, 0.0) + galley.size + button_padding;
desired_size.y = desired_size.y.max(ui.style().spacing.clickable_diameter);
let rect = ui.allocate_space(desired_size);
let response = ui.interact(rect, id, Sense::click());
let text_cursor = response.rect.min
+ ui.style().spacing.button_padding
+ vec2(ui.style().spacing.icon_width, 0.0);
let text_cursor = pos2(
response.rect.min.x + button_padding.x + icon_width,
response.rect.center().y - 0.5 * galley.size.y,
);
let bg_fill = ui.style().interact(&response).bg_fill;
let stroke_color = ui.style().interact(&response).stroke_color;

View file

@ -164,8 +164,8 @@ impl<'a> Slider<'a> {
ui.painter().add(PaintCmd::Rect {
rect: rail_rect,
corner_radius: rail_radius,
fill: ui.style().visuals.background_fill,
outline: LineStyle::new(1.0, Srgba::gray(200)), // TODO
fill: ui.style().visuals.interacted.inactive.bg_fill,
outline: ui.style().visuals.interacted.inactive.bg_outline,
});
ui.painter().add(PaintCmd::Circle {

View file

@ -190,7 +190,7 @@ impl<'t> Widget for TextEdit<'t> {
if ui.memory().has_kb_focus(id) {
let cursor_blink_hz = ui.style().visuals.cursor_blink_hz;
let show_cursor = if let Some(cursor_blink_hz) = cursor_blink_hz {
let show_cursor = if 0.0 < cursor_blink_hz {
ui.ctx().request_repaint(); // TODO: only when cursor blinks on or off
(ui.input().time * cursor_blink_hz as f64 * 3.0).floor() as i64 % 3 != 0
} else {