diff --git a/src/widgets/ProgressDialog.cpp b/src/widgets/ProgressDialog.cpp index 6b450b662..3ae91983e 100644 --- a/src/widgets/ProgressDialog.cpp +++ b/src/widgets/ProgressDialog.cpp @@ -1009,24 +1009,27 @@ ProgressDialog::ProgressDialog(const wxString & title, // ProgressDialog::~ProgressDialog() { + // Delete the window disabler before hiding the dialog to allow + // focus to return to the original window. if (mDisable) { delete mDisable; mDisable = NULL; } - - if (IsShown()) + else if (mTopParent) { - Show(false); - - Beep(); + mTopParent->Enable(true); } + + Beep(); } void ProgressDialog::Init() { mLastValue = 0; mDisable = NULL; + mTopParent = NULL; + mIsTransparent = true; } bool ProgressDialog::Create(const wxString & title, @@ -1041,7 +1044,8 @@ bool ProgressDialog::Create(const wxString & title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | - wxFRAME_FLOAT_ON_PARENT); + wxFRAME_FLOAT_ON_PARENT | + wxTRANSPARENT_WINDOW); if (!success) { return false; @@ -1166,23 +1170,37 @@ bool ProgressDialog::Create(const wxString & title, mCancel = false; mStop = false; - // Even though we won't necessarily show the dialog due to the 500ms - // delay, we MUST disable other windows/menus anyway since we run the risk - // of allowing other tasks to run before this one is complete. - // - // Reviewed this code per Proposed Features #1, at - // http://wiki.audacityteam.org/wiki/Proposal_Timer_Record_Improvements. - // Note that this causes a problem for Timer Record wait dialog - // (see TimerRecordDialog::RunWaitDialog()), because it makes it - // impossible to do any editing, even in other open projects, - // while waiting for Timer Record to start -- and then also - // while it's recording, it has a ProgressDialog, so really, - // no editing in any project until Timer Record finishes. - mDisable = new wxWindowDisabler(this); + // Because wxGTK is very sensitive about maintaining focus when + // this window is not shown, we always show it. But, since we + // want a 500ms delay before it's actually visible for those + // quick tasks, we show it as transparent. If the initial + // delay is exceeded, then we reset the dialog to full opacity. + SetTransparent(0); + mIsTransparent = true; - // On OSX at least, creating the disabler causes the dialog to show, so - // just hide it again until the delay has been reached. - Show(false); + wxDialog::Show(true); + + if (flags & pdlgAppModal) + { + // Even though we won't necessarily show the dialog due to the 500ms + // delay, we MUST disable other windows/menus anyway since we run the risk + // of allowing other tasks to run before this one is complete. + // + // Reviewed this code per Proposed Features #1, at + // http://wiki.audacityteam.org/wiki/Proposal_Timer_Record_Improvements. + // Note that this causes a problem for Timer Record wait dialog + // (see TimerRecordDialog::RunWaitDialog()), because it makes it + // impossible to do any editing, even in other open projects, + // while waiting for Timer Record to start -- and then also + // while it's recording, it has a ProgressDialog, so really, + // no editing in any project until Timer Record finishes. + mDisable = new wxWindowDisabler(this); + } + else + { + mTopParent = wxGetTopLevelParent(GetParent()); + mTopParent->Enable(false); + } return true; } @@ -1190,8 +1208,7 @@ bool ProgressDialog::Create(const wxString & title, // // Update the time and, optionally, the message // -int -ProgressDialog::Update(int value, const wxString & message) +int ProgressDialog::Update(int value, const wxString & message) { if (mCancel) { @@ -1203,7 +1220,19 @@ ProgressDialog::Update(int value, const wxString & message) return eProgressStopped; } - SetMessage(message); + wxLongLong_t now = wxGetLocalTimeMillis().GetValue(); + wxLongLong_t elapsed = now - mStartTime; + + if (elapsed < 500) + { + return eProgressSuccess; + } + + if (mIsTransparent) + { + SetTransparent(255); + mIsTransparent = false; + } if (value <= 0) { @@ -1215,16 +1244,10 @@ ProgressDialog::Update(int value, const wxString & message) value = 1000; } - wxLongLong_t now = wxGetLocalTimeMillis().GetValue(); - wxLongLong_t elapsed = now - mStartTime; wxLongLong_t estimate = elapsed * 1000ll / value; wxLongLong_t remains = (estimate + mStartTime) - now; - if (!IsShown() && elapsed > 500) - { - Show(true); - wxDialog::Update(); - } + SetMessage(message); if (value != mLastValue) { @@ -1233,7 +1256,7 @@ ProgressDialog::Update(int value, const wxString & message) mLastValue = value; } - // Only update if a full second has passed.or track progress is complete + // Only update if a full second has passed or track progress is complete if ((now - mLastUpdate > 1000) || (value == 1000)) { wxTimeSpan tsElapsed(0, 0, 0, elapsed); @@ -1270,8 +1293,7 @@ ProgressDialog::Update(int value, const wxString & message) // // Update the time and, optionally, the message // -int -ProgressDialog::Update(double current, const wxString & message) +int ProgressDialog::Update(double current, const wxString & message) { return Update((int)(current * 1000), message); } @@ -1279,8 +1301,7 @@ ProgressDialog::Update(double current, const wxString & message) // // Update the time and, optionally, the message // -int -ProgressDialog::Update(wxULongLong_t current, wxULongLong_t total, const wxString & message) +int ProgressDialog::Update(wxULongLong_t current, wxULongLong_t total, const wxString & message) { if (total != 0) { @@ -1295,8 +1316,7 @@ ProgressDialog::Update(wxULongLong_t current, wxULongLong_t total, const wxStrin // // Update the time and, optionally, the message // -int -ProgressDialog::Update(wxLongLong current, wxLongLong total, const wxString & message) +int ProgressDialog::Update(wxLongLong current, wxLongLong total, const wxString & message) { if (total.GetValue() != 0) { @@ -1311,8 +1331,7 @@ ProgressDialog::Update(wxLongLong current, wxLongLong total, const wxString & me // // Update the time and, optionally, the message // -int -ProgressDialog::Update(wxLongLong_t current, wxLongLong_t total, const wxString & message) +int ProgressDialog::Update(wxLongLong_t current, wxLongLong_t total, const wxString & message) { if (total != 0) { @@ -1327,8 +1346,7 @@ ProgressDialog::Update(wxLongLong_t current, wxLongLong_t total, const wxString // // Update the time and, optionally, the message // -int -ProgressDialog::Update(int current, int total, const wxString & message) +int ProgressDialog::Update(int current, int total, const wxString & message) { if (total != 0) { @@ -1343,8 +1361,7 @@ ProgressDialog::Update(int current, int total, const wxString & message) // // Update the time and, optionally, the message // -int -ProgressDialog::Update(double current, double total, const wxString & message) +int ProgressDialog::Update(double current, double total, const wxString & message) { if (total != 0) { @@ -1356,12 +1373,10 @@ ProgressDialog::Update(double current, double total, const wxString & message) } } - // // Update the message text // -void -ProgressDialog::SetMessage(const wxString & message) +void ProgressDialog::SetMessage(const wxString & message) { if (!message.IsEmpty()) { @@ -1400,33 +1415,28 @@ ProgressDialog::SetMessage(const wxString & message) SetClientSize(ds); wxDialog::Update(); } - } } -void -ProgressDialog::OnCancel(wxCommandEvent & WXUNUSED(event)) +void ProgressDialog::OnCancel(wxCommandEvent & WXUNUSED(event)) { FindWindowById(wxID_CANCEL, this)->Disable(); mCancel = true; } -void -ProgressDialog::OnStop(wxCommandEvent & WXUNUSED(event)) +void ProgressDialog::OnStop(wxCommandEvent & WXUNUSED(event)) { FindWindowById(wxID_OK, this)->Disable(); mCancel = false; mStop = true; } -void -ProgressDialog::OnCloseWindow(wxCloseEvent & WXUNUSED(event)) +void ProgressDialog::OnCloseWindow(wxCloseEvent & WXUNUSED(event)) { mCancel = true; } -void -ProgressDialog::Beep() +void ProgressDialog::Beep() const { int after; bool should; @@ -1441,10 +1451,12 @@ ProgressDialog::Beep() wxBusyCursor busy; wxSound s; - if (name.IsEmpty()) { + if (name.IsEmpty()) + { s.Create(sizeof(beep), beep); } - else { + else + { s.Create(name); } @@ -1476,28 +1488,24 @@ int TimerProgressDialog::Update(const wxString & message /*= wxEmptyString*/) return eProgressStopped; } - // Copied from wx 3.0.2 generic progress dialog - // - // we have to yield because not only we want to update the display but - // also to process the clicks on the cancel and skip buttons - // NOTE: using YieldFor() this call shouldn't give re-entrancy problems - // for event handlers not interested to UI/user-input events. - wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT); - - wxDialog::Update(); + wxLongLong_t now = wxGetLocalTimeMillis().GetValue(); + wxLongLong_t elapsed = now - mStartTime; + + if (elapsed < 500) + { + return eProgressSuccess; + } + + if (mIsTransparent) + { + SetTransparent(255); + mIsTransparent = false; + } SetMessage(message); - wxLongLong_t now = wxGetLocalTimeMillis().GetValue(); - wxLongLong_t elapsed = now - mStartTime; wxLongLong_t remains = mStartTime + mDuration - now; - if (!IsShown() && elapsed > 500) - { - Show(true); - wxDialog::Update(); - } - int nGaugeValue = (1000 * elapsed) / mDuration; // range = [0,1000] // Running in TimerRecordDialog::RunWaitDialog(), for some unknown reason, // nGaugeValue here is often a little over 1000. @@ -1528,10 +1536,16 @@ int TimerProgressDialog::Update(const wxString & message /*= wxEmptyString*/) // Copied from wx 3.0.2 generic progress dialog // - // allow the window to repaint: - // NOTE: since we yield only for UI events with this call, there - // should be no side-effects - wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI); + // we have to yield because not only we want to update the display but + // also to process the clicks on the cancel and skip buttons + // NOTE: using YieldFor() this call shouldn't give re-entrancy problems + // for event handlers not interested to UI/user-input events. + // + // LL: Added timer category to prevent extreme delays when processing effects + // (and probably other things). I do not yet know why this happens and + // I'm not too keen on having timer events processed here, but you do + // what you have to do. + wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI | wxEVT_CATEGORY_USER_INPUT | wxEVT_CATEGORY_TIMER); return eProgressSuccess; } diff --git a/src/widgets/ProgressDialog.h b/src/widgets/ProgressDialog.h index 9d430cb02..886b9b426 100644 --- a/src/widgets/ProgressDialog.h +++ b/src/widgets/ProgressDialog.h @@ -40,8 +40,9 @@ enum ProgressDialogFlags pdlgEmptyFlags = 0x00000000, pdlgHideStopButton = 0x00000001, pdlgHideCancelButton = 0x00000002, + pdlgAppModal = 0x00000004, - pdlgDefaultFlags = pdlgEmptyFlags + pdlgDefaultFlags = pdlgAppModal }; //////////////////////////////////////////////////////////// @@ -53,9 +54,9 @@ class AUDACITY_DLL_API ProgressDialog:public wxDialog public: ProgressDialog(); ProgressDialog(const wxString & title, const wxString & message = wxEmptyString, ProgressDialogFlags flags = pdlgDefaultFlags); - ~ProgressDialog(); + virtual ~ProgressDialog(); - bool Create(const wxString & title, const wxString & message = wxEmptyString, ProgressDialogFlags flags = pdlgDefaultFlags); + virtual bool Create(const wxString & title, const wxString & message = wxEmptyString, ProgressDialogFlags flags = pdlgDefaultFlags); int Update(int value, const wxString & message = wxEmptyString); int Update(double current, const wxString & message = wxEmptyString); @@ -78,19 +79,23 @@ protected: bool mCancel; bool mStop; + bool mIsTransparent; + private: void Init(); void OnCancel(wxCommandEvent & e); void OnStop(wxCommandEvent & e); void OnCloseWindow(wxCloseEvent & e); - void Beep(); + void Beep() const; private: // This guarantees we have an active event loop...possible during OnInit() wxEventLoopGuarantor mLoop; - wxStaticText *mMessage; + wxWindow *mTopParent; wxWindowDisabler *mDisable; + + wxStaticText *mMessage; int mLastW; int mLastH; @@ -99,14 +104,14 @@ private: class AUDACITY_DLL_API TimerProgressDialog : public ProgressDialog { - public: +public: TimerProgressDialog(const wxLongLong_t duration, - const wxString & title, - const wxString & message = wxEmptyString, - ProgressDialogFlags flags = pdlgDefaultFlags); + const wxString & title, + const wxString & message = wxEmptyString, + ProgressDialogFlags flags = pdlgEmptyFlags); int Update(const wxString & message = wxEmptyString); - protected: +protected: wxLongLong_t mDuration; };