Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add padding to View component #931

Merged
merged 2 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions compositor_api/src/types/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,27 @@ pub struct View {

/// List of box shadows.
pub box_shadow: Option<Vec<BoxShadow>>,

/// (**default=`0.0`**) Padding for all sides of the component.
pub padding: Option<f32>,

/// (**default=`0.0`**) Padding for the top and bottom of the component.
pub padding_vertical: Option<f32>,

/// (**default=`0.0`**) Padding for the left and right of the component.
pub padding_horizontal: Option<f32>,

/// (**default=`0.0`**) Padding on top side in pixels.
pub padding_top: Option<f32>,
noituri marked this conversation as resolved.
Show resolved Hide resolved

/// (**default=`0.0`**) Padding on right side in pixels.
pub padding_right: Option<f32>,

/// (**default=`0.0`**) Padding on bottom side in pixels.
pub padding_bottom: Option<f32>,

/// (**default=`0.0`**) Padding on left side in pixels.
pub padding_left: Option<f32>,
}

#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)]
Expand Down
28 changes: 28 additions & 0 deletions compositor_api/src/types/from_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,33 @@ impl TryFrom<View> for scene::ViewComponent {
Some(Overflow::Fit) => scene::Overflow::Fit,
None => scene::Overflow::Hidden,
};
let padding = scene::Padding {
top: view
.padding_top
.or(view.padding_vertical)
.or(view.padding)
.unwrap_or(0.0),
bottom: view
.padding_bottom
.or(view.padding_vertical)
.or(view.padding)
.unwrap_or(0.0),
left: view
.padding_left
.or(view.padding_horizontal)
.or(view.padding)
.unwrap_or(0.0),
right: view
.padding_right
.or(view.padding_horizontal)
.or(view.padding)
.unwrap_or(0.0),
};

if padding.top < 0.0 || padding.right < 0.0 || padding.bottom < 0.0 || padding.left < 0.0 {
return Err(TypeError::new("Padding values cannot be negative."));
}

Ok(Self {
id: view.id.map(Into::into),
children: view
Expand Down Expand Up @@ -114,6 +141,7 @@ impl TryFrom<View> for scene::ViewComponent {
.into_iter()
.map(TryInto::try_into)
.collect::<Result<_, _>>()?,
padding,
})
}
}
Expand Down
20 changes: 20 additions & 0 deletions compositor_render/src/scene/components.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ pub struct ViewComponent {
pub border_color: RGBAColor,

pub box_shadow: Vec<BoxShadow>,

pub padding: Padding,
}

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -178,6 +180,24 @@ pub enum ViewChildrenDirection {
Column,
}

#[derive(Debug, Clone, Copy, Default)]
pub struct Padding {
pub top: f32,
pub right: f32,
pub bottom: f32,
pub left: f32,
}

impl Padding {
pub fn horizontal(&self) -> f32 {
self.left + self.right
}

pub fn vertical(&self) -> f32 {
self.top + self.bottom
}
}

#[derive(Debug, Clone)]
pub struct RescalerComponent {
pub id: Option<ComponentId>,
Expand Down
24 changes: 23 additions & 1 deletion compositor_render/src/scene/components/position.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::scene::AbsolutePosition;

use super::Position;
use super::{Padding, Position};

impl Position {
pub(crate) fn with_border(self, border_width: f32) -> Self {
Expand All @@ -24,4 +24,26 @@ impl Position {
}),
}
}

pub(crate) fn with_padding(self, padding: Padding) -> Self {
match self {
Position::Static { width, height } => Self::Static {
width: width.map(|w| w + padding.horizontal()),
height: height.map(|h| h + padding.vertical()),
},
Position::Absolute(AbsolutePosition {
width,
height,
position_horizontal,
position_vertical,
rotation_degrees,
}) => Self::Absolute(AbsolutePosition {
width: width.map(|w| w + padding.horizontal()),
height: height.map(|h| h + padding.vertical()),
position_horizontal,
position_vertical,
rotation_degrees,
}),
}
}
}
13 changes: 13 additions & 0 deletions compositor_render/src/scene/types/interpolation.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::scene::Padding;

use super::{HorizontalPosition, VerticalPosition};

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -77,3 +79,14 @@ impl ContinuousValue for HorizontalPosition {
}
}
}

