Input no longer blinks in the background

Also, Expand now expands properly.
This commit is contained in:
Jonathan Johnson 2023-11-08 08:44:16 -08:00
parent b27b9db380
commit fc165628e5
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
6 changed files with 155 additions and 30 deletions

View file

@ -1,6 +1,6 @@
use gooey::widgets::Input; use gooey::widgets::{Expand, Input};
use gooey::Run; use gooey::Run;
fn main() -> gooey::Result { fn main() -> gooey::Result {
Input::new("Hello").run() Expand::new(Input::new("Hello")).run()
} }

View file

@ -858,6 +858,18 @@ impl<'context, 'window> WidgetContext<'context, 'window> {
redraw_status: self.redraw_status.clone(), redraw_status: self.redraw_status.clone(),
} }
} }
/// Returns the window containing this widget.
#[must_use]
pub fn window(&self) -> &RunningWindow<'window> {
self.window
}
/// Returns an exclusive reference to the window containing this widget.
#[must_use]
pub fn window_mut(&mut self) -> &mut RunningWindow<'window> {
self.window
}
} }
pub(crate) struct WindowHandle { pub(crate) struct WindowHandle {
@ -890,6 +902,7 @@ impl<'window> Deref for WidgetContext<'_, 'window> {
self.window self.window
} }
} }
impl<'window> DerefMut for WidgetContext<'_, 'window> { impl<'window> DerefMut for WidgetContext<'_, 'window> {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.window self.window

View file

@ -21,6 +21,7 @@ use std::ops::Sub;
pub use kludgine; pub use kludgine;
use kludgine::app::winit::error::EventLoopError; use kludgine::app::winit::error::EventLoopError;
use kludgine::figures::units::UPx; use kludgine::figures::units::UPx;
use kludgine::figures::{Fraction, IntoUnsigned, ScreenUnit};
pub use names::Name; pub use names::Name;
pub use utils::WithClone; pub use utils::WithClone;
@ -44,6 +45,23 @@ impl ConstraintLimit {
ConstraintLimit::Known(v) | ConstraintLimit::ClippedAfter(v) => v, ConstraintLimit::Known(v) | ConstraintLimit::ClippedAfter(v) => v,
} }
} }
/// Converts `measured` to unsigned pixels, and adjusts it according to the
/// contraint's intentions.
///
/// If this constraint is of a known size, it will return the maximum of the
/// measured size and the contraint. If it is of an unknown size, it will
/// return the measured size.
pub fn fit_measured<Unit>(self, measured: Unit, scale: Fraction) -> UPx
where
Unit: ScreenUnit,
{
let measured = measured.into_px(scale).into_unsigned();
match self {
ConstraintLimit::Known(size) => size.max(measured),
ConstraintLimit::ClippedAfter(_) => measured,
}
}
} }
impl Sub<UPx> for ConstraintLimit { impl Sub<UPx> for ConstraintLimit {

View file

@ -63,7 +63,16 @@ impl Widget for Expand {
); );
let child = self.child.mounted(&mut context.as_event_context()); let child = self.child.mounted(&mut context.as_event_context());
let size = context.for_other(&child).layout(available_space); let size = context.for_other(&child).layout(available_space);
context.set_child_layout(&child, Rect::from(size.into_signed()));
size let expanded_size = Size::new(
available_space
.width
.fit_measured(size.width, context.graphics.scale()),
available_space
.height
.fit_measured(size.height, context.graphics.scale()),
);
context.set_child_layout(&child, Rect::from(expanded_size.into_signed()));
expanded_size
} }
} }

View file

