/////////////////////////////////////////////////////////////////////////////
// Name:        Menu.cpp
// Purpose:     The class to store a DVD Menu
// Author:      Alex Thuering
// Created:	04.11.2003
// RCS-ID:      $Id: Menu.cpp,v 1.63 2008/02/23 17:31:35 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#include "Menu.h"
#include "MenuPalettes.h"
#include "Palette3D.h"
#include <wxVillaLib/SConv.h>
#include <wxVillaLib/utils.h>
#include <wxSVG/svg.h>
#include <wxSVG/SVGCanvas.h>
#include <wxSVGXML/svgxmlhelpr.h>
#include <wx/mstream.h>
#include <wx/filename.h>

#define OBJECTS_DIR wxFindDataDirectory(_T("objects"))
#define BACKGROUNDS_DIR wxFindDataDirectory(_T("backgrounds"))

#define BUTTON_MAX_COLORS 4

Menu::Menu(VideoFormat videoFormat)
{
  m_videoFormat = videoFormat;
  m_startTime = _T("00:00:00.00");
  m_transpColour = wxColour(8,8,8);
  
  m_svg = new wxSVGDocument;
  wxSVGSVGElement* svgElement = new wxSVGSVGElement;
  svgElement->SetWidth(GetResolution().GetWidth());
  svgElement->SetHeight(GetResolution().GetHeight());
  m_svg->AppendChild(svgElement);
  wxSVGDefsElement* defsElement = new wxSVGDefsElement;
  defsElement->SetId(wxT("defs"));
  svgElement->AppendChild(defsElement);
  wxSVGGElement* gElem = new wxSVGGElement;
  gElem->SetId(wxT("objects"));
  svgElement->AppendChild(gElem);
  gElem = new wxSVGGElement;
  gElem->SetId(wxT("buttons"));
  svgElement->AppendChild(gElem);
  
  SetBackgroundColour(wxColour(0,0,0));
}

Menu::~Menu()
{
  delete m_svg;
  WX_CLEAR_ARRAY(m_objects)
}

void Menu::SetVideoFormat(VideoFormat format)
{
  m_videoFormat = format;
  // svg root element
  m_svg->GetRootElement()->SetWidth(GetResolution().GetWidth());
  m_svg->GetRootElement()->SetHeight(GetResolution().GetHeight());
  // background
  wxSVGElement* bgElement = m_svg->GetElementById(wxT("background"));
  if (bgElement)
  {
    if (bgElement->GetDtd() == wxSVG_RECT_ELEMENT)
    {
      ((wxSVGRectElement*)bgElement)->SetWidth(GetResolution().GetWidth());
      ((wxSVGRectElement*)bgElement)->SetHeight(GetResolution().GetHeight());
    }
    else if (bgElement->GetDtd() == wxSVG_IMAGE_ELEMENT)
    {
      ((wxSVGImageElement*)bgElement)->SetWidth(GetResolution().GetWidth());
      ((wxSVGImageElement*)bgElement)->SetHeight(GetResolution().GetHeight());
    }
  }
}

wxSize Menu::GetResolution()
{
  if (m_videoFormat == vfNTSC)
	return wxSize(720,480);
  return wxSize(720,576); // vfPAL
}

void Menu::SetBackground(wxString fileName) {
	SetBackground(m_svg->GetRootElement(), fileName);
}
wxString Menu::GetBackground() {
	return GetBackground(m_svg->GetRootElement());
}

