rect.y -= 2;
rect.width += 8;
rect.height += 4;
-#elif defined(__WXMAC__)
+#elif defined(wxOSX_USE_CARBON) && wxOSX_USE_CARBON
int bestHeight = GetBestSize().y - 8;
if ( rect.height > bestHeight )
{
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)
EVT_PAINT (wxGenericTreeCtrl::OnPaint)
EVT_SIZE (wxGenericTreeCtrl::OnSize)
EVT_MOUSE_EVENTS (wxGenericTreeCtrl::OnMouse)
+ EVT_KEY_DOWN (wxGenericTreeCtrl::OnKeyDown)
EVT_CHAR (wxGenericTreeCtrl::OnChar)
EVT_SET_FOCUS (wxGenericTreeCtrl::OnSetFocus)
EVT_KILL_FOCUS (wxGenericTreeCtrl::OnKillFocus)
EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip)
END_EVENT_TABLE()
-#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__)
-/*
- * wxTreeCtrl has to be a real class or we have problems with
- * the run-time information.
- */
-
-IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl)
-#endif
-
// -----------------------------------------------------------------------------
// construction/destruction
// -----------------------------------------------------------------------------
m_lastOnSame = false;
#if defined( __WXMAC__ )
-#if wxOSX_USE_ATSU_TEXT
- 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
- m_boldFont = wxFont(m_normalFont.GetPointSize(),
- m_normalFont.GetFamily(),
- m_normalFont.GetStyle(),
- wxBOLD,
- m_normalFont.GetUnderlined(),
- m_normalFont.GetFaceName(),
- m_normalFont.GetEncoding());
+ m_boldFont = m_normalFont.Bold();
}
bool wxGenericTreeCtrl::Create(wxWindow *parent,
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,
{
wxTreeCtrlBase::SetFont(font);
- m_normalFont = font ;
- m_boldFont = wxFont(m_normalFont.GetPointSize(),
- m_normalFont.GetFamily(),
- m_normalFont.GetStyle(),
- wxBOLD,
- m_normalFont.GetUnderlined(),
- m_normalFont.GetFaceName(),
- m_normalFont.GetEncoding());
+ m_normalFont = font;
+ m_boldFont = m_normalFont.Bold();
if (m_anchor)
m_anchor->RecursiveResetTextSize();
wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
{
- wxTreeItemId id = GetRootItem();
- if (!id.IsOk())
- return id;
+ wxTreeItemId itemid = GetRootItem();
+ if (!itemid.IsOk())
+ return itemid;
do
{
- if (IsVisible(id))
- return id;
- id = GetNext(id);
- } while (id.IsOk());
+ if (IsVisible(itemid))
+ return itemid;
+ itemid = GetNext(itemid);
+ } while (itemid.IsOk());
return wxTreeItemId();
}
// allows to switch between two items starting with the same letter just by
// pressing it) but we shouldn't jump to the next one if the user is
// continuing to type as otherwise he might easily skip the item he wanted
- wxTreeItemId id = idParent;
+ wxTreeItemId itemid = idParent;
if ( prefix.length() == 1 )
{
- id = GetNext(id);
+ itemid = GetNext(itemid);
}
// look for the item starting with the given prefix after it
- while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) )
+ while ( itemid.IsOk() && !GetItemText(itemid).Lower().StartsWith(prefix) )
{
- id = GetNext(id);
+ itemid = GetNext(itemid);
}
// if we haven't found anything...
- if ( !id.IsOk() )
+ if ( !itemid.IsOk() )
{
// ... wrap to the beginning
- id = GetRootItem();
+ itemid = GetRootItem();
if ( HasFlag(wxTR_HIDE_ROOT) )
{
// can't select virtual root
- id = GetNext(id);
+ itemid = GetNext(itemid);
}
// 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 ( itemid.IsOk() && itemid != idParent &&
+ !GetItemText(itemid).Lower().StartsWith(prefix) )
{
- id = GetNext(id);
+ itemid = GetNext(itemid);
}
// If we haven't found the item, id.IsOk() will be false, as per
// documentation
}
- return id;
+ return itemid;
}
// -----------------------------------------------------------------------------
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;
- if (item_y < start_y+3)
+ const int itemHeight = GetLineHeight(gitem) + 2;
+
+ 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!
#ifdef __WXMAC__
colText = *wxWHITE;
#else
- colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ if (m_hasFocus)
+ colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+ else
+ colText = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT);
#endif
}
else
event.Skip();
}
-void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
+void wxGenericTreeCtrl::OnKeyDown( wxKeyEvent &event )
{
+ // send a tree event
wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this);
te.m_evtKey = event;
if ( GetEventHandler()->ProcessEvent( te ) )
- {
- // intercepted by the user code
return;
- }
+ event.Skip();
+}
+
+void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
+{
if ( (m_current == 0) || (m_key_current == 0) )
{
event.Skip();
// 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 '+':
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
}
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
}
event.Skip(!GetEventHandler()->ProcessEvent(nevent));
// Consistent with MSW (for now), send the ITEM_MENU *after*
- // the RIGHT_CLICK event. TODO: This behavior may change.
+ // the RIGHT_CLICK event. TODO: This behaviour may change.
wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU, this, item);
nevent2.m_pointDrag = CalcScrolledPosition(pt);
GetEventHandler()->ProcessEvent(nevent2);