/////////////////////////////////////////////////////////////////////////////
// Name:        MenuObjectPropDlg.cpp
// Purpose:     DVD menu button properties dialog
// Author:      Alex Thuering
// Created:	20.11.2003
// RCS-ID:      $Id: MenuObjectPropDlg.cpp,v 1.36 2010/04/28 07:34:26 ntalex Exp $
// Copyright:   (c) Alex Thuering
// Licence:     GPL
/////////////////////////////////////////////////////////////////////////////

#include "MenuObjectPropDlg.h"
#include <wx/statline.h>
#include <stdint.h>

enum {
	JUMP_ACTION_RADIO_ID = 7900,
	CUSTOM_ACTION_RADIO_ID,
	TARGET_CHOICE_ID,
	AUTO_SIZE_RADIO_ID,
	CUSTOM_SIZE_RADIO_ID,
	IMAGE_RADIO_ID,
	VIDEOFRAME_RADIO_ID
};

BEGIN_EVENT_TABLE(MenuObjectPropDlg, wxPropDlg)
	EVT_RADIOBUTTON(JUMP_ACTION_RADIO_ID, MenuObjectPropDlg::OnJumpActionSelected)
	EVT_RADIOBUTTON(CUSTOM_ACTION_RADIO_ID, MenuObjectPropDlg::OnCustomActionSelected)
	EVT_CHOICE(TARGET_CHOICE_ID, MenuObjectPropDlg::OnChangeTarget)
	EVT_RADIOBUTTON(AUTO_SIZE_RADIO_ID, MenuObjectPropDlg::OnDefaultSizeSelected)
	EVT_RADIOBUTTON(CUSTOM_SIZE_RADIO_ID, MenuObjectPropDlg::OnCustomSizeSelected)
	EVT_RADIOBUTTON(IMAGE_RADIO_ID, MenuObjectPropDlg::OnImageRadio)
	EVT_RADIOBUTTON(VIDEOFRAME_RADIO_ID, MenuObjectPropDlg::OnImageRadio)
END_EVENT_TABLE()

MenuObjectPropDlg::MenuObjectPropDlg(wxWindow* parent, wxString id, Menu* menu, DVD* dvd, int tsi, int pgci):
		wxPropDlg(parent, _("Properties") + wxString(wxT(" - ")) + menu->GetObject(id)->GetId(true)) {
	m_id = id;
	m_menu = menu;
	m_dvd = dvd;
	m_tsi = tsi;
	m_pgci = pgci;
	m_imageEdit = NULL;
	m_imageRadio = NULL;
	m_videoFrameRadio = NULL;
	m_videoFrameChoice = NULL;
	m_object = menu->GetObject(id);
	Create();
}

