/////////////////////////////////////////////////////////////////////////////
// Name:        reseditr.cpp
// Purpose:     Resource editor class
// Author:      Julian Smart
// Modified by:
// Created:     04/01/98
// RCS-ID:      $Id$
// Copyright:   (c) Julian Smart
// Licence:   	wxWindows license
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
#pragma implementation "reseditr.h"
#endif

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"

#include "wx/checkbox.h"
#include "wx/button.h"
#include "wx/choice.h"
#include "wx/listbox.h"
#include "wx/radiobox.h"
#include "wx/statbox.h"
#include "wx/gauge.h"
#include "wx/slider.h"
#include "wx/textctrl.h"
#endif

#include "wx/scrolbar.h"

#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#if defined(__WINDOWS__) && !defined(__GNUWIN32__)
#include <strstrea.h>
#else
#include <strstream.h>
#endif

#ifdef __WINDOWS__
#include <windows.h>
#endif

#include "wx/help.h"

#include "reseditr.h"
#include "winprop.h"
#include "editrpal.h"
#include "dlghndlr.h"
#include "edtree.h"
#include "edlist.h"

static void ObjectMenuProc(wxMenu& menu, wxCommandEvent& event);
wxResourceManager *wxResourceManager::sm_currentResourceManager = NULL;

#ifdef __X__
#include "bitmaps/load.xbm"
#include "bitmaps/save.xbm"
#include "bitmaps/new.xbm"
#include "bitmaps/vert.xbm"
#include "bitmaps/alignt.xbm"
#include "bitmaps/alignb.xbm"
#include "bitmaps/horiz.xbm"
#include "bitmaps/alignl.xbm"
#include "bitmaps/alignr.xbm"
#include "bitmaps/copysize.xbm"
#include "bitmaps/tofront.xbm"
#include "bitmaps/toback.xbm"
#include "bitmaps/help.xbm"
#include "bitmaps/wxwin.xbm"
#endif

/*
 * Resource manager
 */

wxResourceManager::wxResourceManager():
  m_imageList(16, 16, TRUE)
{
  sm_currentResourceManager = this;
  m_editorFrame = NULL;
  m_editorPanel = NULL;
  m_popupMenu = NULL;
  m_editorResourceTree = NULL;
  m_editorControlList = NULL;
  m_editorPalette = NULL;
  m_nameCounter = 1;
  m_modified = FALSE;
  m_currentFilename = "";
  m_editorToolBar = NULL;

  // Default window positions
  m_resourceEditorWindowSize.width = 470;
  m_resourceEditorWindowSize.height = 300;

  m_resourceEditorWindowSize.x = 0;
  m_resourceEditorWindowSize.y = 0;

  m_propertyWindowSize.width = 300;
  m_propertyWindowSize.height = 300;

  m_helpController = NULL;

  m_bitmapImage = NULL;
  m_rootDialogItem = 0;
}

wxResourceManager::~wxResourceManager()
{
  sm_currentResourceManager = NULL;
  SaveOptions();

  if (m_helpController)
  {
    m_helpController->Quit();
    delete m_helpController;
    m_helpController = NULL;
  }
  delete m_bitmapImage;
  delete m_popupMenu;
}

