viewport: local_viewport() opt-out of root-viewport inheritance; list_item: height/font_size builders
`Viewport::local_viewport()` resolves the child's viewport-relative (vw / vh / vmin) and fluid Lengths against the viewport's own rect instead of the root layout viewport the sub-canvas inherits since the fluid-resolution inheritance change. That inheritance is right for scroll-like clips (content renders the same size inside and outside), but it is exactly wrong for a fixed-size floating mini-UI — crustace's phone-shaped quick-settings pill pinned to a corner of a desktop-wide surface resolved its vw text and fluid stock geometry against the whole monitor, inflating the content past the pill's fixed clip and cutting off the bottom stripe. The flag pins the sub-canvas's layout viewport to its own size via the new crate-internal Canvas::set_local_layout_viewport, nested sub-canvases keep propagating the pinned value, and a unit test covers the override plus propagation. `ListItem::height( impl Into<Length> )` and `ListItem::font_size( impl Into<Length> )` mirror the Toggle / Radio height() builders: override the theme row height (floored at the label's rendered height so the text never clips) and the primary-label font size (subtitle and trailing keep their theme sizes), letting dense context menus trade the stock touch-target generosity for row density. Docs: widgets.md gains both builder sets, architecture.md documents the layout-viewport inheritance model next to the per-canvas density it parallels, the cookbook slide-in panel recipe notes when the pill needs local_viewport(), and the toggle / radio height() rustdoc demotes its private theme::HEIGHT link to a code span so cargo doc is warning-free again. CHANGELOG entries added.
This commit is contained in:
@@ -6,6 +6,9 @@ All notable changes to `ltk` are documented here. The format is based on [Keep a
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- **`Viewport::local_viewport()`** — resolve the child's viewport-relative (`vw` / `vh` / `vmin`) and fluid `Length`s against the viewport's own rect instead of the root layout viewport the sub-canvas inherits. For fixed-size floating mini-UIs (a phone-shaped panel pinned to a corner of a desktop-wide surface) whose content is calibrated against the panel rect; scroll-like clips should keep the default inheritance.
|
||||||
|
- **`ListItem::height( impl Into<Length> )` / `ListItem::font_size( impl Into<Length> )`** — override the theme row height (floored at the label's rendered height so text never clips) and the primary-label font size, mirroring the `Toggle` / `Radio` `height()` builders, so dense menus can trade the touch-target generosity for row density.
|
||||||
|
|
||||||
- **Per-canvas pixel density** — `Canvas::set_density` pins a canvas (and the sub-canvases derived from it) to its own density factor for `Length::dp` resolution, overriding the process `set_density` global; `Canvas::density` reads the effective value. New `Canvas::resolve_geom` / `Canvas::resolve_font` resolve an explicit `Length` in geometry / font space with the canvas' density — widgets now route caller-supplied lengths through them, so a `dp` override follows the canvas it draws on. The hook for surfaces on outputs whose DPI differs from the process-wide one (an overlay on a second monitor, an embedder with several `UiSurface`s).
|
- **Per-canvas pixel density** — `Canvas::set_density` pins a canvas (and the sub-canvases derived from it) to its own density factor for `Length::dp` resolution, overriding the process `set_density` global; `Canvas::density` reads the effective value. New `Canvas::resolve_geom` / `Canvas::resolve_font` resolve an explicit `Length` in geometry / font space with the canvas' density — widgets now route caller-supplied lengths through them, so a `dp` override follows the canvas it draws on. The hook for surfaces on outputs whose DPI differs from the process-wide one (an overlay on a second monitor, an embedder with several `UiSurface`s).
|
||||||
- **`Length::resolve_with_density`** — `Length::resolve` with an explicit density for `LengthBase::Dp`, instead of the process `density()`.
|
- **`Length::resolve_with_density`** — `Length::resolve` with an explicit density for `LengthBase::Dp`, instead of the process `density()`.
|
||||||
- **`docs/backends.md`** — the canonical software/GLES capability matrix: what renders identically, what degrades gracefully on software (gradients, shadows, backdrop blur, bottom fade) and what is GPU-only, replacing per-method rustdoc archaeology. Linked from README, onboarding and the architecture known-gaps list.
|
- **`docs/backends.md`** — the canonical software/GLES capability matrix: what renders identically, what degrades gracefully on software (gradients, shadows, backdrop blur, bottom fade) and what is GPU-only, replacing per-method rustdoc archaeology. Linked from README, onboarding and the architecture known-gaps list.
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ Every size in a widget tree is a `Length`, resolved to concrete pixels at layout
|
|||||||
|
|
||||||
Stock widgets do not hard-code either strategy. Each carries a design pixel per dimension (e.g. `button` height 48, font 16) and resolves it through the process-wide `WidgetScaling` mode: `Length::widget(n)` returns `fluid(n)` under `WidgetScaling::Fluid` (the default) or `dp(n)` under `WidgetScaling::Physical`. `set_widget_scaling(mode)` flips it once for the whole app. An explicit `Length` on an individual widget (`button.height(...)`, `text_edit.height(...)`, `font_size(...)`) bypasses the mode entirely — the mode only decides the meaning of the *default* design pixels, never an override the app wrote on purpose.
|
Stock widgets do not hard-code either strategy. Each carries a design pixel per dimension (e.g. `button` height 48, font 16) and resolves it through the process-wide `WidgetScaling` mode: `Length::widget(n)` returns `fluid(n)` under `WidgetScaling::Fluid` (the default) or `dp(n)` under `WidgetScaling::Physical`. `set_widget_scaling(mode)` flips it once for the whole app. An explicit `Length` on an individual widget (`button.height(...)`, `text_edit.height(...)`, `font_size(...)`) bypasses the mode entirely — the mode only decides the meaning of the *default* design pixels, never an override the app wrote on purpose.
|
||||||
|
|
||||||
Both `density()` and `widget_scaling()` are process globals read during layout; set them at startup (or, for density, whenever the surface moves to an output with a different DPI). Because they are global, ltk's own test suite serialises the tests that touch them. Density is also overridable **per canvas**: `Canvas::set_density` pins a canvas (and every sub-canvas derived from it) to its own factor, and all canvas-routed resolution — `geom_px` / `font_px` for stock-widget design pixels, `Canvas::resolve_geom` / `resolve_font` for explicit `Length` values — uses the local density when one is pinned and the process global otherwise. This is the hook for a surface sitting on an output whose DPI differs from the one the global was derived from (an overlay on a second monitor, an embedder with several `UiSurface`s).
|
Both `density()` and `widget_scaling()` are process globals read during layout; set them at startup (or, for density, whenever the surface moves to an output with a different DPI). Because they are global, ltk's own test suite serialises the tests that touch them. Density is also overridable **per canvas**: `Canvas::set_density` pins a canvas (and every sub-canvas derived from it) to its own factor, and all canvas-routed resolution — `geom_px` / `font_px` for stock-widget design pixels, `Canvas::resolve_geom` / `resolve_font` for explicit `Length` values — uses the local density when one is pinned and the process global otherwise. This is the hook for a surface sitting on an output whose DPI differs from the one the global was derived from (an overlay on a second monitor, an embedder with several `UiSurface`s). The layout viewport follows the same inheritance model: sub-canvases (scroll and viewport clips, GLES clip layers) inherit the root surface's layout viewport so fluid and viewport-relative values resolve identically inside and outside a clip, and `Viewport::local_viewport()` opts a clip out of it — its child then resolves against the clip's own rect, for fixed-size floating mini-UIs whose content must not scale with the host surface.
|
||||||
|
|
||||||
`Length` adapts *sizes* to the orientation; to adapt the *structure* of a layout (a row of panels in landscape, the same panels stacked in portrait), branch the view on `ltk::orientation()`. The runtime records the main surface's physical dimensions on every configure (also readable as `ltk::viewport_size()`) and rebuilds the view after each resize, so a `match ltk::orientation() { Landscape => row()…, Portrait => column()… }` follows the window live. The portrait/landscape rule matches `Length::orient` (a square surface counts as portrait). `examples/clip_path.rs` shows the pattern.
|
`Length` adapts *sizes* to the orientation; to adapt the *structure* of a layout (a row of panels in landscape, the same panels stacked in portrait), branch the view on `ltk::orientation()`. The runtime records the main surface's physical dimensions on every configure (also readable as `ltk::viewport_size()`) and rebuilds the view after each resize, so a `match ltk::orientation() { Landscape => row()…, Portrait => column()… }` follows the window live. The portrait/landscape rule matches `Length::orient` (a square surface counts as portrait). `examples/clip_path.rs` shows the pattern.
|
||||||
|
|
||||||
|
|||||||
@@ -145,6 +145,8 @@ backend renders a hard edge. If your shell must look identical on both
|
|||||||
backends, branch on `ltk::is_software_render()` and skip the fade
|
backends, branch on `ltk::is_software_render()` and skip the fade
|
||||||
when the software path is active.
|
when the software path is active.
|
||||||
|
|
||||||
|
If the panel is a fixed-size pill on a much larger surface (a phone-shaped quick-settings card pinned to a corner of a desktop monitor), add `.local_viewport()` to the `viewport` so `vw` / `vmin` and fluid sizes inside resolve against the pill rect instead of the whole surface — without it the panel's content scales with the monitor and overflows the pill.
|
||||||
|
|
||||||
**See also**: [`Viewport`](./widgets.md#viewport),
|
**See also**: [`Viewport`](./widgets.md#viewport),
|
||||||
[`OverlaySpec`](../src/app.rs).
|
[`OverlaySpec`](../src/app.rs).
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,8 @@ When both are set the text sits to the left of the icon.
|
|||||||
its content (theme default 16 px) — lower it when the enclosing view's
|
its content (theme default 16 px) — lower it when the enclosing view's
|
||||||
own padding already provides the margin.
|
own padding already provides the margin.
|
||||||
|
|
||||||
|
`height( len )` overrides the theme row height (56 design px, 68 with a subtitle) and `font_size( len )` the primary-label size (16 design px; subtitle and trailing keep their theme sizes), both `impl Into<Length>`. Use them together where a dense list — a context menu, a compact picker — should trade the touch-target generosity of a settings list for row density; the resolved height is floored at the label's rendered height so the text never clips however aggressive the override.
|
||||||
|
|
||||||
**See also**: [`pressable`](#pressable) for free-form tappable rows,
|
**See also**: [`pressable`](#pressable) for free-form tappable rows,
|
||||||
[`scroll`](#scroll) to wrap a list of items in a scrollable container.
|
[`scroll`](#scroll) to wrap a list of items in a scrollable container.
|
||||||
|
|
||||||
@@ -578,6 +580,8 @@ viewport( panel_view )
|
|||||||
# }
|
# }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default the clip's sub-canvas inherits the root layout viewport, so viewport-relative (`vw` / `vh` / `vmin`) and fluid `Length`s inside resolve exactly as they would outside the clip — the right behaviour for scroll-like clipping. `local_viewport()` opts out: the child resolves those `Length`s against the viewport's own rect instead. Use it for a fixed-size floating mini-UI — a phone-shaped panel pinned to a corner of a desktop-wide surface — whose content is calibrated against the panel rect and must not scale with the surface hosting it.
|
||||||
|
|
||||||
**See also**: the slide-in panel recipe in
|
**See also**: the slide-in panel recipe in
|
||||||
[`docs/cookbook.md`](./cookbook.md#slide-in-panel).
|
[`docs/cookbook.md`](./cookbook.md#slide-in-panel).
|
||||||
|
|
||||||
|
|||||||
@@ -355,6 +355,7 @@ pub( crate ) fn layout_and_draw<Msg: Clone>(
|
|||||||
let vw = ( rect.width.ceil() as u32 ).max( 1 );
|
let vw = ( rect.width.ceil() as u32 ).max( 1 );
|
||||||
let vh = ( rect.height.ceil() as u32 ).max( 1 );
|
let vh = ( rect.height.ceil() as u32 ).max( 1 );
|
||||||
let mut sub = canvas.sub_canvas( vw, vh );
|
let mut sub = canvas.sub_canvas( vw, vh );
|
||||||
|
if v.local_viewport { sub.set_local_layout_viewport(); }
|
||||||
sub.clear();
|
sub.clear();
|
||||||
|
|
||||||
let child_rect = Rect { x: 0.0, y: 0.0, width: rect.width, height: effective_h };
|
let child_rect = Rect { x: 0.0, y: 0.0, width: rect.width, height: effective_h };
|
||||||
|
|||||||
@@ -296,6 +296,22 @@ impl Canvas
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pin this canvas' layout viewport to its own pixel size, opting a
|
||||||
|
/// sub-canvas out of the root-viewport inheritance: viewport-relative
|
||||||
|
/// and fluid [`Length`]s drawn on it resolve against the canvas rect
|
||||||
|
/// itself. For fixed-size floating mini-UIs (a phone-shaped panel on
|
||||||
|
/// a desktop surface) whose content must not scale with the surface
|
||||||
|
/// hosting them.
|
||||||
|
pub( crate ) fn set_local_layout_viewport( &mut self )
|
||||||
|
{
|
||||||
|
let ( w, h ) = self.size();
|
||||||
|
match self
|
||||||
|
{
|
||||||
|
Canvas::Software( c ) => c.layout_viewport = Some( ( w as f32, h as f32 ) ),
|
||||||
|
Canvas::Gles( c ) => c.layout_viewport = Some( ( w as f32, h as f32 ) ),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Resolve an explicit [`Length`] in **geometry** space: against
|
/// Resolve an explicit [`Length`] in **geometry** space: against
|
||||||
/// [`Self::viewport_layout`], with this canvas' [`Self::density`].
|
/// [`Self::viewport_layout`], with this canvas' [`Self::density`].
|
||||||
/// Widgets resolve caller-supplied geometry lengths through this so
|
/// Widgets resolve caller-supplied geometry lengths through this so
|
||||||
@@ -974,6 +990,21 @@ mod viewport_tests
|
|||||||
assert_eq!( sub.density(), 3.0 );
|
assert_eq!( sub.density(), 3.0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[ test ]
|
||||||
|
fn sub_canvas_local_layout_viewport_overrides_inheritance()
|
||||||
|
{
|
||||||
|
let _g = crate::TEST_GLOBALS_LOCK.lock().unwrap_or_else( |e| e.into_inner() );
|
||||||
|
|
||||||
|
let c = Canvas::new( 1920, 1080 );
|
||||||
|
let mut sub = c.sub_canvas( 396, 644 );
|
||||||
|
assert_eq!( sub.viewport_layout(), ( 1920.0, 1080.0 ) );
|
||||||
|
sub.set_local_layout_viewport();
|
||||||
|
assert_eq!( sub.viewport_layout(), ( 396.0, 644.0 ) );
|
||||||
|
// Nested sub-canvases keep propagating the pinned local viewport.
|
||||||
|
let nested = sub.sub_canvas( 200, 200 );
|
||||||
|
assert_eq!( nested.viewport_layout(), ( 396.0, 644.0 ) );
|
||||||
|
}
|
||||||
|
|
||||||
#[ test ]
|
#[ test ]
|
||||||
fn font_px_is_constant_physical_in_physical_mode()
|
fn font_px_is_constant_physical_in_physical_mode()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ pub struct ListItem<Msg: Clone>
|
|||||||
/// Optional override of the horizontal content inset. `None`
|
/// Optional override of the horizontal content inset. `None`
|
||||||
/// falls back to `theme::PAD_H`.
|
/// falls back to `theme::PAD_H`.
|
||||||
pub( crate ) pad_h: Option<Length>,
|
pub( crate ) pad_h: Option<Length>,
|
||||||
|
/// Optional override of the theme row height.
|
||||||
|
pub( crate ) height: Option<Length>,
|
||||||
|
/// Optional override of the primary-label font size.
|
||||||
|
pub( crate ) font_size: Option<Length>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Msg: Clone> ListItem<Msg>
|
impl<Msg: Clone> ListItem<Msg>
|
||||||
@@ -86,6 +90,8 @@ impl<Msg: Clone> ListItem<Msg>
|
|||||||
selected: false,
|
selected: false,
|
||||||
icon: None,
|
icon: None,
|
||||||
pad_h: None,
|
pad_h: None,
|
||||||
|
height: None,
|
||||||
|
font_size: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +149,26 @@ impl<Msg: Clone> ListItem<Msg>
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Override the preferred row height (default: the theme row
|
||||||
|
/// height, `theme::HEIGHT` / `theme::HEIGHT_SUB` design px).
|
||||||
|
/// Accepts any [`Length`] so dense menus can trade the touch-target
|
||||||
|
/// generosity for row density. The resolved value is floored at the
|
||||||
|
/// label's rendered height so the text never clips.
|
||||||
|
pub fn height( mut self, h: impl Into<Length> ) -> Self
|
||||||
|
{
|
||||||
|
self.height = Some( h.into() );
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Override the primary-label font size (default: `theme::LABEL_SIZE`
|
||||||
|
/// design px, resolved through the widget-scaling mode). Subtitle and
|
||||||
|
/// trailing text keep their theme sizes.
|
||||||
|
pub fn font_size( mut self, s: impl Into<Length> ) -> Self
|
||||||
|
{
|
||||||
|
self.font_size = Some( s.into() );
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the message emitted when the row is tapped.
|
/// Set the message emitted when the row is tapped.
|
||||||
pub fn on_press( mut self, msg: Msg ) -> Self
|
pub fn on_press( mut self, msg: Msg ) -> Self
|
||||||
{
|
{
|
||||||
@@ -157,13 +183,30 @@ impl<Msg: Clone> ListItem<Msg>
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Effective primary-label font size on `canvas`, honouring the
|
||||||
|
/// [`Self::font_size`] override.
|
||||||
|
fn label_px( &self, canvas: &Canvas ) -> f32
|
||||||
|
{
|
||||||
|
match self.font_size
|
||||||
|
{
|
||||||
|
Some( l ) => canvas.resolve_font( l ),
|
||||||
|
None => canvas.font_px( theme::LABEL_SIZE ),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> (f32, f32)
|
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> (f32, f32)
|
||||||
{
|
{
|
||||||
let h = if self.subtitle.is_some()
|
let h = match self.height
|
||||||
{
|
{
|
||||||
canvas.geom_px( theme::HEIGHT_SUB )
|
Some( l ) =>
|
||||||
} else {
|
{
|
||||||
canvas.geom_px( theme::HEIGHT )
|
// Floor at the label's physical height so the row can be
|
||||||
|
// squeezed but the text never clips.
|
||||||
|
let label_phys = self.label_px( canvas ) * canvas.dpi_scale();
|
||||||
|
canvas.resolve_geom( l ).max( label_phys + 4.0 )
|
||||||
|
}
|
||||||
|
None if self.subtitle.is_some() => canvas.geom_px( theme::HEIGHT_SUB ),
|
||||||
|
None => canvas.geom_px( theme::HEIGHT ),
|
||||||
};
|
};
|
||||||
( max_width, h )
|
( max_width, h )
|
||||||
}
|
}
|
||||||
@@ -206,7 +249,7 @@ impl<Msg: Clone> ListItem<Msg>
|
|||||||
canvas.stroke_rect( rect, theme::focus_color(), theme::FOCUS_W, theme::RADIUS );
|
canvas.stroke_rect( rect, theme::focus_color(), theme::FOCUS_W, theme::RADIUS );
|
||||||
}
|
}
|
||||||
|
|
||||||
let label_size = canvas.font_px( theme::LABEL_SIZE );
|
let label_size = self.label_px( canvas );
|
||||||
let pad_h = self.pad_h
|
let pad_h = self.pad_h
|
||||||
.map( |l| canvas.resolve_geom( l ) )
|
.map( |l| canvas.resolve_geom( l ) )
|
||||||
.unwrap_or_else( || canvas.geom_px( theme::PAD_H ) );
|
.unwrap_or_else( || canvas.geom_px( theme::PAD_H ) );
|
||||||
@@ -288,6 +331,8 @@ impl<Msg: Clone> ListItem<Msg>
|
|||||||
selected: self.selected,
|
selected: self.selected,
|
||||||
icon: self.icon,
|
icon: self.icon,
|
||||||
pad_h: self.pad_h,
|
pad_h: self.pad_h,
|
||||||
|
height: self.height,
|
||||||
|
font_size: self.font_size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ impl<Msg: Clone> Radio<Msg>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Override the preferred height (default: the theme row height,
|
/// Override the preferred height (default: the theme row height,
|
||||||
/// [`theme::HEIGHT`] design px). Accepts any [`Length`] so dense
|
/// `theme::HEIGHT` design px). Accepts any [`Length`] so dense
|
||||||
/// layouts can tie the row height to the viewport. The resolved
|
/// layouts can tie the row height to the viewport. The resolved
|
||||||
/// value is floored at the outer circle size so the ring never
|
/// value is floored at the outer circle size so the ring never
|
||||||
/// clips; the circle keeps its theme size and stays centred.
|
/// clips; the circle keeps its theme size and stays centred.
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ impl<Msg: Clone> Toggle<Msg>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Override the preferred height (default: the theme row height,
|
/// Override the preferred height (default: the theme row height,
|
||||||
/// [`theme::HEIGHT`] design px). Accepts any [`Length`] so dense
|
/// `theme::HEIGHT` design px). Accepts any [`Length`] so dense
|
||||||
/// layouts can tie the row height to the viewport. The resolved
|
/// layouts can tie the row height to the viewport. The resolved
|
||||||
/// value is floored at the track height so the pill never clips;
|
/// value is floored at the track height so the pill never clips;
|
||||||
/// the track keeps its theme size and stays vertically centred.
|
/// the track keeps its theme size and stays vertically centred.
|
||||||
|
|||||||
@@ -30,13 +30,17 @@ pub struct Viewport<Msg: Clone>
|
|||||||
/// the leading edge of the animation does not knife-cut against the layer
|
/// the leading edge of the animation does not knife-cut against the layer
|
||||||
/// below it.
|
/// below it.
|
||||||
pub( crate ) fade_bottom: f32,
|
pub( crate ) fade_bottom: f32,
|
||||||
|
/// Resolve the child's viewport-relative and fluid `Length`s against
|
||||||
|
/// this viewport's own rect instead of the inherited root layout
|
||||||
|
/// viewport. See [`Self::local_viewport`].
|
||||||
|
pub( crate ) local_viewport: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Msg: Clone> Viewport<Msg>
|
impl<Msg: Clone> Viewport<Msg>
|
||||||
{
|
{
|
||||||
pub fn new( child: impl Into<Element<Msg>> ) -> Self
|
pub fn new( child: impl Into<Element<Msg>> ) -> Self
|
||||||
{
|
{
|
||||||
Self { child: Box::new( child.into() ), width: None, height: None, fade_bottom: 0.0 }
|
Self { child: Box::new( child.into() ), width: None, height: None, fade_bottom: 0.0, local_viewport: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a fixed viewport width in logical pixels. Mirrors
|
/// Set a fixed viewport width in logical pixels. Mirrors
|
||||||
@@ -66,6 +70,20 @@ impl<Msg: Clone> Viewport<Msg>
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Resolve the child's viewport-relative (`vw` / `vh` / `vmin`) and
|
||||||
|
/// fluid `Length`s against this viewport's own rect instead of the
|
||||||
|
/// root surface the sub-canvas normally inherits. For a fixed-size
|
||||||
|
/// floating mini-UI (e.g. a phone-shaped panel pinned to a corner of
|
||||||
|
/// a desktop-wide surface) whose content is calibrated against the
|
||||||
|
/// panel rect and must not scale with the host surface. Scroll-like
|
||||||
|
/// clips should keep the default inheritance so content renders at
|
||||||
|
/// the same size inside and outside the clip.
|
||||||
|
pub fn local_viewport( mut self ) -> Self
|
||||||
|
{
|
||||||
|
self.local_viewport = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> ( f32, f32 )
|
pub fn preferred_size( &self, max_width: f32, canvas: &Canvas ) -> ( f32, f32 )
|
||||||
{
|
{
|
||||||
let inner_w = self.width.unwrap_or( max_width );
|
let inner_w = self.width.unwrap_or( max_width );
|
||||||
@@ -87,6 +105,7 @@ impl<Msg: Clone> Viewport<Msg>
|
|||||||
width: self.width,
|
width: self.width,
|
||||||
height: self.height,
|
height: self.height,
|
||||||
fade_bottom: self.fade_bottom,
|
fade_bottom: self.fade_bottom,
|
||||||
|
local_viewport: self.local_viewport,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user