Skip to content

Commit 7034039

Browse files
committed
Improved file chooser dialog, extracted some code into separate functions.
1 parent 29670a7 commit 7034039

File tree

2 files changed

+176
-70
lines changed

2 files changed

+176
-70
lines changed

src/GuiFileChooserWindow.cpp

+146-70
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <Poco/SortedDirectoryIterator.h>
66
#include <Poco/String.h>
77

8+
#include <algorithm>
9+
810
void GuiFileChooserWindow::Show()
911
{
1012
_visible = true;
@@ -19,9 +21,10 @@ bool GuiFileChooserWindow::Draw()
1921

2022
bool fileSelected{false};
2123

22-
if (!_currentDir.isDirectory() || !Poco::File(_currentDir).exists())
24+
if (!_currentDir.isDirectory()
25+
|| (!_currentDir.toString().empty() && !Poco::File(_currentDir).exists()))
2326
{
24-
_currentDir = Poco::Path::home();
27+
ChangeDirectory(Poco::Path::home());
2528
}
2629

2730
if (ImGui::Begin("Load Preset", &_visible), ImGuiWindowFlags_NoCollapse)
@@ -30,74 +33,36 @@ bool GuiFileChooserWindow::Draw()
3033

3134
ImGui::Separator();
3235

33-
ImGui::Text("%s", _currentDir.toString().c_str());
36+
char pathBuffer[2048]{};
37+
strncpy(pathBuffer, _currentDir.toString().c_str(), std::min<size_t>(2047, _currentDir.toString().size()));
3438

35-
if (ImGui::BeginListBox("##filelist", ImVec2(-1,-1)))
39+
if (ImGui::InputText("##path", &pathBuffer[0], IM_ARRAYSIZE(pathBuffer)), ImGuiInputTextFlags_EnterReturnsTrue)
3640
{
37-
Poco::SortedDirectoryIterator directoryIterator(_currentDir);
38-
Poco::SortedDirectoryIterator directoryEnd;
41+
ChangeDirectory(std::string(pathBuffer));
42+
}
3943

40-
int index = 0;
41-
while (directoryIterator != directoryEnd)
44+
if (ImGui::BeginListBox("##filelist", ImVec2(-1, -1)))
45+
{
46+
if (_currentDir.toString().empty())
4247
{
43-
bool isSelected = _selectedFileIndex == index;
44-
bool isDirectory = false;
45-
bool isHidden = false;
46-
try
47-
{
48-
// This will throw for broken symlinks or if the file/dir isn't accessible
49-
isHidden = directoryIterator->isHidden();
50-
isDirectory = directoryIterator->isDirectory();
51-
}
52-
catch (...)
53-
{
54-
}
48+
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "No path entered");
49+
}
50+
else
51+
{
52+
Poco::File pathCheck(_currentDir);
5553

56-
if (!_showhidden && isHidden)
54+
if (!pathCheck.exists())
5755
{
58-
++directoryIterator;
59-
continue;
56+
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Directory does not exist");
6057
}
61-
62-
auto filename = directoryIterator.name();
63-
64-
if (isDirectory)
58+
else if (!pathCheck.canRead())
6559
{
66-
filename.append("/");
60+
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Directory cannot be accessed");
6761
}
6862
else
6963
{
70-
if (Poco::icompare(directoryIterator.path().getExtension(), "milk") != 0)
71-
{
72-
++directoryIterator;
73-
continue;
74-
}
75-
}
76-
77-
if (ImGui::Selectable(filename.c_str(), isSelected, ImGuiSelectableFlags_AllowDoubleClick))
78-
{
79-
_selectedFileIndex = index;
80-
81-
if (ImGui::IsMouseDoubleClicked(0))
82-
{
83-
if (isDirectory)
84-
{
85-
_currentDir = directoryIterator.path();
86-
_currentDir.makeDirectory();
87-
poco_debug_f1(_logger, "Changing dir to: %s", _currentDir.toString());
88-
}
89-
else
90-
{
91-
_selectedFile = directoryIterator.path();
92-
poco_debug_f1(_logger, "User selected file: %s", _selectedFile.path());
93-
fileSelected = true;
94-
_visible = false;
95-
}
96-
}
64+
fileSelected = PopulateFileList();
9765
}
98-
99-
++directoryIterator;
100-
index++;
10166
}
10267

10368
ImGui::EndListBox();
@@ -112,6 +77,12 @@ bool GuiFileChooserWindow::Draw()
11277

11378
return fileSelected;
11479
}
80+
81+
const Poco::File& GuiFileChooserWindow::SelectedFile() const
82+
{
83+
return _selectedFile;
84+
}
85+
11586
void GuiFileChooserWindow::DrawNavButtons()
11687
{
11788
ImGui::Checkbox("Show hidden files", &_showhidden);
@@ -122,33 +93,138 @@ void GuiFileChooserWindow::DrawNavButtons()
12293

12394
if (ImGui::Button("Up"))
12495
{
125-
_currentDir = _currentDir.parent();
126-
_currentDir.makeDirectory();
96+
ChangeDirectory(_currentDir.parent());
12797
poco_debug_f1(_logger, "Going one dir up: %s", _currentDir.toString());
12898
}
12999

130100
ImGui::SameLine();
131101

132102
if (ImGui::Button("Home"))
103+
{
104+
ChangeDirectory(Poco::Path::home());
105+
poco_debug_f1(_logger, "Going to user's home dir: %s", _currentDir.toString());
106+
}
107+
108+
for (const auto& root: roots)
109+
{
110+
ImGui::SameLine();
111+
112+
if (ImGui::Button(root.c_str()))
133113
{
134-
_currentDir = Poco::Path::home();
135-
poco_debug_f1(_logger, "Going to user's home dir: %s", _currentDir.toString());
114+
ChangeDirectory(root);
115+
poco_debug_f1(_logger, "Changing root/drive to: %s", _currentDir.toString());
136116
}
117+
}
118+
}
119+
120+
bool GuiFileChooserWindow::PopulateFileList()
121+
{
122+
bool fileSelected{false};
123+
bool changeDir{false};
124+
Poco::Path newDir;
137125

138-
for (const auto& root: roots)
126+
int index = 0;
127+
for (const auto& file : _currentFileList)
128+
{
129+
bool isSelected = _selectedFileIndex == index;
130+
bool isDirectory = false;
131+
try
132+
{
133+
// This will throw for broken symlinks or if the file/dir isn't accessible
134+
isDirectory = file.isDirectory();
135+
}
136+
catch (...)
139137
{
140-
ImGui::SameLine();
138+
}
141139

142-
if (ImGui::Button(root.c_str()))
143-
{
144-
_currentDir = root;
140+
Poco::Path filePath(file.path());
141+
auto filename = filePath.getFileName();
142+
143+
if (isDirectory)
144+
{
145+
filename.append("/");
146+
}
145147

146-
poco_debug_f1(_logger, "Changing root/drive to: %s", _currentDir.toString());
148+
if (ImGui::Selectable(filename.c_str(), isSelected, ImGuiSelectableFlags_AllowDoubleClick))
149+
{
150+
_selectedFileIndex = index;
151+
152+
if (ImGui::IsMouseDoubleClicked(0))
153+
{
154+
if (isDirectory)
155+
{
156+
newDir = filePath;
157+
changeDir = true;
158+
poco_debug_f1(_logger, "Changing dir to: %s", _currentDir.toString());
159+
}
160+
else
161+
{
162+
_selectedFile = filePath;
163+
poco_debug_f1(_logger, "User selected file: %s", _selectedFile.path());
164+
fileSelected = true;
165+
_visible = false;
166+
}
147167
}
148168
}
169+
170+
index++;
171+
}
172+
173+
if (changeDir)
174+
{
175+
ChangeDirectory(newDir);
176+
}
177+
178+
return fileSelected;
149179
}
150180

151-
const Poco::File& GuiFileChooserWindow::SelectedFile() const
181+
void GuiFileChooserWindow::ChangeDirectory(const Poco::Path& newDirectory)
152182
{
153-
return _selectedFile;
183+
_currentDir = newDirectory;
184+
_currentDir.makeDirectory();
185+
186+
_currentFileList.clear();
187+
188+
if (_currentDir.toString().empty())
189+
{
190+
return;
191+
}
192+
193+
Poco::File pathCheck(_currentDir);
194+
if (!pathCheck.exists() || !pathCheck.canRead())
195+
{
196+
return;
197+
}
198+
199+
// Ideally, only use the directory iterator after cd'ing into a new dir and store the path list.
200+
Poco::SortedDirectoryIterator directoryIterator(_currentDir);
201+
Poco::SortedDirectoryIterator directoryEnd;
202+
203+
while (directoryIterator != directoryEnd)
204+
{
205+
bool isHidden = false;
206+
bool isDirectory = false;
207+
try
208+
{
209+
// This will throw for broken symlinks or if the file/dir isn't accessible
210+
isHidden = directoryIterator->isHidden();
211+
isDirectory = directoryIterator->isDirectory();
212+
}
213+
catch (...)
214+
{
215+
}
216+
217+
if (!isDirectory && Poco::icompare(directoryIterator.path().getExtension(), "milk") != 0)
218+
{
219+
++directoryIterator;
220+
continue;
221+
}
222+
223+
if (!isHidden || _showhidden)
224+
{
225+
_currentFileList.push_back(*directoryIterator);
226+
}
227+
228+
++directoryIterator;
229+
}
154230
}

src/GuiFileChooserWindow.h

+30
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
#include <Poco/Path.h>
55
#include <Poco/Logger.h>
66

7+
/**
8+
* @brief File/preset chooser dialog
9+
*
10+
* Displays a file browser that shows directories and .milk files from which the user can choose one.
11+
*/
712
class GuiFileChooserWindow
813
{
914
public:
@@ -16,16 +21,41 @@ class GuiFileChooserWindow
1621
*/
1722
bool Draw();
1823

24+
25+
/**
26+
* @brief Returns the selected file
27+
* @return The selected file
28+
*/
1929
const Poco::File& SelectedFile() const;
2030

2131
protected:
32+
/**
33+
* Draws the navigation buttons on top (up, home, root/drives)
34+
*/
2235
void DrawNavButtons();
2336

37+
/**
38+
* @brief Fills the file list with content and checks if one was chosen
39+
* @return True if the user chose a file.
40+
*/
41+
bool PopulateFileList();
42+
43+
/**
44+
* @brief Changes the currently displayed directory to the given path.
45+
*
46+
* The path must not necessarily exist or be accessible. A message is shown to the user if something is wrong.
47+
*
48+
* @param newDirectory The directory to chdir into
49+
*/
50+
void ChangeDirectory(const Poco::Path& newDirectory);
51+
2452
bool _visible{ false }; //!< File chooser window visible.
2553
bool _showhidden{ false }; //!< If true, hidden files/dirs are shown.
2654
Poco::Path _currentDir{ Poco::Path::current() }; //!< Current working dir.
55+
std::vector<Poco::File> _currentFileList; //!< File list of current directory
2756
Poco::File _selectedFile; //!< Currently selected file.
2857
int _selectedFileIndex{ 0 }; //!< Currently selected item in the file list.
2958

59+
3060
Poco::Logger& _logger{ Poco::Logger::get("GuiFileChooserWindow") };
3161
};

0 commit comments

Comments
 (0)