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