ferroui_base/styling/
container_query.rs1use super::{
2 DuplicateSetterError, ControlTheme, SelectorMatch, SelectorMatchResult, StyleBase, StyleBaseImpl, StyleBaseImplExt, StyleHostRef,
3 StyleQuery,
4};
5use crate::property_store::FrameType;
6use crate::{ferro_class, instantiate, FerroObjectImpl, Ref, StyledElement};
7use std::cell::RefCell;
8
9#[repr(C)]
12pub struct ContainerQuery {
13 base: StyleBase,
14 query: RefCell<Option<StyleQuery>>,
15 name: RefCell<Option<String>>,
16}
17
18ferro_class!(ContainerQuery: StyleBase);
19crate::ferro_class_info!(ContainerQuery { new: ContainerQuery::new });
20
21impl FerroObjectImpl for ContainerQuery {}
22
23impl StyleBaseImpl for ContainerQuery {
24 fn set_parent(this: &Self, parent: Option<&Ref<StyleBase>>) {
25 if parent.is_some_and(|p| p.is::<ControlTheme>()) {
26 Self::parent_set_parent(this, parent);
27 } else {
28 panic!("Container cannot be added as a nested style.");
29 }
30 }
31
32 fn to_display_string(this: &Self) -> String {
34 match &*this.query.borrow() {
35 Some(query) => query.to_string_with_owner(Some(this)),
36 None => "ContainerQuery".to_string(),
37 }
38 }
39}
40
41impl ContainerQuery {
42 pub fn construct() -> Self {
44 Self { base: StyleBase::construct(), query: RefCell::new(None), name: RefCell::new(None) }
45 }
46
47 pub fn new() -> Ref<Self> {
49 instantiate(Self::construct())
50 }
51
52 pub fn with_query(query: StyleQuery, container_name: Option<String>) -> Ref<Self> {
55 let result = Self::new();
56 result.set_query(Some(query));
57 result.set_name(container_name);
58 result
59 }
60
61 pub fn with_query_fn(
64 query: impl FnOnce(Option<StyleQuery>) -> StyleQuery,
65 container_name: Option<String>,
66 ) -> Ref<Self> {
67 Self::with_query(query(None), container_name)
68 }
69
70 pub fn query(&self) -> Option<StyleQuery> {
72 self.query.borrow().clone()
73 }
74
75 pub fn set_query(&self, value: Option<StyleQuery>) {
76 *self.query.borrow_mut() = value;
77 }
78
79 pub fn name(&self) -> Option<String> {
81 self.name.borrow().clone()
82 }
83
84 pub fn set_name(&self, value: Option<String>) {
85 *self.name.borrow_mut() = value;
86 }
87
88 #[allow(dead_code)]
91 pub(crate) fn try_attach(
92 &self,
93 target: &StyledElement,
94 host: Option<&StyleHostRef>,
95 type_: FrameType,
96 ) -> SelectorMatchResult {
97 match self.try_attach_checked(target, host, type_) {
98 Ok(result) => result,
99 Err(error) => panic!("{error}"),
100 }
101 }
102
103 pub(crate) fn try_attach_checked(
106 &self,
107 target: &StyledElement,
108 host: Option<&StyleHostRef>,
109 type_: FrameType,
110 ) -> Result<SelectorMatchResult, DuplicateSetterError> {
111 let mut result = SelectorMatchResult::NeverThisType;
112
113 if self.has_children() {
114 crate::perf_count!(StylesEvaluated);
115 let parent = self.parent();
116 let match_ = match self.query() {
117 Some(query) => query.match_(target, parent.as_deref(), true, self.name().as_deref()),
118 None => {
119 let is_host = host
120 .and_then(StyleHostRef::as_element)
121 .is_some_and(|h| std::ptr::eq::<StyledElement>(&**h, target));
122 if is_host {
123 SelectorMatch::ALWAYS_THIS_INSTANCE
124 } else {
125 SelectorMatch::NEVER_THIS_INSTANCE
126 }
127 }
128 };
129
130 result = match_.result();
131
132 if match_.is_match() {
133 crate::perf_count!(StylesMatched);
134 self.try_attach_instance(target, match_.into_activator(), type_, true)?;
135 }
136 }
137
138 Ok(result)
139 }
140}