/////////////////////////////////////////////////////////////////////////////// // Name: treelay.h // Purpose: wxTreeLayout class // Author: Julian Smart // Modified by: // Created: 7/4/98 // RCS-ID: $Id$ // Copyright: (c) 1998 Julian Smart // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ #pragma implementation "wxtree.h" #endif // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/dc.h" #include "wx/event.h" #endif #if wxUSE_TREELAYOUT #include "wx/treelay.h" /* * Abstract tree * */ IMPLEMENT_ABSTRACT_CLASS(wxTreeLayout, wxObject) wxTreeLayout::wxTreeLayout() { m_xSpacing = 16; m_ySpacing = 20; m_topMargin = 5; m_leftMargin = 5; m_orientation = FALSE; m_parentNode = 0; } void wxTreeLayout::DoLayout(wxDC& dc, long topId) { if (topId != -1) SetTopNode(topId); long actualTopId = GetTopNode(); long id = actualTopId; while (id != -1) { SetNodeX(id, 0); SetNodeY(id, 0); ActivateNode(id, FALSE); id = GetNextNode(id); } m_lastY = m_topMargin; m_lastX = m_leftMargin; CalcLayout(actualTopId, 0, dc); } void wxTreeLayout::Draw(wxDC& dc) { dc.Clear(); DrawBranches(dc); DrawNodes(dc); } void wxTreeLayout::DrawNodes(wxDC& dc) { long id = GetTopNode(); while (id != -1) { if (NodeActive(id)) DrawNode(id, dc); id = GetNextNode(id); } } void wxTreeLayout::DrawBranches(wxDC& dc) { long id = GetTopNode(); while (id != -1) { if (GetNodeParent(id) > -1) { long parent = GetNodeParent(id); if (NodeActive(parent)) DrawBranch(parent, id, dc); } id = GetNextNode(id); } } void wxTreeLayout::DrawNode(long id, wxDC& dc) { wxChar buf[80]; wxString name(GetNodeName(id)); if (name != wxT("")) wxSprintf(buf, wxT("%s"), (const wxChar*) name); else wxSprintf(buf, wxT("")); long x = 80; long y = 20; dc.GetTextExtent(buf, &x, &y); dc.DrawText(buf, GetNodeX(id), (long)(GetNodeY(id) - (y/2.0))); } void wxTreeLayout::DrawBranch(long from, long to, wxDC& dc) { long w, h; GetNodeSize(from, &w, &h, dc); dc.DrawLine(GetNodeX(from)+w, GetNodeY(from), GetNodeX(to), GetNodeY(to)); } void wxTreeLayout::Initialize(void) { } void wxTreeLayout::GetNodeSize(long id, long *x, long *y, wxDC& dc) { wxString name(GetNodeName(id)); if (name != wxT("")) dc.GetTextExtent(name, x, y); else { *x = 70; *y = 20; } } void wxTreeLayout::CalcLayout(long nodeId, int level, wxDC& dc) { wxList children; GetChildren(nodeId, children); int n = children.Number(); if (m_orientation == FALSE) { // Left to right // X Calculations if (level == 0) SetNodeX(nodeId, m_leftMargin); else { long x = 0; long y = 0; long parentId = GetNodeParent(nodeId); if (parentId != -1) GetNodeSize(parentId, &x, &y, dc); SetNodeX(nodeId, (long)(GetNodeX(parentId) + m_xSpacing + x)); } wxNode *node = children.First(); while (node) { CalcLayout((long)node->Data(), level+1, dc); node = node->Next(); } // Y Calculations long averageY; ActivateNode(nodeId, TRUE); if (n > 0) { averageY = 0; node = children.First(); while (node) { averageY += GetNodeY((long)node->Data()); node = node->Next(); } averageY = averageY / n; SetNodeY(nodeId, averageY); } else { SetNodeY(nodeId, m_lastY); long x, y; GetNodeSize(nodeId, &x, &y, dc); m_lastY = m_lastY + y + m_ySpacing; } } else { // Top to bottom // Y Calculations if (level == 0) SetNodeY(nodeId, m_topMargin); else { long x = 0; long y = 0; long parentId = GetNodeParent(nodeId); if (parentId != -1) GetNodeSize(parentId, &x, &y, dc); SetNodeY(nodeId, (long)(GetNodeY(parentId) + m_ySpacing + y)); } wxNode *node = children.First(); while (node) { CalcLayout((long)node->Data(), level+1, dc); node = node->Next(); } // X Calculations long averageX; ActivateNode(nodeId, TRUE); if (n > 0) { averageX = 0; node = children.First(); while (node) { averageX += GetNodeX((long)node->Data()); node = node->Next(); } averageX = averageX / n; SetNodeX(nodeId, averageX); } else { SetNodeX(nodeId, m_lastX); long x, y; GetNodeSize(nodeId, &x, &y, dc); m_lastX = m_lastX + x + m_xSpacing; } } } /* * Tree with storage * */ IMPLEMENT_DYNAMIC_CLASS(wxTreeLayoutStored, wxTreeLayout) wxTreeLayoutStored::wxTreeLayoutStored(int n):wxTreeLayout() { m_nodes = NULL; m_maxNodes = 0; Initialize(n); } wxTreeLayoutStored::~wxTreeLayoutStored(void) { if (m_nodes) delete[] m_nodes; } void wxTreeLayoutStored::Initialize(int n) { m_maxNodes = n; wxTreeLayout::Initialize(); if (m_nodes) delete[] m_nodes; m_nodes = new wxStoredNode[m_maxNodes]; int i; for (i = 0; i < n; i++) { m_nodes[i].m_name = wxT(""); m_nodes[i].m_active = FALSE; m_nodes[i].m_parentId = -1; m_nodes[i].m_x = 0; m_nodes[i].m_y = 0; } m_num = 0; } long wxTreeLayoutStored::AddChild(const wxString& name, const wxString& parent) { if (m_num < (m_maxNodes -1 )) { long i = -1; if (parent != wxT("")) i = NameToId(parent); else m_parentNode = m_num; m_nodes[m_num].m_parentId = i; m_nodes[m_num].m_name = name; m_nodes[m_num].m_x = m_nodes[m_num].m_y = 0; m_nodes[m_num].m_clientData = 0; m_num ++; return (m_num - 1); } else return -1; } long wxTreeLayoutStored::AddChild(const wxString& name, long parent) { if (m_num < (m_maxNodes -1 ) && parent < m_num) { long i = -1; if (parent != -1) { i = parent; } else { m_parentNode = m_num; } m_nodes[m_num].m_parentId = i; m_nodes[m_num].m_name = name; m_nodes[m_num].m_x = m_nodes[m_num].m_y = 0; m_nodes[m_num].m_clientData = 0; m_num ++; return (m_num - 1); } else return -1; } long wxTreeLayoutStored::NameToId(const wxString& name) { long i; for (i = 0; i < m_num; i++) if (name == m_nodes[i].m_name) return i; return -1; } void wxTreeLayoutStored::GetChildren(long id, wxList& list) { long currentId = GetTopNode(); while (currentId != -1) { if (id == GetNodeParent(currentId)) list.Append((wxObject *)currentId); currentId = GetNextNode(currentId); } } wxStoredNode* wxTreeLayoutStored::GetNode(long idx) const { wxASSERT(idx < m_num); return &m_nodes[idx]; }; long wxTreeLayoutStored::GetNodeX(long id) { wxASSERT(id < m_num); return (long)m_nodes[id].m_x; } long wxTreeLayoutStored::GetNodeY(long id) { wxASSERT(id < m_num); return (long)m_nodes[id].m_y; } void wxTreeLayoutStored::SetNodeX(long id, long x) { wxASSERT(id < m_num); m_nodes[id].m_x = (int)x; } void wxTreeLayoutStored::SetNodeY(long id, long y) { wxASSERT(id < m_num); m_nodes[id].m_y = (int)y; } void wxTreeLayoutStored::SetNodeName(long id, const wxString& name) { wxASSERT(id < m_num); m_nodes[id].m_name = name; } wxString wxTreeLayoutStored::GetNodeName(long id) { wxASSERT(id < m_num); return m_nodes[id].m_name; } long wxTreeLayoutStored::GetNodeParent(long id) { if (id != -1) { wxASSERT(id < m_num); return m_nodes[id].m_parentId; } else return -1; } long wxTreeLayoutStored::GetNextNode(long id) { wxASSERT(id < m_num); if ((id != -1) && (id < (m_num - 1))) return id + 1; else return -1; } void wxTreeLayoutStored::SetClientData(long id, long clientData) { wxASSERT(id < m_num); m_nodes[id].m_clientData = clientData; } long wxTreeLayoutStored::GetClientData(long id) const { wxASSERT(id < m_num); return m_nodes[id].m_clientData; } void wxTreeLayoutStored::ActivateNode(long id, bool active) { wxASSERT(id < m_num); m_nodes[id].m_active = active; } bool wxTreeLayoutStored::NodeActive(long id) { wxASSERT(id < m_num); return m_nodes[id].m_active; } wxString wxTreeLayoutStored::HitTest(wxMouseEvent& event, wxDC& dc) { wxPoint pt = event.GetPosition(); wxCoord x = pt.x; wxCoord y = pt.y; int i; for (i = 0; i < m_maxNodes; i++) { long width, height; dc.GetTextExtent(m_nodes[i].m_name, &width, &height); if ( (x >= (m_nodes[i].m_x-10)) && (x < (m_nodes[i].m_x + width+10)) && (y >= m_nodes[i].m_y-10) && (y < (m_nodes[i].m_y + height+10)) ) { return m_nodes[i].m_name; } } return wxString( wxT("") ); } #endif // wxUSE_TREELAYOUT