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