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
) )
632 wxWindow
* const parent
= GetTopParent();
639 wxFAIL_MSG( "Progress dialog must have a valid parent if "
640 "wxPD_APP_MODAL is not used." );
643 //else: otherwise all windows will be disabled by m_taskDialogRunner
645 // Do not show the underlying dialog.
648 #endif // wxHAS_MSW_TASKDIALOG
650 return wxGenericProgressDialog
::Show( show
);
653 bool wxProgressDialog
::HasNativeProgressDialog() const
655 #ifdef wxHAS_MSW_TASKDIALOG
656 // For a native implementation task dialogs are required, which
657 // also require at least one button to be present so the flags needs
658 // to be checked as well to see if this is the case.
659 return HasNativeTaskDialog()
660 && ((m_windowStyle
& (wxPD_CAN_SKIP
| wxPD_CAN_ABORT
))
661 || !(m_windowStyle
& wxPD_AUTO_HIDE
));
662 #else // !wxHAS_MSW_TASKDIALOG
663 // This shouldn't be even called in !wxHAS_MSW_TASKDIALOG case but as we
664 // still must define the function as returning something, return false.
666 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
669 void wxProgressDialog
::UpdateExpandedInformation(int value
)
671 #ifdef wxHAS_MSW_TASKDIALOG
672 unsigned long elapsedTime
;
673 unsigned long estimatedTime
;
674 unsigned long remainingTime
;
675 UpdateTimeEstimates(value
, elapsedTime
, estimatedTime
, remainingTime
);
677 int realEstimatedTime
= estimatedTime
,
678 realRemainingTime
= remainingTime
;
679 if ( m_sharedData
->m_progressBarMarquee
)
681 // In indeterminate mode we don't have any estimation neither for the
682 // remaining nor for estimated time.
684 realRemainingTime
= -1;
687 wxString expandedInformation
;
689 // Calculate the three different timing values.
690 if ( m_windowStyle
& wxPD_ELAPSED_TIME
)
692 expandedInformation
<< GetElapsedLabel()
694 << GetFormattedTime(elapsedTime
);
697 if ( m_windowStyle
& wxPD_ESTIMATED_TIME
)
699 if ( !expandedInformation
.empty() )
700 expandedInformation
+= "\n";
702 expandedInformation
<< GetEstimatedLabel()
704 << GetFormattedTime(realEstimatedTime
);
707 if ( m_windowStyle
& wxPD_REMAINING_TIME
)
709 if ( !expandedInformation
.empty() )
710 expandedInformation
+= "\n";
712 expandedInformation
<< GetRemainingLabel()
714 << GetFormattedTime(realRemainingTime
);
717 // Update with new timing information.
718 if ( expandedInformation
!= m_sharedData
->m_expandedInformation
)
720 m_sharedData
->m_expandedInformation
= expandedInformation
;
721 m_sharedData
->m_notifications
|= wxSPDD_EXPINFO_CHANGED
;
723 #else // !wxHAS_MSW_TASKDIALOG
725 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
728 // ----------------------------------------------------------------------------
729 // wxProgressDialogTaskRunner and related methods
730 // ----------------------------------------------------------------------------
732 #ifdef wxHAS_MSW_TASKDIALOG
734 void* wxProgressDialogTaskRunner
::Entry()
736 WinStruct
<TASKDIALOGCONFIG
> tdc
;
737 wxMSWTaskDialogConfig wxTdc
;
740 wxCriticalSectionLocker
locker(m_sharedData
.m_cs
);
742 wxTdc
.caption
= m_sharedData
.m_title
.wx_str();
743 wxTdc
.message
= m_sharedData
.m_message
.wx_str();
745 wxTdc
.MSWCommonTaskDialogInit( tdc
);
746 tdc
.pfCallback
= TaskDialogCallbackProc
;
747 tdc
.lpCallbackData
= (LONG_PTR
) &m_sharedData
;
749 // Undo some of the effects of MSWCommonTaskDialogInit().
750 tdc
.dwFlags
&= ~TDF_EXPAND_FOOTER_AREA
; // Expand in content area.
751 tdc
.dwCommonButtons
= 0; // Don't use common buttons.
753 wxTdc
.useCustomLabels
= true;
755 if ( m_sharedData
.m_style
& wxPD_CAN_SKIP
)
756 wxTdc
.AddTaskDialogButton( tdc
, Id_SkipBtn
, 0, _("Skip") );
758 // Use a Cancel button when requested or use a Close button when
759 // the dialog does not automatically hide.
760 if ( (m_sharedData
.m_style
& wxPD_CAN_ABORT
)
761 || !(m_sharedData
.m_style
& wxPD_AUTO_HIDE
) )
763 wxTdc
.AddTaskDialogButton( tdc
, IDCANCEL
, 0,
764 m_sharedData
.m_labelCancel
);
767 tdc
.dwFlags
|= TDF_CALLBACK_TIMER
768 | TDF_SHOW_PROGRESS_BAR
769 | TDF_SHOW_MARQUEE_PROGRESS_BAR
;
771 if ( !m_sharedData
.m_expandedInformation
.empty() )
773 tdc
.pszExpandedInformation
=
774 m_sharedData
.m_expandedInformation
.wx_str();
778 TaskDialogIndirect_t taskDialogIndirect
= GetTaskDialogIndirectFunc();
779 if ( !taskDialogIndirect
)
783 HRESULT hr
= taskDialogIndirect(&tdc
, &msAns
, NULL
, NULL
);
785 wxLogApiError( "TaskDialogIndirect", hr
);
792 wxProgressDialogTaskRunner
::TaskDialogCallbackProc
797 LPARAM
WXUNUSED(lParam
),
801 wxProgressDialogSharedData
* const sharedData
=
802 (wxProgressDialogSharedData
*) dwRefData
;
804 wxCriticalSectionLocker
locker(sharedData
->m_cs
);
806 switch ( uNotification
)
809 // Store the HWND for the main thread use.
810 sharedData
->m_hwnd
= hwnd
;
812 // Set the maximum value and disable Close button.
814 TDM_SET_PROGRESS_BAR_RANGE
,
816 MAKELPARAM(0, sharedData
->m_range
) );
818 if ( UsesCloseButtonOnly(sharedData
->m_style
) )
819 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
822 case TDN_BUTTON_CLICKED
:
826 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
827 sharedData
->m_skipped
= true;
831 if ( sharedData
->m_state
832 == wxGenericProgressDialog
::Finished
)
837 // Close button on the window triggers an IDCANCEL press,
838 // don't allow it when it should only be possible to close
839 // a finished dialog.
840 if ( !UsesCloseButtonOnly(sharedData
->m_style
) )
842 wxCHECK_MSG( sharedData
->m_state
==
843 wxGenericProgressDialog
::Continue
,
845 "Dialog not in a cancelable state!");
847 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
848 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
850 sharedData
->m_timeStop
= wxGetCurrentTime();
851 sharedData
->m_state
= wxGenericProgressDialog
::Canceled
;
859 PerformNotificationUpdates(hwnd
, sharedData
);
861 // End dialog in three different cases:
862 // 1. Progress finished and dialog should automatically hide.
863 // 2. The wxProgressDialog object was destructed and should
864 // automatically hide.
865 // 3. The dialog was canceled and wxProgressDialog object
868 sharedData
->m_state
== wxGenericProgressDialog
::Canceled
;
870 sharedData
->m_state
== wxGenericProgressDialog
::Finished
;
872 (sharedData
->m_notifications
& wxSPDD_DESTROYED
) != 0;
873 bool shouldAutoHide
= (sharedData
->m_style
& wxPD_AUTO_HIDE
) != 0;
875 if ( (shouldAutoHide
&& (isFinished
|| wasDestroyed
))
876 || (wasDestroyed
&& isCanceled
) )
878 ::EndDialog( hwnd
, IDCLOSE
);
881 sharedData
->m_notifications
= 0;
890 #endif // wxHAS_MSW_TASKDIALOG
892 #endif // wxUSE_PROGRESSDLG && wxUSE_THREADS