]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
*DO* use wxTR_EDIT_LABELS, it is neccessary
[wxWidgets.git] / src / generic / treectlg.cpp
index a4db0ea4fa1f2034f73c1ec6bef17722e8859a15..ce148cd3012e029e15cb4d491a1a3697faa89450 100644 (file)
@@ -55,6 +55,54 @@ static const int NO_IMAGE = -1;
 
 #define PIXELS_PER_UNIT 10
 
+// ----------------------------------------------------------------------------
+// Aqua arrows
+// ----------------------------------------------------------------------------
+
+/* XPM */
+static const char *aqua_arrow_right[] = {
+/* columns rows colors chars-per-pixel */
+"13 11 4 1",
+"  c None",
+"b c #C0C0C0",
+"c c #707070",
+"d c #A0A0A0",
+/* pixels */
+"    b        ",
+"    ddb      ",
+"    cccdb    ",
+"    cccccd   ",
+"    ccccccdb ",
+"    ccccccccd",
+"    ccccccdb ",
+"    cccccb   ",
+"    cccdb    ",
+"    ddb      ",
+"    b        "
+};
+
+/* XPM */
+static const char *aqua_arrow_down[] = {
+/* columns rows colors chars-per-pixel */
+"13 11 4 1",
+"  c None",
+"b c #C0C0C0",
+"c c #707070",
+"d c #A0A0A0",
+/* pixels */
+"             ",
+"             ",
+" bdcccccccdb ",
+"  dcccccccd  ",
+"  bcccccccb  ",
+"   dcccccd   ",
+"   bcccccb   ",
+"    bcccd    ",
+"     dcd     ",
+"     bcb     ",
+"      d      "
+};
+
 // -----------------------------------------------------------------------------
 // private classes
 // -----------------------------------------------------------------------------
@@ -96,6 +144,7 @@ private:
     wxString           *m_res;
     wxGenericTreeCtrl  *m_owner;
     wxString            m_startValue;
+    bool                m_finished;
 
     DECLARE_EVENT_TABLE()
 };
@@ -108,7 +157,6 @@ public:
     wxGenericTreeItem() { m_data = NULL; }
     wxGenericTreeItem( wxGenericTreeItem *parent,
                        const wxString& text,
-                       wxDC& dc,
                        int image,
                        int selImage,
                        wxTreeItemData *data );
@@ -305,22 +353,25 @@ wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
     (*m_accept) = FALSE;
     (*m_res) = wxEmptyString;
     m_startValue = value;
+    m_finished = FALSE;
 }
 
 void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
 {
-    // TODO focus doesn't return to the wxTextCtrl when this closes...
     if (event.m_keyCode == WXK_RETURN)
     {
         (*m_accept) = TRUE;
         (*m_res) = GetValue();
 
-        if ((*m_accept) && ((*m_res) != m_startValue))
+        if ((*m_res) != m_startValue)
             m_owner->OnRenameAccept();
 
         if (!wxPendingDelete.Member(this))
             wxPendingDelete.Append(this);
 
+        m_finished = TRUE;
+        m_owner->SetFocus(); // This doesn't work. TODO.
+
         return;
     }
     if (event.m_keyCode == WXK_ESCAPE)
@@ -331,6 +382,9 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
         if (!wxPendingDelete.Member(this))
             wxPendingDelete.Append(this);
 
+        m_finished = TRUE;
+        m_owner->SetFocus(); // This doesn't work. TODO.
+
         return;
     }
     event.Skip();
@@ -338,12 +392,18 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
 
 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
 {
+    if (m_finished)
+    {
+        event.Skip();
+        return;
+    }
+
     // auto-grow the textctrl:
     wxSize parentSize = m_owner->GetSize();
     wxPoint myPos = GetPosition();
     wxSize mySize = GetSize();
     int sx, sy;
-    GetTextExtent(GetValue() + _T("MM"), &sx, &sy);
+    GetTextExtent(GetValue() + _T("M"), &sx, &sy);
     if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
     if (mySize.x > sx) sx = mySize.x;
     SetSize(sx, -1);
@@ -351,29 +411,23 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
     event.Skip();
 }
 
