Audacity 3.2.0
gtk/FileDialogPrivate.cpp
Go to the documentation of this file.
1//
2// Copied from wxWidgets 3.0.2 and modified for Audacity
3//
5// Name: src/gtk/filedlg.cpp
6// Purpose: native implementation of wxFileDialog
7// Author: Robert Roebling, Zbigniew Zagorski, Mart Raudsepp
8// Copyright: (c) 1998 Robert Roebling, 2004 Zbigniew Zagorski, 2005 Mart Raudsepp
9// Licence: wxWindows licence
11
12#include <gtk/gtk.h>
13
14#include "Internat.h"
15#include "BasicUI.h"
16#include "../FileDialog.h"
17
18#ifdef __UNIX__
19#include <unistd.h> // chdir
20#endif
21
22#include <wx/filename.h> // wxFilename
23#include <wx/tokenzr.h> // wxStringTokenizer
24#include <wx/filefn.h> // ::wxGetCwd
25#include <wx/modalhook.h>
26#include <wx/sizer.h>
27
28#define wxGTK_CONV(s) (s).utf8_str()
29#define wxGTK_CONV_FN(s) (s).fn_str()
30
31// ----------------------------------------------------------------------------
32// Convenience class for g_freeing a gchar* on scope exit automatically
33// ----------------------------------------------------------------------------
34
36{
37public:
38 explicit wxGtkString(gchar *s) : m_str(s) { }
39 ~wxGtkString() { g_free(m_str); }
40
41 const gchar *c_str() const { return m_str; }
42
43 operator gchar *() const { return m_str; }
44
45private:
46 gchar *m_str;
47
49};
50
51//-----------------------------------------------------------------------------
52// "clicked" for OK-button
53//-----------------------------------------------------------------------------
54
55extern "C" {
56static void gtk_filedialog_ok_callback(GtkWidget *widget, FileDialog *dialog)
57{
58 int style = dialog->GetWindowStyle();
59 wxGtkString filename(gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)));
60
61 // gtk version numbers must be identical with the one in ctor (that calls set_do_overwrite_confirmation)
62#ifndef __WXGTK3__
63#if GTK_CHECK_VERSION(2,7,3)
64 if (gtk_check_version(2, 7, 3) != NULL)
65#endif
66 {
67 if ((style & wxFD_SAVE) && (style & wxFD_OVERWRITE_PROMPT))
68 {
69 if ( g_file_test(filename, G_FILE_TEST_EXISTS) )
70 {
71 using namespace BasicUI;
72 auto result = ShowMessageBox(
73 XO("File '%s' already exists, do you really want to overwrite it?")
74 .Format(wxString::FromUTF8(filename)),
76 .Caption( XO("Confirm") )
77 .IconStyle(Icon::Question)
78 .ButtonStyle(Button::YesNo));
79 if (result != MessageBoxResult::Yes)
80 {
81 return;
82 }
83 }
84 }
85 }
86#endif
87
88 if (style & wxFD_FILE_MUST_EXIST)
89 {
90 if ( !g_file_test(filename, G_FILE_TEST_EXISTS) )
91 {
92 using namespace BasicUI;
93 ShowMessageBox(XO("Please choose an existing file."),
95 .Caption(XO("Error"))
96 .ButtonStyle(Button::Ok)
97 .IconStyle(Icon::Error));
98 return;
99 }
100 }
101
102 // change to the directory where the user went if asked
103 if (style & wxFD_CHANGE_DIR)
104 {
105 // Use chdir to not care about filename encodings
106 wxGtkString folder(g_path_get_dirname(filename));
107 chdir(folder);
108 }
109
110 wxCommandEvent event(wxEVT_BUTTON, wxID_OK);
111 event.SetEventObject(dialog);
112 dialog->HandleWindowEvent(event);
113}
114}
115
116//-----------------------------------------------------------------------------
117// "clicked" for Cancel-button
118//-----------------------------------------------------------------------------
119
120extern "C"
121{
122
123static void
124gtk_filedialog_cancel_callback(GtkWidget * WXUNUSED(w), FileDialog *dialog)
125{
126 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
127 event.SetEventObject(dialog);
128 dialog->HandleWindowEvent(event);
129}
130
131static void gtk_filedialog_response_callback(GtkWidget *w,
132 gint response,
133 FileDialog *dialog)
134{
135 if (response == GTK_RESPONSE_ACCEPT)
137 else // GTK_RESPONSE_CANCEL or GTK_RESPONSE_NONE
139}
140
141static void gtk_filedialog_selchanged_callback(GtkFileChooser *chooser,
142 FileDialog *dialog)
143{
144 wxGtkString filename(gtk_file_chooser_get_preview_filename(chooser));
145
146 dialog->GTKSelectionChanged(wxString::FromUTF8(filename));
147}
148
149static void gtk_filedialog_update_preview_callback(GtkFileChooser *chooser,
150 gpointer user_data)
151{
152 GtkWidget *preview = GTK_WIDGET(user_data);
153
154 wxGtkString filename(gtk_file_chooser_get_preview_filename(chooser));
155
156 if ( !filename )
157 return;
158
159 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_size(filename, 128, 128, NULL);
160 gboolean have_preview = pixbuf != NULL;
161
162 gtk_image_set_from_pixbuf(GTK_IMAGE(preview), pixbuf);
163 if ( pixbuf )
164 g_object_unref (pixbuf);
165
166 gtk_file_chooser_set_preview_widget_active(chooser, have_preview);
167}
168
169static void gtk_filedialog_folderchanged_callback(GtkFileChooser *chooser,
170 FileDialog *dialog)
171{
172 dialog->GTKFolderChanged();
173}
174
175static void gtk_filedialog_filterchanged_callback(GtkFileChooser *chooser,
176 GParamSpec *pspec,
177 FileDialog *dialog)
178{
179 dialog->GTKFilterChanged();
180}
181
182static GtkWidget* find_widget(GtkWidget* parent, const gchar* name, int depth)
183{
184 // printf("%*.*c%s\n", depth, depth, ' ', gtk_widget_get_name(parent));
185
186 GtkWidget *widget = NULL;
187 if (g_ascii_strncasecmp(gtk_widget_get_name(parent), name, strlen(name)) == 0)
188 {
189 return parent;
190 }
191
192 if (GTK_IS_BIN(parent))
193 {
194 return find_widget(gtk_bin_get_child(GTK_BIN(parent)), name, depth + 1);
195 }
196
197 if (GTK_IS_CONTAINER(parent))
198 {
199 GList *list = gtk_container_get_children(GTK_CONTAINER(parent));
200 for (GList *node = list; node; node = node->next)
201 {
202 widget = find_widget(GTK_WIDGET(node->data), name, depth + 1);
203 if (widget)
204 {
205 break;
206 }
207 }
208 g_list_free(list);
209 }
210
211 return widget;
212}
213
214} // extern "C"
215
216void FileDialog::AddChildGTK(wxWindowGTK* child)
217{
218 // allow dialog to be resized smaller horizontally
219 gtk_widget_set_size_request(
220 child->m_widget, child->GetMinWidth(), child->m_height);
221
222// In GTK 3+, adding our container as the extra widget can cause the
223// the filter combo to grow to the same height as our container. This
224// makes for a very odd looking filter combo. So, we manually add our
225// container below the action bar.
226#if GTK_CHECK_VERSION(3,0,0)
227 GtkWidget *actionbar = find_widget(m_widget, "GtkActionBar", 0);
228 if (actionbar)
229 {
230 GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
231 gtk_container_add(GTK_CONTAINER(vbox), child->m_widget);
232 gtk_box_set_child_packing(GTK_BOX(vbox), child->m_widget, TRUE, TRUE, 0, GTK_PACK_START);
233 gtk_widget_show(vbox);
234
235 GtkWidget *abparent = gtk_widget_get_parent(actionbar);
236 gtk_container_add(GTK_CONTAINER(abparent), vbox);
237 gtk_box_set_child_packing(GTK_BOX(abparent), vbox, FALSE, FALSE, 0, GTK_PACK_END);
238 gtk_box_reorder_child(GTK_BOX(abparent), actionbar, -2);
239 }
240#else
241 gtk_file_chooser_set_extra_widget(
242 GTK_FILE_CHOOSER(m_widget), child->m_widget);
243#endif
244}
245
246//-----------------------------------------------------------------------------
247// FileDialog
248//-----------------------------------------------------------------------------
249
251
252BEGIN_EVENT_TABLE(FileDialog,FileDialogBase)
254 EVT_SIZE(FileDialog::OnSize)
256
257FileDialog::FileDialog(wxWindow *parent, const wxString& message,
258 const wxString& defaultDir,
259 const wxString& defaultFileName,
260 const wxString& wildCard,
261 long style, const wxPoint& pos,
262 const wxSize& sz,
263 const wxString& name)
265{
266 Create(parent, message, defaultDir, defaultFileName, wildCard, style, pos, sz, name);
267}
268
269bool FileDialog::Create(wxWindow *parent, const wxString& message,
270 const wxString& defaultDir,
271 const wxString& defaultFileName,
272 const wxString& wildCard,
273 long style, const wxPoint& pos,
274 const wxSize& sz,
275 const wxString& name)
276{
277 parent = GetParentForModalDialog(parent, style);
278
279 if (!FileDialogBase::Create(parent, message, defaultDir, defaultFileName,
280 wildCard, style, pos, sz, name))
281 {
282 return false;
283 }
284
285 if (!PreCreation(parent, pos, wxDefaultSize) ||
286 !CreateBase(parent, wxID_ANY, pos, wxDefaultSize, style,
287 wxDefaultValidator, wxT("filedialog")))
288 {
289 wxFAIL_MSG( wxT("FileDialog creation failed") );
290 return false;
291 }
292
293 GtkFileChooserAction gtk_action;
294 GtkWindow* gtk_parent = NULL;
295 if (parent)
296 gtk_parent = GTK_WINDOW( gtk_widget_get_toplevel(parent->m_widget) );
297
298 const gchar* ok_btn_stock;
299 if ( style & wxFD_SAVE )
300 {
301 gtk_action = GTK_FILE_CHOOSER_ACTION_SAVE;
302 ok_btn_stock = GTK_STOCK_SAVE;
303 }
304 else
305 {
306 gtk_action = GTK_FILE_CHOOSER_ACTION_OPEN;
307 ok_btn_stock = GTK_STOCK_OPEN;
308 }
309
310 m_widget = gtk_file_chooser_dialog_new(
311 wxGTK_CONV(m_message),
312 gtk_parent,
313 gtk_action,
314 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
315 ok_btn_stock, GTK_RESPONSE_ACCEPT,
316 NULL);
317 g_object_ref(m_widget);
318 GtkFileChooser* file_chooser = GTK_FILE_CHOOSER(m_widget);
319
320 m_fc.SetWidget(file_chooser);
321
322 gtk_dialog_set_default_response(GTK_DIALOG(m_widget), GTK_RESPONSE_ACCEPT);
323
324 if ( style & wxFD_MULTIPLE )
325 gtk_file_chooser_set_select_multiple(file_chooser, true);
326
327 // local-only property could be set to false to allow non-local files to be
328 // loaded. In that case get/set_uri(s) should be used instead of
329 // get/set_filename(s) everywhere and the GtkFileChooserDialog should
330 // probably also be created with a backend, e.g. "gnome-vfs", "default", ...
331 // (gtk_file_chooser_dialog_new_with_backend). Currently local-only is kept
332 // as the default - true:
333 // gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(m_widget), true);
334
335 g_signal_connect (m_widget, "response",
336 G_CALLBACK (gtk_filedialog_response_callback), this);
337
338 g_signal_connect (m_widget, "selection-changed",
339 G_CALLBACK (gtk_filedialog_selchanged_callback), this);
340
341 g_signal_connect (m_widget, "current-folder-changed",
342 G_CALLBACK (gtk_filedialog_folderchanged_callback), this);
343
344 g_signal_connect (m_widget, "notify::filter",
345 G_CALLBACK (gtk_filedialog_filterchanged_callback), this);
346
347 // deal with extensions/filters
348 SetWildcard(wildCard);
349
350 wxString defaultFileNameWithExt = defaultFileName;
351 if ( !wildCard.empty() && !defaultFileName.empty() &&
352 !wxFileName(defaultFileName).HasExt() )
353 {
354 // append the default extension, if any, to the initial file name: GTK
355 // won't do it for us by default (unlike e.g. MSW)
356 const wxFileName fnWC(m_fc.GetCurrentWildCard());
357 if ( fnWC.HasExt() )
358 {
359 // Notice that we shouldn't append the extension if it's a wildcard
360 // because this is not useful: the user would need to change it to use
361 // some fixed extension anyhow.
362 const wxString& ext = fnWC.GetExt();
363 if ( ext.find_first_of("?*") == wxString::npos )
364 defaultFileNameWithExt << "." << ext;
365 }
366 }
367
368
369 // if defaultDir is specified it should contain the directory and
370 // defaultFileName should contain the default name of the file, however if
371 // directory is not given, defaultFileName contains both
372 wxFileName fn;
373 if ( defaultDir.empty() )
374 fn.Assign(defaultFileNameWithExt);
375 else if ( !defaultFileNameWithExt.empty() )
376 fn.Assign(defaultDir, defaultFileNameWithExt);
377 else
378 fn.AssignDir(defaultDir);
379
380 // set the initial file name and/or directory
381 fn.MakeAbsolute(); // GTK+ needs absolute path
382 const wxString dir = fn.GetPath();
383 if ( !dir.empty() )
384 {
385 gtk_file_chooser_set_current_folder(file_chooser, wxGTK_CONV_FN(dir));
386 }
387
388 const wxString fname = fn.GetFullName();
389 if ( style & wxFD_SAVE )
390 {
391 if ( !fname.empty() )
392 {
393 gtk_file_chooser_set_current_name(file_chooser, wxGTK_CONV_FN(fname));
394 }
395
396#if GTK_CHECK_VERSION(2,7,3)
397 if ((style & wxFD_OVERWRITE_PROMPT)
398#ifndef __WXGTK3__
399 && gtk_check_version(2,7,3) == NULL
400#endif
401 )
402 {
403 gtk_file_chooser_set_do_overwrite_confirmation(file_chooser, true);
404 }
405#endif
406 }
407 else // wxFD_OPEN
408 {
409 if ( !fname.empty() )
410 {
411 gtk_file_chooser_set_filename(file_chooser,
412 wxGTK_CONV_FN(fn.GetFullPath()));
413 }
414 }
415
416 if ( style & wxFD_PREVIEW )
417 {
418 GtkWidget *previewImage = gtk_image_new();
419
420 gtk_file_chooser_set_preview_widget(file_chooser, previewImage);
421 g_signal_connect(m_widget, "update-preview",
423 previewImage);
424 }
425
426 return true;
427}
428
430{
431 if (m_extraControl)
432 {
433 // get chooser to drop its reference right now, allowing wxWindow dtor
434 // to verify that ref count drops to zero
435 gtk_file_chooser_set_extra_widget(
436 GTK_FILE_CHOOSER(m_widget), NULL);
437 }
438}
439
440void FileDialog::OnFakeOk(wxCommandEvent& WXUNUSED(event))
441{
442 // Update the current directory from here, accessing it later may not work
443 // due to the strange way GtkFileChooser works.
445 str(gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(m_widget)));
446 m_dir = wxString::FromUTF8(str);
447
448 EndDialog(wxID_OK);
449}
450
452{
453 WX_HOOK_MODAL_DIALOG();
454
455 // Create the root window
456 wxBoxSizer *verticalSizer = new wxBoxSizer(wxVERTICAL);
457 wxPanel *root = new wxPanel(this, wxID_ANY);
458
459 if (HasUserPaneCreator())
460 {
461 wxPanel *userpane = new wxPanel(root, wxID_ANY);
462 CreateUserPane(userpane);
463
464 wxBoxSizer *horizontalSizer = new wxBoxSizer(wxHORIZONTAL);
465 horizontalSizer->Add(userpane, 1, wxEXPAND, 0);
466 verticalSizer->Add(horizontalSizer, 1, wxEXPAND|wxALL, 0);
467 }
468
469 root->SetSizer(verticalSizer);
470 root->Layout();
471 verticalSizer->SetSizeHints(root);
472
473 // Send an initial filter changed event
475
476 return wxDialog::ShowModal();
477}
478
479// Change the currently displayed extension
481{
482 wxString filename;
483
484#if defined(__WXGTK3__)
485 filename = wxString::FromUTF8(gtk_file_chooser_get_current_name(GTK_FILE_CHOOSER(m_widget)));
486#else
487 GtkWidget *entry = find_widget(m_widget, "GtkFileChooserEntry", 0);
488 if (entry)
489 {
490 filename = wxString::FromUTF8(gtk_entry_get_text(GTK_ENTRY(entry)));
491 }
492#endif
493
494 if (filename == wxEmptyString)
495 {
496 filename = m_fc.GetFilename();
497 }
498
499 if (filename != wxEmptyString)
500 {
501 wxFileName fn(filename);
502 fn.SetExt(extension);
503
504 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget), fn.GetFullName().utf8_str());
505 }
506}
507
508void FileDialog::DoSetSize(int WXUNUSED(x), int WXUNUSED(y),
509 int WXUNUSED(width), int WXUNUSED(height),
510 int WXUNUSED(sizeFlags))
511{
512}
513
514void FileDialog::OnSize(wxSizeEvent&)
515{
516 // avoid calling DoLayout(), which will set the (wrong) size of
517 // m_extraControl, its size is managed by GtkFileChooser
518}
519
520wxString FileDialog::GetPath() const
521{
522 return m_fc.GetPath();
523}
524
525void FileDialog::GetFilenames(wxArrayString& files) const
526{
527 m_fc.GetFilenames( files );
528}
529
530void FileDialog::GetPaths(wxArrayString& paths) const
531{
532 m_fc.GetPaths( paths );
533}
534
535void FileDialog::SetMessage(const wxString& message)
536{
537 m_message = message;
538 SetTitle(message);
539}
540
541void FileDialog::SetPath(const wxString& path)
542{
543 FileDialogBase::SetPath(path);
544
545 // Don't do anything if no path is specified, in particular don't set the
546 // path to m_dir below as this would result in opening the dialog in the
547 // parent directory of this one instead of m_dir itself.
548 if ( path.empty() )
549 return;
550
551 // we need an absolute path for GTK native chooser so ensure that we have
552 // it: use the initial directory if it was set or just CWD otherwise (this
553 // is the default behaviour if m_dir is empty)
554 wxFileName fn(path);
555 fn.MakeAbsolute(m_dir);
556 m_fc.SetPath(fn.GetFullPath());
557}
558
559void FileDialog::SetDirectory(const wxString& dir)
560{
561 FileDialogBase::SetDirectory(dir);
562
563 m_fc.SetDirectory(dir);
564}
565
566void FileDialog::SetFilename(const wxString& name)
567{
568 FileDialogBase::SetFilename(name);
569
570 if (HasFdFlag(wxFD_SAVE))
571 {
572 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(m_widget), wxGTK_CONV(name));
573 }
574
575 else
576 {
577 wxString path( GetDirectory() );
578 if (path.empty())
579 {
580 // SetPath() fires an assert if fed other than filepaths
581 return;
582 }
583 SetPath(wxFileName(path, name).GetFullPath());
584 }
585}
586
588{
589 wxString currentFilename( m_fc.GetFilename() );
590 if (currentFilename.empty())
591 {
592 // m_fc.GetFilename() will return empty until the dialog has been shown
593 // in which case use any previously provided value
594 currentFilename = m_fileName;
595 }
596 return currentFilename;
597}
598
599void FileDialog::SetWildcard(const wxString& wildCard)
600{
601 FileDialogBase::SetWildcard(wildCard);
602 m_fc.SetWildcard( GetWildcard() );
603}
604
605void FileDialog::SetFilterIndex(int filterIndex)
606{
607 m_fc.SetFilterIndex( filterIndex );
608}
609
611{
612 return m_fc.GetFilterIndex();
613}
614
615void FileDialog::GTKSelectionChanged(const wxString& filename)
616{
617 m_currentlySelectedFilename = filename;
618
619 wxFileCtrlEvent event(wxEVT_FILECTRL_SELECTIONCHANGED, this, GetId());
620
621 wxArrayString filenames;
622 GetFilenames(filenames);
623
624 event.SetDirectory(GetDirectory());
625 event.SetFiles(filenames);
626
627 GetEventHandler()->ProcessEvent(event);
628}
629
631{
632 wxFileCtrlEvent event(wxEVT_FILECTRL_FOLDERCHANGED, this, GetId());
633
634 event.SetDirectory(GetDirectory());
635
636 GetEventHandler()->ProcessEvent(event);
637}
638
640{
641 wxFileName filename;
642
643#if defined(__WXGTK3__)
644 filename.SetFullName(wxString::FromUTF8(gtk_file_chooser_get_current_name(GTK_FILE_CHOOSER(m_widget))));
645#else
646 GtkWidget *entry = find_widget(m_widget, "GtkFileChooserEntry", 0);
647 if (entry)
648 {
649 filename.SetFullName(wxString::FromUTF8(gtk_entry_get_text(GTK_ENTRY(entry))));
650 }
651#endif
652
653 if (filename.HasName())
654 {
655 wxString ext = m_fc.GetCurrentWildCard().AfterLast(wxT('.')).Lower();
656 if (!ext.empty() && ext != wxT("*") && ext != filename.GetExt())
657 {
658 SetFileExtension(ext);
659 }
660 }
661
662 wxFileCtrlEvent event(wxEVT_FILECTRL_FILTERCHANGED, this, GetId());
663
664 event.SetFilterIndex(GetFilterIndex());
665
666 GetEventHandler()->ProcessEvent(event);
667}
668
wxEVT_COMMAND_BUTTON_CLICKED
wxT("CloseDown"))
Toolkit-neutral facade for basic user interface services.
END_EVENT_TABLE()
#define str(a)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) EVT_BUTTON(wxID_YES
const TranslatableString name
Definition: Distortion.cpp:76
XO("Cut/Copy/Paste")
static ProjectFileIORegistry::AttributeWriterEntry entry
IMPLEMENT_DYNAMIC_CLASS(PluginHostModule, wxModule)
static const auto fn
void CreateUserPane(wxWindow *parent)
Definition: FileDialog.cpp:36
virtual bool HasUserPaneCreator() const
Definition: FileDialog.cpp:25
Dialog used to present platform specific "Save As" dialog with custom controls.
virtual void SetDirectory(const wxString &dir)
virtual int GetFilterIndex() const
virtual wxString GetPath() const
virtual wxString GetFilename() const
virtual void SetFileExtension(const wxString &extension)
virtual void SetPath(const wxString &path)
wxString GetFullPath(HWND hwnd, int itm)
virtual void DoSetSize(int x, int y, int width, int height, int sizeFlags=wxSIZE_AUTO)
virtual void GetFilenames(wxArrayString &files) const
virtual void GetPaths(wxArrayString &paths) const
void OnSize(wxSizeEvent &)
void GTKSelectionChanged(const wxString &filename)
virtual void SetMessage(const wxString &message)
virtual void SetFilename(const wxString &name)
void OnFakeOk(wxCommandEvent &event)
virtual void SetFilterIndex(int filterIndex)
wxGtkFileChooser m_fc
virtual void AddChildGTK(wxWindowGTK *child)
virtual void SetWildcard(const wxString &wildCard)
virtual int ShowModal()
bool Create(wxWindow *parent, const wxString &message=wxFileSelectorPromptStr, const wxString &defaultDir=wxEmptyString, const wxString &defaultFile=wxEmptyString, const wxString &wildCard=wxFileSelectorDefaultWildcardStr, long style=wxFD_DEFAULT_STYLE, const wxPoint &pos=wxDefaultPosition, const wxSize &sz=wxDefaultSize, const wxString &name=wxFileDialogNameStr)
Abstract base class used in importing a file.
const gchar * c_str() const
wxDECLARE_NO_COPY_CLASS(wxGtkString)
static void gtk_filedialog_response_callback(GtkWidget *w, gint response, FileDialog *dialog)
#define wxGTK_CONV_FN(s)
static void gtk_filedialog_update_preview_callback(GtkFileChooser *chooser, gpointer user_data)
static void gtk_filedialog_folderchanged_callback(GtkFileChooser *chooser, FileDialog *dialog)
static void gtk_filedialog_ok_callback(GtkWidget *widget, FileDialog *dialog)
static void gtk_filedialog_selchanged_callback(GtkFileChooser *chooser, FileDialog *dialog)
static GtkWidget * find_widget(GtkWidget *parent, const gchar *name, int depth)
#define wxGTK_CONV(s)
static void gtk_filedialog_filterchanged_callback(GtkFileChooser *chooser, GParamSpec *pspec, FileDialog *dialog)
static void gtk_filedialog_cancel_callback(GtkWidget *WXUNUSED(w), FileDialog *dialog)
MessageBoxResult ShowMessageBox(const TranslatableString &message, MessageBoxOptions options={})
Show a modal message box with either Ok or Yes and No, and optionally Cancel.
Definition: BasicUI.h:279
constexpr size_t npos(-1)
MessageBoxOptions && Caption(TranslatableString caption_) &&
Definition: BasicUI.h:101