void Menu::SetBackground(wxSVGSVGElement* root, wxString fileName)
{
  bool image = wxImage::FindHandler(fileName.AfterLast(wxT('.')).Lower(), -1);
  
  // test if element exists
  wxSVGElement* bgElement = (wxSVGElement*) root->GetElementById(wxT("background"));
  if (!bgElement ||
      (image && bgElement->GetDtd() != wxSVG_IMAGE_ELEMENT) ||
      (!image && bgElement->GetDtd() != wxSVG_VIDEO_ELEMENT))
  {
    if (bgElement) // remove old
      bgElement->GetParent()->RemoveChild(bgElement);
    if (image) // create image element
    {
      bgElement = new wxSVGImageElement;
      ((wxSVGImageElement*) bgElement)->SetWidth(GetResolution().GetWidth());
      ((wxSVGImageElement*) bgElement)->SetHeight(GetResolution().GetHeight());
    }
    else // create video element
    {
      bgElement = new wxSVGVideoElement;
      ((wxSVGVideoElement*) bgElement)->SetWidth(GetResolution().GetWidth());
      ((wxSVGVideoElement*) bgElement)->SetHeight(GetResolution().GetHeight());
    }
    bgElement->SetId(wxT("background"));
    root->InsertChild(bgElement, root->GetChildren());
  }
  
  // set href
  if (image)
    ((wxSVGImageElement*) bgElement)->SetHref(fileName);
  else
    ((wxSVGVideoElement*) bgElement)->SetHref(fileName);
}

wxString Menu::GetBackground(wxSVGSVGElement* root)
{
  wxSVGElement* bgElement = (wxSVGElement*) root->GetElementById(wxT("background"));
  if (bgElement)
  {
    if (bgElement->GetDtd() == wxSVG_IMAGE_ELEMENT)
      return ((wxSVGImageElement*)bgElement)->GetHref();
    else if (bgElement->GetDtd() == wxSVG_VIDEO_ELEMENT)
      return ((wxSVGVideoElement*)bgElement)->GetHref();
  }
  return wxT("");
}

void Menu::SetBackgroundColour(wxColour colour)
{
  wxSVGElement* bgElement = m_svg->GetElementById(wxT("background"));
  wxSVGRectElement* bgRect = (wxSVGRectElement*) bgElement;
  if (!bgElement || bgElement->GetDtd() != wxSVG_RECT_ELEMENT)
  {
    if (bgElement)
      bgElement->GetParent()->RemoveChild(bgElement);
    bgRect = new wxSVGRectElement;
    bgRect->SetId(wxT("background"));
    bgRect->SetWidth(GetResolution().GetWidth());
    bgRect->SetHeight(GetResolution().GetHeight());
    m_svg->GetRootElement()->InsertChild(bgRect,
      m_svg->GetRootElement()->GetChildren());
  }
  bgRect->SetFill(wxSVGPaint(colour.Red(), colour.Green(), colour.Blue()));
}

wxColour Menu::GetBackgroundColour()
{
  wxSVGRectElement* bgRect =
    (wxSVGRectElement*) m_svg->GetElementById(wxT("background"));
  if (bgRect && bgRect->GetDtd() == wxSVG_RECT_ELEMENT)
    return bgRect->GetFill().GetRGBColor();
  return wxColour(0,0,0);
}

bool Menu::HasVideoBackground()
{
  wxSVGElement* bgElement = m_svg->GetElementById(wxT("background"));
  return bgElement && bgElement->GetDtd() == wxSVG_VIDEO_ELEMENT;
}

void Menu::SetTransparentColor()
{
  m_transpColour = wxColour(0,0,0);
  wxImageHistogram h1, h2, h3;
  wxImage* images = GetImages();
  images[1].ComputeHistogram(h1);
  images[2].ComputeHistogram(h2);
  images[3].ComputeHistogram(h3);
  for (int i = 1; i< 30; i++)
  {
	m_transpColour = wxColour(i*8, i*8, i*8);
	unsigned long colour = (i*8<<16) + (i*8<<8) + i*8;
	if (h1.find(colour) == h1.end() &&
		h2.find(colour) == h2.end() &&
		h3.find(colour) == h3.end())
	  break;
  }
}

bool Menu::IsDefElement(wxSVGElement* element)
{
  if (!element || element->GetDtd() == wxSVG_SVG_ELEMENT)
    return false;
  if (element->GetDtd() == wxSVG_DEFS_ELEMENT)
    return true;
  return IsDefElement((wxSVGElement*) element->GetParent());
}

