1 ///////////////////////////////////////////////////////////////////////////// 2 // Name: wx/splitter.h 3 // Purpose: wxSplitterWindow class 4 // Author: Julian Smart 5 // Modified by: 6 // Created: 01/02/97 7 // RCS-ID: $Id: splitter.h 61872 2009-09-09 22:37:05Z VZ $ 8 // Copyright: (c) Julian Smart 9 // Licence: wxWindows licence 10 ///////////////////////////////////////////////////////////////////////////// 11 12 #ifndef _WX_GENERIC_SPLITTER_H_ 13 #define _WX_GENERIC_SPLITTER_H_ 14 15 #include "wx/window.h" // base class declaration 16 #include "wx/containr.h" // wxControlContainer 17 18 class WXDLLIMPEXP_FWD_CORE wxSplitterEvent; 19 20 // --------------------------------------------------------------------------- 21 // splitter constants 22 // --------------------------------------------------------------------------- 23 24 enum wxSplitMode 25 { 26 wxSPLIT_HORIZONTAL = 1, 27 wxSPLIT_VERTICAL 28 }; 29 30 enum 31 { 32 wxSPLIT_DRAG_NONE, 33 wxSPLIT_DRAG_DRAGGING, 34 wxSPLIT_DRAG_LEFT_DOWN 35 }; 36 37 // --------------------------------------------------------------------------- 38 // wxSplitterWindow maintains one or two panes, with 39 // an optional vertical or horizontal split which 40 // can be used with the mouse or programmatically. 41 // --------------------------------------------------------------------------- 42 43 // TODO: 44 // 1) Perhaps make the borders sensitive to dragging in order to create a split. 45 // The MFC splitter window manages scrollbars as well so is able to 46 // put sash buttons on the scrollbars, but we probably don't want to go down 47 // this path. 48 // 2) for wxWidgets 2.0, we must find a way to set the WS_CLIPCHILDREN style 49 // to prevent flickering. (WS_CLIPCHILDREN doesn't work in all cases so can't be 50 // standard). 51 52 class WXDLLEXPORT wxSplitterWindow: public wxWindow 53 { 54 public: 55 56 //////////////////////////////////////////////////////////////////////////// 57 // Public API 58 59 // Default constructor wxSplitterWindow()60 wxSplitterWindow() 61 { 62 Init(); 63 } 64 65 // Normal constructor 66 wxSplitterWindow(wxWindow *parent, wxWindowID id = wxID_ANY, 67 const wxPoint& pos = wxDefaultPosition, 68 const wxSize& size = wxDefaultSize, 69 long style = wxSP_3D, 70 const wxString& name = wxT("splitter")) 71 { 72 Init(); 73 Create(parent, id, pos, size, style, name); 74 } 75 76 virtual ~wxSplitterWindow(); 77 78 bool Create(wxWindow *parent, wxWindowID id = wxID_ANY, 79 const wxPoint& pos = wxDefaultPosition, 80 const wxSize& size = wxDefaultSize, 81 long style = wxSP_3D, 82 const wxString& name = wxT("splitter")); 83 84 // Gets the only or left/top pane GetWindow1()85 wxWindow *GetWindow1() const { return m_windowOne; } 86 87 // Gets the right/bottom pane GetWindow2()88 wxWindow *GetWindow2() const { return m_windowTwo; } 89 90 // Sets the split mode SetSplitMode(int mode)91 void SetSplitMode(int mode) 92 { 93 wxASSERT_MSG( mode == wxSPLIT_VERTICAL || mode == wxSPLIT_HORIZONTAL, 94 wxT("invalid split mode") ); 95 96 m_splitMode = (wxSplitMode)mode; 97 } 98 99 // Gets the split mode GetSplitMode()100 wxSplitMode GetSplitMode() const { return m_splitMode; } 101 102 // Initialize with one window 103 void Initialize(wxWindow *window); 104 105 // Associates the given window with window 2, drawing the appropriate sash 106 // and changing the split mode. 107 // Does nothing and returns false if the window is already split. 108 // A sashPosition of 0 means choose a default sash position, 109 // negative sashPosition specifies the size of right/lower pane as it's 110 // absolute value rather than the size of left/upper pane. 111 virtual bool SplitVertically(wxWindow *window1, 112 wxWindow *window2, 113 int sashPosition = 0) 114 { return DoSplit(wxSPLIT_VERTICAL, window1, window2, sashPosition); } 115 virtual bool SplitHorizontally(wxWindow *window1, 116 wxWindow *window2, 117 int sashPosition = 0) 118 { return DoSplit(wxSPLIT_HORIZONTAL, window1, window2, sashPosition); } 119 120 // Removes the specified (or second) window from the view 121 // Doesn't actually delete the window. 122 bool Unsplit(wxWindow *toRemove = (wxWindow *) NULL); 123 124 // Replaces one of the windows with another one (neither old nor new 125 // parameter should be NULL) 126 bool ReplaceWindow(wxWindow *winOld, wxWindow *winNew); 127 128 // Make sure the child window sizes are updated. This is useful 129 // for reducing flicker by updating the sizes before a 130 // window is shown, if you know the overall size is correct. 131 void UpdateSize(); 132 133 // Is the window split? IsSplit()134 bool IsSplit() const { return (m_windowTwo != NULL); } 135 136 // Sets the sash size SetSashSize(int width)137 void SetSashSize(int width) { m_sashSize = width; } 138 139 // Sets the border size SetBorderSize(int WXUNUSED (width))140 void SetBorderSize(int WXUNUSED(width)) { } 141 142 // Gets the sash size 143 int GetSashSize() const; 144 145 // Gets the border size 146 int GetBorderSize() const; 147 148 // Set the sash position 149 void SetSashPosition(int position, bool redraw = true); 150 151 // Gets the sash position GetSashPosition()152 int GetSashPosition() const { return m_sashPosition; } 153 154 // Set the sash gravity 155 void SetSashGravity(double gravity); 156 157 // Gets the sash gravity GetSashGravity()158 double GetSashGravity() const { return m_sashGravity; } 159 160 // If this is zero, we can remove panes by dragging the sash. 161 void SetMinimumPaneSize(int min); GetMinimumPaneSize()162 int GetMinimumPaneSize() const { return m_minimumPaneSize; } 163 164 // NB: the OnXXX() functions below are for backwards compatibility only, 165 // don't use them in new code but handle the events instead! 166 167 // called when the sash position is about to change, may return a new value 168 // for the sash or -1 to prevent the change from happening at all 169 virtual int OnSashPositionChanging(int newSashPosition); 170 171 // Called when the sash position is about to be changed, return 172 // false from here to prevent the change from taking place. 173 // Repositions sash to minimum position if pane would be too small. 174 // newSashPosition here is always positive or zero. 175 virtual bool OnSashPositionChange(int newSashPosition); 176 177 // If the sash is moved to an extreme position, a subwindow 178 // is removed from the splitter window, and the app is 179 // notified. The app should delete or hide the window. 180 virtual void OnUnsplit(wxWindow *removed); 181 182 // Called when the sash is double-clicked. 183 // The default behaviour is to remove the sash if the 184 // minimum pane size is zero. 185 virtual void OnDoubleClickSash(int x, int y); 186 187 //////////////////////////////////////////////////////////////////////////// 188 // Implementation 189 190 // Paints the border and sash 191 void OnPaint(wxPaintEvent& event); 192 193 // Handles mouse events 194 void OnMouseEvent(wxMouseEvent& ev); 195 196 // Adjusts the panes 197 void OnSize(wxSizeEvent& event); 198 199 // In live mode, resize child windows in idle time 200 void OnInternalIdle(); 201 202 // Draws the sash 203 virtual void DrawSash(wxDC& dc); 204 205 // Draws the sash tracker (for whilst moving the sash) 206 virtual void DrawSashTracker(int x, int y); 207 208 // Tests for x, y over sash 209 virtual bool SashHitTest(int x, int y, int tolerance = 5); 210 211 // Resizes subwindows 212 virtual void SizeWindows(); 213 SetNeedUpdating(bool needUpdating)214 void SetNeedUpdating(bool needUpdating) { m_needUpdating = needUpdating; } GetNeedUpdating()215 bool GetNeedUpdating() const { return m_needUpdating ; } 216 217 #ifdef __WXMAC__ MacClipGrandChildren()218 virtual bool MacClipGrandChildren() const { return true ; } 219 #endif 220 221 protected: 222 // event handlers 223 #if defined(__WXMSW__) || defined(__WXMAC__) 224 void OnSetCursor(wxSetCursorEvent& event); 225 #endif // wxMSW 226 227 // send the given event, return false if the event was processed and vetoed 228 // by the user code 229 bool DoSendEvent(wxSplitterEvent& event); 230 231 // common part of all ctors 232 void Init(); 233 234 // common part of SplitVertically() and SplitHorizontally() 235 bool DoSplit(wxSplitMode mode, 236 wxWindow *window1, wxWindow *window2, 237 int sashPosition); 238 239 // adjusts sash position with respect to min. pane and window sizes 240 int AdjustSashPosition(int sashPos) const; 241 242 // get either width or height depending on the split mode 243 int GetWindowSize() const; 244 245 // convert the user specified sash position which may be > 0 (as is), < 0 246 // (specifying the size of the right pane) or 0 (use default) to the real 247 // position to be passed to DoSetSashPosition() 248 int ConvertSashPosition(int sashPos) const; 249 250 // set the real sash position, sashPos here must be positive 251 // 252 // returns true if the sash position has been changed, false otherwise 253 bool DoSetSashPosition(int sashPos); 254 255 // set the sash position and send an event about it having been changed 256 void SetSashPositionAndNotify(int sashPos); 257 258 // callbacks executed when we detect that the mouse has entered or left 259 // the sash 260 virtual void OnEnterSash(); 261 virtual void OnLeaveSash(); 262 263 // set the cursor appropriate for the current split mode 264 void SetResizeCursor(); 265 266 // redraw the splitter if its "hotness" changed if necessary 267 void RedrawIfHotSensitive(bool isHot); 268 269 // return the best size of the splitter equal to best sizes of its 270 // subwindows 271 virtual wxSize DoGetBestSize() const; 272 273 274 wxSplitMode m_splitMode; 275 wxWindow* m_windowOne; 276 wxWindow* m_windowTwo; 277 int m_dragMode; 278 int m_oldX; 279 int m_oldY; 280 int m_sashPosition; // Number of pixels from left or top 281 double m_sashGravity; 282 int m_sashSize; 283 wxSize m_lastSize; 284 int m_requestedSashPosition; 285 int m_sashPositionCurrent; // while dragging 286 int m_firstX; 287 int m_firstY; 288 int m_minimumPaneSize; 289 wxCursor m_sashCursorWE; 290 wxCursor m_sashCursorNS; 291 wxPen *m_sashTrackerPen; 292 293 // when in live mode, set this to true to resize children in idle 294 bool m_needUpdating:1; 295 bool m_permitUnsplitAlways:1; 296 bool m_isHot:1; 297 bool m_checkRequestedSashPosition:1; 298 299 private: 300 WX_DECLARE_CONTROL_CONTAINER(); 301 302 DECLARE_DYNAMIC_CLASS(wxSplitterWindow) 303 DECLARE_EVENT_TABLE() 304 DECLARE_NO_COPY_CLASS(wxSplitterWindow) 305 }; 306 307 // ---------------------------------------------------------------------------- 308 // event class and macros 309 // ---------------------------------------------------------------------------- 310 311 // we reuse the same class for all splitter event types because this is the 312 // usual wxWin convention, but the three event types have different kind of 313 // data associated with them, so the accessors can be only used if the real 314 // event type matches with the one for which the accessors make sense 315 class WXDLLEXPORT wxSplitterEvent : public wxNotifyEvent 316 { 317 public: 318 wxSplitterEvent(wxEventType type = wxEVT_NULL, 319 wxSplitterWindow *splitter = (wxSplitterWindow *)NULL) wxNotifyEvent(type)320 : wxNotifyEvent(type) 321 { 322 SetEventObject(splitter); 323 if (splitter) m_id = splitter->GetId(); 324 } 325 326 // SASH_POS_CHANGED methods 327 328 // setting the sash position to -1 prevents the change from taking place at 329 // all SetSashPosition(int pos)330 void SetSashPosition(int pos) 331 { 332 wxASSERT( GetEventType() == wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED 333 || GetEventType() == wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING); 334 335 m_data.pos = pos; 336 } 337 GetSashPosition()338 int GetSashPosition() const 339 { 340 wxASSERT( GetEventType() == wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED 341 || GetEventType() == wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING); 342 343 return m_data.pos; 344 } 345 346 // UNSPLIT event methods GetWindowBeingRemoved()347 wxWindow *GetWindowBeingRemoved() const 348 { 349 wxASSERT( GetEventType() == wxEVT_COMMAND_SPLITTER_UNSPLIT ); 350 351 return m_data.win; 352 } 353 354 // DCLICK event methods GetX()355 int GetX() const 356 { 357 wxASSERT( GetEventType() == wxEVT_COMMAND_SPLITTER_DOUBLECLICKED ); 358 359 return m_data.pt.x; 360 } 361 GetY()362 int GetY() const 363 { 364 wxASSERT( GetEventType() == wxEVT_COMMAND_SPLITTER_DOUBLECLICKED ); 365 366 return m_data.pt.y; 367 } 368 369 private: 370 friend class WXDLLIMPEXP_FWD_CORE wxSplitterWindow; 371 372 // data for the different types of event 373 union 374 { 375 int pos; // position for SASH_POS_CHANGED event 376 wxWindow *win; // window being removed for UNSPLIT event 377 struct 378 { 379 int x, y; 380 } pt; // position of double click for DCLICK event 381 } m_data; 382 383 DECLARE_DYNAMIC_CLASS_NO_COPY(wxSplitterEvent) 384 }; 385 386 typedef void (wxEvtHandler::*wxSplitterEventFunction)(wxSplitterEvent&); 387 388 #define wxSplitterEventHandler(func) \ 389 (wxObjectEventFunction)(wxEventFunction)wxStaticCastEvent(wxSplitterEventFunction, &func) 390 391 #define wx__DECLARE_SPLITTEREVT(evt, id, fn) \ 392 wx__DECLARE_EVT1(wxEVT_COMMAND_SPLITTER_ ## evt, id, wxSplitterEventHandler(fn)) 393 394 #define EVT_SPLITTER_SASH_POS_CHANGED(id, fn) \ 395 wx__DECLARE_SPLITTEREVT(SASH_POS_CHANGED, id, fn) 396 397 #define EVT_SPLITTER_SASH_POS_CHANGING(id, fn) \ 398 wx__DECLARE_SPLITTEREVT(SASH_POS_CHANGING, id, fn) 399 400 #define EVT_SPLITTER_DCLICK(id, fn) \ 401 wx__DECLARE_SPLITTEREVT(DOUBLECLICKED, id, fn) 402 403 #define EVT_SPLITTER_UNSPLIT(id, fn) \ 404 wx__DECLARE_SPLITTEREVT(UNSPLIT, id, fn) 405 406 #endif // _WX_GENERIC_SPLITTER_H_ 407