Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Modules/lvgl-module/generate-icons.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,18 @@ def generate_icon_names(codepoint_map: dict, codepoint_names: list, variable_nam
"camera",
"lightstrip",
"phone_android", # Display settings: orientation
# Files app
"draft",
"description",
"link",
"sd_card",
"content_copy",
"content_cut",
"content_paste",
"edit",
"play_arrow",
"eject",
"create_new_folder",
]

# Get more from https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Rounded
Expand Down
2 changes: 1 addition & 1 deletion Modules/lvgl-module/include/lvgl/icons/names.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ extern "C" {
#endif

/** Changes whenever the icon TTF subset, its codepoints file or the icon name lists change */
#define LVGL_ICON_FONT_VERSION 0xC28E1A92u
#define LVGL_ICON_FONT_VERSION 0xB2450B17u

// Icon names per icon font, resolved through the .codepoints file next to the TTF
extern const char* const lvgl_icon_shared_names[];
Expand Down
11 changes: 11 additions & 0 deletions Modules/lvgl-module/include/lvgl/icons/shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,14 @@
#define LVGL_ICON_SHARED_CAMERA "\xEE\x8E\xAF"
#define LVGL_ICON_SHARED_LIGHTSTRIP "\xF3\xBF\xBD\xB5"
#define LVGL_ICON_SHARED_PHONE_ANDROID "\xEF\x8B\x9B"
#define LVGL_ICON_SHARED_DRAFT "\xEE\x99\xAD"
#define LVGL_ICON_SHARED_DESCRIPTION "\xEE\xA1\xB3"
#define LVGL_ICON_SHARED_LINK "\xEE\x89\x90"
#define LVGL_ICON_SHARED_SD_CARD "\xEE\x98\xA3"
#define LVGL_ICON_SHARED_CONTENT_COPY "\xEE\x85\x8D"
#define LVGL_ICON_SHARED_CONTENT_CUT "\xEE\x85\x8E"
#define LVGL_ICON_SHARED_CONTENT_PASTE "\xEE\x85\x8F"
#define LVGL_ICON_SHARED_EDIT "\xEF\x82\x97"
#define LVGL_ICON_SHARED_PLAY_ARROW "\xEE\x80\xB7"
#define LVGL_ICON_SHARED_EJECT "\xEE\xA3\xBB"
#define LVGL_ICON_SHARED_CREATE_NEW_FOLDER "\xEE\x8B\x8C"
11 changes: 11 additions & 0 deletions Modules/lvgl-module/source/icon_names.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ const char* const lvgl_icon_shared_names[] = {
"camera",
"lightstrip",
"phone_android",
"draft",
"description",
"link",
"sd_card",
"content_copy",
"content_cut",
"content_paste",
"edit",
"play_arrow",
"eject",
"create_new_folder",
};

const size_t lvgl_icon_shared_name_count = sizeof(lvgl_icon_shared_names) / sizeof(lvgl_icon_shared_names[0]);
Expand Down
7 changes: 7 additions & 0 deletions Modules/lvgl-module/source/themes/lv_theme_material.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ typedef struct {
lv_style_t text_button_pressed;
#endif
lv_style_t icon_button;
lv_style_t icon_button_selected;
lv_style_t icon_button_filled;
lv_style_t icon_button_filled_pressed;
lv_style_t icon_button_tonal;
Expand Down Expand Up @@ -874,6 +875,11 @@ static void style_init(my_theme_t * theme)
lv_style_set_radius(&theme->styles.icon_button, BUTTON_SHAPE);
lv_style_set_pad_all(&theme->styles.icon_button, BUTTON_PAD_VER);

style_init_reset(&theme->styles.icon_button_selected);
lv_style_set_bg_color(&theme->styles.icon_button_selected, LIST_ITEM_FOCUSED_COLOR);
lv_style_set_bg_opa(&theme->styles.icon_button_selected, LV_OPA_COVER);
lv_style_set_text_color(&theme->styles.icon_button_selected, LIST_ITEM_FOCUSED_TEXT_COLOR);

style_init_reset(&theme->styles.icon_button_filled);
lv_style_set_bg_color(&theme->styles.icon_button_filled, ICON_BUTTON_FILLED_COLOR);
lv_style_set_bg_opa(&theme->styles.icon_button_filled, LV_OPA_COVER);
Expand Down Expand Up @@ -1734,6 +1740,7 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
lv_obj_add_style(obj, &theme->styles.transition_exit, 0);
lv_obj_add_style(obj, &theme->styles.state_pressed, LV_STATE_PRESSED);
lv_obj_add_style(obj, &theme->styles.transition_enter, LV_STATE_PRESSED);
lv_obj_add_style(obj, &theme->styles.icon_button_selected, LV_STATE_CHECKED);
lv_obj_add_style(obj, &theme->styles.focus_ring_inset, LV_STATE_FOCUS_KEY);
lv_obj_add_style(obj, &theme->styles.edit_ring_inset, LV_STATE_EDITED);
lv_obj_add_style(obj, &theme->styles.disabled, LV_STATE_DISABLED);
Expand Down
1 change: 1 addition & 0 deletions Modules/lvgl-module/source/themes/lv_theme_material_mono.c
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,7 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
/* icon_button */
lv_obj_add_style(obj, &theme->styles.icon_button, 0);
lv_obj_add_style(obj, &theme->styles.inverted, LV_STATE_PRESSED);
lv_obj_add_style(obj, &theme->styles.inverted, LV_STATE_CHECKED);
lv_obj_add_style(obj, &theme->styles.focus_ring_inset, LV_STATE_FOCUS_KEY);
lv_obj_add_style(obj, &theme->styles.edit_ring_inset, LV_STATE_EDITED);
lv_obj_add_style(obj, &theme->styles.disabled, LV_STATE_DISABLED);
Expand Down
8 changes: 8 additions & 0 deletions Modules/lvgl-module/themes/material.lss
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,13 @@ icon_button {
padAll: @button-pad-ver;
}

// A selected tile, e.g. the file that the Files app shows actions for
icon_button_selected {
bgColor: @list-item-focused-color;
bgOpa: cover;
textColor: @list-item-focused-text-color;
}

icon_button_filled {
bgColor: @icon-button-filled-color;
bgOpa: cover;
Expand Down Expand Up @@ -1348,6 +1355,7 @@ apply(icon_button) {
transition_exit: default;
state_pressed: state.pressed;
transition_enter: state.pressed;
icon_button_selected: state.checked;
focus_ring_inset: state.focusKey;
edit_ring_inset: state.edited;
disabled: state.disabled;
Expand Down
1 change: 1 addition & 0 deletions Modules/lvgl-module/themes/material_mono.lss
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,7 @@ apply(toolbar) {
apply(icon_button) {
icon_button: default;
inverted: state.pressed;
inverted: state.checked;
focus_ring_inset: state.focusKey;
edit_ring_inset: state.edited;
disabled: state.disabled;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,43 +1,47 @@
#pragma once

#include <app/manifest.h>

#include <lvgl.h>

#include <cstdint>
#include <string>
#include <vector>

namespace tt::app {

struct AppGridItem {
/** Owned copy, so a tile never references the app ledger directly */
::AppManifest manifest;
/** Shared icon font glyph */
struct TileGridItem {
/** Identifies the item across rebuilds, e.g. to keep it selected */
std::string id;
std::string name;
/** Shared icon font glyph, or nullptr to resolve it with Callbacks::resolveIcon when the tile is shown */
const char* icon;
/** Rendered with an accent colour when not selected */
/** Marked with a badge */
bool highlighted;
};

/**
* Paged, non-scrolling grid of app tiles (icon above name) with "<" and ">" page buttons.
* Paged, non-scrolling grid of tiles (icon above name) with "<" and ">" page buttons.
* Must outlive the widgets it creates.
*/
class AppGrid final {
class TileGrid final {

public:

struct Callbacks {
/** Returns the items in display order. Called on every rebuild. */
std::vector<AppGridItem> (*collect)(void* userData);
void (*onClicked)(const ::AppManifest& manifest, void* userData);
std::vector<TileGridItem> (*collect)(void* userData);
void (*onClicked)(const TileGridItem& item, void* userData);
/** Optional */
void (*onLongPressed)(const ::AppManifest& manifest, void* userData);
void (*onLongPressed)(const TileGridItem& item, void* userData);
/** Optional */
void (*onKey)(const ::AppManifest& manifest, uint32_t key, void* userData);
void (*onKey)(const TileGridItem& item, uint32_t key, void* userData);
/** Optional: returns the icon of an item without one. Only called for the items on the shown page. */
const char* (*resolveIcon)(const TileGridItem& item, void* userData);
/** Optional: called after the user went to another page */
void (*onPageChanged)(void* userData);
void* userData;
};

explicit AppGrid(const Callbacks& callbacks) : callbacks(callbacks) {}
explicit TileGrid(const Callbacks& callbacks) : callbacks(callbacks) {}

enum class IconColor {
/** The theme's icon colour */
Expand All @@ -57,6 +61,11 @@ class AppGrid final {
/** Swiping left or right over the grid goes to the next or previous page. Call before creating the widgets. */
void setSwipeNavigation(bool enabled) { swipeNavigation = enabled; }

/**
* Creates the grid and populates it. Call setPageButtons() right after it to add page buttons.
* @param[in] parent the container for the grid, with a flex column layout
*/
void createWidgets(lv_obj_t* parent);

/**
* Creates the grid and populates it, with a bar below it: buttons on the left (see addBarButton()),
Expand All @@ -66,6 +75,12 @@ class AppGrid final {
*/
void createWidgetsWithBottomBar(lv_obj_t* parent);

/**
* Makes the buttons go to the previous and next page. They are hidden when there's only one page, and wrap around.
* Call right after createWidgets().
*/
void setPageButtons(lv_obj_t* previous, lv_obj_t* next);

/**
* Adds an icon button to the left side of the bottom bar. Call right after createWidgetsWithBottomBar().
* @param[in] icon a shared icon (see lvgl/icons/shared.h)
Expand All @@ -75,14 +90,17 @@ class AppGrid final {

/**
* Rebuilds the grid asynchronously, so it is safe to call from a tile's own event.
* @param[in] keepSelection when true, the selected app stays selected and its page is shown
* @param[in] keepSelection when true, the selected item stays selected and its page is shown
*/
void requestRepopulate(bool keepSelection);

/** @return the tile of the item on the shown page, or nullptr */
lv_obj_t* findTile(const std::string& id) const;

private:

Callbacks callbacks;
std::vector<AppGridItem> items;
std::vector<TileGridItem> items;
uint32_t page = 0;
uint32_t pageCount = 1;
IconColor iconColor = IconColor::Default;
Expand All @@ -99,6 +117,7 @@ class AppGrid final {
lv_obj_t* barSpacer = nullptr;

void createGrid(lv_obj_t* parent);
void finishCreate(lv_obj_t* parent);
void goToPreviousPage();
void goToNextPage();
void populate();
Expand Down
2 changes: 0 additions & 2 deletions Tactility/Private/Tactility/app/files/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ class State final {
});
}

bool getDirent(uint32_t index, dirent& dirent);

void setSelectedChildEntry(const std::string& newFile) {
selected_child_entry = newFile;
action = ActionNone;
Expand Down
51 changes: 30 additions & 21 deletions Tactility/Private/Tactility/app/files/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "./State.h"

#include <Tactility/app/TileGrid.h>

#include <app/stream.h>
#include <tactility/concurrent/task_event_group.h>

Expand All @@ -19,43 +21,51 @@ class View final {
AppStream inputDialogStream {};
uint8_t inputDialogBuffer[256] {};

size_t current_start_index = 0;
size_t last_loaded_index = 0;
const size_t MAX_BATCH = 50;
TileGrid grid;

lv_obj_t* dir_entry_list = nullptr;
lv_obj_t* action_list = nullptr;
lv_obj_t* overlay = nullptr;
lv_obj_t* navigate_up_button = nullptr;
lv_obj_t* new_file_button = nullptr;
lv_obj_t* new_folder_button = nullptr;
lv_obj_t* paste_button = nullptr;
lv_obj_t* overflow_button = nullptr;

std::string installAppPath = { 0 };
uint32_t installDialogId = 0;

void showActions();
void showActionsForDirectory();
void showActionsForFile();
void showActionsForMountPoint();
static std::vector<TileGridItem> collectItems(void* userData);
static const char* resolveIcon(const TileGridItem& item, void* userData);
static void onTileClicked(const TileGridItem& item, void* userData);
static void onTileLongPressed(const TileGridItem& item, void* userData);
static void onTileKey(const TileGridItem& item, uint32_t key, void* userData);
static void onPageChanged(void* userData);

lv_obj_t* addOverlayButton(const char* icon, lv_event_cb_t callback);
void showOverlay(lv_obj_t* anchorTile);
void hideOverlay();
void showActionsForDirectory(lv_obj_t* tile);
void showActionsForFile(lv_obj_t* tile);
void showActionsForMountPoint(lv_obj_t* tile);
void addCommonFileActions();

void viewFile(const std::string&path, const std::string&filename);
void runFile(const std::string& file_path);
void createDirEntryWidget(lv_obj_t* parent, dirent& dir_entry);
void onNavigate();

public:

View(const std::shared_ptr<State>& state, TaskEventGroup* eventGroup) : state(state), eventGroup(eventGroup) {}
View(const std::shared_ptr<State>& state, TaskEventGroup* eventGroup);

void init(uint32_t appInstanceId, lv_obj_t* parent);
void update(size_t start_index = 0);
/**
* Shows the current entries of the state.
* @param[in] firstPage true after navigating to another directory, false to stay on the current page
*/
void update(bool firstPage);

void onBackPressed();
void onNavigateUpPressed();
void onDirEntryPressed(uint32_t index);
void onDirEntryLongPressed(int32_t index);
void onDirEntryKeyPressed(int32_t index, uint32_t key);
void onOverflowPressed();
void onDirEntryPressed(const std::string& name);
void onDirEntryLongPressed(const std::string& name);
void onDirEntryKeyPressed(const std::string& name, uint32_t key);
void onRenamePressed();
void onDeletePressed();
void onNewFilePressed();
Expand All @@ -65,13 +75,12 @@ class View final {
void onPastePressed();
void onEjectPressed();
void onRunPressed();
void onDirEntryListScrollBegin();
void onOverlayKey(uint32_t key);
void onResult(uint32_t launchId, int32_t result);
void deinit();

private:

bool resolveDirentFromListIndex(int32_t list_index, dirent& out_entry);
bool findDirent(const std::string& name, dirent& out_entry);
void doPaste(const std::string& src, bool is_cut, const std::string& dst);
};

Expand Down
10 changes: 5 additions & 5 deletions Tactility/Private/Tactility/app/launcher/LauncherMode.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once

#include <Tactility/app/AppGrid.h>
#include <Tactility/app/TileGrid.h>

#include <cstdint>
#include <vector>
Expand All @@ -12,13 +12,13 @@ struct LauncherMode {
/** Represents this mode on the button that switches to it */
const char* buttonIcon;
/** The tile icon colour for themes that aren't monochrome */
AppGrid::IconColor iconColor;
TileGrid::IconColor iconColor;
/** Returns the items in display order */
std::vector<AppGridItem> (*collect)();
std::vector<TileGridItem> (*collect)();
/** Optional */
void (*onLongPressed)(AppGrid& grid, const ::AppManifest& manifest);
void (*onLongPressed)(TileGrid& grid, const TileGridItem& item);
/** Optional */
void (*onKey)(AppGrid& grid, const ::AppManifest& manifest, uint32_t key);
void (*onKey)(TileGrid& grid, const TileGridItem& item, uint32_t key);
};

extern const LauncherMode APPS_MODE;
Expand Down
Loading
Loading