areaeditor/
/*
** AreaEditor - a program for editing SMAUG and ROM area files.
** Author: Nick Gammon
** http://www.gammon.com.au/
** See Copyright Notice at the end of AreaEditor.h
*/

// CommandsListDlg.cpp : implementation file
//

#include "stdafx.h"
#include "AreaEditor.h"
#include "CommandsListDlg.h"

#include "EditCommandDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCommandsListDlg dialog


CCommandsListDlg::CCommandsListDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CCommandsListDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CCommandsListDlg)
	m_strCommandCount = _T("");
	//}}AFX_DATA_INIT

  m_last_col = 0;
  m_reverse = FALSE;

}


void CCommandsListDlg::DoDataExchange(CDataExchange* pDX)
{
  if (!pDX->m_bSaveAndValidate)
    m_strCommandCount.Format ("%i commands", App.m_CommandList.GetCount ());

  CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CCommandsListDlg)
	DDX_Control(pDX, IDC_COMMANDS_LIST, m_ctlCommandsList);
	DDX_Text(pDX, IDC_COMMAND_COUNT, m_strCommandCount);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CCommandsListDlg, CDialog)
	//{{AFX_MSG_MAP(CCommandsListDlg)
	ON_BN_CLICKED(IDC_ADD, OnAdd)
	ON_BN_CLICKED(IDC_DELETE, OnDelete)
	ON_BN_CLICKED(IDC_EDIT, OnEdit)
	ON_NOTIFY(NM_DBLCLK, IDC_COMMANDS_LIST, OnDblclkCommandsList)
	ON_NOTIFY(LVN_COLUMNCLICK, IDC_COMMANDS_LIST, OnColumnclickCommandsList)
	//}}AFX_MSG_MAP
  ON_MESSAGE(WM_KICKIDLE, OnKickIdle)
  ON_UPDATE_COMMAND_UI(IDC_EDIT, OnUpdateNeedSelection)
  ON_UPDATE_COMMAND_UI(IDC_DELETE, OnUpdateNeedSelection)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCommandsListDlg message handlers

typedef struct 
  {  
  int        sortkey;             // which key to use
  int        reverse;             // reverse sort or not
  } t_sort_param;

static int CALLBACK CompareFunc ( LPARAM lParam1, 
                           LPARAM lParam2,
                           LPARAM lParamSort)
  { 

 ASSERT (lParamSort != NULL);

t_sort_param * psort_param = (t_sort_param *) lParamSort;

CCommand * pCommand1 = (CCommand *) lParam1;
CCommand * pCommand2 = (CCommand *) lParam2;

 ASSERT (pCommand1 != NULL);
 ASSERT (pCommand2 != NULL);

int iResult = 0;

   switch (psort_param->sortkey)
     {
     case 2:
        if (pCommand1->level < pCommand2->level)
          {
          iResult = -1;
          break;
          }
        else
        if (pCommand1->level > pCommand2->level)
          {
          iResult = 1;
          break;
          }

// note - if level is same - fall through to code


     case 1:
        iResult = pCommand1->do_fun.CompareNoCase (pCommand2->do_fun);
        if (iResult != 0)
          break;

// note - if code is the same - fall through to name

     case 0:
        iResult = pCommand1->name.CompareNoCase (pCommand2->name);
        break;
     }  // end of switch

// if reverse sort wanted, reverse sense of result

  if (psort_param->reverse)
    iResult *= -1;

  return iResult;

  } // end of CompareFunc

#undef LOAD_VALUE
#define LOAD_VALUE(field, value)  \
  dlg.field = command->value

#undef UNLOAD_VALUE
#define UNLOAD_VALUE(field, value)  \
  do {    \
    if (dlg.field != command->value) bChanged = true; \
    command->value = dlg.field;   \
    } while (false)

#define LOAD_FLAG(field, flag)  \
  dlg.field = IS_SET (command->flags, flag);

#undef UNLOAD_FLAG
#define UNLOAD_FLAG(field, flag)  \
  if (dlg.field != IS_SET (command->flags, flag)) bChanged = true; \
  if (dlg.field)                      \
    SET_BIT (command->flags, flag);\
  else                            \
    REMOVE_BIT (command->flags, flag)


void CCommandsListDlg::OnAdd() 
{
  CEditCommandDlg dlg;
  bool bChanged = false;

  dlg.m_bAdd = true;

  if (dlg.DoModal() != IDOK)
    return;

  CCommand * command = new CCommand;

  App.m_CommandList.AddTail (command);

  UNLOAD_VALUE (m_level, level);
  UNLOAD_VALUE (m_log, log);
  UNLOAD_VALUE (m_name, name);
  UNLOAD_VALUE (m_position, position);
  UNLOAD_VALUE (m_do_fun, do_fun);
  UNLOAD_FLAG  (m_possessed, CMD_FLAG_POSSESS);
  UNLOAD_FLAG  (m_polymorphed, CMD_FLAG_POLYMORPHED);
  UNLOAD_FLAG  (m_watch, CMD_WATCH);

  App.SortCommands ();
  App.m_bCommandsDirty = true;
  RedrawList ();
	
}

