diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 65fcf02c3..15c1f0b8c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -71,7 +71,7 @@ jobs: toolchain: [stable] include: - os: ubuntu-latest - toolchain: "1.67.0" + toolchain: "1.75.0" - os: ubuntu-latest toolchain: beta diff --git a/Cargo.toml b/Cargo.toml index 83d50e1f3..4b513e5e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["gui"] categories = ["gui"] repository = "https://github.com/kas-gui/kas" exclude = ["/examples"] -rust-version = "1.66.0" +rust-version = "1.75.0" [package.metadata.docs.rs] features = ["stable"] diff --git a/README.md b/README.md index a06ab340f..8c607fe45 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ KAS GUI [![Crates.io](https://img.shields.io/crates/v/kas.svg)](https://crates.io/crates/kas) [![kas-text](https://img.shields.io/badge/GitHub-kas--text-blueviolet)](https://github.com/kas-gui/kas-text/) [![Docs](https://docs.rs/kas/badge.svg)](https://docs.rs/kas) -![Minimum rustc version](https://img.shields.io/badge/rustc-1.66+-lightgray.svg) +![Minimum rustc version](https://img.shields.io/badge/rustc-1.75+-lightgray.svg) KAS is a stateful, pure-Rust GUI toolkit supporting: diff --git a/crates/kas-view/src/data_impls.rs b/crates/kas-view/src/data_impls.rs index f3451af3a..84068edf5 100644 --- a/crates/kas-view/src/data_impls.rs +++ b/crates/kas-view/src/data_impls.rs @@ -26,8 +26,6 @@ macro_rules! impl_list_data { } } impl ListData for $ty { - type KeyIter<'b> = std::ops::Range; - fn is_empty(&self) -> bool { (*self).is_empty() } @@ -36,7 +34,7 @@ macro_rules! impl_list_data { (*self).len() } - fn iter_from(&self, start: usize, limit: usize) -> Self::KeyIter<'_> { + fn iter_from(&self, start: usize, limit: usize) -> impl Iterator { let len = (*self).len(); start.min(len)..(start + limit).min(len) } diff --git a/crates/kas-view/src/data_traits.rs b/crates/kas-view/src/data_traits.rs index 0863e6e4e..4fb88bf95 100644 --- a/crates/kas-view/src/data_traits.rs +++ b/crates/kas-view/src/data_traits.rs @@ -138,10 +138,6 @@ pub trait SharedData: Debug { #[allow(clippy::len_without_is_empty)] #[autoimpl(for &T, &mut T, std::rc::Rc, std::sync::Arc, Box)] pub trait ListData: SharedData { - type KeyIter<'b>: Iterator - where - Self: 'b; - /// No data is available fn is_empty(&self) -> bool { self.len() == 0 @@ -156,15 +152,13 @@ pub trait ListData: SharedData { /// /// An example where `type Key = usize`: /// ```ignore - /// type KeyIter<'b> = std::ops::Range; - /// - /// fn iter_from(&self, start: usize, limit: usize) -> Self::KeyIter<'_> { + /// fn iter_from(&self, start: usize, limit: usize) -> impl Iterator { /// start.min(self.len)..(start + limit).min(self.len) /// } /// ``` /// /// This method is called on every update so should be reasonably fast. - fn iter_from(&self, start: usize, limit: usize) -> Self::KeyIter<'_>; + fn iter_from(&self, start: usize, limit: usize) -> impl Iterator; } /// Trait for viewable data matrices @@ -177,13 +171,6 @@ pub trait MatrixData: SharedData { /// Row key type type RowKey; - type ColKeyIter<'b>: Iterator - where - Self: 'b; - type RowKeyIter<'b>: Iterator - where - Self: 'b; - /// No data is available fn is_empty(&self) -> bool; @@ -192,35 +179,19 @@ pub trait MatrixData: SharedData { /// Note: users may assume this is `O(1)`. fn len(&self) -> (usize, usize); - /// Iterate over column keys + /// Iterate over up to `limit` column keys from `start` /// /// The result will be in deterministic implementation-defined order, with - /// a length of `max(limit, data_len)` where `data_len` is the number of + /// a length of `max(limit, data_len - start)` where `data_len` is the number of /// items available. - #[inline] - fn col_iter_limit(&self, limit: usize) -> Self::ColKeyIter<'_> { - self.col_iter_from(0, limit) - } - - /// Iterate over column keys from an arbitrary start-point - /// - /// The result is the same as `self.iter_limit(start + limit).skip(start)`. - fn col_iter_from(&self, start: usize, limit: usize) -> Self::ColKeyIter<'_>; + fn col_iter_from(&self, start: usize, limit: usize) -> impl Iterator; - /// Iterate over row keys + /// Iterate over up to `limit` row keys from `start` /// /// The result will be in deterministic implementation-defined order, with - /// a length of `max(limit, data_len)` where `data_len` is the number of + /// a length of `max(limit, data_len - start)` where `data_len` is the number of /// items available. - #[inline] - fn row_iter_limit(&self, limit: usize) -> Self::RowKeyIter<'_> { - self.row_iter_from(0, limit) - } - - /// Iterate over row keys from an arbitrary start-point - /// - /// The result is the same as `self.iter_limit(start + limit).skip(start)`. - fn row_iter_from(&self, start: usize, limit: usize) -> Self::RowKeyIter<'_>; + fn row_iter_from(&self, start: usize, limit: usize) -> impl Iterator; /// Make a key from parts fn make_key(&self, col: &Self::ColKey, row: &Self::RowKey) -> Self::Key; diff --git a/crates/kas-view/src/filter/filter_list.rs b/crates/kas-view/src/filter/filter_list.rs index b215aa326..9714ff472 100644 --- a/crates/kas-view/src/filter/filter_list.rs +++ b/crates/kas-view/src/filter/filter_list.rs @@ -222,9 +222,6 @@ impl_scope! { } impl ListData for Self { - type KeyIter<'b> = KeyIter<'b, A::Key> - where Self: 'b; - fn is_empty(&self) -> bool { self.view.is_empty() } @@ -232,7 +229,7 @@ impl_scope! { self.view.len() } - fn iter_from(&self, start: usize, limit: usize) -> Self::KeyIter<'_> { + fn iter_from(&self, start: usize, limit: usize) -> impl Iterator { let end = self.len().min(start + limit); KeyIter { list: &self.view[start..end], index: 0 } } diff --git a/crates/kas-view/src/list_view.rs b/crates/kas-view/src/list_view.rs index 12d33f63e..8d43b42fd 100644 --- a/crates/kas-view/src/list_view.rs +++ b/crates/kas-view/src/list_view.rs @@ -113,6 +113,10 @@ impl_scope! { impl> ListView { /// Set the direction of contents pub fn set_direction(&mut self, direction: Direction) -> Action { + if direction == self.direction { + return Action::empty(); + } + self.direction = direction; Action::SET_RECT } diff --git a/crates/kas-widgets/src/edit.rs b/crates/kas-widgets/src/edit.rs index bacc33fb0..ee0b276b8 100644 --- a/crates/kas-widgets/src/edit.rs +++ b/crates/kas-widgets/src/edit.rs @@ -920,8 +920,11 @@ impl_scope! { self.selection.set_max_len(len); if self.text.try_prepare().is_ok() { self.text_size = Vec2::from(self.text.bounding_box().unwrap().1).cast_ceil(); - self.view_offset = self.view_offset.min(self.max_scroll_offset()); - action = Action::SCROLLED; + let view_offset = self.view_offset.min(self.max_scroll_offset()); + if view_offset != self.view_offset { + action = Action::SCROLLED; + self.view_offset = view_offset; + } } action | self.set_error_state(false) } diff --git a/crates/kas-widgets/src/tab_stack.rs b/crates/kas-widgets/src/tab_stack.rs index ae53328d9..85b44be55 100644 --- a/crates/kas-widgets/src/tab_stack.rs +++ b/crates/kas-widgets/src/tab_stack.rs @@ -147,6 +147,10 @@ impl_scope! { /// /// Default value: [`Direction::Up`] pub fn set_direction(&mut self, direction: Direction) -> Action { + if direction == self.direction { + return Action::empty(); + } + self.direction = direction; // Note: most of the time SET_RECT would be enough, but margins can be different Action::RESIZE diff --git a/examples/data-list-view.rs b/examples/data-list-view.rs index 1a2a3002b..8d5959d45 100644 --- a/examples/data-list-view.rs +++ b/examples/data-list-view.rs @@ -141,27 +141,6 @@ impl_scope! { } } -// Once RPITIT is stable we can replace this with range + map -struct KeyIter { - start: usize, - end: usize, -} -impl Iterator for KeyIter { - type Item = usize; - fn next(&mut self) -> Option { - let mut item = None; - if self.start < self.end { - item = Some(self.start); - self.start += 1; - } - item - } - fn size_hint(&self) -> (usize, Option) { - let len = self.end.saturating_sub(self.start); - (len, Some(len)) - } -} - impl SharedData for Data { type Key = usize; type Item = Item; @@ -175,17 +154,14 @@ impl SharedData for Data { } } impl ListData for Data { - type KeyIter<'b> = KeyIter; - fn len(&self) -> usize { self.len } - fn iter_from(&self, start: usize, limit: usize) -> Self::KeyIter<'_> { - KeyIter { - start: start.min(self.len), - end: (start + limit).min(self.len), - } + fn iter_from(&self, start: usize, limit: usize) -> impl Iterator { + let start = start.min(self.len); + let end = (start + limit).min(self.len); + (start..end).into_iter() } } diff --git a/examples/times-tables.rs b/examples/times-tables.rs index a8d938d6b..0096749fe 100644 --- a/examples/times-tables.rs +++ b/examples/times-tables.rs @@ -22,9 +22,6 @@ impl MatrixData for TableSize { type ColKey = usize; type RowKey = usize; - type ColKeyIter<'b> = std::ops::Range; - type RowKeyIter<'b> = std::ops::Range; - fn is_empty(&self) -> bool { self.0 == 0 }