void MenuObjectPropDlg::CreatePropPanel(wxSizer* sizer) {
	wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
	wxFlexGridSizer* grid = NULL;
	
	// action
	if (m_object->IsButton()) {
		DVDAction& action = m_object->GetAction();
		AddStaticLine(mainSizer, _("Action"));
		grid = new wxFlexGridSizer(2, 2, 4, 16);
		grid->AddGrowableCol(1);
		// jump to
		AddRadioProp(grid, _("Jump to") + wxString(wxT(":")), !action.IsCustom(), wxRB_GROUP, false,
				JUMP_ACTION_RADIO_ID);
		wxSizer* jumpSizer = new wxFlexGridSizer(4, 4, 4);
		AddChoiceProp(jumpSizer, wxT(""), wxT(""), wxArrayString(), -1, false, TARGET_CHOICE_ID);
		m_targetChoice = (wxChoice*) m_controls[m_controls.Count()-1];
		FillTargets(m_targetChoice);
		AddChoiceProp(jumpSizer, wxT(""), wxT(""), wxArrayString());
		m_chapterChoice = (wxChoice*) m_controls[m_controls.Count()-1];
		UpdateChapters();
		AddCheckProp(jumpSizer, _("Play all titles"), action.IsPlayAll());
		grid->Add(jumpSizer);
		// customAction
		wxString customAction = action.GetCustom();
		if (!customAction.length()) {
			// check if selection was ok, otherwise set this action as custom action
			int tsi = action.GetTsi() > -2 ? action.GetTsi() : m_tsi;
			int pgci = action.GetPgci() > -1 ? action.GetPgci() : m_pgci;
			bool menu = action.GetPgci() > -1 ? action.IsMenu() : true;
			if (GetSelectedTsi() != tsi || GetSelectedPgci() != pgci || IsSelectedMenu() != menu
					|| GetSelectedChapter() != action.GetChapter())
				customAction = action.AsString(m_dvd);
		}
		AddRadioProp(grid, _("Custom") + wxString(wxT(":")), customAction.length()>0, 0, false,
				CUSTOM_ACTION_RADIO_ID);
		AddTextProp(grid, wxT(""), customAction);
		m_customActionEdit = (wxTextCtrl*) m_controls[m_controls.Count()-1];
		mainSizer->Add(grid, 0, wxEXPAND|wxBOTTOM, 8);
		wxCommandEvent evt;
		if (customAction.length())
			OnCustomActionSelected(evt);
		else
			OnJumpActionSelected(evt);
		
		// audio & subtitle
		wxArrayString labels;
		labels.Add(_("last selected"));
		for (unsigned int i = 0; i < m_dvd->GetAudioStreamCount(); i++)
			labels.Add(_("track") + wxString::Format(wxT(" %d"), i + 1));
		AddText(grid, _("Audio") + wxString(wxT(":")), wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT);
		wxSizer* s = AddChoiceProp(grid, wxT(""), labels[action.GetAudio()+1], labels, 0, false);
		if (m_dvd->GetAudioStreamCount() == 1)
			GetLastControl()->Enable(false);
		s->Add(16, 16);
		labels.Clear();
		labels.Add(_("last selected"));
		labels.Add(_("off"));
		for (unsigned int i = 0; i < m_dvd->GetSubtitleStreamsCount(); i++)
			labels.Add(_("track") + wxString::Format(wxT(" %d"), i + 1));
		AddText(s, _("subtitle") + wxString(wxT(":")));
		s->Add(16, 16);
		AddChoiceProp(s, wxT(""), labels[action.GetSubtitle()+1], labels, 0, true);
		if (m_dvd->GetSubtitleStreamsCount() == 0)
			GetLastControl()->Enable(false);
		
		grid = new wxFlexGridSizer(3, 4, 4, 16);
		grid->AddGrowableCol(0);
		grid->Add(10,10);
		AddText(grid, _("Focus"));
		AddDirectionProp(grid, bdUP);
		grid->Add(10,10);
		grid->Add(10,10);
		AddDirectionProp(grid, bdLEFT);
		grid->Add(10,10);
		AddDirectionProp(grid, bdRIGHT);
		grid->Add(10,10);
		grid->Add(10,10);
		AddDirectionProp(grid, bdDOWN);
		grid->Add(10,10);
		mainSizer->Add(grid, 0, wxEXPAND|wxALL, 10);
	}
	
	// object look parameters
	if (m_object->GetObjectParamsCount()>0)
	AddStaticLine(mainSizer, _("Look"));
	bool lastChangeable = false;
	for (int i=0; i<m_object->GetObjectParamsCount(); i++) {
		MenuObjectParam* param = m_object->GetObjectParam(i);
		
		if (i == 0 || param->changeable != lastChangeable) {
			if (param->changeable) {
				grid = new wxFlexGridSizer(3, 4, 4, 16);
				AddText(grid, wxT(""));
				AddText(grid, _("Normal"));
				AddText(grid, _("Highlighted"));
				AddText(grid, _("Selected"));
			} else {
				grid = new wxFlexGridSizer(2, 4, 16);
				grid->AddGrowableCol(1);
			}
			if (i==0)
				mainSizer->Add(grid, 0, wxEXPAND|wxTOP|wxBOTTOM, 8);
			else
				mainSizer->Add(grid, 0, wxEXPAND|wxBOTTOM, 8);
			lastChangeable = param->changeable;
		}
		
		wxString title = wxGetTranslation((const wxChar*)param->title.GetData()) + wxString(wxT(":"));
		
		if (param->changeable && param->type == _T("colour")) {
			AddColourProp(grid, title, m_object->GetParamColour(param->name));
			AddColourProp(grid, wxT(""), m_object->GetParamColour(param->name, mbsHIGHLIGHTED));
			AddColourProp(grid, wxT(""), m_object->GetParamColour(param->name, mbsSELECTED));
		} else {
			if (param->type == _T("text")) {
				AddText(grid, title);
				wxBoxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
				AddTextProp(sizer2, wxT(""), m_object->GetParam(param->name));
				AddFontProp(sizer2, wxT(""), m_object->GetParamFont(param->name), _("Font..."));
				grid->Add(sizer2, 0, wxEXPAND);
			} else if (param->type == _T("string")) {
				AddTextProp(grid, title, m_object->GetParam(param->name));
			} else if (param->type == _T("decimal")) {
				AddTextProp(grid, title, m_object->GetParam(param->name), false, 100);
			} else if (param->type.Mid(0,7) == _T("integer")) {
				long min = 0, max = 999;
				if (param->type.Find(wxT('(')) != -1 && param->type.Find(wxT(')')) != -1) {
					param->type.AfterFirst(wxT('(')).BeforeFirst(wxT(',')).Strip(wxString::both).ToLong(&min);
					param->type.BeforeFirst(wxT(')')).AfterFirst(wxT(',')).Strip(wxString::both).ToLong(&max);
				}
				AddSpinProp(grid, title, m_object->GetParamInt(param->name), min, max,
						max < 1000 ? 54 : 80);
			} else if (param->type == _T("image")) {
				wxString imageFile = m_object->GetParam(param->name);
				if (m_object->IsButton()) {
					bool hasVideo = GetVideoFilename().length();
					wxString fname = imageFile.Find(wxT('#')) != -1 ? imageFile.BeforeLast(wxT('#')) : imageFile;
					bool image = !hasVideo || fname != GetVideoFilename();
					AddRadioProp(grid, wxString(_("Image")) + wxT(":"), image, wxRB_GROUP, false, IMAGE_RADIO_ID);
					m_imageRadio = (wxRadioButton*) GetLastControl();
					AddFileProp(grid, wxT(""), image ? imageFile : wxT(""), wxFD_OPEN, wxT("..."),
							_("Image Files ") + wxImage::GetImageExtWildcard()
							+ wxT("|") + wxString(_("All Files")) + wxT(" (*.*)|*.*"));
					m_imageEdit = (wxTextCtrl*) GetLastControl();
					AddRadioProp(grid, wxString(_("Video Frame")) + wxT(":"), !image, 0, false, VIDEOFRAME_RADIO_ID);
					m_videoFrameRadio = (wxRadioButton*) GetLastControl();
					if (!hasVideo)
						m_videoFrameRadio->Enable(false);
					bool vfAuto = imageFile == GetVideoFilename(true) || image;
					const wxString frameChoices[] = {_("Auto"), _("Custom")};
					wxSizer* frameSizer = AddChoiceCustomProp(grid, wxT(""), frameChoices[vfAuto ? 0 : 1],
							wxArrayString(2, frameChoices), 1, 100, false);
					m_videoFrameChoice = (wxChoice*) GetLastControl();
					m_videoFrameChoice->Enable(!image);
					frameSizer->AddSpacer(4);
					long videoFrame = 0;
					if (!image) {
						wxString vf = imageFile.Find(wxT('#')) != -1 ? imageFile.AfterLast(wxT('#')) : wxT("");
						if (vf.length()> 0)
							vf.ToLong(&videoFrame);
					}
					AddSpinProp(frameSizer, wxT(""), videoFrame, 0, 99999999, 100, _("ms"), false);
					SetLastControlCustom(GetLastControlIndex()-1, !vfAuto);
				} else
					AddFileProp(grid, title, imageFile, wxFD_OPEN,
						wxT("..."), _("Image Files ") + wxImage::GetImageExtWildcard()
						+ wxT("|") + wxString(_("All Files")) + wxT(" (*.*)|*.*"));
			} else if (param->type == _T("colour")) {
				int opacity = 100;
				wxString opacityStr = m_object->GetParam(param->name, wxT("-opacity"));
				if (opacityStr.length()> 0) {
					double dval;
					opacityStr.ToDouble(&dval);
					opacity = (int) (dval*100);
				}
				AddColourProp(grid, title, m_object->GetParamColour(param->name), opacity);
			}
		}
	}
	
	// object location
	AddStaticLine(mainSizer, _("Location and size"));
	grid = new wxFlexGridSizer(1, 4, 4, 16);
	AddSpinProp(grid, _("x:"), m_object->GetX(), 0, m_menu->GetResolution().GetWidth()-8);
	AddSpinProp(grid, _("y:"), m_object->GetY(), 0, m_menu->GetResolution().GetHeight()-8);
	mainSizer->Add(grid, 0, wxEXPAND|wxBOTTOM, 8);
	
	// object size
	grid = new wxFlexGridSizer(2, 6, 4, 16);
	grid->AddGrowableCol(5);
	AddRadioProp(grid, _("Default width and height"), m_object->IsDefaultSize(), wxRB_GROUP, false,
			AUTO_SIZE_RADIO_ID);
	grid->Add(10,10); grid->Add(10,10); grid->Add(10,10); grid->Add(10,10); grid->Add(10,10);
	AddRadioProp(grid, _("Custom"), !m_object->IsDefaultSize(), 0, false, CUSTOM_SIZE_RADIO_ID);
	AddSpinProp(grid, _("width:"), m_object->GetWidth(), 0, m_menu->GetResolution().GetWidth());
	m_widthEdit = (wxTextCtrl*) m_controls[m_controls.Count()-1];
	AddSpinProp(grid, _("height:"), m_object->GetHeight(), 0, m_menu->GetResolution().GetHeight());
	m_heightEdit = (wxTextCtrl*) m_controls[m_controls.Count()-1];
	grid->Add(10,10);
	mainSizer->Add(grid, 0, wxEXPAND|wxBOTTOM, 8);
	wxCommandEvent evt;
	if (m_object->IsDefaultSize())
		OnDefaultSizeSelected(evt);
	else
		OnCustomSizeSelected(evt);
	
	mainSizer->Add(10, 10, 1, wxEXPAND);
	sizer->Add(mainSizer, 1, wxEXPAND|wxALL, 10);
}

