///////////////////////////////////////////////////////////////////////////// // Name: MenuEditor.cpp // Purpose: The widget to edit a DVD Menu // Author: Alex Thuering // Created: 11.10.2003 // RCS-ID: $Id: MenuEditor.cpp,v 1.17 2007/01/12 15:51:35 ntalex Exp $ // Copyright: (c) Alex Thuering // Licence: GPL ///////////////////////////////////////////////////////////////////////////// #include "MenuEditor.h" #include "MenuPropDlg.h" #include "MenuObjectPropDlg.h" #include "MPEG.h" #include #include #include #include #include #include "math.h" #include #include #include #include #include #define OBJECTS_DIR wxFindDataDirectory(_T("objects")) #define CURSOR_FILE(fname) wxFindDataFile(_T("rc") + wxString(wxFILE_SEP_PATH) + fname) ////////////////////////////////////////////////////////////////////////////// ////////////////////////////// MenuDnDFile /////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// class MenuDnDFile : public wxFileDropTarget { public: MenuDnDFile(MenuEditor* pOwner) { m_pOwner = pOwner; } virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) { if (!m_pOwner->GetMenu()) return false; bool res = false; for (int i = 0; i<(int)filenames.Count(); i++) { res = AddFile(x, y, filenames[i]) || res; if (xGetMenu()->GetResolution().x-48 && yGetMenu()->GetResolution().y-48) { x += 16; y += 16; } } return res; } bool AddFile(wxCoord x, wxCoord y, wxString filename) { x = (int) (x/m_pOwner->GetScale()); y = (int) (y/m_pOwner->GetScale()); wxString ext = filename.AfterLast('.').Lower(); if (ext == _T("xml")) m_pOwner->AddButton(filename, x, y); else if (wxImage::FindHandler(ext, -1)) m_pOwner->AddImage(filename, x, y); else if (wxThumbnails::IsVideo(filename)) { if (!MPEG::IsValid(filename)) { wxLogError(filename + _(": not valid mpeg-file")); return false; } if (wxMessageBox(_("Do you want to assign this video as background for this menu?"), _("Confirm"), wxYES_NO|wxICON_QUESTION, m_pOwner) == wxYES) m_pOwner->SetBackground(filename); } m_pOwner->SetFocus(); return true; } protected: MenuEditor *m_pOwner; }; ////////////////////////////////////////////////////////////////////////////// /////////////////////////// Help functions /////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// wxRect ScaleRect(wxRect rect, double scale) { wxRect res; res.x = (int) (rect.x*scale); res.y = (int) (rect.y*scale); res.width = (int) (rect.width*scale); res.height = (int) (rect.height*scale); return res; } wxRect ScaleRect(wxSVGRect rect, double scale) { wxRect res; res.x = (int) (rect.GetX()*scale); res.y = (int) (rect.GetY()*scale); res.width = (int) (rect.GetWidth()*scale); res.height = (int) (rect.GetHeight()*scale); return res; } ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// MenuEditor /////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// enum { EVENT_TIMER_ID = 8500, MENUEDITOR_PROP_ID, MENUEDITOR_OBJMENU_CUT_ID, MENUEDITOR_OBJMENU_COPY_ID, MENUEDITOR_OBJMENU_PASTE_ID, MENUEDITOR_OBJMENU_DELETE_ID, MENUEDITOR_ARRANGEMENU_ID, MENUEDITOR_ARRANGEMENU_TOFRONT_ID, MENUEDITOR_ARRANGEMENU_FORWARD_ID, MENUEDITOR_ARRANGEMENU_BACKWARD_ID, MENUEDITOR_ARRANGEMENU_TOBACK_ID, MENUEDITOR_VIEWMENU_ID, MENUEDITOR_VIEWMENU_SAFETV_ID, MENUEDITOR_GRIDMENU_ID = 8600, MENUEDITOR_GRIDMENU_ITEM_ID, //8601..8605 MENUEDITOR_GRIDMENU_SHOW_ID = 8610, MENUEDITOR_GRIDMENU_OVEROBJECTS_ID, MENUEDITOR_ADDMENU_ID = 9000, MENUEDITOR_ADDMENU_OBJECT_ID //9001..9999 }; BEGIN_EVENT_TABLE(MenuEditor, wxSVGCtrl) EVT_RIGHT_DOWN(MenuEditor::OnMouseRightButton) EVT_RIGHT_UP(MenuEditor::OnMouseRightButton) EVT_LEFT_DOWN(MenuEditor::OnMouseLeftButton) EVT_LEFT_UP(MenuEditor::OnMouseLeftButton) EVT_MOTION(MenuEditor::OnMouseMove) EVT_LEFT_DCLICK(MenuEditor::OnMouseDClick) EVT_KEY_DOWN(MenuEditor::OnKeyDown) EVT_TIMER(EVENT_TIMER_ID, MenuEditor::OnEventTimer) EVT_MENU(MENUEDITOR_PROP_ID, MenuEditor::OnProperties) EVT_MENU(MENUEDITOR_OBJMENU_CUT_ID, MenuEditor::OnObjectCut) EVT_MENU(MENUEDITOR_OBJMENU_COPY_ID, MenuEditor::OnObjectCopy) EVT_MENU(MENUEDITOR_OBJMENU_PASTE_ID, MenuEditor::OnObjectPaste) EVT_UPDATE_UI(MENUEDITOR_OBJMENU_PASTE_ID, MenuEditor::OnUpdateUIObjectPaste) EVT_MENU(MENUEDITOR_OBJMENU_DELETE_ID, MenuEditor::OnObjectDelete) EVT_MENU(MENUEDITOR_ARRANGEMENU_TOFRONT_ID, MenuEditor::OnObjectToFront) EVT_MENU(MENUEDITOR_ARRANGEMENU_FORWARD_ID, MenuEditor::OnObjectForward) EVT_MENU(MENUEDITOR_ARRANGEMENU_BACKWARD_ID, MenuEditor::OnObjectBackward) EVT_MENU(MENUEDITOR_ARRANGEMENU_TOBACK_ID, MenuEditor::OnObjectToBack) EVT_UPDATE_UI(MENUEDITOR_ARRANGEMENU_TOFRONT_ID, MenuEditor::OnUpdateUIObjectForward) EVT_UPDATE_UI(MENUEDITOR_ARRANGEMENU_FORWARD_ID, MenuEditor::OnUpdateUIObjectForward) EVT_UPDATE_UI(MENUEDITOR_ARRANGEMENU_BACKWARD_ID, MenuEditor::OnUpdateUIObjectBackward) EVT_UPDATE_UI(MENUEDITOR_ARRANGEMENU_TOBACK_ID, MenuEditor::OnUpdateUIObjectBackward) EVT_MENU(MENUEDITOR_VIEWMENU_SAFETV_ID, MenuEditor::OnSafeTV) EVT_MENU(MENUEDITOR_GRIDMENU_ITEM_ID, MenuEditor::OnGridMenu) EVT_MENU(MENUEDITOR_GRIDMENU_ITEM_ID+1, MenuEditor::OnGridMenu) EVT_MENU(MENUEDITOR_GRIDMENU_ITEM_ID+2, MenuEditor::OnGridMenu) EVT_MENU(MENUEDITOR_GRIDMENU_ITEM_ID+3, MenuEditor::OnGridMenu) EVT_MENU(MENUEDITOR_GRIDMENU_ITEM_ID+4, MenuEditor::OnGridMenu) EVT_MENU(MENUEDITOR_GRIDMENU_ITEM_ID+5, MenuEditor::OnGridMenu) EVT_MENU(MENUEDITOR_GRIDMENU_SHOW_ID, MenuEditor::OnShowGrid) EVT_MENU(MENUEDITOR_GRIDMENU_OVEROBJECTS_ID, MenuEditor::OnShowGridOverObjects) EVT_MENU_RANGE(MENUEDITOR_ADDMENU_OBJECT_ID, MENUEDITOR_ADDMENU_OBJECT_ID+999, MenuEditor::OnAddObject) END_EVENT_TABLE() DEFINE_EVENT_TYPE(EVT_COMMAND_MENUEDITOR_MENU_CHANGED) DEFINE_EVENT_TYPE(EVT_COMMAND_MENUEDITOR_OBJECT_POINTED) MenuEditor::MenuEditor(wxWindow *parent, wxWindowID id): wxSVGCtrl(parent, id), m_eventTimer(this, EVENT_TIMER_ID) { m_dvd = NULL; m_menu = NULL; DoSelect(); m_safeTV = true; m_showGrid = false; m_gridOverObejcts = false; m_grid = 3; SetDropTarget(new MenuDnDFile(this)); SetFitToFrame(true); // arrange sub menu m_arrangeMenu = new wxMenu; m_arrangeMenu->Append(MENUEDITOR_ARRANGEMENU_TOFRONT_ID, _("&Bring to Front")); m_arrangeMenu->Append(MENUEDITOR_ARRANGEMENU_FORWARD_ID, _("Bring &Forward")); m_arrangeMenu->Append(MENUEDITOR_ARRANGEMENU_BACKWARD_ID, _("Send Back&ward")); m_arrangeMenu->Append(MENUEDITOR_ARRANGEMENU_TOBACK_ID, _("&Send to Back")); // object context menu m_objMenu = new wxMenu; m_objMenu->Append(MENUEDITOR_ARRANGEMENU_ID, _("A&rrange"), m_arrangeMenu); m_objMenu->AppendSeparator(); wxMenuItem* item = new wxMenuItem(m_objMenu, MENUEDITOR_OBJMENU_CUT_ID, _("Cu&t")); item->SetBitmap(wxArtProvider::GetBitmap(wxART_CUT, wxART_MENU)); m_objMenu->Append(item); item = new wxMenuItem(m_objMenu, MENUEDITOR_OBJMENU_COPY_ID, _("&Copy")); item->SetBitmap(wxArtProvider::GetBitmap(wxART_COPY, wxART_MENU)); m_objMenu->Append(item); item = new wxMenuItem(m_objMenu, MENUEDITOR_OBJMENU_PASTE_ID, _("&Paste")); item->SetBitmap(wxArtProvider::GetBitmap(wxART_PASTE, wxART_MENU)); m_objMenu->Append(item); item = new wxMenuItem(m_objMenu, MENUEDITOR_OBJMENU_DELETE_ID, _("&Delete")); item->SetBitmap(wxArtProvider::GetBitmap(wxART_DELETE, wxART_MENU)); m_objMenu->Append(item); m_objMenu->AppendSeparator(); m_objMenu->Append(MENUEDITOR_PROP_ID, _("&Properties...")); // sub menu "Add" m_addMenu = new wxMenu; wxString fname = wxFindFirstFile(OBJECTS_DIR + _T("/*.xml")); int addId = MENUEDITOR_ADDMENU_OBJECT_ID; Menu menu; while (!fname.IsEmpty()) { MenuObject obj(&menu, fname); m_addMenu->Append(addId++, obj.GetTitle()); m_addMenuObjects.Add(obj.GetFileName()); fname = wxFindNextFile(); } // sub menu "View" m_viewMenu = new wxMenu; m_viewMenu->Append(MENUEDITOR_VIEWMENU_SAFETV_ID, _("&Show Safe TV area"), wxEmptyString, wxITEM_CHECK); m_viewMenu->Check(MENUEDITOR_VIEWMENU_SAFETV_ID, m_safeTV); // sub menu "Grid" m_gridMenu = new wxMenu; m_gridMenu->Append(MENUEDITOR_GRIDMENU_ITEM_ID, _("&none"), wxEmptyString, wxITEM_RADIO); m_gridMenu->Append(MENUEDITOR_GRIDMENU_ITEM_ID+1, _T("4x4"), wxEmptyString, wxITEM_RADIO); m_gridMenu->Append(MENUEDITOR_GRIDMENU_ITEM_ID+2, _T("8x8"), wxEmptyString, wxITEM_RADIO); m_gridMenu->Append(MENUEDITOR_GRIDMENU_ITEM_ID+3, _T("16x16"), wxEmptyString, wxITEM_RADIO); m_gridMenu->Append(MENUEDITOR_GRIDMENU_ITEM_ID+4, _T("32x32"), wxEmptyString, wxITEM_RADIO); m_gridMenu->Append(MENUEDITOR_GRIDMENU_ITEM_ID+5, _T("64x64"), wxEmptyString, wxITEM_RADIO); m_gridMenu->Check(MENUEDITOR_GRIDMENU_ITEM_ID + m_grid - 1, true); m_gridMenu->Append(MENUEDITOR_GRIDMENU_SHOW_ID, _("&Show"), wxEmptyString, wxITEM_CHECK); m_gridMenu->Append(MENUEDITOR_GRIDMENU_OVEROBJECTS_ID, _("&Over objects"), wxEmptyString, wxITEM_CHECK); // context menu m_pmenu = new wxMenu; m_pmenu->Append(MENUEDITOR_ADDMENU_ID, _("&Add"), m_addMenu); m_pmenu->Append(MENUEDITOR_VIEWMENU_ID, _("&View"), m_viewMenu); m_pmenu->Append(MENUEDITOR_GRIDMENU_ID, _("&Grid"), m_gridMenu); item = new wxMenuItem(m_pmenu, MENUEDITOR_OBJMENU_PASTE_ID, _("&Paste")); item->SetBitmap(wxArtProvider::GetBitmap(wxART_PASTE, wxART_MENU)); m_pmenu->Append(item); m_pmenu->Append(MENUEDITOR_PROP_ID, _("&Properties...")); } void MenuEditor::SetMenu(DVD* dvd, Menu* menu, int tsi, int pgci) { m_dvd = dvd; m_menu = menu; m_tsi = tsi; m_pgci = pgci; if (m_menu) { SetSVG(m_menu->GetSVG()); ShowSafeTV(); ShowGrid(); } else Clear(); DoSelect(); } bool MenuEditor::SetBackground(wxString fname) { if (!m_menu) return false; if (wxImage::FindHandler(fname.AfterLast(wxT('.')).Lower(), -1)) { wxImage img; if (!img.LoadFile(fname)) return false; } else if (!MPEG::IsValid(fname)) { wxLogError(fname + _(": unknown or not supported format")); return false; } if (m_menu->GetBackground() != fname) { m_menu->SetBackground(fname); Update(); } return true; } void MenuEditor::SetBackgroundColour(wxColour colour) { if (!m_menu) return; if (m_menu->GetBackgroundColour() != colour) { m_menu->SetBackgroundColour(colour); Update(); } } bool MenuEditor::AddImage(wxString fname, int x, int y) { if (!m_menu) return false; if (m_menu->HasVideoBackground()) { wxLogError(_("You can add only buttons to menu with VIDEO background")); return false; } wxImage img; if (!img.LoadFile(fname)) return false; DoSelect(m_menu->AddImage(fname, x, y), true, true); return true; } bool MenuEditor::AddText(wxString text, int x, int y) { if (!m_menu) return false; if (m_menu->HasVideoBackground()) { wxLogError(_("You can add only buttons to menu with VIDEO background")); return false; } DoSelect(m_menu->AddText(text, x, y), true, true); return true; } bool MenuEditor::AddButton(wxString fname, int x, int y) { if (!m_menu || !wxFileExists(fname)) return false; int i = 1; while(1) { wxString id = wxT("button") + wxString::Format(wxT("%02d"), i); if (m_doc->GetElementById(id) == NULL) break; i++; } DoSelect(m_menu->AddObject(fname, wxString::Format(_("button%d"), i), x, y), true, true); return true; } bool MenuEditor::AddObject(wxString fname, int x, int y) { if (!m_menu || !wxFileExists(fname)) return false; wxString param; Menu menu; MenuObject obj(&menu, fname); MenuObjectParam* initParam = obj.GetInitParam(); if (initParam) { if (initParam->type == wxT("text") || initParam->type == wxT("string")) param = wxGetTextFromUser(_("Please type in text to insert"), _("Input text"), _T("Text"), this); else if (initParam->type == wxT("image")) param = wxFileSelector(_("Please choose an image to insert"), wxT(""), wxGetWorkingDirectory(), wxT(""), _("Image Files ") + #if wxCHECK_VERSION(2,6,0) wxImage::GetImageExtWildcard(), #else wxString(wxT("(*.jpg;*.bmp;*.png;*.tif;*.gif;*.pnm;*.pcx)|*.jpg;*.bmp;*.png;*.tif;*.gif;*.pnm;*.pcx")), #endif wxOPEN|wxFILE_MUST_EXIST); else param = _("Text"); if (!param.length()) return false; } DoSelect(m_menu->AddObject(fname, param, x, y), true, true); return true; } wxString MenuEditor::HitTest(int x, int y) { x = (int) (x/GetScale()); y = (int) (y/GetScale()); wxString id; // at frist try to find a button bool button = true; wxSVGUseElement* child = (wxSVGUseElement*) m_doc->GetElementById(wxT("buttons"))->GetChildren(); while (child || button && id.length() == 0) { if (!child) { // no button was found, try to find a object child = (wxSVGUseElement*) m_doc->GetElementById(wxT("objects"))->GetChildren(); button = false; continue; } if (child->GetType() == wxXML_ELEMENT_NODE && child->GetDtd() == wxSVG_USE_ELEMENT) { wxSVGRect bbox = child->GetBBox(); if (!bbox.IsEmpty() && x >= bbox.GetX() && x <= bbox.GetX() + bbox.GetWidth() && y >= bbox.GetY() && y <= bbox.GetY() + bbox.GetHeight()) id = child->GetId(); } child = (wxSVGUseElement*) child->GetNext(); } return id; } void MenuEditor::DoSelect(wxString id, bool refresh, bool sendEvent) { if (!m_menu) return; m_selected = id; // remove old selection wxSVGRectElement* selRect = (wxSVGRectElement*) m_doc->GetElementById(wxT("selection")); if (selRect) { if (refresh) RefreshRect(ScaleRect(selRect->GetBBox(), GetScale()).Inflate(4)); selRect->GetParent()->RemoveChild(selRect); } // create selection rectangle if (id.length()) { wxSVGUseElement* elem = (wxSVGUseElement*) m_doc->GetElementById(id); if (!elem || elem->GetDtd() != wxSVG_USE_ELEMENT) return; wxSVGRect bbox = elem->GetBBox(); selRect = new wxSVGRectElement; selRect->SetId(wxT("selection")); selRect->SetX(bbox.GetX()); selRect->SetY(bbox.GetY()); selRect->SetWidth(bbox.GetWidth()); selRect->SetHeight(bbox.GetHeight()); selRect->SetStroke(wxSVGPaint(255, 0, 0)); selRect->SetFill(wxSVGPaint()); m_doc->GetRootElement()->AppendChild(selRect); if (refresh) RefreshRect(ScaleRect(selRect->GetBBox(), GetScale()).Inflate(4)); } if (sendEvent) SendChangedEvent(); } void MenuEditor::OnMouseLeftButton(wxMouseEvent &event) { if (!m_menu) return; int x = event.GetX(); int y = event.GetY(); m_tt = GetTransformType(x, y); m_oldx = x; m_oldy = y; if (event.LeftDown() && m_tt == ttOut) { // select object DoSelect(HitTest(x, y), true); // change mouse cursor event.m_leftDown = false; OnMouseMove(event); } } void MenuEditor::OnMouseMove(wxMouseEvent &event) { if (!m_menu) return; int x = event.GetX(); int y = event.GetY(); if (!event.LeftIsDown()) { m_tt = GetTransformType(x, y); // change mouse cursor SetMouseCursor(m_tt); // object pointed wxString pointed = HitTest(x, y); if (GetPointed() != pointed) { m_pointed = pointed; wxCommandEvent evt(EVT_COMMAND_MENUEDITOR_OBJECT_POINTED, this->GetId()); GetEventHandler()->ProcessEvent(evt); } return; } // left mouse button is down => move or resize if (m_tt == ttIn) { // move Object int x1 = x - m_oldx; int y1 = y - m_oldy; if (MoveObject(x1, y1)) { DoSelect(GetSelected(), true); // refresh m_eventTimer.Start(500, wxTIMER_ONE_SHOT); // send changed event } m_oldx += x1; m_oldy += y1; } else if (m_tt != ttOut) // m_tt=TL,TR,BL,BR { // resize object if (ResizeObject(x, y, m_tt)) { DoSelect(GetSelected(), true); // refresh m_eventTimer.Start(500, wxTIMER_ONE_SHOT); // send changed event } } } void MenuEditor::OnMouseRightButton(wxMouseEvent &event) { if (event.RightDown() || !m_menu) return; // select Object wxString sel_old = GetSelected(); DoSelect(HitTest(event.GetX(),event.GetY()), true); m_menuPos = event.GetPosition(); if (event.RightUp()) PopupMenu(GetSelected().length() ? m_objMenu : m_pmenu, event.GetPosition()); } TransformType MenuEditor::GetTransformType(int x, int y) { if (!m_menu || !GetSelected().length()) return ttOut; // test all covered object if (HitTest(x,y) != GetSelected()) return ttOut; // outside of the selected object MenuObject* obj = m_menu->GetObject(GetSelected()); if (!obj) return ttOut; wxRect rect = ScaleRect(obj->GetBBox(), GetScale()); wxRect rect2 = rect; rect2.Deflate(3,3); if (!rect2.Inside(x,y)) { int x1 = rect.x + rect.width/2; int y1 = rect.y + rect.height/2; if ((x < x1) && (y < y1)) return ttTL; // top-left else if ((x > x1) && (y < y1)) return ttTR; // top-right else if ((x < x1) && (y > y1)) return ttBL; // bottom-left else if ((x > x1) && (y > y1)) return ttBR; // bottom-right } return ttIn; // inside of the selected object } void MenuEditor::SetMouseCursor(TransformType tt) { switch (tt) { case ttOut: SetCursor(wxCursor(wxCURSOR_ARROW)); break; #ifdef __WXMSW__ case ttIn: SetCursor(wxCursor(_T("wxCURSOR_MOVE"),wxBITMAP_TYPE_CUR_RESOURCE)); break; case ttTL: case ttBR: SetCursor(wxCursor(wxCURSOR_SIZENWSE)); break; case ttTR: case ttBL: SetCursor(wxCursor(wxCURSOR_SIZENESW)); break; #else case ttIn: SetCursor(wxImage(CURSOR_FILE(_T("move.cur"))));break; case ttTL: case ttBR: SetCursor(wxImage(CURSOR_FILE(_T("nwse.cur"))));break; case ttTR: case ttBL: SetCursor(wxImage(CURSOR_FILE(_T("nesw.cur"))));break; #endif } } bool MenuEditor::MoveObject(int& x, int& y) { x = (int) round(x/GetScale()); y = (int) round(y/GetScale()); bool res = MoveObjectInt(x,y); x = (int) round(x*GetScale()); y = (int) round(y*GetScale()); return res; } bool MenuEditor::MoveObjectInt(int& x, int& y) { if (!m_menu) return false; MenuObject* obj = m_menu->GetObject(GetSelected()); if (!obj) return false; wxRect rect = obj->GetBBox(); rect.x += x; rect.y += y; if (m_grid>0) { rect.y = rect.y>>m_grid<>m_grid<IsButton()) { if (rect.x<0) rect.x = 0; else if (rect.x + rect.width >= (int)m_doc->GetRootElement()->GetWidth().GetBaseVal()) rect.x = (int)m_doc->GetRootElement()->GetWidth().GetBaseVal() - rect.width - 1; if (rect.y<0) rect.y = 0; else if (rect.y + rect.height >= (int)m_doc->GetRootElement()->GetHeight().GetBaseVal()) rect.y = (int)m_doc->GetRootElement()->GetHeight().GetBaseVal() - rect.height - 1; } else { if (rect.x + rect.width < 8) rect.x = 8 - rect.width; else if (rect.x > (int)m_doc->GetRootElement()->GetWidth().GetBaseVal()-8) rect.x = (int)m_doc->GetRootElement()->GetWidth().GetBaseVal()-8; if (rect.y + rect.height < 8) rect.y = 8 - rect.height; else if (rect.y > (int)m_doc->GetRootElement()->GetHeight().GetBaseVal()-8) rect.y = (int)m_doc->GetRootElement()->GetHeight().GetBaseVal()-8; } x = rect.x - obj->GetX(); y = rect.y - obj->GetY(); if (obj->GetX() != rect.x || obj->GetY() != rect.y) { obj->SetX(rect.x); obj->SetY(rect.y); return true; } return false; } bool MenuEditor::ResizeObject(int x, int y, TransformType transformType) { x = (int) round(x/GetScale()); y = (int) round(y/GetScale()); return ResizeObjectInt(x, y, transformType); } bool MenuEditor::ResizeObjectInt(int x, int y, TransformType transformType) { if (!m_menu) return false; MenuObject* obj = m_menu->GetObject(GetSelected()); if (!obj) return false; wxRect rect = obj->GetBBox(); if ((transformType == ttBR || transformType == ttTR) && x<8) x = 8; if ((transformType == ttBL || transformType == ttTL) && x > (int)m_doc->GetRootElement()->GetWidth().GetBaseVal() - 8) x = (int)m_doc->GetRootElement()->GetWidth().GetBaseVal() - 8; if ((transformType == ttBL || transformType == ttBR) && y<8) y = 8; if ((transformType == ttTL || transformType == ttTR) && y > (int)m_doc->GetRootElement()->GetHeight().GetBaseVal() - 8) y = (int)m_doc->GetRootElement()->GetHeight().GetBaseVal() - 8; int sx, sy; if ((transformType == ttBR) || (transformType == ttTR)) sx = x - rect.x + 1; else sx = rect.x + rect.width - x + 1; if ((transformType == ttBR) || (transformType == ttBL)) sy = y - rect.y + 1; else sy = rect.y + rect.height - y + 1; if (sx <= 4) sx = 4; if (sy <= 4) sy = 4; obj->SetDefaultSize(false); obj->FixSize(sx, sy); // set new x, y, width, height if ((transformType == ttTL) || (transformType == ttBL)) rect.x += rect.width - sx; if ((transformType == ttTL) || (transformType == ttTR)) rect.y += rect.height - sy; rect.width = sx; rect.height = sy; if (obj->GetBBox() != rect) { obj->SetX(rect.x); obj->SetY(rect.y); obj->SetWidth(rect.width); obj->SetHeight(rect.height); return true; } return false; } ////////////////////////////////////////////////////////////////////////////// void MenuEditor::ShowSafeTV() { wxSVGGElement* gElem = (wxSVGGElement*) m_doc->GetElementById(wxT("safeTV")); if (gElem) gElem->GetParent()->RemoveChild(gElem); if (m_safeTV) { gElem = new wxSVGGElement; gElem->SetId(wxT("safeTV")); wxSVGRectElement* rectElem = new wxSVGRectElement; rectElem->SetX(0); rectElem->SetY(0); rectElem->SetWidth(m_menu->GetResolution().GetWidth()); rectElem->SetHeight(32); rectElem->SetStroke(wxSVGPaint()); rectElem->SetFill(wxSVGPaint(255, 255, 255)); rectElem->SetFillOpacity(0.1); gElem->AppendChild(rectElem); rectElem = (wxSVGRectElement*) rectElem->CloneNode(); rectElem->SetY(m_menu->GetResolution().GetHeight()-33); gElem->AppendChild(rectElem); rectElem = (wxSVGRectElement*) rectElem->CloneNode(); rectElem->SetX(0); rectElem->SetY(32); rectElem->SetWidth(40); rectElem->SetHeight(m_menu->GetResolution().GetHeight()-65); gElem->AppendChild(rectElem); rectElem = (wxSVGRectElement*) rectElem->CloneNode(); rectElem->SetX(m_menu->GetResolution().GetWidth()-41); gElem->AppendChild(rectElem); m_doc->GetRootElement()->AppendChild(gElem); } Refresh(); } void MenuEditor::ShowGrid() { wxSVGGElement* gElem = (wxSVGGElement*) m_doc->GetElementById(wxT("grid")); if (gElem) gElem->GetParent()->RemoveChild(gElem); if (m_showGrid && m_grid>0) { gElem = new wxSVGGElement; gElem->SetId(wxT("grid")); wxSVGLineElement* lineElem = new wxSVGLineElement; lineElem->SetY1(0); lineElem->SetY2(m_menu->GetResolution().GetHeight()-1); lineElem->SetStroke(wxSVGPaint(255, 255, 255)); lineElem->SetFill(wxSVGPaint()); lineElem->SetStrokeOpacity(0.1); int step = 1<GetResolution().GetWidth()-1; x+=step) { lineElem = (wxSVGLineElement*) lineElem->CloneNode(); lineElem->SetX1(x); lineElem->SetX2(x); gElem->AppendChild(lineElem); } lineElem = (wxSVGLineElement*) lineElem->CloneNode(); lineElem->SetX1(0); lineElem->SetX2(m_menu->GetResolution().GetWidth()-1); for (int y = step; yGetResolution().GetHeight()-1; y+=step) { lineElem = (wxSVGLineElement*) lineElem->CloneNode(); lineElem->SetY1(y); lineElem->SetY2(y); gElem->AppendChild(lineElem); } if (m_gridOverObejcts) m_doc->GetRootElement()->AppendChild(gElem); else m_doc->GetRootElement()->InsertBefore(gElem, m_doc->GetElementById(wxT("objects"))); } Refresh(); } ////////////////////////////////////////////////////////////////////////////// void MenuEditor::OnEventTimer(wxTimerEvent& event) { SendChangedEvent(); } ////////////////////////////////////////////////////////////////////////////// void MenuEditor::OnMouseDClick(wxMouseEvent& WXUNUSED(event)) { wxCommandEvent evt; OnProperties(evt); } void MenuEditor::OnKeyDown(wxKeyEvent& event) { if (event.ControlDown() && event.GetKeyCode() == 'V') { m_menuPos = wxPoint(-1,-1); wxCommandEvent evt; OnObjectPaste(evt); return; } if (GetSelected().length()) { if (event.GetKeyCode() == WXK_DELETE) { wxCommandEvent evt; OnObjectDelete(evt); return; } else if (event.ControlDown() && event.GetKeyCode() == 'C') { wxCommandEvent evt; OnObjectCopy(evt); return; } else if (event.ControlDown() && event.GetKeyCode() == 'X') { wxCommandEvent evt; OnObjectCopy(evt); OnObjectDelete(evt); return; } } event.Skip(); } ////////////////////////////////////////////////////////////////////////////// const wxString dvdstylerDataFormatId = _T("application/dvdstyler"); void MenuEditor::OnObjectCopy(wxCommandEvent& WXUNUSED(event)) { wxMemoryOutputStream stream; wxXmlDocument doc; doc.SetRoot(m_menu->GetObject(GetSelected())->GetXML(DVDSTYLER_XML,true)); doc.Save(stream); int bufferSize = stream.GetSize(); char* buffer = new char[bufferSize]; stream.CopyTo(buffer, bufferSize); wxDataFormat format(dvdstylerDataFormatId); wxCustomDataObject* dataObj = new wxCustomDataObject(format); dataObj->TakeData(bufferSize, buffer); wxClipboardLocker locker; if (!locker) wxLogError(wxT("Can't open clipboard")); else if (!wxTheClipboard->SetData(dataObj)) wxLogError(wxT("Can't copy object to the clipboard")); } void MenuEditor::OnObjectPaste(wxCommandEvent& WXUNUSED(event)) { if (!wxTheClipboard->Open()) { wxLogError(wxT("Can't open clipboard")); return; } wxDataFormat format(dvdstylerDataFormatId); if (wxTheClipboard->IsSupported(format)) { wxCustomDataObject dataObj(format); if (!wxTheClipboard->GetData(dataObj)) { wxLogError(wxT("Can't paste data from the clipboard")); wxTheClipboard->Close(); return; } wxTheClipboard->Close(); wxMemoryInputStream stream(dataObj.GetData(), dataObj.GetSize()); wxXmlDocument doc; if (!doc.Load(stream)) { wxLogError(wxT("Can't paste object: error parsing")); return; } wxString id = m_menu->AddObject(doc.GetRoot(), true); MenuObject* obj = m_menu->GetObject(id); if (obj && m_menuPos.x != -1 && m_menuPos.y != -1) { obj->SetX((int)(m_menuPos.x/GetScale())); obj->SetY((int)(m_menuPos.y/GetScale())); } Update(); } else if (wxTheClipboard->IsSupported(wxDF_TEXT)) { wxTextDataObject textObj; if (!wxTheClipboard->GetData(textObj)) { wxLogError(wxT("Can't paste data from the clipboard")); wxTheClipboard->Close(); return; } wxTheClipboard->Close(); wxString id = m_menu->AddText(textObj.GetText()); MenuObject* obj = m_menu->GetObject(id); if (obj && m_menuPos.x != -1 && m_menuPos.y != -1) { obj->SetX((int)(m_menuPos.x/GetScale())); obj->SetY((int)(m_menuPos.y/GetScale())); } Update(); } else wxTheClipboard->Close(); } void MenuEditor::OnUpdateUIObjectPaste(wxUpdateUIEvent& event) { event.Enable(m_menu && (wxTheClipboard->IsSupported(wxDF_TEXT) || wxTheClipboard->IsSupported(wxDataFormat(dvdstylerDataFormatId)))); } void MenuEditor::OnObjectCut(wxCommandEvent& WXUNUSED(event)) { wxCommandEvent evt; OnObjectCopy(evt); OnObjectDelete(evt); } void MenuEditor::OnObjectDelete(wxCommandEvent& WXUNUSED(event)) { m_menu->RemoveObject(GetSelected()); DoSelect(wxT(""), true, true); } void MenuEditor::OnObjectToFront(wxCommandEvent& WXUNUSED(event)) { m_menu->ObjectToFront(GetSelected()); DoSelect(GetSelected(), true, true); } void MenuEditor::OnObjectForward(wxCommandEvent& WXUNUSED(event)) { m_menu->ObjectForward(GetSelected()); DoSelect(GetSelected(), true, true); } void MenuEditor::OnObjectBackward(wxCommandEvent& WXUNUSED(event)) { m_menu->ObjectBackward(GetSelected()); DoSelect(GetSelected(), true, true); } void MenuEditor::OnObjectToBack(wxCommandEvent& WXUNUSED(event)) { m_menu->ObjectToBack(GetSelected()); DoSelect(GetSelected(), true, true); } void MenuEditor::OnUpdateUIObjectForward(wxUpdateUIEvent& event) { event.Enable(!m_menu->IsLastObject(GetSelected())); } void MenuEditor::OnUpdateUIObjectBackward(wxUpdateUIEvent& event) { event.Enable(!m_menu->IsFirstObject(GetSelected())); } void MenuEditor::OnProperties(wxCommandEvent& WXUNUSED(event)) { if (!m_menu) return; if (!GetSelected().length()) // menu properties { MenuPropDlg propDlg(this, m_dvd, m_tsi, m_pgci); if (propDlg.ShowModal() == wxID_OK) Update(); } else // object properties { MenuObject* obj = m_menu->GetObject(GetSelected()); if (!obj) return; MenuObjectPropDlg propDlg(this, GetSelected(), m_menu, m_dvd, m_tsi, m_pgci); if (propDlg.ShowModal() == wxID_OK) DoSelect(GetSelected(), true, true); } } void MenuEditor::OnSafeTV(wxCommandEvent& event) { m_safeTV = !m_safeTV; ShowSafeTV(); } void MenuEditor::OnShowGrid(wxCommandEvent& event) { m_showGrid = !m_showGrid; ShowGrid(); } void MenuEditor::OnShowGridOverObjects(wxCommandEvent& event) { m_gridOverObejcts = !m_gridOverObejcts; ShowGrid(); } void MenuEditor::OnGridMenu(wxCommandEvent& event) { long id = event.GetId() - MENUEDITOR_GRIDMENU_ITEM_ID; m_grid = id; if (m_grid>0) m_grid += 1; if (m_showGrid) ShowGrid(); } void MenuEditor::OnAddObject(wxCommandEvent& event) { long n = event.GetId() - MENUEDITOR_ADDMENU_OBJECT_ID; AddObject(m_addMenuObjects[n], (int)(m_menuPos.x/GetScale()), (int)(m_menuPos.y/GetScale())); } void MenuEditor::SendChangedEvent() { wxCommandEvent evt(EVT_COMMAND_MENUEDITOR_MENU_CHANGED, this->GetId()); GetEventHandler()->ProcessEvent(evt); }