Make the initial sash position work in splitter sample.
[wxWidgets.git] / samples / splitter / splitter.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: splitter.cpp
3 // Purpose: wxSplitterWindow sample
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/log.h"
29
30 #include "wx/app.h"
31 #include "wx/frame.h"
32
33 #include "wx/scrolwin.h"
34 #include "wx/menu.h"
35
36 #include "wx/textdlg.h" // for wxGetTextFromUser
37 #endif
38
39 #include "wx/splitter.h"
40 #include "wx/dcmirror.h"
41
42 #ifndef __WXMSW__
43 #include "../sample.xpm"
44 #endif
45
46 // ----------------------------------------------------------------------------
47 // constants
48 // ----------------------------------------------------------------------------
49
50 // ID for the menu commands
51 enum
52 {
53 SPLIT_QUIT = 1,
54 SPLIT_HORIZONTAL,
55 SPLIT_VERTICAL,
56 SPLIT_UNSPLIT,
57 SPLIT_LIVE,
58 SPLIT_BORDER,
59 SPLIT_3DSASH,
60 SPLIT_SETPOSITION,
61 SPLIT_SETMINSIZE,
62 SPLIT_SETGRAVITY,
63 SPLIT_REPLACE
64 };
65
66 // ----------------------------------------------------------------------------
67 // our classes
68 // ----------------------------------------------------------------------------
69
70 class MyApp: public wxApp
71 {
72 public:
73 MyApp() { }
74
75 virtual bool OnInit();
76
77 wxDECLARE_NO_COPY_CLASS(MyApp);
78 };
79
80 class MyFrame: public wxFrame
81 {
82 public:
83 MyFrame();
84 virtual ~MyFrame();
85
86 void ToggleFlag(int flag, bool enable);
87
88 // Menu commands
89 void OnSplitHorizontal(wxCommandEvent& event);
90 void OnSplitVertical(wxCommandEvent& event);
91 void OnUnsplit(wxCommandEvent& event);
92 void OnToggleLive(wxCommandEvent& event)
93 { ToggleFlag(wxSP_LIVE_UPDATE, event.IsChecked()); }
94 void OnToggleBorder(wxCommandEvent& event)
95 { ToggleFlag(wxSP_BORDER, event.IsChecked()); }
96 void OnToggle3DSash(wxCommandEvent& event)
97 { ToggleFlag(wxSP_3DSASH, event.IsChecked()); }
98 void OnSetPosition(wxCommandEvent& event);
99 void OnSetMinSize(wxCommandEvent& event);
100 void OnSetGravity(wxCommandEvent& event);
101 void OnReplace(wxCommandEvent &event);
102
103 void OnQuit(wxCommandEvent& event);
104
105 // Menu command update functions
106 void OnUpdateUIHorizontal(wxUpdateUIEvent& event);
107 void OnUpdateUIVertical(wxUpdateUIEvent& event);
108 void OnUpdateUIUnsplit(wxUpdateUIEvent& event);
109
110 private:
111 wxScrolledWindow *m_left, *m_right;
112
113 wxSplitterWindow* m_splitter;
114 wxWindow *m_replacewindow;
115
116 DECLARE_EVENT_TABLE()
117 wxDECLARE_NO_COPY_CLASS(MyFrame);
118 };
119
120 class MySplitterWindow : public wxSplitterWindow
121 {
122 public:
123 MySplitterWindow(wxFrame *parent);
124
125 // event handlers
126 void OnPositionChanged(wxSplitterEvent& event);
127 void OnPositionChanging(wxSplitterEvent& event);
128 void OnDClick(wxSplitterEvent& event);
129 void OnUnsplitEvent(wxSplitterEvent& event);
130
131 private:
132 wxFrame *m_frame;
133
134 DECLARE_EVENT_TABLE()
135 wxDECLARE_NO_COPY_CLASS(MySplitterWindow);
136 };
137
138 class MyCanvas: public wxScrolledWindow
139 {
140 public:
141 MyCanvas(wxWindow* parent, bool mirror);
142 virtual ~MyCanvas(){};
143
144 virtual void OnDraw(wxDC& dc);
145
146 private:
147 bool m_mirror;
148
149 wxDECLARE_NO_COPY_CLASS(MyCanvas);
150 };
151
152 // ============================================================================
153 // implementation
154 // ============================================================================
155
156 // ----------------------------------------------------------------------------
157 // MyApp
158 // ----------------------------------------------------------------------------
159
160 IMPLEMENT_APP(MyApp)
161
162 bool MyApp::OnInit()
163 {
164 if ( !wxApp::OnInit() )
165 return false;
166
167 // create and show the main frame
168 MyFrame* frame = new MyFrame;
169
170 frame->Show(true);
171
172 return true;
173 }
174
175 // ----------------------------------------------------------------------------
176 // MyFrame
177 // ----------------------------------------------------------------------------
178
179 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
180 EVT_MENU(SPLIT_VERTICAL, MyFrame::OnSplitVertical)
181 EVT_MENU(SPLIT_HORIZONTAL, MyFrame::OnSplitHorizontal)
182 EVT_MENU(SPLIT_UNSPLIT, MyFrame::OnUnsplit)
183 EVT_MENU(SPLIT_LIVE, MyFrame::OnToggleLive)
184 EVT_MENU(SPLIT_BORDER, MyFrame::OnToggleBorder)
185 EVT_MENU(SPLIT_3DSASH, MyFrame::OnToggle3DSash)
186 EVT_MENU(SPLIT_SETPOSITION, MyFrame::OnSetPosition)
187 EVT_MENU(SPLIT_SETMINSIZE, MyFrame::OnSetMinSize)
188 EVT_MENU(SPLIT_SETGRAVITY, MyFrame::OnSetGravity)
189 EVT_MENU(SPLIT_REPLACE, MyFrame::OnReplace)
190
191 EVT_MENU(SPLIT_QUIT, MyFrame::OnQuit)
192
193 EVT_UPDATE_UI(SPLIT_VERTICAL, MyFrame::OnUpdateUIVertical)
194 EVT_UPDATE_UI(SPLIT_HORIZONTAL, MyFrame::OnUpdateUIHorizontal)
195 EVT_UPDATE_UI(SPLIT_UNSPLIT, MyFrame::OnUpdateUIUnsplit)
196 END_EVENT_TABLE()
197
198 // My frame constructor
199 MyFrame::MyFrame()
200 : wxFrame(NULL, wxID_ANY, wxT("wxSplitterWindow sample"),
201 wxDefaultPosition, wxSize(420, 300),
202 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
203 {
204 SetIcon(wxICON(sample));
205
206 #if wxUSE_STATUSBAR
207 CreateStatusBar(2);
208 #endif // wxUSE_STATUSBAR
209
210 // Make a menubar
211 wxMenu *splitMenu = new wxMenu;
212 splitMenu->Append(SPLIT_VERTICAL,
213 wxT("Split &Vertically\tCtrl-V"),
214 wxT("Split vertically"));
215 splitMenu->Append(SPLIT_HORIZONTAL,
216 wxT("Split &Horizontally\tCtrl-H"),
217 wxT("Split horizontally"));
218 splitMenu->Append(SPLIT_UNSPLIT,
219 wxT("&Unsplit\tCtrl-U"),
220 wxT("Unsplit"));
221 splitMenu->AppendSeparator();
222
223 splitMenu->AppendCheckItem(SPLIT_LIVE,
224 wxT("&Live update\tCtrl-L"),
225 wxT("Toggle live update mode"));
226 splitMenu->AppendCheckItem(SPLIT_BORDER,
227 wxT("3D &Border"),
228 wxT("Toggle wxSP_BORDER flag"));
229 splitMenu->Check(SPLIT_BORDER, true);
230 splitMenu->AppendCheckItem(SPLIT_3DSASH,
231 wxT("&3D Sash"),
232 wxT("Toggle wxSP_3DSASH flag"));
233 splitMenu->Check(SPLIT_3DSASH, true);
234 splitMenu->Append(SPLIT_SETPOSITION,
235 wxT("Set splitter &position\tCtrl-P"),
236 wxT("Set the splitter position"));
237 splitMenu->Append(SPLIT_SETMINSIZE,
238 wxT("Set &min size\tCtrl-M"),
239 wxT("Set minimum pane size"));
240 splitMenu->Append(SPLIT_SETGRAVITY,
241 wxT("Set &gravity\tCtrl-G"),
242 wxT("Set gravity of sash"));
243 splitMenu->AppendSeparator();
244
245 splitMenu->Append(SPLIT_REPLACE,
246 wxT("&Replace right window"),
247 wxT("Replace right window"));
248 splitMenu->AppendSeparator();
249
250 splitMenu->Append(SPLIT_QUIT, wxT("E&xit\tAlt-X"), wxT("Exit"));
251
252 wxMenuBar *menuBar = new wxMenuBar;
253 menuBar->Append(splitMenu, wxT("&Splitter"));
254
255 SetMenuBar(menuBar);
256
257 menuBar->Check(SPLIT_LIVE, true);
258 m_splitter = new MySplitterWindow(this);
259
260 // If you use non-zero gravity you must initialize the splitter with its
261 // correct initial size, otherwise it will change the sash position by a
262 // huge amount when it's resized from its initial default size to its real
263 // size when the frame lays it out. This wouldn't be necessary if default
264 // zero gravity were used (although it would do no harm neither).
265 m_splitter->SetSize(GetClientSize());
266 m_splitter->SetSashGravity(1.0);
267
268 #if 1
269 m_left = new MyCanvas(m_splitter, true);
270 m_left->SetBackgroundColour(*wxRED);
271 m_left->SetScrollbars(20, 20, 5, 5);
272 m_left->SetCursor(wxCursor(wxCURSOR_MAGNIFIER));
273
274 m_right = new MyCanvas(m_splitter, false);
275 m_right->SetBackgroundColour(*wxCYAN);
276 m_right->SetScrollbars(20, 20, 5, 5);
277 #else // for testing kbd navigation inside the splitter
278 m_left = new wxTextCtrl(m_splitter, wxID_ANY, wxT("first text"));
279 m_right = new wxTextCtrl(m_splitter, wxID_ANY, wxT("second text"));
280 #endif
281
282 // you can also do this to start with a single window
283 #if 0
284 m_right->Show(false);
285 m_splitter->Initialize(m_left);
286 #else
287 // you can also try -100
288 m_splitter->SplitVertically(m_left, m_right, 100);
289 #endif
290
291 #if wxUSE_STATUSBAR
292 SetStatusText(wxT("Min pane size = 0"), 1);
293 #endif // wxUSE_STATUSBAR
294
295 m_replacewindow = NULL;
296 }
297
298 MyFrame::~MyFrame()
299 {
300 if (m_replacewindow) {
301 m_replacewindow->Destroy();
302 }
303 }
304
305 // menu command handlers
306
307 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event) )
308 {
309 Close(true);
310 }
311
312 void MyFrame::OnSplitHorizontal(wxCommandEvent& WXUNUSED(event) )
313 {
314 if ( m_splitter->IsSplit() )
315 m_splitter->Unsplit();
316 m_left->Show(true);
317 m_right->Show(true);
318 m_splitter->SplitHorizontally( m_left, m_right );
319 m_replacewindow = NULL;
320
321 #if wxUSE_STATUSBAR
322 SetStatusText(wxT("Splitter split horizontally"), 1);
323 #endif // wxUSE_STATUSBAR
324 }
325
326 void MyFrame::OnSplitVertical(wxCommandEvent& WXUNUSED(event) )
327 {
328 if ( m_splitter->IsSplit() )
329 m_splitter->Unsplit();
330 m_left->Show(true);
331 m_right->Show(true);
332 m_splitter->SplitVertically( m_left, m_right );
333 m_replacewindow = NULL;
334
335 #if wxUSE_STATUSBAR
336 SetStatusText(wxT("Splitter split vertically"), 1);
337 #endif // wxUSE_STATUSBAR
338 }
339
340 void MyFrame::OnUnsplit(wxCommandEvent& WXUNUSED(event) )
341 {
342 if ( m_splitter->IsSplit() )
343 m_splitter->Unsplit();
344 #if wxUSE_STATUSBAR
345 SetStatusText(wxT("No splitter"));
346 #endif // wxUSE_STATUSBAR
347 }
348
349 void MyFrame::ToggleFlag(int flag, bool enable)
350 {
351 long style = m_splitter->GetWindowStyleFlag();
352 if ( enable )
353 style |= flag;
354 else
355 style &= ~flag;
356
357 m_splitter->SetWindowStyleFlag(style);
358
359 // we need to move sash to redraw it
360 int pos = m_splitter->GetSashPosition();
361 m_splitter->SetSashPosition(pos + 1);
362 m_splitter->SetSashPosition(pos);
363 }
364
365 void MyFrame::OnSetPosition(wxCommandEvent& WXUNUSED(event) )
366 {
367 wxString str;
368 str.Printf( wxT("%d"), m_splitter->GetSashPosition());
369 #if wxUSE_TEXTDLG
370 str = wxGetTextFromUser(wxT("Enter splitter position:"), wxT(""), str, this);
371 #endif
372 if ( str.empty() )
373 return;
374
375 long pos;
376 if ( !str.ToLong(&pos) )
377 {
378 wxLogError(wxT("The splitter position should be an integer."));
379 return;
380 }
381
382 m_splitter->SetSashPosition(pos);
383
384 wxLogStatus(this, wxT("Splitter position set to %ld"), pos);
385 }
386
387 void MyFrame::OnSetMinSize(wxCommandEvent& WXUNUSED(event) )
388 {
389 wxString str;
390 str.Printf( wxT("%d"), m_splitter->GetMinimumPaneSize());
391 #if wxUSE_TEXTDLG
392 str = wxGetTextFromUser(wxT("Enter minimal size for panes:"), wxT(""), str, this);
393 #endif
394 if ( str.empty() )
395 return;
396
397 int minsize = wxStrtol( str, (wxChar**)NULL, 10 );
398 m_splitter->SetMinimumPaneSize(minsize);
399 #if wxUSE_STATUSBAR
400 str.Printf( wxT("Min pane size = %d"), minsize);
401 SetStatusText(str, 1);
402 #endif // wxUSE_STATUSBAR
403 }
404
405 void MyFrame::OnSetGravity(wxCommandEvent& WXUNUSED(event) )
406 {
407 wxString str;
408 str.Printf( wxT("%g"), m_splitter->GetSashGravity());
409 #if wxUSE_TEXTDLG
410 str = wxGetTextFromUser(wxT("Enter sash gravity (0,1):"), wxT(""), str, this);
411 #endif
412 if ( str.empty() )
413 return;
414
415 double gravity = wxStrtod( str, (wxChar**)NULL);
416 m_splitter->SetSashGravity(gravity);
417 #if wxUSE_STATUSBAR
418 str.Printf( wxT("Gravity = %g"), gravity);
419 SetStatusText(str, 1);
420 #endif // wxUSE_STATUSBAR
421 }
422
423 void MyFrame::OnReplace(wxCommandEvent& WXUNUSED(event) )
424 {
425 if (m_replacewindow == NULL) {
426 m_replacewindow = m_splitter->GetWindow2();
427 m_splitter->ReplaceWindow(m_replacewindow, new wxPanel(m_splitter, wxID_ANY));
428 m_replacewindow->Hide();
429 } else {
430 wxWindow *empty = m_splitter->GetWindow2();
431 wxASSERT(empty != m_replacewindow);
432 m_splitter->ReplaceWindow(empty, m_replacewindow);
433 m_replacewindow->Show();
434 m_replacewindow = NULL;
435 empty->Destroy();
436 }
437 }
438
439 // Update UI handlers
440
441 void MyFrame::OnUpdateUIHorizontal(wxUpdateUIEvent& event)
442 {
443 event.Enable( (!m_splitter->IsSplit()) || (m_splitter->GetSplitMode() != wxSPLIT_HORIZONTAL) );
444 }
445
446 void MyFrame::OnUpdateUIVertical(wxUpdateUIEvent& event)
447 {
448 event.Enable( ( (!m_splitter->IsSplit()) || (m_splitter->GetSplitMode() != wxSPLIT_VERTICAL) ) );
449 }
450
451 void MyFrame::OnUpdateUIUnsplit(wxUpdateUIEvent& event)
452 {
453 event.Enable( m_splitter->IsSplit() );
454 }
455
456 // ----------------------------------------------------------------------------
457 // MySplitterWindow
458 // ----------------------------------------------------------------------------
459
460 BEGIN_EVENT_TABLE(MySplitterWindow, wxSplitterWindow)
461 EVT_SPLITTER_SASH_POS_CHANGED(wxID_ANY, MySplitterWindow::OnPositionChanged)
462 EVT_SPLITTER_SASH_POS_CHANGING(wxID_ANY, MySplitterWindow::OnPositionChanging)
463
464 EVT_SPLITTER_DCLICK(wxID_ANY, MySplitterWindow::OnDClick)
465
466 EVT_SPLITTER_UNSPLIT(wxID_ANY, MySplitterWindow::OnUnsplitEvent)
467 END_EVENT_TABLE()
468
469 MySplitterWindow::MySplitterWindow(wxFrame *parent)
470 : wxSplitterWindow(parent, wxID_ANY,
471 wxDefaultPosition, wxDefaultSize,
472 wxSP_3D | wxSP_LIVE_UPDATE |
473 wxCLIP_CHILDREN /* | wxSP_NO_XP_THEME */ )
474 {
475 m_frame = parent;
476 }
477
478 void MySplitterWindow::OnPositionChanged(wxSplitterEvent& event)
479 {
480 wxLogStatus(m_frame, wxT("Position has changed, now = %d (or %d)"),
481 event.GetSashPosition(), GetSashPosition());
482
483 event.Skip();
484 }
485
486 void MySplitterWindow::OnPositionChanging(wxSplitterEvent& event)
487 {
488 wxLogStatus(m_frame, wxT("Position is changing, now = %d (or %d)"),
489 event.GetSashPosition(), GetSashPosition());
490
491 event.Skip();
492 }
493
494 void MySplitterWindow::OnDClick(wxSplitterEvent& event)
495 {
496 #if wxUSE_STATUSBAR
497 m_frame->SetStatusText(wxT("Splitter double clicked"), 1);
498 #endif // wxUSE_STATUSBAR
499
500 event.Skip();
501 }
502
503 void MySplitterWindow::OnUnsplitEvent(wxSplitterEvent& event)
504 {
505 #if wxUSE_STATUSBAR
506 m_frame->SetStatusText(wxT("Splitter unsplit"), 1);
507 #endif // wxUSE_STATUSBAR
508
509 event.Skip();
510 }
511
512 // ----------------------------------------------------------------------------
513 // MyCanvas
514 // ----------------------------------------------------------------------------
515
516 MyCanvas::MyCanvas(wxWindow* parent, bool mirror)
517 : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
518 wxHSCROLL | wxVSCROLL | wxNO_FULL_REPAINT_ON_RESIZE)
519 {
520 m_mirror = mirror;
521 }
522
523 void MyCanvas::OnDraw(wxDC& dcOrig)
524 {
525 wxMirrorDC dc(dcOrig, m_mirror);
526
527 dc.SetPen(*wxBLACK_PEN);
528 dc.DrawLine(0, 0, 100, 200);
529
530 dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
531 dc.DrawText(wxT("Testing"), 50, 50);
532
533 dc.SetPen(*wxRED_PEN);
534 dc.SetBrush(*wxGREEN_BRUSH);
535 dc.DrawRectangle(120, 120, 100, 80);
536 }
537