In this tutorial, we create an application using the Flipper Zero's SceneManager and ViewDispatcher. My [YouTube series](https://youtu.be/YbskaB6caqk) also covers using the SceneManager.
The [Flipper Zero](https://flipperzero.one) supports three ways to develop UI (user interface) applications. ViewPort, ViewDispatcher, and SceneManager. This tutorial will focus on using the SceneManager and ViewDispatcher. If you are interested in learning more about ViewPort, please see the [ViewPort Tutorial](../basic/README.md).
If you have more than two pages in your application, you may want to consider using a SceneManager and ViewDispatcher. You can think of a scene as a UI screen with some purpose. Each scene typically uses one module, but multiple scenes may reuse the same module. For example in a sound application, a "volume scene" and a "frequency scene" may both use the same knob module to let the user select the value (but one scene is setting the volume value while the other is setting the frequency). The SceneManager will handle the transition between scenes and uses the ViewDispatcher to handle the transition between views. The Scene Manager is a good way to develop UI applications, where you want to navigate between scenes. Using a Scene Manager helps you to reuse code, handle the transition between scenes, and keeps the logic for each scene separate.
For a list of all of the modules available in applications/services/gui, please see [A Visual Guide to Flipper Zero GUI Components](https://brodan.biz/blog/a-visual-guide-to-flipper-zero-gui-components/) over on brodan.biz/blog.
If you have not already installed Git and VS Code, you will need to do so. The following links will take you to the download pages for Git and VS Code.
Clone the Flipper Zero firmware from GitHub. The following command will clone the firmware into a folder named official-firmware. (The below commands may wrap on your screen. You can copy and paste the entire command; there should only be two lines.)
Replace _<your working directory>_ with the directory where you want to clone the firmware.
## Step 3. Run FBT to build the firmware and configure VS Code.
Run the following commands from the root of the firmware folder to build the firmware and configure VS Code. Replace _<your working directory>_ with the directory where you cloned the firmware. In some environments you do not need the "./" at the beginning of the command.
```console
cd <yourworkingdirectory>
cd official-firmware
./fbt vscode_dist
./fbt updater_package
```
\*\*\* **Please follow the steps at [FBT VSCode integration](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/fbt.md#vscode-integration) before proceeding.** \*\*\*
## Step 4. Create a basic_scenes directory.
After you have followed the steps at [FBT VSCode integration](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/fbt.md#vscode-integration),
you should have Visual Studio Code open and be in the official-firmware folder.
Create a directory named **basic_scenes** in the applications_user directory. This is where we will store all of the files for our application.
![Create directory](./docs/create-directory.png)
## Step 5. Create an icon for the Flipper UI.
Create a **basic_scenes.png** file. This is the icon that will be displayed when selecting the Flipper app in the Flipper UI. I typically use a 10x10 pixel image with black and white pixels. The image can be any 10x10 image you want.
furi.h contains the definions for FURI (Flipper Universal Registry Implementation). furi_delay_ms is a function that will delay the application for the specified number of milliseconds. FuriString is a string type that is used by the Flipper Zero firmware.
The basic_scenes_app function will be called when the application is started. We configured this in our application.fam file entry_point parameter in the previous step. The function returns 0 when the application exits.
## Step 8. Compile and run the application.
Run the following command from the root of the firmware folder to compile and run the application. Make sure you are not currently running the Flipper UI,
qFlipper or lab.flipper.net. In some environments you do not need the "./" at the beginning of the command.
You should see an hour glass on the Flipper for 5 seconds and then the Flipper UI will return to the Desktop application.
![Hour glass](./docs/app-hour-glass.png)
Our code currently does not have any user interface. We will add more code to our application in the next steps.
When the program exits, it will now be installed on the Flipper. You can see the application on the Flipper Zero under Applications, then Misc, then Basic Scenes Demo. Congratulations, you have created a Flipper Zero application!
![App Installed](./docs/app-installed.png)
Troubleshooting:
- If you get "Could not open com port" error, you need to confirm that the Flipper is connected to your computer and that you are not running the Flipper UI, qFlipper or lab.flipper.net.
- If you get "\***\*\*\*\*\*** FBT ERRORS \***\*\*\*\*\***" error, you need to ensure that your code and application.fam matches the code from the previous steps.
## Step 9. Create an enum for the scenes.
Remember that we are creating a basic scenes application with four scenes:
Each scene will have an on_enter, on_event and on_exit function. We will create stub functions for each of these functions. Later in the tutorial we will add code to these functions.
Add the following lines after the App typedef in the basic_scenes.c file:
Create an array of our on_enter handlers. The order of the scenes should be the same order as defined in the BasicScenesScene enum (main menu, lottery, greeting input, greeting message).
The scene manager handlers object will be used to initialize the scene manager. The scene_num field should be set to the number of scenes in our application, which is defined as 4 by the BasicScenesSceneCount enum.
We will create a basic_scene_custom_callback function to handle the custom event. This function will be called when the custom event is received. Custom events can be invoked for various reasons, such as a timer, voltage changes on Flipper Zero pins, new data, or if a view decides to invoke a custom event (perhaps due to keypress or invalid data being entered). We will delegate our custom event handling to the scene manager's handle custom event routine. We will see examples of custom events in steps 28 & 36.
We will create a scene_back_event_callback function to handle the back event. This function will be called when the back event is received due to the user clicking the BACK button. We will delegate our back event handling to the scene manager's handle back event routine.
We will create an app_alloc function to allocate memory for our application. This function will allocate memory for the scene manager, view dispatcher, submenu, widget and text input. The scene manager will be initialized with the scene manager handlers object we created in step 17. We also add the views for the submenu, widget and text input to the view dispatcher, so they can be referenced by their enum values.
We will create an app_free function to free memory allocated for our application. This function will remove all of the views from the view dispatcher, and then free the memory allocated for the scene manager, view dispatcher, submenu, widget and text input.
We will create a stub menu callback function. This function will be called when a menu item is selected. In the future, we will update this function to fire a custom event to navigate to the next scene.
- Set the header of the submenu to "Basic Scenes Demo".
- Add a menu item with the text "Lotto Numbers" and the index 0.
- Add a menu item with the text "Greeting" and the index 1.
## Step 25. Compile and run the application.
Run the following command from the root of the firmware folder to compile and run the application. Make sure you are not currently running the Flipper UI,
qFlipper or lab.flipper.net. In some environments you do not need the "./" at the beginning of the command.
You should see your application's main menu on the Flipper! You can use the UP/DOWN buttons on the Flipper Zero to switch your selection. Press the BACK button to exit the application.
![App Menu](./docs/app-menu.png)
Congratulations, your Flipper Zero application now has a menu!
## Step 26. Create an enum with menu item indexes.
We will create an enum with menu item indexes. This will allow us to reference menu items by their enum values instead of using magic numbers (using "BasicScenesMainMenuSceneGreeting" instead of "1" in our code makes it easier to understand).
## Step 28. Create an enum with custom events from the main menu.
The next step is to create an enum with custom events from the main menu. This will allow us to reference custom events by their enum values instead of using magic numbers.
Add the following lines after the BasicScenesMainMenuSceneIndex in the basic_scenes.c file:
```c
typedef enum {
BasicScenesMainMenuSceneLottoNumbersEvent,
BasicScenesMainMenuSceneGreetingEvent,
} BasicScenesMainMenuEvent;
```
## Step 29. Update the basic_scenes_menu_callback function.
Update the basic_scenes_menu_callback function to fire a custom event when a menu item is selected. The custom event will trigger our scenes on_event function.
Replace the basic_scenes_menu_callback function with the following code:
- When the menu item with the index BasicScenesMainMenuSceneLottoNumbers is selected, the function fires the BasicScenesMainMenuSceneLottoNumbersEvent custom event.
- When the menu item with the index BasicScenesMainMenuSceneGreeting is selected, the function fires the BasicScenesMainMenuSceneGreetingEvent custom event.
- These custom events will be handled in the basic_scenes_main_menu_scene_on_event function, which we update in the next step.
## Step 30. Update the basic_scenes_main_menu_scene_on_event function.
Update the basic_scenes_main_menu_scene_on_event function to handle the custom events from the main menu. The function will navigate to the next scene when a custom event is received. The function should look like this:
- Adds a string element with the text "Lotto numbers:" at position (25, 15).
- Adds a string element with the text "0 4 2" at position (30, 35).
- Switches to the widget view.
## Step 33. Compile and run the application.
Run the following command from the root of the firmware folder to compile and run the application. Make sure you are not currently running the Flipper UI,
qFlipper or lab.flipper.net. In some environments you do not need the "./" at the beginning of the command.
The application should launch the main menu, with options for Lotto Numbers and Greeting. Select the 'Lotto numbers' menu item and click the OK button on the Flipper Zero. The application should show the lotto numbers screen:
![Lotto screen](./docs/app-lotto.png)
Click the BACK button on the Flipper Zero to return to the main menu. Click the BACK button again to exit the application.
Congratulations, your Flipper Zero application can display a lottery number guess! It's https://xkcd.com/221/ all over again!
## Step 34. Add a buffer to the App struct.
In the next five steps, we are going to create the code to prompt the user for their name and store their response in a buffer. The order of the steps is somewhat backwards, so that future steps can reference the code from previous steps.
Add a buffer (user_name) to the App struct. The buffer will be used to store the user's name. We will also add a variable (user_name_size) to indicate the maximum size of the buffer. Update the App struct in the basic_scenes.h file:
Update the app_alloc function to allocate the buffer for the user's name. For this example, we will set the maximum length to 16 characters. The beginning of function should look like this:
We will trigger the custom event when the user has completed entering their name. The BasicScenesGreetingInputEvent enum should be defined after BasicScenesMainMenuEvent in the basic_scenes.h file:
The text_input_callback function will be called when the user has finished entering their name. The function can be added before basic_scenes_greeting_input_scene_on_enter and should look like this:
Update the basic_scenes_greeting_input_scene_on_event function to handle the custom event we created in the previous step. The function should look like this:
Run the following command from the root of the firmware folder to compile and run the application. Make sure you are not currently running the Flipper UI,
qFlipper or lab.flipper.net. In some environments you do not need the "./" at the beginning of the command.
The application should launch the main menu, with options for Lotto Numbers and Greeting. Select the 'Greeting' menu item and click the OK button on the Flipper Zero. The application should prompt for your name: