diff --git a/docs/builtin_elements.md b/docs/builtin_elements.md index f8726c20e..f1a633943 100644 --- a/docs/builtin_elements.md +++ b/docs/builtin_elements.md @@ -51,6 +51,9 @@ When not part of a layout, its width or height defaults to 100% of the parent el * **`border_width`** (*length*): The width of the border. (default value: 0) * **`border_color`** (*brush*): The color of the border. (default value: transparent) * **`border_radius`** (*length*): The size of the radius. (default value: 0) +* **`clip`** (*bool*): By default, when an item is bigger or outside another item, it is still shown. + But when this property is set to true, then the children element of this Rectangle are going to be clipped. + This property must be a literal `true` or `false` (default: false) ### Example @@ -563,6 +566,8 @@ But the `Clip` element make sure to clip any children outside of the rectangle When not part of a layout, its width or height defaults to 100% of the parent element when not specified. +FIXME: deprecate this item as it can be replaced by the `clip:` property + ## `PopupWindow` This allow to show a popup window like a tooltip or a popup menu. @@ -655,7 +660,7 @@ This enum describes the how the text appear if it is too wide to fit in the Text ### Values -* **`TextWrap.clip`**: The text will simpli be clipped. +* **`TextWrap.clip`**: The text will simply be clipped. * **`TextWrap.elide`**: The text will be ellided with `…`. ## `EventResult` diff --git a/examples/printerdemo/ui/ink_page.60 b/examples/printerdemo/ui/ink_page.60 index be836f880..57564a0ad 100644 --- a/examples/printerdemo/ui/ink_page.60 +++ b/examples/printerdemo/ui/ink_page.60 @@ -31,10 +31,11 @@ export InkPage := Page { HorizontalLayout { spacing: root.width * 5%; for color_info in ink_levels : Rectangle { - ink := Clip { + ink := Rectangle { width: parent.width; height: parent.height * color_info.level; y: parent.height - self.height; + clip: true; Rectangle { background: color_info.color; border-radius: width / 2; diff --git a/examples/printerdemo/ui/printer_queue.60 b/examples/printerdemo/ui/printer_queue.60 index 0f6290d81..dd96a4825 100644 --- a/examples/printerdemo/ui/printer_queue.60 +++ b/examples/printerdemo/ui/printer_queue.60 @@ -95,13 +95,15 @@ NarrowPrintQueueElement := Rectangle { border-radius: 14px; border-width: 2px; background: DemoPalette.printer_queue_item_background_color; + clip: true; property expanded; height: layout.minimum-height; animate height { duration: 200ms; easing: ease; } - Clip { + + Rectangle { height: 100%; layout := VerticalLayout { padding: root.border_radius; diff --git a/examples/slide_puzzle/slide_puzzle.60 b/examples/slide_puzzle/slide_puzzle.60 index 456abbef1..13086cd5a 100644 --- a/examples/slide_puzzle/slide_puzzle.60 +++ b/examples/slide_puzzle/slide_puzzle.60 @@ -63,8 +63,9 @@ Checkbox := Rectangle { border-color: unchecked_color; border-radius: 2px; - clip := Clip { + clip := Rectangle { width: 0px; + clip: true; Text { width: root.width; @@ -295,9 +296,9 @@ export MainWindow := Window { for p[i] in pieces : Rectangle { - x: tile.py * (pieces_size + pieces_spacing) + p.offset_x + x: py * (pieces_size + pieces_spacing) + p.offset_x + (parent.width - (4*pieces_size + 3*pieces_spacing))/2; - y: tile.px * (pieces_size + pieces_spacing) + p.offset_y + y: px * (pieces_size + pieces_spacing) + p.offset_y + (parent.height - (4*pieces_size + 3*pieces_spacing))/2; width: pieces_size; height: pieces_size; @@ -308,85 +309,84 @@ export MainWindow := Window { drop-shadow-blur: 6px; drop-shadow-color: #00000080; border-radius: current-theme.piece-radius; + clip: true; - tile := Clip { - property px: p.pos_x; - property py: p.pos_y; - animate px , py { duration: 170ms; easing: cubic-bezier(0.17,0.76,0.4,1.75); } + property px: p.pos_x; + property py: p.pos_y; + animate px , py { duration: 170ms; easing: cubic-bezier(0.17,0.76,0.4,1.75); } - if (current-theme.game-use-background-image) : Image { - height: 100%; width: 100%; - // https://commons.wikimedia.org/wiki/File:Berlin_potsdamer_platz.jpg Belappetit, CC BY-SA 3.0 - source: @image-url("berlin.jpg"); - source-clip-x: mod(i, 4) * 1024 / 4; - source-clip-y: floor(i / 4) * 683 / 4; - source-clip-width: 1024 / 4; - source-clip-height: 683 / 4; + if (current-theme.game-use-background-image) : Image { + height: 100%; width: 100%; + // https://commons.wikimedia.org/wiki/File:Berlin_potsdamer_platz.jpg Belappetit, CC BY-SA 3.0 + source: @image-url("berlin.jpg"); + source-clip-x: mod(i, 4) * 1024 / 4; + source-clip-y: floor(i / 4) * 683 / 4; + source-clip-width: 1024 / 4; + source-clip-height: 683 / 4; - if (root.tiles-left != 0) : Rectangle { - width: 60%; - height: 60%; - x: (parent.width - width) / 2; - y: (parent.height - height) / 2; - border-radius: width; - background: is_correct ? #0008 : #fff8; - } + if (root.tiles-left != 0) : Rectangle { + width: 60%; + height: 60%; + x: (parent.width - width) / 2; + y: (parent.height - height) / 2; + border-radius: width; + background: is_correct ? #0008 : #fff8; } - - if (!current-theme.game-use-background-image) : Rectangle { - background: i >= 8 ? current-theme.piece-background-2 : current-theme.piece-background-1; - border-color: i >= 8 ? current-theme.piece-border-color-2 : current-theme.piece-border-color-1; - border-width: current-theme.piece-border; - border-radius: current-theme.piece-radius; - animate border-width, border-radius { duration: 500ms; easing: ease-out; } - } - - if (!current-theme.game-use-background-image || tiles-left > 0) : Text { - text: i+1; - color: ((!current-theme.game-use-background-image && i >= 8) || (current-theme.game-use-background-image && is_correct)) ? current-theme.piece-text-color-2 : current-theme.piece-text-color-1; - font-size: pieces_size / 3; - font-weight: is_correct ? current-theme.piece-text-weight-correct-pos : current-theme.piece-text-weight-incorrect-pos; - font-family: current-theme.piece-text-font-family; - vertical-alignment: center; - horizontal-alignment: center; - width: 100%; - height: 100%; - } - - touch := TouchArea { - clicked => { root.piece_clicked(i); } - } - - shadow := Rectangle { - circle := Rectangle { - height: width; - border-radius: width/2; - background: #0002; - x: touch.pressed_x - width/2; - y: touch.pressed_y - width/2; - } - } - - states [ - pressed when touch.pressed : { - shadow.color: #0002; - circle.width: shadow.width * 2 * 1.4142; - } - hover when touch.has_hover: { - shadow.color: #0000000d; - } - - ] - transitions [ - in pressed : { - animate shadow.color { duration: 50ms; } - animate circle.width { duration: 2s; easing: ease-out; } - } - out pressed : { - animate shadow.color { duration: 50ms; } - } - ] } + + if (!current-theme.game-use-background-image) : Rectangle { + background: i >= 8 ? current-theme.piece-background-2 : current-theme.piece-background-1; + border-color: i >= 8 ? current-theme.piece-border-color-2 : current-theme.piece-border-color-1; + border-width: current-theme.piece-border; + border-radius: current-theme.piece-radius; + animate border-width, border-radius { duration: 500ms; easing: ease-out; } + } + + if (!current-theme.game-use-background-image || tiles-left > 0) : Text { + text: i+1; + color: ((!current-theme.game-use-background-image && i >= 8) || (current-theme.game-use-background-image && is_correct)) ? current-theme.piece-text-color-2 : current-theme.piece-text-color-1; + font-size: pieces_size / 3; + font-weight: is_correct ? current-theme.piece-text-weight-correct-pos : current-theme.piece-text-weight-incorrect-pos; + font-family: current-theme.piece-text-font-family; + vertical-alignment: center; + horizontal-alignment: center; + width: 100%; + height: 100%; + } + + touch := TouchArea { + clicked => { root.piece_clicked(i); } + } + + shadow := Rectangle { + circle := Rectangle { + height: width; + border-radius: width/2; + background: #0002; + x: touch.pressed_x - width/2; + y: touch.pressed_y - width/2; + } + } + + states [ + pressed when touch.pressed : { + shadow.color: #0002; + circle.width: shadow.width * 2 * 1.4142; + } + hover when touch.has_hover: { + shadow.color: #0000000d; + } + + ] + transitions [ + in pressed : { + animate shadow.color { duration: 50ms; } + animate circle.width { duration: 2s; easing: ease-out; } + } + out pressed : { + animate shadow.color { duration: 50ms; } + } + ] } if (root.tiles-left == 0) : Text { diff --git a/sixtyfps_compiler/lib.rs b/sixtyfps_compiler/lib.rs index 623fbb43e..537096a6e 100644 --- a/sixtyfps_compiler/lib.rs +++ b/sixtyfps_compiler/lib.rs @@ -44,6 +44,7 @@ pub mod typeregister; mod passes { pub mod apply_default_properties_from_style; pub mod check_expressions; + pub mod clip; pub mod collect_globals; pub mod collect_structs; pub mod compile_paths; @@ -153,6 +154,7 @@ pub async fn run_passes( mut type_loader: &mut typeloader::TypeLoader<'_>, compiler_config: &CompilerConfiguration, ) { + let global_type_registry = type_loader.global_type_registry.clone(); passes::resolving::resolve_expressions(doc, &type_loader, diag); passes::inlining::inline(doc); passes::check_expressions::check_expressions(doc, diag); @@ -161,10 +163,7 @@ pub async fn run_passes( passes::focus_item::resolve_element_reference_in_set_focus_calls(&doc.root_component, diag); passes::focus_item::determine_initial_focus_item(&doc.root_component, diag); passes::focus_item::erase_forward_focus_properties(&doc.root_component); - passes::flickable::handle_flickable( - &doc.root_component, - &type_loader.global_type_registry.borrow(), - ); + passes::flickable::handle_flickable(&doc.root_component, &global_type_registry.borrow()); passes::materialize_fake_properties::materialize_fake_properties(&doc.root_component); if compiler_config.embed_resources { passes::embed_resources::embed_resources(&doc.root_component); @@ -174,6 +173,7 @@ pub async fn run_passes( passes::lower_popups::lower_popups(&doc.root_component, &doc.local_registry, diag); passes::lower_layout::lower_layouts(&doc.root_component, &mut type_loader, diag).await; passes::lower_shadows::lower_shadow_properties(&doc.root_component, &doc.local_registry, diag); + passes::clip::handle_clip(&doc.root_component, &global_type_registry.borrow(), diag); passes::default_geometry::default_geometry(&doc.root_component, diag); passes::apply_default_properties_from_style::apply_default_properties_from_style( &doc.root_component, diff --git a/sixtyfps_compiler/typeregister.rs b/sixtyfps_compiler/typeregister.rs index c673ea6c7..1787b7237 100644 --- a/sixtyfps_compiler/typeregister.rs +++ b/sixtyfps_compiler/typeregister.rs @@ -36,6 +36,7 @@ const RESERVED_LAYOUT_PROPERTIES: &'static [(&'static str, Type)] = &[ ("row", Type::Int32), ("colspan", Type::Int32), ("rowspan", Type::Int32), + ("clip", Type::Bool), ]; const RESERVED_OTHER_PROPERTIES: &'static [(&'static str, Type)] = &[