bool wxResourceManager::Initialize()
{
  // Set up the resource filename for each platform.
#ifdef __WINDOWS__
  // dialoged.ini in the Windows directory
  char buf[256];
  GetWindowsDirectory(buf, 256);
  strcat(buf, "\\dialoged.ini");
  m_optionsResourceFilename = buf;
#elif defined(__X__)
  char buf[500];
  ()wxGetHomeDir(buf);
  strcat(buf, "/.dialogedrc");
  m_optionsResourceFilename = buf;
#else
#error "Unsupported platform."
#endif

  LoadOptions();

  m_helpController = new wxHelpController;
  m_helpController->Initialize("dialoged");

  m_popupMenu = new wxMenu("", (wxFunction)ObjectMenuProc);
  m_popupMenu->Append(OBJECT_MENU_EDIT, "Edit properties");
  m_popupMenu->Append(OBJECT_MENU_DELETE, "Delete object");

  if (!m_bitmapImage)
  {
#ifdef __WINDOWS__
    m_bitmapImage = new wxBitmap("WXWINBMP", wxBITMAP_TYPE_BMP_RESOURCE);
#endif
#ifdef __X__
    m_bitmapImage = new wxBitmap(wxwin_bits, wxwin_width, wxwin_height);
#endif
  }

  // Initialize the image list icons
#ifdef __WINDOWS__
  wxIcon icon1("DIALOG_ICON", wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
  wxIcon icon2("FOLDER1_ICON", wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
  wxIcon icon3("FOLDER2_ICON", wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
  wxIcon icon4("BUTTONSM_ICON", wxBITMAP_TYPE_ICO_RESOURCE, 16, 16);
  m_imageList.Add(icon1);
  m_imageList.Add(icon2);
  m_imageList.Add(icon3);
  m_imageList.Add(icon4);
#endif

  return TRUE;
}

bool wxResourceManager::LoadOptions()
{
  wxGetResource("DialogEd", "editorWindowX", &m_resourceEditorWindowSize.x, m_optionsResourceFilename.GetData());
  wxGetResource("DialogEd", "editorWindowY", &m_resourceEditorWindowSize.y, m_optionsResourceFilename.GetData());
  wxGetResource("DialogEd", "editorWindowWidth", &m_resourceEditorWindowSize.width, m_optionsResourceFilename.GetData());
  wxGetResource("DialogEd", "editorWindowHeight", &m_resourceEditorWindowSize.height, m_optionsResourceFilename.GetData());
  wxGetResource("DialogEd", "propertyWindowX", &m_propertyWindowSize.x, m_optionsResourceFilename.GetData());
  wxGetResource("DialogEd", "propertyWindowY", &m_propertyWindowSize.y, m_optionsResourceFilename.GetData());
  wxGetResource("DialogEd", "propertyWindowWidth", &m_propertyWindowSize.width, m_optionsResourceFilename.GetData());
  wxGetResource("DialogEd", "propertyWindowHeight", &m_propertyWindowSize.height, m_optionsResourceFilename.GetData());
  return TRUE;
}

bool wxResourceManager::SaveOptions()
{
  wxWriteResource("DialogEd", "editorWindowX", m_resourceEditorWindowSize.x, m_optionsResourceFilename.GetData());
  wxWriteResource("DialogEd", "editorWindowY", m_resourceEditorWindowSize.y, m_optionsResourceFilename.GetData());
  wxWriteResource("DialogEd", "editorWindowWidth", m_resourceEditorWindowSize.width, m_optionsResourceFilename.GetData());
  wxWriteResource("DialogEd", "editorWindowHeight", m_resourceEditorWindowSize.height, m_optionsResourceFilename.GetData());

  wxWriteResource("DialogEd", "propertyWindowX", m_propertyWindowSize.x, m_optionsResourceFilename.GetData());
  wxWriteResource("DialogEd", "propertyWindowY", m_propertyWindowSize.y, m_optionsResourceFilename.GetData());
  wxWriteResource("DialogEd", "propertyWindowWidth", m_propertyWindowSize.width, m_optionsResourceFilename.GetData());
  wxWriteResource("DialogEd", "propertyWindowHeight", m_propertyWindowSize.height, m_optionsResourceFilename.GetData());

  return TRUE;
}

// Show or hide the resource editor frame, which displays a list
// of resources with ability to edit them.
bool wxResourceManager::ShowResourceEditor(bool show, wxWindow *parent, const char *title)
{
  if (show)
  {
    if (m_editorFrame)
    {
      m_editorFrame->Iconize(FALSE);
      m_editorFrame->Show(TRUE);
      return TRUE;
    }
    m_editorFrame = OnCreateEditorFrame(title);
    SetFrameTitle("");
    wxMenuBar *menuBar = OnCreateEditorMenuBar(m_editorFrame);
    m_editorFrame->SetMenuBar(menuBar);

    m_editorToolBar = (EditorToolBar *)OnCreateToolBar(m_editorFrame);
//    m_editorPalette = OnCreatePalette(m_editorFrame);
    m_editorControlList = new wxResourceEditorControlList(m_editorFrame, IDC_LISTCTRL, wxPoint(0, 0), wxSize(-1, -1));
    m_editorResourceTree = new wxResourceEditorProjectTree(m_editorFrame, IDC_TREECTRL, wxPoint(0, 0), wxSize(-1, -1),
      wxTR_HAS_BUTTONS);
    m_editorPanel = OnCreateEditorPanel(m_editorFrame);

    m_editorResourceTree->SetImageList(& m_imageList);

    // Constraints for toolbar
    wxLayoutConstraints *c = new wxLayoutConstraints;
    c->left.SameAs       (m_editorFrame, wxLeft, 0);
    c->top.SameAs        (m_editorFrame, wxTop, 0);
    c->right.SameAs      (m_editorFrame, wxRight, 0);
    c->bottom.Unconstrained();
    c->width.Unconstrained();
    c->height.Absolute(28);
    m_editorToolBar->SetConstraints(c);
/*
    // Constraints for palette
    c = new wxLayoutConstraints;
    c->left.SameAs       (m_editorFrame, wxLeft, 0);
    c->top.SameAs        (m_editorToolBar, wxBottom, 0);
    c->right.SameAs      (m_editorFrame, wxRight, 0);
    c->bottom.Unconstrained();
    c->width.Unconstrained();
    c->height.Absolute(34);
    m_editorPalette->SetConstraints(c);
*/
    // Constraints for listbox
    c = new wxLayoutConstraints;
    c->left.SameAs       (m_editorFrame, wxLeft, 0);
    c->top.SameAs        (m_editorToolBar, wxBottom, 0);
    c->right.Absolute    (150);
    c->bottom.SameAs     (m_editorControlList, wxTop, 0);
    c->width.Unconstrained();
    c->height.Unconstrained();
    m_editorResourceTree->SetConstraints(c);

    // Constraints for panel
    c = new wxLayoutConstraints;
    c->left.SameAs       (m_editorResourceTree, wxRight, 0);
    c->top.SameAs        (m_editorToolBar, wxBottom, 0);
    c->right.SameAs      (m_editorFrame, wxRight, 0);
    c->bottom.SameAs     (m_editorControlList, wxTop, 0);
    c->width.Unconstrained();
    c->height.Unconstrained();
    m_editorPanel->SetConstraints(c);

    // Constraints for control list (bottom window)
    c = new wxLayoutConstraints;
    c->left.SameAs       (m_editorFrame, wxLeft, 0);
    c->right.SameAs      (m_editorFrame, wxRight, 0);
    c->bottom.SameAs     (m_editorFrame, wxBottom, 0);
    c->width.Unconstrained();
    c->height.Absolute(60);
    m_editorControlList->SetConstraints(c);

    m_editorFrame->SetAutoLayout(TRUE);

    UpdateResourceList();

    m_editorFrame->Show(TRUE);
    return TRUE;
  }
  else
  {
    wxFrame *fr = m_editorFrame;
    if (m_editorFrame->OnClose())
    {
      fr->Show(FALSE);
      delete fr;
      m_editorFrame = NULL;
      m_editorPanel = NULL;
    }
  }
  return TRUE;
}

void wxResourceManager::SetFrameTitle(const wxString& filename)
{
  if (m_editorFrame)
  {
    if (filename == wxString(""))
      m_editorFrame->SetTitle("wxWindows Dialog Editor - untitled");
    else
    {
      wxString str("wxWindows Dialog Editor - ");
      wxString str2(wxFileNameFromPath(WXSTRINGCAST filename));
      str += str2;
      m_editorFrame->SetTitle(str);
    }
  }
}

bool wxResourceManager::Save()
{
  if (m_currentFilename == wxString(""))
    return SaveAs();
  else
    return Save(m_currentFilename);
}

bool wxResourceManager::Save(const wxString& filename)
{
  // Ensure all visible windows are saved to their resources
  m_currentFilename = filename;
  SetFrameTitle(m_currentFilename);
  InstantiateAllResourcesFromWindows();
  if (m_resourceTable.Save(filename))
  {
    Modify(FALSE);
    return TRUE;
  }
  else
    return FALSE;
}

bool wxResourceManager::SaveAs()
{
  wxString s(wxFileSelector("Save resource file", wxPathOnly(WXSTRINGCAST m_currentFilename), wxFileNameFromPath(WXSTRINGCAST m_currentFilename),
    "wxr", "*.wxr", wxSAVE | wxOVERWRITE_PROMPT));
    
  if (s.IsNull() || s == "")
    return FALSE;
    
  m_currentFilename = s;
  Save(m_currentFilename);
  return TRUE;
}

bool wxResourceManager::SaveIfModified()
{
  if (Modified())
    return Save();
  else return TRUE;
}

bool wxResourceManager::Load(const wxString& filename)
{
  return New(TRUE, filename);
}

bool wxResourceManager::New(bool loadFromFile, const wxString& filename)
{
  if (!Clear(TRUE, FALSE))
    return FALSE;
    
  if (loadFromFile)
  {
    wxString str = filename;
    if (str == wxString(""))
    {
      wxString f(wxFileSelector("Open resource file", NULL, NULL, "wxr", "*.wxr", 0, NULL));
      if (!f.IsNull() && f != "")
        str = f;
      else
        return FALSE;
    }
    
    if (!m_resourceTable.ParseResourceFile(WXSTRINGCAST str))
    {
      wxMessageBox("Could not read file.", "Resource file load error", wxOK | wxICON_EXCLAMATION);
      return FALSE;
    }
    m_currentFilename = str;

    SetFrameTitle(m_currentFilename);

    UpdateResourceList();
  }
  else
  {
    SetFrameTitle("");
    m_currentFilename = "";
  }
  Modify(FALSE);
  
  return TRUE;
}

bool wxResourceManager::Clear(bool deleteWindows, bool force)
{
  if (!force && Modified())
  {
    int ans = wxMessageBox("Save modified resource file?", "Dialog Editor", wxYES_NO | wxCANCEL);
    if (ans == wxCANCEL)
      return FALSE;
    if (ans == wxYES)
      if (!SaveIfModified())
        return FALSE;
    if (ans == wxNO)
        Modify(FALSE);
  }
  
  ClearCurrentDialog();
  DisassociateWindows();

  m_resourceTable.ClearTable();
  UpdateResourceList();

  return TRUE;
}

bool wxResourceManager::DisassociateWindows()
{
  m_resourceTable.BeginFind();
  wxNode *node;
  while (node = m_resourceTable.Next())
  {
    wxItemResource *res = (wxItemResource *)node->Data();
    DisassociateResource(res);
  }
  
  return TRUE;
}

void wxResourceManager::AssociateResource(wxItemResource *resource, wxWindow *win)
{
  if (!m_resourceAssociations.Get((long)resource))
    m_resourceAssociations.Put((long)resource, win);

  wxNode *node = resource->GetChildren().First();
  while (node)
  {
    wxItemResource *child = (wxItemResource *)node->Data();
    wxWindow *childWindow = (wxWindow *)m_resourceAssociations.Get((long)child);
    if (!childWindow)
      childWindow = win->FindWindow(child->GetName());
    if (childWindow)
      AssociateResource(child, childWindow);
    else
    {
      char buf[200];
      sprintf(buf, "AssociateResource: cannot find child window %s", child->GetName() ? child->GetName() : "(unnamed)");
      wxMessageBox(buf, "Dialog Editor problem", wxOK);
    }

    node = node->Next();
  }
}

bool wxResourceManager::DisassociateResource(wxItemResource *resource)
{
  wxWindow *win = FindWindowForResource(resource);
  if (!win)
    return FALSE;

  // Disassociate children of window
  if (win->GetChildren())
  {
    wxNode *node = win->GetChildren()->First();
    while (node)
    {
      wxWindow *child = (wxWindow *)node->Data();
      if (child->IsKindOf(CLASSINFO(wxControl)))
      	DisassociateResource(child);
      node = node->Next();
    }
  }
  
  RemoveSelection(win);
  m_resourceAssociations.Delete((long)resource);
  return TRUE;
}

bool wxResourceManager::DisassociateResource(wxWindow *win)
{
  wxItemResource *res = FindResourceForWindow(win);
  if (res)
    return DisassociateResource(res);
  else
    return FALSE;
}

// Saves the window info into the resource, and deletes the
// handler. Doesn't actually disassociate the window from
// the resources. Replaces OnClose.
bool wxResourceManager::SaveInfoAndDeleteHandler(wxWindow* win)
{
    wxItemResource *res = FindResourceForWindow(win);

    if (win->IsKindOf(CLASSINFO(wxPanel)))
    {
        wxResourceEditorDialogHandler* handler = (wxResourceEditorDialogHandler*) win->GetEventHandler();
        win->PopEventHandler();

        // Now reset all child event handlers
        wxNode *node = win->GetChildren()->First();
        while ( node )
        {
	        wxWindow *child = (wxWindow *)node->Data();
	        wxEvtHandler *childHandler = child->GetEventHandler();
	        if ( child->IsKindOf(CLASSINFO(wxControl)) && childHandler != child )
	        {
		        child->PopEventHandler(TRUE);
	        }
	        node = node->Next();
        }
        delete handler;
    }
    else
    {
        win->PopEventHandler(TRUE);
    }
  
    // Save the information
    InstantiateResourceFromWindow(res, win, TRUE);
  
//  DisassociateResource(win);

    return TRUE;
}

// Destroys the window. If this is the 'current' panel, NULLs the
// variable.
bool wxResourceManager::DeleteWindow(wxWindow* win)
{
    if (m_editorPanel->m_childWindow == win)
        m_editorPanel->m_childWindow = NULL;

    win->Destroy();
    return TRUE;
}

wxItemResource *wxResourceManager::FindResourceForWindow(wxWindow *win)
{
  m_resourceAssociations.BeginFind();
  wxNode *node;
  while (node = m_resourceAssociations.Next())
  {
    wxWindow *w = (wxWindow *)node->Data();
    if (w == win)
    {
      return (wxItemResource *)node->key.integer;
    }
  }
  return NULL;
}

wxWindow *wxResourceManager::FindWindowForResource(wxItemResource *resource)
{
  return (wxWindow *)m_resourceAssociations.Get((long)resource);
}


void wxResourceManager::MakeUniqueName(char *prefix, char *buf)
{
  while (TRUE)
  {
    sprintf(buf, "%s%d", prefix, m_nameCounter);
    m_nameCounter ++;

    if (!m_resourceTable.FindResource(buf))
      return;
  }
}

wxFrame *wxResourceManager::OnCreateEditorFrame(const char *title)
{
  int frameWidth = 420;
  int frameHeight = 300;
  
  wxResourceEditorFrame *frame = new wxResourceEditorFrame(this, NULL, title,
    wxPoint(m_resourceEditorWindowSize.x, m_resourceEditorWindowSize.y),
    wxSize(m_resourceEditorWindowSize.width, m_resourceEditorWindowSize.height),
    wxDEFAULT_FRAME_STYLE);

  frame->CreateStatusBar(1);

  frame->SetAutoLayout(TRUE);
#ifdef __WINDOWS__
  wxIcon *icon = new wxIcon("DIALOGEDICON");
  frame->SetIcon(icon);
#endif
  return frame;
}

wxMenuBar *wxResourceManager::OnCreateEditorMenuBar(wxFrame *parent)
{
  wxMenuBar *menuBar = new wxMenuBar;

  wxMenu *fileMenu = new wxMenu;
  fileMenu->Append(RESED_NEW_DIALOG, "New &dialog", "Create a new dialog");
  fileMenu->AppendSeparator();
  fileMenu->Append(wxID_NEW, "&New project",           "Clear the current project");
  fileMenu->Append(wxID_OPEN, "&Open...",         "Load a resource file");
  fileMenu->Append(wxID_SAVE, "&Save",            "Save a resource file");
  fileMenu->Append(wxID_SAVEAS, "Save &As...",   "Save a resource file as...");
  fileMenu->Append(RESED_CLEAR, "&Clear",   "Clear current resources");
  fileMenu->AppendSeparator();
  fileMenu->Append(wxID_EXIT, "E&xit",            "Exit resource editor");

  wxMenu *editMenu = new wxMenu;
  editMenu->Append(RESED_TEST, "&Test Dialog",  "Test dialog");
  editMenu->Append(RESED_RECREATE, "&Recreate",  "Recreate the selected resource(s)");
  editMenu->Append(RESED_DELETE, "&Delete",  "Delete the selected resource(s)");

  wxMenu *helpMenu = new wxMenu;
  helpMenu->Append(RESED_CONTENTS, "&Help topics",          "Invokes the on-line help");
  helpMenu->AppendSeparator();
  helpMenu->Append(wxID_ABOUT, "&About",          "About wxWindows Dialog Editor");

  menuBar->Append(fileMenu, "&File");
  menuBar->Append(editMenu, "&Edit");
  menuBar->Append(helpMenu, "&Help");

  return menuBar;
}

wxResourceEditorScrolledWindow *wxResourceManager::OnCreateEditorPanel(wxFrame *parent)
{
  wxResourceEditorScrolledWindow *panel = new wxResourceEditorScrolledWindow(parent, wxDefaultPosition, wxDefaultSize,
//    wxSUNKEN_BORDER|wxCLIP_CHILDREN);
    wxSUNKEN_BORDER);

  panel->SetScrollbars(10, 10, 100, 100);

  return panel;
}

wxToolBarBase *wxResourceManager::OnCreateToolBar(wxFrame *parent)
{
  // Load palette bitmaps
#ifdef __WINDOWS__
  wxBitmap ToolbarLoadBitmap("LOADTOOL");
  wxBitmap ToolbarSaveBitmap("SAVETOOL");
  wxBitmap ToolbarNewBitmap("NEWTOOL");
  wxBitmap ToolbarVertBitmap("VERTTOOL");
  wxBitmap ToolbarAlignTBitmap("ALIGNTTOOL");
  wxBitmap ToolbarAlignBBitmap("ALIGNBTOOL");
  wxBitmap ToolbarHorizBitmap("HORIZTOOL");
  wxBitmap ToolbarAlignLBitmap("ALIGNLTOOL");
  wxBitmap ToolbarAlignRBitmap("ALIGNRTOOL");
  wxBitmap ToolbarCopySizeBitmap("COPYSIZETOOL");
  wxBitmap ToolbarToBackBitmap("TOBACKTOOL");
  wxBitmap ToolbarToFrontBitmap("TOFRONTTOOL");
  wxBitmap ToolbarHelpBitmap("HELPTOOL");
#endif
#ifdef __X__
  wxBitmap ToolbarLoadBitmap(load_bits, load_width, load_height);
  wxBitmap ToolbarSaveBitmap(save_bits, save_width, save_height);
  wxBitmap ToolbarNewBitmap(new_bits, save_width, save_height);
  wxBitmap ToolbarVertBitmap(vert_bits, vert_width, vert_height);
  wxBitmap ToolbarAlignTBitmap(alignt_bits, alignt_width, alignt_height);
  wxBitmap ToolbarAlignBBitmap(alignb_bits, alignb_width, alignb_height);
  wxBitmap ToolbarHorizBitmap(horiz_bits, horiz_width, horiz_height);
  wxBitmap ToolbarAlignLBitmap(alignl_bits, alignl_width, alignl_height);
  wxBitmap ToolbarAlignRBitmap(alignr_bits, alignr_width, alignr_height);
  wxBitmap ToolbarCopySizeBitmap(copysize_bits, copysize_width, copysize_height);
  wxBitmap ToolbarToBackBitmap(toback_bits, toback_width, toback_height);
  wxBitmap ToolbarToFrontBitmap(tofront_bits, tofront_width, tofront_height);
  wxBitmap ToolbarHelpBitmap(help_bits, help_width, help_height);
#endif

  // Create the toolbar
  EditorToolBar *toolbar = new EditorToolBar(parent, wxPoint(0, 0), wxSize(-1, -1), wxNO_BORDER,
                                        wxVERTICAL, 1);
  toolbar->SetMargins(2, 2);
//  toolbar->GetDC()->SetBackground(wxLIGHT_GREY_BRUSH);

#ifdef __WINDOWS__
  int width = 24;
  int dx = 2;
  int gap = 6;
#else
  int width = ToolbarLoadBitmap->GetWidth();
  int dx = 2;
  int gap = 6;
#endif
  int currentX = gap;
  toolbar->AddSeparator();
  toolbar->AddTool(TOOLBAR_NEW, ToolbarNewBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "New dialog");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_LOAD_FILE, ToolbarLoadBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Load");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_SAVE_FILE, ToolbarSaveBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Save");
  currentX += width + dx + gap;
  toolbar->AddSeparator();
  toolbar->AddTool(TOOLBAR_FORMAT_HORIZ, ToolbarVertBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Horizontal align");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_FORMAT_VERT_TOP_ALIGN, ToolbarAlignTBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Top align");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_FORMAT_VERT_BOT_ALIGN, ToolbarAlignBBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Bottom align");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_FORMAT_VERT, ToolbarHorizBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Vertical align");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_FORMAT_HORIZ_LEFT_ALIGN, ToolbarAlignLBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Left align");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_FORMAT_HORIZ_RIGHT_ALIGN, ToolbarAlignRBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Right align");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_COPY_SIZE, ToolbarCopySizeBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Copy size");
  currentX += width + dx + gap;
  toolbar->AddSeparator();
  toolbar->AddTool(TOOLBAR_TO_FRONT, ToolbarToFrontBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "To front");
  currentX += width + dx;
  toolbar->AddTool(TOOLBAR_TO_BACK, ToolbarToBackBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "To back");
  currentX += width + dx + gap;

  toolbar->AddSeparator();
  toolbar->AddTool(TOOLBAR_HELP, ToolbarHelpBitmap, (wxBitmap *)NULL,
                   FALSE, (float)currentX, -1, NULL, "Help");
  currentX += width + dx;
  
  toolbar->CreateTools();

  return toolbar;

//  parent->OnSize(-1, -1);
}