void Menu::RemoveChangeable(wxSVGElement* element, MenuObject* obj)
{
  wxSVGElement* child = (wxSVGElement*) element->GetChildren();
  while (child)
  {
    wxSVGElement* elem = child;
    child = (wxSVGElement*) child->GetNext();
    if (elem->GetType() != wxSVGXML_ELEMENT_NODE)
      continue;
    // don't remove def elements
    if (IsDefElement(elem))
      continue;
    // check if elem changeable
    if (elem->GetId().length())
    {
      // check if element has changeable attributes
      bool isChangeable = false;
      for (int i=0; i<obj->GetObjectParamsCount(); i++)
      {
        MenuObjectParam* param = obj->GetObjectParam(i);
        if (param->element == elem->GetId() && param->changeable)
        {
          isChangeable = true;
          break;
        }
      }
      if (isChangeable)
      {
        // todo: don't remove if it has not changeable attributes, but
        // remove all changeable attributes: SetFill(none),SetStroke(none)
        elem->GetParent()->RemoveChild(elem);
        continue;
      }
    }
    // remove changeable children
    RemoveChangeable(elem, obj);
  }
}

bool Menu::RemoveNotChangeable(wxSVGElement* element, MenuObject* obj)
{
  wxSVGElement* child = (wxSVGElement*) element->GetChildren();
  while (child)
  {
    wxSVGElement* elem = child;
    child = (wxSVGElement*) child->GetNext();
    if (elem->GetType() != wxSVGXML_ELEMENT_NODE)
    {
      elem->GetParent()->RemoveChild(elem);
      continue;
    }
    // don't remove def elements
    if (IsDefElement(elem))
      continue;
    // check if child changeable
    if (elem->GetId().length())
    {
      // check if element has changeable attributes
      bool isChangeable = false;
      for (int i=0; i<obj->GetObjectParamsCount(); i++)
      {
        MenuObjectParam* param = obj->GetObjectParam(i);
        if (param->element == elem->GetId() && param->changeable)
        {
          isChangeable = true;
          break;
        }
      }
      if (isChangeable)
      {
        // todo: remove not changeable attributes: SetFill(none),SetStroke(none)
        continue;
      }
    }
    // check if it has changeable children
    if (RemoveNotChangeable(elem, obj))
      elem->GetParent()->RemoveChild(elem);
  }
  return element->GetChildren() == NULL; // return if has no children
}

void CopyCachedImages(wxSVGDocument* doc, wxSVGElement* parent1, wxSVGElement* parent2)
{
  wxSVGElement* elem1 = (wxSVGElement*) parent1->GetChildren();
  wxSVGElement* elem2 = (wxSVGElement*) parent2->GetChildren();
  while (elem1 && elem2)
  {
    if (elem1->GetType() == wxSVGXML_ELEMENT_NODE
        && elem1->GetDtd() == wxSVG_IMAGE_ELEMENT)
    {
      wxSVGImageElement* img1 = (wxSVGImageElement*) elem1;
      wxSVGImageElement* img2 = (wxSVGImageElement*) elem2;
      if (img1->GetHref().GetAnimVal().length() && img1->GetCanvasItem() != NULL)
          img2->SetCanvasItem(doc->GetCanvas()->CreateItem(img1));
    } else if (elem1->GetChildren())
      CopyCachedImages(doc, elem1, elem2);
    elem1 = (wxSVGElement*) elem1->GetNext();
    elem2 = (wxSVGElement*) elem2->GetNext();
  }
}

