+///////////////////////////////////////////////////////////////////////////////
+// Name: tree.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/wx.h>
+#endif
+
+#include "wxtree.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)
+{
+ char buf[80];
+ wxString name(GetNodeName(id));
+ if (name != "")
+ sprintf(buf, "%s", (const char*) name);
+ else
+ sprintf(buf, "<unnamed>");
+
+ 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 != "")
+ 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(wxStoredTree, wxTreeLayout)
+
+wxStoredTree::wxStoredTree(int n):wxTreeLayout()
+{
+ m_nodes = NULL;
+ m_maxNodes = 0;
+ Initialize(n);
+}
+
+wxStoredTree::~wxStoredTree(void)
+{
+ if (m_nodes)
+ delete[] m_nodes;
+}
+
+void wxStoredTree::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 = "";
+ 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 wxStoredTree::AddChild(const wxString& name, const wxString& parent)
+{
+ if (m_num < (m_maxNodes -1 ))
+ {
+ long i = -1;
+ if (parent != "")
+ 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 wxStoredTree::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 wxStoredTree::GetChildren(long id, wxList& list)
+{
+ long currentId = GetTopNode();
+ while (currentId != -1)
+ {
+ if (id == GetNodeParent(currentId))
+ list.Append((wxObject *)currentId);
+ currentId = GetNextNode(currentId);
+ }
+}
+
+wxStoredNode* wxStoredTree::GetNode(long id) const
+{
+ wxASSERT(idx < m_num);
+
+ return &m_nodes[idx];
+};
+
+long wxStoredTree::GetNodeX(long id)
+{
+ wxASSERT(id < m_num);
+
+ return (long)m_nodes[id].m_x;
+}
+
+long wxStoredTree::GetNodeY(long id)
+{
+ wxASSERT(id < m_num);
+
+ return (long)m_nodes[id].m_y;
+}
+
+void wxStoredTree::SetNodeX(long id, long x)
+{
+ wxASSERT(id < m_num);
+
+ m_nodes[id].m_x = (int)x;
+}
+
+void wxStoredTree::SetNodeY(long id, long y)
+{
+ wxASSERT(id < m_num);
+
+ m_nodes[id].m_y = (int)y;
+}
+
+void wxStoredTree::SetNodeName(long id, const wxString& name)
+{
+ wxASSERT(id < m_num);
+
+ m_nodes[id].m_name = name;
+}
+
+wxString wxStoredTree::GetNodeName(long id)
+{
+ wxASSERT(id < m_num);
+
+ return m_nodes[id].m_name;
+}
+
+long wxStoredTree::GetNodeParent(long id)
+{
+ if (id != -1)
+ {
+ wxASSERT(id < m_num);
+
+ return m_nodes[id].m_parentId;
+ }
+ else
+ return -1;
+}
+
+long wxStoredTree::GetNextNode(long id)
+{
+ wxASSERT(id < m_num);
+
+ if ((id != -1) && (id < (m_num - 1)))
+ return id + 1;
+ else
+ return -1;
+}
+
+void wxStoredTree::SetClientData(long id, long clientData)
+{
+ wxASSERT(id < m_num);
+
+ m_nodes[id].m_clientData = clientData;
+}
+
+long wxStoredTree::GetClientData(long id) const
+{
+ wxASSERT(id < m_num);
+
+ return m_nodes[id].m_clientData;
+}
+
+void wxStoredTree::ActivateNode(long id, bool active)
+{
+ wxASSERT(id < m_num);
+
+ m_nodes[id].m_active = active;
+}
+
+bool wxStoredTree::NodeActive(long id)
+{
+ wxASSERT(id < m_num);
+
+ return m_nodes[id].m_active;
+}
+
+wxString wxStoredTree::HitTest(wxMouseEvent& event, wxDC& dc)
+{
+ long x, y;
+ event.Position(&x, &y);
+
+ int i;
+ for (i = 0; i < m_maxNodes; i++)
+ {
+ wxStoredNode* item = &m_nodes[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("");
+}