void wxResourceManager::UpdateResourceList()
{
  if (!m_editorResourceTree)
      return;

  m_editorResourceTree->SetInvalid(TRUE);
  m_editorResourceTree->DeleteAllItems();

  long id = m_editorResourceTree->InsertItem(0, "Dialogs"
#ifdef __WINDOWS__
     , 1, 2
#endif
   );

  m_resourceTable.BeginFind();
  wxNode *node;
  while (node = m_resourceTable.Next())
  {
    wxItemResource *res = (wxItemResource *)node->Data();
    wxString resType(res->GetType());
    if (resType == "wxDialog" || resType == "wxDialogBox" || resType == "wxPanel" || resType == "wxBitmap")
    {
      AddItemsRecursively(id, res);
    }
  }
  m_editorResourceTree->ExpandItem(id, wxTREE_EXPAND_EXPAND);
  m_editorResourceTree->SetInvalid(FALSE);
}

void wxResourceManager::AddItemsRecursively(long parent, wxItemResource *resource)
{
  wxString theString("");
  theString = resource->GetName();

  int imageId = 0;
  wxString resType(resource->GetType());
  if (resType == "wxDialog" || resType == "wxDialogBox" || resType == "wxPanel")
    imageId = 0;
  else
    imageId = 3;
  
  long id = m_editorResourceTree->InsertItem(parent, theString
#ifdef __WINDOWS__
     , imageId
#endif
   );

  m_editorResourceTree->SetItemData(id, (long) resource);

  if (strcmp(resource->GetType(), "wxBitmap") != 0)
  {
    wxNode *node = resource->GetChildren().First();
    while (node)
    {
      wxItemResource *res = (wxItemResource *)node->Data();
      AddItemsRecursively(id, res);
      node = node->Next();
    }
  }
  m_editorResourceTree->ExpandItem(id, wxTREE_EXPAND_EXPAND);
}

