Polishing the Tile
In this step, you add a curtain-like cover that opens when clicked. You do this by declaring two rectangles below the Image, so that Slint draws them after the Image and thus on top of the image.
The TouchArea element declares a transparent rectangular region that allows reacting to user input such as a mouse click or tap. The element forwards a callback to the MainWindow indicating that a user clicked the tile.
The MainWindow reacts by flipping a custom open_curtain property. Property bindings for the animated width and x properties also use the custom open_curtain property.
The following table shows more detail on the two states:
open_curtain value: | false | true |
---|---|---|
Left curtain rectangle | Fill the left half by setting the width width to half the parent's width | Width of zero makes the rectangle invisible |
Right curtain rectangle | Fill the right half by setting x and width to half of the parent's width | width of zero makes the rectangle invisible. x moves to the right, sliding the curtain open when animated |
To make the tile extensible, replace the hard-coded icon name with an icon property that can be set when instantiating the element.
For the final polish, add a solved property used to animate the color to a shade of green when a player finds a pair.
Replace the code inside the ui/appwindow.slint
file with the following:
component MemoryTile inherits Rectangle {
callback clicked;
in property <bool> open_curtain;
in property <bool> solved;
in property <image> icon;
height: 64px;
width: 64px;
background: solved ? #34CE57 : #3960D5;
animate background { duration: 800ms; }
Image {
source: icon;
width: parent.width;
height: parent.height;
}
// Left curtain
Rectangle {
background: #193076;
x: 0px;
width: open_curtain ? 0px : (parent.width / 2);
height: parent.height;
animate width { duration: 250ms; easing: ease-in; }
}
// Right curtain
Rectangle {
background: #193076;
x: open_curtain ? parent.width : (parent.width / 2);
width: open_curtain ? 0px : (parent.width / 2);
height: parent.height;
animate width { duration: 250ms; easing: ease-in; }
animate x { duration: 250ms; easing: ease-in; }
}
TouchArea {
clicked => {
// Delegate to the user of this element
root.clicked();
}
}
}
export component MainWindow inherits Window {
MemoryTile {
icon: @image-url("icons/bus.png");
clicked => {
self.open_curtain = !self.open_curtain;
}
}
}
The code uses root
and self
. root
refers to the outermost
element in the component, the MemoryTile in this case. self
refers
to the current element.
The code exports the MainWindow component. This is necessary so that you can later access it from application business logic.
Running the code opens a window with a rectangle that opens up to show the bus icon when clicked. Subsequent clicks close and open the curtain again.