int MenuObjectPropDlg::GetSelectedTsi() {
	int tsi = 0;
	if (m_targetChoice->GetSelection() >= 0)
		tsi = ((intptr_t) m_targetChoice->GetClientData(m_targetChoice->GetSelection()))/1000 - 1;
	return tsi;
}

int MenuObjectPropDlg::GetSelectedPgci() {
	if (m_targetChoice->GetSelection() >= 0)
		return (((intptr_t) m_targetChoice->GetClientData(m_targetChoice->GetSelection())) % 1000) / 2;
	return 0;
}

bool MenuObjectPropDlg::IsSelectedMenu() {
	if (m_targetChoice->GetSelection() >= 0)
		return (((intptr_t) m_targetChoice->GetClientData(m_targetChoice->GetSelection())) % 1000) % 2 == 0;
	return true;
}

int MenuObjectPropDlg::GetSelectedChapter() {
	if (m_chapterChoice->GetSelection() >= 0)
		return m_chapterChoice->GetSelection();
	return 0;
}

void* MenuObjectPropDlg::TargetToPtr(int tsi, int pgci, bool menu) {
	return (void*) ((tsi+1)*1000 + pgci*2 + (menu ? 0 : 1));
}

/**
 * Fills choice "targets" with possible action targets
 */
void MenuObjectPropDlg::FillTargets(wxChoice* ctrl) {
	int sel = 0;
	DVDAction& action = m_object->GetAction(); // current action
	int actionTsi = action.GetTsi() > -2 ? action.GetTsi() : m_tsi; // tsi of current action target
	int actionPgci = action.GetPgci() > -1 ? action.GetPgci() : m_pgci; // pgci of current action target
	int actionMenu = action.GetPgci() > -1 ? action.IsMenu() : true; // menu/title is target of current action

	ctrl->Append(_("start of current menu"), TargetToPtr(m_tsi, m_pgci, true));

	// add a jump target for every title and menu in every titleset if possible
	for (int tsi = -1; tsi < (int)m_dvd->GetTitlesets().Count(); tsi++) {
		if (tsi == -1) { // Video-Manager-Domain
			for (int pgci = 0; pgci < (int) m_dvd->GetVmgm().Count(); pgci++) {
				if (tsi == m_tsi && pgci == m_pgci)
					continue; // current menu
				ctrl->Append(wxString::Format(_("vmMenu %d"), pgci + 1), TargetToPtr(tsi, pgci, true));
				if (tsi == actionTsi && pgci == actionPgci && actionMenu)
					sel = ctrl->GetCount() - 1; // current action target
			}
		} else { // Titleset
			Titleset* ts = m_dvd->GetTitlesets()[tsi];
			for (int pgci = 0; pgci < (int) ts->GetMenus().Count(); pgci++) {
				if (tsi == m_tsi && pgci == m_pgci)
					continue; // current menu
				Pgc* pgc = ts->GetMenus()[pgci];
				if (!m_dvd->IsJumppadsEnabled() && m_tsi != tsi && pgci > 0 && pgc->GetEntries().size() == 0)
					break; // cannot jump to specific menu from other titleset, only to an entry
				wxString label = _("menu") + wxString::Format(wxT(" %d"), pgci + 1);
				if (m_dvd->GetTitlesets().Count() > 1)
					label = _("titleset") + wxString::Format(wxT(" %d "), tsi + 1) + label;
				ctrl->Append(label, TargetToPtr(tsi, pgci, true));
				if (tsi == actionTsi && pgci == actionPgci && actionMenu)
					sel = ctrl->GetCount() - 1;
			}
			// jumping from titleset menu is allowed only to titles from the same titleset
			if (m_dvd->IsJumppadsEnabled() || m_tsi == -1 || m_tsi == tsi) {
				for (int pgci = 0; pgci < (int) ts->GetTitles().Count(); pgci++) {
					wxString label = _("title") + wxString::Format(wxT(" %d"), pgci + 1);
					if (m_dvd->GetTitlesets().Count() > 1)
						label = _("titleset") + wxString::Format(wxT(" %d "), tsi + 1) + label;
					ctrl->Append(label, TargetToPtr(tsi, pgci, false));
					if (tsi == actionTsi && pgci == actionPgci && !actionMenu)
						sel = ctrl->GetCount() - 1;
				}
			}
		}
	}
	ctrl->SetSelection(sel);
}