bool wxResourceManager::EditSelectedResource()
{
  int sel = m_editorResourceTree->GetSelection();
  if (sel > -1)
  {
    wxItemResource *res = (wxItemResource *)m_editorResourceTree->GetItemData(sel);
    return Edit(res);
  }
  return FALSE;
}

bool wxResourceManager::Edit(wxItemResource *res)
{
  ClearCurrentDialog();

  wxString resType(res->GetType());
  wxPanel *panel = (wxPanel *)FindWindowForResource(res);

  if (panel)
  {
    wxMessageBox("Should not find panel in wxResourceManager::Edit");
    return FALSE;
  }
  else
  {
        long style = res->GetStyle();
        res->SetStyle(style|wxRAISED_BORDER);
        panel = new wxPanel;
        wxResourceEditorDialogHandler *handler = new wxResourceEditorDialogHandler(panel, res, panel->GetEventHandler(),
           this);

        panel->LoadFromResource(m_editorPanel, res->GetName(), &m_resourceTable);

        panel->PushEventHandler(handler);

        res->SetStyle(style);
		handler->AddChildHandlers(); // Add event handlers for all controls
        AssociateResource(res, panel);

        m_editorPanel->m_childWindow = panel;
        panel->Move(m_editorPanel->GetMarginX(), m_editorPanel->GetMarginY());
        panel->Show(TRUE);
        panel->Refresh();

        wxClientDC dc(m_editorPanel);
        m_editorPanel->DrawTitle(dc);
  }
  return FALSE;
}

bool wxResourceManager::CreateNewPanel()
{
  ClearCurrentDialog();

  char buf[256];
  MakeUniqueName("panel", buf);
  
  wxItemResource *resource = new wxItemResource;
//  resource->SetType(wxTYPE_PANEL);
  resource->SetType("wxPanel");
  resource->SetName(buf);
  resource->SetTitle(buf);
  m_resourceTable.AddResource(resource);

  wxPanel *panel = new wxPanel(m_editorPanel, -1,
     wxPoint(m_editorPanel->GetMarginX(), m_editorPanel->GetMarginY()),
     wxSize(400, 300), wxRAISED_BORDER, buf);
  m_editorPanel->m_childWindow = panel;

  resource->SetStyle(0); // panel->GetWindowStyleFlag());
  resource->SetSize(10, 10, 400, 300);

  // For editing in situ we will need to use the hash table to ensure
  // we don't dereference invalid pointers.
//  resourceWindowTable.Put((long)resource, panel);

  wxResourceEditorDialogHandler *handler = new wxResourceEditorDialogHandler(panel, resource, panel->GetEventHandler(),
   this);
  panel->PushEventHandler(handler);
  
  AssociateResource(resource, panel);
  UpdateResourceList();
  
  Modify(TRUE);
  m_editorPanel->m_childWindow->Refresh();

//  panel->Refresh();

  wxClientDC dc(m_editorPanel);
  m_editorPanel->DrawTitle(dc);

  return TRUE;
}

