Support unrar64.dll
[xy_vsfilter.git] / src / apps / mplayerc / PlayerSubresyncBar.cpp
blobaa4ba19f0f07b9c4a35d704493f4c7de9d13fe48
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 // PlayerSubresyncBar.cpp : implementation file
25 #include "stdafx.h"
26 #include "mplayerc.h"
27 #include "mainfrm.h"
28 #include "PlayerSubresyncBar.h"
30 // CPlayerSubresyncBar
32 IMPLEMENT_DYNAMIC(CPlayerSubresyncBar, CSizingControlBarG)
33 CPlayerSubresyncBar::CPlayerSubresyncBar()
35 m_rt = 0;
36 m_fUnlink = false;
37 m_lastSegment = -1;
40 CPlayerSubresyncBar::~CPlayerSubresyncBar()
44 BOOL CPlayerSubresyncBar::Create(CWnd* pParentWnd, CCritSec* pSubLock)
46 if(!CSizingControlBarG::Create(_T("Subresync"), pParentWnd, 0))
47 return FALSE;
49 m_pSubLock = pSubLock;
51 m_list.CreateEx(
52 WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE,
53 WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_TABSTOP|LVS_REPORT/*|LVS_SHOWSELALWAYS*/|LVS_AUTOARRANGE|LVS_NOSORTHEADER,
54 CRect(0,0,100,100), this, IDC_SUBRESYNCLIST);
56 m_list.SetExtendedStyle(m_list.GetExtendedStyle()|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER);
58 return TRUE;
61 BOOL CPlayerSubresyncBar::PreCreateWindow(CREATESTRUCT& cs)
63 if(!CSizingControlBarG::PreCreateWindow(cs))
64 return FALSE;
66 return TRUE;
69 BOOL CPlayerSubresyncBar::PreTranslateMessage(MSG* pMsg)
71 if(IsWindow(pMsg->hwnd) && IsVisible() && pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)
73 if(IsShortCut(pMsg) || IsDialogMessage(pMsg))
74 return TRUE;
77 return CSizingControlBarG::PreTranslateMessage(pMsg);
80 void CPlayerSubresyncBar::SetTime(__int64 rt)
82 m_rt = rt;
84 int curSegment;
86 if(!m_sts.SearchSubs((int)(rt/10000), 25, &curSegment))
88 curSegment = -1;
91 if(m_lastSegment != curSegment) m_list.Invalidate();
92 m_lastSegment = curSegment;
95 void CPlayerSubresyncBar::SetSubtitle(ISubStream* pSubStream, double fps)
97 m_pSubStream = pSubStream;
99 m_mode = NONE;
100 m_lastSegment = -1;
101 m_sts.Empty();
103 ResetSubtitle();
105 if(!m_pSubStream) return;
107 CLSID clsid;
108 m_pSubStream->GetClassID(&clsid);
110 if(clsid == __uuidof(CVobSubFile))
112 CVobSubFile* pVSF = (CVobSubFile*)(ISubStream*)m_pSubStream;
114 m_mode = VOBSUB;
116 CAtlArray<CVobSubFile::SubPos>& sp = pVSF->m_langs[pVSF->m_iLang].subpos;
118 for(int i = 0, j = sp.GetCount(); i < j; i++)
120 CString str;
121 str.Format(_T("%d,%d,%d,%d"), sp[i].vobid, sp[i].cellid, sp[i].fForced, i);
122 m_sts.Add(TToW(str), false, (int)sp[i].start, (int)sp[i].stop);
125 m_sts.CreateDefaultStyle(DEFAULT_CHARSET);
127 pVSF->m_fOnlyShowForcedSubs = false;
129 for(int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) m_list.DeleteColumn(0);
130 m_list.InsertColumn(COL_START, _T("Time"), LVCFMT_LEFT, 80);
131 m_list.InsertColumn(COL_END, _T("End"), LVCFMT_LEFT, 80);
132 m_list.InsertColumn(COL_PREVSTART, _T("Preview"), LVCFMT_LEFT, 80);
133 m_list.InsertColumn(COL_PREVEND, _T("End"), LVCFMT_LEFT, 80);
134 m_list.InsertColumn(COL_VOBID, _T("Vob ID"), LVCFMT_CENTER, 60);
135 m_list.InsertColumn(COL_CELLID, _T("Cell ID"), LVCFMT_CENTER, 60);
136 m_list.InsertColumn(COL_FORCED, _T("Forced"), LVCFMT_CENTER, 60);
138 else if(clsid == __uuidof(CRenderedTextSubtitle))
140 CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream;
142 m_mode = TEXTSUB;
144 m_sts.Copy(*pRTS);
145 m_sts.ConvertToTimeBased(fps);
146 m_sts.Sort(true); /*!!m_fUnlink*/
148 #ifndef UNICODE
149 if(!m_sts.IsEntryUnicode(0))
151 CFont* f = m_list.GetFont();
152 LOGFONT lf;
153 f->GetLogFont(&lf);
154 lf.lfCharSet = m_sts.GetCharSet(0);
155 m_font.DeleteObject();
156 m_font.CreateFontIndirect(&lf);
157 m_list.SetFont(&m_font);
159 #endif
160 for(int i = 0, j = m_list.GetHeaderCtrl()->GetItemCount(); i < j; i++) m_list.DeleteColumn(0);
161 m_list.InsertColumn(COL_START, _T("Time"), LVCFMT_LEFT, 90);
162 m_list.InsertColumn(COL_END, _T("End"), LVCFMT_LEFT, 4);
163 m_list.InsertColumn(COL_PREVSTART, _T("Preview"), LVCFMT_LEFT, 80);
164 m_list.InsertColumn(COL_PREVEND, _T("End"), LVCFMT_LEFT, 4);
165 m_list.InsertColumn(COL_TEXT, _T("Text"), LVCFMT_LEFT, 275);
166 m_list.InsertColumn(COL_STYLE, _T("Style"), LVCFMT_LEFT, 80);
167 m_list.InsertColumn(COL_FONT, _T("Font"), LVCFMT_LEFT, 60);
168 m_list.InsertColumn(COL_CHARSET, _T("CharSet"), LVCFMT_CENTER, 20);
169 m_list.InsertColumn(COL_UNICODE, _T("Unicode"), LVCFMT_CENTER, 40);
170 m_list.InsertColumn(COL_LAYER, _T("Layer"), LVCFMT_CENTER, 50);
171 m_list.InsertColumn(COL_ACTOR, _T("Actor"), LVCFMT_LEFT, 80);
172 m_list.InsertColumn(COL_EFFECT, _T("Effect"), LVCFMT_LEFT, 80);
175 m_subtimes.SetCount(m_sts.GetCount());
177 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
179 m_subtimes[i].orgstart = m_sts[i].start;
180 m_subtimes[i].orgend = m_sts[i].end;
183 ResetSubtitle();
186 void CPlayerSubresyncBar::ResetSubtitle()
188 m_list.DeleteAllItems();
190 if(m_mode == VOBSUB || m_mode == TEXTSUB)
192 TCHAR buff[32];
194 int prevstart = INT_MIN;
196 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
198 m_subtimes[i].newstart = m_subtimes[i].orgstart;
199 m_subtimes[i].newend = m_subtimes[i].orgend;
201 FormatTime(i, buff, 0, false);
202 m_list.InsertItem(i, buff, COL_START);
203 FormatTime(i, buff, 0, true);
204 m_list.SetItemText(i, COL_END, buff);
206 if(prevstart > m_subtimes[i].orgstart) m_list.SetItemData(i, TSEP);
207 prevstart = m_subtimes[i].orgstart;
209 SetCheck(i, false, false);
212 UpdatePreview();
214 m_list.SetColumnWidth(COL_START, LVSCW_AUTOSIZE);
215 m_list.SetColumnWidth(COL_PREVSTART, LVSCW_AUTOSIZE);
218 UpdateStrings();
221 void CPlayerSubresyncBar::SaveSubtitle()
223 CMainFrame* pFrame = ((CMainFrame*)AfxGetMainWnd());
224 if(!pFrame) return;
226 CLSID clsid;
227 m_pSubStream->GetClassID(&clsid);
229 if(clsid == __uuidof(CVobSubFile) && m_mode == VOBSUB)
231 CVobSubFile* pVSF = (CVobSubFile*)(ISubStream*)m_pSubStream;
233 CAutoLock cAutoLock(m_pSubLock);
235 CAtlArray<CVobSubFile::SubPos>& sp = pVSF->m_langs[pVSF->m_iLang].subpos;
237 for(int i = 0, j = sp.GetCount(); i < j; i++)
239 sp[i].fValid = false;
242 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
244 int vobid, cellid, forced, spnum, c;
245 if(_stscanf(m_sts.GetStr(i), _T("%d%c%d%c%d%c%d"), &vobid, &c, &cellid, &c, &forced, &c, &spnum) != 7) continue;
246 sp[spnum].start = m_sts[i].start;
247 sp[spnum].stop = m_sts[i].end;
248 sp[spnum].fValid = true;
251 else if(clsid == __uuidof(CRenderedTextSubtitle) && m_mode == TEXTSUB)
253 CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)m_pSubStream;
255 CAutoLock cAutoLock(m_pSubLock);
257 pRTS->Copy(m_sts);
259 else
261 return;
264 pFrame->InvalidateSubtitle();
267 void CPlayerSubresyncBar::UpdatePreview()
269 if(m_mode == VOBSUB || m_mode == TEXTSUB)
271 if(0/*m_fUnlink*/)
273 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
275 bool fStartMod, fEndMod, fStartAdj, fEndAdj;
276 GetCheck(i, fStartMod, fEndMod, fStartAdj, fEndAdj);
277 m_sts[i].start = (fStartMod||fStartAdj) ? m_subtimes[i].newstart : m_subtimes[i].orgstart;
278 m_sts[i].end = (fEndMod||fEndAdj) ? m_subtimes[i].newend : m_subtimes[i].orgend;
281 else
283 CAtlArray<int> schk;
285 for(int i = 0, j = m_sts.GetCount(); i < j;)
287 schk.RemoveAll();
289 int start = i, end;
291 for(end = i; end < j; end++)
293 int data = (int)m_list.GetItemData(end);
294 if((data&TSEP) && end > i) break;
295 if(data&(TSMOD|TSADJ))
296 schk.Add(end);
299 if(schk.GetCount() == 0)
301 for(; start < end; start++)
303 m_sts[start].start = m_subtimes[start].orgstart;
304 m_sts[start].end = m_subtimes[start].orgend;
307 else if(schk.GetCount() == 1)
309 int k = schk[0];
310 int dt = m_subtimes[k].newstart - m_subtimes[k].orgstart;
311 for(; start < end; start++)
313 m_sts[start].start = m_subtimes[start].orgstart + dt;
314 m_sts[start].end = (m_list.GetItemData(start)&TEMOD)
315 ? m_subtimes[start].newend
316 : (m_subtimes[start].orgend + dt);
319 else if(schk.GetCount() >= 2)
321 int i0, i1, ti0, ds;
322 double m = 0;
324 for(int k = 0, l = schk.GetCount()-1; k < l; k++)
326 i0 = schk[k];
327 i1 = schk[k+1];
329 ti0 = m_subtimes[i0].orgstart;
330 ds = m_subtimes[i1].orgstart - ti0;
332 if(ds == 0)
334 for(; start < i1; start++)
336 m_sts[start].start = ti0;
337 m_sts[start].end = (m_list.GetItemData(start)&TEMOD)
338 ? m_subtimes[start].newend
339 : (ti0 + m_subtimes[start].orgend - m_subtimes[start].orgstart);
342 else
344 m = double(m_subtimes[i1].newstart - m_subtimes[i0].newstart) / ds;
346 for(; start < i1; start++)
348 m_sts[start].start = int((m_subtimes[start].orgstart - ti0)*m + m_subtimes[i0].newstart);
349 m_sts[start].end = (m_list.GetItemData(start)&TEMOD)
350 ? m_subtimes[start].newend
351 : m_mode == VOBSUB
352 ? (m_sts[start].start + m_subtimes[start].orgend - m_subtimes[start].orgstart)
353 : (m_sts[start].start + int((m_subtimes[start].orgend - m_subtimes[start].orgstart)*m));
358 if(ds == 0)
360 for(; start < end; start++)
362 m_sts[start].start = ti0;
363 m_sts[start].end = (m_list.GetItemData(start)&TEMOD)
364 ? m_subtimes[start].newend
365 : (ti0 + (m_subtimes[start].orgend - m_subtimes[start].orgstart));
368 else
370 for(; start < end; start++)
372 m_sts[start].start = int((m_subtimes[start].orgstart - ti0)*m + m_subtimes[i0].newstart);
373 m_sts[start].end = (m_list.GetItemData(start)&TEMOD)
374 ? m_subtimes[start].newend
375 : m_mode == VOBSUB
376 ? (m_sts[start].start + m_subtimes[start].orgend - m_subtimes[start].orgstart)
377 : (m_sts[start].start + int((m_subtimes[start].orgend - m_subtimes[start].orgstart)*m));
382 i = end;
386 m_sts.CreateSegments();
388 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
390 TCHAR buff[32];
391 FormatTime(i, buff, 2, false);
392 m_list.SetItemText(i, COL_PREVSTART, buff);
393 FormatTime(i, buff, 2, true);
394 m_list.SetItemText(i, COL_PREVEND, buff);
397 if(IsWindowVisible())
399 SaveSubtitle();
404 void CPlayerSubresyncBar::UpdateStrings()
406 CString str;
408 if(m_mode == TEXTSUB)
410 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
412 STSStyle stss;
413 m_sts.GetStyle(i, stss);
415 m_list.SetItemText(i, COL_TEXT, m_sts.GetStr(i, true));
416 m_list.SetItemText(i, COL_STYLE, m_sts[i].style);
417 m_list.SetItemText(i, COL_FONT, stss.fontName);
418 str.Format(_T("%d"), stss.charSet);
419 m_list.SetItemText(i, COL_CHARSET, str);
420 m_list.SetItemText(i, COL_UNICODE, m_sts.IsEntryUnicode(i) ? _T("yes") : _T("no"));
421 str.Format(_T("%d"), m_sts[i].layer);
422 m_list.SetItemText(i, COL_LAYER, str);
423 m_list.SetItemText(i, COL_ACTOR, m_sts[i].actor);
424 m_list.SetItemText(i, COL_EFFECT, m_sts[i].effect);
427 else if(m_mode == VOBSUB)
429 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
431 int vobid, cellid, forced, c;
432 if(_stscanf(m_sts.GetStr(i), _T("%d%c%d%c%d"), &vobid, &c, &cellid, &c, &forced) != 5) continue;
433 if(vobid < 0) str = _T("-");
434 else str.Format(_T("%d"), vobid);
435 m_list.SetItemText(i, COL_VOBID, str);
436 if(cellid < 0) str = _T("-");
437 else str.Format(_T("%d"), cellid);
438 m_list.SetItemText(i, COL_CELLID, str);
439 str = forced?_T("Yes"):_T("");
440 m_list.SetItemText(i, COL_FORCED, str);
445 void CPlayerSubresyncBar::GetCheck(int iItem, bool& fStartMod, bool& fEndMod, bool& fStartAdj, bool& fEndAdj)
447 if(0 <= iItem && iItem < m_sts.GetCount())
449 int nCheck = (int)m_list.GetItemData(iItem);
450 fStartMod = !!(nCheck&TSMOD);
451 fEndMod = !!(nCheck&TEMOD);
452 fStartAdj = !!(nCheck&TSADJ);
453 fEndAdj = !!(nCheck&TEADJ);
457 void CPlayerSubresyncBar::SetCheck(int iItem, bool fStart, bool fEnd)
459 if(0 <= iItem && iItem < m_sts.GetCount())
461 SubTime& st = m_subtimes[iItem];
463 int nCheck = (int)m_list.GetItemData(iItem) & TSEP;
465 if(fStart) nCheck |= TSMOD;
466 else if(abs(st.orgstart-st.newstart)) nCheck |= TSADJ;
467 if(fEnd) nCheck |= TEMOD;
468 else if(abs(st.orgend-st.newend)) nCheck |= TEADJ;
470 m_list.SetItemData(iItem, (DWORD)nCheck);
472 TCHAR buff[32];
473 FormatTime(iItem, buff, fStart, false);
474 m_list.SetItemText(iItem, COL_START, buff);
475 FormatTime(iItem, buff, fEnd, true);
476 m_list.SetItemText(iItem, COL_END, buff);
480 bool CPlayerSubresyncBar::ModStart(int iItem, int t, bool fReset)
482 bool fRet = false;
484 bool fStartMod, fEndMod, fStartAdj, fEndAdj;
485 GetCheck(iItem, fStartMod, fEndMod, fStartAdj, fEndAdj);
487 SubTime& st = m_subtimes[iItem];
489 // if(fStartMod || fStartAdj || st.orgstart != t || fReset)
491 fRet = (st.newstart != t);
493 st.newstart = t;
494 if(!fEndMod) st.newend = st.newstart + (st.orgend - st.orgstart);
495 else if(fReset) st.newstart = st.newend - (st.orgend - st.orgstart);
497 SetCheck(iItem, !fReset, fEndMod);
500 return(fRet);
503 bool CPlayerSubresyncBar::ModEnd(int iItem, int t, bool fReset)
505 bool fRet = false;
507 bool fStartMod, fEndMod, fStartAdj, fEndAdj;
508 GetCheck(iItem, fStartMod, fEndMod, fStartAdj, fEndAdj);
510 SubTime& st = m_subtimes[iItem];
512 // if(fEndMod || fEndAdj || st.orgend != t || fReset)
514 fRet = (st.newend != t);
516 st.newend = t;
517 if(!fStartMod) st.newstart = st.newend - (st.orgend - st.orgstart);
518 else if(fReset) st.newend = st.newstart + (st.orgend - st.orgstart);
520 SetCheck(iItem, fStartMod, !fReset);
523 return(fRet);
526 void CPlayerSubresyncBar::FormatTime(int iItem, TCHAR* buff, int time, bool fEnd)
528 int t = !fEnd
529 ?(time == 2 ? m_sts[iItem].start
530 : time == 1 ? m_subtimes[iItem].newstart
531 : m_subtimes[iItem].orgstart)
532 : (time == 2 ? m_sts[iItem].end
533 : time == 1 ? m_subtimes[iItem].newend
534 : m_subtimes[iItem].orgend);
536 _stprintf(buff, t >= 0
537 ? _T("%02d:%02d:%02d.%03d")
538 : _T("-%02d:%02d:%02d.%03d"),
539 abs(t)/60/60/1000,
540 (abs(t)/60/1000)%60,
541 (abs(t)/1000)%60,
542 abs(t)%1000);
546 BEGIN_MESSAGE_MAP(CPlayerSubresyncBar, CSizingControlBarG)
547 ON_WM_SIZE()
548 ON_NOTIFY(LVN_BEGINLABELEDIT, IDC_SUBRESYNCLIST, OnBeginlabeleditList)
549 ON_NOTIFY(LVN_DOLABELEDIT, IDC_SUBRESYNCLIST, OnDolabeleditList)
550 ON_NOTIFY(LVN_ENDLABELEDIT, IDC_SUBRESYNCLIST, OnEndlabeleditList)
551 ON_NOTIFY(NM_RCLICK, IDC_SUBRESYNCLIST, OnRclickList)
552 ON_NOTIFY(NM_DBLCLK, IDC_SUBRESYNCLIST, OnNMDblclkList)
553 ON_NOTIFY(LVN_KEYDOWN, IDC_SUBRESYNCLIST, OnLvnKeydownList)
554 ON_NOTIFY(NM_CUSTOMDRAW, IDC_SUBRESYNCLIST, OnCustomdrawList)
555 END_MESSAGE_MAP()
558 // CPlayerSubresyncBar message handlers
560 void CPlayerSubresyncBar::OnSize(UINT nType, int cx, int cy)
562 CSizingControlBarG::OnSize(nType, cx, cy);
564 if(::IsWindow(m_list.m_hWnd))
566 CRect r;
567 GetClientRect(r);
568 r.DeflateRect(2, 2);
569 m_list.MoveWindow(r);
573 static bool ParseTime(CString str, int& ret, bool fWarn = true)
575 int sign = 1, h, m, s, ms;
576 TCHAR c;
578 str.Trim();
579 if(str.GetLength() > 0 && str[0] == '-') sign = -1;
581 int n = _stscanf(str, _T("%d%c%d%c%d%c%d"), &h, &c, &m, &c, &s, &c, &ms);
583 h = abs(h);
585 if(n == 7
586 && 0 <= h && h < 24
587 && 0 <= m && m < 60
588 && 0 <= s && s < 60
589 && 0 <= ms && ms < 1000)
591 ret = sign*(h*60*60*1000+m*60*1000+s*1000+ms);
592 return(true);
595 if(fWarn) AfxMessageBox(_T("The correct time format is [-]hh:mm:ss.ms\n(e.g. 01:23:45.678)"));
596 return(false);
599 void CPlayerSubresyncBar::OnBeginlabeleditList(NMHDR* pNMHDR, LRESULT* pResult)
601 LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
602 LV_ITEM* pItem = &pDispInfo->item;
604 *pResult = FALSE;
606 if(pItem->iItem >= 0)
608 if((pItem->iSubItem == COL_START || pItem->iSubItem == COL_END || pItem->iSubItem == COL_TEXT
609 || pItem->iSubItem == COL_STYLE || pItem->iSubItem == COL_LAYER
610 || pItem->iSubItem == COL_ACTOR || pItem->iSubItem == COL_EFFECT)
611 && m_mode == TEXTSUB)
613 *pResult = TRUE;
615 else if((pItem->iSubItem == COL_START)
616 && m_mode == VOBSUB)
618 *pResult = TRUE;
623 void CPlayerSubresyncBar::OnDolabeleditList(NMHDR* pNMHDR, LRESULT* pResult)
625 LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
626 LV_ITEM* pItem = &pDispInfo->item;
628 *pResult = FALSE;
630 if(pItem->iItem >= 0)
632 if((pItem->iSubItem == COL_START || pItem->iSubItem == COL_END || pItem->iSubItem == COL_TEXT
633 || pItem->iSubItem == COL_STYLE || pItem->iSubItem == COL_LAYER
634 || pItem->iSubItem == COL_ACTOR || pItem->iSubItem == COL_EFFECT)
635 && m_mode == TEXTSUB)
637 m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem);
638 *pResult = TRUE;
640 else if((pItem->iSubItem == COL_START)
641 && m_mode == VOBSUB)
643 m_list.ShowInPlaceEdit(pItem->iItem, pItem->iSubItem);
644 *pResult = TRUE;
649 void CPlayerSubresyncBar::OnEndlabeleditList(NMHDR* pNMHDR, LRESULT* pResult)
651 LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
652 LV_ITEM* pItem = &pDispInfo->item;
654 *pResult = FALSE;
656 if(!m_list.m_fInPlaceDirty)
657 return;
659 bool fNeedsUpdate = false;
661 if(pItem->iItem >= 0 && pItem->pszText && (m_mode == VOBSUB || m_mode == TEXTSUB))
663 if(pItem->iSubItem == COL_START)
665 int t;
666 if(ParseTime(pItem->pszText, t))
668 fNeedsUpdate = ModStart(pItem->iItem, t);
670 *pResult = TRUE;
673 else if(pItem->iSubItem == COL_END && m_mode == TEXTSUB)
675 int t;
676 if(ParseTime(pItem->pszText, t))
678 fNeedsUpdate = ModEnd(pItem->iItem, t);
680 *pResult = TRUE;
683 else if(pItem->iSubItem == COL_TEXT && m_mode == TEXTSUB)
685 CString str = m_sts.GetStr(pItem->iItem, true);
687 if(str != pItem->pszText)
689 fNeedsUpdate = true;
690 m_sts.SetStr(pItem->iItem, CString(pItem->pszText), true);
691 m_list.SetItemText(pItem->iItem, pItem->iSubItem, m_sts.GetStr(pItem->iItem, true));
694 else if(pItem->iSubItem == COL_STYLE && m_mode == TEXTSUB)
696 CString str(pItem->pszText);
697 str.Trim();
699 if(!str.IsEmpty() && m_sts[pItem->iItem].style != str)
701 fNeedsUpdate = true;
703 if(!m_sts.m_styles.Lookup(str))
704 m_sts.AddStyle(str, new STSStyle());
706 m_sts[pItem->iItem].style = str;
708 m_list.SetItemText(pItem->iItem, pItem->iSubItem, pItem->pszText);
711 else if(pItem->iSubItem == COL_LAYER && m_mode == TEXTSUB)
713 int l;
714 if(_stscanf(pItem->pszText, _T("%d"), &l) == 1)
716 fNeedsUpdate = true;
717 m_sts[pItem->iItem].layer = l;
718 CString str;
719 str.Format(_T("%d"), l);
720 m_list.SetItemText(pItem->iItem, pItem->iSubItem, str);
723 else if(pItem->iSubItem == COL_ACTOR && m_mode == TEXTSUB)
725 CString str(pItem->pszText);
726 str.Trim();
727 if(!str.IsEmpty())
729 fNeedsUpdate = true;
730 m_sts[pItem->iItem].actor = str;
731 m_list.SetItemText(pItem->iItem, pItem->iSubItem, str);
734 else if(pItem->iSubItem == COL_EFFECT && m_mode == TEXTSUB)
736 CString str(pItem->pszText);
737 str.Trim();
738 if(!str.IsEmpty())
740 fNeedsUpdate = true;
741 m_sts[pItem->iItem].effect = str;
742 m_list.SetItemText(pItem->iItem, pItem->iSubItem, str);
747 if(fNeedsUpdate)
749 UpdatePreview();
753 static int uintcomp(const void* i1, const void* i2)
755 return(*((UINT*)i2) - *((UINT*)i1));
758 void CPlayerSubresyncBar::OnRclickList(NMHDR* pNMHDR, LRESULT* pResult)
760 LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR;
762 if(lpnmlv->iItem >= 0 && lpnmlv->iSubItem >= 0)
764 enum
766 TOGSEP=1,
767 DUPITEM, DELITEM,
768 RESETS, SETOS, SETCS, RESETE, SETOE, SETCE,
769 STYLEFIRST, STYLELAST=STYLEFIRST+1000, STYLEEDIT,
770 UNICODEYES, UNICODENO,
771 LAYERDEC, LAYERINC,
772 ACTORFIRST, ACTORLAST=ACTORFIRST+1000,
773 EFFECTFIRST, EFFECTLAST=EFFECTFIRST+1000
776 CStringArray styles;
777 CStringArray actors;
778 CStringArray effects;
780 CMenu m;
781 m.CreatePopupMenu();
783 if(m_mode == VOBSUB || m_mode == TEXTSUB)
785 m.AppendMenu(MF_STRING|MF_ENABLED, TOGSEP, ResStr(IDS_SUBRESYNC_SEPARATOR));
786 m.AppendMenu(MF_SEPARATOR);
787 if(m_mode == TEXTSUB) m.AppendMenu(MF_STRING|MF_ENABLED, DUPITEM, ResStr(IDS_SUBRESYNC_DUPLICATE));
788 m.AppendMenu(MF_STRING|MF_ENABLED, DELITEM, ResStr(IDS_SUBRESYNC_DELETE));
791 if(lpnmlv->iSubItem == COL_START && (m_mode == VOBSUB || m_mode == TEXTSUB))
793 m.AppendMenu(MF_SEPARATOR);
794 m.AppendMenu(MF_STRING|MF_ENABLED, RESETS, ResStr(IDS_SUBRESYNC_RESET) + _T("\tF1"));
795 m.AppendMenu(MF_STRING|MF_ENABLED, SETOS, ResStr(IDS_SUBRESYNC_ORIGINAL) + _T("\tF3"));
796 m.AppendMenu(MF_STRING|MF_ENABLED, SETCS, ResStr(IDS_SUBRESYNC_CURRENT) + _T("\tF5"));
798 else if(lpnmlv->iSubItem == COL_END && m_mode == TEXTSUB)
800 m.AppendMenu(MF_SEPARATOR);
801 m.AppendMenu(MF_STRING|MF_ENABLED, RESETE, ResStr(IDS_SUBRESYNC_RESET) + _T("\tF2"));
802 m.AppendMenu(MF_STRING|MF_ENABLED, SETOE, ResStr(IDS_SUBRESYNC_ORIGINAL) + _T("\tF4"));
803 m.AppendMenu(MF_STRING|MF_ENABLED, SETCE, ResStr(IDS_SUBRESYNC_CURRENT) + _T("\tF6"));
805 else if(lpnmlv->iSubItem == COL_STYLE && m_mode == TEXTSUB)
807 m.AppendMenu(MF_SEPARATOR);
809 int id = STYLEFIRST;
811 POSITION pos = m_sts.m_styles.GetStartPosition();
812 while(pos && id <= STYLELAST)
814 CString key;
815 STSStyle* val;
816 m_sts.m_styles.GetNextAssoc(pos, key, val);
817 styles.Add(key);
818 m.AppendMenu(MF_STRING|MF_ENABLED, id++, key);
821 if(id > STYLEFIRST && m_list.GetSelectedCount() == 1)
823 m.AppendMenu(MF_SEPARATOR);
824 m.AppendMenu(MF_STRING|MF_ENABLED, STYLEEDIT, ResStr(IDS_SUBRESYNC_EDIT));
827 else if(lpnmlv->iSubItem == COL_UNICODE && m_mode == TEXTSUB)
829 m.AppendMenu(MF_SEPARATOR);
830 m.AppendMenu(MF_STRING|MF_ENABLED, UNICODEYES, ResStr(IDS_SUBRESYNC_YES));
831 m.AppendMenu(MF_STRING|MF_ENABLED, UNICODENO, ResStr(IDS_SUBRESYNC_NO));
833 else if(lpnmlv->iSubItem == COL_LAYER && m_mode == TEXTSUB)
835 m.AppendMenu(MF_SEPARATOR);
836 m.AppendMenu(MF_STRING|MF_ENABLED, LAYERDEC, ResStr(IDS_SUBRESYNC_DECREASE));
837 m.AppendMenu(MF_STRING|MF_ENABLED, LAYERINC, ResStr(IDS_SUBRESYNC_INCREASE));
839 else if(lpnmlv->iSubItem == COL_ACTOR && m_mode == TEXTSUB)
841 CMapStringToPtr actormap;
843 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
844 actormap[m_sts[i].actor] = NULL;
846 actormap.RemoveKey(_T(""));
848 if(actormap.GetCount() > 0)
850 m.AppendMenu(MF_SEPARATOR);
852 int id = ACTORFIRST;
854 POSITION pos = actormap.GetStartPosition();
855 while(pos && id <= ACTORLAST)
857 CString key;
858 void* val;
859 actormap.GetNextAssoc(pos, key, val);
861 actors.Add(key);
863 m.AppendMenu(MF_STRING|MF_ENABLED, id++, key);
867 else if(lpnmlv->iSubItem == COL_EFFECT && m_mode == TEXTSUB)
869 CMapStringToPtr effectmap;
871 for(int i = 0, j = m_sts.GetCount(); i < j; i++)
872 effectmap[m_sts[i].effect] = NULL;
874 effectmap.RemoveKey(_T(""));
876 if(effectmap.GetCount() > 0)
878 m.AppendMenu(MF_SEPARATOR);
880 int id = EFFECTFIRST;
882 POSITION pos = effectmap.GetStartPosition();
883 while(pos && id <= EFFECTLAST)
885 CString key;
886 void* val;
887 effectmap.GetNextAssoc(pos, key, val);
889 effects.Add(key);
891 m.AppendMenu(MF_STRING|MF_ENABLED, id++, key);
896 CPoint p = lpnmlv->ptAction;
897 ::MapWindowPoints(pNMHDR->hwndFrom, HWND_DESKTOP, &p, 1);
899 UINT id = m.TrackPopupMenu(TPM_LEFTBUTTON|TPM_RETURNCMD, p.x, p.y, this);
901 bool fNeedsUpdate = false;
903 POSITION pos = m_list.GetFirstSelectedItemPosition();
904 while(pos)
906 int iItem = m_list.GetNextSelectedItem(pos);
908 SubTime& st = m_subtimes[iItem];
910 switch(id)
912 case TOGSEP:
913 m_list.SetItemData(iItem, m_list.GetItemData(iItem)^TSEP);
914 m_list.Invalidate();
915 fNeedsUpdate = true;
916 break;
917 case DUPITEM:
919 CUIntArray items;
920 pos = m_list.GetFirstSelectedItemPosition();
921 while(pos) items.Add(m_list.GetNextSelectedItem(pos));
923 qsort(items.GetData(), items.GetCount(), sizeof(UINT), uintcomp);
925 for(int i = 0; i < items.GetCount(); i++)
927 iItem = items[i];
929 STSEntry stse = m_sts[iItem];
930 m_sts.InsertAt(iItem+1, stse);
932 SubTime st = m_subtimes[iItem];
933 m_subtimes.InsertAt(iItem+1, st);
935 CHeaderCtrl* pHeader = (CHeaderCtrl*)m_list.GetDlgItem(0);
936 int nColumnCount = pHeader->GetItemCount();
938 CStringArray sa;
939 sa.SetSize(nColumnCount);
940 for(int col = 0; col < nColumnCount; col++)
941 sa[col] = m_list.GetItemText(iItem, col);
943 DWORD data = m_list.GetItemData(iItem);
944 m_list.InsertItem(iItem+1, sa[0]);
945 m_list.SetItemData(iItem+1, data);
946 for(int col = 1; col < nColumnCount; col++)
947 m_list.SetItemText(iItem+1, col, sa[col]);
951 fNeedsUpdate = true;
952 break;
953 case DELITEM:
955 CUIntArray items;
956 pos = m_list.GetFirstSelectedItemPosition();
957 while(pos) items.Add(m_list.GetNextSelectedItem(pos));
959 qsort(items.GetData(), items.GetCount(), sizeof(UINT), uintcomp);
961 for(int i = 0; i < items.GetCount(); i++)
963 iItem = items[i];
964 m_sts.RemoveAt(iItem);
965 m_subtimes.RemoveAt(iItem);
966 m_list.DeleteItem(iItem);
969 iItem = items[items.GetCount()-1];
970 if(iItem >= m_list.GetItemCount()) iItem = m_list.GetItemCount()-1;
972 m_list.SetSelectionMark(iItem);
974 fNeedsUpdate = true;
975 break;
976 case RESETS: /*if(*/ModStart(iItem, st.orgstart, true);/*)*/ fNeedsUpdate = true; break;
977 case SETOS: /*if(*/ModStart(iItem, st.orgstart);/*)*/ fNeedsUpdate = true; break;
978 case SETCS: /*if(*/ModStart(iItem, (int)(m_rt/10000));/*)*/ fNeedsUpdate = true; break;
979 case RESETE: /*if(*/ModEnd(iItem, st.orgend, true);/*)*/ fNeedsUpdate = true; break;
980 case SETOE: /*if(*/ModEnd(iItem, st.orgend);/*)*/ fNeedsUpdate = true; break;
981 case SETCE: /*if(*/ModEnd(iItem, (int)(m_rt/10000));/*)*/ fNeedsUpdate = true; break;
982 default:
983 if(STYLEFIRST <= id && id <= STYLELAST)
985 CString s = styles[id - STYLEFIRST];
986 if(m_sts[iItem].style != s) fNeedsUpdate = true;
987 m_sts[iItem].style = s;
988 m_list.SetItemText(iItem, lpnmlv->iSubItem, s);
990 else if(id == STYLEEDIT)
992 CAutoPtrArray<CPPageSubStyle> pages;
993 CAtlArray<STSStyle*> styles;
995 STSStyle* stss = m_sts.GetStyle(iItem);
996 int iSelPage = 0;
998 POSITION pos = m_sts.m_styles.GetStartPosition();
999 for(int i = 0; pos; i++)
1001 CString key;
1002 STSStyle* val;
1003 m_sts.m_styles.GetNextAssoc(pos, key, val);
1005 CAutoPtr<CPPageSubStyle> page(new CPPageSubStyle());
1006 page->InitStyle(key, *val);
1007 pages.Add(page);
1008 styles.Add(val);
1010 if(stss == val)
1011 iSelPage = i;
1014 CPropertySheet dlg(_T("Styles..."), this, iSelPage);
1015 for(int i = 0; i < (int)pages.GetCount(); i++) dlg.AddPage(pages[i]);
1017 if(dlg.DoModal() == IDOK)
1019 for(int j = 0; j < (int)pages.GetCount(); j++)
1021 stss = styles[j];
1022 pages[j]->GetStyle(*stss);
1024 for(int i = 0; i < m_sts.GetCount(); i++)
1026 if(m_sts.GetStyle(i) == stss)
1028 CString str;
1029 m_list.SetItemText(i, COL_TEXT, m_sts.GetStr(i, true));
1030 m_list.SetItemText(i, COL_FONT, stss->fontName);
1031 str.Format(_T("%d"), stss->charSet);
1032 m_list.SetItemText(i, COL_CHARSET, str);
1033 str.Format(_T("%d"), m_sts[i].layer);
1038 fNeedsUpdate = true;
1041 else if(id == UNICODEYES || id == UNICODENO)
1043 m_sts.ConvertUnicode(iItem, id == UNICODEYES);
1044 m_list.SetItemText(iItem, COL_TEXT, m_sts.GetStr(iItem, true));
1045 m_list.SetItemText(iItem, COL_UNICODE, m_sts.IsEntryUnicode(iItem) ? _T("yes") : _T("no"));
1046 fNeedsUpdate = true;
1048 else if(id == LAYERDEC || id == LAYERINC)
1050 int d = (id == LAYERDEC) ? -1 : (id == LAYERINC) ? +1 : 0;
1051 if(d != 0) fNeedsUpdate = true;
1052 m_sts[iItem].layer += d;
1053 CString s;
1054 s.Format(_T("%d"), m_sts[iItem].layer);
1055 m_list.SetItemText(iItem, lpnmlv->iSubItem, s);
1057 else if(ACTORFIRST <= id && id <= ACTORLAST)
1059 CString s = actors[id - ACTORFIRST];
1060 if(m_sts[iItem].actor != s) fNeedsUpdate = true;
1061 m_sts[iItem].actor = s;
1062 m_list.SetItemText(iItem, lpnmlv->iSubItem, s);
1064 else if(EFFECTFIRST <= id && id <= EFFECTLAST)
1066 CString s = effects[id - EFFECTFIRST];
1067 if(m_sts[iItem].effect != s) fNeedsUpdate = true;
1068 m_sts[iItem].effect = s;
1069 m_list.SetItemText(iItem, lpnmlv->iSubItem, s);
1071 break;
1075 if(fNeedsUpdate)
1077 UpdatePreview();
1081 *pResult = 0;
1084 void CPlayerSubresyncBar::OnNMDblclkList(NMHDR* pNMHDR, LRESULT* pResult)
1086 LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)pNMHDR;
1088 if(lpnmlv->iItem >= 0 && lpnmlv->iSubItem >= 0 && (m_mode == VOBSUB || m_mode == TEXTSUB))
1090 if(CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd())
1092 int t = 0;
1093 if(!ParseTime(m_list.GetItemText(lpnmlv->iItem, lpnmlv->iSubItem), t, false))
1094 t = m_sts[lpnmlv->iItem].start;
1096 REFERENCE_TIME rt =
1097 lpnmlv->iSubItem == COL_START ? ((REFERENCE_TIME)t*10000) :
1098 lpnmlv->iSubItem == COL_END ? ((REFERENCE_TIME)t*10000) :
1099 lpnmlv->iSubItem == COL_PREVSTART ? ((REFERENCE_TIME)t*10000) :
1100 lpnmlv->iSubItem == COL_PREVEND ? ((REFERENCE_TIME)t*10000) :
1101 ((REFERENCE_TIME)t*10000);
1103 pFrame->SeekTo(rt);
1107 *pResult = 0;
1110 void CPlayerSubresyncBar::OnLvnKeydownList(NMHDR* pNMHDR, LRESULT* pResult)
1112 LPNMLVKEYDOWN pLVKeyDown = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);
1114 *pResult = 0;
1117 static CUIntArray m_itemGroups;
1118 static int m_totalGroups;
1120 void CPlayerSubresyncBar::OnCustomdrawList(NMHDR* pNMHDR, LRESULT* pResult)
1122 NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
1124 *pResult = CDRF_DODEFAULT;
1126 if(CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage)
1128 m_itemGroups.SetSize(m_list.GetItemCount());
1129 m_totalGroups = 0;
1130 for(int i = 0, j = m_list.GetItemCount(); i < j; i++)
1132 if(m_list.GetItemData(i)&TSEP) m_totalGroups++;
1133 m_itemGroups[i] = m_totalGroups;
1136 *pResult = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYITEMDRAW;
1138 else if(CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage)
1140 pLVCD->nmcd.uItemState &= ~CDIS_FOCUS;
1142 *pResult = CDRF_NOTIFYPOSTPAINT|CDRF_NOTIFYSUBITEMDRAW;
1144 else if((CDDS_ITEMPREPAINT|CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage)
1146 COLORREF clrText;
1147 COLORREF clrTextBk;
1149 if((pLVCD->iSubItem == COL_START || pLVCD->iSubItem == COL_END || pLVCD->iSubItem == COL_TEXT || pLVCD->iSubItem == COL_STYLE
1150 || pLVCD->iSubItem == COL_LAYER || pLVCD->iSubItem == COL_ACTOR || pLVCD->iSubItem == COL_EFFECT)
1151 && m_mode == TEXTSUB)
1153 clrText = 0;
1155 else if((pLVCD->iSubItem == COL_START)
1156 && m_mode == VOBSUB)
1158 clrText = 0;
1160 else
1162 clrText = 0x606060;
1165 clrTextBk = 0xffffff;
1166 // if(m_totalGroups > 0)
1167 clrTextBk -= ((m_itemGroups[pLVCD->nmcd.dwItemSpec]&1) ? 0x100010 : 0x200020);
1169 if(m_sts[pLVCD->nmcd.dwItemSpec].start <= m_rt/10000 && m_rt/10000 < m_sts[pLVCD->nmcd.dwItemSpec].end)
1171 clrText |= 0xFF;
1174 int nCheck = (int)m_list.GetItemData(pLVCD->nmcd.dwItemSpec);
1176 if((nCheck&1) && (pLVCD->iSubItem == COL_START || pLVCD->iSubItem == COL_PREVSTART))
1178 clrTextBk = 0xffddbb;
1180 else if((nCheck&4) && (/*pLVCD->iSubItem == COL_START ||*/ pLVCD->iSubItem == COL_PREVSTART))
1182 clrTextBk = 0xffeedd;
1185 if((nCheck&2) && (pLVCD->iSubItem == COL_END || pLVCD->iSubItem == COL_PREVEND))
1187 clrTextBk = 0xffddbb;
1189 else if((nCheck&8) && (/*pLVCD->iSubItem == COL_END ||*/ pLVCD->iSubItem == COL_PREVEND))
1191 clrTextBk = 0xffeedd;
1194 pLVCD->clrText = clrText;
1195 pLVCD->clrTextBk = clrTextBk;
1197 *pResult = CDRF_NOTIFYPOSTPAINT;
1199 else if((CDDS_ITEMPOSTPAINT|CDDS_SUBITEM) == pLVCD->nmcd.dwDrawStage)
1201 // *pResult = CDRF_DODEFAULT;
1203 else if(CDDS_ITEMPOSTPAINT == pLVCD->nmcd.dwDrawStage)
1205 int nItem = static_cast<int>(pLVCD->nmcd.dwItemSpec);
1207 LVITEM rItem;
1208 ZeroMemory(&rItem, sizeof(LVITEM));
1209 rItem.mask = LVIF_IMAGE | LVIF_STATE;
1210 rItem.iItem = nItem;
1211 rItem.stateMask = LVIS_SELECTED;
1212 m_list.GetItem(&rItem);
1215 CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
1217 CRect rcItem;
1218 m_list.GetItemRect(nItem, &rcItem, LVIR_BOUNDS);
1221 bool fSeparator = nItem < m_list.GetItemCount()-1 && (m_list.GetItemData(nItem+1)&TSEP);
1222 CPen p(PS_INSIDEFRAME, 1, fSeparator ? 0x404040 : 0xe0e0e0);
1223 CPen* old = pDC->SelectObject(&p);
1224 pDC->MoveTo(CPoint(rcItem.left, rcItem.bottom-1));
1225 pDC->LineTo(CPoint(rcItem.right, rcItem.bottom-1));
1226 pDC->SelectObject(old);
1230 CPen p(PS_INSIDEFRAME, 1, 0xe0e0e0);
1231 CPen* old = pDC->SelectObject(&p);
1233 CHeaderCtrl* pHeader = (CHeaderCtrl*)m_list.GetDlgItem(0);
1234 int nColumnCount = pHeader->GetItemCount();
1236 // Get the column offset
1237 int offset = rcItem.left;
1238 for(int i = 0; i < nColumnCount; i++)
1240 offset += m_list.GetColumnWidth(i);
1241 pDC->MoveTo(CPoint(offset, rcItem.top));
1242 pDC->LineTo(CPoint(offset, rcItem.bottom));
1245 pDC->SelectObject(old);
1248 *pResult = CDRF_SKIPDEFAULT;
1251 else if(CDDS_POSTPAINT == pLVCD->nmcd.dwDrawStage)
1257 bool CPlayerSubresyncBar::IsShortCut(MSG* pMsg)
1259 if(pMsg->message == WM_KEYDOWN && VK_F1 <= pMsg->wParam && pMsg->wParam <= VK_F6)
1261 int iItem = -1;
1263 bool fNeedsUpdate = false;
1264 bool fStep = false;
1266 POSITION pos = m_list.GetFirstSelectedItemPosition();
1267 while(pos)
1269 iItem = m_list.GetNextSelectedItem(pos);
1271 SubTime& st = m_subtimes[iItem];
1273 switch(pMsg->wParam)
1275 case VK_F1: /*if(*/ModStart(iItem, st.orgstart, true);/*)*/ fNeedsUpdate = true; break;
1276 case VK_F3: /*if(*/ModStart(iItem, st.orgstart);/*)*/ fNeedsUpdate = true; break;
1277 case VK_F5: /*if(*/ModStart(iItem, (int)(m_rt/10000));/*)*/ fNeedsUpdate = true; break;
1278 case VK_F2: /*if(*/ModEnd(iItem, st.orgend, true);/*)*/ fNeedsUpdate = true; break;
1279 case VK_F4: /*if(*/ModEnd(iItem, st.orgend);/*)*/ fNeedsUpdate = true; break;
1280 case VK_F6: /*if(*/ModEnd(iItem, (int)(m_rt/10000));/*)*/ fNeedsUpdate = fStep = true; break;
1284 if(fNeedsUpdate)
1286 if(fStep && m_list.GetSelectedCount() == 1 && iItem < m_list.GetItemCount()-1)
1288 m_list.SetItemState(iItem, 0, LVIS_SELECTED);
1289 m_list.SetItemState(iItem+1, LVIS_SELECTED, LVIS_SELECTED);
1290 m_list.SetSelectionMark(iItem+1);
1291 m_list.EnsureVisible(iItem+1, false);
1294 UpdatePreview();
1296 return true;
1300 return false;