-void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
+void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
 {
+    if (m_finished)
+    {
+        event.Skip();
+        return;
+    }
+
     if (!wxPendingDelete.Member(this))
         wxPendingDelete.Append(this);
 
-    if ((*m_accept) && ((*m_res) != m_startValue))
-        m_owner->OnRenameAccept();
-}
-
-#if 0
-// -----------------------------------------------------------------------------
-// wxTreeEvent
-// -----------------------------------------------------------------------------
-
-IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
+    (*m_accept) = TRUE;
+    (*m_res) = GetValue();
 
-wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
-           : wxNotifyEvent( commandType, id )
-{
-    m_code = 0;
-    m_itemOld = (wxGenericTreeItem *)NULL;
+    if ((*m_res) != m_startValue)
+        m_owner->OnRenameAccept();
 }
-#endif
 
 // -----------------------------------------------------------------------------
 // wxGenericTreeItem
@@ -381,7 +435,6 @@ wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
 
 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
                                      const wxString& text,
-                                     wxDC& WXUNUSED(dc),
                                      int image, int selImage,
                                      wxTreeItemData *data)
                  : m_text(text)
@@ -614,9 +667,23 @@ void wxGenericTreeCtrl::Init()
     m_indent = 15;
     m_spacing = 18;
 
-    m_hilightBrush = new wxBrush(
-               wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT),
-               wxSOLID);
+    m_hilightBrush = new wxBrush
+                         (
+                            wxSystemSettings::GetColour
+                            (
+                                wxSYS_COLOUR_HIGHLIGHT
+                            ),
+                            wxSOLID
+                         );
+
+    m_hilightUnfocusedBrush = new wxBrush
+                              (
+                                 wxSystemSettings::GetColour
+                                 (
+                                     wxSYS_COLOUR_BTNSHADOW
+                                 ),
+                                 wxSOLID
+                              );
 
     m_imageListNormal = m_imageListButtons =
     m_imageListState = (wxImageList *) NULL;
@@ -630,7 +697,7 @@ void wxGenericTreeCtrl::Init()
     m_renameTimer = new wxTreeRenameTimer( this );
     m_lastOnSame = FALSE;
 
-    m_normalFont = wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT );
+    m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
     m_boldFont = wxFont( m_normalFont.GetPointSize(),
                          m_normalFont.GetFamily(),
                          m_normalFont.GetStyle(),
@@ -646,12 +713,37 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
                                const wxValidator &validator,
                                const wxString& name )
 {
+#ifdef __WXMAC__
+    int major,minor;
+    wxGetOsVersion( &major, &minor );
+
+    if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
+    if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
+    style &= ~wxTR_LINES_AT_ROOT;
+    style |= wxTR_NO_LINES;
+    if (major < 10)
+        style |= wxTR_ROW_LINES;
+    if (major >= 10)
+        style |= wxTR_AQUA_BUTTONS;
+#endif
+
+    if (style & wxTR_AQUA_BUTTONS)
+    {
+        m_arrowRight = new wxBitmap( aqua_arrow_right );
+        m_arrowDown = new wxBitmap( aqua_arrow_down );
+    }
+    else
+    {
+        m_arrowRight = NULL;
+        m_arrowDown = NULL;
+    }
+
     wxScrolledWindow::Create( parent, id, pos, size,
                               style|wxHSCROLL|wxVSCROLL, name );
 
-        // If the tree display has no buttons, but does have
-        // connecting lines, we can use a narrower layout.
-        // It may not be a good idea to force this...
+    // If the tree display has no buttons, but does have
+    // connecting lines, we can use a narrower layout.
+    // It may not be a good idea to force this...
     if (!HasButtons() && !HasFlag(wxTR_NO_LINES))
     {
         m_indent= 10;
@@ -662,17 +754,22 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
     SetValidator( validator );
 #endif
 
-    SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
+    SetForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
+    SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX) );
 
 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86