bool wxResourceManager::CreatePanelItem(wxItemResource *panelResource, wxPanel *panel, char *iType, int x, int y, bool isBitmap)
{
  char buf[256];
  if (!panel->IsKindOf(CLASSINFO(wxPanel)) && !panel->IsKindOf(CLASSINFO(wxDialog)))
    return FALSE;

  Modify(TRUE);
  
  wxItemResource *res = new wxItemResource;
  wxControl *newItem = NULL;
  res->SetSize(x, y, -1, -1);
  res->SetType(iType);
  
  wxString itemType(iType);

  if (itemType == "wxButton")
    {
      MakeUniqueName("button", buf);
      res->SetName(buf);
      if (isBitmap)
        newItem = new wxBitmapButton(panel, -1, m_bitmapImage, wxPoint(x, y), wxSize(-1, -1), 0, wxDefaultValidator, buf);
      else
        newItem = new wxButton(panel, -1, "Button", wxPoint(x, y), wxSize(-1, -1), 0, wxDefaultValidator, buf);
    }
  if (itemType == "wxBitmapButton")
    {
      MakeUniqueName("button", buf);
      res->SetName(buf);
      newItem = new wxBitmapButton(panel, -1, m_bitmapImage, wxPoint(x, y), wxSize(-1, -1), 0, wxDefaultValidator, buf);
    }
  else if (itemType == "wxMessage" || itemType == "wxStaticText")
    {
      MakeUniqueName("message", buf);
      res->SetName(buf);
      if (isBitmap)
        newItem = new wxStaticBitmap(panel, -1, m_bitmapImage, wxPoint(x, y), wxSize(0, 0), 0, buf);
      else
        newItem = new wxStaticText(panel, -1, "Message", wxPoint(x, y), wxSize(-1, -1), 0, buf);
    }
  else if (itemType == "wxStaticBitmap")
    {
      MakeUniqueName("message", buf);
      res->SetName(buf);
      newItem = new wxStaticBitmap(panel, -1, m_bitmapImage, wxPoint(x, y), wxSize(-1, -1), 0, buf);
    }
  else if (itemType == "wxCheckBox")
    {
      MakeUniqueName("checkbox", buf);
      res->SetName(buf);
      newItem = new wxCheckBox(panel, -1, "Checkbox", wxPoint(x, y), wxSize(-1, -1), 0, wxDefaultValidator, buf);
    }
  else if (itemType == "wxListBox")
    {
      MakeUniqueName("listbox", buf);
      res->SetName(buf);
      newItem = new wxListBox(panel, -1, wxPoint(x, y), wxSize(-1, -1), 0, NULL, 0, wxDefaultValidator, buf);
    }
  else if (itemType == "wxRadioBox")
    {
      MakeUniqueName("radiobox", buf);
      res->SetName(buf);
      wxString names[] = { "One", "Two" };
      newItem = new wxRadioBox(panel, -1, "Radiobox", wxPoint(x, y), wxSize(-1, -1), 2, names, 2,
	     wxHORIZONTAL, wxDefaultValidator, buf);
      res->SetStringValues(new wxStringList("One", "Two", NULL));
    }
  else if (itemType == "wxChoice")
    {
      MakeUniqueName("choice", buf);
      res->SetName(buf);
      newItem = new wxChoice(panel, -1, wxPoint(x, y), wxSize(-1, -1), 0, NULL, 0, wxDefaultValidator, buf);
    }
  else if (itemType == "wxGroupBox" || itemType == "wxStaticBox")
    {
      MakeUniqueName("group", buf);
      res->SetName(buf);
      newItem = new wxStaticBox(panel, -1, "Groupbox", wxPoint(x, y), wxSize(200, 200), 0, buf);
    }
  else if (itemType == "wxGauge")
    {
      MakeUniqueName("gauge", buf);
      res->SetName(buf);
      newItem = new wxGauge(panel, -1, 10, wxPoint(x, y), wxSize(80, 30), wxHORIZONTAL, wxDefaultValidator, buf);
    }
  else if (itemType == "wxSlider")
    {
      MakeUniqueName("slider", buf);
      res->SetName(buf);
      newItem = new wxSlider(panel, -1, 1, 1, 10, wxPoint(x, y), wxSize(120, -1), wxHORIZONTAL, wxDefaultValidator, buf);
    }
  else if (itemType == "wxText" || itemType == "wxTextCtrl (single-line)")
    {
      MakeUniqueName("textctrl", buf);
      res->SetName(buf);
      res->SetType("wxTextCtrl");
      newItem = new wxTextCtrl(panel, -1, "", wxPoint(x, y), wxSize(120, -1), 0, wxDefaultValidator, buf);
    }
  else if (itemType == "wxMultiText" || itemType == "wxTextCtrl (multi-line)")
    {
      MakeUniqueName("textctrl", buf);
      res->SetName(buf);
      res->SetType("wxTextCtrl");
      newItem = new wxTextCtrl(panel, -1, "", wxPoint(x, y), wxSize(120, 100), wxTE_MULTILINE, wxDefaultValidator, buf);
    }
  else if (itemType == "wxScrollBar")
    {
      MakeUniqueName("scrollbar", buf);
      res->SetName(buf);
      newItem = new wxScrollBar(panel, -1, wxPoint(x, y), wxSize(140, -1), wxHORIZONTAL, wxDefaultValidator, buf);
    }
  if (!newItem)
    return FALSE;

  newItem->PushEventHandler(new wxResourceEditorControlHandler(newItem, newItem));

  res->SetStyle(newItem->GetWindowStyleFlag());
  AssociateResource(res, newItem);
  panelResource->GetChildren().Append(res);

  UpdateResourceList();
  
  return TRUE;
}

void wxResourceManager::ClearCurrentDialog()
{
  if (m_editorPanel->m_childWindow)
  {
    SaveInfoAndDeleteHandler(m_editorPanel->m_childWindow);
    DisassociateResource(m_editorPanel->m_childWindow);
    DeleteWindow(m_editorPanel->m_childWindow);
    m_editorPanel->m_childWindow = NULL;
    m_editorPanel->Clear();
  }
}

// Find the first dialog or panel for which
// there is a selected panel item.
wxWindow *wxResourceManager::FindParentOfSelection()
{
  m_resourceTable.BeginFind();
  wxNode *node;
  while (node = m_resourceTable.Next())
  {
    wxItemResource *res = (wxItemResource *)node->Data();
    wxWindow *win = FindWindowForResource(res);
    if (win)
    {
      wxNode *node1 = win->GetChildren()->First();
      while (node1)
      {
        wxControl *item = (wxControl *)node1->Data();
	    wxResourceEditorControlHandler *childHandler = (wxResourceEditorControlHandler *)item->GetEventHandler();
        if (item->IsKindOf(CLASSINFO(wxControl)) && childHandler->IsSelected())
          return win;
        node1 = node1->Next();
      }
    }
  }
  return NULL;
}

// Format the panel items according to 'flag'
void wxResourceManager::AlignItems(int flag)
{
  wxWindow *win = FindParentOfSelection();
  if (!win)
    return;

  wxNode *node = GetSelections().First();
  if (!node)
    return;
    
  wxControl *firstSelection = (wxControl *)node->Data();
  if (firstSelection->GetParent() != win)
    return;
    
  int firstX, firstY;
  int firstW, firstH;
  firstSelection->GetPosition(&firstX, &firstY);
  firstSelection->GetSize(&firstW, &firstH);
  int centreX = (int)(firstX + (firstW / 2));
  int centreY = (int)(firstY + (firstH / 2));

  while (node = node->Next())
  {
    wxControl *item = (wxControl *)node->Data();
    if (item->GetParent() == win)
    {
      int x, y, w, h;
      item->GetPosition(&x, &y);
      item->GetSize(&w, &h);

      int newX, newY;

      switch (flag)
      {
        case TOOLBAR_FORMAT_HORIZ:
        {
          newX = x;
          newY = (int)(centreY - (h/2.0));
          break;
        }
        case TOOLBAR_FORMAT_VERT:
        {
          newX = (int)(centreX - (w/2.0));
          newY = y;
          break;
        }
        case TOOLBAR_FORMAT_HORIZ_LEFT_ALIGN:
        {
          newX = firstX;
          newY = y;
          break;
        }
        case TOOLBAR_FORMAT_VERT_TOP_ALIGN:
        {
          newX = x;
          newY = firstY;
          break;
        }
        case TOOLBAR_FORMAT_HORIZ_RIGHT_ALIGN:
        {
          newX = firstX + firstW - w;
          newY = y;
          break;
        }
        case TOOLBAR_FORMAT_VERT_BOT_ALIGN:
        {
          newX = x;
          newY = firstY + firstH - h;
          break;
        }
        default:
          newX = x; newY = y;
          break;
      }

      item->SetSize(newX, newY, w, h);
    }
  }
  win->Refresh();
}

// Copy the first image's size to subsequent images
void wxResourceManager::CopySize()
{
  wxWindow *win = FindParentOfSelection();
  if (!win)
    return;

  wxNode *node = GetSelections().First();
  if (!node)
    return;
    
  wxControl *firstSelection = (wxControl *)node->Data();
  if (firstSelection->GetParent() != win)
    return;
    
  int firstX, firstY;
  int firstW, firstH;
  firstSelection->GetPosition(&firstX, &firstY);
  firstSelection->GetSize(&firstW, &firstH);
  int centreX = (int)(firstX + (firstW / 2));
  int centreY = (int)(firstY + (firstH / 2));

  while (node = node->Next())
  {
    wxControl *item = (wxControl *)node->Data();
    if (item->GetParent() == win)
      item->SetSize(-1, -1, firstW, firstH);
  }
  win->Refresh();
}

