Skip to content

Commit

Permalink
Merge branch 'master' into patch08
Browse files Browse the repository at this point in the history
  • Loading branch information
bircni committed Sep 1, 2024
2 parents 9f12566 + da04339 commit c5f19f6
Show file tree
Hide file tree
Showing 27 changed files with 357 additions and 122 deletions.
1 change: 1 addition & 0 deletions crates/ecolor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--generate-link-to-definition"]

[lib]

Expand Down
1 change: 1 addition & 0 deletions crates/eframe/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ include = [
[package.metadata.docs.rs]
all-features = true
targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]
rustdoc-args = ["--generate-link-to-definition"]

[lints]
workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/egui-wgpu/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ workspace = true

[package.metadata.docs.rs]
all-features = true

rustdoc-args = ["--generate-link-to-definition"]

[features]
default = []
Expand Down
2 changes: 1 addition & 1 deletion crates/egui-winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ workspace = true

[package.metadata.docs.rs]
all-features = true

rustdoc-args = ["--generate-link-to-definition"]

[features]
default = ["clipboard", "links", "wayland", "winit/default", "x11"]
Expand Down
1 change: 1 addition & 0 deletions crates/egui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--generate-link-to-definition"]

[lib]

Expand Down
28 changes: 20 additions & 8 deletions crates/egui/src/containers/panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,9 @@ impl SidePanel {
ui.ctx().set_cursor_icon(cursor_icon);
}

// Keep this rect snapped so that panel content can be pixel-perfect
let rect = ui.painter().round_rect_to_pixels(rect);

PanelState { rect }.store(ui.ctx(), id);

{
Expand All @@ -343,10 +346,14 @@ impl SidePanel {
Stroke::NONE
};
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
// In the meantime: nudge the line so its inside the panel, so it won't be covered by neighboring panel
// (hence the shrink).
let resize_x = side.opposite().side_x(rect.shrink(1.0));
let resize_x = ui.painter().round_to_pixel(resize_x);
let resize_x = side.opposite().side_x(rect);

// This makes it pixel-perfect for odd-sized strokes (width=1.0, width=3.0, etc)
let resize_x = ui.painter().round_to_pixel_center(resize_x);

// We want the line exactly on the last pixel but rust rounds away from zero so we bring it back a bit for
// left-side panels
let resize_x = resize_x - if side == Side::Left { 1.0 } else { 0.0 };
ui.painter().vline(resize_x, panel_rect.y_range(), stroke);
}

Expand Down Expand Up @@ -817,6 +824,9 @@ impl TopBottomPanel {
ui.ctx().set_cursor_icon(cursor_icon);
}

// Keep this rect snapped so that panel content can be pixel-perfect
let rect = ui.painter().round_rect_to_pixels(rect);

PanelState { rect }.store(ui.ctx(), id);

{
Expand All @@ -831,10 +841,12 @@ impl TopBottomPanel {
Stroke::NONE
};
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
// In the meantime: nudge the line so its inside the panel, so it won't be covered by neighboring panel
// (hence the shrink).
let resize_y = side.opposite().side_y(rect.shrink(1.0));
let resize_y = ui.painter().round_to_pixel(resize_y);
let resize_y = side.opposite().side_y(rect);
let resize_y = ui.painter().round_to_pixel_center(resize_y);

// We want the line exactly on the last pixel but rust rounds away from zero so we bring it back a bit for
// top-side panels
let resize_y = resize_y - if side == TopBottomSide::Top { 1.0 } else { 0.0 };
ui.painter().hline(panel_rect.x_range(), resize_y, stroke);
}

