Deluge Firmware 1.3.0
Build date: 2026.10.14
Loading...
Searching...
No Matches
browser.h
1/*
2 * Copyright © 2019-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#pragma once
19
20#include "definitions_cxx.hpp"
21#include "gui/ui/qwerty_ui.h"
22#include "hid/button.h"
23#include "io/debug/log.h"
24#include "model/favourite/favourite_manager.h"
25#include "storage/file_item.h"
26#include "util/container/array/c_string_array.h"
27
28extern "C" {
29#include "fatfs/ff.h"
30
31FRESULT f_readdir_get_filepointer(DIR* dp, /* Pointer to the open directory object */
32 FILINFO* fno, /* Pointer to file information to return */
33 FilePointer* filePointer);
34}
35
36class Instrument;
37class FileItem;
39class Song;
40
41// FIXME: std::expected<std::pair<bool, FileItem*>, Error>
43 FileItem* fileItem;
44 bool loadedFromFile;
45 Error error;
46};
47
48struct Slot {
49 int16_t slot;
50 int8_t subSlot;
51};
52
53#define CATALOG_SEARCH_LEFT 0
54#define CATALOG_SEARCH_RIGHT 1
55#define CATALOG_SEARCH_BOTH 2
56
57#define FILE_ITEMS_MAX_NUM_ELEMENTS 20
58#define FILE_ITEMS_MAX_NUM_ELEMENTS_FOR_NAVIGATION 20 // It "should" be able to be way less than this.
59
60extern char const* allowedFileExtensionsXML[];
61
62class Browser : public QwertyUI {
63public:
64 Browser();
65
66 void close();
67 virtual Error getCurrentFilePath(String* path) = 0;
68 ActionResult buttonAction(deluge::hid::Button b, bool on, bool inCardRoutine) override;
69 ActionResult padAction(int32_t x, int32_t y, int32_t velocity) override;
70 ActionResult verticalEncoderAction(int32_t offset, bool inCardRoutine) override;
71 void currentFileDeleted();
72 Error goIntoFolder(char const* folderName);
73 Error createFolder();
74 Error createFoldersRecursiveIfNotExists(const char* path);
75 void selectEncoderAction(int8_t offset) override;
76 static FileItem* getCurrentFileItem();
77 Error readFileItemsForFolder(char const* filePrefixHere, bool allowFolders, char const** allowedFileExtensionsHere,
78 char const* filenameToStartAt, int32_t newMaxNumFileItems,
79 int32_t newCatalogSearchDirection = CATALOG_SEARCH_BOTH);
80 Error setFileByFullPath(OutputType outputType, char const* fullPath);
81 void sortFileItems();
82 FileItem* getNewFileItem();
83 static void emptyFileItems();
84 static void deleteSomeFileItems(int32_t startAt, int32_t stopAt);
85 static void deleteFolderAndDuplicateItems(Availability instrumentAvailabilityRequirement = Availability::ANY);
86 Error getUnusedSlot(OutputType outputType, String* newName, char const* thingName);
101 static Error surveyNameVariations(char const* stem, String* highestNumbered, uint32_t* takenLetters);
102
107 static bool fileItemsAreComplete() { return !numFileItemsDeletedAtStart && !numFileItemsDeletedAtEnd; }
108 bool opened() override;
109 void cullSomeFileItems();
110 bool checkFP();
111
112 void renderOLED(deluge::hid::display::oled_canvas::Canvas& canvas) override;
113
114 static String currentDir;
115 static CStringArray fileItems;
116 static int32_t numFileItemsDeletedAtStart;
117 static int32_t numFileItemsDeletedAtEnd;
118 // These hold the displayName of the boundary FileItem kept when we cull items off either end of the list to stay
119 // under the memory cap. They must own a *copy* of the name (not borrow the FileItem's buffer): the FileItem they
120 // came from can be destructed - freeing its filename buffer - before these get used as search keys in a later
121 // sortFileItems(). (See the kit-copy use-after-free fix.)
122 static String firstFileItemRemaining;
123 static String lastFileItemRemaining;
124
125 static OutputType outputTypeToLoad;
126 static char const* filenameToStartSearchAt;
127
128 // ui
129 ActionResult exitUI() override {
130 exitAction();
131 return ActionResult::ACTIONED_AND_CAUSED_CHANGE;
132 }
133 bool isFavouritesVisible() override;
134 bool isBanksVisible() override;
135
136protected:
137 Error setEnteredTextFromCurrentFilename();
138 Error goUpOneDirectoryLevel();
139 virtual Error arrivedInNewFolder(int32_t direction, char const* filenameToStartAt = nullptr,
140 char const* defaultDir = nullptr);
141 bool predictExtendedText() override;
142 void goIntoDeleteFileContextMenu();
143 ActionResult mainButtonAction(bool on);
144 virtual void exitAction();
145 virtual ActionResult backButtonAction();
146 virtual void folderContentsReady(int32_t entryDirection) {}
147 virtual void currentFileChanged(int32_t movementDirection) {}
148 void displayText(bool blinkImmediately = false) override;
149 // Keeps the selected file index and top visible browser row inside Browser::fileItems.
150 void clampFileSelectionAndScroll(bool allowNoFileSelection = true);
151 static Slot getSlot(char const* displayName);
154 char const* nameAfterPrefix(char const* name) const;
155 Error readFileItemsFromFolderAndMemory(Song* song, OutputType outputType, char const* filePrefixHere,
156 char const* filenameToStartAt, char const* defaultDirToAlsoTry,
157 bool allowFoldersint,
158 Availability availabilityRequirement = Availability::ANY,
159 int32_t newCatalogSearchDirection = CATALOG_SEARCH_RIGHT);
160 void favouritesChanged();
161
162 static int32_t fileIndexSelected; // If -1, we have not selected any real file/folder. Maybe there are no files, or
163 // maybe we're typing a new name.
164 static int32_t scrollPosVertical;
165 static int32_t
166 numCharsInPrefix; // Only used for deciding Drum names within Kit. Oh and initial text scroll position.
167 static bool qwertyVisible;
168 static bool arrivedAtFileByTyping;
169 static bool allowFoldersSharingNameWithFile;
170 static char const** allowedFileExtensions;
171
172 const uint8_t* fileIcon;
173 const uint8_t* fileIconPt2;
174 int32_t fileIconPt2Width;
175
176 // 7Seg Only
177 static int8_t numberEditPos; // -1 is default
178 static NumericLayerScrollingText* scrollingText;
179 bool shouldWrapFolderContents; // As in, wrap around at the end.
180
181 bool mayDefaultToBrandNewNameOnEntry;
182 bool qwertyAlwaysVisible;
183 // filePrefix is SONG/SYNT/SAMP etc., signifying the portion of the filesystem you're in
184 char const* filePrefix;
185 bool shouldInterpretNoteNamesForThisBrowser;
186};
187
188inline void printInstrumentFileList(const char* where) {
189 D_PRINT("\n");
190 D_PRINT(where);
191 D_PRINT(" List: \n");
192 for (uint32_t idx = 0; idx < Browser::fileItems.getNumElements(); ++idx) {
193 FileItem* fileItem = (FileItem*)Browser::fileItems.getElementAddress(idx);
194 D_PRINTLN(" - %s (%lu)", fileItem->displayName, fileItem->filePointer.sclust);
195 }
196 D_PRINT("\n");
197}
ActionResult exitUI() override
returns whether a UI exited
Definition browser.h:129
char const * nameAfterPrefix(char const *name) const
Definition browser.cpp:1435
static Error surveyNameVariations(char const *stem, String *highestNumbered, uint32_t *takenLetters)
Surveys currentDir in one pass for the existing variations of a name.
Definition browser.cpp:863
static bool fileItemsAreComplete()
Whether fileItems holds every file the folder listed, rather than a culled window of them.
Definition browser.h:107
Definition c_string_array.h:23
Definition file_item.h:24
Definition instrument.h:45
Definition numeric_layer_scrolling_text.h:22
Definition song.h:103
Definition d_string.h:41
Definition browser.h:42
Definition browser.h:48