wxSVGSVGElement* Menu::GetSVGCopy(MenuDrawType drawType) {
  wxSVGSVGElement* svgNode = (wxSVGSVGElement*) m_svg->GetRoot()->CloneNode();
  CopyCachedImages(m_svg, (wxSVGElement*) m_svg->GetRoot(), svgNode);
  // remove selection rectangle
  wxSvgXmlElement* elem = svgNode->GetElementById(wxT("selection"));
  if (elem)
    elem->GetParent()->RemoveChild(elem);
  // remove safeTV rectangle
  elem = svgNode->GetElementById(wxT("safeTV"));
  if (elem)
    elem->GetParent()->RemoveChild(elem);
  // remove grid
  elem = svgNode->GetElementById(wxT("grid"));
  if (elem)
    elem->GetParent()->RemoveChild(elem);
  
  if (drawType == mdBACKGROUND)
  {
    // remove changeable elements of objects
    for (int i=0; i<GetObjectsCount(); i++)
    {
      MenuObject* obj = GetObject(i);
      if (obj->IsButton())
      {
        wxSVGElement* elem = (wxSVGElement*) svgNode->GetElementById(wxT("s_") + obj->GetId());
        if (elem)
          RemoveChangeable(elem, obj);
      }
    }
  }
  else if (drawType == mdBUTTONS_NORMAL ||
           drawType == mdBUTTONS_HIGHLIGHTED ||
           drawType == mdBUTTONS_SELECTED)
  {
    // remove background and static elements of objects
    wxSVGElement* bgElement = (wxSVGElement*) svgNode->GetElementById(wxT("background"));
    wxSVGRectElement* bgRect = (wxSVGRectElement*) bgElement;
    if (!bgElement || bgElement->GetDtd() != wxSVG_RECT_ELEMENT)
    {
      if (bgElement)
        bgElement->GetParent()->RemoveChild(bgElement);
      bgRect = new wxSVGRectElement;
      bgRect->SetId(wxT("background"));
      bgRect->SetWidth(GetResolution().GetWidth());
      bgRect->SetHeight(GetResolution().GetHeight());
      svgNode->InsertChild(bgRect, svgNode->GetChildren());
    }
    bgRect->SetFill(wxSVGPaint(m_transpColour.Red(), m_transpColour.Green(), m_transpColour.Blue()));
    for (int i=0; i<GetObjectsCount(); i++)
    {
      MenuObject* obj = GetObject(i);
      if (obj->IsButton())
      {
        wxSVGSVGElement* symbol = (wxSVGSVGElement*) svgNode->GetElementById(wxT("s_") + obj->GetId());
        if (symbol)
          RemoveNotChangeable(symbol, obj);
        for (int i=0; i<obj->GetObjectParamsCount(); i++)
        {
          MenuObjectParam* param = obj->GetObjectParam(i);
          if (param->changeable && drawType != mdBUTTONS_NORMAL)
          {
            wxSVGElement* elem = (wxSVGElement*)
              symbol->GetElementById(param->element);
            if (elem && param->attribute.length())
            {
              wxSVGPaint paint(drawType == mdBUTTONS_SELECTED ?
                param->selectedColour : param->highlightedColour);
              elem->SetAttribute(param->attribute, paint.GetCSSText());
            }
          }
        }
      }
      else
      {
        wxSVGElement* elem = (wxSVGElement*) svgNode->GetElementById(obj->GetId());
        if (elem && elem->GetParent())
          elem->GetParent()->RemoveChild(elem);
        elem = (wxSVGElement*) svgNode->GetElementById(wxT("s_") + obj->GetId());
        if (elem && elem->GetParent())
          elem->GetParent()->RemoveChild(elem);
      }
    }
  }
  
  return svgNode;
}

////////////////////////////// Render ////////////////////////////////////////

wxImage Menu::RenderImage(MenuDrawType drawType, int width, int height)
{
  wxSVGDocument svg;
  svg.AppendChild(GetSVGCopy(drawType));
  return svg.Render(width, height);
}

wxImage Menu::GetImage(int width, int height)
{
  return RenderImage(mdALL, width, height);
}

wxSVGDocument* Menu::GetBackgroundSVG()
{
  wxSVGDocument* svg = new wxSVGDocument;
  svg->AppendChild(GetSVGCopy(mdBACKGROUND));
  return svg;
}

