Skip to content

Commit

Permalink
Merge branch 'emilk:master' into patch8
Browse files Browse the repository at this point in the history
  • Loading branch information
rustbasic authored Dec 27, 2024
2 parents f4d4308 + d20f93e commit 83f3335
Show file tree
Hide file tree
Showing 65 changed files with 631 additions and 327 deletions.
10 changes: 6 additions & 4 deletions crates/egui/src/containers/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
//! It has no frame or own size. It is potentially movable.
//! It is the foundation for windows and popups.
use emath::GuiRounding as _;

use crate::{
emath, pos2, Align2, Context, Id, InnerResponse, LayerId, NumExt, Order, Pos2, Rect, Response,
Sense, Ui, UiBuilder, UiKind, UiStackInfo, Vec2, WidgetRect, WidgetWithState,
Expand Down Expand Up @@ -66,6 +68,7 @@ impl AreaState {
pivot_pos.x - self.pivot.x().to_factor() * size.x,
pivot_pos.y - self.pivot.y().to_factor() * size.y,
)
.round_ui()
}

/// Move the left top positions of the area.
Expand All @@ -80,7 +83,7 @@ impl AreaState {
/// Where the area is on screen.
pub fn rect(&self) -> Rect {
let size = self.size.unwrap_or_default();
Rect::from_min_size(self.left_top_pos(), size)
Rect::from_min_size(self.left_top_pos(), size).round_ui()
}
}

Expand Down Expand Up @@ -493,12 +496,11 @@ impl Area {

if constrain {
state.set_left_top_pos(
ctx.constrain_window_rect_to_area(state.rect(), constrain_rect)
.min,
Context::constrain_window_rect_to_area(state.rect(), constrain_rect).min,
);
}

state.set_left_top_pos(ctx.round_pos_to_pixels(state.left_top_pos()));
state.set_left_top_pos(state.left_top_pos());

// Update response with possibly moved/constrained rect:
move_response.rect = state.rect();
Expand Down
39 changes: 25 additions & 14 deletions crates/egui/src/containers/panel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
//!
//! Add your [`crate::Window`]:s after any top-level panels.
use emath::GuiRounding as _;

use crate::{
lerp, vec2, Align, Context, CursorIcon, Frame, Id, InnerResponse, LayerId, Layout, NumExt,
Rangef, Rect, Sense, Stroke, Ui, UiBuilder, UiKind, UiStackInfo, Vec2,
Expand Down Expand Up @@ -76,6 +78,13 @@ impl Side {
Self::Right => rect.right(),
}
}

fn sign(self) -> f32 {
match self {
Self::Left => -1.0,
Self::Right => 1.0,
}
}
}

/// A panel that covers the entire left or right side of a [`Ui`] or screen.
Expand Down Expand Up @@ -264,6 +273,8 @@ impl SidePanel {
}
}

panel_rect = panel_rect.round_ui();

let mut panel_ui = ui.new_child(
UiBuilder::new()
.id_salt(id)
Expand Down Expand Up @@ -345,12 +356,8 @@ impl SidePanel {
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
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 };
// Make sure the line is on the inside of the panel:
let resize_x = resize_x + 0.5 * side.sign() * stroke.width;
ui.painter().vline(resize_x, panel_rect.y_range(), stroke);
}

Expand Down Expand Up @@ -558,6 +565,13 @@ impl TopBottomSide {
Self::Bottom => rect.bottom(),
}
}

fn sign(self) -> f32 {
match self {
Self::Top => -1.0,
Self::Bottom => 1.0,
}
}
}

/// A panel that covers the entire top or bottom of a [`Ui`] or screen.
Expand Down Expand Up @@ -756,6 +770,8 @@ impl TopBottomPanel {
}
}

panel_rect = panel_rect.round_ui();

let mut panel_ui = ui.new_child(
UiBuilder::new()
.id_salt(id)
Expand Down Expand Up @@ -837,12 +853,8 @@ impl TopBottomPanel {
// TODO(emilk): draw line on top of all panels in this ui when https://github.com/emilk/egui/issues/1516 is done
let resize_y = side.opposite().side_y(rect);

// This makes it pixel-perfect for odd-sized strokes (width=1.0, width=3.0, etc)
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 };
// Make sure the line is on the inside of the panel:
let resize_y = resize_y + 0.5 * side.sign() * stroke.width;
ui.painter().hline(panel_rect.x_range(), resize_y, stroke);
}

