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: splitter.cpp 61458 2009-07-18 22:46:26Z PC $
8// Copyright:   (c) Julian Smart
9// Licence:     wxWindows license
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// ----------------------------------------------------------------------------
43// constants
44// ----------------------------------------------------------------------------
45
46// ID for the menu commands
47enum
48{
49    SPLIT_QUIT = 1,
50    SPLIT_HORIZONTAL,
51    SPLIT_VERTICAL,
52    SPLIT_UNSPLIT,
53    SPLIT_LIVE,
54    SPLIT_SETPOSITION,
55    SPLIT_SETMINSIZE,
56    SPLIT_SETGRAVITY,
57    SPLIT_REPLACE
58};
59
60// ----------------------------------------------------------------------------
61// our classes
62// ----------------------------------------------------------------------------
63
64class MyApp: public wxApp
65{
66public:
67    MyApp() { }
68
69    virtual bool OnInit();
70
71    DECLARE_NO_COPY_CLASS(MyApp)
72};
73
74class MyFrame: public wxFrame
75{
76public:
77    MyFrame();
78    virtual ~MyFrame();
79
80    // Menu commands
81    void SplitHorizontal(wxCommandEvent& event);
82    void SplitVertical(wxCommandEvent& event);
83    void Unsplit(wxCommandEvent& event);
84    void ToggleLive(wxCommandEvent& event);
85    void SetPosition(wxCommandEvent& event);
86    void SetMinSize(wxCommandEvent& event);
87    void SetGravity(wxCommandEvent& event);
88    void Replace(wxCommandEvent &event);
89
90    void Quit(wxCommandEvent& event);
91
92    // Menu command update functions
93    void UpdateUIHorizontal(wxUpdateUIEvent& event);
94    void UpdateUIVertical(wxUpdateUIEvent& event);
95    void UpdateUIUnsplit(wxUpdateUIEvent& event);
96
97private:
98    wxScrolledWindow *m_left, *m_right;
99
100    wxSplitterWindow* m_splitter;
101    wxWindow *m_replacewindow;
102
103    DECLARE_EVENT_TABLE()
104    DECLARE_NO_COPY_CLASS(MyFrame)
105};
106
107class MySplitterWindow : public wxSplitterWindow
108{
109public:
110    MySplitterWindow(wxFrame *parent);
111
112    // event handlers
113    void OnPositionChanged(wxSplitterEvent& event);
114    void OnPositionChanging(wxSplitterEvent& event);
115    void OnDClick(wxSplitterEvent& event);
116    void OnUnsplitEvent(wxSplitterEvent& event);
117
118private:
119    wxFrame *m_frame;
120
121    DECLARE_EVENT_TABLE()
122    DECLARE_NO_COPY_CLASS(MySplitterWindow)
123};
124
125class MyCanvas: public wxScrolledWindow
126{
127public:
128    MyCanvas(wxWindow* parent, bool mirror);
129    virtual ~MyCanvas(){};
130
131    virtual void OnDraw(wxDC& dc);
132
133private:
134    bool m_mirror;
135
136    DECLARE_NO_COPY_CLASS(MyCanvas)
137};
138
139// ============================================================================
140// implementation
141// ============================================================================
142
143// ----------------------------------------------------------------------------
144// MyApp
145// ----------------------------------------------------------------------------
146
147IMPLEMENT_APP(MyApp)
148
149bool MyApp::OnInit()
150{
151    // create and show the main frame
152    MyFrame* frame = new MyFrame;
153
154    frame->Show(true);
155
156    return true;
157}
158
159// ----------------------------------------------------------------------------
160// MyFrame
161// ----------------------------------------------------------------------------
162
163BEGIN_EVENT_TABLE(MyFrame, wxFrame)
164    EVT_MENU(SPLIT_VERTICAL, MyFrame::SplitVertical)
165    EVT_MENU(SPLIT_HORIZONTAL, MyFrame::SplitHorizontal)
166    EVT_MENU(SPLIT_UNSPLIT, MyFrame::Unsplit)
167    EVT_MENU(SPLIT_LIVE, MyFrame::ToggleLive)
168    EVT_MENU(SPLIT_SETPOSITION, MyFrame::SetPosition)
169    EVT_MENU(SPLIT_SETMINSIZE, MyFrame::SetMinSize)
170    EVT_MENU(SPLIT_SETGRAVITY, MyFrame::SetGravity)
171    EVT_MENU(SPLIT_REPLACE, MyFrame::Replace)
172
173    EVT_MENU(SPLIT_QUIT, MyFrame::Quit)
174
175    EVT_UPDATE_UI(SPLIT_VERTICAL, MyFrame::UpdateUIVertical)
176    EVT_UPDATE_UI(SPLIT_HORIZONTAL, MyFrame::UpdateUIHorizontal)
177    EVT_UPDATE_UI(SPLIT_UNSPLIT, MyFrame::UpdateUIUnsplit)
178END_EVENT_TABLE()
179
180// My frame constructor
181MyFrame::MyFrame()
182       : wxFrame(NULL, wxID_ANY, _T("wxSplitterWindow sample"),
183                 wxDefaultPosition, wxSize(420, 300),
184                 wxDEFAULT_FRAME_STYLE | wxNO_FULL_REPAINT_ON_RESIZE)
185{
186#if wxUSE_STATUSBAR
187    CreateStatusBar(2);
188#endif // wxUSE_STATUSBAR
189
190    // Make a menubar
191    wxMenu *splitMenu = new wxMenu;
192    splitMenu->Append(SPLIT_VERTICAL,
193                      _T("Split &Vertically\tCtrl-V"),
194                      _T("Split vertically"));
195    splitMenu->Append(SPLIT_HORIZONTAL,
196                      _T("Split &Horizontally\tCtrl-H"),
197                      _T("Split horizontally"));
198    splitMenu->Append(SPLIT_UNSPLIT,
199                      _T("&Unsplit\tCtrl-U"),
200                      _T("Unsplit"));
201    splitMenu->AppendSeparator();
202
203    splitMenu->AppendCheckItem(SPLIT_LIVE,
204                               _T("&Live update\tCtrl-L"),
205                               _T("Toggle live update mode"));
206    splitMenu->Append(SPLIT_SETPOSITION,
207                      _T("Set splitter &position\tCtrl-P"),
208                      _T("Set the splitter position"));
209    splitMenu->Append(SPLIT_SETMINSIZE,
210                      _T("Set &min size\tCtrl-M"),
211                      _T("Set minimum pane size"));
212    splitMenu->Append(SPLIT_SETGRAVITY,
213                      _T("Set &gravity\tCtrl-G"),
214                      _T("Set gravity of sash"));
215    splitMenu->AppendSeparator();
216
217    splitMenu->Append(SPLIT_REPLACE,
218                      _T("&Replace right window"),
219                      _T("Replace right window"));
220    splitMenu->AppendSeparator();
221
222    splitMenu->Append(SPLIT_QUIT, _T("E&xit\tAlt-X"), _T("Exit"));
223
224    wxMenuBar *menuBar = new wxMenuBar;
225    menuBar->Append(splitMenu, _T("&Splitter"));
226
227    SetMenuBar(menuBar);
228
229    menuBar->Check(SPLIT_LIVE, true);
230    m_splitter = new MySplitterWindow(this);
231
232    m_splitter->SetSashGravity(1.0);
233
234#if 1
235    m_left = new MyCanvas(m_splitter, true);
236    m_left->SetBackgroundColour(*wxRED);
237    m_left->SetScrollbars(20, 20, 5, 5);
238    m_left->SetCursor(wxCursor(wxCURSOR_MAGNIFIER));
239
240    m_right = new MyCanvas(m_splitter, false);
241    m_right->SetBackgroundColour(*wxCYAN);
242    m_right->SetScrollbars(20, 20, 5, 5);
243#else // for testing kbd navigation inside the splitter
244    m_left = new wxTextCtrl(m_splitter, wxID_ANY, _T("first text"));
245    m_right = new wxTextCtrl(m_splitter, wxID_ANY, _T("second text"));
246#endif
247
248    // you can also do this to start with a single window
249#if 0
250    m_right->Show(false);
251    m_splitter->Initialize(m_left);
252#else
253    // you can also try -100
254    m_splitter->SplitVertically(m_left, m_right, 100);
255#endif
256
257#if wxUSE_STATUSBAR
258    SetStatusText(_T("Min pane size = 0"), 1);
259#endif // wxUSE_STATUSBAR
260
261    m_replacewindow = (wxWindow *)0;
262}
263
264MyFrame::~MyFrame()
265{
266    if (m_replacewindow) {
267        m_replacewindow->Destroy();
268        m_replacewindow = (wxWindow *)0;
269    }
270}
271
272// menu command handlers
273
274void MyFrame::Quit(wxCommandEvent& WXUNUSED(event) )
275{
276    Close(true);
277}
278
279void MyFrame::SplitHorizontal(wxCommandEvent& WXUNUSED(event) )
280{
281    if ( m_splitter->IsSplit() )
282        m_splitter->Unsplit();
283    m_left->Show(true);
284    m_right->Show(true);
285    m_splitter->SplitHorizontally( m_left, m_right );
286    m_replacewindow = NULL;
287
288#if wxUSE_STATUSBAR
289    SetStatusText(_T("Splitter split horizontally"), 1);
290#endif // wxUSE_STATUSBAR
291}
292
293void MyFrame::SplitVertical(wxCommandEvent& WXUNUSED(event) )
294{
295    if ( m_splitter->IsSplit() )
296        m_splitter->Unsplit();
297    m_left->Show(true);
298    m_right->Show(true);
299    m_splitter->SplitVertically( m_left, m_right );
300    m_replacewindow = NULL;
301
302#if wxUSE_STATUSBAR
303    SetStatusText(_T("Splitter split vertically"), 1);
304#endif // wxUSE_STATUSBAR
305}
306
307void MyFrame::Unsplit(wxCommandEvent& WXUNUSED(event) )
308{
309    if ( m_splitter->IsSplit() )
310        m_splitter->Unsplit();
311#if wxUSE_STATUSBAR
312    SetStatusText(_T("No splitter"));
313#endif // wxUSE_STATUSBAR
314}
315
316void MyFrame::ToggleLive(wxCommandEvent& event )
317{
318    long style = m_splitter->GetWindowStyleFlag();
319    if ( event.IsChecked() )
320        style |= wxSP_LIVE_UPDATE;
321    else
322        style &= ~wxSP_LIVE_UPDATE;
323
324    m_splitter->SetWindowStyleFlag(style);
325}
326
327void MyFrame::SetPosition(wxCommandEvent& WXUNUSED(event) )
328{
329    wxString str;
330    str.Printf( wxT("%d"), m_splitter->GetSashPosition());
331    str = wxGetTextFromUser(_T("Enter splitter position:"), _T(""), str, this);
332    if ( str.empty() )
333        return;
334
335    long pos;
336    if ( !str.ToLong(&pos) )
337    {
338        wxLogError(_T("The splitter position should be an integer."));
339        return;
340    }
341
342    m_splitter->SetSashPosition(pos);
343
344    wxLogStatus(this, _T("Splitter position set to %ld"), pos);
345}
346
347void MyFrame::SetMinSize(wxCommandEvent& WXUNUSED(event) )
348{
349    wxString str;
350    str.Printf( wxT("%d"), m_splitter->GetMinimumPaneSize());
351    str = wxGetTextFromUser(_T("Enter minimal size for panes:"), _T(""), str, this);
352    if ( str.empty() )
353        return;
354
355    int minsize = wxStrtol( str, (wxChar**)NULL, 10 );
356    m_splitter->SetMinimumPaneSize(minsize);
357#if wxUSE_STATUSBAR
358    str.Printf( wxT("Min pane size = %d"), minsize);
359    SetStatusText(str, 1);
360#endif // wxUSE_STATUSBAR
361}
362void MyFrame::SetGravity(wxCommandEvent& WXUNUSED(event) )
363{
364    wxString str;
365    str.Printf( wxT("%g"), m_splitter->GetSashGravity());
366    str = wxGetTextFromUser(_T("Enter sash gravity (0,1):"), _T(""), str, this);
367    if ( str.empty() )
368        return;
369
370    double gravity = wxStrtod( str, (wxChar**)NULL);
371    m_splitter->SetSashGravity(gravity);
372#if wxUSE_STATUSBAR
373    str.Printf( wxT("Gravity = %g"), gravity);
374    SetStatusText(str, 1);
375#endif // wxUSE_STATUSBAR
376}
377
378void MyFrame::Replace(wxCommandEvent& WXUNUSED(event) )
379{
380    if (m_replacewindow == 0) {
381        m_replacewindow = m_splitter->GetWindow2();
382        m_splitter->ReplaceWindow(m_replacewindow, new wxPanel(m_splitter, wxID_ANY));
383        m_replacewindow->Hide();
384    } else {
385        wxWindow *empty = m_splitter->GetWindow2();
386        m_splitter->ReplaceWindow(empty, m_replacewindow);
387        m_replacewindow->Show();
388        m_replacewindow = 0;
389        empty->Destroy();
390    }
391}
392
393// Update UI handlers
394
395void MyFrame::UpdateUIHorizontal(wxUpdateUIEvent& event)
396{
397    event.Enable( (!m_splitter->IsSplit()) || (m_splitter->GetSplitMode() != wxSPLIT_HORIZONTAL) );
398}
399
400void MyFrame::UpdateUIVertical(wxUpdateUIEvent& event)
401{
402    event.Enable( ( (!m_splitter->IsSplit()) || (m_splitter->GetSplitMode() != wxSPLIT_VERTICAL) ) );
403}
404
405void MyFrame::UpdateUIUnsplit(wxUpdateUIEvent& event)
406{
407    event.Enable( m_splitter->IsSplit() );
408}
409
410// ----------------------------------------------------------------------------
411// MySplitterWindow
412// ----------------------------------------------------------------------------
413
414BEGIN_EVENT_TABLE(MySplitterWindow, wxSplitterWindow)
415    EVT_SPLITTER_SASH_POS_CHANGED(wxID_ANY, MySplitterWindow::OnPositionChanged)
416    EVT_SPLITTER_SASH_POS_CHANGING(wxID_ANY, MySplitterWindow::OnPositionChanging)
417
418    EVT_SPLITTER_DCLICK(wxID_ANY, MySplitterWindow::OnDClick)
419
420    EVT_SPLITTER_UNSPLIT(wxID_ANY, MySplitterWindow::OnUnsplitEvent)
421END_EVENT_TABLE()
422
423MySplitterWindow::MySplitterWindow(wxFrame *parent)
424                : wxSplitterWindow(parent, wxID_ANY,
425                                   wxDefaultPosition, wxDefaultSize,
426                                   wxSP_3D | wxSP_LIVE_UPDATE |
427                                   wxCLIP_CHILDREN /* | wxSP_NO_XP_THEME */ )
428{
429    m_frame = parent;
430}
431
432void MySplitterWindow::OnPositionChanged(wxSplitterEvent& event)
433{
434    wxLogStatus(m_frame, _T("Position has changed, now = %d (or %d)"),
435                event.GetSashPosition(), GetSashPosition());
436
437    event.Skip();
438}
439
440void MySplitterWindow::OnPositionChanging(wxSplitterEvent& event)
441{
442    wxLogStatus(m_frame, _T("Position is changing, now = %d (or %d)"),
443                event.GetSashPosition(), GetSashPosition());
444
445    event.Skip();
446}
447
448void MySplitterWindow::OnDClick(wxSplitterEvent& event)
449{
450#if wxUSE_STATUSBAR
451    m_frame->SetStatusText(_T("Splitter double clicked"), 1);
452#endif // wxUSE_STATUSBAR
453
454    event.Skip();
455}
456
457void MySplitterWindow::OnUnsplitEvent(wxSplitterEvent& event)
458{
459#if wxUSE_STATUSBAR
460    m_frame->SetStatusText(_T("Splitter unsplit"), 1);
461#endif // wxUSE_STATUSBAR
462
463    event.Skip();
464}
465
466// ----------------------------------------------------------------------------
467// MyCanvas
468// ----------------------------------------------------------------------------
469
470MyCanvas::MyCanvas(wxWindow* parent, bool mirror)
471        : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
472                           wxHSCROLL | wxVSCROLL | wxNO_FULL_REPAINT_ON_RESIZE)
473{
474    m_mirror = mirror;
475}
476
477void MyCanvas::OnDraw(wxDC& dcOrig)
478{
479    wxMirrorDC dc(dcOrig, m_mirror);
480
481    dc.SetPen(*wxBLACK_PEN);
482    dc.DrawLine(0, 0, 100, 200);
483
484    dc.SetBackgroundMode(wxTRANSPARENT);
485    dc.DrawText(_T("Testing"), 50, 50);
486
487    dc.SetPen(*wxRED_PEN);
488    dc.SetBrush(*wxGREEN_BRUSH);
489    dc.DrawRectangle(120, 120, 100, 80);
490}
491
492