diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ae1e508..5d652a4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed 🔧 +* New simpler and sleeker look! * Center window titles. * Tweak size and alignment of some emojis to match other text. * Rename `PaintCmd` to `Shape`. diff --git a/egui/src/containers/collapsing_header.rs b/egui/src/containers/collapsing_header.rs index e22d15e0..813ba1fc 100644 --- a/egui/src/containers/collapsing_header.rs +++ b/egui/src/containers/collapsing_header.rs @@ -209,7 +209,8 @@ impl CollapsingHeader { rect: header_response.rect.expand(visuals.expansion), corner_radius: visuals.corner_radius, fill: visuals.bg_fill, - stroke: Default::default(), + stroke: visuals.bg_stroke, + // stroke: Default::default(), }); { diff --git a/egui/src/containers/frame.rs b/egui/src/containers/frame.rs index aa933eea..03101459 100644 --- a/egui/src/containers/frame.rs +++ b/egui/src/containers/frame.rs @@ -44,7 +44,7 @@ impl Frame { corner_radius: style.visuals.window_corner_radius, shadow: style.visuals.window_shadow, fill: style.visuals.widgets.noninteractive.bg_fill, - stroke: style.visuals.widgets.inactive.bg_stroke, // because we can resize windows + stroke: style.visuals.widgets.noninteractive.bg_stroke, } } diff --git a/egui/src/containers/scroll_area.rs b/egui/src/containers/scroll_area.rs index 2dcbc188..d9a99c18 100644 --- a/egui/src/containers/scroll_area.rs +++ b/egui/src/containers/scroll_area.rs @@ -337,8 +337,8 @@ impl Prepared { ui.painter().add(paint::Shape::Rect { rect: handle_rect.expand(-2.0), corner_radius, - fill: visuals.fg_fill, - stroke: visuals.fg_stroke, + fill: visuals.bg_fill, + stroke: visuals.bg_stroke, }); } diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs index a278ad8e..3ed0e077 100644 --- a/egui/src/containers/window.rs +++ b/egui/src/containers/window.rs @@ -744,7 +744,7 @@ impl TitleBar { // let y = lerp(self.rect.bottom()..=content_response.rect.top(), 0.5); ui.painter().line_segment( [pos2(left, y), pos2(right, y)], - ui.style().visuals.widgets.inactive.bg_stroke, + ui.style().visuals.widgets.noninteractive.bg_stroke, ); } diff --git a/egui/src/menu.rs b/egui/src/menu.rs index dc78cdf3..5e1a557b 100644 --- a/egui/src/menu.rs +++ b/egui/src/menu.rs @@ -79,7 +79,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.widgets.active.fg_fill)); + button = button.fill(Some(ui.style().visuals.selection.bg_fill)); } let button_response = ui.add(button); diff --git a/egui/src/style.rs b/egui/src/style.rs index 79714206..579261ec 100644 --- a/egui/src/style.rs +++ b/egui/src/style.rs @@ -56,7 +56,7 @@ pub struct Spacing { /// Indent collapsing regions etc by this much. pub indent: f32, - /// Minimum size of e.g. a button. + /// Minimum size of e.g. a button (including padding). /// `interact_size.y` is the default height of button, slider, etc. /// Anything clickable should be (at least) this size. pub interact_size: Vec2, // TODO: rename min_interact_size ? @@ -181,16 +181,16 @@ pub struct Selection { #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "persistence", serde(default))] 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, + /// For an otherwise interactive widget that has been disabled + pub disabled: WidgetVisuals, + /// For an interactive widget that is "resting" + pub inactive: WidgetVisuals, + /// For an interactive widget that is being hovered + pub hovered: WidgetVisuals, + /// For an interactive widget that is being interacted with + pub active: WidgetVisuals, } impl Widgets { @@ -216,15 +216,12 @@ pub struct WidgetVisuals { /// For surrounding rectangle of things that need it, /// like buttons, the box of the checkbox, etc. + /// Should maybe be called `frame_stroke`. pub bg_stroke: Stroke, /// Button frames etc pub corner_radius: f32, - /// Fill color of the interactive part of a component (slider grab, checkbox, ...) - /// When you need a fill. - pub fg_fill: Color32, - /// Stroke and text color of the interactive part of a component (button text, slider grab, check-mark, ...) pub fg_stroke: Stroke, @@ -256,14 +253,14 @@ impl Default for Spacing { fn default() -> Self { Self { item_spacing: vec2(8.0, 3.0), - window_padding: vec2(4.0, 4.0), - button_padding: vec2(3.0, 1.0), + window_padding: Vec2::splat(6.0), + button_padding: vec2(4.0, 1.0), indent: 25.0, interact_size: vec2(40.0, 20.0), slider_width: 100.0, text_edit_width: 280.0, icon_width: 16.0, - icon_spacing: 1.0, + icon_spacing: 0.0, tooltip_width: 400.0, } } @@ -284,7 +281,7 @@ impl Default for Visuals { override_text_color: None, widgets: Default::default(), selection: Default::default(), - dark_bg_color: Color32::from_black_alpha(140), + dark_bg_color: Color32::from_gray(10), hyperlink_color: Color32::from_rgb(90, 170, 255), window_corner_radius: 10.0, window_shadow: Shadow::big(), @@ -313,46 +310,46 @@ impl Default for Selection { impl Default for Widgets { fn default() -> Self { Self { - active: WidgetVisuals { - bg_fill: Rgba::from_luminance_alpha(0.10, 0.5).into(), - bg_stroke: Stroke::new(2.0, Color32::WHITE), + noninteractive: WidgetVisuals { + bg_stroke: Stroke::new(1.0, Color32::from_gray(65)), // window outline + bg_fill: Color32::from_gray(30), // window background corner_radius: 4.0, - fg_fill: Color32::from_rgb(120, 120, 200), - fg_stroke: Stroke::new(2.0, Color32::WHITE), - expansion: 2.0, - }, - hovered: WidgetVisuals { - bg_fill: Rgba::from_luminance_alpha(0.06, 0.5).into(), - bg_stroke: Stroke::new(1.0, Rgba::from_white_alpha(0.5)), - corner_radius: 4.0, - fg_fill: Color32::from_rgb(100, 100, 150), - fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), - expansion: 1.0, - }, - inactive: WidgetVisuals { - bg_fill: Rgba::from_luminance_alpha(0.04, 0.5).into(), - bg_stroke: Stroke::new(1.0, Rgba::from_white_alpha(0.06)), // default window outline. Should be pretty readable - corner_radius: 4.0, - fg_fill: Color32::from_rgb(60, 60, 80), - fg_stroke: Stroke::new(1.0, Color32::from_gray(200)), // Should NOT look grayed out! + + fg_stroke: Stroke::new(1.0, Color32::from_gray(160)), // text color expansion: 0.0, }, disabled: WidgetVisuals { - bg_fill: Rgba::from_luminance_alpha(0.02, 0.5).into(), - bg_stroke: Stroke::new(0.5, Color32::from_gray(70)), + bg_fill: Color32::from_gray(40), // Should look grayed out + bg_stroke: Stroke::new(1.0, Color32::from_gray(70)), corner_radius: 4.0, - fg_fill: Color32::from_rgb(50, 50, 50), + fg_stroke: Stroke::new(1.0, Color32::from_gray(140)), // Should look grayed out expansion: 0.0, }, - noninteractive: WidgetVisuals { - bg_stroke: Stroke::new(1.0, Rgba::from_white_alpha(0.06)), - bg_fill: Rgba::from_luminance_alpha(0.010, 0.975).into(), // window background + inactive: WidgetVisuals { + bg_fill: Color32::from_gray(70), + bg_stroke: Default::default(), corner_radius: 4.0, - fg_fill: Default::default(), - fg_stroke: Stroke::new(1.0, Color32::from_gray(160)), // text color + + fg_stroke: Stroke::new(1.0, Color32::from_gray(200)), // Should NOT look grayed out! expansion: 0.0, }, + hovered: WidgetVisuals { + bg_fill: Color32::from_gray(80), + bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button + corner_radius: 4.0, + + fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), + expansion: 1.0, + }, + active: WidgetVisuals { + bg_fill: Color32::from_gray(90), + bg_stroke: Stroke::new(1.0, Color32::WHITE), + corner_radius: 4.0, + + fg_stroke: Stroke::new(2.0, Color32::WHITE), + expansion: 2.0, + }, } } } @@ -443,11 +440,26 @@ impl Widgets { noninteractive, } = self; - ui.collapsing("noninteractive", |ui| noninteractive.ui(ui)); - ui.collapsing("interactive & disabled", |ui| disabled.ui(ui)); - ui.collapsing("interactive & inactive", |ui| inactive.ui(ui)); - ui.collapsing("interactive & hovered", |ui| hovered.ui(ui)); - ui.collapsing("interactive & active", |ui| active.ui(ui)); + ui.collapsing("noninteractive", |ui| { + ui.label("The style of something that you cannot interact with."); + noninteractive.ui(ui) + }); + ui.collapsing("interactive & disabled", |ui| { + ui.label("The style of a disabled button."); + disabled.ui(ui) + }); + ui.collapsing("interactive & inactive", |ui| { + ui.label("The style of a widget, such as a button, at rest."); + inactive.ui(ui) + }); + ui.collapsing("interactive & hovered", |ui| { + ui.label("The style of a widget while you hover it."); + hovered.ui(ui) + }); + ui.collapsing("interactive & active", |ui| { + ui.label("The style of a widget as you are clicking or dragging it."); + active.ui(ui) + }); } } @@ -466,7 +478,6 @@ impl WidgetVisuals { bg_fill, bg_stroke, corner_radius, - fg_fill, fg_stroke, expansion, } = self; @@ -474,7 +485,6 @@ impl WidgetVisuals { ui_color(ui, bg_fill, "bg_fill"); stroke_ui(ui, bg_stroke, "bg_stroke"); ui.add(Slider::f32(corner_radius, 0.0..=10.0).text("corner_radius")); - ui_color(ui, fg_fill, "fg_fill"); stroke_ui(ui, fg_stroke, "fg_stroke (text)"); ui.add(Slider::f32(expansion, -5.0..=5.0).text("expansion")); } diff --git a/egui/src/widgets/button.rs b/egui/src/widgets/button.rs index 25d38c56..ca2dae72 100644 --- a/egui/src/widgets/button.rs +++ b/egui/src/widgets/button.rs @@ -217,6 +217,7 @@ impl<'a> Widget for Checkbox<'a> { pos2(small_icon_rect.right(), small_icon_rect.top()), ], visuals.fg_stroke, + // ui.style().visuals.selection.stroke, // too much color )); } @@ -306,9 +307,8 @@ impl Widget for RadioButton { center: small_icon_rect.center(), radius: small_icon_rect.width() / 3.0, fill: visuals.fg_stroke.color, // Intentional to use stroke and not fill + // fill: ui.style().visuals.selection.stroke.color, // too much color stroke: Default::default(), - // fill: visuals.fg_fill, - // stroke: visuals.fg_stroke, }); } diff --git a/egui/src/widgets/color_picker.rs b/egui/src/widgets/color_picker.rs index 375f53d0..7cac8d5b 100644 --- a/egui/src/widgets/color_picker.rs +++ b/egui/src/widgets/color_picker.rs @@ -78,7 +78,7 @@ fn color_button(ui: &mut Ui, color: Color32) -> Response { ui.painter().rect_filled(left, 0.0, color); ui.painter().rect_filled(right, 0.0, color.to_opaque()); ui.painter() - .rect_stroke(rect, corner_radius, visuals.fg_stroke); + .rect_stroke(rect, corner_radius, visuals.bg_stroke); } else { ui.painter().add(Shape::Rect { rect, diff --git a/egui/src/widgets/selected_label.rs b/egui/src/widgets/selected_label.rs index 3243624c..fe595b3c 100644 --- a/egui/src/widgets/selected_label.rs +++ b/egui/src/widgets/selected_label.rs @@ -44,12 +44,18 @@ impl Widget for SelectableLabel { if selected || response.hovered { let rect = rect.expand(visuals.expansion); - let bg_fill = if selected { + let fill = if selected { ui.style().visuals.selection.bg_fill } else { Default::default() }; - ui.painter().rect(rect, 0.0, bg_fill, visuals.bg_stroke); + let stroke = if selected { + ui.style().visuals.selection.stroke + } else { + visuals.bg_stroke + }; + let corner_radius = 2.0; + ui.painter().rect(rect, corner_radius, fill, stroke); } let text_color = ui diff --git a/egui/src/widgets/slider.rs b/egui/src/widgets/slider.rs index 254b14e6..300f3972 100644 --- a/egui/src/widgets/slider.rs +++ b/egui/src/widgets/slider.rs @@ -282,16 +282,19 @@ impl<'a> Slider<'a> { ui.painter().add(Shape::Rect { rect: rail_rect, corner_radius: rail_radius, - // fill: visuals.bg_fill, + fill: ui.style().visuals.widgets.inactive.bg_fill, + // fill: visuals.bg_fill, + // fill: ui.style().visuals.dark_bg_color, + stroke: Default::default(), // stroke: visuals.bg_stroke, - stroke: ui.style().visuals.widgets.inactive.bg_stroke, + // stroke: ui.style().visuals.widgets.inactive.bg_stroke, }); ui.painter().add(Shape::Circle { center: pos2(marker_center_x, rail_rect.center().y), radius: handle_radius(rect) + visuals.expansion, - fill: visuals.fg_fill, + fill: visuals.bg_fill, stroke: visuals.fg_stroke, }); } diff --git a/egui/src/widgets/text_edit.rs b/egui/src/widgets/text_edit.rs index 995f7002..79996211 100644 --- a/egui/src/widgets/text_edit.rs +++ b/egui/src/widgets/text_edit.rs @@ -240,15 +240,24 @@ impl<'t> Widget for TextEdit<'t> { if frame { let visuals = ui.style().interact(&response); let frame_rect = response.rect.expand(visuals.expansion); - ui.painter().set( - where_to_put_background, + let shape = if response.has_kb_focus { + Shape::Rect { + rect: frame_rect, + corner_radius: visuals.corner_radius, + // fill: ui.style().visuals.selection.bg_fill, + fill: ui.style().visuals.dark_bg_color, + stroke: ui.style().visuals.selection.stroke, + } + } else { Shape::Rect { rect: frame_rect, corner_radius: visuals.corner_radius, fill: ui.style().visuals.dark_bg_color, - stroke: visuals.bg_stroke, - }, - ); + stroke: visuals.bg_stroke, // TODO: we want to show something here, or a text-edit field doesn't "pop". + } + }; + + ui.painter().set(where_to_put_background, shape); } response diff --git a/egui_demo_lib/src/apps/demo/toggle_switch.rs b/egui_demo_lib/src/apps/demo/toggle_switch.rs index 060235a4..234a509a 100644 --- a/egui_demo_lib/src/apps/demo/toggle_switch.rs +++ b/egui_demo_lib/src/apps/demo/toggle_switch.rs @@ -40,8 +40,8 @@ pub fn toggle(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { // "how should something that is being interacted with be painted?". // This will, for instance, give us different colors when the widget is hovered or clicked. let visuals = ui.style().interact(&response); - let off_bg_fill = egui::Rgba::TRANSPARENT; - let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.25); + let off_bg_fill = egui::Rgba::from(visuals.bg_fill); + let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.0); let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on); // All coordinates are in absolute screen coordinates so we use `rect` to place the elements. let rect = rect.expand(visuals.expansion); @@ -51,7 +51,7 @@ pub fn toggle(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on); let center = egui::pos2(circle_x, rect.center().y); ui.painter() - .circle(center, 0.75 * radius, visuals.fg_fill, visuals.fg_stroke); + .circle(center, 0.75 * radius, visuals.bg_fill, visuals.fg_stroke); // All done! Return the interaction response so the user can check what happened // (hovered, clicked, ...) and maybe show a tooltip: @@ -67,8 +67,8 @@ fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { let how_on = ui.ctx().animate_bool(response.id, *on); let visuals = ui.style().interact(&response); - let off_bg_fill = egui::Rgba::TRANSPARENT; - let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.25); + let off_bg_fill = egui::Rgba::from(visuals.bg_fill); + let on_bg_fill = egui::Rgba::from_rgb(0.0, 0.5, 0.0); let bg_fill = egui::lerp(off_bg_fill..=on_bg_fill, how_on); let rect = rect.expand(visuals.expansion); let radius = 0.5 * rect.height(); @@ -76,7 +76,7 @@ fn toggle_compact(ui: &mut egui::Ui, on: &mut bool) -> egui::Response { let circle_x = egui::lerp((rect.left() + radius)..=(rect.right() - radius), how_on); let center = egui::pos2(circle_x, rect.center().y); ui.painter() - .circle(center, 0.75 * radius, visuals.fg_fill, visuals.fg_stroke); + .circle(center, 0.75 * radius, visuals.bg_fill, visuals.fg_stroke); response }