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 29, 2024
2 parents 83f3335 + e2c7e9e commit 4d5b236
Show file tree
Hide file tree
Showing 28 changed files with 683 additions and 308 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2202,12 +2202,23 @@ dependencies = [
"byteorder-lite",
"color_quant",
"gif",
"image-webp",
"num-traits",
"png",
"zune-core",
"zune-jpeg",
]

[[package]]
name = "image-webp"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f"
dependencies = [
"byteorder-lite",
"quick-error",
]

[[package]]
name = "images"
version = "0.1.0"
Expand Down Expand Up @@ -3165,6 +3176,12 @@ dependencies = [
"puffin_http",
]

[[package]]
name = "quick-error"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"

[[package]]
name = "quick-xml"
version = "0.30.0"
Expand Down
15 changes: 15 additions & 0 deletions crates/eframe/src/web/app_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,15 @@ impl AppRunner {
}

fn handle_platform_output(&self, platform_output: egui::PlatformOutput) {
#![allow(deprecated)]

#[cfg(feature = "web_screen_reader")]
if self.egui_ctx.options(|o| o.screen_reader) {
super::screen_reader::speak(&platform_output.events_description());
}

let egui::PlatformOutput {
commands,
cursor_icon,
open_url,
copied_text,
Expand All @@ -310,7 +313,19 @@ impl AppRunner {
request_discard_reasons: _, // handled by `Context::run`
} = platform_output;

for command in commands {
match command {
egui::OutputCommand::CopyText(text) => {
super::set_clipboard_text(&text);
}
egui::OutputCommand::OpenUrl(open_url) => {
super::open_url(&open_url.url, open_url.new_tab);
}
}
}

super::set_cursor_icon(cursor_icon);

if let Some(open) = open_url {
super::open_url(&open.url, open.new_tab);
}
Expand Down
13 changes: 13 additions & 0 deletions crates/egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,9 +820,11 @@ impl State {
window: &Window,
platform_output: egui::PlatformOutput,
) {
#![allow(deprecated)]
profiling::function_scope!();

let egui::PlatformOutput {
commands,
cursor_icon,
open_url,
copied_text,
Expand All @@ -835,6 +837,17 @@ impl State {
request_discard_reasons: _, // `egui::Context::run` handles this
} = platform_output;

for command in commands {
match command {
egui::OutputCommand::CopyText(text) => {
self.clipboard.set(text);
}
egui::OutputCommand::OpenUrl(open_url) => {
open_url_in_browser(&open_url.url);
}
}
}

self.set_cursor_icon(window, cursor_icon);

if let Some(open_url) = open_url {
Expand Down
2 changes: 1 addition & 1 deletion crates/egui/src/containers/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use epaint::{Color32, Margin, Rect, Rounding, Shadow, Shape, Stroke};
///
/// ## Dynamic color
/// If you want to change the color of the frame based on the response of
/// the widget, you needs to break it up into multiple steps:
/// the widget, you need to break it up into multiple steps:
///
/// ```
/// # egui::__run_test_ui(|ui| {
Expand Down
122 changes: 85 additions & 37 deletions crates/egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ impl<'open> Window<'open> {
outer_rect,
frame_stroke,
window_frame.rounding,
resize_interaction,
);

// END FRAME --------------------------------
Expand Down Expand Up @@ -652,29 +653,30 @@ fn paint_resize_corner(
outer_rect: Rect,
stroke: impl Into<Stroke>,
rounding: impl Into<Rounding>,
i: ResizeInteraction,
) {
let stroke = stroke.into();
let inactive_stroke = stroke.into();
let rounding = rounding.into();
let (corner, radius) = if possible.resize_right && possible.resize_bottom {
(Align2::RIGHT_BOTTOM, rounding.se)
let (corner, radius, corner_response) = if possible.resize_right && possible.resize_bottom {
(Align2::RIGHT_BOTTOM, rounding.se, i.right & i.bottom)
} else if possible.resize_left && possible.resize_bottom {
(Align2::LEFT_BOTTOM, rounding.sw)
(Align2::LEFT_BOTTOM, rounding.sw, i.left & i.bottom)
} else if possible.resize_left && possible.resize_top {
(Align2::LEFT_TOP, rounding.nw)
(Align2::LEFT_TOP, rounding.nw, i.left & i.top)
} else if possible.resize_right && possible.resize_top {
(Align2::RIGHT_TOP, rounding.ne)
(Align2::RIGHT_TOP, rounding.ne, i.right & i.top)
} else {
// We're not in two directions, but it is still nice to tell the user
// we're resizable by painting the resize corner in the expected place
// (i.e. for windows only resizable in one direction):
if possible.resize_right || possible.resize_bottom {
(Align2::RIGHT_BOTTOM, rounding.se)
(Align2::RIGHT_BOTTOM, rounding.se, i.right & i.bottom)
} else if possible.resize_left || possible.resize_bottom {
(Align2::LEFT_BOTTOM, rounding.sw)
(Align2::LEFT_BOTTOM, rounding.sw, i.left & i.bottom)
} else if possible.resize_left || possible.resize_top {
(Align2::LEFT_TOP, rounding.nw)
(Align2::LEFT_TOP, rounding.nw, i.left & i.top)
} else if possible.resize_right || possible.resize_top {
(Align2::RIGHT_TOP, rounding.ne)
(Align2::RIGHT_TOP, rounding.ne, i.right & i.top)
} else {
return;
}
Expand All @@ -684,6 +686,14 @@ fn paint_resize_corner(
let offset =
((2.0_f32.sqrt() * (1.0 + radius) - radius) * 45.0_f32.to_radians().cos()).max(2.0);

let stroke = if corner_response.drag {
ui.visuals().widgets.active.fg_stroke
} else if corner_response.hover {
ui.visuals().widgets.hovered.fg_stroke
} else {
inactive_stroke
};

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 @@ -745,6 +755,17 @@ impl SideResponse {
}
}

impl std::ops::BitAnd for SideResponse {
type Output = Self;

fn bitand(self, rhs: Self) -> Self::Output {
Self {
hover: self.hover && rhs.hover,
drag: self.drag && rhs.drag,
}
}
}

impl std::ops::BitOrAssign for SideResponse {
fn bitor_assign(&mut self, rhs: Self) {
*self = Self {
Expand Down Expand Up @@ -850,7 +871,7 @@ fn resize_interaction(
};
}

let is_dragging = |rect, id| {
let side_response = |rect, id| {
let response = ctx.create_widget(
WidgetRect {
layer_id,
Expand All @@ -873,6 +894,12 @@ fn resize_interaction(
let side_grab_radius = ctx.style().interaction.resize_grab_radius_side;
let corner_grab_radius = ctx.style().interaction.resize_grab_radius_corner;

let vetrtical_rect = |a: Pos2, b: Pos2| {
Rect::from_min_max(a, b).expand2(vec2(side_grab_radius, -corner_grab_radius))
};
let horizontal_rect = |a: Pos2, b: Pos2| {
Rect::from_min_max(a, b).expand2(vec2(-corner_grab_radius, side_grab_radius))
};
let corner_rect =
|center: Pos2| Rect::from_center_size(center, Vec2::splat(2.0 * corner_grab_radius));

Expand All @@ -883,59 +910,80 @@ fn resize_interaction(
// Check sides first, so that corners are on top, covering the sides (i.e. corners have priority)

if possible.resize_right {
let response = is_dragging(
Rect::from_min_max(rect.right_top(), rect.right_bottom()).expand(side_grab_radius),
let response = side_response(
vetrtical_rect(rect.right_top(), rect.right_bottom()),
id.with("right"),
);
right |= response;
}
if possible.resize_left {
let response = is_dragging(
Rect::from_min_max(rect.left_top(), rect.left_bottom()).expand(side_grab_radius),
let response = side_response(
vetrtical_rect(rect.left_top(), rect.left_bottom()),
id.with("left"),
);
left |= response;
}
if possible.resize_bottom {
let response = is_dragging(
Rect::from_min_max(rect.left_bottom(), rect.right_bottom()).expand(side_grab_radius),
let response = side_response(
horizontal_rect(rect.left_bottom(), rect.right_bottom()),
id.with("bottom"),
);
bottom |= response;
}
if possible.resize_top {
let response = is_dragging(
Rect::from_min_max(rect.left_top(), rect.right_top()).expand(side_grab_radius),
let response = side_response(
horizontal_rect(rect.left_top(), rect.right_top()),
id.with("top"),
);
top |= response;
}

// ----------------------------------------
// Now check corners:

if possible.resize_right && possible.resize_bottom {
let response = is_dragging(corner_rect(rect.right_bottom()), id.with("right_bottom"));
right |= response;
bottom |= response;
// Now check corners.
// We check any corner that has either side resizable,
// because we shrink the side resize handled by the corner width.
// Also, even if we can only change the width (or height) of a window,
// we show one of the corners as a grab-handle, so it makes sense that
// the whole corner is grabbable:

if possible.resize_right || possible.resize_bottom {
let response = side_response(corner_rect(rect.right_bottom()), id.with("right_bottom"));
if possible.resize_right {
right |= response;
}
if possible.resize_bottom {
bottom |= response;
}
}

if possible.resize_right && possible.resize_top {
let response = is_dragging(corner_rect(rect.right_top()), id.with("right_top"));
right |= response;
top |= response;
if possible.resize_right || possible.resize_top {
let response = side_response(corner_rect(rect.right_top()), id.with("right_top"));
if possible.resize_right {
right |= response;
}
if possible.resize_top {
top |= response;
}
}

if possible.resize_left && possible.resize_bottom {
let response = is_dragging(corner_rect(rect.left_bottom()), id.with("left_bottom"));
left |= response;
bottom |= response;
if possible.resize_left || possible.resize_bottom {
let response = side_response(corner_rect(rect.left_bottom()), id.with("left_bottom"));
if possible.resize_left {
left |= response;
}
if possible.resize_bottom {
bottom |= response;
}
}

if possible.resize_left && possible.resize_top {
let response = is_dragging(corner_rect(rect.left_top()), id.with("left_top"));
left |= response;
top |= response;
if possible.resize_left || possible.resize_top {
let response = side_response(corner_rect(rect.left_top()), id.with("left_top"));
if possible.resize_left {
left |= response;
}
if possible.resize_top {
top |= response;
}
}

let interaction = ResizeInteraction {
Expand Down
18 changes: 8 additions & 10 deletions crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1419,6 +1419,12 @@ impl Context {
self.output_mut(|o| o.cursor_icon = cursor_icon);
}

/// Add a command to [`PlatformOutput::commands`],
/// for the integration to execute at the end of the frame.
pub fn send_cmd(&self, cmd: crate::OutputCommand) {
self.output_mut(|o| o.commands.push(cmd));
}

/// Open an URL in a browser.
///
/// Equivalent to:
Expand All @@ -1428,24 +1434,16 @@ impl Context {
/// ctx.output_mut(|o| o.open_url = Some(open_url));
/// ```
pub fn open_url(&self, open_url: crate::OpenUrl) {
self.output_mut(|o| o.open_url = Some(open_url));
self.send_cmd(crate::OutputCommand::OpenUrl(open_url));
}

/// Copy the given text to the system clipboard.
///
/// Empty strings are ignored.
///
/// Note that in wasm applications, the clipboard is only accessible in secure contexts (e.g.,
/// HTTPS or localhost). If this method is used outside of a secure context, it will log an
/// error and do nothing. See <https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts>.
///
/// Equivalent to:
/// ```
/// # let ctx = egui::Context::default();
/// ctx.output_mut(|o| o.copied_text = "Copy this".to_owned());
/// ```
pub fn copy_text(&self, text: String) {
self.output_mut(|o| o.copied_text = text);
self.send_cmd(crate::OutputCommand::CopyText(text));
}

/// Format the given shortcut in a human-readable way (e.g. `Ctrl+Shift+X`).
Expand Down
Loading

0 comments on commit 4d5b236

Please sign in to comment.