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 wxProgressDialog
::State 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()
104 : wxThread(wxTHREAD_JOINABLE
)
107 wxProgressDialogSharedData
* GetSharedDataObject()
108 { return &m_sharedData
; }
111 wxProgressDialogSharedData m_sharedData
;
113 virtual void* Entry();
115 static HRESULT CALLBACK
TaskDialogCallbackProc(HWND hwnd
,
122 // ============================================================================
124 // ============================================================================
129 // This function returns true if the progress dialog with the given style
130 // (combination of wxPD_XXX constants) needs the "Close" button and this button
131 // only, i.e. not a "Cancel" one.
132 bool UsesCloseButtonOnly(long style
)
134 return !(style
& (wxPD_CAN_ABORT
| wxPD_AUTO_HIDE
));
137 BOOL CALLBACK
DisplayCloseButton(HWND hwnd
, LPARAM lParam
)
139 wxProgressDialogSharedData
*sharedData
=
140 (wxProgressDialogSharedData
*) lParam
;
142 if ( wxGetWindowText( hwnd
) == sharedData
->m_labelCancel
)
144 sharedData
->m_labelCancel
= _("Close");
145 SendMessage( hwnd
, WM_SETTEXT
, 0,
146 (LPARAM
) sharedData
->m_labelCancel
.wx_str() );
154 void PerformNotificationUpdates(HWND hwnd
,
155 wxProgressDialogSharedData
*sharedData
)
157 // Update the appropriate dialog fields.
158 if ( sharedData
->m_notifications
& wxSPDD_RANGE_CHANGED
)
161 TDM_SET_PROGRESS_BAR_RANGE
,
163 MAKELPARAM(0, sharedData
->m_range
) );
166 if ( sharedData
->m_notifications
& wxSPDD_VALUE_CHANGED
)
169 TDM_SET_PROGRESS_BAR_POS
,
174 if ( sharedData
->m_notifications
& wxSPDD_PBMARQUEE_CHANGED
)
176 BOOL val
= sharedData
->m_progressBarMarquee ? TRUE
: FALSE
;
178 TDM_SET_MARQUEE_PROGRESS_BAR
,
182 TDM_SET_PROGRESS_BAR_MARQUEE
,
187 if ( sharedData
->m_notifications
& wxSPDD_TITLE_CHANGED
)
188 ::SetWindowText( hwnd
, sharedData
->m_title
.wx_str() );
190 if ( sharedData
->m_notifications
& wxSPDD_MESSAGE_CHANGED
)
192 // Split the message in the title string and the rest if it has
195 title
= sharedData
->m_message
,
198 const size_t posNL
= title
.find('\n');
199 if ( posNL
!= wxString
::npos
)
201 // There can an extra new line between the first and subsequent
202 // lines to separate them as it looks better with the generic
203 // version -- but in this one, they're already separated by the use
204 // of different dialog elements, so suppress the extra new line.
206 if ( posNL
< title
.length() - 1 && title
[posNL
+ 1] == '\n' )
209 body
.assign(title
, posNL
+ numNLs
, wxString
::npos
);
214 TDM_SET_ELEMENT_TEXT
,
215 TDE_MAIN_INSTRUCTION
,
216 (LPARAM
) title
.wx_str() );
219 TDM_SET_ELEMENT_TEXT
,
221 (LPARAM
) body
.wx_str() );
224 if ( sharedData
->m_notifications
& wxSPDD_EXPINFO_CHANGED
)
226 const wxString
& expandedInformation
=
227 sharedData
->m_expandedInformation
;
228 if ( !expandedInformation
.empty() )
231 TDM_SET_ELEMENT_TEXT
,
232 TDE_EXPANDED_INFORMATION
,
233 (LPARAM
) expandedInformation
.wx_str() );
237 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_SKIP
)
238 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, TRUE
);
240 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_ABORT
)
241 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
243 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_SKIP
)
244 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
246 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_ABORT
)
247 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
249 // Is the progress finished?
250 if ( sharedData
->m_notifications
& wxSPDD_FINISHED
)
252 sharedData
->m_state
= wxProgressDialog
::Finished
;
254 if ( !(sharedData
->m_style
& wxPD_AUTO_HIDE
) )
256 // Change Cancel into Close and activate the button.
257 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
258 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
259 ::EnumChildWindows( hwnd
, DisplayCloseButton
,
260 (LPARAM
) sharedData
);
265 } // anonymous namespace
267 #endif // wxHAS_MSW_TASKDIALOG
269 // ============================================================================
270 // wxProgressDialog implementation
271 // ============================================================================
273 wxProgressDialog
::wxProgressDialog( const wxString
& title
,
274 const wxString
& message
,
278 : wxGenericProgressDialog(parent
, style
),
279 m_taskDialogRunner(NULL
),
284 #ifdef wxHAS_MSW_TASKDIALOG
285 if ( HasNativeProgressDialog() )
290 DisableOtherWindows();
294 #endif // wxHAS_MSW_TASKDIALOG
296 Create(title
, message
, maximum
, parent
, style
);
299 wxProgressDialog
::~wxProgressDialog()
301 #ifdef wxHAS_MSW_TASKDIALOG
302 if ( !m_taskDialogRunner
)
307 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
308 m_sharedData
->m_notifications
|= wxSPDD_DESTROYED
;
311 m_taskDialogRunner
->Wait();
313 delete m_taskDialogRunner
;
315 ReenableOtherWindows();
317 if ( GetTopParent() )
318 GetTopParent()->Raise();
319 #endif // wxHAS_MSW_TASKDIALOG
322 bool wxProgressDialog
::Update(int value
, const wxString
& newmsg
, bool *skip
)
324 #ifdef wxHAS_MSW_TASKDIALOG
325 if ( HasNativeProgressDialog() )
327 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
329 // Do nothing in canceled state.
330 if ( !DoNativeBeforeUpdate(skip
) )
335 wxASSERT_MSG( value
<= m_maximum
, wxT("invalid progress value") );
337 m_sharedData
->m_value
= value
;
338 m_sharedData
->m_notifications
|= wxSPDD_VALUE_CHANGED
;
340 if ( !newmsg
.empty() )
343 m_sharedData
->m_message
= newmsg
;
344 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
347 if ( m_sharedData
->m_progressBarMarquee
)
349 m_sharedData
->m_progressBarMarquee
= false;
350 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
353 UpdateExpandedInformation( value
);
355 // Has the progress bar finished?
356 if ( value
== m_maximum
)
358 if ( m_state
== Finished
)
362 m_sharedData
->m_state
= Finished
;
363 m_sharedData
->m_notifications
|= wxSPDD_FINISHED
;
364 if( !HasPDFlag(wxPD_AUTO_HIDE
) && newmsg
.empty() )
366 // Provide the finishing message if the application didn't.
367 m_message
= _("Done.");
368 m_sharedData
->m_message
= m_message
;
369 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
373 return m_sharedData
->m_state
!= Canceled
;
375 #endif // wxHAS_MSW_TASKDIALOG
377 return wxGenericProgressDialog
::Update( value
, newmsg
, skip
);
380 bool wxProgressDialog
::Pulse(const wxString
& newmsg
, bool *skip
)
382 #ifdef wxHAS_MSW_TASKDIALOG
383 if ( HasNativeProgressDialog() )
385 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
387 // Do nothing in canceled state.
388 if ( !DoNativeBeforeUpdate(skip
) )
391 if ( !m_sharedData
->m_progressBarMarquee
)
393 m_sharedData
->m_progressBarMarquee
= true;
394 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
397 if ( !newmsg
.empty() )
400 m_sharedData
->m_message
= newmsg
;
401 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
404 // The value passed here doesn't matter, only elapsed time makes sense
405 // in indeterminate mode anyhow.
406 UpdateExpandedInformation(0);
408 return m_sharedData
->m_state
!= Canceled
;
410 #endif // wxHAS_MSW_TASKDIALOG
412 return wxGenericProgressDialog
::Pulse( newmsg
, skip
);
415 bool wxProgressDialog
::DoNativeBeforeUpdate(bool *skip
)
417 #ifdef wxHAS_MSW_TASKDIALOG
418 if ( HasNativeProgressDialog() )
420 if ( m_sharedData
->m_skipped
)
422 if ( skip
&& !*skip
)
425 m_sharedData
->m_skipped
= false;
426 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
430 if ( m_sharedData
->m_state
== Canceled
)
431 m_timeStop
= m_sharedData
->m_timeStop
;
433 return m_sharedData
->m_state
!= Canceled
;
435 #endif // wxHAS_MSW_TASKDIALOG
438 wxFAIL_MSG( "unreachable" );
443 void wxProgressDialog
::Resume()
445 wxGenericProgressDialog
::Resume();
447 #ifdef wxHAS_MSW_TASKDIALOG
448 if ( HasNativeProgressDialog() )
453 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
454 m_sharedData
->m_state
= m_state
;
456 // "Skip" was disabled when "Cancel" had been clicked, so re-enable
458 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
460 if ( !UsesCloseButtonOnly(GetPDStyle()) )
461 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_ABORT
;
463 hwnd
= m_sharedData
->m_hwnd
;
464 } // Unlock m_cs, we can't call any function operating on a dialog with
465 // it locked as it can result in a deadlock if the dialog callback is
466 // called by Windows.
468 // After resuming we need to bring the window on top of the Z-order as
469 // it could be hidden by another window shown from the main thread,
470 // e.g. a confirmation dialog asking whether the user really wants to
473 // Notice that this must be done from the main thread as it owns the
474 // currently active window and attempts to do this from the task dialog
475 // thread would simply fail.
476 ::BringWindowToTop(hwnd
);
478 #endif // wxHAS_MSW_TASKDIALOG
481 int wxProgressDialog
::GetValue() const
483 #ifdef wxHAS_MSW_TASKDIALOG
484 if ( HasNativeProgressDialog() )
486 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
487 return m_sharedData
->m_value
;
489 #endif // wxHAS_MSW_TASKDIALOG
491 return wxGenericProgressDialog
::GetValue();
494 wxString wxProgressDialog
::GetMessage() const
496 #ifdef wxHAS_MSW_TASKDIALOG
497 if ( HasNativeProgressDialog() )
499 #endif // wxHAS_MSW_TASKDIALOG
501 return wxGenericProgressDialog
::GetMessage();
504 void wxProgressDialog
::SetRange(int maximum
)
506 #ifdef wxHAS_MSW_TASKDIALOG
507 if ( HasNativeProgressDialog() )
511 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
513 m_sharedData
->m_range
= maximum
;
514 m_sharedData
->m_notifications
|= wxSPDD_RANGE_CHANGED
;
518 #endif // wxHAS_MSW_TASKDIALOG
520 wxGenericProgressDialog
::SetRange( maximum
);
523 bool wxProgressDialog
::WasSkipped() const
525 #ifdef wxHAS_MSW_TASKDIALOG
526 if ( HasNativeProgressDialog() )
530 // Couldn't be skipped before being shown.
534 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
535 return m_sharedData
->m_skipped
;
537 #endif // wxHAS_MSW_TASKDIALOG
539 return wxGenericProgressDialog
::WasSkipped();
542 bool wxProgressDialog
::WasCancelled() const
544 #ifdef wxHAS_MSW_TASKDIALOG
545 if ( HasNativeProgressDialog() )
547 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
548 return m_sharedData
->m_state
== Canceled
;
550 #endif // wxHAS_MSW_TASKDIALOG
552 return wxGenericProgressDialog
::WasCancelled();
555 void wxProgressDialog
::SetTitle(const wxString
& title
)
557 #ifdef wxHAS_MSW_TASKDIALOG
558 if ( HasNativeProgressDialog() )
564 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
565 m_sharedData
->m_title
= title
;
566 m_sharedData
->m_notifications
= wxSPDD_TITLE_CHANGED
;
569 #endif // wxHAS_MSW_TASKDIALOG
571 wxGenericProgressDialog
::SetTitle(title
);
574 wxString wxProgressDialog
::GetTitle() const
576 #ifdef wxHAS_MSW_TASKDIALOG
577 if ( HasNativeProgressDialog() )
579 #endif // wxHAS_MSW_TASKDIALOG
581 return wxGenericProgressDialog
::GetTitle();
584 bool wxProgressDialog
::Show(bool show
)
586 #ifdef wxHAS_MSW_TASKDIALOG
587 if ( HasNativeProgressDialog() )
589 // The dialog can't be hidden at all and showing it again after it had
590 // been shown before doesn't do anything.
591 if ( !show
|| m_taskDialogRunner
)
594 // We're showing the dialog for the first time, create the thread that
596 m_taskDialogRunner
= new wxProgressDialogTaskRunner
;
597 m_sharedData
= m_taskDialogRunner
->GetSharedDataObject();
599 // Initialize shared data.
600 m_sharedData
->m_title
= m_title
;
601 m_sharedData
->m_message
= m_message
;
602 m_sharedData
->m_range
= m_maximum
;
603 m_sharedData
->m_state
= Uncancelable
;
604 m_sharedData
->m_style
= GetPDStyle();
606 if ( HasPDFlag(wxPD_CAN_ABORT
) )
608 m_sharedData
->m_state
= Continue
;
609 m_sharedData
->m_labelCancel
= _("Cancel");
611 else if ( !HasPDFlag(wxPD_AUTO_HIDE
) )
613 m_sharedData
->m_labelCancel
= _("Close");
616 if ( HasPDFlag(wxPD_ELAPSED_TIME
|
617 wxPD_ESTIMATED_TIME
|
618 wxPD_REMAINING_TIME
) )
620 // Use a non-empty string just to have the collapsible pane shown.
621 m_sharedData
->m_expandedInformation
= " ";
624 // Do launch the thread.
625 if ( m_taskDialogRunner
->Create() != wxTHREAD_NO_ERROR
)
627 wxLogError( "Unable to create thread!" );
631 if ( m_taskDialogRunner
->Run() != wxTHREAD_NO_ERROR
)
633 wxLogError( "Unable to start thread!" );
637 // Do not show the underlying dialog.
640 #endif // wxHAS_MSW_TASKDIALOG
642 return wxGenericProgressDialog
::Show( show
);
645 bool wxProgressDialog
::HasNativeProgressDialog() const
647 #ifdef wxHAS_MSW_TASKDIALOG
648 // Native task dialog, if available, can't be used without any buttons so
649 // we fall back to the generic one if none of "Skip", "Cancel" and "Close"
651 return HasNativeTaskDialog()
652 && (HasPDFlag(wxPD_CAN_SKIP
| wxPD_CAN_ABORT
) ||
653 !HasPDFlag(wxPD_AUTO_HIDE
));
654 #else // !wxHAS_MSW_TASKDIALOG
655 // This shouldn't be even called in !wxHAS_MSW_TASKDIALOG case but as we
656 // still must define the function as returning something, return false.
658 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
661 void wxProgressDialog
::UpdateExpandedInformation(int value
)
663 #ifdef wxHAS_MSW_TASKDIALOG
664 unsigned long elapsedTime
;
665 unsigned long estimatedTime
;
666 unsigned long remainingTime
;
667 UpdateTimeEstimates(value
, elapsedTime
, estimatedTime
, remainingTime
);
669 int realEstimatedTime
= estimatedTime
,
670 realRemainingTime
= remainingTime
;
671 if ( m_sharedData
->m_progressBarMarquee
)
673 // In indeterminate mode we don't have any estimation neither for the
674 // remaining nor for estimated time.
676 realRemainingTime
= -1;
679 wxString expandedInformation
;
681 // Calculate the three different timing values.
682 if ( HasPDFlag(wxPD_ELAPSED_TIME
) )
684 expandedInformation
<< GetElapsedLabel()
686 << GetFormattedTime(elapsedTime
);
689 if ( HasPDFlag(wxPD_ESTIMATED_TIME
) )
691 if ( !expandedInformation
.empty() )
692 expandedInformation
+= "\n";
694 expandedInformation
<< GetEstimatedLabel()
696 << GetFormattedTime(realEstimatedTime
);
699 if ( HasPDFlag(wxPD_REMAINING_TIME
) )
701 if ( !expandedInformation
.empty() )
702 expandedInformation
+= "\n";
704 expandedInformation
<< GetRemainingLabel()
706 << GetFormattedTime(realRemainingTime
);
709 // Update with new timing information.
710 if ( expandedInformation
!= m_sharedData
->m_expandedInformation
)
712 m_sharedData
->m_expandedInformation
= expandedInformation
;
713 m_sharedData
->m_notifications
|= wxSPDD_EXPINFO_CHANGED
;
715 #else // !wxHAS_MSW_TASKDIALOG
717 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
720 // ----------------------------------------------------------------------------
721 // wxProgressDialogTaskRunner and related methods
722 // ----------------------------------------------------------------------------
724 #ifdef wxHAS_MSW_TASKDIALOG
726 void* wxProgressDialogTaskRunner
::Entry()
728 WinStruct
<TASKDIALOGCONFIG
> tdc
;
729 wxMSWTaskDialogConfig wxTdc
;
732 wxCriticalSectionLocker
locker(m_sharedData
.m_cs
);
734 wxTdc
.caption
= m_sharedData
.m_title
.wx_str();
735 wxTdc
.message
= m_sharedData
.m_message
.wx_str();
737 wxTdc
.MSWCommonTaskDialogInit( tdc
);
738 tdc
.pfCallback
= TaskDialogCallbackProc
;
739 tdc
.lpCallbackData
= (LONG_PTR
) &m_sharedData
;
741 // Undo some of the effects of MSWCommonTaskDialogInit().
742 tdc
.dwFlags
&= ~TDF_EXPAND_FOOTER_AREA
; // Expand in content area.
743 tdc
.dwCommonButtons
= 0; // Don't use common buttons.
745 wxTdc
.useCustomLabels
= true;
747 if ( m_sharedData
.m_style
& wxPD_CAN_SKIP
)
748 wxTdc
.AddTaskDialogButton( tdc
, Id_SkipBtn
, 0, _("Skip") );
750 // Use a Cancel button when requested or use a Close button when
751 // the dialog does not automatically hide.
752 if ( (m_sharedData
.m_style
& wxPD_CAN_ABORT
)
753 || !(m_sharedData
.m_style
& wxPD_AUTO_HIDE
) )
755 wxTdc
.AddTaskDialogButton( tdc
, IDCANCEL
, 0,
756 m_sharedData
.m_labelCancel
);
759 tdc
.dwFlags
|= TDF_CALLBACK_TIMER
| TDF_SHOW_PROGRESS_BAR
;
761 if ( !m_sharedData
.m_expandedInformation
.empty() )
763 tdc
.pszExpandedInformation
=
764 m_sharedData
.m_expandedInformation
.wx_str();
768 TaskDialogIndirect_t taskDialogIndirect
= GetTaskDialogIndirectFunc();
769 if ( !taskDialogIndirect
)
773 HRESULT hr
= taskDialogIndirect(&tdc
, &msAns
, NULL
, NULL
);
775 wxLogApiError( "TaskDialogIndirect", hr
);
782 wxProgressDialogTaskRunner
::TaskDialogCallbackProc
787 LPARAM
WXUNUSED(lParam
),
791 wxProgressDialogSharedData
* const sharedData
=
792 (wxProgressDialogSharedData
*) dwRefData
;
794 wxCriticalSectionLocker
locker(sharedData
->m_cs
);
796 switch ( uNotification
)
799 // Store the HWND for the main thread use.
800 sharedData
->m_hwnd
= hwnd
;
802 // Set the maximum value and disable Close button.
804 TDM_SET_PROGRESS_BAR_RANGE
,
806 MAKELPARAM(0, sharedData
->m_range
) );
808 if ( UsesCloseButtonOnly(sharedData
->m_style
) )
809 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
812 case TDN_BUTTON_CLICKED
:
816 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
817 sharedData
->m_skipped
= true;
821 if ( sharedData
->m_state
== wxProgressDialog
::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
) )
833 sharedData
->m_state
== wxProgressDialog
::Continue
,
835 "Dialog not in a cancelable state!"
838 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
839 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
841 sharedData
->m_timeStop
= wxGetCurrentTime();
842 sharedData
->m_state
= wxProgressDialog
::Canceled
;
850 PerformNotificationUpdates(hwnd
, sharedData
);
852 // End dialog in three different cases:
853 // 1. Progress finished and dialog should automatically hide.
854 // 2. The wxProgressDialog object was destructed and should
855 // automatically hide.
856 // 3. The dialog was canceled and wxProgressDialog object
859 sharedData
->m_state
== wxGenericProgressDialog
::Canceled
;
861 sharedData
->m_state
== wxGenericProgressDialog
::Finished
;
863 (sharedData
->m_notifications
& wxSPDD_DESTROYED
) != 0;
864 bool shouldAutoHide
= (sharedData
->m_style
& wxPD_AUTO_HIDE
) != 0;
866 if ( (shouldAutoHide
&& (isFinished
|| wasDestroyed
))
867 || (wasDestroyed
&& isCanceled
) )
869 ::EndDialog( hwnd
, IDCLOSE
);
872 sharedData
->m_notifications
= 0;
881 #endif // wxHAS_MSW_TASKDIALOG
883 #endif // wxUSE_PROGRESSDLG && wxUSE_THREADS