OpenCPN Partial API docs
Loading...
Searching...
No Matches
scrollingdialog.cpp
1
2// Name: scrollingdialog.cpp
3// Purpose: wxScrollingDialog
4// Author: Julian Smart
5// Modified by:
6// Created: 2007-12-11
7// Copyright: (c) Julian Smart
8// Licence: wxWindows licence
10
11#include "wx/wx.h"
12#include "wx/module.h"
13#include "wx/display.h"
14#include "wx/bookctrl.h"
15
16#include "scrollingdialog.h"
17
18// Allow for caption size on wxWidgets < 2.9
19#if defined(__WXGTK__) && !wxCHECK_VERSION(2, 9, 0)
20#define wxEXTRA_DIALOG_HEIGHT 30
21#else
22#define wxEXTRA_DIALOG_HEIGHT 0
23#endif
24
25IMPLEMENT_CLASS(wxDialogLayoutAdapter, wxObject)
26
27
33bool wxDialogHelper::sm_layoutAdaptation = true;
34
35void wxDialogHelper::Init() {
36 m_layoutAdaptationLevel = 3;
37 m_layoutLayoutAdaptationDone = FALSE;
38}
39
42 if (GetLayoutAdapter())
43 return GetLayoutAdapter()->DoLayoutAdaptation(this);
44 else
45 return false;
46}
47
50 return (GetLayoutAdaptation() && !m_layoutLayoutAdaptationDone &&
51 GetLayoutAdaptationLevel() != 0 && GetLayoutAdapter() != NULL &&
52 GetLayoutAdapter()->CanDoLayoutAdaptation(this));
53}
54
57 wxDialogLayoutAdapter* adapter) {
58 wxDialogLayoutAdapter* oldLayoutAdapter = sm_layoutAdapter;
59 sm_layoutAdapter = adapter;
60 return oldLayoutAdapter;
61}
62
68
69
70bool wxStandardDialogLayoutAdapter::CanDoLayoutAdaptation(
71 wxDialogHelper* dialog) {
72 if (dialog->GetDialog()->GetSizer()) {
73 wxSize windowSize, displaySize;
74 return MustScroll(dialog->GetDialog(), windowSize, displaySize) != 0;
75 } else
76 return false;
77}
78
80 if (dialog->GetDialog()->GetSizer()) {
81 // The wxRTTI is wrong for wxNotebook in < 2.8.8 and 2.9, so use
82 // dynamic_cast instead
83#if !wxCHECK_VERSION(2, 8, 8) || \
84 (wxCHECK_VERSION(2, 9, 0) && !wxCHECK_VERSION(3, 0, 0))
85 wxBookCtrlBase* bookContentWindow =
86 dynamic_cast<wxBookCtrlBase*>(dialog->GetContentWindow());
87#else
88 wxBookCtrlBase* bookContentWindow =
89 wxDynamicCast(dialog->GetContentWindow(), wxBookCtrlBase);
90#endif
91
92 if (bookContentWindow) {
93 // If we have a book control, make all the pages (that use sizers)
94 // scrollable
95 wxWindowList windows;
96 for (size_t i = 0; i < bookContentWindow->GetPageCount(); i++) {
97 wxWindow* page = bookContentWindow->GetPage(i);
98
99 wxScrolledWindow* scrolledWindow =
100 wxDynamicCast(page, wxScrolledWindow);
101 if (scrolledWindow)
102 windows.Append(scrolledWindow);
103 else if (!scrolledWindow && page->GetSizer()) {
104 // Create a scrolled window and reparent
105 scrolledWindow = new wxScrolledWindow(
106 page, wxID_ANY, wxDefaultPosition, wxDefaultSize,
107 wxTAB_TRAVERSAL | wxVSCROLL | wxHSCROLL | wxBORDER_NONE);
108 wxSizer* oldSizer = page->GetSizer();
109
110 wxSizer* newSizer = new wxBoxSizer(wxVERTICAL);
111 newSizer->Add(scrolledWindow, 1, wxEXPAND, 0);
112
113 page->SetSizer(newSizer, false /* don't delete the old sizer */);
114
115 scrolledWindow->SetSizer(oldSizer);
116
117 ReparentControls(page, scrolledWindow, NULL);
118
119 windows.Append(scrolledWindow);
120 }
121 }
122
123 FitWithScrolling(dialog->GetDialog(), windows);
124 } else {
125 // If we have an arbitrary dialog, create a scrolling area for the main
126 // content, and a button sizer for the main buttons.
127 wxScrolledWindow* scrolledWindow = new wxScrolledWindow(
128 dialog->GetDialog(), wxID_ANY, wxDefaultPosition, wxDefaultSize,
129 wxTAB_TRAVERSAL | wxVSCROLL | wxHSCROLL | wxBORDER_NONE);
130
131 int buttonSizerBorder = 0;
132
133 // First try to find a wxStdDialogButtonSizer
134 wxSizer* buttonSizer =
135 FindButtonSizer(true /* find std button sizer */, dialog,
136 dialog->GetDialog()->GetSizer(), buttonSizerBorder);
137
138 // Next try to find a wxBoxSizer containing the controls
139 if (!buttonSizer && dialog->GetLayoutAdaptationLevel() > 1)
140 buttonSizer =
141 FindButtonSizer(false /* find ordinary sizer */, dialog,
142 dialog->GetDialog()->GetSizer(), buttonSizerBorder);
143
144 // If we still don't have a button sizer, collect any 'loose' buttons in
145 // the layout
146 if (!buttonSizer && dialog->GetLayoutAdaptationLevel() > 2) {
147 int count = 0;
148 wxStdDialogButtonSizer* stdButtonSizer = new wxStdDialogButtonSizer;
149 buttonSizer = stdButtonSizer;
150
151 FindLooseButtons(dialog, stdButtonSizer,
152 dialog->GetDialog()->GetSizer(), count);
153 if (count > 0)
154 stdButtonSizer->Realize();
155 else {
156 delete buttonSizer;
157 buttonSizer = NULL;
158 }
159 }
160
161 if (buttonSizerBorder == 0) buttonSizerBorder = 5;
162
163 ReparentControls(dialog->GetDialog(), scrolledWindow, buttonSizer);
164
165 wxBoxSizer* newTopSizer = new wxBoxSizer(wxVERTICAL);
166 wxSizer* oldSizer = dialog->GetDialog()->GetSizer();
167
168 dialog->GetDialog()->SetSizer(newTopSizer,
169 false /* don't delete old sizer */);
170
171 newTopSizer->Add(scrolledWindow, 1, wxEXPAND | wxALL, 0);
172 if (buttonSizer)
173 newTopSizer->Add(buttonSizer, 0, wxEXPAND | wxALL, buttonSizerBorder);
174
175 scrolledWindow->SetSizer(oldSizer);
176
177 FitWithScrolling(dialog->GetDialog(), scrolledWindow);
178 }
179 }
180
181 dialog->SetLayoutAdaptationDone(true);
182 return true;
183}
184
187 wxDialogHelper* dialog,
188 wxSizer* sizer,
189 int& retBorder,
190 int accumlatedBorder) {
191 for (wxSizerItemList::compatibility_iterator node =
192 sizer->GetChildren().GetFirst();
193 node; node = node->GetNext()) {
194 wxSizerItem* item = node->GetData();
195 wxSizer* childSizer = item->GetSizer();
196
197 if (childSizer) {
198 int newBorder = accumlatedBorder;
199 if (item->GetFlag() & wxALL) newBorder += item->GetBorder();
200
201 if (stdButtonSizer) // find wxStdDialogButtonSizer
202 {
203 wxStdDialogButtonSizer* buttonSizer =
204 wxDynamicCast(childSizer, wxStdDialogButtonSizer);
205 if (buttonSizer) {
206 sizer->Detach(childSizer);
207 retBorder = newBorder;
208 return buttonSizer;
209 }
210 } else // find a horizontal box sizer containing standard buttons
211 {
212 wxBoxSizer* buttonSizer = wxDynamicCast(childSizer, wxBoxSizer);
213 if (buttonSizer && IsOrdinaryButtonSizer(dialog, buttonSizer)) {
214 sizer->Detach(childSizer);
215 retBorder = newBorder;
216 return buttonSizer;
217 }
218 }
219
220 wxSizer* s = FindButtonSizer(stdButtonSizer, dialog, childSizer,
221 retBorder, newBorder);
222 if (s) return s;
223 }
224 }
225 return NULL;
226}
227
231 wxDialogHelper* dialog, wxBoxSizer* sizer) {
232 if (sizer->GetOrientation() != wxHORIZONTAL) return false;
233
234 for (wxSizerItemList::compatibility_iterator node =
235 sizer->GetChildren().GetFirst();
236 node; node = node->GetNext()) {
237 wxSizerItem* item = node->GetData();
238 wxButton* childButton = wxDynamicCast(item->GetWindow(), wxButton);
239
240 if (childButton && IsStandardButton(dialog, childButton)) return true;
241 }
242 return false;
243}
244
247 wxButton* button) {
248 wxWindowID id = button->GetId();
249
250 return (id == wxID_OK || id == wxID_CANCEL || id == wxID_YES ||
251 id == wxID_NO || id == wxID_SAVE || id == wxID_APPLY ||
252 id == wxID_HELP || id == wxID_CONTEXT_HELP ||
253 dialog->IsUserButtonId(id));
254}
255
259 wxDialogHelper* dialog, wxStdDialogButtonSizer* buttonSizer, wxSizer* sizer,
260 int& count) {
261 wxSizerItemList::compatibility_iterator node =
262 sizer->GetChildren().GetFirst();
263 while (node) {
264 wxSizerItemList::compatibility_iterator next = node->GetNext();
265 wxSizerItem* item = node->GetData();
266 wxSizer* childSizer = item->GetSizer();
267 wxButton* childButton = wxDynamicCast(item->GetWindow(), wxButton);
268
269 if (childButton && IsStandardButton(dialog, childButton)) {
270 sizer->Detach(childButton);
271 buttonSizer->AddButton(childButton);
272 count++;
273 }
274
275 if (childSizer) FindLooseButtons(dialog, buttonSizer, childSizer, count);
276
277 node = next;
278 }
279 return true;
280}
281
284 wxWindow* reparentTo,
285 wxSizer* buttonSizer) {
286 wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
287 while (node) {
288 wxWindowList::compatibility_iterator next = node->GetNext();
289
290 wxWindow* win = node->GetData();
291
292 // Don't reparent the scrolled window or buttons in the button sizer
293 if (win != reparentTo && (!buttonSizer || !buttonSizer->GetItem(win))) {
294 win->Reparent(reparentTo);
295#ifdef __WXMSW__
296 // Restore correct tab order
297 ::SetWindowPos((HWND)win->GetHWND(), HWND_BOTTOM, -1, -1, -1, -1,
298 SWP_NOMOVE | SWP_NOSIZE);
299#endif
300 }
301
302 node = next;
303 }
304}
305
309 wxSize& windowSize,
310 wxSize& displaySize) {
311 wxSize minWindowSize = dialog->GetSizer()->GetMinSize();
312 windowSize = dialog->GetSize();
313 windowSize = wxSize(wxMax(windowSize.x, minWindowSize.x),
314 wxMax(windowSize.y, minWindowSize.y));
315 displaySize =
316 wxDisplay(wxDisplay::GetFromWindow(dialog)).GetClientArea().GetSize();
317
318 int flags = 0;
319
320 if (windowSize.y >= (displaySize.y - wxEXTRA_DIALOG_HEIGHT))
321 flags |= wxVERTICAL;
322 if (windowSize.x >= displaySize.x) flags |= wxHORIZONTAL;
323
324 return flags;
325}
326
327// A function to fit the dialog around its contents, and then adjust for screen
328// size. If scrolled windows are passed, scrolling is enabled in the required
329// orientation(s).
331 wxWindowList& windows) {
332 wxSizer* sizer = dialog->GetSizer();
333 if (!sizer) return false;
334
335 sizer->SetSizeHints(dialog);
336
337 wxSize windowSize, displaySize;
338 int scrollFlags = MustScroll(dialog, windowSize, displaySize);
339 int scrollBarSize = 20;
340
341 if (scrollFlags) {
342 int scrollBarExtraX = 0, scrollBarExtraY = 0;
343 bool resizeHorizontally = (scrollFlags & wxHORIZONTAL) != 0;
344 bool resizeVertically = (scrollFlags & wxVERTICAL) != 0;
345
346 if (windows.GetCount() != 0) {
347 // Allow extra for a scrollbar, assuming we resizing in one direction
348 // only.
349 if ((resizeVertically && !resizeHorizontally) &&
350 (windowSize.x < (displaySize.x - scrollBarSize)))
351 scrollBarExtraX = scrollBarSize;
352 if ((resizeHorizontally && !resizeVertically) &&
353 (windowSize.y < (displaySize.y - scrollBarSize)))
354 scrollBarExtraY = scrollBarSize;
355 }
356
357 wxWindowList::compatibility_iterator node = windows.GetFirst();
358 while (node) {
359 wxWindow* win = node->GetData();
360 wxScrolledWindow* scrolledWindow = wxDynamicCast(win, wxScrolledWindow);
361 if (scrolledWindow) {
362 scrolledWindow->SetScrollRate(resizeHorizontally ? 10 : 0,
363 resizeVertically ? 10 : 0);
364
365 if (scrolledWindow->GetSizer())
366 scrolledWindow->GetSizer()->Fit(scrolledWindow);
367 }
368
369 node = node->GetNext();
370 }
371
372 wxSize limitTo = windowSize + wxSize(scrollBarExtraX, scrollBarExtraY);
373 if (resizeVertically) limitTo.y = displaySize.y - wxEXTRA_DIALOG_HEIGHT;
374 if (resizeHorizontally) limitTo.x = displaySize.x;
375
376 dialog->SetMinSize(limitTo);
377 dialog->SetSize(limitTo);
378
379 dialog->SetSizeHints(limitTo.x, limitTo.y, dialog->GetMaxWidth(),
380 dialog->GetMaxHeight());
381 }
382
383 return true;
384}
385
386// A function to fit the dialog around its contents, and then adjust for screen
387// size. If a scrolled window is passed, scrolling is enabled in the required
388// orientation(s).
390 wxDialog* dialog, wxScrolledWindow* scrolledWindow) {
391 wxWindowList windows;
392 windows.Append(scrolledWindow);
393 return FitWithScrolling(dialog, windows);
394}
395
400class wxDialogLayoutAdapterModule : public wxModule {
401 DECLARE_DYNAMIC_CLASS(wxDialogLayoutAdapterModule)
402public:
404 virtual void OnExit() { delete wxDialogHelper::SetLayoutAdapter(NULL); }
405 virtual bool OnInit() {
407 return true;
408 }
409};
410
411IMPLEMENT_DYNAMIC_CLASS(wxDialogLayoutAdapterModule, wxModule)
412
413
417IMPLEMENT_CLASS(wxScrollingDialog, wxDialog)
418
419void wxScrollingDialog::Init() { wxDialogHelper::SetDialog(this); }
420
421bool wxScrollingDialog::Create(wxWindow* parent, int id, const wxString& title,
422 const wxPoint& pos, const wxSize& size,
423 long style) {
424 return wxDialog::Create(parent, id, title, pos, size, style);
425}
426
428bool wxScrollingDialog::Show(bool show) {
430
431 return wxDialog::Show(show);
432}
433
437
438 return wxDialog::ShowModal();
439}
440
445IMPLEMENT_DYNAMIC_CLASS(wxScrollingPropertySheetDialog, wxPropertySheetDialog)
446
447void wxScrollingPropertySheetDialog::Init() { wxDialogHelper::SetDialog(this); }
448
451 return GetBookCtrl();
452}
453
457
458 return wxPropertySheetDialog::Show(show);
459}
460
464
465 return wxPropertySheetDialog::ShowModal();
466}
int GetLayoutAdaptationLevel() const
Get level of adaptation.
virtual wxWindow * GetContentWindow() const
Returns a content window if there is one.
void SetLayoutAdaptationDone(bool adaptationDone)
Returns true if the adaptation has been done.
static bool GetLayoutAdaptation()
Global switch for layout adaptation.
static wxDialogLayoutAdapter * sm_layoutAdapter
static wxDialogLayoutAdapter * SetLayoutAdapter(wxDialogLayoutAdapter *adapter)
Set layout adapter class, returning old adapter.
bool IsUserButtonId(wxWindowID id)
Is this id in the custom button id array?
virtual bool DoLayoutAdaptation()
Do the adaptation.
virtual bool CanDoLayoutAdaptation()
Can we do the adaptation?
virtual bool DoLayoutAdaptation(wxDialogHelper *dialog)=0
Override this function to do the adaptation.
virtual bool Show(bool show=true)
Override Show to rejig the control and sizer hierarchy if necessary.
virtual int ShowModal()
Override ShowModal to rejig the control and sizer hierarchy if necessary.
virtual bool Show(bool show=true)
Operations.
virtual int ShowModal()
Override ShowModal to rejig the control and sizer hierarchy if necessary.
virtual wxWindow * GetContentWindow() const
Returns the content window.
virtual bool FitWithScrolling(wxDialog *dialog, wxScrolledWindow *scrolledWindow)
A function to fit the dialog around its contents, and then adjust for screen size.
virtual bool IsOrdinaryButtonSizer(wxDialogHelper *dialog, wxBoxSizer *sizer)
Check if this sizer contains standard buttons, and so can be repositioned in the dialog.
virtual bool FindLooseButtons(wxDialogHelper *dialog, wxStdDialogButtonSizer *buttonSizer, wxSizer *sizer, int &count)
Find 'loose' main buttons in the existing layout and add them to the standard dialog sizer.
virtual bool DoLayoutAdaptation(wxDialogHelper *dialog)
Do layout adaptation.
virtual void ReparentControls(wxWindow *parent, wxWindow *reparentTo, wxSizer *buttonSizer=NULL)
Reparent the controls to the scrolled window, except those in buttonSizer.
virtual bool IsStandardButton(wxDialogHelper *dialog, wxButton *button)
Check if this is a standard button.
virtual int MustScroll(wxDialog *dialog, wxSize &windowSize, wxSize &displaySize)
Find whether scrolling will be necessary for the dialog, returning wxVERTICAL, wxHORIZONTAL or both.
virtual wxSizer * FindButtonSizer(bool stdButtonSizer, wxDialogHelper *dialog, wxSizer *sizer, int &retBorder, int accumlatedBorder=0)
Find a standard or horizontal box sizer.