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