system settings
git clone https://git.lucas.co/cce-system-interface.git
refactor(pages): sections are placed by PageFlow and drawn once
Every page took a &mut dyn LayoutStrategy (an AdaptiveGrid) and drew each
section twice, once into a measure-only PageContent. cce-ui's PageFlow places a
section before it draws, so the pages take a &mut PageFlow and PageContent's
measure_only mode is gone. All 14 pages pixel-identical before and after in a
scale-2 shadow, live readings aside.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
src/app.rs | 53 ++++------------------------------------------
src/main.rs | 4 ++--
src/pages/accounts.rs | 14 ++++++------
src/pages/audio.rs | 10 ++++-----
src/pages/bluetooth.rs | 6 +++---
src/pages/browser.rs | 4 ++--
src/pages/default_apps.rs | 6 +++---
src/pages/mod.rs | 4 ++--
src/pages/network.rs | 10 ++++-----
src/pages/notifications.rs | 6 +++---
src/pages/packages.rs | 12 +++++------
src/pages/power.rs | 10 ++++-----
src/pages/processes.rs | 20 ++++++++---------
src/pages/services.rs | 6 +++---
src/pages/storage.rs | 6 +++---
src/pages/system_info.rs | 8 +++----
src/pages/timers.rs | 6 +++---
src/renderer.rs | 7 +++---
18 files changed, 73 insertions(+), 119 deletions(-)
diff --git a/src/app.rs b/src/app.rs
index 7e8b215..f5c5ec2 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -226,23 +226,6 @@ pub struct PageContent {
/// over the highlight. The popover layer interleaves on these marks.
pub control_relief_marks: Vec<usize>,
pub clip_stack: Vec<[f32; 4]>,
- pub measure_only: bool,
-}
-
-impl Default for PageContent {
- fn default() -> Self {
- Self {
- rects: Vec::new(),
- texts: Vec::new(),
- buttons: Vec::new(),
- icons: Vec::new(),
- reliefs: Vec::new(),
- control_reliefs: Vec::new(),
- control_relief_marks: Vec::new(),
- clip_stack: Vec::new(),
- measure_only: true,
- }
- }
}
impl PageContent {
@@ -256,7 +239,6 @@ impl PageContent {
control_reliefs: Vec::new(),
control_relief_marks: Vec::new(),
clip_stack: Vec::new(),
- measure_only: false,
}
}
@@ -297,20 +279,17 @@ impl PageContent {
}
pub fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
- if self.measure_only { return; }
if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
self.rects.push((color, cx, cy, cw, ch, 0.0, (true, true, true, true)));
}
}
pub fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
- if self.measure_only { return; }
let cb = self.get_clipped_bounds(None);
self.texts.push((content.to_string(), size, x, y, color, None, cb));
}
pub fn text_with_font(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str) {
- if self.measure_only { return; }
let cb = self.get_clipped_bounds(None);
self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
}
@@ -321,23 +300,20 @@ impl PageContent {
/// Rasterized at twice the rect's longer side for a 2x output.
///
/// `false` when the icon set lacks the glyph, so the caller can say it
- /// in a WORD instead; a measuring pass answers without recording.
+ /// in a WORD instead.
pub fn icon(&mut self, name: &str, x: f32, y: f32, w: f32, h: f32, color: [f32; 4]) -> bool {
let px = (w.max(h) * 2.0).ceil().max(1.0) as u32;
let Some((image, _, _)) = cce_ui::upload_icon_tinted(name, px, cce_ui::icon_tint(color)) else {
return false;
};
- if !self.measure_only {
- let clip = self.clip_stack.last().copied();
- self.icons.push(PageIcon { image, x, y, w, h, alpha: color[3], clip });
- }
+ let clip = self.clip_stack.last().copied();
+ self.icons.push(PageIcon { image, x, y, w, h, alpha: color[3], clip });
true
}
pub fn button(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32,
bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
action: AppAction) {
- if self.measure_only { return; }
let btn = cce_ui::widget::Button::new(x, y, w, h)
.with_label(label)
.with_bg(bg)
@@ -358,7 +334,6 @@ impl PageContent {
pub fn button_icon(&mut self, icon: &str, label: &str, x: f32, y: f32, w: f32, h: f32,
bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
alpha: f32, action: AppAction) {
- if self.measure_only { return; }
let mut btn = cce_ui::widget::Button::new(x, y, w, h)
.with_label(label)
.with_bg(bg)
@@ -382,7 +357,6 @@ impl PageContent {
///
/// [`button`]: PageContent::button
pub fn list_row(&mut self, x: f32, y: f32, w: f32, h: f32, action: AppAction) {
- if self.measure_only { return; }
let btn = cce_ui::widget::Button::new_list_row(x, y, w, h);
let clip = self.clip_stack.last().copied();
self.buttons.push((Owned::new(btn), action, clip));
@@ -395,7 +369,6 @@ impl PageContent {
pub fn button_icon_tinted(&mut self, icon: &str, label: &str, x: f32, y: f32, w: f32, h: f32,
bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
action: AppAction) {
- if self.measure_only { return; }
let mut btn = cce_ui::widget::Button::new(x, y, w, h)
.with_label(label)
.with_bg(bg)
@@ -411,7 +384,6 @@ impl PageContent {
pub fn button_left(&mut self, label: &str, x: f32, y: f32, w: f32, h: f32,
bg: [f32; 4], hover_bg: [f32; 4], label_color: [f32; 4],
action: AppAction) {
- if self.measure_only { return; }
let btn = cce_ui::widget::Button::new(x, y, w, h)
.with_label(label)
.with_bg(bg)
@@ -429,46 +401,39 @@ impl RenderTarget for PageContent {
}
fn rect(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32) {
- if self.measure_only { return; }
if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
self.rects.push((color, cx, cy, cw, ch, 0.0, (true, true, true, true)));
}
}
fn rect_with_radius(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32) {
- if self.measure_only { return; }
if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
self.rects.push((color, cx, cy, cw, ch, radius, (true, true, true, true)));
}
}
fn rect_with_radius_corners(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, corners: (bool, bool, bool, bool)) {
- if self.measure_only { return; }
if let Some((cx, cy, cw, ch)) = self.get_clipped_rect(x, y, w, h) {
self.rects.push((color, cx, cy, cw, ch, radius, corners));
}
}
fn text(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4]) {
- if self.measure_only { return; }
let cb = self.get_clipped_bounds(None);
self.texts.push((content.to_string(), size, x, y, color, None, cb));
}
fn text_with_font(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str) {
- if self.measure_only { return; }
let cb = self.get_clipped_bounds(None);
self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
}
fn text_with_bounds(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], bounds: Option<[f32; 4]>) {
- if self.measure_only { return; }
let cb = self.get_clipped_bounds(bounds);
self.texts.push((content.to_string(), size, x, y, color, None, cb));
}
fn text_with_font_and_bounds(&mut self, content: &str, x: f32, y: f32, size: f32, color: [f32; 4], font: &str, bounds: Option<[f32; 4]>) {
- if self.measure_only { return; }
let cb = self.get_clipped_bounds(bounds);
self.texts.push((content.to_string(), size, x, y, color, Some(font.to_string()), cb));
}
@@ -480,9 +445,6 @@ impl RenderTarget for PageContent {
/// The flat-path bridge offers each Dropdown's flush inset trough here;
/// carve it for real (display_list turns these into inset plates).
fn inset_plate(&mut self, color: [f32; 4], x: f32, y: f32, w: f32, h: f32, radius: f32, depth: f32) {
- if self.measure_only {
- return;
- }
self.control_relief_marks.push(self.rects.len());
self.control_reliefs.push(ControlCarve::Plate { x, y, w, h, radius, depth, color, tint: None });
}
@@ -495,9 +457,6 @@ impl RenderTarget for PageContent {
/// face left level, a well drops the whole interior, a boss raises it.
/// Collapsing them would give this app controls no other relief host has.
fn relief_carve(&mut self, carve: &cce_ui::layout::ReliefCarve) {
- if self.measure_only {
- return;
- }
self.control_relief_marks.push(self.rects.len());
self.control_reliefs.push(ControlCarve::Step(*carve));
}
@@ -508,14 +467,11 @@ impl RenderTarget for PageContent {
if f.focused || !cce_ui::layout::control_relief() {
return false;
}
- if !self.measure_only {
- self.reliefs.push(((f.x, f.y, f.w, f.h), f.tab));
- }
+ self.reliefs.push(((f.x, f.y, f.w, f.h), f.tab));
true
}
fn push_clip_rect(&mut self, x: f32, y: f32, w: f32, h: f32) {
- if self.measure_only { return; }
let clip = if let Some(&parent_clip) = self.clip_stack.last() {
let cx = x.max(parent_clip[0]);
let cy = y.max(parent_clip[1]);
@@ -529,7 +485,6 @@ impl RenderTarget for PageContent {
}
fn pop_clip_rect(&mut self) {
- if self.measure_only { return; }
self.clip_stack.pop();
}
}
diff --git a/src/main.rs b/src/main.rs
index 710d03e..e737c85 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1149,8 +1149,8 @@ fn main() {
// One gap everywhere: the wells fill their grid allocations, so the grid
// gap IS the visual section gap. The sections stand on the root plate,
- // so it is the root rung's sibling gap — `AdaptiveGrid::init` reads the
- // toolkit's grid_gap, hence the set here rather than a constructor arg.
+ // so it is the root rung's sibling gap — `PageFlow::init` reads the
+ // toolkit's grid_gap, hence the set here.
cce_ui::layout::set_grid_gap(cce_ui::layout::root_plate_gap());
let mut initial_page = Page::ALL[0];
diff --git a/src/pages/accounts.rs b/src/pages/accounts.rs
index fc6c055..1fd08c7 100644
--- a/src/pages/accounts.rs
+++ b/src/pages/accounts.rs
@@ -1,6 +1,6 @@
use crate::app::{AppAction, PageContent, SectionContextExt, section_divider, section_kv_row};
use cce_ui::widget::Owned;
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy, RenderTarget};
+use cce_ui::layout::{PageLayoutBuilder, PageFlow, RenderTarget};
use cce_ui::widget::ScrollRegion;
use cce_ui::widget::{TextBox, WidgetHost};
@@ -626,7 +626,7 @@ const LIST_GAP: f32 = 4.0;
/// one-or-two-account host this page usually runs on.
const LIST_MAX_ROWS: usize = 8;
-pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut AccountsState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(1);
@@ -1296,7 +1296,7 @@ impl crate::pages::AppPage for AccountsState {
ch: f32,
_root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn cce_ui::layout::LayoutStrategy,
+ layout: &mut cce_ui::layout::PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, sec_focused, layout, ctx)
@@ -1362,13 +1362,13 @@ impl crate::pages::AppPage for AccountsState {
#[cfg(test)]
mod tests {
use super::*;
- use cce_ui::layout::AdaptiveGrid;
+ use cce_ui::layout::PageFlow;
#[test]
fn test_accounts_page_view() {
let mut state = AccountsState::default_mock();
state.loaded = true;
- let mut layout = AdaptiveGrid::new(260.0, 20.0);
+ let mut layout = PageFlow::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false], &mut layout, &mut cce_ui::context::UiContext::new());
println!("PC BUTTONS COUNT: {}", pc.buttons.len());
for (i, (btn, _, _)) in pc.buttons.iter().enumerate() {
@@ -1392,7 +1392,7 @@ mod tests {
let mut state = AccountsState::default_mock();
state.loaded = true;
state.accounts = (0..12).map(|i| acct(&format!("a{i}@example.org"), false)).collect();
- let mut layout = AdaptiveGrid::new(260.0, 20.0);
+ let mut layout = PageFlow::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false], &mut layout, &mut cce_ui::context::UiContext::new());
let list_bottom = state.list.y + state.list.h;
@@ -1418,7 +1418,7 @@ mod tests {
let mut state = AccountsState::default_mock();
state.loaded = true;
state.accounts = (0..40).map(|i| acct(&format!("a{i}@example.org"), false)).collect();
- let mut layout = AdaptiveGrid::new(260.0, 20.0);
+ let mut layout = PageFlow::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false], &mut layout, &mut cce_ui::context::UiContext::new());
let rows = pc
diff --git a/src/pages/audio.rs b/src/pages/audio.rs
index 4f0978b..f77b826 100644
--- a/src/pages/audio.rs
+++ b/src/pages/audio.rs
@@ -1,6 +1,6 @@
use crate::app::{AppAction, PageContent, SectionContextExt, section_divider};
use cce_ui::widget::Owned;
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, PageFlow};
use cce_ui::widget::{Spinbox, Slider, WidgetHost};
#[derive(Debug, Clone)]
@@ -294,7 +294,7 @@ fn device_row(
});
}
-pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut AudioState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(1);
@@ -427,7 +427,7 @@ impl crate::pages::AppPage for AudioState {
ch: f32,
_root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn cce_ui::layout::LayoutStrategy,
+ layout: &mut cce_ui::layout::PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, sec_focused, layout, ctx)
@@ -476,7 +476,7 @@ impl crate::pages::AppPage for AudioState {
#[cfg(test)]
mod tests {
use super::*;
- use cce_ui::layout::AdaptiveGrid;
+ use cce_ui::layout::PageFlow;
#[test]
fn test_view_layout_grid() {
@@ -505,7 +505,7 @@ mod tests {
],
source_sliders: vec![],
};
- let mut layout = AdaptiveGrid::new(260.0, 20.0);
+ let mut layout = PageFlow::new();
// One flag: section_widgets() returns a single group (the output ids
// with input appended), so the view draws one section and reads [0].
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false], &mut layout, &mut cce_ui::context::UiContext::new());
diff --git a/src/pages/bluetooth.rs b/src/pages/bluetooth.rs
index 0c6254c..f3609ad 100644
--- a/src/pages/bluetooth.rs
+++ b/src/pages/bluetooth.rs
@@ -1,6 +1,6 @@
use crate::app::{AppAction, PageContent, SectionContextExt};
use cce_ui::widget::Owned;
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, PageFlow};
use cce_ui::widget::{Adapted, Toggle};
#[derive(Debug, Clone)]
@@ -153,7 +153,7 @@ fn bt_scan() {
.spawn();
}
-pub fn view(state: &mut BluetoothState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut BluetoothState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(1);
@@ -326,7 +326,7 @@ impl crate::pages::AppPage for BluetoothState {
ch: f32,
_root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, sec_focused, layout, ctx)
diff --git a/src/pages/browser.rs b/src/pages/browser.rs
index e9659b6..a8f957a 100644
--- a/src/pages/browser.rs
+++ b/src/pages/browser.rs
@@ -8,7 +8,7 @@
use std::fs;
use cce_ui::widget::Owned;
-use cce_ui::layout::{LayoutStrategy, PageLayoutBuilder};
+use cce_ui::layout::{PageFlow, PageLayoutBuilder};
use cce_ui::widget::input::{Dropdown, Toggle};
use cce_ui::widget::{TextBox, WidgetHost};
@@ -274,7 +274,7 @@ impl AppPage for BrowserState {
ch: f32,
_root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> PageContent {
let mut final_pc = PageContent::new();
diff --git a/src/pages/default_apps.rs b/src/pages/default_apps.rs
index 025aedc..139975f 100644
--- a/src/pages/default_apps.rs
+++ b/src/pages/default_apps.rs
@@ -12,7 +12,7 @@
use crate::app::{AppAction, PageContent};
use cce_ui::widget::Owned;
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{PageLayoutBuilder, PageFlow};
use cce_ui::widget::{Dropdown, WidgetHost};
use std::collections::HashMap;
use std::path::PathBuf;
@@ -124,7 +124,7 @@ fn rebuild_entry_options(entry: &mut CategoryEntry) {
entry.option_ids = ids;
}
-pub fn view(state: &mut DefaultAppsState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut DefaultAppsState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(1);
@@ -441,7 +441,7 @@ impl crate::pages::AppPage for DefaultAppsState {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, root_focused, sec_focused, layout, ctx)
diff --git a/src/pages/mod.rs b/src/pages/mod.rs
index 95ce087..5ca353c 100644
--- a/src/pages/mod.rs
+++ b/src/pages/mod.rs
@@ -93,7 +93,7 @@ pub trait AppPage {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn cce_ui::layout::LayoutStrategy,
+ layout: &mut cce_ui::layout::PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent;
@@ -172,7 +172,7 @@ mod list_clip_tests {
use cce_ui::widget::ScrollRegion;
fn render(page: &mut dyn AppPage) -> crate::app::PageContent {
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let mut ctx = cce_ui::context::UiContext::new();
page.view(10.0, 20.0, 820.0, 640.0, false, &[false; 4], &mut layout, &mut ctx)
}
diff --git a/src/pages/network.rs b/src/pages/network.rs
index f1df89d..9535080 100644
--- a/src/pages/network.rs
+++ b/src/pages/network.rs
@@ -1,7 +1,7 @@
use crate::app::{AppAction, PageContent};
use cce_ui::widget::Owned;
use cce_ui::widget::ScrollRegion;
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy, RenderTarget};
+use cce_ui::layout::{PageLayoutBuilder, PageFlow, RenderTarget};
use cce_ui::widget::{Adapted, Toggle};
#[derive(Debug, Clone)]
@@ -162,7 +162,7 @@ const BTN_HOVER: [f32; 4] = [0.25, 0.30, 0.26, 1.0];
const NET_BTN: [f32; 4] = [0.13, 0.20, 0.27, 1.0];
const ACT_BTN: [f32; 4] = [0.16, 0.29, 0.18, 1.0];
-pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut NetworkState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(1);
@@ -314,7 +314,7 @@ impl crate::pages::AppPage for NetworkState {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
// Page root dissolved (6u): the ctrl-nav entry focuses section 0 now, which used to
@@ -369,7 +369,7 @@ mod tests {
let mut state = NetworkState::default();
state.loaded = true;
state.wifi_enabled = true;
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &mut layout, &mut cce_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty() || !pc.buttons.is_empty());
}
@@ -382,7 +382,7 @@ mod tests {
state.connected_ssid = "MyHomeWiFi".to_string();
state.signal_strength = 80;
state.ip_address = "192.168.1.50".to_string();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &mut layout, &mut cce_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty() || !pc.buttons.is_empty());
}
diff --git a/src/pages/notifications.rs b/src/pages/notifications.rs
index f00e1df..302a95d 100644
--- a/src/pages/notifications.rs
+++ b/src/pages/notifications.rs
@@ -3,7 +3,7 @@ use std::io::Write;
use cce_ui::widget::Owned;
use cce_ui::widget::input::{Toggle, Dropdown, Spinbox};
use cce_ui::widget::WidgetHost;
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{PageLayoutBuilder, PageFlow};
use crate::app::{AppAction, PageContent, SectionContextExt};
use crate::pages::AppPage;
@@ -205,7 +205,7 @@ impl AppPage for NotificationsState {
ch: f32,
_root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> PageContent {
let mut final_pc = PageContent::new();
@@ -284,7 +284,7 @@ pub(crate) mod tests {
#[test]
fn test_view_layout_grid() {
let mut state = NotificationsState::default();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false];
let mut ctx = cce_ui::context::UiContext::new();
let pc = state.view(10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
diff --git a/src/pages/packages.rs b/src/pages/packages.rs
index 6fccf4d..b61594b 100644
--- a/src/pages/packages.rs
+++ b/src/pages/packages.rs
@@ -1,7 +1,7 @@
use crate::app::{AppAction, PageContent, SectionContextExt, section_divider};
use cce_ui::widget::Owned;
use cce_ui::widget::ScrollRegion;
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, SectionContext, RenderTarget};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, PageFlow, SectionContext, RenderTarget};
use cce_ui::widget::{WidgetHost, TextBox, InteractiveListItem};
#[derive(Debug, Clone, Default)]
@@ -531,7 +531,7 @@ pub fn view(
cw: f32,
ch: f32,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> PageContent {
let m = crate::app::section_margin();
@@ -1251,7 +1251,7 @@ impl crate::pages::AppPage for PackagesState {
ch: f32,
_root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, sec_focused, layout, ctx)
@@ -1444,7 +1444,7 @@ mod tests {
fn row_click_resolves_through_the_filter() {
let mut st = loaded_state();
update(&mut st, PackagesMessage::SetFilter(InstalledFilter::Orphans));
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let mut ctx = cce_ui::context::UiContext::new();
view(&mut st, 10.0, 20.0, 800.0, 600.0, &[false], &mut layout, &mut ctx);
assert_eq!(st.installed_items.len(), 2);
@@ -1499,7 +1499,7 @@ mod tests {
assert!(st.previewing);
update(&mut st, PackagesMessage::RemovalPreviewed(vec!["beta".into()], Err(err.clone())));
assert!(!st.previewing);
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let pc = view(&mut st, 10.0, 20.0, 800.0, 600.0, &[false], &mut layout, &mut cce_ui::context::UiContext::new());
let texts: Vec<String> = pc.texts.iter().map(|t| t.0.clone()).collect();
assert!(texts.iter().any(|t| t.contains("required by alpha")), "the reason is painted: {texts:?}");
@@ -1579,7 +1579,7 @@ mod tests {
#[test]
fn test_view_layout_grid() {
let mut state = PackagesState::default();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, &[false, false], &mut layout, &mut cce_ui::context::UiContext::new());
assert!(!pc.rects.is_empty() || !pc.texts.is_empty() || !pc.buttons.is_empty());
}
diff --git a/src/pages/power.rs b/src/pages/power.rs
index 3d38c3b..262ee3a 100644
--- a/src/pages/power.rs
+++ b/src/pages/power.rs
@@ -45,7 +45,7 @@
use crate::app::{AppAction, PageContent};
use crate::power_plan::{self, Automation, ChargeLimit, Lever, Mode, PowerPlan, Source};
use cce_ui::widget::Owned;
-use cce_ui::layout::{LayoutStrategy, PageLayoutBuilder};
+use cce_ui::layout::{PageFlow, PageLayoutBuilder};
use cce_ui::widget::{Adapted, Dropdown, WidgetHost};
use std::path::{Path, PathBuf};
@@ -728,7 +728,7 @@ fn when_text(source: Source) -> &'static str {
Source::Battery => "unplugged",
}
}
-pub fn view(state: &mut PowerState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut PowerState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let focused = |i: usize| sec_focused.get(i).copied().unwrap_or(false);
@@ -1046,7 +1046,7 @@ impl crate::pages::AppPage for PowerState {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, root_focused, sec_focused, layout, ctx)
@@ -1419,7 +1419,7 @@ mod tests {
fn the_three_sections_paint_and_the_assignment_one_drops_on_a_desktop() {
let mut ctx = cce_ui::context::UiContext::new();
let mut paint = |st: &mut PowerState, sections: usize| {
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false; sections];
let pc = st.view(10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
assert!(!pc.rects.is_empty() || !pc.texts.is_empty());
@@ -1439,7 +1439,7 @@ mod tests {
fn a_stale_root_helper_is_named_on_the_page() {
let mut ctx = cce_ui::context::UiContext::new();
let mut lines = |st: &mut PowerState| -> Vec<String> {
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false; 3];
let pc = st.view(10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
pc.texts.iter().map(|t| t.0.clone()).collect()
diff --git a/src/pages/processes.rs b/src/pages/processes.rs
index 337523f..898d468 100644
--- a/src/pages/processes.rs
+++ b/src/pages/processes.rs
@@ -1,7 +1,7 @@
use crate::app::{AppAction, PageContent};
use crate::power_meter::{self, Meter, Mode};
use cce_ui::widget::ScrollRegion;
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy, RenderTarget};
+use cce_ui::layout::{PageLayoutBuilder, PageFlow, RenderTarget};
use std::sync::Mutex;
#[derive(Debug, Clone)]
@@ -246,7 +246,7 @@ pub async fn fetch_processes_state() -> ProcessesState {
const TEXT_FG: [f32; 4] = [0.83, 0.83, 0.83, 1.0];
const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
-pub fn view(state: &mut ProcessesState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, _ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut ProcessesState, cx: f32, cy: f32, cw: f32, ch: f32, root_focused: bool, sec_focused: &[bool], layout: &mut PageFlow, _ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(1);
@@ -482,7 +482,7 @@ impl crate::pages::AppPage for ProcessesState {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, root_focused, sec_focused, layout, ctx)
@@ -532,7 +532,7 @@ mod tests {
#[test]
fn test_view_layout_grid() {
let mut state = ProcessesState::default();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false];
let mut ctx = cce_ui::context::UiContext::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
@@ -571,7 +571,7 @@ mod tests {
let mut state = ProcessesState { loaded: true, ..Default::default() };
state.processes = (1..=3).map(|i| row(&i.to_string())).collect();
state.killing.insert("2".to_string());
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false];
let mut ctx = cce_ui::context::UiContext::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
@@ -678,7 +678,7 @@ mod tests {
fn header_sort_buttons_emitted() {
let mut state = ProcessesState { loaded: true, ..Default::default() };
state.processes = vec![sized_row("1", "1.0", 1)];
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false];
let mut ctx = cce_ui::context::UiContext::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
@@ -707,7 +707,7 @@ mod tests {
fn columns_pan_with_horizontal_scroll() {
let mut state = ProcessesState { loaded: true, ..Default::default() };
state.processes = (0..3).map(|i| row(&i.to_string())).collect();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false];
let mut ctx = cce_ui::context::UiContext::new();
@@ -750,7 +750,7 @@ mod tests {
// letter and every row's hover wash its left edge.
let mut state = ProcessesState { loaded: true, ..Default::default() };
state.processes = (0..40).map(|i| row(&i.to_string())).collect();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let mut ctx = cce_ui::context::UiContext::new();
let pc = view(&mut state, 10.0, 20.0, 820.0, 640.0, false, &[false], &mut layout, &mut ctx);
for t in &pc.texts {
@@ -772,7 +772,7 @@ mod tests {
// stood alone in the reserve band under the last row.
let mut state = ProcessesState { loaded: true, ..Default::default() };
state.processes = (0..40).map(|i| row(&i.to_string())).collect();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let mut ctx = cce_ui::context::UiContext::new();
let pc = view(&mut state, 10.0, 20.0, 820.0, 640.0, false, &[false], &mut layout, &mut ctx);
let rows_bottom = state.cpu_list.viewport_y + state.cpu_list.viewport_h;
@@ -821,7 +821,7 @@ mod tests {
};
update(&mut state, ProcessesMessage::Refreshed(fresh));
assert_eq!(state.power.mode, Mode::Battery);
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let mut ctx = cce_ui::context::UiContext::new();
let pc = view(&mut state, 10.0, 20.0, 900.0, 600.0, false, &[false], &mut layout, &mut ctx);
let all: Vec<&str> = pc.texts.iter().map(|t| t.0.as_str()).collect();
diff --git a/src/pages/services.rs b/src/pages/services.rs
index 568014e..15abe59 100644
--- a/src/pages/services.rs
+++ b/src/pages/services.rs
@@ -1,7 +1,7 @@
use crate::app::{PageContent, SectionContextExt};
use cce_ui::widget::Owned;
use cce_ui::widget::ScrollRegion;
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, RenderTarget};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, PageFlow, RenderTarget};
use cce_ui::widget::{TextBox, InteractiveListItem, WidgetHost};
#[derive(Debug, Clone)]
@@ -59,7 +59,7 @@ pub enum ServicesMessage {
const TEXT_DIM: [f32; 4] = [0.53, 0.53, 0.60, 1.0];
-pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut ServicesState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let m = crate::app::section_margin();
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
@@ -471,7 +471,7 @@ impl crate::pages::AppPage for ServicesState {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, root_focused, sec_focused, layout, ctx)
diff --git a/src/pages/storage.rs b/src/pages/storage.rs
index b3505f1..c82b735 100644
--- a/src/pages/storage.rs
+++ b/src/pages/storage.rs
@@ -1,6 +1,6 @@
use crate::app::{AppAction, PageContent};
use cce_ui::widget::Owned;
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, PageFlow};
use std::fs;
/// What the background poll produces — the fetched numbers only, never the
@@ -224,7 +224,7 @@ const BTN_HOVER: [f32; 4] = [0.28, 0.50, 0.78, 1.0];
const BTN_DISABLED: [f32; 4] = [0.15, 0.18, 0.22, 1.0];
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
-pub fn view(state: &mut StorageState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut StorageState, cx: f32, cy: f32, cw: f32, ch: f32, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
let mut builder = PageLayoutBuilder::new(layout, cx, cy, cw, ch, sec_w).with_section_count(3);
@@ -401,7 +401,7 @@ impl crate::pages::AppPage for StorageState {
ch: f32,
_root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, sec_focused, layout, ctx)
diff --git a/src/pages/system_info.rs b/src/pages/system_info.rs
index ee666c5..40a4dac 100644
--- a/src/pages/system_info.rs
+++ b/src/pages/system_info.rs
@@ -1,6 +1,6 @@
use crate::app::{AppAction, PageContent, SectionContextExt};
use cce_ui::widget::Owned;
-use cce_ui::layout::{PageLayoutBuilder, LayoutStrategy};
+use cce_ui::layout::{PageLayoutBuilder, PageFlow};
use cce_ui::widget::{Label, WidgetHost, Button};
@@ -558,7 +558,7 @@ const DANGER_BG: [f32; 4] = [0.67, 0.20, 0.20, 1.0];
const SAFE_BG: [f32; 4] = [0.20, 0.33, 0.22, 1.0];
const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0];
-pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, _ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut SystemState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut PageFlow, _ctx: &mut cce_ui::context::UiContext) -> PageContent {
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
// Six, matching the add_section calls below and the six groups
@@ -889,7 +889,7 @@ impl crate::pages::AppPage for SystemState {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
// Phase 6u: System used to render through the WIDGET TREE (the only page that
@@ -955,7 +955,7 @@ mod tests {
#[test]
fn test_view_layout_grid() {
let mut state = SystemState::default();
- let mut layout = cce_ui::layout::ColumnLayout::new(20.0);
+ let mut layout = cce_ui::layout::PageFlow::new();
let sec_focused = vec![false, false, false, false, false, false, false];
let mut ctx = cce_ui::context::UiContext::new();
let pc = view(&mut state, 10.0, 20.0, 800.0, 600.0, false, &sec_focused, &mut layout, &mut ctx);
diff --git a/src/pages/timers.rs b/src/pages/timers.rs
index f8c884c..fc3b665 100644
--- a/src/pages/timers.rs
+++ b/src/pages/timers.rs
@@ -5,7 +5,7 @@
use crate::app::{PageContent, SectionContextExt};
use cce_ui::widget::Owned;
use cce_ui::widget::ScrollRegion;
-use cce_ui::layout::{render_widget, PageLayoutBuilder, LayoutStrategy, RenderTarget};
+use cce_ui::layout::{render_widget, PageLayoutBuilder, PageFlow, RenderTarget};
use cce_ui::widget::{StatusDot, DotStatus, InteractiveListItem, TextBox, WidgetHost};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -401,7 +401,7 @@ fn button_glyph(pc: &mut PageContent, compact: bool, icon: &str, word: &str, x:
}
}
-pub fn view(state: &mut TimersState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut dyn LayoutStrategy, ctx: &mut cce_ui::context::UiContext) -> PageContent {
+pub fn view(state: &mut TimersState, cx: f32, cy: f32, cw: f32, ch: f32, _root_focused: bool, sec_focused: &[bool], layout: &mut PageFlow, ctx: &mut cce_ui::context::UiContext) -> PageContent {
let m = crate::app::section_margin();
let mut final_pc = PageContent::new();
let sec_w = 320.0f32;
@@ -789,7 +789,7 @@ impl crate::pages::AppPage for TimersState {
ch: f32,
root_focused: bool,
sec_focused: &[bool],
- layout: &mut dyn LayoutStrategy,
+ layout: &mut PageFlow,
ctx: &mut cce_ui::context::UiContext,
) -> crate::app::PageContent {
view(self, cx, cy, cw, ch, root_focused, sec_focused, layout, ctx)
diff --git a/src/renderer.rs b/src/renderer.rs
index f619710..d3c4973 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -826,12 +826,11 @@ impl SystemInterface {
}
pub(crate) fn render_page_content(&mut self, cx: f32, cy: f32, cw: f32, ch: f32) -> PageContent {
- use cce_ui::layout::AdaptiveGrid;
+ use cce_ui::layout::PageFlow;
// The sections are wells carved straight into the root plate (no
// sidebar, no pane between), so the page's edge is the window's edge:
// the root rung's inset, and the grid's gap the root rung's gap (set
- // once in main; `AdaptiveGrid::init` reads the toolkit getters, the
- // constructor args are the same numbers stated for the record).
+ // once in main; `PageFlow::init` reads the toolkit's grid getters).
let margin = cce_ui::layout::root_plate_inset();
let cx = cx + margin;
let cy = cy + margin;
@@ -839,7 +838,7 @@ impl SystemInterface {
// over the sections, behind the root plate until a scroll raises it.
let cw = (cw - 2.0 * margin).max(1.0);
let ch = (ch - 2.0 * margin).max(1.0);
- let mut layout = AdaptiveGrid::new(cce_ui::layout::grid_min_col_width(), cce_ui::layout::root_plate_gap());
+ let mut layout = PageFlow::new();
// Page root dissolved (6u): the ctrl-nav entry focuses section 0, so root focus is
// permanently false; views that highlighted on it OR in their first section's bool.
// Section focus is the app-side index now (Phase 6w).