Skip to content

Commit

Permalink
Merge pull request #7 from leedave/feature/button_menu
Browse files Browse the repository at this point in the history
Added Scene with Button Menu
  • Loading branch information
leedave committed Jun 3, 2023
2 parents cb29a56 + 458519a commit b214565
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Use this code as a foundation for developing Flipper Zero Applications, change t
### Features
- Start Screen
- Menu
- Button Menu
- Different Scenes / Views
- Settings Page (On/Off for haptics, sound, led)
- Handling of Button Inputs
Expand Down
3 changes: 3 additions & 0 deletions boilerplate.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ Boilerplate* boilerplate_app_alloc() {
view_dispatcher_add_view(app->view_dispatcher, BoilerplateViewIdScene1, boilerplate_scene_1_get_view(app->boilerplate_scene_1));
app->boilerplate_scene_2 = boilerplate_scene_2_alloc();
view_dispatcher_add_view(app->view_dispatcher, BoilerplateViewIdScene2, boilerplate_scene_2_get_view(app->boilerplate_scene_2));
app->button_menu = button_menu_alloc();
view_dispatcher_add_view(app->view_dispatcher, BoilerplateViewIdScene3, button_menu_get_view(app->button_menu));

app->variable_item_list = variable_item_list_alloc();
view_dispatcher_add_view(app->view_dispatcher, BoilerplateViewIdSettings, variable_item_list_get_view(app->variable_item_list));

Expand Down
5 changes: 5 additions & 0 deletions boilerplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <gui/modules/submenu.h>
#include <gui/scene_manager.h>
#include <gui/modules/variable_item_list.h>
#include <gui/modules/button_menu.h>
#include "scenes/boilerplate_scene.h"
#include "views/boilerplate_startscreen.h"
#include "views/boilerplate_scene_1.h"
Expand All @@ -33,13 +34,17 @@ typedef struct {
uint32_t speaker;
uint32_t led;
uint32_t save_settings;
ButtonMenu* button_menu;
} Boilerplate;

typedef enum {
BoilerplateViewIdStartscreen,
BoilerplateViewIdMenu,
BoilerplateViewIdScene1,
BoilerplateViewIdScene2,
BoilerplateViewIdScene3,
BoilerplateViewIdScene4,
BoilerplateViewIdScene5,
BoilerplateViewIdSettings,
} BoilerplateViewId;

Expand Down
40 changes: 39 additions & 1 deletion helpers/boilerplate_custom_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,42 @@ typedef enum {
BoilerplateCustomEventScene2Right,
BoilerplateCustomEventScene2Ok,
BoilerplateCustomEventScene2Back,
} BoilerplateCustomEvent;
} BoilerplateCustomEvent;

enum BoilerplateCustomEventType {
// Reserve first 100 events for button types and indexes, starting from 0
BoilerplateCustomEventMenuVoid,
BoilerplateCustomEventMenuSelected,
};

#pragma pack(push, 1)
typedef union {
uint32_t packed_value;
struct {
uint16_t type;
int16_t value;
} content;
} BoilerplateCustomEventMenu;
#pragma pack(pop)

static inline uint32_t boilerplate_custom_menu_event_pack(uint16_t type, int16_t value) {
BoilerplateCustomEventMenu event = {.content = {.type = type, .value = value}};
return event.packed_value;
}
static inline void boilerplate_custom_menu_event_unpack(uint32_t packed_value, uint16_t* type, int16_t* value) {
BoilerplateCustomEventMenu event = {.packed_value = packed_value};
if(type) *type = event.content.type;
if(value) *value = event.content.value;
}

static inline uint16_t boilerplate_custom_menu_event_get_type(uint32_t packed_value) {
uint16_t type;
boilerplate_custom_menu_event_unpack(packed_value, &type, NULL);
return type;
}

static inline int16_t boilerplate_custom_menu_event_get_value(uint32_t packed_value) {
int16_t value;
boilerplate_custom_menu_event_unpack(packed_value, NULL, &value);
return value;
}
1 change: 1 addition & 0 deletions scenes/boilerplate_scene_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ ADD_SCENE(boilerplate, startscreen, Startscreen)
ADD_SCENE(boilerplate, menu, Menu)
ADD_SCENE(boilerplate, scene_1, Scene_1)
ADD_SCENE(boilerplate, scene_2, Scene_2)
ADD_SCENE(boilerplate, scene_3, Scene_3)
ADD_SCENE(boilerplate, settings, Settings)
12 changes: 10 additions & 2 deletions scenes/boilerplate_scene_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
enum SubmenuIndex {
SubmenuIndexScene1 = 10,
SubmenuIndexScene2,
SubmenuIndexScene3,
SubmenuIndexScene4,
SubmenuIndexScene5,
SubmenuIndexSettings,
};

