Fixes and new apps (#30)
- M5 Unit Modules library + M5 Unit Test app - Minor fixes for TodoList, TwoEleven, Snake, Brainfuck and Breakout - Fixed SerialConsole to use the uart controller as it was broken in one of the many updates - Fixed keyboard input in TwoEleven, Breakout, Magic8Ball and Snake - Bluetooth Media Keys app, supports pressing physical keys to trigger the corresponding buttonmatrix button - Epub Reader app
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <TactilityCpp/LvglLock.h>
|
||||
|
||||
#include <tactility/lvgl_module.h>
|
||||
#include <tactility/lvgl_fonts.h>
|
||||
|
||||
constexpr auto* TAG = "Snake";
|
||||
|
||||
@@ -42,14 +43,19 @@ static constexpr int32_t SELECTION_HELL = 4;
|
||||
// Hell uses same size as Hard but with wall collision enabled
|
||||
static const uint16_t difficultySizes[DIFFICULTY_COUNT] = { SNAKE_CELL_LARGE, SNAKE_CELL_MEDIUM, SNAKE_CELL_SMALL, SNAKE_CELL_SMALL };
|
||||
|
||||
static int getToolbarHeight(UiDensity density) {
|
||||
if (density == LVGL_UI_DENSITY_COMPACT) {
|
||||
return 22;
|
||||
static uint32_t getToolbarHeight(UiDensity uiDensity) {
|
||||
if (uiDensity == LVGL_UI_DENSITY_COMPACT) {
|
||||
return lvgl_get_text_font_height(FONT_SIZE_DEFAULT) * 1.4f;
|
||||
} else {
|
||||
return 40;
|
||||
return lvgl_get_text_font_height(FONT_SIZE_LARGE) * 2.2f;
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t getActionIconPadding(UiDensity uiDensity) {
|
||||
auto toolbar_height = getToolbarHeight(uiDensity);
|
||||
return (uiDensity != LVGL_UI_DENSITY_COMPACT) ? (uint32_t)(toolbar_height * 0.2f) : 8;
|
||||
}
|
||||
|
||||
static void loadHighScores() {
|
||||
PreferencesHandle prefs = tt_preferences_alloc(PREF_NAMESPACE);
|
||||
if (prefs) {
|
||||
@@ -194,23 +200,21 @@ void Snake::createGame(lv_obj_t* parent, uint16_t cell_size, bool wallCollision,
|
||||
lv_obj_set_style_text_color(scoreLabel, lv_palette_main(LV_PALETTE_GREEN), LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(gameObject, snakeEventCb, LV_EVENT_VALUE_CHANGED, this);
|
||||
|
||||
auto ui_density = lvgl_get_ui_density();
|
||||
auto toolbar_height = getToolbarHeight(ui_density);
|
||||
auto icon_padding = getActionIconPadding(ui_density);
|
||||
|
||||
// Create new game button wrapper
|
||||
newGameWrapper = lv_obj_create(tb);
|
||||
lv_obj_set_width(newGameWrapper, LV_SIZE_CONTENT);
|
||||
lv_obj_set_flex_flow(newGameWrapper, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_style_pad_all(newGameWrapper, 2, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_pad_all(newGameWrapper, icon_padding / 2, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_border_width(newGameWrapper, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_set_style_bg_opa(newGameWrapper, 0, LV_STATE_DEFAULT);
|
||||
|
||||
// Create new game button
|
||||
auto ui_density = lvgl_get_ui_density();
|
||||
auto toolbar_height = getToolbarHeight(ui_density);
|
||||
lv_obj_t* newGameBtn = lv_btn_create(newGameWrapper);
|
||||
if (ui_density == LVGL_UI_DENSITY_COMPACT) {
|
||||
lv_obj_set_size(newGameBtn, toolbar_height - 8, toolbar_height - 8);
|
||||
} else {
|
||||
lv_obj_set_size(newGameBtn, toolbar_height - 6, toolbar_height - 6);
|
||||
}
|
||||
lv_obj_set_size(newGameBtn, toolbar_height - icon_padding, toolbar_height - icon_padding);
|
||||
lv_obj_set_style_pad_all(newGameBtn, 0, LV_STATE_DEFAULT);
|
||||
lv_obj_align(newGameBtn, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_add_event_cb(newGameBtn, newGameBtnEvent, LV_EVENT_CLICKED, this);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
static void game_play_event(lv_event_t* e);
|
||||
static void snake_timer_cb(lv_timer_t* timer);
|
||||
static void delete_event(lv_event_t* e);
|
||||
static void focus_event(lv_event_t* e);
|
||||
static void reenter_key_mode_event(lv_event_t* e);
|
||||
static void snake_draw(snake_game_t* game);
|
||||
static void snake_create_segment_objects(snake_game_t* game);
|
||||
static void snake_delete_segment_objects(snake_game_t* game);
|
||||
@@ -35,12 +35,11 @@ static void delete_event(lv_event_t* e) {
|
||||
game->timer = NULL;
|
||||
}
|
||||
|
||||
// Restore edit mode to false before cleanup
|
||||
// Restore edit mode and remove from group before cleanup
|
||||
if (tt_lvgl_hardware_keyboard_is_available()) {
|
||||
lv_group_t* group = lv_group_get_default();
|
||||
if (group) {
|
||||
lv_group_set_editing(group, false);
|
||||
}
|
||||
if (group) lv_group_set_editing(group, false);
|
||||
lv_group_remove_obj(game->container);
|
||||
}
|
||||
|
||||
// Delete LVGL objects for snake segments
|
||||
@@ -59,21 +58,17 @@ static void delete_event(lv_event_t* e) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle focus/defocus to manage edit mode for keyboard input
|
||||
* @brief Re-enter key mode when the game area is clicked after Q/Esc exit
|
||||
*/
|
||||
static void focus_event(lv_event_t* e) {
|
||||
lv_event_code_t code = lv_event_get_code(e);
|
||||
static void reenter_key_mode_event(lv_event_t* e) {
|
||||
lv_obj_t* container = lv_event_get_current_target_obj(e);
|
||||
lv_group_t* group = lv_group_get_default();
|
||||
|
||||
if (!group) return;
|
||||
|
||||
if (code == LV_EVENT_FOCUSED) {
|
||||
// Enable edit mode so arrow keys control the game
|
||||
lv_group_set_editing(group, true);
|
||||
} else if (code == LV_EVENT_DEFOCUSED) {
|
||||
// Restore normal focus navigation
|
||||
lv_group_set_editing(group, false);
|
||||
if (lv_obj_get_group(container) == NULL) {
|
||||
lv_group_add_obj(group, container);
|
||||
}
|
||||
lv_group_focus_obj(container);
|
||||
lv_group_set_editing(group, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -278,6 +273,16 @@ static void game_play_event(lv_event_t* e) {
|
||||
case '/':
|
||||
snake_set_direction(game, SNAKE_DIR_RIGHT);
|
||||
break;
|
||||
case LV_KEY_ESC:
|
||||
case 'q':
|
||||
case 'Q': {
|
||||
// Exit key/edit mode - remove from group so navigation is restored
|
||||
// Re-entry: tap/click the game area to return to key mode
|
||||
lv_group_t* grp = lv_group_get_default();
|
||||
if (grp) lv_group_set_editing(grp, false);
|
||||
lv_group_remove_obj(lv_event_get_current_target_obj(e));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -396,11 +401,9 @@ lv_obj_t* snake_create(lv_obj_t* parent, uint16_t cell_size, bool wall_collision
|
||||
lv_group_t* group = lv_group_get_default();
|
||||
if (group) {
|
||||
lv_group_add_obj(group, game->container);
|
||||
// Register focus handlers to manage edit mode lifecycle
|
||||
lv_obj_add_event_cb(game->container, focus_event, LV_EVENT_FOCUSED, NULL);
|
||||
lv_obj_add_event_cb(game->container, focus_event, LV_EVENT_DEFOCUSED, NULL);
|
||||
// Focus the container (will trigger FOCUSED event and enable edit mode)
|
||||
lv_obj_add_event_cb(game->container, reenter_key_mode_event, LV_EVENT_CLICKED, NULL);
|
||||
lv_group_focus_obj(game->container);
|
||||
lv_group_set_editing(group, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ sdk=0.7.0-dev
|
||||
platforms=esp32,esp32s3,esp32c6,esp32p4
|
||||
[app]
|
||||
id=one.tactility.snake
|
||||
versionName=0.4.0
|
||||
versionCode=4
|
||||
versionName=0.5.0
|
||||
versionCode=5
|
||||
name=Snake
|
||||
description=Classic Snake game
|
||||
|
||||
Reference in New Issue
Block a user