void CCommandsListDlg::OnDelete() 
{
bool bChanged = false;

  for (int nIndex = -1;
      (nIndex = m_ctlCommandsList.GetNextItem(nIndex, LVNI_SELECTED)) != -1; )
   {
   CCommand * Command = (CCommand *) m_ctlCommandsList.GetItemData (nIndex);
  
// ask if they want to delete it

  if (::AfxMessageBox (CFormat ("OK to delete the command \"%s\"?", 
                    (LPCTSTR) Command->name), 
                    MB_ICONQUESTION | MB_YESNO) != IDYES)
                    continue;

   App.m_CommandList.RemoveAt (App.m_CommandList.Find (Command, NULL));
   bChanged = true;
   }

  if (bChanged)
    {
    App.m_bCommandsDirty = true;
    RedrawList ();
    }
	
}


void CCommandsListDlg::OnEdit() 
{
    for (int nIndex = -1;
      (nIndex = m_ctlCommandsList.GetNextItem(nIndex, LVNI_SELECTED)) != -1; )
   {
    CCommand * command = (CCommand *) m_ctlCommandsList.GetItemData (nIndex);

    CEditCommandDlg dlg;
    bool bChanged = false;

    LOAD_VALUE (m_level, level);
    LOAD_VALUE (m_log, log);
    LOAD_VALUE (m_name, name);
    LOAD_VALUE (m_position, position);
    LOAD_VALUE (m_do_fun, do_fun);
    LOAD_FLAG  (m_possessed, CMD_FLAG_POSSESS);
    LOAD_FLAG  (m_polymorphed, CMD_FLAG_POLYMORPHED);
    LOAD_FLAG  (m_watch, CMD_WATCH);


    if (dlg.DoModal() != IDOK)
      return;

    UNLOAD_VALUE (m_level, level);
    UNLOAD_VALUE (m_log, log);
    UNLOAD_VALUE (m_name, name);
    UNLOAD_VALUE (m_position, position);
    UNLOAD_VALUE (m_do_fun, do_fun);
    UNLOAD_FLAG  (m_possessed, CMD_FLAG_POSSESS);
    UNLOAD_FLAG  (m_polymorphed, CMD_FLAG_POLYMORPHED);
    UNLOAD_FLAG  (m_watch, CMD_WATCH);
	
    if (bChanged)
      {
      App.m_bCommandsDirty = true;
      RedrawList ();
      }

    }
	
}

void CCommandsListDlg::OnDblclkCommandsList(NMHDR* pNMHDR, LRESULT* pResult) 
{
  OnEdit ();
	
	*pResult = 0;
}

BOOL CCommandsListDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
// set list control to display whole row when selected

  m_ctlCommandsList.SendMessage (LVM_SETEXTENDEDLISTVIEWSTYLE, 0, 
                              m_ctlCommandsList.SendMessage (LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0) 
                              | LVS_EX_FULLROWSELECT);
  
  m_ctlCommandsList.InsertColumn(0, "Name", LVCFMT_LEFT, 80);
  m_ctlCommandsList.InsertColumn(1, "Code", LVCFMT_LEFT, 200);
  m_ctlCommandsList.InsertColumn(2, "Level", LVCFMT_RIGHT, 50);
	RedrawList ();
  
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}


void CCommandsListDlg::RedrawList (void) 
  {
int nItem = 0;

POSITION commandPos;
CCommand * command;

  m_ctlCommandsList.DeleteAllItems ();


  for (commandPos = App.m_CommandList.GetHeadPosition (); commandPos; )
    {
    command = App.m_CommandList.GetNext (commandPos);


		m_ctlCommandsList.InsertItem (nItem, command->name);     
		m_ctlCommandsList.SetItemText(nItem, 1, command->do_fun);
		m_ctlCommandsList.SetItemText(nItem, 2, CFormat ("%i", command->level));
    m_ctlCommandsList.SetItemData (nItem, (DWORD) command);

    nItem++;

    }

  t_sort_param sort_param;

  sort_param.sortkey = m_last_col;
  sort_param.reverse = m_reverse;

  m_ctlCommandsList.SortItems (CompareFunc, (LPARAM) &sort_param); 

  } // end of CCommandsListDlg::RedrawList

void CCommandsListDlg::OnColumnclickCommandsList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	
int col = pNMListView->iSubItem;

  t_sort_param sort_param;

  if (col == m_last_col)
    m_reverse = !m_reverse;
  else
    m_reverse = FALSE;

  m_last_col = col;

  sort_param.sortkey = m_last_col;
  sort_param.reverse = m_reverse;

  m_ctlCommandsList.SortItems (CompareFunc, (LPARAM) &sort_param); 

	*pResult = 0;
}


LRESULT CCommandsListDlg::OnKickIdle(WPARAM, LPARAM)
  {
  UpdateDialogControls (AfxGetApp()->m_pMainWnd, false);
  return 0;
  } // end of CCommandsListDlg::OnKickIdle


void CCommandsListDlg::OnUpdateNeedSelection(CCmdUI* pCmdUI)
  {
  pCmdUI->Enable (m_ctlCommandsList.GetFirstSelectedItemPosition () != NULL);
  } // end of CCommandsListDlg::OnUpdateNeedSelection