splitter.cpp 16 KB

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