1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! CSS style integration methods for RenderContext
use crate::style::{BorderStyle, Color, Size, Spacing};
impl RenderContext<'_> {
/// Get foreground color from CSS style or use default
pub fn css_color(&self, default: Color) -> Color {
self.style
.map(|s| {
let c = s.visual.color;
if c == Color::default() {
default
} else {
c
}
})
.unwrap_or(default)
}
/// Get background color from CSS style or use default
pub fn css_background(&self, default: Color) -> Color {
self.style
.map(|s| {
let c = s.visual.background;
if c == Color::default() {
default
} else {
c
}
})
.unwrap_or(default)
}
/// Get border color from CSS style or use default
pub fn css_border_color(&self, default: Color) -> Color {
self.style
.map(|s| {
let c = s.visual.border_color;
if c == Color::default() {
default
} else {
c
}
})
.unwrap_or(default)
}
/// Get opacity from CSS style (1.0 = fully opaque)
pub fn css_opacity(&self) -> f32 {
self.style.map(|s| s.visual.opacity).unwrap_or(1.0)
}
/// Check if visible according to CSS
pub fn css_visible(&self) -> bool {
self.style.map(|s| s.visual.visible).unwrap_or(true)
}
/// Get padding from CSS style
pub fn css_padding(&self) -> Spacing {
self.style.map(|s| s.spacing.padding).unwrap_or_default()
}
/// Get margin from CSS style
pub fn css_margin(&self) -> Spacing {
self.style.map(|s| s.spacing.margin).unwrap_or_default()
}
/// Get width from CSS style
pub fn css_width(&self) -> Size {
self.style.map(|s| s.sizing.width).unwrap_or_default()
}
/// Get height from CSS style
pub fn css_height(&self) -> Size {
self.style.map(|s| s.sizing.height).unwrap_or_default()
}
/// Get border style from CSS
pub fn css_border_style(&self) -> BorderStyle {
self.style
.map(|s| s.visual.border_style)
.unwrap_or_default()
}
/// Get gap from CSS style (for flex/grid layouts)
pub fn css_gap(&self) -> u16 {
self.style.map(|s| s.layout.gap).unwrap_or(0)
}
/// Check if CSS flex-wrap is enabled
pub fn css_flex_wrap(&self) -> bool {
self.style
.map(|s| {
s.layout.flex_wrap == crate::style::FlexWrap::Wrap
|| s.layout.flex_wrap == crate::style::FlexWrap::WrapReverse
})
.unwrap_or(false)
}
/// Check if CSS overflow is hidden
///
/// Returns true if the computed style has `overflow: hidden`.
/// Containers should use this to decide whether to clip children.
pub fn css_overflow_hidden(&self) -> bool {
self.style
.map(|s| s.visual.overflow == crate::style::Overflow::Hidden)
.unwrap_or(false)
}
/// Create a child RenderContext that inherits clipping from overflow style
///
/// If this context's CSS style has `overflow: hidden`, the child context
/// will have a clip region set to the given area. Otherwise no clip is set.
/// This is the recommended way to create child contexts in container widgets.
pub fn child_ctx_with_overflow<'b>(
buffer: &'b mut crate::render::Buffer,
area: crate::layout::Rect,
overflow_hidden: bool,
parent_clip: Option<crate::layout::Rect>,
) -> RenderContext<'b> {
let mut ctx = RenderContext::new(buffer, area);
if overflow_hidden {
ctx = ctx.with_clip(area);
} else if let Some(clip) = parent_clip {
ctx = ctx.with_clip(clip);
}
ctx
}
// NOTE: Color resolution is handled by WidgetState::resolve_fg/resolve_bg/resolve_colors_interactive
// Use self.state.resolve_colors_interactive(ctx.style, default_fg, default_bg) for widget color resolution
}
use crate::widget::traits::render_context::RenderContext;