bool Menu::ReduceColours()
{
  // create 3d palette
  Palette3D palette;
  for (int i=0; i<GetObjectsCount(); i++)
  {
    MenuObject& obj = *GetObject(i);
    if (!obj.IsButton())
      continue;
    for (int j=0; j<obj.GetObjectParamsCount(); j++)
    {
      MenuObjectParam* param = obj.GetObjectParam(j);
      if (param->changeable) 
      {
      	palette.Add(param->normalColour, param->highlightedColour,
      	  param->selectedColour);
      }
    }
  }
  palette.Add(wxColour(), wxColour(), wxColour());
  // reduce the number of colours
  if (palette.GetColoursCount() <= BUTTON_MAX_COLORS)
  	return false;
  palette.ReduceColours(BUTTON_MAX_COLORS);
  // apply palette
  for (int i=0; i<GetObjectsCount(); i++)
  {
    MenuObject& obj = *GetObject(i);
    if (!obj.IsButton())
      continue;
    for (int i=0; i<obj.GetObjectParamsCount(); i++)
    {
      MenuObjectParam* param = obj.GetObjectParam(i);
      if (param->changeable) 
      {
      	if (palette.Apply(param->normalColour, param->highlightedColour,
      	  param->selectedColour))
      	{
      		obj.SetParamColour(param->name, param->normalColour, mbsNORMAL);
      		obj.SetParamColour(param->name, param->highlightedColour, mbsHIGHLIGHTED);
      		obj.SetParamColour(param->name, param->selectedColour, mbsSELECTED);
      	}
      }
    }
  }
  return true;
}

wxImage* Menu::GetImages()
{
  ReduceColours();
  
  // render images
  wxImage* images = new wxImage[4];
  images[0] = RenderImage(mdBACKGROUND, -1, -1);
  images[1] = RenderImage(mdBUTTONS_NORMAL, -1, -1);
  images[2] = RenderImage(mdBUTTONS_HIGHLIGHTED, -1, -1);
  images[3] = RenderImage(mdBUTTONS_SELECTED, -1, -1);
  
  // make aliasing for buttons
  for (int i=0; i<GetObjectsCount(); i++)
  {
      MenuObject& obj = *GetObject(i);
      if (!obj.IsButton())
        continue;
      // make palette
      MenuPalettes objPalette(obj, m_transpColour);
      
      // apply palette
      unsigned char* img1 =
        images[1].GetData() + obj.GetY()*images[1].GetWidth()*3 + obj.GetX()*3;
      unsigned char* img2 =
        images[2].GetData() + obj.GetY()*images[2].GetWidth()*3 + obj.GetX()*3;
      unsigned char* img3 =
        images[3].GetData() + obj.GetY()*images[3].GetWidth()*3 + obj.GetX()*3;
      for (int y=0; y<obj.GetHeight(); y++)
      {
        for (int x=0; x<obj.GetWidth(); x++)
        {
          objPalette.Apply(img1, img1);
          objPalette.Apply(img1, img2, img2);
          objPalette.Apply(img1, img2, img3, img3);
          img1+=3;
          img2+=3;
          img3+=3;
        }
        img1 += (images[1].GetWidth()-obj.GetWidth())*3;
        img2 += (images[2].GetWidth()-obj.GetWidth())*3;
        img3 += (images[3].GetWidth()-obj.GetWidth())*3;
      }
  }
  
  // all pixels that don't belong to objects must be transparent
  unsigned char* img1 = images[1].GetData();
  unsigned char* img2 = images[2].GetData();
  unsigned char* img3 = images[3].GetData();
  for (int y=0; y<images[1].GetHeight(); y++)
  {
    for (int x=0; x<images[1].GetWidth(); x++)
    {
      bool found = false;
      for (int i=0; i<GetObjectsCount(); i++)
	  {
  		MenuObject& obj = *GetObject(i);
  		if (!obj.IsButton())
    	  continue;
    	if (x>=obj.GetX() && x < obj.GetX() + obj.GetWidth()
    		&& y>=obj.GetY() && y < obj.GetY() + obj.GetHeight())
    	{
    		found = true;
    		break;
    	}
	  }
	  if (!found) {
	  	img1[0] = m_transpColour.Red();
		img1[1] = m_transpColour.Green();
		img1[2] = m_transpColour.Blue();
		img2[0] = m_transpColour.Red();
		img2[1] = m_transpColour.Green();
		img2[2] = m_transpColour.Blue();
		img3[0] = m_transpColour.Red();
		img3[1] = m_transpColour.Green();
		img3[2] = m_transpColour.Blue();
	  }
      img1+=3;
      img2+=3;
      img3+=3;
    }
  }
  
  return images;
}

