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