// Author: Robert Roebling
// Created: 01/02/97
// Modified: 22/10/98 - almost total rewrite, simpler interface (VZ)
-// Id: $Id$
// Copyright: (c) 1998 Robert Roebling and Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; }
- virtual void Notify() { m_owner->m_findPrefix.clear(); }
+ virtual void Notify() { m_owner->ResetFindState(); }
private:
wxGenericTreeCtrl *m_owner;
END_EVENT_TABLE()
wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
- wxGenericTreeItem *item)
- : m_itemEdited(item), m_startValue(item->GetText())
+ wxGenericTreeItem *itm)
+ : m_itemEdited(itm), m_startValue(itm->GetText())
{
m_owner = owner;
m_aboutToFinish = false;
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 )
{
(void)Create(m_owner, wxID_ANY, m_startValue,
rect.GetPosition(), rect.GetSize());
- SetSelection(-1, -1);
+ SelectAll();
}
void wxTreeTextCtrl::EndEdit(bool discardChanges)
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_renameTimer = NULL;
m_findTimer = NULL;
+ m_findBell = 0; // default is to not ring bell at all
m_dropEffectAboveItem = false;
m_lastOnSame = false;
#if defined( __WXMAC__ )
- m_normalFont.CreateSystemFont(wxOSX_SYSTEM_FONT_VIEWS);
+ 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,
#endif
if ( !wxControl::Create( parent, id, pos, size,
- style|wxHSCROLL|wxVSCROLL,
+ style|wxHSCROLL|wxVSCROLL|wxWANTS_CHARS,
validator,
name ) )
return false;
delete m_imageListButtons;
}
+void wxGenericTreeCtrl::EnableBellOnNoMatch( bool on )
+{
+ m_findBell = on;
+}
+
// -----------------------------------------------------------------------------
// accessors
// -----------------------------------------------------------------------------
{
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();
}
m_textCtrl = NULL;
}
+void wxGenericTreeCtrl::ResetFindState()
+{
+ m_findPrefix.clear();
+ if ( m_findBell )
+ m_findBell = 1;
+}
+
// find the first item starting with the given prefix after the given item
wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
const wxString& prefixOrig) const
// 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) )
+ {
+ itemid = GetNext(itemid);
+ }
+ // If we haven't found the item but wrapped back to the one we started
+ // from, id.IsOk() must be false
+ if ( itemid == idParent )
{
- id = GetNext(id);
+ itemid = wxTreeItemId();
}
- // If we haven't found the item, id.IsOk() will be false, as per
- // documentation
}
- return id;
+ return itemid;
}
// -----------------------------------------------------------------------------
void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
{
- wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item);
+ wxTreeEvent event(wxEVT_TREE_DELETE_ITEM, this, item);
GetEventHandler()->ProcessEvent( event );
}
if ( item->IsExpanded() )
return;
- wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item);
+ wxTreeEvent event(wxEVT_TREE_ITEM_EXPANDING, this, item);
if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
{
m_dirty = true;
}
- event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
+ event.SetEventType(wxEVT_TREE_ITEM_EXPANDED);
GetEventHandler()->ProcessEvent( event );
}
if ( !item->IsExpanded() )
return;
- wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, this, item);
+ wxTreeEvent event(wxEVT_TREE_ITEM_COLLAPSING, this, item);
if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
{
// cancelled by program
RefreshSubtree(item);
- event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
+ event.SetEventType(wxEVT_TREE_ITEM_COLLAPSED);
GetEventHandler()->ProcessEvent( event );
}
}
}
+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())
wxGenericTreeItem *
item = (wxGenericTreeItem*) ((wxTreeItemId)children[0]).m_pItem;
- wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+ wxTreeEvent event(wxEVT_TREE_SEL_CHANGING, this, item);
event.m_itemOld = m_current;
if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
}
- event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+ event.SetEventType(wxEVT_TREE_SEL_CHANGED);
GetEventHandler()->ProcessEvent( event );
}
if (crt_item==last_item)
return true;
- if (crt_item->HasChildren())
+ // We should leave the not shown children of collapsed items alone.
+ if (crt_item->HasChildren() && crt_item->IsExpanded())
{
wxArrayGenericTreeItems& children = crt_item->GetChildren();
size_t count = children.GetCount();
return;
}
- wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+ wxTreeEvent event(wxEVT_TREE_SEL_CHANGING, this, item);
event.m_itemOld = m_current;
// TODO : Here we don't send any selection mode yet !
// selection is set
EnsureVisible( itemId );
- event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+ event.SetEventType(wxEVT_TREE_SEL_CHANGED);
GetEventHandler()->ProcessEvent( event );
}
}
else // deselect
{
- wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+ wxTreeEvent event(wxEVT_TREE_SEL_CHANGING, this, item);
if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
return;
item->SetHilight(false);
RefreshLine(item);
- event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+ event.SetEventType(wxEVT_TREE_SEL_CHANGED);
GetEventHandler()->ProcessEvent( event );
}
}
// update the control before scrolling it
if (m_dirty)
-#if defined( __WXMSW__ ) || defined(__WXMAC__)
+ {
+#if defined( __WXMSW__ )
+ Update();
+#elif defined(__WXMAC__)
Update();
+ DoDirtyProcessing();
#else
DoDirtyProcessing();
#endif
-
+ }
+
wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
int itemY = gitem->GetY();
{
// need to scroll up by enough to show this item fully
itemY += itemHeight - clientHeight;
+#ifdef __WXOSX__
+ // because itemY below will be divided by PIXELS_PER_UNIT it may
+ // be rounded down, with the result of the item still only being
+ // partially visible, so make sure we are rounding up
+ itemY += PIXELS_PER_UNIT-1;
+#endif
}
else if ( itemY > start_y*PIXELS_PER_UNIT )
{
#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
yOrigin = abs(yOrigin);
GetClientSize(&width, &height);
- // Move end points to the begining/end of the view?
+ // Move end points to the beginning/end of the view?
if (y_mid < yOrigin)
y_mid = yOrigin;
if (oldY > yOrigin + height)
event.Skip();
}
-void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
+void wxGenericTreeCtrl::OnKeyDown( wxKeyEvent &event )
{
- wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this);
+ // send a tree event
+ wxTreeEvent te( wxEVT_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 '+':
GetBoundingRect(m_current, ItemRect, true);
wxTreeEvent
- eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU, this, m_current);
+ eventMenu(wxEVT_TREE_ITEM_MENU, this, m_current);
// Use the left edge, vertical middle
eventMenu.m_pointDrag = wxPoint(ItemRect.GetX(),
ItemRect.GetY() +
if ( !event.HasModifiers() )
{
wxTreeEvent
- eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current);
+ eventAct(wxEVT_TREE_ITEM_ACTIVATED, this, m_current);
GetEventHandler()->ProcessEvent( eventAct );
}
if ( !event.HasModifiers() &&
((keyCode >= '0' && keyCode <= '9') ||
(keyCode >= 'a' && keyCode <= 'z') ||
- (keyCode >= 'A' && keyCode <= 'Z' )))
+ (keyCode >= 'A' && keyCode <= 'Z') ||
+ (keyCode == '_')))
{
// find the next item starting with the given prefix
wxChar ch = (wxChar)keyCode;
+ wxTreeItemId id;
- wxTreeItemId id = FindItem(m_current, m_findPrefix + ch);
- if ( !id.IsOk() )
+ // if the same character is typed multiple times then go to the
+ // next entry starting with that character instead of searching
+ // for an item starting with multiple copies of this character,
+ // this is more useful and is how it works under Windows.
+ if ( m_findPrefix.length() == 1 && m_findPrefix[0] == ch )
{
- // no such item
- break;
+ id = FindItem(m_current, ch);
+ }
+ else
+ {
+ const wxString newPrefix(m_findPrefix + ch);
+ id = FindItem(m_current, newPrefix);
+ if ( id.IsOk() )
+ m_findPrefix = newPrefix;
}
-
- SelectItem(id);
-
- m_findPrefix += ch;
// also start the timer to reset the current prefix if the user
// doesn't press any more alnum keys soon -- we wouldn't want
m_findTimer = new wxTreeFindTimer(this);
}
+ // Notice that we should start the timer even if we didn't find
+ // anything to make sure we reset the search state later.
m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT);
+
+ if ( id.IsOk() )
+ {
+ SelectItem(id);
+
+ // Reset the bell flag if it had been temporarily disabled
+ // before.
+ if ( m_findBell )
+ m_findBell = 1;
+ }
+ else // No such item
+ {
+ // Signal it with a bell if enabled.
+ if ( m_findBell == 1 )
+ {
+ ::wxBell();
+
+ // Disable it for the next unsuccessful match, we only
+ // beep once, this is usually enough and continuing to
+ // do it would be annoying.
+ m_findBell = -1;
+ }
+ }
}
else
{
wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
- wxTreeEvent te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, this, itemEdit);
+ wxTreeEvent te(wxEVT_TREE_BEGIN_LABEL_EDIT, this, itemEdit);
if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
{
// vetoed by user
// question might just have been added and no screen
// update taken place.
if ( m_dirty )
-#if defined( __WXMSW__ ) || defined(__WXMAC__)
- Update();
-#else
DoDirtyProcessing();
-#endif
// TODO: use textCtrlClass here to create the control of correct class
m_textCtrl = new wxTreeTextCtrl(this, itemEdit);
bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
const wxString& value)
{
- wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item);
+ wxTreeEvent le(wxEVT_TREE_END_LABEL_EDIT, this, item);
le.m_label = value;
le.m_editCancelled = false;
void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item)
{
// let owner know that the edit was cancelled
- wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item);
+ wxTreeEvent le(wxEVT_TREE_END_LABEL_EDIT, this, item);
le.m_label = wxEmptyString;
le.m_editCancelled = true;
{
// Ask the tree control what tooltip (if any) should be shown
wxTreeEvent
- hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, this, hoverItem);
+ hevent(wxEVT_TREE_ITEM_GETTOOLTIP, this, hoverItem);
- if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() )
+ // setting a tooltip upon leaving a view is getting the tooltip displayed
+ // on the neighbouring view ...
+#ifdef __WXOSX__
+ if ( event.Leaving() )
+ SetToolTip(NULL);
+ else
+#endif
+ if ( GetEventHandler()->ProcessEvent(hevent) )
{
- SetToolTip(hevent.m_label);
+ // If the user permitted the tooltip change, update it, otherwise
+ // remove any old tooltip we might have.
+ if ( hevent.IsAllowed() )
+ SetToolTip(hevent.m_label);
+ else
+ SetToolTip(NULL);
}
}
#endif
}
wxEventType command = event.RightIsDown()
- ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
- : wxEVT_COMMAND_TREE_BEGIN_DRAG;
+ ? wxEVT_TREE_BEGIN_RDRAG
+ : wxEVT_TREE_BEGIN_DRAG;
wxTreeEvent nevent(command, this, m_current);
nevent.SetPoint(CalcScrolledPosition(pt));
}
// generate the drag end event
- wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG, this, item);
+ wxTreeEvent eventEndDrag(wxEVT_TREE_END_DRAG, this, item);
eventEndDrag.m_pointDrag = CalcScrolledPosition(pt);
}
wxTreeEvent
- nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, this, item);
+ nevent(wxEVT_TREE_ITEM_RIGHT_CLICK, this, item);
nevent.m_pointDrag = CalcScrolledPosition(pt);
event.Skip(!GetEventHandler()->ProcessEvent(nevent));
// Consistent with MSW (for now), send the ITEM_MENU *after*
- // the RIGHT_CLICK event. TODO: This behavior may change.
- wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU, this, item);
+ // the RIGHT_CLICK event. TODO: This behaviour may change.
+ wxTreeEvent nevent2(wxEVT_TREE_ITEM_MENU, this, item);
nevent2.m_pointDrag = CalcScrolledPosition(pt);
GetEventHandler()->ProcessEvent(nevent2);
}
else if ( event.MiddleDown() )
{
wxTreeEvent
- nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, this, item);
+ nevent(wxEVT_TREE_ITEM_MIDDLE_CLICK, this, item);
nevent.m_pointDrag = CalcScrolledPosition(pt);
event.Skip(!GetEventHandler()->ProcessEvent(nevent));
}
if (flags & wxTREE_HITTEST_ONITEMSTATEICON)
{
wxTreeEvent
- nevent(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, this, item);
+ nevent(wxEVT_TREE_STATE_IMAGE_CLICK, this, item);
GetEventHandler()->ProcessEvent(nevent);
}
// ==> LeftDown() || LeftDClick()
if ( event.LeftDown() )
{
- m_lastOnSame = item == m_current;
+ // If we click on an already selected item but do it to return
+ // the focus to the control, it shouldn't start editing the
+ // item label because it's too easy to start editing
+ // accidentally (and also because nobody else does it like
+ // this). So only set this flag, used to decide whether we
+ // should start editing the label later, if we already have
+ // focus.
+ m_lastOnSame = item == m_current && HasFocus();
}
if ( flags & wxTREE_HITTEST_ONITEMBUTTON )
// send activate event first
wxTreeEvent
- nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, item);
+ nevent(wxEVT_TREE_ITEM_ACTIVATED, this, item);
nevent.m_pointDrag = CalcScrolledPosition(pt);
if ( !GetEventHandler()->ProcessEvent( nevent ) )
{
return true;
}
-// Process the tooltip event, to speed up event processing.
-// Doesn't actually get a tooltip.
void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event )
{
- event.Veto();
+#if wxUSE_TOOLTIPS
+ wxTreeItemId itemId = event.GetItem();
+ const wxGenericTreeItem* const pItem = (wxGenericTreeItem*)itemId.m_pItem;
+
+ // Check if the item fits into the client area:
+ if ( pItem->GetX() + pItem->GetWidth() > GetClientSize().x )
+ {
+ // If it doesn't, show its full text in the tooltip.
+ event.SetLabel(pItem->GetText());
+ }
+ else
+#endif // wxUSE_TOOLTIPS
+ {
+ // veto processing the event, nixing any tooltip
+ event.Veto();
+ }
}