Style tweaks (#450)

* Tweak style

More compact, less round, less noisy

* Button text is now same size as body text
* The rounder corners are now less rounded
* Collapsing headers no longer have a frame around them
* Combo-boxes looks better when opened
* Slightly more muted colors
* Remove extra line spacing after `\n` (i.e. between paragraphs)

* Thinner scrollbars

* Tweak light mode

* Tweak shadows

* Fix broken doc link

* Add style tweak to CHANGELOG
This commit is contained in:
Emil Ernerfeldt 2021-06-12 15:53:56 +02:00 committed by GitHub
parent a50ddc2703
commit 778bcc1ef7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 365 additions and 166 deletions

View file

@ -24,6 +24,7 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md) and [
* Add `ScrollArea::enable_scrolling` to allow freezing scrolling when editing TextEdit widgets within it
### Changed 🔧
* [Tweaked the default visuals style](https://github.com/emilk/egui/pull/450).
* Plot: Changed `Curve` to `Line`.
* `TopPanel::top` is now `TopBottomPanel::top`.
* `SidePanel::left` no longet takes the default width by argument, but by a builder call.

View file

@ -246,6 +246,8 @@ impl CollapsingHeader {
let visuals = ui.style().interact(&header_response);
let text_color = visuals.text_color();
if ui.visuals().collapsing_header_frame {
ui.painter().add(Shape::Rect {
rect: header_response.rect.expand(visuals.expansion),
corner_radius: visuals.corner_radius,
@ -253,6 +255,7 @@ impl CollapsingHeader {
stroke: visuals.bg_stroke,
// stroke: Default::default(),
});
}
{
let (mut icon_rect, _) = ui.spacing().icon_rectangles(header_response.rect);

View file

@ -176,8 +176,8 @@ fn combo_box(
) -> Response {
let popup_id = button_id.with("popup");
let button_active = ui.memory().is_popup_open(popup_id);
let button_response = button_frame(ui, button_id, button_active, Sense::click(), |ui| {
let is_popup_open = ui.memory().is_popup_open(popup_id);
let button_response = button_frame(ui, button_id, is_popup_open, Sense::click(), |ui| {
// We don't want to change width when user selects something new
let full_minimum_width = ui.spacing().slider_width;
let icon_size = Vec2::splat(ui.spacing().icon_width);
@ -193,10 +193,14 @@ fn combo_box(
let (_, rect) = ui.allocate_space(Vec2::new(width, height));
let button_rect = ui.min_rect().expand2(ui.spacing().button_padding);
let response = ui.interact(button_rect, button_id, Sense::click());
// response.active |= button_active;
// response.active |= is_popup_open;
let icon_rect = Align2::RIGHT_CENTER.align_size_within_rect(icon_size, rect);
let visuals = ui.style().interact(&response);
let visuals = if is_popup_open {
&ui.visuals().widgets.open
} else {
ui.style().interact(&response)
};
paint_icon(ui.painter(), icon_rect.expand(visuals.expansion), visuals);
let text_rect = Align2::LEFT_CENTER.align_size_within_rect(galley.size, rect);
@ -207,9 +211,8 @@ fn combo_box(
if button_response.clicked() {
ui.memory().toggle_popup(popup_id);
}
const MAX_COMBO_HEIGHT: f32 = 128.0;
crate::popup::popup_below_widget(ui, popup_id, &button_response, |ui| {
ScrollArea::from_max_height(MAX_COMBO_HEIGHT).show(ui, menu_contents)
ScrollArea::from_max_height(ui.spacing().combo_height).show(ui, menu_contents)
});
button_response
@ -218,7 +221,7 @@ fn combo_box(
fn button_frame(
ui: &mut Ui,
id: Id,
button_active: bool,
is_popup_open: bool,
sense: Sense,
add_contents: impl FnOnce(&mut Ui),
) -> Response {
@ -237,9 +240,12 @@ fn button_frame(
let mut outer_rect = content_ui.min_rect().expand2(margin);
outer_rect.set_height(outer_rect.height().at_least(interact_size.y));
let mut response = ui.interact(outer_rect, id, sense);
response.is_pointer_button_down_on |= button_active;
let visuals = ui.style().interact(&response);
let response = ui.interact(outer_rect, id, sense);
let visuals = if is_popup_open {
&ui.visuals().widgets.open
} else {
ui.style().interact(&response)
};
ui.painter().set(
where_to_put_background,

View file

@ -24,8 +24,8 @@ impl Frame {
pub fn group(style: &Style) -> Self {
Self {
margin: Vec2::new(8.0, 6.0),
corner_radius: 4.0,
stroke: style.visuals.window_stroke(),
corner_radius: style.visuals.widgets.noninteractive.corner_radius,
stroke: style.visuals.widgets.noninteractive.bg_stroke,
..Default::default()
}
}
@ -63,8 +63,8 @@ impl Frame {
pub fn menu(style: &Style) -> Self {
Self {
margin: Vec2::splat(1.0),
corner_radius: 2.0,
shadow: Shadow::small(),
corner_radius: style.visuals.widgets.noninteractive.corner_radius,
shadow: style.visuals.popup_shadow,
fill: style.visuals.window_fill(),
stroke: style.visuals.window_stroke(),
}
@ -73,8 +73,8 @@ impl Frame {
pub fn popup(style: &Style) -> Self {
Self {
margin: style.spacing.window_padding,
corner_radius: 5.0,
shadow: Shadow::small(),
corner_radius: style.visuals.widgets.noninteractive.corner_radius,
shadow: style.visuals.popup_shadow,
fill: style.visuals.window_fill(),
stroke: style.visuals.window_stroke(),
}
@ -84,7 +84,7 @@ impl Frame {
pub fn dark_canvas(style: &Style) -> Self {
Self {
margin: Vec2::new(10.0, 10.0),
corner_radius: 5.0,
corner_radius: style.visuals.widgets.noninteractive.corner_radius,
fill: Color32::from_black_alpha(250),
stroke: style.visuals.window_stroke(),
..Default::default()

View file

@ -357,7 +357,6 @@ impl Prepared {
let margin = animation_t * ui.spacing().item_spacing.x;
let left = inner_rect.right() + margin;
let right = outer_rect.right();
let corner_radius = (right - left) / 2.0;
let top = inner_rect.top();
let bottom = inner_rect.bottom();
@ -415,7 +414,7 @@ impl Prepared {
pos2(left, from_content(state.offset.y)),
pos2(right, from_content(state.offset.y + inner_rect.height())),
);
let min_handle_height = (2.0 * corner_radius).max(8.0);
let min_handle_height = ui.spacing().scroll_bar_width;
if handle_rect.size().y < min_handle_height {
handle_rect = Rect::from_center_size(
handle_rect.center(),
@ -429,21 +428,17 @@ impl Prepared {
&ui.style().visuals.widgets.inactive
};
ui.painter().add(epaint::Shape::Rect {
rect: outer_scroll_rect,
corner_radius,
fill: ui.visuals().extreme_bg_color,
stroke: Default::default(),
// fill: visuals.bg_fill,
// stroke: visuals.bg_stroke,
});
ui.painter().add(epaint::Shape::rect_filled(
outer_scroll_rect,
visuals.corner_radius,
ui.visuals().extreme_bg_color,
));
ui.painter().add(epaint::Shape::Rect {
rect: handle_rect.expand(-2.0),
corner_radius,
fill: visuals.bg_fill,
stroke: visuals.bg_stroke,
});
ui.painter().add(epaint::Shape::rect_filled(
handle_rect,
visuals.corner_radius,
visuals.bg_fill,
));
}
let size = vec2(
@ -465,5 +460,5 @@ impl Prepared {
}
fn max_scroll_bar_width_with_margin(ui: &Ui) -> f32 {
ui.spacing().item_spacing.x + 16.0
ui.spacing().item_spacing.x + ui.spacing().scroll_bar_width
}

View file

@ -198,12 +198,7 @@ impl GridLayout {
let rect = rect.expand2(0.5 * self.spacing.y * Vec2::Y);
let rect = rect.expand2(2.0 * Vec2::X); // HACK: just looks better with some spacing on the sides
let color = if self.style.visuals.dark_mode {
Rgba::from_white_alpha(0.0075)
} else {
Rgba::from_black_alpha(0.075)
};
painter.rect_filled(rect, 2.0, color);
painter.rect_filled(rect, 2.0, self.style.visuals.faint_bg_color);
}
}
}

View file

@ -132,14 +132,17 @@ impl Widget for &mut epaint::TessellationOptions {
debug_paint_text_rects,
debug_ignore_clip_rects,
} = self;
ui.checkbox(anti_alias, "Antialias");
ui.checkbox(anti_alias, "Antialias")
.on_hover_text("Turn off for small performance gain.");
ui.collapsing("debug", |ui| {
ui.checkbox(
coarse_tessellation_culling,
"Do coarse culling in the tessellator",
"Do coarse culling in the tessellator)",
);
ui.checkbox(debug_ignore_clip_rects, "Ignore clip rectangles (debug)");
ui.checkbox(debug_paint_clip_rects, "Paint clip rectangles (debug)");
ui.checkbox(debug_paint_text_rects, "Paint text bounds (debug)");
ui.checkbox(debug_ignore_clip_rects, "Ignore clip rectangles");
ui.checkbox(debug_paint_clip_rects, "Paint clip rectangles");
ui.checkbox(debug_paint_text_rects, "Paint text bounds");
});
})
.response
}

View file

@ -75,7 +75,8 @@ fn menu_impl<'c>(ui: &mut Ui, title: impl ToString, add_contents: Box<dyn FnOnce
let mut button = Button::new(title);
if bar_state.open_menu == Some(menu_id) {
button = button.fill(Some(ui.visuals().selection.bg_fill));
button = button.fill(ui.visuals().widgets.open.bg_fill);
button = button.stroke(ui.visuals().widgets.open.bg_stroke);
}
let button_response = ui.add(button);

View file

@ -117,6 +117,14 @@ pub struct Spacing {
/// Width of a tooltip (`on_hover_ui`, `on_hover_text` etc).
pub tooltip_width: f32,
/// End indented regions with a horizontal line
pub indent_ends_with_horizontal_line: bool,
/// Height of a combo-box before showing scroll bars.
pub combo_height: f32,
pub scroll_bar_width: f32,
}
impl Spacing {
@ -188,20 +196,26 @@ pub struct Visuals {
pub selection: Selection,
/// The color used for `Hyperlink`,
pub hyperlink_color: Color32,
/// Something just barely different from the background color.
/// Used for [`crate::Grid::striped`].
pub faint_bg_color: Color32,
/// Very dark or light color (for corresponding theme).
/// Used as the background of text edits, scroll bars and others things
/// that needs to look different from other interactive stuff.
pub extreme_bg_color: Color32,
/// The color used for `Hyperlink`,
pub hyperlink_color: Color32,
/// Background color behind code-styled monospaced labels.
pub code_bg_color: Color32,
pub window_corner_radius: f32,
pub window_shadow: Shadow,
pub popup_shadow: Shadow,
pub resize_corner_size: f32,
pub text_cursor_width: f32,
@ -210,6 +224,12 @@ pub struct Visuals {
/// Allow child widgets to be just on the border and still have a stroke with some thickness
pub clip_rect_margin: f32,
/// Show a background behind buttons.
pub button_frame: bool,
/// Show a background behind collapsing headers.
pub collapsing_header_frame: bool,
}
impl Visuals {
@ -264,6 +284,8 @@ pub struct Widgets {
pub hovered: WidgetVisuals,
/// The style of an interactive widget as you are clicking or dragging it.
pub active: WidgetVisuals,
/// The style of a button that has an open menu beneath it (e.g. a combo-box)
pub open: WidgetVisuals,
}
impl Widgets {
@ -344,13 +366,16 @@ impl Default for Spacing {
item_spacing: vec2(8.0, 3.0),
window_padding: Vec2::splat(6.0),
button_padding: vec2(4.0, 1.0),
indent: 25.0,
interact_size: vec2(40.0, 20.0),
indent: 18.0, // match checkbox/radio-button with `button_padding.x + icon_width + icon_spacing`
interact_size: vec2(40.0, 18.0),
slider_width: 100.0,
text_edit_width: 280.0,
icon_width: 16.0,
icon_width: 14.0,
icon_spacing: 0.0,
tooltip_width: 600.0,
combo_height: 200.0,
scroll_bar_width: 8.0,
indent_ends_with_horizontal_line: false,
}
}
}
@ -373,15 +398,19 @@ impl Visuals {
override_text_color: None,
widgets: Widgets::default(),
selection: Selection::default(),
extreme_bg_color: Color32::from_gray(10),
hyperlink_color: Color32::from_rgb(90, 170, 255),
faint_bg_color: Color32::from_gray(24),
extreme_bg_color: Color32::from_gray(10),
code_bg_color: Color32::from_gray(64),
window_corner_radius: 10.0,
window_corner_radius: 6.0,
window_shadow: Shadow::big_dark(),
popup_shadow: Shadow::small_dark(),
resize_corner_size: 12.0,
text_cursor_width: 2.0,
text_cursor_preview: false,
clip_rect_margin: 3.0, // should be at least half the size of the widest frame stroke + max WidgetVisuals::expansion
button_frame: true,
collapsing_header_frame: false,
}
}
@ -391,10 +420,12 @@ impl Visuals {
dark_mode: false,
widgets: Widgets::light(),
selection: Selection::light(),
extreme_bg_color: Color32::from_gray(235), // TODO: rename
hyperlink_color: Color32::from_rgb(0, 133, 218),
hyperlink_color: Color32::from_rgb(0, 155, 255),
faint_bg_color: Color32::from_gray(240),
extreme_bg_color: Color32::from_gray(250),
code_bg_color: Color32::from_gray(200),
window_shadow: Shadow::big_light(),
popup_shadow: Shadow::small_light(),
..Self::dark()
}
}
@ -431,32 +462,39 @@ impl Widgets {
pub fn dark() -> Self {
Self {
noninteractive: WidgetVisuals {
bg_fill: Color32::from_gray(30), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(65)), // window outline
fg_stroke: Stroke::new(1.0, Color32::from_gray(160)), // normal text color
corner_radius: 4.0,
bg_fill: Color32::from_gray(27), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)), // separators, indentation lines, windows outlines
fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // normal text color
corner_radius: 2.0,
expansion: 0.0,
},
inactive: WidgetVisuals {
bg_fill: Color32::from_gray(70),
bg_fill: Color32::from_gray(60), // button background
bg_stroke: Default::default(),
fg_stroke: Stroke::new(1.0, Color32::from_gray(200)), // Should NOT look grayed out!
corner_radius: 4.0,
fg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // button text
corner_radius: 2.0,
expansion: 0.0,
},
hovered: WidgetVisuals {
bg_fill: Color32::from_gray(80),
bg_fill: Color32::from_gray(70),
bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button
fg_stroke: Stroke::new(1.5, Color32::from_gray(240)),
corner_radius: 4.0,
corner_radius: 3.0,
expansion: 1.0,
},
active: WidgetVisuals {
bg_fill: Color32::from_gray(90),
bg_fill: Color32::from_gray(55),
bg_stroke: Stroke::new(1.0, Color32::WHITE),
fg_stroke: Stroke::new(2.0, Color32::WHITE),
corner_radius: 4.0,
expansion: 2.0,
corner_radius: 2.0,
expansion: 1.0,
},
open: WidgetVisuals {
bg_fill: Color32::from_gray(27),
bg_stroke: Stroke::new(1.0, Color32::from_gray(60)),
fg_stroke: Stroke::new(1.0, Color32::from_gray(210)),
corner_radius: 2.0,
expansion: 0.0,
},
}
}
@ -464,32 +502,39 @@ impl Widgets {
pub fn light() -> Self {
Self {
noninteractive: WidgetVisuals {
bg_fill: Color32::from_gray(220), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(180)), // window outline
fg_stroke: Stroke::new(1.0, Color32::from_gray(70)), // normal text color
corner_radius: 4.0,
bg_fill: Color32::from_gray(235), // window background
bg_stroke: Stroke::new(1.0, Color32::from_gray(190)), // separators, indentation lines, windows outlines
fg_stroke: Stroke::new(1.0, Color32::from_gray(100)), // normal text color
corner_radius: 2.0,
expansion: 0.0,
},
inactive: WidgetVisuals {
bg_fill: Color32::from_gray(195),
bg_fill: Color32::from_gray(215), // button background
bg_stroke: Default::default(),
fg_stroke: Stroke::new(1.0, Color32::from_gray(55)), // Should NOT look grayed out!
corner_radius: 4.0,
fg_stroke: Stroke::new(1.0, Color32::from_gray(80)), // button text
corner_radius: 2.0,
expansion: 0.0,
},
hovered: WidgetVisuals {
bg_fill: Color32::from_gray(175),
bg_fill: Color32::from_gray(210),
bg_stroke: Stroke::new(1.0, Color32::from_gray(105)), // e.g. hover over window edge or button
fg_stroke: Stroke::new(2.0, Color32::BLACK),
corner_radius: 4.0,
fg_stroke: Stroke::new(1.5, Color32::BLACK),
corner_radius: 3.0,
expansion: 1.0,
},
active: WidgetVisuals {
bg_fill: Color32::from_gray(165),
bg_stroke: Stroke::new(1.0, Color32::BLACK),
fg_stroke: Stroke::new(2.0, Color32::BLACK),
corner_radius: 4.0,
expansion: 2.0,
corner_radius: 2.0,
expansion: 1.0,
},
open: WidgetVisuals {
bg_fill: Color32::from_gray(220),
bg_stroke: Stroke::new(1.0, Color32::from_gray(160)),
fg_stroke: Stroke::new(1.0, Color32::BLACK),
corner_radius: 2.0,
expansion: 0.0,
},
}
}
@ -520,14 +565,25 @@ impl Style {
visuals.light_dark_radio_buttons(ui);
crate::Grid::new("_options").show(ui, |ui| {
ui.label("Default body text style:");
ui.horizontal(|ui| {
ui.label("Default text style:");
for &value in &[TextStyle::Body, TextStyle::Monospace] {
ui.radio_value(body_text_style, value, format!("{:?}", value));
for &style in &[TextStyle::Body, TextStyle::Monospace] {
if ui
.add(
RadioButton::new(*body_text_style == style, format!("{:?}", style))
.text_style(style),
)
.clicked()
{
*body_text_style = style;
};
}
});
ui.end_row();
crate::ComboBox::from_label("Global text style override")
ui.label("Override text style:");
crate::ComboBox::from_id_source("Override text style")
.selected_text(match override_text_style {
None => "None".to_owned(),
Some(override_text_style) => format!("{:?}", override_text_style),
@ -535,15 +591,29 @@ impl Style {
.show_ui(ui, |ui| {
ui.selectable_value(override_text_style, None, "None");
for style in TextStyle::all() {
ui.selectable_value(override_text_style, Some(style), format!("{:?}", style));
// ui.selectable_value(override_text_style, Some(style), format!("{:?}", style));
let selected = *override_text_style == Some(style);
if ui
.add(
SelectableLabel::new(selected, format!("{:?}", style))
.text_style(style),
)
.clicked()
{
*override_text_style = Some(style);
}
}
});
ui.end_row();
ui.label("Animation duration:");
ui.add(
Slider::new(animation_time, 0.0..=1.0)
.text("animation durations")
.clamp_to_range(true)
.suffix(" s"),
);
ui.end_row();
});
ui.collapsing("📏 Spacing", |ui| spacing.ui(ui));
ui.collapsing("☝ Interaction", |ui| interaction.ui(ui));
@ -567,19 +637,61 @@ impl Spacing {
icon_width,
icon_spacing,
tooltip_width,
indent_ends_with_horizontal_line,
combo_height,
scroll_bar_width,
} = self;
ui.add(slider_vec2(item_spacing, 0.0..=10.0, "item_spacing"));
ui.add(slider_vec2(window_padding, 0.0..=10.0, "window_padding"));
ui.add(slider_vec2(button_padding, 0.0..=10.0, "button_padding"));
ui.add(slider_vec2(interact_size, 0.0..=60.0, "interact_size"))
ui.add(slider_vec2(item_spacing, 0.0..=20.0, "Item spacing"));
ui.add(slider_vec2(window_padding, 0.0..=20.0, "Window padding"));
ui.add(slider_vec2(button_padding, 0.0..=20.0, "Button padding"));
ui.add(slider_vec2(interact_size, 4.0..=60.0, "Interact size"))
.on_hover_text("Minimum size of an interactive widget");
ui.add(Slider::new(indent, 0.0..=100.0).text("indent"));
ui.add(Slider::new(slider_width, 0.0..=1000.0).text("slider_width"));
ui.add(Slider::new(text_edit_width, 0.0..=1000.0).text("text_edit_width"));
ui.add(Slider::new(icon_width, 0.0..=60.0).text("icon_width"));
ui.add(Slider::new(icon_spacing, 0.0..=10.0).text("icon_spacing"));
ui.add(Slider::new(tooltip_width, 0.0..=1000.0).text("tooltip_width"));
ui.horizontal(|ui| {
ui.add(DragValue::new(indent).clamp_range(0.0..=100.0));
ui.label("Indent");
});
ui.horizontal(|ui| {
ui.add(DragValue::new(slider_width).clamp_range(0.0..=1000.0));
ui.label("Slider width");
});
ui.horizontal(|ui| {
ui.add(DragValue::new(text_edit_width).clamp_range(0.0..=1000.0));
ui.label("TextEdit width");
});
ui.horizontal(|ui| {
ui.add(DragValue::new(scroll_bar_width).clamp_range(0.0..=32.0));
ui.label("Scroll-bar width width");
});
ui.horizontal(|ui| {
ui.label("Checkboxes etc:");
ui.add(
DragValue::new(icon_width)
.prefix("width:")
.clamp_range(0.0..=60.0),
);
ui.add(
DragValue::new(icon_spacing)
.prefix("spacing:")
.clamp_range(0.0..=10.0),
);
});
ui.horizontal(|ui| {
ui.add(DragValue::new(tooltip_width).clamp_range(0.0..=1000.0));
ui.label("Tooltip wrap width");
});
ui.checkbox(
indent_ends_with_horizontal_line,
"End indented regions with a horizontal separator",
);
ui.horizontal(|ui| {
ui.label("Max height of a combo box");
ui.add(DragValue::new(combo_height).clamp_range(0.0..=1000.0));
});
ui.vertical_centered(|ui| reset_button(ui, self));
}
@ -612,33 +724,40 @@ impl Widgets {
hovered,
inactive,
noninteractive,
open,
} = self;
ui.collapsing("noninteractive", |ui| {
ui.label("The style of a widget that you cannot interact with.");
ui.collapsing("Noninteractive", |ui| {
ui.label(
"The style of a widget that you cannot interact with, e.g. labels and separators.",
);
noninteractive.ui(ui)
});
ui.collapsing("interactive & inactive", |ui| {
ui.collapsing("Interactive but inactive", |ui| {
ui.label("The style of an interactive widget, such as a button, at rest.");
inactive.ui(ui)
});
ui.collapsing("interactive & hovered", |ui| {
ui.collapsing("Interactive and hovered", |ui| {
ui.label("The style of an interactive widget while you hover it.");
hovered.ui(ui)
});
ui.collapsing("interactive & active", |ui| {
ui.collapsing("Interactive and active", |ui| {
ui.label("The style of an interactive widget as you are clicking or dragging it.");
active.ui(ui)
});
ui.collapsing("Open menu", |ui| {
ui.label("The style of an open combo-box or menu button");
open.ui(ui)
});
ui.vertical_centered(|ui| reset_button(ui, self));
// ui.vertical_centered(|ui| reset_button(ui, self));
}
}
impl Selection {
pub fn ui(&mut self, ui: &mut crate::Ui) {
let Self { bg_fill, stroke } = self;
ui.label("Selectable labels");
ui_color(ui, bg_fill, "bg_fill");
stroke_ui(ui, stroke, "stroke");
}
@ -653,12 +772,12 @@ impl WidgetVisuals {
fg_stroke,
expansion,
} = self;
ui_color(ui, bg_fill, "bg_fill");
stroke_ui(ui, bg_stroke, "bg_stroke");
ui.add(Slider::new(corner_radius, 0.0..=10.0).text("corner_radius"));
stroke_ui(ui, fg_stroke, "fg_stroke (text)");
ui.add(Slider::new(expansion, -5.0..=5.0).text("expansion"));
ui.add(Slider::new(expansion, -5.0..=5.0).text("expansion"))
.on_hover_text("make shapes this much larger");
}
}
@ -703,42 +822,66 @@ impl Visuals {
override_text_color: _,
widgets,
selection,
extreme_bg_color,
hyperlink_color,
faint_bg_color,
extreme_bg_color,
code_bg_color,
window_corner_radius,
window_shadow,
popup_shadow,
resize_corner_size,
text_cursor_width,
text_cursor_preview,
clip_rect_margin,
button_frame,
collapsing_header_frame,
} = self;
ui.collapsing("widgets", |ui| widgets.ui(ui));
ui.collapsing("selection", |ui| selection.ui(ui));
ui.collapsing("Background Colors", |ui| {
ui_color(ui, &mut widgets.inactive.bg_fill, "Buttons");
ui_color(ui, &mut widgets.noninteractive.bg_fill, "Windows");
ui_color(ui, faint_bg_color, "Faint accent").on_hover_text(
"Used for faint accentuation of interactive things, like striped grids.",
);
ui_color(ui, extreme_bg_color, "Extreme")
.on_hover_text("Background of plots and paintings");
});
ui.group(|ui| {
ui.label("Window");
ui.collapsing("Window", |ui| {
// Common shortcuts
ui_color(ui, &mut widgets.noninteractive.bg_fill, "Fill");
stroke_ui(ui, &mut widgets.noninteractive.bg_stroke, "Outline");
ui.add(Slider::new(window_corner_radius, 0.0..=20.0).text("Corner Radius"));
ui.add(Slider::new(window_corner_radius, 0.0..=20.0).text("Rounding"));
shadow_ui(ui, window_shadow, "Shadow");
shadow_ui(ui, popup_shadow, "Shadow (small menus and popups)");
});
ui.collapsing("Widgets", |ui| widgets.ui(ui));
ui.collapsing("Selection", |ui| selection.ui(ui));
ui_color(
ui,
&mut widgets.noninteractive.fg_stroke.color,
"Text color",
);
ui_color(ui, code_bg_color, Label::new("Code background").code()).on_hover_ui(|ui| {
ui.horizontal(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;
ui.label("For monospaced inlined text ");
ui.code("like this");
ui.label(".");
});
});
ui_color(ui, extreme_bg_color, "extreme_bg_color");
ui_color(ui, hyperlink_color, "hyperlink_color");
ui_color(ui, code_bg_color, "code_bg_color");
ui.add(Slider::new(resize_corner_size, 0.0..=20.0).text("resize_corner_size"));
ui.add(Slider::new(text_cursor_width, 0.0..=2.0).text("text_cursor_width"));
ui.checkbox(text_cursor_preview, "text_cursor_preview");
ui.add(Slider::new(text_cursor_width, 0.0..=4.0).text("text_cursor_width"));
ui.checkbox(text_cursor_preview, "Preview text cursor on hover");
ui.add(Slider::new(clip_rect_margin, 0.0..=20.0).text("clip_rect_margin"));
ui.checkbox(button_frame, "Button has a frame");
ui.checkbox(collapsing_header_frame, "Collapsing header has a frame");
ui.vertical_centered(|ui| reset_button(ui, self));
}
}
@ -775,17 +918,26 @@ fn slider_vec2<'a>(
) -> impl Widget + 'a {
move |ui: &mut crate::Ui| {
ui.horizontal(|ui| {
ui.add(Slider::new(&mut value.x, range.clone()).text("w"));
ui.add(Slider::new(&mut value.y, range.clone()).text("h"));
ui.add(
DragValue::new(&mut value.x)
.clamp_range(range.clone())
.prefix("x: "),
);
ui.add(
DragValue::new(&mut value.y)
.clamp_range(range.clone())
.prefix("y: "),
);
ui.label(text);
})
.response
}
}
fn ui_color(ui: &mut Ui, srgba: &mut Color32, text: &str) {
fn ui_color(ui: &mut Ui, srgba: &mut Color32, text: impl Into<Label>) -> Response {
ui.horizontal(|ui| {
ui.color_edit_button_srgba(srgba);
ui.label(text);
});
})
.response
}

View file

@ -137,6 +137,11 @@ impl Ui {
self.style = style.into();
}
/// Reset to the default style set in [`Context`].
pub fn reset_style(&mut self) {
self.style = self.ctx().style();
}
/// The current spacing options for this `Ui`.
/// Short for `ui.style().spacing`.
#[inline(always)]
@ -1317,6 +1322,9 @@ impl Ui {
}
/// Create a child ui which is indented to the right.
///
/// The `id_source` here be anything at all.
// TODO: remove `id_source` argument?
#[inline(always)]
pub fn indent<R>(
&mut self,
@ -1347,7 +1355,8 @@ impl Ui {
};
let ret = add_contents(&mut child_ui);
let end_with_horizontal_line = true;
let end_with_horizontal_line = self.spacing().indent_ends_with_horizontal_line;
if end_with_horizontal_line {
child_ui.add_space(4.0);
}

View file

@ -18,9 +18,10 @@ pub struct Button {
text_style: Option<TextStyle>,
/// None means default for interact
fill: Option<Color32>,
stroke: Option<Stroke>,
sense: Sense,
small: bool,
frame: bool,
frame: Option<bool>,
wrap: Option<bool>,
min_size: Vec2,
}
@ -32,10 +33,11 @@ impl Button {
text: text.to_string(),
text_color: None,
text_style: None,
fill: Default::default(),
fill: None,
stroke: None,
sense: Sense::click(),
small: false,
frame: true,
frame: None,
wrap: None,
min_size: Vec2::ZERO,
}
@ -56,8 +58,19 @@ impl Button {
self
}
pub fn fill(mut self, fill: Option<Color32>) -> Self {
self.fill = fill;
/// Override background fill color. Note that this will override any on-hover effects.
/// Calling this will also turn on the frame.
pub fn fill(mut self, fill: impl Into<Color32>) -> Self {
self.fill = Some(fill.into());
self.frame = Some(true);
self
}
/// Override button stroke. Note that this will override any on-hover effects.
/// Calling this will also turn on the frame.
pub fn stroke(mut self, stroke: impl Into<Stroke>) -> Self {
self.stroke = Some(stroke.into());
self.frame = Some(true);
self
}
@ -70,7 +83,7 @@ impl Button {
/// Turn off the frame
pub fn frame(mut self, frame: bool) -> Self {
self.frame = frame;
self.frame = Some(frame);
self
}
@ -116,6 +129,7 @@ impl Button {
text_color,
text_style,
fill,
stroke,
sense,
small,
frame,
@ -123,6 +137,8 @@ impl Button {
min_size,
} = self;
let frame = frame.unwrap_or_else(|| ui.visuals().button_frame);
let text_style = text_style
.or(ui.style().override_text_style)
.unwrap_or(TextStyle::Button);
@ -159,11 +175,12 @@ impl Button {
if frame {
let fill = fill.unwrap_or(visuals.bg_fill);
let stroke = stroke.unwrap_or(visuals.bg_stroke);
ui.painter().rect(
rect.expand(visuals.expansion),
visuals.corner_radius,
fill,
visuals.bg_stroke,
stroke,
);
}

View file

@ -67,11 +67,15 @@ fn show_hsva(ui: &mut Ui, color: Hsva, desired_size: Vec2) -> Response {
response
}
fn color_button(ui: &mut Ui, color: Color32) -> Response {
fn color_button(ui: &mut Ui, color: Color32, open: bool) -> Response {
let size = ui.spacing().interact_size;
let (rect, response) = ui.allocate_exact_size(size, Sense::click());
response.widget_info(|| WidgetInfo::new(WidgetType::ColorButton));
let visuals = ui.style().interact(&response);
let visuals = if open {
&ui.visuals().widgets.open
} else {
ui.style().interact(&response)
};
let rect = rect.expand(visuals.expansion);
background_checkers(ui.painter(), rect);
@ -83,7 +87,7 @@ fn color_button(ui: &mut Ui, color: Color32) -> Response {
let corner_radius = visuals.corner_radius.at_most(2.0);
ui.painter()
.rect_stroke(rect, corner_radius, (2.0, visuals.bg_fill)); // fill is intentional!
.rect_stroke(rect, corner_radius, (2.0, visuals.bg_fill)); // fill is intentional, because default style has no border
response
}
@ -335,7 +339,9 @@ fn color_picker_hsva_2d(ui: &mut Ui, hsva: &mut Hsva, alpha: Alpha) -> bool {
pub fn color_edit_button_hsva(ui: &mut Ui, hsva: &mut Hsva, alpha: Alpha) -> Response {
let pupup_id = ui.auto_id_with("popup");
let mut button_response = color_button(ui, (*hsva).into()).on_hover_text("Click to edit color");
let open = ui.memory().is_popup_open(pupup_id);
let mut button_response =
color_button(ui, (*hsva).into(), open).on_hover_text("Click to edit color");
if button_response.clicked() {
ui.memory().toggle_popup(pupup_id);

View file

@ -353,7 +353,7 @@ impl Widget for Plot {
rect,
corner_radius: 2.0,
fill: ui.visuals().extreme_bg_color,
stroke: ui.visuals().window_stroke(),
stroke: ui.visuals().widgets.noninteractive.bg_stroke,
});
// Legend

View file

@ -375,7 +375,10 @@ impl<'a> Slider<'a> {
{
let value = self.get_value();
let rail_radius = ui.painter().round_to_pixel((rect.height() / 8.0).max(2.0));
let rail_radius = ui
.painter()
.round_to_pixel((rect.height() / 4.0).at_least(2.0));
let rail_rect = Rect::from_min_max(
pos2(rect.left(), rect.center().y - rail_radius),
pos2(rect.right(), rect.center().y + rail_radius),
@ -385,8 +388,7 @@ impl<'a> Slider<'a> {
let visuals = ui.style().interact(response);
ui.painter().add(Shape::Rect {
rect: rail_rect,
corner_radius: rail_radius,
corner_radius: ui.visuals().widgets.inactive.corner_radius,
fill: ui.visuals().widgets.inactive.bg_fill,
// fill: visuals.bg_fill,
// fill: ui.visuals().extreme_bg_color,

View file

@ -8,7 +8,7 @@ pub fn easy_mark(ui: &mut Ui, easy_mark: &str) {
pub fn easy_mark_it<'em>(ui: &mut Ui, items: impl Iterator<Item = easy_mark::Item<'em>>) {
ui.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing = Vec2::new(0.0, 0.0);
ui.spacing_mut().item_spacing.x = 0.0;
ui.set_row_height(ui.fonts()[TextStyle::Body].row_height());
for item in items {

View file

@ -15,10 +15,18 @@ pub struct Shadow {
impl Shadow {
/// Tooltips, menus, ...
pub fn small() -> Self {
pub fn small_dark() -> Self {
Self {
extrusion: 8.0,
color: Color32::from_black_alpha(64),
extrusion: 16.0,
color: Color32::from_black_alpha(96),
}
}
/// Tooltips, menus, ...
pub fn small_light() -> Self {
Self {
extrusion: 16.0,
color: Color32::from_black_alpha(32),
}
}

View file

@ -400,7 +400,8 @@ impl Font {
row.y_max += cursor_y;
}
cursor_y = paragraph_rows.last().unwrap().y_max;
cursor_y += row_height * 0.2; // Extra spacing between paragraphs. TODO: less hacky
// cursor_y += row_height * 0.2; // Extra spacing between paragraphs.
rows.append(&mut paragraph_rows);

View file

@ -195,7 +195,7 @@ impl Default for FontDefinitions {
let mut family_and_size = BTreeMap::new();
family_and_size.insert(TextStyle::Small, (FontFamily::Proportional, 10.0));
family_and_size.insert(TextStyle::Body, (FontFamily::Proportional, 14.0));
family_and_size.insert(TextStyle::Button, (FontFamily::Proportional, 16.0));
family_and_size.insert(TextStyle::Button, (FontFamily::Proportional, 14.0));
family_and_size.insert(TextStyle::Heading, (FontFamily::Proportional, 20.0));
family_and_size.insert(TextStyle::Monospace, (FontFamily::Monospace, 13.0)); // 13 for `ProggyClean`