void wxResourceManager::ToBackOrFront(bool toBack)
{
  wxWindow *win = FindParentOfSelection();
  if (!win)
    return;
  wxItemResource *winResource = FindResourceForWindow(win);

  wxNode *node = GetSelections().First();
  while (node)
  {
    wxControl *item = (wxControl *)node->Data();
    wxItemResource *itemResource = FindResourceForWindow(item);
    if (item->GetParent() == win)
    {
      win->GetChildren()->DeleteObject(item);
      if (winResource)
        winResource->GetChildren().DeleteObject(itemResource);
      if (toBack)
      {
        win->GetChildren()->Insert(item);
        if (winResource)
          winResource->GetChildren().Insert(itemResource);
      }
      else
      {
        win->GetChildren()->Append(item);
        if (winResource)
          winResource->GetChildren().Append(itemResource);
      }
    }
    node = node->Next();
  }
//  win->Refresh();
}

void wxResourceManager::AddSelection(wxWindow *win)
{
  if (!m_selections.Member(win))
    m_selections.Append(win);
}

void wxResourceManager::RemoveSelection(wxWindow *win)
{
  m_selections.DeleteObject(win);
}

// Need to search through resource table removing this from
// any resource which has this as a parent.
bool wxResourceManager::RemoveResourceFromParent(wxItemResource *res)
{
  m_resourceTable.BeginFind();
  wxNode *node;
  while (node = m_resourceTable.Next())
  {
    wxItemResource *thisRes = (wxItemResource *)node->Data();
    if (thisRes->GetChildren().Member(res))
    {
      thisRes->GetChildren().DeleteObject(res);
      return TRUE;
    }
  }
  return FALSE;
}

bool wxResourceManager::DeleteResource(wxItemResource *res)
{
  if (!res)
    return FALSE;

  RemoveResourceFromParent(res);

  wxNode *node = res->GetChildren().First();
  while (node)
  {
    wxNode *next = node->Next();
    wxItemResource *child = (wxItemResource *)node->Data();
    DeleteResource(child);
    node = next;
  }
  
  // If this is a button or message resource, delete the
  // associate bitmap resource if not being used.
  wxString resType(res->GetType());
  
  if ((resType == "wxMessage" || resType == "wxStaticBitmap" || resType == "wxButton" || resType == "wxBitmapButton") && res->GetValue4())
  {
    PossiblyDeleteBitmapResource(res->GetValue4());
  }

  m_resourceTable.Delete(res->GetName());
  delete res;
  Modify(TRUE);
  return TRUE;
}

bool wxResourceManager::DeleteResource(wxWindow *win)
{
  if (win->IsKindOf(CLASSINFO(wxControl)))
  {
    // Deselect and refresh window in case we leave selection
    // handles behind
    wxControl *item = (wxControl *)win;
    wxResourceEditorControlHandler *childHandler = (wxResourceEditorControlHandler *)item->GetEventHandler();
    if (childHandler->IsSelected())
    {
      RemoveSelection(item);
      childHandler->SelectItem(FALSE);
      item->GetParent()->Refresh();
    }
  }
  
  wxItemResource *res = FindResourceForWindow(win);
  
  DisassociateResource(res);
  DeleteResource(res);
  UpdateResourceList();

  return TRUE;
}

// Will eventually have bitmap type information, for different
// kinds of bitmap.
char *wxResourceManager::AddBitmapResource(char *filename)
{
  wxItemResource *resource = FindBitmapResourceByFilename(filename);
  if (!resource)
  {
    char buf[256];
    MakeUniqueName("bitmap", buf);
    resource = new wxItemResource;
    resource->SetType("wxBitmap");
    resource->SetName(buf);
    
    // A bitmap resource has one or more children, specifying
    // alternative bitmaps.
    wxItemResource *child = new wxItemResource;
    child->SetType("wxBitmap");
    child->SetName(filename);
    child->SetValue1(wxBITMAP_TYPE_BMP);
    child->SetValue2(RESOURCE_PLATFORM_ANY);
    child->SetValue3(0); // Depth
    child->SetSize(0,0,0,0);
    resource->GetChildren().Append(child);

    m_resourceTable.AddResource(resource);

    UpdateResourceList();
  }
  if (resource)
    return resource->GetName();
  else
    return NULL;
}

 // Delete the bitmap resource if it isn't being used by another resource.
void wxResourceManager::PossiblyDeleteBitmapResource(char *resourceName)
{
  if (!IsBitmapResourceUsed(resourceName))
  {
    wxItemResource *res = m_resourceTable.FindResource(resourceName);
    DeleteResource(res);
    UpdateResourceList();
  }
}

bool wxResourceManager::IsBitmapResourceUsed(char *resourceName)
{
  m_resourceTable.BeginFind();
  wxNode *node;
  while (node = m_resourceTable.Next())
  {
    wxItemResource *res = (wxItemResource *)node->Data();
    wxString resType(res->GetType());
    if (resType == "wxDialog")
    {
      wxNode *node1 = res->GetChildren().First();
      while (node1)
      {
        wxItemResource *child = (wxItemResource *)node1->Data();
        wxString childResType(child->GetType());
        
        if ((childResType == "wxMessage" || childResType == "wxButton") &&
             child->GetValue4() &&
            (strcmp(child->GetValue4(), resourceName) == 0))
          return TRUE;
        node1 = node1->Next();
      }
    }
  }
  return FALSE;
}

// Given a wxButton or wxMessage, find the corresponding bitmap filename.
char *wxResourceManager::FindBitmapFilenameForResource(wxItemResource *resource)
{
  if (!resource || !resource->GetValue4())
    return NULL;
  wxItemResource *bitmapResource = m_resourceTable.FindResource(resource->GetValue4());
  if (!bitmapResource)
    return NULL;

  wxNode *node = bitmapResource->GetChildren().First();
  while (node)
  {
    // Eventually augment this to return a bitmap of the right kind or something...
    // Maybe the root of the filename remains the same, so it doesn't matter which we
    // pick up. Otherwise how do we specify multiple filenames... too boring...
    wxItemResource *child = (wxItemResource *)node->Data();
    return child->GetName();
    
    node = node->Next();
  }
  return NULL;
}

wxItemResource *wxResourceManager::FindBitmapResourceByFilename(char *filename)
{
  m_resourceTable.BeginFind();
  wxNode *node;
  while (node = m_resourceTable.Next())
  {
    wxItemResource *res = (wxItemResource *)node->Data();
    wxString resType(res->GetType());
    if (resType == "wxBitmap")
    {
      wxNode *node1 = res->GetChildren().First();
      while (node1)
      {
        wxItemResource *child = (wxItemResource *)node1->Data();
        if (child->GetName() && (strcmp(child->GetName(), filename) == 0))
          return res;
        node1 = node1->Next();
      }
    }
  }
  return NULL;
}

 // Deletes 'win' and creates a new window from the resource that
 // was associated with it. E.g. if you can't change properties on the
 // fly, you'll need to delete the window and create it again.
wxWindow *wxResourceManager::RecreateWindowFromResource(wxWindow *win, wxWindowPropertyInfo *info)
{
  wxItemResource *resource = FindResourceForWindow(win);

  // Put the current window properties into the wxItemResource object
  
  wxWindowPropertyInfo *newInfo = NULL;
  if (!info)
  {
    newInfo = CreatePropertyInfoForWindow(win);
    info = newInfo;
  }

  info->InstantiateResource(resource);

  wxWindow *newWin = NULL;
  wxWindow *parent = win->GetParent();
  
  if (win->IsKindOf(CLASSINFO(wxPanel)))
  {
    Edit(resource);
    newWin = FindWindowForResource(resource);
  }
  else
  {
    DisassociateResource(resource);
    DeleteWindow(win);
    newWin = m_resourceTable.CreateItem((wxPanel *)parent, resource);
    AssociateResource(resource, newWin);
    UpdateResourceList();
  }

  if (info)
    info->SetPropertyWindow(newWin);
    
  if (newInfo)
    delete newInfo;
  
  return newWin;
}

// Delete resource highlighted in the listbox
bool wxResourceManager::DeleteSelection()
{
  int sel = m_editorResourceTree->GetSelection();
  if (sel > -1)
  {
    wxItemResource *res = (wxItemResource *)m_editorResourceTree->GetItemData(sel);
    wxWindow *win = FindWindowForResource(res);
    if (win)
    {
        DeleteResource(win);
        DeleteWindow(win);
        UpdateResourceList();
        Modify(TRUE);
    }
    return TRUE;
  }

  return FALSE;
}