-    m_dottedPen = wxPen( "grey", 0, 0 );
+    m_dottedPen = wxPen( wxT("grey"), 0, 0 );
 
     return TRUE;
 }
 
 wxGenericTreeCtrl::~wxGenericTreeCtrl()
 {
-    wxDELETE( m_hilightBrush );
+    delete m_hilightBrush;
+    delete m_hilightUnfocusedBrush;
+
+    if (m_arrowRight) delete m_arrowRight;
+    if (m_arrowDown) delete m_arrowDown;
 
     DeleteAllItems();
 
@@ -693,13 +790,13 @@ size_t wxGenericTreeCtrl::GetCount() const
 
 void wxGenericTreeCtrl::SetIndent(unsigned int indent)
 {
-    m_indent = indent;
+    m_indent = (unsigned short) indent;
     m_dirty = TRUE;
 }
 
 void wxGenericTreeCtrl::SetSpacing(unsigned int spacing)
 {
-    m_spacing = spacing;
+    m_spacing = (unsigned short) spacing;
     m_dirty = TRUE;
 }
 
@@ -883,7 +980,12 @@ bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
 
-    return !((wxGenericTreeItem*) item.m_pItem)->GetChildren().IsEmpty();
+    // consider that the item does have children if it has the "+" button: it
+    // might not have them (if it had never been expanded yet) but then it
+    // could have them as well and it's better to err on this side rather than
+    // disabling some operations which are restricted to the items with
+    // children for an item which does have them
+    return ((wxGenericTreeItem*) item.m_pItem)->HasPlus();
 }
 
 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const
@@ -1017,15 +1119,6 @@ wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const
     }
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetPrev(const wxTreeItemId& item) const
-{
-    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
-
-    wxFAIL_MSG(wxT("not implemented"));
-
-    return wxTreeItemId();
-}
-
 wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
 {
     wxTreeItemId id = GetRootItem();
@@ -1086,9 +1179,8 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
 
     m_dirty = TRUE;     // do this first so stuff below doesn't cause flicker
 
-    wxClientDC dc(this);
     wxGenericTreeItem *item =
-        new wxGenericTreeItem( parent, text, dc, image, selImage, data );
+        new wxGenericTreeItem( parent, text, image, selImage, data );
 
     if ( data != NULL )
     {
@@ -1108,9 +1200,13 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
 
     m_dirty = TRUE;     // do this first so stuff below doesn't cause flicker
 
-    wxClientDC dc(this);
-    m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
+    m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text,
                                    image, selImage, data);
+    if ( data != NULL )
+    {
+        data->m_pItem = (long) m_anchor;
+    }
+
     if (HasFlag(wxTR_HIDE_ROOT))
     {
         // if root is hidden, make sure we can navigate
@@ -1118,10 +1214,6 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
         m_anchor->SetHasPlus();
         Expand(m_anchor);
     }
-    if ( data != NULL )
-    {
-        data->m_pItem = (long) m_anchor;
-    }
 
     if (!HasFlag(wxTR_MULTIPLE))
     {
@@ -1387,7 +1479,13 @@ void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
 
 void wxGenericTreeCtrl::UnselectAll()
 {
-    UnselectAllChildren((wxGenericTreeItem*) GetRootItem().m_pItem);
+    wxTreeItemId rootItem = GetRootItem();
+
+    // the tree might not have the root item at all
+    if ( rootItem )
+    {
+        UnselectAllChildren((wxGenericTreeItem*) rootItem.m_pItem);
+    }
 }
 
 // Recursive function !
@@ -1838,10 +1936,9 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 
     int total_h = GetLineHeight(item);
 
-    bool paintBg = item->IsSelected() && m_hasFocus;
-    if ( paintBg )
+    if ( item->IsSelected() )
     {
-        dc.SetBrush(*m_hilightBrush);
+        dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush));
     }
     else
     {
@@ -1855,18 +1952,29 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 
     int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
 
-    if ( item->IsSelected() && image != NO_IMAGE)
+    if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT) )
     {
-        // If it's selected, and there's an image, then we should
-        // take care to leave the area under the image painted in the
-        // background colour.
-        dc.DrawRectangle( item->GetX() + image_w - 2, item->GetY()+offset,
-                          item->GetWidth() - image_w + 2, total_h-offset );
+        int x, y, w, h;
+
+        DoGetPosition(&x, &y);
+        DoGetSize(&w, &h);
+        dc.DrawRectangle(x, item->GetY()+offset, w, total_h-offset);
     }
     else
     {
-        dc.DrawRectangle( item->GetX()-2, item->GetY()+offset,
-                          item->GetWidth()+2, total_h-offset );
+        if ( item->IsSelected() && image != NO_IMAGE )
+        {
+            // If it's selected, and there's an image, then we should
+            // take care to leave the area under the image painted in the
+            // background colour.
+            dc.DrawRectangle( item->GetX() + image_w - 2, item->GetY()+offset,
+                              item->GetWidth() - image_w + 2, total_h-offset );
+        }
+        else
+        {
+            dc.DrawRectangle( item->GetX()-2, item->GetY()+offset,
+                              item->GetWidth()+2, total_h-offset );
+        }
     }
 
     if ( image != NO_IMAGE )
