Skip to content

Commit 5aaecae

Browse files
authored
Merge pull request #480 from kas-gui/work3
Non-mut Layout::{rect, try_probe, draw}
2 parents 681e845 + 9f9d92e commit 5aaecae

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+396
-378
lines changed

crates/kas-core/src/core/impls.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
//! Widget method implementations
77
8-
use crate::event::{ConfigCx, Event, EventCx, FocusSource, IsUsed, Scroll, Unused, Used};
8+
use crate::event::{ConfigCx, Event, EventCx, FocusSource, IsUsed, Scroll, Unused};
99
#[cfg(debug_assertions)] use crate::util::IdentifyWidget;
1010
use crate::{Events, Id, NavAdvance, Node, Tile, Widget};
1111

@@ -25,14 +25,14 @@ pub fn _send<W: Events>(
2525
return is_used;
2626
}
2727

28+
// Side-effects of receiving events at the target widget.
29+
// These actions do not affect is_used or event propagation.
2830
match &event {
2931
Event::MouseHover(state) => {
3032
widget.handle_hover(cx, *state);
31-
return Used;
3233
}
3334
Event::NavFocus(FocusSource::Key) => {
3435
cx.set_scroll(Scroll::Rect(widget.rect()));
35-
is_used |= Used;
3636
}
3737
_ => (),
3838
}