Expand Down
26 changes: 8 additions & 18 deletions crates/egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,9 +439,6 @@ impl<'open> Window<'open> {
let mut window_frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
// Keep the original inner margin for later use
let window_margin = window_frame.inner_margin;
let border_padding = window_frame.stroke.width / 2.0;
// Add border padding to the inner margin to prevent it from covering the contents
window_frame.inner_margin += border_padding;

let is_explicitly_closed = matches!(open, Some(false));
let is_open = !is_explicitly_closed || ctx.memory(|mem| mem.everything_is_visible());
Expand Down Expand Up @@ -575,9 +572,9 @@ impl<'open> Window<'open> {

if let Some(title_bar) = title_bar {
let mut title_rect = Rect::from_min_size(
outer_rect.min + vec2(border_padding, border_padding),
outer_rect.min,
Vec2 {
x: outer_rect.size().x - border_padding * 2.0,
x: outer_rect.size().x,
y: title_bar_height,
},
);
Expand All @@ -587,9 +584,6 @@ impl<'open> Window<'open> {
if on_top && area_content_ui.visuals().window_highlight_topmost {
let mut round = window_frame.rounding;

// Eliminate the rounding gap between the title bar and the window frame
round -= border_padding;

if !is_collapsed {
round.se = 0.0;
round.sw = 0.0;
Expand All @@ -603,7 +597,7 @@ impl<'open> Window<'open> {

// Fix title bar separator line position
if let Some(response) = &mut content_response {
response.rect.min.y = outer_rect.min.y + title_bar_height + border_padding;
response.rect.min.y = outer_rect.min.y + title_bar_height;
}

title_bar.ui(
Expand Down Expand Up @@ -667,14 +661,10 @@ fn paint_resize_corner(
}
};

// Adjust the corner offset to accommodate the stroke width and window rounding
let offset = if radius <= 2.0 && stroke.width < 2.0 {
2.0
} else {
// The corner offset is calculated to make the corner appear to be in the correct position
(2.0_f32.sqrt() * (1.0 + radius + stroke.width / 2.0) - radius)
* 45.0_f32.to_radians().cos()
};
// Adjust the corner offset to accommodate for window rounding
let offset =
((2.0_f32.sqrt() * (1.0 + radius) - radius) * 45.0_f32.to_radians().cos()).max(2.0);

let corner_size = Vec2::splat(ui.visuals().resize_corner_size);
let corner_rect = corner.align_size_within_rect(corner_size, outer_rect);
let corner_rect = corner_rect.translate(-offset * corner.to_sign()); // move away from corner
Expand Down Expand Up @@ -1136,7 +1126,6 @@ impl TitleBar {
let text_pos =
emath::align::center_size_in_rect(self.title_galley.size(), full_top_rect).left_top();
let text_pos = text_pos - self.title_galley.rect.min.to_vec2();
let text_pos = text_pos - 1.5 * Vec2::Y; // HACK: center on x-height of text (looks better)
ui.painter().galley(
text_pos,
self.title_galley.clone(),
Expand All @@ -1150,6 +1139,7 @@ impl TitleBar {
let stroke = ui.visuals().widgets.noninteractive.bg_stroke;
// Workaround: To prevent border infringement,
// the 0.1 value should ideally be calculated using TessellationOptions::feathering_size_in_pixels
// or we could support selectively disabling feathering on line caps
let x_range = outer_rect.x_range().shrink(0.1);
ui.painter().hline(x_range, y, stroke);
}
Expand Down
24 changes: 20 additions & 4 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1717,26 +1717,42 @@ impl Context {
});
}

/// Useful for pixel-perfect rendering
/// Useful for pixel-perfect rendering of lines that are one pixel wide (or any odd number of pixels).
#[inline]
pub(crate) fn round_to_pixel_center(&self, point: f32) -> f32 {
let pixels_per_point = self.pixels_per_point();
((point * pixels_per_point - 0.5).round() + 0.5) / pixels_per_point
}

/// Useful for pixel-perfect rendering of lines that are one pixel wide (or any odd number of pixels).
#[inline]
pub(crate) fn round_pos_to_pixel_center(&self, point: Pos2) -> Pos2 {
pos2(
self.round_to_pixel_center(point.x),
self.round_to_pixel_center(point.y),
)
}

/// Useful for pixel-perfect rendering of filled shapes
#[inline]
pub(crate) fn round_to_pixel(&self, point: f32) -> f32 {
let pixels_per_point = self.pixels_per_point();
(point * pixels_per_point).round() / pixels_per_point
}

/// Useful for pixel-perfect rendering
/// Useful for pixel-perfect rendering of filled shapes
#[inline]
pub(crate) fn round_pos_to_pixels(&self, pos: Pos2) -> Pos2 {
pos2(self.round_to_pixel(pos.x), self.round_to_pixel(pos.y))
}

/// Useful for pixel-perfect rendering
/// Useful for pixel-perfect rendering of filled shapes
#[inline]
pub(crate) fn round_vec_to_pixels(&self, vec: Vec2) -> Vec2 {
vec2(self.round_to_pixel(vec.x), self.round_to_pixel(vec.y))
}

/// Useful for pixel-perfect rendering
/// Useful for pixel-perfect rendering of filled shapes
#[inline]
pub(crate) fn round_rect_to_pixels(&self, rect: Rect) -> Rect {
Rect {
Expand Down
14 changes: 13 additions & 1 deletion crates/egui/src/painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,19 @@ impl Painter {
self.clip_rect = clip_rect;
}

/// Useful for pixel-perfect rendering.
/// Useful for pixel-perfect rendering of lines that are one pixel wide (or any odd number of pixels).
#[inline]
pub fn round_to_pixel_center(&self, point: f32) -> f32 {
self.ctx().round_to_pixel_center(point)
}

/// Useful for pixel-perfect rendering of lines that are one pixel wide (or any odd number of pixels).
#[inline]
pub fn round_pos_to_pixel_center(&self, pos: Pos2) -> Pos2 {
self.ctx().round_pos_to_pixel_center(pos)
}

/// Useful for pixel-perfect rendering of filled shapes.
#[inline]
pub fn round_to_pixel(&self, point: f32) -> f32 {
self.ctx().round_to_pixel(point)
Expand Down
8 changes: 6 additions & 2 deletions crates/egui/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2477,8 +2477,12 @@ impl Widget for &mut Stroke {

// stroke preview:
let (_id, stroke_rect) = ui.allocate_space(ui.spacing().interact_size);
let left = stroke_rect.left_center();
let right = stroke_rect.right_center();
let left = ui
.painter()
.round_pos_to_pixel_center(stroke_rect.left_center());
let right = ui
.painter()
.round_pos_to_pixel_center(stroke_rect.right_center());
ui.painter().line_segment([left, right], (*width, *color));
})
.response
Expand Down
4 changes: 2 additions & 2 deletions crates/egui/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2211,9 +2211,9 @@ impl Ui {

let stroke = self.visuals().widgets.noninteractive.bg_stroke;
let left_top = child_rect.min - 0.5 * indent * Vec2::X;
let left_top = self.painter().round_pos_to_pixels(left_top);
let left_top = self.painter().round_pos_to_pixel_center(left_top);
let left_bottom = pos2(left_top.x, child_ui.min_rect().bottom() - 2.0);
let left_bottom = self.painter().round_pos_to_pixels(left_bottom);
let left_bottom = self.painter().round_pos_to_pixel_center(left_bottom);

if left_vline {
// draw a faint line on the left to mark the indented section
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/ui_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::Ui;
/// except for `max_rect` which by default is set to
/// the parent [`Ui::available_rect_before_wrap`].
#[must_use]
#[derive(Default)]
#[derive(Clone, Default)]
pub struct UiBuilder {
pub id_salt: Option<Id>,
pub ui_stack_info: UiStackInfo,
Expand Down
4 changes: 2 additions & 2 deletions crates/egui/src/widgets/separator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,12 @@ impl Widget for Separator {
if is_horizontal_line {
painter.hline(
(rect.left() - grow)..=(rect.right() + grow),
painter.round_to_pixel(rect.center().y),
painter.round_to_pixel_center(rect.center().y),
stroke,
);
} else {
painter.vline(
painter.round_to_pixel(rect.center().x),
painter.round_to_pixel_center(rect.center().x),
(rect.top() - grow)..=(rect.bottom() + grow),
stroke,
);
Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--generate-link-to-definition"]

[lib]
crate-type = ["cdylib", "rlib"]
Expand Down
13 changes: 8 additions & 5 deletions crates/egui_demo_app/src/wrap_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,12 +277,14 @@ impl eframe::App for WrapApp {
}

let mut cmd = Command::Nothing;
egui::TopBottomPanel::top("wrap_app_top_bar").show(ctx, |ui| {
ui.horizontal_wrapped(|ui| {
ui.visuals_mut().button_frame = false;
self.bar_contents(ui, frame, &mut cmd);
egui::TopBottomPanel::top("wrap_app_top_bar")
.frame(egui::Frame::none().inner_margin(4.0))
.show(ctx, |ui| {
ui.horizontal_wrapped(|ui| {
ui.visuals_mut().button_frame = false;
self.bar_contents(ui, frame, &mut cmd);
});
});
});

self.state.backend_panel.update(ctx, frame);

Expand Down Expand Up @@ -324,6 +326,7 @@ impl WrapApp {
egui::SidePanel::left("backend_panel")
.resizable(false)
.show_animated(ctx, is_open, |ui| {
ui.add_space(4.0);
ui.vertical_centered(|ui| {
ui.heading("💻 Backend");
});
Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ workspace = true

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--generate-link-to-definition"]

[lib]

Expand Down
1 change: 1 addition & 0 deletions crates/egui_demo_lib/src/demo/demo_app_windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ impl DemoWindows {
.resizable(false)
.default_width(150.0)
.show(ctx, |ui| {
ui.add_space(4.0);
ui.vertical_centered(|ui| {
ui.heading("✒ egui demos");
});
Expand Down
43 changes: 43 additions & 0 deletions crates/egui_demo_lib/src/rendering_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,49 @@ pub fn pixel_test(ui: &mut Ui) {
ui.add_space(4.0);

pixel_test_squares(ui);

ui.add_space(4.0);

pixel_test_strokes(ui);
}

fn pixel_test_strokes(ui: &mut Ui) {
ui.label("The strokes should align to the physical pixel grid.");
let color = if ui.style().visuals.dark_mode {
egui::Color32::WHITE
} else {
egui::Color32::BLACK
};

let pixels_per_point = ui.ctx().pixels_per_point();

for thickness_pixels in 1..=3 {
let thickness_pixels = thickness_pixels as f32;
let thickness_points = thickness_pixels / pixels_per_point;
let num_squares = (pixels_per_point * 10.0).round().max(10.0) as u32;
let size_pixels = vec2(
ui.available_width(),
num_squares as f32 + thickness_pixels * 2.0,
);
let size_points = size_pixels / pixels_per_point + Vec2::splat(2.0);
let (response, painter) = ui.allocate_painter(size_points, Sense::hover());

let mut cursor_pixel = Pos2::new(
response.rect.min.x * pixels_per_point + thickness_pixels,
response.rect.min.y * pixels_per_point + thickness_pixels,
)
.ceil();

let stroke = Stroke::new(thickness_points, color);
for size in 1..=num_squares {
let rect_points = Rect::from_min_size(
Pos2::new(cursor_pixel.x, cursor_pixel.y),
Vec2::splat(size as f32),
);
painter.rect_stroke(rect_points / pixels_per_point, 0.0, stroke);
cursor_pixel.x += (1 + size) as f32 + thickness_pixels * 2.0;
}
}
}

fn pixel_test_squares(ui: &mut Ui) {
Expand Down
Loading

0 comments on commit c5f19f6

Please sign in to comment.