// Delete resource highlighted in the listbox
bool wxResourceManager::RecreateSelection()
{
  wxNode *node = GetSelections().First();
  while (node)
  {
    wxControl *item = (wxControl *)node->Data();
    wxResourceEditorControlHandler *childHandler = (wxResourceEditorControlHandler *)item->GetEventHandler();
    wxNode *next = node->Next();
    childHandler->SelectItem(FALSE);

    RemoveSelection(item);
    
    RecreateWindowFromResource(item);
    
    node = next;
  }
  return TRUE;
}

bool wxResourceManager::EditDialog(wxDialog *dialog, wxWindow *parent)
{
  return FALSE;
}

// Ensures that all currently shown windows are saved to resources,
// e.g. just before writing to a .wxr file.
bool wxResourceManager::InstantiateAllResourcesFromWindows()
{
  m_resourceTable.BeginFind();
  wxNode *node;
  while (node = m_resourceTable.Next())
  {
    wxItemResource *res = (wxItemResource *)node->Data();
    wxString resType(res->GetType());
    
    if (resType == "wxDialog")
    {
      wxWindow *win = (wxWindow *)FindWindowForResource(res);
      if (win)
        InstantiateResourceFromWindow(res, win, TRUE);
    }
    else if (resType == "wxPanel")
    {
      wxWindow *win = (wxWindow *)FindWindowForResource(res);
      if (win)
        InstantiateResourceFromWindow(res, win, TRUE);
    }
  }
  return TRUE;  
}

bool wxResourceManager::InstantiateResourceFromWindow(wxItemResource *resource, wxWindow *window, bool recurse)
{
  wxWindowPropertyInfo *info = CreatePropertyInfoForWindow(window);
  info->SetResource(resource);
  info->InstantiateResource(resource);
  delete info;
  
  if (recurse)
  {
    wxNode *node = resource->GetChildren().First();
    while (node)
    {
      wxItemResource *child = (wxItemResource *)node->Data();
      wxWindow *childWindow = FindWindowForResource(child);
      
      if (!childWindow)
      {
        char buf[200];
        sprintf(buf, "Could not find window %s", child->GetName());
        wxMessageBox(buf, "Dialog Editor problem", wxOK);
      }
      else
        InstantiateResourceFromWindow(child, childWindow, recurse);
      node = node->Next();
    }
  }
  
  return TRUE;
}

// Create a window information object for the give window
wxWindowPropertyInfo *wxResourceManager::CreatePropertyInfoForWindow(wxWindow *win)
{
  wxWindowPropertyInfo *info = NULL;
  if (win->IsKindOf(CLASSINFO(wxScrollBar)))
        {
          info = new wxScrollBarPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxStaticBox)))
        {
          info = new wxGroupBoxPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxCheckBox)))
        {
          info = new wxCheckBoxPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxSlider)))
        {
          info = new wxSliderPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxGauge)))
        {
          info = new wxGaugePropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxListBox)))
        {
          info = new wxListBoxPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxRadioBox)))
        {
          info = new wxRadioBoxPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxChoice)))
        {
          info = new wxChoicePropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxButton)))
        {
          info = new wxButtonPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxBitmapButton)))
        {
          info = new wxBitmapButtonPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxStaticText)))
        {
          info = new wxStaticTextPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxStaticBitmap)))
        {
          info = new wxStaticBitmapPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxTextCtrl)))
        {
          info = new wxTextPropertyInfo(win);
        }
  else if (win->IsKindOf(CLASSINFO(wxPanel)))
        {
          info = new wxPanelPropertyInfo(win);
        }
  else
        {
          info = new wxWindowPropertyInfo(win);
        }
  return info;
}

// Edit the given window
void wxResourceManager::EditWindow(wxWindow *win)
{
  wxWindowPropertyInfo *info = CreatePropertyInfoForWindow(win);
  if (info)
  {
    info->SetResource(FindResourceForWindow(win));
    wxString str("Editing ");
    str += win->GetClassInfo()->GetClassName();
    str += ": ";
    if (win->GetName() != "")
        str += win->GetName();
    else
        str += "properties";
    info->Edit(NULL, str);
  }
}


/*
 * Resource editor frame
 */

IMPLEMENT_CLASS(wxResourceEditorFrame, wxFrame)

BEGIN_EVENT_TABLE(wxResourceEditorFrame, wxFrame)
    EVT_MENU(wxID_NEW, wxResourceEditorFrame::OnNew)
    EVT_MENU(RESED_NEW_DIALOG, wxResourceEditorFrame::OnNewDialog)
    EVT_MENU(wxID_OPEN, wxResourceEditorFrame::OnOpen)
    EVT_MENU(RESED_CLEAR, wxResourceEditorFrame::OnClear)
    EVT_MENU(wxID_SAVE, wxResourceEditorFrame::OnSave)
    EVT_MENU(wxID_SAVEAS, wxResourceEditorFrame::OnSaveAs)
    EVT_MENU(wxID_EXIT, wxResourceEditorFrame::OnExit)
    EVT_MENU(wxID_ABOUT, wxResourceEditorFrame::OnAbout)
    EVT_MENU(RESED_CONTENTS, wxResourceEditorFrame::OnContents)
    EVT_MENU(RESED_DELETE, wxResourceEditorFrame::OnDeleteSelection)
    EVT_MENU(RESED_RECREATE, wxResourceEditorFrame::OnRecreateSelection)
    EVT_MENU(RESED_TEST, wxResourceEditorFrame::OnTest)
END_EVENT_TABLE()

wxResourceEditorFrame::wxResourceEditorFrame(wxResourceManager *resMan, wxFrame *parent, const wxString& title,
    const wxPoint& pos, const wxSize& size, long style, const wxString& name):
  wxFrame(parent, -1, title, pos, size, style, name)
{
  manager = resMan;
}

wxResourceEditorFrame::~wxResourceEditorFrame()
{
}

void wxResourceEditorFrame::OnNew(wxCommandEvent& event)
{
      manager->New(FALSE);
}

void wxResourceEditorFrame::OnNewDialog(wxCommandEvent& event)
{
      manager->CreateNewPanel();
}

void wxResourceEditorFrame::OnOpen(wxCommandEvent& event)
{
      manager->New(TRUE);
}

void wxResourceEditorFrame::OnClear(wxCommandEvent& event)
{
      manager->Clear(TRUE, FALSE);
}

void wxResourceEditorFrame::OnSave(wxCommandEvent& event)
{
      manager->Save();
}

void wxResourceEditorFrame::OnSaveAs(wxCommandEvent& event)
{
      manager->SaveAs();
}

void wxResourceEditorFrame::OnExit(wxCommandEvent& event)
{
	  manager->Clear(TRUE, FALSE) ;
      this->Close();
}

void wxResourceEditorFrame::OnAbout(wxCommandEvent& event)
{
      char buf[300];
      sprintf(buf, "wxWindows Dialog Editor %.1f\nAuthor: Julian Smart J.Smart@ed.ac.uk\nJulian Smart (c) 1996", wxDIALOG_EDITOR_VERSION);
      wxMessageBox(buf, "About Dialog Editor", wxOK|wxCENTRE);
}

void wxResourceEditorFrame::OnTest(wxCommandEvent& event)
{
    // TODO should show the current dialog
}

void wxResourceEditorFrame::OnContents(wxCommandEvent& event)
{
      wxBeginBusyCursor();
      manager->GetHelpController()->LoadFile();
      manager->GetHelpController()->DisplayContents();
      wxEndBusyCursor();
}

void wxResourceEditorFrame::OnDeleteSelection(wxCommandEvent& event)
{
      manager->DeleteSelection();
}

void wxResourceEditorFrame::OnRecreateSelection(wxCommandEvent& event)
{
      manager->RecreateSelection();
}

