11 #if defined(__APPLE__) && GUI_USE_NATIVE_FILE_DIALOG
20 #include <unordered_map>
21 #include <unordered_set>
41 namespace visualization {
48 static std::string g_file_dialog_dir;
59 display_ = std::string(
"[ ] ") + name_ +
"/";
61 display_ = std::string(
" ") + name_;
66 const std::string &
GetName()
const {
return name_; }
70 return (type_ == rhs.type_ && name_ == rhs.name_);
80 if (name_ == rhs.name_) {
81 if (type_ == rhs.type_) {
84 return (type_ ==
DIR);
87 return (name_ < rhs.name_);
92 if (type_ == rhs.type_) {
93 return (name_ < rhs.name_);
95 return (type_ ==
DIR);
103 std::string display_;
113 std::unordered_map<int, std::unordered_set<std::string>>
116 std::shared_ptr<Button>
ok_;
122 static DirEntry g_bogus(
"", DirEntry::Type::FILE);
135 std::vector<std::string> raw_subdirs, raw_files;
139 entries_.reserve(raw_subdirs.size() + raw_files.size());
140 for (
auto &dir : raw_subdirs) {
142 entries_.emplace_back(d, DirEntry::Type::DIR);
144 std::unordered_set<std::string> filter;
149 for (
auto &file : raw_files) {
153 ext = std::string(
".") + ext;
155 if (filter.empty() || filter.find(ext) != filter.end()) {
156 entries_.emplace_back(f, DirEntry::Type::FILE);
172 DirEntry(
"..", DirEntry::Type::DIR));
176 std::vector<std::string> display;
179 display.push_back(e.GetDisplayText());
192 const int nSkipSlash = 1;
194 const int nSkipSlash = 2;
196 auto idx =
dirtree_->GetSelectedIndex();
198 for (
int i = 0; i <= idx; ++i) {
199 if (i >= nSkipSlash) {
208 ok_->SetEnabled(std::string(
filename_->GetText()) !=
"");
214 auto em =
theme.font_size;
215 auto layout = std::make_shared<Vert>(
int(
std::ceil(0.5 * em)),
Margins(em));
220 impl_->filename_ = std::make_shared<TextEdit>();
222 auto filenameLabel = std::make_shared<Label>(
"Save as:");
223 auto horiz = std::make_shared<Horiz>();
225 horiz->AddChild(filenameLabel);
226 horiz->AddChild(impl_->filename_);
228 layout->AddChild(horiz);
231 impl_->dirtree_ = std::make_shared<Combobox>();
234 impl_->filelist_ = std::make_shared<ListView>();
235 layout->AddChild(impl_->filelist_);
237 impl_->cancel_ = std::make_shared<Button>(
"Cancel");
239 impl_->ok_ = std::make_shared<Button>(
"Open");
241 impl_->ok_ = std::make_shared<Button>(
"Save");
244 impl_->filter_ = std::make_shared<Combobox>();
245 auto filter_label = std::make_shared<Label>(
"File type:");
246 impl_->filter_row_ = std::make_shared<Horiz>();
247 impl_->filter_row_->AddStretch();
248 impl_->filter_row_->AddChild(filter_label);
249 impl_->filter_row_->AddChild(impl_->filter_);
250 impl_->filter_row_->AddStretch();
251 impl_->filter_row_->SetVisible(
false);
252 layout->AddChild(impl_->filter_row_);
254 auto horiz = std::make_shared<Horiz>(em);
256 horiz->AddChild(impl_->cancel_);
257 horiz->AddChild(impl_->ok_);
258 layout->AddChild(horiz);
261 impl_->filename_->SetOnTextChanged(
262 [
this](
const char *) { this->impl_->UpdateOk(); });
263 impl_->dirtree_->SetOnValueChanged([
this](
const char *,
int) {
264 this->impl_->UpdateDirectoryListing();
266 impl_->filelist_->SetOnValueChanged([
this](
const char *value,
267 bool is_double_click) {
268 auto &entry = this->impl_->GetSelectedEntry();
269 if (is_double_click) {
270 if (entry.GetType() == DirEntry::Type::FILE) {
274 auto new_dir = this->impl_->CalcCurrentDirectory();
275 new_dir = new_dir +
"/" + entry.GetName();
276 this->SetPath(new_dir.c_str());
279 if (entry.GetType() == DirEntry::Type::FILE) {
280 this->impl_->filename_->SetText(entry.GetName().c_str());
282 if (this->impl_->mode_ == Mode::OPEN) {
283 this->impl_->filename_->SetText(
"");
287 this->impl_->UpdateOk();
289 impl_->filter_->SetOnValueChanged([
this](
const char *,
int) {
290 this->impl_->UpdateDirectoryListing();
292 impl_->cancel_->SetOnClicked([
this]() {
293 if (this->impl_->on_cancel_) {
294 this->impl_->on_cancel_();
296 utility::LogError(
"FileDialog: need to call SetOnClicked()");
299 impl_->ok_->SetOnClicked([
this]() { this->OnDone(); });
301 if (g_file_dialog_dir ==
"") {
304 SetPath(g_file_dialog_dir.c_str());
309 FileDialog::~FileDialog() {}
311 void FileDialog::SetPath(
const char *
path) {
314 std::string dirpath =
"";
315 for (
auto &dir : components) {
316 if (dirpath !=
"" && dirpath !=
"/") {
323 impl_->dirtree_->ClearItems();
324 int n = int(is_dir ? components.size() : components.size() - 1);
325 for (
int i = 0; i < n; ++i) {
326 impl_->dirtree_->AddItem(components[i].c_str());
328 impl_->dirtree_->SetSelectedIndex(n - 1);
329 impl_->UpdateDirectoryListing();
331 g_file_dialog_dir = dirpath;
335 impl_->filename_->SetText(components.back().c_str());
339 void FileDialog::AddFilter(
const char *filter,
const char *description) {
342 std::unordered_set<std::string> ext_filter;
343 for (
auto &ext : exts) {
344 ext_filter.insert(ext);
347 bool first_filter = impl_->filter_idx_2_filter.empty();
348 impl_->filter_idx_2_filter[int(impl_->filter_idx_2_filter.size())] =
350 impl_->filter_->AddItem(description);
352 impl_->filter_->SetSelectedIndex(0);
353 impl_->UpdateDirectoryListing();
355 impl_->filter_row_->SetVisible(
true);
358 void FileDialog::SetOnCancel(std::function<
void()> on_cancel) {
359 impl_->on_cancel_ = on_cancel;
362 void FileDialog::SetOnDone(std::function<
void(
const char *)> on_done) {
363 impl_->on_done_ = on_done;
366 void FileDialog::OnWillShow() {}
368 void FileDialog::OnDone() {
369 if (this->impl_->on_done_) {
370 auto dir = this->impl_->CalcCurrentDirectory();
372 std::string
name = this->impl_->filename_->GetText();
375 if (
name.find(
".") == std::string::npos && !
name.empty()) {
376 int idx = this->impl_->filter_->GetSelectedIndex();
378 auto &exts = impl_->filter_idx_2_filter[idx];
381 if (exts.find(
".png") != exts.end()) {
385 name += *exts.begin();
391 this->impl_->on_done_((dir +
"/" +
name).c_str());
399 auto em =
context.theme.font_size;
const std::string & GetDisplayText() const
bool operator==(const DirEntry &rhs) const
bool operator<(const DirEntry &rhs) const
const std::string & GetName() const
DirEntry(const std::string &name, Type type)
bool operator!=(const DirEntry &rhs) const
FileDialog(Mode type, const char *title, const Theme &theme)
static std::shared_ptr< Horiz > MakeCentered(std::shared_ptr< Widget > w)
Helper functions for the ml ops.
static const std::string path
bool ChangeWorkingDirectory(const std::string &directory)
std::string GetWorkingDirectory()
bool DirectoryExists(const std::string &directory)
std::string GetFileExtensionInLowerCase(const std::string &filename)
std::vector< std::string > GetPathComponents(const std::string &path)
std::string GetFileNameWithoutDirectory(const std::string &filename)
bool ListDirectory(const std::string &directory, std::vector< std::string > &subdirs, std::vector< std::string > &filenames)
void SplitString(std::vector< std::string > &tokens, const std::string &str, const std::string &delimiters=" ", bool trim_empty_str=true)
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Generic file read and write utility for python interface.
std::vector< DirEntry > entries_
const DirEntry & GetSelectedEntry()
std::shared_ptr< Horiz > filter_row_
std::shared_ptr< Button > cancel_
std::shared_ptr< Combobox > filter_
std::function< void()> on_cancel_
void UpdateDirectoryListing()
std::function< void(const char *)> on_done_
std::shared_ptr< Combobox > dirtree_
std::unordered_map< int, std::unordered_set< std::string > > filter_idx_2_filter
std::string CalcCurrentDirectory() const
std::shared_ptr< Button > ok_
std::shared_ptr< ListView > filelist_
std::shared_ptr< TextEdit > filename_