Audacity 3.2.0
wxWidgetsBasicUI.cpp
Go to the documentation of this file.
1/*!********************************************************************
2
3Audacity: A Digital Audio Editor
4
5@file wxWidgetsBasicUI.cpp
6
7Paul Licameli
8
9**********************************************************************/
10#include "wxWidgetsBasicUI.h"
12#include "MemoryX.h" // for Destroy_ptr
13#include "ErrorDialog.h"
14#ifdef HAS_SENTRY_REPORTING
15#include "ErrorReportDialog.h"
16#endif
17#include "AudacityMessageBox.h"
18#include "ProgressDialog.h"
19#include "MultiDialog.h"
20#include <wx/app.h>
21#include <wx/progdlg.h>
22#include <wx/windowptr.h>
23#include <wx/utils.h>
24
25using namespace BasicUI;
26
28
30{
31 wxTheApp->CallAfter(action);
32}
33
35{
36 wxTheApp->Yield();
37}
38
40 const BasicUI::WindowPlacement &placement,
41 const TranslatableString &dlogTitle,
42 const TranslatableString &message,
43 const ManualPageID &helpPage,
44 const BasicUI::ErrorDialogOptions &options)
45{
46 using namespace BasicUI;
47 bool modal = true;
48 auto parent = wxWidgetsWindowPlacement::GetParent(placement);
49 switch (options.type) {
50 case ErrorDialogType::ModalErrorReport: {
51#ifdef HAS_SENTRY_REPORTING
52 ErrorReportDialog dlog(parent, dlogTitle, message, helpPage,
53 options.log, modal);
54
55 dlog.CentreOnParent();
56 dlog.ShowModal();
57 return;
58#else
59 break;
60#endif
61 }
62 case ErrorDialogType::ModelessError: {
63 if (!parent)
64 parent = wxTheApp->GetTopWindow();
65 // To be nonmodal, either it needs a parent, to avoid leaks, or it must
66 // guarantee eventual deletion of itself. There might be no top window
67 // on MacOS. Let's just force it to be modal in that case.
68 if (parent)
69 modal = false;
70 break;
71 }
72 default:
73 break;
74 }
75 auto pDlog = Destroy_ptr<ErrorDialog>( safenew ErrorDialog{ parent,
76 dlogTitle, message, helpPage, options.log,
77 options.modalHelp, modal } );
78 pDlog->CentreOnParent();
79 if (modal)
80 pDlog->ShowModal();
81 else {
82 pDlog->Show();
83 pDlog.release(); // not a memory leak, because it has a parent
84 }
85}
86
89 const TranslatableString &message,
90 MessageBoxOptions options)
91{
92 // Compute the style argument to pass to wxWidgets
93 long style = 0;
94 switch (options.iconStyle) {
95 case Icon::Warning :
96 style = wxICON_WARNING;
97 break;
98 case Icon::Error :
99 style = wxICON_ERROR;
100 break;
101 case Icon::Question :
102 style = wxICON_QUESTION;
103 break;
104 case Icon::Information :
105 style = wxICON_INFORMATION;
106 break;
107 default:
108 break;
109 }
110 switch (options.buttonStyle) {
111 case Button::Ok :
112 style |= wxOK;
113 break;
114 case Button::YesNo :
115 style |= wxYES_NO;
116 break;
117 default:
118 break;
119 }
120 if (!options.yesOrOkDefaultButton && options.buttonStyle == Button::YesNo)
121 style |= wxNO_DEFAULT;
122 if (options.cancelButton)
123 style |= wxCANCEL;
124 if (options.centered)
125 style |= wxCENTER;
126
127 // Preserving the default style AudacityMessageBox had,
128 // when none of the above were explicitly specified
129 if (!style)
130 style = wxOK | wxCENTRE;
131
132 // This calls through to ::wxMessageBox:
133 auto wxResult =
134 ::AudacityMessageBox(message, options.caption, style,
135 options.parent
137 : nullptr);
138 // This switch exhausts all possibilities for the return from::wxMessageBox.
139 // see utilscmn.cpp in wxWidgets.
140 // Remap to our toolkit-neutral enumeration.
141 switch (wxResult) {
142 case wxYES:
143 return MessageBoxResult::Yes;
144 case wxNO:
145 return MessageBoxResult::No;
146 case wxOK:
147 return MessageBoxResult::Ok;
148 case wxCANCEL:
149 return MessageBoxResult::Cancel;
150 case wxHELP:
151 // should not happen, because we don't ever pass wxHELP
152 default:
153 wxASSERT(false);
154 return MessageBoxResult::None;
155 }
156}
157
158std::unique_ptr<BasicUI::ProgressDialog>
160 const TranslatableString &message,
161 unsigned flags,
162 const TranslatableString &remainingLabelText)
163{
164 unsigned options = 0;
165 if (!(flags & ProgressShowStop))
166 options |= pdlgHideStopButton;
167 if (!(flags & ProgressShowCancel))
168 options |= pdlgHideCancelButton;
169 if ((flags & ProgressHideTime))
170 options |= pdlgHideElapsedTime;
171 if ((flags & ProgressConfirmStopOrCancel))
172 options |= pdlgConfirmStopCancel;
173 // Usually wxWindow objects should not be managed by std::unique_ptr
174 // See https://docs.wxwidgets.org/3.0/overview_windowdeletion.html
175 // But on macOS the use of wxWindowPtr for the progress dialog sometimes
176 // causes hangs.
177 return std::make_unique<::ProgressDialog>(
178 title, message, options, remainingLabelText);
179}
180
181namespace {
182struct MyGenericProgress : wxGenericProgressDialog, GenericProgressDialog {
184 const TranslatableString &message,
185 wxWindow *parent = nullptr)
186 : wxGenericProgressDialog{
187 title.Translation(), message.Translation(),
188 300000, // range
189 parent,
190 wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH
191 }
192 {}
193 ~MyGenericProgress() override = default;
195 {
196 if (wxGenericProgressDialog::Pulse())
198 else if (WasCancelled())
200 else
202 }
203};
204}
205
206std::unique_ptr<GenericProgressDialog>
208 const BasicUI::WindowPlacement &placement,
210 const TranslatableString &message)
211{
212 return std::make_unique<MyGenericProgress>(
213 title, message, wxWidgetsWindowPlacement::GetParent(placement));
214}
215
218 const TranslatableStrings &buttons,
219 const ManualPageID &helpPage,
220 const TranslatableString &boxMsg, bool log)
221{
222 return ::ShowMultiDialog(message, title, buttons, helpPage, boxMsg, log);
223}
224
226{
227 return wxLaunchDefaultBrowser(url);
228}
229
230std::unique_ptr<BasicUI::WindowPlacement> wxWidgetsBasicUI::DoFindFocus()
231{
232 return std::make_unique<wxWidgetsWindowPlacement>(wxWindow::FindFocus());
233}
234
236{
237 auto pWindow = wxWidgetsWindowPlacement::GetParent(focus);
238 pWindow->SetFocus();
239}
240
242{
243 return wxLayout_RightToLeft == wxTheApp->GetLayoutDirection();
244}
245
247{
248 return wxIsMainThread();
249}
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
#define safenew
Definition: MemoryX.h:10
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:164
static const auto title
@ pdlgConfirmStopCancel
@ pdlgHideStopButton
@ pdlgHideElapsedTime
@ pdlgHideCancelButton
std::vector< TranslatableString > TranslatableStrings
Abstraction of a progress dialog with undefined time-to-completion estimate.
Definition: BasicUI.h:179
Subclasses may hold information such as a parent window pointer for a dialog.
Definition: BasicUI.h:30
Gives an Error message with an option for help.
Definition: ErrorDialog.h:26
A dialog, that has "Send", "Don't send" and help buttons.
Holds a msgid for the translation catalog; may also bind format arguments.
bool IsUiThread() const override
void DoCallAfter(const BasicUI::Action &action) override
bool DoOpenInDefaultBrowser(const wxString &url) override
BasicUI::MessageBoxResult DoMessageBox(const TranslatableString &message, BasicUI::MessageBoxOptions options) override
void DoSetFocus(const BasicUI::WindowPlacement &focus) override
int DoMultiDialog(const TranslatableString &message, const TranslatableString &title, const TranslatableStrings &buttons, const ManualPageID &helpPage, const TranslatableString &boxMsg, bool log) override
~wxWidgetsBasicUI() override
std::unique_ptr< BasicUI::GenericProgressDialog > DoMakeGenericProgress(const BasicUI::WindowPlacement &placement, const TranslatableString &title, const TranslatableString &message) override
std::unique_ptr< BasicUI::ProgressDialog > DoMakeProgress(const TranslatableString &title, const TranslatableString &message, unsigned flags, const TranslatableString &remainingLabelText) override
bool IsUsingRtlLayout() const override
std::unique_ptr< BasicUI::WindowPlacement > DoFindFocus() override
void DoYield() override
void DoShowErrorDialog(const BasicUI::WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const BasicUI::ErrorDialogOptions &options) override
ProgressResult
Definition: BasicUI.h:148
@ ProgressHideTime
Definition: BasicUI.h:143
@ ProgressShowCancel
Definition: BasicUI.h:142
@ ProgressConfirmStopOrCancel
Definition: BasicUI.h:144
@ ProgressShowStop
Definition: BasicUI.h:141
int ShowMultiDialog(const TranslatableString &message, const TranslatableString &title, const TranslatableStrings &buttons, const ManualPageID &helpPage, const TranslatableString &boxMsg, bool log)
Display a dialog with radio buttons.
Definition: BasicUI.h:359
std::function< void()> Action
Definition: BasicUI.h:24
MessageBoxResult
Definition: BasicUI.h:132
std::unique_ptr< WindowPlacement > FindFocus()
Find the window that is accepting keyboard input, if any.
Definition: BasicUI.h:375
Options for variations of error dialogs; the default is for modal dialogs.
Definition: BasicUI.h:52
ErrorDialogType type
Type of help dialog.
Definition: BasicUI.h:70
std::wstring log
Optional extra logging information to be shown.
Definition: BasicUI.h:74
bool modalHelp
Whether the secondary help dialog with more information should be modal.
Definition: BasicUI.h:72
TranslatableString caption
Definition: BasicUI.h:124
WindowPlacement * parent
Definition: BasicUI.h:123
ProgressResult Pulse() override
Give some visual indication of progress. Call only on the main thread.
MyGenericProgress(const TranslatableString &title, const TranslatableString &message, wxWindow *parent=nullptr)
static wxWindow * GetParent(const WindowPlacement &placement)
Retrieve the pointer to window, if placement is of this type; else null.
Implementation of BasicUI using wxWidgets.