@ -280,7 +280,8 @@ impl Widget for Input {
(Err(_), Err(_)) => {} (Err(_), Err(_)) => {}
} }
} else if let Ok((location, _)) = cursor_glyph(buffer, &cursor) { } else if let Ok((location, _)) = cursor_glyph(buffer, &cursor) {
if cursor_state.visible { let window_focused = context.window().focused().get();
if window_focused && cursor_state.visible {
context.graphics.draw_shape( context.graphics.draw_shape(
&Shape::filled_rect( &Shape::filled_rect(
Rect::new( Rect::new(
@ -294,7 +295,11 @@ impl Widget for Input {
None, None,
); );
} }
context.redraw_in(cursor_state.remaining_until_blink); if window_focused {
context.redraw_in(cursor_state.remaining_until_blink);
} else {
context.redraw_when_changed(context.window().focused());
}
} }
} }

View file

@ -4,6 +4,7 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::HashMap;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::ops::{Deref, DerefMut};
use std::panic::{AssertUnwindSafe, UnwindSafe}; use std::panic::{AssertUnwindSafe, UnwindSafe};
use std::path::Path; use std::path::Path;
use std::string::ToString; use std::string::ToString;
@ -34,7 +35,53 @@ use crate::window::sealed::WindowCommand;
use crate::{ConstraintLimit, Run}; use crate::{ConstraintLimit, Run};
/// A currently running Gooey window. /// A currently running Gooey window.
pub type RunningWindow<'window> = kludgine::app::Window<'window, WindowCommand>; pub struct RunningWindow<'window> {
window: kludgine::app::Window<'window, WindowCommand>,
focused: Dynamic<bool>,
occluded: Dynamic<bool>,
}
impl<'window> RunningWindow<'window> {
pub(crate) fn new(
window: kludgine::app::Window<'window, WindowCommand>,
focused: &Dynamic<bool>,
occluded: &Dynamic<bool>,
) -> Self {
Self {
window,
focused: focused.clone(),
occluded: occluded.clone(),
}
}
/// Returns a dynamic that is updated whenever this window's focus status
/// changes.
#[must_use]
pub const fn focused(&self) -> &Dynamic<bool> {
&self.focused
}
/// Returns a dynamic that is updated whenever this window's occlusion
/// status changes.
#[must_use]
pub fn occluded(&self) -> &Dynamic<bool> {
&self.occluded
}
}
impl<'window> Deref for RunningWindow<'window> {
type Target = kludgine::app::Window<'window, WindowCommand>;
fn deref(&self) -> &Self::Target {
&self.window
}
}
impl<'window> DerefMut for RunningWindow<'window> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.window
}
}
/// The attributes of a Gooey window. /// The attributes of a Gooey window.
pub type WindowAttributes = kludgine::app::WindowAttributes<WindowCommand>; pub type WindowAttributes = kludgine::app::WindowAttributes<WindowCommand>;
@ -194,8 +241,8 @@ struct GooeyWindow<T> {
mouse_state: MouseState, mouse_state: MouseState,
redraw_status: RedrawStatus, redraw_status: RedrawStatus,
initial_frame: bool, initial_frame: bool,
occluded: Option<Dynamic<bool>>, occluded: Dynamic<bool>,
focused: Option<Dynamic<bool>>, focused: Dynamic<bool>,
} }
impl<T> GooeyWindow<T> impl<T> GooeyWindow<T>
@ -216,14 +263,27 @@ where
type Context = AssertUnwindSafe<sealed::Context<T::Context>>; type Context = AssertUnwindSafe<sealed::Context<T::Context>>;
fn initialize( fn initialize(
mut window: RunningWindow<'_>, window: kludgine::app::Window<'_, WindowCommand>,
_graphics: &mut kludgine::Graphics<'_>, _graphics: &mut kludgine::Graphics<'_>,
AssertUnwindSafe(context): Self::Context, AssertUnwindSafe(context): Self::Context,
) -> Self { ) -> Self {
let mut behavior = T::initialize(&mut window, context.user); let occluded = context
.settings
.borrow_mut()
.occluded
.take()
.unwrap_or_default();
let focused = context
.settings
.borrow_mut()
.focused
.take()
.unwrap_or_default();
let mut behavior = T::initialize(
&mut RunningWindow::new(window, &focused, &occluded),
context.user,
);
let root = Tree::default().push_boxed(behavior.make_root(), None); let root = Tree::default().push_boxed(behavior.make_root(), None);
let occluded = context.settings.borrow_mut().occluded.take();
let focused = context.settings.borrow_mut().focused.take();
Self { Self {
behavior, behavior,
@ -242,11 +302,16 @@ where
} }
} }
fn prepare(&mut self, mut window: RunningWindow<'_>, graphics: &mut kludgine::Graphics<'_>) { fn prepare(
&mut self,
window: kludgine::app::Window<'_, WindowCommand>,
graphics: &mut kludgine::Graphics<'_>,
) {
self.redraw_status.refresh_received(); self.redraw_status.refresh_received();
graphics.reset_text_attributes(); graphics.reset_text_attributes();
self.root.tree.reset_render_order(); self.root.tree.reset_render_order();
let graphics = self.contents.new_frame(graphics); let graphics = self.contents.new_frame(graphics);
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
let mut context = GraphicsContext { let mut context = GraphicsContext {
widget: WidgetContext::new(self.root.clone(), &self.redraw_status, &mut window), widget: WidgetContext::new(self.root.clone(), &self.redraw_status, &mut window),
graphics: Exclusive::Owned(Graphics::new(graphics)), graphics: Exclusive::Owned(Graphics::new(graphics)),
@ -280,9 +345,7 @@ where
window: kludgine::app::Window<'_, WindowCommand>, window: kludgine::app::Window<'_, WindowCommand>,
_kludgine: &mut Kludgine, _kludgine: &mut Kludgine,
) { ) {
if let Some(focused) = &self.focused { self.focused.update(window.focused());
focused.update(window.focused());
}
} }
fn occlusion_changed( fn occlusion_changed(
@ -290,14 +353,12 @@ where
window: kludgine::app::Window<'_, WindowCommand>, window: kludgine::app::Window<'_, WindowCommand>,
_kludgine: &mut Kludgine, _kludgine: &mut Kludgine,
) { ) {
if let Some(occluded) = &self.occluded { self.occluded.update(window.ocluded());
occluded.update(window.ocluded());
}
} }
fn render<'pass>( fn render<'pass>(
&'pass mut self, &'pass mut self,
_window: RunningWindow<'_>, _window: kludgine::app::Window<'_, WindowCommand>,
graphics: &mut kludgine::RenderingGraphics<'_, 'pass>, graphics: &mut kludgine::RenderingGraphics<'_, 'pass>,
) -> bool { ) -> bool {
self.contents.render(graphics); self.contents.render(graphics);
@ -316,8 +377,16 @@ where
.expect("called more than once") .expect("called more than once")
} }
fn close_requested(&mut self, mut window: RunningWindow<'_>, _kludgine: &mut Kludgine) -> bool { fn close_requested(
self.request_close(&mut window) &mut self,
window: kludgine::app::Window<'_, WindowCommand>,
_kludgine: &mut Kludgine,
) -> bool {
self.request_close(&mut RunningWindow::new(
window,
&self.focused,
&self.occluded,
))
} }
// fn power_preference() -> wgpu::PowerPreference { // fn power_preference() -> wgpu::PowerPreference {
@ -352,7 +421,7 @@ where
fn keyboard_input( fn keyboard_input(
&mut self, &mut self,
mut window: RunningWindow<'_>, window: kludgine::app::Window<'_, WindowCommand>,
kludgine: &mut Kludgine, kludgine: &mut Kludgine,
device_id: DeviceId, device_id: DeviceId,
input: KeyEvent, input: KeyEvent,
@ -360,6 +429,7 @@ where
) { ) {
let target = self.root.tree.focused_widget().unwrap_or(self.root.id()); let target = self.root.tree.focused_widget().unwrap_or(self.root.id());
let target = self.root.tree.widget(target).expect("missing widget"); let target = self.root.tree.widget(target).expect("missing widget");
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
let mut target = EventContext::new( let mut target = EventContext::new(
WidgetContext::new(target, &self.redraw_status, &mut window), WidgetContext::new(target, &self.redraw_status, &mut window),
kludgine, kludgine,
@ -404,7 +474,7 @@ where
fn mouse_wheel( fn mouse_wheel(
&mut self, &mut self,
mut window: RunningWindow<'_>, window: kludgine::app::Window<'_, WindowCommand>,
kludgine: &mut Kludgine, kludgine: &mut Kludgine,
device_id: DeviceId, device_id: DeviceId,
delta: MouseScrollDelta, delta: MouseScrollDelta,
@ -422,6 +492,7 @@ where
.expect("missing widget") .expect("missing widget")
}); });
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
let mut widget = EventContext::new( let mut widget = EventContext::new(
WidgetContext::new(widget, &self.redraw_status, &mut window), WidgetContext::new(widget, &self.redraw_status, &mut window),
kludgine, kludgine,
@ -433,7 +504,12 @@ where
// fn modifiers_changed(&mut self, window: kludgine::app::Window<'_, ()>) {} // fn modifiers_changed(&mut self, window: kludgine::app::Window<'_, ()>) {}
fn ime(&mut self, mut window: RunningWindow<'_>, kludgine: &mut Kludgine, ime: Ime) { fn ime(
&mut self,
window: kludgine::app::Window<'_, WindowCommand>,
kludgine: &mut Kludgine,
ime: Ime,
) {
let widget = self let widget = self
.root .root
.tree .tree
@ -445,6 +521,7 @@ where
.widget(self.root.id()) .widget(self.root.id())
.expect("missing widget") .expect("missing widget")
}); });
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
let mut target = EventContext::new( let mut target = EventContext::new(
WidgetContext::new(widget, &self.redraw_status, &mut window), WidgetContext::new(widget, &self.redraw_status, &mut window),
kludgine, kludgine,
@ -456,7 +533,7 @@ where
fn cursor_moved( fn cursor_moved(
&mut self, &mut self,
mut window: RunningWindow<'_>, window: kludgine::app::Window<'_, WindowCommand>,
kludgine: &mut Kludgine, kludgine: &mut Kludgine,
device_id: DeviceId, device_id: DeviceId,
position: PhysicalPosition<f64>, position: PhysicalPosition<f64>,
@ -464,6 +541,7 @@ where
let location = Point::<Px>::from(position); let location = Point::<Px>::from(position);
self.mouse_state.location = Some(location); self.mouse_state.location = Some(location);
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
if let Some(state) = self.mouse_state.devices.get(&device_id) { if let Some(state) = self.mouse_state.devices.get(&device_id) {
// Mouse Drag // Mouse Drag
for (button, handler) in state { for (button, handler) in state {
@ -505,11 +583,12 @@ where
fn cursor_left( fn cursor_left(
&mut self, &mut self,
mut window: RunningWindow<'_>, window: kludgine::app::Window<'_, WindowCommand>,
kludgine: &mut Kludgine, kludgine: &mut Kludgine,
_device_id: DeviceId, _device_id: DeviceId,
) { ) {
if self.mouse_state.widget.take().is_some() { if self.mouse_state.widget.take().is_some() {
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
let mut context = EventContext::new( let mut context = EventContext::new(
WidgetContext::new(self.root.clone(), &self.redraw_status, &mut window), WidgetContext::new(self.root.clone(), &self.redraw_status, &mut window),
kludgine, kludgine,
@ -520,12 +599,13 @@ where
fn mouse_input( fn mouse_input(
&mut self, &mut self,
mut window: RunningWindow<'_>, window: kludgine::app::Window<'_, WindowCommand>,
kludgine: &mut Kludgine, kludgine: &mut Kludgine,
device_id: DeviceId, device_id: DeviceId,
state: ElementState, state: ElementState,
button: MouseButton, button: MouseButton,
) { ) {
let mut window = RunningWindow::new(window, &self.focused, &self.occluded);
match state { match state {
ElementState::Pressed => { ElementState::Pressed => {
EventContext::new( EventContext::new(
@ -587,7 +667,7 @@ where
fn event( fn event(
&mut self, &mut self,
mut window: RunningWindow<'_>, mut window: kludgine::app::Window<'_, WindowCommand>,
_kludgine: &mut Kludgine, _kludgine: &mut Kludgine,
event: WindowCommand, event: WindowCommand,
) { ) {