layout: adaptive grid and vertical flex; enforce the mechanical style rules
grid_min_cell( width ) adds the adaptive mode WrapGrid was missing: instead of a fixed column count, the count is derived at layout time from the available width so every cell is at least `width` wide (any Length, so a fluid threshold works; never fewer than one column), re-derived on every resize. Cells then share the width equally, and WrapGrid::max_columns( n ) caps the derived count so cells grow instead of multiplying on very wide surfaces — the cap only applies to the adaptive mode, grid( n ) keeps the fixed behaviour untouched. Four new layout tests cover width derivation, spacing accounting, the one-column floor and the cap; the row-wrap assertions check X positions rather than Y because zero-height spacer children produce zero-height rows. flex( child ) now distributes leftover height inside a Column, mirroring its leftover-width behaviour in a Row: flex children join the weight pool alongside weight-only spacers and y-scrolls, draw their child inside the allocated share at full inner width, and contribute zero to the column's natural height exactly like a row counts flex width. This closes the documented "vertical flex is not yet implemented" gap; the Flex rustdoc and the widgets.md entry now describe both axes. Add scripts/style-check.sh and a make stylecheck target, wired into CI: mechanical verification of the grep-checkable subset of code_style_guide.md — tab indentation and spaces inside attribute brackets — with comment lines skipped so prose may cite raw attribute syntax. To turn the check on green, the 82 unspaced attribute sites across 24 files (#[test], #[derive(...)], #[cfg(...)], #[allow(...)]) were normalized to the spaced form. CONTRIBUTING and the style guide reference the new target; brace placement and paren spacing remain review concerns.
This commit is contained in:
@@ -26,7 +26,7 @@ use crate::render::Canvas;
|
||||
use crate::types::{ Rect, WidgetId };
|
||||
use crate::widget::Element;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
pub struct Carousel<Msg: Clone>
|
||||
|
||||
@@ -17,7 +17,7 @@ fn three_spacer_carousel() -> Carousel<()>
|
||||
.push( spacer() )
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn empty_layout_is_empty()
|
||||
{
|
||||
let c: Carousel<()> = carousel();
|
||||
@@ -25,7 +25,7 @@ fn empty_layout_is_empty()
|
||||
assert!( c.layout( rect, &canvas() ).is_empty() );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn first_child_centred_at_offset_zero()
|
||||
{
|
||||
let c = three_spacer_carousel();
|
||||
@@ -36,7 +36,7 @@ fn first_child_centred_at_offset_zero()
|
||||
assert!( ( rects[0].0.width - 80.0 ).abs() < 0.01 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn children_strided_by_child_width_plus_gap()
|
||||
{
|
||||
let c = carousel::<()>()
|
||||
@@ -50,7 +50,7 @@ fn children_strided_by_child_width_plus_gap()
|
||||
assert!( ( rects[1].0.x - ( rects[0].0.x + 108.0 ) ).abs() < 0.01 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn snap_offset_centres_target_index()
|
||||
{
|
||||
let c = three_spacer_carousel();
|
||||
@@ -58,7 +58,7 @@ fn snap_offset_centres_target_index()
|
||||
assert!( ( c.snap_offset( 100.0, 2 ) - ( -160.0 ) ).abs() < 0.01 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn focused_index_rounds_to_nearest_tile()
|
||||
{
|
||||
let mut c = three_spacer_carousel();
|
||||
@@ -68,7 +68,7 @@ fn focused_index_rounds_to_nearest_tile()
|
||||
assert_eq!( c.focused_index( 100.0 ), 1 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn focused_index_clamps_to_valid_range()
|
||||
{
|
||||
let mut c = three_spacer_carousel();
|
||||
@@ -78,7 +78,7 @@ fn focused_index_clamps_to_valid_range()
|
||||
assert_eq!( c.focused_index( 100.0 ), 2 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn offset_shifts_all_children_horizontally()
|
||||
{
|
||||
let c = three_spacer_carousel().offset( -25.0 );
|
||||
@@ -90,7 +90,7 @@ fn offset_shifts_all_children_horizontally()
|
||||
assert!( ( rects[1].0.x - rects[0].0.x - 80.0 ).abs() < 0.01 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn focused_width_frac_is_clamped_to_unit_range()
|
||||
{
|
||||
let c: Carousel<()> = carousel().focused_width_frac( 5.0 ).push( spacer() );
|
||||
@@ -99,7 +99,7 @@ fn focused_width_frac_is_clamped_to_unit_range()
|
||||
assert!( c2.focused_width_frac > 0.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn children_use_full_rect_height()
|
||||
{
|
||||
let c = three_spacer_carousel();
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::Element;
|
||||
|
||||
mod theme;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
/// A two-state opt-in control with a square box and a check glyph.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn checkbox_default_state()
|
||||
{
|
||||
let c = checkbox::<()>( true );
|
||||
@@ -11,7 +11,7 @@ fn checkbox_default_state()
|
||||
assert!( c.on_toggle.is_none() );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn checkbox_unchecked()
|
||||
{
|
||||
let c = checkbox::<()>( false );
|
||||
|
||||
@@ -4,16 +4,19 @@
|
||||
use crate::render::Canvas;
|
||||
use super::Element;
|
||||
|
||||
/// Wraps an [`Element`] so that a [`Row`](crate::layout::row::Row) treats it
|
||||
/// like a [`Spacer`](crate::layout::spacer::Spacer) for leftover-width
|
||||
/// distribution, but draws the child inside the allocated rect.
|
||||
/// Wraps an [`Element`] so its parent treats it like a
|
||||
/// [`Spacer`](crate::layout::spacer::Spacer) for leftover-space
|
||||
/// distribution, but draws the child inside the allocated rect: leftover
|
||||
/// **width** inside a [`Row`](crate::layout::row::Row), leftover
|
||||
/// **height** inside a [`Column`](crate::layout::column::Column).
|
||||
///
|
||||
/// Use this to make a non-trivial child fill remaining width without resorting
|
||||
/// to a hard-coded `max_width`. The row computes how much width is left after
|
||||
/// the fixed-size siblings, splits it across all flex / spacer children
|
||||
/// proportionally to their `weight`, and gives the flex its share. The wrapped
|
||||
/// child sees that share as its layout rect — text inside it triggers its own
|
||||
/// elide path on overflow, columns adjust their inner width, etc.
|
||||
/// Use this to make a non-trivial child fill remaining space without
|
||||
/// resorting to a hard-coded size. The parent computes how much of its
|
||||
/// main axis is left after the fixed-size siblings, splits it across all
|
||||
/// flex / spacer children proportionally to their `weight`, and gives
|
||||
/// the flex its share. The wrapped child sees that share as its layout
|
||||
/// rect — text inside it triggers its own elide path on overflow,
|
||||
/// columns adjust their inner width, etc.
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use ltk::{ column, flex, row, Element };
|
||||
@@ -30,10 +33,6 @@ use super::Element;
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// Currently only [`Row`](crate::layout::row::Row) honours flex distribution.
|
||||
/// Inside a [`Column`](crate::layout::column::Column) a flex child behaves
|
||||
/// like a regular zero-width child along the main axis — vertical flex is not
|
||||
/// yet implemented.
|
||||
pub struct Flex<Msg: Clone>
|
||||
{
|
||||
pub( crate ) child: Box<Element<Msg>>,
|
||||
@@ -51,9 +50,9 @@ impl<Msg: Clone> Flex<Msg>
|
||||
}
|
||||
}
|
||||
|
||||
/// Relative weight when sharing leftover width with other flex / spacer
|
||||
/// children in the same row (default `1`). A flex with `weight = 2`
|
||||
/// claims twice the space of a sibling with `weight = 1`.
|
||||
/// Relative weight when sharing leftover space with other flex / spacer
|
||||
/// children in the same row or column (default `1`). A flex with
|
||||
/// `weight = 2` claims twice the space of a sibling with `weight = 1`.
|
||||
pub fn weight( mut self, w: u32 ) -> Self
|
||||
{
|
||||
self.weight = w;
|
||||
|
||||
@@ -9,7 +9,7 @@ use super::Element;
|
||||
|
||||
mod theme;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
/// A row inside a list with a primary label and optional subtitle / trailing
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn list_item_default()
|
||||
{
|
||||
let l = list_item::<()>( "Test" );
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::Element;
|
||||
|
||||
mod theme;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
/// A linear progress indicator for determinate operations.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn value_clamped_on_creation()
|
||||
{
|
||||
let p = progress_bar( 1.5 );
|
||||
@@ -12,7 +12,7 @@ fn value_clamped_on_creation()
|
||||
assert_eq!( p.value, 0.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn preferred_width_fills_available()
|
||||
{
|
||||
let p = progress_bar( 0.5 );
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::Element;
|
||||
|
||||
mod theme;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
/// One option inside a mutually-exclusive group.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn radio_default_state()
|
||||
{
|
||||
let r = radio::<()>( true );
|
||||
@@ -11,7 +11,7 @@ fn radio_default_state()
|
||||
assert!( r.on_select.is_none() );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn radio_unselected()
|
||||
{
|
||||
let r = radio::<()>( false );
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::render::Canvas;
|
||||
use crate::types::WidgetId;
|
||||
use crate::widget::Element;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
/// Which axes a `Scroll` viewport allows to move along. Determines
|
||||
|
||||
@@ -3,46 +3,46 @@
|
||||
|
||||
use super::clamp_offset;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn offset_zero_when_content_fits()
|
||||
{
|
||||
// Content shorter than viewport — no scrolling possible
|
||||
assert_eq!( clamp_offset( 50.0, 300.0, 500.0 ), 0.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn offset_clamped_to_zero_when_negative()
|
||||
{
|
||||
assert_eq!( clamp_offset( -10.0, 600.0, 400.0 ), 0.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn offset_clamped_to_max()
|
||||
{
|
||||
// max = 600 - 400 = 200; offset 999 → clamped to 200
|
||||
assert_eq!( clamp_offset( 999.0, 600.0, 400.0 ), 200.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn offset_within_range_unchanged()
|
||||
{
|
||||
// max = 600 - 400 = 200; offset 100 stays 100
|
||||
assert_eq!( clamp_offset( 100.0, 600.0, 400.0 ), 100.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn zero_offset_stays_zero()
|
||||
{
|
||||
assert_eq!( clamp_offset( 0.0, 600.0, 400.0 ), 0.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn exact_max_offset_is_valid()
|
||||
{
|
||||
assert_eq!( clamp_offset( 200.0, 600.0, 400.0 ), 200.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn content_equal_to_viewport_gives_zero_max()
|
||||
{
|
||||
// No overflow — max = 0
|
||||
|
||||
@@ -142,5 +142,5 @@ impl<Msg: Clone> From<Separator> for Element<Msg>
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn default_thickness_and_pad_follow_the_mode()
|
||||
{
|
||||
let s = separator();
|
||||
@@ -11,7 +11,7 @@ fn default_thickness_and_pad_follow_the_mode()
|
||||
assert_eq!( s.pad_v, None );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn explicit_zero_pad_v_is_flush_not_the_mode_default()
|
||||
{
|
||||
// The Option repr lets `0.0` mean a real flush divider, distinct from
|
||||
@@ -22,7 +22,7 @@ fn explicit_zero_pad_v_is_flush_not_the_mode_default()
|
||||
assert_eq!( s.preferred_size( 200.0, &canvas ).1, canvas.geom_px( theme::THICKNESS ) );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn preferred_height_includes_padding()
|
||||
{
|
||||
let _g = crate::TEST_GLOBALS_LOCK.lock().unwrap_or_else( |e| e.into_inner() );
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use super::*;
|
||||
use crate::types::Rect;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn value_clamped_on_creation()
|
||||
{
|
||||
let s = slider::<()>( 1.5 );
|
||||
@@ -13,7 +13,7 @@ fn value_clamped_on_creation()
|
||||
assert_eq!( s.value, 0.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn value_from_x_left_edge()
|
||||
{
|
||||
let s = slider::<()>( 0.5 );
|
||||
@@ -22,7 +22,7 @@ fn value_from_x_left_edge()
|
||||
assert_eq!( v, 0.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn value_from_x_right_edge()
|
||||
{
|
||||
let s = slider::<()>( 0.5 );
|
||||
@@ -31,7 +31,7 @@ fn value_from_x_right_edge()
|
||||
assert_eq!( v, 1.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn value_from_x_center()
|
||||
{
|
||||
let s = slider::<()>( 0.0 );
|
||||
@@ -40,7 +40,7 @@ fn value_from_x_center()
|
||||
assert!( (v - 0.5).abs() < 0.1 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn axis_dispatch_horizontal_uses_x()
|
||||
{
|
||||
let rect = Rect { x: 0.0, y: 0.0, width: 200.0, height: 36.0 };
|
||||
@@ -53,7 +53,7 @@ fn axis_dispatch_horizontal_uses_x()
|
||||
assert_eq!( v, 1.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn axis_dispatch_vertical_uses_y()
|
||||
{
|
||||
let rect = Rect { x: 0.0, y: 0.0, width: 56.0, height: 160.0 };
|
||||
@@ -67,7 +67,7 @@ fn axis_dispatch_vertical_uses_y()
|
||||
assert_eq!( v, 1.0 );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn value_from_x_respects_thumb_pad()
|
||||
{
|
||||
let rect = Rect { x: 0.0, y: 0.0, width: 100.0, height: 36.0 };
|
||||
@@ -82,14 +82,14 @@ fn value_from_x_respects_thumb_pad()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn track_paint_default_is_none()
|
||||
{
|
||||
let s = slider::<()>( 0.5 );
|
||||
assert!( s.track_paint.is_none() );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn track_paint_builder_stores_paint()
|
||||
{
|
||||
use crate::theme::{ ColorStop, GradientSpace, LinearGradient, Paint };
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::Element;
|
||||
|
||||
mod theme;
|
||||
|
||||
#[cfg(test)]
|
||||
#[ cfg( test ) ]
|
||||
mod tests;
|
||||
|
||||
/// A two-state on / off switch.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn toggle_default_state()
|
||||
{
|
||||
let t = toggle::<()>( true );
|
||||
@@ -12,7 +12,7 @@ fn toggle_default_state()
|
||||
assert!( t.label.is_none() );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ test ]
|
||||
fn toggle_off_state()
|
||||
{
|
||||
let t = toggle::<()>( false );
|
||||
|
||||
Reference in New Issue
Block a user