1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        wx/dialog.h
3 // Purpose:     wxDialogBase class
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     29.06.99
7 // Copyright:   (c) Vadim Zeitlin
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef _WX_DIALOG_H_BASE_
12 #define _WX_DIALOG_H_BASE_
13 
14 #include "wx/toplevel.h"
15 #include "wx/containr.h"
16 #include "wx/sharedptr.h"
17 
18 class WXDLLIMPEXP_FWD_CORE wxSizer;
19 class WXDLLIMPEXP_FWD_CORE wxStdDialogButtonSizer;
20 class WXDLLIMPEXP_FWD_CORE wxBoxSizer;
21 class WXDLLIMPEXP_FWD_CORE wxDialogLayoutAdapter;
22 class WXDLLIMPEXP_FWD_CORE wxDialog;
23 class WXDLLIMPEXP_FWD_CORE wxButton;
24 class WXDLLIMPEXP_FWD_CORE wxScrolledWindow;
25 class wxTextSizerWrapper;
26 
27 // Also see the bit summary table in wx/toplevel.h.
28 
29 #define wxDIALOG_NO_PARENT      0x00000020  // Don't make owned by apps top window
30 
31 #ifdef __WXWINCE__
32 #define wxDEFAULT_DIALOG_STYLE  (wxCAPTION | wxMAXIMIZE | wxCLOSE_BOX | wxNO_BORDER)
33 #else
34 #define wxDEFAULT_DIALOG_STYLE  (wxCAPTION | wxSYSTEM_MENU | wxCLOSE_BOX)
35 #endif
36 
37 // Layout adaptation levels, for SetLayoutAdaptationLevel
38 
39 // Don't do any layout adaptation
40 #define wxDIALOG_ADAPTATION_NONE             0
41 
42 // Only look for wxStdDialogButtonSizer for non-scrolling part
43 #define wxDIALOG_ADAPTATION_STANDARD_SIZER   1
44 
45 // Also look for any suitable sizer for non-scrolling part
46 #define wxDIALOG_ADAPTATION_ANY_SIZER        2
47 
48 // Also look for 'loose' standard buttons for non-scrolling part
49 #define wxDIALOG_ADAPTATION_LOOSE_BUTTONS    3
50 
51 // Layout adaptation mode, for SetLayoutAdaptationMode
52 enum wxDialogLayoutAdaptationMode
53 {
54     wxDIALOG_ADAPTATION_MODE_DEFAULT = 0,   // use global adaptation enabled status
55     wxDIALOG_ADAPTATION_MODE_ENABLED = 1,   // enable this dialog overriding global status
56     wxDIALOG_ADAPTATION_MODE_DISABLED = 2   // disable this dialog overriding global status
57 };
58 
59 enum wxDialogModality
60 {
61     wxDIALOG_MODALITY_NONE = 0,
62     wxDIALOG_MODALITY_WINDOW_MODAL = 1,
63     wxDIALOG_MODALITY_APP_MODAL = 2
64 };
65 
66 extern WXDLLIMPEXP_DATA_CORE(const char) wxDialogNameStr[];
67 
68 class WXDLLIMPEXP_CORE wxDialogBase : public wxNavigationEnabled<wxTopLevelWindow>
69 {
70 public:
71     wxDialogBase();
~wxDialogBase()72     virtual ~wxDialogBase() { }
73 
74     // define public wxDialog methods to be implemented by the derived classes
75     virtual int ShowModal() = 0;
76     virtual void EndModal(int retCode) = 0;
77     virtual bool IsModal() const = 0;
78     // show the dialog frame-modally (needs a parent), using app-modal
79     // dialogs on platforms that don't support it
80     virtual void ShowWindowModal () ;
81     virtual void SendWindowModalDialogEvent ( wxEventType type );
82 
83 #ifdef wxHAS_EVENT_BIND
84     template<typename Functor>
85     void ShowWindowModalThenDo(const Functor& onEndModal);
86 #endif // wxHAS_EVENT_BIND
87 
88     // Modal dialogs have a return code - usually the id of the last
89     // pressed button
SetReturnCode(int returnCode)90     void SetReturnCode(int returnCode) { m_returnCode = returnCode; }
GetReturnCode()91     int GetReturnCode() const { return m_returnCode; }
92 
93     // Set the identifier for the affirmative button: this button will close
94     // the dialog after validating data and calling TransferDataFromWindow()
95     void SetAffirmativeId(int affirmativeId);
GetAffirmativeId()96     int GetAffirmativeId() const { return m_affirmativeId; }
97 
98     // Set identifier for Esc key translation: the button with this id will
99     // close the dialog without doing anything else; special value wxID_NONE
100     // means to not handle Esc at all while wxID_ANY means to map Esc to
101     // wxID_CANCEL if present and GetAffirmativeId() otherwise
102     void SetEscapeId(int escapeId);
GetEscapeId()103     int GetEscapeId() const { return m_escapeId; }
104 
105     // Find the parent to use for modal dialog: try to use the specified parent
106     // but fall back to the current active window or main application window as
107     // last resort if it is unsuitable.
108     //
109     // As this function is often called from the ctor, the window style may be
110     // not set yet and hence must be passed explicitly to it so that we could
111     // check whether it contains wxDIALOG_NO_PARENT bit.
112     //
113     // This function always returns a valid top level window or NULL.
114     wxWindow *GetParentForModalDialog(wxWindow *parent, long style) const;
115 
116     // This overload can only be used for already initialized windows, i.e. not
117     // from the ctor. It uses the current window parent and style.
GetParentForModalDialog()118     wxWindow *GetParentForModalDialog() const
119     {
120         return GetParentForModalDialog(GetParent(), GetWindowStyle());
121     }
122 
123 #if wxUSE_STATTEXT // && wxUSE_TEXTCTRL
124     // splits text up at newlines and places the lines into a vertical
125     // wxBoxSizer
126     wxSizer *CreateTextSizer( const wxString& message );
127 
128     // same as above but uses a customized wxTextSizerWrapper to create
129     // non-standard controls for the lines
130     wxSizer *CreateTextSizer( const wxString& message,
131                               wxTextSizerWrapper& wrapper );
132 #endif // wxUSE_STATTEXT // && wxUSE_TEXTCTRL
133 
134     // returns a horizontal wxBoxSizer containing the given buttons
135     //
136     // notice that the returned sizer can be NULL if no buttons are put in the
137     // sizer (this mostly happens under smart phones and other atypical
138     // platforms which have hardware buttons replacing OK/Cancel and such)
139     wxSizer *CreateButtonSizer(long flags);
140 
141     // returns a sizer containing the given one and a static line separating it
142     // from the preceding elements if it's appropriate for the current platform
143     wxSizer *CreateSeparatedSizer(wxSizer *sizer);
144 
145     // returns the sizer containing CreateButtonSizer() below a separating
146     // static line for the platforms which use static lines for items
147     // separation (i.e. not Mac)
148     //
149     // this is just a combination of CreateButtonSizer() and
150     // CreateSeparatedSizer()
151     wxSizer *CreateSeparatedButtonSizer(long flags);
152 
153 #if wxUSE_BUTTON
154     wxStdDialogButtonSizer *CreateStdDialogButtonSizer( long flags );
155 #endif // wxUSE_BUTTON
156 
157     // Do layout adaptation
158     virtual bool DoLayoutAdaptation();
159 
160     // Can we do layout adaptation?
161     virtual bool CanDoLayoutAdaptation();
162 
163     // Returns a content window if there is one. This can be used by the layout adapter, for
164     // example to make the pages of a book control into scrolling windows
GetContentWindow()165     virtual wxWindow* GetContentWindow() const { return NULL; }
166 
167     // Add an id to the list of main button identifiers that should be in the button sizer
AddMainButtonId(wxWindowID id)168     void AddMainButtonId(wxWindowID id) { m_mainButtonIds.Add((int) id); }
GetMainButtonIds()169     wxArrayInt& GetMainButtonIds() { return m_mainButtonIds; }
170 
171     // Is this id in the main button id array?
IsMainButtonId(wxWindowID id)172     bool IsMainButtonId(wxWindowID id) const { return (m_mainButtonIds.Index((int) id) != wxNOT_FOUND); }
173 
174     // Level of adaptation, from none (Level 0) to full (Level 3). To disable adaptation,
175     // set level 0, for example in your dialog constructor. You might
176     // do this if you know that you are displaying on a large screen and you don't want the
177     // dialog changed.
SetLayoutAdaptationLevel(int level)178     void SetLayoutAdaptationLevel(int level) { m_layoutAdaptationLevel = level; }
GetLayoutAdaptationLevel()179     int GetLayoutAdaptationLevel() const { return m_layoutAdaptationLevel; }
180 
181     /// Override global adaptation enabled/disabled status
SetLayoutAdaptationMode(wxDialogLayoutAdaptationMode mode)182     void SetLayoutAdaptationMode(wxDialogLayoutAdaptationMode mode) { m_layoutAdaptationMode = mode; }
GetLayoutAdaptationMode()183     wxDialogLayoutAdaptationMode GetLayoutAdaptationMode() const { return m_layoutAdaptationMode; }
184 
185     // Returns true if the adaptation has been done
SetLayoutAdaptationDone(bool adaptationDone)186     void SetLayoutAdaptationDone(bool adaptationDone) { m_layoutAdaptationDone = adaptationDone; }
GetLayoutAdaptationDone()187     bool GetLayoutAdaptationDone() const { return m_layoutAdaptationDone; }
188 
189     // Set layout adapter class, returning old adapter
190     static wxDialogLayoutAdapter* SetLayoutAdapter(wxDialogLayoutAdapter* adapter);
GetLayoutAdapter()191     static wxDialogLayoutAdapter* GetLayoutAdapter() { return sm_layoutAdapter; }
192 
193     // Global switch for layout adaptation
IsLayoutAdaptationEnabled()194     static bool IsLayoutAdaptationEnabled() { return sm_layoutAdaptation; }
EnableLayoutAdaptation(bool enable)195     static void EnableLayoutAdaptation(bool enable) { sm_layoutAdaptation = enable; }
196 
197     // modality kind
198     virtual wxDialogModality GetModality() const;
199 protected:
200     // emulate click of a button with the given id if it's present in the dialog
201     //
202     // return true if button was "clicked" or false if we don't have it
203     bool EmulateButtonClickIfPresent(int id);
204 
205     // this function is used by OnCharHook() to decide whether the given key
206     // should close the dialog
207     //
208     // for most platforms the default implementation (which just checks for
209     // Esc) is sufficient, but Mac port also adds Cmd-. here and other ports
210     // could do something different if needed
211     virtual bool IsEscapeKey(const wxKeyEvent& event);
212 
213     // end either modal or modeless dialog, for the modal dialog rc is used as
214     // the dialog return code
215     void EndDialog(int rc);
216 
217     // call Validate() and TransferDataFromWindow() and close dialog with
218     // wxID_OK return code
219     void AcceptAndClose();
220 
221     // The return code from modal dialog
222     int m_returnCode;
223 
224     // The identifier for the affirmative button (usually wxID_OK)
225     int m_affirmativeId;
226 
227     // The identifier for cancel button (usually wxID_CANCEL)
228     int m_escapeId;
229 
230     // Flags whether layout adaptation has been done for this dialog
231     bool                                m_layoutAdaptationDone;
232 
233     // Extra button identifiers to be taken as 'main' button identifiers
234     // to be placed in the non-scrolling area
235     wxArrayInt                          m_mainButtonIds;
236 
237     // Adaptation level
238     int                                 m_layoutAdaptationLevel;
239 
240     // Local override for global adaptation enabled status
241     wxDialogLayoutAdaptationMode        m_layoutAdaptationMode;
242 
243     // Global layout adapter
244     static wxDialogLayoutAdapter*       sm_layoutAdapter;
245 
246     // Global adaptation switch
247     static bool                         sm_layoutAdaptation;
248 
249 private:
250     // helper of GetParentForModalDialog(): returns the passed in window if it
251     // can be used as our parent or NULL if it can't
252     wxWindow *CheckIfCanBeUsedAsParent(wxWindow *parent) const;
253 
254     // Helper of OnCharHook() and OnCloseWindow(): find the appropriate button
255     // for closing the dialog and send a click event for it.
256     //
257     // Return true if we found a button to close the dialog and "clicked" it or
258     // false otherwise.
259     bool SendCloseButtonClickEvent();
260 
261     // handle Esc key presses
262     void OnCharHook(wxKeyEvent& event);
263 
264     // handle closing the dialog window
265     void OnCloseWindow(wxCloseEvent& event);
266 
267     // handle the standard buttons
268     void OnButton(wxCommandEvent& event);
269 
270     // update the background colour
271     void OnSysColourChanged(wxSysColourChangedEvent& event);
272 
273 
274     wxDECLARE_NO_COPY_CLASS(wxDialogBase);
275     DECLARE_EVENT_TABLE()
276 };
277 
278 /*!
279  * Base class for layout adapters - code that, for example, turns a dialog into a
280  * scrolling dialog if there isn't enough screen space. You can derive further
281  * adapter classes to do any other kind of adaptation, such as applying a watermark, or adding
282  * a help mechanism.
283  */
284 
285 class WXDLLIMPEXP_CORE wxDialogLayoutAdapter: public wxObject
286 {
DECLARE_CLASS(wxDialogLayoutAdapter)287     DECLARE_CLASS(wxDialogLayoutAdapter)
288 public:
289     wxDialogLayoutAdapter() {}
290 
291     // Override this function to indicate that adaptation should be done
292     virtual bool CanDoLayoutAdaptation(wxDialog* dialog) = 0;
293 
294     // Override this function to do the adaptation
295     virtual bool DoLayoutAdaptation(wxDialog* dialog) = 0;
296 };
297 
298 /*!
299  * Standard adapter. Does scrolling adaptation for paged and regular dialogs.
300  *
301  */
302 
303 class WXDLLIMPEXP_CORE wxStandardDialogLayoutAdapter: public wxDialogLayoutAdapter
304 {
DECLARE_CLASS(wxStandardDialogLayoutAdapter)305     DECLARE_CLASS(wxStandardDialogLayoutAdapter)
306 public:
307     wxStandardDialogLayoutAdapter() {}
308 
309 // Overrides
310 
311     // Indicate that adaptation should be done
312     virtual bool CanDoLayoutAdaptation(wxDialog* dialog);
313 
314     // Do layout adaptation
315     virtual bool DoLayoutAdaptation(wxDialog* dialog);
316 
317 // Implementation
318 
319     // Create the scrolled window
320     virtual wxScrolledWindow* CreateScrolledWindow(wxWindow* parent);
321 
322 #if wxUSE_BUTTON
323     // Find a standard or horizontal box sizer
324     virtual wxSizer* FindButtonSizer(bool stdButtonSizer, wxDialog* dialog, wxSizer* sizer, int& retBorder, int accumlatedBorder = 0);
325 
326     // Check if this sizer contains standard buttons, and so can be repositioned in the dialog
327     virtual bool IsOrdinaryButtonSizer(wxDialog* dialog, wxBoxSizer* sizer);
328 
329     // Check if this is a standard button
330     virtual bool IsStandardButton(wxDialog* dialog, wxButton* button);
331 
332     // Find 'loose' main buttons in the existing layout and add them to the standard dialog sizer
333     virtual bool FindLooseButtons(wxDialog* dialog, wxStdDialogButtonSizer* buttonSizer, wxSizer* sizer, int& count);
334 #endif // wxUSE_BUTTON
335 
336     // Reparent the controls to the scrolled window, except those in buttonSizer
337     virtual void ReparentControls(wxWindow* parent, wxWindow* reparentTo, wxSizer* buttonSizer = NULL);
338     static void DoReparentControls(wxWindow* parent, wxWindow* reparentTo, wxSizer* buttonSizer = NULL);
339 
340     // A function to fit the dialog around its contents, and then adjust for screen size.
341     // If scrolled windows are passed, scrolling is enabled in the required orientation(s).
342     virtual bool FitWithScrolling(wxDialog* dialog, wxScrolledWindow* scrolledWindow);
343     virtual bool FitWithScrolling(wxDialog* dialog, wxWindowList& windows);
344     static bool DoFitWithScrolling(wxDialog* dialog, wxScrolledWindow* scrolledWindow);
345     static bool DoFitWithScrolling(wxDialog* dialog, wxWindowList& windows);
346 
347     // Find whether scrolling will be necessary for the dialog, returning wxVERTICAL, wxHORIZONTAL or both
348     virtual int MustScroll(wxDialog* dialog, wxSize& windowSize, wxSize& displaySize);
349     static int DoMustScroll(wxDialog* dialog, wxSize& windowSize, wxSize& displaySize);
350 };
351 
352 #if defined(__WXUNIVERSAL__) && !defined(__WXMICROWIN__)
353     #include "wx/univ/dialog.h"
354 #else
355     #if defined(__WXMSW__)
356         #include "wx/msw/dialog.h"
357     #elif defined(__WXMOTIF__)
358         #include "wx/motif/dialog.h"
359     #elif defined(__WXGTK20__)
360         #include "wx/gtk/dialog.h"
361     #elif defined(__WXGTK__)
362         #include "wx/gtk1/dialog.h"
363     #elif defined(__WXMAC__)
364         #include "wx/osx/dialog.h"
365     #elif defined(__WXCOCOA__)
366         #include "wx/cocoa/dialog.h"
367     #elif defined(__WXPM__)
368         #include "wx/os2/dialog.h"
369     #endif
370 #endif
371 
372 class WXDLLIMPEXP_CORE wxWindowModalDialogEvent  : public wxCommandEvent
373 {
374 public:
375     wxWindowModalDialogEvent (wxEventType commandType = wxEVT_NULL, int id = 0)
wxCommandEvent(commandType,id)376         : wxCommandEvent(commandType, id) { }
377 
GetDialog()378     wxDialog *GetDialog() const
379         { return wxStaticCast(GetEventObject(), wxDialog); }
380 
GetReturnCode()381     int GetReturnCode() const
382         { return GetDialog()->GetReturnCode(); }
383 
Clone()384     virtual wxEvent *Clone() const { return new wxWindowModalDialogEvent (*this); }
385 
386 private:
387     DECLARE_DYNAMIC_CLASS_NO_ASSIGN(wxWindowModalDialogEvent )
388 };
389 
390 wxDECLARE_EXPORTED_EVENT(WXDLLIMPEXP_CORE, wxEVT_WINDOW_MODAL_DIALOG_CLOSED , wxWindowModalDialogEvent );
391 
392 typedef void (wxEvtHandler::*wxWindowModalDialogEventFunction)(wxWindowModalDialogEvent &);
393 
394 #define wxWindowModalDialogEventHandler(func) \
395     wxEVENT_HANDLER_CAST(wxWindowModalDialogEventFunction, func)
396 
397 #define EVT_WINDOW_MODAL_DIALOG_CLOSED(winid, func) \
398     wx__DECLARE_EVT1(wxEVT_WINDOW_MODAL_DIALOG_CLOSED, winid, wxWindowModalDialogEventHandler(func))
399 
400 #ifdef wxHAS_EVENT_BIND
401 template<typename Functor>
402 class wxWindowModalDialogEventFunctor
403 {
404 public:
wxWindowModalDialogEventFunctor(const Functor & f)405     wxWindowModalDialogEventFunctor(const Functor& f)
406         : m_f(new Functor(f))
407     {}
408 
operator()409     void operator()(wxWindowModalDialogEvent& event)
410     {
411         if ( m_f )
412         {
413             // We only want to call this handler once. Also, by deleting
414             // the functor here, its data (such as wxWindowPtr pointing to
415             // the dialog) are freed immediately after exiting this operator().
416             wxSharedPtr<Functor> functor(m_f);
417             m_f.reset();
418 
419             (*functor)(event.GetReturnCode());
420         }
421         else // was already called once
422         {
423             event.Skip();
424         }
425     }
426 
427 private:
428     wxSharedPtr<Functor> m_f;
429 };
430 
431 template<typename Functor>
ShowWindowModalThenDo(const Functor & onEndModal)432 void wxDialogBase::ShowWindowModalThenDo(const Functor& onEndModal)
433 {
434     Bind(wxEVT_WINDOW_MODAL_DIALOG_CLOSED,
435          wxWindowModalDialogEventFunctor<Functor>(onEndModal));
436     ShowWindowModal();
437 }
438 #endif // wxHAS_EVENT_BIND
439 
440 #endif
441     // _WX_DIALOG_H_BASE_
442