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