fs: add support for mounting nca, save and gamecard fs. file picker inherits from browser. fix bugs (see below).
- fixed fs real path length not actually being 0x301, but instead 255. fixes #204 - file picker inherits from file browser now so there's a lot less duplicated code. - file browser now saves the last highlighted file. - fix bug in file browser where the new file path could be empty (ie not containing a /). - added support for viewing qlaunch romfs. - moved fs mount options to the top of the list (may revert).
This commit is contained in:
@@ -182,15 +182,37 @@ inline FsPath operator+(const std::string_view& v, const FsPath& fp) {
|
||||
return r += fp;
|
||||
}
|
||||
|
||||
static_assert(FsPath::Test("abc"));
|
||||
static_assert(FsPath::Test(std::string_view{"abc"}));
|
||||
static_assert(FsPath::Test(std::string{"abc"}));
|
||||
static_assert(FsPath::Test(FsPath{"abc"}));
|
||||
// Fs seems to be limted to file paths of 255 characters.
|
||||
struct FsPathReal {
|
||||
static constexpr inline size_t FS_REAL_MAX_LENGTH = 255;
|
||||
|
||||
static_assert(FsPath::TestFrom("abc"));
|
||||
static_assert(FsPath::TestFrom(std::string_view{"abc"}));
|
||||
static_assert(FsPath::TestFrom(std::string{"abc"}));
|
||||
static_assert(FsPath::TestFrom(FsPath{"abc"}));
|
||||
constexpr FsPathReal(const FsPath& str) : FsPathReal{str.s} { }
|
||||
explicit constexpr FsPathReal(const char* str) {
|
||||
size_t real = 0;
|
||||
for (size_t i = 0; str[i]; i++) {
|
||||
// skip multiple slashes.
|
||||
if (i && str[i] == '/' && str[i - 1] == '/') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// save single char.
|
||||
s[real++] = str[i];
|
||||
|
||||
// check if we have exceeded the path.
|
||||
if (real >= FS_REAL_MAX_LENGTH) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// null the end.
|
||||
s[real] = '\0';
|
||||
}
|
||||
|
||||
constexpr operator const char*() const { return s; }
|
||||
constexpr operator std::string_view() const { return s; }
|
||||
|
||||
char s[FS_MAX_PATH];
|
||||
};
|
||||
|
||||
// fwd
|
||||
struct Fs;
|
||||
@@ -227,44 +249,38 @@ struct Dir {
|
||||
|
||||
FsPath AppendPath(const fs::FsPath& root_path, const fs::FsPath& file_path);
|
||||
|
||||
Result CreateFile(FsFileSystem* fs, const FsPath& path, u64 size = 0, u32 option = 0, bool ignore_read_only = true);
|
||||
Result CreateDirectory(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
||||
Result CreateFile(FsFileSystem* fs, const FsPathReal& path, u64 size = 0, u32 option = 0, bool ignore_read_only = true);
|
||||
Result CreateDirectory(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
||||
Result CreateDirectoryRecursively(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
||||
Result CreateDirectoryRecursivelyWithPath(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
||||
Result DeleteFile(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
||||
Result DeleteDirectory(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
||||
Result DeleteDirectoryRecursively(FsFileSystem* fs, const FsPath& path, bool ignore_read_only = true);
|
||||
Result RenameFile(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool ignore_read_only = true);
|
||||
Result RenameDirectory(FsFileSystem* fs, const FsPath& src, const FsPath& dst, bool ignore_read_only = true);
|
||||
Result GetEntryType(FsFileSystem* fs, const FsPath& path, FsDirEntryType* out);
|
||||
Result GetFileTimeStampRaw(FsFileSystem* fs, const FsPath& path, FsTimeStampRaw *out);
|
||||
Result SetTimestamp(FsFileSystem* fs, const FsPath& path, const FsTimeStampRaw* ts);
|
||||
Result DeleteFile(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
||||
Result DeleteDirectory(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
||||
Result DeleteDirectoryRecursively(FsFileSystem* fs, const FsPathReal& path, bool ignore_read_only = true);
|
||||
Result RenameFile(FsFileSystem* fs, const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
||||
Result RenameDirectory(FsFileSystem* fs, const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
||||
Result GetEntryType(FsFileSystem* fs, const FsPathReal& path, FsDirEntryType* out);
|
||||
Result GetFileTimeStampRaw(FsFileSystem* fs, const FsPathReal& path, FsTimeStampRaw *out);
|
||||
Result SetTimestamp(FsFileSystem* fs, const FsPathReal& path, const FsTimeStampRaw* ts);
|
||||
bool FileExists(FsFileSystem* fs, const FsPath& path);
|
||||
bool DirExists(FsFileSystem* fs, const FsPath& path);
|
||||
Result read_entire_file(FsFileSystem* fs, const FsPath& path, std::vector<u8>& out);
|
||||
Result write_entire_file(FsFileSystem* fs, const FsPath& path, const std::vector<u8>& in, bool ignore_read_only = true);
|
||||
Result copy_entire_file(FsFileSystem* fs, const FsPath& dst, const FsPath& src, bool ignore_read_only = true);
|
||||
|
||||
Result CreateFile(const FsPath& path, u64 size = 0, u32 option = 0, bool ignore_read_only = true);
|
||||
Result CreateDirectory(const FsPath& path, bool ignore_read_only = true);
|
||||
Result CreateFile(const FsPathReal& path, u64 size = 0, u32 option = 0, bool ignore_read_only = true);
|
||||
Result CreateDirectory(const FsPathReal& path, bool ignore_read_only = true);
|
||||
Result CreateDirectoryRecursively(const FsPath& path, bool ignore_read_only = true);
|
||||
Result CreateDirectoryRecursivelyWithPath(const FsPath& path, bool ignore_read_only = true);
|
||||
Result DeleteFile(const FsPath& path, bool ignore_read_only = true);
|
||||
Result DeleteDirectory(const FsPath& path, bool ignore_read_only = true);
|
||||
Result DeleteFile(const FsPathReal& path, bool ignore_read_only = true);
|
||||
Result DeleteDirectory(const FsPathReal& path, bool ignore_read_only = true);
|
||||
Result DeleteDirectoryRecursively(const FsPath& path, bool ignore_read_only = true);
|
||||
Result RenameFile(const FsPath& src, const FsPath& dst, bool ignore_read_only = true);
|
||||
Result RenameDirectory(const FsPath& src, const FsPath& dst, bool ignore_read_only = true);
|
||||
Result GetEntryType(const FsPath& path, FsDirEntryType* out);
|
||||
Result GetFileTimeStampRaw(const FsPath& path, FsTimeStampRaw *out);
|
||||
Result SetTimestamp(const FsPath& path, const FsTimeStampRaw* ts);
|
||||
Result RenameFile(const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
||||
Result RenameDirectory(const FsPathReal& src, const FsPathReal& dst, bool ignore_read_only = true);
|
||||
Result GetEntryType(const FsPathReal& path, FsDirEntryType* out);
|
||||
Result GetFileTimeStampRaw(const FsPathReal& path, FsTimeStampRaw *out);
|
||||
Result SetTimestamp(const FsPathReal& path, const FsTimeStampRaw* ts);
|
||||
bool FileExists(const FsPath& path);
|
||||
bool DirExists(const FsPath& path);
|
||||
Result read_entire_file(const FsPath& path, std::vector<u8>& out);
|
||||
Result write_entire_file(const FsPath& path, const std::vector<u8>& in, bool ignore_read_only = true);
|
||||
Result copy_entire_file(const FsPath& dst, const FsPath& src, bool ignore_read_only = true);
|
||||
|
||||
Result OpenFile(fs::Fs* fs, const fs::FsPath& path, u32 mode, File* f);
|
||||
Result OpenDirectory(fs::Fs* fs, const fs::FsPath& path, u32 mode, Dir* d);
|
||||
Result OpenFile(fs::Fs* fs, const FsPathReal& path, u32 mode, File* f);
|
||||
Result OpenDirectory(fs::Fs* fs, const FsPathReal& path, u32 mode, Dir* d);
|
||||
|
||||
// opens dir, fetches count for all entries.
|
||||
// NOTE: this function will be slow on non-native fs, due to multiple
|
||||
@@ -281,6 +297,11 @@ Result DirGetEntryCount(fs::Fs* fs, const fs::FsPath& path, s64* file_count, s64
|
||||
Result FileGetSizeAndTimestamp(fs::Fs* fs, const FsPath& path, FsTimeStampRaw* ts, s64* size);
|
||||
Result IsDirEmpty(fs::Fs* m_fs, const fs::FsPath& path, bool* out);
|
||||
|
||||
// helpers.
|
||||
Result read_entire_file(Fs* fs, const FsPath& path, std::vector<u8>& out);
|
||||
Result write_entire_file(Fs* fs, const FsPath& path, const std::vector<u8>& in, bool ignore_read_only = true);
|
||||
Result copy_entire_file(Fs* fs, const FsPath& dst, const FsPath& src, bool ignore_read_only = true);
|
||||
|
||||
struct Fs {
|
||||
Fs(bool ignore_read_only = true) : m_ignore_read_only{ignore_read_only} {}
|
||||
virtual ~Fs() = default;
|
||||
@@ -302,9 +323,6 @@ struct Fs {
|
||||
virtual bool DirExists(const FsPath& path) = 0;
|
||||
virtual bool IsNative() const = 0;
|
||||
virtual FsPath Root() const { return "/"; }
|
||||
virtual Result read_entire_file(const FsPath& path, std::vector<u8>& out) = 0;
|
||||
virtual Result write_entire_file(const FsPath& path, const std::vector<u8>& in) = 0;
|
||||
virtual Result copy_entire_file(const FsPath& dst, const FsPath& src) = 0;
|
||||
|
||||
Result OpenFile(const fs::FsPath& path, u32 mode, File* f) {
|
||||
return fs::OpenFile(this, path, mode, f);
|
||||
@@ -324,6 +342,15 @@ struct Fs {
|
||||
Result IsDirEmpty(const fs::FsPath& path, bool* out) {
|
||||
return fs::IsDirEmpty(this, path, out);
|
||||
}
|
||||
Result read_entire_file(const FsPath& path, std::vector<u8>& out) {
|
||||
return fs::read_entire_file(this, path, out);
|
||||
}
|
||||
Result write_entire_file(const FsPath& path, const std::vector<u8>& in) {
|
||||
return fs::write_entire_file(this, path, in, m_ignore_read_only);
|
||||
}
|
||||
Result copy_entire_file(const FsPath& dst, const FsPath& src) {
|
||||
return fs::copy_entire_file(this, dst, src, m_ignore_read_only);
|
||||
}
|
||||
|
||||
void SetIgnoreReadOnly(bool enable) {
|
||||
m_ignore_read_only = enable;
|
||||
@@ -388,15 +415,6 @@ struct FsStdio : Fs {
|
||||
FsPath Root() const override {
|
||||
return m_root;
|
||||
}
|
||||
Result read_entire_file(const FsPath& path, std::vector<u8>& out) override {
|
||||
return fs::read_entire_file(path, out);
|
||||
}
|
||||
Result write_entire_file(const FsPath& path, const std::vector<u8>& in) override {
|
||||
return fs::write_entire_file(path, in, m_ignore_read_only);
|
||||
}
|
||||
Result copy_entire_file(const FsPath& dst, const FsPath& src) override {
|
||||
return fs::copy_entire_file(dst, src, m_ignore_read_only);
|
||||
}
|
||||
|
||||
const FsPath m_root;
|
||||
};
|
||||
@@ -475,15 +493,6 @@ struct FsNative : Fs {
|
||||
bool IsNative() const override {
|
||||
return true;
|
||||
}
|
||||
Result read_entire_file(const FsPath& path, std::vector<u8>& out) override {
|
||||
return fs::read_entire_file(&m_fs, path, out);
|
||||
}
|
||||
Result write_entire_file(const FsPath& path, const std::vector<u8>& in) override {
|
||||
return fs::write_entire_file(&m_fs, path, in, m_ignore_read_only);
|
||||
}
|
||||
Result copy_entire_file(const FsPath& dst, const FsPath& src) override {
|
||||
return fs::copy_entire_file(&m_fs, dst, src, m_ignore_read_only);
|
||||
}
|
||||
|
||||
FsFileSystem m_fs{};
|
||||
Result m_open_result{};
|
||||
|
||||
@@ -1,143 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "ui/menus/filebrowser.hpp"
|
||||
#include "ui/menus/menu_base.hpp"
|
||||
#include "ui/scrolling_text.hpp"
|
||||
#include "ui/list.hpp"
|
||||
#include "fs.hpp"
|
||||
#include "option.hpp"
|
||||
#include <span>
|
||||
|
||||
namespace sphaira::ui::menu::filepicker {
|
||||
|
||||
enum FsEntryFlag {
|
||||
FsEntryFlag_None,
|
||||
// write protected.
|
||||
FsEntryFlag_ReadOnly = 1 << 0,
|
||||
// supports file assoc.
|
||||
FsEntryFlag_Assoc = 1 << 1,
|
||||
};
|
||||
|
||||
enum SortType {
|
||||
SortType_Size,
|
||||
SortType_Alphabetical,
|
||||
};
|
||||
|
||||
enum OrderType {
|
||||
OrderType_Descending,
|
||||
OrderType_Ascending,
|
||||
};
|
||||
|
||||
using FsType = filebrowser::FsType;
|
||||
using FsEntry = filebrowser::FsEntry;
|
||||
using FileEntry = filebrowser::FileEntry;
|
||||
using LastFile = filebrowser::LastFile;
|
||||
namespace sphaira::ui::menu::filebrowser::picker {
|
||||
|
||||
using Callback = std::function<bool(const fs::FsPath& path)>;
|
||||
|
||||
struct Menu final : MenuBase {
|
||||
struct Menu final : Base {
|
||||
explicit Menu(const Callback& cb, const std::vector<std::string>& filter = {}, const fs::FsPath& path = {});
|
||||
~Menu();
|
||||
|
||||
auto GetShortTitle() const -> const char* override { return "Picker"; };
|
||||
void Update(Controller* controller, TouchInfo* touch) override;
|
||||
void Draw(NVGcontext* vg, Theme* theme) override;
|
||||
void OnFocusGained() override;
|
||||
|
||||
static auto GetNewPath(const fs::FsPath& root_path, const fs::FsPath& file_path) -> fs::FsPath {
|
||||
return fs::AppendPath(root_path, file_path);
|
||||
}
|
||||
|
||||
private:
|
||||
auto GetFs() {
|
||||
return m_fs.get();
|
||||
}
|
||||
|
||||
auto& GetFsEntry() const {
|
||||
return m_fs_entry;
|
||||
}
|
||||
|
||||
void SetIndex(s64 index);
|
||||
|
||||
auto Scan(const fs::FsPath& new_path, bool is_walk_up = false) -> Result;
|
||||
|
||||
auto GetNewPath(const FileEntry& entry) const -> fs::FsPath {
|
||||
return GetNewPath(m_path, entry.name);
|
||||
}
|
||||
|
||||
auto GetNewPath(s64 index) const -> fs::FsPath {
|
||||
return GetNewPath(m_path, GetEntry(index).name);
|
||||
}
|
||||
|
||||
auto GetNewPathCurrent() const -> fs::FsPath {
|
||||
return GetNewPath(m_index);
|
||||
}
|
||||
|
||||
auto GetEntry(u32 index) -> FileEntry& {
|
||||
return m_entries[m_entries_current[index]];
|
||||
}
|
||||
|
||||
auto GetEntry(u32 index) const -> const FileEntry& {
|
||||
return m_entries[m_entries_current[index]];
|
||||
}
|
||||
|
||||
auto GetEntry() -> FileEntry& {
|
||||
return GetEntry(m_index);
|
||||
}
|
||||
|
||||
auto GetEntry() const -> const FileEntry& {
|
||||
return GetEntry(m_index);
|
||||
}
|
||||
|
||||
auto IsSd() const -> bool {
|
||||
return m_fs_entry.type == FsType::Sd;
|
||||
}
|
||||
|
||||
void Sort();
|
||||
void SortAndFindLastFile(bool scan = false);
|
||||
void SetIndexFromLastFile(const LastFile& last_file);
|
||||
|
||||
void SetFs(const fs::FsPath& new_path, const FsEntry& new_entry);
|
||||
|
||||
auto GetNative() -> fs::FsNative* {
|
||||
return (fs::FsNative*)m_fs.get();
|
||||
}
|
||||
|
||||
void DisplayOptions();
|
||||
|
||||
void UpdateSubheading();
|
||||
void PromptIfShouldExit();
|
||||
void OnClick(FsView* view, const FsEntry& fs_entry, const FileEntry& entry, const fs::FsPath& path) override;
|
||||
|
||||
private:
|
||||
static constexpr inline const char* INI_SECTION = "filepicker";
|
||||
|
||||
Callback m_callback;
|
||||
std::vector<std::string> m_filter;
|
||||
|
||||
std::unique_ptr<fs::Fs> m_fs{};
|
||||
FsEntry m_fs_entry{};
|
||||
fs::FsPath m_path{};
|
||||
std::vector<FileEntry> m_entries{};
|
||||
std::vector<u32> m_entries_index{}; // files not including hidden
|
||||
std::vector<u32> m_entries_index_hidden{}; // includes hidden files
|
||||
std::span<u32> m_entries_current{};
|
||||
|
||||
std::unique_ptr<List> m_list{};
|
||||
|
||||
// this keeps track of the highlighted file before opening a folder
|
||||
// if the user presses B to go back to the previous dir
|
||||
// this vector is popped, then, that entry is checked if it still exists
|
||||
// if it does, the index becomes that file.
|
||||
std::vector<LastFile> m_previous_highlighted_file{};
|
||||
s64 m_index{};
|
||||
ScrollingText m_scroll_name{};
|
||||
|
||||
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_Alphabetical, false};
|
||||
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending, false};
|
||||
option::OptionBool m_show_hidden{INI_SECTION, "show_hidden", false, false};
|
||||
option::OptionBool m_folders_first{INI_SECTION, "folders_first", true, false};
|
||||
option::OptionBool m_hidden_last{INI_SECTION, "hidden_last", false, false};
|
||||
option::OptionBool m_ignore_read_only{INI_SECTION, "ignore_read_only", false, false};
|
||||
const Callback m_callback;
|
||||
};
|
||||
|
||||
} // namespace sphaira::ui::menu::filepicker
|
||||
} // namespace sphaira::ui::menu::filebrowser::picker
|
||||
|
||||
@@ -11,12 +11,35 @@
|
||||
|
||||
namespace sphaira::ui::menu::filebrowser {
|
||||
|
||||
enum FsOption : u32 {
|
||||
FsOption_NONE,
|
||||
|
||||
// can split screen.
|
||||
FsOption_CanSplit = BIT(0),
|
||||
// can upload files.
|
||||
FsOption_CanUpload = BIT(1),
|
||||
// can selected multiple files.
|
||||
FsOption_CanSelect = BIT(2),
|
||||
// shows the option to install.
|
||||
FsOption_CanInstall = BIT(3),
|
||||
// loads file assoc.
|
||||
FsOption_LoadAssoc = BIT(4),
|
||||
// do not prompt on exit even if not tabbed.
|
||||
FsOption_DoNotPrompt = BIT(5),
|
||||
|
||||
FsOption_Normal = FsOption_LoadAssoc | FsOption_CanInstall | FsOption_CanSplit | FsOption_CanUpload | FsOption_CanSelect,
|
||||
FsOption_All = FsOption_DoNotPrompt | FsOption_Normal,
|
||||
FsOption_Picker = FsOption_NONE,
|
||||
};
|
||||
|
||||
enum FsEntryFlag {
|
||||
FsEntryFlag_None,
|
||||
// write protected.
|
||||
FsEntryFlag_ReadOnly = 1 << 0,
|
||||
// supports file assoc.
|
||||
FsEntryFlag_Assoc = 1 << 1,
|
||||
// this is an sd card, files can be launched from here.
|
||||
FsEntryFlag_IsSd = 1 << 2,
|
||||
};
|
||||
|
||||
enum class FsType {
|
||||
@@ -24,6 +47,7 @@ enum class FsType {
|
||||
ImageNand,
|
||||
ImageSd,
|
||||
Stdio,
|
||||
Custom,
|
||||
};
|
||||
|
||||
enum class SelectedType {
|
||||
@@ -62,13 +86,17 @@ struct FsEntry {
|
||||
return flags & FsEntryFlag_Assoc;
|
||||
}
|
||||
|
||||
auto IsSd() const -> bool {
|
||||
return flags & FsEntryFlag_IsSd;
|
||||
}
|
||||
|
||||
auto IsSame(const FsEntry& e) const {
|
||||
return root == e.root && type == e.type;
|
||||
}
|
||||
};
|
||||
|
||||
// roughly 1kib in size per entry
|
||||
struct FileEntry : FsDirectoryEntry {
|
||||
struct FileEntry final : FsDirectoryEntry {
|
||||
std::string extension{}; // if any
|
||||
std::string internal_name{}; // if any
|
||||
std::string internal_extension{}; // if any
|
||||
@@ -161,13 +189,14 @@ using FsDirCollections = std::vector<FsDirCollection>;
|
||||
|
||||
void SignalChange();
|
||||
|
||||
struct Menu;
|
||||
struct Base;
|
||||
|
||||
struct FsView final : Widget {
|
||||
friend class Menu;
|
||||
friend class Base;
|
||||
|
||||
FsView(Menu* menu, ViewSide side);
|
||||
FsView(Menu* menu, const fs::FsPath& path, const FsEntry& entry, ViewSide side);
|
||||
FsView(FsView* view, ViewSide side);
|
||||
FsView(Base* menu, ViewSide side);
|
||||
FsView(Base* menu, const std::shared_ptr<fs::Fs>& fs, const fs::FsPath& path, const FsEntry& entry, ViewSide side);
|
||||
~FsView();
|
||||
|
||||
void Update(Controller* controller, TouchInfo* touch) override;
|
||||
@@ -192,7 +221,9 @@ struct FsView final : Widget {
|
||||
static auto get_collection(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result;
|
||||
static auto get_collections(fs::Fs* fs, const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;
|
||||
|
||||
private:
|
||||
// private:
|
||||
void OnClick();
|
||||
|
||||
void SetIndex(s64 index);
|
||||
void InstallForwarder();
|
||||
|
||||
@@ -201,7 +232,7 @@ private:
|
||||
void ZipFiles(fs::FsPath zip_path);
|
||||
void UploadFiles();
|
||||
|
||||
auto Scan(const fs::FsPath& new_path, bool is_walk_up = false) -> Result;
|
||||
auto Scan(fs::FsPath new_path, bool is_walk_up = false) -> Result;
|
||||
|
||||
auto GetNewPath(const FileEntry& entry) const -> fs::FsPath {
|
||||
return GetNewPath(m_path, entry.name);
|
||||
@@ -248,7 +279,7 @@ private:
|
||||
}
|
||||
|
||||
auto IsSd() const -> bool {
|
||||
return m_fs_entry.type == FsType::Sd;
|
||||
return m_fs_entry.IsSd();
|
||||
}
|
||||
|
||||
void Sort();
|
||||
@@ -263,7 +294,7 @@ private:
|
||||
auto get_collection(const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollection& out, bool inc_file, bool inc_dir, bool inc_size) -> Result;
|
||||
auto get_collections(const fs::FsPath& path, const fs::FsPath& parent_name, FsDirCollections& out, bool inc_size = false) -> Result;
|
||||
|
||||
void SetFs(const fs::FsPath& new_path, const FsEntry& new_entry);
|
||||
void SetFs(const std::shared_ptr<fs::Fs>& fs, const fs::FsPath& new_path, const FsEntry& new_entry);
|
||||
|
||||
auto GetNative() -> fs::FsNative* {
|
||||
return (fs::FsNative*)m_fs.get();
|
||||
@@ -274,11 +305,11 @@ private:
|
||||
void DisplayOptions();
|
||||
void DisplayAdvancedOptions();
|
||||
|
||||
private:
|
||||
Menu* m_menu{};
|
||||
// private:
|
||||
Base* m_menu{};
|
||||
ViewSide m_side{};
|
||||
|
||||
std::unique_ptr<fs::Fs> m_fs{};
|
||||
std::shared_ptr<fs::Fs> m_fs{};
|
||||
FsEntry m_fs_entry{};
|
||||
fs::FsPath m_path{};
|
||||
std::vector<FileEntry> m_entries{};
|
||||
@@ -345,22 +376,28 @@ struct SelectedStash {
|
||||
SelectedType m_type{SelectedType::None};
|
||||
};
|
||||
|
||||
struct Menu final : MenuBase {
|
||||
struct Base : MenuBase {
|
||||
friend class FsView;
|
||||
|
||||
Menu(u32 flags);
|
||||
~Menu();
|
||||
Base(u32 flags, u32 options);
|
||||
Base(const std::shared_ptr<fs::Fs>& fs, const FsEntry& fs_entry, const fs::FsPath& path, bool is_custom, u32 flags, u32 options);
|
||||
|
||||
void SetFilter(const std::vector<std::string>& filter) {
|
||||
m_filter = filter;
|
||||
}
|
||||
|
||||
auto GetShortTitle() const -> const char* override { return "Files"; };
|
||||
void Update(Controller* controller, TouchInfo* touch) override;
|
||||
void Draw(NVGcontext* vg, Theme* theme) override;
|
||||
void OnFocusGained() override;
|
||||
virtual void OnFocusGained() override;
|
||||
|
||||
static auto GetNewPath(const fs::FsPath& root_path, const fs::FsPath& file_path) -> fs::FsPath {
|
||||
return fs::AppendPath(root_path, file_path);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void OnClick(FsView* view, const FsEntry& fs_entry, const FileEntry& entry, const fs::FsPath& path);
|
||||
|
||||
protected:
|
||||
auto IsSplitScreen() const {
|
||||
return m_split_screen;
|
||||
}
|
||||
@@ -390,9 +427,20 @@ private:
|
||||
|
||||
void PromptIfShouldExit();
|
||||
|
||||
private:
|
||||
auto CanInstall() const {
|
||||
return m_options & FsOption_CanInstall;
|
||||
}
|
||||
|
||||
auto CreateFs(const FsEntry& fs_entry) -> std::shared_ptr<fs::Fs>;
|
||||
|
||||
protected:
|
||||
static constexpr inline const char* INI_SECTION = "filebrowser";
|
||||
|
||||
const u32 m_options;
|
||||
|
||||
std::shared_ptr<fs::Fs> m_custom_fs{};
|
||||
FsEntry m_custom_fs_entry{};
|
||||
|
||||
FsView* view{};
|
||||
std::unique_ptr<FsView> view_left{};
|
||||
std::unique_ptr<FsView> view_right{};
|
||||
@@ -400,6 +448,8 @@ private:
|
||||
std::vector<FileAssocEntry> m_assoc_entries{};
|
||||
SelectedStash m_selected{};
|
||||
|
||||
std::vector<std::string> m_filter{};
|
||||
|
||||
option::OptionLong m_sort{INI_SECTION, "sort", SortType::SortType_Alphabetical};
|
||||
option::OptionLong m_order{INI_SECTION, "order", OrderType::OrderType_Descending};
|
||||
option::OptionBool m_show_hidden{INI_SECTION, "show_hidden", false};
|
||||
@@ -411,4 +461,19 @@ private:
|
||||
bool m_split_screen{};
|
||||
};
|
||||
|
||||
struct Menu final : Base {
|
||||
Menu(u32 flags, u32 options = FsOption_All) : Base{flags, options} {
|
||||
}
|
||||
|
||||
Menu(const std::shared_ptr<fs::Fs>& fs, const FsEntry& fs_entry, const fs::FsPath& path, u32 options = FsOption_All)
|
||||
: Base{fs, fs_entry, path, true, MenuFlag_None, options} {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// case insensitive check
|
||||
auto IsSamePath(std::string_view a, std::string_view b) -> bool;
|
||||
auto IsExtension(std::string_view ext1, std::string_view ext2) -> bool;
|
||||
auto IsExtension(std::string_view ext, std::span<const std::string_view> list) -> bool;
|
||||
|
||||
} // namespace sphaira::ui::menu::filebrowser
|
||||
|
||||
@@ -77,6 +77,7 @@ private:
|
||||
}
|
||||
|
||||
void DumpNcas();
|
||||
Result MountNcaFs();
|
||||
|
||||
private:
|
||||
Entry& m_entry;
|
||||
|
||||
@@ -199,6 +199,8 @@ private:
|
||||
void OnChangeIndex(s64 new_index);
|
||||
Result DumpGames(u32 flags);
|
||||
|
||||
Result MountGcFs();
|
||||
|
||||
private:
|
||||
FsDeviceOperator m_dev_op{};
|
||||
FsGameCardHandle m_handle{};
|
||||
|
||||
@@ -80,6 +80,8 @@ private:
|
||||
m_selected_count = 0;
|
||||
}
|
||||
|
||||
void DisplayOptions();
|
||||
|
||||
void BackupSaves(std::vector<std::reference_wrapper<Entry>>& entries);
|
||||
void RestoreSave();
|
||||
|
||||
@@ -87,6 +89,8 @@ private:
|
||||
Result RestoreSaveInternal(ProgressBox* pbox, const Entry& e, const fs::FsPath& path) const;
|
||||
Result BackupSaveInternal(ProgressBox* pbox, const dump::DumpLocation& location, const Entry& e, bool compressed, bool is_auto = false) const;
|
||||
|
||||
Result MountSaveFs();
|
||||
|
||||
private:
|
||||
static constexpr inline const char* INI_SECTION = "saves";
|
||||
|
||||
|
||||
@@ -80,6 +80,6 @@ static constexpr inline bool HasRequiredSystemVersion(const NcmContentMetaKey *k
|
||||
}
|
||||
|
||||
// fills program id and out path of the control nca.
|
||||
Result GetControlPathFromContentId(NcmContentStorage* cs, const NcmContentMetaKey& key, const NcmContentId& id, u64* out_program_id, fs::FsPath* out_path);
|
||||
Result GetFsPathFromContentId(NcmContentStorage* cs, const NcmContentMetaKey& key, const NcmContentId& id, u64* out_program_id, fs::FsPath* out_path);
|
||||
|
||||
} // namespace sphaira::ncm
|
||||
|
||||
Reference in New Issue
Block a user