Skip to content
Open
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
3 changes: 3 additions & 0 deletions crates/libs/reactor/src/backend/winui/generated_set_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,9 @@ pub fn dispatch(handle: &Handle, prop: Prop, value: &PropValue) -> Result<bool>
(Prop::OnContent, PropValue::Unset, Handle::ToggleSwitch(h)) => {
h.SetOnContent(None)?;
}
(Prop::OpenPaneLength, PropValue::F64(v), Handle::NavigationView(h)) => {
h.SetOpenPaneLength(*v)?;
}
(Prop::OpenPaneLength, PropValue::F64(v), Handle::SplitView(h)) => {
h.SetOpenPaneLength(*v)?;
}
Expand Down
63 changes: 48 additions & 15 deletions crates/libs/reactor/src/backend/winui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ fn style_target_for_handle(handle: &Handle) -> Option<(&'static str, bindings::I
Handle::StackPanel(s) => s.cast().ok().map(|fe| ("StackPanel", fe)),
Handle::Grid(g) => g.cast().ok().map(|fe| ("Grid", fe)),
Handle::Button(b) => b.cast().ok().map(|fe| ("Button", fe)),
Handle::TextBox(t) => t.cast().ok().map(|fe| ("TextBox", fe)),
Handle::TextBlock(t) => t.cast().ok().map(|fe| ("TextBlock", fe)),
Handle::Canvas(c) => c.cast().ok().map(|fe| ("Canvas", fe)),
_ => None,
Expand Down Expand Up @@ -1010,6 +1011,37 @@ fn set_foreground(
Ok(true)
}

fn set_border_brush(
handle: &Handle,
brush: impl windows_core::Param<bindings::Brush>,
) -> Result<()> {
match handle {
Handle::Border(b) => b.SetBorderBrush(brush)?,
_ => {
if let Ok(ctl) = handle.cast_inner::<bindings::IControl>() {
ctl.SetBorderBrush(brush)?;
} else {
diag::unhandled_modifier("set_prop", Prop::BorderBrush, handle);
}
}
}
Ok(())
}

fn set_border_thickness(handle: &Handle, thickness: Thickness) -> Result<()> {
match handle {
Handle::Border(b) => b.SetBorderThickness(thickness)?,
_ => {
if let Ok(ctl) = handle.cast_inner::<bindings::IControl>() {
ctl.SetBorderThickness(thickness)?;
} else {
diag::unhandled_modifier("set_prop", Prop::BorderThickness, handle);
}
}
}
Ok(())
}

fn set_font_f64(handle: &Handle, v: f64) -> Result<bool> {
match handle {
Handle::TextBlock(h) => h.SetFontSize(v)?,
Expand Down Expand Up @@ -1314,23 +1346,15 @@ impl Backend for WinUIBackend {
(Prop::CornerRadius, PropValue::Unset, Handle::Border(b)) => {
b.SetCornerRadius(bindings::CornerRadius::default())
}
(Prop::BorderBrush, PropValue::Color(br), Handle::Border(b)) => {
b.SetBorderBrush(&solid_brush(*br)?)
}
(Prop::BorderBrush, PropValue::Unset, Handle::Border(b)) => b.SetBorderBrush(None),
(Prop::BorderBrush, _, h) => {
diag::unhandled_modifier("set_prop", Prop::BorderBrush, h);
Ok(())
}
(Prop::BorderThickness, PropValue::Thickness(t), Handle::Border(b)) => {
b.SetBorderThickness(*t)
(Prop::BorderBrush, PropValue::Color(br), h) => {
set_border_brush(h, &solid_brush(*br)?)
}
(Prop::BorderThickness, PropValue::Unset, Handle::Border(b)) => {
b.SetBorderThickness(Thickness::default())
(Prop::BorderBrush, PropValue::Unset, h) => {
set_border_brush(h, None::<&bindings::Brush>)
}
(Prop::BorderThickness, _, h) => {
diag::unhandled_modifier("set_prop", Prop::BorderThickness, h);
Ok(())
(Prop::BorderThickness, PropValue::Thickness(t), h) => set_border_thickness(h, *t),
(Prop::BorderThickness, PropValue::Unset, h) => {
set_border_thickness(h, Thickness::default())
}
(Prop::LineEndpoints, PropValue::LineEndpoints(p), Handle::Line(l)) => l
.SetX1(p.x1)
Expand Down Expand Up @@ -1959,6 +1983,15 @@ impl Backend for WinUIBackend {
} else {
let _ = tb.SetRightHeader(None);
}
} else if let Handle::NavigationView(nv) = handle {
if let Some(pid) = pane_id {
if let Some(pane_handle) = map.get(&pid) {
let ui_elem = pane_handle.as_ui_element();
let _ = nv.SetPaneFooter(&ui_elem);
}
} else {
let _ = nv.SetPaneFooter(None);
}
}
}

Expand Down
60 changes: 58 additions & 2 deletions crates/libs/reactor/src/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6775,6 +6775,27 @@ impl IControl {
.ok()
}
}
pub(crate) fn SetBorderThickness(&self, value: Thickness) -> windows_core::Result<()> {
unsafe {
(windows_core::Interface::vtable(self).SetBorderThickness)(
windows_core::Interface::as_raw(self),
value,
)
.ok()
}
}
pub(crate) fn SetBorderBrush<P0>(&self, value: P0) -> windows_core::Result<()>
where
P0: windows_core::Param<Brush>,
{
unsafe {
(windows_core::Interface::vtable(self).SetBorderBrush)(
windows_core::Interface::as_raw(self),
value.param().abi(),
)
.ok()
}
}
}
#[repr(C)]
pub struct IControl_Vtbl {
Expand Down Expand Up @@ -6828,6 +6849,16 @@ pub struct IControl_Vtbl {
*mut core::ffi::c_void,
*mut core::ffi::c_void,
) -> windows_core::HRESULT,
BackgroundSizing: usize,
SetBackgroundSizing: usize,
BorderThickness: usize,
pub SetBorderThickness:
unsafe extern "system" fn(*mut core::ffi::c_void, Thickness) -> windows_core::HRESULT,
BorderBrush: usize,
pub SetBorderBrush: unsafe extern "system" fn(
*mut core::ffi::c_void,
*mut core::ffi::c_void,
) -> windows_core::HRESULT,
}
windows_core::imp::define_interface!(
ICubicBezierEasingFunction,
Expand Down Expand Up @@ -9681,6 +9712,18 @@ impl INavigationView {
.ok()
}
}
pub(crate) fn SetPaneFooter<P0>(&self, value: P0) -> windows_core::Result<()>
where
P0: windows_core::Param<UIElement>,
{
unsafe {
(windows_core::Interface::vtable(self).SetPaneFooter)(
windows_core::Interface::as_raw(self),
value.param().abi(),
)
.ok()
}
}
pub(crate) fn SetHeader<P0>(&self, value: P0) -> windows_core::Result<()>
where
P0: windows_core::Param<windows_core::IInspectable>,
Expand Down Expand Up @@ -9711,6 +9754,15 @@ impl INavigationView {
.ok()
}
}
pub(crate) fn SetOpenPaneLength(&self, value: f64) -> windows_core::Result<()> {
unsafe {
(windows_core::Interface::vtable(self).SetOpenPaneLength)(
windows_core::Interface::as_raw(self),
value,
)
.ok()
}
}
pub(crate) fn SetSelectedItem<P0>(&self, value: P0) -> windows_core::Result<()>
where
P0: windows_core::Param<windows_core::IInspectable>,
Expand Down Expand Up @@ -9812,7 +9864,10 @@ pub struct INavigationView_Vtbl {
FooterMenuItemsSource: usize,
SetFooterMenuItemsSource: usize,
PaneFooter: usize,
SetPaneFooter: usize,
pub SetPaneFooter: unsafe extern "system" fn(
*mut core::ffi::c_void,
*mut core::ffi::c_void,
) -> windows_core::HRESULT,
Header: usize,
pub SetHeader: unsafe extern "system" fn(
*mut core::ffi::c_void,
Expand All @@ -9832,7 +9887,8 @@ pub struct INavigationView_Vtbl {
CompactPaneLength: usize,
SetCompactPaneLength: usize,
OpenPaneLength: usize,
SetOpenPaneLength: usize,
pub SetOpenPaneLength:
unsafe extern "system" fn(*mut core::ffi::c_void, f64) -> windows_core::HRESULT,
PaneToggleButtonStyle: usize,
SetPaneToggleButtonStyle: usize,
SelectedItem: usize,
Expand Down
29 changes: 29 additions & 0 deletions crates/libs/reactor/src/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1123,6 +1123,35 @@ fn apply_brush_binding(m: &mut Modifiers, prop: Prop, binding: BrushBinding, is_
}
}

/// Applies a [`BrushBinding`] to a widget-owned brush slot (e.g. a border
/// brush stored on the widget struct rather than in [`Modifiers`]). A direct
/// color is stored in `slot` and any prior theme binding for `prop` is cleared;
/// a theme reference clears `slot` and records the binding. This keeps
/// "last call wins" holding regardless of the direct/theme call order.
pub(crate) fn apply_widget_brush_binding(
slot: &mut Option<BrushBinding>,
m: &mut Modifiers,
prop: Prop,
binding: BrushBinding,
) {
if let Some(map) = m.theme_bindings.as_deref_mut() {
map.remove(&prop);
}
match binding {
BrushBinding::Direct(b) => *slot = Some(BrushBinding::Direct(b)),
BrushBinding::Theme(t) => {
*slot = None;
m.theme_bindings
.get_or_insert_with(|| Box::new(rustc_hash::FxHashMap::default()))
.insert(prop, t);
}
}

if m.theme_bindings.as_deref().is_some_and(|m| m.is_empty()) {
m.theme_bindings = None;
}
}

fn ensure_animations(m: &mut Modifiers) -> &mut AnimationModifiers {
m.animations
.get_or_insert_with(|| Box::new(AnimationModifiers::default()))
Expand Down
6 changes: 5 additions & 1 deletion crates/libs/reactor/src/generated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ pub fn menu_bar_bindings(w: &MenuBar) -> PropBindings {
)]
}
pub fn navigation_view_bindings(w: &NavigationView) -> PropBindings {
let mut out = Vec::with_capacity(12usize);
let mut out = Vec::with_capacity(13usize);
out.push(Binding::Event(
Event::BackRequested,
w.on_back_requested
Expand Down Expand Up @@ -406,6 +406,10 @@ pub fn navigation_view_bindings(w: &NavigationView) -> PropBindings {
Prop::IsSettingsVisible,
PropValue::Bool(w.is_settings_visible),
));
out.push(Binding::Prop(
Prop::OpenPaneLength,
PropValue::F64(w.open_pane_length),
));
out.push(Binding::Prop(
Prop::PaneDisplayMode,
PropValue::I32(w.pane_display_mode.0),
Expand Down
8 changes: 8 additions & 0 deletions crates/libs/reactor/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ impl Color {
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self { a: 255, r, g, b }
}
pub const fn transparent() -> Self {
Self {
a: 0,
r: 0,
g: 0,
b: 0,
}
}
}

#[derive(Copy, Clone, Debug, PartialEq)]
Expand Down
20 changes: 6 additions & 14 deletions crates/libs/reactor/src/widgets/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,12 @@ impl Border {
/// the stroke to actually render. Accepts a direct [`Color`] or a
/// [`ThemeRef`] for theme-aware strokes.
pub fn border_brush(mut self, v: impl Into<BrushBinding>) -> Self {
match v.into() {
BrushBinding::Direct(b) => {
self.border_brush = Some(BrushBinding::Direct(b));
}
BrushBinding::Theme(t) => {
self.border_brush = None;
self.modifiers
.theme_bindings
.get_or_insert_with(|| {
Box::new(rustc_hash::FxHashMap::default())
})
.insert(Prop::BorderBrush, t);
}
}
apply_widget_brush_binding(
&mut self.border_brush,
&mut self.modifiers,
Prop::BorderBrush,
v.into(),
);
self
}

Expand Down
15 changes: 15 additions & 0 deletions crates/libs/reactor/src/widgets/navigation_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ pub struct NavigationView {
pub on_suggestion_chosen: Option<Callback<String>>,
pub is_pane_toggle_button_visible: bool,
pub is_back_button_visible: bool,
pub open_pane_length: f64,
pub pane_footer: Option<Box<Element>>,
}
impl Default for NavigationView {
fn default() -> Self {
Expand All @@ -81,6 +83,8 @@ impl Default for NavigationView {
on_suggestion_chosen: None,
is_pane_toggle_button_visible: true,
is_back_button_visible: true,
open_pane_length: 320.0,
pane_footer: None,
}
}
}
Expand Down Expand Up @@ -163,6 +167,14 @@ impl NavigationView {
self.is_back_button_visible = v;
self
}
pub fn open_pane_length(mut self, len: f64) -> Self {
self.open_pane_length = len;
self
}
pub fn pane_footer(mut self, el: impl Into<Element>) -> Self {
self.pane_footer = Some(Box::new(el.into()));
self
}
}

impl Widget for NavigationView {
Expand Down Expand Up @@ -197,4 +209,7 @@ impl Widget for NavigationView {
fn children(&self) -> Children<'_> {
Children::PositionalSingle(&self.content)
}
fn pane_element(&self) -> Option<&Element> {
self.pane_footer.as_deref()
}
}
30 changes: 30 additions & 0 deletions crates/libs/reactor/src/widgets/text_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ pub struct TextBox {
pub is_enabled: bool,
pub accepts_return: bool,
pub text_wrapping: TextWrapping,
pub border_brush: Option<BrushBinding>,
pub border_thickness: Option<Thickness>,
}
impl TextBox {
pub fn new(value: impl Into<String>) -> Self {
Expand All @@ -30,6 +32,15 @@ impl Widget for TextBox {
Prop::Value,
PropValue::Str(self.value.clone()),
));
if let Some(BrushBinding::Direct(br)) = &self.border_brush {
out.push(Binding::Prop(Prop::BorderBrush, PropValue::Color(*br)));
}
if let Some(v) = self.border_thickness {
out.push(Binding::Prop(
Prop::BorderThickness,
PropValue::Thickness(v),
));
}
out
}
}
Expand Down Expand Up @@ -70,6 +81,25 @@ impl TextBox {
self.text_wrapping = TextWrapping::Wrap;
self
}

/// Brush used to paint the border stroke. Maps to WinUI
/// `Control.BorderBrush`. Accepts a direct [`Color`] or a [`ThemeRef`].
pub fn border_brush(mut self, v: impl Into<BrushBinding>) -> Self {
apply_widget_brush_binding(
&mut self.border_brush,
&mut self.modifiers,
Prop::BorderBrush,
v.into(),
);
Comment thread
kennykerr marked this conversation as resolved.
self
}

/// Border stroke thickness, in DIPs, on each side. Maps to WinUI
/// `Control.BorderThickness`.
pub fn border_thickness(mut self, v: Thickness) -> Self {
self.border_thickness = Some(v);
self
}
}

pub fn text_box(value: impl Into<String>) -> TextBox {
Expand Down
Loading
Loading