1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/progdlg.cpp
3 // Purpose: wxProgressDialog
4 // Author: Rickard Westerlund
7 // Copyright: (c) 2010 wxWidgets team
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 #if wxUSE_PROGRESSDLG && wxUSE_THREADS
28 #include "wx/msw/private/msgdlg.h"
29 #include "wx/progdlg.h"
31 using namespace wxMSWMessageDialog
;
33 #ifdef wxHAS_MSW_TASKDIALOG
35 // ----------------------------------------------------------------------------
37 // ----------------------------------------------------------------------------
42 // Notification values of wxProgressDialogSharedData::m_notifications
43 const int wxSPDD_VALUE_CHANGED
= 0x0001;
44 const int wxSPDD_RANGE_CHANGED
= 0x0002;
45 const int wxSPDD_PBMARQUEE_CHANGED
= 0x0004;
46 const int wxSPDD_TITLE_CHANGED
= 0x0008;
47 const int wxSPDD_MESSAGE_CHANGED
= 0x0010;
48 const int wxSPDD_EXPINFO_CHANGED
= 0x0020;
49 const int wxSPDD_ENABLE_SKIP
= 0x0040;
50 const int wxSPDD_ENABLE_ABORT
= 0x0080;
51 const int wxSPDD_DISABLE_SKIP
= 0x0100;
52 const int wxSPDD_DISABLE_ABORT
= 0x0200;
53 const int wxSPDD_FINISHED
= 0x0400;
54 const int wxSPDD_DESTROYED
= 0x0800;
56 const int Id_SkipBtn
= wxID_HIGHEST
+ 1;
58 } // anonymous namespace
60 // ============================================================================
62 // ============================================================================
64 // Class used to share data between the main thread and the task dialog runner.
65 class wxProgressDialogSharedData
68 wxProgressDialogSharedData()
72 m_progressBarMarquee
= false;
77 wxCriticalSection m_cs
;
79 HWND m_hwnd
; // Task dialog handler
80 long m_style
; // wxProgressDialog style
85 wxString m_expandedInformation
;
86 wxString m_labelCancel
; // Privately used by callback.
87 unsigned long m_timeStop
;
89 wxGenericProgressDialog::ProgressDialogState m_state
;
90 bool m_progressBarMarquee
;
93 // Bit field that indicates fields that have been modified by the
94 // main thread so the task dialog runner knows what to update.
98 // Runner thread that takes care of displaying and updating the
100 class wxProgressDialogTaskRunner
: public wxThread
103 wxProgressDialogTaskRunner(wxWindow
* parent
)
104 : wxThread(wxTHREAD_JOINABLE
),
108 wxProgressDialogSharedData
* GetSharedDataObject()
109 { return &m_sharedData
; }
113 wxProgressDialogSharedData m_sharedData
;
115 virtual void* Entry();
117 static HRESULT CALLBACK
TaskDialogCallbackProc(HWND hwnd
,
124 // ============================================================================
126 // ============================================================================
131 bool UsesCloseButtonOnly(long style
)
133 return !((style
& wxPD_CAN_ABORT
) || (style
& wxPD_AUTO_HIDE
));
136 BOOL CALLBACK
DisplayCloseButton(HWND hwnd
, LPARAM lParam
)
138 wxProgressDialogSharedData
*sharedData
=
139 (wxProgressDialogSharedData
*) lParam
;
141 if ( wxGetWindowText( hwnd
) == sharedData
->m_labelCancel
)
143 sharedData
->m_labelCancel
= _("Close");
144 SendMessage( hwnd
, WM_SETTEXT
, 0,
145 (LPARAM
) sharedData
->m_labelCancel
.wx_str() );
153 void PerformNotificationUpdates(HWND hwnd
,
154 wxProgressDialogSharedData
*sharedData
)
156 // Update the appropriate dialog fields.
157 if ( sharedData
->m_notifications
& wxSPDD_RANGE_CHANGED
)
160 TDM_SET_PROGRESS_BAR_RANGE
,
162 MAKELPARAM(0, sharedData
->m_range
) );
165 if ( sharedData
->m_notifications
& wxSPDD_VALUE_CHANGED
)
168 TDM_SET_PROGRESS_BAR_POS
,
173 if ( sharedData
->m_notifications
& wxSPDD_PBMARQUEE_CHANGED
)
175 BOOL val
= sharedData
->m_progressBarMarquee
? TRUE
: FALSE
;
177 TDM_SET_MARQUEE_PROGRESS_BAR
,
181 TDM_SET_PROGRESS_BAR_MARQUEE
,
186 if ( sharedData
->m_notifications
& wxSPDD_TITLE_CHANGED
)
187 ::SetWindowText( hwnd
, sharedData
->m_title
.wx_str() );
189 if ( sharedData
->m_notifications
& wxSPDD_MESSAGE_CHANGED
)
191 // Split the message in the title string and the rest if it has
194 title
= sharedData
->m_message
,
197 const size_t posNL
= title
.find('\n');
198 if ( posNL
!= wxString::npos
)
200 // There can an extra new line between the first and subsequent
201 // lines to separate them as it looks better with the generic
202 // version -- but in this one, they're already separated by the use
203 // of different dialog elements, so suppress the extra new line.
205 if ( posNL
< title
.length() - 1 && title
[posNL
+ 1] == '\n' )
208 body
.assign(title
, posNL
+ numNLs
, wxString::npos
);
213 TDM_SET_ELEMENT_TEXT
,
214 TDE_MAIN_INSTRUCTION
,
215 (LPARAM
) title
.wx_str() );
218 TDM_SET_ELEMENT_TEXT
,
220 (LPARAM
) body
.wx_str() );
223 if ( sharedData
->m_notifications
& wxSPDD_EXPINFO_CHANGED
)
225 const wxString
& expandedInformation
=
226 sharedData
->m_expandedInformation
;
227 if ( !expandedInformation
.empty() )
230 TDM_SET_ELEMENT_TEXT
,
231 TDE_EXPANDED_INFORMATION
,
232 (LPARAM
) expandedInformation
.wx_str() );
236 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_SKIP
)
237 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, TRUE
);
239 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_ABORT
)
240 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
242 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_SKIP
)
243 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
245 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_ABORT
)
246 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
248 // Is the progress finished?
249 if ( sharedData
->m_notifications
& wxSPDD_FINISHED
)
251 sharedData
->m_state
= wxGenericProgressDialog::Finished
;
253 if ( !(sharedData
->m_style
& wxPD_AUTO_HIDE
) )
255 // Change Cancel into Close and activate the button.
256 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
257 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
258 ::EnumChildWindows( hwnd
, DisplayCloseButton
,
259 (LPARAM
) sharedData
);
264 } // anonymous namespace
266 #endif // wxHAS_MSW_TASKDIALOG
268 // ============================================================================
269 // wxProgressDialog implementation
270 // ============================================================================
272 wxProgressDialog::wxProgressDialog( const wxString
& title
,
273 const wxString
& message
,
277 : wxGenericProgressDialog(parent
, maximum
, style
),
278 m_taskDialogRunner(NULL
),
283 #ifdef wxHAS_MSW_TASKDIALOG
284 if ( HasNativeProgressDialog() )
287 DisableOtherWindows();
291 #endif // wxHAS_MSW_TASKDIALOG
293 Create(title
, message
, maximum
, parent
, style
);
296 wxProgressDialog::~wxProgressDialog()
298 #ifdef wxHAS_MSW_TASKDIALOG
299 if ( !m_taskDialogRunner
)
304 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
305 m_sharedData
->m_notifications
|= wxSPDD_DESTROYED
;
308 m_taskDialogRunner
->Wait();
310 delete m_taskDialogRunner
;
312 ReenableOtherWindows();
314 if ( GetTopParent() )
315 GetTopParent()->Raise();
316 #endif // wxHAS_MSW_TASKDIALOG
319 bool wxProgressDialog::Update(int value
, const wxString
& newmsg
, bool *skip
)
321 #ifdef wxHAS_MSW_TASKDIALOG
322 if ( HasNativeProgressDialog() )
324 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
326 // Do nothing in canceled state.
327 if ( !DoNativeBeforeUpdate(skip
) )
332 wxASSERT_MSG( value
<= m_maximum
, wxT("invalid progress value") );
334 m_sharedData
->m_value
= value
;
335 m_sharedData
->m_notifications
|= wxSPDD_VALUE_CHANGED
;
337 if ( !newmsg
.empty() )
340 m_sharedData
->m_message
= newmsg
;
341 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
344 if ( m_sharedData
->m_progressBarMarquee
)
346 m_sharedData
->m_progressBarMarquee
= false;
347 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
350 UpdateExpandedInformation( value
);
352 // Has the progress bar finished?
353 if ( value
== m_maximum
)
355 if ( m_state
== Finished
)
359 m_sharedData
->m_state
= Finished
;
360 m_sharedData
->m_notifications
|= wxSPDD_FINISHED
;
361 if( !HasFlag(wxPD_AUTO_HIDE
) && newmsg
.empty() )
363 // Provide the finishing message if the application didn't.
364 m_message
= _("Done.");
365 m_sharedData
->m_message
= m_message
;
366 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
370 return m_sharedData
->m_state
!= Canceled
;
372 #endif // wxHAS_MSW_TASKDIALOG
374 return wxGenericProgressDialog::Update( value
, newmsg
, skip
);
377 bool wxProgressDialog::Pulse(const wxString
& newmsg
, bool *skip
)
379 #ifdef wxHAS_MSW_TASKDIALOG
380 if ( HasNativeProgressDialog() )
382 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
384 // Do nothing in canceled state.
385 if ( !DoNativeBeforeUpdate(skip
) )
388 if ( !m_sharedData
->m_progressBarMarquee
)
390 m_sharedData
->m_progressBarMarquee
= true;
391 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
394 if ( !newmsg
.empty() )
397 m_sharedData
->m_message
= newmsg
;
398 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
401 // The value passed here doesn't matter, only elapsed time makes sense
402 // in indeterminate mode anyhow.
403 UpdateExpandedInformation(0);
405 return m_sharedData
->m_state
!= Canceled
;
407 #endif // wxHAS_MSW_TASKDIALOG
409 return wxGenericProgressDialog::Pulse( newmsg
, skip
);
412 bool wxProgressDialog::DoNativeBeforeUpdate(bool *skip
)
414 #ifdef wxHAS_MSW_TASKDIALOG
415 if ( HasNativeProgressDialog() )
417 if ( m_sharedData
->m_skipped
)
419 if ( skip
&& !*skip
)
422 m_sharedData
->m_skipped
= false;
423 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
427 if ( m_sharedData
->m_state
== Canceled
)
428 m_timeStop
= m_sharedData
->m_timeStop
;
430 return m_sharedData
->m_state
!= Canceled
;
432 #endif // wxHAS_MSW_TASKDIALOG
435 wxFAIL_MSG( "unreachable" );
440 void wxProgressDialog::Resume()
442 wxGenericProgressDialog::Resume();
444 #ifdef wxHAS_MSW_TASKDIALOG
445 if ( HasNativeProgressDialog() )
450 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
451 m_sharedData
->m_state
= m_state
;
453 // "Skip" was disabled when "Cancel" had been clicked, so re-enable
455 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
457 if ( !UsesCloseButtonOnly(m_windowStyle
) )
458 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_ABORT
;
460 hwnd
= m_sharedData
->m_hwnd
;
461 } // Unlock m_cs, we can't call any function operating on a dialog with
462 // it locked as it can result in a deadlock if the dialog callback is
463 // called by Windows.
465 // After resuming we need to bring the window on top of the Z-order as
466 // it could be hidden by another window shown from the main thread,
467 // e.g. a confirmation dialog asking whether the user really wants to
470 // Notice that this must be done from the main thread as it owns the
471 // currently active window and attempts to do this from the task dialog
472 // thread would simply fail.
473 ::BringWindowToTop(hwnd
);
475 #endif // wxHAS_MSW_TASKDIALOG
478 int wxProgressDialog::GetValue() const
480 #ifdef wxHAS_MSW_TASKDIALOG
481 if ( HasNativeProgressDialog() )
483 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
484 return m_sharedData
->m_value
;
486 #endif // wxHAS_MSW_TASKDIALOG
488 return wxGenericProgressDialog::GetValue();
491 wxString
wxProgressDialog::GetMessage() const
493 #ifdef wxHAS_MSW_TASKDIALOG
494 if ( HasNativeProgressDialog() )
496 #endif // wxHAS_MSW_TASKDIALOG
498 return wxGenericProgressDialog::GetMessage();
501 void wxProgressDialog::SetRange(int maximum
)
503 wxGenericProgressDialog::SetRange( maximum
);
505 #ifdef wxHAS_MSW_TASKDIALOG
506 if ( HasNativeProgressDialog() )
508 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
510 m_sharedData
->m_range
= maximum
;
511 m_sharedData
->m_notifications
|= wxSPDD_RANGE_CHANGED
;
513 #endif // wxHAS_MSW_TASKDIALOG
516 bool wxProgressDialog::WasSkipped() const
518 #ifdef wxHAS_MSW_TASKDIALOG
519 if ( HasNativeProgressDialog() )
523 // Couldn't be skipped before being shown.
527 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
528 return m_sharedData
->m_skipped
;
530 #endif // wxHAS_MSW_TASKDIALOG
532 return wxGenericProgressDialog::WasSkipped();
535 bool wxProgressDialog::WasCancelled() const
537 #ifdef wxHAS_MSW_TASKDIALOG
538 if ( HasNativeProgressDialog() )
540 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
541 return m_sharedData
->m_state
== Canceled
;
543 #endif // wxHAS_MSW_TASKDIALOG
545 return wxGenericProgressDialog::WasCancelled();
548 void wxProgressDialog::SetTitle(const wxString
& title
)
550 #ifdef wxHAS_MSW_TASKDIALOG
551 if ( HasNativeProgressDialog() )
557 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
558 m_sharedData
->m_title
= title
;
559 m_sharedData
->m_notifications
= wxSPDD_TITLE_CHANGED
;
562 #endif // wxHAS_MSW_TASKDIALOG
564 wxGenericProgressDialog::SetTitle(title
);
567 wxString
wxProgressDialog::GetTitle() const
569 #ifdef wxHAS_MSW_TASKDIALOG
570 if ( HasNativeProgressDialog() )
572 #endif // wxHAS_MSW_TASKDIALOG
574 return wxGenericProgressDialog::GetTitle();
577 bool wxProgressDialog::Show(bool show
)
579 #ifdef wxHAS_MSW_TASKDIALOG
580 if ( HasNativeProgressDialog() )
582 // The dialog can't be hidden at all and showing it again after it had
583 // been shown before doesn't do anything.
584 if ( !show
|| m_taskDialogRunner
)
587 // We're showing the dialog for the first time, create the thread that
589 m_taskDialogRunner
= new wxProgressDialogTaskRunner(GetParent());
590 m_sharedData
= m_taskDialogRunner
->GetSharedDataObject();
592 // Initialize shared data.
593 m_sharedData
->m_title
= m_title
;
594 m_sharedData
->m_message
= m_message
;
595 m_sharedData
->m_range
= m_maximum
;
596 m_sharedData
->m_state
= Uncancelable
;
597 m_sharedData
->m_style
= m_windowStyle
;
599 if ( HasFlag(wxPD_CAN_ABORT
) )
601 m_sharedData
->m_state
= Continue
;
602 m_sharedData
->m_labelCancel
= _("Cancel");
604 else if ( !HasFlag(wxPD_AUTO_HIDE
) )
606 m_sharedData
->m_labelCancel
= _("Close");
609 if ( m_windowStyle
& (wxPD_ELAPSED_TIME
610 | wxPD_ESTIMATED_TIME
611 | wxPD_REMAINING_TIME
) )
613 // Use a non-empty string just to have the collapsible pane shown.
614 m_sharedData
->m_expandedInformation
= " ";
617 // Do launch the thread.
618 if ( m_taskDialogRunner
->Create() != wxTHREAD_NO_ERROR
)
620 wxLogError( "Unable to create thread!" );
624 if ( m_taskDialogRunner
->Run() != wxTHREAD_NO_ERROR
)
626 wxLogError( "Unable to start thread!" );
630 if ( !HasFlag(wxPD_APP_MODAL
) )
631 GetParent()->Disable();
632 //else: otherwise all windows will be disabled by m_taskDialogRunner
634 // Do not show the underlying dialog.
637 #endif // wxHAS_MSW_TASKDIALOG
639 return wxGenericProgressDialog::Show( show
);
642 bool wxProgressDialog::HasNativeProgressDialog() const
644 #ifdef wxHAS_MSW_TASKDIALOG
645 // For a native implementation task dialogs are required, which
646 // also require at least one button to be present so the flags needs
647 // to be checked as well to see if this is the case.
648 return HasNativeTaskDialog()
649 && ((m_windowStyle
& (wxPD_CAN_SKIP
| wxPD_CAN_ABORT
))
650 || !(m_windowStyle
& wxPD_AUTO_HIDE
));
651 #else // !wxHAS_MSW_TASKDIALOG
652 // This shouldn't be even called in !wxHAS_MSW_TASKDIALOG case but as we
653 // still must define the function as returning something, return false.
655 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
658 void wxProgressDialog::UpdateExpandedInformation(int value
)
660 #ifdef wxHAS_MSW_TASKDIALOG
661 unsigned long elapsedTime
;
662 unsigned long estimatedTime
;
663 unsigned long remainingTime
;
664 UpdateTimeEstimates(value
, elapsedTime
, estimatedTime
, remainingTime
);
666 int realEstimatedTime
= estimatedTime
,
667 realRemainingTime
= remainingTime
;
668 if ( m_sharedData
->m_progressBarMarquee
)
670 // In indeterminate mode we don't have any estimation neither for the
671 // remaining nor for estimated time.
673 realRemainingTime
= -1;
676 wxString expandedInformation
;
678 // Calculate the three different timing values.
679 if ( m_windowStyle
& wxPD_ELAPSED_TIME
)
681 expandedInformation
<< GetElapsedLabel()
683 << GetFormattedTime(elapsedTime
);
686 if ( m_windowStyle
& wxPD_ESTIMATED_TIME
)
688 if ( !expandedInformation
.empty() )
689 expandedInformation
+= "\n";
691 expandedInformation
<< GetEstimatedLabel()
693 << GetFormattedTime(realEstimatedTime
);
696 if ( m_windowStyle
& wxPD_REMAINING_TIME
)
698 if ( !expandedInformation
.empty() )
699 expandedInformation
+= "\n";
701 expandedInformation
<< GetRemainingLabel()
703 << GetFormattedTime(realRemainingTime
);
706 // Update with new timing information.
707 if ( expandedInformation
!= m_sharedData
->m_expandedInformation
)
709 m_sharedData
->m_expandedInformation
= expandedInformation
;
710 m_sharedData
->m_notifications
|= wxSPDD_EXPINFO_CHANGED
;
712 #else // !wxHAS_MSW_TASKDIALOG
714 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
717 // ----------------------------------------------------------------------------
718 // wxProgressDialogTaskRunner and related methods
719 // ----------------------------------------------------------------------------
721 #ifdef wxHAS_MSW_TASKDIALOG
723 void* wxProgressDialogTaskRunner::Entry()
725 WinStruct
<TASKDIALOGCONFIG
> tdc
;
726 wxMSWTaskDialogConfig wxTdc
;
729 wxCriticalSectionLocker
locker(m_sharedData
.m_cs
);
731 wxTdc
.caption
= m_sharedData
.m_title
.wx_str();
732 wxTdc
.message
= m_sharedData
.m_message
.wx_str();
734 wxTdc
.MSWCommonTaskDialogInit( tdc
);
735 tdc
.pfCallback
= TaskDialogCallbackProc
;
736 tdc
.lpCallbackData
= (LONG_PTR
) &m_sharedData
;
738 // Undo some of the effects of MSWCommonTaskDialogInit().
739 tdc
.dwFlags
&= ~TDF_EXPAND_FOOTER_AREA
; // Expand in content area.
740 tdc
.dwCommonButtons
= 0; // Don't use common buttons.
742 wxTdc
.useCustomLabels
= true;
744 if ( m_sharedData
.m_style
& wxPD_CAN_SKIP
)
745 wxTdc
.AddTaskDialogButton( tdc
, Id_SkipBtn
, 0, _("Skip") );
747 // Use a Cancel button when requested or use a Close button when
748 // the dialog does not automatically hide.
749 if ( (m_sharedData
.m_style
& wxPD_CAN_ABORT
)
750 || !(m_sharedData
.m_style
& wxPD_AUTO_HIDE
) )
752 wxTdc
.AddTaskDialogButton( tdc
, IDCANCEL
, 0,
753 m_sharedData
.m_labelCancel
);
756 tdc
.dwFlags
|= TDF_CALLBACK_TIMER
757 | TDF_SHOW_PROGRESS_BAR
758 | TDF_SHOW_MARQUEE_PROGRESS_BAR
;
760 if ( !m_sharedData
.m_expandedInformation
.empty() )
762 tdc
.pszExpandedInformation
=
763 m_sharedData
.m_expandedInformation
.wx_str();
767 TaskDialogIndirect_t taskDialogIndirect
= GetTaskDialogIndirectFunc();
768 if ( !taskDialogIndirect
)
772 HRESULT hr
= taskDialogIndirect(&tdc
, &msAns
, NULL
, NULL
);
774 wxLogApiError( "TaskDialogIndirect", hr
);
781 wxProgressDialogTaskRunner::TaskDialogCallbackProc
786 LPARAM
WXUNUSED(lParam
),
790 wxProgressDialogSharedData
* const sharedData
=
791 (wxProgressDialogSharedData
*) dwRefData
;
793 wxCriticalSectionLocker
locker(sharedData
->m_cs
);
795 switch ( uNotification
)
798 // Store the HWND for the main thread use.
799 sharedData
->m_hwnd
= hwnd
;
801 // Set the maximum value and disable Close button.
803 TDM_SET_PROGRESS_BAR_RANGE
,
805 MAKELPARAM(0, sharedData
->m_range
) );
807 if ( UsesCloseButtonOnly(sharedData
->m_style
) )
808 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
811 case TDN_BUTTON_CLICKED
:
815 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
816 sharedData
->m_skipped
= true;
820 if ( sharedData
->m_state
821 == wxGenericProgressDialog::Finished
)
826 // Close button on the window triggers an IDCANCEL press,
827 // don't allow it when it should only be possible to close
828 // a finished dialog.
829 if ( !UsesCloseButtonOnly(sharedData
->m_style
) )
831 wxCHECK_MSG( sharedData
->m_state
==
832 wxGenericProgressDialog::Continue
,
834 "Dialog not in a cancelable state!");
836 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
837 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
839 sharedData
->m_timeStop
= wxGetCurrentTime();
840 sharedData
->m_state
= wxGenericProgressDialog::Canceled
;
848 PerformNotificationUpdates(hwnd
, sharedData
);
850 // End dialog in three different cases:
851 // 1. Progress finished and dialog should automatically hide.
852 // 2. The wxProgressDialog object was destructed and should
853 // automatically hide.
854 // 3. The dialog was canceled and wxProgressDialog object
857 sharedData
->m_state
== wxGenericProgressDialog::Canceled
;
859 sharedData
->m_state
== wxGenericProgressDialog::Finished
;
861 (sharedData
->m_notifications
& wxSPDD_DESTROYED
) != 0;
862 bool shouldAutoHide
= (sharedData
->m_style
& wxPD_AUTO_HIDE
) != 0;
864 if ( (shouldAutoHide
&& (isFinished
|| wasDestroyed
))
865 || (wasDestroyed
&& isCanceled
) )
867 ::EndDialog( hwnd
, IDCLOSE
);
870 sharedData
->m_notifications
= 0;
879 #endif // wxHAS_MSW_TASKDIALOG
881 #endif // wxUSE_PROGRESSDLG && wxUSE_THREADS