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()
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 bool UsesCloseButtonOnly(long style
)
131 return !((style
& wxPD_CAN_ABORT
) || (style
& wxPD_AUTO_HIDE
));
134 BOOL CALLBACK
DisplayCloseButton(HWND hwnd
, LPARAM lParam
)
136 wxProgressDialogSharedData
*sharedData
=
137 (wxProgressDialogSharedData
*) lParam
;
139 if ( wxGetWindowText( hwnd
) == sharedData
->m_labelCancel
)
141 sharedData
->m_labelCancel
= _("Close");
142 SendMessage( hwnd
, WM_SETTEXT
, 0,
143 (LPARAM
) sharedData
->m_labelCancel
.wx_str() );
151 void PerformNotificationUpdates(HWND hwnd
,
152 wxProgressDialogSharedData
*sharedData
)
154 // Update the appropriate dialog fields.
155 if ( sharedData
->m_notifications
& wxSPDD_RANGE_CHANGED
)
158 TDM_SET_PROGRESS_BAR_RANGE
,
160 MAKELPARAM(0, sharedData
->m_range
) );
163 if ( sharedData
->m_notifications
& wxSPDD_VALUE_CHANGED
)
166 TDM_SET_PROGRESS_BAR_POS
,
171 if ( sharedData
->m_notifications
& wxSPDD_PBMARQUEE_CHANGED
)
173 BOOL val
= sharedData
->m_progressBarMarquee ? TRUE
: FALSE
;
175 TDM_SET_MARQUEE_PROGRESS_BAR
,
179 TDM_SET_PROGRESS_BAR_MARQUEE
,
184 if ( sharedData
->m_notifications
& wxSPDD_TITLE_CHANGED
)
185 ::SetWindowText( hwnd
, sharedData
->m_title
.wx_str() );
187 if ( sharedData
->m_notifications
& wxSPDD_MESSAGE_CHANGED
)
189 // Split the message in the title string and the rest if it has
192 title
= sharedData
->m_message
,
195 const size_t posNL
= title
.find('\n');
196 if ( posNL
!= wxString
::npos
)
198 // There can an extra new line between the first and subsequent
199 // lines to separate them as it looks better with the generic
200 // version -- but in this one, they're already separated by the use
201 // of different dialog elements, so suppress the extra new line.
203 if ( posNL
< title
.length() - 1 && title
[posNL
+ 1] == '\n' )
206 body
.assign(title
, posNL
+ numNLs
, wxString
::npos
);
211 TDM_SET_ELEMENT_TEXT
,
212 TDE_MAIN_INSTRUCTION
,
213 (LPARAM
) title
.wx_str() );
216 TDM_SET_ELEMENT_TEXT
,
218 (LPARAM
) body
.wx_str() );
221 if ( sharedData
->m_notifications
& wxSPDD_EXPINFO_CHANGED
)
223 const wxString
& expandedInformation
=
224 sharedData
->m_expandedInformation
;
225 if ( !expandedInformation
.empty() )
228 TDM_SET_ELEMENT_TEXT
,
229 TDE_EXPANDED_INFORMATION
,
230 (LPARAM
) expandedInformation
.wx_str() );
234 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_SKIP
)
235 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, TRUE
);
237 if ( sharedData
->m_notifications
& wxSPDD_ENABLE_ABORT
)
238 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
240 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_SKIP
)
241 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
243 if ( sharedData
->m_notifications
& wxSPDD_DISABLE_ABORT
)
244 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
246 // Is the progress finished?
247 if ( sharedData
->m_notifications
& wxSPDD_FINISHED
)
249 sharedData
->m_state
= wxGenericProgressDialog
::Finished
;
251 if ( !(sharedData
->m_style
& wxPD_AUTO_HIDE
) )
253 // Change Cancel into Close and activate the button.
254 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
255 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, TRUE
);
256 ::EnumChildWindows( hwnd
, DisplayCloseButton
,
257 (LPARAM
) sharedData
);
262 } // anonymous namespace
264 #endif // wxHAS_MSW_TASKDIALOG
266 // ============================================================================
267 // wxProgressDialog implementation
268 // ============================================================================
270 wxProgressDialog
::wxProgressDialog( const wxString
& title
,
271 const wxString
& message
,
275 : wxGenericProgressDialog(parent
, maximum
, style
),
276 m_taskDialogRunner(NULL
),
281 #ifdef wxHAS_MSW_TASKDIALOG
282 if ( HasNativeProgressDialog() )
285 DisableOtherWindows();
289 #endif // wxHAS_MSW_TASKDIALOG
291 Create(title
, message
, maximum
, parent
, style
);
294 wxProgressDialog
::~wxProgressDialog()
296 #ifdef wxHAS_MSW_TASKDIALOG
297 if ( !m_taskDialogRunner
)
302 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
303 m_sharedData
->m_notifications
|= wxSPDD_DESTROYED
;
306 m_taskDialogRunner
->Wait();
308 delete m_taskDialogRunner
;
310 ReenableOtherWindows();
312 if ( GetTopParent() )
313 GetTopParent()->Raise();
314 #endif // wxHAS_MSW_TASKDIALOG
317 bool wxProgressDialog
::Update(int value
, const wxString
& newmsg
, bool *skip
)
319 #ifdef wxHAS_MSW_TASKDIALOG
320 if ( HasNativeProgressDialog() )
322 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
324 // Do nothing in canceled state.
325 if ( !DoNativeBeforeUpdate(skip
) )
330 wxASSERT_MSG( value
<= m_maximum
, wxT("invalid progress value") );
332 m_sharedData
->m_value
= value
;
333 m_sharedData
->m_notifications
|= wxSPDD_VALUE_CHANGED
;
335 if ( !newmsg
.empty() )
338 m_sharedData
->m_message
= newmsg
;
339 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
342 if ( m_sharedData
->m_progressBarMarquee
)
344 m_sharedData
->m_progressBarMarquee
= false;
345 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
348 UpdateExpandedInformation( value
);
350 // Has the progress bar finished?
351 if ( value
== m_maximum
)
353 if ( m_state
== Finished
)
357 m_sharedData
->m_state
= Finished
;
358 m_sharedData
->m_notifications
|= wxSPDD_FINISHED
;
359 if( !HasFlag(wxPD_AUTO_HIDE
) && newmsg
.empty() )
361 // Provide the finishing message if the application didn't.
362 m_message
= _("Done.");
363 m_sharedData
->m_message
= m_message
;
364 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
368 return m_sharedData
->m_state
!= Canceled
;
370 #endif // wxHAS_MSW_TASKDIALOG
372 return wxGenericProgressDialog
::Update( value
, newmsg
, skip
);
375 bool wxProgressDialog
::Pulse(const wxString
& newmsg
, bool *skip
)
377 #ifdef wxHAS_MSW_TASKDIALOG
378 if ( HasNativeProgressDialog() )
380 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
382 // Do nothing in canceled state.
383 if ( !DoNativeBeforeUpdate(skip
) )
386 if ( !m_sharedData
->m_progressBarMarquee
)
388 m_sharedData
->m_progressBarMarquee
= true;
389 m_sharedData
->m_notifications
|= wxSPDD_PBMARQUEE_CHANGED
;
392 if ( !newmsg
.empty() )
395 m_sharedData
->m_message
= newmsg
;
396 m_sharedData
->m_notifications
|= wxSPDD_MESSAGE_CHANGED
;
399 // The value passed here doesn't matter, only elapsed time makes sense
400 // in indeterminate mode anyhow.
401 UpdateExpandedInformation(0);
403 return m_sharedData
->m_state
!= Canceled
;
405 #endif // wxHAS_MSW_TASKDIALOG
407 return wxGenericProgressDialog
::Pulse( newmsg
, skip
);
410 bool wxProgressDialog
::DoNativeBeforeUpdate(bool *skip
)
412 #ifdef wxHAS_MSW_TASKDIALOG
413 if ( HasNativeProgressDialog() )
415 if ( m_sharedData
->m_skipped
)
417 if ( skip
&& !*skip
)
420 m_sharedData
->m_skipped
= false;
421 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
425 if ( m_sharedData
->m_state
== Canceled
)
426 m_timeStop
= m_sharedData
->m_timeStop
;
428 return m_sharedData
->m_state
!= Canceled
;
430 #endif // wxHAS_MSW_TASKDIALOG
433 wxFAIL_MSG( "unreachable" );
438 void wxProgressDialog
::Resume()
440 wxGenericProgressDialog
::Resume();
442 #ifdef wxHAS_MSW_TASKDIALOG
443 if ( HasNativeProgressDialog() )
448 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
449 m_sharedData
->m_state
= m_state
;
451 // "Skip" was disabled when "Cancel" had been clicked, so re-enable
453 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_SKIP
;
455 if ( !UsesCloseButtonOnly(m_windowStyle
) )
456 m_sharedData
->m_notifications
|= wxSPDD_ENABLE_ABORT
;
458 hwnd
= m_sharedData
->m_hwnd
;
459 } // Unlock m_cs, we can't call any function operating on a dialog with
460 // it locked as it can result in a deadlock if the dialog callback is
461 // called by Windows.
463 // After resuming we need to bring the window on top of the Z-order as
464 // it could be hidden by another window shown from the main thread,
465 // e.g. a confirmation dialog asking whether the user really wants to
468 // Notice that this must be done from the main thread as it owns the
469 // currently active window and attempts to do this from the task dialog
470 // thread would simply fail.
471 ::BringWindowToTop(hwnd
);
473 #endif // wxHAS_MSW_TASKDIALOG
476 int wxProgressDialog
::GetValue() const
478 #ifdef wxHAS_MSW_TASKDIALOG
479 if ( HasNativeProgressDialog() )
481 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
482 return m_sharedData
->m_value
;
484 #endif // wxHAS_MSW_TASKDIALOG
486 return wxGenericProgressDialog
::GetValue();
489 wxString wxProgressDialog
::GetMessage() const
491 #ifdef wxHAS_MSW_TASKDIALOG
492 if ( HasNativeProgressDialog() )
494 #endif // wxHAS_MSW_TASKDIALOG
496 return wxGenericProgressDialog
::GetMessage();
499 void wxProgressDialog
::SetRange(int maximum
)
501 wxGenericProgressDialog
::SetRange( maximum
);
503 #ifdef wxHAS_MSW_TASKDIALOG
504 if ( HasNativeProgressDialog() )
506 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
508 m_sharedData
->m_range
= maximum
;
509 m_sharedData
->m_notifications
|= wxSPDD_RANGE_CHANGED
;
511 #endif // wxHAS_MSW_TASKDIALOG
514 bool wxProgressDialog
::WasSkipped() const
516 #ifdef wxHAS_MSW_TASKDIALOG
517 if ( HasNativeProgressDialog() )
521 // Couldn't be skipped before being shown.
525 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
526 return m_sharedData
->m_skipped
;
528 #endif // wxHAS_MSW_TASKDIALOG
530 return wxGenericProgressDialog
::WasSkipped();
533 bool wxProgressDialog
::WasCancelled() const
535 #ifdef wxHAS_MSW_TASKDIALOG
536 if ( HasNativeProgressDialog() )
538 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
539 return m_sharedData
->m_state
== Canceled
;
541 #endif // wxHAS_MSW_TASKDIALOG
543 return wxGenericProgressDialog
::WasCancelled();
546 void wxProgressDialog
::SetTitle(const wxString
& title
)
548 #ifdef wxHAS_MSW_TASKDIALOG
549 if ( HasNativeProgressDialog() )
555 wxCriticalSectionLocker
locker(m_sharedData
->m_cs
);
556 m_sharedData
->m_title
= title
;
557 m_sharedData
->m_notifications
= wxSPDD_TITLE_CHANGED
;
560 #endif // wxHAS_MSW_TASKDIALOG
562 wxGenericProgressDialog
::SetTitle(title
);
565 wxString wxProgressDialog
::GetTitle() const
567 #ifdef wxHAS_MSW_TASKDIALOG
568 if ( HasNativeProgressDialog() )
570 #endif // wxHAS_MSW_TASKDIALOG
572 return wxGenericProgressDialog
::GetTitle();
575 bool wxProgressDialog
::Show(bool show
)
577 #ifdef wxHAS_MSW_TASKDIALOG
578 if ( HasNativeProgressDialog() )
580 // The dialog can't be hidden at all and showing it again after it had
581 // been shown before doesn't do anything.
582 if ( !show
|| m_taskDialogRunner
)
585 // We're showing the dialog for the first time, create the thread that
587 m_taskDialogRunner
= new wxProgressDialogTaskRunner
;
588 m_sharedData
= m_taskDialogRunner
->GetSharedDataObject();
590 // Initialize shared data.
591 m_sharedData
->m_title
= m_title
;
592 m_sharedData
->m_message
= m_message
;
593 m_sharedData
->m_range
= m_maximum
;
594 m_sharedData
->m_state
= Uncancelable
;
595 m_sharedData
->m_style
= m_windowStyle
;
597 if ( HasFlag(wxPD_CAN_ABORT
) )
599 m_sharedData
->m_state
= Continue
;
600 m_sharedData
->m_labelCancel
= _("Cancel");
602 else if ( !HasFlag(wxPD_AUTO_HIDE
) )
604 m_sharedData
->m_labelCancel
= _("Close");
607 if ( m_windowStyle
& (wxPD_ELAPSED_TIME
608 | wxPD_ESTIMATED_TIME
609 | wxPD_REMAINING_TIME
) )
611 // Use a non-empty string just to have the collapsible pane shown.
612 m_sharedData
->m_expandedInformation
= " ";
615 // Do launch the thread.
616 if ( m_taskDialogRunner
->Create() != wxTHREAD_NO_ERROR
)
618 wxLogError( "Unable to create thread!" );
622 if ( m_taskDialogRunner
->Run() != wxTHREAD_NO_ERROR
)
624 wxLogError( "Unable to start thread!" );
628 if ( !HasFlag(wxPD_APP_MODAL
) )
630 wxWindow
* const parent
= GetTopParent();
637 wxFAIL_MSG( "Progress dialog must have a valid parent if "
638 "wxPD_APP_MODAL is not used." );
641 //else: otherwise all windows will be disabled by m_taskDialogRunner
643 // Do not show the underlying dialog.
646 #endif // wxHAS_MSW_TASKDIALOG
648 return wxGenericProgressDialog
::Show( show
);
651 bool wxProgressDialog
::HasNativeProgressDialog() const
653 #ifdef wxHAS_MSW_TASKDIALOG
654 // For a native implementation task dialogs are required, which
655 // also require at least one button to be present so the flags needs
656 // to be checked as well to see if this is the case.
657 return HasNativeTaskDialog()
658 && ((m_windowStyle
& (wxPD_CAN_SKIP
| wxPD_CAN_ABORT
))
659 || !(m_windowStyle
& wxPD_AUTO_HIDE
));
660 #else // !wxHAS_MSW_TASKDIALOG
661 // This shouldn't be even called in !wxHAS_MSW_TASKDIALOG case but as we
662 // still must define the function as returning something, return false.
664 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
667 void wxProgressDialog
::UpdateExpandedInformation(int value
)
669 #ifdef wxHAS_MSW_TASKDIALOG
670 unsigned long elapsedTime
;
671 unsigned long estimatedTime
;
672 unsigned long remainingTime
;
673 UpdateTimeEstimates(value
, elapsedTime
, estimatedTime
, remainingTime
);
675 int realEstimatedTime
= estimatedTime
,
676 realRemainingTime
= remainingTime
;
677 if ( m_sharedData
->m_progressBarMarquee
)
679 // In indeterminate mode we don't have any estimation neither for the
680 // remaining nor for estimated time.
682 realRemainingTime
= -1;
685 wxString expandedInformation
;
687 // Calculate the three different timing values.
688 if ( m_windowStyle
& wxPD_ELAPSED_TIME
)
690 expandedInformation
<< GetElapsedLabel()
692 << GetFormattedTime(elapsedTime
);
695 if ( m_windowStyle
& wxPD_ESTIMATED_TIME
)
697 if ( !expandedInformation
.empty() )
698 expandedInformation
+= "\n";
700 expandedInformation
<< GetEstimatedLabel()
702 << GetFormattedTime(realEstimatedTime
);
705 if ( m_windowStyle
& wxPD_REMAINING_TIME
)
707 if ( !expandedInformation
.empty() )
708 expandedInformation
+= "\n";
710 expandedInformation
<< GetRemainingLabel()
712 << GetFormattedTime(realRemainingTime
);
715 // Update with new timing information.
716 if ( expandedInformation
!= m_sharedData
->m_expandedInformation
)
718 m_sharedData
->m_expandedInformation
= expandedInformation
;
719 m_sharedData
->m_notifications
|= wxSPDD_EXPINFO_CHANGED
;
721 #else // !wxHAS_MSW_TASKDIALOG
723 #endif // wxHAS_MSW_TASKDIALOG/!wxHAS_MSW_TASKDIALOG
726 // ----------------------------------------------------------------------------
727 // wxProgressDialogTaskRunner and related methods
728 // ----------------------------------------------------------------------------
730 #ifdef wxHAS_MSW_TASKDIALOG
732 void* wxProgressDialogTaskRunner
::Entry()
734 WinStruct
<TASKDIALOGCONFIG
> tdc
;
735 wxMSWTaskDialogConfig wxTdc
;
738 wxCriticalSectionLocker
locker(m_sharedData
.m_cs
);
740 wxTdc
.caption
= m_sharedData
.m_title
.wx_str();
741 wxTdc
.message
= m_sharedData
.m_message
.wx_str();
743 wxTdc
.MSWCommonTaskDialogInit( tdc
);
744 tdc
.pfCallback
= TaskDialogCallbackProc
;
745 tdc
.lpCallbackData
= (LONG_PTR
) &m_sharedData
;
747 // Undo some of the effects of MSWCommonTaskDialogInit().
748 tdc
.dwFlags
&= ~TDF_EXPAND_FOOTER_AREA
; // Expand in content area.
749 tdc
.dwCommonButtons
= 0; // Don't use common buttons.
751 wxTdc
.useCustomLabels
= true;
753 if ( m_sharedData
.m_style
& wxPD_CAN_SKIP
)
754 wxTdc
.AddTaskDialogButton( tdc
, Id_SkipBtn
, 0, _("Skip") );
756 // Use a Cancel button when requested or use a Close button when
757 // the dialog does not automatically hide.
758 if ( (m_sharedData
.m_style
& wxPD_CAN_ABORT
)
759 || !(m_sharedData
.m_style
& wxPD_AUTO_HIDE
) )
761 wxTdc
.AddTaskDialogButton( tdc
, IDCANCEL
, 0,
762 m_sharedData
.m_labelCancel
);
765 tdc
.dwFlags
|= TDF_CALLBACK_TIMER
766 | TDF_SHOW_PROGRESS_BAR
767 | TDF_SHOW_MARQUEE_PROGRESS_BAR
;
769 if ( !m_sharedData
.m_expandedInformation
.empty() )
771 tdc
.pszExpandedInformation
=
772 m_sharedData
.m_expandedInformation
.wx_str();
776 TaskDialogIndirect_t taskDialogIndirect
= GetTaskDialogIndirectFunc();
777 if ( !taskDialogIndirect
)
781 HRESULT hr
= taskDialogIndirect(&tdc
, &msAns
, NULL
, NULL
);
783 wxLogApiError( "TaskDialogIndirect", hr
);
790 wxProgressDialogTaskRunner
::TaskDialogCallbackProc
795 LPARAM
WXUNUSED(lParam
),
799 wxProgressDialogSharedData
* const sharedData
=
800 (wxProgressDialogSharedData
*) dwRefData
;
802 wxCriticalSectionLocker
locker(sharedData
->m_cs
);
804 switch ( uNotification
)
807 // Store the HWND for the main thread use.
808 sharedData
->m_hwnd
= hwnd
;
810 // Set the maximum value and disable Close button.
812 TDM_SET_PROGRESS_BAR_RANGE
,
814 MAKELPARAM(0, sharedData
->m_range
) );
816 if ( UsesCloseButtonOnly(sharedData
->m_style
) )
817 ::SendMessage( hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
820 case TDN_BUTTON_CLICKED
:
824 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
825 sharedData
->m_skipped
= true;
829 if ( sharedData
->m_state
830 == wxGenericProgressDialog
::Finished
)
835 // Close button on the window triggers an IDCANCEL press,
836 // don't allow it when it should only be possible to close
837 // a finished dialog.
838 if ( !UsesCloseButtonOnly(sharedData
->m_style
) )
840 wxCHECK_MSG( sharedData
->m_state
==
841 wxGenericProgressDialog
::Continue
,
843 "Dialog not in a cancelable state!");
845 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, Id_SkipBtn
, FALSE
);
846 ::SendMessage(hwnd
, TDM_ENABLE_BUTTON
, IDCANCEL
, FALSE
);
848 sharedData
->m_timeStop
= wxGetCurrentTime();
849 sharedData
->m_state
= wxGenericProgressDialog
::Canceled
;
857 PerformNotificationUpdates(hwnd
, sharedData
);
859 // End dialog in three different cases:
860 // 1. Progress finished and dialog should automatically hide.
861 // 2. The wxProgressDialog object was destructed and should
862 // automatically hide.
863 // 3. The dialog was canceled and wxProgressDialog object
866 sharedData
->m_state
== wxGenericProgressDialog
::Canceled
;
868 sharedData
->m_state
== wxGenericProgressDialog
::Finished
;
870 (sharedData
->m_notifications
& wxSPDD_DESTROYED
) != 0;
871 bool shouldAutoHide
= (sharedData
->m_style
& wxPD_AUTO_HIDE
) != 0;
873 if ( (shouldAutoHide
&& (isFinished
|| wasDestroyed
))
874 || (wasDestroyed
&& isCanceled
) )
876 ::EndDialog( hwnd
, IDCLOSE
);
879 sharedData
->m_notifications
= 0;
888 #endif // wxHAS_MSW_TASKDIALOG
890 #endif // wxUSE_PROGRESSDLG && wxUSE_THREADS