| 1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
| 2 | // SPDX-License-Identifier: MIT |
| 3 | |
| 4 | import { Theme } from "../theme.slint" ; |
| 5 | import { MenuButton } from "menu_button.slint" ; |
| 6 | import { MenuBackground } from "../components/menu_background.slint" ; |
| 7 | |
| 8 | export component Menu { |
| 9 | in-out property <bool> menu-button-visible; |
| 10 | in property <length> start-y; |
| 11 | in property <length> end-y; |
| 12 | in property <bool> stays-open; |
| 13 | in property <length> menu-width <=> i-menu-container.width; |
| 14 | in property <length> menu-height <=> i-menu-container.height; |
| 15 | out property <bool> open; |
| 16 | |
| 17 | callback opened(); |
| 18 | callback closed(); |
| 19 | |
| 20 | public function hide-button() { |
| 21 | menu-button-visible = false; |
| 22 | } |
| 23 | |
| 24 | public function open-menu() { |
| 25 | open = true; |
| 26 | } |
| 27 | |
| 28 | public function hide() { |
| 29 | menu-button-visible = false; |
| 30 | open = false; |
| 31 | closed(); |
| 32 | } |
| 33 | |
| 34 | private property <int> container-visibility; |
| 35 | |
| 36 | states [ |
| 37 | open when root.open : { |
| 38 | container-visibility: 1.0; |
| 39 | i-menu-container.y: end-y; |
| 40 | |
| 41 | in { |
| 42 | animate i-menu-container.y { duration: Theme.durations.medium; } |
| 43 | } |
| 44 | out { |
| 45 | animate container-visibility, i-menu-container.y { duration: Theme.durations.medium; } |
| 46 | } |
| 47 | } |
| 48 | ] |
| 49 | |
| 50 | if (open) : Rectangle { |
| 51 | background: Theme.palette.pure-black; |
| 52 | opacity: 0.5; |
| 53 | |
| 54 | TouchArea { |
| 55 | clicked => { |
| 56 | hide(); |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | i-menu-container := Rectangle { |
| 62 | x: (parent.width - self.width) / 2; |
| 63 | y: parent.height - start-y; |
| 64 | width: root.width / 3; |
| 65 | height: root.height - 75px; |
| 66 | |
| 67 | i-container := MenuBackground { |
| 68 | visible: container-visibility == 1.0; |
| 69 | |
| 70 | // avoid click-through |
| 71 | TouchArea {} |
| 72 | |
| 73 | @children |
| 74 | } |
| 75 | |
| 76 | if(menu-button-visible || container-visibility == 1.0 || stays-open) : HorizontalLayout { |
| 77 | y: -i-menu-button.height / 2; |
| 78 | alignment: center; |
| 79 | |
| 80 | VerticalLayout { |
| 81 | alignment: start; |
| 82 | |
| 83 | i-menu-button := MenuButton { |
| 84 | clicked => { |
| 85 | if(open) { |
| 86 | hide(); |
| 87 | } else { |
| 88 | open-menu(); |
| 89 | } |
| 90 | } |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | export component MobileMenu { |
| 98 | out property <bool> open; |
| 99 | in property <length> end-y; |
| 100 | in property <length> menu-x; |
| 101 | out property <length> menu-width: 200px; |
| 102 | |
| 103 | if (root.open) : Rectangle { |
| 104 | background: Theme.palette.pure-black; |
| 105 | opacity: 0.5; |
| 106 | |
| 107 | TouchArea { |
| 108 | clicked => { |
| 109 | hide(); |
| 110 | } |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | public function open-menu() { |
| 115 | root.open = true; |
| 116 | } |
| 117 | |
| 118 | public function hide() { |
| 119 | root.open = false; |
| 120 | } |
| 121 | |
| 122 | Rectangle { |
| 123 | clip: true; |
| 124 | menu := Rectangle { |
| 125 | x: root.menu-x; |
| 126 | y: -self.height; |
| 127 | width: root.menu-width; |
| 128 | height: root.height / 2; |
| 129 | visible: visibility > 0.0; |
| 130 | |
| 131 | private property <float> visibility; |
| 132 | |
| 133 | MenuBackground { |
| 134 | // avoid click-through |
| 135 | TouchArea {} |
| 136 | |
| 137 | @children |
| 138 | } |
| 139 | |
| 140 | states [ |
| 141 | open when root.open : { |
| 142 | menu.y: end-y; |
| 143 | visibility: 1.0; |
| 144 | |
| 145 | out { |
| 146 | animate visibility { duration: Theme.durations.medium; } |
| 147 | } |
| 148 | } |
| 149 | ] |
| 150 | |
| 151 | animate y { duration: Theme.durations.fast; } |
| 152 | } |
| 153 | |
| 154 | } |
| 155 | } |
| 156 | |