@@ -1899,10 +2007,26 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
     }
     else if (level == 0)
     {
+        // always expand hidden root
+        int origY = y;
         wxArrayGenericTreeItems& children = item->GetChildren();
-        size_t n, count = children.Count();
-        for (n = 0; n < count; ++n)
-            PaintLevel(children[n], dc, 1, y);
+        int count = children.Count();
+        if (count > 0)
+        {
+            int n = 0, oldY;
+            do {
+                oldY = y;
+                PaintLevel(children[n], dc, 1, y);
+            } while (++n < count);
+
+            if (!HasFlag(wxTR_NO_LINES) && HasFlag(wxTR_LINES_AT_ROOT) && count > 0)
+            {
+                // draw line down to last child
+                origY += GetLineHeight(children[0])>>1;
+                oldY += GetLineHeight(children[n-1])>>1;
+                dc.DrawLine(3, origY, 3, oldY);
+            }
+        }
         return;
     }
 
@@ -1919,22 +2043,68 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
 
     if (IsExposed(exposed_x, exposed_y, 10000, h))  // 10000 = very much
     {
+        wxPen *pen =
+#ifndef __WXMAC__
+            // don't draw rect outline if we already have the
+            // background color under Mac
+            (item->IsSelected() && m_hasFocus) ? wxBLACK_PEN :
+#endif // !__WXMAC__
+            wxTRANSPARENT_PEN;
+
+        wxColour colText;
+        if ( item->IsSelected() )
+        {
+            colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+        }
+        else
+        {
+            wxTreeItemAttr *attr = item->GetAttributes();
+            if (attr && attr->HasTextColour())
+                colText = attr->GetTextColour();
+            else
+                colText = GetForegroundColour();
+        }
+
+        // prepare to draw
+        dc.SetTextForeground(colText);
+        dc.SetPen(*pen);
+
+        // draw
+        PaintItem(item, dc);
+
+        if (HasFlag(wxTR_ROW_LINES))
+        {
+            // if the background colour is white, choose a
+            // contrasting color for the lines
+            dc.SetPen(*((GetBackgroundColour() == *wxWHITE)
+                         ? wxMEDIUM_GREY_PEN : wxWHITE_PEN));
+            dc.DrawLine(0, y_top, 10000, y_top);
+            dc.DrawLine(0, y, 10000, y);
+        }
+
+        // restore DC objects
+        dc.SetBrush(*wxWHITE_BRUSH);
+        dc.SetPen(m_dottedPen);
+        dc.SetTextForeground(*wxBLACK);
+
         if (item->HasPlus() && HasButtons())  // should the item show a button?
         {
             if (!HasFlag(wxTR_NO_LINES))
             {
-                if (x > (signed)m_indent || HasFlag(wxTR_LINES_AT_ROOT))
+                if (x > (signed)m_indent)
                     dc.DrawLine(x - m_indent, y_mid, x - 5, y_mid);
+                else if (HasFlag(wxTR_LINES_AT_ROOT))
+                    dc.DrawLine(3, y_mid, x - 5, y_mid);
                 dc.DrawLine(x + 5, y_mid, x + m_spacing, y_mid);
             }
 
             if (m_imageListButtons != NULL)
             {
                 // draw the image button here
-                int image_h = 0, image_w = 0, image = wxCLOSED_BUTTON;
-                if (item->IsExpanded()) image = wxOPEN_BUTTON;
+                int image_h = 0, image_w = 0, image = wxTreeItemIcon_Normal;
+                if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
                 if (item->IsSelected())
-                    image += wxOPEN_BUTTON_SELECTED - wxOPEN_BUTTON;
+                    image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
                 m_imageListButtons->GetSize(image, image_w, image_h);
                 int xx = x - (image_w>>1);
                 int yy = y_mid - (image_h>>1);
@@ -1946,32 +2116,41 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
             else if (HasFlag(wxTR_TWIST_BUTTONS))
             {
                 // draw the twisty button here
-                dc.SetPen(*wxBLACK_PEN);
-                dc.SetBrush(*m_hilightBrush);
-
-                wxPoint button[3];
 
-                if (item->IsExpanded())
+                if (HasFlag(wxTR_AQUA_BUTTONS))
                 {
-                    button[0].x = x-5;
-                    button[0].y = y_mid-2;
-                    button[1].x = x+5;
-                    button[1].y = y_mid-2;
-                    button[2].x = x;
-                    button[2].y = y_mid+3;
+                    if (item->IsExpanded())
+                        dc.DrawBitmap( *m_arrowDown, x-5, y_mid-6, TRUE );
+                    else
+                        dc.DrawBitmap( *m_arrowRight, x-5, y_mid-6, TRUE );
                 }
                 else
                 {
-                    button[0].y = y_mid-5;
-                    button[0].x = x-2;
-                    button[1].y = y_mid+5;
-                    button[1].x = x-2;
-                    button[2].y = y_mid;
-                    button[2].x = x+3;
-                }
-                dc.DrawPolygon(3, button);
+                    dc.SetBrush(*m_hilightBrush);
+                    dc.SetPen(*wxBLACK_PEN);
+                    wxPoint button[3];
 
-                dc.SetPen(m_dottedPen);
+                    if (item->IsExpanded())
+                    {
+                        button[0].x = x-5;
+                        button[0].y = y_mid-2;
+                        button[1].x = x+5;
+                        button[1].y = y_mid-2;
+                        button[2].x = x;
+                        button[2].y = y_mid+3;
+                    }
+                    else
+                    {
+                        button[0].y = y_mid-5;
+                        button[0].x = x-2;
+                        button[1].y = y_mid+5;
+                        button[1].x = x-2;
+                        button[2].y = y_mid;
+                        button[2].x = x+3;
+                    }
+                    dc.DrawPolygon(3, button);
+                    dc.SetPen(m_dottedPen);
+                }
             }
             else // if (HasFlag(wxTR_HAS_BUTTONS))
             {
@@ -1990,51 +2169,12 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
         {
             // draw the horizontal line here
             int x_start = x;
-            if (x > (signed)m_indent || HasFlag(wxTR_LINES_AT_ROOT))
+            if (x > (signed)m_indent)
                 x_start -= m_indent;
+            else if (HasFlag(wxTR_LINES_AT_ROOT))
+                x_start = 3;
             dc.DrawLine(x_start, y_mid, x + m_spacing, y_mid);
         }
-
-        wxPen *pen =
-#ifndef __WXMAC__
-            // don't draw rect outline if we already have the
-            // background color under Mac
-            (item->IsSelected()) ? wxBLACK_PEN :
-#endif // !__WXMAC__
-            wxTRANSPARENT_PEN;
-
-        wxColour colText;
-        if (item->IsSelected() && m_hasFocus)
-        {
-            colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
-        }
-        else
-        {
-            wxTreeItemAttr *attr = item->GetAttributes();
-            if (attr && attr->HasTextColour())
-                colText = attr->GetTextColour();
-            else
-                colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
-        }
-
-        // prepare to draw
-        dc.SetTextForeground(colText);
-        dc.SetPen(*pen);
-
-        // draw
-        PaintItem(item, dc);
-
-        if (HasFlag(wxTR_ROW_LINES))
-        {
-            dc.SetPen(*wxWHITE_PEN);
-            dc.DrawLine(0, y_top, 10000, y_top);
-            dc.DrawLine(0, y, 10000, y);
-        }
-
-        // restore DC objects
-        dc.SetBrush(*wxWHITE_BRUSH);
-        dc.SetPen(m_dottedPen);
-        dc.SetTextForeground(*wxBLACK);
     }
 
     if (item->IsExpanded())
@@ -2050,10 +2190,10 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
                 PaintLevel(children[n], dc, level, y);
             } while (++n < count);
 
-            if (!HasFlag(wxTR_NO_LINES))
+            if (!HasFlag(wxTR_NO_LINES) && count > 0)
             {
                 // draw line down to last child
-                oldY += GetLineHeight(children[n-1])/2;
+                oldY += GetLineHeight(children[n-1])>>1;
                 if (HasButtons()) y_mid += 5;
                 dc.DrawLine(x, y_mid, x, oldY);
             }
@@ -2146,28 +2286,34 @@ void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
     PaintLevel( m_anchor, dc, 0, y );
 }
 
