// Created: 01/02/97
// Modified: 22/10/98 - almost total rewrite, simpler interface (VZ)
// Id: $Id$
-// Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
+// Copyright: (c) 1998 Robert Roebling and Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// headers
// -----------------------------------------------------------------------------
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "treectlg.h"
#endif
#include "wx/settings.h"
#include "wx/dcclient.h"
+#include "wx/renderer.h"
+
+#ifdef __WXMAC__
+ #include "wx/mac/private.h"
+#endif
+
// -----------------------------------------------------------------------------
// array types
// -----------------------------------------------------------------------------
class WXDLLEXPORT wxGenericTreeItem;
-WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
+WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
// ----------------------------------------------------------------------------
// constants
static const int PIXELS_PER_UNIT = 10;
-// ----------------------------------------------------------------------------
-// Aqua arrows
-// ----------------------------------------------------------------------------
-
-/* XPM */
-static const char *aqua_arrow_right[] = {
-/* columns rows colors chars-per-pixel */
-"13 11 4 1",
-" c None",
-"b c #C0C0C0",
-"c c #707070",
-"d c #A0A0A0",
-/* pixels */
-" b ",
-" ddb ",
-" cccdb ",
-" cccccd ",
-" ccccccdb ",
-" ccccccccd",
-" ccccccdb ",
-" cccccb ",
-" cccdb ",
-" ddb ",
-" b "
-};
-
-/* XPM */
-static const char *aqua_arrow_down[] = {
-/* columns rows colors chars-per-pixel */
-"13 11 4 1",
-" c None",
-"b c #C0C0C0",
-"c c #707070",
-"d c #A0A0A0",
-/* pixels */
-" ",
-" ",
-" bdcccccccdb ",
-" dcccccccd ",
-" bcccccccb ",
-" dcccccd ",
-" bcccccb ",
-" bcccd ",
-" dcd ",
-" bcb ",
-" d "
-};
-
// -----------------------------------------------------------------------------
// private classes
// -----------------------------------------------------------------------------
private:
wxGenericTreeCtrl *m_owner;
+
+ DECLARE_NO_COPY_CLASS(wxTreeRenameTimer)
};
// control used for in-place edit
class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
{
public:
- wxTreeTextCtrl( wxWindow *parent,
- const wxWindowID id,
- bool *accept,
- wxString *res,
- wxGenericTreeCtrl *owner,
- const wxString &value = wxEmptyString,
- const wxPoint &pos = wxDefaultPosition,
- const wxSize &size = wxDefaultSize,
- int style = wxSIMPLE_BORDER,
- const wxValidator& validator = wxDefaultValidator,
- const wxString &name = wxTextCtrlNameStr );
+ wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item);
+ void StopEditing()
+ {
+ Finish();
+ m_owner->OnRenameCancelled(m_itemEdited);
+ }
+ const wxGenericTreeItem* item() const { return m_itemEdited; }
+
+protected:
void OnChar( wxKeyEvent &event );
void OnKeyUp( wxKeyEvent &event );
void OnKillFocus( wxFocusEvent &event );
+ bool AcceptChanges();
+ void Finish();
+
private:
- bool *m_accept;
- wxString *m_res;
wxGenericTreeCtrl *m_owner;
+ wxGenericTreeItem *m_itemEdited;
wxString m_startValue;
bool m_finished;
DECLARE_EVENT_TABLE()
+ DECLARE_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)
};
// a tree item
void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; }
void SetData(wxTreeItemData *data) { m_data = data; }
- void SetHasPlus(bool has = TRUE) { m_hasPlus = has; }
+ void SetHasPlus(bool has = true) { m_hasPlus = has; }
void SetBold(bool bold) { m_isBold = bold; }
void DeleteChildren(wxGenericTreeCtrl *tree = NULL);
// get count of all children (and grand children if 'recursively')
- size_t GetChildrenCount(bool recursively = TRUE) const;
+ size_t GetChildrenCount(bool recursively = true) const;
void Insert(wxGenericTreeItem *child, size_t index)
{ m_children.Insert(child, index); }
void GetSize( int &x, int &y, const wxGenericTreeCtrl* );
// 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 button's label
+ // true if the point belongs to the item's button, otherwise it lies
+ // on the item's label
wxGenericTreeItem *HitTest( const wxPoint& point,
const wxGenericTreeCtrl *,
int &flags,
int level );
- void Expand() { m_isCollapsed = FALSE; }
- void Collapse() { m_isCollapsed = TRUE; }
+ void Expand() { m_isCollapsed = false; }
+ void Collapse() { m_isCollapsed = true; }
- void SetHilight( bool set = TRUE ) { m_hasHilight = set; }
+ void SetHilight( bool set = true ) { m_hasHilight = set; }
// status inquiries
bool HasChildren() const { return !m_children.IsEmpty(); }
if ( !m_attr )
{
m_attr = new wxTreeItemAttr;
- m_ownsAttr = TRUE;
+ m_ownsAttr = true;
}
return *m_attr;
}
{
if ( m_ownsAttr ) delete m_attr;
m_attr = attr;
- m_ownsAttr = FALSE;
+ m_ownsAttr = false;
}
// set them and delete when done
void AssignAttributes(wxTreeItemAttr *attr)
{
SetAttributes(attr);
- m_ownsAttr = TRUE;
+ m_ownsAttr = true;
}
private:
// tree ctrl images for the normal, selected, expanded and
// expanded+selected states
- short m_images[wxTreeItemIcon_Max];
+ int m_images[wxTreeItemIcon_Max];
wxCoord m_x; // (virtual) offset from top
- short m_y; // (virtual) offset from left
- short m_width; // width of this item
- unsigned char m_height; // height of this item
+ wxCoord m_y; // (virtual) offset from left
+ int m_width; // width of this item
+ int m_height; // height of this item
// use bitfields to save size
int m_isCollapsed :1;
// children but has a [+] button
int m_isBold :1; // render the label in bold font
int m_ownsAttr :1; // delete attribute when done
+
+ DECLARE_NO_COPY_CLASS(wxGenericTreeItem)
};
// =============================================================================
unselect_others = !(extended_select || (ctrlDown && is_multiple));
}
+// check if the given item is under another one
+static bool IsDescendantOf(const wxGenericTreeItem *parent, const wxGenericTreeItem *item)
+{
+ while ( item )
+ {
+ if ( item == parent )
+ {
+ // item is a descendant of parent
+ return true;
+ }
+
+ item = item->GetParent();
+ }
+
+ return false;
+}
+
// -----------------------------------------------------------------------------
// wxTreeRenameTimer (internal)
// -----------------------------------------------------------------------------
EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus)
END_EVENT_TABLE()
-wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
- const wxWindowID id,
- bool *accept,
- wxString *res,
- wxGenericTreeCtrl *owner,
- const wxString &value,
- const wxPoint &pos,
- const wxSize &size,
- int style,
- const wxValidator& validator,
- const wxString &name )
- : wxTextCtrl( parent, id, value, pos, size, style, validator, name )
-{
- m_res = res;
- m_accept = accept;
+wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
+ wxGenericTreeItem *item)
+ : m_itemEdited(item), m_startValue(item->GetText())
+{
m_owner = owner;
- (*m_accept) = FALSE;
- (*m_res) = wxEmptyString;
- m_startValue = value;
- m_finished = FALSE;
+ m_finished = 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 += 4;
+ }
+ else
+ {
+ wxFAIL_MSG(_T("you must create an image list to use images!"));
+ }
+ }
+
+ // 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
+
+ (void)Create(m_owner, wxID_ANY, m_startValue,
+ wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8));
}
-void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
+bool wxTreeTextCtrl::AcceptChanges()
{
- if (event.m_keyCode == WXK_RETURN)
+ const wxString value = GetValue();
+
+ if ( value == m_startValue )
{
- (*m_accept) = TRUE;
- (*m_res) = GetValue();
+ // nothing changed, always accept
+ return true;
+ }
- if ((*m_res) != m_startValue)
- m_owner->OnRenameAccept();
+ if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
+ {
+ // vetoed by the user
+ return false;
+ }
- if (!wxPendingDelete.Member(this))
- wxPendingDelete.Append(this);
+ // accepted, do rename the item
+ m_owner->SetItemText(m_itemEdited, value);
- m_finished = TRUE;
- m_owner->SetFocus(); // This doesn't work. TODO.
+ return true;
+}
- return;
- }
- if (event.m_keyCode == WXK_ESCAPE)
+void wxTreeTextCtrl::Finish()
+{
+ if ( !m_finished )
{
- (*m_accept) = FALSE;
- (*m_res) = "";
+ m_owner->ResetTextControl();
+
+ wxPendingDelete.Append(this);
- if (!wxPendingDelete.Member(this))
- wxPendingDelete.Append(this);
+ m_finished = true;
- m_finished = TRUE;
m_owner->SetFocus(); // This doesn't work. TODO.
+ }
+}
- return;
+void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
+{
+ switch ( event.m_keyCode )
+ {
+ case WXK_RETURN:
+ if ( AcceptChanges() )
+ {
+ // Close the text control, changes were accepted
+ Finish();
+ }
+ // else do nothing, do not accept and do not close
+ break;
+
+ case WXK_ESCAPE:
+ StopEditing();
+ break;
+
+ default:
+ event.Skip();
}
- event.Skip();
}
void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
{
- if (m_finished)
+ if ( !m_finished )
{
- event.Skip();
- return;
+ // auto-grow the textctrl:
+ wxSize parentSize = m_owner->GetSize();
+ wxPoint myPos = GetPosition();
+ wxSize mySize = GetSize();
+ int sx, sy;
+ GetTextExtent(GetValue() + _T("M"), &sx, &sy);
+ if (myPos.x + sx > parentSize.x)
+ sx = parentSize.x - myPos.x;
+ if (mySize.x > sx)
+ sx = mySize.x;
+ SetSize(sx, wxDefaultCoord);
}
- // auto-grow the textctrl:
- wxSize parentSize = m_owner->GetSize();
- wxPoint myPos = GetPosition();
- wxSize mySize = GetSize();
- int sx, sy;
- GetTextExtent(GetValue() + _T("M"), &sx, &sy);
- if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
- if (mySize.x > sx) sx = mySize.x;
- SetSize(sx, -1);
-
event.Skip();
}
void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
{
- if (m_finished)
+ if ( !m_finished )
{
- event.Skip();
- return;
+ AcceptChanges();
+ // We must finish regardless of success, otherwise we'll get
+ // focus problems:
+ Finish();
}
- if (!wxPendingDelete.Member(this))
- wxPendingDelete.Append(this);
-
- (*m_accept) = TRUE;
- (*m_res) = GetValue();
-
- if ((*m_res) != m_startValue)
- m_owner->OnRenameAccept();
+ // We must let the native text control handle focus, too, otherwise
+ // it could have problems with the cursor (e.g., in wxGTK):
+ event.Skip();
}
// -----------------------------------------------------------------------------
m_data = data;
m_x = m_y = 0;
- m_isCollapsed = TRUE;
- m_hasHilight = FALSE;
- m_hasPlus = FALSE;
- m_isBold = FALSE;
+ m_isCollapsed = true;
+ m_hasHilight = false;
+ m_hasPlus = false;
+ m_isBold = false;
m_parent = parent;
m_attr = (wxTreeItemAttr *)NULL;
- m_ownsAttr = FALSE;
+ m_ownsAttr = false;
// We don't know the height here yet.
m_width = 0;
tree->SendDeleteEvent(child);
child->DeleteChildren(tree);
+ if (child == tree->m_select_me)
+ tree->m_select_me = NULL;
delete child;
}
else
flags |= wxTREE_HITTEST_ONITEMLOWERPART;
- // 5 is the size of the plus sign
int xCross = m_x - theCtrl->GetSpacing();
- if ((point.x > xCross-5) && (point.x < xCross+5) &&
- (point.y > y_mid-5) && (point.y < y_mid+5) &&
+#ifdef __WXMAC__
+ // according to the drawing code the triangels are drawn
+ // at -4 , -4 from the position up to +10/+10 max
+ if ((point.x > xCross-4) && (point.x < xCross+10) &&
+ (point.y > y_mid-4) && (point.y < y_mid+10) &&
HasPlus() && theCtrl->HasButtons() )
+#else
+ // 5 is the size of the plus sign
+ if ((point.x > xCross-6) && (point.x < xCross+6) &&
+ (point.y > y_mid-6) && (point.y < y_mid+6) &&
+ HasPlus() && theCtrl->HasButtons() )
+#endif
{
flags |= wxTREE_HITTEST_ONITEMBUTTON;
return this;
EVT_CHAR (wxGenericTreeCtrl::OnChar)
EVT_SET_FOCUS (wxGenericTreeCtrl::OnSetFocus)
EVT_KILL_FOCUS (wxGenericTreeCtrl::OnKillFocus)
- EVT_IDLE (wxGenericTreeCtrl::OnIdle)
+ EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip)
END_EVENT_TABLE()
-#if !defined(__WXMSW__) || defined(__WIN16__) || defined(__WXUNIVERSAL__)
+#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__)
/*
* wxTreeCtrl has to be a real class or we have problems with
* the run-time information.
void wxGenericTreeCtrl::Init()
{
- m_current = m_key_current = m_anchor = (wxGenericTreeItem *) NULL;
- m_hasFocus = FALSE;
- m_dirty = FALSE;
+ m_current = m_key_current = m_anchor = m_select_me = (wxGenericTreeItem *) NULL;
+ m_hasFocus = false;
+ m_dirty = false;
m_lineHeight = 10;
m_indent = 15;
m_imageListNormal = m_imageListButtons =
m_imageListState = (wxImageList *) NULL;
m_ownsImageListNormal = m_ownsImageListButtons =
- m_ownsImageListState = FALSE;
+ m_ownsImageListState = false;
m_dragCount = 0;
- m_isDragging = FALSE;
- m_dropTarget = m_oldSelection = (wxGenericTreeItem *)NULL;
+ m_isDragging = false;
+ m_dropTarget = m_oldSelection = NULL;
+ m_underMouse = NULL;
+ m_textCtrl = NULL;
m_renameTimer = NULL;
+ m_freezeCount = 0;
+
m_findTimer = NULL;
- m_lastOnSame = FALSE;
+ m_lastOnSame = false;
+#ifdef __WXMAC_CARBON__
+ m_normalFont.MacCreateThemeFont( kThemeViewsFont ) ;
+#else
m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
- m_boldFont = wxFont( m_normalFont.GetPointSize(),
- m_normalFont.GetFamily(),
- m_normalFont.GetStyle(),
- wxBOLD,
- m_normalFont.GetUnderlined());
+#endif
+ m_boldFont = wxFont(m_normalFont.GetPointSize(),
+ m_normalFont.GetFamily(),
+ m_normalFont.GetStyle(),
+ wxBOLD,
+ m_normalFont.GetUnderlined(),
+ m_normalFont.GetFaceName(),
+ m_normalFont.GetEncoding());
}
bool wxGenericTreeCtrl::Create(wxWindow *parent,
const wxPoint& pos,
const wxSize& size,
long style,
- const wxValidator &validator,
+ const wxValidator& wxVALIDATOR_PARAM(validator),
const wxString& name )
{
#ifdef __WXMAC__
int major,minor;
wxGetOsVersion( &major, &minor );
- if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
- if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
style &= ~wxTR_LINES_AT_ROOT;
style |= wxTR_NO_LINES;
if (major < 10)
style |= wxTR_ROW_LINES;
- if (major >= 10)
- style |= wxTR_AQUA_BUTTONS;
-#endif
-
- if (style & wxTR_AQUA_BUTTONS)
- {
- m_arrowRight = new wxBitmap( aqua_arrow_right );
- m_arrowDown = new wxBitmap( aqua_arrow_down );
- }
- else
- {
- m_arrowRight = NULL;
- m_arrowDown = NULL;
- }
+#endif // __WXMAC__
wxScrolledWindow::Create( parent, id, pos, size,
style|wxHSCROLL|wxVSCROLL, name );
SetValidator( validator );
#endif
- SetForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
- SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX) );
+ wxVisualAttributes attr = GetDefaultAttributes();
+ SetOwnForegroundColour( attr.colFg );
+ SetOwnBackgroundColour( attr.colBg );
+ if (!m_hasFont)
+ SetOwnFont(attr.font);
// m_dottedPen = wxPen( "grey", 0, wxDOT ); too slow under XFree86
m_dottedPen = wxPen( wxT("grey"), 0, 0 );
- return TRUE;
+ SetBestSize(size);
+
+ return true;
}
wxGenericTreeCtrl::~wxGenericTreeCtrl()
delete m_hilightBrush;
delete m_hilightUnfocusedBrush;
- delete m_arrowRight;
- delete m_arrowDown;
-
DeleteAllItems();
delete m_renameTimer;
size_t wxGenericTreeCtrl::GetCount() const
{
- return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
+ if ( !m_anchor )
+ {
+ // the tree is empty
+ return 0;
+ }
+
+ size_t count = m_anchor->GetChildrenCount();
+ if ( !HasFlag(wxTR_HIDE_ROOT) )
+ {
+ // take the root itself into account
+ count++;
+ }
+
+ return count;
}
void wxGenericTreeCtrl::SetIndent(unsigned int indent)
{
m_indent = (unsigned short) indent;
- m_dirty = TRUE;
+ m_dirty = true;
}
void wxGenericTreeCtrl::SetSpacing(unsigned int spacing)
{
m_spacing = (unsigned short) spacing;
- m_dirty = TRUE;
+ m_dirty = true;
}
-size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
+size_t
+wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
+ bool recursively) const
{
wxCHECK_MSG( item.IsOk(), 0u, wxT("invalid tree item") );
void wxGenericTreeCtrl::SetWindowStyle(const long styles)
{
- // right now, just sets the styles. Eventually, we may
- // want to update the inherited styles, but right now
- // none of the parents has updatable styles
+ if (!HasFlag(wxTR_HIDE_ROOT) && (styles & wxTR_HIDE_ROOT))
+ {
+ // if we will hide the root, make sure children are visible
+ m_anchor->SetHasPlus();
+ m_anchor->Expand();
+ CalculatePositions();
+ }
+
+ // right now, just sets the styles. Eventually, we may
+ // want to update the inherited styles, but right now
+ // none of the parents has updatable styles
m_windowStyle = styles;
- m_dirty = TRUE;
+ m_dirty = true;
}
// -----------------------------------------------------------------------------
return ((wxGenericTreeItem*) item.m_pItem)->GetData();
}
+wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const
+{
+ wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
+
+ wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+ return pItem->Attr().GetTextColour();
+}
+
+wxColour wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
+{
+ wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
+
+ wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+ return pItem->Attr().GetBackgroundColour();
+}
+
+wxFont wxGenericTreeCtrl::GetItemFont(const wxTreeItemId& item) const
+{
+ wxCHECK_MSG( item.IsOk(), wxNullFont, wxT("invalid tree item") );
+
+ wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+ return pItem->Attr().GetFont();
+}
+
void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
{
wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
{
wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+ if (data)
+ data->SetId( item );
+
((wxGenericTreeItem*) item.m_pItem)->SetData(data);
}
wxScrolledWindow::SetFont(font);
m_normalFont = font ;
- m_boldFont = wxFont( m_normalFont.GetPointSize(),
- m_normalFont.GetFamily(),
- m_normalFont.GetStyle(),
- wxBOLD,
- m_normalFont.GetUnderlined());
+ m_boldFont = wxFont(m_normalFont.GetPointSize(),
+ m_normalFont.GetFamily(),
+ m_normalFont.GetStyle(),
+ wxBOLD,
+ m_normalFont.GetUnderlined(),
+ m_normalFont.GetFaceName(),
+ m_normalFont.GetEncoding());
- return TRUE;
+ return true;
}
bool wxGenericTreeCtrl::IsVisible(const wxTreeItemId& item) const
{
- wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+ wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
// An item is only visible if it's not a descendant of a collapsed item
wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
while (parent)
{
if (!parent->IsExpanded())
- return FALSE;
+ return false;
parent = parent->GetParent();
}
wxRect rect;
if (!GetBoundingRect(item, rect))
- return FALSE;
+ return false;
if (rect.GetWidth() == 0 || rect.GetHeight() == 0)
- return FALSE;
+ return false;
if (rect.GetBottom() < 0 || rect.GetTop() > clientSize.y)
- return FALSE;
+ return false;
if (rect.GetRight() < 0 || rect.GetLeft() > clientSize.x)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
{
- wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+ wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
// consider that the item does have children if it has the "+" button: it
// might not have them (if it had never been expanded yet) but then it
bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const
{
- wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+ wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
return ((wxGenericTreeItem*) item.m_pItem)->IsExpanded();
}
bool wxGenericTreeCtrl::IsSelected(const wxTreeItemId& item) const
{
- wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+ wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
return ((wxGenericTreeItem*) item.m_pItem)->IsSelected();
}
bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const
{
- wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
+ wxCHECK_MSG( item.IsOk(), false, wxT("invalid tree item") );
return ((wxGenericTreeItem*) item.m_pItem)->IsBold();
}
// navigation
// -----------------------------------------------------------------------------
-wxTreeItemId wxGenericTreeCtrl::GetParent(const wxTreeItemId& item) const
+wxTreeItemId wxGenericTreeCtrl::GetItemParent(const wxTreeItemId& item) const
{
wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
return ((wxGenericTreeItem*) item.m_pItem)->GetParent();
}
-wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
+wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item,
+ wxTreeItemIdValue& cookie) const
{
wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
return GetNextChild(item, cookie);
}
-wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
+wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item,
+ wxTreeItemIdValue& cookie) const
+{
+ wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+
+ 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 *"
+ size_t *pIndex = (size_t *)&cookie;
+ if ( *pIndex < children.Count() )
+ {
+ return children.Item((*pIndex)++);
+ }
+ else
+ {
+ // there are no more of them
+ return wxTreeItemId();
+ }
+}
+
+#if WXWIN_COMPATIBILITY_2_4
+
+wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item,
+ long& cookie) const
+{
+ wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+
+ cookie = 0;
+ return GetNextChild(item, cookie);
+}
+
+wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item,
+ long& cookie) const
{
wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
}
}
+#endif // WXWIN_COMPATIBILITY_2_4
+
wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const
{
wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
do
{
toFind = GetNextSibling(p);
- p = GetParent(p);
+ p = GetItemParent(p);
} while (p.IsOk() && !toFind.IsOk());
return toFind;
}
return wxTreeItemId();
}
+// called by wxTextTreeCtrl when it marks itself for deletion
+void wxGenericTreeCtrl::ResetTextControl()
+{
+ m_textCtrl = NULL;
+}
+
// find the first item starting with the given prefix after the given item
wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
const wxString& prefixOrig) const
return AddRoot(text, image, selImage, data);
}
- m_dirty = TRUE; // do this first so stuff below doesn't cause flicker
+ m_dirty = true; // do this first so stuff below doesn't cause flicker
wxGenericTreeItem *item =
new wxGenericTreeItem( parent, text, image, selImage, data );
if ( data != NULL )
{
- data->m_pItem = (long) item;
+ data->m_pItem = item;
}
parent->Insert( item, previous );
{
wxCHECK_MSG( !m_anchor, wxTreeItemId(), wxT("tree can have only one root") );
- m_dirty = TRUE; // do this first so stuff below doesn't cause flicker
+ m_dirty = true; // do this first so stuff below doesn't cause flicker
m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text,
image, selImage, data);
if ( data != NULL )
{
- data->m_pItem = (long) m_anchor;
+ data->m_pItem = m_anchor;
}
if (HasFlag(wxTR_HIDE_ROOT))
if (!HasFlag(wxTR_MULTIPLE))
{
m_current = m_key_current = m_anchor;
- m_current->SetHilight( TRUE );
+ m_current->SetHilight( true );
}
return m_anchor;
void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
{
wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
- event.m_item = (long) item;
+ event.m_item = item;
event.SetEventObject( this );
ProcessEvent( event );
}
+// 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 (item != m_key_current && IsDescendantOf(item, m_key_current)) {
+ m_key_current = NULL;
+ }
+ if (IsDescendantOf(item, m_select_me)) {
+ m_select_me = item;
+ }
+ if (item != m_current && IsDescendantOf(item, m_current)) {
+ m_current = NULL;
+ m_select_me = item;
+ }
+}
+
void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
{
- m_dirty = TRUE; // do this first so stuff below doesn't cause flicker
+ m_dirty = true; // do this first so stuff below doesn't cause flicker
wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
+ ChildrenClosing(item);
item->DeleteChildren(this);
}
void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
{
- m_dirty = TRUE; // do this first so stuff below doesn't cause flicker
+ m_dirty = true; // do this first so stuff below doesn't cause flicker
wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
- // don't stay with invalid m_key_current or we will crash in
- // the next call to OnChar()
- bool changeKeyCurrent = FALSE;
- wxGenericTreeItem *itemKey = m_key_current;
- while ( itemKey )
+ if (m_textCtrl != NULL && IsDescendantOf(item, m_textCtrl->item()))
{
- if ( itemKey == item )
- {
- // m_key_current is a descendant of the item being deleted
- changeKeyCurrent = TRUE;
- break;
- }
- itemKey = itemKey->GetParent();
+ // can't delete the item being edited, cancel editing it first
+ m_textCtrl->StopEditing();
}
wxGenericTreeItem *parent = item->GetParent();
+
+ // don't keep stale pointers around!
+ if ( IsDescendantOf(item, m_key_current) )
+ {
+ // Don't silently change the selection:
+ // do it properly in idle time, so event
+ // handlers get called.
+
+ // m_key_current = parent;
+ m_key_current = NULL;
+ }
+
+ // m_select_me records whether we need to select
+ // a different item, in idle time.
+ if ( m_select_me && IsDescendantOf(item, m_select_me) )
+ {
+ m_select_me = parent;
+ }
+
+ if ( IsDescendantOf(item, m_current) )
+ {
+ // Don't silently change the selection:
+ // do it properly in idle time, so event
+ // handlers get called.
+
+ // m_current = parent;
+ m_current = NULL;
+ m_select_me = parent;
+ }
+
+ // remove the item from the tree
if ( parent )
{
parent->GetChildren().Remove( item ); // remove by value
}
-
- if ( changeKeyCurrent )
+ else // deleting the root
{
- // may be NULL or not
- m_key_current = parent;
+ // nothing will be left in the tree
+ m_anchor = NULL;
}
+ // and delete all of its children and the item itself now
item->DeleteChildren(this);
SendDeleteEvent(item);
+
+ if (item == m_select_me)
+ m_select_me = NULL;
+
delete item;
}
{
if ( m_anchor )
{
- m_dirty = TRUE;
-
- m_anchor->DeleteChildren(this);
- delete m_anchor;
-
- m_anchor = NULL;
+ Delete(m_anchor);
}
}
return;
wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
- event.m_item = (long) item;
+ event.m_item = item;
event.SetEventObject( this );
if ( ProcessEvent( event ) && !event.IsAllowed() )
void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
{
- Expand(item);
- if ( IsExpanded(item) )
+ if ( !HasFlag(wxTR_HIDE_ROOT) || item != GetRootItem())
{
- long cookie;
- wxTreeItemId child = GetFirstChild(item, cookie);
- while ( child.IsOk() )
- {
- ExpandAll(child);
+ Expand(item);
+ if ( !IsExpanded(item) )
+ return;
+ }
- child = GetNextChild(item, cookie);
- }
+ wxTreeItemIdValue cookie;
+ wxTreeItemId child = GetFirstChild(item, cookie);
+ while ( child.IsOk() )
+ {
+ ExpandAll(child);
+
+ child = GetNextChild(item, cookie);
}
}
return;
wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
- event.m_item = (long) item;
+ event.m_item = item;
event.SetEventObject( this );
if ( ProcessEvent( event ) && !event.IsAllowed() )
{
return;
}
+ ChildrenClosing(item);
item->Collapse();
#if 0 // TODO why should items be collapsed recursively?
{
if (m_current)
{
- m_current->SetHilight( FALSE );
+ m_current->SetHilight( false );
RefreshLine( m_current );
+
+ m_current = NULL;
+ m_select_me = NULL;
}
}
{
if (item->IsSelected())
{
- item->SetHilight(FALSE);
+ item->SetHilight(false);
RefreshLine(item);
}
size_t count = children.Count();
for (size_t n=(size_t)(index+1); n<count; ++n)
{
- if (TagAllChildrenUntilLast(children[n], last_item, select)) return TRUE;
+ if (TagAllChildrenUntilLast(children[n], last_item, select)) return true;
}
return TagNextChildren(parent, last_item, select);
RefreshLine(crt_item);
if (crt_item==last_item)
- return TRUE;
+ return true;
if (crt_item->HasChildren())
{
for ( size_t n = 0; n < count; ++n )
{
if (TagAllChildrenUntilLast(children[n], last_item, select))
- return TRUE;
+ return true;
}
}
- return FALSE;
+ return false;
}
void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeItem *item2)
{
- // item2 is not necessary after item1
- wxGenericTreeItem *first=NULL, *last=NULL;
+ m_select_me = NULL;
+ // item2 is not necessary after item1
// choice first' and 'last' between item1 and item2
- if (item1->GetY()<item2->GetY())
- {
- first=item1;
- last=item2;
- }
- else
- {
- first=item2;
- last=item1;
- }
+ wxGenericTreeItem *first= (item1->GetY()<item2->GetY()) ? item1 : item2;
+ wxGenericTreeItem *last = (item1->GetY()<item2->GetY()) ? item2 : item1;
bool select = m_current->IsSelected();
TagNextChildren(first,last,select);
}
-void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
- bool unselect_others,
- bool extended_select)
+void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId,
+ bool unselect_others,
+ bool extended_select)
{
wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
+ m_select_me = NULL;
+
bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE);
wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
{
if (item->IsSelected())
return; // nothing to do
- unselect_others = TRUE;
- extended_select = FALSE;
+ unselect_others = true;
+ extended_select = false;
}
else if ( unselect_others && item->IsSelected() )
{
}
wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
- event.m_item = (long) item;
- event.m_itemOld = (long) m_current;
+ event.m_item = item;
+ event.m_itemOld = m_current;
event.SetEventObject( this );
// TODO : Here we don't send any selection mode yet !
if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
return;
- wxTreeItemId parent = GetParent( itemId );
+ wxTreeItemId parent = GetItemParent( itemId );
while (parent.IsOk())
{
if (!IsExpanded(parent))
Expand( parent );
- parent = GetParent( parent );
+ parent = GetItemParent( parent );
}
EnsureVisible( itemId );
}
else
{
- bool select=TRUE; // the default
+ bool select = true; // the default
// Check if we need to toggle hilight (ctrl mode)
if (!unselect_others)
GetEventHandler()->ProcessEvent( event );
}
+void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
+{
+ if ( select )
+ {
+ DoSelectItem(itemId);
+ }
+ else // deselect
+ {
+ wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
+ wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
+
+ item->SetHilight(false);
+ RefreshLine(item);
+ }
+}
+
void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item,
wxArrayTreeItemIds &array) const
{
void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
{
+ wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
if (!item.IsOk()) return;
wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
if ( HasFlag(wxTR_HIDE_ROOT) )
{
- while ( parent != m_anchor )
+ while ( parent && parent != m_anchor )
{
Expand(parent);
parent = parent->GetParent();
// We have to call this here because the label in
// question might just have been added and no screen
// update taken place.
- if (m_dirty) wxYieldIfNeeded();
-
+ if (m_dirty)
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+ Update();
+#else
+ wxYieldIfNeeded();
+#endif
wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
// now scroll to the item
wxArrayGenericTreeItems& children = item->GetChildren();
if ( children.Count() > 1 )
{
- m_dirty = TRUE;
+ m_dirty = true;
s_treeBeingSorted = this;
children.Sort(tree_ctrl_compare_func);
{
if (m_ownsImageListNormal) delete m_imageListNormal;
m_imageListNormal = imageList;
- m_ownsImageListNormal = FALSE;
- m_dirty = TRUE;
+ m_ownsImageListNormal = false;
+ m_dirty = true;
// 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)
{
if (m_ownsImageListState) delete m_imageListState;
m_imageListState = imageList;
- m_ownsImageListState = FALSE;
+ m_ownsImageListState = false;
}
void wxGenericTreeCtrl::SetButtonsImageList(wxImageList *imageList)
{
if (m_ownsImageListButtons) delete m_imageListButtons;
m_imageListButtons = imageList;
- m_ownsImageListButtons = FALSE;
- m_dirty = TRUE;
+ m_ownsImageListButtons = false;
+ m_dirty = true;
CalculateLineHeight();
}
void wxGenericTreeCtrl::AssignImageList(wxImageList *imageList)
{
SetImageList(imageList);
- m_ownsImageListNormal = TRUE;
+ m_ownsImageListNormal = true;
}
void wxGenericTreeCtrl::AssignStateImageList(wxImageList *imageList)
{
SetStateImageList(imageList);
- m_ownsImageListState = TRUE;
+ m_ownsImageListState = true;
}
void wxGenericTreeCtrl::AssignButtonsImageList(wxImageList *imageList)
{
SetButtonsImageList(imageList);
- m_ownsImageListButtons = TRUE;
+ m_ownsImageListButtons = true;
}
// -----------------------------------------------------------------------------
if ( item->IsSelected() )
{
+// under mac selections are only a rectangle in case they don't have the focus
+#ifdef __WXMAC__
+ if ( !m_hasFocus )
+ {
+ dc.SetBrush( *wxTRANSPARENT_BRUSH ) ;
+ dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) , 1 , wxSOLID ) ) ;
+ }
+ else
+ {
+ dc.SetBrush( *m_hilightBrush ) ;
+ }
+#else
dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush));
+#endif
}
else
{
dc.SetPen(m_dottedPen);
dc.SetTextForeground(*wxBLACK);
- if (item->HasPlus() && HasButtons()) // should the item show a button?
+ if ( !HasFlag(wxTR_NO_LINES) )
{
- if (!HasFlag(wxTR_NO_LINES))
- {
- if (x > (signed)m_indent)
- dc.DrawLine(x - m_indent, y_mid, x - 5, y_mid);
- else if (HasFlag(wxTR_LINES_AT_ROOT))
- dc.DrawLine(3, y_mid, x - 5, y_mid);
- dc.DrawLine(x + 5, y_mid, x + m_spacing, y_mid);
- }
+ // draw the horizontal line here
+ int x_start = x;
+ if (x > (signed)m_indent)
+ x_start -= m_indent;
+ else if (HasFlag(wxTR_LINES_AT_ROOT))
+ x_start = 3;
+ dc.DrawLine(x_start, y_mid, x + m_spacing, y_mid);
+ }
- if (m_imageListButtons != NULL)
+ // should the item show a button?
+ if ( item->HasPlus() && HasButtons() )
+ {
+ if ( m_imageListButtons )
{
// draw the image button here
- int image_h = 0, image_w = 0, image = wxTreeItemIcon_Normal;
- if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
- if (item->IsSelected())
+ int image_h = 0,
+ image_w = 0;
+ int image = item->IsExpanded() ? wxTreeItemIcon_Expanded
+ : wxTreeItemIcon_Normal;
+ if ( item->IsSelected() )
image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
+
m_imageListButtons->GetSize(image, image_w, image_h);
- int xx = x - (image_w>>1);
- int yy = y_mid - (image_h>>1);
- dc.SetClippingRegion(xx, yy, image_w, image_h);
+ int xx = x - image_w/2;
+ int yy = y_mid - image_h/2;
+
+ wxDCClipper clip(dc, xx, yy, image_w, image_h);
m_imageListButtons->Draw(image, dc, xx, yy,
wxIMAGELIST_DRAW_TRANSPARENT);
- dc.DestroyClippingRegion();
}
- else if (HasFlag(wxTR_TWIST_BUTTONS))
+ else // no custom buttons
{
- // draw the twisty button here
-
- if (HasFlag(wxTR_AQUA_BUTTONS))
- {
- if (item->IsExpanded())
- dc.DrawBitmap( *m_arrowDown, x-5, y_mid-6, TRUE );
- else
- dc.DrawBitmap( *m_arrowRight, x-5, y_mid-6, TRUE );
- }
- else
- {
- dc.SetBrush(*m_hilightBrush);
- dc.SetPen(*wxBLACK_PEN);
- wxPoint button[3];
-
- if (item->IsExpanded())
- {
- button[0].x = x-5;
- button[0].y = y_mid-2;
- button[1].x = x+5;
- button[1].y = y_mid-2;
- button[2].x = x;
- button[2].y = y_mid+3;
- }
- else
- {
- button[0].y = y_mid-5;
- button[0].x = x-2;
- button[1].y = y_mid+5;
- button[1].x = x-2;
- button[2].y = y_mid;
- button[2].x = x+3;
- }
- dc.DrawPolygon(3, button);
- dc.SetPen(m_dottedPen);
- }
- }
- else // if (HasFlag(wxTR_HAS_BUTTONS))
- {
- // draw the plus sign here
- dc.SetPen(*wxGREY_PEN);
- dc.SetBrush(*wxWHITE_BRUSH);
- dc.DrawRectangle(x-5, y_mid-4, 11, 9);
- dc.SetPen(*wxBLACK_PEN);
- dc.DrawLine(x-2, y_mid, x+3, y_mid);
- if (!item->IsExpanded())
- dc.DrawLine(x, y_mid-2, x, y_mid+3);
- dc.SetPen(m_dottedPen);
+ static const int wImage = 9;
+ static const int hImage = 9;
+
+ int flag = 0;
+ if (item->IsExpanded())
+ flag |= wxCONTROL_EXPANDED;
+ if (item == m_underMouse)
+ flag |= wxCONTROL_CURRENT;
+
+ wxRendererNative::Get().DrawTreeItemButton
+ (
+ this,
+ dc,
+ wxRect(x - wImage/2,
+ y_mid - hImage/2,
+ wImage, hImage),
+ flag
+ );
}
}
- else if (!HasFlag(wxTR_NO_LINES)) // no button; maybe a line?
- {
- // draw the horizontal line here
- int x_start = x;
- if (x > (signed)m_indent)
- x_start -= m_indent;
- else if (HasFlag(wxTR_LINES_AT_ROOT))
- x_start = 3;
- dc.DrawLine(x_start, y_mid, x + m_spacing, y_mid);
- }
}
if (item->IsExpanded())
// draw line down to last child
oldY += GetLineHeight(children[n-1])>>1;
if (HasButtons()) y_mid += 5;
- dc.DrawLine(x, y_mid, x, oldY);
+
+ // 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);
+ GetClientSize(&width, &height);
+
+ // Move end points to the begining/end of the view?
+ if (y_mid < yOrigin)
+ y_mid = yOrigin;
+ 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
+ if (y_mid < oldY)
+ dc.DrawLine(x, y_mid, x, oldY);
}
}
}
{
// draw a line under the drop target because the item will be
// dropped there
- DrawLine(item, TRUE /* below */);
+ DrawLine(item, true /* below */);
}
SetCursor(wxCURSOR_BULLSEYE);
}
// -----------------------------------------------------------------------------
-// wxWindows callbacks
+// wxWidgets callbacks
// -----------------------------------------------------------------------------
void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
void wxGenericTreeCtrl::OnSetFocus( wxFocusEvent &event )
{
- m_hasFocus = TRUE;
+ m_hasFocus = true;
RefreshSelected();
void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event )
{
- m_hasFocus = FALSE;
+ m_hasFocus = false;
RefreshSelected();
// home : go to root
// end : go to last item without opening parents
// alnum : start or continue searching for the item with this prefix
- int keyCode = event.KeyCode();
+ int keyCode = event.GetKeyCode();
switch ( keyCode )
{
case '+':
case ' ':
case WXK_RETURN:
+ if ( !event.HasModifiers() )
{
wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
- event.m_item = (long) m_current;
+ event.m_item = m_current;
event.SetEventObject( this );
GetEventHandler()->ProcessEvent( event );
}
+
+ // in any case, also generate the normal key event for this key,
+ // even if we generated the ACTIVATED event above: this is what
+ // wxMSW does and it makes sense because you might not want to
+ // process ACTIVATED event at all and handle Space and Return
+ // directly (and differently) which would be impossible otherwise
+ event.Skip();
break;
// up goes to the previous sibling or to the last
wxTreeItemId prev = GetPrevSibling( m_key_current );
if (!prev)
{
- prev = GetParent( m_key_current );
+ prev = GetItemParent( m_key_current );
if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
{
break; // don't go to root if it is hidden
}
if (prev)
{
- long cookie = 0;
+ 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?
if (current == GetFirstChild( prev, cookie ))
{
// otherwise we return to where we came from
- SelectItem( prev, unselect_others, extended_select );
+ DoSelectItem( prev, unselect_others, extended_select );
m_key_current= (wxGenericTreeItem*) prev.m_pItem;
break;
}
}
}
- SelectItem( prev, unselect_others, extended_select );
+ DoSelectItem( prev, unselect_others, extended_select );
m_key_current=(wxGenericTreeItem*) prev.m_pItem;
}
}
// left arrow goes to the parent
case WXK_LEFT:
{
- wxTreeItemId prev = GetParent( m_current );
+ wxTreeItemId prev = GetItemParent( m_current );
if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
{
// don't go to root if it is hidden
}
if (prev)
{
- SelectItem( prev, unselect_others, extended_select );
+ DoSelectItem( prev, unselect_others, extended_select );
}
}
break;
{
if (IsExpanded(m_key_current) && HasChildren(m_key_current))
{
- long cookie = 0;
+ wxTreeItemIdValue cookie;
wxTreeItemId child = GetFirstChild( m_key_current, cookie );
- SelectItem( child, unselect_others, extended_select );
+ DoSelectItem( child, unselect_others, extended_select );
m_key_current=(wxGenericTreeItem*) child.m_pItem;
}
else
if (!next)
{
wxTreeItemId current = m_key_current;
- while (current && !next)
+ while (current.IsOk() && !next)
{
- current = GetParent( current );
+ current = GetItemParent( current );
if (current) next = GetNextSibling( current );
}
}
if (next)
{
- SelectItem( next, unselect_others, extended_select );
+ DoSelectItem( next, unselect_others, extended_select );
m_key_current=(wxGenericTreeItem*) next.m_pItem;
}
}
// it may happen if the item was expanded but then all of
// its children have been deleted - so IsExpanded() returned
- // TRUE, but GetLastChild() returned invalid item
+ // true, but GetLastChild() returned invalid item
if ( !lastChild )
break;
if ( last.IsOk() )
{
- SelectItem( last, unselect_others, extended_select );
+ DoSelectItem( last, unselect_others, extended_select );
}
}
break;
if ( HasFlag(wxTR_HIDE_ROOT) )
{
- long dummy;
- prev = GetFirstChild(prev, dummy);
+ wxTreeItemIdValue cookie;
+ prev = GetFirstChild(prev, cookie);
if (!prev)
break;
}
- SelectItem( prev, unselect_others, extended_select );
+ DoSelectItem( prev, unselect_others, extended_select );
}
break;
default:
// do not use wxIsalnum() here
- if ( !event.HasModifiers() &&
+ if ( !event.HasModifiers() &&
((keyCode >= '0' && keyCode <= '9') ||
(keyCode >= 'a' && keyCode <= 'z') ||
(keyCode >= 'A' && keyCode <= 'Z' )))
{
// find the next item starting with the given prefix
- char ch = (char)keyCode;
-
- wxTreeItemId id = FindItem(m_current, m_findPrefix + (wxChar)ch);
+ wxChar ch = (wxChar)keyCode;
+
+ wxTreeItemId id = FindItem(m_current, m_findPrefix + ch);
if ( !id.IsOk() )
{
// no such item
// get the bounding rectangle of the item (or of its label only)
bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
- wxRect& rect,
- bool WXUNUSED(textOnly)) const
+ wxRect& rect,
+ bool WXUNUSED(textOnly)) const
{
- wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
+ wxCHECK_MSG( item.IsOk(), false, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
//rect.height = i->GetHeight();
rect.height = GetLineHeight(i);
- return TRUE;
+ return true;
}
-/* **** */
-
void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
{
- if (!item.IsOk()) return;
+ wxCHECK_RET( item.IsOk(), _T("can't edit an invalid item") );
- m_currentEdit = (wxGenericTreeItem*) item.m_pItem;
+ wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
- te.m_item = (long) m_currentEdit;
+ te.m_item = itemEdit;
te.SetEventObject( this );
- GetEventHandler()->ProcessEvent( te );
-
- if (!te.IsAllowed()) return;
+ if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
+ {
+ // vetoed by user
+ return;
+ }
// We have to call this here because the label in
// question might just have been added and no screen
// update taken place.
- if (m_dirty) wxYieldIfNeeded();
-
- wxString s = m_currentEdit->GetText();
- int w = m_currentEdit->GetWidth();
- int h = m_currentEdit->GetHeight();
- int x, y;
- CalcScrolledPosition(m_currentEdit->GetX(), m_currentEdit->GetY(), &x, &y);
+ if ( m_dirty )
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+ Update();
+#else
+ wxYieldIfNeeded();
+#endif
- int image_h = 0;
- int image_w = 0;
+ m_textCtrl = new wxTreeTextCtrl(this, itemEdit);
- int image = m_currentEdit->GetCurrentImage();
- if ( image != NO_IMAGE )
- {
- if ( m_imageListNormal )
- {
- m_imageListNormal->GetSize( image, image_w, image_h );
- image_w += 4;
- }
- else
- {
- wxFAIL_MSG(_T("you must create an image list to use images!"));
- }
- }
- x += image_w;
- w -= image_w + 4; // I don't know why +4 is needed
+ m_textCtrl->SetFocus();
+}
- wxTreeTextCtrl *text = new wxTreeTextCtrl(this, -1,
- &m_renameAccept,
- &m_renameRes,
- this,
- s,
- wxPoint(x-4,y-4),
- wxSize(w+11,h+8));
- text->SetFocus();
+// returns a pointer to the text edit control if the item is being
+// edited, NULL otherwise (it's assumed that no more than one item may
+// be edited simultaneously)
+wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const
+{
+ return m_textCtrl;
}
-void wxGenericTreeCtrl::OnRenameTimer()
+bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
+ const wxString& value)
{
- Edit( m_current );
+ wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
+ le.m_item = item;
+ le.SetEventObject( this );
+ le.m_label = value;
+ le.m_editCancelled = false;
+
+ return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed();
}
-void wxGenericTreeCtrl::OnRenameAccept()
+void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item)
{
- // TODO if the validator fails this causes a crash
+ // let owner know that the edit was cancelled
wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
- le.m_item = (long) m_currentEdit;
+ le.m_item = item;
le.SetEventObject( this );
- le.m_label = m_renameRes;
- GetEventHandler()->ProcessEvent( le );
+ le.m_label = wxEmptyString;
+ le.m_editCancelled = true;
- if (!le.IsAllowed()) return;
+ GetEventHandler()->ProcessEvent( le );
+}
- SetItemText( m_currentEdit, m_renameRes );
+void wxGenericTreeCtrl::OnRenameTimer()
+{
+ Edit( m_current );
}
void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
{
if ( !m_anchor ) return;
+ wxPoint pt = CalcUnscrolledPosition(event.GetPosition());
+
+ // Is the mouse over a tree item button?
+ int flags = 0;
+ wxGenericTreeItem *thisItem = m_anchor->HitTest(pt, this, flags, 0);
+ wxGenericTreeItem *underMouse = thisItem;
+#if wxUSE_TOOLTIPS
+ bool underMouseChanged = (underMouse != m_underMouse) ;
+#endif // wxUSE_TOOLTIPS
+
+ if ((underMouse) &&
+ (flags & wxTREE_HITTEST_ONITEMBUTTON) &&
+ (!event.LeftIsDown()) &&
+ (!m_isDragging) &&
+ (!m_renameTimer || !m_renameTimer->IsRunning()))
+ {
+ }
+ else
+ {
+ underMouse = NULL;
+ }
+
+ if (underMouse != m_underMouse)
+ {
+ if (m_underMouse)
+ {
+ // unhighlight old item
+ wxGenericTreeItem *tmp = m_underMouse;
+ m_underMouse = NULL;
+ RefreshLine( tmp );
+ }
+
+ m_underMouse = underMouse;
+ if (m_underMouse)
+ RefreshLine( m_underMouse );
+ }
+
+#if wxUSE_TOOLTIPS
+ // 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()))
+ {
+ // Ask the tree control what tooltip (if any) should be shown
+ wxTreeEvent hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, GetId());
+ hevent.m_item = hoverItem;
+ hevent.SetEventObject(this);
+
+ if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() )
+ {
+ SetToolTip(hevent.m_label);
+ }
+ }
+#endif
+
// we process left mouse up event (enables in-place edit), right down
// (pass to the user code), left dbl click (activate item) and
// dragging/moving events for items drag-and-drop
return;
}
- wxPoint pt = CalcUnscrolledPosition(event.GetPosition());
- int flags = 0;
+ flags = 0;
wxGenericTreeItem *item = m_anchor->HitTest(pt, this, flags, 0);
if ( event.Dragging() && !m_isDragging )
: wxEVT_COMMAND_TREE_BEGIN_DRAG;
wxTreeEvent nevent( command, GetId() );
- nevent.m_item = (long) m_current;
+ nevent.m_item = m_current;
nevent.SetEventObject(this);
// by default the dragging is not supported, the user code must
if ( GetEventHandler()->ProcessEvent(nevent) && nevent.IsAllowed() )
{
// we're going to drag this item
- m_isDragging = TRUE;
+ m_isDragging = true;
// remember the old cursor because we will change it while
// dragging
if ( m_oldSelection )
{
- m_oldSelection->SetHilight(FALSE);
+ m_oldSelection->SetHilight(false);
RefreshLine(m_oldSelection);
}
}
// highlight the current drop target if any
DrawDropEffect(m_dropTarget);
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+ Update();
+#else
wxYieldIfNeeded();
+#endif
}
}
else if ( (event.LeftUp() || event.RightUp()) && m_isDragging )
if ( m_oldSelection )
{
- m_oldSelection->SetHilight(TRUE);
+ m_oldSelection->SetHilight(true);
RefreshLine(m_oldSelection);
m_oldSelection = (wxGenericTreeItem *)NULL;
}
// generate the drag end event
wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
- event.m_item = (long) item;
+ event.m_item = item;
event.m_pointDrag = pt;
event.SetEventObject(this);
(void)GetEventHandler()->ProcessEvent(event);
- m_isDragging = FALSE;
+ m_isDragging = false;
m_dropTarget = (wxGenericTreeItem *)NULL;
ReleaseMouse();
SetCursor(m_oldCursor);
+#if defined( __WXMSW__ ) || defined(__WXMAC__)
+ Update();
+#else
wxYieldIfNeeded();
+#endif
}
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.
+ // 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.
+ if ( event.LeftDown() )
+ {
+ event.Skip();
+ }
+
// here we process only the messages which happen on tree items
m_dragCount = 0;
if ( event.RightDown() )
{
wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
- nevent.m_item = (long) item;
+ nevent.m_item = item;
nevent.m_pointDrag = CalcScrolledPosition(pt);
nevent.SetEventObject(this);
GetEventHandler()->ProcessEvent(nevent);
}
else if ( event.LeftUp() )
{
+ // this facilitates multiple-item drag-and-drop
+
+ if (item && HasFlag(wxTR_MULTIPLE))
+ {
+ wxArrayTreeItemIds selections;
+ size_t count = GetSelections(selections);
+
+ if (count > 1 &&
+ !event.ControlDown() &&
+ !event.ShiftDown())
+ {
+ DoSelectItem(item, true, false);
+ }
+ }
+
if ( m_lastOnSame )
{
if ( (item == m_current) &&
m_renameTimer = new wxTreeRenameTimer( this );
}
- m_renameTimer->Start( wxTreeRenameTimer::DELAY, TRUE );
+ m_renameTimer->Start( wxTreeRenameTimer::DELAY, true );
}
- m_lastOnSame = FALSE;
+ m_lastOnSame = false;
}
}
else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick()
return;
}
- // how should the selection work for this event?
- bool is_multiple, extended_select, unselect_others;
- EventFlagsToSelType(GetWindowStyleFlag(),
- event.ShiftDown(),
- event.ControlDown(),
- is_multiple, extended_select, unselect_others);
- SelectItem(item, unselect_others, extended_select);
+ // clear the previously selected items, if the
+ // user clicked outside of the present selection.
+ // otherwise, perform the deselection on mouse-up.
+ // this allows multiple drag and drop to work.
+
+ if (!IsSelected(item))
+ {
+ // how should the selection work for this event?
+ bool is_multiple, extended_select, unselect_others;
+ EventFlagsToSelType(GetWindowStyleFlag(),
+ event.ShiftDown(),
+ event.ControlDown(),
+ is_multiple, extended_select, unselect_others);
+
+ DoSelectItem(item, unselect_others, extended_select);
+ }
+
// For some reason, Windows isn't recognizing a left double-click,
// so we need to simulate it here. Allow 200 milliseconds for now.
if ( m_renameTimer )
m_renameTimer->Stop();
- m_lastOnSame = FALSE;
+ m_lastOnSame = false;
// send activate event first
wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
- nevent.m_item = (long) item;
+ nevent.m_item = item;
nevent.m_pointDrag = CalcScrolledPosition(pt);
nevent.SetEventObject( this );
if ( !GetEventHandler()->ProcessEvent( nevent ) )
}
}
-void wxGenericTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
+void wxGenericTreeCtrl::OnInternalIdle()
{
+ wxWindow::OnInternalIdle();
+
+ // Check if we need to select the root item
+ // because nothing else has been selected.
+ // Delaying it means that we can invoke event handlers
+ // as required, when a first item is selected.
+ if (!HasFlag(wxTR_MULTIPLE) && !GetSelection().IsOk())
+ {
+ if (m_select_me)
+ SelectItem(m_select_me);
+ else if (GetRootItem().IsOk())
+ SelectItem(GetRootItem());
+ }
+
/* after all changes have been done to the tree control,
* we actually redraw the tree when everything is over */
if (!m_dirty) return;
+ if (m_freezeCount) return;
- m_dirty = FALSE;
+ m_dirty = false;
CalculatePositions();
Refresh();
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;
void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
{
if (m_dirty) return;
+ if (m_freezeCount) return;
wxSize client = GetClientSize();
rect.width = client.x;
rect.height = client.y;
- Refresh(TRUE, &rect);
+ Refresh(true, &rect);
AdjustMyScrollbars();
}
void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
{
if (m_dirty) return;
+ if (m_freezeCount) return;
wxRect rect;
CalcScrolledPosition(0, item->GetY(), NULL, &rect.y);
rect.width = GetClientSize().x;
rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
- Refresh(TRUE, &rect);
+ Refresh(true, &rect);
}
void wxGenericTreeCtrl::RefreshSelected()
{
+ if (m_freezeCount) return;
+
// TODO: this is awfully inefficient, we should keep the list of all
// selected items internally, should be much faster
if ( m_anchor )
void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
{
+ if (m_freezeCount) return;
+
if ( item->IsSelected() )
RefreshLine(item);
}
}
+void wxGenericTreeCtrl::Freeze()
+{
+ m_freezeCount++;
+}
+
+void wxGenericTreeCtrl::Thaw()
+{
+ wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen tree control?") );
+
+ if ( !--m_freezeCount )
+ {
+ Refresh();
+ }
+}
+
// ----------------------------------------------------------------------------
// changing colours: we need to refresh the tree control
// ----------------------------------------------------------------------------
bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour)
{
if ( !wxWindow::SetBackgroundColour(colour) )
- return FALSE;
+ return false;
+
+ if (m_freezeCount) return true;
Refresh();
- return TRUE;
+ return true;
}
bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
{
if ( !wxWindow::SetForegroundColour(colour) )
- return FALSE;
+ return false;
+
+ if (m_freezeCount) return true;
Refresh();
- return TRUE;
+ return true;
+}
+
+// Process the tooltip event, to speed up event processing.
+// Doesn't actually get a tooltip.
+void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event )
+{
+ event.Veto();
+}
+
+
+wxSize wxGenericTreeCtrl::DoGetBestSize() const
+{
+ // something is better than nothing...
+ // 100x80 is what the MSW version will get from the default
+ // wxControl::DoGetBestSize
+ return wxSize(100,80);
+}
+
+
+// NOTE: If using the wxListBox visual attributes works everywhere then this can
+// be removed, as well as the #else case below.
+#define _USE_VISATTR 0
+
+#if _USE_VISATTR
+#include "wx/listbox.h"
+#endif
+
+//static
+wxVisualAttributes
+#if _USE_VISATTR
+wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant variant)
+#else
+wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
+#endif
+{
+#if _USE_VISATTR
+ // Use the same color scheme as wxListBox
+ return wxListBox::GetClassDefaultAttributes(variant);
+#else
+ wxVisualAttributes attr;
+ attr.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
+ attr.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX);
+ attr.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
+ return attr;
+#endif
}
#endif // wxUSE_TREECTRL