Code::Blocks  SVN r11506
scrollingdialog.cpp
Go to the documentation of this file.
1 // Name: scrollingdialog.cpp
3 // Purpose: wxScrollingDialog
4 // Author: Julian Smart
5 // Modified by: Jens Lody
6 // Created: 2007-12-11
7 // RCS-ID: $Id: scrollingdialog.cpp 11399 2018-05-08 21:54:03Z fuscated $
8 // Copyright: (c) Julian Smart
9 // Licence:
11 #include "sdk_precomp.h"
12 
13 #ifndef CB_PRECOMP
14  #include "wx/button.h"
15  #include "wx/scrolwin.h"
16  #include "wx/sizer.h"
17 #endif // CB_PRECOMP
18 
19 #include "wx/module.h"
20 #include "wx/display.h"
21 #include "wx/bookctrl.h"
22 
23 #include "scrollingdialog.h"
24 
25 // Allow for caption size on wxWidgets < 3.0
26 #if defined(__WXGTK__) && !wxCHECK_VERSION(3, 0, 0)
27 #define wxEXTRA_DIALOG_HEIGHT 30
28 #else
29 #define wxEXTRA_DIALOG_HEIGHT 0
30 #endif
31 
32 #if !wxCHECK_VERSION(3, 0, 0)
33 IMPLEMENT_CLASS(wxDialogLayoutAdapter, wxObject)
34 
35 
40 wxDialogLayoutAdapter* wxDialogHelper::sm_layoutAdapter = NULL;
41 bool wxDialogHelper::sm_layoutAdaptation = true;
42 
43 void wxDialogHelper::Init()
44 {
45  m_layoutAdaptationLevel = 3;
46  m_layoutLayoutAdaptationDone = FALSE;
47 }
48 
50 bool wxDialogHelper::DoLayoutAdaptation()
51 {
52  if (GetLayoutAdapter())
53  return GetLayoutAdapter()->DoLayoutAdaptation(this);
54  else
55  return false;
56 }
57 
59 bool wxDialogHelper::CanDoLayoutAdaptation()
60 {
61  return (GetLayoutAdaptation() && !m_layoutLayoutAdaptationDone && GetLayoutAdaptationLevel() != 0 && GetLayoutAdapter() != NULL && GetLayoutAdapter()->CanDoLayoutAdaptation(this));
62 }
63 
65 wxDialogLayoutAdapter* wxDialogHelper::SetLayoutAdapter(wxDialogLayoutAdapter* adapter)
66 {
67  wxDialogLayoutAdapter* oldLayoutAdapter = sm_layoutAdapter;
68  sm_layoutAdapter = adapter;
69  return oldLayoutAdapter;
70 }
71 
76 IMPLEMENT_CLASS(wxStandardDialogLayoutAdapter, wxDialogLayoutAdapter)
77 
78 bool wxStandardDialogLayoutAdapter::CanDoLayoutAdaptation(wxDialogHelper* dialog)
80 {
81  if (dialog->GetDialog()->GetSizer())
82  {
83  wxSize windowSize, displaySize;
84  return MustScroll(dialog->GetDialog(), windowSize, displaySize) != 0;
85  }
86  else
87  return false;
88 }
89 
90 bool wxStandardDialogLayoutAdapter::DoLayoutAdaptation(wxDialogHelper* dialog)
91 {
92  if (dialog->GetDialog()->GetSizer())
93  {
94  wxBookCtrlBase* bookContentWindow = wxDynamicCast(dialog->GetContentWindow(), wxBookCtrlBase);
95  if (bookContentWindow)
96  {
97  // If we have a book control, make all the pages (that use sizers) scrollable
98  wxWindowList windows;
99  for (size_t i = 0; i < bookContentWindow->GetPageCount(); i++)
100  {
101  wxWindow* page = bookContentWindow->GetPage(i);
102 
103  wxScrolledWindow* scrolledWindow = wxDynamicCast(page, wxScrolledWindow);
104  if (scrolledWindow)
105  windows.Append(scrolledWindow);
106  else if (!scrolledWindow && page->GetSizer())
107  {
108  // Create a scrolled window and reparent
110  wxSizer* oldSizer = page->GetSizer();
111 
112  wxSizer* newSizer = new wxBoxSizer(wxVERTICAL);
113  newSizer->Add(scrolledWindow,1, wxEXPAND, 0);
114 
115  page->SetSizer(newSizer, false /* don't delete the old sizer */);
116 
117  scrolledWindow->SetSizer(oldSizer);
118 
119  ReparentControls(page, scrolledWindow, NULL);
120 
121  windows.Append(scrolledWindow);
122  }
123  }
124 
125  FitWithScrolling(dialog->GetDialog(), windows);
126  }
127  else
128  {
129  // If we have an arbitrary dialog, create a scrolling area for the main content, and a button sizer
130  // for the main buttons.
132 
133  int buttonSizerBorder = 0;
134 
135  // First try to find a wxStdDialogButtonSizer
136  wxSizer* buttonSizer = FindButtonSizer(true /* find std button sizer */, dialog, dialog->GetDialog()->GetSizer(), buttonSizerBorder);
137 
138  // Next try to find a wxBoxSizer containing the controls
139  if (!buttonSizer && dialog->GetLayoutAdaptationLevel() > 1)
140  buttonSizer = FindButtonSizer(false /* find ordinary sizer */, dialog, dialog->GetDialog()->GetSizer(), buttonSizerBorder);
141 
142  // If we still don't have a button sizer, collect any 'loose' buttons in the layout
143  if (!buttonSizer && dialog->GetLayoutAdaptationLevel() > 2)
144  {
145  int count = 0;
146  wxStdDialogButtonSizer* stdButtonSizer = new wxStdDialogButtonSizer;
147  buttonSizer = stdButtonSizer;
148 
149  FindLooseButtons(dialog, stdButtonSizer, dialog->GetDialog()->GetSizer(), count);
150  if (count > 0)
151  stdButtonSizer->Realize();
152  else
153  {
154  delete buttonSizer;
155  buttonSizer = NULL;
156  }
157  }
158 
159  if (buttonSizerBorder == 0)
160  buttonSizerBorder = 5;
161 
162  ReparentControls(dialog->GetDialog(), scrolledWindow, buttonSizer);
163 
164  wxBoxSizer* newTopSizer = new wxBoxSizer(wxVERTICAL);
165  wxSizer* oldSizer = dialog->GetDialog()->GetSizer();
166 
167  dialog->GetDialog()->SetSizer(newTopSizer, false /* don't delete old sizer */);
168 
169  newTopSizer->Add(scrolledWindow, 1, wxEXPAND|wxALL, 0);
170  if (buttonSizer)
171  newTopSizer->Add(buttonSizer, 0, wxEXPAND|wxALL, buttonSizerBorder);
172 
173  scrolledWindow->SetSizer(oldSizer);
174 
175  FitWithScrolling(dialog->GetDialog(), scrolledWindow);
176  }
177  }
178 
179  dialog->SetLayoutAdaptationDone(true);
180  return true;
181 }
182 
184 wxSizer* wxStandardDialogLayoutAdapter::FindButtonSizer(bool stdButtonSizer, wxDialogHelper* dialog, wxSizer* sizer, int& retBorder, int accumlatedBorder)
185 {
186  for ( wxSizerItemList::compatibility_iterator node = sizer->GetChildren().GetFirst();
187  node; node = node->GetNext() )
188  {
189  wxSizerItem *item = node->GetData();
190  wxSizer *childSizer = item->GetSizer();
191 
192  if ( childSizer )
193  {
194  int newBorder = accumlatedBorder;
195  if (item->GetFlag() & wxALL)
196  newBorder += item->GetBorder();
197 
198  if (stdButtonSizer) // find wxStdDialogButtonSizer
199  {
200  wxStdDialogButtonSizer* buttonSizer = wxDynamicCast(childSizer, wxStdDialogButtonSizer);
201  if (buttonSizer)
202  {
203  sizer->Detach(childSizer);
204  retBorder = newBorder;
205  return buttonSizer;
206  }
207  }
208  else // find a horizontal box sizer containing standard buttons
209  {
210  wxBoxSizer* buttonSizer = wxDynamicCast(childSizer, wxBoxSizer);
211  if (buttonSizer && IsOrdinaryButtonSizer(dialog, buttonSizer))
212  {
213  sizer->Detach(childSizer);
214  retBorder = newBorder;
215  return buttonSizer;
216  }
217  }
218 
219  wxSizer* s = FindButtonSizer(stdButtonSizer, dialog, childSizer, retBorder, newBorder);
220  if (s)
221  return s;
222  }
223  }
224  return NULL;
225 }
226 
228 bool wxStandardDialogLayoutAdapter::IsOrdinaryButtonSizer(wxDialogHelper* dialog, wxBoxSizer* sizer)
229 {
230  if (sizer->GetOrientation() != wxHORIZONTAL)
231  return false;
232 
233  for ( wxSizerItemList::compatibility_iterator node = sizer->GetChildren().GetFirst();
234  node; node = node->GetNext() )
235  {
236  wxSizerItem *item = node->GetData();
237  wxButton *childButton = wxDynamicCast(item->GetWindow(), wxButton);
238 
239  if (childButton && IsStandardButton(dialog, childButton))
240  return true;
241  }
242  return false;
243 }
244 
246 bool wxStandardDialogLayoutAdapter::IsStandardButton(wxDialogHelper* dialog, wxButton* button)
247 {
248  wxWindowID id = button->GetId();
249 
250  return (id == wxID_OK || id == wxID_CANCEL || id == wxID_YES || id == wxID_NO || id == wxID_SAVE ||
251  id == wxID_APPLY || id == wxID_HELP || id == wxID_CONTEXT_HELP || dialog->IsUserButtonId(id));
252 }
253 
255 bool wxStandardDialogLayoutAdapter::FindLooseButtons(wxDialogHelper* dialog, wxStdDialogButtonSizer* buttonSizer, wxSizer* sizer, int& count)
256 {
257  wxSizerItemList::compatibility_iterator node = sizer->GetChildren().GetFirst();
258  while (node)
259  {
260  wxSizerItemList::compatibility_iterator next = node->GetNext();
261  wxSizerItem *item = node->GetData();
262  wxSizer *childSizer = item->GetSizer();
263  wxButton *childButton = wxDynamicCast(item->GetWindow(), wxButton);
264 
265  if (childButton && IsStandardButton(dialog, childButton))
266  {
267  sizer->Detach(childButton);
268  buttonSizer->AddButton(childButton);
269  count ++;
270  }
271 
272  if (childSizer)
273  FindLooseButtons(dialog, buttonSizer, childSizer, count);
274 
275  node = next;
276  }
277  return true;
278 }
279 
281 void wxStandardDialogLayoutAdapter::ReparentControls(wxWindow* parent, wxWindow* reparentTo, wxSizer* buttonSizer)
282 {
283  wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
284  while (node)
285  {
286  wxWindowList::compatibility_iterator next = node->GetNext();
287 
288  wxWindow *win = node->GetData();
289 
290  // Don't reparent the scrolled window or buttons in the button sizer
291  if (win != reparentTo && (!buttonSizer || !buttonSizer->GetItem(win)))
292  {
293  win->Reparent(reparentTo);
294 #ifdef __WXMSW__
295  // Restore correct tab order
296  ::SetWindowPos((HWND) win->GetHWND(), HWND_BOTTOM, -1, -1, -1, -1, SWP_NOMOVE|SWP_NOSIZE);
297 #endif
298  }
299 
300  node = next;
301  }
302 }
303 
305 int wxStandardDialogLayoutAdapter::MustScroll(wxDialog* dialog, wxSize& windowSize, wxSize& displaySize)
306 {
307  wxSize minWindowSize = dialog->GetSizer()->GetMinSize();
308  windowSize = dialog->GetSize();
309  windowSize = wxSize(wxMax(windowSize.x, minWindowSize.x), wxMax(windowSize.y, minWindowSize.y));
310 #ifdef __WXMSW__
311  // On windows wxWidgets does not recognize a (dis)connection of additional monitors on run
312  // and therefore wxDisplay::GetFromWindow() fails and returns wxNOT_FOUND.
313  // This results in a displaySize of (0,0) and invisible dialogs.
314  // Using 0 as displayIndex in this case is safe, because one display must be there if
315  // C::B is running, or we have a real problem.
316  int displayIndex = wxDisplay::GetFromWindow(dialog);
317  if ( displayIndex == wxNOT_FOUND)
318  displayIndex = 0;
319  displaySize = wxDisplay(displayIndex).GetClientArea().GetSize();
320 #else //__WXMSW__
321  displaySize = wxDisplay(wxDisplay::GetFromWindow(dialog)).GetClientArea().GetSize();
322 #endif //__WXMSW__
323  int flags = 0;
324 
325  if (windowSize.y >= (displaySize.y - wxEXTRA_DIALOG_HEIGHT))
326  flags |= wxVERTICAL;
327  if (windowSize.x >= displaySize.x)
328  flags |= wxHORIZONTAL;
329 
330  return flags;
331 }
332 
333 // A function to fit the dialog around its contents, and then adjust for screen size.
334 // If scrolled windows are passed, scrolling is enabled in the required orientation(s).
335 bool wxStandardDialogLayoutAdapter::FitWithScrolling(wxDialog* dialog, wxWindowList& windows)
336 {
337  wxSizer* sizer = dialog->GetSizer();
338  if (!sizer)
339  return false;
340 
341  sizer->SetSizeHints(dialog);
342 
343  wxSize windowSize, displaySize;
344  int scrollFlags = MustScroll(dialog, windowSize, displaySize);
345  int scrollBarSize = 20;
346 
347  if (scrollFlags)
348  {
349  int scrollBarExtraX = 0, scrollBarExtraY = 0;
350  bool resizeHorizontally = (scrollFlags & wxHORIZONTAL) != 0;
351  bool resizeVertically = (scrollFlags & wxVERTICAL) != 0;
352 
353  if (windows.GetCount() != 0)
354  {
355  // Allow extra for a scrollbar, assuming we resizing in one direction only.
356  if ((resizeVertically && !resizeHorizontally) && (windowSize.x < (displaySize.x - scrollBarSize)))
357  scrollBarExtraX = scrollBarSize;
358  if ((resizeHorizontally && !resizeVertically) && (windowSize.y < (displaySize.y - scrollBarSize)))
359  scrollBarExtraY = scrollBarSize;
360  }
361 
362  wxWindowList::compatibility_iterator node = windows.GetFirst();
363  while (node)
364  {
365  wxWindow *win = node->GetData();
366  wxScrolledWindow* scrolledWindow = wxDynamicCast(win, wxScrolledWindow);
367  if (scrolledWindow)
368  {
369  scrolledWindow->SetScrollRate(resizeHorizontally ? 10 : 0, resizeVertically ? 10 : 0);
370 
371  if (scrolledWindow->GetSizer())
372  scrolledWindow->GetSizer()->Fit(scrolledWindow);
373  }
374 
375  node = node->GetNext();
376  }
377 
378  wxSize limitTo = windowSize + wxSize(scrollBarExtraX, scrollBarExtraY);
379  if (resizeVertically)
380  limitTo.y = displaySize.y - wxEXTRA_DIALOG_HEIGHT;
381  if (resizeHorizontally)
382  limitTo.x = displaySize.x;
383 
384  dialog->SetMinSize(limitTo);
385  dialog->SetSize(limitTo);
386 
387  dialog->SetSizeHints( limitTo.x, limitTo.y, dialog->GetMaxWidth(), dialog->GetMaxHeight() );
388  }
389 
390  return true;
391 }
392 
393 // A function to fit the dialog around its contents, and then adjust for screen size.
394 // If a scrolled window is passed, scrolling is enabled in the required orientation(s).
395 bool wxStandardDialogLayoutAdapter::FitWithScrolling(wxDialog* dialog, wxScrolledWindow* scrolledWindow)
396 {
397  wxWindowList windows;
398  windows.Append(scrolledWindow);
399  return FitWithScrolling(dialog, windows);
400 }
401 
406 class wxDialogLayoutAdapterModule: public wxModule
407 {
408  DECLARE_DYNAMIC_CLASS(wxDialogLayoutAdapterModule)
409 public:
410  wxDialogLayoutAdapterModule() {}
411  void OnExit() override { delete wxDialogHelper::SetLayoutAdapter(NULL); }
412  bool OnInit() override { wxDialogHelper::SetLayoutAdapter(new wxStandardDialogLayoutAdapter); return true; }
413 };
414 
415 IMPLEMENT_DYNAMIC_CLASS(wxDialogLayoutAdapterModule, wxModule)
416 #endif //#if !wxCHECK_VERSION(3, 0, 0)
417 
422 IMPLEMENT_CLASS(wxScrollingDialog, wxDialog)
423 
424 #if !wxCHECK_VERSION(3, 0, 0)
425 void wxScrollingDialog::Init()
426 {
427  wxDialogHelper::SetDialog(this);
428 }
429 
430 bool wxScrollingDialog::Create(wxWindow *parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name)
431 {
432  return wxDialog::Create(parent, id, title, pos, size, style, name);
433 }
434 
436 bool wxScrollingDialog::Show(bool show)
437 {
438  if (CanDoLayoutAdaptation())
439  DoLayoutAdaptation();
440 
441  return wxDialog::Show(show);
442 }
443 
446 {
447  if (CanDoLayoutAdaptation())
448  DoLayoutAdaptation();
449 
450  return wxDialog::ShowModal();
451 }
452 #endif //#if !wxCHECK_VERSION(3, 0, 0)
453 
459 
460 #if !wxCHECK_VERSION(3, 0, 0)
461 void wxScrollingPropertySheetDialog::Init()
462 {
463  wxDialogHelper::SetDialog(this);
464 }
465 
467 wxWindow* wxScrollingPropertySheetDialog::GetContentWindow() const
468 {
469  return GetBookCtrl();
470 }
471 
473 bool wxScrollingPropertySheetDialog::Show(bool show)
474 {
475  if (CanDoLayoutAdaptation())
476  DoLayoutAdaptation();
477 
478  return wxPropertySheetDialog::Show(show);
479 }
480 
483 {
484  if (CanDoLayoutAdaptation())
485  DoLayoutAdaptation();
486 
488 }
489 #endif //#if !wxCHECK_VERSION(3, 0, 0)
490 
#define wxDynamicCast(ptr, classname)
virtual size_t GetPageCount() const
wxRect GetClientArea() const
int GetOrientation() const
#define wxHSCROLL
wxScrolled< wxPanel > wxScrolledWindow
void AddButton(wxButton *button)
#define wxNOT_FOUND
#define wxTAB_TRAVERSAL
const wxSize wxDefaultSize
const wxPoint wxDefaultPosition
wxSize GetSize() const
IMPLEMENT_DYNAMIC_CLASS(cbDummyEditor, wxPGEditor)
#define wxEXTRA_DIALOG_HEIGHT
virtual int ShowModal()
static int GetFromWindow(const wxWindow *win)
wxSizerItemList & GetChildren()
#define NULL
Definition: prefix.cpp:59
int wxWindowID
#define wxVSCROLL