bool wxResourceEditorFrame::OnClose()
{
  if (manager->Modified())
  {
  if (!manager->Clear(TRUE, FALSE))
     return FALSE;
  }
    
  if (!Iconized())
  {
    int w, h;
    GetSize(&w, &h);
    manager->m_resourceEditorWindowSize.width = w;
    manager->m_resourceEditorWindowSize.height = h;

    int x, y;
    GetPosition(&x, &y);

    manager->m_resourceEditorWindowSize.x = x;
    manager->m_resourceEditorWindowSize.y = y;
  }
  manager->SetEditorFrame(NULL);
  manager->SetEditorToolBar(NULL);
  manager->SetEditorPalette(NULL);

  return TRUE;
}

/*
 * Resource editor window that contains the dialog/panel being edited
 */

BEGIN_EVENT_TABLE(wxResourceEditorScrolledWindow, wxScrolledWindow)
    EVT_SCROLL(wxResourceEditorScrolledWindow::OnScroll)
    EVT_PAINT(wxResourceEditorScrolledWindow::OnPaint)
END_EVENT_TABLE()

wxResourceEditorScrolledWindow::wxResourceEditorScrolledWindow(wxWindow *parent, const wxPoint& pos, const wxSize& size,
    long style):
  wxScrolledWindow(parent, -1, pos, size, style)
{
    m_marginX = 10;
    m_marginY = 40;
    m_childWindow = NULL;
}

wxResourceEditorScrolledWindow::~wxResourceEditorScrolledWindow()
{
}

void wxResourceEditorScrolledWindow::OnScroll(wxScrollEvent& event)
{
    wxScrolledWindow::OnScroll(event);

    int x, y;
    ViewStart(& x, & y);

    if (m_childWindow)
        m_childWindow->Move(m_marginX + (- x * 10), m_marginY + (- y * 10));
}

void wxResourceEditorScrolledWindow::OnPaint(wxPaintEvent& event)
{
    wxPaintDC dc(this);

    DrawTitle(dc);
}

void wxResourceEditorScrolledWindow::DrawTitle(wxDC& dc)
{
    if (m_childWindow)
    {
        wxItemResource* res = wxResourceManager::GetCurrentResourceManager()->FindResourceForWindow(m_childWindow);
        if (res)
        {
            wxString str(res->GetTitle());
            int x, y;
            ViewStart(& x, & y);

            wxFont font(10, wxSWISS, wxNORMAL, wxBOLD);
            dc.SetFont(font);
            dc.SetBackgroundMode(wxTRANSPARENT);
            dc.SetTextForeground(wxColour(0, 0, 0));

            long w, h;
            dc.GetTextExtent(str, & w, & h);

            dc.DrawText(str, m_marginX + (- x * 10), m_marginY + (- y * 10) - h - 5);
        }
    }
}

// Popup menu callback
void ObjectMenuProc(wxMenu& menu, wxCommandEvent& event)
{
  wxWindow *data = (wxWindow *)menu.GetClientData();
  if (!data)
    return;

  switch (event.GetInt())
  {
    case OBJECT_MENU_EDIT:
    {
      wxResourceManager::GetCurrentResourceManager()->EditWindow(data);
      break;
    }
    case OBJECT_MENU_DELETE:
    {
      wxResourceManager::GetCurrentResourceManager()->SaveInfoAndDeleteHandler(data);
      wxResourceManager::GetCurrentResourceManager()->DeleteResource(data);
      wxResourceManager::GetCurrentResourceManager()->DeleteWindow(data);
      break;
    }
    default:
      break;
  }
}

/*
 * Main toolbar
 *
 */

BEGIN_EVENT_TABLE(EditorToolBar, wxToolBar)
	EVT_PAINT(EditorToolBar::OnPaint)
END_EVENT_TABLE()

EditorToolBar::EditorToolBar(wxFrame *frame, const wxPoint& pos, const wxSize& size,
            long style, int direction, int RowsOrColumns):
  wxToolBar(frame, -1, pos, size, style, direction, RowsOrColumns)
{
}

bool EditorToolBar::OnLeftClick(int toolIndex, bool toggled)
{
  wxResourceManager *manager = wxResourceManager::GetCurrentResourceManager();

  switch (toolIndex)
  {
    case TOOLBAR_LOAD_FILE:
    {
      manager->New(TRUE);
      break;
    }
    case TOOLBAR_NEW:
    {
      manager->CreateNewPanel();
      break;
    }
    case TOOLBAR_SAVE_FILE:
    {
      manager->Save();
      break;
    }
    case TOOLBAR_HELP:
    {
      wxBeginBusyCursor();
      manager->GetHelpController()->LoadFile();
      manager->GetHelpController()->DisplayContents();
      wxEndBusyCursor();
      break;
    }
    case TOOLBAR_FORMAT_HORIZ:
    {
      manager->AlignItems(TOOLBAR_FORMAT_HORIZ);
      break;
    }
    case TOOLBAR_FORMAT_HORIZ_LEFT_ALIGN:
    {
      manager->AlignItems(TOOLBAR_FORMAT_HORIZ_LEFT_ALIGN);
      break;
    }
    case TOOLBAR_FORMAT_HORIZ_RIGHT_ALIGN:
    {
      manager->AlignItems(TOOLBAR_FORMAT_HORIZ_RIGHT_ALIGN);
      break;
    }
    case TOOLBAR_FORMAT_VERT:
    {
      manager->AlignItems(TOOLBAR_FORMAT_VERT);
      break;
    }
    case TOOLBAR_FORMAT_VERT_TOP_ALIGN:
    {
      manager->AlignItems(TOOLBAR_FORMAT_VERT_TOP_ALIGN);
      break;
    }
    case TOOLBAR_FORMAT_VERT_BOT_ALIGN:
    {
      manager->AlignItems(TOOLBAR_FORMAT_VERT_BOT_ALIGN);
      break;
    }
    case TOOLBAR_COPY_SIZE:
    {
      manager->CopySize();
      break;
    }
    case TOOLBAR_TO_BACK:
    {
      manager->ToBackOrFront(TRUE);
      break;
    }
    case TOOLBAR_TO_FRONT:
    {
      manager->ToBackOrFront(FALSE);
      break;
    }
    default:
      break;
  }
  return TRUE;
}

void EditorToolBar::OnMouseEnter(int toolIndex)
{
  wxFrame *frame = (wxFrame *)GetParent();
  
  if (!frame) return;
  
  if (toolIndex > -1)
  {
      switch (toolIndex)
      {
        case TOOLBAR_LOAD_FILE:
          frame->SetStatusText("Load project file");
          break;
        case TOOLBAR_SAVE_FILE:
          frame->SetStatusText("Save project file");
          break;
        case TOOLBAR_NEW:
          frame->SetStatusText("Create a new resource");
          break;
        case TOOLBAR_FORMAT_HORIZ:
          frame->SetStatusText("Align items horizontally");
          break;
        case TOOLBAR_FORMAT_VERT:
          frame->SetStatusText("Align items vertically");
          break;
        case TOOLBAR_FORMAT_HORIZ_LEFT_ALIGN:
          frame->SetStatusText("Left-align items");
          break;
        case TOOLBAR_FORMAT_HORIZ_RIGHT_ALIGN:
          frame->SetStatusText("Right-align items");
          break;
        case TOOLBAR_FORMAT_VERT_TOP_ALIGN:
          frame->SetStatusText("Top-align items");
          break;
        case TOOLBAR_FORMAT_VERT_BOT_ALIGN:
          frame->SetStatusText("Bottom-align items");
          break;
        case TOOLBAR_COPY_SIZE:
          frame->SetStatusText("Copy size from first selection");
          break;
        case TOOLBAR_TO_FRONT:
          frame->SetStatusText("Put image to front");
          break;
        case TOOLBAR_TO_BACK:
          frame->SetStatusText("Put image to back");
          break;
        case TOOLBAR_HELP:
          frame->SetStatusText("Display help contents");
          break;
        default:
          break;
      }
  }
  else frame->SetStatusText("");
}

void EditorToolBar::OnPaint(wxPaintEvent& event)
{
  wxToolBar::OnPaint(event);

  wxPaintDC dc(this);
  int w, h;
  GetSize(&w, &h);
  dc.SetPen(wxBLACK_PEN);
  dc.SetBrush(wxTRANSPARENT_BRUSH);
  dc.DrawLine(0, h-1, w, h-1);
}