Expand Down Expand Up @@ -1130,15 +1142,14 @@ impl CentralPanel {
ctx: &Context,
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
) -> InnerResponse<R> {
let available_rect = ctx.available_rect();
let id = Id::new((ctx.viewport_id(), "central_panel"));

let mut panel_ui = Ui::new(
ctx.clone(),
id,
UiBuilder::new()
.layer_id(LayerId::background())
.max_rect(available_rect),
.max_rect(ctx.available_rect().round_ui()),
);
panel_ui.set_clip_rect(ctx.screen_rect());

Expand Down
11 changes: 8 additions & 3 deletions crates/egui/src/containers/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ impl Resize {
.at_most(self.max_size)
.at_most(
ui.ctx().screen_rect().size() - ui.spacing().window_margin.sum(), // hack for windows
);
)
.round_ui();

State {
desired_size: default_size,
Expand All @@ -233,7 +234,8 @@ impl Resize {
state.desired_size = state
.desired_size
.at_least(self.min_size)
.at_most(self.max_size);
.at_most(self.max_size)
.round_ui();

let mut user_requested_size = state.requested_size.take();

Expand Down Expand Up @@ -383,6 +385,7 @@ impl Resize {
}
}

use emath::GuiRounding as _;
use epaint::Stroke;

pub fn paint_resize_corner(ui: &Ui, response: &Response) {
Expand All @@ -397,7 +400,9 @@ pub fn paint_resize_corner_with_style(
corner: Align2,
) {
let painter = ui.painter();
let cp = painter.round_pos_to_pixels(corner.pos_in_rect(rect));
let cp = corner
.pos_in_rect(rect)
.round_to_pixels(ui.pixels_per_point());
let mut w = 2.0;
let stroke = Stroke {
width: 1.0, // Set width to 1.0 to prevent overlapping
Expand Down
20 changes: 10 additions & 10 deletions crates/egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
Align, Align2, Context, CursorIcon, Id, InnerResponse, LayerId, NumExt, Order, Response, Sense,
TextStyle, Ui, UiKind, Vec2b, WidgetInfo, WidgetRect, WidgetText, WidgetType,
};
use emath::GuiRounding as _;
use epaint::{emath, pos2, vec2, Galley, Pos2, Rect, RectShape, Rounding, Shape, Stroke, Vec2};

use super::scroll_area::ScrollBarVisibility;
Expand Down Expand Up @@ -596,7 +597,7 @@ impl<'open> Window<'open> {
)
.shrink(frame_stroke.width);

title_rect = area_content_ui.painter().round_rect_to_pixels(title_rect);
title_rect = title_rect.round_to_pixels(area_content_ui.pixels_per_point());

if on_top && area_content_ui.visuals().window_highlight_topmost {
let mut round = window_frame.rounding;
Expand Down Expand Up @@ -789,13 +790,12 @@ fn resize_response(
area: &mut area::Prepared,
resize_id: Id,
) {
let Some(new_rect) = move_and_resize_window(ctx, &resize_interaction) else {
let Some(mut new_rect) = move_and_resize_window(ctx, &resize_interaction) else {
return;
};
let mut new_rect = ctx.round_rect_to_pixels(new_rect);

if area.constrain() {
new_rect = ctx.constrain_window_rect_to_area(new_rect, area.constrain_rect());
new_rect = Context::constrain_window_rect_to_area(new_rect, area.constrain_rect());
}

// TODO(emilk): add this to a Window state instead as a command "move here next frame"
Expand All @@ -820,18 +820,18 @@ fn move_and_resize_window(ctx: &Context, interaction: &ResizeInteraction) -> Opt
let mut rect = interaction.start_rect; // prevent drift

if interaction.left.drag {
rect.min.x = ctx.round_to_pixel(pointer_pos.x);
rect.min.x = pointer_pos.x;
} else if interaction.right.drag {
rect.max.x = ctx.round_to_pixel(pointer_pos.x);
rect.max.x = pointer_pos.x;
}

if interaction.top.drag {
rect.min.y = ctx.round_to_pixel(pointer_pos.y);
rect.min.y = pointer_pos.y;
} else if interaction.bottom.drag {
rect.max.y = ctx.round_to_pixel(pointer_pos.y);
rect.max.y = pointer_pos.y;
}

Some(rect)
Some(rect.round_ui())
}

fn resize_interaction(
Expand Down Expand Up @@ -1071,7 +1071,7 @@ impl TitleBar {
let item_spacing = ui.spacing().item_spacing;
let button_size = Vec2::splat(ui.spacing().icon_width);

let pad = (height - button_size.y) / 2.0; // calculated so that the icon is on the diagonal (if window padding is symmetrical)
let pad = ((height - button_size.y) / 2.0).round_ui(); // calculated so that the icon is on the diagonal (if window padding is symmetrical)

if collapsible {
ui.add_space(pad);
Expand Down
60 changes: 7 additions & 53 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration};

use containers::area::AreaState;
use emath::GuiRounding as _;
use epaint::{
emath::{self, TSTransform},
mutex::RwLock,
pos2,
stats::PaintStats,
tessellator,
text::{FontInsert, FontPriority, Fonts},
Expand Down Expand Up @@ -1989,50 +1989,6 @@ impl Context {
});
}

/// 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 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 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 of filled shapes
#[inline]
pub(crate) fn round_rect_to_pixels(&self, rect: Rect) -> Rect {
Rect {
min: self.round_pos_to_pixels(rect.min),
max: self.round_pos_to_pixels(rect.max),
}
}

/// Allocate a texture.
///
/// This is for advanced users.
Expand Down Expand Up @@ -2107,7 +2063,7 @@ impl Context {
// ---------------------------------------------------------------------

/// Constrain the position of a window/area so it fits within the provided boundary.
pub(crate) fn constrain_window_rect_to_area(&self, window: Rect, area: Rect) -> Rect {
pub(crate) fn constrain_window_rect_to_area(window: Rect, area: Rect) -> Rect {
let mut pos = window.min;

// Constrain to screen, unless window is too large to fit:
Expand All @@ -2119,9 +2075,7 @@ impl Context {
pos.y = pos.y.at_most(area.bottom() + margin_y - window.height()); // move right if needed
pos.y = pos.y.at_least(area.top() - margin_y); // move down if needed

pos = self.round_pos_to_pixels(pos);

Rect::from_min_size(pos, window.size())
Rect::from_min_size(pos, window.size()).round_ui()
}
}

Expand Down Expand Up @@ -2554,15 +2508,15 @@ impl Context {

/// Position and size of the egui area.
pub fn screen_rect(&self) -> Rect {
self.input(|i| i.screen_rect())
self.input(|i| i.screen_rect()).round_ui()
}

/// How much space is still available after panels has been added.
///
/// This is the "background" area, what egui doesn't cover with panels (but may cover with windows).
/// This is also the area to which windows are constrained.
pub fn available_rect(&self) -> Rect {
self.pass_state(|s| s.available_rect())
self.pass_state(|s| s.available_rect()).round_ui()
}

/// How much space is used by panels and windows.
Expand All @@ -2572,15 +2526,15 @@ impl Context {
for (_id, window) in ctx.memory.areas().visible_windows() {
used = used.union(window.rect());
}
used
used.round_ui()
})
}

/// How much space is used by panels and windows.
///
/// You can shrink your egui area to this size and still fit all egui components.
pub fn used_size(&self) -> Vec2 {
self.used_rect().max - Pos2::ZERO
(self.used_rect().max - Pos2::ZERO).round_ui()
}

// ---------------------------------------------------------------------
Expand Down
8 changes: 6 additions & 2 deletions crates/egui/src/grid.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use emath::GuiRounding as _;

use crate::{
vec2, Align2, Color32, Context, Id, InnerResponse, NumExt, Painter, Rect, Region, Style, Ui,
UiBuilder, Vec2,
Expand Down Expand Up @@ -179,13 +181,15 @@ impl GridLayout {
let width = self.prev_state.col_width(self.col).unwrap_or(0.0);
let height = self.prev_row_height(self.row);
let size = child_size.max(vec2(width, height));
Rect::from_min_size(cursor.min, size)
Rect::from_min_size(cursor.min, size).round_ui()
}

#[allow(clippy::unused_self)]
pub(crate) fn align_size_within_rect(&self, size: Vec2, frame: Rect) -> Rect {
// TODO(emilk): allow this alignment to be customized
Align2::LEFT_CENTER.align_size_within_rect(size, frame)
Align2::LEFT_CENTER
.align_size_within_rect(size, frame)
.round_ui()
}

pub(crate) fn justify_and_align(&self, frame: Rect, size: Vec2) -> Rect {
Expand Down
Loading

0 comments on commit 83f3335

Please sign in to comment.