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"
30 #include "wx/evtloop.h"
32 using namespace wxMSWMessageDialog
;
34 #ifdef wxHAS_MSW_TASKDIALOG
36 // ----------------------------------------------------------------------------
38 // ----------------------------------------------------------------------------
43 // Notification values of wxProgressDialogSharedData::m_notifications
44 const int wxSPDD_VALUE_CHANGED
= 0x0001;
45 const int wxSPDD_RANGE_CHANGED
= 0x0002;
46 const int wxSPDD_PBMARQUEE_CHANGED
= 0x0004;
47 const int wxSPDD_TITLE_CHANGED
= 0x0008;
48 const int wxSPDD_MESSAGE_CHANGED
= 0x0010;
49 const int wxSPDD_EXPINFO_CHANGED
= 0x0020;
50 const int wxSPDD_ENABLE_SKIP
= 0x0040;
51 const int wxSPDD_ENABLE_ABORT
= 0x0080;
52 const int wxSPDD_DISABLE_SKIP
= 0x0100;
53 const int wxSPDD_DISABLE_ABORT
= 0x0200;
54 const int wxSPDD_FINISHED
= 0x0400;
55 const int wxSPDD_DESTROYED
= 0x0800;
57 const int Id_SkipBtn
= wxID_HIGHEST
+ 1;
59 } // anonymous namespace
61 // ============================================================================
63 // ============================================================================
65 // Class used to share data between the main thread and the task dialog runner.
66 class wxProgressDialogSharedData
69 wxProgressDialogSharedData()
73 m_progressBarMarquee
= false;
78 wxCriticalSection m_cs
;
80 HWND m_hwnd
; // Task dialog handler
81 long m_style
; // wxProgressDialog style
86 wxString m_expandedInformation
;
87 wxString m_labelCancel
; // Privately used by callback.
88 unsigned long m_timeStop
;
90 wxProgressDialog::State m_state
;
91 bool m_progressBarMarquee
;
94 // Bit field that indicates fields that have been modified by the
95 // main thread so the task dialog runner knows what to update.
99 // Runner thread that takes care of displaying and updating the
101 class wxProgressDialogTaskRunner
: public wxThread
104 wxProgressDialogTaskRunner()
105 : wxThread(wxTHREAD_JOINABLE
)
108 wxProgressDialogSharedData
* GetSharedDataObject()
109 { return &m_sharedData
; }
112 wxProgressDialogSharedData m_sharedData
;
114 virtual void* Entry();
116 static HRESULT CALLBACK
TaskDialogCallbackProc(HWND hwnd
,
126 // A custom event loop which runs until the state of the dialog becomes
128 class wxProgressDialogModalLoop
: public wxEventLoop
131 wxProgressDialogModalLoop(wxProgressDialogSharedData
& data
)
137 virtual void OnNextIteration()
139 wxCriticalSectionLocker
locker(m_data
.m_cs
);
141 if ( m_data
.m_state
== wxProgressDialog::Dismissed
)
145 wxProgressDialogSharedData
& m_data
;
147 wxDECLARE_NO_COPY_CLASS(wxProgressDialogModalLoop
);
150 // ============================================================================
152 // ============================================================================
154 BOOL CALLBACK
DisplayCloseButton(HWND hwnd
, LPARAM lParam
)
156 wxProgressDialogSharedData
*sharedData
=
157 (wxProgressDialogSharedData
*) lParam
;
159 if ( wxGetWindowText( hwnd
) == sharedData
->m_labelCancel
)
161 sharedData
->m_labelCancel
= _("Close");
162 SendMessage( hwnd
, WM_SETTEXT
, 0,
163 (LPARAM
) sharedData
->m_labelCancel
.wx_str() );
171 void PerformNotificationUpdates(HWND hwnd
,
172 wxProgressDialogSharedData
*sharedData
)
174 // Update the appropriate dialog fields.
175 if ( sharedData
->m_notifications
& wxSPDD_RANGE_CHANGED
)
178 TDM_SET_PROGRESS_BAR_RANGE
,
180 MAKELPARAM(0, sharedData
->m_range
) );
183 if ( sharedData
->m_notifications
& wxSPDD_VALUE_CHANGED
)
186 TDM_SET_PROGRESS_BAR_POS
,
191 if ( sharedData
->m_notifications
& wxSPDD_PBMARQUEE_CHANGED
)
193 BOOL val
= sharedData
->m_progressBarMarquee
? TRUE
: FALSE
;
195 TDM_SET_MARQUEE_PROGRESS_BAR
,
199 TDM_SET_PROGRESS_BAR_MARQUEE
,
204 if ( sharedData
->m_notifications
& wxSPDD_TITLE_CHANGED
)
205 ::SetWindowText( hwnd
, sharedData
->m_title
.wx_str() );
207 if ( sharedData
->m_notifications
& wxSPDD_MESSAGE_CHANGED
)
209 // Split the message in the title string and the rest if it has
212 title
= sharedData
->m_message
,
215 const size_t posNL
= title
.find('\n');
216 if ( posNL
!= wxString::npos
)
218 // There can an extra new line between the first and subsequent
219 // lines to separate them as it looks better with the generic
220 // version -- but in this one, they're already separated by the use
221 // of different dialog elements, so suppress the extra new line.
223 if ( posNL
< title
.length() - 1 && title
[posNL
+ 1] == '\n' )
226 body
.assign(title
, posNL
+ numNLs
, wxString::npos
);
231 TDM_SET_ELEMENT_TEXT
,
232 TDE_MAIN_INSTRUCTION
,
233 (LPARAM
) title
.wx_str() );
236 TDM_SET_ELEMENT_TEXT
,
238 (LPARAM
) body
.wx_str() );
241 if ( sharedData
->m_notifications
& wxSPDD_EXPINFO_CHANGED
)
243 const wxString
& expandedInformation
=
244 sharedData
->m_expandedInformation
;
245 if ( !expandedInformation
.empty() )
248 TDM_SET_ELEMENT_TEXT
,
249 TDE_EXPANDED_INFORMATION
,
250 (LPARAM
) expandedInformation
.wx_str() );
254 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_SKIP
)
255 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, TRUE
);
257 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_ABORT
)
258 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
260 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_SKIP
)
261 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
263 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_ABORT
)
264 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
266 // Is the progress finished?
267 if ( sharedData
->m_notifications
& wxSPDD_FINISHED
)
269 sharedData
->m_state
= wxProgressDialog::Finished
;
271 if ( !(sharedData
->m_style
& wxPD_AUTO_HIDE
) )
273 // Change Cancel into Close and activate the button.
274 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
275 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
276 ::EnumChildWindows( hwnd
, DisplayCloseButton
,
277 (LPARAM
) sharedData
);
282 } // anonymous namespace
284 #endif // wxHAS_MSW_TASKDIALOG
286 // ============================================================================
287 // wxProgressDialog implementation
288 // ============================================================================
290 wxProgressDialog::wxProgressDialog( const wxString
& title
,
291 const wxString
& message
,
295 : wxGenericProgressDialog(parent
, style
),
296 m_taskDialogRunner(NULL
),
301 #ifdef wxHAS_MSW_TASKDIALOG
302 if ( HasNativeTaskDialog() )
307 DisableOtherWindows();
311 #endif // wxHAS_MSW_TASKDIALOG
313 Create(title
, message
, maximum
, parent
, style
);
316 wxProgressDialog::~wxProgressDialog()
318 #ifdef wxHAS_MSW_TASKDIALOG
319 if ( !m_taskDialogRunner
)
324 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
325 m_sharedData
->m_notifications
|= wxSPDD_DESTROYED
;
328 m_taskDialogRunner
->Wait();
330 delete m_taskDialogRunner
;
332 ReenableOtherWindows();
334 if ( GetTopParent() )
335 GetTopParent()->Raise();
336 #endif // wxHAS_MSW_TASKDIALOG
339 bool wxProgressDialog::Update(int value
, const wxString
& newmsg
, bool *skip
)
341 #ifdef wxHAS_MSW_TASKDIALOG
342 if ( HasNativeTaskDialog() )
345 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
347 // Do nothing in canceled state.
348 if ( !DoNativeBeforeUpdate(skip
) )
353 wxASSERT_MSG( value
<= m_maximum
, wxT("invalid progress value") );
355 m_sharedData
->m_value
= value
;
356 m_sharedData
->m_notifications
|= wxSPDD_VALUE_CHANGED
;
358 if ( !newmsg
.empty() )
361 m_sharedData
->m_message
= newmsg
;
362 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
365 if ( m_sharedData
->m_progressBarMarquee
)
367 m_sharedData
->m_progressBarMarquee
= false;
368 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
371 UpdateExpandedInformation( value
);
373 // If we didn't just reach the finish, all we have to do is to
374 // return true if the dialog wasn't cancelled and false otherwise.
375 if ( value
!= m_maximum
|| m_state
== Finished
)
376 return m_sharedData
->m_state
!= Canceled
;
379 // On finishing, the dialog without wxPD_AUTO_HIDE style becomes a
380 // modal one meaning that we must block here until the user
383 m_sharedData
->m_state
= Finished
;
384 m_sharedData
->m_notifications
|= wxSPDD_FINISHED
;
385 if ( HasPDFlag(wxPD_AUTO_HIDE
) )
388 if ( newmsg
.empty() )
390 // Provide the finishing message if the application didn't.
391 m_message
= _("Done.");
392 m_sharedData
->m_message
= m_message
;
393 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
395 } // unlock m_sharedData->m_cs
397 // We only get here when we need to wait for the dialog to terminate so
398 // do just this by running a custom event loop until the dialog is
400 wxProgressDialogModalLoop
loop(*m_sharedData
);
404 #endif // wxHAS_MSW_TASKDIALOG
406 return wxGenericProgressDialog::Update( value
, newmsg
, skip
);
409 bool wxProgressDialog::Pulse(const wxString
& newmsg
, bool *skip
)
411 #ifdef wxHAS_MSW_TASKDIALOG
412 if ( HasNativeTaskDialog() )
414 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
416 // Do nothing in canceled state.
417 if ( !DoNativeBeforeUpdate(skip
) )
420 if ( !m_sharedData
->m_progressBarMarquee
)
422 m_sharedData
->m_progressBarMarquee
= true;
423 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
426 if ( !newmsg
.empty() )
429 m_sharedData
->m_message
= newmsg
;
430 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
433 // The value passed here doesn't matter, only elapsed time makes sense
434 // in indeterminate mode anyhow.
435 UpdateExpandedInformation(0);
437 return m_sharedData
->m_state
!= Canceled
;
439 #endif // wxHAS_MSW_TASKDIALOG
441 return wxGenericProgressDialog::Pulse( newmsg
, skip
);
444 bool wxProgressDialog::DoNativeBeforeUpdate(bool *skip
)
446 #ifdef wxHAS_MSW_TASKDIALOG
447 if ( HasNativeTaskDialog() )
449 if ( m_sharedData
->m_skipped
)
451 if ( skip
&& !*skip
)
454 m_sharedData
->m_skipped
= false;
455 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
459 if ( m_sharedData
->m_state
== Canceled
)
460 m_timeStop
= m_sharedData
->m_timeStop
;
462 return m_sharedData
->m_state
!= Canceled
;
464 #endif // wxHAS_MSW_TASKDIALOG
467 wxFAIL_MSG( "unreachable" );
472 void wxProgressDialog::Resume()
474 wxGenericProgressDialog::Resume();
476 #ifdef wxHAS_MSW_TASKDIALOG
477 if ( HasNativeTaskDialog() )
482 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
483 m_sharedData
->m_state
= m_state
;
485 // "Skip" was disabled when "Cancel" had been clicked, so re-enable
487 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
489 // Also re-enable "Cancel" itself
490 if ( HasPDFlag(wxPD_CAN_ABORT
) )
491 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_ABORT
;
493 hwnd
= m_sharedData
->m_hwnd
;
494 } // Unlock m_cs, we can't call any function operating on a dialog with
495 // it locked as it can result in a deadlock if the dialog callback is
496 // called by Windows.
498 // After resuming we need to bring the window on top of the Z-order as
499 // it could be hidden by another window shown from the main thread,
500 // e.g. a confirmation dialog asking whether the user really wants to
503 // Notice that this must be done from the main thread as it owns the
504 // currently active window and attempts to do this from the task dialog
505 // thread would simply fail.
506 ::BringWindowToTop(hwnd
);
508 #endif // wxHAS_MSW_TASKDIALOG
511 int wxProgressDialog::GetValue() const
513 #ifdef wxHAS_MSW_TASKDIALOG
514 if ( HasNativeTaskDialog() )
516 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
517 return m_sharedData
->m_value
;
519 #endif // wxHAS_MSW_TASKDIALOG
521 return wxGenericProgressDialog::GetValue();
524 wxString
wxProgressDialog::GetMessage() const
526 #ifdef wxHAS_MSW_TASKDIALOG
527 if ( HasNativeTaskDialog() )
529 #endif // wxHAS_MSW_TASKDIALOG
531 return wxGenericProgressDialog::GetMessage();
534 void wxProgressDialog::SetRange(int maximum
)
536 #ifdef wxHAS_MSW_TASKDIALOG
537 if ( HasNativeTaskDialog() )
541 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
543 m_sharedData
->m_range
= maximum
;
544 m_sharedData
->m_notifications
|= wxSPDD_RANGE_CHANGED
;
548 #endif // wxHAS_MSW_TASKDIALOG
550 wxGenericProgressDialog::SetRange( maximum
);
553 bool wxProgressDialog::WasSkipped() const
555 #ifdef wxHAS_MSW_TASKDIALOG
556 if ( HasNativeTaskDialog() )
560 // Couldn't be skipped before being shown.
564 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
565 return m_sharedData
->m_skipped
;
567 #endif // wxHAS_MSW_TASKDIALOG
569 return wxGenericProgressDialog::WasSkipped();
572 bool wxProgressDialog::WasCancelled() const
574 #ifdef wxHAS_MSW_TASKDIALOG
575 if ( HasNativeTaskDialog() )
577 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
578 return m_sharedData
->m_state
== Canceled
;
580 #endif // wxHAS_MSW_TASKDIALOG
582 return wxGenericProgressDialog::WasCancelled();
585 void wxProgressDialog::SetTitle(const wxString
& title
)
587 #ifdef wxHAS_MSW_TASKDIALOG
588 if ( HasNativeTaskDialog() )
594 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
595 m_sharedData
->m_title
= title
;
596 m_sharedData
->m_notifications
= wxSPDD_TITLE_CHANGED
;
599 #endif // wxHAS_MSW_TASKDIALOG
601 wxGenericProgressDialog::SetTitle(title
);
604 wxString
wxProgressDialog::GetTitle() const
606 #ifdef wxHAS_MSW_TASKDIALOG
607 if ( HasNativeTaskDialog() )
609 #endif // wxHAS_MSW_TASKDIALOG
611 return wxGenericProgressDialog::GetTitle();
614 bool wxProgressDialog::Show(bool show
)
616 #ifdef wxHAS_MSW_TASKDIALOG
617 if ( HasNativeTaskDialog() )
619 // The dialog can't be hidden at all and showing it again after it had
620 // been shown before doesn't do anything.
621 if ( !show
|| m_taskDialogRunner
)
624 // We're showing the dialog for the first time, create the thread that
626 m_taskDialogRunner
= new wxProgressDialogTaskRunner
;
627 m_sharedData
= m_taskDialogRunner
->GetSharedDataObject();
629 // Initialize shared data.
630 m_sharedData
->m_title
= m_title
;
631 m_sharedData
->m_message
= m_message
;
632 m_sharedData
->m_range
= m_maximum
;
633 m_sharedData
->m_state
= Uncancelable
;
634 m_sharedData
->m_style
= GetPDStyle();
636 if ( HasPDFlag(wxPD_CAN_ABORT
) )
638 m_sharedData
->m_state
= Continue
;
639 m_sharedData
->m_labelCancel
= _("Cancel");
641 else // Dialog can't be cancelled.
643 // We still must have at least a single button in the dialog so
644 // just don't call it "Cancel" in this case.
645 m_sharedData
->m_labelCancel
= _("Close");
648 if ( HasPDFlag(wxPD_ELAPSED_TIME
|
649 wxPD_ESTIMATED_TIME
|
650 wxPD_REMAINING_TIME
) )
652 // Use a non-empty string just to have the collapsible pane shown.
653 m_sharedData
->m_expandedInformation
= " ";
656 // Do launch the thread.
657 if ( m_taskDialogRunner
->Create() != wxTHREAD_NO_ERROR
)
659 wxLogError( "Unable to create thread!" );
663 if ( m_taskDialogRunner
->Run() != wxTHREAD_NO_ERROR
)
665 wxLogError( "Unable to start thread!" );
669 // Do not show the underlying dialog.
672 #endif // wxHAS_MSW_TASKDIALOG
674 return wxGenericProgressDialog::Show( show
);
677 void wxProgressDialog::UpdateExpandedInformation(int value
)
679 #ifdef wxHAS_MSW_TASKDIALOG
680 unsigned long elapsedTime
;
681 unsigned long estimatedTime
;
682 unsigned long remainingTime
;
683 UpdateTimeEstimates(value
, elapsedTime
, estimatedTime
, remainingTime
);
685 int realEstimatedTime
= estimatedTime
,
686 realRemainingTime
= remainingTime
;
687 if ( m_sharedData
->m_progressBarMarquee
)
689 // In indeterminate mode we don't have any estimation neither for the
690 // remaining nor for estimated time.
692 realRemainingTime
= -1;
695 wxString expandedInformation
;
697 // Calculate the three different timing values.
698 if ( HasPDFlag(wxPD_ELAPSED_TIME
) )
700 expandedInformation
<< GetElapsedLabel()
702 << GetFormattedTime(elapsedTime
);
705 if ( HasPDFlag(wxPD_ESTIMATED_TIME
) )
707 if ( !expandedInformation
.empty() )
708 expandedInformation
+= "\n";
710 expandedInformation
<< GetEstimatedLabel()
712 << GetFormattedTime(realEstimatedTime
);
715 if ( HasPDFlag(wxPD_REMAINING_TIME
) )
717 if ( !expandedInformation
.empty() )
718 expandedInformation
+= "\n";
720 expandedInformation
<< GetRemainingLabel()
722 << GetFormattedTime(realRemainingTime
);
725 // Update with new timing information.
726 if ( expandedInformation
!= m_sharedData
->m_expandedInformation
)
728 m_sharedData
->m_expandedInformation
= expandedInformation
;
729 m_sharedData
->m_notifications
|= wxSPDD_EXPINFO_CHANGED
;
731 #else // !wxHAS_MSW_TASKDIALOG
733 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
736 // ----------------------------------------------------------------------------
737 // wxProgressDialogTaskRunner and related methods
738 // ----------------------------------------------------------------------------
740 #ifdef wxHAS_MSW_TASKDIALOG
742 void* wxProgressDialogTaskRunner::Entry()
744 WinStruct
<TASKDIALOGCONFIG
> tdc
;
745 wxMSWTaskDialogConfig wxTdc
;
748 wxCriticalSectionLocker
locker(m_sharedData
.m_cs
);
750 wxTdc
.caption
= m_sharedData
.m_title
.wx_str();
751 wxTdc
.message
= m_sharedData
.m_message
.wx_str();
753 wxTdc
.MSWCommonTaskDialogInit( tdc
);
754 tdc
.pfCallback
= TaskDialogCallbackProc
;
755 tdc
.lpCallbackData
= (LONG_PTR
) &m_sharedData
;
757 // Undo some of the effects of MSWCommonTaskDialogInit().
758 tdc
.dwFlags
&= ~TDF_EXPAND_FOOTER_AREA
; // Expand in content area.
759 tdc
.dwCommonButtons
= 0; // Don't use common buttons.
761 wxTdc
.useCustomLabels
= true;
763 if ( m_sharedData
.m_style
& wxPD_CAN_SKIP
)
764 wxTdc
.AddTaskDialogButton( tdc
, Id_SkipBtn
, 0, _("Skip") );
766 // Use a Cancel button when requested or use a Close button when
767 // the dialog does not automatically hide.
768 wxTdc
.AddTaskDialogButton( tdc
, IDCANCEL
, 0,
769 m_sharedData
.m_labelCancel
);
771 tdc
.dwFlags
|= TDF_CALLBACK_TIMER
| TDF_SHOW_PROGRESS_BAR
;
773 if ( !m_sharedData
.m_expandedInformation
.empty() )
775 tdc
.pszExpandedInformation
=
776 m_sharedData
.m_expandedInformation
.wx_str();
780 TaskDialogIndirect_t taskDialogIndirect
= GetTaskDialogIndirectFunc();
781 if ( !taskDialogIndirect
)
785 HRESULT hr
= taskDialogIndirect(&tdc
, &msAns
, NULL
, NULL
);
787 wxLogApiError( "TaskDialogIndirect", hr
);
789 // If the main thread is waiting for us to exit inside the event loop in
790 // Update(), wake it up so that it checks our status again.
798 wxProgressDialogTaskRunner::TaskDialogCallbackProc
803 LPARAM
WXUNUSED(lParam
),
807 wxProgressDialogSharedData
* const sharedData
=
808 (wxProgressDialogSharedData
*) dwRefData
;
810 wxCriticalSectionLocker
locker(sharedData
->m_cs
);
812 switch ( uNotification
)
815 // Store the HWND for the main thread use.
816 sharedData
->m_hwnd
= hwnd
;
818 // Set the maximum value and disable Close button.
820 TDM_SET_PROGRESS_BAR_RANGE
,
822 MAKELPARAM(0, sharedData
->m_range
) );
824 // If we can't be aborted, the "Close" button will only be enabled
825 // when the progress ends (and not even then with wxPD_AUTO_HIDE).
826 if ( !(sharedData
->m_style
& wxPD_CAN_ABORT
) )
827 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
830 case TDN_BUTTON_CLICKED
:
834 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
835 sharedData
->m_skipped
= true;
839 if ( sharedData
->m_state
== wxProgressDialog::Finished
)
841 // If the main thread is waiting for us, tell it that
842 // we're gone (and if it doesn't wait, it's harmless).
843 sharedData
->m_state
= wxProgressDialog::Dismissed
;
845 // Let Windows close the dialog.
849 // Close button on the window triggers an IDCANCEL press,
850 // don't allow it when it should only be possible to close
851 // a finished dialog.
852 if ( sharedData
->m_style
& wxPD_CAN_ABORT
)
856 sharedData
->m_state
== wxProgressDialog::Continue
,
858 "Dialog not in a cancelable state!"
861 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
862 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
864 sharedData
->m_timeStop
= wxGetCurrentTime();
865 sharedData
->m_state
= wxProgressDialog::Canceled
;
873 PerformNotificationUpdates(hwnd
, sharedData
);
876 Decide whether we should end the dialog. This is done if either
877 the dialog object itself was destroyed or if the progress
878 finished and we were configured to hide automatically without
879 waiting for the user to dismiss us.
881 Notice that we do not close the dialog if it was cancelled
882 because it's up to the user code in the main thread to decide
883 whether it really wants to cancel the dialog.
885 if ( (sharedData
->m_notifications
& wxSPDD_DESTROYED
) ||
886 (sharedData
->m_state
== wxProgressDialog::Finished
&&
887 sharedData
->m_style
& wxPD_AUTO_HIDE
) )
889 ::EndDialog( hwnd
, IDCLOSE
);
892 sharedData
->m_notifications
= 0;
901 #endif // wxHAS_MSW_TASKDIALOG
903 #endif // wxUSE_PROGRESSDLG && wxUSE_THREADS