crates/kas-core/src/core/layout.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ use kas_macros::autoimpl;
5151
/// [`#widget`]: macros::widget
5252
#[autoimpl(for<T: trait + ?Sized> &'_ mut T, Box<T>)]
5353
pub trait Layout {
54+
/// Get the widget's region
55+
///
56+
/// Coordinates are relative to the parent's coordinate space.
57+
///
58+
/// This method is usually implemented by the `#[widget]` macro.
59+
/// See also [`kas::widget_set_rect`].
60+
fn rect(&self) -> Rect;
61+
5462
/// Get size rules for the given axis
5563
///
5664
/// # Calling
@@ -156,7 +164,7 @@ pub trait Layout {
156164
///
157165
/// Non-widgets do not have an [`Id`], and therefore should use the default
158166
/// implementation which simply returns `None`.
159-
fn try_probe(&mut self, coord: Coord) -> Option<Id> {
167+
fn try_probe(&self, coord: Coord) -> Option<Id> {
160168
let _ = coord;
161169
None
162170
}
@@ -189,7 +197,7 @@ pub trait Layout {
189197
/// This method modification should never cause issues (besides the implied
190198
/// limitation that widgets cannot easily detect a parent's state while
191199
/// being drawn).
192-
fn draw(&mut self, draw: DrawCx);
200+
fn draw(&self, draw: DrawCx);
193201
}
194202

195203
/// Macro-defined layout
@@ -201,15 +209,18 @@ pub trait Layout {
201209
///
202210
/// TODO: add an example
203211
pub trait MacroDefinedLayout {
212+
/// Get the widget's region
213+
fn rect(&self) -> Rect;
214+
204215
/// Get size rules for the given axis
205216
fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules;
206217

207218
/// Set size and position
208219
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints);
209220

210221
/// Probe a coordinate for a widget's [`Id`]
211-
fn try_probe(&mut self, coord: Coord) -> Option<Id>;
222+
fn try_probe(&self, coord: Coord) -> Option<Id>;
212223

213224
/// Draw a widget and its children
214-
fn draw(&mut self, draw: DrawCx);
225+
fn draw(&self, draw: DrawCx);
215226
}

crates/kas-core/src/core/node.rs

+2-29
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
88
use super::Widget;
99
use crate::event::{ConfigCx, Event, EventCx, IsUsed};
10-
use crate::geom::{Coord, Rect};
10+
use crate::geom::Rect;
1111
use crate::layout::{AlignHints, AxisInfo, SizeRules};
12-
use crate::theme::{DrawCx, SizeCx};
12+
use crate::theme::SizeCx;
1313
use crate::{Id, NavAdvance, Tile};
1414

1515
#[cfg(not(feature = "unsafe_node"))]
@@ -28,8 +28,6 @@ trait NodeT {
2828
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints);
2929

3030
fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize>;
31-
fn try_probe(&mut self, coord: Coord) -> Option<Id>;
32-
fn _draw(&mut self, draw: DrawCx);
3331

3432
fn _configure(&mut self, cx: &mut ConfigCx, id: Id);
3533
fn _update(&mut self, cx: &mut ConfigCx);
@@ -80,12 +78,6 @@ impl<'a, T> NodeT for (&'a mut dyn Widget<Data = T>, &'a T) {
8078
fn nav_next(&self, reverse: bool, from: Option<usize>) -> Option<usize> {
8179
self.0.nav_next(reverse, from)
8280
}
83-
fn try_probe(&mut self, coord: Coord) -> Option<Id> {
84-
self.0.try_probe(coord)
85-
}
86-
fn _draw(&mut self, mut draw: DrawCx) {
87-
self.0.draw(draw.re());
88-
}
8981

9082
fn _configure(&mut self, cx: &mut ConfigCx, id: Id) {
9183
self.0._configure(cx, self.1, id);
@@ -302,25 +294,6 @@ impl<'a> Node<'a> {
302294
self.0.nav_next(reverse, from)
303295
}
304296

305-
/// Translate a coordinate to an [`Id`]
306-
pub(crate) fn try_probe(&mut self, coord: Coord) -> Option<Id> {
307-
self.0.try_probe(coord)
308-
}
309-
310-
cfg_if::cfg_if! {
311-
if #[cfg(feature = "unsafe_node")] {
312-
/// Draw a widget and its children
313-
pub(crate) fn _draw(&mut self, mut draw: DrawCx) {
314-
self.0.draw(draw.re());
315-
}
316-
} else {
317-
/// Draw a widget and its children
318-
pub(crate) fn _draw(&mut self, draw: DrawCx) {
319-
self.0._draw(draw);
320-
}
321-
}
322-
}
323-
324297
/// Internal method: configure recursively
325298
pub(crate) fn _configure(&mut self, cx: &mut ConfigCx, id: Id) {
326299
cfg_if::cfg_if! {

crates/kas-core/src/core/tile.rs

+3-9
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
//! Layout, Tile and TileExt traits
77
8-
use crate::geom::{Coord, Offset, Rect};
8+
use crate::geom::{Coord, Offset};
99
use crate::util::IdentifyWidget;
1010
use crate::{HasId, Id, Layout};
1111
use kas_macros::autoimpl;
@@ -21,7 +21,7 @@ use kas_macros::autoimpl;
2121
///
2222
/// - Has no [`Data`](Widget::Data) parameter
2323
/// - Supports read-only tree reflection: [`Self::get_child`]
24-
/// - Provides some basic operations: [`Self::id_ref`], [`Self::rect`]
24+
/// - Provides some basic operations: [`Self::id_ref`]
2525
/// - Covers sizing and drawing operations from [`Layout`]
2626
///
2727
/// `Tile` may not be implemented directly; it will be implemented by the
@@ -74,12 +74,6 @@ pub trait Tile: Layout {
7474
self.id_ref().clone()
7575
}
7676

77-
/// Get the widget's region, relative to its parent.
78-
///
79-
/// This method is usually implemented by the `#[widget]` macro.
80-
/// See also [`kas::widget_set_rect`].
81-
fn rect(&self) -> Rect;
82-
8377
/// Get the name of the widget struct
8478
///
8579
/// This method is implemented by the `#[widget]` macro.
@@ -197,7 +191,7 @@ pub trait Tile: Layout {
197191
/// let coord = coord + self.translation();
198192
/// MacroDefinedLayout::try_probe(self, coord).unwrap_or_else(|| self.id())
199193
/// ```
200-
fn probe(&mut self, coord: Coord) -> Id
194+
fn probe(&self, coord: Coord) -> Id
201195
where
202196
Self: Sized,
203197
{

crates/kas-core/src/core/widget.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
#[allow(unused)] use super::Layout;
99
use super::{Node, Tile};
10-
#[allow(unused)] use crate::event::Used;
10+
#[allow(unused)] use crate::event::EventState;
1111
use crate::event::{ConfigCx, Event, EventCx, IsUsed, Scroll, Unused};
1212
use crate::Id;
1313
#[allow(unused)] use kas_macros as macros;
@@ -150,13 +150,13 @@ pub trait Events: Widget + Sized {
150150
/// default implementation of this method does nothing.
151151
///
152152
/// Note: to implement `hover_highlight`, simply request a redraw on
153-
/// focus gain and loss. To implement `cursor_icon`, call
154-
/// `cx.set_hover_cursor(EXPR);` on focus gain.
153+
/// hover gain and loss. To implement `cursor_icon`, call
154+
/// [`EventState::set_hover_cursor`] on hover gain only.
155155
///
156156
/// [`#widget`]: macros::widget
157157
#[inline]
158-
fn handle_hover(&mut self, cx: &mut EventCx, state: bool) {
159-
let _ = (cx, state);
158+
fn handle_hover(&mut self, cx: &mut EventCx, is_hovered: bool) {
159+
let _ = (cx, is_hovered);
160160
}
161161

162162
/// Handle an [`Event`]

crates/kas-core/src/decorations.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl_scope! {
8080
SizeRules::EMPTY
8181
}
8282

83-
fn draw(&mut self, _: DrawCx) {}
83+
fn draw(&self, _: DrawCx) {}
8484
}
8585

8686
impl Events for Self {
@@ -123,7 +123,6 @@ impl_scope! {
123123

124124
impl Layout for Self {
125125
fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
126-
widget_set_rect!(rect);
127126
self.text.set_rect(cx, rect, hints.combine(AlignHints::CENTER));
128127
}
129128
}
@@ -178,7 +177,7 @@ impl_scope! {
178177
sizer.feature(self.style.into(), axis)
179178
}
180179

181-
fn draw(&mut self, mut draw: DrawCx) {
180+
fn draw(&self, mut draw: DrawCx) {
182181
draw.mark(self.rect(), self.style);
183182
}
184183
}

crates/kas-core/src/draw/draw.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use std::time::Instant;
2929
/// # _pd: std::marker::PhantomData<DS>,
3030
/// # }
3131
/// impl CircleWidget {
32-
/// fn draw(&mut self, mut draw: DrawCx) {
32+
/// fn draw(&self, mut draw: DrawCx) {
3333
/// // This type assumes usage of kas_wgpu without a custom draw pipe:
3434
/// type DrawIface = DrawIface<kas_wgpu::draw::DrawPipe<()>>;
3535
/// if let Some(mut draw) = DrawIface::downcast_from(draw.draw_device()) {

crates/kas-core/src/event/components.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use crate::{Action, Id};
1515
use kas_macros::impl_default;
1616
use std::time::{Duration, Instant};
1717

18-
const TIMER_SELECT: u64 = 1 << 60;
19-
const TIMER_GLIDE: u64 = (1 << 60) + 1;
18+
const TIMER_SELECT: TimerHandle = TimerHandle::new(1 << 60, true);
19+
const TIMER_GLIDE: TimerHandle = TimerHandle::new((1 << 60) + 1, true);
2020
const GLIDE_POLL_MS: u64 = 3;
2121
const GLIDE_MAX_SAMPLES: usize = 8;
2222

@@ -336,7 +336,7 @@ impl ScrollComponent {
336336
let timeout = cx.config().event().scroll_flick_timeout();
337337
let pan_dist_thresh = cx.config().event().pan_dist_thresh();
338338
if self.glide.press_end(timeout, pan_dist_thresh) {
339-
cx.request_timer(id.clone(), TIMER_GLIDE, Duration::new(0, 0));
339+
cx.request_timer(id.clone(), TIMER_GLIDE, Duration::ZERO);
340340
}
341341
}
342342
Event::Timer(pl) if pl == TIMER_GLIDE => {
@@ -484,7 +484,7 @@ impl TextInput {
484484
|| matches!(press.source, PressSource::Mouse(..) if cx.config_enable_mouse_text_pan()))
485485
{
486486
self.touch_phase = TouchPhase::None;
487-
cx.request_timer(w_id, TIMER_GLIDE, Duration::new(0, 0));
487+
cx.request_timer(w_id, TIMER_GLIDE, Duration::ZERO);
488488
}
489489
Action::None
490490
}

crates/kas-core/src/event/cx/cx_pub.rs

+9-23
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,6 @@ impl EventState {
6767
self.mouse_grab.is_none() && *w_id == self.hover
6868
}
6969

70-
/// Get whether widget `id` or any of its descendants are under the mouse cursor
71-
#[inline]
72-
pub fn is_hovered_recursive(&self, id: &Id) -> bool {
73-
self.mouse_grab.is_none()
74-
&& self
75-
.hover
76-
.as_ref()
77-
.map(|h| id.is_ancestor_of(h))
78-
.unwrap_or(false)
79-
}
80-
8170
/// Check whether the given widget is visually depressed
8271
pub fn is_depressed(&self, w_id: &Id) -> bool {
8372
for (_, id) in &self.key_depress {
@@ -200,34 +189,35 @@ impl EventState {
200189
/// Widget updates may be used for animation and timed responses. See also
201190
/// [`Draw::animate`](crate::draw::Draw::animate) for animation.
202191
///
203-
/// Widget `id` will receive [`Event::Timer`] with this `payload` at
192+
/// Widget `id` will receive [`Event::Timer`] with this `handle` at
204193
/// approximately `time = now + delay` (or possibly a little later due to
205194
/// frame-rate limiters and processing time).
206195
///
207196
/// Requesting an update with `delay == 0` is valid, except from an
208197
/// [`Event::Timer`] handler (where it may cause an infinite loop).
209198
///
210-
/// Multiple timer requests with the same `id` and `payload` are merged
211-
/// (choosing the earliest time).
212-
pub fn request_timer(&mut self, id: Id, payload: u64, delay: Duration) {
199+
/// Multiple timer requests with the same `id` and `handle` are merged
200+
/// (see [`TimerHandle`] documentation).
201+
pub fn request_timer(&mut self, id: Id, handle: TimerHandle, delay: Duration) {
213202
let time = Instant::now() + delay;
214203
if let Some(row) = self
215204
.time_updates
216205
.iter_mut()
217-
.find(|row| row.1 == id && row.2 == payload)
206+
.find(|row| row.1 == id && row.2 == handle)
218207
{
219-
if row.0 <= time {
208+
let earliest = handle.earliest();
209+
if earliest && row.0 <= time || !earliest && row.0 >= time {
220210
return;
221211
}
222212

223213
row.0 = time;
214+
} else {
224215
log::trace!(
225216
target: "kas_core::event",
226217
"request_timer: update {id} at now+{}ms",
227218
delay.as_millis()
228219
);
229-
} else {
230-
self.time_updates.push((time, id, payload));
220+
self.time_updates.push((time, id, handle));
231221
}
232222

233223
self.time_updates.sort_by(|a, b| b.0.cmp(&a.0)); // reverse sort
@@ -888,7 +878,6 @@ impl<'a> EventCx<'a> {
888878
///
889879
/// In case of failure, paste actions will simply fail. The implementation
890880
/// may wish to log an appropriate warning message.
891-
#[inline]
892881
pub fn get_clipboard(&mut self) -> Option<String> {
893882
#[cfg(all(wayland_platform, feature = "clipboard"))]
894883
if let Some(cb) = self.window.wayland_clipboard() {
@@ -905,7 +894,6 @@ impl<'a> EventCx<'a> {
905894
}
906895

907896
/// Attempt to set clipboard contents
908-
#[inline]
909897
pub fn set_clipboard(&mut self, content: String) {
910898
#[cfg(all(wayland_platform, feature = "clipboard"))]
911899
if let Some(cb) = self.window.wayland_clipboard() {
@@ -932,7 +920,6 @@ impl<'a> EventCx<'a> {
932920
///
933921
/// Linux has a "primary buffer" with implicit copy on text selection and
934922
/// paste on middle-click. This method does nothing on other platforms.
935-
#[inline]
936923
pub fn get_primary(&mut self) -> Option<String> {
937924
#[cfg(all(wayland_platform, feature = "clipboard"))]
938925
if let Some(cb) = self.window.wayland_clipboard() {
@@ -952,7 +939,6 @@ impl<'a> EventCx<'a> {
952939
///
953940
/// Linux has a "primary buffer" with implicit copy on text selection and
954941
/// paste on middle-click. This method does nothing on other platforms.
955-
#[inline]
956942
pub fn set_primary(&mut self, content: String) {
957943
#[cfg(all(wayland_platform, feature = "clipboard"))]
958944
if let Some(cb) = self.window.wayland_clipboard() {

crates/kas-core/src/event/cx/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ pub struct EventState {
209209
// For each: (WindowId of popup, popup descriptor, old nav focus)
210210
popups: SmallVec<[(WindowId, crate::PopupDescriptor, Option<Id>); 16]>,
211211
popup_removed: SmallVec<[(Id, WindowId); 16]>,
212-
time_updates: Vec<(Instant, Id, u64)>,
212+
time_updates: Vec<(Instant, Id, TimerHandle)>,
213213
// Set of messages awaiting sending
214214
send_queue: VecDeque<(Id, Erased)>,
215215
// Set of futures of messages together with id of sending widget

0 commit comments

Comments
 (0)