diff --git a/emigui/src/containers/area.rs b/emigui/src/containers/area.rs index 64e4b5a6..2bf2b4d0 100644 --- a/emigui/src/containers/area.rs +++ b/emigui/src/containers/area.rs @@ -24,6 +24,12 @@ pub(crate) struct State { pub vel: Vec2, } +impl State { + pub fn rect(&self) -> Rect { + Rect::from_min_size(self.pos, self.size) + } +} + #[derive(Clone, Copy, Debug)] pub struct Area { id: Id, @@ -93,9 +99,8 @@ impl Area { pub(crate) struct Prepared { layer: Layer, - pub(crate) state: State, + state: State, movable: bool, - pub(crate) content_ui: Ui, } impl Area { @@ -122,35 +127,44 @@ impl Area { state.pos = fixed_pos.unwrap_or(state.pos); state.pos = state.pos.round(); - let content_ui = Ui::new( - ctx.clone(), - layer, - id, - Rect::from_min_size(state.pos, Vec2::infinity()), - ); - Prepared { layer, state, movable, - content_ui, } } pub fn show(self, ctx: &Arc, add_contents: impl FnOnce(&mut Ui)) -> InteractInfo { - let mut prepared = self.begin(ctx); - add_contents(&mut prepared.content_ui); - prepared.end(ctx) + let prepared = self.begin(ctx); + let mut content_ui = prepared.content_ui(ctx); + add_contents(&mut content_ui); + prepared.end(ctx, content_ui) } } impl Prepared { - pub(crate) fn end(self, ctx: &Arc) -> InteractInfo { + pub(crate) fn state(&self) -> &State { + &self.state + } + + pub(crate) fn state_mut(&mut self) -> &mut State { + &mut self.state + } + + pub(crate) fn content_ui(&self, ctx: &Arc) -> Ui { + Ui::new( + ctx.clone(), + self.layer, + self.layer.id, + Rect::from_min_size(self.state.pos, Vec2::infinity()), + ) + } + + pub(crate) fn end(self, ctx: &Arc, content_ui: Ui) -> InteractInfo { let Prepared { layer, mut state, movable, - content_ui, } = self; state.size = (content_ui.child_bounds().max - state.pos).ceil(); diff --git a/emigui/src/containers/window.rs b/emigui/src/containers/window.rs index 20f63d24..0a85537c 100644 --- a/emigui/src/containers/window.rs +++ b/emigui/src/containers/window.rs @@ -167,9 +167,29 @@ impl<'open> Window<'open> { let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style())); let mut area = area.begin(ctx); + + // First interact (move etc) to avoid frame delay: + let last_frame_outer_rect = area.state().rect(); + let interaction = if possible.movable || possible.resizable { + interact( + ctx, + possible, + area_layer, + area.state_mut(), + window_id, + resize_id, + last_frame_outer_rect, + ) + } else { + None + }; + let hover_interaction = resize_hover(ctx, possible, area_layer, last_frame_outer_rect); + + let mut area_content_ui = area.content_ui(ctx); + { // BEGIN FRAME -------------------------------- - let mut frame = frame.begin(&mut area.content_ui); + let mut frame = frame.begin(&mut area_content_ui); let default_expanded = true; let mut collapsing = collapsing_header::State::from_memory_with_default_open( @@ -201,40 +221,25 @@ impl<'open> Window<'open> { }) .map(|ri| ri.1); - let outer_rect = frame.end(&mut area.content_ui); + let outer_rect = frame.end(&mut area_content_ui); // END FRAME -------------------------------- - let interaction = if possible.movable || possible.resizable { - interact( - ctx, - possible, - area_layer, - &mut area.state, - window_id, - resize_id, - outer_rect, - ) - } else { - None - }; - let hover_interaction = resize_hover(ctx, possible, area_layer, outer_rect); - title_bar.ui( - &mut area.content_ui, + &mut area_content_ui, outer_rect, content_rect, open, &mut collapsing, ); - area.content_ui + area_content_ui .memory() .collapsing_headers .insert(collapsing_id, collapsing); if let Some(interaction) = interaction { paint_frame_interaction( - &mut area.content_ui, + &mut area_content_ui, outer_rect, interaction, ctx.style().interact.active, @@ -242,7 +247,7 @@ impl<'open> Window<'open> { } else { if let Some(hover_interaction) = hover_interaction { paint_frame_interaction( - &mut area.content_ui, + &mut area_content_ui, outer_rect, hover_interaction, ctx.style().interact.hovered, @@ -250,7 +255,7 @@ impl<'open> Window<'open> { } } } - let full_interact = area.end(ctx); + let full_interact = area.end(ctx, area_content_ui); Some(full_interact) } @@ -377,6 +382,7 @@ fn window_interaction( hover_window_interaction.set_cursor(ctx); if ctx.input().mouse.pressed { ctx.memory().interaction.drag_id = Some(id); + ctx.memory().interaction.drag_is_window = true; window_interaction = Some(hover_window_interaction); ctx.memory().window_interaction = window_interaction; } diff --git a/emigui/src/context.rs b/emigui/src/context.rs index 0b77d67e..999482ed 100644 --- a/emigui/src/context.rs +++ b/emigui/src/context.rs @@ -309,9 +309,13 @@ impl Context { info.active = true; } - if sense.drag && !memory.interaction.drag_id.is_some() { + if sense.drag + && (!memory.interaction.drag_id.is_some() || memory.interaction.drag_is_window) + { // start of a drag memory.interaction.drag_id = Some(interaction_id); + memory.interaction.drag_is_window = false; + memory.window_interaction = None; // HACK: stop moving windows (if any) info.active = true; } diff --git a/emigui/src/memory.rs b/emigui/src/memory.rs index 4872a22b..bf186288 100644 --- a/emigui/src/memory.rs +++ b/emigui/src/memory.rs @@ -44,6 +44,13 @@ pub struct Interaction { /// A widget interested in drags that has a mouse press on it. pub drag_id: Option, + /// HACK: windows have low priority on dragging. + /// This is so that if you drag a slider in a window, + /// the slider will steal the drag away from the window. + /// This is needed because we do window interaction first (to prevent frame delay), + /// and then do content layout. + pub drag_is_window: bool, + /// Any interest in catching clicks this frame? /// Cleared to false at start of each frame. pub click_interest: bool,