void MenuObjectPropDlg::UpdateChapters() {
	wxChoice* ctrl = m_chapterChoice;
	int tsi = GetSelectedTsi();
	int pgci = GetSelectedPgci();
	bool menu = IsSelectedMenu();
	int chapter = ctrl->GetCount() ? GetSelectedChapter() : m_object->GetAction().GetChapter();
	ctrl->Clear();
	ctrl->Append(wxString::Format(_("chapter %d"), 1));
	PgcArray& pgcs = m_dvd->GetPgcArray(tsi, false);
	if (tsi >= 0 && !menu && pgci < (int) pgcs.Count())
		for (unsigned int i = 1; i < pgcs[pgci]->GetChapterCount(); i++)
			ctrl->Append(wxString::Format(_("chapter %d"), i + 1));
	ctrl->SetSelection(chapter);
	ctrl->Enable(ctrl->GetCount() > 1 && (m_dvd->IsJumppadsEnabled() || m_tsi != -1));
}

void MenuObjectPropDlg::OnChangeTarget(wxCommandEvent& evt) {
	UpdateChapters();
	if (m_videoFrameRadio) {
		m_videoFrameRadio->Enable(GetVideoFilename().length());
		if (!m_videoFrameRadio->IsEnabled()) {
			m_imageRadio->SetValue(true);
			wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_imageRadio->GetId());
			GetEventHandler()->ProcessEvent(event);
		}
	}
}

