]> git.saurik.com Git - wxWidgets.git/blob - contrib/utils/wxrcedit/splittree.cpp
give focus to show top level windows
[wxWidgets.git] / contrib / utils / wxrcedit / splittree.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: splittree.cpp
3 // Purpose: Classes to achieve a remotely-scrolled tree in a splitter
4 // window that can be scrolled by a scrolled window higher in the
5 // hierarchy
6 // Author: Julian Smart
7 // Modified by:
8 // Created: 8/7/2000
9 // RCS-ID: $Id$
10 // Copyright: (c) Julian Smart
11 // Licence: wxWindows licence
12 /////////////////////////////////////////////////////////////////////////////
13
14 // ============================================================================
15 // declarations
16 // ============================================================================
17
18 // ----------------------------------------------------------------------------
19 // headers
20 // ----------------------------------------------------------------------------
21 #ifdef __GNUG__
22 #pragma implementation "splittree.h"
23 #endif
24
25 // For compilers that support precompilation, includes "wx/wx.h".
26 #include "wx/wxprec.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 // for all others, include the necessary headers (this file is usually all you
33 // need because it includes almost all "standard" wxWindows headers)
34 #ifndef WX_PRECOMP
35 #include "wx/wx.h"
36 #endif
37
38 #include "wx/generic/treectlg.h"
39
40 #ifdef __WXMSW__
41 #include "windows.h"
42 #include "wx/msw/winundef.h"
43 #endif
44
45 #include "splittree.h"
46
47 /*
48 * wxRemotelyScrolledTreeCtrl
49 */
50
51 #if USE_GENERIC_TREECTRL
52 IMPLEMENT_CLASS(wxRemotelyScrolledTreeCtrl, wxGenericTreeCtrl)
53 #else
54 IMPLEMENT_CLASS(wxRemotelyScrolledTreeCtrl, wxTreeCtrl)
55 #endif
56
57 #if USE_GENERIC_TREECTRL
58 BEGIN_EVENT_TABLE(wxRemotelyScrolledTreeCtrl, wxGenericTreeCtrl)
59 #else
60 BEGIN_EVENT_TABLE(wxRemotelyScrolledTreeCtrl, wxTreeCtrl)
61 #endif
62 EVT_SIZE(wxRemotelyScrolledTreeCtrl::OnSize)
63 EVT_TREE_ITEM_EXPANDED(-1, wxRemotelyScrolledTreeCtrl::OnExpand)
64 EVT_TREE_ITEM_COLLAPSED(-1, wxRemotelyScrolledTreeCtrl::OnExpand)
65 EVT_SCROLLWIN(wxRemotelyScrolledTreeCtrl::OnScroll)
66 END_EVENT_TABLE()
67
68 wxRemotelyScrolledTreeCtrl::wxRemotelyScrolledTreeCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pt,
69 const wxSize& sz, long style):
70 wxTreeCtrl(parent, id, pt, sz, style)
71 {
72 m_companionWindow = NULL;
73 }
74
75 wxRemotelyScrolledTreeCtrl::~wxRemotelyScrolledTreeCtrl()
76 {
77 }
78
79 void wxRemotelyScrolledTreeCtrl::HideVScrollbar()
80 {
81 #ifdef __WXMSW__
82 if (!IsKindOf(CLASSINFO(wxGenericTreeCtrl)))
83 {
84 ::ShowScrollBar((HWND) GetHWND(), SB_VERT, FALSE);
85 }
86 else
87 #endif
88 {
89 // Implicit in overriding SetScrollbars
90 }
91 }
92
93 // Number of pixels per user unit (0 or -1 for no scrollbar)
94 // Length of virtual canvas in user units
95 // Length of page in user units
96 void wxRemotelyScrolledTreeCtrl::SetScrollbars(int pixelsPerUnitX, int pixelsPerUnitY,
97 int noUnitsX, int noUnitsY,
98 int xPos, int yPos,
99 bool noRefresh)
100 {
101 if (IsKindOf(CLASSINFO(wxGenericTreeCtrl)))
102 {
103 wxGenericTreeCtrl* win = (wxGenericTreeCtrl*) this;
104 win->wxGenericTreeCtrl::SetScrollbars(pixelsPerUnitX, 0, noUnitsX, 0, xPos, 0, noRefresh);
105
106 wxScrolledWindow* scrolledWindow = GetScrolledWindow();
107 if (scrolledWindow)
108 {
109 scrolledWindow->SetScrollbars(0, pixelsPerUnitY, 0, noUnitsY, 0, yPos, noRefresh);
110 }
111 }
112 }
113
114 // In case we're using the generic tree control.
115 int wxRemotelyScrolledTreeCtrl::GetScrollPos(int orient) const
116 {
117 wxScrolledWindow* scrolledWindow = GetScrolledWindow();
118
119 if (IsKindOf(CLASSINFO(wxGenericTreeCtrl)))
120 {
121 wxGenericTreeCtrl* win = (wxGenericTreeCtrl*) this;
122
123 if (orient == wxHORIZONTAL)
124 return win->wxGenericTreeCtrl::GetScrollPos(orient);
125 else
126 {
127 return scrolledWindow->GetScrollPos(orient);
128 }
129 }
130 return 0;
131 }
132
133
134 // In case we're using the generic tree control.
135 // Get the view start
136 void wxRemotelyScrolledTreeCtrl::GetViewStart(int *x, int *y) const
137 {
138 wxScrolledWindow* scrolledWindow = GetScrolledWindow();
139
140 if (IsKindOf(CLASSINFO(wxGenericTreeCtrl)))
141 {
142
143 wxGenericTreeCtrl* win = (wxGenericTreeCtrl*) this;
144 int x1, y1, x2, y2;
145 win->wxGenericTreeCtrl::GetViewStart(& x1, & y1);
146 * x = x1; * y = y1;
147 if (!scrolledWindow)
148 return;
149
150 scrolledWindow->GetViewStart(& x2, & y2);
151 * y = y2;
152 }
153 else
154 {
155 // x is wrong since the horizontal scrollbar is controlled by the
156 // tree control, but we probably don't need it.
157 scrolledWindow->GetViewStart(x, y);
158 }
159 }
160
161 // In case we're using the generic tree control.
162 void wxRemotelyScrolledTreeCtrl::PrepareDC(wxDC& dc)
163 {
164 if (IsKindOf(CLASSINFO(wxGenericTreeCtrl)))
165 {
166 wxScrolledWindow* scrolledWindow = GetScrolledWindow();
167
168 wxGenericTreeCtrl* win = (wxGenericTreeCtrl*) this;
169
170 int startX, startY;
171 GetViewStart(& startX, & startY);
172
173 int xppu1, yppu1, xppu2, yppu2;
174 win->wxGenericTreeCtrl::GetScrollPixelsPerUnit(& xppu1, & yppu1);
175 scrolledWindow->GetScrollPixelsPerUnit(& xppu2, & yppu2);
176
177 dc.SetDeviceOrigin( -startX * xppu1, -startY * yppu2 );
178 //dc.SetUserScale( win->GetScaleX(), win->GetScaleY() );
179 }
180 }
181
182 // Scroll to the given line (in scroll units where each unit is
183 // the height of an item)
184 void wxRemotelyScrolledTreeCtrl::ScrollToLine(int posHoriz, int posVert)
185 {
186 #ifdef __WXMSW__
187 if (!IsKindOf(CLASSINFO(wxGenericTreeCtrl)))
188 {
189 UINT sbCode = SB_THUMBPOSITION;
190 HWND vertScrollBar = 0;
191 MSWDefWindowProc((WXUINT) WM_VSCROLL, MAKELONG(sbCode, posVert), (WXHWND) vertScrollBar);
192 }
193 else
194 #endif
195 {
196 wxGenericTreeCtrl* win = (wxGenericTreeCtrl*) this;
197 win->Refresh();
198 /* Doesn't work yet because scrolling is ignored by Scroll
199 int xppu, yppu;
200 wxScrolledWindow* scrolledWindow = GetScrolledWindow();
201 if (scrolledWindow)
202 {
203 scrolledWindow->GetScrollPixelsPerUnit(& xppu, & yppu);
204 win->Scroll(-1, posVert*yppu);
205 }
206 */
207 }
208 }
209
210 void wxRemotelyScrolledTreeCtrl::OnSize(wxSizeEvent& event)
211 {
212 HideVScrollbar();
213 AdjustRemoteScrollbars();
214 event.Skip();
215 }
216
217 void wxRemotelyScrolledTreeCtrl::OnExpand(wxTreeEvent& event)
218 {
219 AdjustRemoteScrollbars();
220 event.Skip();
221
222 // If we don't have this, we get some bits of lines still remaining
223 if (event.GetEventType() == wxEVT_COMMAND_TREE_ITEM_COLLAPSED)
224 Refresh();
225
226 // Pass on the event
227 if (m_companionWindow)
228 m_companionWindow->GetEventHandler()->ProcessEvent(event);
229 }
230
231 // Adjust the containing wxScrolledWindow's scrollbars appropriately
232 void wxRemotelyScrolledTreeCtrl::AdjustRemoteScrollbars()
233 {
234 if (IsKindOf(CLASSINFO(wxGenericTreeCtrl)))
235 {
236 // This is for the generic tree control.
237 // It calls SetScrollbars which has been overridden
238 // to adjust the parent scrolled window vertical
239 // scrollbar.
240 ((wxGenericTreeCtrl*) this)->AdjustMyScrollbars();
241 return;
242 }
243 else
244 {
245 // This is for the wxMSW tree control
246 wxScrolledWindow* scrolledWindow = GetScrolledWindow();
247 if (scrolledWindow)
248 {
249 wxRect itemRect;
250 if (GetBoundingRect(GetRootItem(), itemRect))
251 {
252 int itemHeight = itemRect.GetHeight();
253
254 int w, h;
255 GetClientSize(&w, &h);
256
257 wxRect rect(0, 0, 0, 0);
258 CalcTreeSize(rect);
259 int treeViewHeight = rect.GetHeight()/itemHeight;
260
261 int scrollPixelsPerLine = itemHeight;
262 int scrollPos = - (itemRect.y / itemHeight);
263
264 scrolledWindow->SetScrollbars(0, scrollPixelsPerLine, 0, treeViewHeight, 0, scrollPos);
265
266 // Ensure that when a scrollbar becomes hidden or visible,
267 // the contained window sizes are right.
268 // Problem: this is called too early (?)
269 wxSizeEvent event(scrolledWindow->GetSize(), scrolledWindow->GetId());
270 scrolledWindow->GetEventHandler()->ProcessEvent(event);
271 }
272 }
273 }
274 }
275
276
277 // Calculate the area that contains both rectangles
278 static wxRect CombineRectangles(const wxRect& rect1, const wxRect& rect2)
279 {
280 wxRect rect;
281
282 int right1 = rect1.GetRight();
283 int bottom1 = rect1.GetBottom();
284 int right2 = rect2.GetRight();
285 int bottom2 = rect2.GetBottom();
286
287 wxPoint topLeft = wxPoint(wxMin(rect1.x, rect2.x), wxMin(rect1.y, rect2.y));
288 wxPoint bottomRight = wxPoint(wxMax(right1, right2), wxMax(bottom1, bottom2));
289
290 rect.x = topLeft.x; rect.y = topLeft.y;
291 rect.SetRight(bottomRight.x);
292 rect.SetBottom(bottomRight.y);
293
294 return rect;
295 }
296
297
298 // Calculate the tree overall size so we can set the scrollbar
299 // correctly
300 void wxRemotelyScrolledTreeCtrl::CalcTreeSize(wxRect& rect)
301 {
302 CalcTreeSize(GetRootItem(), rect);
303 }
304
305 void wxRemotelyScrolledTreeCtrl::CalcTreeSize(const wxTreeItemId& id, wxRect& rect)
306 {
307 // TODO: implement GetFirst/NextVisibleItem
308 // for wxGenericTreeCtrl, plus GetBoundingRect.
309
310 // More efficient implementation would be to find the last item (but how?)
311 // Q: is the bounding rect relative to the top of the virtual tree workspace
312 // or the top of the window? How would we convert?
313 wxRect itemSize;
314 if (GetBoundingRect(id, itemSize))
315 {
316 rect = CombineRectangles(rect, itemSize);
317 }
318
319 long cookie;
320 wxTreeItemId childId = GetFirstChild(id, cookie);
321 while (childId != 0)
322 {
323 CalcTreeSize(childId, rect);
324 childId = GetNextChild(childId, cookie);
325 }
326 }
327
328 // Find the scrolled window that contains this control
329 wxScrolledWindow* wxRemotelyScrolledTreeCtrl::GetScrolledWindow() const
330 {
331 wxWindow* parent = wxWindow::GetParent();
332 while (parent)
333 {
334 if (parent->IsKindOf(CLASSINFO(wxScrolledWindow)))
335 return (wxScrolledWindow*) parent;
336 parent = parent->GetParent();
337 }
338 return NULL;
339 }
340
341 void wxRemotelyScrolledTreeCtrl::OnScroll(wxScrollWinEvent& event)
342 {
343 int orient = event.GetOrientation();
344 if (orient == wxHORIZONTAL)
345 {
346 event.Skip();
347 return;
348 }
349 wxScrolledWindow* scrollWin = GetScrolledWindow();
350 if (!scrollWin)
351 return;
352
353 int x, y;
354 scrollWin->GetViewStart(& x, & y);
355
356 ScrollToLine(-1, y);
357 }
358
359 /*
360 * wxTreeCompanionWindow
361 *
362 * A window displaying values associated with tree control items.
363 */
364
365 IMPLEMENT_CLASS(wxTreeCompanionWindow, wxWindow)
366
367 BEGIN_EVENT_TABLE(wxTreeCompanionWindow, wxWindow)
368 EVT_PAINT(wxTreeCompanionWindow::OnPaint)
369 EVT_SCROLLWIN(wxTreeCompanionWindow::OnScroll)
370 EVT_TREE_ITEM_EXPANDED(-1, wxTreeCompanionWindow::OnExpand)
371 EVT_TREE_ITEM_COLLAPSED(-1, wxTreeCompanionWindow::OnExpand)
372 END_EVENT_TABLE()
373
374 wxTreeCompanionWindow::wxTreeCompanionWindow(wxWindow* parent, wxWindowID id,
375 const wxPoint& pos,
376 const wxSize& sz,
377 long style):
378 wxWindow(parent, id, pos, sz, style)
379 {
380 m_treeCtrl = NULL;
381 }
382
383 void wxTreeCompanionWindow::DrawItem(wxDC& dc, wxTreeItemId id, const wxRect& rect)
384 {
385 // TEST CODE
386 #if 1
387 if (m_treeCtrl)
388 {
389 wxString text = m_treeCtrl->GetItemText(id);
390 dc.SetTextForeground(* wxBLACK);
391 dc.SetBackgroundMode(wxTRANSPARENT);
392
393 int textW, textH;
394 dc.GetTextExtent(text, & textW, & textH);
395
396 int x = 5;
397 int y = rect.GetY() + wxMax(0, (rect.GetHeight() - textH) / 2);
398
399 dc.DrawText(text, x, y);
400 }
401 #endif
402 }
403
404 void wxTreeCompanionWindow::OnPaint(wxPaintEvent& event)
405 {
406 wxPaintDC dc(this);
407
408 if (!m_treeCtrl)
409 return;
410
411 wxPen pen(wxColour(_T("BLACK")), 1, wxSOLID);
412 dc.SetPen(pen);
413 dc.SetBrush(* wxTRANSPARENT_BRUSH);
414 wxFont font(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
415 dc.SetFont(font);
416
417 wxSize clientSize = GetClientSize();
418 wxRect itemRect;
419 int cy=0;
420 wxTreeItemId h, lastH;
421 for(h=m_treeCtrl->GetFirstVisibleItem();h;h=m_treeCtrl->GetNextVisible(h))
422 {
423 if (m_treeCtrl->GetBoundingRect(h, itemRect))
424 {
425 cy = itemRect.GetTop();
426 wxRect drawItemRect(0, cy, clientSize.x, itemRect.GetHeight());
427
428 lastH = h;
429
430 // Draw the actual item
431 DrawItem(dc, h, drawItemRect);
432 dc.DrawLine(0, cy, clientSize.x, cy);
433 }
434 }
435 if (lastH.IsOk() && m_treeCtrl->GetBoundingRect(lastH, itemRect))
436 {
437 cy = itemRect.GetBottom();
438 dc.DrawLine(0, cy, clientSize.x, cy);
439 }
440 }
441
442 void wxTreeCompanionWindow::OnScroll(wxScrollWinEvent& event)
443 {
444 int orient = event.GetOrientation();
445 if (orient == wxHORIZONTAL)
446 {
447 event.Skip();
448 return;
449 }
450 if (!m_treeCtrl)
451 return;
452
453 // TODO: scroll the window physically instead of just refreshing.
454 Refresh(TRUE);
455 }
456
457 void wxTreeCompanionWindow::OnExpand(wxTreeEvent& event)
458 {
459 // TODO: something more optimized than simply refresh the whole
460 // window when the tree is expanded/collapsed. Tricky.
461 Refresh();
462 }
463
464 /*
465 * wxThinSplitterWindow
466 */
467
468 IMPLEMENT_CLASS(wxThinSplitterWindow, wxSplitterWindow)
469
470 BEGIN_EVENT_TABLE(wxThinSplitterWindow, wxSplitterWindow)
471 EVT_SIZE(wxThinSplitterWindow::OnSize)
472 END_EVENT_TABLE()
473
474 wxThinSplitterWindow::wxThinSplitterWindow(wxWindow* parent, wxWindowID id,
475 const wxPoint& pos,
476 const wxSize& sz,
477 long style):
478 wxSplitterWindow(parent, id, pos, sz, style)
479 {
480 }
481
482 void wxThinSplitterWindow::SizeWindows()
483 {
484 // The client size may have changed inbetween
485 // the sizing of the first window and the sizing of
486 // the second. So repeat SizeWindows.
487 wxSplitterWindow::SizeWindows();
488 wxSplitterWindow::SizeWindows();
489 }
490
491 // Tests for x, y over sash
492 bool wxThinSplitterWindow::SashHitTest(int x, int y, int tolerance)
493 {
494 return wxSplitterWindow::SashHitTest(x, y, 4);
495 }
496
497 void wxThinSplitterWindow::DrawSash(wxDC& dc)
498 {
499 if ( m_sashPosition == 0 || !m_windowTwo)
500 return;
501 if (GetWindowStyle() & wxSP_NOSASH)
502 return;
503
504 int w, h;
505 GetClientSize(&w, &h);
506
507 if ( m_splitMode == wxSPLIT_VERTICAL )
508 {
509 dc.SetPen(* m_facePen);
510 dc.SetBrush(* m_faceBrush);
511 int h1 = h-1;
512 int y1 = 0;
513 if ( (GetWindowStyleFlag() & wxSP_BORDER) != wxSP_BORDER && (GetWindowStyleFlag() & wxSP_3DBORDER) != wxSP_3DBORDER )
514 h1 += 1; // Not sure why this is necessary...
515 if ( (GetWindowStyleFlag() & wxSP_3DBORDER) == wxSP_3DBORDER)
516 {
517 y1 = 2; h1 -= 3;
518 }
519 dc.DrawRectangle(m_sashPosition, y1, m_sashSize, h1);
520 }
521 else
522 {
523 dc.SetPen(* m_facePen);
524 dc.SetBrush(* m_faceBrush);
525 int w1 = w-1;
526 int x1 = 0;
527 if ( (GetWindowStyleFlag() & wxSP_BORDER) != wxSP_BORDER && (GetWindowStyleFlag() & wxSP_3DBORDER) != wxSP_3DBORDER )
528 w1 ++;
529 if ( (GetWindowStyleFlag() & wxSP_3DBORDER) == wxSP_3DBORDER)
530 {
531 x1 = 2; w1 -= 3;
532 }
533 dc.DrawRectangle(x1, m_sashPosition, w1, m_sashSize);
534 }
535
536 dc.SetPen(wxNullPen);
537 dc.SetBrush(wxNullBrush);
538 }
539
540 void wxThinSplitterWindow::OnSize(wxSizeEvent& event)
541 {
542 wxSplitterWindow::OnSize(event);
543 }
544
545 /*
546 * wxSplitterScrolledWindow
547 */
548
549 IMPLEMENT_CLASS(wxSplitterScrolledWindow, wxScrolledWindow)
550
551 BEGIN_EVENT_TABLE(wxSplitterScrolledWindow, wxScrolledWindow)
552 EVT_SCROLLWIN(wxSplitterScrolledWindow::OnScroll)
553 EVT_SIZE(wxSplitterScrolledWindow::OnSize)
554 END_EVENT_TABLE()
555
556 wxSplitterScrolledWindow::wxSplitterScrolledWindow(wxWindow* parent, wxWindowID id,
557 const wxPoint& pos,
558 const wxSize& sz,
559 long style):
560 wxScrolledWindow(parent, id, pos, sz, style)
561 {
562 }
563
564 void wxSplitterScrolledWindow::OnSize(wxSizeEvent& event)
565 {
566 wxSize sz = GetClientSize();
567 if (GetChildren().First())
568 {
569 ((wxWindow*) GetChildren().First()->Data())->SetSize(0, 0, sz.x, sz.y);
570 }
571 }
572
573 void wxSplitterScrolledWindow::OnScroll(wxScrollWinEvent& event)
574 {
575 // Ensure that events being propagated back up the window hierarchy
576 // don't cause an infinite loop
577 static bool inOnScroll = FALSE;
578 if (inOnScroll)
579 return;
580 inOnScroll = TRUE;
581
582 int orient = event.GetOrientation();
583
584 int nScrollInc = 16;// FIXME CalcScrollInc(event);
585 if (nScrollInc == 0)
586 {
587 inOnScroll = FALSE;
588 return;
589 }
590
591 if (orient == wxHORIZONTAL)
592 {
593 inOnScroll = FALSE;
594 event.Skip();
595 return;
596 #if 0
597 int newPos = m_xScrollPosition + nScrollInc;
598 SetScrollPos(wxHORIZONTAL, newPos, TRUE );
599 #endif
600 }
601 else
602 {
603 int newPos = m_yScrollPosition + nScrollInc;
604 SetScrollPos(wxVERTICAL, newPos, TRUE );
605 }
606
607 if (orient == wxHORIZONTAL)
608 {
609 m_xScrollPosition += nScrollInc;
610 }
611 else
612 {
613 m_yScrollPosition += nScrollInc;
614 }
615
616 // Find targets in splitter window and send the event to them
617 wxNode* node = GetChildren().First();
618 while (node)
619 {
620 wxWindow* child = (wxWindow*) node->Data();
621 if (child->IsKindOf(CLASSINFO(wxSplitterWindow)))
622 {
623 wxSplitterWindow* splitter = (wxSplitterWindow*) child;
624 if (splitter->GetWindow1())
625 splitter->GetWindow1()->ProcessEvent(event);
626 if (splitter->GetWindow2())
627 splitter->GetWindow2()->ProcessEvent(event);
628 break;
629 }
630 node = node->Next();
631 }
632
633 #ifdef __WXMAC__
634 m_targetWindow->MacUpdateImmediately() ;
635 #endif
636
637 inOnScroll = FALSE;
638 }
639