Polishing the Tile
Next, let's add a curtain like cover that opens up when clicking. We achieve this by declaring two rectangles below the Image, so that they are drawn afterwards 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. We use that to forward a callback to the MainWindow that the tile was clicked on. In the MainWindow we react by flipping a custom open_curtain property. That in turn is used in property bindings for the animated width and x properties. Let's look at the two states a bit more in detail:
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 is moved to the right, to slide the curtain open when animated |
In order to make our tile extensible, the hard-coded icon name is replaced with an icon
property that can be set from the outside when instantiating the element. For the final polish, we add a
solved property that we use to animate the color to a shade of green when we've found a pair, later. We
replace the code inside the slint!
macro with the following:
MemoryTile := Rectangle {
callback clicked;
property <bool> open_curtain;
property <bool> solved;
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;
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();
}
}
}
MainWindow := Window {
MemoryTile {
icon: @image-url("icons/bus.png");
clicked => {
self.open_curtain = !self.open_curtain;
}
}
}
Note the use of root
and self
in the code. root
refers to the outermost
element in the component, that's the MemoryTile in this case. self
refers
to the current element.
Running this gives us a window on the screen with a rectangle that opens up to show us the bus icon, when clicking on it. Subsequent clicks will close and open the curtain again.