mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-10-01 01:26:06 -04:00
Fileman fit and finish
This commit is contained in:
parent
2f343adf21
commit
c6316f5aa6
@ -22,7 +22,6 @@
|
||||
|
||||
/* TODO:
|
||||
* - Paging menu items
|
||||
* - UI with empty SD card
|
||||
* - Copy/Move
|
||||
*/
|
||||
|
||||
@ -101,6 +100,9 @@ void insert_sorted(std::vector<fileman_entry>& entries, fileman_entry&& entry) {
|
||||
|
||||
// Returns the partner file path or an empty path if no partner is found.
|
||||
fs::path get_partner_file(fs::path path) {
|
||||
if (fs::is_directory(path))
|
||||
return { };
|
||||
|
||||
const fs::path txt_path{ u".TXT" };
|
||||
const fs::path c16_path{ u".C16" };
|
||||
auto ext = path.extension();
|
||||
@ -113,12 +115,13 @@ fs::path get_partner_file(fs::path path) {
|
||||
return { };
|
||||
|
||||
path.replace_extension(ext);
|
||||
return file_exists(path) ? path : fs::path{ };
|
||||
return fs::file_exists(path) && !fs::is_directory(path) ? path : fs::path{ };
|
||||
}
|
||||
|
||||
// Modal prompt to update the partner file if it exists.
|
||||
// Runs continuation on_partner_action to update the partner file.
|
||||
// Returns true is a partner is found, otherwise false.
|
||||
// Path must be the full path to the file.
|
||||
bool partner_file_prompt(
|
||||
NavigationView& nav,
|
||||
const fs::path& path,
|
||||
@ -147,6 +150,8 @@ bool partner_file_prompt(
|
||||
|
||||
namespace ui {
|
||||
|
||||
/* FileManBaseView ***********************************************************/
|
||||
|
||||
void FileManBaseView::load_directory_contents(const fs::path& dir_path) {
|
||||
current_path = dir_path;
|
||||
entry_list.clear();
|
||||
@ -180,6 +185,7 @@ fs::path FileManBaseView::get_selected_full_path() const {
|
||||
}
|
||||
|
||||
const fileman_entry& FileManBaseView::get_selected_entry() const {
|
||||
// TODO: return reference to an "empty" entry on OOB?
|
||||
return entry_list[menu_view.highlighted_index()];
|
||||
}
|
||||
|
||||
@ -212,8 +218,7 @@ FileManBaseView::FileManBaseView(
|
||||
text_current.set("EMPTY SD CARD!");
|
||||
} else {
|
||||
menu_view.on_left = [this]() {
|
||||
current_path = current_path.parent_path();
|
||||
reload_current();
|
||||
pop_dir();
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -226,10 +231,32 @@ void FileManBaseView::focus() {
|
||||
}
|
||||
}
|
||||
|
||||
void FileManBaseView::push_dir(const fs::path& path) {
|
||||
if (path == parent_dir_path) {
|
||||
pop_dir();
|
||||
} else {
|
||||
current_path /= path;
|
||||
saved_index_stack.push_back(menu_view.highlighted_index());
|
||||
menu_view.set_highlighted(0);
|
||||
reload_current();
|
||||
}
|
||||
}
|
||||
|
||||
void FileManBaseView::pop_dir() {
|
||||
if (saved_index_stack.empty())
|
||||
return;
|
||||
|
||||
current_path = current_path.parent_path();
|
||||
reload_current();
|
||||
menu_view.set_highlighted(saved_index_stack.back());
|
||||
saved_index_stack.pop_back();
|
||||
}
|
||||
|
||||
void FileManBaseView::refresh_list() {
|
||||
if (on_refresh_widgets)
|
||||
on_refresh_widgets(false);
|
||||
|
||||
auto prev_highlight = menu_view.highlighted_index();
|
||||
menu_view.clear();
|
||||
|
||||
for (const auto& entry : entry_list) {
|
||||
@ -262,7 +289,7 @@ void FileManBaseView::refresh_list() {
|
||||
}
|
||||
}
|
||||
|
||||
menu_view.set_highlighted(0); // Refresh
|
||||
menu_view.set_highlighted(prev_highlight);
|
||||
}
|
||||
|
||||
void FileManBaseView::reload_current() {
|
||||
@ -305,6 +332,8 @@ FileSaveView::FileSaveView(
|
||||
};
|
||||
}*/
|
||||
|
||||
/* FileLoadView **************************************************************/
|
||||
|
||||
void FileLoadView::refresh_widgets(const bool) {
|
||||
set_dirty();
|
||||
}
|
||||
@ -329,35 +358,32 @@ FileLoadView::FileLoadView(
|
||||
|
||||
on_select_entry = [this](KeyEvent) {
|
||||
if (get_selected_entry().is_directory) {
|
||||
current_path = get_selected_full_path();
|
||||
reload_current();
|
||||
push_dir(get_selected_entry().path);
|
||||
} else {
|
||||
nav_.pop();
|
||||
if (on_changed)
|
||||
on_changed(get_selected_full_path());
|
||||
nav_.pop();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* FileManagerView ***********************************************************/
|
||||
|
||||
void FileManagerView::on_rename() {
|
||||
auto& entry = get_selected_entry();
|
||||
|
||||
// Don't rename ".."
|
||||
if (entry.path == parent_dir_path)
|
||||
return;
|
||||
|
||||
name_buffer = entry.path.filename().string();
|
||||
|
||||
uint32_t cursor_pos = (uint32_t)name_buffer.length();
|
||||
if (auto pos = name_buffer.find_last_of("."); pos != name_buffer.npos)
|
||||
|
||||
if (auto pos = name_buffer.find_last_of(".");
|
||||
pos != name_buffer.npos && !entry.is_directory)
|
||||
cursor_pos = pos;
|
||||
|
||||
text_prompt(nav_, name_buffer, cursor_pos, max_filename_length,
|
||||
[this, &entry](std::string& renamed) {
|
||||
[this](std::string& renamed) {
|
||||
auto renamed_path = fs::path{ renamed };
|
||||
rename_file(get_selected_full_path(), current_path / renamed_path);
|
||||
|
||||
auto has_partner = partner_file_prompt(nav_, entry.path, "Rename",
|
||||
auto has_partner = partner_file_prompt(nav_, get_selected_full_path(), "Rename",
|
||||
[this, renamed_path](const fs::path& partner, bool should_rename) mutable {
|
||||
if (should_rename) {
|
||||
auto new_name = renamed_path.replace_extension(partner.extension());
|
||||
@ -373,20 +399,14 @@ void FileManagerView::on_rename() {
|
||||
}
|
||||
|
||||
void FileManagerView::on_delete() {
|
||||
auto& entry = get_selected_entry();
|
||||
|
||||
// Don't delete ".."
|
||||
if (entry.path == parent_dir_path)
|
||||
return;
|
||||
|
||||
auto name = entry.path.filename().string();
|
||||
auto name = get_selected_entry().path.filename().string();
|
||||
nav_.push<ModalMessageView>("Delete", "Delete " + name + "\nAre you sure?", YESNO,
|
||||
[this, &entry](bool choice) {
|
||||
[this](bool choice) {
|
||||
if (choice) {
|
||||
delete_file(get_selected_full_path());
|
||||
|
||||
auto has_partner = partner_file_prompt(
|
||||
nav_, entry.path, "Delete",
|
||||
nav_, get_selected_full_path(), "Delete",
|
||||
[this](const fs::path& partner, bool should_delete) {
|
||||
if (should_delete)
|
||||
delete_file(current_path / partner);
|
||||
@ -409,6 +429,11 @@ void FileManagerView::on_new_dir() {
|
||||
});
|
||||
}
|
||||
|
||||
bool FileManagerView::selected_is_valid() const {
|
||||
return !entry_list.empty() &&
|
||||
get_selected_entry().path != parent_dir_path;
|
||||
}
|
||||
|
||||
void FileManagerView::refresh_widgets(const bool v) {
|
||||
button_rename.hidden(v);
|
||||
button_delete.hidden(v);
|
||||
@ -438,26 +463,31 @@ FileManagerView::FileManagerView(
|
||||
});
|
||||
|
||||
menu_view.on_highlight = [this]() {
|
||||
text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_full_path())));
|
||||
// TODO: enable/disable buttons.
|
||||
if (selected_is_valid())
|
||||
text_date.set(to_string_FAT_timestamp(file_created_date(get_selected_full_path())));
|
||||
else
|
||||
text_date.set("");
|
||||
};
|
||||
|
||||
refresh_list();
|
||||
|
||||
|
||||
on_select_entry = [this](KeyEvent key) {
|
||||
if (key == KeyEvent::Select && get_selected_entry().is_directory) {
|
||||
load_directory_contents(get_selected_full_path());
|
||||
refresh_list();
|
||||
push_dir(get_selected_entry().path);
|
||||
} else {
|
||||
button_rename.focus();
|
||||
}
|
||||
};
|
||||
|
||||
button_rename.on_select = [this](Button&) {
|
||||
on_rename();
|
||||
if (selected_is_valid())
|
||||
on_rename();
|
||||
};
|
||||
|
||||
button_delete.on_select = [this](Button&) {
|
||||
on_delete();
|
||||
if (selected_is_valid())
|
||||
on_delete();
|
||||
};
|
||||
|
||||
button_new_dir.on_select = [this](Button&) {
|
||||
|
@ -69,6 +69,8 @@ protected:
|
||||
std::filesystem::path get_selected_full_path() const;
|
||||
const fileman_entry& get_selected_entry() const;
|
||||
|
||||
void push_dir(const std::filesystem::path& path);
|
||||
void pop_dir();
|
||||
void refresh_list();
|
||||
void reload_current();
|
||||
void load_directory_contents(const std::filesystem::path& dir_path);
|
||||
@ -85,6 +87,7 @@ protected:
|
||||
std::filesystem::path extension_filter { u"" };
|
||||
|
||||
std::vector<fileman_entry> entry_list { };
|
||||
std::vector<uint32_t> saved_index_stack { };
|
||||
|
||||
Labels labels {
|
||||
{ { 0, 0 }, "Path:", Color::light_grey() }
|
||||
@ -152,6 +155,9 @@ private:
|
||||
void on_rename();
|
||||
void on_delete();
|
||||
void on_new_dir();
|
||||
|
||||
// True if the selected entry is a real file item.
|
||||
bool selected_is_valid() const;
|
||||
|
||||
Labels labels {
|
||||
{ { 0, 26 * 8 }, "Created ", Color::light_grey() }
|
||||
|
@ -197,13 +197,6 @@ std::vector<std::filesystem::path> scan_root_directories(const std::filesystem::
|
||||
return directory_list;
|
||||
}
|
||||
|
||||
bool file_exists(const std::filesystem::path& file_path) {
|
||||
FILINFO filinfo;
|
||||
auto fr = f_stat(reinterpret_cast<const TCHAR*>(file_path.c_str()), &filinfo);
|
||||
|
||||
return fr == FR_OK;
|
||||
}
|
||||
|
||||
uint32_t delete_file(const std::filesystem::path& file_path) {
|
||||
return f_unlink(reinterpret_cast<const TCHAR*>(file_path.c_str()));
|
||||
}
|
||||
@ -316,6 +309,10 @@ bool operator==(const path& lhs, const path& rhs) {
|
||||
return lhs.native() == rhs.native();
|
||||
}
|
||||
|
||||
bool operator!=(const path& lhs, const path& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
bool operator<(const path& lhs, const path& rhs) {
|
||||
return lhs.native() < rhs.native();
|
||||
}
|
||||
@ -343,7 +340,7 @@ directory_iterator::directory_iterator(
|
||||
{
|
||||
impl = std::make_shared<Impl>();
|
||||
const auto result = f_findfirst(&impl->dir, &impl->filinfo, reinterpret_cast<const TCHAR*>(path.c_str()), reinterpret_cast<const TCHAR*>(pattern.c_str()));
|
||||
if( result != FR_OK ) {
|
||||
if( result != FR_OK || impl->filinfo.fname[0] == (TCHAR)'\0') {
|
||||
impl.reset();
|
||||
// TODO: Throw exception if/when I enable exceptions...
|
||||
}
|
||||
@ -365,6 +362,20 @@ bool is_regular_file(const file_status s) {
|
||||
return !(s & AM_DIR);
|
||||
}
|
||||
|
||||
bool file_exists(const path& file_path) {
|
||||
FILINFO filinfo;
|
||||
auto fr = f_stat(reinterpret_cast<const TCHAR*>(file_path.c_str()), &filinfo);
|
||||
|
||||
return fr == FR_OK;
|
||||
}
|
||||
|
||||
bool is_directory(const path& file_path) {
|
||||
FILINFO filinfo;
|
||||
auto fr = f_stat(reinterpret_cast<const TCHAR*>(file_path.c_str()), &filinfo);
|
||||
|
||||
return fr == FR_OK && is_directory(static_cast<file_status>(filinfo.fattrib));
|
||||
}
|
||||
|
||||
space_info space(const path& p) {
|
||||
DWORD free_clusters { 0 };
|
||||
FATFS* fs;
|
||||
|
@ -166,6 +166,7 @@ private:
|
||||
};
|
||||
|
||||
bool operator==(const path& lhs, const path& rhs);
|
||||
bool operator!=(const path& lhs, const path& rhs);
|
||||
bool operator<(const path& lhs, const path& rhs);
|
||||
bool operator>(const path& lhs, const path& rhs);
|
||||
path operator+(const path& lhs, const path& rhs);
|
||||
@ -238,6 +239,8 @@ inline bool operator!=(const directory_iterator& lhs, const directory_iterator&
|
||||
|
||||
bool is_directory(const file_status s);
|
||||
bool is_regular_file(const file_status s);
|
||||
bool file_exists(const path& file_path);
|
||||
bool is_directory(const path& file_path);
|
||||
|
||||
space_info space(const path& p);
|
||||
|
||||
@ -249,7 +252,6 @@ struct FATTimestamp {
|
||||
uint16_t FAT_time;
|
||||
};
|
||||
|
||||
bool file_exists(const std::filesystem::path& file_path);
|
||||
uint32_t delete_file(const std::filesystem::path& file_path);
|
||||
uint32_t rename_file(const std::filesystem::path& file_path, const std::filesystem::path& new_name);
|
||||
FATTimestamp file_created_date(const std::filesystem::path& file_path);
|
||||
|
@ -163,6 +163,8 @@ void MenuView::clear() {
|
||||
}
|
||||
|
||||
menu_items.clear();
|
||||
highlighted_item = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
void MenuView::add_item(MenuItem new_item) {
|
||||
@ -209,7 +211,7 @@ MenuItemView* MenuView::item_view(size_t index) const {
|
||||
bool MenuView::set_highlighted(int32_t new_value) {
|
||||
int32_t item_count = (int32_t)menu_items.size();
|
||||
|
||||
if (new_value < 0)
|
||||
if (new_value < 0 || item_count == 0)
|
||||
return false;
|
||||
|
||||
if (new_value >= item_count)
|
||||
|
Loading…
Reference in New Issue
Block a user