]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/gizmos/dynamicsash.cpp
don't use wxStaticCast to wxBookCtrlBase -- it doesn't work
[wxWidgets.git] / contrib / src / gizmos / dynamicsash.cpp
CommitLineData
eacb91fc
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: dynamicsash.cpp
3// Purpose: A window which can be dynamically split to an arbitrary depth
4// and later reunified through the user interface
5// Author: Matt Kimball
6// Modified by:
7// Created: 7/15/2001
8// RCS-ID: $Id$
9// Copyright: (c) 2001 Matt Kimball
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
744d5712
RD
13// For compilers that support precompilation, includes "wx/wx.h".
14#include "wx/wxprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
20// for all others, include the necessary headers (this file is usually all you
be5a51fb 21// need because it includes almost all "standard" wxWidgets headers)
744d5712
RD
22#ifndef WX_PRECOMP
23 #include "wx/wx.h"
24#endif
25
21131143
RD
26#ifdef __WXMSW__
27#include "wx/mdi.h"
28#endif
29
eacb91fc
VZ
30#include "wx/gizmos/dynamicsash.h"
31
9e053640
RD
32
33const wxChar* wxDynamicSashWindowNameStr = wxT("dynamicSashWindow");
34
35
eacb91fc
VZ
36/*
37 wxDynamicSashWindow works by internally storing a tree of Implementation
38 objects (wxDynamicSsahWindowImpl) and Leaf objects
39 (wxDynamicSashWindowLeaf). The wxDynamicSashWindow has a pointer to one
40 implementation, and each implementation either has a pointer to a one
41 leaf (m_leaf) or a pointer to two children implementation objects
42 (m_child). The leaves each are responsible for drawing the frame and
43 decorations around one user-provided views and for responding to mouse
44 and scrollbar events.
45
46 A resulting tree might look something like this:
47
48 wxDynamicSashWindow
49 |
50 +- wxDynamicSashWindowImpl
51 |
52 +- wxDynamicSashWindowLeaf
53 | |
54 | +- user view window
55 |
56 +- wxDynamicSashWindowImpl
57 |
58 +- wxDynamicSashWindowLeaf
59 | |
60 | +- user view window
61 |
62 +- wxDynamicSashWindowLeaf
63 |
64 +- user view window
65
66 Each time a split occurs, one of the implementation objects removes its
67 leaf, generates two new implementation object children, each with a new
68 leaf, and reparents the user view which was connected to its old leaf
69 to be one of the new leaf's user view, and sends a Split event to the
70 user view in the hopes that it will generate a new user view for the
71 other new leaf.
72
73 When a unification ocurrs, an implementation object is replaced by one
74 of its children, and the tree of its other child is pruned.
75
76 One quirk is that the top-level implementation object (m_top) always
77 keeps a pointer to the implementation object where a new child is needed.
78 (m_add_child_target). This is so that when a new uesr view is added
79 to the hierarchy, AddChild() is able to reparent the new user view to
80 the correct implementation object's leaf.
81
82*/
83
3a6bdcad
VZ
84#include "wx/dcmemory.h"
85#include "wx/dcscreen.h"
86#include "wx/layout.h"
87#include "wx/scrolbar.h"
88#include "wx/settings.h"
eacb91fc
VZ
89
90
0ed0bcc8
VZ
91const wxEventType wxEVT_DYNAMIC_SASH_SPLIT = wxNewEventType();
92const wxEventType wxEVT_DYNAMIC_SASH_UNIFY = wxNewEventType();
93const wxEventType wxEVT_DYNAMIC_SASH_REPARENT = wxNewEventType();
eacb91fc 94
3a6bdcad
VZ
95enum DynamicSashRegion
96{
97 DSR_NONE,
98 DSR_VERTICAL_TAB,
99 DSR_HORIZONTAL_TAB,
100 DSR_CORNER,
101 DSR_LEFT_EDGE,
102 DSR_TOP_EDGE,
103 DSR_RIGHT_EDGE,
104 DSR_BOTTOM_EDGE
105};
106
107
eacb91fc
VZ
108/*
109 wxDynamicSashReparentEvent is generated by the AddChild() method of
110 wxDynamicSashWindow when it wants a Leaf to reparent a user view window
111 to its viewport at some time in the future. We can't reparent the window
112 immediately, because switching parents in AddChild() confuses the wxWindow
113 class. Instead, we queue up this event, and the window is actually
114 reparented the next time we process events in the idle loop.
115*/
3a6bdcad
VZ
116class wxDynamicSashReparentEvent : public wxEvent
117{
eacb91fc
VZ
118public:
119 wxDynamicSashReparentEvent();
120 wxDynamicSashReparentEvent(wxObject *object);
aa83902a 121 wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt);
eacb91fc 122
aa83902a 123 virtual wxEvent* Clone() const { return new wxDynamicSashReparentEvent(*this); }
41286fd1 124
fde63257 125 DECLARE_DYNAMIC_CLASS(wxDynamicSashReparentEvent)
eacb91fc
VZ
126};
127
128
3a6bdcad
VZ
129class wxDynamicSashWindowImpl : public wxEvtHandler
130{
eacb91fc
VZ
131public:
132 wxDynamicSashWindowImpl(wxDynamicSashWindow *window);
133 ~wxDynamicSashWindowImpl();
134
135 bool Create();
136 void AddChild(wxWindow *window);
137 void DrawSash(int x, int y) const;
138 void ConstrainChildren(int px, int py);
139 void Split(int x, int y);
140 void Unify(int panel);
141 void Resize(int x, int y);
142 wxDynamicSashWindowImpl *FindParent(DynamicSashRegion side) const;
143 wxDynamicSashWindowImpl *FindUpperParent(wxDynamicSashWindowImpl *sash_a,
144 wxDynamicSashWindowImpl *sash_b) const;
145 wxWindow *FindFrame() const;
146 wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;
147
148 void OnSize(wxSizeEvent &event);
149 void OnPaint(wxPaintEvent &event);
150 void OnMouseMove(wxMouseEvent &event);
151 void OnLeave(wxMouseEvent &event);
152 void OnPress(wxMouseEvent &event);
153 void OnRelease(wxMouseEvent &event);
154
155 wxDynamicSashWindow *m_window;
156 wxDynamicSashWindowImpl *m_add_child_target;
157
158 /* This is the window we are responsible for managing. Either of
159 leaf or our children are in this window. For the top level
160 implementation object, this is the same as m_window.
161 Otherwise it is a window we've created an will destroy when we
162 are deleted. */
163 wxWindow *m_container;
164
165 wxDynamicSashWindowImpl *m_parent;
166 wxDynamicSashWindowImpl *m_top;
167 wxDynamicSashWindowImpl *m_child[2];
168
169 class wxDynamicSashWindowLeaf *m_leaf;
170
171 /* If the implementation is split horizontally or vertically, m_split
172 is set to DSR_HORIZONTAL_TAB or DSR_VERTICAL_TAB, respectively.
173 Otherwise it is set to DSR_NONE. */
174 DynamicSashRegion m_split;
175
176 /* These are used to keep track of a sash as it is being dragged, for
177 drawing the user interface correctly. */
178 DynamicSashRegion m_dragging;
179 int m_drag_x, m_drag_y;
180};
181
3a6bdcad
VZ
182class wxDynamicSashWindowLeaf : public wxEvtHandler
183{
eacb91fc
VZ
184public:
185 wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl);
186 ~wxDynamicSashWindowLeaf();
187
188 bool Create();
189 void AddChild(wxWindow *window);
190 DynamicSashRegion GetRegion(int x, int y);
67631cee 191 void ResizeChild(const wxSize& size);
eacb91fc
VZ
192 wxScrollBar *FindScrollBar(const wxWindow *child, int vert) const;
193
194 void OnSize(wxSizeEvent &event);
7e068925 195 void OnViewSize(wxSizeEvent &event);
eacb91fc
VZ
196 void OnPaint(wxPaintEvent &event);
197 void OnScroll(wxScrollEvent &event);
198 void OnFocus(wxFocusEvent &event);
199 void OnMouseMove(wxMouseEvent &event);
200 void OnLeave(wxMouseEvent &event);
201 void OnPress(wxMouseEvent &event);
202 void OnRelease(wxMouseEvent &event);
203 void OnReparent(wxEvent &event);
204
205 wxDynamicSashWindowImpl *m_impl;
206
a7daa76e
VZ
207 wxScrollBar *m_vscroll,
208 *m_hscroll;
eacb91fc
VZ
209
210 /* m_child is the window provided to us by the application developer.
211 m_viewport is a window we've created, and it is the immediately
212 parent of m_child. We scroll m_child by moving it around within
213 m_viewport. */
a7daa76e
VZ
214 wxWindow *m_viewport,
215 *m_child;
eacb91fc
VZ
216};
217
eacb91fc 218
3a6bdcad
VZ
219// ============================================================================
220// wxDynamicSashWindow
221// ============================================================================
222
223wxDynamicSashWindow::wxDynamicSashWindow()
224{
eacb91fc
VZ
225 m_impl = NULL;
226}
227
3a6bdcad
VZ
228wxDynamicSashWindow::wxDynamicSashWindow(wxWindow *parent,
229 wxWindowID id,
230 const wxPoint& pos,
231 const wxSize& size,
232 long style,
233 const wxString& name)
234{
eacb91fc
VZ
235 m_impl = NULL;
236 Create(parent, id, pos, size, style, name);
237}
238
3a6bdcad
VZ
239wxDynamicSashWindow::~wxDynamicSashWindow()
240{
eacb91fc
VZ
241 SetEventHandler(this);
242 delete m_impl;
243}
244
3a6bdcad
VZ
245bool wxDynamicSashWindow::Create(wxWindow *parent,
246 wxWindowID id,
247 const wxPoint& pos,
248 const wxSize& size,
249 long style,
250 const wxString& name)
251{
eacb91fc 252 if (m_impl)
a2d49353 253 return false;
eacb91fc
VZ
254
255 if (!wxWindow::Create(parent, id, pos, size, style, name))
a2d49353 256 return false;
eacb91fc
VZ
257
258 m_impl = new wxDynamicSashWindowImpl(this);
259 if (!m_impl)
a2d49353 260 return false;
eacb91fc 261
3a6bdcad
VZ
262 if (!m_impl->Create())
263 {
eacb91fc
VZ
264 delete m_impl;
265 m_impl = NULL;
a2d49353 266 return false;
eacb91fc
VZ
267 }
268
a2d49353 269 return true;
eacb91fc
VZ
270}
271
3a6bdcad
VZ
272void wxDynamicSashWindow::AddChild(wxWindowBase *child)
273{
eacb91fc
VZ
274 wxWindow::AddChild(child);
275
276 m_impl->AddChild(wxDynamicCast(child, wxWindow));
277}
278
3a6bdcad
VZ
279wxScrollBar *wxDynamicSashWindow::GetHScrollBar(const wxWindow *child) const
280{
eacb91fc
VZ
281 return m_impl->FindScrollBar(child, 0);
282}
283
3a6bdcad
VZ
284wxScrollBar *wxDynamicSashWindow::GetVScrollBar(const wxWindow *child) const
285{
eacb91fc
VZ
286 return m_impl->FindScrollBar(child, 1);
287}
288
289IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashWindow, wxWindow)
290
eacb91fc 291
3a6bdcad
VZ
292// ============================================================================
293// wxDynamicSashWindowImpl
294// ============================================================================
295
296wxDynamicSashWindowImpl::wxDynamicSashWindowImpl(wxDynamicSashWindow *window)
297{
eacb91fc
VZ
298 m_window = window;
299 m_add_child_target = this;
300
301 m_container = NULL;
302 m_parent = NULL;
303 m_top = this;
3a6bdcad
VZ
304 m_child[0] =
305 m_child[1] = NULL;
eacb91fc
VZ
306 m_leaf = NULL;
307 m_dragging = DSR_NONE;
308 m_split = DSR_NONE;
309}
310
3a6bdcad
VZ
311wxDynamicSashWindowImpl::~wxDynamicSashWindowImpl()
312{
eacb91fc
VZ
313 delete m_leaf;
314 delete m_child[0];
315 m_child[0] = NULL;
316 delete m_child[1];
317 m_child[1] = NULL;
318 m_leaf = NULL;
319
3a6bdcad
VZ
320 if (m_container != m_window && m_container)
321 {
eacb91fc
VZ
322 m_container->SetEventHandler(m_container);
323 m_container->Destroy();
324 }
325}
326
3a6bdcad
VZ
327bool wxDynamicSashWindowImpl::Create()
328{
329 if (!m_container)
eacb91fc 330 m_container = m_window;
eacb91fc
VZ
331
332 wxCursor cursor(wxCURSOR_ARROW);
333 m_container->SetCursor(cursor);
334
335 m_leaf = new wxDynamicSashWindowLeaf(this);
336 if (!m_leaf)
a2d49353 337 return false;
eacb91fc 338
3a6bdcad
VZ
339 if (!m_leaf->Create())
340 {
eacb91fc
VZ
341 delete m_leaf;
342 m_leaf = NULL;
a2d49353 343 return false;
eacb91fc
VZ
344 }
345
346 m_container->SetEventHandler(this);
347
3a6bdcad
VZ
348 Connect(wxEVT_SIZE, wxSizeEventHandler(wxDynamicSashWindowImpl::OnSize));
349 Connect(wxEVT_PAINT, wxPaintEventHandler(wxDynamicSashWindowImpl::OnPaint));
350 Connect(wxEVT_MOTION,
351 wxMouseEventHandler(wxDynamicSashWindowImpl::OnMouseMove));
352 Connect(wxEVT_ENTER_WINDOW,
353 wxMouseEventHandler(wxDynamicSashWindowImpl::OnMouseMove));
354 Connect(wxEVT_LEAVE_WINDOW,
355 wxMouseEventHandler(wxDynamicSashWindowImpl::OnLeave));
356 Connect(wxEVT_LEFT_DOWN,
357 wxMouseEventHandler(wxDynamicSashWindowImpl::OnPress));
358 Connect(wxEVT_LEFT_UP,
359 wxMouseEventHandler(wxDynamicSashWindowImpl::OnRelease));
eacb91fc 360
a2d49353 361 return true;
eacb91fc
VZ
362}
363
3a6bdcad
VZ
364void wxDynamicSashWindowImpl::AddChild(wxWindow *window)
365{
366 if (m_add_child_target && m_add_child_target->m_leaf)
eacb91fc 367 m_add_child_target->m_leaf->AddChild(window);
eacb91fc
VZ
368}
369
3a6bdcad
VZ
370void wxDynamicSashWindowImpl::DrawSash(int x, int y) const
371{
eacb91fc
VZ
372 int i, j;
373
374 wxScreenDC dc;
375 dc.StartDrawingOnTop(m_container);
376
377 wxBitmap bmp(8, 8);
378 wxMemoryDC bdc;
379 bdc.SelectObject(bmp);
380 bdc.DrawRectangle(-1, -1, 10, 10);
3a6bdcad
VZ
381 for (i = 0; i < 8; i++)
382 {
383 for (j = 0; j < 8; j++)
384 {
385 if ((i + j) & 1)
eacb91fc 386 bdc.DrawPoint(i, j);
eacb91fc
VZ
387 }
388 }
389
390 wxBrush brush(bmp);
391 dc.SetBrush(brush);
392 dc.SetLogicalFunction(wxXOR);
393
281de223 394 if ((m_dragging == DSR_CORNER) &&
3a6bdcad
VZ
395 (m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0)
396 {
eacb91fc
VZ
397 int cx = 0;
398 int cy = 0;
399
400 m_container->ClientToScreen(&cx, &cy);
401 m_container->ClientToScreen(&x, &y);
402
3a6bdcad
VZ
403 if (cx < x && cy < y)
404 {
eacb91fc
VZ
405 dc.DrawRectangle(cx - 2, cy - 2, x - cx + 4, 4);
406 dc.DrawRectangle(x - 2, cy + 2, 4, y - cy);
407 dc.DrawRectangle(cx - 2, cy + 2, 4, y - cy);
408 dc.DrawRectangle(cx + 2, y - 2, x - cx - 4, 4);
409 }
3a6bdcad
VZ
410 }
411 else
412 {
eacb91fc
VZ
413 int body_w, body_h;
414 m_container->GetClientSize(&body_w, &body_h);
415
416 if (y < 0)
417 y = 0;
418 if (y > body_h)
419 y = body_h;
420 if (x < 0)
421 x = 0;
422 if (x > body_w)
423 x = body_w;
424
425 if (m_dragging == DSR_HORIZONTAL_TAB)
426 x = 0;
427 else
428 y = 0;
429
430 m_container->ClientToScreen(&x, &y);
431
432 int w, h;
433 w = body_w; h = body_h;
434
435 if (m_dragging == DSR_HORIZONTAL_TAB)
436 dc.DrawRectangle(x, y - 2, w, 4);
437 else
438 dc.DrawRectangle(x - 2, y, 4, h);
439 }
440
441 dc.EndDrawingOnTop();
442}
443
3a6bdcad
VZ
444wxDynamicSashWindowImpl *
445wxDynamicSashWindowImpl::FindParent(DynamicSashRegion side) const
446{
447 if (m_parent == NULL)
eacb91fc 448 return NULL;
eacb91fc 449
3a6bdcad
VZ
450 if (m_parent->m_split == DSR_HORIZONTAL_TAB)
451 {
eacb91fc
VZ
452 if (side == DSR_TOP_EDGE && m_parent->m_child[1] == this)
453 return m_parent;
454 if (side == DSR_BOTTOM_EDGE && m_parent->m_child[0] == this)
455 return m_parent;
3a6bdcad
VZ
456 }
457 else if (m_parent->m_split == DSR_VERTICAL_TAB)
458 {
eacb91fc
VZ
459 if (side == DSR_LEFT_EDGE && m_parent->m_child[1] == this)
460 return m_parent;
461 if (side == DSR_RIGHT_EDGE && m_parent->m_child[0] == this)
462 return m_parent;
463 }
464
465 return m_parent->FindParent(side);
466}
467
3a6bdcad
VZ
468wxDynamicSashWindowImpl *
469wxDynamicSashWindowImpl::FindUpperParent(wxDynamicSashWindowImpl *sash_a,
470 wxDynamicSashWindowImpl *sash_b) const
471{
eacb91fc
VZ
472 wxWindow *win;
473 win = sash_a->m_container->GetParent();
3a6bdcad
VZ
474 while (win && !win->IsTopLevel())
475 {
476 if (win == sash_b->m_container)
eacb91fc 477 return sash_b;
eacb91fc
VZ
478
479 win = win->GetParent();
480 }
481
482 return sash_a;
483}
484
485
3a6bdcad
VZ
486wxWindow *wxDynamicSashWindowImpl::FindFrame() const
487{
eacb91fc
VZ
488 wxWindow *win;
489
490 win = m_window->GetParent();
21131143
RD
491 while (win && !win->IsTopLevel()
492#ifdef __WXMSW__
493 && ! wxIsKindOf(win, wxMDIChildFrame) // not top-level but still a frame
494#endif
3a6bdcad
VZ
495 )
496 {
eacb91fc
VZ
497 win = win->GetParent();
498 }
499
500 return win;
501}
502
3a6bdcad
VZ
503wxScrollBar *
504wxDynamicSashWindowImpl::FindScrollBar(const wxWindow *child, int vert) const
505{
506 if (m_child[0] == NULL && m_leaf == NULL)
eacb91fc 507 return NULL;
eacb91fc 508
3a6bdcad
VZ
509 if (!m_child[0])
510 {
eacb91fc 511 return m_leaf->FindScrollBar(child, vert);
eacb91fc 512 }
3a6bdcad
VZ
513
514 wxScrollBar *ret = m_child[0]->FindScrollBar(child, vert);
515 if (!ret)
516 ret = m_child[1]->FindScrollBar(child, vert);
517
518 return ret;
eacb91fc
VZ
519}
520
3a6bdcad
VZ
521void wxDynamicSashWindowImpl::ConstrainChildren(int px, int py)
522{
eacb91fc
VZ
523 wxLayoutConstraints *layout = new wxLayoutConstraints();
524 layout->left.SameAs(m_container, wxLeft);
525 layout->top.SameAs(m_container, wxTop);
3a6bdcad
VZ
526 if (m_split == DSR_HORIZONTAL_TAB)
527 {
eacb91fc
VZ
528 layout->right.SameAs(m_container, wxRight);
529 layout->height.PercentOf(m_container, wxHeight, py);
3a6bdcad
VZ
530 }
531 else
532 {
eacb91fc
VZ
533 layout->bottom.SameAs(m_container, wxBottom);
534 layout->width.PercentOf(m_container, wxWidth, px);
535 }
536 m_child[0]->m_container->SetConstraints(layout);
537
538 layout = new wxLayoutConstraints();
539 layout->right.SameAs(m_container, wxRight);
540 layout->bottom.SameAs(m_container, wxBottom);
3a6bdcad
VZ
541 if (m_split == DSR_HORIZONTAL_TAB)
542 {
eacb91fc
VZ
543 layout->top.Below(m_child[0]->m_container, 1);
544 layout->left.SameAs(m_container, wxLeft);
3a6bdcad
VZ
545 }
546 else
547 {
eacb91fc
VZ
548 layout->left.RightOf(m_child[0]->m_container, 1);
549 layout->top.SameAs(m_container, wxTop);
550 }
551 m_child[1]->m_container->SetConstraints(layout);
552}
553
3a6bdcad
VZ
554void wxDynamicSashWindowImpl::Unify(int panel)
555{
556 int other = panel == 0 ? 1 : 0;
eacb91fc 557
3a6bdcad
VZ
558 if (m_child[panel]->m_leaf)
559 {
eacb91fc
VZ
560 wxDynamicSashWindowImpl *child[2];
561
562 child[0] = m_child[0];
563 child[1] = m_child[1];
564
565 m_child[0] = m_child[1] = NULL;
566
567 m_leaf = new wxDynamicSashWindowLeaf(this);
568 m_leaf->Create();
569 m_leaf->m_child = child[panel]->m_leaf->m_child;
570
571 m_leaf->m_vscroll->SetScrollbar(child[panel]->m_leaf->m_vscroll->GetThumbPosition(),
572 child[panel]->m_leaf->m_vscroll->GetThumbSize(),
573 child[panel]->m_leaf->m_vscroll->GetRange(),
574 child[panel]->m_leaf->m_vscroll->GetPageSize());
575 m_leaf->m_hscroll->SetScrollbar(child[panel]->m_leaf->m_hscroll->GetThumbPosition(),
576 child[panel]->m_leaf->m_hscroll->GetThumbSize(),
577 child[panel]->m_leaf->m_hscroll->GetRange(),
578 child[panel]->m_leaf->m_hscroll->GetPageSize());
579 m_add_child_target = NULL;
580 wxDynamicSashReparentEvent event(m_leaf);
581 m_leaf->ProcessEvent(event);
582
583 delete child[0];
584 delete child[1];
585
586 m_split = DSR_NONE;
587
588 wxDynamicSashUnifyEvent unify(m_leaf->m_child);
589 m_leaf->m_child->ProcessEvent(unify);
3a6bdcad
VZ
590 }
591 else
592 {
eacb91fc
VZ
593 m_split = m_child[panel]->m_split;
594
595 delete m_child[other];
596
597 wxDynamicSashWindowImpl *child_panel = m_child[panel];
598 m_child[0] = child_panel->m_child[0];
599 m_child[1] = child_panel->m_child[1];
600
601 m_child[0]->m_parent = this;
602 m_child[1]->m_parent = this;
603
604 m_add_child_target = NULL;
605 m_child[0]->m_container->Reparent(m_container);
606 m_child[1]->m_container->Reparent(m_container);
607
608 child_panel->m_child[0] = child_panel->m_child[1] = NULL;
609 delete child_panel;
610
611 wxSize size = m_container->GetSize();
612 wxSize child_size = m_child[0]->m_container->GetSize();
613
614 ConstrainChildren(child_size.GetWidth() * 100 / size.GetWidth(),
615 child_size.GetHeight() * 100 / size.GetHeight());
616
617 m_container->Layout();
618 }
619}
620
3a6bdcad
VZ
621void wxDynamicSashWindowImpl::Split(int px, int py)
622{
eacb91fc
VZ
623
624 m_add_child_target = NULL;
625
626 m_child[0] = new wxDynamicSashWindowImpl(m_window);
a2d49353 627 m_child[0]->m_container = new wxWindow(m_container, wxID_ANY);
eacb91fc
VZ
628 m_child[0]->m_parent = this;
629 m_child[0]->m_top = m_top;
630 m_child[0]->Create();
3a6bdcad
VZ
631 if (m_leaf->m_child)
632 {
eacb91fc
VZ
633 m_leaf->m_child->Reparent(m_container);
634 m_child[0]->AddChild(m_leaf->m_child);
635 }
636
637 m_child[1] = new wxDynamicSashWindowImpl(m_window);
a2d49353 638 m_child[1]->m_container = new wxWindow(m_container, wxID_ANY);
eacb91fc
VZ
639 m_child[1]->m_parent = this;
640 m_child[1]->m_top = m_top;
641 m_child[1]->Create();
642
643 m_split = m_dragging;
644 ConstrainChildren(px, py);
645
646 m_top->m_add_child_target = m_child[1];
647 wxDynamicSashSplitEvent split(m_child[0]->m_leaf->m_child);
648 m_child[0]->m_leaf->m_child->ProcessEvent(split);
649
650 m_child[0]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
651 m_leaf->m_vscroll->GetThumbSize(),
652 m_leaf->m_vscroll->GetRange(),
653 m_leaf->m_vscroll->GetPageSize());
654 m_child[0]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
655 m_leaf->m_hscroll->GetThumbSize(),
656 m_leaf->m_hscroll->GetRange(),
657 m_leaf->m_hscroll->GetPageSize());
658 m_child[1]->m_leaf->m_vscroll->SetScrollbar(m_leaf->m_vscroll->GetThumbPosition(),
659 m_leaf->m_vscroll->GetThumbSize(),
660 m_leaf->m_vscroll->GetRange(),
661 m_leaf->m_vscroll->GetPageSize());
662 m_child[1]->m_leaf->m_hscroll->SetScrollbar(m_leaf->m_hscroll->GetThumbPosition(),
663 m_leaf->m_hscroll->GetThumbSize(),
664 m_leaf->m_hscroll->GetRange(),
665 m_leaf->m_hscroll->GetPageSize());
666 delete m_leaf;
667 m_leaf = NULL;
668
669 m_container->Layout();
eacb91fc
VZ
670}
671
281de223 672
eacb91fc
VZ
673/* This code is called when you finish resizing a view by dragging the
674 corner tab, but I think this implementation is lousy and will surprise
675 the user more often than it will do what they are trying to do. What
676 I really need to be doing here is do a rewrite such that *no* sashes
677 move except the ones immediately to the bottom and right of this window,
678 and handle the case where you resize a window larger than it's neighbors
679 by destroying the neighbors.
680
681 But this will do for now. */
3a6bdcad
VZ
682void wxDynamicSashWindowImpl::Resize(int x, int y)
683{
eacb91fc
VZ
684 wxDynamicSashWindowImpl *h_parent = FindParent(DSR_BOTTOM_EDGE);
685 wxDynamicSashWindowImpl *v_parent = FindParent(DSR_RIGHT_EDGE);
686 int h_unify = -1;
687 int v_unify = -1;
688 wxWindow *frame = FindFrame();
689
3a6bdcad 690 if (x < 0)
eacb91fc 691 x = 0;
3a6bdcad 692 if (y < 0)
eacb91fc 693 y = 0;
eacb91fc 694
3a6bdcad
VZ
695 if (h_parent)
696 {
eacb91fc
VZ
697 m_container->ClientToScreen(NULL, &y);
698 h_parent->m_container->ScreenToClient(NULL, &y);
699
700 int py = (int)((y * 100) / h_parent->m_container->GetSize().GetHeight() + 0.5);
701
3a6bdcad
VZ
702 if (py < 10)
703 {
eacb91fc
VZ
704 wxDynamicSashWindowImpl *ho_parent = FindParent(DSR_TOP_EDGE);
705
3a6bdcad
VZ
706 if (ho_parent)
707 {
708 if (FindUpperParent(h_parent, ho_parent) == ho_parent)
709 {
eacb91fc 710 h_unify = 1;
3a6bdcad
VZ
711 }
712 else
713 {
eacb91fc
VZ
714 py = (int)((ho_parent->m_child[0]->m_container->GetSize().GetHeight() * 100)
715 / h_parent->m_container->GetSize().GetHeight() + 0.5);
716 h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
717 h_parent->m_container, wxHeight, py);
718
719 h_parent = ho_parent;
720 h_unify = 0;
721 }
3a6bdcad
VZ
722 }
723 else
724 {
eacb91fc
VZ
725 h_unify = 1;
726 }
3a6bdcad
VZ
727 }
728 else if (py > 90)
729 {
eacb91fc 730 h_unify = 0;
3a6bdcad
VZ
731 }
732 else
733 {
eacb91fc
VZ
734 h_parent->m_child[0]->m_container->GetConstraints()->height.PercentOf(
735 h_parent->m_container, wxHeight, py);
736 h_parent->m_container->Layout();
737 }
3a6bdcad
VZ
738 }
739 else
740 {
eacb91fc
VZ
741 int do_resize = 1;
742 h_parent = FindParent(DSR_TOP_EDGE);
743
3a6bdcad
VZ
744 if (h_parent)
745 {
eacb91fc
VZ
746 int py = (int)((y * 100) /
747 (h_parent->m_container->GetSize().GetHeight() +
748 y - m_container->GetSize().GetHeight()) + 0.5);
749
3a6bdcad 750 if (py < 10)
eacb91fc 751 h_unify = 0;
3a6bdcad
VZ
752 }
753 else if (y < 64)
754 {
eacb91fc
VZ
755 do_resize = 0;
756 }
757
3a6bdcad
VZ
758 if (do_resize)
759 {
eacb91fc
VZ
760 wxSize size = frame->GetSize();
761 frame->SetSize(size.GetWidth(), size.GetHeight() + y - m_container->GetSize().GetHeight());
762 }
763 }
764
3a6bdcad
VZ
765 if (v_parent)
766 {
eacb91fc
VZ
767 m_container->ClientToScreen(&x, NULL);
768 v_parent->m_container->ScreenToClient(&x, NULL);
769
770 int px = (int)((x * 100) / v_parent->m_container->GetSize().GetWidth() + 0.5);
771
3a6bdcad
VZ
772 if (px < 10)
773 {
eacb91fc
VZ
774 wxDynamicSashWindowImpl *vo_parent = FindParent(DSR_LEFT_EDGE);
775
3a6bdcad
VZ
776 if (vo_parent)
777 {
778 if (FindUpperParent(v_parent, vo_parent) == vo_parent)
779 {
eacb91fc 780 v_unify = 1;
3a6bdcad
VZ
781 }
782 else
783 {
eacb91fc
VZ
784 px = (int)((vo_parent->m_child[0]->m_container->GetSize().GetWidth() * 100)
785 / v_parent->m_container->GetSize().GetWidth() + 0.5);
786 v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
787 v_parent->m_container, wxWidth, px);
788
789 v_parent = vo_parent;
790 v_unify = 0;
791 }
3a6bdcad
VZ
792 }
793 else
794 {
eacb91fc
VZ
795 v_unify = 1;
796 }
3a6bdcad
VZ
797 }
798 else if (px > 90)
799 {
eacb91fc 800 v_unify = 0;
3a6bdcad
VZ
801 }
802 else
803 {
eacb91fc
VZ
804 v_parent->m_child[0]->m_container->GetConstraints()->width.PercentOf(
805 v_parent->m_container, wxWidth, px);
806 v_parent->m_container->Layout();
807 }
3a6bdcad
VZ
808 }
809 else
810 {
eacb91fc
VZ
811 int do_resize = 1;
812 v_parent = FindParent(DSR_LEFT_EDGE);
813
3a6bdcad
VZ
814 if (v_parent)
815 {
eacb91fc
VZ
816 int px = (int)((x * 100) /
817 (v_parent->m_container->GetSize().GetWidth() +
818 x - m_container->GetSize().GetWidth()) + 0.5);
819
3a6bdcad 820 if (px < 10)
eacb91fc 821 v_unify = 0;
3a6bdcad
VZ
822 }
823 else if (x < 64)
824 {
eacb91fc
VZ
825 do_resize = 0;
826 }
827
3a6bdcad
VZ
828 if (do_resize)
829 {
eacb91fc
VZ
830 wxSize size = frame->GetSize();
831 frame->SetSize(size.GetWidth() + x - m_container->GetSize().GetWidth(), size.GetHeight());
832 }
833 }
834
3a6bdcad
VZ
835 if (h_unify != -1 && v_unify != -1)
836 {
eacb91fc
VZ
837 wxDynamicSashWindowImpl *parent = FindUpperParent(h_parent, v_parent);
838
3a6bdcad
VZ
839 if (parent == h_parent)
840 {
eacb91fc 841 h_parent->Unify(h_unify);
3a6bdcad
VZ
842 }
843 else
844 {
eacb91fc
VZ
845 v_parent->Unify(v_unify);
846 }
3a6bdcad
VZ
847 }
848 else if (h_unify != -1)
849 {
eacb91fc 850 h_parent->Unify(h_unify);
3a6bdcad
VZ
851 }
852 else if (v_unify != -1)
853 {
eacb91fc
VZ
854 v_parent->Unify(v_unify);
855 }
856}
857
858
3a6bdcad
VZ
859void wxDynamicSashWindowImpl::OnSize(wxSizeEvent &event)
860{
eacb91fc
VZ
861 m_container->Layout();
862
863 if (m_leaf)
864 m_leaf->OnSize(event);
865}
866
3a6bdcad
VZ
867void wxDynamicSashWindowImpl::OnPaint(wxPaintEvent &event)
868{
eacb91fc
VZ
869 if (m_leaf)
870 m_leaf->OnPaint(event);
3a6bdcad
VZ
871 else
872 {
eacb91fc
VZ
873 wxPaintDC dc(m_container);
874 dc.SetBackground(wxBrush(m_container->GetBackgroundColour(), wxSOLID));
875 dc.Clear();
876 }
877}
878
3a6bdcad
VZ
879void wxDynamicSashWindowImpl::OnMouseMove(wxMouseEvent &event)
880{
881 if (m_dragging)
882 {
eacb91fc
VZ
883 DrawSash(m_drag_x, m_drag_y);
884 m_drag_x = event.m_x; m_drag_y = event.m_y;
885 DrawSash(m_drag_x, m_drag_y);
3a6bdcad
VZ
886 }
887 else if (m_leaf)
888 {
eacb91fc
VZ
889 m_leaf->OnMouseMove(event);
890 }
891}
892
3a6bdcad
VZ
893void wxDynamicSashWindowImpl::OnLeave(wxMouseEvent &event)
894{
895 if (m_leaf)
eacb91fc 896 m_leaf->OnLeave(event);
eacb91fc
VZ
897}
898
3a6bdcad
VZ
899void wxDynamicSashWindowImpl::OnPress(wxMouseEvent &event)
900{
901 if (m_leaf)
902 {
eacb91fc 903 m_leaf->OnPress(event);
3a6bdcad
VZ
904 }
905 else
906 {
eacb91fc
VZ
907 m_dragging = m_split;
908 m_drag_x = event.m_x;
909 m_drag_y = event.m_y;
910 DrawSash(m_drag_x, m_drag_y);
911 m_container->CaptureMouse();
912 }
913}
914
3a6bdcad
VZ
915void wxDynamicSashWindowImpl::OnRelease(wxMouseEvent &event)
916{
281de223 917 if ((m_dragging == DSR_CORNER) &&
3a6bdcad
VZ
918 (m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0)
919 {
eacb91fc
VZ
920 DrawSash(m_drag_x, m_drag_y);
921 m_container->ReleaseMouse();
922
923 Resize(event.m_x, event.m_y);
924
925 m_dragging = DSR_NONE;
3a6bdcad
VZ
926 }
927 else if (m_dragging)
928 {
eacb91fc
VZ
929 DrawSash(m_drag_x, m_drag_y);
930 m_container->ReleaseMouse();
931
932 wxSize size = m_container->GetSize();
933 int px = (int)((event.m_x * 100) / size.GetWidth() + 0.5);
934 int py = (int)((event.m_y * 100) / size.GetHeight() + 0.5);
935
936 if ((m_dragging == DSR_HORIZONTAL_TAB && py >= 10 && py <= 90)
3a6bdcad
VZ
937 || (m_dragging == DSR_VERTICAL_TAB && px >= 10 && px <= 90))
938 {
939 if (m_child[0] == NULL)
940 {
eacb91fc 941 Split(px, py);
3a6bdcad
VZ
942 }
943 else
944 {
eacb91fc
VZ
945 /* It would be nice if moving *this* sash didn't implicitly move
946 the sashes of our children (if any). But this will do. */
947 wxLayoutConstraints *layout = m_child[0]->m_container->GetConstraints();
3a6bdcad
VZ
948 if (m_split == DSR_HORIZONTAL_TAB)
949 {
eacb91fc 950 layout->height.PercentOf(m_container, wxHeight, py);
3a6bdcad
VZ
951 }
952 else
953 {
eacb91fc
VZ
954 layout->width.PercentOf(m_container, wxWidth, px);
955 }
956 m_container->Layout();
957 }
3a6bdcad
VZ
958 }
959 else
960 {
961 if (m_child[0] != NULL)
962 {
eacb91fc 963 if ((m_dragging == DSR_HORIZONTAL_TAB && py <= 10)
3a6bdcad
VZ
964 || (m_dragging == DSR_VERTICAL_TAB && px <= 10))
965 {
eacb91fc 966 Unify(1);
3a6bdcad
VZ
967 }
968 else
969 {
eacb91fc
VZ
970 Unify(0);
971 }
972 }
973 }
974
3a6bdcad
VZ
975 wxCursor cursor;
976 if (m_split == DSR_HORIZONTAL_TAB)
eacb91fc 977 cursor = wxCursor(wxCURSOR_SIZENS);
3a6bdcad 978 else if (m_split == DSR_VERTICAL_TAB)
eacb91fc 979 cursor = wxCursor(wxCURSOR_SIZEWE);
3a6bdcad
VZ
980 else
981 cursor = wxCursor(wxCURSOR_ARROW);
982
eacb91fc
VZ
983 m_container->SetCursor(cursor);
984
985 m_dragging = DSR_NONE;
3a6bdcad
VZ
986 }
987 else if (m_leaf)
988 {
eacb91fc
VZ
989 m_leaf->OnRelease(event);
990 }
991}
992
3a6bdcad
VZ
993// ============================================================================
994// wxDynamicSashWindowLeaf
995// ============================================================================
eacb91fc 996
3a6bdcad
VZ
997wxDynamicSashWindowLeaf::wxDynamicSashWindowLeaf(wxDynamicSashWindowImpl *impl)
998{
eacb91fc
VZ
999 m_impl = impl;
1000
7e068925
VZ
1001 m_hscroll =
1002 m_vscroll = NULL;
1003
eacb91fc
VZ
1004 m_child = NULL;
1005}
1006
3a6bdcad
VZ
1007wxDynamicSashWindowLeaf::~wxDynamicSashWindowLeaf()
1008{
eacb91fc
VZ
1009 m_hscroll->SetEventHandler(m_hscroll);
1010 m_vscroll->SetEventHandler(m_vscroll);
eacb91fc
VZ
1011
1012 m_hscroll->Destroy();
1013 m_vscroll->Destroy();
1014 m_viewport->Destroy();
1015}
1016
3a6bdcad
VZ
1017bool wxDynamicSashWindowLeaf::Create()
1018{
eacb91fc
VZ
1019 m_hscroll = new wxScrollBar();
1020 m_vscroll = new wxScrollBar();
1021 m_viewport = new wxWindow();
1022
eacb91fc
VZ
1023 wxDynamicSashWindowImpl *add_child_target = m_impl->m_add_child_target;
1024 m_impl->m_add_child_target = NULL;
7e068925
VZ
1025
1026 bool success = m_hscroll->Create(m_impl->m_container, wxID_ANY,
1027 wxDefaultPosition, wxDefaultSize,
1028 wxSB_HORIZONTAL);
1029 if ( success )
1030 success = m_vscroll->Create(m_impl->m_container, wxID_ANY,
1031 wxDefaultPosition, wxDefaultSize,
1032 wxSB_VERTICAL);
1033 if ( success )
1034 success = m_viewport->Create(m_impl->m_container, wxID_ANY);
1035 if ( !success )
1036 return false;
1037
eacb91fc
VZ
1038 m_impl->m_add_child_target = add_child_target;
1039
1040 wxCursor cursor(wxCURSOR_ARROW);
1041 m_hscroll->SetCursor(cursor);
1042 m_vscroll->SetCursor(cursor);
1043 m_viewport->SetCursor(cursor);
1044
7e068925
VZ
1045 // the viewport must resize its child when it is itself resized, but it's
1046 // more convenient to do it in our own method instead of deriving a new
1047 // class just for this: this is why we pass this as last Connect() argument
1048 m_viewport->Connect(wxEVT_SIZE,
1049 wxSizeEventHandler(wxDynamicSashWindowLeaf::OnViewSize),
1050 NULL, this);
1051
a7daa76e
VZ
1052 Connect(wxEVT_DYNAMIC_SASH_REPARENT,
1053 wxEventHandler(wxDynamicSashWindowLeaf::OnReparent));
eacb91fc 1054
3a6bdcad
VZ
1055 if (m_impl->m_window->GetWindowStyle() & wxDS_MANAGE_SCROLLBARS)
1056 {
eacb91fc
VZ
1057 m_hscroll->SetEventHandler(this);
1058 m_vscroll->SetEventHandler(this);
1059
a7daa76e
VZ
1060 Connect(wxEVT_SET_FOCUS,
1061 wxFocusEventHandler(wxDynamicSashWindowLeaf::OnFocus));
1062 Connect(wxEVT_SCROLL_TOP,
1063 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
1064 Connect(wxEVT_SCROLL_BOTTOM,
1065 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
1066 Connect(wxEVT_SCROLL_LINEUP,
1067 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
1068 Connect(wxEVT_SCROLL_LINEDOWN,
1069 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
1070 Connect(wxEVT_SCROLL_PAGEUP,
1071 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
1072 Connect(wxEVT_SCROLL_PAGEDOWN,
1073 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
1074 Connect(wxEVT_SCROLL_THUMBTRACK,
1075 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
1076 Connect(wxEVT_SCROLL_THUMBRELEASE,
1077 wxScrollEventHandler(wxDynamicSashWindowLeaf::OnScroll));
eacb91fc
VZ
1078 }
1079
1080 wxLayoutConstraints *layout = new wxLayoutConstraints();
1081 if (!layout)
a2d49353 1082 return false;
a7daa76e 1083
eacb91fc 1084 wxSize size = m_hscroll->GetBestSize();
eacb91fc
VZ
1085
1086 layout->left.SameAs(m_impl->m_container, wxLeft, 10);
1087 layout->right.LeftOf(m_vscroll);
1088 layout->bottom.SameAs(m_impl->m_container, wxBottom, 3);
1089 layout->height.Absolute(size.GetHeight());
1090 m_hscroll->SetConstraints(layout);
1091
1092 layout = new wxLayoutConstraints();
1093 if (!layout)
a2d49353 1094 return false;
a7daa76e
VZ
1095
1096 size = m_vscroll->GetBestSize();
eacb91fc
VZ
1097
1098 layout->top.SameAs(m_impl->m_container, wxTop, 10);
1099 layout->bottom.Above(m_hscroll);
1100 layout->right.SameAs(m_impl->m_container, wxRight, 3);
1101 layout->width.Absolute(size.GetWidth());
1102 m_vscroll->SetConstraints(layout);
1103
1104 layout = new wxLayoutConstraints();
1105 if (!layout)
a2d49353 1106 return false;
eacb91fc
VZ
1107 layout->left.SameAs(m_impl->m_container, wxLeft, 3);
1108 layout->right.LeftOf(m_vscroll);
1109 layout->top.SameAs(m_impl->m_container, wxTop, 3);
1110 layout->bottom.Above(m_hscroll);
1111 m_viewport->SetConstraints(layout);
1112
1113 m_impl->m_container->Layout();
1114
7e068925 1115 return true;
eacb91fc
VZ
1116}
1117
3a6bdcad
VZ
1118void wxDynamicSashWindowLeaf::AddChild(wxWindow *window)
1119{
1120 if (m_child)
eacb91fc 1121 m_child->Destroy();
eacb91fc
VZ
1122
1123 m_child = window;
1124
1125 wxDynamicSashReparentEvent event(this);
1126 AddPendingEvent(event);
1127}
1128
3a6bdcad
VZ
1129DynamicSashRegion wxDynamicSashWindowLeaf::GetRegion(int x, int y)
1130{
eacb91fc
VZ
1131 wxSize size = m_impl->m_container->GetSize();
1132 int w = size.GetWidth();
1133 int h = size.GetHeight();
1134 size = m_hscroll->GetSize();
1135 int sh = size.GetHeight();
1136 size = m_vscroll->GetSize();
1137 int sw = size.GetWidth();
1138
1139 if (x >= w - sw - 3 && x < w && y >= h - sh - 3 && y < h)
1140 return DSR_CORNER;
1141 if (x >= 3 && x < 10 && y >= h - sh - 3 && y < h - 2)
1142 return DSR_VERTICAL_TAB;
1143 if (x >= w - sw - 3 && x < w - 2 && y >= 3 && y < 10)
1144 return DSR_HORIZONTAL_TAB;
1145 if (x < 3)
1146 return DSR_LEFT_EDGE;
1147 if (y < 3)
1148 return DSR_TOP_EDGE;
1149 if (x >= w - 2)
1150 return DSR_RIGHT_EDGE;
1151 if (y >= h - 2)
1152 return DSR_BOTTOM_EDGE;
1153
1154 return DSR_NONE;
1155}
1156
67631cee 1157void wxDynamicSashWindowLeaf::ResizeChild(const wxSize& size)
3a6bdcad
VZ
1158{
1159 if (m_child)
1160 {
67631cee 1161 if (m_impl->m_window->HasFlag(wxDS_MANAGE_SCROLLBARS))
3a6bdcad 1162 {
eacb91fc 1163 wxSize best_size = m_child->GetBestSize();
3a6bdcad 1164 if (best_size.GetWidth() < size.GetWidth())
eacb91fc 1165 best_size.SetWidth(size.GetWidth());
3a6bdcad 1166 if (best_size.GetHeight() < size.GetHeight())
eacb91fc 1167 best_size.SetHeight(size.GetHeight());
eacb91fc
VZ
1168 m_child->SetSize(best_size);
1169
1170 int hpos = m_hscroll->GetThumbPosition();
1171 int vpos = m_vscroll->GetThumbPosition();
1172
3a6bdcad 1173 if (hpos < 0)
eacb91fc 1174 hpos = 0;
3a6bdcad 1175 if (vpos < 0)
eacb91fc 1176 vpos = 0;
3a6bdcad 1177 if (hpos > best_size.GetWidth() - size.GetWidth())
eacb91fc 1178 hpos = best_size.GetWidth() - size.GetWidth();
3a6bdcad 1179 if (vpos > best_size.GetHeight() - size.GetHeight())
eacb91fc 1180 vpos = best_size.GetHeight() - size.GetHeight();
eacb91fc
VZ
1181
1182 m_hscroll->SetScrollbar(hpos, size.GetWidth(),
1183 best_size.GetWidth(), size.GetWidth());
1184 m_vscroll->SetScrollbar(vpos, size.GetHeight(),
1185 best_size.GetHeight(), size.GetHeight());
1186
1187 // Umm, the scrollbars are doing something insane under GTK+ and subtracting
1188 // one from the position I pass in. This works around that.
1189 m_hscroll->SetThumbPosition(hpos + hpos - m_hscroll->GetThumbPosition());
1190 m_vscroll->SetThumbPosition(vpos + vpos - m_vscroll->GetThumbPosition());
1191
1192 wxPoint pos = m_child->GetPosition();
1193 m_viewport->ScrollWindow(-hpos - pos.x, -vpos - pos.y);
3a6bdcad 1194 }
67631cee 1195 else // !wxDS_MANAGE_SCROLLBARS
3a6bdcad 1196 {
eacb91fc
VZ
1197 m_child->SetSize(size);
1198 }
1199 }
1200}
1201
3a6bdcad
VZ
1202wxScrollBar *
1203wxDynamicSashWindowLeaf::FindScrollBar(const wxWindow *child, int vert) const
1204{
1205 if (m_child == child)
1206 {
1207 return vert ? m_vscroll : m_hscroll;
eacb91fc
VZ
1208 }
1209
1210 return NULL;
1211}
1212
3a6bdcad
VZ
1213void wxDynamicSashWindowLeaf::OnSize(wxSizeEvent &WXUNUSED(event))
1214{
eacb91fc 1215 m_impl->m_container->Refresh();
7e068925
VZ
1216}
1217
1218void wxDynamicSashWindowLeaf::OnViewSize(wxSizeEvent &WXUNUSED(event))
1219{
1220 if ( m_viewport )
1221 ResizeChild(m_viewport->GetSize());
eacb91fc
VZ
1222}
1223
3a6bdcad
VZ
1224void wxDynamicSashWindowLeaf::OnPaint(wxPaintEvent &WXUNUSED(event))
1225{
eacb91fc
VZ
1226 wxPaintDC dc(m_impl->m_container);
1227 dc.SetBackground(wxBrush(m_impl->m_container->GetBackgroundColour(), wxSOLID));
1228 dc.Clear();
1229
e1c6c6ae
VS
1230 wxPen highlight(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), 1, wxSOLID);
1231 wxPen shadow(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), 1, wxSOLID);
eacb91fc
VZ
1232 wxPen black(*wxBLACK, 1, wxSOLID);
1233
1234 wxSize size = m_impl->m_container->GetSize();
1235 int w = size.GetWidth();
1236 int h = size.GetHeight();
1237 size = m_hscroll->GetSize();
1238 int sh = size.GetHeight();
1239 size = m_vscroll->GetSize();
1240 int sw = size.GetWidth();
1241
1242 dc.SetPen(shadow);
1243 dc.DrawLine(1, 1, 1, h - 2);
1244 dc.DrawLine(1, 1, w - 2, 1);
1245 dc.SetPen(black);
1246 dc.DrawLine(2, 2, 2, h - 3);
1247 dc.DrawLine(2, 2, w - 3, 2);
1248 dc.SetPen(highlight);
1249 dc.DrawLine(w - 2, 2, w - 2, h - sh - 2);
1250 dc.DrawLine(w - 2, h - sh - 2, w - sw - 2, h - sh - 2);
1251 dc.DrawLine(w - sw - 2, h - sh - 2, w - sw - 2, h - 2);
1252 dc.DrawLine(w - sw - 2, h - 2, 2, h - 2);
1253
1254 dc.SetPen(highlight);
1255 dc.DrawLine(w - sw - 2, 8, w - sw - 2, 4);
1256 dc.DrawLine(w - sw - 2, 4, w - 5, 4);
1257 dc.SetPen(shadow);
1258 dc.DrawLine(w - 5, 4, w - 5, 8);
1259 dc.DrawLine(w - 5, 8, w - sw - 2, 8);
1260 dc.SetPen(black);
1261 dc.DrawLine(w - 4, 3, w - 4, 9);
1262 dc.DrawLine(w - 4, 9, w - sw - 3, 9);
1263
1264 dc.SetPen(highlight);
1265 dc.DrawLine(4, h - 5, 4, h - sh - 2);
1266 dc.DrawLine(4, h - sh - 2, 8, h - sh - 2);
1267 dc.SetPen(shadow);
1268 dc.DrawLine(8, h - sh - 2, 8, h - 5);
1269 dc.DrawLine(8, h - 5, 4, h - 5);
1270 dc.SetPen(black);
1271 dc.DrawLine(9, h - sh - 3, 9, h - 4);
1272 dc.DrawLine(9, h - 4, 3, h - 4);
1273
eacb91fc
VZ
1274 int cy = (h - sh + h - 6) / 2 + 1;
1275 int cx = (w - sw + w - 6) / 2 + 1;
1276 int sy = cy;
1277 while (sy > h - sh)
1278 sy -= 4;
1279 int sx = cx;
1280 while (sx > w - sw)
1281 sx -= 4;
1282
1283 int x, y;
3a6bdcad
VZ
1284 for (y = sy; y < h - 2; y += 4)
1285 {
1286 for (x = sx; x < w - 2; x += 4)
1287 {
1288 if (x - cx >= -(y - cy))
1289 {
eacb91fc
VZ
1290 dc.SetPen(highlight);
1291 dc.DrawPoint(x, y);
1292 dc.SetPen(shadow);
1293 dc.DrawPoint(x + 1, y + 1);
1294 }
1295 }
1296 }
1297}
1298
3a6bdcad
VZ
1299void wxDynamicSashWindowLeaf::OnScroll(wxScrollEvent &WXUNUSED(event))
1300{
eacb91fc
VZ
1301 int nx = -m_hscroll->GetThumbPosition();
1302 int ny = -m_vscroll->GetThumbPosition();
1303
3a6bdcad
VZ
1304 if (m_child)
1305 {
eacb91fc
VZ
1306 wxPoint pos = m_child->GetPosition();
1307
1308 m_viewport->ScrollWindow(nx - pos.x, ny - pos.y);
1309 }
1310}
1311
3a6bdcad
VZ
1312void wxDynamicSashWindowLeaf::OnFocus(wxFocusEvent &event)
1313{
1314 if ( event.GetEventObject() == m_hscroll ||
1315 event.GetEventObject() == m_vscroll )
1316 {
eacb91fc
VZ
1317 m_child->SetFocus();
1318 }
1319}
1320
1321
3a6bdcad
VZ
1322void wxDynamicSashWindowLeaf::OnMouseMove(wxMouseEvent &event)
1323{
1324 if (m_impl->m_dragging)
eacb91fc 1325 return;
eacb91fc
VZ
1326
1327 DynamicSashRegion region = GetRegion(event.m_x, event.m_y);
1328
1329 wxCursor cursor(wxCURSOR_ARROW);
3a6bdcad
VZ
1330 if (region == DSR_HORIZONTAL_TAB)
1331 {
eacb91fc 1332 cursor = wxCursor(wxCURSOR_SIZENS);
3a6bdcad
VZ
1333 }
1334 else if (region == DSR_VERTICAL_TAB)
1335 {
eacb91fc 1336 cursor = wxCursor(wxCURSOR_SIZEWE);
3a6bdcad
VZ
1337 }
1338 else if ((region == DSR_CORNER) &&
1339 (m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) != 0)
1340 {
eacb91fc 1341 cursor = wxCursor(wxCURSOR_SIZENWSE);
3a6bdcad
VZ
1342 }
1343 else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
1344 || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE)
1345 {
1346 if (m_impl->FindParent(region))
1347 {
1348 if (region == DSR_LEFT_EDGE || region == DSR_RIGHT_EDGE)
1349 {
eacb91fc 1350 cursor = wxCursor(wxCURSOR_SIZEWE);
3a6bdcad
VZ
1351 }
1352 else
1353 {
eacb91fc
VZ
1354 cursor = wxCursor(wxCURSOR_SIZENS);
1355 }
1356 }
1357 }
1358
1359 m_impl->m_container->SetCursor(cursor);
1360}
1361
3a6bdcad
VZ
1362void wxDynamicSashWindowLeaf::OnLeave(wxMouseEvent &WXUNUSED(event))
1363{
eacb91fc
VZ
1364 wxCursor cursor(wxCURSOR_ARROW);
1365 m_impl->m_container->SetCursor(cursor);
1366}
1367
1368
3a6bdcad
VZ
1369void wxDynamicSashWindowLeaf::OnPress(wxMouseEvent &event)
1370{
eacb91fc
VZ
1371 DynamicSashRegion region = GetRegion(event.m_x, event.m_y);
1372
281de223
RD
1373 if ((region == DSR_CORNER) && (m_impl->m_window->GetWindowStyle() & wxDS_DRAG_CORNER) == 0)
1374 return;
1375
3a6bdcad
VZ
1376 if (region == DSR_HORIZONTAL_TAB || region == DSR_VERTICAL_TAB || region == DSR_CORNER)
1377 {
eacb91fc
VZ
1378 m_impl->m_dragging = region;
1379 m_impl->m_drag_x = event.m_x;
1380 m_impl->m_drag_y = event.m_y;
1381 m_impl->DrawSash(event.m_x, event.m_y);
1382 m_impl->m_container->CaptureMouse();
3a6bdcad
VZ
1383 }
1384 else if (region == DSR_LEFT_EDGE || region == DSR_TOP_EDGE
1385 || region == DSR_RIGHT_EDGE || region == DSR_BOTTOM_EDGE)
1386 {
eacb91fc
VZ
1387 wxDynamicSashWindowImpl *parent = m_impl->FindParent(region);
1388
3a6bdcad
VZ
1389 if (parent)
1390 {
eacb91fc
VZ
1391 int x = event.m_x;
1392 int y = event.m_y;
1393
1394 m_impl->m_container->ClientToScreen(&x, &y);
1395 parent->m_container->ScreenToClient(&x, &y);
1396
1397 parent->m_dragging = parent->m_split;
1398 parent->m_drag_x = x;
1399 parent->m_drag_y = y;
1400 parent->DrawSash(x, y);
1401 parent->m_container->CaptureMouse();
1402 }
1403 }
1404}
1405
3a6bdcad
VZ
1406void wxDynamicSashWindowLeaf::OnRelease(wxMouseEvent &WXUNUSED(event))
1407{
eacb91fc
VZ
1408}
1409
3a6bdcad
VZ
1410void wxDynamicSashWindowLeaf::OnReparent(wxEvent &WXUNUSED(event))
1411{
1412 if (m_child)
1413 {
eacb91fc
VZ
1414 m_child->Reparent(m_viewport);
1415 }
1416
1417 ResizeChild(m_viewport->GetSize());
1418}
1419
3a6bdcad
VZ
1420// ============================================================================
1421// events
1422// ============================================================================
eacb91fc 1423
3a6bdcad
VZ
1424wxDynamicSashSplitEvent::wxDynamicSashSplitEvent()
1425{
eacb91fc
VZ
1426 m_eventObject = NULL;
1427 m_eventType = wxEVT_DYNAMIC_SASH_SPLIT;
1428}
1429
3a6bdcad
VZ
1430wxDynamicSashSplitEvent::wxDynamicSashSplitEvent(wxObject *object)
1431{
eacb91fc
VZ
1432 m_eventObject = object;
1433 m_eventType = wxEVT_DYNAMIC_SASH_SPLIT;
1434}
1435
1436IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashSplitEvent, wxCommandEvent)
1437
3a6bdcad
VZ
1438wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent()
1439{
eacb91fc
VZ
1440 m_eventObject = NULL;
1441 m_eventType = wxEVT_DYNAMIC_SASH_UNIFY;
1442}
1443
3a6bdcad
VZ
1444wxDynamicSashUnifyEvent::wxDynamicSashUnifyEvent(wxObject *object)
1445{
eacb91fc
VZ
1446 m_eventObject = object;
1447 m_eventType = wxEVT_DYNAMIC_SASH_UNIFY;
1448}
1449
1450IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashUnifyEvent, wxCommandEvent)
1451
eacb91fc 1452
3a6bdcad
VZ
1453wxDynamicSashReparentEvent::wxDynamicSashReparentEvent()
1454{
eacb91fc
VZ
1455 m_eventObject = NULL;
1456 m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
1457}
1458
3a6bdcad
VZ
1459wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(wxObject *object)
1460{
eacb91fc
VZ
1461 m_eventObject = object;
1462 m_eventType = wxEVT_DYNAMIC_SASH_REPARENT;
1463}
1464
aa83902a
RD
1465wxDynamicSashReparentEvent::wxDynamicSashReparentEvent(const wxDynamicSashReparentEvent& evt)
1466 : wxEvent(evt)
1467{
1468}
1469
eacb91fc
VZ
1470IMPLEMENT_DYNAMIC_CLASS(wxDynamicSashReparentEvent, wxEvent)
1471