void MenuObjectPropDlg::OnJumpActionSelected(wxCommandEvent& evt) {
	m_targetChoice->Enable(true);
	m_chapterChoice->Enable(m_chapterChoice->GetCount() > 1 && (m_dvd->IsJumppadsEnabled() || m_tsi != -1));
	m_customActionEdit->Enable(false);
	if (m_videoFrameRadio) {
		m_videoFrameRadio->Enable(GetVideoFilename().length());
		if (GetVideoFilename().length() == 0) {
			m_imageRadio->SetValue(true);
			wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_imageRadio->GetId());
			GetEventHandler()->ProcessEvent(event);
		}
		else if (GetVideoFilename().length() && m_imageEdit->GetValue().length() == 0)
			m_videoFrameRadio->SetValue(true);
	}
}

void MenuObjectPropDlg::OnCustomActionSelected(wxCommandEvent& evt) {
	m_targetChoice->Enable(false);
	m_chapterChoice->Enable(false);
	m_customActionEdit->Enable(true);
	if (m_customActionEdit->GetValue().length() == 0) {
		int tsi = m_object->GetAction().GetTsi();
		m_object->GetAction().SetTsi(GetSelectedTsi() != m_tsi ? GetSelectedTsi() : -2);
		m_customActionEdit->SetValue(m_object->GetAction().AsString(m_dvd));
		m_object->GetAction().SetTsi(tsi);
	}
	if (m_videoFrameRadio) {
		m_videoFrameRadio->Enable(false);
		m_imageRadio->SetValue(true);
		wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, m_imageRadio->GetId());
		GetEventHandler()->ProcessEvent(event);
	}
}

