X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6f7f0d0a2d882ca8fab9e9c98f9b8e7188b4f426..0dd48109b4d2983fe600b3faf260b31cb82353c4:/src/generic/treectlg.cpp diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index 704200e11b..c143230058 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -42,7 +42,7 @@ #include "wx/renderer.h" #ifdef __WXMAC__ - #include "wx/mac/private.h" + #include "wx/osx/private.h" #endif // ----------------------------------------------------------------------------- @@ -51,7 +51,7 @@ class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem; -WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems); +WX_DEFINE_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems); // ---------------------------------------------------------------------------- // constants @@ -61,6 +61,9 @@ static const int NO_IMAGE = -1; static const int PIXELS_PER_UNIT = 10; +// the margin between the item state image and the item normal image +static const int MARGIN_BETWEEN_STATE_AND_IMAGE = 2; + // the margin between the item image and the item text static const int MARGIN_BETWEEN_IMAGE_AND_TEXT = 4; @@ -92,29 +95,8 @@ class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl public: wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item); - void EndEdit(bool discardChanges = false) - { - if ( discardChanges ) - { - StopEditing(); - } - else - { - m_aboutToFinish = true; - - // Notify the owner about the changes - AcceptChanges(); - - // Even if vetoed, close the control (consistent with MSW) - Finish(); - } - } + void EndEdit( bool discardChanges ); - void StopEditing() - { - Finish(); - m_owner->OnRenameCancelled(m_itemEdited); - } const wxGenericTreeItem* item() const { return m_itemEdited; } protected: @@ -123,13 +105,12 @@ protected: void OnKillFocus( wxFocusEvent &event ); bool AcceptChanges(); - void Finish(); + void Finish( bool setfocus ); private: wxGenericTreeCtrl *m_owner; wxGenericTreeItem *m_itemEdited; wxString m_startValue; - bool m_finished; bool m_aboutToFinish; DECLARE_EVENT_TABLE() @@ -159,7 +140,13 @@ class WXDLLEXPORT wxGenericTreeItem { public: // ctors & dtor - wxGenericTreeItem() { m_data = NULL; } + wxGenericTreeItem() + { + m_data = NULL; + m_widthText = + m_heightText = -1; + } + wxGenericTreeItem( wxGenericTreeItem *parent, const wxString& text, int image, @@ -175,18 +162,36 @@ public: int GetImage(wxTreeItemIcon which = wxTreeItemIcon_Normal) const { return m_images[which]; } wxTreeItemData *GetData() const { return m_data; } + int GetState() const { return m_state; } // returns the current image for the item (depending on its // selected/expanded/whatever state) int GetCurrentImage() const; - void SetText( const wxString &text ); - void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; } + void SetText(const wxString& text) + { + m_text = text; + + ResetTextSize(); + } + + void SetImage(int image, wxTreeItemIcon which) + { + m_images[which] = image; + m_width = 0; + } + void SetData(wxTreeItemData *data) { m_data = data; } + void SetState(int state) { m_state = state; m_width = 0; } void SetHasPlus(bool has = true) { m_hasPlus = has; } - void SetBold(bool bold) { m_isBold = bold; } + void SetBold(bool bold) + { + m_isBold = bold; + + ResetTextSize(); + } int GetX() const { return m_x; } int GetY() const { return m_y; } @@ -194,14 +199,43 @@ public: void SetX(int x) { m_x = x; } void SetY(int y) { m_y = y; } - int GetHeight() const { return m_height; } - int GetWidth() const { return m_width; } + int GetHeight() const { return m_height; } + int GetWidth() const { return m_width; } - void SetHeight(int h) { m_height = h; } - void SetWidth(int w) { m_width = w; } + int GetTextHeight() const + { + wxASSERT_MSG( m_heightText != -1, "must call CalculateSize() first" ); + + return m_heightText; + } + + int GetTextWidth() const + { + wxASSERT_MSG( m_widthText != -1, "must call CalculateSize() first" ); + + return m_widthText; + } wxGenericTreeItem *GetParent() const { return m_parent; } + // sets the items font for the specified DC if it uses any special font or + // simply returns false otherwise + bool SetFont(wxGenericTreeCtrl *control, wxDC& dc) const + { + wxFont font; + + wxTreeItemAttr * const attr = GetAttributes(); + if ( attr && attr->HasFont() ) + font = attr->GetFont(); + else if ( IsBold() ) + font = control->m_boldFont; + else + return false; + + dc.SetFont(font); + return true; + } + // operations // deletes all children notifying the treectrl about it @@ -211,10 +245,22 @@ public: size_t GetChildrenCount(bool recursively = true) const; void Insert(wxGenericTreeItem *child, size_t index) - { m_children.Insert(child, index); } + { m_children.Insert(child, index); } + + // calculate and cache the item size using either the provided DC (which is + // supposed to have wxGenericTreeCtrl::m_normalFont selected into it!) or a + // wxClientDC on the control window + void CalculateSize(wxGenericTreeCtrl *control, wxDC& dc) + { DoCalculateSize(control, dc, true /* dc uses normal font */); } + void CalculateSize(wxGenericTreeCtrl *control); void GetSize( int &x, int &y, const wxGenericTreeCtrl* ); + void ResetSize() { m_width = 0; } + void ResetTextSize() { m_width = 0; m_widthText = -1; } + void RecursiveResetSize(); + void RecursiveResetTextSize(); + // return the item at given position (or NULL if no item), onButton is // true if the point belongs to the item's button, otherwise it lies // on the item's label @@ -254,22 +300,39 @@ public: if ( m_ownsAttr ) delete m_attr; m_attr = attr; m_ownsAttr = false; + m_width = 0; + m_widthText = -1; } // set them and delete when done void AssignAttributes(wxTreeItemAttr *attr) { SetAttributes(attr); m_ownsAttr = true; + m_width = 0; + m_widthText = -1; } private: + // calculate the size of this item, i.e. set m_width, m_height and + // m_widthText and m_heightText properly + // + // if dcUsesNormalFont is true, the current dc font must be the normal tree + // control font + void DoCalculateSize(wxGenericTreeCtrl *control, + wxDC& dc, + bool dcUsesNormalFont); + // since there can be very many of these, we save size by chosing // the smallest representation for the elements and by ordering // the members to avoid padding. wxString m_text; // label to be rendered for item + int m_widthText; + int m_heightText; wxTreeItemData *m_data; // user-provided data + int m_state; // item state + wxArrayGenericTreeItems m_children; // list of children wxGenericTreeItem *m_parent; // parent of this item @@ -318,7 +381,8 @@ static void EventFlagsToSelType(long style, } // check if the given item is under another one -static bool IsDescendantOf(const wxGenericTreeItem *parent, const wxGenericTreeItem *item) +static bool +IsDescendantOf(const wxGenericTreeItem *parent, const wxGenericTreeItem *item) { while ( item ) { @@ -363,48 +427,54 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner, : m_itemEdited(item), m_startValue(item->GetText()) { m_owner = owner; - m_finished = false; m_aboutToFinish = false; - int w = m_itemEdited->GetWidth(), - h = m_itemEdited->GetHeight(); + wxRect rect; + m_owner->GetBoundingRect(m_itemEdited, rect, true); + + // corrects position and size for better appearance +#ifdef __WXMSW__ + rect.x -= 5; + rect.width += 10; +#elif defined(__WXGTK__) + rect.x -= 5; + rect.y -= 2; + rect.width += 8; + rect.height += 4; +#elif defined(__WXMAC__) + int bestHeight = GetBestSize().y - 8; + if ( rect.height > bestHeight ) + { + int diff = rect.height - bestHeight; + rect.height -= diff; + rect.y += diff / 2; + } +#endif // platforms - int x, y; - m_owner->CalcScrolledPosition(item->GetX(), item->GetY(), &x, &y); + (void)Create(m_owner, wxID_ANY, m_startValue, + rect.GetPosition(), rect.GetSize()); - int image_h = 0, - image_w = 0; + SetSelection(-1, -1); +} - int image = item->GetCurrentImage(); - if ( image != NO_IMAGE ) - { - if ( m_owner->m_imageListNormal ) - { - m_owner->m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; - } - else - { - wxFAIL_MSG(_T("you must create an image list to use images!")); - } - } +void wxTreeTextCtrl::EndEdit(bool discardChanges) +{ + m_aboutToFinish = true; - // FIXME: what are all these hardcoded 4, 8 and 11s really? - x += image_w; - w -= image_w + 4; -#ifdef __WXMAC__ - wxSize bs = DoGetBestSize() ; - // edit control height - if ( h > bs.y - 8 ) + if ( discardChanges ) { - int diff = h - ( bs.y - 8 ) ; - h -= diff ; - y += diff / 2 ; + m_owner->OnRenameCancelled(m_itemEdited); + + Finish( true ); } -#endif + else + { + // Notify the owner about the changes + AcceptChanges(); - (void)Create(m_owner, wxID_ANY, m_startValue, - wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8)); + // Even if vetoed, close the control (consistent with MSW) + Finish( true ); + } } bool wxTreeTextCtrl::AcceptChanges() @@ -435,18 +505,14 @@ bool wxTreeTextCtrl::AcceptChanges() return true; } -void wxTreeTextCtrl::Finish() +void wxTreeTextCtrl::Finish( bool setfocus ) { - if ( !m_finished ) - { - m_owner->ResetTextControl(); + m_owner->ResetTextControl(); - wxPendingDelete.Append(this); - - m_finished = true; + wxPendingDelete.Append(this); + if (setfocus) m_owner->SetFocus(); - } } void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) @@ -454,11 +520,11 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) switch ( event.m_keyCode ) { case WXK_RETURN: - EndEdit(); + EndEdit( false ); break; case WXK_ESCAPE: - StopEditing(); + EndEdit( true ); break; default: @@ -468,7 +534,7 @@ void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) { - if ( !m_finished ) + if ( !m_aboutToFinish ) { // auto-grow the textctrl: wxSize parentSize = m_owner->GetSize(); @@ -488,18 +554,15 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event ) void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event ) { - if ( !m_finished && !m_aboutToFinish ) + if ( !m_aboutToFinish ) { - // We must finish regardless of success, otherwise we'll get - // focus problems: - Finish(); - if ( !AcceptChanges() ) m_owner->OnRenameCancelled( m_itemEdited ); + + Finish( false ); } - // We must let the native text control handle focus, too, otherwise - // it could have problems with the cursor (e.g., in wxGTK). + // We should let the native text control handle focus, too. event.Skip(); } @@ -519,6 +582,7 @@ wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent, m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE; m_data = data; + m_state = wxTREE_ITEMSTATE_NONE; m_x = m_y = 0; m_isCollapsed = true; @@ -528,12 +592,15 @@ wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent, m_parent = parent; - m_attr = (wxTreeItemAttr *)NULL; + m_attr = NULL; m_ownsAttr = false; // We don't know the height here yet. m_width = 0; m_height = 0; + + m_widthText = -1; + m_heightText = -1; } wxGenericTreeItem::~wxGenericTreeItem() @@ -543,7 +610,7 @@ wxGenericTreeItem::~wxGenericTreeItem() if (m_ownsAttr) delete m_attr; wxASSERT_MSG( m_children.IsEmpty(), - wxT("please call DeleteChildren() before deleting the item") ); + "must call DeleteChildren() before deleting the item" ); } void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree) @@ -563,11 +630,6 @@ void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree) m_children.Empty(); } -void wxGenericTreeItem::SetText( const wxString &text ) -{ - m_text = text; -} - size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const { size_t count = m_children.GetCount(); @@ -644,10 +706,29 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point, // assuming every image (normal and selected) has the same size! if ( (GetImage() != NO_IMAGE) && theCtrl->m_imageListNormal ) + { theCtrl->m_imageListNormal->GetSize(GetImage(), image_w, image_h); + } + + int state_w = -1; + int state_h; + + if ( (GetState() != wxTREE_ITEMSTATE_NONE) && + theCtrl->m_imageListState ) + { + theCtrl->m_imageListState->GetSize(GetState(), + state_w, state_h); + } - if ((image_w != -1) && (point.x <= m_x + image_w + 1)) + if ((state_w != -1) && (point.x <= m_x + state_w + 1)) + flags |= wxTREE_HITTEST_ONITEMSTATEICON; + else if ((image_w != -1) && + (point.x <= m_x + + (state_w != -1 ? state_w + + MARGIN_BETWEEN_STATE_AND_IMAGE + : 0) + + image_w + 1)) flags |= wxTREE_HITTEST_ONITEMICON; else flags |= wxTREE_HITTEST_ONITEMLABEL; @@ -664,7 +745,7 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point, } // if children are expanded, fall through to evaluate them - if (m_isCollapsed) return (wxGenericTreeItem*) NULL; + if (m_isCollapsed) return NULL; } // evaluate children @@ -679,7 +760,7 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point, return res; } - return (wxGenericTreeItem*) NULL; + return NULL; } int wxGenericTreeItem::GetCurrentImage() const @@ -712,6 +793,105 @@ int wxGenericTreeItem::GetCurrentImage() const return image; } +void wxGenericTreeItem::CalculateSize(wxGenericTreeCtrl* control) +{ + // check if we need to do anything before creating the DC + if ( m_width != 0 ) + return; + + wxClientDC dc(control); + DoCalculateSize(control, dc, false /* normal font not used */); +} + +void +wxGenericTreeItem::DoCalculateSize(wxGenericTreeCtrl* control, + wxDC& dc, + bool dcUsesNormalFont) +{ + if ( m_width != 0 ) // Size known, nothing to do + return; + + if ( m_widthText == -1 ) + { + bool fontChanged; + if ( SetFont(control, dc) ) + { + fontChanged = true; + } + else // we have no special font + { + if ( !dcUsesNormalFont ) + { + // but we do need to ensure that the normal font is used: notice + // that this doesn't count as changing the font as we don't need + // to restore it + dc.SetFont(control->m_normalFont); + } + + fontChanged = false; + } + + dc.GetTextExtent( GetText(), &m_widthText, &m_heightText ); + + // restore normal font if the DC used it previously and we changed it + if ( fontChanged ) + dc.SetFont(control->m_normalFont); + } + + int text_h = m_heightText + 2; + + int image_h = 0, image_w = 0; + int image = GetCurrentImage(); + if ( image != NO_IMAGE && control->m_imageListNormal ) + { + control->m_imageListNormal->GetSize(image, image_w, image_h); + image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; + } + + int state_h = 0, state_w = 0; + int state = GetState(); + if ( state != wxTREE_ITEMSTATE_NONE && control->m_imageListState ) + { + control->m_imageListState->GetSize(state, state_w, state_h); + if ( image_w != 0 ) + state_w += MARGIN_BETWEEN_STATE_AND_IMAGE; + else + state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; + } + + int img_h = wxMax(state_h, image_h); + m_height = wxMax(img_h, text_h); + + if (m_height < 30) + m_height += 2; // at least 2 pixels + else + m_height += m_height / 10; // otherwise 10% extra spacing + + if (m_height > control->m_lineHeight) + control->m_lineHeight = m_height; + + m_width = state_w + image_w + m_widthText + 2; +} + +void wxGenericTreeItem::RecursiveResetSize() +{ + m_width = 0; + + const size_t count = m_children.Count(); + for (size_t i = 0; i < count; i++ ) + m_children[i]->RecursiveResetSize(); +} + +void wxGenericTreeItem::RecursiveResetTextSize() +{ + m_width = 0; + m_widthText = -1; + + const size_t count = m_children.Count(); + for (size_t i = 0; i < count; i++ ) + m_children[i]->RecursiveResetTextSize(); +} + // ----------------------------------------------------------------------------- // wxGenericTreeCtrl implementation // ----------------------------------------------------------------------------- @@ -746,7 +926,7 @@ void wxGenericTreeCtrl::Init() m_current = m_key_current = m_anchor = - m_select_me = (wxGenericTreeItem *) NULL; + m_select_me = NULL; m_hasFocus = false; m_dirty = false; @@ -760,7 +940,7 @@ void wxGenericTreeCtrl::Init() ( wxSYS_COLOUR_HIGHLIGHT ), - wxSOLID + wxBRUSHSTYLE_SOLID ); m_hilightUnfocusedBrush = new wxBrush @@ -769,7 +949,7 @@ void wxGenericTreeCtrl::Init() ( wxSYS_COLOUR_BTNSHADOW ), - wxSOLID + wxBRUSHSTYLE_SOLID ); m_imageListButtons = NULL; @@ -782,16 +962,22 @@ void wxGenericTreeCtrl::Init() m_textCtrl = NULL; m_renameTimer = NULL; - m_freezeCount = 0; m_findTimer = NULL; m_dropEffectAboveItem = false; + m_dndEffect = NoEffect; + m_dndEffectItem = NULL; + m_lastOnSame = false; -#ifdef __WXMAC_CARBON__ - m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ; +#if defined( __WXMAC__ ) +#if wxOSX_USE_ATSU_TEXT + m_normalFont.MacCreateFromThemeFont( kThemeViewsFont ) ; +#else + m_normalFont.MacCreateFromUIFont( kCTFontViewsFontType ) ; +#endif #else m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); #endif @@ -813,21 +999,12 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent, const wxString& name ) { #ifdef __WXMAC__ - int major,minor; - wxGetOsVersion( &major, &minor ); + int major, minor; + wxGetOsVersion(&major, &minor); - style &= ~wxTR_LINES_AT_ROOT; - style |= wxTR_NO_LINES; if (major < 10) style |= wxTR_ROW_LINES; - - if (style == 0 || style & wxTR_DEFAULT_STYLE) - style |= wxTR_FULL_ROW_HIGHLIGHT; - #endif // __WXMAC__ -#ifdef __WXGTK20__ - style |= wxTR_NO_LINES; -#endif if ( !wxControl::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, @@ -850,7 +1027,14 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent, if (!m_hasFont) SetOwnFont(attr.font); - m_dottedPen = wxPen( wxT("grey"), 0, 0 ); + // this is a misnomer: it's called "dotted pen" but uses (default) wxSOLID + // style because we apparently get performance problems when using dotted + // pen for drawing in some ports -- but under MSW it seems to work fine +#ifdef __WXMSW__ + m_dottedPen = wxPen(*wxLIGHT_GREY, 0, wxPENSTYLE_DOT); +#else + m_dottedPen = *wxGREY_PEN; +#endif SetInitialSize(size); @@ -952,6 +1136,14 @@ wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const return ((wxGenericTreeItem*) item.m_pItem)->GetData(); } +int wxGenericTreeCtrl::DoGetItemState(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxTREE_ITEMSTATE_NONE, wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + return pItem->GetState(); +} + wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); @@ -960,7 +1152,8 @@ wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const return pItem->Attr().GetTextColour(); } -wxColour wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const +wxColour +wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); @@ -976,14 +1169,14 @@ wxFont wxGenericTreeCtrl::GetItemFont(const wxTreeItemId& item) const return pItem->Attr().GetFont(); } -void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) +void +wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) { wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); - wxClientDC dc(this); wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; pItem->SetText(text); - CalculateSize(pItem, dc); + pItem->CalculateSize(this); RefreshLine(pItem); } @@ -995,13 +1188,12 @@ void wxGenericTreeCtrl::SetItemImage(const wxTreeItemId& item, wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; pItem->SetImage(image, which); - - wxClientDC dc(this); - CalculateSize(pItem, dc); + pItem->CalculateSize(this); RefreshLine(pItem); } -void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) +void +wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) { wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); @@ -1011,6 +1203,16 @@ void wxGenericTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *da ((wxGenericTreeItem*) item.m_pItem)->SetData(data); } +void wxGenericTreeCtrl::DoSetItemState(const wxTreeItemId& item, int state) +{ + wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + pItem->SetState(state); + pItem->CalculateSize(this); + RefreshLine(pItem); +} + void wxGenericTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) { wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); @@ -1032,9 +1234,7 @@ void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold) // recalculate the item size as bold and non bold fonts have different // widths - wxClientDC dc(this); - CalculateSize(pItem, dc); - + pItem->CalculateSize(this); RefreshLine(pItem); } } @@ -1078,12 +1278,15 @@ void wxGenericTreeCtrl::SetItemBackgroundColour(const wxTreeItemId& item, RefreshLine(pItem); } -void wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) +void +wxGenericTreeCtrl::SetItemFont(const wxTreeItemId& item, const wxFont& font) { wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; pItem->Attr().SetFont(font); + pItem->ResetTextSize(); + pItem->CalculateSize(this); RefreshLine(pItem); } @@ -1100,6 +1303,9 @@ bool wxGenericTreeCtrl::SetFont( const wxFont &font ) m_normalFont.GetFaceName(), m_normalFont.GetEncoding()); + if (m_anchor) + m_anchor->RecursiveResetTextSize(); + return true; } @@ -1198,7 +1404,8 @@ wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, { wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); + wxArrayGenericTreeItems& + children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); // it's ok to cast cookie to size_t, we never have indices big enough to // overflow "void *" @@ -1218,8 +1425,9 @@ wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); - wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); - return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last())); + wxArrayGenericTreeItems& + children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren(); + return children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last()); } wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const @@ -1239,7 +1447,8 @@ wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent? size_t n = (size_t)(index + 1); - return n == siblings.GetCount() ? wxTreeItemId() : wxTreeItemId(siblings[n]); + return n == siblings.GetCount() ? wxTreeItemId() + : wxTreeItemId(siblings[n]); } wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const @@ -1308,6 +1517,7 @@ wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") ); wxTreeItemId id = item; if (id.IsOk()) @@ -1324,10 +1534,37 @@ wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); + wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") ); - wxFAIL_MSG(wxT("not implemented")); + // find out the starting point + wxTreeItemId prevItem = GetPrevSibling(item); + if ( !prevItem.IsOk() ) + { + prevItem = GetItemParent(item); + } - return wxTreeItemId(); + // find the first visible item after it + while ( prevItem.IsOk() && !IsVisible(prevItem) ) + { + prevItem = GetNext(prevItem); + if ( !prevItem.IsOk() || prevItem == item ) + { + // there are no visible items before item + return wxTreeItemId(); + } + } + + // from there we must be able to navigate until this item + while ( prevItem.IsOk() ) + { + const wxTreeItemId nextItem = GetNextVisible(prevItem); + if ( !nextItem.IsOk() || nextItem == item ) + break; + + prevItem = nextItem; + } + + return prevItem; } // called by wxTextTreeCtrl when it marks itself for deletion @@ -1373,7 +1610,8 @@ wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent, } // and try all the items (stop when we get to the one we started from) - while (id.IsOk() && id != idParent && !GetItemText(id).Lower().StartsWith(prefix) ) + while ( id.IsOk() && id != idParent && + !GetItemText(id).Lower().StartsWith(prefix) ) { id = GetNext(id); } @@ -1424,11 +1662,11 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text, int selImage, wxTreeItemData *data) { - wxCHECK_MSG( !m_anchor, wxTreeItemId(), wxT("tree can have only one root") ); + wxCHECK_MSG( !m_anchor, wxTreeItemId(), "tree can have only one root" ); m_dirty = true; // do this first so stuff below doesn't cause flicker - m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, + m_anchor = new wxGenericTreeItem(NULL, text, image, selImage, data); if ( data != NULL ) { @@ -1470,9 +1708,11 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId, int index = -1; if (idPrevious.IsOk()) { - index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem); + index = parent->GetChildren().Index( + (wxGenericTreeItem*) idPrevious.m_pItem); wxASSERT_MSG( index != wxNOT_FOUND, - wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") ); + "previous item in wxGenericTreeCtrl::InsertItem() " + "is not a sibling" ); } return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data); @@ -1488,16 +1728,24 @@ void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item) // Don't leave edit or selection on a child which is about to disappear void wxGenericTreeCtrl::ChildrenClosing(wxGenericTreeItem* item) { - if (m_textCtrl != NULL && item != m_textCtrl->item() && IsDescendantOf(item, m_textCtrl->item())) { - m_textCtrl->StopEditing(); + if ( m_textCtrl && item != m_textCtrl->item() && + IsDescendantOf(item, m_textCtrl->item()) ) + { + m_textCtrl->EndEdit( true ); } - if (item != m_key_current && IsDescendantOf(item, m_key_current)) { + + if ( item != m_key_current && IsDescendantOf(item, m_key_current) ) + { m_key_current = NULL; } - if (IsDescendantOf(item, m_select_me)) { + + if ( IsDescendantOf(item, m_select_me) ) + { m_select_me = item; } - if (item != m_current && IsDescendantOf(item, m_current)) { + + if ( item != m_current && IsDescendantOf(item, m_current) ) + { m_current->SetHilight( false ); m_current = NULL; m_select_me = item; @@ -1523,7 +1771,7 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId) if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item())) { // can't delete the item being edited, cancel editing it first - m_textCtrl->StopEditing(); + m_textCtrl->EndEdit( true ); } wxGenericTreeItem *parent = item->GetParent(); @@ -1611,9 +1859,16 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId) } item->Expand(); - CalculatePositions(); + if ( !IsFrozen() ) + { + CalculatePositions(); - RefreshSubtree(item); + RefreshSubtree(item); + } + else // frozen + { + m_dirty = true; + } event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); GetEventHandler()->ProcessEvent( event ); @@ -1720,7 +1975,10 @@ void wxGenericTreeCtrl::UnselectAll() // Tag all next children, when no more children, // Move to parent (not to tag) // Keep going... if we found last_item, we stop. -bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select) +bool +wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, + wxGenericTreeItem *last_item, + bool select) { wxGenericTreeItem *parent = crt_item->GetParent(); @@ -1734,13 +1992,17 @@ bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTr size_t count = children.GetCount(); for (size_t n=(size_t)(index+1); nSetHilight(select); RefreshLine(crt_item); @@ -1762,7 +2024,9 @@ bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxG return false; } -void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2) +void +wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, + wxGenericTreeItem *item2) { m_select_me = NULL; @@ -1837,7 +2101,8 @@ void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId, { if ( !m_current ) { - m_current = m_key_current = (wxGenericTreeItem*) GetRootItem().m_pItem; + m_current = + m_key_current = (wxGenericTreeItem*) GetRootItem().m_pItem; } // don't change the mark (m_current) @@ -1875,7 +2140,7 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select) { wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") ); - + wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item); if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) return; @@ -1986,7 +2251,9 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels int x_pos = GetScrollPos( wxHORIZONTAL ); // Item should appear at top - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, item_y/PIXELS_PER_UNIT ); + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, + x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, + x_pos, item_y/PIXELS_PER_UNIT ); } else if (item_y+GetLineHeight(gitem) > start_y+client_h) { @@ -1999,7 +2266,10 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item) item_y += PIXELS_PER_UNIT+2; int x_pos = GetScrollPos( wxHORIZONTAL ); // Item should appear at bottom - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT ); + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, + x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, + x_pos, + (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT ); } } @@ -2009,7 +2279,8 @@ static wxGenericTreeCtrl *s_treeBeingSorted = NULL; static int LINKAGEMODE tree_ctrl_compare_func(wxGenericTreeItem **item1, wxGenericTreeItem **item2) { - wxCHECK_MSG( s_treeBeingSorted, 0, wxT("bug in wxGenericTreeCtrl::SortChildren()") ); + wxCHECK_MSG( s_treeBeingSorted, 0, + "bug in wxGenericTreeCtrl::SortChildren()" ); return s_treeBeingSorted->OnCompareItems(*item1, *item2); } @@ -2054,6 +2325,20 @@ void wxGenericTreeCtrl::CalculateLineHeight() } } + if ( m_imageListState ) + { + // Calculate a m_lineHeight value from the state Image sizes. + // May be toggle off. Then wxGenericTreeCtrl will spread when + // necessary (which might look ugly). + int n = m_imageListState->GetImageCount(); + for (int i = 0; i < n ; i++) + { + int width = 0, height = 0; + m_imageListState->GetSize(i, width, height); + if (height > m_lineHeight) m_lineHeight = height; + } + } + if (m_imageListButtons) { // Calculate a m_lineHeight value from the Button image sizes. @@ -2080,6 +2365,10 @@ void wxGenericTreeCtrl::SetImageList(wxImageList *imageList) m_imageListNormal = imageList; m_ownsImageListNormal = false; m_dirty = true; + + if (m_anchor) + m_anchor->RecursiveResetSize(); + // Don't do any drawing if we're setting the list to NULL, // since we may be in the process of deleting the tree control. if (imageList) @@ -2091,6 +2380,15 @@ void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList) if (m_ownsImageListState) delete m_imageListState; m_imageListState = imageList; m_ownsImageListState = false; + m_dirty = true; + + if (m_anchor) + m_anchor->RecursiveResetSize(); + + // Don't do any drawing if we're setting the list to NULL, + // since we may be in the process of deleting the tree control. + if (imageList) + CalculateLineHeight(); } void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList) @@ -2099,6 +2397,10 @@ void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList) m_imageListButtons = imageList; m_ownsImageListButtons = false; m_dirty = true; + + if (m_anchor) + m_anchor->RecursiveResetSize(); + CalculateLineHeight(); } @@ -2122,7 +2424,9 @@ void wxGenericTreeCtrl::AdjustMyScrollbars() x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels int x_pos = GetScrollPos( wxHORIZONTAL ); int y_pos = GetScrollPos( wxVERTICAL ); - SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, x_pos, y_pos ); + SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT, + x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT, + x_pos, y_pos ); } else { @@ -2140,16 +2444,10 @@ int wxGenericTreeCtrl::GetLineHeight(wxGenericTreeItem *item) const void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) { - // TODO implement "state" icon on items - - wxTreeItemAttr *attr = item->GetAttributes(); - if ( attr && attr->HasFont() ) - dc.SetFont(attr->GetFont()); - else if (item->IsBold()) - dc.SetFont(m_boldFont); + item->SetFont(this, dc); + item->CalculateSize(this, dc); - wxCoord text_w = 0, text_h = 0; - dc.GetTextExtent( item->GetText(), &text_w, &text_h ); + wxCoord text_h = item->GetTextHeight(); int image_h = 0, image_w = 0; int image = item->GetCurrentImage(); @@ -2157,7 +2455,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) { if ( m_imageListNormal ) { - m_imageListNormal->GetSize( image, image_w, image_h ); + m_imageListNormal->GetSize(image, image_w, image_h); image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; } else @@ -2166,8 +2464,27 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) } } + int state_h = 0, state_w = 0; + int state = item->GetState(); + if ( state != wxTREE_ITEMSTATE_NONE ) + { + if ( m_imageListState ) + { + m_imageListState->GetSize(state, state_w, state_h); + if ( image_w != 0 ) + state_w += MARGIN_BETWEEN_STATE_AND_IMAGE; + else + state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; + } + else + { + state = wxTREE_ITEMSTATE_NONE; + } + } + int total_h = GetLineHeight(item); - bool drawItemBackground = false; + bool drawItemBackground = false, + hasBgColour = false; if ( item->IsSelected() ) { @@ -2177,16 +2494,18 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) else { wxColour colBg; + wxTreeItemAttr * const attr = item->GetAttributes(); if ( attr && attr->HasBackgroundColour() ) { - drawItemBackground = true; + drawItemBackground = + hasBgColour = true; colBg = attr->GetBackgroundColour(); } else { colBg = GetBackgroundColour(); } - dc.SetBrush(wxBrush(colBg, wxSOLID)); + dc.SetBrush(wxBrush(colBg, wxBRUSHSTYLE_SOLID)); } int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0; @@ -2197,9 +2516,6 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) x=0; GetVirtualSize(&w, &h); wxRect rect( x, item->GetY()+offset, w, total_h-offset); -#if !defined(__WXGTK20__) && !defined(__WXMAC__) - dc.DrawRectangle(rect); -#else if (!item->IsSelected()) { dc.DrawRectangle(rect); @@ -2208,38 +2524,43 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) { int flags = wxCONTROL_SELECTED; if (m_hasFocus -#ifdef __WXMAC__ +#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON // TODO CS && IsControlActive( (ControlRef)GetHandle() ) #endif ) flags |= wxCONTROL_FOCUSED; if ((item == m_current) && (m_hasFocus)) flags |= wxCONTROL_CURRENT; - wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); + + wxRendererNative::Get(). + DrawItemSelectionRect(this, dc, rect, flags); } -#endif } - else + else // no full row highlight { - if ( item->IsSelected() && image != NO_IMAGE ) + if ( item->IsSelected() && + (state != wxTREE_ITEMSTATE_NONE || 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. - wxRect rect( item->GetX() + image_w - 2, item->GetY()+offset, - item->GetWidth() - image_w + 2, total_h-offset ); + // If it's selected, and there's an state image or normal image, + // then we should take care to leave the area under the image + // painted in the background colour. + wxRect rect( item->GetX() + state_w + image_w - 2, + item->GetY() + offset, + item->GetWidth() - state_w - image_w + 2, + total_h - offset ); #if !defined(__WXGTK20__) && !defined(__WXMAC__) dc.DrawRectangle( rect ); #else rect.x -= 1; rect.width += 2; - + int flags = wxCONTROL_SELECTED; if (m_hasFocus) flags |= wxCONTROL_FOCUSED; if ((item == m_current) && (m_hasFocus)) flags |= wxCONTROL_CURRENT; - wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); + wxRendererNative::Get(). + DrawItemSelectionRect(this, dc, rect, flags); #endif } // On GTK+ 2, drawing a 'normal' background is wrong for themes that @@ -2247,53 +2568,104 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) // except for custom item backgrounds, works for both kinds of theme. else if (drawItemBackground) { - wxRect rect( item->GetX()-2, item->GetY()+offset, - item->GetWidth()+2, total_h-offset ); -#if !defined(__WXGTK20__) && !defined(__WXMAC__) - dc.DrawRectangle( rect ); -#else - if ( attr && attr->HasBackgroundColour() ) + wxRect rect( item->GetX() + state_w + image_w - 2, + item->GetY() + offset, + item->GetWidth() - state_w - image_w + 2, + total_h - offset ); + if ( hasBgColour ) { dc.DrawRectangle( rect ); } - else + else // no specific background colour { rect.x -= 1; rect.width += 2; - + int flags = wxCONTROL_SELECTED; if (m_hasFocus) flags |= wxCONTROL_FOCUSED; if ((item == m_current) && (m_hasFocus)) flags |= wxCONTROL_CURRENT; - wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags ); + wxRendererNative::Get(). + DrawItemSelectionRect(this, dc, rect, flags); } -#endif } } + if ( state != wxTREE_ITEMSTATE_NONE ) + { + dc.SetClippingRegion( item->GetX(), item->GetY(), state_w, total_h ); + m_imageListState->Draw( state, dc, + item->GetX(), + item->GetY() + + (total_h > state_h ? (total_h-state_h)/2 + : 0), + wxIMAGELIST_DRAW_TRANSPARENT ); + dc.DestroyClippingRegion(); + } + if ( image != NO_IMAGE ) { - dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, total_h ); + dc.SetClippingRegion(item->GetX() + state_w, item->GetY(), + image_w, total_h); m_imageListNormal->Draw( image, dc, - item->GetX(), - item->GetY() +((total_h > image_h)?((total_h-image_h)/2):0), + item->GetX() + state_w, + item->GetY() + + (total_h > image_h ? (total_h-image_h)/2 + : 0), wxIMAGELIST_DRAW_TRANSPARENT ); dc.DestroyClippingRegion(); } - dc.SetBackgroundMode(wxTRANSPARENT); + dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT); int extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0; dc.DrawText( item->GetText(), - (wxCoord)(image_w + item->GetX()), + (wxCoord)(state_w + image_w + item->GetX()), (wxCoord)(item->GetY() + extraH)); // restore normal font dc.SetFont( m_normalFont ); + + if (item == m_dndEffectItem) + { + dc.SetPen( *wxBLACK_PEN ); + // DnD visual effects + switch (m_dndEffect) + { + case BorderEffect: + { + dc.SetBrush(*wxTRANSPARENT_BRUSH); + int w = item->GetWidth() + 2; + int h = total_h + 2; + dc.DrawRectangle( item->GetX() - 1, item->GetY() - 1, w, h); + break; + } + case AboveEffect: + { + int x = item->GetX(), + y = item->GetY(); + dc.DrawLine( x, y, x + item->GetWidth(), y); + break; + } + case BelowEffect: + { + int x = item->GetX(), + y = item->GetY(); + y += total_h - 1; + dc.DrawLine( x, y, x + item->GetWidth(), y); + break; + } + case NoEffect: + break; + } + } } -// 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 ) +void +wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem *item, + wxDC &dc, + int level, + int &y) { int x = level*m_indent; if (!HasFlag(wxTR_HIDE_ROOT)) @@ -2314,7 +2686,8 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level PaintLevel(children[n], dc, 1, y); } while (++n < count); - if (!HasFlag(wxTR_NO_LINES) && HasFlag(wxTR_LINES_AT_ROOT) && count > 0) + if ( !HasFlag(wxTR_NO_LINES) && HasFlag(wxTR_LINES_AT_ROOT) + && count > 0 ) { // draw line down to last child origY += GetLineHeight(children[0])>>1; @@ -2348,7 +2721,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level wxColour colText; if ( item->IsSelected() -#ifdef __WXMAC__ +#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__) && wxOSX_USE_CARBON // TODO CS // On wxMac, if the tree doesn't have the focus we draw an empty // rectangle, so we want to make sure that the text is visible // against the normal background, not the highlightbackground, so @@ -2469,7 +2842,8 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level oldY += GetLineHeight(children[n-1])>>1; if (HasButtons()) y_mid += 5; - // Only draw the portion of the line that is visible, in case it is huge + // Only draw the portion of the line that is visible, in case + // it is huge wxCoord xOrigin=0, yOrigin=0, width, height; dc.GetDeviceOrigin(&xOrigin, &yOrigin); yOrigin = abs(yOrigin); @@ -2481,8 +2855,8 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level if (oldY > yOrigin + height) oldY = yOrigin + height; - // after the adjustments if y_mid is larger than oldY then the line - // isn't visible at all so don't draw anything + // after the adjustments if y_mid is larger than oldY then the + // line isn't visible at all so don't draw anything if (y_mid < oldY) dc.DrawLine(x, y_mid, x, oldY); } @@ -2506,7 +2880,7 @@ void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item) DrawLine(item, !m_dropEffectAboveItem ); } - SetCursor(wxCURSOR_BULLSEYE); + SetCursor(*wxSTANDARD_CURSOR); } else { @@ -2517,39 +2891,49 @@ void wxGenericTreeCtrl::DrawDropEffect(wxGenericTreeItem *item) void wxGenericTreeCtrl::DrawBorder(const wxTreeItemId &item) { - wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); + wxCHECK_RET( item.IsOk(), "invalid item in wxGenericTreeCtrl::DrawLine" ); wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - wxClientDC dc(this); - PrepareDC( dc ); - dc.SetLogicalFunction(wxINVERT); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - - int w = i->GetWidth() + 2; - int h = GetLineHeight(i) + 2; + if (m_dndEffect == NoEffect) + { + m_dndEffect = BorderEffect; + m_dndEffectItem = i; + } + else + { + m_dndEffect = NoEffect; + m_dndEffectItem = NULL; + } - dc.DrawRectangle( i->GetX() - 1, i->GetY() - 1, w, h); + wxRect rect( i->GetX()-1, i->GetY()-1, i->GetWidth()+2, GetLineHeight(i)+2 ); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + RefreshRect( rect ); } void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below) { - wxCHECK_RET( item.IsOk(), _T("invalid item in wxGenericTreeCtrl::DrawLine") ); + wxCHECK_RET( item.IsOk(), "invalid item in wxGenericTreeCtrl::DrawLine" ); wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; - wxClientDC dc(this); - PrepareDC( dc ); - dc.SetLogicalFunction(wxINVERT); - - int x = i->GetX(), - y = i->GetY(); - if ( below ) + if (m_dndEffect == NoEffect) { - y += GetLineHeight(i) - 1; + if (below) + m_dndEffect = BelowEffect; + else + m_dndEffect = AboveEffect; + m_dndEffectItem = i; + } + else + { + m_dndEffect = NoEffect; + m_dndEffectItem = NULL; } - dc.DrawLine( x, y, x + i->GetWidth(), y); + wxRect rect( i->GetX()-1, i->GetY()-1, i->GetWidth()+2, GetLineHeight(i)+2 ); + CalcScrolledPosition( rect.x, rect.y, &rect.x, &rect.y ); + RefreshRect( rect ); } // ----------------------------------------------------------------------------- @@ -2676,14 +3060,17 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) case WXK_MENU: { - // Use the item's bounding rectangle to determine position for the event + // Use the item's bounding rectangle to determine position for + // the event wxRect ItemRect; GetBoundingRect(m_current, ItemRect, true); - wxTreeEvent eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU, this, m_current); + wxTreeEvent + eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU, this, m_current); // Use the left edge, vertical middle eventMenu.m_pointDrag = wxPoint(ItemRect.GetX(), - ItemRect.GetY() + ItemRect.GetHeight() / 2); + ItemRect.GetY() + + ItemRect.GetHeight() / 2); GetEventHandler()->ProcessEvent( eventMenu ); } break; @@ -2692,7 +3079,8 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) case WXK_RETURN: if ( !event.HasModifiers() ) { - wxTreeEvent eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current); + wxTreeEvent + eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current); GetEventHandler()->ProcessEvent( eventAct ); } @@ -2720,12 +3108,15 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) { wxTreeItemIdValue cookie; wxTreeItemId current = m_key_current; - // TODO: Huh? If we get here, we'd better be the first child of our parent. How else could it be? + // TODO: Huh? If we get here, we'd better be the first + // child of our parent. How else could it be? if (current == GetFirstChild( prev, cookie )) { // otherwise we return to where we came from - DoSelectItem( prev, unselect_others, extended_select ); - m_key_current= (wxGenericTreeItem*) prev.m_pItem; + DoSelectItem(prev, + unselect_others, + extended_select); + m_key_current = (wxGenericTreeItem*) prev.m_pItem; break; } } @@ -2766,7 +3157,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) case WXK_RIGHT: // this works the same as the down arrow except that we // also expand the item if it wasn't expanded yet - if (m_current != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT)) + if (m_current != GetRootItem().m_pItem || !HasFlag(wxTR_HIDE_ROOT)) Expand(m_current); //else: don't try to expand hidden root item (which can be the // current one when the tree is empty) @@ -2921,21 +3312,35 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect, bool textOnly) const { - wxCHECK_MSG( item.IsOk(), false, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") ); + wxCHECK_MSG( item.IsOk(), false, + "invalid item in wxGenericTreeCtrl::GetBoundingRect" ); wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem; if ( textOnly ) { - rect.x = i->GetX(); - rect.width = i->GetWidth(); + int image_h = 0, image_w = 0; + int image = ((wxGenericTreeItem*) item.m_pItem)->GetCurrentImage(); + if ( image != NO_IMAGE && m_imageListNormal ) + { + m_imageListNormal->GetSize( image, image_w, image_h ); + image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; + } - if ( m_imageListNormal ) + int state_h = 0, state_w = 0; + int state = ((wxGenericTreeItem*) item.m_pItem)->GetState(); + if ( state != wxTREE_ITEMSTATE_NONE && m_imageListState ) { - int image_w, image_h; - m_imageListNormal->GetSize( 0, image_w, image_h ); - rect.width += image_w + MARGIN_BETWEEN_IMAGE_AND_TEXT; + m_imageListState->GetSize( state, state_w, state_h ); + if ( image_w != 0 ) + state_w += MARGIN_BETWEEN_STATE_AND_IMAGE; + else + state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; } + + rect.x = i->GetX() + state_w + image_w; + rect.width = i->GetWidth() - state_w - image_w; + } else // the entire line { @@ -3070,11 +3475,16 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) // Determines what item we are hovering over and need a tooltip for wxTreeItemId hoverItem = thisItem; - // We do not want a tooltip if we are dragging, or if the rename timer is running - if (underMouseChanged && hoverItem.IsOk() && !m_isDragging && (!m_renameTimer || !m_renameTimer->IsRunning())) + // We do not want a tooltip if we are dragging, or if the rename timer is + // running + if ( underMouseChanged && + hoverItem.IsOk() && + !m_isDragging && + (!m_renameTimer || !m_renameTimer->IsRunning()) ) { // Ask the tree control what tooltip (if any) should be shown - wxTreeEvent hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, this, hoverItem); + wxTreeEvent + hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, this, hoverItem); if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() ) { @@ -3181,7 +3591,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) { m_oldSelection->SetHilight(true); RefreshLine(m_oldSelection); - m_oldSelection = (wxGenericTreeItem *)NULL; + m_oldSelection = NULL; } // generate the drag end event @@ -3192,7 +3602,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) (void)GetEventHandler()->ProcessEvent(eventEndDrag); m_isDragging = false; - m_dropTarget = (wxGenericTreeItem *)NULL; + m_dropTarget = NULL; SetCursor(m_oldCursor); @@ -3205,10 +3615,12 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) else { // If we got to this point, we are not dragging or moving the mouse. - // Because the code in carbon/toplevel.cpp will only set focus to the tree - // if we skip for EVT_LEFT_DOWN, we MUST skip this event here for focus to work. + // Because the code in carbon/toplevel.cpp will only set focus to the + // tree if we skip for EVT_LEFT_DOWN, we MUST skip this event here for + // focus to work. // We skip even if we didn't hit an item because we still should - // restore focus to the tree control even if we didn't exactly hit an item. + // restore focus to the tree control even if we didn't exactly hit an + // item. if ( event.LeftDown() ) { event.Skip(); @@ -3223,13 +3635,15 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) if ( event.RightDown() ) { // If the item is already selected, do not update the selection. - // Multi-selections should not be cleared if a selected item is clicked. + // Multi-selections should not be cleared if a selected item is + // clicked. if (!IsSelected(item)) { DoSelectItem(item, true, false); } - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, this, item); + wxTreeEvent + nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, this, item); nevent.m_pointDrag = CalcScrolledPosition(pt); event.Skip(!GetEventHandler()->ProcessEvent(nevent)); @@ -3241,12 +3655,20 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) } else if ( event.MiddleDown() ) { - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, this, item); + wxTreeEvent + nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, this, item); nevent.m_pointDrag = CalcScrolledPosition(pt); event.Skip(!GetEventHandler()->ProcessEvent(nevent)); } else if ( event.LeftUp() ) { + if (flags & wxTREE_HITTEST_ONITEMSTATEICON) + { + wxTreeEvent + nevent(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, this, item); + GetEventHandler()->ProcessEvent(nevent); + } + // this facilitates multiple-item drag-and-drop if ( /* item && */ HasFlag(wxTR_MULTIPLE)) @@ -3284,8 +3706,9 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) m_lastOnSame = false; } } - else // !RightDown() && !MiddleDown() && !LeftUp() ==> LeftDown() || LeftDClick() + else // !RightDown() && !MiddleDown() && !LeftUp() { + // ==> LeftDown() || LeftDClick() if ( event.LeftDown() ) { m_lastOnSame = item == m_current; @@ -3317,7 +3740,9 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) EventFlagsToSelType(GetWindowStyleFlag(), event.ShiftDown(), event.CmdDown(), - is_multiple, extended_select, unselect_others); + is_multiple, + extended_select, + unselect_others); DoSelectItem(item, unselect_others, extended_select); } @@ -3334,7 +3759,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) m_lastOnSame = false; // send activate event first - wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, item); + wxTreeEvent + nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, item); nevent.m_pointDrag = CalcScrolledPosition(pt); if ( !GetEventHandler()->ProcessEvent( nevent ) ) { @@ -3373,55 +3799,11 @@ void wxGenericTreeCtrl::OnInternalIdle() DoDirtyProcessing(); } -void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc ) -{ - wxCoord text_w = 0; - wxCoord text_h = 0; - - wxTreeItemAttr *attr = item->GetAttributes(); - if ( attr && attr->HasFont() ) - dc.SetFont(attr->GetFont()); - else if ( item->IsBold() ) - dc.SetFont(m_boldFont); - else - dc.SetFont(m_normalFont); - - dc.GetTextExtent( item->GetText(), &text_w, &text_h ); - text_h+=2; - - // restore normal font - dc.SetFont( m_normalFont ); - - int image_h = 0; - int image_w = 0; - int image = item->GetCurrentImage(); - if ( image != NO_IMAGE ) - { - if ( m_imageListNormal ) - { - m_imageListNormal->GetSize( image, image_w, image_h ); - image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT; - } - } - - int total_h = (image_h > text_h) ? image_h : text_h; - - if (total_h < 30) - total_h += 2; // at least 2 pixels - else - total_h += total_h/10; // otherwise 10% extra spacing - - item->SetHeight(total_h); - if (total_h>m_lineHeight) - m_lineHeight=total_h; - - item->SetWidth(image_w+text_w+2); -} - -// ----------------------------------------------------------------------------- -// for developper : y is now the top of the level -// not the middle of it ! -void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y ) +void +wxGenericTreeCtrl::CalculateLevel(wxGenericTreeItem *item, + wxDC &dc, + int level, + int &y ) { int x = level*m_indent; if (!HasFlag(wxTR_HIDE_ROOT)) @@ -3435,7 +3817,7 @@ void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int l goto Recurse; } - CalculateSize( item, dc ); + item->CalculateSize(this, dc); // set its position item->SetX( x+m_spacing ); @@ -3475,13 +3857,13 @@ void wxGenericTreeCtrl::CalculatePositions() void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect) { - if ( !m_freezeCount ) + if ( !IsFrozen() ) wxTreeCtrlBase::Refresh(eraseBackground, rect); } void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) { - if (m_dirty || m_freezeCount) + if (m_dirty || IsFrozen() ) return; wxSize client = GetClientSize(); @@ -3498,7 +3880,7 @@ void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item ) { - if (m_dirty || m_freezeCount) + if (m_dirty || IsFrozen() ) return; wxRect rect; @@ -3511,7 +3893,7 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item ) void wxGenericTreeCtrl::RefreshSelected() { - if (m_freezeCount) + if (IsFrozen()) return; // TODO: this is awfully inefficient, we should keep the list of all @@ -3522,7 +3904,7 @@ void wxGenericTreeCtrl::RefreshSelected() void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item) { - if (m_freezeCount) + if (IsFrozen()) return; if ( item->IsSelected() ) @@ -3536,19 +3918,14 @@ void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item) } } -void wxGenericTreeCtrl::Freeze() +void wxGenericTreeCtrl::DoThaw() { - m_freezeCount++; -} + wxTreeCtrlBase::DoThaw(); -void wxGenericTreeCtrl::Thaw() -{ - wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen tree control?") ); - - if ( --m_freezeCount == 0 ) - { + if ( m_dirty ) + DoDirtyProcessing(); + else Refresh(); - } } // ---------------------------------------------------------------------------- @@ -3600,7 +3977,7 @@ wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) return wxListBox::GetClassDefaultAttributes(variant); #else wxVisualAttributes attr; - attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXTEXT); attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX); attr.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); return attr; @@ -3609,7 +3986,7 @@ wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) void wxGenericTreeCtrl::DoDirtyProcessing() { - if (m_freezeCount) + if (IsFrozen()) return; m_dirty = false;