added incremental keyboard search to wxTreeCtrl

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@15741 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2002-06-04 15:00:57 +00:00
parent b0a2d8a882
commit cb59313ce5
3 changed files with 136 additions and 41 deletions

View File

@@ -167,6 +167,7 @@ All (GUI):
- added wxTextCtrl::EmulateKeyPress() - added wxTextCtrl::EmulateKeyPress()
- Added wxMouseCaptureChangedEvent - Added wxMouseCaptureChangedEvent
- Added custom character filtering to wxTextValidator - Added custom character filtering to wxTextValidator
- wxTreeCtrl now supports incremental keyboard search
wxMSW: wxMSW:

View File

@@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
// Name: treectrl.h // Name: wx/generic/treectlg.h
// Purpose: wxTreeCtrl class // Purpose: wxTreeCtrl class
// Author: Robert Roebling // Author: Robert Roebling
// Modified by: // Modified by:
@@ -31,6 +31,7 @@ class WXDLLEXPORT wxGenericTreeItem;
class WXDLLEXPORT wxTreeItemData; class WXDLLEXPORT wxTreeItemData;
class WXDLLEXPORT wxTreeRenameTimer; class WXDLLEXPORT wxTreeRenameTimer;
class WXDLLEXPORT wxTreeFindTimer;
class WXDLLEXPORT wxTreeTextCtrl; class WXDLLEXPORT wxTreeTextCtrl;
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -341,21 +342,19 @@ public:
void OnIdle( wxIdleEvent &event ); void OnIdle( wxIdleEvent &event );
// implementation helpers // implementation helpers
void SendDeleteEvent(wxGenericTreeItem *itemBeingDeleted);
void DrawBorder(const wxTreeItemId& item);
void DrawLine(const wxTreeItemId& item, bool below);
protected: protected:
friend class wxGenericTreeItem; friend class wxGenericTreeItem;
friend class wxTreeRenameTimer; friend class wxTreeRenameTimer;
friend class wxTreeFindTimer;
friend class wxTreeTextCtrl; friend class wxTreeTextCtrl;
wxFont m_normalFont; wxFont m_normalFont;
wxFont m_boldFont; wxFont m_boldFont;
wxGenericTreeItem *m_anchor; wxGenericTreeItem *m_anchor;
wxGenericTreeItem *m_current, *m_key_current, *m_currentEdit; wxGenericTreeItem *m_current,
*m_key_current,
*m_currentEdit;
unsigned short m_indent; unsigned short m_indent;
unsigned short m_spacing; unsigned short m_spacing;
int m_lineHeight; int m_lineHeight;
@@ -383,22 +382,36 @@ protected:
wxTimer *m_renameTimer; wxTimer *m_renameTimer;
wxString m_renameRes; wxString m_renameRes;
wxBitmap *m_arrowRight,*m_arrowDown; wxBitmap *m_arrowRight,
*m_arrowDown;
// incremental search data
wxString m_findPrefix;
wxTimer *m_findTimer;
// the common part of all ctors // the common part of all ctors
void Init(); void Init();
// misc helpers // misc helpers
void SendDeleteEvent(wxGenericTreeItem *itemBeingDeleted);
void DrawBorder(const wxTreeItemId& item);
void DrawLine(const wxTreeItemId& item, bool below);
void DrawDropEffect(wxGenericTreeItem *item);
wxTreeItemId DoInsertItem(const wxTreeItemId& parent, wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
size_t previous, size_t previous,
const wxString& text, const wxString& text,
int image, int selectedImage, int image, int selectedImage,
wxTreeItemData *data); wxTreeItemData *data);
// find the first item starting with the given prefix after the given item
wxTreeItemId FindItem(const wxTreeItemId& id, const wxString& prefix) const;
bool HasButtons(void) const bool HasButtons(void) const
{ return (m_imageListButtons != NULL) { return (m_imageListButtons != NULL)
|| HasFlag(wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); } || HasFlag(wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
protected:
void CalculateLineHeight(); void CalculateLineHeight();
int GetLineHeight(wxGenericTreeItem *item) const; int GetLineHeight(wxGenericTreeItem *item) const;
void PaintLevel( wxGenericTreeItem *item, wxDC& dc, int level, int &y ); void PaintLevel( wxGenericTreeItem *item, wxDC& dc, int level, int &y );
@@ -426,8 +439,6 @@ protected:
bool TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select); bool TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTreeItem *last_item, bool select);
void UnselectAllChildren( wxGenericTreeItem *item ); void UnselectAllChildren( wxGenericTreeItem *item );
void DrawDropEffect(wxGenericTreeItem *item);
private: private:
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
DECLARE_DYNAMIC_CLASS(wxGenericTreeCtrl) DECLARE_DYNAMIC_CLASS(wxGenericTreeCtrl)

