1 /////////////////////////////////////////////////////////////////////////////
2 // Name: ChaptersDlg.cpp
3 // Purpose: The chapters dialog
4 // Author: Alex Thuering
5 // Created: 19.04.2010
6 // RCS-ID: $Id: ChaptersDlg.cpp,v 1.13 2016/05/16 21:13:35 ntalex Exp $
7 // Copyright: (c) Alex Thuering
8 // Licence: GPL
9 /////////////////////////////////////////////////////////////////////////////
10
11 #include "ChaptersDlg.h"
12 #include "TitlePropDlg.h"
13 #include "Utils.h"
14 #include "Config.h"
15 #include <wx/regex.h>
16 #include <wx/imaglist.h>
17 #include <wxVillaLib/utils.h>
18 #include <wxVillaLib/rc/video.png.h>
19 #include "rc/add.png.h"
20 #include "rc/remove.png.h"
21 #include "rc/preferences.png.h"
22 #include "Utils.h"
23
24 //(*InternalHeaders(ChaptersDlg)
25 #include <wx/bitmap.h>
26 #include <wx/intl.h>
27 #include <wx/button.h>
28 #include <wx/image.h>
29 #include <wx/string.h>
30 //*)
31
32 //(*IdInit(ChaptersDlg)
33 const long ChaptersDlg::ID_THUMBNAILS = wxNewId();
34 const long ChaptersDlg::ID_ADD_BT = wxNewId();
35 const long ChaptersDlg::ID_DEL_BT = wxNewId();
36 const long ChaptersDlg::ID_PANEL1 = wxNewId();
37 const long ChaptersDlg::ID_MEDIA_CTRL = wxNewId();
38 const long ChaptersDlg::ID_SLIDER = wxNewId();
39 const long ChaptersDlg::ID_TIME_CTRL = wxNewId();
40 const long ChaptersDlg::ID_TIME_SPINB = wxNewId();
41 const long ChaptersDlg::ID_FRAME_SPINBT = wxNewId();
42 const long ChaptersDlg::ID_RADIOBUTTON1 = wxNewId();
43 const long ChaptersDlg::ID_RADIOBUTTON2 = wxNewId();
44 const long ChaptersDlg::ID_RADIOBUTTON3 = wxNewId();
45 const long ChaptersDlg::ID_STATICTEXT1 = wxNewId();
46 const long ChaptersDlg::ID_CHOICE1 = wxNewId();
47 const long ChaptersDlg::ID_END_CTRL = wxNewId();
48 const long ChaptersDlg::ID_END_SPIN = wxNewId();
49 const long ChaptersDlg::ID_END_FRAME_SPINBT = wxNewId();
50 const long ChaptersDlg::ID_DURATION_CTRL = wxNewId();
51 const long ChaptersDlg::ID_COMMANDS_CTRL = wxNewId();
52 const long ChaptersDlg::ID_PANEL2 = wxNewId();
53 const long ChaptersDlg::ID_SPLITTERWINDOW = wxNewId();
54 const long ChaptersDlg::ID_ADD_CELL_CHECK = wxNewId();
55 //*)
56
BEGIN_EVENT_TABLE(ChaptersDlg,wxDialog)57 BEGIN_EVENT_TABLE(ChaptersDlg, wxDialog)
58 //(*EventTable(ChaptersDlg)
59 //*)
60 EVT_COMMAND_SCROLL(ID_SLIDER, ChaptersDlg::OnSliderScroll)
61 END_EVENT_TABLE()
62
63 ChaptersDlg::ChaptersDlg(wxWindow* parent, DVD* dvd, int tsi, int pgci, int vobi, Vob* vob) {
64 m_dvd = dvd;
65 m_tsi = tsi;
66 m_pgci = pgci;
67 m_vobi = vobi;
68 m_vob = vob;
69 VECTOR_COPY(m_vob->GetCells(), m_cells, Cell);
70 m_selectedCell = NULL;
71
72 //(*Initialize(ChaptersDlg)
73 wxBoxSizer* BoxSizer4;
74 wxBoxSizer* BoxSizer6;
75 wxPanel* panel1;
76 wxStaticText* staticText2;
77 wxBoxSizer* BoxSizer5;
78 wxBoxSizer* boxSizer1;
79 wxStaticText* staticText5;
80 wxStaticText* staticText4;
81 wxSplitterWindow* splitterWindow;
82 wxBoxSizer* boxSizer2;
83 wxStaticText* staticText3;
84 wxStaticText* StaticText1;
85 wxBoxSizer* BoxSizer2;
86 wxFlexGridSizer* flexGridSizer1;
87 wxStdDialogButtonSizer* stdDialogButtonSizer;
88 wxStaticText* staticText1;
89 wxBoxSizer* BoxSizer1;
90 wxPanel* panel2;
91 wxBoxSizer* BoxSizer3;
92 wxBoxSizer* mainSizer;
93
94 Create(parent, wxID_ANY, _("Chapters"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER, _T("wxID_ANY"));
95 SetClientSize(wxSize(800,450));
96 mainSizer = new wxBoxSizer(wxVERTICAL);
97 splitterWindow = new wxSplitterWindow(this, ID_SPLITTERWINDOW, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_3DSASH, _T("ID_SPLITTERWINDOW"));
98 splitterWindow->SetMinSize(wxSize(50,50));
99 splitterWindow->SetMinimumPaneSize(50);
100 splitterWindow->SetSashGravity(0.5);
101 panel1 = new wxPanel(splitterWindow, ID_PANEL1, wxPoint(47,173), wxDefaultSize, wxTAB_TRAVERSAL, _T("ID_PANEL1"));
102 BoxSizer2 = new wxBoxSizer(wxVERTICAL);
103 staticText1 = new wxStaticText(panel1, wxID_ANY, _("Chapters:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
104 BoxSizer2->Add(staticText1, 0, wxTOP|wxLEFT|wxRIGHT|wxEXPAND, 5);
105 BoxSizer3 = new wxBoxSizer(wxHORIZONTAL);
106 m_thumbnails = new wxThumbnails(panel1,ID_THUMBNAILS);
107 BoxSizer3->Add(m_thumbnails, 1, wxEXPAND, 5);
108 boxSizer2 = new wxBoxSizer(wxVERTICAL);
109 m_addBt = new wxBitmapButton(panel1, ID_ADD_BT, wxBITMAP_FROM_MEMORY(add), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, _T("ID_ADD_BT"));
110 boxSizer2->Add(m_addBt, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 4);
111 m_delBt = new wxBitmapButton(panel1, ID_DEL_BT, wxBITMAP_FROM_MEMORY(remove), wxDefaultPosition, wxDefaultSize, wxBU_AUTODRAW, wxDefaultValidator, _T("ID_DEL_BT"));
112 boxSizer2->Add(m_delBt, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 4);
113 BoxSizer3->Add(boxSizer2, 0, wxEXPAND, 5);
114 BoxSizer2->Add(BoxSizer3, 1, wxTOP|wxBOTTOM|wxLEFT|wxEXPAND, 5);
115 panel1->SetSizer(BoxSizer2);
116 BoxSizer2->Fit(panel1);
117 BoxSizer2->SetSizeHints(panel1);
118 panel2 = new wxPanel(splitterWindow, ID_PANEL2, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL, _T("ID_PANEL2"));
119 BoxSizer4 = new wxBoxSizer(wxVERTICAL);
120 m_mediaCtrl = new MediaCtrlFF(panel2, ID_MEDIA_CTRL, wxT(""), wxDefaultPosition,wxDefaultSize, 0, wxDefaultValidator, _T("ID_MEDIA_CTRL"));
121 m_mediaCtrl->SetMinSize(wxSize(300, 200));
122 m_mediaCtrl->SetWindowStyle(wxBORDER_NONE);
123 BoxSizer4->Add(m_mediaCtrl, 1, wxALL|wxEXPAND, 4);
124 m_slider = new wxSlider(panel2, ID_SLIDER, 0, 0, 100, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_SLIDER"));
125 BoxSizer4->Add(m_slider, 0, wxEXPAND, 2);
126 flexGridSizer1 = new wxFlexGridSizer(0, 2, 2, 4);
127 flexGridSizer1->AddGrowableCol(1);
128 StaticText1 = new wxStaticText(panel2, wxID_ANY, _("Time:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
129 flexGridSizer1->Add(StaticText1, 0, wxLEFT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 4);
130 BoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
131 m_timeCtrl = new wxTextCtrl(panel2, ID_TIME_CTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_TIME_CTRL"));
132 BoxSizer5->Add(m_timeCtrl, 0, wxEXPAND, 5);
133 m_timeSpinBt = new wxSpinButton(panel2, ID_TIME_SPINB, wxDefaultPosition, wxDefaultSize, wxSP_VERTICAL|wxSP_ARROW_KEYS, _T("ID_TIME_SPINB"));
134 m_timeSpinBt->SetRange(0, 100);
135 m_timeSpinBt->SetMinSize(wxSize(16,12));
136 BoxSizer5->Add(m_timeSpinBt, 0, wxEXPAND, 5);
137 m_frameSpinBt = new wxSpinButton(panel2, ID_FRAME_SPINBT, wxDefaultPosition, wxDefaultSize, wxSP_VERTICAL|wxSP_ARROW_KEYS, _T("ID_FRAME_SPINBT"));
138 m_frameSpinBt->SetRange(-9999, 9999);
139 m_frameSpinBt->SetMinSize(wxSize(16,12));
140 BoxSizer5->Add(m_frameSpinBt, 0, wxEXPAND, 5);
141 flexGridSizer1->Add(BoxSizer5, 0, wxALL|wxEXPAND, 0);
142 staticText5 = new wxStaticText(panel2, wxID_ANY, _("Type:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
143 flexGridSizer1->Add(staticText5, 0, wxLEFT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 4);
144 boxSizer1 = new wxBoxSizer(wxHORIZONTAL);
145 m_chapterBt = new wxRadioButton(panel2, ID_RADIOBUTTON1, _("Chapter"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP, wxDefaultValidator, _T("ID_RADIOBUTTON1"));
146 boxSizer1->Add(m_chapterBt, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 4);
147 m_programBt = new wxRadioButton(panel2, ID_RADIOBUTTON2, _("Program"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_RADIOBUTTON2"));
148 boxSizer1->Add(m_programBt, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
149 m_regularBt = new wxRadioButton(panel2, ID_RADIOBUTTON3, _("Regular cell"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_RADIOBUTTON3"));
150 boxSizer1->Add(m_regularBt, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
151 flexGridSizer1->Add(boxSizer1, 1, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
152 StaticText2 = new wxStaticText(panel2, ID_STATICTEXT1, _("End:"), wxDefaultPosition, wxDefaultSize, 0, _T("ID_STATICTEXT1"));
153 flexGridSizer1->Add(StaticText2, 1, wxLEFT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 5);
154 BoxSizer6 = new wxBoxSizer(wxHORIZONTAL);
155 m_endChoice = new wxChoice(panel2, ID_CHOICE1, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_CHOICE1"));
156 m_endChoice->SetSelection( m_endChoice->Append(_("Auto")) );
157 m_endChoice->Append(_("Custom"));
158 BoxSizer6->Add(m_endChoice, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
159 m_endCtrl = new wxTextCtrl(panel2, ID_END_CTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_END_CTRL"));
160 BoxSizer6->Add(m_endCtrl, 0, wxLEFT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 2);
161 m_endSpinBt = new wxSpinButton(panel2, ID_END_SPIN, wxDefaultPosition, wxDefaultSize, wxSP_VERTICAL|wxSP_ARROW_KEYS, _T("ID_END_SPIN"));
162 m_endSpinBt->SetRange(0, 100);
163 m_endSpinBt->SetMinSize(wxSize(16,12));
164 BoxSizer6->Add(m_endSpinBt, 0, wxEXPAND, 0);
165 m_endFrameSpinBt = new wxSpinButton(panel2, ID_END_FRAME_SPINBT, wxDefaultPosition, wxDefaultSize, wxSP_VERTICAL|wxSP_ARROW_KEYS, _T("ID_END_FRAME_SPINBT"));
166 m_endFrameSpinBt->SetRange(-9999, 9999);
167 m_endFrameSpinBt->SetMinSize(wxSize(16,12));
168 BoxSizer6->Add(m_endFrameSpinBt, 0, wxEXPAND, 5);
169 staticText2 = new wxStaticText(panel2, wxID_ANY, _("Pause:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
170 BoxSizer6->Add(staticText2, 0, wxLEFT|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 8);
171 m_pauseSpin = new wxSpinCtrl(panel2, ID_DURATION_CTRL, _T("0"), wxDefaultPosition, wxSize(60,-1), 0, -1, 999, 0, _T("ID_DURATION_CTRL"));
172 m_pauseSpin->SetValue(_T("0"));
173 BoxSizer6->Add(m_pauseSpin, 0, wxLEFT|wxEXPAND, 4);
174 staticText3 = new wxStaticText(panel2, wxID_ANY, _("sec"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
175 BoxSizer6->Add(staticText3, 0, wxLEFT|wxALIGN_CENTER_VERTICAL, 2);
176 flexGridSizer1->Add(BoxSizer6, 1, wxALL|wxEXPAND, 0);
177 staticText4 = new wxStaticText(panel2, wxID_ANY, _("Commands:"), wxDefaultPosition, wxDefaultSize, 0, _T("wxID_ANY"));
178 flexGridSizer1->Add(staticText4, 0, wxLEFT|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL, 4);
179 m_commandsCtrl = new wxComboBox(panel2, ID_COMMANDS_CTRL, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, 0, 0, wxDefaultValidator, _T("ID_COMMANDS_CTRL"));
180 flexGridSizer1->Add(m_commandsCtrl, 1, wxEXPAND, 4);
181 BoxSizer4->Add(flexGridSizer1, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND, 5);
182 panel2->SetSizer(BoxSizer4);
183 BoxSizer4->Fit(panel2);
184 BoxSizer4->SetSizeHints(panel2);
185 splitterWindow->SplitVertically(panel1, panel2);
186 mainSizer->Add(splitterWindow, 1, wxEXPAND, 5);
187 BoxSizer1 = new wxBoxSizer(wxHORIZONTAL);
188 m_addCellAtBegin = new wxCheckBox(this, ID_ADD_CELL_CHECK, _("Add cell at begin if it doesn\'t exist"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, _T("ID_ADD_CELL_CHECK"));
189 m_addCellAtBegin->SetValue(false);
190 BoxSizer1->Add(m_addCellAtBegin, 0, wxALIGN_CENTER_VERTICAL, 5);
191 stdDialogButtonSizer = new wxStdDialogButtonSizer();
192 stdDialogButtonSizer->AddButton(new wxButton(this, wxID_OK, wxEmptyString));
193 stdDialogButtonSizer->AddButton(new wxButton(this, wxID_CANCEL, wxEmptyString));
194 stdDialogButtonSizer->Realize();
195 BoxSizer1->Add(stdDialogButtonSizer, 1, wxTOP|wxEXPAND, 5);
196 mainSizer->Add(BoxSizer1, 0, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND, 5);
197 SetSizer(mainSizer);
198 SetSizer(mainSizer);
199 Layout();
200 Center();
201
202 Connect(ID_ADD_BT,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&ChaptersDlg::OnAddBt);
203 Connect(ID_DEL_BT,wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&ChaptersDlg::OnDelBt);
204 Connect(ID_TIME_CTRL,wxEVT_COMMAND_TEXT_UPDATED,(wxObjectEventFunction)&ChaptersDlg::OnChangeTime);
205 Connect(ID_TIME_SPINB,wxEVT_SCROLL_THUMBTRACK,(wxObjectEventFunction)&ChaptersDlg::OnTimeSpin);
206 Connect(ID_FRAME_SPINBT,wxEVT_SCROLL_LINEUP,(wxObjectEventFunction)&ChaptersDlg::OnFrameSpin);
207 Connect(ID_FRAME_SPINBT,wxEVT_SCROLL_LINEDOWN,(wxObjectEventFunction)&ChaptersDlg::OnFrameSpinDown);
208 Connect(ID_CHOICE1,wxEVT_COMMAND_CHOICE_SELECTED,(wxObjectEventFunction)&ChaptersDlg::OnEndChoice);
209 Connect(ID_END_CTRL,wxEVT_COMMAND_TEXT_UPDATED,(wxObjectEventFunction)&ChaptersDlg::OnChangeEnd);
210 Connect(ID_END_SPIN,wxEVT_SCROLL_THUMBTRACK,(wxObjectEventFunction)&ChaptersDlg::OnEndSpin);
211 Connect(ID_END_FRAME_SPINBT,wxEVT_SCROLL_LINEUP,(wxObjectEventFunction)&ChaptersDlg::OnEndFrameSpin);
212 Connect(ID_END_FRAME_SPINBT,wxEVT_SCROLL_LINEDOWN,(wxObjectEventFunction)&ChaptersDlg::OnEndFrameSpinDown);
213 //*)
214 Connect(ID_THUMBNAILS, EVT_COMMAND_THUMBNAILS_SEL_CHANGED, (wxObjectEventFunction)&ChaptersDlg::OnSelectionChanged);
215 m_thumbnails->Connect(wxID_ANY, wxEVT_KEY_DOWN, wxKeyEventHandler(ChaptersDlg::OnKeyDown), (wxObject*) NULL, this);
216 Connect(wxID_OK, wxEVT_COMMAND_BUTTON_CLICKED,(wxObjectEventFunction)&ChaptersDlg::OnOkBt);
217 stdDialogButtonSizer->GetAffirmativeButton()->SetDefault();
218
219 SetIcon(((wxTopLevelWindow*)wxGetTopLevelParent(parent))->GetIcon());
220
221 int x = 0;
222 m_timeCtrl->GetTextExtent(wxT("00:00:00.000"), &x, NULL);
223 m_timeCtrl->SetMinSize(wxSize(x + 10, -1));
224 m_endCtrl->SetMinSize(wxSize(x + 10, -1));
225 m_pauseSpin->GetTextExtent(wxT("999"), &x, NULL);
226 m_pauseSpin->SetMinSize(wxSize(x + 32, -1));
227 m_mediaCtrl->Load(m_vob->GetFilename());
228 m_slider->SetMax(m_vob->GetResultDuration());
229 m_timeSpinBt->SetMax(m_vob->GetResultDuration());
230 m_endSpinBt->SetMax(m_vob->GetResultDuration());
231 m_commandsCtrl->Append(TitlePropDlg::GetCommandList(m_dvd, m_tsi));
232
233 m_thumbnails->Clear();
234 for (vector<Cell*>::const_iterator it = m_cells.begin(); it != m_cells.end(); it++) {
235 AddThumbnail((*it));
236 }
237
238 m_addCellAtBegin->SetValue(m_cells.size() == 0 || m_cells.front()->GetStart() == 0);
239
240 if (m_thumbnails->GetItemCount() > 0)
241 m_thumbnails->SetSelected(0);
242 wxCommandEvent evt;
243 OnSelectionChanged(evt);
244 m_thumbnails->SetFocus();
245 }
246
~ChaptersDlg()247 ChaptersDlg::~ChaptersDlg() {
248 //(*Destroy(ChaptersDlg)
249 //*)
250 }
251
LoadFrame(long pos)252 wxImage ChaptersDlg::LoadFrame(long pos) {
253 double dpos = ((double) pos)/1000;
254 wxImage image;
255 wxFfmpegMediaDecoder& decoder = m_mediaCtrl->GetDecoder();
256 if (decoder.SetPosition(dpos >= 1 ? dpos - 1 : 0)) {
257 for (int i = 0; i < 60; i++) {
258 image = decoder.GetNextFrame();
259 if (decoder.GetPosition() >= dpos)
260 break;
261 }
262 }
263 return image.Ok() ? image : wxBITMAP_FROM_MEMORY(video).ConvertToImage();
264 }
265
AddThumbnail(Cell * cell,int pos)266 void ChaptersDlg::AddThumbnail(Cell* cell, int pos) {
267 wxThumb* thumb = new wxThumb(wxT(""), cell->GetStartStr());
268 thumb->SetImage(LoadFrame(cell->GetStart() + (m_vob->GetStartTime()*1000)));
269 m_thumbnails->InsertItem(thumb, pos);
270 }
271
OnAddBt(wxCommandEvent & event)272 void ChaptersDlg::OnAddBt(wxCommandEvent& event) {
273 long start = m_cells.size() > 0 ? m_cells.back()->GetStart() + s_config.GetDefChapterLength() * 60000 : 0;
274 long duration = m_vob->GetResultDuration()*1000;
275 Cell* cell = new Cell(start < duration ? start : (duration > 1000 ? duration - 1000 - (duration % 1000): 0));
276 m_cells.push_back(cell);
277 AddThumbnail(cell);
278 m_thumbnails->Refresh();
279 }
280
OnDelBt(wxCommandEvent & event)281 void ChaptersDlg::OnDelBt(wxCommandEvent& event) {
282 if (m_thumbnails->GetSelected() < 0)
283 return;
284 m_selectedCell = NULL;
285 m_thumbnails->RemoveItemAt(m_thumbnails->GetSelected());
286 m_cells.erase(m_cells.begin() + m_thumbnails->GetSelected());
287 if (m_thumbnails->GetSelected() >= m_thumbnails->GetItemCount()) {
288 m_thumbnails->SetSelected(m_thumbnails->GetItemCount() - 1);
289 }
290 wxCommandEvent evt;
291 OnSelectionChanged(evt);
292 m_thumbnails->Refresh();
293 }
294
OnSelectionChanged(wxCommandEvent & event)295 void ChaptersDlg::OnSelectionChanged(wxCommandEvent& event) {
296 if (m_selectedCell != NULL && !CheckCellValues()) {
297 for (unsigned int idx = 0; idx < m_cells.size(); idx++) {
298 if (m_cells[idx] == m_selectedCell) {
299 m_thumbnails->SetSelected(idx);
300 break;
301 }
302 }
303 return;
304 }
305
306 int idx = m_thumbnails->GetSelected();
307 m_selectedCell = idx >= 0 ? m_cells[idx] : NULL;
308
309 bool enable = idx >= 0;
310 m_delBt->Enable(enable);
311 m_slider->Enable(enable);
312 m_timeCtrl->Enable(enable);
313 m_timeSpinBt->Enable(enable);
314 m_frameSpinBt->Enable(enable);
315 m_endChoice->Enable(enable);
316 m_endSpinBt->Enable(enable);
317 m_endCtrl->Enable(enable);
318 m_pauseSpin->Enable(enable);
319 m_regularBt->Enable(enable);
320 m_chapterBt->Enable(enable);
321 m_programBt->Enable(enable);
322 m_commandsCtrl->Enable(enable);
323 if (enable) {
324 m_endChoice->SetSelection(m_selectedCell->GetEnd() == -1 ? 0 : 1);
325 m_endSpinBt->SetValue(m_selectedCell->GetEnd() >= 0 ? m_selectedCell->GetEnd() / 1000 : 0);
326 m_endCtrl->ChangeValue(m_selectedCell->GetEnd() >= 0 ? Time2String(m_selectedCell->GetEnd(), true) : wxString(wxT("")));
327 m_pauseSpin->SetValue(m_selectedCell->GetPause());
328 m_regularBt->SetValue(true);
329 m_chapterBt->SetValue(m_selectedCell->IsChapter());
330 m_programBt->SetValue(m_selectedCell->IsProgram());
331 m_commandsCtrl->SetValue(m_selectedCell->GetCommands());
332 SeekVideo(m_selectedCell->GetStart());
333 } else {
334 SeekVideo(0);
335 }
336 }
337
OnKeyDown(wxKeyEvent & event)338 void ChaptersDlg::OnKeyDown(wxKeyEvent& event) {
339 switch (event.GetKeyCode()) {
340 case WXK_DELETE: {
341 wxCommandEvent evt;
342 OnDelBt(evt);
343 break;
344 }
345 default:
346 event.Skip();
347 break;
348 }
349 }
350
SeekVideo(long pos,bool updateTimeCtrl)351 void ChaptersDlg::SeekVideo(long pos, bool updateTimeCtrl) {
352 m_slider->SetValue(lround(pos / 1000));
353 m_timeSpinBt->SetValue(lround(pos / 1000));
354 m_mediaCtrl->Seek((wxFileOffset) (pos + (m_vob->GetStartTime()*1000)));
355 if (updateTimeCtrl)
356 m_timeCtrl->ChangeValue(Time2String(pos, true));
357
358 int idx = m_thumbnails->GetSelected();
359 if (idx < 0)
360 return;
361 Cell* cell = m_cells[idx];
362 cell->SetStart(pos);
363 int idx2 = idx;
364 while (idx2 > 0 && cell->GetStart() < m_cells[idx2-1]->GetStart())
365 idx2--;
366 while (idx2 < (int) m_cells.size() - 1 && cell->GetStart() > m_cells[idx2+1]->GetStart())
367 idx2++;
368 if (idx2 != idx) {
369 m_cells.erase(m_cells.begin() + idx);
370 m_cells.insert(m_cells.begin() + idx2, cell);
371 m_thumbnails->RemoveItemAt(idx);
372 AddThumbnail(cell, idx2);
373 m_thumbnails->SetSelected(idx2);
374 }
375 m_thumbnails->GetSelectedItem()->SetCaption(cell->GetStartStr());
376 wxImage image = m_mediaCtrl->GetImage();
377 m_thumbnails->GetSelectedItem()->SetImage(image.Ok() ? image : wxBITMAP_FROM_MEMORY(video).ConvertToImage());
378 m_thumbnails->GetSelectedItem()->Update();
379 m_thumbnails->Refresh();
380 wxCommandEvent evt;
381 OnEndChoice(evt); // update end time if selected "auto"
382 }
383
OnChangeTime(wxCommandEvent & event)384 void ChaptersDlg::OnChangeTime(wxCommandEvent& event) {
385 if (s_timeRE.Matches(m_timeCtrl->GetValue())) {
386 SeekVideo(String2Time(m_timeCtrl->GetValue(), m_mediaCtrl->GetFps()), false);
387 }
388 }
389
OnTimeSpin(wxSpinEvent & event)390 void ChaptersDlg::OnTimeSpin(wxSpinEvent& event) {
391 SeekVideo(((long)m_timeSpinBt->GetValue())*1000);
392 }
393
OnSliderScroll(wxScrollEvent & event)394 void ChaptersDlg::OnSliderScroll(wxScrollEvent& event) {
395 SeekVideo(((long)m_slider->GetValue())*1000);
396 }
397
OnEndChoice(wxCommandEvent & event)398 void ChaptersDlg::OnEndChoice(wxCommandEvent& event) {
399 if (m_endChoice->GetSelection() == 0) {
400 int idx = m_thumbnails->GetSelected();
401 Cell* nextCell = idx >= 0 && idx + 1 < (int) m_cells.size() ? m_cells[idx + 1] : NULL;
402 long endTime = nextCell ? nextCell->GetStart() : m_vob->GetResultDuration()*1000;
403 m_endSpinBt->SetValue(endTime / 1000);
404 m_endCtrl->ChangeValue(Time2String(endTime, true));
405 }
406 m_endCtrl->Enable(m_endChoice->GetSelection() > 0);
407 m_endSpinBt->Enable(m_endChoice->GetSelection() > 0);
408 m_endFrameSpinBt->Enable(m_endChoice->GetSelection() > 0);
409 }
410
OnChangeEnd(wxCommandEvent & event)411 void ChaptersDlg::OnChangeEnd(wxCommandEvent& event) {
412 if (s_timeRE.Matches(m_endCtrl->GetValue())) {
413 m_endSpinBt->SetValue(String2Time(m_endCtrl->GetValue(), m_mediaCtrl->GetFps()) / 1000);
414 }
415 }
416
OnFrameSpin(wxSpinEvent & event)417 void ChaptersDlg::OnFrameSpin(wxSpinEvent& event) {
418 SeekVideo(String2Time(m_timeCtrl->GetValue(), m_mediaCtrl->GetFps()) + 1000 / m_mediaCtrl->GetFps());
419 }
420
OnFrameSpinDown(wxSpinEvent & event)421 void ChaptersDlg::OnFrameSpinDown(wxSpinEvent& event) {
422 long pos = String2Time(m_timeCtrl->GetValue(), m_mediaCtrl->GetFps()) - 1000 / m_mediaCtrl->GetFps();
423 SeekVideo(pos >= 0 ? pos : 0);
424 }
425
OnEndSpin(wxSpinEvent & event)426 void ChaptersDlg::OnEndSpin(wxSpinEvent& event) {
427 m_endCtrl->ChangeValue(Time2String(m_endSpinBt->GetValue() * 1000, true));
428 }
429
OnEndFrameSpin(wxSpinEvent & event)430 void ChaptersDlg::OnEndFrameSpin(wxSpinEvent& event) {
431 long pos = String2Time(m_endCtrl->GetValue(), m_mediaCtrl->GetFps()) + 1000 / m_mediaCtrl->GetFps();
432 m_endCtrl->ChangeValue(Time2String(pos, true));
433 }
434
OnEndFrameSpinDown(wxSpinEvent & event)435 void ChaptersDlg::OnEndFrameSpinDown(wxSpinEvent& event) {
436 long pos = String2Time(m_endCtrl->GetValue(), m_mediaCtrl->GetFps()) - 1000 / m_mediaCtrl->GetFps();
437 m_endCtrl->ChangeValue(Time2String(pos >= 0 ? pos : 0, true));
438 }
439
CheckCellValues()440 bool ChaptersDlg::CheckCellValues() {
441 if (m_selectedCell == NULL)
442 return true;
443
444 if (!s_timeRE.Matches(m_timeCtrl->GetValue())) {
445 wxLogError(_("'%s' is not valid time"), m_timeCtrl->GetValue().c_str());
446 return false;
447 }
448 if (m_endChoice->GetSelection() > 0 && m_endCtrl->GetValue().length() > 0
449 && !s_timeRE.Matches(m_endCtrl->GetValue())) {
450 wxLogError(_("'%s' is not valid time"), m_endCtrl->GetValue().c_str());
451 return false;
452 }
453 if (m_endChoice->GetSelection() > 0 && m_endCtrl->GetValue().length() > 0
454 && String2Time(m_timeCtrl->GetValue()) > String2Time(m_endCtrl->GetValue())) {
455 wxLogError(_("Start time cannot be after end time"));
456 return false;
457 }
458 DVDAction action;
459 action.SetCustom(m_commandsCtrl->GetValue());
460 if (m_commandsCtrl->GetValue().length() && !action.IsValid(m_dvd, m_tsi, m_pgci, false, wxT(""), true, false)) {
461 return false;
462 }
463
464 // update
465 m_selectedCell->SetStart(String2Time(m_timeCtrl->GetValue(), m_mediaCtrl->GetFps()));
466 m_selectedCell->SetEnd(m_endChoice->GetSelection() > 0 && m_endCtrl->GetValue().length()
467 ? String2Time(m_endCtrl->GetValue(), m_mediaCtrl->GetFps()) : -1);
468 m_selectedCell->SetPause(m_pauseSpin->GetValue());
469 m_selectedCell->SetCommands(m_commandsCtrl->GetValue());
470 m_selectedCell->SetChapter(m_chapterBt->GetValue());
471 m_selectedCell->SetProgram(m_programBt->GetValue());
472 return true;
473 }
474
OnOkBt(wxCommandEvent & event)475 void ChaptersDlg::OnOkBt(wxCommandEvent& event) {
476 if (!CheckCellValues())
477 return;
478 // update VOB
479 if (m_cells.size() == 0 && m_vobi == 0)
480 m_cells.push_back(new Cell(0));
481 else if (m_cells.size() && m_cells.front()->GetStart() != 0 && m_addCellAtBegin->GetValue())
482 m_cells.insert(m_cells.begin(), new Cell(0, m_vobi == 0));
483 m_vob->GetCells().swap(m_cells);
484 EndModal(wxID_OK);
485 }
486