mirror of
https://github.com/emilk/egui.git
synced 2026-06-26 22:53:14 -04:00
This PR has a smaller scope, and this are some reverts
Will no longer change egui::Window!
This commit is contained in:
934
Cargo.lock
generated
934
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ pub mod panel;
|
|||||||
pub mod popup;
|
pub mod popup;
|
||||||
pub(crate) mod resize;
|
pub(crate) mod resize;
|
||||||
pub mod scroll_area;
|
pub mod scroll_area;
|
||||||
pub mod window;
|
pub(crate) mod window;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
area::Area,
|
area::Area,
|
||||||
|
|||||||
@@ -280,7 +280,6 @@ pub fn was_tooltip_open_last_frame(ctx: &Context, tooltip_id: Id) -> bool {
|
|||||||
for (count, (individual_id, _size)) in &state.individual_ids_and_sizes {
|
for (count, (individual_id, _size)) in &state.individual_ids_and_sizes {
|
||||||
if *individual_id == tooltip_id {
|
if *individual_id == tooltip_id {
|
||||||
let area_id = common_id.with(count);
|
let area_id = common_id.with(count);
|
||||||
|
|
||||||
let layer_id = LayerId::new(Order::Tooltip, area_id);
|
let layer_id = LayerId::new(Order::Tooltip, area_id);
|
||||||
if ctx.memory(|mem| mem.areas.visible_last_frame(&layer_id)) {
|
if ctx.memory(|mem| mem.areas.visible_last_frame(&layer_id)) {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use crate::collapsing_header::CollapsingState;
|
use crate::collapsing_header::CollapsingState;
|
||||||
use crate::{widget_text::WidgetTextGalley, *};
|
use crate::{widget_text::WidgetTextGalley, *};
|
||||||
use crate::{ViewportBuilder, ViewportCommand};
|
|
||||||
use epaint::*;
|
use epaint::*;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -35,9 +34,7 @@ pub struct Window<'open> {
|
|||||||
scroll: ScrollArea,
|
scroll: ScrollArea,
|
||||||
collapsible: bool,
|
collapsible: bool,
|
||||||
default_open: bool,
|
default_open: bool,
|
||||||
default_embedded: bool,
|
|
||||||
with_title_bar: bool,
|
with_title_bar: bool,
|
||||||
window_builder: ViewportBuilder,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'open> Window<'open> {
|
impl<'open> Window<'open> {
|
||||||
@@ -48,7 +45,6 @@ impl<'open> Window<'open> {
|
|||||||
let title = title.into().fallback_text_style(TextStyle::Heading);
|
let title = title.into().fallback_text_style(TextStyle::Heading);
|
||||||
let area = Area::new(Id::new(title.text()));
|
let area = Area::new(Id::new(title.text()));
|
||||||
Self {
|
Self {
|
||||||
window_builder: ViewportBuilder::new(title.text().to_owned()).with_title(title.text()),
|
|
||||||
title,
|
title,
|
||||||
open: None,
|
open: None,
|
||||||
area,
|
area,
|
||||||
@@ -57,20 +53,16 @@ impl<'open> Window<'open> {
|
|||||||
.with_stroke(false)
|
.with_stroke(false)
|
||||||
.min_size([96.0, 32.0])
|
.min_size([96.0, 32.0])
|
||||||
.default_size([340.0, 420.0]), // Default inner size of a window
|
.default_size([340.0, 420.0]), // Default inner size of a window
|
||||||
scroll: ScrollArea::both()
|
scroll: ScrollArea::neither(),
|
||||||
.auto_shrink([false, false])
|
|
||||||
.enable_scrolling(true),
|
|
||||||
collapsible: true,
|
collapsible: true,
|
||||||
default_open: true,
|
default_open: true,
|
||||||
with_title_bar: true,
|
with_title_bar: true,
|
||||||
default_embedded: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assign a unique id to the Window. Required if the title changes, or is shared with another window.
|
/// Assign a unique id to the Window. Required if the title changes, or is shared with another window.
|
||||||
pub fn id(mut self, id: Id) -> Self {
|
pub fn id(mut self, id: Id) -> Self {
|
||||||
self.area = self.area.id(id);
|
self.area = self.area.id(id);
|
||||||
self.window_builder.id = id;
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,14 +76,6 @@ impl<'open> Window<'open> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This will only be used on window creation!
|
|
||||||
/// If embedded is false the window will be a native window, if is possible
|
|
||||||
/// Look at `Context::is_desktop` to see if is possible to create a native window!
|
|
||||||
pub fn default_embedded(mut self, embedded: bool) -> Self {
|
|
||||||
self.default_embedded = embedded;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If `false` the window will be grayed out and non-interactive.
|
/// If `false` the window will be grayed out and non-interactive.
|
||||||
pub fn enabled(mut self, enabled: bool) -> Self {
|
pub fn enabled(mut self, enabled: bool) -> Self {
|
||||||
self.area = self.area.enabled(enabled);
|
self.area = self.area.enabled(enabled);
|
||||||
@@ -301,7 +285,6 @@ impl<'open> Window<'open> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'open> Window<'open> {
|
impl<'open> Window<'open> {
|
||||||
/// You can only use this on the main thread, or use ```Window::show_async```
|
|
||||||
/// Returns `None` if the window is not open (if [`Window::open`] was called with `&mut false`).
|
/// Returns `None` if the window is not open (if [`Window::open`] was called with `&mut false`).
|
||||||
/// Returns `Some(InnerResponse { inner: None })` if the window is collapsed.
|
/// Returns `Some(InnerResponse { inner: None })` if the window is collapsed.
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -313,20 +296,14 @@ impl<'open> Window<'open> {
|
|||||||
self.show_dyn(ctx, Box::new(add_contents))
|
self.show_dyn(ctx, Box::new(add_contents))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// You will probably need to put your state in a ```Arc<RwLock<T>>```
|
fn show_dyn<'c, R>(
|
||||||
#[inline]
|
|
||||||
pub fn show_async(self, ctx: &Context, add_contents: impl Fn(&mut Ui) + Send + Sync + 'static) {
|
|
||||||
self.show_dyn_async(ctx, Box::new(add_contents));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn show_dyn<'a, R>(
|
|
||||||
self,
|
self,
|
||||||
ctx: &Context,
|
ctx: &Context,
|
||||||
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'a>,
|
add_contents: Box<dyn FnOnce(&mut Ui) -> R + 'c>,
|
||||||
) -> Option<InnerResponse<Option<R>>> {
|
) -> Option<InnerResponse<Option<R>>> {
|
||||||
let Window {
|
let Window {
|
||||||
title,
|
title,
|
||||||
mut open,
|
open,
|
||||||
area,
|
area,
|
||||||
frame,
|
frame,
|
||||||
resize,
|
resize,
|
||||||
@@ -334,304 +311,18 @@ impl<'open> Window<'open> {
|
|||||||
collapsible,
|
collapsible,
|
||||||
default_open,
|
default_open,
|
||||||
with_title_bar,
|
with_title_bar,
|
||||||
mut window_builder,
|
|
||||||
default_embedded,
|
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let is_embedded = ctx.data_mut(|data| {
|
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
|
||||||
*data.get_persisted_mut_or(area.id.with("_embedded"), default_embedded)
|
|
||||||
});
|
|
||||||
|
|
||||||
let is_open = if let Some(open) = &mut open {
|
let is_explicitly_closed = matches!(open, Some(false));
|
||||||
if let Some(tmp_open) = ctx.data_mut(|data| {
|
let is_open = !is_explicitly_closed || ctx.memory(|mem| mem.everything_is_visible());
|
||||||
let tmp = data.get_persisted::<bool>(area.id.with("_open"));
|
area.show_open_close_animation(ctx, &frame, is_open);
|
||||||
data.remove::<bool>(area.id.with("_open"));
|
|
||||||
tmp
|
|
||||||
}) {
|
|
||||||
**open = tmp_open;
|
|
||||||
}
|
|
||||||
**open
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
|
|
||||||
let is_open = is_open || ctx.memory(|mem| mem.everything_is_visible());
|
|
||||||
|
|
||||||
ctx.data_mut(|data| {
|
|
||||||
data.insert_persisted(area.id.with("_is_open"), is_open);
|
|
||||||
});
|
|
||||||
|
|
||||||
if !is_open {
|
if !is_open {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let show_close_button = open.is_some();
|
|
||||||
|
|
||||||
'create_viewport: {
|
|
||||||
if !is_embedded && !ctx.force_embedding() {
|
|
||||||
if let Some(size) = ctx.data(|data| data.get_temp::<Vec2>(area.id.with("size"))) {
|
|
||||||
let size = size.round() * ctx.pixels_per_point();
|
|
||||||
window_builder =
|
|
||||||
window_builder.with_inner_size(Some((size.x as u32, size.y as u32)));
|
|
||||||
} else {
|
|
||||||
ctx.request_repaint();
|
|
||||||
break 'create_viewport;
|
|
||||||
}
|
|
||||||
window_builder = window_builder
|
|
||||||
.with_close_button(open.is_some())
|
|
||||||
.with_resizable(resize.is_resizable())
|
|
||||||
.with_decorations(!with_title_bar);
|
|
||||||
let pix = ctx.pixels_per_point();
|
|
||||||
let min_size = resize.min_size * pix;
|
|
||||||
let max_size = resize.max_size * pix;
|
|
||||||
let max_size = if !max_size.is_finite() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(max_size)
|
|
||||||
};
|
|
||||||
window_builder = window_builder
|
|
||||||
.with_min_inner_size(Some((min_size.x as u32, min_size.y as u32)));
|
|
||||||
if let Some(max_size) = max_size {
|
|
||||||
window_builder = window_builder
|
|
||||||
.with_max_inner_size(Some((max_size.x as u32, max_size.y as u32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(ctx.create_viewport_sync(window_builder, move |ctx| {
|
|
||||||
let mut op = is_open;
|
|
||||||
let open = if show_close_button {
|
|
||||||
Some(&mut op)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let scroll = scroll.clone();
|
|
||||||
let title = title.clone();
|
|
||||||
let frame = frame
|
|
||||||
.unwrap_or_else(|| Frame::window(&ctx.style()))
|
|
||||||
.outer_margin(0.0)
|
|
||||||
.shadow(Shadow::NONE)
|
|
||||||
.stroke(Stroke::new(
|
|
||||||
1.0,
|
|
||||||
if ctx.input(|i| i.focused) {
|
|
||||||
Color32::BLUE
|
|
||||||
} else {
|
|
||||||
Color32::BROWN
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
area.show_open_close_animation(ctx, &frame, is_open);
|
|
||||||
|
|
||||||
let area_id = area.id;
|
|
||||||
let area_layer_id = area.layer();
|
|
||||||
let resize_id = area_id.with("resize");
|
|
||||||
let mut collapsing = CollapsingState::load_with_default_open(
|
|
||||||
ctx,
|
|
||||||
area_id.with("collapsing"),
|
|
||||||
default_open,
|
|
||||||
);
|
|
||||||
|
|
||||||
let is_collapsed = with_title_bar && !collapsing.is_open();
|
|
||||||
let possible = PossibleInteractions::new(&area, &resize, is_collapsed);
|
|
||||||
|
|
||||||
let area = area.movable(false); // We move it manually, or the area will move the window when we want to resize it
|
|
||||||
let resize = resize.resizable(false); // We move it manually
|
|
||||||
let mut resize = resize.id(resize_id);
|
|
||||||
|
|
||||||
let mut area = area.begin(ctx);
|
|
||||||
let win_size = ctx.screen_rect().size();
|
|
||||||
area.state_mut().set_left_top_pos(Pos2::ZERO);
|
|
||||||
area.state_mut().size = win_size;
|
|
||||||
let title_content_spacing = 2.0 * ctx.style().spacing.item_spacing.y;
|
|
||||||
|
|
||||||
let title_bar_height = if with_title_bar {
|
|
||||||
let style = ctx.style();
|
|
||||||
ctx.fonts(|f| title.font_height(f, &style)) + title_content_spacing
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let margins = frame.outer_margin.sum()
|
|
||||||
+ frame.inner_margin.sum()
|
|
||||||
+ vec2(0.0, title_bar_height)
|
|
||||||
- vec2(0.0, 3.0); //magic number
|
|
||||||
|
|
||||||
if let Some(mut state) = resize::State::load(ctx, resize_id) {
|
|
||||||
state.requested_size = Some(win_size - margins);
|
|
||||||
state.store(ctx, resize_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// First interact (move etc) to avoid frame delay:
|
|
||||||
let last_frame_outer_rect = area.state().rect();
|
|
||||||
|
|
||||||
let interaction = if possible.movable || possible.resizable() {
|
|
||||||
window_interaction(
|
|
||||||
ctx,
|
|
||||||
possible,
|
|
||||||
area_layer_id,
|
|
||||||
area_id.with("frame_resize"),
|
|
||||||
last_frame_outer_rect,
|
|
||||||
)
|
|
||||||
.map(|window_interaction| {
|
|
||||||
// Calculate roughly how much larger the window size is compared to the inner rect
|
|
||||||
|
|
||||||
window_interaction.set_cursor(ctx);
|
|
||||||
if window_interaction.is_resize() {
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::Resize(
|
|
||||||
window_interaction.top,
|
|
||||||
window_interaction.bottom,
|
|
||||||
window_interaction.right,
|
|
||||||
window_interaction.left,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else if ctx.input(|i| i.pointer.primary_pressed()) {
|
|
||||||
}
|
|
||||||
ctx.memory_mut(|mem| mem.areas.move_to_top(area_layer_id));
|
|
||||||
|
|
||||||
window_interaction
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let hover_interaction =
|
|
||||||
resize_hover(ctx, possible, area_layer_id, last_frame_outer_rect);
|
|
||||||
|
|
||||||
let mut area_content_ui = area.content_ui(ctx);
|
|
||||||
|
|
||||||
let mut size = Vec2::new(1.0, 1.0);
|
|
||||||
|
|
||||||
let content_inner = {
|
|
||||||
// BEGIN FRAME --------------------------------
|
|
||||||
let frame_stroke = frame.stroke;
|
|
||||||
let mut frame = frame.begin(&mut area_content_ui);
|
|
||||||
|
|
||||||
let title_bar = if with_title_bar {
|
|
||||||
let title_bar = show_title_bar(
|
|
||||||
&mut frame.content_ui,
|
|
||||||
title,
|
|
||||||
show_close_button,
|
|
||||||
&mut collapsing,
|
|
||||||
collapsible,
|
|
||||||
area_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
resize.min_size.x = resize.min_size.x.at_least(title_bar.rect.width()); // Prevent making window smaller than title bar width
|
|
||||||
Some(title_bar)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let (content_inner, content_response) = collapsing
|
|
||||||
.show_body_unindented(&mut frame.content_ui, |ui| {
|
|
||||||
resize.show(ui, |ui| {
|
|
||||||
if title_bar.is_some() {
|
|
||||||
ui.add_space(title_content_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
if scroll.has_any_bar() {
|
|
||||||
scroll.show(ui, |ui| add_contents(ui)).inner
|
|
||||||
} else {
|
|
||||||
add_contents(ui)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.map_or((None, None), |ir| (Some(ir.inner), Some(ir.response)));
|
|
||||||
if let Some(content_response) = &content_response {
|
|
||||||
size = content_response.rect.max.to_vec2();
|
|
||||||
}
|
|
||||||
|
|
||||||
let outer_rect = frame.end(&mut area_content_ui).rect;
|
|
||||||
paint_resize_corner(
|
|
||||||
&mut area_content_ui,
|
|
||||||
&possible,
|
|
||||||
outer_rect,
|
|
||||||
frame_stroke,
|
|
||||||
);
|
|
||||||
|
|
||||||
// END FRAME --------------------------------
|
|
||||||
|
|
||||||
if let Some(title_bar) = title_bar {
|
|
||||||
let res = title_bar.ui(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
&content_response,
|
|
||||||
open,
|
|
||||||
&mut collapsing,
|
|
||||||
collapsible,
|
|
||||||
);
|
|
||||||
if res.is_pointer_button_down_on() {
|
|
||||||
ctx.viewport_command(ctx.get_viewport_id(), ViewportCommand::Drag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
collapsing.store(ctx);
|
|
||||||
|
|
||||||
if let Some(interaction) = interaction {
|
|
||||||
paint_frame_interaction(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
interaction,
|
|
||||||
ctx.style().visuals.widgets.active,
|
|
||||||
);
|
|
||||||
} else if let Some(hover_interaction) = hover_interaction {
|
|
||||||
if ctx.input(|i| i.pointer.has_pointer()) {
|
|
||||||
paint_frame_interaction(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
hover_interaction,
|
|
||||||
ctx.style().visuals.widgets.hovered,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
content_inner
|
|
||||||
};
|
|
||||||
|
|
||||||
let full_response = area.end(ctx, area_content_ui);
|
|
||||||
|
|
||||||
if !collapsing.is_open() {
|
|
||||||
let size = full_response.rect.size() * ctx.pixels_per_point();
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::InnerSize(size.x as u32, size.y as u32),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if win_size.x < size.x {
|
|
||||||
println!("Set size! {win_size:?} {size:?}");
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::InnerSize(
|
|
||||||
(size.x * ctx.pixels_per_point()).round() as u32,
|
|
||||||
(win_size.y * ctx.pixels_per_point()).round() as u32,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if win_size.y < size.y {
|
|
||||||
println!("Set size! {win_size:?} {size:?}");
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::InnerSize(
|
|
||||||
(win_size.x * ctx.pixels_per_point()).round() as u32,
|
|
||||||
(size.y * ctx.pixels_per_point()).round() as u32,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if show_close_button && op != is_open {
|
|
||||||
ctx.data_mut(|data| data.insert_persisted(area_id.with("_open"), op));
|
|
||||||
ctx.request_repaint_viewport(ctx.get_parent_viewport_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
InnerResponse {
|
|
||||||
inner: content_inner,
|
|
||||||
response: full_response,
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
|
|
||||||
|
|
||||||
area.show_open_close_animation(ctx, &frame, is_open);
|
|
||||||
|
|
||||||
let area_id = area.id;
|
let area_id = area.id;
|
||||||
let area_layer_id = area.layer();
|
let area_layer_id = area.layer();
|
||||||
let resize_id = area_id.with("resize");
|
let resize_id = area_id.with("resize");
|
||||||
@@ -687,13 +378,12 @@ impl<'open> Window<'open> {
|
|||||||
|
|
||||||
let mut area_content_ui = area.content_ui(ctx);
|
let mut area_content_ui = area.content_ui(ctx);
|
||||||
|
|
||||||
let mut size = Vec2::new(1.0, 1.0);
|
|
||||||
|
|
||||||
let content_inner = {
|
let content_inner = {
|
||||||
// BEGIN FRAME --------------------------------
|
// BEGIN FRAME --------------------------------
|
||||||
let frame_stroke = frame.stroke;
|
let frame_stroke = frame.stroke;
|
||||||
let mut frame = frame.begin(&mut area_content_ui);
|
let mut frame = frame.begin(&mut area_content_ui);
|
||||||
|
|
||||||
|
let show_close_button = open.is_some();
|
||||||
let title_bar = if with_title_bar {
|
let title_bar = if with_title_bar {
|
||||||
let title_bar = show_title_bar(
|
let title_bar = show_title_bar(
|
||||||
&mut frame.content_ui,
|
&mut frame.content_ui,
|
||||||
@@ -701,9 +391,7 @@ impl<'open> Window<'open> {
|
|||||||
show_close_button,
|
show_close_button,
|
||||||
&mut collapsing,
|
&mut collapsing,
|
||||||
collapsible,
|
collapsible,
|
||||||
area_id,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
resize.min_size.x = resize.min_size.x.at_least(title_bar.rect.width()); // Prevent making window smaller than title bar width
|
resize.min_size.x = resize.min_size.x.at_least(title_bar.rect.width()); // Prevent making window smaller than title bar width
|
||||||
Some(title_bar)
|
Some(title_bar)
|
||||||
} else {
|
} else {
|
||||||
@@ -718,16 +406,13 @@ impl<'open> Window<'open> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if scroll.has_any_bar() {
|
if scroll.has_any_bar() {
|
||||||
scroll.show(ui, |ui| add_contents(ui)).inner
|
scroll.show(ui, add_contents).inner
|
||||||
} else {
|
} else {
|
||||||
add_contents(ui)
|
add_contents(ui)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.map_or((None, None), |ir| (Some(ir.inner), Some(ir.response)));
|
.map_or((None, None), |ir| (Some(ir.inner), Some(ir.response)));
|
||||||
if let Some(content_response) = &content_response {
|
|
||||||
size = content_response.rect.max.to_vec2();
|
|
||||||
}
|
|
||||||
|
|
||||||
let outer_rect = frame.end(&mut area_content_ui).rect;
|
let outer_rect = frame.end(&mut area_content_ui).rect;
|
||||||
paint_resize_corner(&mut area_content_ui, &possible, outer_rect, frame_stroke);
|
paint_resize_corner(&mut area_content_ui, &possible, outer_rect, frame_stroke);
|
||||||
@@ -775,7 +460,6 @@ impl<'open> Window<'open> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let full_response = area.end(ctx, area_content_ui);
|
let full_response = area.end(ctx, area_content_ui);
|
||||||
ctx.data_mut(|data| data.insert_temp(area_id.with("size"), size));
|
|
||||||
|
|
||||||
let inner_response = InnerResponse {
|
let inner_response = InnerResponse {
|
||||||
inner: content_inner,
|
inner: content_inner,
|
||||||
@@ -783,463 +467,6 @@ impl<'open> Window<'open> {
|
|||||||
};
|
};
|
||||||
Some(inner_response)
|
Some(inner_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_dyn_async(self, ctx: &Context, add_contents: Box<dyn Fn(&mut Ui) + Send + Sync>) {
|
|
||||||
let Window {
|
|
||||||
title,
|
|
||||||
mut open,
|
|
||||||
area,
|
|
||||||
frame,
|
|
||||||
resize,
|
|
||||||
scroll,
|
|
||||||
collapsible,
|
|
||||||
default_open,
|
|
||||||
with_title_bar,
|
|
||||||
mut window_builder,
|
|
||||||
default_embedded,
|
|
||||||
} = self;
|
|
||||||
|
|
||||||
let is_embedded = ctx.data_mut(|data| {
|
|
||||||
*data.get_persisted_mut_or(area.id.with("_embedded"), default_embedded)
|
|
||||||
});
|
|
||||||
|
|
||||||
let is_open = if let Some(open) = &mut open {
|
|
||||||
if let Some(tmp_open) = ctx.data_mut(|data| {
|
|
||||||
let tmp = data.get_persisted::<bool>(area.id.with("_open"));
|
|
||||||
data.remove::<bool>(area.id.with("_open"));
|
|
||||||
tmp
|
|
||||||
}) {
|
|
||||||
**open = tmp_open;
|
|
||||||
}
|
|
||||||
**open
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
};
|
|
||||||
|
|
||||||
let is_open = is_open || ctx.memory(|mem| mem.everything_is_visible());
|
|
||||||
|
|
||||||
ctx.data_mut(|data| {
|
|
||||||
data.insert_persisted(area.id.with("_is_open"), is_open);
|
|
||||||
});
|
|
||||||
|
|
||||||
if !is_open {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let show_close_button = open.is_some();
|
|
||||||
|
|
||||||
'create_viewport: {
|
|
||||||
if !is_embedded && !ctx.force_embedding() {
|
|
||||||
if let Some(size) = ctx.data(|data| data.get_temp::<Vec2>(area.id.with("size"))) {
|
|
||||||
let size = size.round() * ctx.pixels_per_point();
|
|
||||||
window_builder =
|
|
||||||
window_builder.with_inner_size(Some((size.x as u32, size.y as u32)));
|
|
||||||
} else {
|
|
||||||
ctx.request_repaint();
|
|
||||||
break 'create_viewport;
|
|
||||||
}
|
|
||||||
window_builder = window_builder
|
|
||||||
.with_close_button(open.is_some())
|
|
||||||
.with_resizable(resize.is_resizable())
|
|
||||||
.with_decorations(!with_title_bar);
|
|
||||||
let pix = ctx.pixels_per_point();
|
|
||||||
let min_size = resize.min_size * pix;
|
|
||||||
let max_size = resize.max_size * pix;
|
|
||||||
let max_size = if !max_size.is_finite() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(max_size)
|
|
||||||
};
|
|
||||||
window_builder = window_builder
|
|
||||||
.with_min_inner_size(Some((min_size.x as u32, min_size.y as u32)));
|
|
||||||
if let Some(max_size) = max_size {
|
|
||||||
window_builder = window_builder
|
|
||||||
.with_max_inner_size(Some((max_size.x as u32, max_size.y as u32)));
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.create_viewport(window_builder, move |ctx| {
|
|
||||||
let mut op = is_open;
|
|
||||||
let open = if show_close_button {
|
|
||||||
Some(&mut op)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let scroll = scroll.clone();
|
|
||||||
let title = title.clone();
|
|
||||||
let frame = frame
|
|
||||||
.unwrap_or_else(|| Frame::window(&ctx.style()))
|
|
||||||
.outer_margin(0.0)
|
|
||||||
.shadow(Shadow::NONE)
|
|
||||||
.stroke(Stroke::new(
|
|
||||||
1.0,
|
|
||||||
if ctx.input(|i| i.focused) {
|
|
||||||
Color32::BLUE
|
|
||||||
} else {
|
|
||||||
Color32::BROWN
|
|
||||||
},
|
|
||||||
));
|
|
||||||
|
|
||||||
area.show_open_close_animation(ctx, &frame, is_open);
|
|
||||||
|
|
||||||
let area_id = area.id;
|
|
||||||
let area_layer_id = area.layer();
|
|
||||||
let resize_id = area_id.with("resize");
|
|
||||||
let mut collapsing = CollapsingState::load_with_default_open(
|
|
||||||
ctx,
|
|
||||||
area_id.with("collapsing"),
|
|
||||||
default_open,
|
|
||||||
);
|
|
||||||
|
|
||||||
let is_collapsed = with_title_bar && !collapsing.is_open();
|
|
||||||
let possible = PossibleInteractions::new(&area, &resize, is_collapsed);
|
|
||||||
|
|
||||||
let area = area.movable(false); // We move it manually, or the area will move the window when we want to resize it
|
|
||||||
let resize = resize.resizable(false); // We move it manually
|
|
||||||
let mut resize = resize.id(resize_id);
|
|
||||||
|
|
||||||
let mut area = area.begin(ctx);
|
|
||||||
let win_size = ctx.screen_rect().size();
|
|
||||||
area.state_mut().set_left_top_pos(Pos2::ZERO);
|
|
||||||
area.state_mut().size = win_size;
|
|
||||||
let title_content_spacing = 2.0 * ctx.style().spacing.item_spacing.y;
|
|
||||||
|
|
||||||
let title_bar_height = if with_title_bar {
|
|
||||||
let style = ctx.style();
|
|
||||||
ctx.fonts(|f| title.font_height(f, &style)) + title_content_spacing
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let margins = frame.outer_margin.sum()
|
|
||||||
+ frame.inner_margin.sum()
|
|
||||||
+ vec2(0.0, title_bar_height)
|
|
||||||
- vec2(0.0, 3.0); //magic number
|
|
||||||
|
|
||||||
if let Some(mut state) = resize::State::load(ctx, resize_id) {
|
|
||||||
state.requested_size = Some(win_size - margins);
|
|
||||||
state.store(ctx, resize_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// First interact (move etc) to avoid frame delay:
|
|
||||||
let last_frame_outer_rect = area.state().rect();
|
|
||||||
|
|
||||||
let interaction = if possible.movable || possible.resizable() {
|
|
||||||
window_interaction(
|
|
||||||
ctx,
|
|
||||||
possible,
|
|
||||||
area_layer_id,
|
|
||||||
area_id.with("frame_resize"),
|
|
||||||
last_frame_outer_rect,
|
|
||||||
)
|
|
||||||
.map(|window_interaction| {
|
|
||||||
// Calculate roughly how much larger the window size is compared to the inner rect
|
|
||||||
|
|
||||||
window_interaction.set_cursor(ctx);
|
|
||||||
if window_interaction.is_resize() {
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::Resize(
|
|
||||||
window_interaction.top,
|
|
||||||
window_interaction.bottom,
|
|
||||||
window_interaction.right,
|
|
||||||
window_interaction.left,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else if ctx.input(|i| i.pointer.primary_pressed()) {
|
|
||||||
}
|
|
||||||
ctx.memory_mut(|mem| mem.areas.move_to_top(area_layer_id));
|
|
||||||
|
|
||||||
window_interaction
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let hover_interaction =
|
|
||||||
resize_hover(ctx, possible, area_layer_id, last_frame_outer_rect);
|
|
||||||
|
|
||||||
let mut area_content_ui = area.content_ui(ctx);
|
|
||||||
|
|
||||||
let mut size = Vec2::new(1.0, 1.0);
|
|
||||||
|
|
||||||
let _content_inner = {
|
|
||||||
// BEGIN FRAME --------------------------------
|
|
||||||
let frame_stroke = frame.stroke;
|
|
||||||
let mut frame = frame.begin(&mut area_content_ui);
|
|
||||||
|
|
||||||
let title_bar = if with_title_bar {
|
|
||||||
let title_bar = show_title_bar(
|
|
||||||
&mut frame.content_ui,
|
|
||||||
title,
|
|
||||||
show_close_button,
|
|
||||||
&mut collapsing,
|
|
||||||
collapsible,
|
|
||||||
area_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
resize.min_size.x = resize.min_size.x.at_least(title_bar.rect.width()); // Prevent making window smaller than title bar width
|
|
||||||
Some(title_bar)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let (content_inner, content_response) = collapsing
|
|
||||||
.show_body_unindented(&mut frame.content_ui, |ui| {
|
|
||||||
resize.show(ui, |ui| {
|
|
||||||
if title_bar.is_some() {
|
|
||||||
ui.add_space(title_content_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
if scroll.has_any_bar() {
|
|
||||||
scroll.show(ui, |ui| add_contents(ui));
|
|
||||||
} else {
|
|
||||||
add_contents(ui);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.map_or((None, None), |ir| (Some(()), Some(ir.response)));
|
|
||||||
if let Some(content_response) = &content_response {
|
|
||||||
size = content_response.rect.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
let outer_rect = frame.end(&mut area_content_ui).rect;
|
|
||||||
paint_resize_corner(
|
|
||||||
&mut area_content_ui,
|
|
||||||
&possible,
|
|
||||||
outer_rect,
|
|
||||||
frame_stroke,
|
|
||||||
);
|
|
||||||
|
|
||||||
// END FRAME --------------------------------
|
|
||||||
|
|
||||||
if let Some(title_bar) = title_bar {
|
|
||||||
let res = title_bar.ui(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
&content_response,
|
|
||||||
open,
|
|
||||||
&mut collapsing,
|
|
||||||
collapsible,
|
|
||||||
);
|
|
||||||
if res.is_pointer_button_down_on() {
|
|
||||||
ctx.viewport_command(ctx.get_viewport_id(), ViewportCommand::Drag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
collapsing.store(ctx);
|
|
||||||
|
|
||||||
if let Some(interaction) = interaction {
|
|
||||||
paint_frame_interaction(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
interaction,
|
|
||||||
ctx.style().visuals.widgets.active,
|
|
||||||
);
|
|
||||||
} else if let Some(hover_interaction) = hover_interaction {
|
|
||||||
if ctx.input(|i| i.pointer.has_pointer()) {
|
|
||||||
paint_frame_interaction(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
hover_interaction,
|
|
||||||
ctx.style().visuals.widgets.hovered,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
content_inner
|
|
||||||
};
|
|
||||||
|
|
||||||
let full_response = area.end(ctx, area_content_ui);
|
|
||||||
|
|
||||||
if !collapsing.is_open() {
|
|
||||||
let size = full_response.rect.max.to_vec2() * ctx.pixels_per_point();
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::InnerSize(size.x as u32, size.y as u32),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// let size = ctx.round_vec_to_pixels(full_response.rect.size());
|
|
||||||
if win_size.x < size.x {
|
|
||||||
println!("Set size! {win_size:?} {size:?}");
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::InnerSize(
|
|
||||||
(size.x * ctx.pixels_per_point()).round() as u32,
|
|
||||||
(win_size.y * ctx.pixels_per_point()).round() as u32,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if win_size.y < size.y {
|
|
||||||
println!("Set size! {win_size:?} {size:?}");
|
|
||||||
ctx.viewport_command(
|
|
||||||
ctx.get_viewport_id(),
|
|
||||||
ViewportCommand::InnerSize(
|
|
||||||
(win_size.x * ctx.pixels_per_point()).round() as u32,
|
|
||||||
(size.y * ctx.pixels_per_point()).round() as u32,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if show_close_button && op != is_open {
|
|
||||||
ctx.data_mut(|data| data.insert_persisted(area_id.with("_open"), op));
|
|
||||||
ctx.request_repaint_viewport(ctx.get_parent_viewport_id());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
|
|
||||||
|
|
||||||
area.show_open_close_animation(ctx, &frame, is_open);
|
|
||||||
|
|
||||||
let area_id = area.id;
|
|
||||||
let area_layer_id = area.layer();
|
|
||||||
let resize_id = area_id.with("resize");
|
|
||||||
let mut collapsing =
|
|
||||||
CollapsingState::load_with_default_open(ctx, area_id.with("collapsing"), default_open);
|
|
||||||
|
|
||||||
let is_collapsed = with_title_bar && !collapsing.is_open();
|
|
||||||
let possible = PossibleInteractions::new(&area, &resize, is_collapsed);
|
|
||||||
|
|
||||||
let area = area.movable(false); // We move it manually, or the area will move the window when we want to resize it
|
|
||||||
let resize = resize.resizable(false); // We move it manually
|
|
||||||
let mut resize = resize.id(resize_id);
|
|
||||||
|
|
||||||
let mut area = area.begin(ctx);
|
|
||||||
|
|
||||||
let title_content_spacing = 2.0 * ctx.style().spacing.item_spacing.y;
|
|
||||||
|
|
||||||
// First interact (move etc) to avoid frame delay:
|
|
||||||
let last_frame_outer_rect = area.state().rect();
|
|
||||||
let interaction = if possible.movable || possible.resizable() {
|
|
||||||
window_interaction(
|
|
||||||
ctx,
|
|
||||||
possible,
|
|
||||||
area_layer_id,
|
|
||||||
area_id.with("frame_resize"),
|
|
||||||
last_frame_outer_rect,
|
|
||||||
)
|
|
||||||
.and_then(|window_interaction| {
|
|
||||||
// Calculate roughly how much larger the window size is compared to the inner rect
|
|
||||||
let title_bar_height = if with_title_bar {
|
|
||||||
let style = ctx.style();
|
|
||||||
ctx.fonts(|f| title.font_height(f, &style)) + title_content_spacing
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let margins = frame.outer_margin.sum()
|
|
||||||
+ frame.inner_margin.sum()
|
|
||||||
+ vec2(0.0, title_bar_height);
|
|
||||||
|
|
||||||
interact(
|
|
||||||
window_interaction,
|
|
||||||
ctx,
|
|
||||||
margins,
|
|
||||||
area_layer_id,
|
|
||||||
&mut area,
|
|
||||||
resize_id,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let hover_interaction = resize_hover(ctx, possible, area_layer_id, last_frame_outer_rect);
|
|
||||||
|
|
||||||
let mut area_content_ui = area.content_ui(ctx);
|
|
||||||
|
|
||||||
let mut size = Vec2::new(1.0, 1.0);
|
|
||||||
|
|
||||||
let content_inner = {
|
|
||||||
// BEGIN FRAME --------------------------------
|
|
||||||
let frame_stroke = frame.stroke;
|
|
||||||
let mut frame = frame.begin(&mut area_content_ui);
|
|
||||||
|
|
||||||
let title_bar = if with_title_bar {
|
|
||||||
let title_bar = show_title_bar(
|
|
||||||
&mut frame.content_ui,
|
|
||||||
title,
|
|
||||||
show_close_button,
|
|
||||||
&mut collapsing,
|
|
||||||
collapsible,
|
|
||||||
area_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
resize.min_size.x = resize.min_size.x.at_least(title_bar.rect.width()); // Prevent making window smaller than title bar width
|
|
||||||
Some(title_bar)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let (content_inner, content_response) = collapsing
|
|
||||||
.show_body_unindented(&mut frame.content_ui, |ui| {
|
|
||||||
resize.show(ui, |ui| {
|
|
||||||
if title_bar.is_some() {
|
|
||||||
ui.add_space(title_content_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
if scroll.has_any_bar() {
|
|
||||||
scroll.show(ui, |ui| add_contents(ui));
|
|
||||||
} else {
|
|
||||||
add_contents(ui);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.map_or((None, None), |ir| (Some(()), Some(ir.response)));
|
|
||||||
if let Some(content_response) = &content_response {
|
|
||||||
size = content_response.rect.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
let outer_rect = frame.end(&mut area_content_ui).rect;
|
|
||||||
paint_resize_corner(&mut area_content_ui, &possible, outer_rect, frame_stroke);
|
|
||||||
|
|
||||||
// END FRAME --------------------------------
|
|
||||||
|
|
||||||
if let Some(title_bar) = title_bar {
|
|
||||||
title_bar.ui(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
&content_response,
|
|
||||||
open,
|
|
||||||
&mut collapsing,
|
|
||||||
collapsible,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
collapsing.store(ctx);
|
|
||||||
|
|
||||||
if let Some(interaction) = interaction {
|
|
||||||
paint_frame_interaction(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
interaction,
|
|
||||||
ctx.style().visuals.widgets.active,
|
|
||||||
);
|
|
||||||
} else if let Some(hover_interaction) = hover_interaction {
|
|
||||||
if ctx.input(|i| i.pointer.has_pointer()) {
|
|
||||||
paint_frame_interaction(
|
|
||||||
&mut area_content_ui,
|
|
||||||
outer_rect,
|
|
||||||
hover_interaction,
|
|
||||||
ctx.style().visuals.widgets.hovered,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
content_inner
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let pos = ctx
|
|
||||||
.constrain_window_rect_to_area(area.state().rect(), area.drag_bounds())
|
|
||||||
.left_top();
|
|
||||||
area.state_mut().set_left_top_pos(pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
let full_response = area.end(ctx, area_content_ui);
|
|
||||||
ctx.data_mut(|data| data.insert_temp(area_id.with("size"), size));
|
|
||||||
|
|
||||||
let _inner_response = InnerResponse {
|
|
||||||
inner: content_inner,
|
|
||||||
response: full_response,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_resize_corner(
|
fn paint_resize_corner(
|
||||||
@@ -1614,7 +841,6 @@ fn show_title_bar(
|
|||||||
show_close_button: bool,
|
show_close_button: bool,
|
||||||
collapsing: &mut CollapsingState,
|
collapsing: &mut CollapsingState,
|
||||||
collapsible: bool,
|
collapsible: bool,
|
||||||
id: Id,
|
|
||||||
) -> TitleBar {
|
) -> TitleBar {
|
||||||
let inner_response = ui.horizontal(|ui| {
|
let inner_response = ui.horizontal(|ui| {
|
||||||
let height = ui
|
let height = ui
|
||||||
@@ -1632,25 +858,13 @@ fn show_title_bar(
|
|||||||
collapsing.show_default_button_with_size(ui, button_size);
|
collapsing.show_default_button_with_size(ui, button_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
let embedded =
|
|
||||||
ui.data_mut(|data| data.get_persisted::<bool>(id.with("_embedded")).unwrap());
|
|
||||||
let c = if embedded { "^" } else { "-" };
|
|
||||||
if ui.button(c).clicked() {
|
|
||||||
ui.data_mut(|data| data.insert_persisted(id.with("_embedded"), !embedded));
|
|
||||||
// If the window is native to be embedded need for the parent to redraw
|
|
||||||
ui.ctx()
|
|
||||||
.request_repaint_viewport(ui.ctx().get_parent_viewport_id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let title_galley = title.into_galley(ui, Some(false), f32::INFINITY, TextStyle::Heading);
|
let title_galley = title.into_galley(ui, Some(false), f32::INFINITY, TextStyle::Heading);
|
||||||
|
|
||||||
let minimum_width = if collapsible || show_close_button {
|
let minimum_width = if collapsible || show_close_button {
|
||||||
// If at least one button is shown we make room for both buttons (since title is centered):
|
// If at least one button is shown we make room for both buttons (since title is centered):
|
||||||
2.0 * (pad + button_size.x + item_spacing.x) + title_galley.size().x
|
2.0 * (pad + button_size.x + item_spacing.x) + title_galley.size().x
|
||||||
} else {
|
} else {
|
||||||
pad + pad + title_galley.size().x + pad
|
pad + title_galley.size().x + pad
|
||||||
};
|
};
|
||||||
let min_rect = Rect::from_min_size(ui.min_rect().min, vec2(minimum_width, height));
|
let min_rect = Rect::from_min_size(ui.min_rect().min, vec2(minimum_width, height));
|
||||||
let id = ui.advance_cursor_after_rect(min_rect);
|
let id = ui.advance_cursor_after_rect(min_rect);
|
||||||
@@ -1692,7 +906,7 @@ impl TitleBar {
|
|||||||
open: Option<&mut bool>,
|
open: Option<&mut bool>,
|
||||||
collapsing: &mut CollapsingState,
|
collapsing: &mut CollapsingState,
|
||||||
collapsible: bool,
|
collapsible: bool,
|
||||||
) -> Response {
|
) {
|
||||||
if let Some(content_response) = &content_response {
|
if let Some(content_response) = &content_response {
|
||||||
// Now we know how large we got to be:
|
// Now we know how large we got to be:
|
||||||
self.rect.max.x = self.rect.max.x.max(content_response.rect.max.x);
|
self.rect.max.x = self.rect.max.x.max(content_response.rect.max.x);
|
||||||
@@ -1725,18 +939,15 @@ impl TitleBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't cover the close- and collapse buttons:
|
// Don't cover the close- and collapse buttons:
|
||||||
// After 32 is used for a temporary embedded button!
|
let double_click_rect = self.rect.shrink2(vec2(32.0, 0.0));
|
||||||
let double_click_rect = self.rect.shrink2(vec2(
|
|
||||||
32.0 + ui.style().visuals.text_cursor.width + ui.style().spacing.icon_width,
|
|
||||||
0.0,
|
|
||||||
));
|
|
||||||
|
|
||||||
let res = ui.interact(double_click_rect, self.id, Sense::click());
|
if ui
|
||||||
|
.interact(double_click_rect, self.id, Sense::click())
|
||||||
if res.double_clicked() && collapsible {
|
.double_clicked()
|
||||||
|
&& collapsible
|
||||||
|
{
|
||||||
collapsing.toggle(ui);
|
collapsing.toggle(ui);
|
||||||
}
|
}
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paints the "Close" button at the right side of the title bar
|
/// Paints the "Close" button at the right side of the title bar
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ impl Demos {
|
|||||||
#[cfg_attr(feature = "serde", serde(default))]
|
#[cfg_attr(feature = "serde", serde(default))]
|
||||||
struct Tests {
|
struct Tests {
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
demos: Vec<Box<dyn Demo + Sync + Send>>,
|
demos: Vec<Box<dyn Demo>>,
|
||||||
|
|
||||||
open: BTreeSet<String>,
|
open: BTreeSet<String>,
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ impl Default for Tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Tests {
|
impl Tests {
|
||||||
pub fn from_demos(demos: Vec<Box<dyn Demo + Sync + Send>>) -> Self {
|
pub fn from_demos(demos: Vec<Box<dyn Demo>>) -> Self {
|
||||||
let mut open = BTreeSet::new();
|
let mut open = BTreeSet::new();
|
||||||
open.insert(
|
open.insert(
|
||||||
super::widget_gallery::WidgetGallery::default()
|
super::widget_gallery::WidgetGallery::default()
|
||||||
@@ -146,7 +146,6 @@ fn set_open(open: &mut BTreeSet<String>, key: &'static str, is_open: bool) {
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/// A menu bar in which you can select different demo windows to show.
|
/// A menu bar in which you can select different demo windows to show.
|
||||||
|
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(default))]
|
#[cfg_attr(feature = "serde", serde(default))]
|
||||||
pub struct DemoWindows {
|
pub struct DemoWindows {
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ pub fn drop_target<R>(
|
|||||||
InnerResponse::new(ret, response)
|
InnerResponse::new(ret, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct DragAndDropDemo {
|
pub struct DragAndDropDemo {
|
||||||
/// columns with items
|
/// columns with items
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ enum WidgetType {
|
|||||||
TextEdit,
|
TextEdit,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct ManualLayoutTest {
|
pub struct ManualLayoutTest {
|
||||||
widget_offset: egui::Vec2,
|
widget_offset: egui::Vec2,
|
||||||
widget_size: egui::Vec2,
|
widget_size: egui::Vec2,
|
||||||
@@ -133,7 +133,7 @@ impl super::View for ManualLayoutTest {
|
|||||||
fn ui(&mut self, ui: &mut egui::Ui) {
|
fn ui(&mut self, ui: &mut egui::Ui) {
|
||||||
egui::reset_button(ui, self);
|
egui::reset_button(ui, self);
|
||||||
|
|
||||||
let ManualLayoutTest {
|
let Self {
|
||||||
widget_offset,
|
widget_offset,
|
||||||
widget_size,
|
widget_size,
|
||||||
widget_type,
|
widget_type,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/// Showcase [`TextEdit`].
|
/// Showcase [`TextEdit`].
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(default))]
|
#[cfg_attr(feature = "serde", serde(default))]
|
||||||
pub struct TextEdit {
|
pub struct TextEdit {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ impl super::View for WidgetGallery {
|
|||||||
self.gallery_grid_contents(ui);
|
self.gallery_grid_contents(ui);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
|||||||
@@ -54,12 +54,10 @@ impl eframe::App for MyApp {
|
|||||||
|
|
||||||
if ui.button("Yes!").clicked() {
|
if ui.button("Yes!").clicked() {
|
||||||
self.allowed_to_close = true;
|
self.allowed_to_close = true;
|
||||||
|
frame.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if self.allowed_to_close {
|
|
||||||
frame.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,12 +34,8 @@ impl eframe::App for MyApp {
|
|||||||
&mut self,
|
&mut self,
|
||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
_frame: &mut eframe::Frame,
|
_frame: &mut eframe::Frame,
|
||||||
render: Option<&ViewportRender>,
|
_: Option<&ViewportRender>,
|
||||||
) {
|
) {
|
||||||
if let Some(render) = render {
|
|
||||||
render(ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("My egui Application");
|
ui.heading("My egui Application");
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
|
|||||||
@@ -13,6 +13,5 @@ eframe = { path = "../../crates/eframe", default-features = false, features = [
|
|||||||
# accesskit struggles with threading
|
# accesskit struggles with threading
|
||||||
"default_fonts",
|
"default_fonts",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"x11"
|
|
||||||
] }
|
] }
|
||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
|
|||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use std::{sync::mpsc, thread::JoinHandle};
|
use std::sync::mpsc;
|
||||||
|
use std::thread::JoinHandle;
|
||||||
|
|
||||||
use eframe::egui::{self, ViewportRender};
|
use eframe::egui::{self, ViewportRender};
|
||||||
|
|
||||||
@@ -39,20 +40,20 @@ impl ThreadState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn show(&mut self, ctx: &egui::Context) {
|
fn show(&mut self, ctx: &egui::Context) {
|
||||||
let thread_nr = self.thread_nr;
|
let pos = egui::pos2(16.0, 128.0 * (self.thread_nr as f32 + 1.0));
|
||||||
let pos = egui::pos2(16.0, 128.0 * (thread_nr as f32 + 1.0));
|
egui::Window::new(&self.title)
|
||||||
let title = self.title.clone();
|
.default_pos(pos)
|
||||||
egui::Window::new(title).default_pos(pos).show(ctx, |ui| {
|
.show(ctx, |ui| {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("Your name: ");
|
ui.label("Your name: ");
|
||||||
ui.text_edit_singleline(&mut self.name);
|
ui.text_edit_singleline(&mut self.name);
|
||||||
|
});
|
||||||
|
ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
|
||||||
|
if ui.button("Click each year").clicked() {
|
||||||
|
self.age += 1;
|
||||||
|
}
|
||||||
|
ui.label(format!("Hello '{}', age {}", self.name, self.age));
|
||||||
});
|
});
|
||||||
ui.add(egui::Slider::new(&mut self.age, 0..=120).text("age"));
|
|
||||||
if ui.button("Click each year").clicked() {
|
|
||||||
self.age += 1;
|
|
||||||
}
|
|
||||||
ui.label(format!("Hello '{}', age {}", self.name, self.age));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +97,7 @@ impl MyApp {
|
|||||||
|
|
||||||
slf
|
slf
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl MyApp {
|
|
||||||
fn spawn_thread(&mut self) {
|
fn spawn_thread(&mut self) {
|
||||||
let thread_nr = self.threads.len();
|
let thread_nr = self.threads.len();
|
||||||
self.threads
|
self.threads
|
||||||
@@ -120,22 +119,19 @@ impl eframe::App for MyApp {
|
|||||||
&mut self,
|
&mut self,
|
||||||
ctx: &egui::Context,
|
ctx: &egui::Context,
|
||||||
_frame: &mut eframe::Frame,
|
_frame: &mut eframe::Frame,
|
||||||
render: Option<&ViewportRender>,
|
_: Option<&ViewportRender>,
|
||||||
) {
|
) {
|
||||||
if let Some(render) = render {
|
|
||||||
render(ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
egui::Window::new("Main thread").show(ctx, |ui| {
|
egui::Window::new("Main thread").show(ctx, |ui| {
|
||||||
if ui.button("Spawn another thread").clicked() {
|
if ui.button("Spawn another thread").clicked() {
|
||||||
self.spawn_thread();
|
self.spawn_thread();
|
||||||
ui.ctx()
|
|
||||||
.request_repaint_viewport(ui.ctx().get_parent_viewport_id());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (_handle, show_tx) in &self.threads {
|
for (_handle, show_tx) in &self.threads {
|
||||||
let _ = show_tx.send(ctx.clone());
|
let _ = show_tx.send(ctx.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..self.threads.len() {
|
||||||
let _ = self.on_done_rc.recv();
|
let _ = self.on_done_rc.recv();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,9 @@ const RENDERER: eframe::Renderer = eframe::Renderer::Glow;
|
|||||||
pub struct App {
|
pub struct App {
|
||||||
show_async_viewport: bool,
|
show_async_viewport: bool,
|
||||||
show_sync_viewport: bool,
|
show_sync_viewport: bool,
|
||||||
show_async_window: bool,
|
|
||||||
show_sync_window: bool,
|
|
||||||
|
|
||||||
async_viewport_state: Arc<RwLock<usize>>,
|
async_viewport_state: Arc<RwLock<usize>>,
|
||||||
sync_viewport_state: usize,
|
sync_viewport_state: usize,
|
||||||
async_window_state: Arc<RwLock<usize>>,
|
|
||||||
sync_window_state: usize,
|
|
||||||
|
|
||||||
show_async_viewport2: Arc<RwLock<bool>>,
|
show_async_viewport2: Arc<RwLock<bool>>,
|
||||||
show_sync_viewport2: Arc<RwLock<bool>>,
|
show_sync_viewport2: Arc<RwLock<bool>>,
|
||||||
@@ -61,8 +57,6 @@ impl eframe::App for App {
|
|||||||
}
|
}
|
||||||
ui.checkbox(&mut self.show_async_viewport, "Show Async Viewport");
|
ui.checkbox(&mut self.show_async_viewport, "Show Async Viewport");
|
||||||
ui.checkbox(&mut self.show_sync_viewport, "Show Sync Viewport");
|
ui.checkbox(&mut self.show_sync_viewport, "Show Sync Viewport");
|
||||||
ui.checkbox(&mut self.show_async_window, "Show Async Window");
|
|
||||||
ui.checkbox(&mut self.show_sync_window, "Show Sync Window");
|
|
||||||
|
|
||||||
let ctx = ui.ctx();
|
let ctx = ui.ctx();
|
||||||
// Showing Async Viewport
|
// Showing Async Viewport
|
||||||
@@ -343,49 +337,6 @@ impl eframe::App for App {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Showing Async Window
|
|
||||||
if self.show_async_window {
|
|
||||||
let state = self.async_window_state.clone();
|
|
||||||
egui::Window::new("Async Window")
|
|
||||||
.default_embedded(false)
|
|
||||||
.show_async(ctx, move |ui| {
|
|
||||||
let ctx = ui.ctx().clone();
|
|
||||||
let mut state = state.write().unwrap();
|
|
||||||
ui.label(format!("Frame: {}", ctx.frame_nr()));
|
|
||||||
ui.label(format!("Current Viewport Id: {}", ctx.get_viewport_id()));
|
|
||||||
ui.label(format!(
|
|
||||||
"Current Parent Viewport Id: {}",
|
|
||||||
ctx.get_viewport_id()
|
|
||||||
));
|
|
||||||
ui.label(format!("Pos: {:?}", ctx.viewport_outer_pos()));
|
|
||||||
ui.label(format!("Size: {:?}", ctx.viewport_inner_size()));
|
|
||||||
ui.label(format!("Count: {state}"));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
*state += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Showing Sync Window
|
|
||||||
if self.show_sync_window {
|
|
||||||
egui::Window::new("Sync Window")
|
|
||||||
.default_embedded(false)
|
|
||||||
.show(ctx, |ui| {
|
|
||||||
ui.label(format!("Frame: {}", ctx.frame_nr()));
|
|
||||||
ui.label(format!("Current Viewport Id: {}", ctx.get_viewport_id()));
|
|
||||||
ui.label(format!(
|
|
||||||
"Current Parent Viewport Id: {}",
|
|
||||||
ctx.get_viewport_id()
|
|
||||||
));
|
|
||||||
ui.label(format!("Pos: {:?}", ctx.viewport_outer_pos()));
|
|
||||||
ui.label(format!("Size: {:?}", ctx.viewport_inner_size()));
|
|
||||||
ui.label(format!("Count: {}", self.sync_window_state));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
self.sync_window_state += 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user