i_slint_compiler/builtin_elements.rs
1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4// cSpell: ignore langtype typeregister borderless commonmark Strikethroughs
5
6//! The builtin elements of the language and the runtime items they lower to.
7//!
8//! `item!` declares a runtime item, one per item struct, with the properties, callbacks and
9//! functions the item implements. An item that has every property of another one names it
10//! after a colon, so the compiler can lower to the smaller item when the larger one isn't needed:
11//!
12//! ```text
13//! item! { SimpleText: Empty {
14//! /// Documentation of the member.
15//! in property <string> text;
16//! in property <length> font-size: 12px;
17//! @deprecated in property <angle> rotation-angle <=> transform-rotation; // deprecated alias
18//! //! ### Section heading // free-form documentation kept in source order
19//! callback edited(text: string) -> bool;
20//! function close() { } // implemented by a compiler pass
21//! function start() { BuiltinFunction.StartTimer } // implemented by a BuiltinFunction
22//! out property <FontMetrics> font-metrics { BuiltinFunction.ItemFontMetrics } // computed per element
23//! } }
24//! ```
25//!
26//! `element!` declares an element `.slint` code can use. An element names the native item it
27//! lowers to; the compiler picks the smallest item in that item's parent chain that has every
28//! property the element uses, so a `Rectangle { }` becomes an `Empty`. Members declared on the
29//! element itself only exist in the compiler. Accepted child elements are listed with
30//! `children:`.
31//!
32//! ```text
33//! element! {
34//! /// Documentation of the element.
35//! @implicit_size
36//! Text: ComplexText
37//! }
38//!
39//! element! { Window: WindowItem { children: MenuBar; } }
40//!
41//! element! {
42//! @is_non_item_type
43//! Timer {
44//! in property <duration> interval;
45//! function start() { BuiltinFunction.StartTimer }
46//! }
47//! }
48//! ```
49//!
50//! The `@flags` of an element are the boolean fields of `BuiltinElement` (`is_internal`,
51//! `is_global`, ...) plus `expands_to_parent_geometry` or `implicit_size` for the default size,
52//! `builtin_struct(Name)`, `sc` for an element of the Slint SC subset and `skip_inherited` to
53//! leave the docs of the native items out of the element's.
54//! Member modifiers `@shadowable`, `@deprecated` (aliases only) and `@pure` keep their Slint
55//! meaning; `@constexpr` marks a property whose value is known at compile time, `@fake` one
56//! that exists only at compile time and `@sc` one of the Slint SC subset. A default value is a
57//! literal (`true`, `4`, `8px`, `500ms`, `"text"`, `#00f`) or an enum value
58//! (`ImageFit.contain`); the compiler sets it as the property's binding.
59//!
60//! Elements that are accepted children of another element are only reachable through it.
61//! A native item or an element must be declared before the items and elements using it, so each
62//! item sits right before the element that lowers to it. The macros expand to calls on a
63//! [`Builder`] that fill a [`NativeClass`] and a [`BuiltinElement`]; [`load`] runs them.
64
65use crate::expression_tree::{BuiltinFunction, Unit};
66use crate::langtype::{
67 BuiltinElement, BuiltinPropertyDefault, BuiltinPropertyInfo, BuiltinStruct, ConstantExpression,
68 DefaultSizeBinding, ElementDocEntry, ElementType, Function, NativeClass, Type,
69};
70use crate::object_tree::{Component, Element, PropertyVisibility};
71use crate::typeregister::TypeRegister;
72use smol_str::SmolStr;
73use std::cell::RefCell;
74use std::collections::HashMap;
75use std::rc::Rc;
76use std::sync::Arc;
77
78/// `stringify!` output of a hyphenated name, without the spaces it puts around `-`.
79fn kebab(spelled: &str) -> SmolStr {
80 debug_assert!(!spelled.contains('_'), "`{spelled}` must be spelled with dashes");
81 spelled.split(' ').collect()
82}
83
84/// Joins doc lines like the parser did for `///` comments: one space after the marker is
85/// dropped, lines are separated by `\n`.
86fn join_docs(lines: &[&str]) -> Option<String> {
87 (!lines.is_empty()).then(|| {
88 lines.iter().map(|l| l.strip_prefix(' ').unwrap_or(l)).collect::<Vec<_>>().join("\n")
89 })
90}
91
92/// The default value as written after the property: a literal (`true`, `4`, `8px`, `"text"`,
93/// `#00f`) or an enum value (`ImageFit.contain`). A number on an `int` property is cast, as the
94/// compiler does for a binding.
95fn default(ty: &Type, text: &str) -> Option<ConstantExpression> {
96 if text.is_empty() {
97 return None;
98 }
99 if text.starts_with('"') {
100 return Some(ConstantExpression::StringLiteral(
101 crate::literals::unescape_string(text).unwrap(),
102 ));
103 }
104 let text = text.replace(' ', "");
105 Some(match text.as_str() {
106 "true" => ConstantExpression::BoolLiteral(true),
107 "false" => ConstantExpression::BoolLiteral(false),
108 color if color.starts_with('#') => {
109 let argb = i_slint_common::color_parsing::parse_color_literal(color).unwrap();
110 ConstantExpression::Cast {
111 from: Box::new(ConstantExpression::NumberLiteral(argb as f64, Unit::None)),
112 to: Type::Color,
113 }
114 }
115 value if value.starts_with(|c: char| c.is_ascii_alphabetic()) => {
116 let (qualifier, value) = value.split_once('.').unwrap();
117 let Type::Enumeration(enumeration) = ty else {
118 panic!("enum default `{qualifier}.{value}` on a property of type {ty}")
119 };
120 assert_eq!(qualifier, enumeration.name, "wrong enum in `{qualifier}.{value}`");
121 let value = enumeration.clone().try_value_from_string(&kebab(value)).unwrap();
122 ConstantExpression::EnumerationValue(value)
123 }
124 number => {
125 let (value, unit) =
126 crate::literals::parse_number_literal(SmolStr::new(number)).unwrap();
127 let (value, unit) = unit.normalize(value);
128 let number = ConstantExpression::NumberLiteral(value, unit);
129 match ty {
130 Type::Int32 => ConstantExpression::Cast { from: Box::new(number), to: Type::Int32 },
131 _ => number,
132 }
133 }
134 })
135}
136
137#[cfg(feature = "builtin-docs")]
138macro_rules! docs {
139 ($($l:literal)*) => { &[$($l),*] };
140}
141/// Without the feature the doc strings stay out of the binary.
142#[cfg(not(feature = "builtin-docs"))]
143macro_rules! docs {
144 ($($l:literal)*) => {
145 &[]
146 };
147}
148
149#[rustfmt::skip]
150macro_rules! visibility {
151 (in) => { PropertyVisibility::Input };
152 (out) => { PropertyVisibility::Output };
153 (in - out) => { PropertyVisibility::InOut };
154 (private) => { PropertyVisibility::Private };
155}
156
157/// An `@flag` of an element; a bare flag names a `BuiltinElement` field.
158macro_rules! flag {
159 ($e:ident sc) => { $e.element.slint_sc = true };
160 ($e:ident skip_inherited) => { $e.element.docs.truncate(1) };
161 ($e:ident expands_to_parent_geometry) => { $e.element.default_size_binding = DefaultSizeBinding::ExpandsToParentGeometry };
162 ($e:ident implicit_size) => { $e.element.default_size_binding = DefaultSizeBinding::ImplicitSize };
163 ($e:ident builtin_struct($s:ident)) => { $e.class.builtin_struct = Some(BuiltinStruct::$s) };
164 ($e:ident $flag:ident) => { $e.element.$flag = true };
165}
166
167/// The members of a native item or builtin element, as calls on the builder `$e`.
168macro_rules! members {
169 ($l:ident $e:ident $(#![doc = $s:literal])*) => { $e.section(docs!($($s)*)); };
170 // property
171 ($l:ident $e:ident $(#![doc = $s:literal])* $(#[doc = $d:literal])* $(@$mod:ident)*
172 $vis:ident $(- $vis2:ident)? property < $($ty:tt)-+ > $($name:tt)-+ $(: $default:tt $(. $($dv:tt)-+)? $($hex:literal)?)? $(<=> $($alias:tt)-+)? ;
173 $($rest:tt)*) => {
174 $e.section(docs!($($s)*));
175 {
176 let ty = $l.ty(stringify!($($ty)-+));
177 let default = default(&ty, stringify!($($default $(. $($dv)-+)? $($hex)?)?));
178 $e.property(stringify!($($name)-+), ty, visibility!($vis $(- $vis2)?), default,
179 None $(.or(Some(stringify!($($alias)-+))))?, &[$(stringify!($mod)),*], docs!($($d)*));
180 }
181 members!($l $e $($rest)*);
182 };
183 // property computed by a BuiltinFunction, per element or per process
184 ($l:ident $e:ident $(#![doc = $s:literal])* $(#[doc = $d:literal])* $(@$mod:ident)*
185 $vis:ident property < $($ty:tt)-+ > $($name:tt)-+ { BuiltinFunction . $bf:ident } $($rest:tt)*) => {
186 $e.section(docs!($($s)*));
187 {
188 let mut info = BuiltinPropertyInfo::new($l.ty(stringify!($($ty)-+)));
189 info.property_visibility = visibility!($vis);
190 info.default_value = computed_default(BuiltinFunction::$bf);
191 $e.add(stringify!($($name)-+), info, &[$(stringify!($mod)),*], docs!($($d)*));
192 }
193 members!($l $e $($rest)*);
194 };
195 // callback
196 ($l:ident $e:ident $(#![doc = $s:literal])* $(#[doc = $d:literal])* $(@$mod:ident)*
197 callback $($name:tt)-+ $(( $($n:tt : $($t:tt)-+),* ))? $(-> $($ret:tt)-+)? ; $($rest:tt)*) => {
198 $e.section(docs!($($s)*));
199 $e.function(stringify!($($name)-+), Type::Callback,
200 $l.function(&[$($((stringify!($n), stringify!($($t)-+))),*)?], stringify!($($($ret)-+)?)),
201 None, &[$(stringify!($mod)),*], docs!($($d)*));
202 members!($l $e $($rest)*);
203 };
204 // function, implemented by a compiler pass or by the BuiltinFunction named in its body
205 ($l:ident $e:ident $(#![doc = $s:literal])* $(#[doc = $d:literal])* $(@$mod:ident)*
206 function $($name:tt)-+ ( $($n:tt : $($t:tt)-+),* ) $(-> $($ret:tt)-+)? { $(BuiltinFunction . $bf:ident)? } $($rest:tt)*) => {
207 $e.section(docs!($($s)*));
208 $e.function(stringify!($($name)-+), Type::Function,
209 $l.function(&[$((stringify!($n), stringify!($($t)-+))),*], stringify!($($($ret)-+)?)),
210 None $(.or(Some(BuiltinFunction::$bf)))?, &[$(stringify!($mod)),*], docs!($($d)*));
211 members!($l $e $($rest)*);
212 };
213 // accepted child elements
214 ($l:ident $e:ident $(#![doc = $s:literal])* children : $($child:ident),+ ; $($rest:tt)*) => {
215 $e.section(docs!($($s)*));
216 $l.children(&mut $e, &[$(stringify!($child)),+]);
217 members!($l $e $($rest)*);
218 };
219}
220
221/// The default of a property a `BuiltinFunction` computes.
222/// A function that takes the element computes a value per element, one that takes nothing
223/// answers for the whole process.
224fn computed_default(function: BuiltinFunction) -> BuiltinPropertyDefault {
225 if function.ty().args.is_empty() {
226 BuiltinPropertyDefault::RuntimeValue(function)
227 } else {
228 BuiltinPropertyDefault::ElementFunction(function)
229 }
230}
231
232/// A native item or builtin element being built.
233struct Builder {
234 class: NativeClass,
235 element: BuiltinElement,
236}
237
238impl Builder {
239 /// `//!` lines, kept in the docs in source order.
240 fn section(&mut self, lines: &[&str]) {
241 if let Some(text) = join_docs(lines) {
242 self.element.docs.push(ElementDocEntry::Text(text));
243 }
244 }
245
246 fn add(&mut self, name: &str, mut info: BuiltinPropertyInfo, mods: &[&str], docs: &[&str]) {
247 info.shadowable = mods.contains(&"shadowable");
248 info.slint_sc = mods.contains(&"sc");
249 info.docs = join_docs(docs);
250 let name = kebab(name);
251 self.member_doc(name.clone());
252 // A property computed per element isn't a property of the native item.
253 match info.default_value {
254 BuiltinPropertyDefault::ElementFunction(_) => {
255 self.element.properties.insert(name, info)
256 }
257 _ => self.class.properties.insert(name, info),
258 };
259 }
260
261 /// The docs are only assembled when they reach the binary.
262 fn member_doc(&mut self, name: SmolStr) {
263 if cfg!(feature = "builtin-docs") {
264 self.element.docs.push(ElementDocEntry::Member(name));
265 }
266 }
267
268 #[inline(never)]
269 fn property(
270 &mut self,
271 name: &str,
272 ty: Type,
273 vis: PropertyVisibility,
274 default: Option<ConstantExpression>,
275 alias: Option<&str>,
276 mods: &[&str],
277 docs: &[&str],
278 ) {
279 debug_assert_eq!(
280 mods.contains(&"deprecated"),
281 alias.is_some(),
282 "`@deprecated` on {}::{name} is only for two-way-binding aliases, and every alias must have it",
283 self.class.class_name
284 );
285 if let Some(target) = alias {
286 let name = kebab(name);
287 self.class.deprecated_aliases.insert(name.clone(), kebab(target));
288 self.member_doc(name);
289 return;
290 }
291 let mut info = BuiltinPropertyInfo::new(ty);
292 info.property_visibility = if mods.contains(&"constexpr") {
293 PropertyVisibility::Constexpr
294 } else if mods.contains(&"fake") {
295 PropertyVisibility::Fake
296 } else {
297 vis
298 };
299 if let Some(default) = default {
300 assert!(
301 !mods.contains(&"shadowable"),
302 "shadowable property {}::{name} can't have a default value as it would end up on the shadowing declaration",
303 self.class.class_name
304 );
305 debug_assert_eq!(
306 default.to_expression().ty(),
307 info.ty,
308 "the default value of {}::{name} has the wrong type",
309 self.class.class_name
310 );
311 info.default_value = BuiltinPropertyDefault::Expr(default);
312 }
313 self.add(name, info, mods, docs);
314 }
315
316 /// A callback or a function; `ty` is the `Type` constructor. A function is implemented by
317 /// a compiler pass, or by `builtin`.
318 #[inline(never)]
319 fn function(
320 &mut self,
321 name: &str,
322 ty: fn(Arc<Function>) -> Type,
323 function: Function,
324 builtin: Option<BuiltinFunction>,
325 mods: &[&str],
326 docs: &[&str],
327 ) {
328 let declared_pure = mods.contains(&"pure");
329 let info = match builtin {
330 Some(builtin) => {
331 // The BuiltinFunction type prepends implicit ElementReference arguments.
332 let builtin_ty = builtin.ty();
333 let implicit = builtin_ty.args.len().saturating_sub(function.args.len());
334 debug_assert!(
335 builtin_ty.args.ends_with(&function.args)
336 && builtin_ty.args[..implicit]
337 .iter()
338 .all(|t| matches!(t, Type::ElementReference))
339 && builtin_ty.return_type == function.return_type,
340 "the declared signature of {}::{name} doesn't match {builtin:?}: {builtin_ty:?}",
341 self.class.class_name
342 );
343 let mut merged = (*builtin_ty).clone();
344 merged.arg_names = std::iter::repeat_n(SmolStr::default(), implicit)
345 .chain(function.arg_names)
346 .collect();
347 debug_assert_eq!(
348 declared_pure,
349 builtin.is_pure(),
350 "the 'pure' qualifier of {}::{name} doesn't match {builtin:?}",
351 self.class.class_name
352 );
353 // `pure` comes from the BuiltinFunction, see BuiltinPropertyInfo::pure.
354 let mut info = BuiltinPropertyInfo::from(builtin);
355 info.ty = ty(Arc::new(merged));
356 info
357 }
358 None => {
359 let mut info = BuiltinPropertyInfo::new(ty(Arc::new(function)));
360 info.pure = declared_pure;
361 info
362 }
363 };
364 self.add(name, info, mods, docs);
365 }
366}
367
368struct Loader<'a> {
369 register: &'a mut TypeRegister,
370 /// The native items by name, each with the properties and docs of its whole parent chain.
371 items: HashMap<SmolStr, (Arc<NativeClass>, BuiltinElement)>,
372 /// The builtin elements by name.
373 elements: HashMap<SmolStr, Rc<BuiltinElement>>,
374}
375
376impl Loader<'_> {
377 /// A type as written: `length`, `[MenuEntry]`, or nothing for `void`.
378 fn ty(&self, text: &str) -> Type {
379 if text.is_empty() {
380 return Type::Void;
381 }
382 if let Some(inner) = text.strip_prefix('[').and_then(|t| t.strip_suffix(']')) {
383 return Type::Array(Arc::new(self.ty(inner)));
384 }
385 let ty = self.register.lookup(&kebab(text));
386 assert!(ty != Type::Invalid, "unknown type `{text}` in a builtin element");
387 ty
388 }
389
390 /// The signature of a callback or function from its `(name: type, ..)` and return type.
391 fn function(&self, args: &[(&str, &str)], ret: &str) -> Function {
392 Function {
393 return_type: self.ty(ret),
394 args: args.iter().map(|(_, t)| self.ty(t)).collect(),
395 arg_names: args.iter().map(|(n, _)| kebab(n)).collect(),
396 }
397 }
398
399 fn item_chain(&self, name: &str) -> &(Arc<NativeClass>, BuiltinElement) {
400 self.items
401 .get(name)
402 .unwrap_or_else(|| panic!("native item `{name}` must be declared before its use"))
403 }
404
405 #[inline(never)]
406 fn item(&self, name: &str, parent: Option<&str>) -> Builder {
407 let mut class = NativeClass::new(name);
408 let mut element = BuiltinElement::default();
409 if let Some(parent) = parent {
410 let (parent_class, chain) = self.item_chain(parent);
411 class.parent = Some(parent_class.clone());
412 element.properties = chain.properties.clone();
413 element.docs = chain.docs.clone();
414 }
415 Builder { class, element }
416 }
417
418 fn finish_item(&mut self, mut e: Builder) {
419 e.element.properties.extend(e.class.properties.clone());
420 self.items.insert(e.class.class_name.clone(), (Arc::new(e.class), e.element));
421 }
422
423 #[inline(never)]
424 fn element(&self, name: &str, docs: &[&str]) -> Builder {
425 let mut e = self.item(name, None);
426 if cfg!(feature = "builtin-docs") {
427 e.element.docs.push(ElementDocEntry::Text(join_docs(docs).unwrap_or_default()));
428 }
429 e
430 }
431
432 /// The native item the element lowers to. The element gets the properties and docs of the
433 /// item and of its parents.
434 fn base(&self, e: &mut Builder, item: &str) {
435 let (class, chain) = self.item_chain(item);
436 e.element.properties.extend(chain.properties.clone());
437 e.element.docs.extend(chain.docs.iter().cloned());
438 e.class.parent = Some(class.clone());
439 }
440
441 /// The accepted child elements, which can only be used within this one.
442 fn children(&mut self, e: &mut Builder, names: &[&str]) {
443 let parent = e.class.class_name.clone();
444 for name in names {
445 let name = SmolStr::new(name);
446 if name == parent {
447 e.element.additional_accept_self = true;
448 } else {
449 let child = self.elements.get(&name).unwrap_or_else(|| {
450 panic!(
451 "`{name}` must be declared before the builtin elements using it as a child"
452 )
453 });
454 e.element.additional_accepted_child_types.insert(name.clone(), child.clone());
455 }
456 self.register.context_restricted_types.entry(name).or_default().insert(parent.clone());
457 }
458 }
459
460 fn finish_element(&mut self, e: Builder) {
461 let mut builtin = e.element;
462 builtin.name = e.class.class_name.clone();
463 builtin.properties.extend(e.class.properties.clone());
464 // An element without members of its own is the native item it lowers to.
465 let own_members = !e.class.properties.is_empty()
466 || !e.class.deprecated_aliases.is_empty()
467 || e.class.builtin_struct.is_some();
468 builtin.native_class = match e.class.parent.clone() {
469 Some(item) if !own_members => item,
470 _ => Arc::new(e.class),
471 };
472 let builtin = Rc::new(builtin);
473 if builtin.is_global {
474 let global = Rc::new(Component {
475 id: builtin.name.clone(),
476 root_element: Rc::new(RefCell::new(Element {
477 base_type: ElementType::Builtin(builtin.clone()),
478 ..Default::default()
479 })),
480 ..Default::default()
481 });
482 global.root_element.borrow_mut().enclosing_component = Rc::downgrade(&global);
483 self.register.add(global);
484 }
485 self.elements.insert(builtin.name.clone(), builtin);
486 }
487}
488
489/// The declarations. `item!` declares a runtime item, `element!` an element of the language.
490fn build(l: &mut Loader) {
491 macro_rules! item {
492 ($Name:ident $(: $Parent:ident)? { $($body:tt)* }) => {{
493 let mut e = l.item(stringify!($Name), None $(.or(Some(stringify!($Parent))))?);
494 members!(l e $($body)*);
495 l.finish_item(e);
496 }};
497 }
498 macro_rules! element {
499 ($(#[doc = $d:literal])* $(@$flag:ident $(($arg:ident))?)* $Name:ident $(: $Item:ident)? $({ $($body:tt)* })?) => {{
500 let mut e = l.element(stringify!($Name), docs!($($d)*));
501 $( l.base(&mut e, stringify!($Item)); )?
502 $( flag!(e $flag $(($arg))?); )*
503 members!(l e $($($body)*)?);
504 l.finish_element(e);
505 }};
506 }
507
508 item! { Empty { } }
509
510 element! {
511 @is_internal
512 Empty: Empty
513 }
514
515 item! { Rectangle: Empty {
516 /// The background brush of this `Rectangle`, filling its geometry. \{#sls.ref.rectangle.background}
517 ///
518 /// Without a `background` and without a border, the `Rectangle` paints nothing. \{#sls.ref.rectangle.empty}
519 ///
520 /// A translucent background lets the content underneath show through. \{#sls.ref.rectangle.translucent}
521 ///
522 /// ```slint imageAlt="rectangle background" width="200" height="400"
523 /// property <brush> rainbow-gradient: @linear-gradient(40deg, rgba(255, 0, 0, 1) 0%, rgba(255, 154, 0, 1) 10%, rgba(208, 222, 33, 1) 20%,rgba(79, 220, 74, 1) 30%, rgba(63, 218, 216, 1) 40%, rgba(47, 201, 226, 1) 50%, rgba(28, 127, 238, 1) 60%, rgba(95, 21, 242, 1) 70%, rgba(186, 12, 248, 1) 80%, rgba(251, 7, 217, 1) 90%, rgba(255, 0, 0, 1) 100%);
524 ///
525 /// Rectangle {
526 /// x: 10px;
527 /// y: 10px;
528 /// width: 180px;
529 /// height: 180px;
530 /// background: #315afd;
531 /// }
532 ///
533 ///
534 /// Rectangle {
535 /// x: 10px;
536 /// y: 210px;
537 /// width: 180px;
538 /// height: 180px;
539 /// background: rainbow-gradient;
540 /// }
541 /// ```
542 /// \default transparent
543 @sc in property <brush> background;
544 @deprecated in property <brush> color <=> background;
545 } }
546
547 item! { BasicBorderRectangle: Rectangle {
548 /// ```slint imageAlt="rectangle border-color" width="200" height="200"
549 /// Rectangle {
550 /// width: 200px;
551 /// height: 200px;
552 /// border-width: 10px;
553 /// border-color: lightslategray;
554 /// }
555 /// ```
556 /// The color of the border.
557 /// :::caution[Caution]
558 /// The default `border-width` is `0px`, so the border is invisible. After setting a color also ensure that the `border-width` is set to a non-zero value.
559 /// :::
560 /// \default transparent
561 in property <brush> border-color;
562 /// ```slint imageAlt="rectangle border-width" width="200" height="200"
563 /// Rectangle {
564 /// width: 200px;
565 /// height: 200px;
566 /// border-width: 30px;
567 /// border-color: lightslategray;
568 /// }
569 /// ```
570 /// The width of the border.
571 /// \default 0
572 in property <length> border-width;
573 //! ### clip
574 //! <SlintProperty propName="clip" typeName="bool" defaultValue="false">
575 //! ```slint imageAlt="rectangle clip" width="200" height="400"
576 //! // clip: false; the default
577 //! Rectangle {
578 //! x: 50px; y: 50px;
579 //! width: 150px;
580 //! height: 150px;
581 //! background: darkslategray;
582 //! # Text {
583 //! # text: "clip: false";
584 //! # font-size: 20pt;
585 //! # color: white;
586 //! # }
587 //! Rectangle {
588 //! x: -40px; y: -40px;
589 //! width: 100px;
590 //! height: 100px;
591 //! background: lightslategray;
592 //! }
593 //! }
594 //!
595 //! // clip: true; Clips the children of this Rectangle
596 //! Rectangle {
597 //! x: 50px; y: 250px;
598 //! width: 150px;
599 //! height: 150px;
600 //! background: darkslategray;
601 //! clip: true;
602 //! # Text {
603 //! # text: "clip: true";
604 //! # font-size: 20pt;
605 //! # color: white;
606 //! # }
607 //! Rectangle {
608 //! x: -40px; y: -40px;
609 //! width: 100px;
610 //! height: 100px;
611 //! background: lightslategray;
612 //! }
613 //! }
614 //!
615 //! ```
616 //! By default, when child elements are outside the bounds of a parent,
617 //! they are still shown. When this property is set to `true`, the children
618 //! of this `Rectangle` are clipped and only the contents inside the elements bounds are shown.
619 //! </SlintProperty>
620 //!
621 //!
622 //! ## Border Radius Properties
623 /// The size of the radius. This single value is applied to all four corners.
624 /// \default 0
625 in property <length> border-radius;
626 } }
627
628 item! { BorderRectangle: BasicBorderRectangle {
629 //! To target specific corners with different values use the following properties:
630 ///
631 in property <length> border-top-left-radius;
632 ///
633 in property <length> border-top-right-radius;
634 ///
635 in property <length> border-bottom-left-radius;
636 ///
637 in property <length> border-bottom-right-radius;
638 //! ## Drop Shadows
639 //!
640 //! To achieve the graphical effect of a visually elevated shape that shows a shadow effect underneath the frame of
641 //! an element, it's possible to set the following `drop-shadow` properties:
642 //!
643 //! The CSS equivalent is `box-shadow`: `box-shadow: 2px 2px 4px 1px black` translates to
644 //! `drop-shadow-offset-x: 2px; drop-shadow-offset-y: 2px; drop-shadow-blur: 4px;
645 //! drop-shadow-spread: 1px; drop-shadow-color: black;`.
646 //!
647 //! ### drop-shadow-blur
648 //! <SlintProperty propName="drop-shadow-blur" typeName="length"/>
649 //! The radius of the shadow that also describes the level of blur applied to the shadow. Negative values are ignored and zero means no blur.
650 //!
651 //! ### drop-shadow-color
652 //! <SlintProperty propName="drop-shadow-color" typeName="color"/>
653 //! The base color of the shadow to use. Typically that color is the starting color of a gradient that fades into transparency.
654 //!
655 //! ### drop-shadow-offset-x
656 //! <SlintProperty propName="drop-shadow-offset-x" typeName="length"/>
657 //! The horizontal distance of the shadow from the element's frame.
658 //!
659 //!
660 //! ### drop-shadow-offset-y
661 //! <SlintProperty propName="drop-shadow-offset-y" typeName="length"/>
662 //! The vertical distance of the shadow from the element's frame.
663 //!
664 //! ### drop-shadow-spread
665 //! <SlintProperty propName="drop-shadow-spread" typeName="length"/>
666 //! Grows (positive) or shrinks (negative) the shadow shape on all sides before the blur is applied.
667 //! Equivalent to the spread radius in CSS `box-shadow`. Currently only supported by the Skia renderer.
668 //!
669 //! ## Inner Shadows
670 //!
671 //! Inner shadows are rendered inside the element's geometry (inverted from drop shadows), giving
672 //! the appearance of an inwards-cast shadow. They follow the same parameters as drop shadows.
673 //! Currently only supported by the Skia renderer.
674 //!
675 //! The CSS equivalent is `box-shadow` with the `inset` keyword: `box-shadow: inset 2px 2px 4px 1px black`
676 //! translates to `inner-shadow-offset-x: 2px; inner-shadow-offset-y: 2px; inner-shadow-blur: 4px;
677 //! inner-shadow-spread: 1px; inner-shadow-color: black;`.
678 //!
679 //! ### inner-shadow-blur
680 //! <SlintProperty propName="inner-shadow-blur" typeName="length"/>
681 //! The blur radius of the inner shadow.
682 //!
683 //! ### inner-shadow-color
684 //! <SlintProperty propName="inner-shadow-color" typeName="color"/>
685 //! The base color of the inner shadow.
686 //!
687 //! ### inner-shadow-offset-x
688 //! <SlintProperty propName="inner-shadow-offset-x" typeName="length"/>
689 //! Horizontal offset of the inner shadow inside the element.
690 //!
691 //! ### inner-shadow-offset-y
692 //! <SlintProperty propName="inner-shadow-offset-y" typeName="length"/>
693 //! Vertical offset of the inner shadow inside the element.
694 //!
695 //! ### inner-shadow-spread
696 //! <SlintProperty propName="inner-shadow-spread" typeName="length"/>
697 //! Positive spread thickens the shadow band along the element's interior boundary; negative spread
698 //! thins it.
699 } }
700
701 element! {
702 /// By default, a `Rectangle` is just an empty item that shows nothing. By setting a color or configuring a border,
703 /// it's then possible to draw a rectangle on the screen. \{#sls.meta.rectangle.purpose}
704 ///
705 /// <NotInSC>
706 /// When not part of a layout, its width and height default to 100% of the parent element.
707 /// </NotInSC>
708 ///
709 /// ```slint playground imageAlt="rectangle example"
710 /// export component ExampleRectangle inherits Window {
711 /// width: 200px; height: 800px; background: transparent;
712 ///
713 /// Rectangle {
714 /// x: 10px; y: 10px;
715 /// width: 180px;
716 /// height: 180px;
717 /// background: #315afd;
718 /// }
719 ///
720 /// // Rectangle with a border
721 /// Rectangle {
722 /// x: 10px; y: 210px;
723 /// width: 180px;
724 /// height: 180px;
725 /// background: green;
726 /// border-width: 2px;
727 /// border-color: red;
728 /// }
729 ///
730 /// // Transparent Rectangle with a border and a radius
731 /// Rectangle {
732 /// x: 10px; y: 410px;
733 /// width: 180px;
734 /// height: 180px;
735 /// border-width: 4px;
736 /// border-color: black;
737 /// border-radius: 30px;
738 /// }
739 ///
740 /// // A radius of width/2 makes it a circle
741 /// Rectangle {
742 /// x: 10px; y: 610px;
743 /// width: 180px;
744 /// height: 180px;
745 /// background: yellow;
746 /// border-width: 2px;
747 /// border-color: blue;
748 /// border-radius: self.width/2;
749 /// }
750 /// }
751 /// ```
752 /// \group:elements
753 @sc @expands_to_parent_geometry
754 Rectangle: BorderRectangle
755 }
756
757 item! { ImageItem: Empty {
758 in property <length> width;
759 in property <length> height;
760 /// When set, the image is used as an alpha mask and is drawn in the given color (or with the gradient).
761 /// ```slint imageAlt="image example" width="300" height="200"
762 /// Image {
763 /// source: @image-url("slint-logo-simple-dark.png");
764 /// colorize: darkorange;
765 /// }
766 /// ```
767 in property <brush> colorize;
768 /// The [image](/reference/property-types/images/) to draw, created with
769 /// [`@image-url()`](/reference/language/expressions/#sls.expr.image.form)
770 /// or set by the application: by default no image, drawing
771 /// nothing. \{#sls.ref.image.source}
772 ///
773 /// Access an `image`'s source dimension using its `source.width` and
774 /// `source.height` properties. \{#sls.ref.image.source.dimensions}
775 ///
776 /// ```slint
777 /// export component Example inherits Window {
778 /// in property <image> some_image: @image-url("images/logo.png");
779 ///
780 /// out property <int> image-width: some_image.width;
781 /// out property <int> image-height: some_image.height;
782 /// }
783 /// ```
784 @sc in property <image> source;
785 /// ```slint imageAlt="image fill example" width="300" height="200"
786 /// Image {
787 /// width: 200px; height: 50px;
788 /// source: @image-url("mini-banner.png");
789 /// image-fit: fill;
790 /// }
791 /// ```
792 ///
793 /// ```slint imageAlt="image contain example" width="300" height="200"
794 /// Image {
795 /// width: 250px; height: 40px;
796 /// source: @image-url("mini-banner.png");
797 /// image-fit: contain;
798 /// }
799 /// ```
800 ///
801 /// ```slint imageAlt="image cover example" width="300" height="200"
802 /// Image {
803 /// width: 250px; height: 250px;
804 /// source: @image-url("mini-banner.png");
805 /// image-fit: cover;
806 /// }
807 /// ```
808 ///
809 /// ```slint imageAlt="image preserve example" width="400" height="400"
810 /// Image {
811 /// width: 400px; height: 400px;
812 /// source: @image-url("mini-banner.png");
813 /// image-fit: preserve;
814 /// }
815 /// ```
816 /// \default `contain` when the `Image` element is part of a layout, `fill` otherwise
817 in property <ImageFit> image-fit;
818 /// ```slint imageAlt="image smooth example" width="300" height="300"
819 /// Image {
820 /// width: 800px;
821 /// source: @image-url("mini-banner.png");
822 /// image-rendering: smooth;
823 /// }
824 /// ```
825 ///
826 /// ```slint imageAlt="image pixelated example" width="300" height="300"
827 /// Image {
828 /// width: 800px;
829 /// source: @image-url("mini-banner.png");
830 /// image-rendering: pixelated;
831 /// }
832 /// ```
833 /// \default smooth
834 in property <ImageRendering> image-rendering;
835
836 @deprecated in property <angle> rotation-angle <=> transform-rotation;
837 } }
838
839 item! { ClippedImage: ImageItem {
840 /// The horizontal alignment of the image within the element.
841 /// \default center
842 in property <ImageHorizontalAlignment> horizontal-alignment;
843 /// The vertical alignment of the image within the element.
844 /// \default center
845 in property <ImageVerticalAlignment> vertical-alignment;
846 //! ## Image Tiling
847 /// How the image is tiled horizontally.
848 /// \default none
849 in property <ImageTiling> horizontal-tiling;
850 /// ```slint imageAlt="image horizontal tiling repeat example" width="400" height="400"
851 /// Image {
852 /// width: 400px;
853 /// height: 400px;
854 /// source: @image-url("slint-logo.png");
855 /// horizontal-tiling: repeat;
856 /// }
857 /// ```
858 ///
859 /// ```slint imageAlt="image horizontal tiling round example" width="400" height="400"
860 /// Image {
861 /// width: 400px;
862 /// height: 400px;
863 /// source: @image-url("slint-logo.png");
864 /// horizontal-tiling: round;
865 /// }
866 /// ```
867 /// ```slint imageAlt="image vertical tiling repeat example" width="400" height="400"
868 /// Image {
869 /// width: 400px;
870 /// height: 400px;
871 /// source: @image-url("slint-logo.png");
872 /// vertical-tiling: repeat;
873 /// }
874 /// ```
875 ///
876 /// ```slint imageAlt="image vertical tiling round example" width="400" height="400"
877 /// Image {
878 /// width: 400px;
879 /// height: 400px;
880 /// source: @image-url("slint-logo.png");
881 /// vertical-tiling: round;
882 /// }
883 /// ```
884 ///
885 /// ```slint imageAlt="image vertical and horizontal tiling round example" width="400" height="400"
886 /// Image {
887 /// width: 400px;
888 /// height: 400px;
889 /// source: @image-url("slint-logo.png");
890 /// vertical-tiling: round;
891 /// horizontal-tiling: round;
892 /// }
893 /// ```
894 /// \default none
895 in property <ImageTiling> vertical-tiling;
896 // TODO: sets both horizontal-tiling and vertical-tiling at the same time.
897 // in property <ImageTiling> tiling;
898 //! ## Source Clip
899 ///
900 in property <int> source-clip-x;
901 ///
902 in property <int> source-clip-y;
903 /// \default source.width - source.clip-x
904 in property <int> source-clip-width;
905 /// \default source.height - source.clip-y
906 in property <int> source-clip-height;
907 //! Properties in source image coordinates that define the region of the source image that is rendered.
908 //! By default the entire source image is visible:
909 } }
910
911 element! {
912 /// ```slint imageAlt="image example" width="300" height="200"
913 /// Image {
914 /// source: @image-url("mini-banner.png");
915 /// }
916 /// ```
917 ///
918 /// Use the `Image` element to display an
919 /// [image](/reference/property-types/images/). \{#sls.meta.image.purpose}
920 ///
921 /// <OnlyInSC>
922 /// The element draws the image of its `source` property pixel for pixel:
923 /// the image's top-left pixel is at the element's position, and one image
924 /// pixel covers one frame-buffer pixel, without scaling. \{#sls.ref.image.draw}
925 ///
926 /// The element is always the size of its source image: `width` and `height`
927 /// hold the dimensions of that image, and setting them is an
928 /// error. \{#sls.ref.image.size}
929 /// </OnlyInSC>
930 ///
931 /// \footer
932 /// <NotInSC>
933 /// ## Accessibility
934 ///
935 /// ### Alternative text
936 ///
937 /// Consider giving an alternative text description of your image by setting the `accessible-label` property:
938 ///
939 /// ```slint
940 /// Image {
941 /// width: 100px;
942 /// height: 100px;
943 /// source: @image-url("slint-logo.png");
944 /// accessible-label: "Slint logo";
945 /// }
946 /// ```
947 ///
948 /// ### Filtering out images for users of assistive technologies
949 ///
950 /// By default, images have the `accessible-role` property set to `image`.
951 /// If your image is purely decorative and doesn't convey any information,
952 /// consider removing it from the accessibility tree:
953 ///
954 /// ```slint
955 /// Image {
956 /// source: @image-url("mini-banner.png");
957 /// accessible-role: none;
958 /// }
959 /// ```
960 /// </NotInSC>
961 /// \group:elements
962 @sc @implicit_size
963 Image: ClippedImage
964 }
965
966 item! { ComponentContainer: Empty {
967 in property <component-factory> component-factory;
968 out property <bool> has-component;
969
970 in-out property <length> width;
971 in-out property <length> height;
972 } }
973
974 element! {
975 @accepts_focus
976 ComponentContainer: ComponentContainer
977 }
978
979 item! { Transform: Empty {
980 in property <angle> transform-rotation;
981 in property <percent> transform-scale-x;
982 in property <percent> transform-scale-y;
983 in property <Point> transform-origin;
984 } }
985
986 element! {
987 @is_internal @expands_to_parent_geometry
988 Transform: Transform
989 }
990
991 item! { SimpleText: Empty {
992 in property <length> width;
993 in property <length> height;
994 /// The color of the text.
995 ///
996 /// ```slint "color: #3586f4;" imageAlt="text color" width="200" height="200" needsBackground
997 /// Text {
998 /// text: "Hello";
999 /// color: #3586f4;
1000 /// font-size: 40pt;
1001 /// }
1002 /// ```
1003 /// \default <depends on theme>
1004 in property <brush> color; // StyleMetrics.default-text-color set in apply_default_properties_from_style
1005 /// The font size of the text.
1006 ///
1007 /// ```slint "font-size: 70pt;" imageAlt="text font-size" width="200" height="200" needsBackground
1008 /// Text {
1009 /// text: "Big";
1010 /// color: black;
1011 /// font-size: 70pt;
1012 /// }
1013 /// ```
1014 in property <length> font-size;
1015 /// The weight of the font. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight. Use the <Link type="FontWeight" /> namespace for predefined constants.
1016 ///
1017 /// ```slint 'font-weight: FontWeight.extra-bold;' imageAlt="text font-weight" width="200" height="200" needsBackground
1018 /// Text {
1019 /// text: "BOLD";
1020 /// color: black;
1021 /// font-size: 30pt;
1022 /// font-weight: FontWeight.extra-bold;
1023 /// }
1024 /// ```
1025 in property <int> font-weight;
1026 /// ```slint "horizontal-alignment: left;" imageAlt="text-horizontal-alignment" width="200" height="200" needsBackground
1027 /// Text {
1028 /// x: 0;
1029 /// text: "Hello";
1030 /// color: black;
1031 /// font-size: 40pt;
1032 /// horizontal-alignment: left;
1033 /// }
1034 /// ```
1035 in property <TextHorizontalAlignment> horizontal-alignment;
1036 /// The maximum number of lines to display. Wrapped lines count towards the limit, and
1037 /// with `overflow` set to `elide`, the ellipsis is placed on the last visible line.
1038 /// Values less than or equal to zero don't limit the number of lines.
1039 /// \default 0
1040 in property <int> max-lines;
1041 /// The text rendered.
1042 /// \default ""
1043 in property <string> text;
1044 /// The vertical alignment of the text.
1045 in property <TextVerticalAlignment> vertical-alignment;
1046
1047
1048 @deprecated in property <angle> rotation-angle <=> transform-rotation;
1049 } }
1050
1051 item! { ComplexText: SimpleText {
1052 /// The name of the font family selected for rendering the text.
1053 ///
1054 /// ```slint 'font-family: "Comic Sans MS";' imageAlt="text font-family" width="200" height="200" needsBackground
1055 /// Text {
1056 /// text: "CoMiC!";
1057 /// color: black;
1058 /// font-size: 40pt;
1059 /// font-family: "Comic Sans MS";
1060 /// }
1061 /// ```
1062 ///
1063 /// :::note[Note]
1064 /// Make sure the font is loaded before using it in a `Text` element.
1065 /// See <Link type="FontHandling" /> for more.
1066 /// :::
1067 in property <string> font-family;
1068 /// Whether or not the font face should be drawn italicized or not.
1069 ///
1070 /// ```slint "font-italic: true;" imageAlt="text font-family" width="200" height="200" needsBackground
1071 /// Text {
1072 /// text: "Italic";
1073 /// color: black;
1074 /// font-italic: true;
1075 /// font-size: 40pt;
1076 /// }
1077 /// ```
1078 /// \default false
1079 in property <bool> font-italic;
1080 /// How the text should behave when it exceeds the available space.
1081 in property <TextOverflow> overflow;
1082 /// ```slint "wrap: word-wrap;" imageAlt="wrap" width="200" height="200" needsBackground
1083 /// Text {
1084 /// text: "This paragraph breaks into multiple lines of text";
1085 /// font-size: 20pt;
1086 /// wrap: word-wrap;
1087 /// width: 180px;
1088 /// }
1089 /// ```
1090 in property <TextWrap> wrap;
1091 /// The letter spacing allows changing the spacing between the glyphs. A positive value increases the spacing and a negative value decreases the distance.
1092 /// ```slint "letter-spacing: 4px;" imageAlt="text-horizontal-alignment" width="200" height="200" needsBackground
1093 /// Text {
1094 /// text: "Spaced!";
1095 /// color: black;
1096 /// font-size: 30pt;
1097 /// letter-spacing: 4px;
1098 /// }
1099 /// ```
1100 in property <length> letter-spacing;
1101 /// The line height as a unitless factor (or a percentage: `150%` equals `1.5`) applied to
1102 /// the font's natural line height (ascent + descent + line gap). The default of `1` keeps
1103 /// the natural line height; larger values spread the lines apart, smaller values pull them
1104 /// together, and `0` collapses them onto each other. Negative or non-numeric values behave
1105 /// like `1`. Unlike CSS `line-height`, the factor is relative to the natural line height,
1106 /// not the font size, and keyword or length values aren't supported.
1107 ///
1108 /// ```slint "line-height-factor: 1.5;" imageAlt="text with increased line height" width="200" height="200" needsBackground
1109 /// Text {
1110 /// text: "Two lines\nof text";
1111 /// color: black;
1112 /// font-size: 30pt;
1113 /// line-height-factor: 1.5;
1114 /// }
1115 /// ```
1116 /// \default 1
1117 in property <float> line-height-factor: 1;
1118 /// The brush used for the text outline.
1119 /// ```slint "stroke: darkblue;" imageAlt="text stroke" width="300" height="200" needsBackground
1120 /// Text {
1121 /// text: "Stroke";
1122 /// stroke-width: 2px;
1123 /// stroke: darkblue;
1124 /// stroke-style: center;
1125 /// font-size: 80px;
1126 /// color: lightblue;
1127 /// }
1128 /// ```
1129 in property <brush> stroke;
1130 /// The width of the text outline. If the width is zero, then a hairline stroke (1 physical pixel) will be rendered.
1131 in property <length> stroke-width;
1132 /// ```slint "stroke-style: center;" imageAlt="stroke-style" width="200" height="200" needsBackground
1133 /// Text {
1134 /// text: "Style";
1135 /// stroke-width: 2px;
1136 /// stroke: #3586f4;
1137 /// stroke-style: center;
1138 /// font-size: 60px;
1139 /// color: white;
1140 /// }
1141 /// ```
1142 in property <TextStrokeStyle> stroke-style;
1143 /// The design metrics of the font scaled to the font pixel size used by the element.
1144 out property <FontMetrics> font-metrics { BuiltinFunction.ItemFontMetrics }
1145 } }
1146
1147 element! {
1148 /// ```slint playground
1149 /// // text-example.slint
1150 /// export component TextExample inherits Window {
1151 /// // Text colored red.
1152 /// Text {
1153 /// x:0; y:0;
1154 /// text: "Hello World";
1155 /// color: red;
1156 /// }
1157 ///
1158 /// // This paragraph breaks into multiple lines of text.
1159 /// Text {
1160 /// x:0; y: 30px;
1161 /// text: "This paragraph breaks into multiple lines of text";
1162 /// wrap: word-wrap;
1163 /// width: 150px;
1164 /// height: 100%;
1165 /// }
1166 /// }
1167 /// ```
1168 ///
1169 /// A `Text` element for displaying text.
1170 ///
1171 /// By default, the `min-width`, `min-height`, `preferred-width`, and `preferred-height`
1172 /// of a `Text` element are set to fit the full text as if it were displayed on a single line
1173 /// (unless the text contains explicit line breaks).
1174 /// However, if the `wrap` property is set to `word-wrap`, and/or if the `overflow` property is set to `elide`,
1175 /// the `min-width` is reduced to zero, allowing the text to wrap or be elided,
1176 /// while the `preferred-width` and `preferred-height` remain unchanged.
1177 ///
1178 /// \footer
1179 /// ## Accessibility
1180 ///
1181 /// By default, `Text` elements have the following accessibility properties set:
1182 ///
1183 /// - `accessible-role: text;`
1184 /// - `accessible-label: text;`
1185 /// \group:elements
1186 @implicit_size
1187 Text: ComplexText
1188 }
1189
1190 item! { StyledTextItem: Empty {
1191 in property <length> width;
1192 in property <length> height;
1193 /// The default color of the text, used when no color is specified via markup.
1194 /// \default <depends on theme>
1195 in property <brush> default-color;
1196 /// The default font family used to render the text, when no font is specified via markup. If left empty, the value falls back to the enclosing `Window`'s `default-font-family`.
1197 in property <string> default-font-family;
1198 /// The default font size used to render the text, when no size is specified via markup. If unset (or zero), the value falls back to the enclosing `Window`'s `default-font-size`.
1199 in property <length> default-font-size;
1200 /// The horizontal alignment of the text.
1201 in property <TextHorizontalAlignment> horizontal-alignment;
1202 /// The color used for rendering links in the text.
1203 in property <color> link-color: #00f;
1204 /// The maximum number of lines to display. Wrapped lines count towards the limit.
1205 /// Values less than or equal to zero don't limit the number of lines.
1206 /// \default 0
1207 in property <int> max-lines;
1208 /// The styled text rendered, using CommonMark markup with additional HTML tags for styling.
1209 /// \default ""
1210 in property <styled-text> text;
1211 /// The vertical alignment of the text.
1212 in property <TextVerticalAlignment> vertical-alignment;
1213 /// A callback that's invoked when a link in the text is clicked. The parameter contains the clicked link as a string.
1214 callback link-clicked(link: string);
1215 } }
1216
1217 element! {
1218 /// The `StyledText` element renders text with various styling and interactive properties, such as bolded, underlined and colored sections as well as HTTP links. It is based on a subset of the [commonmark](https://commonmark.org/) spec.
1219 ///
1220 /// ```slint imageAlt="Styled Text Example" width="200" height="200" scale="3"
1221 /// export component Example inherits Window {
1222 /// in property <string> value: 55;
1223 /// width: 200px;
1224 /// height: 200px;
1225 /// StyledText {
1226 /// text: @markdown("This is a piece of <u>Styled Text</u>\n"
1227 /// "with a red value inserted:"
1228 /// "<font color=\"red\">\{value}</font>");
1229 /// }
1230 /// }
1231 /// ```
1232 ///
1233 ///
1234 /// ## Features
1235 ///
1236 /// Styled Text supports the following features:
1237 ///
1238 /// Feature | Method
1239 /// ---------------|-------
1240 /// Italics | Builtin
1241 /// Strikethroughs | Builtin
1242 /// Inline code | Builtin
1243 /// Links | Builtin
1244 /// Ordered and unordered lists | Builtin
1245 /// Underlines | `<u>` HTML tag
1246 /// Text Colors |`<font color="...">` HTML tags
1247 ///
1248 /// ### Currently Unsupported
1249 ///
1250 /// Feature |
1251 /// -----------------|
1252 /// Headings |
1253 /// Images |
1254 /// Tables |
1255 /// Block Quotes |
1256 /// Subscripts |
1257 /// Superscripts |
1258 /// Horizontal Rules |
1259 /// Footnotes |
1260 /// Math expressions |
1261 /// Other HTML tags |
1262 /// \group:elements
1263 @implicit_size
1264 StyledText: StyledTextItem
1265 }
1266
1267 item! { TouchArea {
1268 /// When disabled, the `TouchArea` doesn't recognize any touch or mouse events and they are
1269 /// passed through to elements underneath.
1270 ///
1271 /// ```slint playground imageAlt="Basic syntax" width="200" height="100" scale="2"
1272 /// import { Button, CheckBox } from "std-widgets.slint";
1273 ///
1274 /// export component Example inherits Window {
1275 /// width: 200px; height: 100px;
1276 ///
1277 /// VerticalLayout {
1278 /// Rectangle {
1279 /// Button {
1280 /// text: "Try to press me";
1281 /// }
1282 /// TouchArea {
1283 /// enabled: event-blocker.checked;
1284 /// }
1285 /// }
1286 /// event-blocker := CheckBox {
1287 /// text: "Block Access";
1288 /// }
1289 /// }
1290 /// }
1291 /// ```
1292 ///
1293 /// :::note{Note}
1294 /// When `enabled` is set to false while the `TouchArea` is pressed, `pointer-event` will be
1295 /// invoked with `PointerEventKind.Cancel`, and the `pressed` and `has-hover` properties will
1296 /// be reset to `false`.
1297 /// :::
1298 in property <bool> enabled: true;
1299 /// Set to true when the mouse is over the `TouchArea` area.
1300 out property <bool> has-hover;
1301 /// The mouse cursor when the mouse is hovering the `TouchArea`.
1302 in property <MouseCursor> mouse-cursor;
1303 /// Set by the `TouchArea` to the position of the mouse within it.
1304 out property <length> mouse-x;
1305 /// Set by the `TouchArea` to the position of the mouse within it.
1306 out property <length> mouse-y;
1307 /// Set by the `TouchArea` to the position of the mouse at the moment it was last pressed.
1308 out property <length> pressed-x;
1309 /// Set by the `TouchArea` to the position of the mouse at the moment it was last pressed.
1310 out property <length> pressed-y;
1311 /// Set to `true` by the `TouchArea` when the mouse is pressed over it.
1312 out property <bool> pressed;
1313 /// Invoked when clicked: A finger or the left mouse button is pressed, then released on this element. \{#sls.ref.toucharea.clicked}
1314 ///
1315 /// <OnlyInSC>
1316 /// The Touch Input chapter specifies when a press and a release count as a click. \{#sls.ref.toucharea.clicked.input}
1317 /// </OnlyInSC>
1318 @sc callback clicked;
1319 /// Invoked when double-clicked. The left mouse button is pressed and released twice on this element in a short
1320 /// period of time, or the same is done with a finger. The `clicked()` callbacks will be triggered before the `double-clicked()` callback is triggered.
1321 callback double-clicked;
1322 /// The mouse or finger has been moved. This will only be called if the mouse is also pressed or the finger continues to touch
1323 /// the display. See also **pointer-event(PointerEvent)**.
1324 callback moved;
1325 /// <PointerEvent />
1326 callback pointer-event(event: PointerEvent);
1327 /// Invoked when the mouse wheel was rotated or another scroll gesture was made.
1328 /// The `PointerScrollEvent` argument contains information about how much to scroll in what direction.
1329 /// <PointerScrollEvent />
1330 /// The returned `EventResult`indicates whether to accept or ignore the event. Ignored events are
1331 /// forwarded to the parent element.
1332 /// <EventResult />
1333 callback scroll-event(event: PointerScrollEvent) -> EventResult;
1334 } }
1335
1336 element! {
1337 /// Use `TouchArea` to control what happens when the region it covers is touched or interacted with
1338 /// using the mouse. \{#sls.meta.toucharea.purpose}
1339 ///
1340 /// When not part of a layout, its width or height default to 100% of the parent element. \{#sls.ref.toucharea.size}
1341 ///
1342 /// <OnlyInSC>
1343 /// Of the members of `TouchArea`, only `clicked` and the geometry properties are part of Slint SC. \{#sls.ref.toucharea.members}
1344 /// </OnlyInSC>
1345 ///
1346 /// <NotInSC>
1347 /// ```slint playground
1348 /// export component Example inherits Window {
1349 /// width: 200px;
1350 /// height: 100px;
1351 /// area := TouchArea {
1352 /// width: parent.width;
1353 /// height: parent.height;
1354 /// clicked => {
1355 /// rect2.background = #ff0;
1356 /// }
1357 /// }
1358 /// Rectangle {
1359 /// x:0;
1360 /// width: parent.width / 2;
1361 /// height: parent.height;
1362 /// background: area.pressed ? blue: red;
1363 /// }
1364 /// rect2 := Rectangle {
1365 /// x: parent.width / 2;
1366 /// width: parent.width / 2;
1367 /// height: parent.height;
1368 /// }
1369 /// }
1370 /// ```
1371 /// </NotInSC>
1372 /// \group:gestures
1373 @sc @expands_to_parent_geometry
1374 TouchArea: TouchArea
1375 }
1376
1377 item! { KeyBinding {
1378 /// The <Link type="keys" label="keys" /> to match against incoming key events.
1379 in property <keys> keys;
1380 /// Whether this KeyBinding is currently enabled. Disabled KeyBinding elements don't consume key events and never invoke their `activated()` callback.
1381 in property <bool> enabled: true;
1382 /// Invoked when the parent `FocusScope` receives a key event that matches the `keys` of this `KeyBinding`.
1383 callback activated;
1384 } }
1385
1386 element! {
1387 /// Place `KeyBinding` elements inside a `FocusScope` to declare keyboard shortcuts.
1388 /// KeyBindings use **logical keys**, based on the character a key produces, not physical key positions.
1389 ///
1390 /// See <Link type="KeyBindingOverview" label="Key Bindings"/> for details.
1391 @is_non_item_type
1392 KeyBinding: KeyBinding
1393 }
1394
1395 item! { FocusScope {
1396 /// Is `true` when the element has keyboard focus.
1397 out property <bool> has-focus;
1398 /// When false, the FocusScope will not accept focus, neither via click nor via tab focus traversal, not even programmatically.
1399 ///
1400 /// A parent `FocusScope` will still receive key events from child `FocusScope`s that were rejected, even if `enabled` is set to false.
1401 in property <bool> enabled: true;
1402 /// When true, the `FocusScope` will make itself the focused element when clicked.
1403 ///
1404 /// This property has no effect if the `enabled` property is set to false.
1405 in property <bool> focus-on-click: true;
1406 /// When true, the `FocusScope` will accept focus as part of the tab focus traversal.
1407 ///
1408 /// This property has no effect if the `enabled` property is set to false.
1409 in property <bool> focus-on-tab-navigation: true;
1410 //! ## Functions
1411 //!
1412 //! ### focus()
1413 //! Call this function to transfer keyboard focus to this `FocusScope`, to receive future <Link type="KeyEvent" />s.
1414 //!
1415 //! ### clear-focus()
1416 //! Call this function to remove keyboard focus from this `FocusScope` if it currently has the focus. See also <Link type="FocusHandling" />.
1417 /// This function is called during key event handling, *before* `key-pressed` is called. Use this to intercept key press events. The returned <Link type="EventResult" />
1418 /// indicates whether to accept or reject the event. Rejected events are forwarded to the parent element.
1419 callback capture-key-pressed(event: KeyEvent) -> EventResult;
1420 /// This function is called during key event handling, *before* `key-released` is called. Use this to intercept key release events. The returned <Link type="EventResult" />
1421 /// indicates whether to accept or reject the event. Rejected events are forwarded to the parent element.
1422 callback capture-key-released(event: KeyEvent) -> EventResult;
1423 /// Invoked when a key is pressed, the argument is a <Link type="KeyEvent" /> struct. The returned <Link type="EventResult" />
1424 /// indicates whether to accept or reject the event. Rejected events are forwarded to the parent element.
1425 callback key-pressed(event: KeyEvent) -> EventResult;
1426 /// Invoked when a key is released, the argument is a <Link type="KeyEvent" /> struct. The returned <Link type="EventResult" />
1427 /// indicates whether to accept or reject the event. Rejected events are forwarded to the parent element.
1428 callback key-released(event: KeyEvent) -> EventResult;
1429 /// Invoked when the focus on the `FocusScope` has changed. The argument is a a <Link type="FocusReason" /> enum containing the reason for focus change.
1430 callback focus-changed-event(reason: FocusReason);
1431 /// Invoked when the `FocusScope` gains focus. The argument is a a <Link type="FocusReason" /> enum containing the reason for focus gain.
1432 callback focus-gained(reason: FocusReason);
1433 /// Invoked when the `FocusScope` loses focus. The argument is a a <Link type="FocusReason" /> enum containing the reason for focus loss.
1434 callback focus-lost(reason: FocusReason);
1435
1436
1437
1438 } }
1439
1440 element! {
1441 /// ```slint playground
1442 /// export component Example inherits Window {
1443 /// width: 100px;
1444 /// height: 100px;
1445 /// forward-focus: my-key-handler;
1446 /// my-key-handler := FocusScope {
1447 /// key-pressed(event) => {
1448 /// debug(event.text);
1449 /// if (event.modifiers.control) {
1450 /// debug("control was pressed during this event");
1451 /// }
1452 /// if (event.text == Key.Escape) {
1453 /// debug("Esc key was pressed")
1454 /// }
1455 /// accept
1456 /// }
1457 ///
1458 /// KeyBinding {
1459 /// keys: @keys(Control + X);
1460 /// activated => {
1461 /// debug("Control + X pressed")
1462 /// }
1463 /// }
1464 /// }
1465 /// }
1466 /// ```
1467 ///
1468 /// The `FocusScope` can react to <Link type="KeyBindingOverview" label="keyboard shortcuts"/> using the <Link type="KeyBinding" label="KeyBinding element"/>, and exposes callbacks to handle key events manually.
1469 /// Note that `FocusScope` will only handle key events when it either `has-focus`, or when it surrounds another FocusScope that `has-focus` (see [Key Event Delivery](#key-event-delivery))
1470 ///
1471 /// The <Link type="KeyEvent" /> has a text property, which is a character of the key entered.
1472 /// When a non-printable key is pressed, the character will be either a control character,
1473 /// or it will be mapped to a private unicode character. The mapping of these non-printable, special characters is available in the <Link type="KeyEvent"/> namespace
1474 ///
1475 /// ## Key Event Delivery
1476 ///
1477 /// Key events are delivered to the element that `has-focus`.
1478 ///
1479 /// Before attempting to deliver the `KeyEvent`, it is checked whether some other element wants to intercept the `KeyEvent`.
1480 /// Visiting all the elements starting at the Window, going down toward the focused element, `capture_key_pressed` or `capture_key_released` is called.
1481 /// If any of these returns `EventResult::accept`, then key event processing stops at this point. If `EventResult::reject` is returned,
1482 /// then event delivery continues.
1483 ///
1484 /// If no element captures the `KeyEvent`, then the `KeyEvent` is delivered to the focused element by calling `key-pressed` or `key-released`.
1485 /// If these callbacks return `EventResult::accept`, then event delivery is finished and the event has been handled. Otherwise, (recursively) try
1486 /// to deliver the key event to the parent element.
1487 /// \group:keyboard-input
1488 @accepts_focus @expands_to_parent_geometry
1489 FocusScope: FocusScope {
1490 children: KeyBinding;
1491 }
1492 }
1493
1494 item! { Flickable: Empty {
1495 /// ```slint imageAlt="flickable interactive" width="200" height="200"
1496 /// Flickable {
1497 /// interactive: false;
1498 /// }
1499 /// ```
1500 /// When false, the content can't be panned by the user, neither by dragging with the mouse
1501 /// nor with touch.
1502 in property <bool> interactive: true;
1503 /// When true, the content can be scrolled by clicking on it and dragging it with the cursor.
1504 /// Panning with a touch screen is only affected by `interactive`.
1505 in property <bool> mouse-drag-pan-enabled: true;
1506 /// The total width of the scrollable content.
1507 @shadowable in property <length> content-width;
1508 /// The total height of the scrollable content.
1509 @shadowable in property <length> content-height;
1510 /// The position of the scrollable content relative to the `Flickable`. This is usually a negative value.
1511 @shadowable in-out property <length> content-x;
1512 /// The position of the scrollable content relative to the `Flickable`. This is usually a negative value.
1513 @shadowable in-out property <length> content-y;
1514 @deprecated in property <length> viewport-width <=> content-width;
1515 @deprecated in property <length> viewport-height <=> content-height;
1516 @deprecated in-out property <length> viewport-x <=> content-x;
1517 @deprecated in-out property <length> viewport-y <=> content-y;
1518 /// Invoked when `content-x` or `content-y` is changed by a user action (dragging, scrolling).
1519 callback flicked;
1520 } }
1521
1522 element! {
1523 /// ```slint playground
1524 /// export component Example inherits Window {
1525 /// width: 270px;
1526 /// height: 100px;
1527 ///
1528 /// Flickable {
1529 /// content-height: 300px;
1530 /// Text {
1531 /// x:0;
1532 /// y: 150px;
1533 /// text: "This is some text that you have to scroll to see";
1534 /// }
1535 /// }
1536 /// }
1537 /// ```
1538 ///
1539 /// The `Flickable` is a low-level element that is the base for scrollable
1540 /// widgets, such as the <Link type="ScrollView"/> or <Link type="ListView"/>.
1541 /// When the `content-width` or the `content-height` is greater than the parent's `width` or `height`
1542 /// respectively, the element becomes scrollable.
1543 ///
1544 /// When unset, the `content-width` and `content-height` are
1545 /// calculated automatically based on the `Flickable`'s children. This isn't the
1546 /// case when using a `for` loop to populate the elements. This is a bug tracked in
1547 /// issue [#407](https://github.com/slint-ui/slint/issues/407).
1548 /// The maximum and preferred size of the `Flickable` are based on the content size.
1549 ///
1550 /// Note that the `Flickable` doesn't create a scrollbar.
1551 /// You can use a <Link type="ScrollView"/> instead or add your own scroll bars.
1552 ///
1553 /// When not part of a layout, its width or height defaults to 100% of the parent
1554 /// element when not specified.
1555 ///
1556 /// ## Pointer Event Interaction
1557 ///
1558 /// If the `Flickable`'s area contains elements that use `TouchArea` to act on clicking, such as `Button`
1559 /// widgets, then the following algorithm is used to distinguish between the user's intent of scrolling or
1560 /// interacting with `TouchArea` elements:
1561 ///
1562 /// 1. If the `Flickable`'s `interactive` property is `false`, all events are forwarded to elements underneath.
1563 /// If `mouse-drag-pan-enabled` is `false`, only mouse events are forwarded this way, while touch events keep panning.
1564 /// 2. If a press event is received where the event's coordinates interact with a `TouchArea`, the event is stored
1565 /// and any subsequent move and release events are handled as follows:
1566 /// 1. If 100ms elapse without any events, the stored press event is delivered to the `TouchArea`.
1567 /// 2. If a release event is received before 100ms have elapsed, the stored press event as well as the
1568 /// release event are immediately delivered to the `TouchArea` and the algorithm resets.
1569 /// 3. Any move events received will start a flicking operation on the `Flickable` if all of the following
1570 /// conditions are met:
1571 /// 1. The event is received before 500ms have elapsed since receiving the press event.
1572 /// 2. The distance to the press event exceeds 8 logical pixels in an orientation in which we are allowed to move.
1573 /// If `Flickable` decides to flick, any press event sent previously to a `TouchArea`, is followed up
1574 /// by an exit event. During the phase of receiving move events, the flickable follows the coordinates.
1575 /// 3. If the interaction of press, move, and release events begins at coordinates that do not intersect with
1576 /// a `TouchArea`, then `Flickable` will flick immediately on pointer move events when the euclidean distance
1577 /// to the coordinates of the press event exceeds 8 logical pixels.
1578 ///
1579 /// If no element underneath claims a press, the `Flickable` itself only intercepts it when it can actually pan in some direction,
1580 /// i.e. when its `content-width`/`content-height` exceed its own size, or its content is currently scrolled away from the origin.
1581 /// Otherwise the event is forwarded to elements underneath it,
1582 /// the same way wheel/scroll events already are (see below).
1583 ///
1584 /// ## Wheel/Scroll Event Interaction
1585 ///
1586 /// The `Flickable` also supports scrolling with the mouse wheel and touchpad scroll gestures.
1587 /// It will scroll regardless of the `interactive` and `mouse-drag-pan-enabled` properties.
1588 /// If the `Flickable` can scroll in the event's direction, the event will be intercepted.
1589 /// If the Flickable can't scroll in the direction of the event, the event will be forwarded to the parent.
1590 /// \group:gestures
1591 @expands_to_parent_geometry
1592 Flickable: Flickable
1593 }
1594
1595 item! { SwipeGestureHandler {
1596 /// When disabled, the `SwipeGestureHandler` doesn't recognize any gestures.
1597 in property <bool> enabled: true;
1598 /// The position of the pointer when the swipe started.
1599 out property <Point> pressed-position;
1600 /// The current pointer position.
1601 out property <Point> current-position;
1602 /// `true` while the gesture is recognized, false otherwise.
1603 out property <bool> swiping;
1604 //! ### Handle swipe directions properties
1605 /// \default false
1606 in property <bool> handle-swipe-left;
1607 /// \default false
1608 in property <bool> handle-swipe-right;
1609 /// \default false
1610 in property <bool> handle-swipe-up;
1611 /// \default false
1612 in property <bool> handle-swipe-down;
1613
1614 // For the future
1615 //in property <length> swipe-distance-threshold: 8px;
1616 //in property <duration> swipe-duration-threshold: 500ms;
1617 // in property <bool> delays-propagation;
1618 //in property <duration> propagation-delay: 100ms;
1619 // in property <int> required-touch-points: 1;
1620 //callback swipe-recognized();
1621
1622 /// Invoked when the pointer is moved.
1623 callback moved;
1624 /// Invoked after the swipe gesture was recognized and the pointer was released.
1625 callback swiped;
1626 /// Invoked when the swipe is cancelled programmatically or if the window loses focus.
1627 callback cancelled;
1628
1629 /// Cancel any on-going swipe gesture recognition.
1630 function cancel() { }
1631 } }
1632
1633 element! {
1634 /// Use the `SwipeGestureHandler` to handle swipe gesture in some particular direction.
1635 /// Recognition is limited to the element's geometry.
1636 ///
1637 /// The `SwipeGestureHandler` recognizes touchscreen swipes and mouse drags.
1638 ///
1639 /// ```slint playground
1640 /// export component Example inherits Window {
1641 /// width: 270px;
1642 /// height: 100px;
1643 ///
1644 /// property <int> current-page: 0;
1645 ///
1646 /// sgr := SwipeGestureHandler {
1647 /// handle-swipe-right: current-page > 0;
1648 /// handle-swipe-left: current-page < 5;
1649 /// swiped => {
1650 /// if self.current-position.x > self.pressed-position.x + self.width / 4 {
1651 /// current-page -= 1;
1652 /// } else if self.current-position.x < self.pressed-position.x - self.width / 4 {
1653 /// current-page += 1;
1654 /// }
1655 /// }
1656 ///
1657 /// HorizontalLayout {
1658 /// property <length> position: - current-page * root.width;
1659 /// animate position { duration: 200ms; easing: ease-in-out; }
1660 /// property <length> swipe-offset;
1661 /// x: position + swipe-offset;
1662 /// states [
1663 /// swiping when sgr.swiping : {
1664 /// swipe-offset: sgr.current-position.x - sgr.pressed-position.x;
1665 /// out { animate swipe-offset { duration: 200ms; easing: ease-in-out; } }
1666 /// }
1667 /// ]
1668 ///
1669 /// Rectangle { width: root.width; background: green; }
1670 /// Rectangle { width: root.width; background: limegreen; }
1671 /// Rectangle { width: root.width; background: yellow; }
1672 /// Rectangle { width: root.width; background: orange; }
1673 /// Rectangle { width: root.width; background: red; }
1674 /// Rectangle { width: root.width; background: violet; }
1675 /// }
1676 /// }
1677 /// }
1678 /// ```
1679 ///
1680 /// Specify the different swipe directions you'd like to handle by setting the `handle-swipe-left/right/up/down` properties and react to the gesture in the `swiped` callback.
1681 ///
1682 /// Pointer press events on the recognizer's area are forwarded to the children with a small delay.
1683 /// If the pointer moves by more than 8 logical pixels in one of the enabled swipe directions, the gesture is recognized, and events are no longer forwarded to the children.
1684 ///
1685 /// To keep the gesture-recognition area large enough to feel responsive, wrap the `SwipeGestureHandler` around the controls it should
1686 /// handle swipes for, rather than placing it as a sibling before them.
1687 ///
1688 /// :::note{Known issue}
1689 /// [#6781](https://github.com/slint-ui/slint/issues/6781): `SwipeGestureHandler` can interfere with other controls that also recognize swipe gestures, such as `Slider`.
1690 /// Work around it by disabling the relevant `handle-swipe-*` properties while the child is being interacted with, for example in a
1691 /// `Slider`'s `changed` and `released` callbacks.
1692 /// :::
1693 /// \group:gestures
1694 @expands_to_parent_geometry
1695 SwipeGestureHandler: SwipeGestureHandler
1696 }
1697
1698 item! { ScaleRotateGestureHandler {
1699 /// When disabled, the `ScaleRotateGestureHandler` doesn't recognize any gestures and any on-going gesture is cancelled.
1700 in property <bool> enabled: true;
1701
1702 /// `true` while a gesture is being recognized, `false` otherwise.
1703 out property <bool> active;
1704 /// The cumulative scale factor of the gesture. Always starts at `1.0` when the gesture begins.
1705 /// A value greater than `1.0` means zooming in, less than `1.0` means zooming out.
1706 /// When the gesture is not active, the value is `1.0`.
1707 out property <float> scale;
1708 /// The cumulative rotation angle of the gesture. Always starts at `0deg` when the gesture begins.
1709 /// Positive values indicate clockwise rotation, negative values indicate counter-clockwise rotation.
1710 /// When the gesture is not active, the value is `0deg`.
1711 out property <angle> rotation;
1712 /// The center point of the gesture, in the coordinate system of the `ScaleRotateGestureHandler`.
1713 /// For two-finger touch input, this is the midpoint between the two fingers.
1714 /// For trackpad gestures, this is the mouse cursor position.
1715 out property <Point> center;
1716
1717 /// Invoked when a gesture begins. Use this to capture the initial state you want to transform.
1718 callback started;
1719 /// Invoked whenever the `scale`, `rotation`, or `center` changes during the gesture.
1720 callback updated;
1721 /// Invoked when the gesture completes normally (fingers lifted).
1722 callback ended;
1723 /// Invoked when the gesture is cancelled, for example when the handler is disabled during an active gesture or the window loses focus.
1724 callback cancelled;
1725 } }
1726
1727 element! {
1728 /// Use the `ScaleRotateGestureHandler` to handle pinch and rotation gestures.
1729 /// Recognition is limited to the element's geometry.
1730 ///
1731 /// The `ScaleRoteGestureHandler` supports touchscreens on all platforms, and additionally supports trackpad gestures on macOS and iOS.
1732 ///
1733 /// ```slint playground
1734 /// export component Example inherits Window {
1735 /// width: 400px;
1736 /// height: 400px;
1737 ///
1738 /// property <float> start-scale;
1739 /// property <angle> start-rotation;
1740 ///
1741 /// gesture := ScaleRotateGestureHandler {
1742 /// started => {
1743 /// start-scale = rect.current-scale;
1744 /// start-rotation = rect.current-rotation;
1745 /// }
1746 /// updated => {
1747 /// rect.current-scale = start-scale * self.scale;
1748 /// rect.current-rotation = start-rotation + self.rotation;
1749 /// }
1750 ///
1751 /// rect := Rectangle {
1752 /// background: @radial-gradient(circle, #4488ff, #224488);
1753 /// border-radius: 8px;
1754 ///
1755 /// property <float> current-scale: 1.0;
1756 /// property <angle> current-rotation: 0deg;
1757 /// width: 200px * self.current-scale;
1758 /// height: 200px * self.current-scale;
1759 /// x: (parent.width - self.width) / 2;
1760 /// y: (parent.height - self.height) / 2;
1761 ///
1762 /// Text {
1763 /// text: "Pinch & rotate";
1764 /// color: white;
1765 /// }
1766 /// }
1767 /// }
1768 /// }
1769 /// ```
1770 ///
1771 /// The `scale` property provides a cumulative scale factor relative to the start of the gesture (starting at `1.0`).
1772 /// The `rotation` property provides a cumulative rotation angle (starting at `0deg`).
1773 /// Use the `started` callback to capture your initial state, then multiply by `scale` and add `rotation` in the `updated` callback to apply the gesture.
1774 /// \group:gestures
1775 @expands_to_parent_geometry
1776 ScaleRotateGestureHandler: ScaleRotateGestureHandler
1777 }
1778
1779 item! { DragArea {
1780 /// Set to `false` to stop the `DragArea` from starting drags.
1781 /// Events still reach the child elements.
1782 in property <bool> enabled: true;
1783 /// The payload that's transferred to a <Link type="DropArea" /> when a drop happens.
1784 in property <data-transfer> data;
1785 /// Bitmap drawn under the cursor while a drag is in flight.
1786 /// When unset (the default empty image), no overlay is drawn.
1787 in property <image> drag-image;
1788 /// Horizontal hot spot within `drag-image` that aligns with the cursor, in image pixel coordinates.
1789 /// `0` puts the image's left edge at the cursor; following HTML5's `setDragImage(image, x, y)` convention.
1790 in property <int> drag-image-offset-x;
1791 /// Vertical hot spot within `drag-image` that aligns with the cursor, in image pixel coordinates.
1792 /// `0` puts the image's top edge at the cursor.
1793 in property <int> drag-image-offset-y;
1794 /// Whether the source allows the drop to copy the data. The source retains the data.
1795 in property <bool> allow-copy;
1796 /// Whether the source allows the drop to move the data. The source should remove the
1797 /// original from its model in the `drag-finished` callback when the action is `move`.
1798 in property <bool> allow-move;
1799 /// Whether the source allows the drop to link to the data. Neither side gives up ownership.
1800 in property <bool> allow-link;
1801 /// `true` once the press has crossed the drag threshold and a drag is in flight,
1802 /// `false` once the drop completes or the drag is cancelled.
1803 out property <bool> dragging;
1804 /// Fires when the drag ends: with the chosen action on a successful drop, or with
1805 /// `DragAction.none` if the drag was cancelled.
1806 callback drag-finished(action: DragAction);
1807 } }
1808
1809 element! {
1810 /// Use `DragArea` to make any part of the UI draggable.
1811 /// A drag starts when the user presses the mouse inside the area and moves past a small threshold,
1812 /// and the value bound to `data` becomes the drag payload delivered to a <Link type="DropArea" />.
1813 /// A click doesn't start a drag, so child elements like <Link type="TouchArea" /> stay interactive.
1814 ///
1815 /// The payload is a `data-transfer` value, which abstracts over the file-type transfer mechanisms supported by each platform.
1816 /// `data-transfer` values are opaque in Slint code:
1817 /// construct and read them via callbacks implemented in the host language.
1818 ///
1819 /// The source declares which actions it permits via `allow-copy`, `allow-move`, and `allow-link`.
1820 /// At least one must be set to true; a `DragArea` that permits no action never starts a drag.
1821 /// When no modifier key is pressed, the proposed action is the first allowed of move, copy, link;
1822 /// modifier keys request a specific action (Ctrl -> copy, Shift -> move, Ctrl+Shift -> link).
1823 /// The target picks the final action from this set in its `can-drop` callback. Once a drop completes
1824 /// (or the drag is cancelled), `drag-finished(action)` fires so a "move" source can remove the original data.
1825 ///
1826 /// See <Link type="DragAndDrop" /> for a usage guide and a complete example.
1827 /// \group:drag-and-drop
1828 @expands_to_parent_geometry
1829 DragArea: DragArea
1830 }
1831
1832 item! { DropArea {
1833 /// Set to `false` to stop the `DropArea` from accepting any drops.
1834 in property <bool> enabled: true;
1835 /// Return the action this target wants to perform with the drag, or `DragAction.none` to reject.
1836 /// The runtime clamps the returned value to the source's allowed set: anything the source did not
1837 /// allow is treated as `none`.
1838 /// The argument is a <Link type="DropEvent" /> describing the drag.
1839 callback can-drop(event: DropEvent) -> DragAction;
1840 /// Invoked when the user releases the mouse over the area after `can-drop` returned a non-`none`
1841 /// action. Use this callback to read `event.data` and apply the drop. The returned
1842 /// `DragAction` is reported to the source via `drag-finished`; return `event.proposed-action`
1843 /// to mirror what was negotiated during hover, or a different action to refine the choice at
1844 /// drop time. The runtime clamps the return value against the source's allowed set.
1845 callback dropped(event: DropEvent) -> DragAction;
1846 /// `true` while an accepted drag hovers over the area, `false` otherwise.
1847 /// Bind it to a visual property to give the user feedback, for example a background color.
1848 out property <bool> has-drag;
1849 /// The action the runtime is currently negotiating with the source: `none` when no drag is hovering,
1850 /// or `copy`/`move`/`link` once a concrete action is settled.
1851 out property <DragAction> current-action;
1852 } }
1853
1854 element! {
1855 /// Use `DropArea` to accept drops coming from a <Link type="DragArea" />, or from another application on platforms that support it.
1856 /// The `can-drop` callback runs while the cursor moves over the area to decide whether to accept the drag,
1857 /// and which action (copy/move/link) to perform.
1858 /// The `dropped` callback runs when the user releases the mouse inside the area after `can-drop` returned
1859 /// a non-`none` action.
1860 ///
1861 /// See <Link type="DragAndDrop" /> for a usage guide and a complete example.
1862 /// \group:drag-and-drop
1863 @expands_to_parent_geometry
1864 DropArea: DropArea
1865 }
1866
1867 item! { MenuItem {
1868 /// The title shown for this menu item.
1869 /// \default ""
1870 in property <string> title;
1871 /// Invoked when the menu entry is activated.
1872 callback activated;
1873 /// When disabled, the `MenuItem` can be selected but not activated.
1874 in property <bool> enabled: true;
1875 /// When true, the `MenuItem` can be checked. The value of the `checked` property is toggled when the user activates the menu item.
1876 /// \default false
1877 in property <bool> checkable: false;
1878 /// The keyboard shortcut for this `MenuItem`.
1879 ///
1880 /// This property can only be set in a `MenuItem` that is part of a <Link type="MenuBar"/>.
1881 in property <keys> shortcut;
1882 /// When true, a checkmark will be shown next to the title of the `MenuItem`.
1883 /// \default false
1884 in-out property <bool> checked: false;
1885 /// The icon shown next to the title.
1886 in property <image> icon;
1887 } }
1888
1889 element! {
1890 /// A `MenuItem` represents a single menu entry. It must be a child of a `Menu` element.
1891 @is_non_item_type @disallow_global_types_as_child_elements
1892 MenuItem: MenuItem
1893 }
1894
1895 element! {
1896 /// A `MenuSeparator` represents a separator in a menu.
1897 /// It cannot have children, and doesn't have properties or callbacks.
1898 /// MenuSeparator at the beginning or end of a menu will not be visible.
1899 /// Consecutive `MenuSeparator`s will be merged into one.
1900 @is_non_item_type @disallow_global_types_as_child_elements
1901 MenuSeparator
1902 }
1903
1904 element! {
1905 /// Place the `Menu` element in a <Link type="MenuBar" />, a `ContextMenuArea`, or within another `Menu`.
1906 /// Use `MenuItem` children of individual menu items, `Menu` children to create sub-menus, and `MenuSeparator` to create separators.
1907 @is_non_item_type @disallow_global_types_as_child_elements
1908 Menu {
1909 /// This is the label of the menu as written in the menu bar or in the parent menu.
1910 /// \default ""
1911 in property <string> title;
1912 /// When disabled, the `Menu` can be selected but not activated.
1913 in property <bool> enabled: true;
1914 /// The icon shown next to the title when in a parent menu.
1915 in property <image> icon;
1916
1917
1918 children: MenuItem, MenuSeparator, Menu;
1919 }
1920 }
1921
1922 element! {
1923 /// Use the `MenuBar` element in a <Link type="Window" /> to declare the structure of a menu bar, including the actual
1924 /// menus and sub-menus.
1925 ///
1926 /// :::note{Note}
1927 /// There can only be one `MenuBar` element in a `Window` and it must not be in a `for` or a `if`.
1928 /// :::
1929 ///
1930 /// The `MenuBar` doesn't have properties, but it must contain <Link type="Menu" /> as children that represent top level entries in the menu bar.
1931 ///
1932 /// Depending on the platform, the menu bar might be native or rendered by Slint.
1933 /// This means that for example, on macOS, the menu bar will be at the top of the screen.
1934 /// The `width` and `height` property of the <Link type="Window" /> define the client area, excluding the menu bar.
1935 /// The `x` and `y` properties of `Window` children are also relative to the client area.
1936 ///
1937 /// ### Example
1938 ///
1939 /// ```slint
1940 /// export component Example inherits Window {
1941 /// MenuBar {
1942 /// Menu {
1943 /// title: @tr("File");
1944 /// MenuItem {
1945 /// title: @tr("New");
1946 /// activated => { file-new(); }
1947 /// shortcut: @keys(Control + N);
1948 /// }
1949 /// MenuItem {
1950 /// title: @tr("Open");
1951 /// activated => { file-open(); }
1952 /// shortcut: @keys(Control + O);
1953 /// }
1954 /// }
1955 /// Menu {
1956 /// title: @tr("Edit");
1957 /// MenuItem {
1958 /// title: @tr("Copy");
1959 /// }
1960 /// MenuItem {
1961 /// title: @tr("Paste");
1962 /// }
1963 /// MenuSeparator {}
1964 /// Menu {
1965 /// title: @tr("Find");
1966 /// MenuItem {
1967 /// title: @tr("Find in document...");
1968 /// }
1969 /// MenuItem {
1970 /// title: @tr("Find Next");
1971 /// }
1972 /// MenuItem {
1973 /// title: @tr("Find Previous");
1974 /// }
1975 /// }
1976 /// }
1977 /// }
1978 ///
1979 /// callback file-new();
1980 /// callback file-open();
1981 ///
1982 /// // ... actual window content goes here
1983 /// }
1984 /// ```
1985 /// \skip_children
1986 @is_non_item_type @disallow_global_types_as_child_elements
1987 MenuBar {
1988 /// Whether this menu bar should be visible. If the menu bar is not visible, the menu bar will not take up any space but shortcuts will still function.
1989 /// \default true
1990 in property <bool> visible: true;
1991
1992
1993 children: Menu;
1994 }
1995 }
1996
1997 item! { ContextMenu: Empty {
1998 callback activated(entry: MenuEntry);
1999 callback sub-menu(entry: MenuEntry) -> [MenuEntry];
2000 callback show(position: Point);
2001 function close() { }
2002 @pure function is-open() -> bool { }
2003 in property <bool> enabled: true;
2004 } }
2005
2006 element! {
2007 // The NativeItem, exported as ContextMenuInternal for the style
2008 @is_internal @expands_to_parent_geometry
2009 ContextMenuInternal: ContextMenu {
2010 in property <[MenuEntry]> entries;
2011 }
2012 }
2013
2014 element! {
2015 // Lowered in lower_menus pass.
2016 /// Use the non-visual `ContextMenuArea` element to declare an area where the user can show a context menu.
2017 ///
2018 /// The context menu is shown if the user right-clicks on the area covered by the `ContextMenuArea` element,
2019 /// or if the user presses the "Menu" key on their keyboard while a `FocusScope` within the `ContextMenuArea` has focus.
2020 /// On Android, the menu is shown with a long press.
2021 /// Call the `show()` function on the `ContextMenuArea` element to programmatically show the context menu.
2022 ///
2023 /// One of the children of the `ContextMenuArea` must be a `Menu` element, which defines the menu to be shown.
2024 /// There can be at most one `Menu` child, all other children must be of a different type and will be shown as regular visual children.
2025 /// Define the structure of the menu by placing `MenuItem` or `Menu` elements inside that `Menu`.
2026 ///
2027 /// \footer
2028 /// ## Example
2029 ///
2030 /// ```slint
2031 /// export component Example {
2032 /// ContextMenuArea {
2033 /// Menu {
2034 /// MenuItem {
2035 /// title: @tr("Cut");
2036 /// activated => { debug("Cut"); }
2037 /// }
2038 /// MenuItem {
2039 /// title: @tr("Copy");
2040 /// activated => { debug("Copy"); }
2041 /// }
2042 /// MenuItem {
2043 /// title: @tr("Paste");
2044 /// activated => { debug("Paste"); }
2045 /// }
2046 /// MenuSeparator {}
2047 /// Menu {
2048 /// title: @tr("Find");
2049 /// MenuItem {
2050 /// title: @tr("Find Next");
2051 /// }
2052 /// MenuItem {
2053 /// title: @tr("Find Previous");
2054 /// }
2055 /// }
2056 /// }
2057 /// }
2058 /// }
2059 /// ```
2060 /// \group:window
2061 @expands_to_parent_geometry
2062 ContextMenuArea: Empty {
2063 //! ## Function
2064 //!
2065 //! ### show(Point)
2066 //!
2067 //! Call this function to programmatically show the context menu at the given position relative to the `ContextMenuArea` element.
2068 //!
2069 //! ## close()
2070 //!
2071 //! Close the context menu if it's currently open.
2072 // This is actually function as part of out interface, but a callback as much is the runtime concerned
2073 callback show(position: Point);
2074 function close() { }
2075
2076
2077 //! ### enabled
2078 //!
2079 //! <SlintProperty propName="enabled" typeName="bool" defaultValue="true">
2080 //! When disabled, the `Menu` is not showing.
2081 //! </SlintProperty>
2082 in property <bool> enabled: true;
2083 children: Menu;
2084 }
2085 }
2086
2087 item! { WindowItem {
2088 /// The width of the window. \{#sls.ref.window.width}
2089 ///
2090 /// <OnlyInSC>
2091 /// The application gives the window its size when it creates the component, so this is a value the file reads,
2092 /// and binding it is an error. \{#sls.ref.window.width-out}
2093 /// </OnlyInSC>
2094 @sc in-out property <length> width;
2095 /// The height of the window. \{#sls.ref.window.height}
2096 ///
2097 /// <OnlyInSC>
2098 /// The application gives the window its size when it creates the component, so this is a value the file reads,
2099 /// and binding it is an error. \{#sls.ref.window.height-out}
2100 /// </OnlyInSC>
2101 @sc in-out property <length> height;
2102 /// Whether the window should be placed above all other windows on window managers supporting it.
2103 /// \default false
2104 in property <bool> always-on-top;
2105 /// Whether to display the Window in full-screen mode. In full-screen mode the Window will occupy the entire screen, it will not be resizable, and it will not display the title bar.
2106 /// \default true if 'SLINT_FULLSCREEN' environment variable is set, otherwise false
2107 in-out property <bool> full-screen;
2108 /// Whether the window is minimized. Setting this to true minimizes the window.
2109 @shadowable in-out property <bool> minimized;
2110 /// Whether the window is maximized. Setting this to true maximizes the window.
2111 @shadowable in-out property <bool> maximized;
2112 /// The background brush of the `Window`. It is painted first, covering the whole window. \{#sls.ref.window.background}
2113 ///
2114 /// <OnlyInSC>
2115 /// This background must be an opaque color literal.
2116 /// Rendering writes every pixel of the frame buffer, and there's nothing
2117 /// underneath the window for a translucent background to blend with. \{#sls.ref.window.opaque}
2118 /// </OnlyInSC>
2119 /// \default depends on the style
2120 @sc in property <brush> background; // StyleMetrics.background set in apply_default_properties_from_style
2121 @deprecated in property <brush> color <=> background;
2122 /// The font family to use as default in text elements inside this window, that don't have their `font-family` property set.
2123 in property <string> default-font-family;
2124 /// The font size to use as default in text elements inside this window, that don't have their `font-size` property set. The value of this property also forms the basis for relative font sizes.
2125 /// \default 0
2126 in property <length> default-font-size;
2127 /// The font weight to use as default in text elements inside this window, that don't have their `font-weight` property set. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight. Use the <Link type="FontWeight" /> namespace for predefined constants.
2128 in property <int> default-font-weight;
2129 /// The window icon shown in the title bar or the task bar on window managers supporting it.
2130 in property <image> icon;
2131 /// Whether the window should be borderless/frameless or not.
2132 /// \default false
2133 in property <bool> no-frame;
2134 /// :::caution[Caution]
2135 /// This property is `winit` only for now.
2136 /// :::
2137 /// Size of the resize border in borderless/frameless windows.
2138 /// \default 0
2139 in property <length> resize-border-width;
2140 /// The window title that is shown in the title bar.
2141 /// \default the name of the running program
2142 in property <string> title { BuiltinFunction.DefaultWindowTitle }
2143 /// Some devices, such as mobile phones, allow programs to overlap the system UI. A few examples for this are the notch on iPhones, the window buttons on macOS on windows that extend their content over the titlebar and the system bar on Android. This property exposes the amount of space at the edges of the window that can be drawn to but where no interactive elements should be placed. On most devices, this is 0 for all sides.
2144 out property <Edges> safe-area-insets;
2145 /// On mobile devices, virtual keyboards (aka software keyboards or onscreen keyboards) are displayed on top of the application. When such a keyboard is shown, this property denotes the position of the top left boundary of the rectangle covered by it in window coordinates.
2146 out property <Point> virtual-keyboard-position;
2147 /// On mobile devices, virtual keyboards (aka software keyboards or onscreen keyboards) are displayed on top of the application. When such a keyboard is shown, this property denotes the width and height of the rectangle covered by it in window coordinates.
2148 out property <Size> virtual-keyboard-size;
2149 /// Request that the window be closed.
2150 /// This triggers the `close-requested` callback, giving the application a chance to cancel the close.
2151 /// Returns `true` if the application accepted the close request; false otherwise.
2152 /// Returns `false` if called on a child `Window` element, which can't be closed independently.
2153 @shadowable function close() -> bool { }
2154 /// Hide this window. This also drops the strong reference on the window, so if this was
2155 /// the last reference, the event loop will quit.
2156 @shadowable function hide() { }
2157 } }
2158
2159 element! {
2160 /// `Window` is the root of the tree of elements that are visible on the screen. \{#sls.meta.window.purpose}
2161 ///
2162 /// <NotInSC>
2163 /// The `Window` geometry will be restricted by its layout constraints: Setting the `width` will result in a fixed width,
2164 /// and the window manager will respect the `min-width` and `max-width` so the window can't be resized bigger
2165 /// or smaller. The initial width can be controlled with the `preferred-width` property. The same applies to the `Window`s height.
2166 /// </NotInSC>
2167 ///
2168 /// <NotInSC>
2169 /// Use the <Link type="MenuBar" /> element to declare a menu bar for the window.
2170 /// </NotInSC>
2171 /// \group:window
2172 @sc
2173 Window: WindowItem {
2174 children: MenuBar;
2175 }
2176 }
2177
2178 item! { WindowMoveArea {
2179 /// Set to `false` to stop the `WindowMoveArea` from initiating window moves.
2180 /// Events still reach the child elements.
2181 in property <bool> enabled: true;
2182 } }
2183
2184 element! {
2185 /// Use `WindowMoveArea` to let the user move the window by dragging a region of your UI,
2186 /// such as a custom title bar in a window without native decorations (`no-frame: true`).
2187 ///
2188 /// The move starts when the user presses the left mouse button inside the area and drags past a small threshold.
2189 /// A plain click doesn't move the window, so child elements like <Link type="TouchArea" /> stay interactive.
2190 ///
2191 /// The windowing system performs the move.
2192 /// It requires a backend and platform with support for it (winit on Windows, macOS, X11, and Wayland; Qt).
2193 /// On platforms without support, the element does nothing.
2194 ///
2195 /// When not part of a layout, its width and height default to 100% of the parent element.
2196 ///
2197 /// ```slint playground
2198 /// export component Example inherits Window {
2199 /// no-frame: true;
2200 /// preferred-width: 400px;
2201 /// preferred-height: 300px;
2202 /// VerticalLayout {
2203 /// Rectangle {
2204 /// height: 32px;
2205 /// background: #444444;
2206 /// WindowMoveArea {
2207 /// HorizontalLayout {
2208 /// Text {
2209 /// text: "My Application";
2210 /// color: white;
2211 /// vertical-alignment: center;
2212 /// horizontal-alignment: center;
2213 /// }
2214 /// }
2215 /// }
2216 /// }
2217 /// Rectangle {
2218 /// background: white;
2219 /// }
2220 /// }
2221 /// }
2222 /// ```
2223 /// \group:window
2224 @expands_to_parent_geometry
2225 WindowMoveArea: WindowMoveArea
2226 }
2227
2228 item! { BoxShadow: Empty {
2229 in property <length> border-top-left-radius;
2230 in property <length> border-top-right-radius;
2231 in property <length> border-bottom-left-radius;
2232 in property <length> border-bottom-right-radius;
2233 in property <length> offset-x;
2234 in property <length> offset-y;
2235 in property <color> color;
2236 in property <length> blur;
2237 in property <length> spread;
2238 in property <bool> inset;
2239 } }
2240
2241 element! {
2242 @is_internal @expands_to_parent_geometry
2243 BoxShadow: BoxShadow
2244 }
2245
2246 item! { TextInput {
2247 /// The text rendered and editable by the user.
2248 /// \default ""
2249 in-out property <string> text;
2250 /// The name of the font family selected for rendering the text.
2251 in property <string> font-family;
2252 /// The font size of the text.
2253 in property <length> font-size;
2254 /// Whether or not the font face should be drawn italicized or not.
2255 /// \default false
2256 in property <bool> font-italic;
2257 /// The weight of the font. The values range from 100 (lightest) to 900 (thickest). 400 is the normal weight.
2258 in property <int> font-weight;
2259 /// The color of the text.
2260 /// \default depends on the style
2261 in property <brush> color; // StyleMetrics.default-text-color set in apply_default_properties_from_style
2262 /// The foreground color of the selection.
2263 in property <color> selection-foreground-color; // StyleMetrics.selection-foreground set in apply_default_properties_from_style
2264 /// The background color of the selection.
2265 in property <color> selection-background-color; // StyleMetrics.selection-background set in apply_default_properties_from_style
2266 /// The horizontal alignment of the text.
2267 in property <TextHorizontalAlignment> horizontal-alignment;
2268 /// The vertical alignment of the text.
2269 in property <TextVerticalAlignment> vertical-alignment;
2270 /// The way the text input wraps. Only makes sense when `single-line` is false.
2271 /// \default no-wrap
2272 in property <TextWrap> wrap;
2273 /// The letter spacing allows changing the spacing between the glyphs. A positive value increases the spacing and a negative value decreases the distance.
2274 /// \default 0
2275 in property <length> letter-spacing;
2276 /// The line height as a unitless factor (or a percentage: `150%` equals `1.5`) applied to
2277 /// the font's natural line height (ascent + descent + line gap). The default of `1` keeps
2278 /// the natural line height; larger values spread the lines apart, smaller values pull them
2279 /// together, and `0` collapses them onto each other. Negative or non-numeric values behave
2280 /// like `1`. Unlike CSS `line-height`, the factor is relative to the natural line height,
2281 /// not the font size, and keyword or length values aren't supported.
2282 /// \default 1
2283 in property <float> line-height-factor: 1;
2284 in property <length> width;
2285 in property <length> height;
2286 /// The height of the page used to compute how much to scroll when the user presses page up or page down.
2287 in property <length> page-height;
2288 /// The width of the text cursor.
2289 /// \default provided at run-time by the selected widget style
2290 in property <length> text-cursor-width; // StyleMetrics.text-cursor-width set in apply_default_properties_from_style
2291 /// Use this to configure `TextInput` for editing special input, such as password fields.
2292 /// \default text
2293 in property <InputType> input-type;
2294 /// Hints for the platform's input method (such as a soft keyboard), for example to configure auto-capitalization.
2295 /// The input method may take these hints into account, but might also ignore them.
2296 in property <InputMethodHints> input-method-hints;
2297 // Internal, undocumented property, only exposed for tests.
2298 out property <int> cursor-position-byte-offset;
2299 // Internal, undocumented property, only exposed for tests.
2300 out property <int> anchor-position-byte-offset;
2301 /// `TextInput` sets this to `true` when it's focused. Only then it receives <Link type="KeyEvent"/>s.
2302 out property <bool> has-focus;
2303 /// Invoked when the enter key is pressed.
2304 callback accepted;
2305 /// Invoked when the text has changed because the user modified it.
2306 callback edited;
2307 /// The cursor was moved to the new (x, y) position described by the `Point` argument.
2308 callback cursor-position-changed(position: Point);
2309 /// Invoked when a key is pressed, the argument is a <Link type="KeyEvent" /> struct. Use this callback to
2310 /// handle keys before `TextInput` does. Return `accept` to indicate that you've handled the event, or return
2311 /// `reject` to let `TextInput` handle it.
2312 callback key-pressed(event: KeyEvent) -> EventResult;
2313 /// Invoked when a key is released, the argument is a <Link type="KeyEvent" /> struct. Use this callback to
2314 /// handle keys before `TextInput` does. Return `accept` to indicate that you've handled the event, or return
2315 /// `reject` to let `TextInput` handle it.
2316 callback key-released(event: KeyEvent) -> EventResult;
2317 in property <bool> enabled: true;
2318 /// When set to `true`, the text is always rendered as a single line, regardless of new line separators in the text.
2319 in property <bool> single-line: true;
2320 /// When set to `true`, text editing via keyboard and mouse is disabled but selecting text is still enabled as well as editing text programmatically.
2321 in property <bool> read-only: false;
2322 // Internal, undocumented property, only exposed for IME.
2323 out property <string> preedit-text;
2324 /// The design metrics of the font scaled to the font pixel size used by the element.
2325 out property <FontMetrics> font-metrics { BuiltinFunction.ItemFontMetrics }
2326
2327
2328 /// Selects the text between two UTF-8 offsets.
2329 /// `anchor` is the end of the selection that stays put and `focus` the end the cursor moves to,
2330 /// so `focus` may precede `anchor` to select backwards.
2331 /// Pass the same value for both to place the text cursor at that offset without selecting anything.
2332 function set-selection-offsets(anchor: int, focus: int) { BuiltinFunction.SetSelectionOffsets }
2333 /// Selects all text.
2334 function select-all() { }
2335 /// Clears the selection.
2336 function clear-selection() { }
2337 /// Copies the selected text to the clipboard and removes it from the editable area.
2338 function cut() { }
2339 /// Copies the selected text to the clipboard.
2340 function copy() { }
2341 /// Pastes the text content of the clipboard at the cursor position.
2342 function paste() { }
2343 /// Undoes the last text operation.
2344 function undo() { }
2345 /// Redoes the last undone text operation.
2346 function redo() { }
2347 //! ### focus()
2348 //! Call this function to focus the text input and make it receive future keyboard events.
2349 //!
2350 //! ### clear-focus()
2351 //! Call this function to remove keyboard focus from this `TextInput` if it currently has the focus. See also <Link type="FocusHandling" />.
2352 } }
2353
2354 element! {
2355 /// The `TextInput` is a lower-level item that shows text and allows entering text.
2356 /// You should probably not use this directly, but instead use the <Link type="LineEdit" /> or <Link type="TextEdit" /> component.
2357 ///
2358 /// When not part of a layout, its width and height defaults to 100% of the parent element.
2359 ///
2360 /// The `TextInput` does not scroll automatically when the cursor is outside of the visible area.
2361 /// This is the responsibility of the enclosing widget to ensure using the `cursor-position-changed` callback.
2362 ///
2363 /// ## Example
2364 ///
2365 /// ```slint playground
2366 /// export component Example inherits Window {
2367 /// width: 270px;
2368 /// height: 40px;
2369 /// Rectangle {
2370 /// clip: true;
2371 ///
2372 /// TextInput {
2373 /// text: "Edit me";
2374 /// width: max(parent.width, self.preferred-width);
2375 /// vertical-alignment: center;
2376 ///
2377 /// private property <length> margin: 1rem;
2378 /// cursor-position-changed(cursor-position) => {
2379 /// if cursor-position.x + self.x < margin {
2380 /// self.x = - cursor-position.x + margin;
2381 /// } else if cursor-position.x + self.x > parent.width - margin - self.text-cursor-width {
2382 /// self.x = parent.width - cursor-position.x - margin - self.text-cursor-width;
2383 /// }
2384 /// }
2385 /// }
2386 /// }
2387 /// }
2388 /// ```
2389 ///
2390 /// \footer
2391 /// ## Accessibility
2392 ///
2393 /// By default, `TextInput` elements have the following accessibility properties set:
2394 ///
2395 /// - `accessible-role: text-input;`
2396 /// - `accessible-value: text;`
2397 /// - `accessible-enabled: enabled;`
2398 /// - `accessible-read-only: read-only; `
2399 /// \group:keyboard-input
2400 @accepts_focus @expands_to_parent_geometry
2401 TextInput: TextInput
2402 }
2403
2404 item! { Clip {
2405 in property <length> border-top-left-radius;
2406 in property <length> border-top-right-radius;
2407 in property <length> border-bottom-left-radius;
2408 in property <length> border-bottom-right-radius;
2409 in property <length> border-width;
2410 in property <bool> clip;
2411 in property <bool> is-visibility-clip;
2412 } }
2413
2414 element! {
2415 @is_internal @expands_to_parent_geometry
2416 Clip: Clip
2417 }
2418
2419 item! { Opacity {
2420 in property <float> opacity: 1;
2421 } }
2422
2423 element! {
2424 @is_internal @expands_to_parent_geometry
2425 Opacity: Opacity
2426 }
2427
2428 item! { Layer: Empty {
2429 in property <bool> cache-rendering-hint;
2430 } }
2431
2432 element! {
2433 @is_internal @expands_to_parent_geometry
2434 Layer: Layer
2435 }
2436
2437 element! {
2438 @is_non_item_type
2439 Row
2440 }
2441
2442 element! {
2443 /// `GridLayout` places elements on a grid.
2444 ///
2445 /// `GridLayout` covers its entire surface with cells. Cells are not aligned.
2446 /// The elements constituting the cells will be stretched inside their allocated
2447 /// space, unless their size constraints—like, e.g., `min-height` or
2448 /// `max-width`—work against this.
2449 ///
2450 ///
2451 /// ```slint playground imageAlt="gridlayout example" width="200" height="100"
2452 /// // This example uses the `Row` element
2453 /// export component Foo inherits Window {
2454 /// width: 200px;
2455 /// height: 200px;
2456 /// GridLayout {
2457 /// spacing: 5px;
2458 /// Row {
2459 /// Rectangle { background: red; }
2460 /// Rectangle { background: blue; }
2461 /// }
2462 /// Row {
2463 /// Rectangle { background: yellow; }
2464 /// Rectangle { background: green; }
2465 /// }
2466 /// }
2467 /// }
2468 /// ```
2469 ///
2470 ///
2471 /// ```slint playground imageAlt="gridlayout example2" width="200" height="100"
2472 /// // This example uses the `col` and `row` properties
2473 /// export component Foo inherits Window {
2474 /// width: 200px;
2475 /// height: 150px;
2476 /// GridLayout {
2477 /// Rectangle { background: red; }
2478 /// Rectangle { background: blue; }
2479 /// Rectangle { background: yellow; row: 1; }
2480 /// Rectangle { background: green; }
2481 /// Rectangle { background: black; col: 2; row: 0; }
2482 /// }
2483 /// }
2484 /// ```
2485 ///
2486 /// \footer
2487 /// ## Cell elements
2488 /// Cell elements inside a `GridLayout` obtain the following new properties. Any bindings to these properties must be compile-time constants:
2489 ///
2490 /// ### row
2491 /// <SlintProperty propName="row" typeName="int" defaultValue="auto">
2492 /// The index of the element's row within the grid. Setting this property resets the element's column to zero, unless explicitly set.
2493 /// </SlintProperty>
2494 ///
2495 /// ### col
2496 /// <SlintProperty propName="col" typeName="int" defaultValue="auto">
2497 /// The index of the element's column within the grid. Set this property to override the sequential column assignment (e.g., to skip a column).
2498 /// </SlintProperty>
2499 ///
2500 /// ### rowspan
2501 /// <SlintProperty propName="rowspan" typeName="int" defaultValue="1">
2502 /// The number of rows this element should span.
2503 /// </SlintProperty>
2504 ///
2505 /// ### colspan
2506 /// <SlintProperty propName="colspan" typeName="int" defaultValue="1">
2507 /// The number of columns this element should span.
2508 /// </SlintProperty>
2509 ///
2510 /// To implicitly sequentially assign row indices—just like with `col`—wrap cell elements in `Row` elements.
2511 ///
2512 /// The following example creates a 2-by-2 grid with `Row` elements, omitting one cell:
2513 ///
2514 /// ```slint
2515 /// import { Button } from "std-widgets.slint";
2516 /// export component Foo inherits Window {
2517 /// width: 200px;
2518 /// height: 100px;
2519 /// GridLayout {
2520 /// Row { // children implicitly on row 0
2521 /// Button { col: 1; text: "Top Right"; } // implicit column after this would be 2
2522 /// }
2523 /// Row { // children implicitly on row 1
2524 /// Button { text: "Bottom Left"; } // implicitly in column 0...
2525 /// Button { text: "Bottom Right"; } // ...and 1
2526 /// }
2527 /// }
2528 /// }
2529 /// ```
2530 ///
2531 /// The following example creates the same grid using the `row` property. Row indices must be taken care of manually:
2532 ///
2533 /// ```slint
2534 /// import { Button } from "std-widgets.slint";
2535 /// export component Foo inherits Window {
2536 /// width: 200px;
2537 /// height: 100px;
2538 /// GridLayout {
2539 /// Button { row: 0; col: 1; text: "Top Right"; } // `row: 0;` could even be left out at the start
2540 /// Button { row: 1; text: "Bottom Left"; } // new row, implicitly resets column to 0
2541 /// Button { text: "Bottom Right"; } // same row, sequentially assigned column 1
2542 /// }
2543 /// }
2544 /// ```
2545 /// \group:layouts
2546 GridLayout {
2547 //! ## Spacing Properties
2548 /// The distance between the elements in the layout. This single value is applied to both horizontal and vertical spacing.
2549 in property <length> spacing;
2550 //! To target specific axis with different values use the following properties:
2551 ///
2552 in property <length> spacing-horizontal;
2553 ///
2554 in property <length> spacing-vertical;
2555 //! ## Padding Properties
2556 //!
2557 //! ### padding
2558 //! <SlintProperty propName="padding" typeName="length">
2559 //! The padding around the grid structure as a whole. This single value is applied to all sides.
2560 //! </SlintProperty>
2561 //!
2562 //! To target specific sides with different values use the following properties:
2563 //!
2564 //! ### padding-left
2565 //! <SlintProperty propName="padding-left" typeName="length"/>
2566 //!
2567 //! ### padding-right
2568 //! <SlintProperty propName="padding-right" typeName="length"/>
2569 //!
2570 //! ### padding-top
2571 //! <SlintProperty propName="padding-top" typeName="length"/>
2572 //!
2573 //! ### padding-bottom
2574 //! <SlintProperty propName="padding-bottom" typeName="length"/>
2575
2576 // Additional accepted child
2577 children: Row;
2578 }
2579 }
2580
2581 element! {
2582 /// ```slint
2583 /// export component Foo inherits Window {
2584 /// width: 200px;
2585 /// height: 100px;
2586 /// VerticalLayout {
2587 /// spacing: 5px;
2588 /// Rectangle { background: red; width: 10px; }
2589 /// Rectangle { background: blue; min-width: 10px; }
2590 /// Rectangle { background: yellow; vertical-stretch: 1; }
2591 /// Rectangle { background: green; vertical-stretch: 2; }
2592 /// }
2593 /// }
2594 /// ```
2595 ///
2596 /// Places its children next to each other vertically.
2597 /// The size of elements can either be fixed with the `width` or `height` property, or if they aren't set
2598 /// they will be computed by the layout respecting the minimum and maximum sizes and the stretch factor.
2599 /// \footer
2600 /// ## Cell elements
2601 /// Cell elements inside a `VerticalLayout` obtain the following new properties:
2602 ///
2603 /// ### cross-axis-self-alignment
2604 /// <SlintProperty propName="cross-axis-self-alignment" typeName="enum" enumName="CrossAxisAlignment" defaultValue="auto">
2605 /// Overrides the container's `cross-axis-alignment` for this element.
2606 /// The default value `auto` uses the container's `cross-axis-alignment`.
2607 /// </SlintProperty>
2608 ///
2609 /// ### layout-order
2610 /// <SlintProperty propName="layout-order" typeName="int" defaultValue="0">
2611 /// Controls the visual order of the elements: they are laid out in ascending
2612 /// order value, and elements with the same value keep their declaration order.
2613 /// ```slint no-test
2614 /// VerticalLayout {
2615 /// Rectangle { layout-order: 2; }
2616 /// Rectangle { layout-order: 1; } // appears first
2617 /// }
2618 /// ```
2619 /// Only the visual order changes: keyboard focus still moves in declaration order.
2620 /// </SlintProperty>
2621 /// \group:layouts
2622 VerticalLayout {
2623 //! ## Spacing Properties
2624 /// The distance between the elements in the layout.
2625 in property <length> spacing;
2626 //! ## Padding Properties
2627 //! ### padding
2628 //! <SlintProperty propName="padding" typeName="length">
2629 //! The padding within the layout as a whole. This single value is applied to all sides.
2630 //! </SlintProperty>
2631 //!
2632 //! To target specific sides with different values use the following properties:
2633 //! ### padding-left
2634 //! <SlintProperty propName="padding-left" typeName="length"/>
2635 //!
2636 //! ### padding-right
2637 //! <SlintProperty propName="padding-right" typeName="length"/>
2638 //!
2639 //! ### padding-top
2640 //! <SlintProperty propName="padding-top" typeName="length"/>
2641 //!
2642 //! ### padding-bottom
2643 //! <SlintProperty propName="padding-bottom" typeName="length"/>
2644 //!
2645 //! ## Alignment Properties
2646 /// Set the alignment along the main (vertical) axis. Matches the CSS flex box.
2647 in property <LayoutAlignment> alignment;
2648 /// Set the alignment of items along the cross (horizontal) axis.
2649 /// The default is `stretch`, meaning each item fills the full width of the layout.
2650 /// The other values (`start`, `end`, `center`) size each
2651 /// item to its preferred width, clamped to its min/max, and position it at the
2652 /// left, right, or center of the layout's content box.
2653 ///
2654 /// ```slint
2655 /// export component Example inherits Window {
2656 /// width: 200px;
2657 /// height: 100px;
2658 /// VerticalLayout {
2659 /// cross-axis-alignment: end;
2660 /// Rectangle { background: red; preferred-width: 30px; preferred-height: 20px; }
2661 /// Rectangle { background: blue; preferred-width: 60px; preferred-height: 20px; }
2662 /// Rectangle { background: green; preferred-width: 90px; preferred-height: 20px; }
2663 /// }
2664 /// }
2665 /// ```
2666 in property <CrossAxisAlignment> cross-axis-alignment;
2667 }
2668 }
2669
2670 element! {
2671 /// ```slint
2672 /// export component Foo inherits Window {
2673 /// width: 200px;
2674 /// height: 100px;
2675 /// HorizontalLayout {
2676 /// spacing: 5px;
2677 /// Rectangle { background: red; width: 10px; }
2678 /// Rectangle { background: blue; min-width: 10px; }
2679 /// Rectangle { background: yellow; horizontal-stretch: 1; }
2680 /// Rectangle { background: green; horizontal-stretch: 2; }
2681 /// }
2682 /// }
2683 /// ```
2684 ///
2685 /// Places its children next to each other horizontally.
2686 /// The size of elements can either be fixed with the `width` or `height` property, or if they aren't set
2687 /// they will be computed by the layout respecting the minimum and maximum sizes and the stretch factor.
2688 /// \footer
2689 /// ## Cell elements
2690 /// Cell elements inside a `HorizontalLayout` obtain the following new properties:
2691 ///
2692 /// ### cross-axis-self-alignment
2693 /// <SlintProperty propName="cross-axis-self-alignment" typeName="enum" enumName="CrossAxisAlignment" defaultValue="auto">
2694 /// Overrides the container's `cross-axis-alignment` for this element.
2695 /// The default value `auto` uses the container's `cross-axis-alignment`.
2696 /// </SlintProperty>
2697 ///
2698 /// ### layout-order
2699 /// <SlintProperty propName="layout-order" typeName="int" defaultValue="0">
2700 /// Controls the visual order of the elements: they are laid out in ascending
2701 /// order value, and elements with the same value keep their declaration order.
2702 /// ```slint no-test
2703 /// HorizontalLayout {
2704 /// Rectangle { layout-order: 2; }
2705 /// Rectangle { layout-order: 1; } // appears first
2706 /// }
2707 /// ```
2708 /// Only the visual order changes: keyboard focus still moves in declaration order.
2709 /// </SlintProperty>
2710 /// \group:layouts
2711 HorizontalLayout {
2712 //! ## Spacing Properties
2713 /// The distance between the elements in the layout.
2714 in property <length> spacing;
2715 //! ## Padding Properties
2716 //!
2717 //! ### padding
2718 //! <SlintProperty propName="padding" typeName="length">
2719 //! The padding within the layout as a whole. This single value is applied to all sides.
2720 //! </SlintProperty>
2721 //!
2722 //! To target specific sides with different values use the following properties:
2723 //!
2724 //! ### padding-left
2725 //! <SlintProperty propName="padding-left" typeName="length"/>
2726 //!
2727 //! ### padding-right
2728 //! <SlintProperty propName="padding-right" typeName="length"/>
2729 //!
2730 //! ### padding-top
2731 //! <SlintProperty propName="padding-top" typeName="length"/>
2732 //!
2733 //! ### padding-bottom
2734 //! <SlintProperty propName="padding-bottom" typeName="length"/>
2735 //!
2736 //! ## Alignment Properties
2737 /// Set the alignment along the main (horizontal) axis. Matches the CSS flex box.
2738 in property <LayoutAlignment> alignment;
2739 /// Set the alignment of items along the cross (vertical) axis.
2740 /// The default is `stretch`, meaning each item fills the full height of the layout.
2741 /// The other values (`start`, `end`, `center`) size each
2742 /// item to its preferred height, clamped to its min/max, and position it at the
2743 /// top, bottom, or center of the layout's content box.
2744 ///
2745 /// ```slint
2746 /// export component Example inherits Window {
2747 /// width: 200px;
2748 /// height: 100px;
2749 /// HorizontalLayout {
2750 /// cross-axis-alignment: center;
2751 /// Rectangle { background: red; preferred-width: 30px; preferred-height: 20px; }
2752 /// Rectangle { background: blue; preferred-width: 30px; preferred-height: 40px; }
2753 /// Rectangle { background: green; preferred-width: 30px; preferred-height: 60px; }
2754 /// }
2755 /// }
2756 /// ```
2757 in property <CrossAxisAlignment> cross-axis-alignment;
2758 }
2759 }
2760
2761 element! {
2762 /// `FlexboxLayout` is a flexible box layout that arranges its children in rows or columns with automatic wrapping.
2763 /// It implements a CSS Flexbox-like layout model suitable for creating flexible, responsive UIs.
2764 ///
2765 /// Use `FlexboxLayout` when the items should wrap: items that don't fit continue on the next line.
2766 /// That's why `flex-wrap` defaults to `wrap`, unlike CSS.
2767 /// For a single row or column, use the simpler and faster
2768 /// <Link type="HorizontalLayout" /> or <Link type="VerticalLayout" /> instead,
2769 /// unless you need a `flex-direction` that changes at runtime,
2770 /// or the reversed directions (`row-reverse` / `column-reverse`).
2771 ///
2772 ///
2773 /// ```slint playground imageAlt="flexboxlayout example with row direction" width="300" height="150"
2774 /// // This example demonstrates FlexboxLayout with row direction (default)
2775 /// export component Foo inherits Window {
2776 /// width: 300px;
2777 /// height: 150px;
2778 /// FlexboxLayout {
2779 /// spacing: 8px;
2780 /// padding: 8px;
2781 /// flex-direction: row;
2782 /// Rectangle { background: red; width: 60px; height: 50px; }
2783 /// Rectangle { background: blue; width: 60px; height: 50px; }
2784 /// Rectangle { background: yellow; width: 60px; height: 50px; }
2785 /// Rectangle { background: green; width: 60px; height: 50px; }
2786 /// Rectangle { background: purple; width: 60px; height: 50px; }
2787 /// }
2788 /// }
2789 /// ```
2790 ///
2791 ///
2792 /// ```slint playground imageAlt="flexboxlayout example with column direction" width="200" height="300"
2793 /// // This example demonstrates FlexboxLayout with column direction
2794 /// export component Foo inherits Window {
2795 /// width: 200px;
2796 /// height: 300px;
2797 /// FlexboxLayout {
2798 /// spacing: 8px;
2799 /// padding: 8px;
2800 /// flex-direction: column;
2801 /// Rectangle { background: red; width: 50px; height: 60px; }
2802 /// Rectangle { background: blue; width: 50px; height: 60px; }
2803 /// Rectangle { background: yellow; width: 50px; height: 60px; }
2804 /// Rectangle { background: green; width: 50px; height: 60px; }
2805 /// Rectangle { background: purple; width: 50px; height: 60px; }
2806 /// }
2807 /// }
2808 /// ```
2809 ///
2810 /// ## Overview
2811 ///
2812 /// In row direction, items are placed from left to right. When the available width is exceeded, items automatically wrap to the next row. In column direction, items are placed from top to bottom and wrap to the next column when the available height is exceeded.
2813 ///
2814 /// A wrapping column direction container reports the width of all its columns
2815 /// only when its `height` is set to a plain length, such as `height: 200px`.
2816 /// `phx` and `rem` do not count, since they depend on the window's scale factor
2817 /// and the default font size, which are only known while running.
2818 /// Set it on the container, on a component it inherits from, or where the container is used.
2819 /// A height a parent layout assigns, a percentage, and an expression all report
2820 /// the width of a single column instead,
2821 /// as for a CSS column flex container with an automatic height.
2822 /// A height on the root of a component used elsewhere does not count for the elements inside it,
2823 /// since each use may override it: set the height on the container instead.
2824 /// A `wrap` column container never wraps into columns wider than its width:
2825 /// the content overflows downward instead, like a wrapping `Text` given too little height.
2826 /// A `wrap-reverse` one still wraps, since its lines are anchored at the opposite edge.
2827 /// To wrap without setting a height, give the container more width,
2828 /// with `horizontal-stretch` or a `min-width`: it wraps into whatever width it gets.
2829 ///
2830 /// \footer
2831 /// ## Cell elements
2832 /// Cell elements inside a `FlexboxLayout` obtain the following new properties:
2833 ///
2834 /// ### cross-axis-self-alignment
2835 /// <SlintProperty propName="cross-axis-self-alignment" typeName="enum" enumName="CrossAxisAlignment" defaultValue="auto">
2836 /// Overrides the container's `cross-axis-alignment` for this element. CSS Flexbox calls this "align-self".
2837 /// The default value `auto` uses the container's `cross-axis-alignment`.
2838 /// </SlintProperty>
2839 ///
2840 /// ### layout-order
2841 /// <SlintProperty propName="layout-order" typeName="int" defaultValue="0">
2842 /// Controls the visual order of the items, like the CSS `order` property:
2843 /// items are laid out in ascending order value, and items with the same value keep
2844 /// their declaration order.
2845 /// ```slint no-test
2846 /// FlexboxLayout {
2847 /// Rectangle { layout-order: 2; }
2848 /// Rectangle { layout-order: 1; } // appears first
2849 /// }
2850 /// ```
2851 /// Only the visual order changes: keyboard focus still moves in declaration order.
2852 /// </SlintProperty>
2853 ///
2854 /// ## CSS Mapping
2855 ///
2856 /// The container properties map to CSS Flexbox as follows:
2857 ///
2858 /// | CSS | Slint |
2859 /// | ----------------- | --------------------------------------------------------- |
2860 /// | `flex-direction` | `flex-direction` |
2861 /// | `flex-wrap` | `flex-wrap`, but the default is `wrap` (CSS: `nowrap`) |
2862 /// | `justify-content` | `alignment` |
2863 /// | `align-items` | `cross-axis-alignment` |
2864 /// | `align-content` | `cross-axis-line-alignment` |
2865 /// | `gap` | `spacing` |
2866 /// | `column-gap` | `spacing-horizontal` |
2867 /// | `row-gap` | `spacing-vertical` |
2868 /// | `padding` | `padding`, `padding-left` / `-right` / `-top` / `-bottom` |
2869 ///
2870 /// The CSS per-item flexbox properties are expressed with the properties the
2871 /// other layouts already use:
2872 ///
2873 /// | CSS | Slint |
2874 /// | ------------- | -------------------------------------------------------------- |
2875 /// | `flex-grow` | `alignment: stretch` on the container, weighted per item by `horizontal-stretch` / `vertical-stretch`; `max-width` / `max-height` caps growing (space a capped item cannot take stays free) |
2876 /// | `flex-shrink` | nothing to opt into: every item shrinks, in proportion to its preferred size; `min-width` / `min-height` refuses shrinking |
2877 /// | `flex-basis` | `preferred-width` (row) / `preferred-height` (column) |
2878 /// | `align-self` | `cross-axis-self-alignment` |
2879 ///
2880 /// ## Layout Behavior
2881 ///
2882 /// The layouting algorithm for FlexboxLayout is entirely implemented by <a href="https://github.com/DioxusLabs/taffy">taffy</a>
2883 ///
2884 /// You can learn more about the CSS Flexbox specification from
2885 /// - <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Flexible_box_layout/Basic_concepts">the Mozilla developer website</a>
2886 /// - <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">A Complete Guide To Flexbox by CSS Tricks</a>. This is detailed guide with illustrations and comprehensive written explanation of the different Flexbox properties and how they work.
2887 ///
2888 /// \group:layouts
2889 FlexboxLayout {
2890 //! ## Spacing Properties
2891 /// The distance between the elements in the layout. CSS Flexbox usually calls this "gap", but "spacing" is used in Slint for consistency with other layout types.
2892 /// This single value is applied as both horizontal and vertical spacing between items.
2893 in property <length> spacing;
2894 //! To target specific directions with different values use the following properties:
2895 /// The horizontal distance between items in the layout. CSS Flexbox calls this "column-gap".
2896 in property <length> spacing-horizontal;
2897 /// The vertical distance between items in the layout. CSS Flexbox calls this "row-gap".
2898 in property <length> spacing-vertical;
2899 //! ## Padding Properties
2900 //!
2901 //! ### padding
2902 //! <SlintProperty propName="padding" typeName="length">
2903 //! The padding around the layout as a whole. This single value is applied to all sides.
2904 //! </SlintProperty>
2905 //!
2906 //! To target specific sides with different values use the following properties:
2907 //! ### padding-left
2908 //! <SlintProperty propName="padding-left" typeName="length"/>
2909 //!
2910 //! ### padding-right
2911 //! <SlintProperty propName="padding-right" typeName="length"/>
2912 //!
2913 //! ### padding-top
2914 //! <SlintProperty propName="padding-top" typeName="length"/>
2915 //!
2916 //! ### padding-bottom
2917 //! <SlintProperty propName="padding-bottom" typeName="length"/>
2918 //!
2919 //! ## Alignment Properties
2920 /// Set the alignment of items along the main axis. CSS Flexbox calls this "justify-content".
2921 /// With `stretch`, items grow along the main axis to fill each line,
2922 /// weighted by their `horizontal-stretch` (row) or `vertical-stretch` (column) factor.
2923 /// When every factor is 0, the free space is split evenly.
2924 /// Use `max-width`/`max-height` to cap an item's growth;
2925 /// space a capped item cannot take stays free at the end of the line.
2926 /// CSS Flexbox expresses this per item with `flex-grow` instead.
2927 in property <LayoutAlignment> alignment: LayoutAlignment.start; // CSS default is flex-start
2928 //! ## Direction Properties
2929 /// The primary direction in which items are placed. Set to `row` to place items horizontally left-to-right (default), or `column` to place items vertically top-to-bottom.
2930 /// It also supports `row-reverse` and `column-reverse` which invert the flow: `row-reverse` places items right-to-left (starting at the right edge), and `column-reverse` places items bottom-to-top (starting at the bottom edge).
2931 in property <FlexboxLayoutDirection> flex-direction;
2932 /// Set the distribution of flex lines along the cross axis. CSS Flexbox calls this "align-content";
2933 /// the name here pairs with `cross-axis-alignment`, which aligns the items within one line.
2934 /// The default value is `stretch`.
2935 in property <LayoutAlignment> cross-axis-line-alignment;
2936 /// Set the alignment of individual items along the cross axis within each flex line.
2937 /// CSS Flexbox calls this "align-items". The default value is `stretch`.
2938 in property <CrossAxisAlignment> cross-axis-alignment;
2939 /// Controls whether flex items wrap onto multiple lines when they don't fit in the container.
2940 /// The default value is `wrap`, unlike CSS where it is `nowrap`.
2941 in property <FlexboxLayoutWrap> flex-wrap;
2942 }
2943 }
2944
2945 element! {
2946 /// The `MoveTo` sub-element closes the current sub-path, if present, and moves the current point
2947 /// to the location specified by the `x` and `y` properties. Subsequent elements such as `LineTo`
2948 /// will use this new position as their starting point, therefore this starts a new sub-path.
2949 @is_non_item_type @builtin_struct(PathMoveTo)
2950 MoveTo {
2951 /// The x position of the new current point.
2952 in property <float> x;
2953 /// The y position of the new current point.
2954 in property <float> y;
2955 }
2956 }
2957
2958 element! {
2959 /// The `LineTo` sub-element describes a line from the path's current position to the
2960 /// location specified by the `x` and `y` properties.
2961 @is_non_item_type @builtin_struct(PathLineTo)
2962 LineTo {
2963 /// The target x position of the line.
2964 in property <float> x;
2965 /// The target y position of the line.
2966 in property <float> y;
2967 }
2968 }
2969
2970 element! {
2971 /// The `ArcTo` sub-element describes the portion of an ellipse. The arc is drawn from the path's
2972 /// current position to the location specified by the `x` and `y` properties. The remaining properties
2973 /// are modelled after the SVG specification and allow tuning visual features such as the direction
2974 /// or angle.
2975 @is_non_item_type @builtin_struct(PathArcTo)
2976 ArcTo {
2977 /// Out of the two arcs of a closed ellipse, this flag selects that the larger arc is to be rendered. If the property is `false`, the shorter arc is rendered instead.
2978 in property <bool> large-arc;
2979 /// The x-radius of the ellipse.
2980 in property <float> radius-x;
2981 /// The y-radius of the ellipse.
2982 in property <float> radius-y;
2983 /// If the property is `true`, the arc will be drawn as a clockwise turning arc; anti-clockwise otherwise.
2984 in property <bool> sweep;
2985 /// The x-axis of the ellipse will be rotated by the value of this properties, specified in as angle in degrees from 0 to 360.
2986 in property <float> x-rotation;
2987 /// The target x position of the line.
2988 in property <float> x;
2989 /// The target y position of the line.
2990 in property <float> y;
2991 }
2992 }
2993
2994 element! {
2995 /// The `CubicTo` sub-element describes a smooth Bézier from the path's current position to the
2996 /// location specified by the `x` and `y` properties, using two control points specified by their
2997 /// respective properties.
2998 @is_non_item_type @builtin_struct(PathCubicTo)
2999 CubicTo {
3000 /// The x coordinate of the curve's first control point.
3001 in property <float> control-1-x;
3002 /// The y coordinate of the curve's first control point.
3003 in property <float> control-1-y;
3004 /// The x coordinate of the curve's second control point.
3005 in property <float> control-2-x;
3006 /// The y coordinate of the curve's second control point.
3007 in property <float> control-2-y;
3008 /// The target x position of the curve.
3009 in property <float> x;
3010 /// The target y position of the curve.
3011 in property <float> y;
3012 }
3013 }
3014
3015 element! {
3016 /// The QuadraticTo sub-element describes a smooth Bézier from the path's current position to the
3017 /// location specified by the `x` and `y` properties, using the control points specified by the
3018 /// `control-x` and `control-y` properties.
3019 @is_non_item_type @builtin_struct(PathQuadraticTo)
3020 QuadraticTo {
3021 /// The x coordinate of the curve's control point.
3022 in property <float> control-x;
3023 /// The y coordinate of the curve's control point.
3024 in property <float> control-y;
3025 /// The target x position of the curve.
3026 in property <float> x;
3027 /// The target y position of the curve.
3028 in property <float> y;
3029 }
3030 }
3031
3032 element! {
3033 /// The `Close` element closes the current sub-path and draws a straight line from the current
3034 /// position to the beginning of the path.
3035 @is_non_item_type @builtin_struct(PathClose)
3036 Close
3037 }
3038
3039 item! { Path {
3040 /// The color for filling the shape of the path.
3041 in property <brush> fill;
3042 /// The fill rule to use for the path.
3043 /// \default nonzero
3044 in property <FillRule> fill-rule;
3045 /// The color for drawing the outline of the path.
3046 in property <brush> stroke;
3047 /// The width of the outline.
3048 in property <length> stroke-width;
3049 /// The appearance of the ends of the path's outline.
3050 /// \default butt
3051 in property <LineCap> stroke-line-cap;
3052 /// The appearance of the joins between segments of stroked paths.
3053 /// \default miter
3054 in property <LineJoin> stroke-line-join;
3055 /// The limit on the ratio of the miter length to the stroke width when `stroke-line-join` is set to `miter`.
3056 /// When the limit is exceeded, the join is rendered as a bevel instead.
3057 in property <float> stroke-miter-limit: 4; // SVG default is 4
3058 //! ### width
3059 //! <SlintProperty propName="width" typeName="length">
3060 //! If non-zero, the path will be scaled to fit into the specified width.
3061 //! </SlintProperty>
3062 //!
3063 //! ### height
3064 //! <SlintProperty propName="height" typeName="length">
3065 //! If non-zero, the path will be scaled to fit into the specified height.
3066 //! </SlintProperty>
3067 //!
3068
3069 @fake in property <string> commands;
3070 /// Defines how the path's view box is scaled to fit the element's width and height.
3071 /// If no view box is defined, the implicit bounding rectangle is used.
3072 /// \default contain
3073 in property <ImageFit> fit: ImageFit.contain;
3074 /// By default, when a path has a view box defined and the elements render
3075 /// outside of it, they are still rendered. When this property is set to `true`, then rendering will be
3076 /// clipped at the boundaries of the view box.
3077 /// \default false
3078 in property <bool> clip;
3079 /// By default, the fill and stroke of a path is rendered with anti-aliasing, for best quality. Some GPUs
3080 /// have performance issues when rendering with anti-aliasing and animation. Setting the value to `false`
3081 /// might improve the frame-rate at the expense of a smoother looking path.
3082 /// \default true
3083 in property <bool> anti-alias: true;
3084 //! ## Viewbox Properties
3085 //!
3086 //! These four properties allow defining the position and size of the viewport of the path in path coordinates.
3087 //!
3088 //! If the `viewbox-width` or `viewbox-height` is less or equal than zero, the viewbox properties are
3089 //! ignored and instead the bounding rectangle of all path elements is used to define the view port.
3090 ///
3091 in property <float> viewbox-x;
3092 ///
3093 in property <float> viewbox-y;
3094 ///
3095 in property <float> viewbox-width;
3096 ///
3097 in property <float> viewbox-height;
3098 /// Returns a point at the given percent along the path in the Path element's coordinate space.
3099 /// Returns (0, 0) if the path is empty.
3100 ///
3101 /// If a `t` outside the bounds of 0 and 1 is passed, it will be converted to its decimal fraction.
3102 /// Ex: 1.5 -> 0.5 and 2.0 -> 1.0. This allows for N iterations of a loop
3103 /// by animating t from 0 to N. If `t` is animated from N to 0, it will loop N times backwards.
3104 @pure function point-at(t: float) -> Point { BuiltinFunction.PathPointAt }
3105 /// Returns the angle (in degrees) between the x-axis and the path's tangent vector at the given `t`.
3106 /// The tangent points in the direction the path was defined, so this reflects the path's shape and not
3107 /// the object's current direction of travel. Returns 0 if the path is empty.
3108 /// If a `t` outside the bounds of 0 and 1 is passed, the decimal fraction will be passed.
3109 @pure function angle-at(t: float) -> angle { BuiltinFunction.PathAngleAt }
3110 //!
3111 //! ## Path Using SVG Commands
3112 //!
3113 //! SVG is a popular file format for defining scalable graphics, which are often composed of paths. In SVG
3114 //! paths are composed using [commands](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d#path_commands),
3115 //! which in turn are written in a string. In `.slint` the path commands are provided to the `commands`
3116 //! property. The following example renders a shape consists of an arc and a rectangle, composed of `line-to`,
3117 //! `move-to` and `arc` commands:
3118 //!
3119 //! ```slint
3120 //! export component Example inherits Path {
3121 //! width: 100px;
3122 //! height: 100px;
3123 //! commands: "M 0 0 L 0 100 A 1 1 0 0 0 100 100 L 100 0 Z";
3124 //! stroke: red;
3125 //! stroke-width: 1px;
3126 //! }
3127 //! ```
3128 //!
3129 //! The commands are provided in a property:
3130 //!
3131 //! ### Commands
3132 //! <SlintProperty propName="commands" typeName="string">
3133 //! A string providing the commands according to the SVG path specification.
3134 //! This property can only be set in a binding and cannot be accessed in an expression.
3135 //! </SlintProperty>
3136 //!
3137 //! ## Path Using SVG Path Elements
3138 //!
3139 //! The shape of the path can also be described using elements that resemble the SVG path commands but use the
3140 //! `.slint` markup syntax. The earlier example using SVG commands can also be written like that:
3141 //!
3142 //! ```slint
3143 //! export component Example inherits Path {
3144 //! width: 100px;
3145 //! height: 100px;
3146 //! stroke: blue;
3147 //! stroke-width: 1px;
3148 //!
3149 //! MoveTo {
3150 //! x: 0;
3151 //! y: 0;
3152 //! }
3153 //! LineTo {
3154 //! x: 0;
3155 //! y: 100;
3156 //! }
3157 //! ArcTo {
3158 //! radius-x: 1;
3159 //! radius-y: 1;
3160 //! x: 100;
3161 //! y: 100;
3162 //! }
3163 //! LineTo {
3164 //! x: 100;
3165 //! y: 0;
3166 //! }
3167 //! Close {
3168 //! }
3169 //! }
3170 //! ```
3171 //!
3172 //! Note how the coordinates of the path elements don't use units - they operate within the imaginary
3173 //! coordinate system of the scalable path.
3174
3175
3176
3177
3178
3179
3180
3181 } }
3182
3183 element! {
3184 /// The `Path` element allows rendering a generic shape, composed of different geometric commands. A path
3185 /// shape can be filled and outlined.
3186 ///
3187 /// When not part of a layout, its width or height defaults to 100% of the parent element when not specified.
3188 ///
3189 /// A path can be defined in two different ways:
3190 ///
3191 /// - Using SVG path commands as a string
3192 /// - Using path command elements in `.slint` markup.
3193 ///
3194 /// The coordinates used in the geometric commands are within the imaginary coordinate system of the path.
3195 /// When rendering on the screen, the shape is drawn relative to the `x` and `y` properties. If the `width`
3196 /// and `height` properties are non-zero, then the entire shape is fit into these bounds - by scaling
3197 /// accordingly.
3198 /// \group:elements
3199 @disallow_global_types_as_child_elements @expands_to_parent_geometry
3200 Path: Path {
3201 children: MoveTo, LineTo, ArcTo, CubicTo, QuadraticTo, Close;
3202 }
3203 }
3204
3205 element! {
3206 Tab {
3207 in property <string> title;
3208 }
3209 }
3210
3211 element! {
3212 // Note: not a native class, handled in the lower_tabs pass
3213 @is_internal @disallow_global_types_as_child_elements @expands_to_parent_geometry
3214 TabWidget {
3215 in-out property <int> current-index;
3216
3217 @constexpr in property <Orientation> orientation;
3218
3219
3220 children: Tab;
3221 }
3222 }
3223
3224 element! {
3225 RadioButton {
3226 in property <string> text;
3227 in property <bool> enabled: true;
3228 in-out property <bool> checked;
3229 callback toggled;
3230 }
3231 }
3232
3233 element! {
3234 // Note: not a native class, handled in the lower_radiogroup pass
3235 @is_internal @disallow_global_types_as_child_elements
3236 RadioGroup {
3237 in property <string> title;
3238 in property <bool> enabled: true;
3239 in property <Orientation> orientation;
3240 out property <string> current-value;
3241 out property <bool> has-focus;
3242 callback selected(value: string);
3243
3244
3245 children: RadioButton;
3246 }
3247 }
3248
3249 element! {
3250 /// ```slint playground
3251 /// export component Example inherits Window {
3252 /// width: 100px;
3253 /// height: 100px;
3254 ///
3255 /// popup := PopupWindow {
3256 /// Rectangle { height:100%; width: 100%; background: yellow; }
3257 /// x: 20px; y: 20px; height: 50px; width: 50px;
3258 /// }
3259 ///
3260 /// TouchArea {
3261 /// height:100%; width: 100%;
3262 /// clicked => { popup.show(); }
3263 /// }
3264 /// }
3265 /// ```
3266 ///
3267 /// Use this element to show a popup window like a tooltip or a popup menu.
3268 ///
3269 /// :::note{Note}
3270 /// It isn't allowed to access properties of elements within the popup from outside of the `PopupWindow`. See [#4438](https://github.com/slint-ui/slint/issues/4438).
3271 /// :::
3272 /// \group:window
3273 PopupWindow {
3274 //property <length> x;
3275 //property <length> y;
3276 in property <length> width;
3277 in property <length> height;
3278 /*property <length> anchor_x;
3279 in property <length> anchor-y;
3280 in property <length> anchor-height;
3281 in property <length> anchor-width;*/
3282
3283 @constexpr in property <bool> close-on-click;
3284 /// By default, a PopupWindow closes when the user clicks. Set this to false to prevent that behavior and close it manually using the `close()` function.
3285 /// \default close-on-click
3286
3287 @constexpr in property <PopupClosePolicy> close-policy;
3288 /// Use this read-only property to style the element that opened the popup, for example
3289 /// to rotate a ComboBox's arrow while the dropdown is open.
3290 /// `true` while the popup is shown on the screen, and `false` once it is closed, for example
3291 /// when dismissed by a click, by a selection, or by a programmatic `close()`.
3292 out property <bool> is-open;
3293 /// Show the popup on the screen.
3294 function show() { BuiltinFunction.ShowPopupWindow }
3295 /// Closes the popup. Use this if you set the `close-policy` property to `no-auto-close`.
3296 function close() { BuiltinFunction.ClosePopupWindow }
3297 }
3298 }
3299
3300 item! { TooltipArea: Empty {
3301 // Set when the mouse is over the parent's region while this area is expanded to fill it during lowering.
3302 out property <bool> has-hover;
3303 // Pointer x within this area during hover.
3304 out property <length> mouse-x;
3305 // Pointer y within this area during hover.
3306 out property <length> mouse-y;
3307 // Tooltip configuration folded from the user-facing Tooltip element during lowering.
3308 in property <styled-text> text;
3309 // Delay and offset are not user-facing in 1.17; the values used here are the
3310 // built-in defaults applied to the synthesized element on instantiation.
3311 in property <duration> delay: 500ms;
3312 in property <length> offset: 8px;
3313 callback show;
3314 callback hide;
3315 } }
3316
3317 element! {
3318 // Internal hover tracker used with `Tooltip` lowering (the compiler inserts `TooltipArea` so `Tooltip` can react to hover and pointer position).
3319 @is_internal @expands_to_parent_geometry
3320 TooltipArea: TooltipArea
3321 }
3322
3323 element! {
3324 /// ```slint playground
3325 /// import { Button } from "std-widgets.slint";
3326 ///
3327 /// export component Example inherits Window {
3328 /// width: 280px;
3329 /// height: 160px;
3330 ///
3331 /// VerticalLayout {
3332 /// alignment: center;
3333 ///
3334 /// Button {
3335 /// text: "Hover me";
3336 ///
3337 /// Tooltip {
3338 /// text: @markdown("This is a tooltip");
3339 /// }
3340 /// }
3341 /// }
3342 /// }
3343 /// ```
3344 ///
3345 /// Place a `Tooltip` inside any element to show helpful information when hovering over it.
3346 /// The tooltip appears after a short delay near the pointer and hides when the pointer leaves.
3347 ///
3348 /// Set the `text` property for a simple text tooltip,
3349 /// or add a child element instead for custom content.
3350 ///
3351 /// Each element can contain at most one `Tooltip`.
3352 ///
3353 /// \footer
3354 /// ## Custom Content
3355 ///
3356 /// For richer tooltips, omit `text` and provide your own layout inside a single child element.
3357 ///
3358 ///
3359 /// ```slint playground
3360 /// import { Button, VerticalBox, HorizontalBox } from "std-widgets.slint";
3361 ///
3362 /// export component Example inherits Window {
3363 /// width: 320px;
3364 /// height: 200px;
3365 ///
3366 /// VerticalLayout {
3367 /// alignment: center;
3368 ///
3369 /// Button {
3370 /// text: "Custom tooltip";
3371 ///
3372 /// Tooltip {
3373 /// VerticalBox {
3374 /// padding: 10px;
3375 /// spacing: 6px;
3376 ///
3377 /// Text {
3378 /// text: "Quick Actions";
3379 /// font-weight: 700;
3380 /// color: #fff;
3381 /// }
3382 ///
3383 /// Text {
3384 /// text: "Open command palette and search settings.";
3385 /// color: #d1d5db;
3386 /// wrap: word-wrap;
3387 /// }
3388 ///
3389 /// HorizontalBox {
3390 /// spacing: 6px;
3391 ///
3392 /// Rectangle {
3393 /// border-radius: 4px;
3394 /// background: #374151;
3395 /// HorizontalBox {
3396 /// padding: 4px;
3397 /// Text { text: "Ctrl"; color: #fff; }
3398 /// }
3399 /// }
3400 ///
3401 /// Rectangle {
3402 /// border-radius: 4px;
3403 /// background: #374151;
3404 /// HorizontalBox {
3405 /// padding: 4px;
3406 /// Text { text: "K"; color: #fff; }
3407 /// }
3408 /// }
3409 /// }
3410 /// }
3411 /// }
3412 /// }
3413 /// }
3414 /// }
3415 /// ```
3416 /// \group:window
3417 @is_non_item_type @can_be_declared_without_children_slot
3418 Tooltip: Empty {
3419 /// The text to display in the tooltip.
3420 /// Don't set this property when using custom content.
3421 in property <styled-text> text;
3422 }
3423 }
3424
3425 element! {
3426 /// :::note[Note]
3427 /// Timer is not an actual element visible in the tree, therefore it doesn't have the common properties such as `x`, `y`, `width`, `height`, etc. It also doesn't take room in a layout and cannot have any children or be inherited from.
3428 /// :::
3429 ///
3430 /// This example shows a timer that counts down from 10 to 0 every second:
3431 ///
3432 /// ```slint playground
3433 /// import { Button } from "std-widgets.slint";
3434 /// export component Example inherits Window {
3435 /// property <int> value: 10;
3436 /// timer := Timer {
3437 /// interval: 1s;
3438 /// running: true;
3439 /// triggered() => {
3440 /// value -= 1;
3441 /// if (value == 0) {
3442 /// self.running = false;
3443 /// }
3444 /// }
3445 /// }
3446 /// HorizontalLayout {
3447 /// Text { text: value; }
3448 /// Button {
3449 /// text: "Reset";
3450 /// clicked() => { value = 10; timer.running = true; }
3451 /// }
3452 /// }
3453 /// }
3454 /// ```
3455 ///
3456 ///
3457 ///
3458 /// Use the Timer pseudo-element to schedule a callback at a given interval.
3459 /// The timer is only running when the `running` property is set to `true`. To stop or start the timer, set that property to `true` or `false`.
3460 /// It can be also set to a binding expression.
3461 /// When already running, the timer will be restarted if the `interval` property is changed.
3462 ///
3463 /// :::caution[Caution]
3464 /// By default the `Timer` is always running `running: true`. This can result in constant CPU usage and
3465 /// power usage so ensure that you set `running` to `false` when you don't want the timer to run.
3466 /// :::
3467 ///
3468 /// ```slint
3469 /// property <int> count: 0;
3470 /// Timer {
3471 /// interval: 8s; // every 8 seconds the timer will activate (tick)
3472 /// triggered() => { // The triggered callback activates every time the timer ticks
3473 /// if count >= 5 {
3474 /// self.running = false; // stop the timer after 5 ticks
3475 /// }
3476 /// count += 1;
3477 /// }
3478 /// }
3479 /// ```
3480 @is_non_item_type @disallow_global_types_as_child_elements
3481 Timer {
3482 /// The interval between timer ticks. This property is mandatory.
3483 /// ```slint "interval: 250ms;"
3484 /// Timer {
3485 /// property <int> count: 0;
3486 /// interval: 250ms;
3487 /// triggered() => {
3488 /// debug("count is:", count);
3489 /// count += 1;
3490 /// }
3491 /// }
3492 /// ```
3493 in property <duration> interval;
3494 /// `true` if the timer is running.
3495 /// ```slint "running: false; // timer is not running"
3496 /// Timer {
3497 /// property <int> count: 0;
3498 /// interval: 250ms;
3499 /// running: false; // timer is not running
3500 /// triggered() => {
3501 /// debug("count is:", count);
3502 /// }
3503 /// }
3504 /// ```
3505 in property <bool> running: true;
3506 /// Invoked every time the timer ticks (every `interval`).
3507 /// ```slint {4-6}
3508 /// Timer {
3509 /// property <int> count: 0;
3510 /// interval: 250ms;
3511 /// triggered() => {
3512 /// debug("count is:", count);
3513 /// }
3514 /// }
3515 /// ```
3516 callback triggered;
3517 /// Start the timer (equivalent to setting `running` to true).
3518 function start() { BuiltinFunction.StartTimer }
3519 /// Stop the timer (equivalent to setting `running` to false).
3520 function stop() { BuiltinFunction.StopTimer }
3521 /// Restarts the timer if it was previously started.
3522 function restart() { BuiltinFunction.RestartTimer }
3523 }
3524 }
3525
3526 element! {
3527 /// ```slint playground imageAlt="dialog example" width="200" height="100"
3528 /// import { StandardButton, Button } from "std-widgets.slint";
3529 /// export component Example inherits Dialog {
3530 /// Text {
3531 /// text: "This is a dialog box";
3532 /// }
3533 /// StandardButton { kind: ok; }
3534 /// StandardButton { kind: cancel; }
3535 /// Button {
3536 /// text: "More Info";
3537 /// dialog-button-role: action;
3538 /// }
3539 /// }
3540 /// ```
3541 ///
3542 /// Dialog can be used in place of <Link type="Window"/>, but it has buttons that are automatically laid out.
3543 ///
3544 /// A Dialog should have one main element as child, that isn't a button.
3545 /// The dialog can have any number of `StandardButton` widgets or other buttons
3546 /// with the `dialog-button-role` property.
3547 /// The buttons will be placed in an order that depends on the target platform at run-time.
3548 ///
3549 /// The `kind` property of the `StandardButton`s and the `dialog-button-role` properties need to be set to a constant value, it can't be an arbitrary variable expression.
3550 /// There can't be several `StandardButton`s of the same kind.
3551 ///
3552 /// A callback `<kind>_clicked` is automatically added for each `StandardButton` which doesn't have an explicit
3553 /// callback handler, so it can be handled from the native code: For example if there is a button of kind `cancel`,
3554 /// a `cancel_clicked` callback will be added.
3555 /// Each of these automatically-generated callbacks is an alias for the `clicked` callback of the associated `StandardButton`.
3556 ///
3557 /// ## Properties
3558 ///
3559 /// Same as <Link type="Window"/>.
3560 ///
3561 /// ## Functions
3562 ///
3563 /// Same as <Link type="Window"/>.
3564 /// \group:window
3565 @skip_inherited
3566 Dialog: WindowItem
3567 }
3568
3569 element! {
3570 @is_non_item_type
3571 PropertyAnimation {
3572 in property <duration> delay;
3573 in property <duration> duration;
3574 in property <AnimationDirection> direction;
3575 in property <easing> easing;
3576 in property <float> iteration-count: 1.0;
3577 in property <bool> enabled: true;
3578 }
3579 }
3580
3581 element! {
3582 /// ```slint
3583 /// import { LineEdit } from "std-widgets.slint";
3584 ///
3585 /// component VKB {
3586 /// Rectangle { background: yellow; }
3587 /// }
3588 ///
3589 /// export component Example inherits Window {
3590 /// width: 200px;
3591 /// height: 100px;
3592 /// VerticalLayout {
3593 /// LineEdit {}
3594 /// FocusScope {}
3595 /// if TextInputInterface.text-input-focused: VKB {}
3596 /// }
3597 /// }
3598 /// ```
3599 ///
3600 /// \group:keyboard-input
3601 @is_global
3602 TextInputInterface {
3603 //! ## Properties
3604 //!
3605 //! The `TextInputInterface.text-input-focused` property can be used to find out if a `TextInput` element has the focus.
3606 //! If you're implementing your own virtual keyboard, this property is an indicator whether the virtual keyboard should be shown or hidden.
3607 /// True if an `TextInput` element has the focus; false otherwise.
3608 in property <bool> text-input-focused;
3609 }
3610 }
3611
3612 element! {
3613 /// The **Platform** namespace contains properties that help deal with platform specific differences.
3614 @is_global
3615 Platform {
3616 /// This property holds the type of the operating system detected at run-time.
3617 ///
3618 /// :::note{Note}
3619 /// When running in a web browser, the value of this property is computed at run-time by querying the web browser's navigator properties.
3620 /// :::
3621 ///
3622 /// :::note{Note}
3623 /// When Slint is ported to new operating systems in the future, new enum values will be added.
3624 /// :::
3625 out property <OperatingSystemType> os;
3626 /// `true` when the `.slint` file is being interpreted on its own, with nothing behind it, such as
3627 /// when previewed with `slint-viewer` or the editor's preview, and `false` when the user interface
3628 /// is driven by a host application: your business logic written in Rust, C++, JavaScript or Python.
3629 ///
3630 /// Use it to provide placeholder data and preview-only decorations that are removed from your
3631 /// compiled application. This property is a compile-time constant, so branches that depend on it
3632 /// are optimized away when the value is known to be `false` or `true`.
3633 //
3634 // ```slint playground
3635 // import { ListView, VerticalBox } from "std-widgets.slint";
3636 //
3637 // export struct Data {
3638 // text: string,
3639 // color: color,
3640 // bg: color,
3641 // }
3642 // export component Example inherits Window {
3643 // width: 150px;
3644 // height: 150px;
3645 // in property<[Data]> data: Platform.uses-mock-data ? [
3646 // { text: "Blue", color: #0000ff, bg: #eeeeee},
3647 // { text: "Red", color: #ff0000, bg: #eeeeee},
3648 // { text: "Green", color: #00ff00, bg: #eeeeee},
3649 // { text: "Yellow", color: #ffff00, bg: #222222 },
3650 // { text: "Black", color: #000000, bg: #eeeeee },
3651 // { text: "White", color: #ffffff, bg: #222222 },
3652 // { text: "Magenta", color: #ff00ff, bg: #eeeeee },
3653 // { text: "Cyan", color: #00ffff, bg: #222222 },
3654 // ] : [];
3655 //
3656 // VerticalBox {
3657 // ListView {
3658 // for data in root.data : Rectangle {
3659 // height: 30px;
3660 // background: data.bg;
3661 // width: parent.width;
3662 // Text {
3663 // x: 0;
3664 // text: data.text;
3665 // color: data.color;
3666 // }
3667 // }
3668 // }
3669 // }
3670 // }
3671 // ```
3672 out property <bool> uses-mock-data;
3673 /// The name of the currently selected <Link type="StyleWidgets" label="widget style"/>. Some widget
3674 /// styles have dark and light variant suffixes, such as `fluent-light`. This property contains the
3675 /// style name without the suffix. Use <Link type="Palette" label="Palette"/>'s `color-scheme` to
3676 /// determine the currently used scheme.
3677 out property <string> style-name;
3678 /// The decimal separator used when converting between `float` and `string`.
3679 /// It defaults to the dot (`.`) and is determined by the locale.
3680 /// See the <Link type="translations" label="translations guide"/> for details.
3681 out property <string> decimal-separator;
3682 /// Opens the specified URL in an external browser. This function invokes the platform's URL opening mechanism.
3683 /// Returns `true` on success, or `false` if the platform doesn't support opening URLs or the operation failed.
3684 ///
3685 /// ```slint playground
3686 /// import { Button } from "std-widgets.slint";
3687 ///
3688 /// export component Example inherits Window {
3689 /// Button {
3690 /// text: "Open Slint Website";
3691 /// clicked => {
3692 /// Platform.open-url("https://slint.dev");
3693 /// }
3694 /// }
3695 /// }
3696 /// ```
3697 function open-url(url: string) -> bool { }
3698 /// Brings all application windows to the front of the screen.
3699 ///
3700 /// On macOS this invokes `[NSApp arrangeInFront:]`, which raises every application window
3701 /// to the top of the window stack. On other platforms this function is a no-op.
3702 ///
3703 /// This corresponds to the standard macOS **Window › Bring All to Front** menu item.
3704 function macos-bring-all-windows-to-front() { }
3705 }
3706 }
3707
3708 item! { NativeButton {
3709 in property <string> text;
3710 in property <image> icon;
3711 out property <bool> pressed;
3712 in property <bool> checkable;
3713 in-out property <bool> checked;
3714 out property <bool> has-focus;
3715 in property <bool> primary;
3716 in property <bool> colorize-icon;
3717 in property <length> icon-size;
3718 callback clicked;
3719 in property <bool> enabled: true;
3720 in property <StandardButtonKind> standard-button-kind;
3721 in property <bool> is-standard-button;
3722 } }
3723
3724 element! {
3725 @is_internal @accepts_focus
3726 NativeButton: NativeButton
3727 }
3728
3729 item! { NativeCheckBox {
3730 in property <bool> enabled: true;
3731 in property <string> text;
3732 in-out property <bool> checked;
3733 out property <bool> has-focus;
3734 callback toggled;
3735 } }
3736
3737 element! {
3738 @is_internal @accepts_focus
3739 NativeCheckBox: NativeCheckBox
3740 }
3741
3742 item! { NativeSpinBox {
3743 in property <bool> enabled: true;
3744 out property <bool> has-focus;
3745 in-out property <int> value;
3746 in property <int> minimum;
3747 in property <int> maximum: 100;
3748 in property <int> step-size: 1;
3749 in property <TextHorizontalAlignment> horizontal-alignment;
3750 in property <bool> read-only;
3751 callback edited(value: int);
3752 } }
3753
3754 element! {
3755 @is_internal @accepts_focus
3756 NativeSpinBox: NativeSpinBox
3757 }
3758
3759 item! { NativeSlider {
3760 in property <bool> enabled: true;
3761 out property <bool> has-focus;
3762 in-out property <float> value;
3763 in property <float> minimum;
3764 in property <float> maximum: 100;
3765 in property <float> step: 1;
3766 in property <Orientation> orientation: Orientation.horizontal;
3767 callback changed(value: float);
3768 callback released(value: float);
3769 } }
3770
3771 element! {
3772 @is_internal @accepts_focus
3773 NativeSlider: NativeSlider
3774 }
3775
3776 item! { NativeProgressIndicator {
3777 in property <bool> indeterminate;
3778 in property <float> progress;
3779 } }
3780
3781 element! {
3782 @is_internal
3783 NativeProgressIndicator: NativeProgressIndicator
3784 }
3785
3786 item! { NativeGroupBox {
3787 in property <bool> enabled: true;
3788 in property <string> title;
3789 out property <length> native-padding-left;
3790 out property <length> native-padding-right;
3791 out property <length> native-padding-top;
3792 out property <length> native-padding-bottom;
3793 } }
3794
3795 element! {
3796 @is_internal @expands_to_parent_geometry
3797 NativeGroupBox: NativeGroupBox
3798 }
3799
3800 item! { NativeLineEdit {
3801 out property <length> native-padding-left;
3802 out property <length> native-padding-right;
3803 out property <length> native-padding-top;
3804 out property <length> native-padding-bottom;
3805 out property <image> clear-icon;
3806 in property <bool> has-focus;
3807 in property <bool> enabled: true;
3808 } }
3809
3810 element! {
3811 @is_internal
3812 NativeLineEdit: NativeLineEdit
3813 }
3814
3815 item! { NativeScrollView {
3816 in property <length> horizontal-max;
3817 in property <length> horizontal-page-size;
3818 in property <length> horizontal-value;
3819 in property <length> vertical-max;
3820 in property <length> vertical-page-size;
3821 in-out property <length> vertical-value;
3822 out property <length> native-padding-left;
3823 out property <length> native-padding-right;
3824 out property <length> native-padding-top;
3825 out property <length> native-padding-bottom;
3826 in property <bool> has-focus;
3827 in property <ScrollBarPolicy> vertical-scrollbar-policy;
3828 in property <ScrollBarPolicy> horizontal-scrollbar-policy;
3829 in property <bool> enabled: true;
3830 callback scrolled;
3831 } }
3832
3833 element! {
3834 @is_internal @expands_to_parent_geometry
3835 NativeScrollView: NativeScrollView
3836 }
3837
3838 item! { NativeStandardListViewItem {
3839 in property <int> index;
3840 in property <StandardListViewItem> item;
3841 in-out property <bool> is-selected;
3842 in property <bool> has-hover;
3843 in property <bool> has-focus;
3844 in property <bool> pressed;
3845 in property <bool> combobox;
3846 in property <length> pressed-x;
3847 in property <length> pressed-y;
3848 } }
3849
3850 element! {
3851 @is_internal
3852 NativeStandardListViewItem: NativeStandardListViewItem
3853 }
3854
3855 item! { NativeTableHeaderSection {
3856 in property <int> index;
3857 in property <TableColumn> item;
3858 in property <bool> has-hover;
3859 } }
3860
3861 element! {
3862 @is_internal
3863 NativeTableHeaderSection: NativeTableHeaderSection
3864 }
3865
3866 item! { NativeComboBox {
3867 in-out property <string> current-value;
3868 in property <bool> enabled: true;
3869 in property <bool> has-focus;
3870 } }
3871
3872 element! {
3873 @is_internal
3874 NativeComboBox: NativeComboBox
3875 }
3876
3877 item! { NativeComboBoxPopup { } }
3878
3879 element! {
3880 @is_internal
3881 NativeComboBoxPopup: NativeComboBoxPopup
3882 }
3883
3884 item! { NativeTabWidget {
3885 in property <length> width;
3886 in property <length> height;
3887
3888 out property <length> content-x;
3889 out property <length> content-y;
3890 out property <length> content-height;
3891 out property <length> content-width;
3892 out property <length> tabbar-x;
3893 out property <length> tabbar-y;
3894 out property <length> tabbar-height;
3895 out property <length> tabbar-width;
3896 in property <length> tabbar-preferred-height;
3897 in property <length> tabbar-preferred-width;
3898 in property <length> content-min-height;
3899 in property <length> content-min-width;
3900
3901 in property <int> current-index;
3902 in property <int> current-focused;
3903 in property <Orientation> orientation: Orientation.horizontal;
3904 } }
3905
3906 element! {
3907 @is_internal @expands_to_parent_geometry
3908 NativeTabWidget: NativeTabWidget
3909 }
3910
3911 item! { NativeTab {
3912 in property <string> title;
3913 in property <image> icon;
3914 in property <bool> enabled: true;
3915 in-out property <int> current; // supposed to be a binding to the tab
3916 in property <int> tab-index;
3917 in property <int> current-focused;
3918 in property <int> num-tabs;
3919 } }
3920
3921 element! {
3922 @is_internal
3923 NativeTab: NativeTab
3924 }
3925
3926 item! { NativeStyleMetrics {
3927 out property <length> layout-spacing;
3928 out property <length> layout-padding;
3929 out property <length> text-cursor-width;
3930 out property <color> window-background;
3931 out property <color> default-text-color;
3932 out property <color> textedit-background;
3933 out property <color> textedit-text-color;
3934 out property <color> textedit-background-disabled;
3935 out property <color> textedit-text-color-disabled;
3936
3937 out property <bool> dark-color-scheme;
3938
3939 // specific to the Native one
3940 out property <color> placeholder-color;
3941 out property <color> placeholder-color-disabled;
3942
3943 // Tab Bar metrics:
3944 out property <LayoutAlignment> tab-bar-alignment;
3945 } }
3946
3947 element! {
3948 @is_internal @is_non_item_type @is_global
3949 NativeStyleMetrics: NativeStyleMetrics
3950 }
3951
3952 item! { NativePalette {
3953 out property <brush> background;
3954 out property <brush> foreground;
3955 out property <brush> alternate-background;
3956 out property <brush> alternate-foreground;
3957 out property <brush> control-background;
3958 out property <brush> control-foreground;
3959 out property <brush> accent-background;
3960 out property <brush> accent-foreground;
3961 out property <brush> selection-background;
3962 out property <brush> selection-foreground;
3963 out property <brush> border;
3964 in-out property <ColorScheme> color-scheme;
3965 } }
3966
3967 element! {
3968 @is_internal @is_non_item_type @is_global
3969 NativePalette: NativePalette
3970 }
3971
3972 item! { SystemTrayIcon {
3973 /// The icon shown in the system tray. The image is scaled by the platform to the size expected
3974 /// for tray icons. Use `@image-url(...)` to embed an icon asset, or bind to an `image` property
3975 /// fed from your code. The tray icon is only created once a non-empty image has been assigned.
3976 in property <image> icon;
3977 /// The hover text shown over the tray icon.
3978 /// Typically the application name or a short status message.
3979 in property <string> tooltip;
3980 /// Whether the tray icon is registered with the OS.
3981 /// Set it to `false` to hide the icon without dropping the component instance, and back to `true` to show it again.
3982 /// The `show()` and `hide()` methods on the language-binding side are convenience aliases that set this property.
3983 in property <bool> visible: true;
3984 /// A descriptive name for the tray entry, separate from the hover tooltip.
3985 /// Where it actually shows up depends on the platform:
3986 ///
3987 /// | Platform | Where `title` appears |
3988 /// | ------------- | ------------------------------------------------------------------------------------------------ |
3989 /// | Linux, \*BSD | Used by accessibility tools and shown by some desktops when listing tray icons (e.g. an overflow menu). Set as the [StatusNotifierItem `Title`](https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/StatusNotifierItem/) property. |
3990 /// | macOS | The visible text label rendered next to the icon in the menu bar (think battery percent, clock). |
3991 /// | Windows | Has no visible effect; the notification area renders only the icon. |
3992 in property <string> title;
3993 /// Invoked when the user left-clicks the tray icon itself, as opposed to picking an entry from its menu.
3994 /// Whether it's invoked at all depends on the platform:
3995 ///
3996 /// | Platform | Click behavior |
3997 /// | ------------- | ------------------------------------------------------------------------------------- |
3998 /// | Linux, \*BSD | Invoked on a left-click of the icon. The exact gesture is decided by the desktop environment or shell extension hosting the tray. |
3999 /// | macOS | Invoked on a left-click when no `Menu` is attached (or when an `if cond : Menu { ... }`'s condition is currently false). When a populated menu is attached, AppKit pops it open instead and `clicked` doesn't fire. |
4000 /// | Windows | Invoked on a left-click of the icon. Right-click opens the menu. |
4001 callback clicked;
4002 } }
4003
4004 element! {
4005 // Lowered in lower_menus pass. See that pass documentation for more info.
4006 // The optional Menu child is lifted into a separate item tree and wired via
4007 // the `SetupSystemTrayIcon` builtin.
4008 /// Use the `SystemTrayIcon` element to add an icon and menu to the desktop's system tray,
4009 /// also known as the notification area, status area, or menu bar extras, depending on the platform.
4010 ///
4011 /// `SystemTrayIcon` is a top-level component: derive your own component
4012 /// from it with `inherits SystemTrayIcon` instead of placing it inside a <Link type="Window" />.
4013 /// A `SystemTrayIcon` component has no window of its own — the icon lives in the tray, and the only UI
4014 /// it presents is the menu.
4015 ///
4016 /// ```slint
4017 /// export component ExampleTray inherits SystemTrayIcon {
4018 /// icon: @image-url("tray-icon.png");
4019 /// tooltip: "My App";
4020 ///
4021 /// Menu {
4022 /// MenuItem {
4023 /// title: "Quit";
4024 /// activated => { quit(); }
4025 /// }
4026 /// }
4027 ///
4028 /// callback quit();
4029 /// }
4030 /// ```
4031 ///
4032 /// Create the component from your language binding as you would any other Slint component;
4033 /// the tray icon appears as soon as the instance is created and an event loop is running,
4034 /// and disappears when the instance is dropped.
4035 ///
4036 /// :::note{Note}
4037 /// A `SystemTrayIcon` exported alongside a `Window` doesn't share <Link type="Globals" label="globals" /> with that window — each instance gets its own copy.
4038 /// You may need to initialize the relevant globals on each instance, the same way you would across multiple windows.
4039 /// :::
4040 ///
4041 /// :::note{Note}
4042 /// A `SystemTrayIcon` must contain exactly one <Link type="Menu" /> child, and that `Menu` must not
4043 /// be inside an `if` or a `for`. No other child element types are permitted. The menu itself may
4044 /// use `if` / `for` to build its entries dynamically.
4045 /// :::
4046 ///
4047 /// \skip_children
4048 /// \footer
4049 /// ## Menu
4050 ///
4051 /// The child `Menu` defines the menu that is shown when the user clicks or right-clicks the tray
4052 /// icon. Its structure is the same as for <Link type="MenuBar" /> and `ContextMenuArea`: use
4053 /// `MenuItem` for entries, nested `Menu` elements for sub-menus, and `MenuSeparator` for
4054 /// separators. See <Link type="Menu" /> for the properties and callbacks available on those
4055 /// elements.
4056 ///
4057 /// The menu tree is reactive: when any property the menu reads changes (for example the `title`,
4058 /// `enabled`, or `checked` binding of a `MenuItem`), Slint rebuilds the platform menu so the tray
4059 /// reflects the new state on its next open.
4060 ///
4061 /// Keyboard `shortcut` bindings on `MenuItem`s within a `SystemTrayIcon` are ignored — tray menus are
4062 /// not attached to a focused window, so there is nothing for the shortcut to fire against.
4063 ///
4064 /// ## Language Bindings
4065 ///
4066 /// The generated public API for a `SystemTrayIcon`-rooted component is smaller than the one
4067 /// for a `Window`-rooted component. Construction, property and callback accessors, and global
4068 /// access work the same way. Two things are missing:
4069 ///
4070 /// | Operation | Window-rooted | SystemTrayIcon-rooted |
4071 /// | ---------------------- | :-----------: | :---------------: |
4072 /// | access the window | yes | **no** |
4073 /// | run the event loop | yes | **no** |
4074 ///
4075 /// `show` and `hide` exist on both, but on a `SystemTrayIcon` they set the `visible` property,
4076 /// and the platform backend translates that into the native tray API.
4077 /// A visible `SystemTrayIcon` keeps the event loop alive the same way a visible window does.
4078 ///
4079 /// A typical app instantiates both a main window and a tray, shows them, and runs the event loop.
4080 /// The snippets below also wire the built-in `clicked` callback so a left-click on the tray icon
4081 /// brings the window back if the user has hidden it.
4082 ///
4083 /// <Tabs syncKey="dev-language">
4084 /// <TabItem label="Rust">
4085 /// ```rust
4086 /// fn main() -> Result<(), slint::PlatformError> {
4087 /// let window = MainWindow::new()?;
4088 /// let tray = ExampleTray::new()?;
4089 ///
4090 /// let window_weak = window.as_weak();
4091 /// tray.on_clicked(move || {
4092 /// if let Some(w) = window_weak.upgrade() {
4093 /// let _ = w.show();
4094 /// }
4095 /// });
4096 ///
4097 /// window.show()?;
4098 /// tray.show()?;
4099 /// slint::run_event_loop()
4100 /// }
4101 /// ```
4102 /// </TabItem>
4103 /// <TabItem label="C++">
4104 /// ```cpp
4105 /// int main() {
4106 /// auto window = MainWindow::create();
4107 /// auto tray = ExampleTray::create();
4108 ///
4109 /// auto window_weak = slint::ComponentWeakHandle(window);
4110 /// tray->on_clicked([window_weak] {
4111 /// if (auto w = window_weak.lock()) {
4112 /// (*w)->show();
4113 /// }
4114 /// });
4115 ///
4116 /// window->show();
4117 /// tray->show();
4118 /// slint::run_event_loop();
4119 /// }
4120 /// ```
4121 /// </TabItem>
4122 /// <TabItem label="NodeJS">
4123 /// ```js
4124 /// const window = new ui.MainWindow();
4125 /// const tray = new ui.ExampleTray();
4126 /// tray.clicked = () => window.show();
4127 /// window.show();
4128 /// tray.show();
4129 /// await slint.runEventLoop();
4130 /// ```
4131 /// </TabItem>
4132 /// <TabItem label="Python">
4133 /// ```python
4134 /// window = module.MainWindow()
4135 /// tray = module.ExampleTray()
4136 /// tray.clicked = lambda: window.show()
4137 /// window.show()
4138 /// tray.show()
4139 /// slint.run_event_loop()
4140 /// ```
4141 /// </TabItem>
4142 /// </Tabs>
4143 ///
4144 /// A program that exposes only a `SystemTrayIcon` and no window is also valid: skip the
4145 /// `MainWindow` instance, and the loop quits once the tray is hidden (or `slint::quit_event_loop`
4146 /// is called). No `WindowAdapter` is created in that case — the platform backend is still
4147 /// selected the usual way, but no window opens.
4148 ///
4149 /// ## Platform Support
4150 ///
4151 /// | Platform | Mechanism |
4152 /// | ------------- | ----------------------------------------------------- |
4153 /// | Linux, \*BSD | `StatusNotifierItem` / `AppIndicator` on D-Bus |
4154 /// | macOS | `NSStatusItem` in the menu bar |
4155 /// | Windows | Shell notification area icon (`Shell_NotifyIcon`) |
4156 ///
4157 /// On Linux, a desktop environment or shell extension that implements the `StatusNotifierItem`
4158 /// specification is required; plain X11 system trays are not supported. GNOME, for example,
4159 /// needs an extension such as *AppIndicator and KStatusNotifierItem Support*.
4160 ///
4161 /// \group:window
4162 @is_non_item_type @disallow_global_types_as_child_elements
4163 SystemTrayIcon: SystemTrayIcon {
4164 children: Menu;
4165 }
4166 }
4167}
4168
4169/// Fill `register` with the builtin elements. It must already contain the basic types
4170/// (string, int, ...), the builtin structs and enums.
4171pub(crate) fn load(register: &mut TypeRegister) {
4172 let mut loader = Loader { register, items: HashMap::new(), elements: HashMap::new() };
4173 build(&mut loader);
4174 let Loader { register, elements, .. } = loader;
4175 // Elements that are accepted children of another one are only reachable through it.
4176 let is_child = |name: &SmolStr| {
4177 elements.values().any(|e| e.additional_accepted_child_types.contains_key(name))
4178 };
4179 for (name, element) in &elements {
4180 match name.as_str() {
4181 "Empty" => register.empty_type = ElementType::Builtin(element.clone()),
4182 "PropertyAnimation" => {
4183 register.property_animation_type = ElementType::Builtin(element.clone())
4184 }
4185 _ if !element.is_global && !is_child(name) => register.add_builtin(element.clone()),
4186 _ => {}
4187 }
4188 }
4189}