// Copyright © SixtyFPS GmbH // SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-commercial struct TileData { image: image, image-visible: bool, solved: bool, } component MemoryTile inherits Rectangle { border-radius: 8px; callback clicked; in property open-curtain; in property solved; in property icon; background: root.solved ? #70ff00 : #858585; animate background { duration: 800ms; } Image { source: root.icon; width: parent.width - 16px; height: parent.height - 16px; x: 8px; y: 8px; } // Left curtain Rectangle { x:0; background: #0025ff; border-radius: 4px; width: root.open-curtain ? 0px : parent.width / 2 + 4px; height: parent.height; animate width { duration: 250ms; easing: ease-in; } clip: true; Image { width: root.width - 32px; height: root.height - 32px; x: 16px; y: 16px; source: @image-url("icons/tile_logo.png"); } } // Right curtain right-curtain := Rectangle { background: #0025ff; border-radius: 4px; x: root.open-curtain ? parent.width : parent.width / 2 - 4px; width: root.open-curtain ? 0px : parent.width / 2 + 4px; height: parent.height; animate width { duration: 250ms; easing: ease-in; } animate x { duration: 250ms; easing: ease-in; } clip: true; Image { width: root.width - 32px; height: root.height - 32px; x: right-curtain.width - self.width - 16px; y: 16px; source: @image-url("icons/tile_logo.png"); } } TouchArea { width: 100%; height: 100%; clicked => { root.clicked(); } } } export component MainWindow inherits Window { title: "Memory Game - Slint Demo"; callback check-if-pair-solved(); in property disable-tiles; private property tile-size: 80px; private property tile-spacing: 10px; private property row-count: 4; private property column-count: 4; // "column_count + 1" and "row_count + 1" are the number of gaps between the tiles. width: (root.column-count * root.tile-size) + ((root.column-count + 1) * root.tile-spacing); height: (root.row-count * root.tile-size) + ((root.row-count + 1) * root.tile-spacing); in property<[TileData]> memory-tiles : [ { image: @image-url("icons/at.png") }, { image: @image-url("icons/balance-scale.png") }, { image: @image-url("icons/bicycle.png") }, { image: @image-url("icons/bus.png") }, { image: @image-url("icons/cloud.png") }, { image: @image-url("icons/cogs.png") }, { image: @image-url("icons/motorcycle.png") }, { image: @image-url("icons/video.png") }, ]; for tile[i] in root.memory-tiles: MemoryTile { x: root.tile-spacing + mod(i, root.column-count) * (root.tile-size + root.tile-spacing); y: root.tile-spacing + floor(i / root.row-count) * (root.tile-size + root.tile-spacing); width: root.tile-size; height: root.tile-size; icon: tile.image; open-curtain: tile.image-visible || tile.solved; solved: tile.solved; clicked => { if (!root.disable-tiles) { tile.image-visible = !tile.image-visible; root.check-if-pair-solved(); } } } }