impl ContinuousValue for Padding {
fn interpolate(start: &Self, end: &Self, state: InterpolationState) -> Self {
Self {
top: ContinuousValue::interpolate(&start.top, &end.top, state),
right: ContinuousValue::interpolate(&start.right, &end.right, state),
bottom: ContinuousValue::interpolate(&start.bottom, &end.bottom, state),
left: ContinuousValue::interpolate(&start.left, &end.left, state),
}
}
}
11 changes: 8 additions & 3 deletions compositor_render/src/scene/view_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use super::{
scene_state::BuildStateTreeCtx,
transition::{TransitionOptions, TransitionState},
types::interpolation::ContinuousValue,
BorderRadius, BoxShadow, Component, ComponentId, IntermediateNode, Overflow, Position,
BorderRadius, BoxShadow, Component, ComponentId, IntermediateNode, Overflow, Padding, Position,
RGBAColor, SceneError, Size, StatefulComponent,
};

Expand Down Expand Up @@ -37,6 +37,8 @@ struct ViewComponentParam {
border_color: RGBAColor,

box_shadow: Vec<BoxShadow>,

padding: Padding,
}

impl StatefulViewComponent {
Expand All @@ -56,10 +58,12 @@ impl StatefulViewComponent {
self.children.iter_mut().collect()
}

/// External position of a component (includes border)
/// External position of a component (includes border and padding)
pub(super) fn position(&self, pts: Duration) -> Position {
let view = self.view(pts);
view.position.with_border(view.border_width)
view.position
.with_border(view.border_width)
.with_padding(view.padding)
}

pub(super) fn component_id(&self) -> Option<&ComponentId> {
Expand Down Expand Up @@ -130,6 +134,7 @@ impl ViewComponent {
border_width: self.border_width,
border_color: self.border_color,
box_shadow: self.box_shadow,
padding: self.padding,
},
transition,
children: self
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl ContinuousValue for ViewComponentParam {
),
border_color: end.border_color,
box_shadow: ContinuousValue::interpolate(&start.box_shadow, &end.box_shadow, state),
padding: ContinuousValue::interpolate(&start.padding, &end.padding, state),
}
}
}
21 changes: 13 additions & 8 deletions compositor_render/src/scene/view_component/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,21 +135,26 @@ impl ViewComponentParam {
let (top, left, width, height) = match self.direction {
ViewChildrenDirection::Row => {
let width = opts.width.unwrap_or(opts.static_child_size);
let height = opts.height.unwrap_or(opts.parent_size.height);
let top = opts.parent_border_width;
let left = static_offset;
let height = opts
.height
.unwrap_or(opts.parent_size.height - self.padding.vertical());
let top = opts.parent_border_width + self.padding.top;
let left = static_offset + self.padding.left;
static_offset += width;
(top, left, width, height)
}
ViewChildrenDirection::Column => {
let height = opts.height.unwrap_or(opts.static_child_size);
let width = opts.width.unwrap_or(opts.parent_size.width);
let top = static_offset;
let left = opts.parent_border_width;
let width = opts
.width
.unwrap_or(opts.parent_size.width - self.padding.horizontal());
let top = static_offset + self.padding.top;
let left = opts.parent_border_width + self.padding.left;
static_offset += height;
(top, left, width, height)
}
};

let layout = match child {
StatefulComponent::Layout(layout_component) => {
let children_layouts = layout_component.layout(Size { width, height }, pts);
Expand Down Expand Up @@ -201,8 +206,8 @@ impl ViewComponentParam {
/// size represents dimensions of content (without a border).
fn static_child_size(&self, size: Size, children: &[StatefulComponent], pts: Duration) -> f32 {
let max_size = match self.direction {
super::ViewChildrenDirection::Row => size.width,
super::ViewChildrenDirection::Column => size.height,
super::ViewChildrenDirection::Row => size.width - self.padding.horizontal(),
super::ViewChildrenDirection::Column => size.height - self.padding.vertical(),
};

let children_with_unknown_size_count = Self::static_children_iter(children, pts)
Expand Down
2 changes: 1 addition & 1 deletion integration_tests/examples/tiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn client_code() -> Result<()> {
.map(|_| {
json!({
"type": "input_stream",
"input_id": "input_1",
"input_id": "input_1"
})
})
.collect();
Expand Down
56 changes: 56 additions & 0 deletions schemas/scene.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 47 additions & 0 deletions snapshot_tests/view/nested_padding_static_children.scene.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"video": {
"root": {
"type": "view",
"background_color": "red",
"direction": "row",
"children": [
{
"type": "view",
"border_width": 10,
"border_color": "blue",
"children": []
},
{
"type": "view",
"padding_top": 20,
"padding_left": 20,
"border_width": 10,
"border_color": "blue",
"children": [
{
"type": "view",
"padding_vertical": 20,
"padding_left": 20,
"padding_right": 40,
"border_width": 10,
"border_color": "green",
"background_color": "blue",
"children": [
{
"type": "view",
"width": 150,
"height": 150,
"padding_left": 80,
"border_width": 10,
"border_color": "magenta",
"background_color": "yellow",
"children": []
}
]
}
]
}
]
}
}
}
Loading