Expand All @@ -14,8 +17,9 @@ void boilerplate_scene_menu_submenu_callback(void* context, uint32_t index) {
void boilerplate_scene_menu_on_enter(void* context) {
Boilerplate* app = context;

submenu_add_item(app->submenu, "Scene 1", SubmenuIndexScene1, boilerplate_scene_menu_submenu_callback, app);
submenu_add_item(app->submenu, "Scene 2", SubmenuIndexScene2, boilerplate_scene_menu_submenu_callback, app);
submenu_add_item(app->submenu, "Scene 1 (empty)", SubmenuIndexScene1, boilerplate_scene_menu_submenu_callback, app);
submenu_add_item(app->submenu, "Scene 2 (Inputs/Effects)", SubmenuIndexScene2, boilerplate_scene_menu_submenu_callback, app);
submenu_add_item(app->submenu, "Scene 3 (Buttonmenu)", SubmenuIndexScene3, boilerplate_scene_menu_submenu_callback, app);
submenu_add_item(app->submenu, "Settings", SubmenuIndexSettings, boilerplate_scene_menu_submenu_callback, app);

submenu_set_selected_item(app->submenu, scene_manager_get_scene_state(app->scene_manager, BoilerplateSceneMenu));
Expand All @@ -42,6 +46,10 @@ bool boilerplate_scene_menu_on_event(void* context, SceneManagerEvent event) {
app->scene_manager, BoilerplateSceneMenu, SubmenuIndexScene2);
scene_manager_next_scene(app->scene_manager, BoilerplateSceneScene_2);
return true;
} else if (event.event == SubmenuIndexScene3) {
scene_manager_set_scene_state(
app->scene_manager, BoilerplateSceneMenu, SubmenuIndexScene3);
scene_manager_next_scene(app->scene_manager, BoilerplateSceneScene_3);
} else if (event.event == SubmenuIndexSettings) {
scene_manager_set_scene_state(
app->scene_manager, BoilerplateSceneMenu, SubmenuIndexSettings);
Expand Down
142 changes: 142 additions & 0 deletions scenes/boilerplate_scene_scene_3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include "../boilerplate.h"
#include "../helpers/boilerplate_custom_event.h"
#include "../helpers/boilerplate_haptic.h"
#include "../helpers/boilerplate_led.h"
#include "../views/boilerplate_scene_2.h"

typedef enum {
ButtonIndexControl3 = -3,
ButtonIndexControl2 = -2,
ButtonIndexControl1 = -1,
ButtonIndexButton1 = 0,
ButtonIndexButton2 = 1,
ButtonIndexButton3 = 2,
} ButtonIndex;

static void boilerplate_scene_3_callback(void* context, int32_t index, InputType type) {
Boilerplate* app = context;

uint16_t custom_type;
if(type == InputTypePress) {
custom_type = BoilerplateCustomEventMenuSelected;
} else if(type == InputTypeRelease) {
custom_type = BoilerplateCustomEventMenuVoid;
} else if(type == InputTypeShort) {
//somehow ButtonMenuItemTypeCommon uses InputTypeShort
custom_type = BoilerplateCustomEventMenuSelected;
} else {
furi_crash("Unexpected Input Type");
}
view_dispatcher_send_custom_event(app->view_dispatcher, boilerplate_custom_menu_event_pack(custom_type, index));
}

void boilerplate_scene_scene_3_on_enter(void* context) {
furi_assert(context);
Boilerplate* app = context;
ButtonMenu* button_menu = app->button_menu;
SceneManager* scene_manager = app->scene_manager;

button_menu_add_item(
button_menu,
"Common",
ButtonIndexButton1,
boilerplate_scene_3_callback,
ButtonMenuItemTypeCommon,
context);
button_menu_add_item(
button_menu,
"Button",
ButtonIndexButton2,
boilerplate_scene_3_callback,
ButtonMenuItemTypeCommon,
context);
button_menu_add_item(
button_menu,
"Examples",
ButtonIndexButton1,
boilerplate_scene_3_callback,
ButtonMenuItemTypeCommon,
context);

button_menu_add_item(
button_menu,
"Control",
ButtonIndexControl1,
boilerplate_scene_3_callback,
ButtonMenuItemTypeControl,
context);

button_menu_add_item(
button_menu,
"Button",
ButtonIndexControl2,
boilerplate_scene_3_callback,
ButtonMenuItemTypeControl,
context);

button_menu_add_item(
button_menu,
"Examples",
ButtonIndexControl3,
boilerplate_scene_3_callback,
ButtonMenuItemTypeControl,
context);

button_menu_set_header(button_menu, "Button Menu");
const int16_t button_index =
(signed)scene_manager_get_scene_state(app->scene_manager, BoilerplateViewIdScene3);
button_menu_set_selected_item(button_menu, button_index);
scene_manager_set_scene_state(scene_manager, BoilerplateSceneScene_3, ButtonIndexButton1);

view_dispatcher_switch_to_view(app->view_dispatcher, BoilerplateViewIdScene3);
}

bool boilerplate_scene_scene_3_on_event(void* context, SceneManagerEvent event) {
Boilerplate* app = context;
bool consumed = false;

if(event.type == SceneManagerEventTypeCustom) {
const uint16_t custom_type = boilerplate_custom_menu_event_get_type(event.event);
const int16_t button_index = boilerplate_custom_menu_event_get_value(event.event);
if (custom_type == BoilerplateCustomEventMenuSelected) {
switch(button_index) {
case ButtonIndexButton1:
boilerplate_play_happy_bump(app);
boilerplate_led_set_rgb(app, 255, 0, 0);
break;
case ButtonIndexButton2:
boilerplate_play_happy_bump(app);
boilerplate_led_set_rgb(app, 0, 255, 0);
break;
case ButtonIndexButton3:
boilerplate_play_happy_bump(app);
boilerplate_led_set_rgb(app, 0, 0, 255);
break;
case ButtonIndexControl1:
boilerplate_play_bad_bump(app);
boilerplate_led_set_rgb(app, 255, 0, 255);
break;
case ButtonIndexControl2:
boilerplate_play_bad_bump(app);
boilerplate_led_set_rgb(app, 255, 255, 0);
break;
case ButtonIndexControl3:
boilerplate_play_bad_bump(app);
boilerplate_led_set_rgb(app, 0, 255, 255);
break;
}
consumed = true;
}
}

return consumed;
}

void boilerplate_scene_scene_3_on_exit(void* context) {
Boilerplate* app = context;
button_menu_reset(app->button_menu);
notification_message(app->notification, &sequence_reset_red);
notification_message(app->notification, &sequence_reset_green);
notification_message(app->notification, &sequence_reset_blue);
}

0 comments on commit b214565

Please sign in to comment.