wxString MenuObjectPropDlg::GetVideoFilename(bool withTimestamp, long position) {
	if (!GetBool(0))
		return wxT("");
	if (IsSelectedMenu()) // menu
		return wxT("");
	Vob* vob = m_dvd->GetVob(GetSelectedTsi(), false, GetSelectedPgci(), 0);
	if (!vob)
		return wxT("");
	if (!withTimestamp)
		return vob->GetVideoFrameUri(-1);
	return vob->GetVideoFrameUri(GetSelectedChapter(), position);
}


void MenuObjectPropDlg::OnImageRadio(wxCommandEvent& evt){
	m_videoFrameChoice->Enable(m_videoFrameRadio->GetValue());
	wxCommandEvent event(wxEVT_COMMAND_CHOICE_SELECTED, m_videoFrameChoice->GetId());
	event.SetEventObject(m_videoFrameChoice);
	event.SetInt(m_videoFrameChoice->GetSelection());
	GetEventHandler()->ProcessEvent(event);
}

void MenuObjectPropDlg::OnDefaultSizeSelected(wxCommandEvent& evt) {
	m_widthEdit->Enable(false);
	m_heightEdit->Enable(false);
}

void MenuObjectPropDlg::OnCustomSizeSelected(wxCommandEvent& evt) {
	m_widthEdit->Enable(true);
	m_heightEdit->Enable(true);
}

void MenuObjectPropDlg::AddDirectionProp(wxSizer* sizer, ButtonDirCommand dir) {
	wxFlexGridSizer* grid = new wxFlexGridSizer(2, 1, 4, 16);
	AddChoiceProp(grid, wxT(""), wxT(""), wxArrayString());
	wxChoice* ctrl = (wxChoice*) m_controls[m_controls.Count()-1];

	// add all buttons except current
	ctrl->Append(_("auto"), new wxString);
	int sel = 0;
	for (unsigned int i=0; i<m_menu->GetObjectsCount(); i++) {
		MenuObject* obj = m_menu->GetObject(i);
		if (obj->IsButton() && obj != m_object) {
			wxString id = obj->GetId();
			if (m_object->GetDirection(dir-bdLEFT) == id)
			sel = ctrl->GetCount();
			long l = 0;
			id.Mid(6).ToLong(&l);
			wxString text = _("button") + wxString::Format(wxT(" %d"), l);
			if (obj->GetParam(wxT("text")).length())
				text += wxT(": ") + obj->GetParam(_T("text"));
			ctrl->Append(text, new wxString(id));
		}
	}
	for (unsigned int i=0; i<m_menu->GetActionsCount(); i++) {
		DVDAction* action = m_menu->GetAction(i);
		wxString id = action->GetId();
		if (m_object->GetDirection(dir-bdLEFT) == id)
			sel = ctrl->GetCount();
		ctrl->Append(id, new wxString(id));
	}
	ctrl->SetSelection(sel);
	ctrl->SetSizeHints(ctrl->GetSize().GetWidth()*3/2, -1, ctrl->GetSize().GetWidth()*3/2, -1);
	sizer->Add(grid, 0, 0, 0);
}

