Merge branch 'progress-dialog-fixes'
Make native MSW wxProgressDialog much more usable and some minor improvements to the generic version.
This commit is contained in:
@@ -223,6 +223,7 @@ wxMSW:
|
|||||||
- Fix updating radio groups when non-radio item is inserted to wxMenu.
|
- Fix updating radio groups when non-radio item is inserted to wxMenu.
|
||||||
- Fix autoselecting the contents of wxTextCtrl with wxWANTS_CHARS style.
|
- Fix autoselecting the contents of wxTextCtrl with wxWANTS_CHARS style.
|
||||||
- Implement SetIcon(), SetPosition(), GetPosition() for native wxProgressDialog.
|
- Implement SetIcon(), SetPosition(), GetPosition() for native wxProgressDialog.
|
||||||
|
- Fix focus-related problems when using native wxProgressDialog.
|
||||||
- Fix crash when reparenting the currently focused window to another TLW.
|
- Fix crash when reparenting the currently focused window to another TLW.
|
||||||
|
|
||||||
wxOSX:
|
wxOSX:
|
||||||
|
@@ -12,6 +12,7 @@
|
|||||||
#define __PROGDLGH_G__
|
#define __PROGDLGH_G__
|
||||||
|
|
||||||
#include "wx/dialog.h"
|
#include "wx/dialog.h"
|
||||||
|
#include "wx/weakref.h"
|
||||||
|
|
||||||
class WXDLLIMPEXP_FWD_CORE wxButton;
|
class WXDLLIMPEXP_FWD_CORE wxButton;
|
||||||
class WXDLLIMPEXP_FWD_CORE wxEventLoop;
|
class WXDLLIMPEXP_FWD_CORE wxEventLoop;
|
||||||
@@ -43,18 +44,18 @@ public:
|
|||||||
virtual bool Update(int value, const wxString& newmsg = wxEmptyString, bool *skip = NULL);
|
virtual bool Update(int value, const wxString& newmsg = wxEmptyString, bool *skip = NULL);
|
||||||
virtual bool Pulse(const wxString& newmsg = wxEmptyString, bool *skip = NULL);
|
virtual bool Pulse(const wxString& newmsg = wxEmptyString, bool *skip = NULL);
|
||||||
|
|
||||||
void Resume();
|
virtual void Resume();
|
||||||
|
|
||||||
int GetValue() const;
|
virtual int GetValue() const;
|
||||||
int GetRange() const;
|
virtual int GetRange() const;
|
||||||
wxString GetMessage() const;
|
virtual wxString GetMessage() const;
|
||||||
|
|
||||||
void SetRange(int maximum);
|
virtual void SetRange(int maximum);
|
||||||
|
|
||||||
// Return whether "Cancel" or "Skip" button was pressed, always return
|
// Return whether "Cancel" or "Skip" button was pressed, always return
|
||||||
// false if the corresponding button is not shown.
|
// false if the corresponding button is not shown.
|
||||||
bool WasCancelled() const;
|
virtual bool WasCancelled() const;
|
||||||
bool WasSkipped() const;
|
virtual bool WasSkipped() const;
|
||||||
|
|
||||||
// Must provide overload to avoid hiding it (and warnings about it)
|
// Must provide overload to avoid hiding it (and warnings about it)
|
||||||
virtual void Update() wxOVERRIDE { wxDialog::Update(); }
|
virtual void Update() wxOVERRIDE { wxDialog::Update(); }
|
||||||
@@ -104,6 +105,9 @@ protected:
|
|||||||
// Converts seconds to HH:mm:ss format.
|
// Converts seconds to HH:mm:ss format.
|
||||||
static wxString GetFormattedTime(unsigned long timeInSec);
|
static wxString GetFormattedTime(unsigned long timeInSec);
|
||||||
|
|
||||||
|
// Create a new event loop if there is no currently running one.
|
||||||
|
void EnsureActiveEventLoopExists();
|
||||||
|
|
||||||
// callback for optional abort button
|
// callback for optional abort button
|
||||||
void OnCancel(wxCommandEvent&);
|
void OnCancel(wxCommandEvent&);
|
||||||
|
|
||||||
@@ -120,8 +124,8 @@ protected:
|
|||||||
// the dialog was shown
|
// the dialog was shown
|
||||||
void ReenableOtherWindows();
|
void ReenableOtherWindows();
|
||||||
|
|
||||||
// Set the top level parent we store from the parent window provided when
|
// Store the parent window as wxWindow::m_parent and also set the top level
|
||||||
// creating the dialog.
|
// parent reference we store in this class itself.
|
||||||
void SetTopParent(wxWindow* parent);
|
void SetTopParent(wxWindow* parent);
|
||||||
|
|
||||||
// return the top level parent window of this dialog (may be NULL)
|
// return the top level parent window of this dialog (may be NULL)
|
||||||
@@ -183,8 +187,9 @@ private:
|
|||||||
*m_estimated,
|
*m_estimated,
|
||||||
*m_remaining;
|
*m_remaining;
|
||||||
|
|
||||||
// parent top level window (may be NULL)
|
// Reference to the parent top level window, automatically becomes NULL if
|
||||||
wxWindow *m_parentTop;
|
// it it is destroyed and could be always NULL if it's not given at all.
|
||||||
|
wxWindowRef m_parentTop;
|
||||||
|
|
||||||
// Progress dialog styles: this is not the same as m_windowStyle because
|
// Progress dialog styles: this is not the same as m_windowStyle because
|
||||||
// wxPD_XXX constants clash with the existing TLW styles so to be sure we
|
// wxPD_XXX constants clash with the existing TLW styles so to be sure we
|
||||||
|
@@ -26,17 +26,17 @@ public:
|
|||||||
virtual bool Update(int value, const wxString& newmsg = wxEmptyString, bool *skip = NULL) wxOVERRIDE;
|
virtual bool Update(int value, const wxString& newmsg = wxEmptyString, bool *skip = NULL) wxOVERRIDE;
|
||||||
virtual bool Pulse(const wxString& newmsg = wxEmptyString, bool *skip = NULL) wxOVERRIDE;
|
virtual bool Pulse(const wxString& newmsg = wxEmptyString, bool *skip = NULL) wxOVERRIDE;
|
||||||
|
|
||||||
void Resume();
|
virtual void Resume() wxOVERRIDE;
|
||||||
|
|
||||||
int GetValue() const;
|
virtual int GetValue() const wxOVERRIDE;
|
||||||
wxString GetMessage() const;
|
virtual wxString GetMessage() const wxOVERRIDE;
|
||||||
|
|
||||||
void SetRange(int maximum);
|
virtual void SetRange(int maximum) wxOVERRIDE;
|
||||||
|
|
||||||
// Return whether "Cancel" or "Skip" button was pressed, always return
|
// Return whether "Cancel" or "Skip" button was pressed, always return
|
||||||
// false if the corresponding button is not shown.
|
// false if the corresponding button is not shown.
|
||||||
bool WasSkipped() const;
|
virtual bool WasSkipped() const wxOVERRIDE;
|
||||||
bool WasCancelled() const;
|
virtual bool WasCancelled() const wxOVERRIDE;
|
||||||
|
|
||||||
virtual void SetTitle(const wxString& title) wxOVERRIDE;
|
virtual void SetTitle(const wxString& title) wxOVERRIDE;
|
||||||
virtual wxString GetTitle() const wxOVERRIDE;
|
virtual wxString GetTitle() const wxOVERRIDE;
|
||||||
@@ -44,6 +44,8 @@ public:
|
|||||||
virtual void SetIcons(const wxIconBundle& icons) wxOVERRIDE;
|
virtual void SetIcons(const wxIconBundle& icons) wxOVERRIDE;
|
||||||
virtual void DoMoveWindow(int x, int y, int width, int height) wxOVERRIDE;
|
virtual void DoMoveWindow(int x, int y, int width, int height) wxOVERRIDE;
|
||||||
virtual void DoGetPosition(int *x, int *y) const wxOVERRIDE;
|
virtual void DoGetPosition(int *x, int *y) const wxOVERRIDE;
|
||||||
|
virtual void DoGetSize(int *width, int *height) const wxOVERRIDE;
|
||||||
|
virtual void Fit() wxOVERRIDE;
|
||||||
|
|
||||||
virtual bool Show( bool show = true ) wxOVERRIDE;
|
virtual bool Show( bool show = true ) wxOVERRIDE;
|
||||||
|
|
||||||
@@ -53,15 +55,24 @@ public:
|
|||||||
virtual WXWidget GetHandle() const wxOVERRIDE;
|
virtual WXWidget GetHandle() const wxOVERRIDE;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Performs common routines to Update() and Pulse(). Requires the
|
// Common part of Update() and Pulse().
|
||||||
// shared object to have been entered.
|
//
|
||||||
|
// Returns false if the user requested cancelling the dialog.
|
||||||
bool DoNativeBeforeUpdate(bool *skip);
|
bool DoNativeBeforeUpdate(bool *skip);
|
||||||
|
|
||||||
|
// Dispatch the pending events to let the windows to update, just as the
|
||||||
|
// generic version does. This is done as part of DoNativeBeforeUpdate().
|
||||||
|
void DispatchEvents();
|
||||||
|
|
||||||
// Updates the various timing informations for both determinate
|
// Updates the various timing informations for both determinate
|
||||||
// and indeterminate modes. Requires the shared object to have
|
// and indeterminate modes. Requires the shared object to have
|
||||||
// been entered.
|
// been entered.
|
||||||
void UpdateExpandedInformation(int value);
|
void UpdateExpandedInformation(int value);
|
||||||
|
|
||||||
|
// Get the task dialog geometry when using the native dialog.
|
||||||
|
wxRect GetTaskDialogRect() const;
|
||||||
|
|
||||||
|
|
||||||
wxProgressDialogTaskRunner *m_taskDialogRunner;
|
wxProgressDialogTaskRunner *m_taskDialogRunner;
|
||||||
|
|
||||||
wxProgressDialogSharedData *m_sharedData;
|
wxProgressDialogSharedData *m_sharedData;
|
||||||
|
@@ -90,6 +90,9 @@ public:
|
|||||||
// NULL if getting the system menu failed.
|
// NULL if getting the system menu failed.
|
||||||
wxMenu *MSWGetSystemMenu() const;
|
wxMenu *MSWGetSystemMenu() const;
|
||||||
|
|
||||||
|
// Enable or disable the close button of the specified window.
|
||||||
|
static bool MSWEnableCloseButton(WXHWND hwnd, bool enable = true);
|
||||||
|
|
||||||
|
|
||||||
// implementation from now on
|
// implementation from now on
|
||||||
// --------------------------
|
// --------------------------
|
||||||
|
@@ -33,6 +33,26 @@
|
|||||||
wxProgressDialog in a multi-threaded application you should be sure to use
|
wxProgressDialog in a multi-threaded application you should be sure to use
|
||||||
wxThreadEvent for your inter-threads communications).
|
wxThreadEvent for your inter-threads communications).
|
||||||
|
|
||||||
|
Although wxProgressDialog is not really modal, it should be created on the
|
||||||
|
stack, and not the heap, as other modal dialogs, e.g. use it like this:
|
||||||
|
@code
|
||||||
|
void MyFrame::SomeFunc()
|
||||||
|
{
|
||||||
|
wxProgressDialog dialog(...);
|
||||||
|
for ( int i = 0; i < 100; ++i ) {
|
||||||
|
if ( !dialog.Update(i)) {
|
||||||
|
// Cancelled by user.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
... do something time-consuming (but not too much) ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
Note that this becomes even more important if the dialog is instantiated
|
||||||
|
during the program initialization, e.g. from wxApp::OnInit(): the dialog
|
||||||
|
must be destroyed before the main event loop is started in this case.
|
||||||
|
|
||||||
@beginStyleTable
|
@beginStyleTable
|
||||||
@style{wxPD_APP_MODAL}
|
@style{wxPD_APP_MODAL}
|
||||||
Make the progress dialog modal. If this flag is not given, it is
|
Make the progress dialog modal. If this flag is not given, it is
|
||||||
@@ -192,9 +212,19 @@ public:
|
|||||||
for the user to dismiss it, meaning that this function does not return
|
for the user to dismiss it, meaning that this function does not return
|
||||||
until this happens.
|
until this happens.
|
||||||
|
|
||||||
Notice that you may want to call Fit() to change the dialog size to
|
Notice that if @a newmsg is longer than the currently shown message,
|
||||||
conform to the length of the new message if desired. The dialog does
|
the dialog will be automatically made wider to account for it. However
|
||||||
not do this automatically.
|
if the new message is shorter than the previous one, the dialog doesn't
|
||||||
|
shrink back to avoid constant resizes if the message is changed often.
|
||||||
|
To do this and fit the dialog to its current contents you may call
|
||||||
|
Fit() explicitly. However the native MSW implementation of this class
|
||||||
|
does make the dialog shorter if the new text has fewer lines of text
|
||||||
|
than the old one, so it is recommended to keep the number of lines of
|
||||||
|
text constant in order to avoid jarring dialog size changes. You may
|
||||||
|
also want to make the initial message, specified when creating the
|
||||||
|
dialog, wide enough to avoid having to resize the dialog later, e.g. by
|
||||||
|
appending a long string of unbreakable spaces (@c wxString(L'\u00a0',
|
||||||
|
100)) to it.
|
||||||
|
|
||||||
@param value
|
@param value
|
||||||
The new value of the progress meter. It should be less than or equal to
|
The new value of the progress meter. It should be less than or equal to
|
||||||
|
@@ -233,6 +233,9 @@ wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
|
|||||||
|
|
||||||
#if wxUSE_PROGRESSDLG
|
#if wxUSE_PROGRESSDLG
|
||||||
EVT_MENU(DIALOGS_PROGRESS, MyFrame::ShowProgress)
|
EVT_MENU(DIALOGS_PROGRESS, MyFrame::ShowProgress)
|
||||||
|
#ifdef wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
|
EVT_MENU(DIALOGS_PROGRESS_GENERIC, MyFrame::ShowProgressGeneric)
|
||||||
|
#endif // wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
#endif // wxUSE_PROGRESSDLG
|
#endif // wxUSE_PROGRESSDLG
|
||||||
|
|
||||||
EVT_MENU(DIALOGS_APP_PROGRESS, MyFrame::ShowAppProgress)
|
EVT_MENU(DIALOGS_APP_PROGRESS, MyFrame::ShowAppProgress)
|
||||||
@@ -349,7 +352,25 @@ bool MyApp::OnInit()
|
|||||||
);
|
);
|
||||||
for ( int i = 0; i <= PROGRESS_COUNT; i++ )
|
for ( int i = 0; i <= PROGRESS_COUNT; i++ )
|
||||||
{
|
{
|
||||||
if ( !dlg.Update(i) )
|
wxString msg;
|
||||||
|
switch ( i )
|
||||||
|
{
|
||||||
|
case 15:
|
||||||
|
msg = "And the same dialog but with a very, very, very long"
|
||||||
|
" message, just to test how it appears in this case.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 30:
|
||||||
|
msg = "Back to brevity";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 80:
|
||||||
|
msg = "Back and adjusted";
|
||||||
|
dlg.Fit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !dlg.Update(i, msg) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
wxMilliSleep(50);
|
wxMilliSleep(50);
|
||||||
@@ -490,6 +511,10 @@ bool MyApp::OnInit()
|
|||||||
|
|
||||||
#if wxUSE_PROGRESSDLG
|
#if wxUSE_PROGRESSDLG
|
||||||
info_menu->Append(DIALOGS_PROGRESS, wxT("Pro&gress dialog\tCtrl-G"));
|
info_menu->Append(DIALOGS_PROGRESS, wxT("Pro&gress dialog\tCtrl-G"));
|
||||||
|
#ifdef wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
|
info_menu->Append(DIALOGS_PROGRESS_GENERIC,
|
||||||
|
wxT("Generic progress dialog\tCtrl-Alt-G"));
|
||||||
|
#endif // wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
#endif // wxUSE_PROGRESSDLG
|
#endif // wxUSE_PROGRESSDLG
|
||||||
|
|
||||||
info_menu->Append(DIALOGS_APP_PROGRESS, wxT("&App progress\tShift-Ctrl-G"));
|
info_menu->Append(DIALOGS_APP_PROGRESS, wxT("&App progress\tShift-Ctrl-G"));
|
||||||
@@ -2652,10 +2677,10 @@ void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event) )
|
|||||||
|
|
||||||
#if wxUSE_PROGRESSDLG
|
#if wxUSE_PROGRESSDLG
|
||||||
|
|
||||||
|
static const int max = 100;
|
||||||
|
|
||||||
void MyFrame::ShowProgress( wxCommandEvent& WXUNUSED(event) )
|
void MyFrame::ShowProgress( wxCommandEvent& WXUNUSED(event) )
|
||||||
{
|
{
|
||||||
static const int max = 100;
|
|
||||||
|
|
||||||
wxProgressDialog dialog("Progress dialog example",
|
wxProgressDialog dialog("Progress dialog example",
|
||||||
// "Reserve" enough space for the multiline
|
// "Reserve" enough space for the multiline
|
||||||
// messages below, we'll change it anyhow
|
// messages below, we'll change it anyhow
|
||||||
@@ -2673,6 +2698,30 @@ void MyFrame::ShowProgress( wxCommandEvent& WXUNUSED(event) )
|
|||||||
wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small
|
wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DoShowProgress(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
|
void MyFrame::ShowProgressGeneric( wxCommandEvent& WXUNUSED(event) )
|
||||||
|
{
|
||||||
|
wxGenericProgressDialog dialog("Generic progress dialog example",
|
||||||
|
wxString(' ', 100) + "\n\n\n\n",
|
||||||
|
max,
|
||||||
|
this,
|
||||||
|
wxPD_CAN_ABORT |
|
||||||
|
wxPD_CAN_SKIP |
|
||||||
|
wxPD_APP_MODAL |
|
||||||
|
wxPD_ELAPSED_TIME |
|
||||||
|
wxPD_ESTIMATED_TIME |
|
||||||
|
wxPD_REMAINING_TIME |
|
||||||
|
wxPD_SMOOTH);
|
||||||
|
|
||||||
|
DoShowProgress(dialog);
|
||||||
|
}
|
||||||
|
#endif // wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
|
|
||||||
|
void MyFrame::DoShowProgress(wxGenericProgressDialog& dialog)
|
||||||
|
{
|
||||||
bool cont = true;
|
bool cont = true;
|
||||||
for ( int i = 0; i <= max; i++ )
|
for ( int i = 0; i <= max; i++ )
|
||||||
{
|
{
|
||||||
@@ -2721,8 +2770,8 @@ void MyFrame::ShowProgress( wxCommandEvent& WXUNUSED(event) )
|
|||||||
{
|
{
|
||||||
i += max/4;
|
i += max/4;
|
||||||
|
|
||||||
if ( i >= 100 )
|
if ( i >= max )
|
||||||
i = 99;
|
i = max - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !cont )
|
if ( !cont )
|
||||||
@@ -2736,7 +2785,7 @@ void MyFrame::ShowProgress( wxCommandEvent& WXUNUSED(event) )
|
|||||||
dialog.Resume();
|
dialog.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxMilliSleep(200);
|
wxMilliSleep(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !cont )
|
if ( !cont )
|
||||||
@@ -2768,7 +2817,7 @@ void MyFrame::ShowAppProgress( wxCommandEvent& WXUNUSED(event) )
|
|||||||
{
|
{
|
||||||
progress.SetValue(i);
|
progress.SetValue(i);
|
||||||
|
|
||||||
wxMilliSleep(500);
|
wxMilliSleep(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxLogStatus("Progress finished");
|
wxLogStatus("Progress finished");
|
||||||
|
@@ -452,6 +452,10 @@ public:
|
|||||||
|
|
||||||
#if wxUSE_PROGRESSDLG
|
#if wxUSE_PROGRESSDLG
|
||||||
void ShowProgress(wxCommandEvent& event);
|
void ShowProgress(wxCommandEvent& event);
|
||||||
|
#ifdef wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
|
void ShowProgressGeneric(wxCommandEvent& event);
|
||||||
|
#endif // wxHAS_NATIVE_PROGRESSDIALOG
|
||||||
|
void DoShowProgress(wxGenericProgressDialog& dialog);
|
||||||
#endif // wxUSE_PROGRESSDLG
|
#endif // wxUSE_PROGRESSDLG
|
||||||
void ShowAppProgress(wxCommandEvent& event);
|
void ShowAppProgress(wxCommandEvent& event);
|
||||||
|
|
||||||
@@ -596,6 +600,7 @@ enum
|
|||||||
DIALOGS_ONTOP,
|
DIALOGS_ONTOP,
|
||||||
DIALOGS_MODELESS_BTN,
|
DIALOGS_MODELESS_BTN,
|
||||||
DIALOGS_PROGRESS,
|
DIALOGS_PROGRESS,
|
||||||
|
DIALOGS_PROGRESS_GENERIC,
|
||||||
DIALOGS_APP_PROGRESS,
|
DIALOGS_APP_PROGRESS,
|
||||||
DIALOGS_ABOUTDLG_SIMPLE,
|
DIALOGS_ABOUTDLG_SIMPLE,
|
||||||
DIALOGS_ABOUTDLG_FANCY,
|
DIALOGS_ABOUTDLG_FANCY,
|
||||||
|
@@ -133,6 +133,7 @@ wxGenericProgressDialog::wxGenericProgressDialog(const wxString& title,
|
|||||||
|
|
||||||
void wxGenericProgressDialog::SetTopParent(wxWindow* parent)
|
void wxGenericProgressDialog::SetTopParent(wxWindow* parent)
|
||||||
{
|
{
|
||||||
|
m_parent = parent;
|
||||||
m_parentTop = GetParentForModalDialog(parent, GetWindowStyle());
|
m_parentTop = GetParentForModalDialog(parent, GetWindowStyle());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,13 +145,9 @@ bool wxGenericProgressDialog::Create( const wxString& title,
|
|||||||
{
|
{
|
||||||
SetTopParent(parent);
|
SetTopParent(parent);
|
||||||
|
|
||||||
m_parentTop = wxGetTopLevelParent(parent);
|
|
||||||
m_pdStyle = style;
|
m_pdStyle = style;
|
||||||
|
|
||||||
wxWindow* const
|
if (!wxDialog::Create(m_parentTop, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, GetWindowStyle()))
|
||||||
realParent = GetParentForModalDialog(parent, GetWindowStyle());
|
|
||||||
|
|
||||||
if (!wxDialog::Create(realParent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, GetWindowStyle()))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SetMaximum(maximum);
|
SetMaximum(maximum);
|
||||||
@@ -160,11 +157,7 @@ bool wxGenericProgressDialog::Create( const wxString& title,
|
|||||||
// even if this means we have to start it ourselves (this happens most
|
// even if this means we have to start it ourselves (this happens most
|
||||||
// commonly during the program initialization, e.g. for the progress
|
// commonly during the program initialization, e.g. for the progress
|
||||||
// dialogs shown from overridden wxApp::OnInit()).
|
// dialogs shown from overridden wxApp::OnInit()).
|
||||||
if ( !wxEventLoopBase::GetActive() )
|
EnsureActiveEventLoopExists();
|
||||||
{
|
|
||||||
m_tempEventLoop = new wxEventLoop;
|
|
||||||
wxEventLoop::SetActive(m_tempEventLoop);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
|
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__)
|
||||||
// we have to remove the "Close" button from the title bar then as it is
|
// we have to remove the "Close" button from the title bar then as it is
|
||||||
@@ -363,6 +356,15 @@ wxString wxGenericProgressDialog::GetFormattedTime(unsigned long timeInSec)
|
|||||||
return timeAsHMS;
|
return timeAsHMS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxGenericProgressDialog::EnsureActiveEventLoopExists()
|
||||||
|
{
|
||||||
|
if ( !wxEventLoopBase::GetActive() )
|
||||||
|
{
|
||||||
|
m_tempEventLoop = new wxEventLoop;
|
||||||
|
wxEventLoop::SetActive(m_tempEventLoop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wxStaticText *
|
wxStaticText *
|
||||||
wxGenericProgressDialog::CreateLabel(const wxString& text, wxSizer *sizer)
|
wxGenericProgressDialog::CreateLabel(const wxString& text, wxSizer *sizer)
|
||||||
{
|
{
|
||||||
@@ -695,6 +697,21 @@ wxGenericProgressDialog::~wxGenericProgressDialog()
|
|||||||
|
|
||||||
if ( m_tempEventLoop )
|
if ( m_tempEventLoop )
|
||||||
{
|
{
|
||||||
|
// If another event loop has been installed as active during the life
|
||||||
|
// time of this object, we shouldn't deactivate it, but we also can't
|
||||||
|
// delete our m_tempEventLoop in this case because it risks leaving the
|
||||||
|
// new event loop with a dangling pointer, which it will set back as
|
||||||
|
// the active loop when it exits, resulting in a crash. So we have no
|
||||||
|
// choice but to just leak this pointer then, which is, of course, bad
|
||||||
|
// and usually easily avoidable by just destroying the progress dialog
|
||||||
|
// sooner, so warn the programmer about it.
|
||||||
|
wxCHECK_RET
|
||||||
|
(
|
||||||
|
wxEventLoopBase::GetActive() == m_tempEventLoop,
|
||||||
|
"current event loop must not be changed during "
|
||||||
|
"wxGenericProgressDialog lifetime"
|
||||||
|
);
|
||||||
|
|
||||||
wxEventLoopBase::SetActive(NULL);
|
wxEventLoopBase::SetActive(NULL);
|
||||||
delete m_tempEventLoop;
|
delete m_tempEventLoop;
|
||||||
}
|
}
|
||||||
@@ -765,8 +782,17 @@ void wxGenericProgressDialog::UpdateMessage(const wxString &newmsg)
|
|||||||
{
|
{
|
||||||
if ( !newmsg.empty() && newmsg != m_msg->GetLabel() )
|
if ( !newmsg.empty() && newmsg != m_msg->GetLabel() )
|
||||||
{
|
{
|
||||||
|
const wxSize sizeOld = m_msg->GetSize();
|
||||||
|
|
||||||
m_msg->SetLabel(newmsg);
|
m_msg->SetLabel(newmsg);
|
||||||
|
|
||||||
|
if ( m_msg->GetSize().x > sizeOld.x )
|
||||||
|
{
|
||||||
|
// Resize the dialog to fit its new, longer contents instead of
|
||||||
|
// just truncating it.
|
||||||
|
Fit();
|
||||||
|
}
|
||||||
|
|
||||||
// allow the window to repaint:
|
// allow the window to repaint:
|
||||||
// NOTE: since we yield only for UI events with this call, there
|
// NOTE: since we yield only for UI events with this call, there
|
||||||
// should be no side-effects
|
// should be no side-effects
|
||||||
|
@@ -57,7 +57,6 @@ const int wxSPDD_EXPINFO_CHANGED = 0x0020;
|
|||||||
const int wxSPDD_ENABLE_SKIP = 0x0040;
|
const int wxSPDD_ENABLE_SKIP = 0x0040;
|
||||||
const int wxSPDD_ENABLE_ABORT = 0x0080;
|
const int wxSPDD_ENABLE_ABORT = 0x0080;
|
||||||
const int wxSPDD_DISABLE_SKIP = 0x0100;
|
const int wxSPDD_DISABLE_SKIP = 0x0100;
|
||||||
const int wxSPDD_DISABLE_ABORT = 0x0200;
|
|
||||||
const int wxSPDD_FINISHED = 0x0400;
|
const int wxSPDD_FINISHED = 0x0400;
|
||||||
const int wxSPDD_DESTROYED = 0x0800;
|
const int wxSPDD_DESTROYED = 0x0800;
|
||||||
const int wxSPDD_ICON_CHANGED = 0x1000;
|
const int wxSPDD_ICON_CHANGED = 0x1000;
|
||||||
@@ -81,6 +80,7 @@ public:
|
|||||||
m_value = 0;
|
m_value = 0;
|
||||||
m_progressBarMarquee = false;
|
m_progressBarMarquee = false;
|
||||||
m_skipped = false;
|
m_skipped = false;
|
||||||
|
m_msgChangeElementText = TDM_UPDATE_ELEMENT_TEXT;
|
||||||
m_notifications = 0;
|
m_notifications = 0;
|
||||||
m_parent = NULL;
|
m_parent = NULL;
|
||||||
}
|
}
|
||||||
@@ -105,9 +105,48 @@ public:
|
|||||||
bool m_progressBarMarquee;
|
bool m_progressBarMarquee;
|
||||||
bool m_skipped;
|
bool m_skipped;
|
||||||
|
|
||||||
|
// The task dialog message to use for changing the text of its elements:
|
||||||
|
// it is set to TDM_SET_ELEMENT_TEXT by Fit() to let the dialog adjust
|
||||||
|
// itself to the size of its elements during the next update, but otherwise
|
||||||
|
// TDM_UPDATE_ELEMENT_TEXT is used in order to prevent the dialog from
|
||||||
|
// performing a layout on each update, which is annoying as it can result
|
||||||
|
// in its size constantly changing.
|
||||||
|
int m_msgChangeElementText;
|
||||||
|
|
||||||
// Bit field that indicates fields that have been modified by the
|
// Bit field that indicates fields that have been modified by the
|
||||||
// main thread so the task dialog runner knows what to update.
|
// main thread so the task dialog runner knows what to update.
|
||||||
int m_notifications;
|
int m_notifications;
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function to split a single message, passed via our public API,
|
||||||
|
// into the title and the main content body used by the native dialog.
|
||||||
|
//
|
||||||
|
// Note that it uses m_message and so must be called with m_cs locked.
|
||||||
|
void SplitMessageIntoTitleAndBody(wxString& title, wxString& body) const
|
||||||
|
{
|
||||||
|
title = m_message;
|
||||||
|
|
||||||
|
const size_t posNL = title.find('\n');
|
||||||
|
if ( posNL != wxString::npos )
|
||||||
|
{
|
||||||
|
// There can an extra new line between the first and subsequent
|
||||||
|
// lines to separate them as it looks better with the generic
|
||||||
|
// version -- but in this one, they're already separated by the use
|
||||||
|
// of different dialog elements, so suppress the extra new line.
|
||||||
|
int numNLs = 1;
|
||||||
|
if ( posNL < title.length() - 1 && title[posNL + 1] == '\n' )
|
||||||
|
numNLs++;
|
||||||
|
|
||||||
|
body.assign(title, posNL + numNLs, wxString::npos);
|
||||||
|
title.erase(posNL);
|
||||||
|
}
|
||||||
|
else // A single line
|
||||||
|
{
|
||||||
|
// Don't use title without the body, this doesn't make sense.
|
||||||
|
body.clear();
|
||||||
|
title.swap(body);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Runner thread that takes care of displaying and updating the
|
// Runner thread that takes care of displaying and updating the
|
||||||
@@ -182,6 +221,16 @@ BOOL CALLBACK DisplayCloseButton(HWND hwnd, LPARAM lParam)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function enables or disables both the cancel button in the task dialog
|
||||||
|
// and the close button in its title bar, as they perform the same function and
|
||||||
|
// so should be kept in the same state.
|
||||||
|
void EnableCloseButtons(HWND hwnd, bool enable)
|
||||||
|
{
|
||||||
|
::SendMessage(hwnd, TDM_ENABLE_BUTTON, IDCANCEL, enable ? TRUE : FALSE);
|
||||||
|
|
||||||
|
wxTopLevelWindow::MSWEnableCloseButton(hwnd, enable);
|
||||||
|
}
|
||||||
|
|
||||||
void PerformNotificationUpdates(HWND hwnd,
|
void PerformNotificationUpdates(HWND hwnd,
|
||||||
wxProgressDialogSharedData *sharedData)
|
wxProgressDialogSharedData *sharedData)
|
||||||
{
|
{
|
||||||
@@ -196,6 +245,33 @@ void PerformNotificationUpdates(HWND hwnd,
|
|||||||
|
|
||||||
if ( sharedData->m_notifications & wxSPDD_VALUE_CHANGED )
|
if ( sharedData->m_notifications & wxSPDD_VALUE_CHANGED )
|
||||||
{
|
{
|
||||||
|
// Use a hack to avoid progress bar animation: we can't afford to use
|
||||||
|
// it because animating the gauge movement smoothly requires a
|
||||||
|
// constantly running message loop and while it does run in this (task
|
||||||
|
// dialog) thread, it is often blocked from proceeding by some lock
|
||||||
|
// held by the main thread which is busy doing something and may not
|
||||||
|
// dispatch events frequently enough. So, in practice, the animation
|
||||||
|
// can lag far behind the real value and results in showing a wrong
|
||||||
|
// value in the progress bar.
|
||||||
|
//
|
||||||
|
// To prevent this from happening, set the progress bar value to
|
||||||
|
// something greater than its maximal value and then move it back: in
|
||||||
|
// the current implementations of the progress bar control, moving its
|
||||||
|
// position backwards does it directly, without using the animation,
|
||||||
|
// which is exactly what we want here.
|
||||||
|
//
|
||||||
|
// Finally notice that this hack doesn't really work for the last
|
||||||
|
// value, but while we could use a nested hack and temporarily increase
|
||||||
|
// the progress bar range when the value is equal to it, it isn't
|
||||||
|
// actually necessary in practice because when we reach the end of the
|
||||||
|
// bar the dialog is either hidden immediately anyhow or the main
|
||||||
|
// thread enters a modal event loop which does dispatch events and so
|
||||||
|
// it's not a problem to have an animated transition in this particular
|
||||||
|
// case.
|
||||||
|
::SendMessage( hwnd,
|
||||||
|
TDM_SET_PROGRESS_BAR_POS,
|
||||||
|
sharedData->m_value + 1,
|
||||||
|
0 );
|
||||||
::SendMessage( hwnd,
|
::SendMessage( hwnd,
|
||||||
TDM_SET_PROGRESS_BAR_POS,
|
TDM_SET_PROGRESS_BAR_POS,
|
||||||
sharedData->m_value,
|
sharedData->m_value,
|
||||||
@@ -235,39 +311,31 @@ void PerformNotificationUpdates(HWND hwnd,
|
|||||||
{
|
{
|
||||||
// Split the message in the title string and the rest if it has
|
// Split the message in the title string and the rest if it has
|
||||||
// multiple lines.
|
// multiple lines.
|
||||||
wxString
|
wxString title, body;
|
||||||
title = sharedData->m_message,
|
sharedData->SplitMessageIntoTitleAndBody(title, body);
|
||||||
body;
|
|
||||||
|
|
||||||
const size_t posNL = title.find('\n');
|
|
||||||
if ( posNL != wxString::npos )
|
|
||||||
{
|
|
||||||
// There can an extra new line between the first and subsequent
|
|
||||||
// lines to separate them as it looks better with the generic
|
|
||||||
// version -- but in this one, they're already separated by the use
|
|
||||||
// of different dialog elements, so suppress the extra new line.
|
|
||||||
int numNLs = 1;
|
|
||||||
if ( posNL < title.length() - 1 && title[posNL + 1] == '\n' )
|
|
||||||
numNLs++;
|
|
||||||
|
|
||||||
body.assign(title, posNL + numNLs, wxString::npos);
|
|
||||||
title.erase(posNL);
|
|
||||||
}
|
|
||||||
else // A single line
|
|
||||||
{
|
|
||||||
// Don't use title without the body, this doesn't make sense.
|
|
||||||
title.swap(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
::SendMessage( hwnd,
|
::SendMessage( hwnd,
|
||||||
TDM_SET_ELEMENT_TEXT,
|
sharedData->m_msgChangeElementText,
|
||||||
TDE_MAIN_INSTRUCTION,
|
TDE_MAIN_INSTRUCTION,
|
||||||
wxMSW_CONV_LPARAM(title) );
|
wxMSW_CONV_LPARAM(title) );
|
||||||
|
|
||||||
::SendMessage( hwnd,
|
::SendMessage( hwnd,
|
||||||
TDM_SET_ELEMENT_TEXT,
|
sharedData->m_msgChangeElementText,
|
||||||
TDE_CONTENT,
|
TDE_CONTENT,
|
||||||
wxMSW_CONV_LPARAM(body) );
|
wxMSW_CONV_LPARAM(body) );
|
||||||
|
|
||||||
|
// After using TDM_SET_ELEMENT_TEXT once, we don't want to use it for
|
||||||
|
// the subsequent updates as it could result in dialog size changing
|
||||||
|
// unexpectedly, so reset it (which does nothing if we had already done
|
||||||
|
// it, of course, but it's not a problem).
|
||||||
|
//
|
||||||
|
// Notice that, contrary to its documentation, even using this message
|
||||||
|
// still increases the dialog size if the new text is longer (at least
|
||||||
|
// under Windows 7), but it doesn't shrink back if the text becomes
|
||||||
|
// shorter later and stays at the bigger size which is still a big gain
|
||||||
|
// as it prevents jumping back and forth between the smaller and larger
|
||||||
|
// sizes.
|
||||||
|
sharedData->m_msgChangeElementText = TDM_UPDATE_ELEMENT_TEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sharedData->m_notifications & wxSPDD_EXPINFO_CHANGED )
|
if ( sharedData->m_notifications & wxSPDD_EXPINFO_CHANGED )
|
||||||
@@ -276,8 +344,15 @@ void PerformNotificationUpdates(HWND hwnd,
|
|||||||
sharedData->m_expandedInformation;
|
sharedData->m_expandedInformation;
|
||||||
if ( !expandedInformation.empty() )
|
if ( !expandedInformation.empty() )
|
||||||
{
|
{
|
||||||
|
// Here we never need to use TDM_SET_ELEMENT_TEXT as the size of
|
||||||
|
// the expanded information doesn't change drastically.
|
||||||
|
//
|
||||||
|
// Notice that TDM_UPDATE_ELEMENT_TEXT for this element only works
|
||||||
|
// when using TDF_EXPAND_FOOTER_AREA, as we do. Without this flag,
|
||||||
|
// only TDM_SET_ELEMENT_TEXT could be used as otherwise the dialog
|
||||||
|
// layout becomes completely mangled (at least under Windows 7).
|
||||||
::SendMessage( hwnd,
|
::SendMessage( hwnd,
|
||||||
TDM_SET_ELEMENT_TEXT,
|
TDM_UPDATE_ELEMENT_TEXT,
|
||||||
TDE_EXPANDED_INFORMATION,
|
TDE_EXPANDED_INFORMATION,
|
||||||
wxMSW_CONV_LPARAM(expandedInformation) );
|
wxMSW_CONV_LPARAM(expandedInformation) );
|
||||||
}
|
}
|
||||||
@@ -287,14 +362,11 @@ void PerformNotificationUpdates(HWND hwnd,
|
|||||||
::SendMessage( hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, TRUE );
|
::SendMessage( hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, TRUE );
|
||||||
|
|
||||||
if ( sharedData->m_notifications & wxSPDD_ENABLE_ABORT )
|
if ( sharedData->m_notifications & wxSPDD_ENABLE_ABORT )
|
||||||
::SendMessage( hwnd, TDM_ENABLE_BUTTON, IDCANCEL, TRUE );
|
EnableCloseButtons(hwnd, true);
|
||||||
|
|
||||||
if ( sharedData->m_notifications & wxSPDD_DISABLE_SKIP )
|
if ( sharedData->m_notifications & wxSPDD_DISABLE_SKIP )
|
||||||
::SendMessage( hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE );
|
::SendMessage( hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE );
|
||||||
|
|
||||||
if ( sharedData->m_notifications & wxSPDD_DISABLE_ABORT )
|
|
||||||
::SendMessage( hwnd, TDM_ENABLE_BUTTON, IDCANCEL, FALSE );
|
|
||||||
|
|
||||||
// Is the progress finished?
|
// Is the progress finished?
|
||||||
if ( sharedData->m_notifications & wxSPDD_FINISHED )
|
if ( sharedData->m_notifications & wxSPDD_FINISHED )
|
||||||
{
|
{
|
||||||
@@ -304,7 +376,7 @@ void PerformNotificationUpdates(HWND hwnd,
|
|||||||
{
|
{
|
||||||
// Change Cancel into Close and activate the button.
|
// Change Cancel into Close and activate the button.
|
||||||
::SendMessage( hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE );
|
::SendMessage( hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE );
|
||||||
::SendMessage( hwnd, TDM_ENABLE_BUTTON, IDCANCEL, TRUE );
|
EnableCloseButtons(hwnd, true);
|
||||||
::EnumChildWindows( hwnd, DisplayCloseButton,
|
::EnumChildWindows( hwnd, DisplayCloseButton,
|
||||||
(LPARAM) sharedData );
|
(LPARAM) sharedData );
|
||||||
}
|
}
|
||||||
@@ -337,6 +409,7 @@ wxProgressDialog::wxProgressDialog( const wxString& title,
|
|||||||
SetPDStyle(style);
|
SetPDStyle(style);
|
||||||
SetMaximum(maximum);
|
SetMaximum(maximum);
|
||||||
|
|
||||||
|
EnsureActiveEventLoopExists();
|
||||||
Show();
|
Show();
|
||||||
DisableOtherWindows();
|
DisableOtherWindows();
|
||||||
|
|
||||||
@@ -359,14 +432,49 @@ wxProgressDialog::~wxProgressDialog()
|
|||||||
m_sharedData->m_notifications |= wxSPDD_DESTROYED;
|
m_sharedData->m_notifications |= wxSPDD_DESTROYED;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_taskDialogRunner->Wait();
|
// We can't use simple wxThread::Wait() here as we would deadlock because
|
||||||
|
// the task dialog thread expects this thread to process some messages
|
||||||
|
// (presumably those the task dialog sends to its parent during its
|
||||||
|
// destruction).
|
||||||
|
const WXHANDLE hThread = m_taskDialogRunner->MSWGetHandle();
|
||||||
|
for ( bool cont = true; cont; )
|
||||||
|
{
|
||||||
|
DWORD rc = ::MsgWaitForMultipleObjects
|
||||||
|
(
|
||||||
|
1, // number of objects to wait for
|
||||||
|
(HANDLE *)&hThread, // the objects
|
||||||
|
false, // wait for any objects, not all
|
||||||
|
INFINITE, // no timeout
|
||||||
|
QS_ALLINPUT | // return as soon as there are any events
|
||||||
|
QS_ALLPOSTMESSAGE
|
||||||
|
);
|
||||||
|
|
||||||
delete m_taskDialogRunner;
|
switch ( rc )
|
||||||
|
{
|
||||||
|
case 0xFFFFFFFF:
|
||||||
|
// This is unexpected, but we can't do anything about it and
|
||||||
|
// probably shouldn't continue waiting as we risk doing it
|
||||||
|
// forever.
|
||||||
|
wxLogLastError("MsgWaitForMultipleObjectsEx");
|
||||||
|
cont = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WAIT_OBJECT_0:
|
||||||
|
// Thread has terminated.
|
||||||
|
cont = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// An event has arrive, so dispatch it.
|
||||||
|
wxEventLoop::GetActive()->Dispatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the windows before deleting the task dialog to ensure that we
|
||||||
|
// can regain the activation.
|
||||||
ReenableOtherWindows();
|
ReenableOtherWindows();
|
||||||
|
|
||||||
if ( GetTopParent() )
|
delete m_taskDialogRunner;
|
||||||
GetTopParent()->Raise();
|
|
||||||
#endif // wxHAS_MSW_TASKDIALOG
|
#endif // wxHAS_MSW_TASKDIALOG
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -375,21 +483,26 @@ bool wxProgressDialog::Update(int value, const wxString& newmsg, bool *skip)
|
|||||||
#ifdef wxHAS_MSW_TASKDIALOG
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
if ( HasNativeTaskDialog() )
|
if ( HasNativeTaskDialog() )
|
||||||
{
|
{
|
||||||
|
if ( !DoNativeBeforeUpdate(skip) )
|
||||||
|
{
|
||||||
|
// Dialog was cancelled.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
value /= m_factor;
|
||||||
|
|
||||||
|
wxASSERT_MSG( value <= m_maximum, wxT("invalid progress value") );
|
||||||
|
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
|
|
||||||
// Do nothing in canceled state.
|
if ( value != m_sharedData->m_value )
|
||||||
if ( !DoNativeBeforeUpdate(skip) )
|
{
|
||||||
return false;
|
m_sharedData->m_value = value;
|
||||||
|
m_sharedData->m_notifications |= wxSPDD_VALUE_CHANGED;
|
||||||
|
}
|
||||||
|
|
||||||
value /= m_factor;
|
if ( !newmsg.empty() && newmsg != m_message )
|
||||||
|
|
||||||
wxASSERT_MSG( value <= m_maximum, wxT("invalid progress value") );
|
|
||||||
|
|
||||||
m_sharedData->m_value = value;
|
|
||||||
m_sharedData->m_notifications |= wxSPDD_VALUE_CHANGED;
|
|
||||||
|
|
||||||
if ( !newmsg.empty() )
|
|
||||||
{
|
{
|
||||||
m_message = newmsg;
|
m_message = newmsg;
|
||||||
m_sharedData->m_message = newmsg;
|
m_sharedData->m_message = newmsg;
|
||||||
@@ -445,11 +558,13 @@ bool wxProgressDialog::Pulse(const wxString& newmsg, bool *skip)
|
|||||||
#ifdef wxHAS_MSW_TASKDIALOG
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
if ( HasNativeTaskDialog() )
|
if ( HasNativeTaskDialog() )
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
|
||||||
|
|
||||||
// Do nothing in canceled state.
|
|
||||||
if ( !DoNativeBeforeUpdate(skip) )
|
if ( !DoNativeBeforeUpdate(skip) )
|
||||||
|
{
|
||||||
|
// Dialog was cancelled.
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
|
|
||||||
if ( !m_sharedData->m_progressBarMarquee )
|
if ( !m_sharedData->m_progressBarMarquee )
|
||||||
{
|
{
|
||||||
@@ -457,15 +572,15 @@ bool wxProgressDialog::Pulse(const wxString& newmsg, bool *skip)
|
|||||||
m_sharedData->m_notifications |= wxSPDD_PBMARQUEE_CHANGED;
|
m_sharedData->m_notifications |= wxSPDD_PBMARQUEE_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !newmsg.empty() )
|
if ( !newmsg.empty() && newmsg != m_message )
|
||||||
{
|
{
|
||||||
m_message = newmsg;
|
m_message = newmsg;
|
||||||
m_sharedData->m_message = newmsg;
|
m_sharedData->m_message = newmsg;
|
||||||
m_sharedData->m_notifications |= wxSPDD_MESSAGE_CHANGED;
|
m_sharedData->m_notifications |= wxSPDD_MESSAGE_CHANGED;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The value passed here doesn't matter, only elapsed time makes sense
|
// Value of 0 is special and is used when we can't estimate the
|
||||||
// in indeterminate mode anyhow.
|
// remaining and total times, which is exactly what we need here.
|
||||||
UpdateExpandedInformation(0);
|
UpdateExpandedInformation(0);
|
||||||
|
|
||||||
return m_sharedData->m_state != Canceled;
|
return m_sharedData->m_state != Canceled;
|
||||||
@@ -475,32 +590,49 @@ bool wxProgressDialog::Pulse(const wxString& newmsg, bool *skip)
|
|||||||
return wxGenericProgressDialog::Pulse( newmsg, skip );
|
return wxGenericProgressDialog::Pulse( newmsg, skip );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxProgressDialog::DispatchEvents()
|
||||||
|
{
|
||||||
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
|
// No need for HasNativeTaskDialog() check, we're only called when this is
|
||||||
|
// the case.
|
||||||
|
|
||||||
|
// We don't need to dispatch the user input events as the task dialog
|
||||||
|
// handles its own ones in its thread and we shouldn't react to any
|
||||||
|
// other user actions while the dialog is shown.
|
||||||
|
wxEventLoop::GetActive()->
|
||||||
|
YieldFor(wxEVT_CATEGORY_ALL & ~wxEVT_CATEGORY_USER_INPUT);
|
||||||
|
#else // !wxHAS_MSW_TASKDIALOG
|
||||||
|
wxFAIL_MSG( "unreachable" );
|
||||||
|
#endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
|
||||||
|
}
|
||||||
|
|
||||||
bool wxProgressDialog::DoNativeBeforeUpdate(bool *skip)
|
bool wxProgressDialog::DoNativeBeforeUpdate(bool *skip)
|
||||||
{
|
{
|
||||||
#ifdef wxHAS_MSW_TASKDIALOG
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
if ( HasNativeTaskDialog() )
|
DispatchEvents();
|
||||||
|
|
||||||
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
|
|
||||||
|
if ( m_sharedData->m_skipped )
|
||||||
{
|
{
|
||||||
if ( m_sharedData->m_skipped )
|
if ( skip && !*skip )
|
||||||
{
|
{
|
||||||
if ( skip && !*skip )
|
*skip = true;
|
||||||
{
|
m_sharedData->m_skipped = false;
|
||||||
*skip = true;
|
m_sharedData->m_notifications |= wxSPDD_ENABLE_SKIP;
|
||||||
m_sharedData->m_skipped = false;
|
|
||||||
m_sharedData->m_notifications |= wxSPDD_ENABLE_SKIP;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_sharedData->m_state == Canceled )
|
|
||||||
m_timeStop = m_sharedData->m_timeStop;
|
|
||||||
|
|
||||||
return m_sharedData->m_state != Canceled;
|
|
||||||
}
|
}
|
||||||
#endif // wxHAS_MSW_TASKDIALOG
|
|
||||||
|
|
||||||
|
if ( m_sharedData->m_state == Canceled )
|
||||||
|
m_timeStop = m_sharedData->m_timeStop;
|
||||||
|
|
||||||
|
return m_sharedData->m_state != Canceled;
|
||||||
|
#else // !wxHAS_MSW_TASKDIALOG
|
||||||
wxUnusedVar(skip);
|
wxUnusedVar(skip);
|
||||||
wxFAIL_MSG( "unreachable" );
|
wxFAIL_MSG( "unreachable" );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
#endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxProgressDialog::Resume()
|
void wxProgressDialog::Resume()
|
||||||
@@ -514,7 +646,7 @@ void wxProgressDialog::Resume()
|
|||||||
|
|
||||||
{
|
{
|
||||||
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
m_sharedData->m_state = m_state;
|
m_sharedData->m_state = Continue;
|
||||||
|
|
||||||
// "Skip" was disabled when "Cancel" had been clicked, so re-enable
|
// "Skip" was disabled when "Cancel" had been clicked, so re-enable
|
||||||
// it now.
|
// it now.
|
||||||
@@ -542,20 +674,16 @@ void wxProgressDialog::Resume()
|
|||||||
#endif // wxHAS_MSW_TASKDIALOG
|
#endif // wxHAS_MSW_TASKDIALOG
|
||||||
}
|
}
|
||||||
|
|
||||||
WXWidget wxProgressDialog::GetHandle() const
|
WXWidget wxProgressDialog::GetHandle() const
|
||||||
{
|
{
|
||||||
#ifdef wxHAS_MSW_TASKDIALOG
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
if ( HasNativeTaskDialog() )
|
if ( HasNativeTaskDialog() )
|
||||||
{
|
{
|
||||||
HWND hwnd;
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
{
|
return m_sharedData->m_hwnd;
|
||||||
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
|
||||||
m_sharedData->m_state = m_state;
|
|
||||||
hwnd = m_sharedData->m_hwnd;
|
|
||||||
}
|
|
||||||
return hwnd;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif // wxHAS_MSW_TASKDIALOG
|
||||||
|
|
||||||
return wxGenericProgressDialog::GetHandle();
|
return wxGenericProgressDialog::GetHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -715,21 +843,33 @@ void wxProgressDialog::DoMoveWindow(int x, int y, int width, int height)
|
|||||||
wxGenericProgressDialog::DoMoveWindow(x, y, width, height);
|
wxGenericProgressDialog::DoMoveWindow(x, y, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxRect wxProgressDialog::GetTaskDialogRect() const
|
||||||
|
{
|
||||||
|
wxRect r;
|
||||||
|
|
||||||
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
|
if ( m_sharedData )
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
|
r = wxRectFromRECT(wxGetWindowRect(m_sharedData->m_hwnd));
|
||||||
|
}
|
||||||
|
#else // !wxHAS_MSW_TASKDIALOG
|
||||||
|
wxFAIL_MSG( "unreachable" );
|
||||||
|
#endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
void wxProgressDialog::DoGetPosition(int *x, int *y) const
|
void wxProgressDialog::DoGetPosition(int *x, int *y) const
|
||||||
{
|
{
|
||||||
#ifdef wxHAS_MSW_TASKDIALOG
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
if ( HasNativeTaskDialog() )
|
if ( HasNativeTaskDialog() )
|
||||||
{
|
{
|
||||||
wxPoint pos;
|
const wxRect r = GetTaskDialogRect();
|
||||||
{
|
|
||||||
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
|
||||||
m_sharedData->m_state = m_state;
|
|
||||||
pos = m_sharedData->m_winPosition;
|
|
||||||
}
|
|
||||||
if (x)
|
if (x)
|
||||||
*x = pos.x;
|
*x = r.x;
|
||||||
if (y)
|
if (y)
|
||||||
*y = pos.y;
|
*y = r.y;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -738,6 +878,42 @@ void wxProgressDialog::DoGetPosition(int *x, int *y) const
|
|||||||
wxGenericProgressDialog::DoGetPosition(x, y);
|
wxGenericProgressDialog::DoGetPosition(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxProgressDialog::DoGetSize(int *width, int *height) const
|
||||||
|
{
|
||||||
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
|
if ( HasNativeTaskDialog() )
|
||||||
|
{
|
||||||
|
const wxRect r = GetTaskDialogRect();
|
||||||
|
if ( width )
|
||||||
|
*width = r.width;
|
||||||
|
if ( height )
|
||||||
|
*height = r.height;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif // wxHAS_MSW_TASKDIALOG
|
||||||
|
|
||||||
|
wxGenericProgressDialog::DoGetSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxProgressDialog::Fit()
|
||||||
|
{
|
||||||
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
|
if ( HasNativeTaskDialog() )
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
|
|
||||||
|
// Force the task dialog to use this message to adjust it layout.
|
||||||
|
m_sharedData->m_msgChangeElementText = TDM_SET_ELEMENT_TEXT;
|
||||||
|
|
||||||
|
// Don't change the message, but pretend that it did change.
|
||||||
|
m_sharedData->m_notifications |= wxSPDD_MESSAGE_CHANGED;
|
||||||
|
}
|
||||||
|
#endif // wxHAS_MSW_TASKDIALOG
|
||||||
|
|
||||||
|
wxGenericProgressDialog::Fit();
|
||||||
|
}
|
||||||
|
|
||||||
bool wxProgressDialog::Show(bool show)
|
bool wxProgressDialog::Show(bool show)
|
||||||
{
|
{
|
||||||
#ifdef wxHAS_MSW_TASKDIALOG
|
#ifdef wxHAS_MSW_TASKDIALOG
|
||||||
@@ -777,8 +953,9 @@ bool wxProgressDialog::Show(bool show)
|
|||||||
wxPD_ESTIMATED_TIME |
|
wxPD_ESTIMATED_TIME |
|
||||||
wxPD_REMAINING_TIME) )
|
wxPD_REMAINING_TIME) )
|
||||||
{
|
{
|
||||||
// Use a non-empty string just to have the collapsible pane shown.
|
// Set the expanded information field from the beginning to avoid
|
||||||
m_sharedData->m_expandedInformation = " ";
|
// having to re-layout the dialog later when it changes.
|
||||||
|
UpdateExpandedInformation(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do launch the thread.
|
// Do launch the thread.
|
||||||
@@ -794,6 +971,16 @@ bool wxProgressDialog::Show(bool show)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait until the dialog is shown as the program may need some time
|
||||||
|
// before it calls Update() and we want to show something to the user
|
||||||
|
// in the meanwhile.
|
||||||
|
while ( wxEventLoop::GetActive()->Dispatch() )
|
||||||
|
{
|
||||||
|
wxCriticalSectionLocker locker(m_sharedData->m_cs);
|
||||||
|
if ( m_sharedData->m_hwnd )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Do not show the underlying dialog.
|
// Do not show the underlying dialog.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -810,14 +997,15 @@ void wxProgressDialog::UpdateExpandedInformation(int value)
|
|||||||
unsigned long remainingTime;
|
unsigned long remainingTime;
|
||||||
UpdateTimeEstimates(value, elapsedTime, estimatedTime, remainingTime);
|
UpdateTimeEstimates(value, elapsedTime, estimatedTime, remainingTime);
|
||||||
|
|
||||||
int realEstimatedTime = estimatedTime,
|
// The value of 0 is special, we can't estimate anything before we have at
|
||||||
realRemainingTime = remainingTime;
|
// least one update, so leave the times dependent on it indeterminate.
|
||||||
if ( m_sharedData->m_progressBarMarquee )
|
//
|
||||||
|
// This value is also used by Pulse(), as in the indeterminate mode we can
|
||||||
|
// never estimate anything.
|
||||||
|
if ( !value )
|
||||||
{
|
{
|
||||||
// In indeterminate mode we don't have any estimation neither for the
|
estimatedTime =
|
||||||
// remaining nor for estimated time.
|
remainingTime = static_cast<unsigned long>(-1);
|
||||||
realEstimatedTime =
|
|
||||||
realRemainingTime = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wxString expandedInformation;
|
wxString expandedInformation;
|
||||||
@@ -837,7 +1025,7 @@ void wxProgressDialog::UpdateExpandedInformation(int value)
|
|||||||
|
|
||||||
expandedInformation << GetEstimatedLabel()
|
expandedInformation << GetEstimatedLabel()
|
||||||
<< " "
|
<< " "
|
||||||
<< GetFormattedTime(realEstimatedTime);
|
<< GetFormattedTime(estimatedTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( HasPDFlag(wxPD_REMAINING_TIME) )
|
if ( HasPDFlag(wxPD_REMAINING_TIME) )
|
||||||
@@ -847,7 +1035,7 @@ void wxProgressDialog::UpdateExpandedInformation(int value)
|
|||||||
|
|
||||||
expandedInformation << GetRemainingLabel()
|
expandedInformation << GetRemainingLabel()
|
||||||
<< " "
|
<< " "
|
||||||
<< GetFormattedTime(realRemainingTime);
|
<< GetFormattedTime(remainingTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update with new timing information.
|
// Update with new timing information.
|
||||||
@@ -875,8 +1063,20 @@ void* wxProgressDialogTaskRunner::Entry()
|
|||||||
{
|
{
|
||||||
wxCriticalSectionLocker locker(m_sharedData.m_cs);
|
wxCriticalSectionLocker locker(m_sharedData.m_cs);
|
||||||
|
|
||||||
|
// If we have a parent, we must use it to have correct Z-order and
|
||||||
|
// icon, even if this comes at the price of attaching this thread input
|
||||||
|
// to the thread that created the parent window, i.e. the main thread.
|
||||||
|
wxTdc.parent = m_sharedData.m_parent;
|
||||||
wxTdc.caption = m_sharedData.m_title.wx_str();
|
wxTdc.caption = m_sharedData.m_title.wx_str();
|
||||||
wxTdc.message = m_sharedData.m_message.wx_str();
|
|
||||||
|
// Split the message into the title and main body text in the same way
|
||||||
|
// as it's done later in PerformNotificationUpdates() when the message
|
||||||
|
// is changed by Update() or Pulse().
|
||||||
|
m_sharedData.SplitMessageIntoTitleAndBody
|
||||||
|
(
|
||||||
|
wxTdc.message,
|
||||||
|
wxTdc.extendedMessage
|
||||||
|
);
|
||||||
|
|
||||||
// MSWCommonTaskDialogInit() will add an IDCANCEL button but we need to
|
// MSWCommonTaskDialogInit() will add an IDCANCEL button but we need to
|
||||||
// give it the correct label.
|
// give it the correct label.
|
||||||
@@ -887,10 +1087,6 @@ void* wxProgressDialogTaskRunner::Entry()
|
|||||||
tdc.pfCallback = TaskDialogCallbackProc;
|
tdc.pfCallback = TaskDialogCallbackProc;
|
||||||
tdc.lpCallbackData = (LONG_PTR) &m_sharedData;
|
tdc.lpCallbackData = (LONG_PTR) &m_sharedData;
|
||||||
|
|
||||||
// Undo some of the effects of MSWCommonTaskDialogInit().
|
|
||||||
tdc.dwFlags &= ~TDF_EXPAND_FOOTER_AREA; // Expand in content area.
|
|
||||||
tdc.dwCommonButtons = 0; // Don't use common buttons.
|
|
||||||
|
|
||||||
if ( m_sharedData.m_style & wxPD_CAN_SKIP )
|
if ( m_sharedData.m_style & wxPD_CAN_SKIP )
|
||||||
wxTdc.AddTaskDialogButton( tdc, Id_SkipBtn, 0, _("Skip") );
|
wxTdc.AddTaskDialogButton( tdc, Id_SkipBtn, 0, _("Skip") );
|
||||||
|
|
||||||
@@ -900,6 +1096,13 @@ void* wxProgressDialogTaskRunner::Entry()
|
|||||||
{
|
{
|
||||||
tdc.pszExpandedInformation =
|
tdc.pszExpandedInformation =
|
||||||
m_sharedData.m_expandedInformation.t_str();
|
m_sharedData.m_expandedInformation.t_str();
|
||||||
|
|
||||||
|
// If we have elapsed/estimated/... times to show, show them from
|
||||||
|
// the beginning for consistency with the generic version and also
|
||||||
|
// because showing them later may be very sluggish if the main
|
||||||
|
// thread doesn't update the dialog sufficiently frequently, while
|
||||||
|
// hiding them still works reasonably well.
|
||||||
|
tdc.dwFlags |= TDF_EXPANDED_BY_DEFAULT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -930,6 +1133,10 @@ wxProgressDialogTaskRunner::TaskDialogCallbackProc
|
|||||||
LONG_PTR dwRefData
|
LONG_PTR dwRefData
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
bool endDialog = false;
|
||||||
|
|
||||||
|
// Block for shared data critical section.
|
||||||
|
{
|
||||||
wxProgressDialogSharedData * const sharedData =
|
wxProgressDialogSharedData * const sharedData =
|
||||||
(wxProgressDialogSharedData *) dwRefData;
|
(wxProgressDialogSharedData *) dwRefData;
|
||||||
|
|
||||||
@@ -941,45 +1148,20 @@ wxProgressDialogTaskRunner::TaskDialogCallbackProc
|
|||||||
// Store the HWND for the main thread use.
|
// Store the HWND for the main thread use.
|
||||||
sharedData->m_hwnd = hwnd;
|
sharedData->m_hwnd = hwnd;
|
||||||
|
|
||||||
|
// The main thread is sitting in an event dispatching loop waiting
|
||||||
|
// for this dialog to be shown, so make sure it does get an event.
|
||||||
|
wxWakeUpIdle();
|
||||||
|
|
||||||
// Set the maximum value and disable Close button.
|
// Set the maximum value and disable Close button.
|
||||||
::SendMessage( hwnd,
|
::SendMessage( hwnd,
|
||||||
TDM_SET_PROGRESS_BAR_RANGE,
|
TDM_SET_PROGRESS_BAR_RANGE,
|
||||||
0,
|
0,
|
||||||
MAKELPARAM(0, sharedData->m_range) );
|
MAKELPARAM(0, sharedData->m_range) );
|
||||||
|
|
||||||
// We always create this task dialog with NULL parent because our
|
|
||||||
// parent in wx sense is a window created from a different thread
|
|
||||||
// and so can't be used as our real parent. However we still center
|
|
||||||
// this window on the parent one as the task dialogs do with their
|
|
||||||
// real parent usually.
|
|
||||||
if ( sharedData->m_parent )
|
|
||||||
{
|
|
||||||
wxRect rect(wxRectFromRECT(wxGetWindowRect(hwnd)));
|
|
||||||
rect = rect.CentreIn(sharedData->m_parent->GetRect());
|
|
||||||
::SetWindowPos(hwnd,
|
|
||||||
NULL,
|
|
||||||
rect.x,
|
|
||||||
rect.y,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
SWP_NOACTIVATE |
|
|
||||||
SWP_NOOWNERZORDER |
|
|
||||||
SWP_NOSIZE |
|
|
||||||
SWP_NOZORDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store current position for the main thread use
|
|
||||||
// if no position update is pending.
|
|
||||||
if ( !(sharedData->m_notifications & wxSPDD_WINDOW_MOVED) )
|
|
||||||
{
|
|
||||||
RECT r = wxGetWindowRect(hwnd);
|
|
||||||
sharedData->m_winPosition = wxPoint(r.left, r.top);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we can't be aborted, the "Close" button will only be enabled
|
// If we can't be aborted, the "Close" button will only be enabled
|
||||||
// when the progress ends (and not even then with wxPD_AUTO_HIDE).
|
// when the progress ends (and not even then with wxPD_AUTO_HIDE).
|
||||||
if ( !(sharedData->m_style & wxPD_CAN_ABORT) )
|
if ( !(sharedData->m_style & wxPD_CAN_ABORT) )
|
||||||
::SendMessage( hwnd, TDM_ENABLE_BUTTON, IDCANCEL, FALSE );
|
EnableCloseButtons(hwnd, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TDN_BUTTON_CLICKED:
|
case TDN_BUTTON_CLICKED:
|
||||||
@@ -988,7 +1170,7 @@ wxProgressDialogTaskRunner::TaskDialogCallbackProc
|
|||||||
case Id_SkipBtn:
|
case Id_SkipBtn:
|
||||||
::SendMessage(hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE);
|
::SendMessage(hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE);
|
||||||
sharedData->m_skipped = true;
|
sharedData->m_skipped = true;
|
||||||
return TRUE;
|
return S_FALSE;
|
||||||
|
|
||||||
case IDCANCEL:
|
case IDCANCEL:
|
||||||
if ( sharedData->m_state == wxProgressDialog::Finished )
|
if ( sharedData->m_state == wxProgressDialog::Finished )
|
||||||
@@ -998,7 +1180,7 @@ wxProgressDialogTaskRunner::TaskDialogCallbackProc
|
|||||||
sharedData->m_state = wxProgressDialog::Dismissed;
|
sharedData->m_state = wxProgressDialog::Dismissed;
|
||||||
|
|
||||||
// Let Windows close the dialog.
|
// Let Windows close the dialog.
|
||||||
return FALSE;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close button on the window triggers an IDCANCEL press,
|
// Close button on the window triggers an IDCANCEL press,
|
||||||
@@ -1006,26 +1188,48 @@ wxProgressDialogTaskRunner::TaskDialogCallbackProc
|
|||||||
// a finished dialog.
|
// a finished dialog.
|
||||||
if ( sharedData->m_style & wxPD_CAN_ABORT )
|
if ( sharedData->m_style & wxPD_CAN_ABORT )
|
||||||
{
|
{
|
||||||
wxCHECK_MSG
|
switch ( sharedData->m_state )
|
||||||
(
|
{
|
||||||
sharedData->m_state == wxProgressDialog::Continue,
|
case wxProgressDialog::Canceled:
|
||||||
TRUE,
|
// It can happen that we receive a second
|
||||||
"Dialog not in a cancelable state!"
|
// cancel request before we had time to process
|
||||||
);
|
// the first one, in which case simply do
|
||||||
|
// nothing for the subsequent one.
|
||||||
|
break;
|
||||||
|
|
||||||
::SendMessage(hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE);
|
case wxProgressDialog::Continue:
|
||||||
::SendMessage(hwnd, TDM_ENABLE_BUTTON, IDCANCEL, FALSE);
|
::SendMessage(hwnd, TDM_ENABLE_BUTTON, Id_SkipBtn, FALSE);
|
||||||
|
EnableCloseButtons(hwnd, false);
|
||||||
|
|
||||||
sharedData->m_timeStop = wxGetCurrentTime();
|
sharedData->m_timeStop = wxGetCurrentTime();
|
||||||
sharedData->m_state = wxProgressDialog::Canceled;
|
sharedData->m_state = wxProgressDialog::Canceled;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// States which shouldn't be possible here:
|
||||||
|
|
||||||
|
// We shouldn't have an (enabled) cancel button at
|
||||||
|
// all then.
|
||||||
|
case wxProgressDialog::Uncancelable:
|
||||||
|
|
||||||
|
// This one was already dealt with above.
|
||||||
|
case wxProgressDialog::Finished:
|
||||||
|
|
||||||
|
// Normally it shouldn't be possible to get any
|
||||||
|
// notifications after switching to this state.
|
||||||
|
case wxProgressDialog::Dismissed:
|
||||||
|
wxFAIL_MSG( "unreachable" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TDN_TIMER:
|
case TDN_TIMER:
|
||||||
PerformNotificationUpdates(hwnd, sharedData);
|
// Don't perform updates if nothing needs to be done.
|
||||||
|
if ( sharedData->m_notifications )
|
||||||
|
PerformNotificationUpdates(hwnd, sharedData);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Decide whether we should end the dialog. This is done if either
|
Decide whether we should end the dialog. This is done if either
|
||||||
@@ -1041,21 +1245,30 @@ wxProgressDialogTaskRunner::TaskDialogCallbackProc
|
|||||||
(sharedData->m_state == wxProgressDialog::Finished &&
|
(sharedData->m_state == wxProgressDialog::Finished &&
|
||||||
sharedData->m_style & wxPD_AUTO_HIDE) )
|
sharedData->m_style & wxPD_AUTO_HIDE) )
|
||||||
{
|
{
|
||||||
::EndDialog( hwnd, IDCLOSE );
|
// Don't call EndDialog() from here as it could deadlock
|
||||||
|
// because we are inside the shared data critical section, do
|
||||||
|
// it below after leaving it instead.
|
||||||
|
endDialog = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedData->m_notifications = 0;
|
sharedData->m_notifications = 0;
|
||||||
{
|
|
||||||
// Update current position for the main thread use.
|
|
||||||
RECT r = wxGetWindowRect(hwnd);
|
|
||||||
sharedData->m_winPosition = wxPoint(r.left, r.top);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
if ( endDialog )
|
||||||
|
break;
|
||||||
|
|
||||||
|
return S_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Leave shared data critical section.
|
||||||
|
|
||||||
|
if ( endDialog )
|
||||||
|
{
|
||||||
|
::EndDialog( hwnd, IDCLOSE );
|
||||||
|
return S_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return anything.
|
// Return anything.
|
||||||
return 0;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // wxHAS_MSW_TASKDIALOG
|
#endif // wxHAS_MSW_TASKDIALOG
|
||||||
|
@@ -986,10 +986,11 @@ void wxTopLevelWindowMSW::SetIcons(const wxIconBundle& icons)
|
|||||||
DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG);
|
DoSelectAndSetIcon(icons, SM_CXICON, SM_CYICON, ICON_BIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
|
// static
|
||||||
|
bool wxTopLevelWindowMSW::MSWEnableCloseButton(WXHWND hwnd, bool enable)
|
||||||
{
|
{
|
||||||
// get system (a.k.a. window) menu
|
// get system (a.k.a. window) menu
|
||||||
HMENU hmenu = GetSystemMenu(GetHwnd(), FALSE /* get it */);
|
HMENU hmenu = GetSystemMenu(hwnd, FALSE /* get it */);
|
||||||
if ( !hmenu )
|
if ( !hmenu )
|
||||||
{
|
{
|
||||||
// no system menu at all -- ok if we want to remove the close button
|
// no system menu at all -- ok if we want to remove the close button
|
||||||
@@ -1008,7 +1009,7 @@ bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// update appearance immediately
|
// update appearance immediately
|
||||||
if ( !::DrawMenuBar(GetHwnd()) )
|
if ( !::DrawMenuBar(hwnd) )
|
||||||
{
|
{
|
||||||
wxLogLastError(wxT("DrawMenuBar"));
|
wxLogLastError(wxT("DrawMenuBar"));
|
||||||
}
|
}
|
||||||
@@ -1016,6 +1017,11 @@ bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxTopLevelWindowMSW::EnableCloseButton(bool enable)
|
||||||
|
{
|
||||||
|
return MSWEnableCloseButton(GetHwnd(), enable);
|
||||||
|
}
|
||||||
|
|
||||||
// Window must have wxCAPTION and either wxCLOSE_BOX or wxSYSTEM_MENU for the
|
// Window must have wxCAPTION and either wxCLOSE_BOX or wxSYSTEM_MENU for the
|
||||||
// button to be visible. Also check for wxMAXIMIZE_BOX because we don't want
|
// button to be visible. Also check for wxMAXIMIZE_BOX because we don't want
|
||||||
// to enable a button that is excluded from the current style.
|
// to enable a button that is excluded from the current style.
|
||||||
|
Reference in New Issue
Block a user