In the last few steps, we built an image grid for our app. Image grids allow you to view multiple images at the same time. Sometimes, however, instead of viewing multiple images at the same time, you want to view multiple images one at a time. That's what slideshows are for. In the next few steps, we're going to create a slideshow for our app.
Our slideshow will be structured as follows:
- The `Slideshow` consists of a single `Image`, with a transparent `SlideshowOverlay` on top.
- The `SlideshowOverlay` contains two `SlideshowNavigateButton`s, one on each side.
- The two `SlideshowNavigationButton`s will be used to navigate the slideshow by mouse.
To keep our initial implementation simple, our slideshow will only display a placeholder image, and won't respond to user events yet. We'll remove this limitations in later steps.
In this step, we'll start by creating the two `SlideshowNavigateButton`s.
> **Note:**
> If you don't feel like typing along, you can find all the code for this step here:
> https://github.com/makepad/image_viewer/tree/main/step_8
## What you will learn
In this step, you will learn:
- How to use a `Button`.
- How inheritance works in Makepad.
## Adding Arrow Icons
For the two `SlideshowNavigateButton`s, we need some arrow icons, so we first need to add those as resources to our app.
Navigate to the **resources** directory, and download the following files to it:
[[left_arrow.svg]]
[[right_arrow.svg]]
We'll use these files as our arrow icons.
## Defining Variables
Now that we've added the arrow icons, we'll define some variables to refer to our arrow icons in the DSL code.
In **app.rs**, add the following code to the top of the live design block:
```rust
LEFT_ARROW = dep("crate://self/resources/left_arrow.svg");
RIGHT_ARROW = dep("crate://self/resources/right_arrow.svg");
```
This defines two variable named `LEFT_ARROW` and `RIGHT_ARROW`. We'll use these variables to refer to our arrow icons elsewhere in the DSL Code.
### Defining `SlideshowNavigateButton`
Now that we have a way to refer to the arrow icons, we can add a definition for the `SlideshowNavigateButton`s. A `SlideshowNavigateButton` is a tall, narrow strip that takes up the height of its container and contains a single arrow icon.
In **app.rs**, add the following code to the live design block, before the definition of `App`:
```rust
SlideshowNavigateButton = <Button> {
width: 50,
height: Fill,
draw_bg: {
color: #fff0,
color_down: #fff2,
}
icon_walk: { width: 9 },
text: "",
grab_key_focus: false,
}
```
This defines a `SlideshowNavigateButton` with the following properties:
- `width: 50` and `height: Fill` ensure the button has the desired size.
- `draw_bg { ... }` controls how the button's background is drawn.
- `color: #fff0` makes the button fully invisible by default.
- `color_down: #fff2` makes the button slightly more visible when it is pressed.
- `icon_walk { ... }` controls how to button's icon is laid out.
- `width: 9` makes the icon 9 pixels wide.
- `text: ""` disables the label for this button.
- `grab_key_focus: false` prevents the button from grabbing key focus when it is clicked (we'll explain this further when we talk about how key focus works).
#### A Primer on Inheritance
This would be a good time to talk a bit about how **inheritance** works in Makepad.
Inheritance in Makepad works very similar to prototypal inheritance in languages such as JavaScript:
- The syntax `{ ... }` is used to define an object. An object is simply a collection of properties, each of which has a name and a value.
- The syntax `Object = { ... }` is used to assign a name to an object.
- Top-level named objects can be used as base classes for other objects.
- The syntax `<Base> { ... }` is used to define an object that inherits from an object `Base`.
- When an object inherits from another object, it copies over all properties from that object.
- Objects can override existing properties to change their values.
- Objects can also add new properties that weren't present in the original.
An example of this is is the `SlideshowNavigateButton` we just defined. The definition of `SlideshowNavigateButton` looks like this:
```rust
SlideshowNavigationButton = <Button> {
...
}
```
That means `SlideshowNavigateButton` derives from `Button`. Recall that Button is one of the built-in widgets we imported with `use link::widgets::*;`. `SlideshowNavigateButton` copies over all properties from `Button`, and then overrides several of its properties.
You may have noticed that we did not specify an image for the icon in our definition of `SlideshowNavigateButton`. That is because `SlideshowNavigateButton` is *itself* intended to be used as a base class: each time we create an instance of it, we'll specify an image for the icon of that specific instance. You'll see an example of this when we update `App`, just below.
## Updating `App`
Now that we have an `SlideshowNavigateButton`, let's update our definition of `App` to display two `SlideshowNavigateButton`s instead of an `ImageGrid` (we'll put the `ImageGrid` back later, when we talk about switching between views).
In **app.rs**, replace the definition of `App` in the live design block with the one here below:
```rust
App = {{App}} {
ui: <Root> {
<Window> {
body = <View> {
<SlideshowNavigateButton> {
draw_icon: { svg_file: (LEFT_ARROW) }
}
<SlideshowNavigateButton> {
draw_icon: { svg_file: (RIGHT_ARROW) }
}
}
}
}
}
```
As you can see, we create two instances of `SlideshowNavigateButton`. For each `SlideshowNavigationButton`, we override the `svg_file` property of `draw_icon` with the variables for the arrow icons we defined earlier. This is an example of the inheritance we mentioned earlier.
## Checking our Progress so Far
Let's check our progress so far.
Make sure you're in your package directory, and run:
```
cargo run --release
```
If everything is working correctly, you should see two buttons — one with a left arrow icon and one with a right arrow icon:
![[SlideshowNavigateButton.png]]
## What's next
In this step, we created the two `SlideshowNavigateButton`s. In the next step, we'll create the `SlideshowOverlay`.