X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/57591e0edb8cbaa2b12e4a0da68fe445fa636747..0cd7d9b2355834dfabd0faeab0c5e812ebc3905a:/src/generic/treectlg.cpp diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index 7d9ea69e54..113dbba584 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -25,9 +25,11 @@ #include "wx/wxprec.h" #ifdef __BORLANDC__ -#pragma hdrstop + #pragma hdrstop #endif +#if wxUSE_TREECTRL + #include "wx/generic/treectlg.h" #include "wx/imaglist.h" #include "wx/settings.h" @@ -44,7 +46,7 @@ class WXDLLEXPORT wxGenericTreeItem; -WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems); +WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems); //WX_DEFINE_OBJARRAY(wxArrayTreeItemIds); // ---------------------------------------------------------------------------- @@ -89,6 +91,7 @@ public: const wxString &name = wxTextCtrlNameStr ); void OnChar( wxKeyEvent &event ); + void OnKeyUp( wxKeyEvent &event ); void OnKillFocus( wxFocusEvent &event ); private: @@ -178,10 +181,10 @@ public: // status inquiries bool HasChildren() const { return !m_children.IsEmpty(); } - bool IsSelected() const { return m_hasHilight; } + bool IsSelected() const { return m_hasHilight != 0; } bool IsExpanded() const { return !m_isCollapsed; } bool HasPlus() const { return m_hasPlus || HasChildren(); } - bool IsBold() const { return m_isBold; } + bool IsBold() const { return m_isBold != 0; } // attributes // get them - may be NULL @@ -266,6 +269,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxTreeTextCtrl,wxTextCtrl); BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl) EVT_CHAR (wxTreeTextCtrl::OnChar) + EVT_KEY_UP (wxTreeTextCtrl::OnKeyUp) EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus) END_EVENT_TABLE() @@ -296,28 +300,43 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) { (*m_accept) = TRUE; (*m_res) = GetValue(); - + if (!wxPendingDelete.Member(this)) wxPendingDelete.Append(this); if ((*m_accept) && ((*m_res) != m_startValue)) m_owner->OnRenameAccept(); - + return; } if (event.m_keyCode == WXK_ESCAPE) { (*m_accept) = FALSE; (*m_res) = ""; - + if (!wxPendingDelete.Member(this)) wxPendingDelete.Append(this); - + return; } event.Skip(); } +void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) +{ + // auto-grow the textctrl: + wxSize parentSize = m_owner->GetSize(); + wxPoint myPos = GetPosition(); + wxSize mySize = GetSize(); + int sx, sy; + GetTextExtent(GetValue() + _T("MM"), &sx, &sy); + if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x; + if (mySize.x > sx) sx = mySize.x; + SetSize(sx, -1); + + event.Skip(); +} + void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) { if (!wxPendingDelete.Member(this)) @@ -615,6 +634,8 @@ void wxGenericTreeCtrl::Init() m_imageListNormal = m_imageListState = (wxImageList *) NULL; + m_ownsImageListNormal = + m_ownsImageListState = FALSE; m_dragCount = 0; m_isDragging = FALSE; @@ -645,6 +666,7 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent, wxWindowID id, #endif SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) ); + // m_dottedPen = wxPen( "grey", 0, wxDOT ); too slow under XFree86 m_dottedPen = wxPen( "grey", 0, 0 ); @@ -658,6 +680,8 @@ wxGenericTreeCtrl::~wxGenericTreeCtrl() DeleteAllItems(); delete m_renameTimer; + if (m_ownsImageListNormal) delete m_imageListNormal; + if (m_ownsImageListState) delete m_imageListState; } // ----------------------------------------------------------------------------- @@ -797,6 +821,21 @@ void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font RefreshLine(pItem); } +bool wxGenericTreeCtrl::SetFont( const wxFont &font ) +{ + wxScrolledWindow::SetFont(font); + + m_normalFont = font ; + m_boldFont = wxFont( m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined()); + + return TRUE; +} + + // ----------------------------------------------------------------------------- // item status inquiries // ----------------------------------------------------------------------------- @@ -805,15 +844,15 @@ bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") ); - // An item is only visible if it's not a descendant of a collapsed item + // An item is only visible if it's not a descendant of a collapsed item wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; - wxGenericTreeItem* parent = pItem->GetParent(); - while (parent) - { - if (!parent->IsExpanded()) - return FALSE; - parent = parent->GetParent(); - } + wxGenericTreeItem* parent = pItem->GetParent(); + while (parent) + { + if (!parent->IsExpanded()) + return FALSE; + parent = parent->GetParent(); + } int startX, startY; GetViewStart(& startX, & startY); @@ -823,8 +862,8 @@ bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const wxRect rect; if (!GetBoundingRect(item, rect)) return FALSE; - if (rect.GetWidth() == 0 || rect.GetHeight() == 0) - return FALSE; + if (rect.GetWidth() == 0 || rect.GetHeight() == 0) + return FALSE; if (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y) return FALSE; if (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x) @@ -1003,10 +1042,10 @@ wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const wxTreeItemId id = item; while (id.IsOk()) { - id = GetNext(id); + id = GetNext(id); - if (id.IsOk() && IsVisible(id)) - return id; + if (id.IsOk() && IsVisible(id)) + return id; } return wxTreeItemId(); } @@ -1536,7 +1575,7 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) // We have to call this here because the label in // question might just have been added and no screen // update taken place. - if (m_dirty) wxYield(); + if (m_dirty) wxYieldIfNeeded(); wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem; @@ -1545,7 +1584,7 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) int start_x = 0; int start_y = 0; - ViewStart( &start_x, &start_y ); + GetViewStart( &start_x, &start_y ); start_y *= PIXELS_PER_UNIT; int client_h = 0; @@ -1629,7 +1668,10 @@ wxImageList *wxGenericTreeCtrl::GetStateImageList() const void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) { + if (m_ownsImageListNormal) delete m_imageListNormal; + m_imageListNormal = imageList; + m_ownsImageListNormal = FALSE; if ( !m_imageListNormal ) return; @@ -1656,7 +1698,21 @@ void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList) { + if (m_ownsImageListState) delete m_imageListState; m_imageListState = imageList; + m_ownsImageListState = FALSE; +} + +void wxGenericTreeCtrl::AssignImageList(wxImageList *imageList) +{ + SetImageList(imageList); + m_ownsImageListNormal = TRUE; +} + +void wxGenericTreeCtrl::AssignStateImageList(wxImageList *imageList) +{ + SetStateImageList(imageList); + m_ownsImageListState = TRUE; } // ----------------------------------------------------------------------------- @@ -1732,7 +1788,22 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) dc.SetBrush(wxBrush(colBg, wxSOLID)); } - dc.DrawRectangle( item->GetX()-2, item->GetY(), item->GetWidth()+2, total_h ); + int offset = 0; + if (HasFlag(wxTR_ROW_LINES)) offset = 1; + + 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 ) { @@ -1757,46 +1828,79 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) // Now y stands for the top of the item, whereas it used to stand for middle ! void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y ) { - int horizX = level*m_indent; + int x = (level+1)*m_indent; - item->SetX( horizX+m_indent+m_spacing ); + item->SetX( x+m_spacing ); item->SetY( y ); int oldY = y; y+=GetLineHeight(item)/2; - item->SetCross( horizX+m_indent, y ); + item->SetCross( x, y ); int exposed_x = dc.LogicalToDeviceX( 0 ); int exposed_y = dc.LogicalToDeviceY( item->GetY() ); - bool drawLines = ((GetWindowStyle() & wxTR_NO_LINES) == 0); + bool drawLines = (!HasFlag(wxTR_NO_LINES) && !HasFlag(wxTR_MAC_BUTTONS)); if (IsExposed( exposed_x, exposed_y, 10000, GetLineHeight(item) )) // 10000 = very much { - int startX = horizX; - int endX = horizX + (m_indent-5); + int startX = x - m_indent; + int endX = x-5; -// if (!item->HasChildren()) endX += (m_indent+5); if (!item->HasChildren()) endX += 20; - - if (drawLines) - dc.DrawLine( startX, y, endX, y ); - - if (item->HasPlus()) + + if (HasFlag( wxTR_MAC_BUTTONS )) + { + if (item->HasPlus()) + { + dc.SetPen( *wxBLACK_PEN ); + dc.SetBrush( *m_hilightBrush ); + + wxPoint button[3]; + + if (item->IsExpanded()) + { + button[0].x = x-5; + button[0].y = y-2; + button[1].x = x+5; + button[1].y = y-2; + button[2].x = x; + button[2].y = y+3; + } + else + { + button[0].y = y-5; + button[0].x = x-2; + button[1].y = y+5; + button[1].x = x-2; + button[2].y = y; + button[2].x = x+3; + } + dc.DrawPolygon( 3, button ); + + dc.SetPen( m_dottedPen ); + } + } + else { if (drawLines) - dc.DrawLine( horizX+(m_indent+5), y, horizX+(m_indent+15), y ); - dc.SetPen( *wxGREY_PEN ); - dc.SetBrush( *wxWHITE_BRUSH ); - dc.DrawRectangle( horizX+(m_indent-5), y-4, 11, 9 ); - - dc.SetPen( *wxBLACK_PEN ); - dc.DrawLine( horizX+(m_indent-2), y, horizX+(m_indent+3), y ); - if (!item->IsExpanded()) - dc.DrawLine( horizX+m_indent, y-2, horizX+m_indent, y+3 ); + dc.DrawLine( startX, y, endX, y ); - dc.SetPen( m_dottedPen ); + if (item->HasPlus()) + { + if (drawLines) + dc.DrawLine( x+5, y, x+15, y ); + dc.SetPen( *wxGREY_PEN ); + dc.SetBrush( *wxWHITE_BRUSH ); + dc.DrawRectangle( x-5, y-4, 11, 9 ); + + dc.SetPen( *wxBLACK_PEN ); + dc.DrawLine( x-2, y, x+3, y ); + if (!item->IsExpanded()) + dc.DrawLine( x, y-2, x, y+3 ); + dc.SetPen( m_dottedPen ); + } } wxPen *pen = wxTRANSPARENT_PEN; @@ -1826,6 +1930,13 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level // draw PaintItem(item, dc); + if (HasFlag( wxTR_ROW_LINES )) + { + dc.SetPen( *wxWHITE_PEN ); + dc.DrawLine( 0, oldY, 10000, oldY ); + dc.DrawLine( 0, oldY + GetLineHeight(item), 10000, oldY + GetLineHeight(item) ); + } + // restore DC objects dc.SetBrush( *wxWHITE_BRUSH ); dc.SetPen( m_dottedPen ); @@ -1854,7 +1965,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level { semiOldY+=GetLineHeight(children[--n])/2; if (drawLines) - dc.DrawLine( horizX+m_indent, oldY+5, horizX+m_indent, semiOldY ); + dc.DrawLine( x, oldY+5, x, semiOldY ); } } } @@ -2165,7 +2276,9 @@ wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags) // We have to call this here because the label in // question might just have been added and no screen // update taken place. - if (m_dirty) wxYield(); + // JACS: removed this because the yield can cause the window to be + // deleted from under us if a close window event is pending + // if (m_dirty) wxYieldIfNeeded(); wxClientDC dc(this); PrepareDC(dc); @@ -2180,13 +2293,16 @@ wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags) if (point.y<0) flags|=wxTREE_HITTEST_ABOVE; if (point.y>h) flags|=wxTREE_HITTEST_BELOW; - return m_anchor->HitTest( wxPoint(x, y), this, flags); + if (m_anchor) + return m_anchor->HitTest( wxPoint(x, y), this, flags); + else + return wxTreeItemId(); } // get the bounding rectangle of the item (or of its label only) bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect, - bool textOnly) const + bool WXUNUSED(textOnly)) const { wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); @@ -2196,10 +2312,10 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item, GetViewStart(& startX, & startY); rect.x = i->GetX() - startX*PIXELS_PER_UNIT; - rect.y = i->GetY() - startY*PIXELS_PER_UNIT; + rect.y = i->GetY() - startY*PIXELS_PER_UNIT; rect.width = i->GetWidth(); - //rect.height = i->GetHeight(); - rect.height = GetLineHeight(i); + //rect.height = i->GetHeight(); + rect.height = GetLineHeight(i); return TRUE; } @@ -2222,7 +2338,7 @@ void wxGenericTreeCtrl::Edit( const wxTreeItemId& item ) // We have to call this here because the label in // question might just have been added and no screen // update taken place. - if (m_dirty) wxYield(); + if (m_dirty) wxYieldIfNeeded(); wxString s = m_currentEdit->GetText(); int x = m_currentEdit->GetX(); @@ -2254,8 +2370,13 @@ void wxGenericTreeCtrl::Edit( const wxTreeItemId& item ) x = dc.LogicalToDeviceX( x ); y = dc.LogicalToDeviceY( y ); - wxTreeTextCtrl *text = new wxTreeTextCtrl( - this, -1, &m_renameAccept, &m_renameRes, this, s, wxPoint(x-4,y-4), wxSize(w+11,h+8) ); + wxTreeTextCtrl *text = new wxTreeTextCtrl(this, -1, + &m_renameAccept, + &m_renameRes, + this, + s, + wxPoint(x-4,y-4), + wxSize(w+11,h+8)); text->SetFocus(); } @@ -2365,7 +2486,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) // highlight the current drop target if any DrawDropEffect(m_dropTarget); - wxYield(); + wxYieldIfNeeded(); } } else if ( (event.LeftUp() || event.RightUp()) && m_isDragging ) @@ -2396,7 +2517,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) SetCursor(m_oldCursor); - wxYield(); + wxYieldIfNeeded(); } else { @@ -2411,27 +2532,49 @@ 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.SetEventObject(this); GetEventHandler()->ProcessEvent(nevent); } - else if ( event.LeftUp() && m_lastOnSame ) + else if ( event.LeftUp() ) { - if ( (item == m_current) && - (flags & wxTREE_HITTEST_ONITEMLABEL) && - HasFlag(wxTR_EDIT_LABELS) ) + if ( m_lastOnSame ) { - m_renameTimer->Start( 100, TRUE ); - } + if ( (item == m_current) && + (flags & wxTREE_HITTEST_ONITEMLABEL) && + HasFlag(wxTR_EDIT_LABELS) ) + { + if ( m_renameTimer->IsRunning() ) + m_renameTimer->Stop(); + + m_renameTimer->Start( 100, TRUE ); + } - m_lastOnSame = FALSE; + m_lastOnSame = FALSE; + } } - else + else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick() { if ( event.LeftDown() ) { m_lastOnSame = item == m_current; } + if ( flags & wxTREE_HITTEST_ONITEMBUTTON ) + { + // only toggle the item for a single click, double click on + // the button doesn't do anything (it toggles the item twice) + if ( event.LeftDown() ) + { + Toggle( item ); + } + + // don't select the item if the button was clicked + return; + } + // how should the selection work for this event? bool is_multiple, extended_select, unselect_others; EventFlagsToSelType(GetWindowStyleFlag(), @@ -2439,13 +2582,6 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) event.ControlDown(), is_multiple, extended_select, unselect_others); - if ( (flags & wxTREE_HITTEST_ONITEMBUTTON) && event.LeftDown() ) - { - Toggle( item ); - if ( is_multiple ) - return; - } - SelectItem(item, unselect_others, extended_select); if ( event.LeftDClick() ) @@ -2457,6 +2593,9 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) 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 ); } @@ -2604,3 +2743,4 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item ) Refresh( TRUE, &rect ); } +#endif // wxUSE_TREECTRL