1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: MIT |
3 | |
4 | struct TileData { |
5 | image: image, |
6 | image-visible: bool, |
7 | solved: bool, |
8 | } |
9 | |
10 | component MemoryTile inherits Rectangle { |
11 | in property <bool> open-curtain; |
12 | in property <bool> solved; |
13 | in property <image> icon; |
14 | |
15 | callback clicked; |
16 | |
17 | border-radius: 8px; |
18 | background: root.solved ? #70ff00 : #858585; |
19 | |
20 | animate background { duration: 800ms; } |
21 | |
22 | Image { |
23 | source: root.icon; |
24 | width: parent.width - 16px; |
25 | height: parent.height - 16px; |
26 | x: 8px; |
27 | y: 8px; |
28 | } |
29 | |
30 | // Left curtain |
31 | Rectangle { |
32 | x: 0; |
33 | background: #0025ff; |
34 | border-radius: 4px; |
35 | width: root.open-curtain ? 0px : parent.width / 2 + 4px; |
36 | height: parent.height; |
37 | clip: true; |
38 | |
39 | animate width { duration: 250ms; easing: ease-in; } |
40 | |
41 | Image { |
42 | width: root.width - 32px; |
43 | height: root.height - 32px; |
44 | x: 16px; |
45 | y: 16px; |
46 | source: @image-url("icons/tile_logo.png" ); |
47 | } |
48 | } |
49 | |
50 | // Right curtain |
51 | right-curtain := Rectangle { |
52 | background: #0025ff; |
53 | border-radius: 4px; |
54 | x: root.open-curtain ? parent.width : parent.width / 2 - 4px; |
55 | width: root.open-curtain ? 0px : parent.width / 2 + 4px; |
56 | height: parent.height; |
57 | clip: true; |
58 | |
59 | animate width { duration: 250ms; easing: ease-in; } |
60 | animate x { duration: 250ms; easing: ease-in; } |
61 | |
62 | Image { |
63 | width: root.width - 32px; |
64 | height: root.height - 32px; |
65 | x: right-curtain.width - self.width - 16px; |
66 | y: 16px; |
67 | source: @image-url("icons/tile_logo.png" ); |
68 | } |
69 | } |
70 | |
71 | TouchArea { |
72 | clicked => { |
73 | root.clicked(); |
74 | } |
75 | |
76 | width: 100%; |
77 | height: 100%; |
78 | } |
79 | } |
80 | |
81 | export component MainWindow inherits Window { |
82 | in property <bool> disable-tiles; |
83 | in property <[TileData]> memory-tiles : [ |
84 | { image: @image-url("icons/at.png" ) }, |
85 | { image: @image-url("icons/balance-scale.png" ) }, |
86 | { image: @image-url("icons/bicycle.png" ) }, |
87 | { image: @image-url("icons/bus.png" ) }, |
88 | { image: @image-url("icons/cloud.png" ) }, |
89 | { image: @image-url("icons/cogs.png" ) }, |
90 | { image: @image-url("icons/motorcycle.png" ) }, |
91 | { image: @image-url("icons/video.png" ) }, |
92 | ]; |
93 | |
94 | callback check-if-pair-solved(); |
95 | |
96 | private property <length> tile-size: 80px; |
97 | private property <length> tile-spacing: 10px; |
98 | private property <int> row-count: 4; |
99 | private property <int> column-count: 4; |
100 | |
101 | // "column_count + 1" and "row_count + 1" are the number of gaps between the tiles. |
102 | width: (root.column-count * root.tile-size) + ((root.column-count + 1) * root.tile-spacing); |
103 | height: (root.row-count * root.tile-size) + ((root.row-count + 1) * root.tile-spacing); |
104 | title: "Memory Game - Slint Demo" ; |
105 | |
106 | for tile[i] in root.memory-tiles: MemoryTile { |
107 | clicked => { |
108 | if (!root.disable-tiles) { |
109 | tile.image-visible = !tile.image-visible; |
110 | root.check-if-pair-solved(); |
111 | } |
112 | } |
113 | |
114 | x: root.tile-spacing + mod(i, root.column-count) * (root.tile-size + root.tile-spacing); |
115 | y: root.tile-spacing + floor(i / root.row-count) * (root.tile-size + root.tile-spacing); |
116 | width: root.tile-size; |
117 | height: root.tile-size; |
118 | |
119 | icon: tile.image; |
120 | |
121 | open-curtain: tile.image-visible || tile.solved; |
122 | solved: tile.solved; |
123 | } |
124 | } |
125 | |