-void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
+void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &event )
 {
     m_hasFocus = TRUE;
 
-    if (m_current)
-        RefreshLine( m_current );
+    RefreshSelected();
+
+    event.Skip();
 }
 
-void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
+void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event )
 {
     m_hasFocus = FALSE;
 
-    if (m_current)
-        RefreshLine( m_current );
+    RefreshSelected();
+
+    event.Skip();
 }
 
 void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 {
     wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
-    te.m_code = (int)event.KeyCode();
+    te.m_evtKey = event;
     te.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( te );
+    if ( GetEventHandler()->ProcessEvent( te ) )
+    {
+        // intercepted by the user code
+        return;
+    }
 
     if ( (m_current == 0) || (m_key_current == 0) )
     {
@@ -2225,7 +2371,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             {
                 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
                 event.m_item = (long) m_current;
-                event.m_code = 0;
                 event.SetEventObject( this );
                 GetEventHandler()->ProcessEvent( event );
             }
@@ -2398,14 +2543,8 @@ wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
         return wxTreeItemId();
     }
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
-    wxCoord x = dc.DeviceToLogicalX( point.x );
-    wxCoord y = dc.DeviceToLogicalY( point.y );
-    wxGenericTreeItem *hit =  m_anchor->HitTest(wxPoint(x, y),
-                                                this,
-                                                flags,
-                                                0 );
+    wxGenericTreeItem *hit =  m_anchor->HitTest(CalcUnscrolledPosition(point),
+                                                this, flags, 0);
     if (hit == NULL)
     {
         flags = wxTREE_HITTEST_NOWHERE;
@@ -2456,10 +2595,10 @@ void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
     if (m_dirty) wxYieldIfNeeded();
 
     wxString s = m_currentEdit->GetText();
-    int x = m_currentEdit->GetX();
-    int y = m_currentEdit->GetY();
     int w = m_currentEdit->GetWidth();
     int h = m_currentEdit->GetHeight();
+    int x, y;
+    CalcScrolledPosition(m_currentEdit->GetX(), m_currentEdit->GetY(), &x, &y);
 
     int image_h = 0;
     int image_w = 0;
@@ -2480,11 +2619,6 @@ void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
     x += image_w;
     w -= image_w + 4; // I don't know why +4 is needed
 
-    wxClientDC dc(this);
-    PrepareDC( dc );
-    x = dc.LogicalToDeviceX( x );
-    y = dc.LogicalToDeviceY( y );
-
     wxTreeTextCtrl *text = new wxTreeTextCtrl(this, -1,
                                               &m_renameAccept,
                                               &m_renameRes,
@@ -2533,21 +2667,15 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         return;
     }
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
-    wxCoord x = dc.DeviceToLogicalX( event.GetX() );
-    wxCoord y = dc.DeviceToLogicalY( event.GetY() );
+    wxPoint pt = CalcUnscrolledPosition(event.GetPosition());
 
     int flags = 0;
-    wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y),
-                                                 this,
-                                                 flags,
-                                                 0 );
+    wxGenericTreeItem *item = m_anchor->HitTest(pt, this, flags, 0);
 
     if ( event.Dragging() && !m_isDragging )
     {
         if (m_dragCount == 0)
-            m_dragStart = wxPoint(x,y);
+            m_dragStart = pt;
 
         m_dragCount++;
 
@@ -2624,7 +2752,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
 
         event.m_item = (long) item;
-        event.m_pointDrag = wxPoint(x, y);
+        event.m_pointDrag = pt;
         event.SetEventObject(this);
 
         (void)GetEventHandler()->ProcessEvent(event);
@@ -2650,10 +2778,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         {
             wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
             nevent.m_item = (long) item;
-            nevent.m_code = 0;
-            CalcScrolledPosition(x, y,
-                                 &nevent.m_pointDrag.x,
-                                 &nevent.m_pointDrag.y);
+            nevent.m_pointDrag = CalcScrolledPosition(pt);
             nevent.SetEventObject(this);
             GetEventHandler()->ProcessEvent(nevent);
         }
@@ -2711,23 +2836,20 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                 m_renameTimer->Stop();
                 m_lastOnSame = FALSE;
 
-                if (item->HasPlus())
+                // send activate event first
+                wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
+                nevent.m_item = (long) item;
+                nevent.m_pointDrag = CalcScrolledPosition(pt);
+                nevent.SetEventObject( this );
+                if ( !GetEventHandler()->ProcessEvent( nevent ) )
                 {
-                    // for a "directory" node, toggle expansion
-                    Toggle(item);
-                }
-                else
-                {
-                    // for a "file" node, activate it
-                    wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
-                                        GetId() );
-                    nevent.m_item = (long) item;
-                    nevent.m_code = 0;
-                    CalcScrolledPosition(x, y,
-                                         &nevent.m_pointDrag.x,
-                                         &nevent.m_pointDrag.y);
-                    nevent.SetEventObject( this );
-                    GetEventHandler()->ProcessEvent( nevent );
+                    // if the user code didn't process the activate event,
+                    // handle it ourselves by toggling the item when it is
+                    // double clicked
+                    if ( item->HasPlus() )
+                    {
+                        Toggle(item);
+                    }
                 }
             }
         }
