From 56b1f2d2cb0e5eafed714358c290e715147e06e8 Mon Sep 17 00:00:00 2001 From: tip2tail Date: Tue, 30 Aug 2016 20:29:10 +0100 Subject: [PATCH] Bug 1403 - Message can now be displayed in multiple columns Uses 'End-of-Transmission-Block' character to mark the column split(s) and is defined as a static constant for ease of use. --- src/TimerRecordDialog.cpp | 97 ++++++++++------- src/widgets/ProgressDialog.cpp | 188 ++++++++++++++++----------------- src/widgets/ProgressDialog.h | 5 + 3 files changed, 155 insertions(+), 135 deletions(-) diff --git a/src/TimerRecordDialog.cpp b/src/TimerRecordDialog.cpp index 81f91252b..3e0a0f614 100644 --- a/src/TimerRecordDialog.cpp +++ b/src/TimerRecordDialog.cpp @@ -550,19 +550,26 @@ int TimerRecordDialog::RunWaitDialog() bool bIsRecording = true; wxString sPostAction = m_pTimerAfterCompleteChoiceCtrl->GetString(m_pTimerAfterCompleteChoiceCtrl->GetSelection()); - wxString strMsg; - strMsg.Printf(_("Recording start:\t\t\t%s\n") + - _("Duration:\t\t\t%s\n") + - _("Recording end:\t\t\t%s\n\n") + - _("Automatic Save enabled:\t\t%s\n") + - _("Automatic Export enabled:\t\t%s\n") + - _("Action after Timer Recording:\t%s"), - GetDisplayDate(m_DateTime_Start).c_str(), - m_TimeSpan_Duration.Format(), - GetDisplayDate(m_DateTime_End).c_str(), - (m_bAutoSaveEnabled ? _("Yes") : _("No")), - (m_bAutoExportEnabled ? _("Yes") : _("No")), - sPostAction); + + // Two column layout. Line spacing must match for both columns. + // First column + wxString strMsg = wxString::Format(_("Recording start:\n") + + _("Duration:\n") + + _("Recording end:\n\n") + + _("Automatic Save enabled:\n") + + _("Automatic Export enabled:\n") + + _("Action after Timer Recording:")); + + strMsg += ProgressDialog::ColoumnSplitMarker; + + // Second column + strMsg += wxString::Format(wxT("%s\n%s\n%s\n\n%s\n%s\n%s"), + GetDisplayDate(m_DateTime_Start).c_str(), + m_TimeSpan_Duration.Format(), + GetDisplayDate(m_DateTime_End).c_str(), + (m_bAutoSaveEnabled ? _("Yes") : _("No")), + (m_bAutoExportEnabled ? _("Yes") : _("No")), + sPostAction); TimerProgressDialog progress(m_TimeSpan_Duration.GetMilliseconds().GetValue(), @@ -833,7 +840,10 @@ void TimerRecordDialog::PopulateOrExchange(ShuttleGui& S) safenew wxDatePickerCtrl(this, // wxWindow *parent, ID_DATEPICKER_END, // wxWindowID id, m_DateTime_End); // const wxDateTime& dt = wxDefaultDateTime, - // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDP_DEFAULT | wxDP_SHOWCENTURY, const wxValidator& validator = wxDefaultValidator, const wxString& name = "datectrl") + // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, + // long style = wxDP_DEFAULT | wxDP_SHOWCENTURY, + // const wxValidator& validator = wxDefaultValidator, + // const wxString& name = "datectrl") m_pDatePickerCtrl_End->SetRange(m_DateTime_Start, wxInvalidDateTime); // No backdating. m_pDatePickerCtrl_End->SetName(_("End Date")); #if wxUSE_ACCESSIBILITY @@ -1019,21 +1029,25 @@ int TimerRecordDialog::WaitForStart() // MY: The Waiting For Start dialog now shows what actions will occur after recording has completed wxString sPostAction = m_pTimerAfterCompleteChoiceCtrl->GetString(m_pTimerAfterCompleteChoiceCtrl->GetSelection()); - /* i18n-hint: Time specifications like "Sunday 28th October 2007 15:16:17 GMT" - * but hopefully translated by wxwidgets will be inserted into this */ - wxString strMsg; - strMsg.Printf(_("Waiting to start recording at:\t%s\n") + - _("Recording duration:\t\t%s\n") + - _("Scheduled to stop at:\t\t%s\n\n") + - _("Automatic Save enabled:\t\t%s\n") + - _("Automatic Export enabled:\t\t%s\n") + - _("Action after Timer Recording:\t%s"), - GetDisplayDate(m_DateTime_Start).c_str(), - m_TimeSpan_Duration.Format(), - GetDisplayDate(m_DateTime_End).c_str(), - (m_bAutoSaveEnabled ? _("Yes") : _("No")), - (m_bAutoExportEnabled ? _("Yes") : _("No")), - sPostAction); + // Two column layout. Line spacing must match for both columns. + // First column + wxString strMsg = wxString::Format(_("Waiting to start recording at:\n") + + _("Recording duration:\n") + + _("Scheduled to stop at:\n\n") + + _("Automatic Save enabled:\n") + + _("Automatic Export enabled:\n") + + _("Action after Timer Recording:")); + + strMsg += ProgressDialog::ColoumnSplitMarker; + + // Second column + strMsg += wxString::Format(wxT("%s\n%s\n%s\n\n%s\n%s\n%s"), + GetDisplayDate(m_DateTime_Start).c_str(), + m_TimeSpan_Duration.Format(), + GetDisplayDate(m_DateTime_End).c_str(), + (m_bAutoSaveEnabled ? _("Yes") : _("No")), + (m_bAutoExportEnabled ? _("Yes") : _("No")), + sPostAction); wxDateTime startWait_DateTime = wxDateTime::UNow(); wxTimeSpan waitDuration = m_DateTime_Start - startWait_DateTime; @@ -1060,15 +1074,20 @@ int TimerRecordDialog::PreActionDelay(int iActionIndex, TimerRecordCompletedActi wxString sCountdownLabel; sCountdownLabel.Printf("%s in:", sAction); - // Build a clearer message... - wxString sMessage; - sMessage.Printf(_("Timer Recording completed.\n\n") + - _("Recording Saved:\t\t\t%s\n") + - _("Recording Exported:\t\t%s\n") + - _("Action after Timer Recording:\t%s"), - ((eCompletedActions & TR_ACTION_SAVED) ? _("Yes") : _("No")), - ((eCompletedActions & TR_ACTION_EXPORTED) ? _("Yes") : _("No")), - sAction); + // Two column layout. Line spacing must match for both columns. + // First column + wxString strMsg = wxString::Format(_("Timer Recording completed.\n\n") + + _("Recording Saved:\n") + + _("Recording Exported:\n") + + _("Action after Timer Recording:")); + + strMsg += ProgressDialog::ColoumnSplitMarker; + + // Second column + strMsg += wxString::Format(wxT("\n\n%s\n%s\n%s"), + ((eCompletedActions & TR_ACTION_SAVED) ? _("Yes") : _("No")), + ((eCompletedActions & TR_ACTION_EXPORTED) ? _("Yes") : _("No")), + sAction); wxDateTime dtNow = wxDateTime::UNow(); wxTimeSpan tsWait = wxTimeSpan(0, 1, 0, 0); @@ -1076,7 +1095,7 @@ int TimerRecordDialog::PreActionDelay(int iActionIndex, TimerRecordCompletedActi TimerProgressDialog dlgAction(tsWait.GetMilliseconds().GetValue(), _("Audacity Timer Record - Waiting"), - sMessage, + strMsg, pdlgHideStopButton | pdlgHideElapsedTime, sCountdownLabel); diff --git a/src/widgets/ProgressDialog.cpp b/src/widgets/ProgressDialog.cpp index d59268ef3..760c9b4a7 100644 --- a/src/widgets/ProgressDialog.cpp +++ b/src/widgets/ProgressDialog.cpp @@ -29,6 +29,8 @@ #include "../Audacity.h" #include "../MemoryX.h" +#include + #include #include #include @@ -1066,6 +1068,27 @@ void ProgressDialog::Init() #endif } +// Add a new text column each time this is called. +void ProgressDialog::AddMessageAsColumn(wxBoxSizer * pSizer, const wxString & sText) { + + // Assuming that we don't want empty columns, bail out if there is no text. + if (sText.IsEmpty()) + { + return; + } + + // Create a statictext object and add to the sizer + wxStaticText* oText = safenew wxStaticText(this, + wxID_ANY, + sText, + wxDefaultPosition, + wxDefaultSize, + wxALIGN_LEFT); + oText->SetName(sText); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) + + pSizer->Add(oText, 1, wxEXPAND | wxALL, 5); +} + bool ProgressDialog::Create(const wxString & title, const wxString & message /* = wxEmptyString */, int flags /* = pdlgDefaultFlags */, @@ -1089,70 +1112,63 @@ bool ProgressDialog::Create(const wxString & title, { return false; } - SetName(GetTitle()); - wxWindow *w; - wxSize ds; + SetName(GetTitle()); // This was added for NVDA screen reader and may now be redundant. + SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT); // Ancient code. Is it still required? - SetExtraStyle(GetExtraStyle() | wxWS_EX_TRANSIENT); - - wxFlexGridSizer *g; - wxBoxSizer *h; { - auto v = std::make_unique(wxVERTICAL); + wxWindow *window; + wxArrayString arMessages(wxSplit(message, ProgressDialog::ColoumnSplitMarker)); - mMessage = safenew wxStaticText(this, - wxID_ANY, - message, - wxDefaultPosition, - wxDefaultSize, - wxALIGN_LEFT); - mMessage->SetName(message); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) - v->Add(mMessage, 1, wxEXPAND | wxALL, 10); - ds.y += mMessage->GetSize().y + 20; + // There may be more than one column, so create a BoxSizer container + auto uColSizer = std::make_unique(wxHORIZONTAL); + //wxBoxSizer * pColSizer = safenew wxBoxSizer(wxHORIZONTAL); + auto colSizer = uColSizer.get(); + + for (size_t column = 0; column < arMessages.GetCount(); column++) { + AddMessageAsColumn(colSizer, arMessages[column]); + } + + // and put message column(s) into a main vertical sizer. + auto vertSizer = std::make_unique(wxVERTICAL); + vertSizer->Add(uColSizer.release(), 1, wxEXPAND | wxALL, 10); - // - // - // mGauge = safenew wxGauge(this, - wxID_ANY, - 1000, - wxDefaultPosition, - wxDefaultSize, - wxGA_HORIZONTAL); - v->Add(mGauge, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10); - ds.y += mGauge->GetSize().y + 10; + wxID_ANY, + 1000, + wxDefaultPosition, + wxDefaultSize, + wxGA_HORIZONTAL); + vertSizer->Add(mGauge, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10); - // - // - // { - auto ug = std::make_unique(2, 2, 10, 10); - // MY: Only one row if we are not going to show the elapsed time + auto uGridSizer = std::make_unique(2, 2, 10, 10); + // Only one row if we are not going to show the elapsed time if (m_bShowElapsedTime == false) { - ug = std::make_unique(1, 2, 10, 10); + uGridSizer = std::make_unique(1, 2, 10, 10); } - g = ug.get(); + auto gridSizer = uGridSizer.get(); if (m_bShowElapsedTime) { - w = safenew wxStaticText(this, - wxID_ANY, - _("Elapsed Time:"), - wxDefaultPosition, - wxDefaultSize, - wxALIGN_RIGHT); - w->SetName(w->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) - g->Add(w, 0, wxALIGN_RIGHT); + window = safenew wxStaticText(this, + wxID_ANY, + _("Elapsed Time:"), + wxDefaultPosition, + wxDefaultSize, + wxALIGN_RIGHT); + + window->SetName(window->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) + gridSizer->Add(window, 0, wxALIGN_RIGHT); mElapsed = safenew wxStaticText(this, - wxID_ANY, - wxT("00:00:00"), - wxDefaultPosition, - wxDefaultSize, - wxALIGN_LEFT); + wxID_ANY, + wxT("00:00:00"), + wxDefaultPosition, + wxDefaultSize, + wxALIGN_LEFT); + mElapsed->SetName(mElapsed->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) - g->Add(mElapsed, 0, wxALIGN_LEFT); - ds.y += mElapsed->GetSize().y + 10; + gridSizer->Add(mElapsed, 0, wxALIGN_LEFT); } // Customised "Remaining" label text @@ -1161,73 +1177,53 @@ bool ProgressDialog::Create(const wxString & title, sRemainingText = _("Remaining Time:"); } - // - // - // - w = safenew wxStaticText(this, - wxID_ANY, - sRemainingText, - wxDefaultPosition, - wxDefaultSize, - wxALIGN_RIGHT); - w->SetName(w->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) - g->Add(w, 0, wxALIGN_RIGHT); + window = safenew wxStaticText(this, + wxID_ANY, + sRemainingText, + wxDefaultPosition, + wxDefaultSize, + wxALIGN_RIGHT); + window->SetName(window->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) + gridSizer->Add(window, 0, wxALIGN_RIGHT); mRemaining = safenew wxStaticText(this, - wxID_ANY, - wxT("00:00:00"), - wxDefaultPosition, - wxDefaultSize, - wxALIGN_LEFT); + wxID_ANY, + wxT("00:00:00"), + wxDefaultPosition, + wxDefaultSize, + wxALIGN_LEFT); mRemaining->SetName(mRemaining->GetLabel()); // fix for bug 577 (NVDA/Narrator screen readers do not read static text in dialogs) - g->Add(mRemaining, 0, wxALIGN_LEFT); + gridSizer->Add(mRemaining, 0, wxALIGN_LEFT); - v->Add(ug.release(), 0, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxBOTTOM, 10); + vertSizer->Add(uGridSizer.release(), 0, wxALIGN_CENTER | wxLEFT | wxRIGHT | wxBOTTOM, 10); } - ds.y += mRemaining->GetSize().y + 10; - { - auto uh = std::make_unique(wxHORIZONTAL); - h = uh.get(); + auto uButtonBar = std::make_unique(wxHORIZONTAL); + auto buttonBarSizer = uButtonBar.get(); - if (!(flags & pdlgHideStopButton)) - { - w = safenew wxButton(this, wxID_OK, _("Stop")); - h->Add(w, 0, wxRIGHT, 10); + if (!(flags & pdlgHideStopButton)) { + window = safenew wxButton(this, wxID_OK, _("Stop")); + buttonBarSizer->Add(window, 0, wxRIGHT, 10); } - - if (!(flags & pdlgHideCancelButton)) - { - w = safenew wxButton(this, wxID_CANCEL, _("Cancel")); - h->Add(w, 0, wxRIGHT, 10); + if (!(flags & pdlgHideCancelButton)) { + window = safenew wxButton(this, wxID_CANCEL, _("Cancel")); + buttonBarSizer->Add(window, 0, wxRIGHT, 10); } - - v->Add(uh.release(), 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10); + vertSizer->Add(uButtonBar.release(), 0, wxALIGN_RIGHT | wxRIGHT | wxBOTTOM, 10); } - SetSizer(v.release()); + SetSizerAndFit(vertSizer.release()); } Layout(); - ds.x = wxMax(g->GetSize().x, h->GetSize().x) + 10; - ds.y += w->GetSize().y + 10; - wxClientDC dc(this); dc.GetMultiLineTextExtent(message, &mLastW, &mLastH); - // MY: Add a little bit more width when we have TABs to stop words wrapping + // Add a little bit more width when we have TABs to stop words wrapping int iTabFreq = wxMax((message.Freq('\t') - 1), 0); mLastW = mLastW + (iTabFreq * 8); -#if defined(__WXMAC__) - mMessage->SetMinSize(wxSize(mLastW, mLastH)); -#endif - - // The 300 really isn't needed, but it keeps it at a decent width. - ds.x = wxMax(wxMax(wxMax(ds.x, mLastW) + 20, wxMax(ds.y, mLastH)), 300); - SetClientSize(ds); - Centre(wxCENTER_FRAME | wxBOTH); mStartTime = wxGetLocalTimeMillis().GetValue(); @@ -1551,7 +1547,7 @@ void ProgressDialog::Beep() const } } -// MY: Confirm action taken by user. +// Confirm action taken by user. // Returns TRUE if the user confirms Yes bool ProgressDialog::ConfirmAction(const wxString & sPrompt, const wxString & sTitle, diff --git a/src/widgets/ProgressDialog.h b/src/widgets/ProgressDialog.h index f4c2b01c3..933ec590f 100644 --- a/src/widgets/ProgressDialog.h +++ b/src/widgets/ProgressDialog.h @@ -78,6 +78,9 @@ public: int Update(int current, int total, const wxString & message = wxEmptyString); void SetMessage(const wxString & message); + // 'ETB' character to indicate a new column in the message text. + static const wxChar ColoumnSplitMarker = (char)23; + protected: wxWindow *mHadFocus; @@ -110,6 +113,8 @@ private: const wxString & sTitle, int iButtonID = -1); + void AddMessageAsColumn(wxBoxSizer * pSizer, const wxString & sText); + private: // This guarantees we have an active event loop...possible during OnInit() wxEventLoopGuarantor mLoop;