New SD manager

TODO: file preview is still missing.
This commit is contained in:
Raphael Coeffic
2022-06-11 15:38:08 +02:00
committed by Raphael Coeffic
parent d9c1af2080
commit ad413242d7
7 changed files with 455 additions and 422 deletions
+1
View File
@@ -30,6 +30,7 @@ set(GUI_SRC
color_editor.cpp
color_list.cpp
preview_window.cpp
file_browser.cpp
file_preview.cpp
file_carosell.cpp
listbox.cpp
+172
View File
@@ -0,0 +1,172 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "file_browser.h"
#include "libopenui_file.h"
#include "font.h"
#include <list>
#include <string>
#define CELL_CTRL_DIR LV_TABLE_CELL_CTRL_CUSTOM_1
#define CELL_CTRL_FILE LV_TABLE_CELL_CTRL_CUSTOM_2
static const char* getFullPath(const char* filename)
{
static char full_path[FF_MAX_LFN + 1];
f_getcwd((TCHAR*)full_path, FF_MAX_LFN);
strcat(full_path, "/");
strcat(full_path, filename);
return full_path;
}
static const char* getCurrentPath()
{
static char path[FF_MAX_LFN + 1];
f_getcwd((TCHAR*)path, FF_MAX_LFN);
return path;
}
static int scan_files(std::list<std::string>& files,
std::list<std::string>& directories)
{
FILINFO fno;
DIR dir;
FRESULT res = f_opendir(&dir, "."); // Open the directory
if (res != FR_OK) return -1;
// read all entries
bool firstTime = true;
for (;;) {
res = sdReadDir(&dir, &fno, firstTime);
if (res != FR_OK || fno.fname[0] == 0)
break; // Break on error or end of dir
// if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH)
// continue;
if (fno.fname[0] == '.' && fno.fname[1] != '.')
continue; // Ignore hidden files under UNIX, but not ..
if (fno.fattrib & AM_DIR) {
directories.push_back((char*)fno.fname);
} else {
files.push_back((char*)fno.fname);
}
}
directories.sort(compare_nocase);
files.sort(compare_nocase);
return 0;
}
FileBrowser::FileBrowser(Window* parent, const rect_t& rect, const char* dir) :
TableField(parent, rect)
{
setColumnCount(1);
setColumnWidth(0, rect.w);
f_chdir(dir);
}
void FileBrowser::setFileAction(FileAction fct) { fileAction = std::move(fct); }
void FileBrowser::refresh()
{
std::list<std::string> files;
std::list<std::string> directories;
if (scan_files(files, directories) < 0) return;
setRowCount(files.size() + directories.size());
uint16_t row = 0;
for (const auto& name: directories) {
// LV_SYMBOL_DIRECTORY
lv_table_set_cell_value(lvobj, row, 0, name.c_str());
lv_table_add_cell_ctrl(lvobj, row, 0, CELL_CTRL_DIR);
row++;
}
for (const auto& name: files) {
// LV_SYMBOL_FILE
lv_table_set_cell_value(lvobj, row, 0, name.c_str());
lv_table_clear_cell_ctrl(lvobj, row, 0, CELL_CTRL_DIR);
row++;
}
select(0, 0);
}
void FileBrowser::onPress(uint16_t row, uint16_t col)
{
bool is_dir = lv_table_has_cell_ctrl(lvobj, row, col, CELL_CTRL_DIR);
onPress(lv_table_get_cell_value(lvobj, row, col), is_dir);
}
void FileBrowser::onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
{
lv_coord_t cell_left = lv_obj_get_style_pad_left(lvobj, LV_PART_ITEMS);
dsc->label_dsc->ofs_x = getFontHeight(FONT(STD)) + cell_left;
}
void FileBrowser::onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc)
{
const char* sym = nullptr;
if (lv_table_has_cell_ctrl(lvobj, row, 0, CELL_CTRL_DIR)) {
// dir
const char* dir = lv_table_get_cell_value(lvobj, row, 0);
if (dir[0] == '.')
sym = LV_SYMBOL_LEFT;
else
sym = LV_SYMBOL_DIRECTORY;
} else {
// file
sym = LV_SYMBOL_FILE;
}
lv_area_t coords;
lv_coord_t area_h = lv_area_get_height(dsc->draw_area);
lv_coord_t cell_left = lv_obj_get_style_pad_left(lvobj, LV_PART_ITEMS);
lv_coord_t font_h = getFontHeight(FONT(STD));
coords.x1 = dsc->draw_area->x1 + cell_left;
coords.x2 = coords.x1 + dsc->label_dsc->ofs_x - cell_left;
coords.y1 = dsc->draw_area->y1 + (area_h - font_h) / 2;
coords.y2 = coords.y1 + font_h - 1;
dsc->label_dsc->ofs_x = 0;
lv_draw_label(dsc->draw_ctx, dsc->label_dsc, &coords, sym, nullptr);
}
void FileBrowser::onPress(const char* name, bool is_dir)
{
const char* path = getCurrentPath();
const char* fullpath = getFullPath(name);
if (is_dir) {
f_chdir(fullpath);
refresh();
} else if (fileAction){
fileAction(path, name, fullpath);
}
}
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#pragma once
#include "table.h"
class FileBrowser : public TableField
{
public:
// path, name, fullpath
typedef std::function<void(const char*, const char*, const char*)> FileAction;
FileBrowser(Window* parent, const rect_t& rect, const char* dir);
void setFileAction(FileAction fct);
void refresh();
protected:
void onPress(const char* name, bool is_dir);
// TableField methods
void onPress(uint16_t row, uint16_t col) override;
void onDrawBegin(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
void onDrawEnd(uint16_t row, uint16_t col, lv_obj_draw_part_dsc_t* dsc) override;
private:
FileAction fileAction;
};
+225 -415
View File
@@ -30,8 +30,12 @@
#include "sdcard.h"
#include "view_text.h"
#include "file_preview.h"
#include "file_browser.h"
constexpr int WARN_FILE_LENGTH = 96000;
constexpr int WARN_FILE_LENGTH = 16;
#define CELL_CTRL_DIR LV_TABLE_CELL_CTRL_CUSTOM_1
#define CELL_CTRL_FILE LV_TABLE_CELL_CTRL_CUSTOM_2
class FileNameEditWindow : public Page
{
@@ -98,41 +102,12 @@ class FileNameEditWindow : public Page
RadioSdManagerPage::RadioSdManagerPage() :
PageTab(SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD, ICON_RADIO_SD_MANAGER)
{
setOnSetVisibleHandler([]() {
TRACE("f_chdir(ROOT_PATH)");
f_chdir(ROOT_PATH);
});
// setOnSetVisibleHandler([]() {
// TRACE("f_chdir(ROOT_PATH)");
// f_chdir(ROOT_PATH);
// });
}
void RadioSdManagerPage::rebuild(FormWindow * window)
{
auto scroll_y = lv_obj_get_scroll_y(window->getLvObj());
window->clear();
build(window);
lv_obj_scroll_to_y(window->getLvObj(), scroll_y, LV_ANIM_OFF);
}
// TODO elsewhere
extern bool compare_nocase(const std::string &first, const std::string &second);
char * getFullPath(const std::string &filename)
{
static char full_path[FF_MAX_LFN + 1]; // TODO optimize that!
f_getcwd((TCHAR*)full_path, FF_MAX_LFN);
strcat(full_path, "/");
strcat(full_path, filename.c_str());
return full_path;
}
char * getCurrentPath()
{
static char path[FF_MAX_LFN + 1]; // TODO optimize that!
f_getcwd((TCHAR*)path, FF_MAX_LFN);
return path;
}
template <class T>
class FlashDialog: public FullScreenDialog
{
@@ -174,411 +149,246 @@ class FlashDialog: public FullScreenDialog
Progress progress;
};
class SDmanagerButton : public TextButton
{
public:
SDmanagerButton(FormGroup* parent, const rect_t& rect, std::string text,
std::function<uint8_t(void)> pressHandler = nullptr,
WindowFlags windowFlags = BUTTON_BACKGROUND | OPAQUE,
LcdFlags textFlags = 0 ) : TextButton(parent, rect, text, pressHandler, windowFlags, textFlags)
{
};
#if defined(HARDWARE_TOUCH)
bool onTouchStart(coord_t x, coord_t y) override
{
if (enabled) {
if (!(windowFlags & NO_FOCUS)) {
setFocus(SET_FOCUS_DEFAULT);
}
}
return true;
}
#endif
};
void RadioSdManagerPage::build(FormWindow * window)
{
FormGridLayout grid;
grid.spacer(PAGE_PADDING);
FILINFO fno;
DIR dir;
std::list<std::string> files;
std::list<std::string> directories;
std::string currentPath(getCurrentPath());
auto preview = new FilePreview(window, {LCD_W / 2 + 6, 0, LCD_W / 2 - 16, window->height()});
FRESULT res = f_opendir(&dir, "."); // Open the directory
if (res == FR_OK) {
// read all entries
bool firstTime = true;
for (;;) {
res = sdReadDir(&dir, &fno, firstTime);
if (res != FR_OK || fno.fname[0] == 0)
break; // Break on error or end of dir
if (strlen((const char*)fno.fname) > SD_SCREEN_FILE_LENGTH)
continue;
if (fno.fname[0] == '.' && fno.fname[1] != '.')
continue; // Ignore hidden files under UNIX, but not ..
if (fno.fattrib & AM_DIR) {
directories.push_back((char*)fno.fname);
} else {
files.push_back((char*)fno.fname);
}
}
// sort directories and files
directories.sort(compare_nocase);
files.sort(compare_nocase);
for (auto name: directories) {
new SDmanagerButton(window, grid.getLabelSlot(), name, [=]() -> uint8_t {
std::string fullpath = currentPath + "/" + name;
f_chdir((TCHAR*)fullpath.c_str());
window->clear();
build(window);
return 0;
});
grid.nextLine();
}
for (auto name: files) {
auto button = new SDmanagerButton(window, grid.getLabelSlot(), name, [=]() -> uint8_t {
auto menu = new Menu(window);
f_chdir(currentPath.c_str());
const char *ext = getFileExtension(name.c_str());
if (ext) {
if (!strcasecmp(ext, SOUNDS_EXT)) {
menu->addLine(STR_PLAY_FILE, [=]() {
audioQueue.stopAll();
audioQueue.playFile(getFullPath(name), 0, ID_PLAY_FROM_SD_MANAGER);
});
}
#if defined(MULTIMODULE) && !defined(DISABLE_MULTI_UPDATE)
if (!READ_ONLY() && !strcasecmp(ext, MULTI_FIRMWARE_EXT)) {
MultiFirmwareInformation information;
if (information.readMultiFirmwareInformation(name.c_str()) == nullptr) {
#if defined(INTERNAL_MODULE_MULTI)
menu->addLine(STR_FLASH_INTERNAL_MULTI, [=]() {
MultiFirmwareUpdate(name, INTERNAL_MODULE,
MULTI_TYPE_MULTIMODULE);
});
rect_t r = window->getRect();
#if LCD_W > LCD_H
r.w = r.w * 0.6;
#endif
menu->addLine(STR_FLASH_EXTERNAL_MULTI, [=]() {
MultiFirmwareUpdate(name, EXTERNAL_MODULE,
MULTI_TYPE_MULTIMODULE);
});
}
}
#endif
else if (!READ_ONLY() && !strcasecmp(ext, ELRS_FIRMWARE_EXT)) {
menu->addLine(STR_FLASH_EXTERNAL_ELRS, [=]() {
MultiFirmwareUpdate(name, EXTERNAL_MODULE, MULTI_TYPE_ELRS);
});
}
else if (isExtensionMatching(ext, BITMAPS_EXT)) {
menu->addLine(STR_ASSIGN_BITMAP, [=]() {
memcpy(g_model.header.bitmap, name.c_str(),
sizeof(g_model.header.bitmap));
storageDirty(EE_MODEL);
});
}
else if (!strcasecmp(ext, TEXT_EXT) || !strcasecmp(ext, LOGS_EXT)) {
menu->addLine(STR_VIEW_TEXT, [=]() {
static char lfn[FF_MAX_LFN + 1]; // TODO optimize that!
f_getcwd((TCHAR *)lfn, FF_MAX_LFN);
FIL file;
std::string fileName =
std::string(lfn) + "/" + std::string(name);
if (FR_OK == f_open(&file, (TCHAR *)fileName.c_str(),
FA_OPEN_EXISTING | FA_READ)) {
const int fileLenght = file.obj.objsize;
f_close(&file);
browser = new FileBrowser(window, r, ROOT_PATH);
browser->setFileAction([=](const char* path, const char* name, const char* fullpath) {
fileAction(path, name, fullpath);
});
browser->refresh();
if (fileLenght > WARN_FILE_LENGTH) {
char buf[64];
sprintf(buf, " %s %dkB. %s", STR_FILE_SIZE,
fileLenght / 1024, STR_FILE_OPEN);
new ConfirmDialog(window, STR_WARNING, buf, [=] {
auto textView = new ViewTextWindow(lfn, name);
textView->setCloseHandler([=]() { rebuild(window); });
});
} else {
auto textView = new ViewTextWindow(lfn, name);
textView->setCloseHandler([=]() { rebuild(window); });
}
}
});
}
if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) {
if (isBootloader(name.c_str())) {
menu->addLine(STR_FLASH_BOOTLOADER, [=]() {
BootloaderUpdate(name);
});
}
} else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) {
if (HAS_SPORT_UPDATE_CONNECTOR()) {
menu->addLine(STR_FLASH_EXTERNAL_DEVICE, [=]() {
FrSkyFirmwareUpdate(name, SPORT_MODULE);
});
}
menu->addLine(STR_FLASH_INTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(name, INTERNAL_MODULE);
});
menu->addLine(STR_FLASH_EXTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(name, EXTERNAL_MODULE);
});
} else if (!READ_ONLY() && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) {
FrSkyFirmwareInformation information;
if (readFrSkyFirmwareInformation(getFullPath(name),
information) == nullptr) {
#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)
menu->addLine(STR_FLASH_INTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(name, INTERNAL_MODULE);
});
#endif
if (information.productFamily ==
FIRMWARE_FAMILY_EXTERNAL_MODULE) {
menu->addLine(STR_FLASH_EXTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(name, EXTERNAL_MODULE);
});
}
if (information.productFamily == FIRMWARE_FAMILY_RECEIVER ||
information.productFamily == FIRMWARE_FAMILY_SENSOR) {
if (HAS_SPORT_UPDATE_CONNECTOR()) {
menu->addLine(STR_FLASH_EXTERNAL_DEVICE, [=]() {
FrSkyFirmwareUpdate(name, SPORT_MODULE);
});
} else {
menu->addLine(STR_FLASH_EXTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(name, EXTERNAL_MODULE);
});
}
}
// TODO: Integrate the remaining options
#if 0
#if defined(PXX2)
if (information.productFamily == FIRMWARE_FAMILY_RECEIVER) {
if (isReceiverOTAEnabledFromModule(INTERNAL_MODULE,
information.productId))
menu->addLine(
STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA, [=]() {
FrSkyFirmwareUpdate(name, INTERNAL_MODULE_OTA);
});
if (isReceiverOTAEnabledFromModule(EXTERNAL_MODULE,
information.productId))
menu->addLine(
STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA, [=]() {
FrSkyFirmwareUpdate(name, EXTERNAL_MODULE_OTA);
});
}
if (information.productFamily ==
FIRMWARE_FAMILY_FLIGHT_CONTROLLER) {
menu->addLine(
STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA,
[=]() {
FrSkyFirmwareUpdate(
name,
STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA);
});
menu->addLine(
STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA,
[=]() {
FrSkyFirmwareUpdate(
name,
STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA);
});
}
#endif
#if defined(BLUETOOTH)
if (information.productFamily ==
FIRMWARE_FAMILY_BLUETOOTH_CHIP) {
menu->addLine(STR_FLASH_BLUETOOTH_MODULE, [=]() {
FrSkyFirmwareUpdate(name, STR_FLASH_BLUETOOTH_MODULE);
});
}
#endif
#if defined(HARDWARE_POWER_MANAGEMENT_UNIT)
if (information.productFamily ==
FIRMWARE_FAMILY_POWER_MANAGEMENT_UNIT) {
menu->addLine(STR_FLASH_POWER_MANAGEMENT_UNIT, [=]() {
FrSkyFirmwareUpdate(name, STR_FLASH_POWER_MANAGEMENT_UNIT);
});
}
#endif
#endif
}
}
#if defined(LUA)
else if (isExtensionMatching(ext, SCRIPTS_EXT)) {
std::string fullpath = currentPath + "/" + name;
menu->addLine(STR_EXECUTE_FILE, [=]() {
luaExec(fullpath.c_str());
StandaloneLuaWindow::instance()->attach(window);
});
}
#endif
}
if (!READ_ONLY()) {
menu->addLine(STR_COPY_FILE, [=]() {
clipboard.type = CLIPBOARD_TYPE_SD_FILE;
f_getcwd(clipboard.data.sd.directory, CLIPBOARD_PATH_LEN);
strncpy(clipboard.data.sd.filename, name.c_str(),
CLIPBOARD_PATH_LEN - 1);
});
if (clipboard.type == CLIPBOARD_TYPE_SD_FILE) {
menu->addLine(STR_PASTE, [=]() {
static char lfn[FF_MAX_LFN + 1]; // TODO optimize that!
f_getcwd((TCHAR *)lfn, FF_MAX_LFN);
// prevent copying to the same directory with the same name
char *destNamePtr = clipboard.data.sd.filename;
if (!strcmp(clipboard.data.sd.directory, lfn)) {
char destFileName[2 * CLIPBOARD_PATH_LEN + 1];
destNamePtr = strAppend(destFileName, FILE_COPY_PREFIX,
CLIPBOARD_PATH_LEN);
destNamePtr = strAppend(destNamePtr, clipboard.data.sd.filename,
CLIPBOARD_PATH_LEN);
destNamePtr = destFileName;
}
sdCopyFile(clipboard.data.sd.filename,
clipboard.data.sd.directory, destNamePtr, lfn);
clipboard.type = CLIPBOARD_TYPE_NONE;
// button->setFocusHandler([=](bool active) {
// if (active) {
// preview->setFile(getFullPath(name));
// }
// });
// grid.nextLine();
// }
// }
rebuild(window);
});
}
menu->addLine(STR_RENAME_FILE, [=]() {
auto few = new FileNameEditWindow(name);
few->setCloseHandler([=]() {
rebuild(window);
});
});
menu->addLine(STR_DELETE_FILE, [=]() {
f_unlink((const TCHAR*)getFullPath(name));
window->clear();
build(window);
});
}
return 0;
}, BUTTON_BACKGROUND, COLOR_THEME_PRIMARY1);
button->setFocusHandler([=](bool active) {
if (active) {
preview->setFile(getFullPath(name));
}
});
grid.nextLine();
}
}
preview->setHeight(max(window->height(), grid.getWindowHeight()));
// preview->setHeight(max(window->height(), grid.getWindowHeight()));
}
void RadioSdManagerPage::BootloaderUpdate(const std::string name)
void RadioSdManagerPage::fileAction(const char* path, const char* name,
const char* fullpath)
{
auto window = Layer::back();
auto menu = new Menu(window);
const char* ext = getFileExtension(name);
if (ext) {
if (!strcasecmp(ext, SOUNDS_EXT)) {
menu->addLine(STR_PLAY_FILE, [=]() {
audioQueue.stopAll();
audioQueue.playFile(fullpath, 0, ID_PLAY_FROM_SD_MANAGER);
});
}
#if defined(MULTIMODULE) && !defined(DISABLE_MULTI_UPDATE)
if (!READ_ONLY() && !strcasecmp(ext, MULTI_FIRMWARE_EXT)) {
MultiFirmwareInformation information;
if (information.readMultiFirmwareInformation(fullpath) == nullptr) {
#if defined(INTERNAL_MODULE_MULTI)
menu->addLine(STR_FLASH_INTERNAL_MULTI, [=]() {
MultiFirmwareUpdate(fullpath, INTERNAL_MODULE,
MULTI_TYPE_MULTIMODULE);
});
#endif
menu->addLine(STR_FLASH_EXTERNAL_MULTI, [=]() {
MultiFirmwareUpdate(fullpath, EXTERNAL_MODULE,
MULTI_TYPE_MULTIMODULE);
});
}
}
#endif
else if (!READ_ONLY() && !strcasecmp(ext, ELRS_FIRMWARE_EXT)) {
menu->addLine(STR_FLASH_EXTERNAL_ELRS, [=]() {
MultiFirmwareUpdate(fullpath, EXTERNAL_MODULE, MULTI_TYPE_ELRS);
});
} else if (!strcasecmp(BITMAPS_PATH, path) &&
isExtensionMatching(ext, BITMAPS_EXT)) {
menu->addLine(STR_ASSIGN_BITMAP, [=]() {
memcpy(g_model.header.bitmap, name, sizeof(g_model.header.bitmap));
storageDirty(EE_MODEL);
});
} else if (!strcasecmp(ext, TEXT_EXT) || !strcasecmp(ext, LOGS_EXT)) {
menu->addLine(STR_VIEW_TEXT, [=]() {
FIL file;
if (FR_OK == f_open(&file, fullpath, FA_OPEN_EXISTING | FA_READ)) {
const int fileLength = file.obj.objsize;
f_close(&file);
if (fileLength > WARN_FILE_LENGTH) {
char buf[64];
sprintf(buf, " %s %dkB. %s", STR_FILE_SIZE, fileLength / 1024,
STR_FILE_OPEN);
new ConfirmDialog(window, STR_WARNING, buf,
[=] { new ViewTextWindow(path, name); });
} else {
new ViewTextWindow(path, name);
}
}
});
}
if (!READ_ONLY() && !strcasecmp(ext, FIRMWARE_EXT)) {
if (isBootloader(fullpath)) {
menu->addLine(STR_FLASH_BOOTLOADER,
[=]() { BootloaderUpdate(fullpath); });
}
} else if (!READ_ONLY() && !strcasecmp(ext, SPORT_FIRMWARE_EXT)) {
if (HAS_SPORT_UPDATE_CONNECTOR()) {
menu->addLine(STR_FLASH_EXTERNAL_DEVICE,
[=]() { FrSkyFirmwareUpdate(fullpath, SPORT_MODULE); });
}
menu->addLine(STR_FLASH_INTERNAL_MODULE,
[=]() { FrSkyFirmwareUpdate(fullpath, INTERNAL_MODULE); });
menu->addLine(STR_FLASH_EXTERNAL_MODULE,
[=]() { FrSkyFirmwareUpdate(fullpath, EXTERNAL_MODULE); });
} else if (!READ_ONLY() && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) {
FrSkyFirmwareInformation information;
if (readFrSkyFirmwareInformation(fullpath, information) ==
nullptr) {
#if defined(INTERNAL_MODULE_PXX1) || defined(INTERNAL_MODULE_PXX2)
menu->addLine(STR_FLASH_INTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(fullpath, INTERNAL_MODULE);
});
#endif
if (information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE) {
menu->addLine(STR_FLASH_EXTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(fullpath, EXTERNAL_MODULE);
});
}
if (information.productFamily == FIRMWARE_FAMILY_RECEIVER ||
information.productFamily == FIRMWARE_FAMILY_SENSOR) {
if (HAS_SPORT_UPDATE_CONNECTOR()) {
menu->addLine(STR_FLASH_EXTERNAL_DEVICE, [=]() {
FrSkyFirmwareUpdate(fullpath, SPORT_MODULE);
});
} else {
menu->addLine(STR_FLASH_EXTERNAL_MODULE, [=]() {
FrSkyFirmwareUpdate(fullpath, EXTERNAL_MODULE);
});
}
}
#if _NYI_ // Not yet implemented
#if defined(PXX2)
if (information.productFamily == FIRMWARE_FAMILY_RECEIVER) {
if (isReceiverOTAEnabledFromModule(INTERNAL_MODULE,
information.productId))
menu->addLine(STR_FLASH_RECEIVER_BY_INTERNAL_MODULE_OTA, [=]() {
FrSkyFirmwareUpdate(fullpath, INTERNAL_MODULE_OTA);
});
if (isReceiverOTAEnabledFromModule(EXTERNAL_MODULE,
information.productId))
menu->addLine(STR_FLASH_RECEIVER_BY_EXTERNAL_MODULE_OTA, [=]() {
FrSkyFirmwareUpdate(fullpath, EXTERNAL_MODULE_OTA);
});
}
if (information.productFamily == FIRMWARE_FAMILY_FLIGHT_CONTROLLER) {
menu->addLine(
STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA, [=]() {
FrSkyFirmwareUpdate(
fullpath,
STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA);
});
menu->addLine(
STR_FLASH_FLIGHT_CONTROLLER_BY_EXTERNAL_MODULE_OTA, [=]() {
FrSkyFirmwareUpdate(
fullpath,
STR_FLASH_FLIGHT_CONTROLLER_BY_INTERNAL_MODULE_OTA);
});
}
#endif
#if defined(BLUETOOTH)
if (information.productFamily == FIRMWARE_FAMILY_BLUETOOTH_CHIP) {
menu->addLine(STR_FLASH_BLUETOOTH_MODULE, [=]() {
FrSkyFirmwareUpdate(fullpath, STR_FLASH_BLUETOOTH_MODULE);
});
}
#endif
#if defined(HARDWARE_POWER_MANAGEMENT_UNIT)
if (information.productFamily ==
FIRMWARE_FAMILY_POWER_MANAGEMENT_UNIT) {
menu->addLine(STR_FLASH_POWER_MANAGEMENT_UNIT, [=]() {
FrSkyFirmwareUpdate(fullpath, STR_FLASH_POWER_MANAGEMENT_UNIT);
});
}
#endif
#endif // _NYI_
}
}
#if defined(LUA)
else if (isExtensionMatching(ext, SCRIPTS_EXT)) {
menu->addLine(STR_EXECUTE_FILE, [=]() {
luaExec(fullpath);
StandaloneLuaWindow::instance()->attach();
});
}
#endif
}
if (!READ_ONLY()) {
menu->addLine(STR_COPY_FILE, [=]() {
clipboard.type = CLIPBOARD_TYPE_SD_FILE;
f_getcwd(clipboard.data.sd.directory, CLIPBOARD_PATH_LEN);
strncpy(clipboard.data.sd.filename, name, CLIPBOARD_PATH_LEN - 1);
});
if (clipboard.type == CLIPBOARD_TYPE_SD_FILE) {
menu->addLine(STR_PASTE, [=]() {
static char lfn[FF_MAX_LFN + 1]; // TODO optimize that!
f_getcwd((TCHAR*)lfn, FF_MAX_LFN);
// prevent copying to the same directory with the same name
char* destNamePtr = clipboard.data.sd.filename;
if (!strcmp(clipboard.data.sd.directory, lfn)) {
char destFileName[2 * CLIPBOARD_PATH_LEN + 1];
destNamePtr =
strAppend(destFileName, FILE_COPY_PREFIX, CLIPBOARD_PATH_LEN);
destNamePtr = strAppend(destNamePtr, clipboard.data.sd.filename,
CLIPBOARD_PATH_LEN);
destNamePtr = destFileName;
}
sdCopyFile(clipboard.data.sd.filename, clipboard.data.sd.directory,
destNamePtr, lfn);
clipboard.type = CLIPBOARD_TYPE_NONE;
browser->refresh();
});
}
menu->addLine(STR_RENAME_FILE, [=]() {
auto few = new FileNameEditWindow(name);
few->setCloseHandler([=]() { browser->refresh(); });
});
menu->addLine(STR_DELETE_FILE, [=]() {
f_unlink(fullpath);
browser->refresh();
});
}
}
void RadioSdManagerPage::BootloaderUpdate(const char* fn)
{
BootloaderFirmwareUpdate bootloaderFirmwareUpdate;
auto dialog =
new FlashDialog<BootloaderFirmwareUpdate>(bootloaderFirmwareUpdate);
dialog->flash(getFullPath(name));
dialog->flash(fn);
}
void RadioSdManagerPage::FrSkyFirmwareUpdate(const std::string name,
void RadioSdManagerPage::FrSkyFirmwareUpdate(const char* fn,
ModuleIndex module)
{
FrskyDeviceFirmwareUpdate deviceFirmwareUpdate(module);
auto dialog =
new FlashDialog<FrskyDeviceFirmwareUpdate>(deviceFirmwareUpdate);
dialog->flash(getFullPath(name));
dialog->flash(fn);
}
void RadioSdManagerPage::MultiFirmwareUpdate(const std::string name,
void RadioSdManagerPage::MultiFirmwareUpdate(const char* fn,
ModuleIndex module,
MultiModuleType type)
{
MultiDeviceFirmwareUpdate deviceFirmwareUpdate(module, type);
auto dialog =
new FlashDialog<MultiDeviceFirmwareUpdate>(deviceFirmwareUpdate);
dialog->flash(getFullPath(name));
dialog->flash(fn);
}
#if 0
bool menuRadioSdManagerInfo(event_t event)
{
SIMPLE_SUBMENU(STR_SD_INFO_TITLE, ICON_RADIO_SD_MANAGER, 1);
lcdDrawText(MENUS_MARGIN_LEFT, 2*FH, STR_SD_TYPE);
lcdDrawText(100, 2*FH, SD_IS_HC() ? STR_SDHC_CARD : STR_SD_CARD);
lcdDrawText(MENUS_MARGIN_LEFT, 3*FH, STR_SD_SIZE);
lcdDrawNumber(100, 3*FH, sdGetSize(), LEFT, 0, nullptr, "M");
lcdDrawText(MENUS_MARGIN_LEFT, 4*FH, STR_SD_SECTORS);
#if defined(SD_GET_FREE_BLOCKNR)
lcdDrawNumber(100, 4*FH, SD_GET_FREE_BLOCKNR()/1000, LEFT, 0, nullptr, "/");
lcdDrawNumber(150, 4*FH, sdGetNoSectors()/1000, LEFT);
#else
lcdDrawNumber(100, 4*FH, sdGetNoSectors()/1000, LEFT, 0, NULL, "k");
#endif
lcdDrawText(MENUS_MARGIN_LEFT, 5*FH, STR_SD_SPEED);
lcdDrawNumber(100, 5*FH, SD_GET_SPEED()/1000, LEFT, 0, NULL, "kb/s");
return true;
}
#endif
#if 0
void onSdManagerMenu(const char * result)
{
TCHAR lfn[FF_MAX_LFN+1];
// TODO possible buffer overflows here!
uint8_t index = menuVerticalPosition-menuVerticalOffset;
char *line = reusableBuffer.sdmanager.lines[index];
if (result == STR_SD_INFO) {
pushMenu(menuRadioSdManagerInfo);
}
else if (result == STR_SD_FORMAT) {
POPUP_CONFIRMATION(STR_CONFIRM_FORMAT);
}
else if (result == STR_PASTE) {
f_getcwd(lfn, FF_MAX_LFN);
// if destination is dir, copy into that dir
if (IS_DIRECTORY(line)) {
strcat(lfn, PSTR("/"));
strcat(lfn, line);
}
if (strcmp(clipboard.data.sd.directory, lfn)) { // prevent copying to the same directory
POPUP_WARNING(sdCopyFile(clipboard.data.sd.filename, clipboard.data.sd.directory, clipboard.data.sd.filename, lfn));
REFRESH_FILES();
}
}
else if (result == STR_RENAME_FILE) {
memcpy(reusableBuffer.sdmanager.originalName, line, sizeof(reusableBuffer.sdmanager.originalName));
uint8_t fnlen = 0, extlen = 0;
getFileExtension(line, 0, LEN_FILE_EXTENSION_MAX, &fnlen, &extlen);
// write spaces to allow extending the length of a filename
memset(line + fnlen - extlen, ' ', SD_SCREEN_FILE_LENGTH - fnlen + extlen);
line[SD_SCREEN_FILE_LENGTH-extlen] = '\0';
s_editMode = EDIT_MODIFY_STRING;
editNameCursorPos = 0;
}
else if (result == STR_ASSIGN_BITMAP) {
memcpy(g_model.header.bitmap, line, sizeof(g_model.header.bitmap));
storageDirty(EE_MODEL);
}
else if (result == STR_ASSIGN_SPLASH) {
f_getcwd(lfn, FF_MAX_LFN);
sdCopyFile(line, lfn, SPLASH_FILE, BITMAPS_PATH);
}
else if (result == STR_VIEW_TEXT) {
getSelectionFullPath(lfn);
pushMenuTextView(lfn);
}
}
#endif
+9 -5
View File
@@ -23,17 +23,21 @@
#include "tabsgroup.h"
enum MultiModuleType : short;
class FileBrowser;
class RadioSdManagerPage : public PageTab
{
FileBrowser* browser = nullptr;
public:
RadioSdManagerPage();
void build(FormWindow* window) override;
protected:
void BootloaderUpdate(const std::string name);
void FrSkyFirmwareUpdate(const std::string name, ModuleIndex module);
void MultiFirmwareUpdate(const std::string name, ModuleIndex module,
void fileAction(const char* path, const char* name, const char* fullpath);
void BootloaderUpdate(const char* fn);
void FrSkyFirmwareUpdate(const char* fn, ModuleIndex module);
void MultiFirmwareUpdate(const char* fn, ModuleIndex module,
MultiModuleType type);
void rebuild(FormWindow* window);
};
@@ -812,7 +812,7 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
lv_obj_add_style(obj, &styles.scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED);
lv_obj_add_style(obj, &styles.bg_color_white, LV_PART_ITEMS);
lv_obj_add_style(obj, &styles.table_cell, LV_PART_ITEMS);
lv_obj_add_style(obj, &styles.pad_normal, LV_PART_ITEMS);
lv_obj_add_style(obj, &styles.pad_small, LV_PART_ITEMS);
lv_obj_add_style(obj, &styles.pressed, LV_PART_ITEMS | LV_STATE_PRESSED);
lv_obj_add_style(obj, &styles.bg_color_primary, LV_PART_ITEMS | LV_STATE_FOCUS_KEY);
lv_obj_add_style(obj, &styles.bg_color_secondary, LV_PART_ITEMS | LV_STATE_EDITED);