MenuObject* Menu::GetObject(wxString id)
{
  for (int i=0; i<(int)m_objects.Count(); i++)
    if (m_objects[i]->GetId() == id)
      return m_objects[i];
  return NULL;
}

void Menu::RemoveObject(wxString id)
{
  MenuObject* obj = GetObject(id);
  if (obj)
  {
    m_objects.Remove(obj);
    delete obj;
  }
}

wxString Menu::AddImage(wxString fileName, int x, int y)
{
  return AddObject(OBJECTS_DIR + wxT("/image.xml"), fileName, x, y);
}

wxString Menu::AddText(wxString text, int x, int y)
{
  return AddObject(OBJECTS_DIR + wxT("/text.xml"), text, x, y);
}

wxString Menu::AddObject(wxString fileName, wxString param, int x, int y)
{
  MenuObject* obj = new MenuObject(this, fileName, x, y, param);
  m_objects.Add(obj);
  return obj->GetId();
}

bool Menu::SaveSpumux(wxString fileName,
  wxString btFile, wxString hlFile, wxString selFile)
{
  wxSvgXmlDocument xml;
  wxSvgXmlNode* root = new wxSvgXmlNode(wxSVGXML_ELEMENT_NODE, _T("subpictures"));
  wxSvgXmlNode* streamNode = new wxSvgXmlNode(wxSVGXML_ELEMENT_NODE, _T("stream"));
  wxSvgXmlNode* spuNode = new wxSvgXmlNode(wxSVGXML_ELEMENT_NODE, _T("spu"));
  if (GetStartTime().Length())
	spuNode->AddProperty(_T("start"), GetStartTime());
  if (GetEndTime().Length())
	spuNode->AddProperty(_T("end"), GetEndTime());
  spuNode->AddProperty(_T("image"), btFile);
  spuNode->AddProperty(_T("highlight"), hlFile);
  spuNode->AddProperty(_T("select"), selFile);
  spuNode->AddProperty(_T("transparent"), SConv::ToString(m_transpColour, false));
  spuNode->AddProperty(_T("force"), _T("yes"));
  // buttons
  for (int i=0; i<(int)GetObjectsCount(); i++)
  {
    MenuObject* obj = GetObject(i);
	if (obj->IsButton())
	  spuNode->AddChild(obj->GetXML(SPUMUX_XML));
  }
  // actions
  for (unsigned int i=0; i<m_actions.Count(); i++)
    spuNode->AddChild(m_actions[i]->GetXML(SPUMUX_XML));
  streamNode->AddChild(spuNode);
  root->AddChild(streamNode);
  xml.SetRoot(root);
  return xml.Save(fileName);
}

wxSvgXmlNode* Menu::GetXML(DVDFileType type, int playAllRegister, wxSvgXmlNode* node)
{
  if (node == NULL)
	node = new wxSvgXmlNode(wxSVGXML_ELEMENT_NODE, _T("menu"));
  
  if (type == DVDSTYLER_XML)
  {
	node->AddProperty(_T("videoFormat"), (m_videoFormat == vfPAL) ? _T("PAL") : _T("NTSC"));
    
    // add svg
	if (m_svg && m_svg->GetRoot()) {
		wxSVGSVGElement* svg = GetSVGCopy();
		// fix path
		wxString bgFile = GetBackground(svg);
		if (bgFile.length() > 0) {
			wxString dir = BACKGROUNDS_DIR;
			if (bgFile.StartsWith(dir))
 				SetBackground(svg, bgFile.substr(dir.length()));
		}
		node->AppendChild(svg);
	}
  }
  
  // add buttons info (action, etc.)
  for (int i=0; i<GetObjectsCount(); i++)
  {
	MenuObject* obj = GetObject(i);
	if (type == DVDSTYLER_XML || obj->IsButton())
	  node->AddChild(obj->GetXML(type, false, playAllRegister));
  }
  
  // actions
  for (unsigned int i=0; i<m_actions.Count(); i++)
    node->AddChild(m_actions[i]->GetXML(type));
  
  return node;
}

