feat: add ".." go-up entry to directory picker

The folder picker had no visible way to navigate to a parent directory.
Add a ".." list item (shown when not at root) so users can go up by
selecting it, matching standard file-picker conventions.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-02 15:28:29 -05:00
parent 7eaced602f
commit c09f7b4a22
2 changed files with 27 additions and 15 deletions

View File

@@ -63,6 +63,14 @@ void DirectoryPickerActivity::loadDirectories() {
StringUtils::sortFileList(directories);
}
void DirectoryPickerActivity::navigateToParent() {
auto slash = basepath.find_last_of('/');
basepath = (slash == 0) ? "/" : basepath.substr(0, slash);
selectorIndex = 0;
loadDirectories();
requestUpdate();
}
void DirectoryPickerActivity::loop() {
// Absorb the Confirm release from the parent activity that launched us
if (waitForConfirmRelease) {
@@ -72,14 +80,16 @@ void DirectoryPickerActivity::loop() {
return;
}
// Index 0 = "Save Here", indices 1..N = directory entries
const int totalItems = 1 + static_cast<int>(directories.size());
const int offset = directoryOffset();
const int totalItems = offset + static_cast<int>(directories.size());
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
if (selectorIndex == 0) {
onSelect(basepath);
} else if (showGoUp() && selectorIndex == 1) {
navigateToParent();
} else {
const auto& dirName = directories[selectorIndex - 1];
const auto& dirName = directories[selectorIndex - offset];
// Strip trailing '/'
std::string folderName = dirName.substr(0, dirName.length() - 1);
basepath = (basepath.back() == '/' ? basepath : basepath + "/") + folderName;
@@ -94,11 +104,7 @@ void DirectoryPickerActivity::loop() {
if (basepath == "/") {
onCancel();
} else {
auto slash = basepath.find_last_of('/');
basepath = (slash == 0) ? "/" : basepath.substr(0, slash);
selectorIndex = 0;
loadDirectories();
requestUpdate();
navigateToParent();
}
return;
}
@@ -139,21 +145,24 @@ void DirectoryPickerActivity::render(Activity::RenderLock&&) {
const int contentTop = metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing;
const int contentHeight = pageHeight - contentTop - metrics.buttonHintsHeight - metrics.verticalSpacing;
const int totalItems = 1 + static_cast<int>(directories.size());
const int offset = directoryOffset();
const int totalItems = offset + static_cast<int>(directories.size());
const bool goUp = showGoUp();
GUI.drawList(
renderer, Rect{0, contentTop, pageWidth, contentHeight}, totalItems, selectorIndex,
[this](int index) -> std::string {
[this, offset, goUp](int index) -> std::string {
if (index == 0) {
std::string label = std::string(tr(STR_SAVE_HERE)) + " (" + basepath + ")";
return label;
return std::string(tr(STR_SAVE_HERE)) + " (" + basepath + ")";
}
// Strip trailing '/' for display
const auto& dir = directories[index - 1];
if (goUp && index == 1) {
return "..";
}
const auto& dir = directories[index - offset];
return dir.substr(0, dir.length() - 1);
},
nullptr,
[this](int index) -> UIIcon {
[](int index) -> UIIcon {
return (index == 0) ? UIIcon::File : UIIcon::Folder;
});

View File

@@ -41,4 +41,7 @@ class DirectoryPickerActivity final : public Activity {
std::function<void()> onCancel;
void loadDirectories();
void navigateToParent();
[[nodiscard]] bool showGoUp() const { return basepath != "/"; }
[[nodiscard]] int directoryOffset() const { return showGoUp() ? 2 : 1; }
};