bool MenuObjectPropDlg::SetValues() {
	// check Action
	if (m_object->IsButton()) {
		if (!m_dvd->IsJumppadsEnabled() && m_tsi < 0 && GetString(0).Find(_T("chapter")) >= 0) {
			wxMessageBox(_("You cannot jump from vmgMenu to a chapter."),
			GetTitle(), wxOK|wxICON_ERROR, this);
			return false;
		}
		if (GetBool(4) && GetString(5).length() == 0) // empty custom action
		{
			wxMessageBox(_("Please enter the action command."),
			GetTitle(), wxOK|wxICON_ERROR, this);
			return false;
		}
		if (GetBool(4)) {
			DVDAction action(m_object->GetAction());
			action.SetCustom(GetString(5));
			if (!action.IsValid(m_dvd, m_tsi, m_pgci, true, m_object->GetId(), true, false))
				return false;
		}
	}
	
	int n = 0;
	
	// set action
	if (m_object->IsButton()) {
		DVDAction& action = m_object->GetAction();
		action.SetTsi(GetSelectedTsi() != m_tsi ? GetSelectedTsi() : -2);
		action.SetPgci(GetSelectedTsi() != m_tsi || GetSelectedPgci() != m_pgci || !IsSelectedMenu() ? GetSelectedPgci() : -1);
		action.SetMenu(IsSelectedMenu());
		if (GetSelectedTsi() != m_tsi && IsSelectedMenu() && GetSelectedPgci() > 0) {
			const StringSet& entries = m_dvd->GetPgcArray(GetSelectedTsi(), true)[GetSelectedPgci()]->GetEntries();
			action.SetEntry(entries.size() > 0 ? *entries.begin() : wxT(""));
		} else
			action.SetEntry(wxT(""));
		action.SetChapter(GetSelectedChapter());
		n += 3;
		action.SetPlayAll(GetBool(n++));
		if (GetBool(n++)) {
			if (GetString(n) == wxT("jump title 1;")) {
				action.SetTsi(-2);
				action.SetPgci(0);
				action.SetMenu(false);
				action.SetChapter(0);
				action.SetCustom(_T(""));
			} else
				action.SetCustom(GetString(n));
		} else
			action.SetCustom(_T(""));
		n++;
		action.SetAudio(GetInt(n++) - 1);
		action.SetSubtitle(GetInt(n++) - 1);
		
		wxString* id = (wxString*) GetClientData(n++);
		m_object->SetDirection(2, *id);
		delete id;
		id = (wxString*) GetClientData(n++);
		m_object->SetDirection(0, *id);
		delete id;
		id = (wxString*) GetClientData(n++);
		m_object->SetDirection(1, *id);
		delete id;
		id = (wxString*) GetClientData(n++);
		m_object->SetDirection(3, *id);
		delete id;
	}
	
	// set look parameters
	for (int i = 0; i < m_object->GetObjectParamsCount(); i++) {
		MenuObjectParam* param = m_object->GetObjectParam(i);
		if (param->changeable && param->type == _T("colour")) {
			m_object->SetParamColour(param->name, GetColour(n++));
			m_object->SetParamColour(param->name, GetColour(n++), mbsHIGHLIGHTED);
			m_object->SetParamColour(param->name, GetColour(n++), mbsSELECTED);
		} else {
			if (param->type == _T("text")) {
				m_object->SetParam(param->name, GetString(n++));
				m_object->SetParamFont(param->name, GetFont(n++).GetChosenFont());
			} else if (param->type == _T("string") || param->type == _T("decimal"))
				m_object->SetParam(param->name, GetString(n++));
			else if (param->type.Mid(0, 7) == _T("integer"))
				m_object->SetParamInt(param->name, GetInt(n++));
			else if (param->type == _T("colour")) {
				m_object->SetParamColour(param->name, GetColour(n++));
				wxString opacity = wxString::Format(wxT("%g"), (double) GetInt(n++) / 100);
				m_object->SetParam(param->name, opacity, wxT("-opacity"));
			} else if (param->type == _T("image")) {
				if (m_object->IsButton()) {
					bool image = GetBool(n++);
					wxString imgFile = GetString(n++);
					n++;
					if (!image) {
						int videoFrame = -1;
						if (GetInt(n++) == 1) // custom frame
							videoFrame = GetInt(n++);
						else
							n++;
						imgFile = GetVideoFilename(true, videoFrame);
					} else
						n += 2;
					m_object->SetParam(param->name, imgFile);
				} else
					m_object->SetParam(param->name, GetString(n++));
			}
		}
	}
	
	// set position
	m_object->SetX(GetInt(n++));
	m_object->SetY(GetInt(n++));
	
	// set size
	m_object->SetDefaultSize(GetBool(n++));
	if (!m_object->IsDefaultSize()) {
		// set size manual by user
		n++;
		m_object->SetWidth(GetInt(n++));
		m_object->SetHeight(GetInt(n++));
	}
	m_object->UpdateSize();
	
	return true;
}