View File

@@ -45,7 +45,6 @@
class WXDLLEXPORT wxGenericTreeItem; class WXDLLEXPORT wxGenericTreeItem;
WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems); WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
//WX_DEFINE_OBJARRAY(wxArrayTreeItemIds);
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// constants // constants
@@ -53,7 +52,7 @@ WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
static const int NO_IMAGE = -1; static const int NO_IMAGE = -1;
#define PIXELS_PER_UNIT 10 static const int PIXELS_PER_UNIT = 10;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Aqua arrows // Aqua arrows
@@ -111,9 +110,13 @@ static const char *aqua_arrow_down[] = {
class WXDLLEXPORT wxTreeRenameTimer: public wxTimer class WXDLLEXPORT wxTreeRenameTimer: public wxTimer
{ {
public: public:
// start editing the current item after half a second (if the mouse hasn't
// been clicked/moved)
static const int DELAY = 500;
wxTreeRenameTimer( wxGenericTreeCtrl *owner ); wxTreeRenameTimer( wxGenericTreeCtrl *owner );
void Notify(); virtual void Notify();
private: private:
wxGenericTreeCtrl *m_owner; wxGenericTreeCtrl *m_owner;
@@ -149,6 +152,22 @@ private:
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };
// timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed
// for a sufficiently long time
class WXDLLEXPORT wxTreeFindTimer : public wxTimer
{
public:
// reset the current prefix after half a second of inactivity
static const int DELAY = 500;
wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; }
virtual void Notify() { m_owner->m_findPrefix.clear(); }
private:
wxGenericTreeCtrl *m_owner;
};
// a tree item // a tree item
class WXDLLEXPORT wxGenericTreeItem class WXDLLEXPORT wxGenericTreeItem
{ {
@@ -694,7 +713,9 @@ void wxGenericTreeCtrl::Init()
m_isDragging = FALSE; m_isDragging = FALSE;
m_dropTarget = m_oldSelection = (wxGenericTreeItem *)NULL; m_dropTarget = m_oldSelection = (wxGenericTreeItem *)NULL;
m_renameTimer = new wxTreeRenameTimer( this ); m_renameTimer = NULL;
m_findTimer = NULL;
m_lastOnSame = FALSE; m_lastOnSame = FALSE;
m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
@@ -768,15 +789,20 @@ wxGenericTreeCtrl::~wxGenericTreeCtrl()
delete m_hilightBrush; delete m_hilightBrush;
delete m_hilightUnfocusedBrush; delete m_hilightUnfocusedBrush;
if (m_arrowRight) delete m_arrowRight; delete m_arrowRight;
if (m_arrowDown) delete m_arrowDown; delete m_arrowDown;
DeleteAllItems(); DeleteAllItems();
delete m_renameTimer; delete m_renameTimer;
if (m_ownsImageListNormal) delete m_imageListNormal; delete m_findTimer;
if (m_ownsImageListState) delete m_imageListState;
if (m_ownsImageListButtons) delete m_imageListButtons; if (m_ownsImageListNormal)
delete m_imageListNormal;
if (m_ownsImageListState)
delete m_imageListState;
if (m_ownsImageListButtons)
delete m_imageListButtons;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -1160,6 +1186,25 @@ wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
return wxTreeItemId(); return wxTreeItemId();
} }
// find the first item starting with the given prefix after the given item
wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
const wxString& prefixOrig) const
{
// match is case insensitive as this is more convenient to the user: having
// to press Shift-letter to go to the item starting with a capital letter
// would be too bothersome
wxString prefix = prefixOrig.Lower();
wxTreeItemId id = idParent;
while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) )
{
id = GetNext(id);
}
return id;
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// operations // operations
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -2363,7 +2408,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
// right : open if parent and go next // right : open if parent and go next
// home : go to root // home : go to root
// end : go to last item without opening parents // end : go to last item without opening parents
switch (event.KeyCode()) // alnum : start or continue searching for the item with this prefix
int keyCode = event.KeyCode();
switch ( keyCode )
{ {
case '+': case '+':
case WXK_ADD: case WXK_ADD:
@@ -2423,7 +2470,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
// otherwise we return to where we came from // otherwise we return to where we came from
SelectItem( prev, unselect_others, extended_select ); SelectItem( prev, unselect_others, extended_select );
m_key_current= (wxGenericTreeItem*) prev.m_pItem; m_key_current= (wxGenericTreeItem*) prev.m_pItem;
EnsureVisible( prev );
break; break;
} }
} }
@@ -2441,7 +2487,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
SelectItem( prev, unselect_others, extended_select ); SelectItem( prev, unselect_others, extended_select );
m_key_current=(wxGenericTreeItem*) prev.m_pItem; m_key_current=(wxGenericTreeItem*) prev.m_pItem;
EnsureVisible( prev );
} }
} }
break; break;
@@ -2457,7 +2502,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
} }
if (prev) if (prev)
{ {
EnsureVisible( prev );
SelectItem( prev, unselect_others, extended_select ); SelectItem( prev, unselect_others, extended_select );
} }
} }
@@ -2477,7 +2521,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
wxTreeItemId child = GetFirstChild( m_key_current, cookie ); wxTreeItemId child = GetFirstChild( m_key_current, cookie );
SelectItem( child, unselect_others, extended_select ); SelectItem( child, unselect_others, extended_select );
m_key_current=(wxGenericTreeItem*) child.m_pItem; m_key_current=(wxGenericTreeItem*) child.m_pItem;
EnsureVisible( child );
} }
else else
{ {
@@ -2495,7 +2538,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
{ {
SelectItem( next, unselect_others, extended_select ); SelectItem( next, unselect_others, extended_select );
m_key_current=(wxGenericTreeItem*) next.m_pItem; m_key_current=(wxGenericTreeItem*) next.m_pItem;
EnsureVisible( next );
} }
} }
} }
@@ -2521,7 +2563,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
if ( last.IsOk() ) if ( last.IsOk() )
{ {
EnsureVisible( last );
SelectItem( last, unselect_others, extended_select ); SelectItem( last, unselect_others, extended_select );
} }
} }
@@ -2531,21 +2572,54 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
case WXK_HOME: case WXK_HOME:
{ {
wxTreeItemId prev = GetRootItem(); wxTreeItemId prev = GetRootItem();
if (!prev) break; if (!prev)
if (HasFlag(wxTR_HIDE_ROOT)) break;
if ( HasFlag(wxTR_HIDE_ROOT) )
{ {
long dummy; long dummy;
prev = GetFirstChild(prev, dummy); prev = GetFirstChild(prev, dummy);
if (!prev) break; if (!prev)
break;
} }
EnsureVisible( prev );
SelectItem( prev, unselect_others, extended_select ); SelectItem( prev, unselect_others, extended_select );
} }
break; break;
default: default:
// do not use wxIsalnum() here
if ( !event.HasModifiers() && isalnum(keyCode) )
{
// find the next item starting with the given prefix
char ch = (char)keyCode;
wxTreeItemId id = FindItem(m_current, m_findPrefix + ch);
if ( !id.IsOk() )
{
// no such item
break;
}
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
// to use this prefix for a new item search
if ( !m_findTimer )
{
m_findTimer = new wxTreeFindTimer(this);
}
m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT);
}
else
{
event.Skip(); event.Skip();
} }
}
} }
wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags) wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
@@ -2814,11 +2888,18 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
if ( (item == m_current) && if ( (item == m_current) &&
(flags & wxTREE_HITTEST_ONITEMLABEL) && (flags & wxTREE_HITTEST_ONITEMLABEL) &&
HasFlag(wxTR_EDIT_LABELS) ) HasFlag(wxTR_EDIT_LABELS) )
{
if ( m_renameTimer )
{ {
if ( m_renameTimer->IsRunning() ) if ( m_renameTimer->IsRunning() )
m_renameTimer->Stop(); m_renameTimer->Stop();
}
else
{
m_renameTimer = new wxTreeRenameTimer( this );
}
m_renameTimer->Start( 100, TRUE ); m_renameTimer->Start( wxTreeRenameTimer::DELAY, TRUE );
} }
m_lastOnSame = FALSE; m_lastOnSame = FALSE;
@@ -2858,7 +2939,9 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
if ( event.LeftDClick() ) if ( event.LeftDClick() )
{ {
// double clicking should not start editing the item label // double clicking should not start editing the item label
if ( m_renameTimer )
m_renameTimer->Stop(); m_renameTimer->Stop();
m_lastOnSame = FALSE; m_lastOnSame = FALSE;
// send activate event first // send activate event first