@@ -2753,7 +2875,10 @@ void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
     wxCoord text_w = 0;
     wxCoord text_h = 0;
 
-    if (item->IsBold())
+    wxTreeItemAttr *attr = item->GetAttributes();
+    if ( attr && attr->HasFont() )
+        dc.SetFont(attr->GetFont());
+    else if ( item->IsBold() )
         dc.SetFont(m_boldFont);
 
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
@@ -2847,20 +2972,14 @@ void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 {
     if (m_dirty) return;
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
-
-    int cw = 0;
-    int ch = 0;
-    GetClientSize( &cw, &ch );
+    wxSize client = GetClientSize();
 
     wxRect rect;
-    rect.x = dc.LogicalToDeviceX( 0 );
-    rect.width = cw;
-    rect.y = dc.LogicalToDeviceY( item->GetY() );
-    rect.height = ch;
+    CalcScrolledPosition(0, item->GetY(), &rect.x, &rect.y);
+    rect.width = client.x;
+    rect.height = client.y;
 
-    Refresh( TRUE, &rect );
+    Refresh(TRUE, &rect);
 
     AdjustMyScrollbars();
 }
@@ -2869,20 +2988,57 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 {
     if (m_dirty) return;
 
-    wxClientDC dc(this);
-    PrepareDC( dc );
-
-    int cw = 0;
-    int ch = 0;
-    GetClientSize( &cw, &ch );
-
     wxRect rect;
-    rect.x = dc.LogicalToDeviceX( 0 );
-    rect.y = dc.LogicalToDeviceY( item->GetY() );
-    rect.width = cw;
+    CalcScrolledPosition(0, item->GetY(), &rect.x, &rect.y);
+    rect.width = GetClientSize().x;
     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
 
-    Refresh( TRUE, &rect );
+    Refresh(TRUE, &rect);
+}
+
+void wxGenericTreeCtrl::RefreshSelected()
+{
+    // TODO: this is awfully inefficient, we should keep the list of all
+    //       selected items internally, should be much faster
+    if ( m_anchor )
+        RefreshSelectedUnder(m_anchor);
+}
+
+void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
+{
+    if ( item->IsSelected() )
+        RefreshLine(item);
+
+    const wxArrayGenericTreeItems& children = item->GetChildren();
+    size_t count = children.GetCount();
+    for ( size_t n = 0; n < count; n++ )
+    {
+        RefreshSelectedUnder(children[n]);
+    }
+}
+
+// ----------------------------------------------------------------------------
+// changing colours: we need to refresh the tree control
+// ----------------------------------------------------------------------------
+
+bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour)
+{
+    if ( !wxWindow::SetBackgroundColour(colour) )
+        return FALSE;
+
+    Refresh();
+
+    return TRUE;
+}
+
+bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
+{
+    if ( !wxWindow::SetForegroundColour(colour) )
+        return FALSE;
+
+    Refresh();
+
+    return TRUE;
 }
 
 #endif // wxUSE_TREECTRL