Files
edgetx-gx12/radio/src/thirdparty/libopenui/src/filechoice.cpp
T

198 lines
5.2 KiB
C++

/*
* Copyright (C) EdgeTX
*
* Based on code named
* libopenui - https://github.com/opentx/libopenui
*
* 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 "filechoice.h"
#include <algorithm>
#include "opentx.h"
#include "libopenui_file.h"
#include "menu.h"
#include "menutoolbar.h"
class FileChoiceMenuToolbar : public MenuToolbar
{
public:
FileChoiceMenuToolbar(FileChoice *choice, Menu *menu) :
MenuToolbar(choice, menu, FC_COLS)
{
filterButton(choice, 'a', 'd', "aA-dD");
filterButton(choice, 'e', 'h', "eE-hH");
filterButton(choice, 'i', 'l', "iI-lL");
filterButton(choice, 'm', 'p', "mM-pP");
filterButton(choice, 'q', 't', "qQ-tT");
filterButton(choice, 'u', 'z', "uU-zZ");
filterButton(choice, '0', '9', "0-9");
bool found = false;
for (int i = 0; i <= choice->getMax(); i += 1) {
char c = choice->getString(i)[0];
if (c && !isdigit(c) && !isalpha(c)) {
found = true;
break;
}
}
if (found) {
addButton(
"._-", 0, choice->getMax(),
[=](int16_t index) {
char c = choice->getString(index)[0];
return c && !isdigit(c) && !isalpha(c);
},
STR_MENU_OTHER);
}
addButton(STR_SELECT_MENU_CLR, 0, 0, nullptr, nullptr, true);
}
void filterButton(FileChoice *choice, char from, char to, const char* title)
{
bool found = false;
for (int i = 0; i <= choice->getMax(); i += 1) {
char c = choice->getString(i)[0];
if (isupper(c)) c += 0x20;
if (c >= from && c <= to) {
found = true;
break;
}
}
if (found) {
char s[4];
s[0] = from; s[1] = '-'; s[2] = to; s[3] = 0;
addButton(
s, 0, choice->getMax(),
[=](int16_t index) {
char c = choice->getString(index)[0];
if (isupper(c)) c += 0x20;
return (c >= from && c <= to);
},
title);
}
}
static LAYOUT_VAL(FC_COLS, 3, 2)
protected:
};
FileChoice::FileChoice(Window *parent, const rect_t &rect, std::string folder,
const char *extension, int maxlen,
std::function<std::string()> getValue,
std::function<void(std::string)> setValue,
bool stripExtension, const char *title) :
Choice(
parent, rect, 0, 0, [=]() { return selectedIdx; },
[=](int val) { setValue(getString(val)); }, title, CHOICE_TYPE_FOLDER),
folder(std::move(folder)),
extension(extension),
maxlen(maxlen),
getValue(std::move(getValue)),
setValue(std::move(setValue)),
stripExtension(stripExtension)
{
update();
}
std::string FileChoice::getLabelText() { return getValue(); }
void FileChoice::loadFiles()
{
if (loaded) return;
loaded = true;
FILINFO fno;
DIR dir;
std::list<std::string> files;
const char *fnExt;
uint8_t fnLen, extLen;
FRESULT res = f_opendir(&dir, folder.c_str()); // Open the directory
if (res == FR_OK) {
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 (fno.fattrib & (AM_HID | AM_SYS | AM_DIR))
continue; // Ignore subfolders, hidden files and system files
if (fno.fname[0] == '.' && fno.fname[1] != '.')
continue; // Ignore hidden files under UNIX, but not ..
fnExt = getFileExtension(fno.fname, 0, 0, &fnLen, &extLen);
if (extension && (!fnExt || !isExtensionMatching(fnExt, extension)))
continue; // wrong extension
if (stripExtension) fnLen -= extLen;
if (!fnLen || fnLen > maxlen) continue; // wrong size
// eject duplicates
std::string newFile(fno.fname, fnLen);
if (std::find(files.begin(), files.end(), newFile) != files.end())
continue;
files.emplace_back(newFile);
}
f_closedir(&dir);
}
if (!files.empty()) {
// sort files
files.sort(compare_nocase);
files.push_front("");
std::string value = getValue();
int idx = 0;
for (const auto &file : files) {
addValue(file.c_str());
if (strcmp(value.c_str(), file.c_str()) == 0) selectedIdx = idx;
idx += 1;
}
setMax(files.size() - 1);
}
fileCount = files.size();
}
void FileChoice::openMenu()
{
loadFiles();
if (fileCount > 0) {
setEditMode(true); // this needs to be done first before menu is created.
auto menu = new Menu(this);
if (menuTitle) menu->setTitle(menuTitle);
auto tb = new FileChoiceMenuToolbar(this, menu);
menu->setToolbar(tb);
// fillMenu(menu); - called by MenuToolbar
menu->setCloseHandler([=]() { setEditMode(false); });
} else {
new MessageDialog(this, STR_SDCARD, STR_NO_FILES_ON_SD);
}
}