bool Menu::PutXML(wxSvgXmlNode* node)
{
  if (node->GetName() == _T("spumux"))
    node = node->GetChildren();
  if (node != NULL && node->GetName() == _T("menu"))
  {
    wxString val;
    m_videoFormat = vfPAL;
    if (node->GetPropVal(_T("videoFormat"), &val) && val == _T("NTSC"))
      m_videoFormat = vfNTSC;
      
    wxSvgXmlNode* svgNode = XmlFindNode(node, wxT("svg"));
    if (svgNode)
    {
      wxSvgXmlDocument xml;
      xml.SetRoot(svgNode->CloneNode());
      wxMemoryOutputStream output;
      xml.Save(output);
      wxMemoryInputStream input(output);
      m_svg->Load(input);
      // fix path
      if (GetBackground().length() > 0) {
		wxFileName fn(GetBackground());
		if (fn.IsRelative())
	 	  SetBackground(BACKGROUNDS_DIR + GetBackground());
	  }					   
    }
    else // deprecated
    {
      if (node->GetPropVal(_T("bgFile"), &val))
        SetBackground(val);
      else if (node->GetPropVal(_T("bgColour"), &val))
        SetBackgroundColour(SConv::ToColour(val));
    }
	
	for (wxSvgXmlNode* child = node->GetChildren(); child != NULL; child = child->GetNext())
	  if (child->GetType() == wxSVGXML_ELEMENT_NODE)
		AddObject(child);
	// fix for old version (<=1.5b5)
	if (m_svg->GetElementById(wxT("objects")) == NULL) {
	  	wxSVGGElement* objectsElem = new wxSVGGElement;
	  	objectsElem->SetId(wxT("objects"));
  		m_svg->GetRoot()->AppendChild(objectsElem);
  		wxSVGGElement* buttonsElem = new wxSVGGElement;
  		buttonsElem->SetId(wxT("buttons"));
  		m_svg->GetRoot()->AppendChild(buttonsElem);
  		m_svg->GetRootElement()->GetChildren();
  		for (unsigned int i = 0; i < m_objects.GetCount(); i++) {
  			MenuObject& obj = *m_objects.Item(i);
  			wxSVGElement* useElem = m_svg->GetElementById(obj.GetId());
  			useElem->GetParent()->RemoveChild(useElem);
	  		if (obj.IsButton())
	  			buttonsElem->AppendChild(useElem);
	  		else
	  			objectsElem->AppendChild(useElem);
  		}
	}
  }
  return true;
}

wxString Menu::AddObject(wxSvgXmlNode* node, bool fixPosition)
{
    if (node->GetName() == _T("action")) {
        MenuAction* action = new MenuAction();
        if (!action->PutXML(node)) {
            delete action;
            return wxT("");
        }
        m_actions.Add(action);
        return action->GetId();
    } else if (node->GetName() == _T("button") || node->GetName() == _T("object")) {
        MenuObject* obj = new MenuObject(this);
        if (!obj->PutXML(node)) {
            delete obj;
            return wxT("");
        }
        if (fixPosition) // for copy & paste
            FixPosition(obj);
        m_objects.Add(obj);
        return obj->GetId();
    }
    return wxT("");
}

void Menu::FixPosition(MenuObject* obj)
{
  if (obj->GetX() == -1)
    obj->SetX(GetResolution().x/4);
  if (obj->GetY() == -1)
    obj->SetY(GetResolution().y/4);
  while (obj->GetX()<GetResolution().x-48 && obj->GetY()<GetResolution().y-48)
  {
	bool found = false;
	for (int i=0; i<(int)GetObjectsCount(); i++)
	{
	  MenuObject* obj1 = GetObject(i);
	  if (obj1->GetX() == obj->GetX() &&
		  obj1->GetY() == obj->GetY())
	  {
		found = true;
		break;
	  }
	}
	if (!found)
	  break;
	obj->SetX(obj->GetX()+16);
    obj->SetY(obj->GetY()+16);
  }
}
