private:
wxGenericTreeCtrl *m_owner;
- DECLARE_NO_COPY_CLASS(wxTreeRenameTimer)
+ wxDECLARE_NO_COPY_CLASS(wxTreeRenameTimer);
};
// control used for in-place edit
bool m_aboutToFinish;
DECLARE_EVENT_TABLE()
- DECLARE_NO_COPY_CLASS(wxTreeTextCtrl)
+ wxDECLARE_NO_COPY_CLASS(wxTreeTextCtrl);
};
// timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed
private:
wxGenericTreeCtrl *m_owner;
- DECLARE_NO_COPY_CLASS(wxTreeFindTimer)
+ wxDECLARE_NO_COPY_CLASS(wxTreeFindTimer);
};
// a tree item
unsigned int m_isBold :1; // render the label in bold font
unsigned int m_ownsAttr :1; // delete attribute when done
- DECLARE_NO_COPY_CLASS(wxGenericTreeItem)
+ wxDECLARE_NO_COPY_CLASS(wxGenericTreeItem);
};
// =============================================================================
m_owner = owner;
m_aboutToFinish = false;
- int w = m_itemEdited->GetWidth(),
- h = m_itemEdited->GetHeight();
-
- int x, y;
- m_owner->CalcScrolledPosition(item->GetX(), item->GetY(), &x, &y);
-
- int image_h = 0,
- image_w = 0;
-
- 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!"));
- }
- }
+ wxRect rect;
+ m_owner->GetBoundingRect(m_itemEdited, rect, 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 )
- {
- int diff = h - ( bs.y - 8 ) ;
- h -= diff ;
- y += diff / 2 ;
- }
-#endif
+ // 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
(void)Create(m_owner, wxID_ANY, m_startValue,
- wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8));
+ rect.GetPosition(), rect.GetSize());
+
+ SetSelection(-1, -1);
}
void wxTreeTextCtrl::EndEdit(bool discardChanges)
wxPoint myPos = GetPosition();
wxSize mySize = GetSize();
int sx, sy;
- GetTextExtent(GetValue() + _T("M"), &sx, &sy);
+ GetTextExtent(GetValue() + wxT("M"), &sx, &sy);
if (myPos.x + sx > parentSize.x)
sx = parentSize.x - myPos.x;
if (mySize.x > sx)
m_parent = parent;
- m_attr = (wxTreeItemAttr *)NULL;
+ m_attr = NULL;
m_ownsAttr = false;
// We don't know the height here yet.
}
// if children are expanded, fall through to evaluate them
- if (m_isCollapsed) return (wxGenericTreeItem*) NULL;
+ if (m_isCollapsed) return NULL;
}
// evaluate children
return res;
}
- return (wxGenericTreeItem*) NULL;
+ return NULL;
}
int wxGenericTreeItem::GetCurrentImage() const
int text_h = m_heightText + 2;
- int image_h = 0;
- int image_w = 0;
+ int image_h = 0, image_w = 0;
int image = GetCurrentImage();
- if ( image != NO_IMAGE )
+ if ( image != NO_IMAGE && control->m_imageListNormal )
{
- if ( control->m_imageListNormal )
- {
- control->m_imageListNormal->GetSize( image, image_w, image_h );
- image_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
- }
+ 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 )
+ if ( state != wxTREE_ITEMSTATE_NONE && control->m_imageListState )
{
- if ( control->m_imageListState )
- {
- control->m_imageListState->GetSize( state, state_w, state_h );
- if ( image != NO_IMAGE )
- state_w += MARGIN_BETWEEN_STATE_AND_IMAGE;
- else
- state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
- }
+ control->m_imageListState->GetSize(state, state_w, state_h);
+ if ( image_w != 0 )
+ state_w += MARGIN_BETWEEN_STATE_AND_IMAGE;
else
- {
- state = wxTREE_ITEMSTATE_NONE;
- }
+ state_w += MARGIN_BETWEEN_IMAGE_AND_TEXT;
}
- m_height = (image_h > text_h) ? image_h : text_h;
+ 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
m_current =
m_key_current =
m_anchor =
- m_select_me = (wxGenericTreeItem *) NULL;
+ m_select_me = NULL;
m_hasFocus = false;
m_dirty = false;
m_dropEffectAboveItem = false;
+ m_dndEffect = NoEffect;
+ m_dndEffectItem = NULL;
+
m_lastOnSame = false;
#if defined( __WXMAC__ )
-#if wxOSX_USE_CARBON
- m_normalFont.MacCreateFromThemeFont( kThemeViewsFont ) ;
-#else
- m_normalFont.MacCreateFromUIFont( kCTFontViewsFontType ) ;
-#endif
+ m_normalFont = wxFont(wxOSX_SYSTEM_FONT_VIEWS);
#else
m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
#endif
if (major < 10)
style |= wxTR_ROW_LINES;
+
+ if (style & wxTR_HAS_BUTTONS)
+ style |= wxTR_NO_LINES;
#endif // __WXMAC__
+#ifdef __WXGTK20__
+ if (style & wxTR_HAS_BUTTONS)
+ style |= wxTR_NO_LINES;
+#endif
+
if ( !wxControl::Create( parent, id, pos, size,
style|wxHSCROLL|wxVSCROLL,
validator,
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 )
{
wxGenericTreeItem *parent = item->GetParent();
+ // if the selected item will be deleted, select the parent ...
+ wxGenericTreeItem *to_be_selected = parent;
+ if (parent)
+ {
+ // .. unless there is a next sibling like wxMSW does it
+ int pos = parent->GetChildren().Index( item );
+ if ((int)(parent->GetChildren().GetCount()) > pos+1)
+ to_be_selected = parent->GetChildren().Item( pos+1 );
+ }
+
// don't keep stale pointers around!
if ( IsDescendantOf(item, m_key_current) )
{
// a different item, in idle time.
if ( m_select_me && IsDescendantOf(item, m_select_me) )
{
- m_select_me = parent;
+ m_select_me = to_be_selected;
}
if ( IsDescendantOf(item, m_current) )
// m_current = parent;
m_current = NULL;
- m_select_me = parent;
+ m_select_me = to_be_selected;
}
// remove the item from the tree
{
wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
- wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") );
+ wxCHECK_RET( item, wxT("invalid item in wxGenericTreeCtrl::Expand") );
wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
- _T("can't expand hidden root") );
+ wxT("can't expand hidden root") );
if ( !item->HasPlus() )
return;
void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
{
wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
- _T("can't collapse hidden root") );
+ wxT("can't collapse hidden root") );
wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
}
}
+void wxGenericTreeCtrl::ClearFocusedItem()
+{
+ wxTreeItemId item = GetFocusedItem();
+ if ( item.IsOk() )
+ SelectItem(item, false);
+}
+
+void wxGenericTreeCtrl::SetFocusedItem(const wxTreeItemId& item)
+{
+ wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+ SelectItem(item, true);
+}
+
void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
{
if (item->IsSelected())
}
}
+void wxGenericTreeCtrl::SelectChildren(const wxTreeItemId& parent)
+{
+ wxCHECK_RET( HasFlag(wxTR_MULTIPLE),
+ "this only works with multiple selection controls" );
+
+ UnselectAll();
+
+ if ( !HasChildren(parent) )
+ return;
+
+
+ wxArrayGenericTreeItems&
+ children = ((wxGenericTreeItem*) parent.m_pItem)->GetChildren();
+ size_t count = children.GetCount();
+
+ wxGenericTreeItem *
+ item = (wxGenericTreeItem*) ((wxTreeItemId)children[0]).m_pItem;
+ wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+ event.m_itemOld = m_current;
+
+ if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
+ return;
+
+ for ( size_t n = 0; n < count; ++n )
+ {
+ m_current = m_key_current = children[n];
+ m_current->SetHilight(true);
+ RefreshSelected();
+ }
+
+
+ event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+ GetEventHandler()->ProcessEvent( event );
+}
+
+
// Recursive function !
// To stop we must have crt_item<last_item
// Algorithm :
void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
{
+ wxGenericTreeItem * const item = (wxGenericTreeItem*) itemId.m_pItem;
+ wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
+
if ( select )
{
- DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE));
+ if ( !item->IsSelected() )
+ DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE));
}
else // deselect
{
- 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;
void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
{
- if (!item.IsOk()) return;
+ if (!item.IsOk())
+ return;
- // We have to call this here because the label in
- // question might just have been added and no screen
- // update taken place.
+ // update the control before scrolling it
if (m_dirty)
#if defined( __WXMSW__ ) || defined(__WXMAC__)
Update();
#else
DoDirtyProcessing();
#endif
+
wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
- // now scroll to the item
- int item_y = gitem->GetY();
+ int itemY = gitem->GetY();
int start_x = 0;
int start_y = 0;
GetViewStart( &start_x, &start_y );
- start_y *= PIXELS_PER_UNIT;
- int client_h = 0;
- int client_w = 0;
- GetClientSize( &client_w, &client_h );
+ const int clientHeight = GetClientSize().y;
+
+ const int itemHeight = GetLineHeight(gitem) + 2;
- if (item_y < start_y+3)
+ if ( itemY + itemHeight > start_y*PIXELS_PER_UNIT + clientHeight )
{
- // going down
- int x = 0;
- int y = 0;
- m_anchor->GetSize( x, y, this );
- y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
- 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 );
+ // need to scroll up by enough to show this item fully
+ itemY += itemHeight - clientHeight;
}
- else if (item_y+GetLineHeight(gitem) > start_y+client_h)
+ else if ( itemY > start_y*PIXELS_PER_UNIT )
{
- // going up
- int x = 0;
- int y = 0;
- m_anchor->GetSize( x, y, this );
- y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
- x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
- 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 );
+ // item is already fully visible, don't do anything
+ return;
}
+ //else: scroll down to make this item the top one displayed
+
+ Scroll(-1, itemY/PIXELS_PER_UNIT);
}
// FIXME: tree sorting functions are not reentrant and not MT-safe!
void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
{
item->SetFont(this, dc);
+ item->CalculateSize(this, dc);
wxCoord text_h = item->GetTextHeight();
{
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
{
if ( m_imageListState )
{
- m_imageListState->GetSize( state, state_w, state_h );
- if ( image != NO_IMAGE )
+ 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;
// 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 );
+ 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 );
// 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;
+ }
+ }
}
void
DrawLine(item, !m_dropEffectAboveItem );
}
- SetCursor(wxCURSOR_BULLSEYE);
+ SetCursor(*wxSTANDARD_CURSOR);
}
else
{
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)
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)
+ {
+ if (below)
+ m_dndEffect = BelowEffect;
+ else
+ m_dndEffect = AboveEffect;
+ m_dndEffectItem = i;
+ }
+ else
{
- y += GetLineHeight(i) - 1;
+ 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 );
}
// -----------------------------------------------------------------------------
// end : go to last item without opening parents
// alnum : start or continue searching for the item with this prefix
int keyCode = event.GetKeyCode();
+
+#ifdef __WXOSX__
+ // Make the keys work as they do in the native control:
+ // right => expand
+ // left => collapse if current item is expanded
+ if (keyCode == WXK_RIGHT)
+ {
+ keyCode = '+';
+ }
+ else if (keyCode == WXK_LEFT && IsExpanded(m_current))
+ {
+ keyCode = '-';
+ }
+#endif // __WXOSX__
+
switch ( keyCode )
{
case '+':
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
{
wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item,
wxClassInfo * WXUNUSED(textCtrlClass))
{
- wxCHECK_MSG( item.IsOk(), NULL, _T("can't edit an invalid item") );
+ wxCHECK_MSG( item.IsOk(), NULL, wxT("can't edit an invalid item") );
wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item),
bool discardChanges)
{
- wxCHECK_RET( m_textCtrl, _T("not editing label") );
+ wxCHECK_RET( m_textCtrl, wxT("not editing label") );
m_textCtrl->EndEdit(discardChanges);
}
#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__)
Update();
#else
+ // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI)
+ // instead (needs to be tested!)
wxYieldIfNeeded();
#endif
}
{
m_oldSelection->SetHilight(true);
RefreshLine(m_oldSelection);
- m_oldSelection = (wxGenericTreeItem *)NULL;
+ m_oldSelection = NULL;
}
// generate the drag end event
(void)GetEventHandler()->ProcessEvent(eventEndDrag);
m_isDragging = false;
- m_dropTarget = (wxGenericTreeItem *)NULL;
+ m_dropTarget = NULL;
SetCursor(m_oldCursor);
-#if defined( __WXMSW__ ) || defined(__WXMAC__)
+#if defined( __WXMSW__ ) || defined(__WXMAC__) || defined(__WXGTK20__)
Update();
#else
+ // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI)
+ // instead (needs to be tested!)
wxYieldIfNeeded();
#endif
}
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;