#include #include #include #include #include "resource.h" #include "defs.h" HWND HElv; LPLVITEM LpLviElvSelection; /* Most recently selected episode. */ HWND ElvCreate() { LVCOLUMN lvc; LpLviElvSelection = malloc(sizeof(LVITEM)); if (!LpLviElvSelection) return NULL; HElv = LvCreate((HMENU)IDC_EPISODELISTVIEW, 0); lvc.mask = LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; lvc.iSubItem = 0; lvc.pszText = TEXT("#"); lvc.cx = Dpi(42); ListView_InsertColumn(HElv, 0, &lvc); lvc.iSubItem = 1; lvc.pszText = TEXT("/"); lvc.cx = Dpi(20); ListView_InsertColumn(HElv, 1, &lvc); lvc.iSubItem = 1; lvc.pszText = TEXT("Title"); lvc.cx = 500; ListView_InsertColumn(HElv, 2, &lvc); return HElv; } LRESULT ElvHandleNotify(LPARAM lParam) { LPNMLISTVIEW lpNmLv; lpNmLv = (LPNMLISTVIEW)lParam; switch (lpNmLv->hdr.code) { case LVN_ITEMCHANGED: if ((lpNmLv->uChanged & LVIF_STATE) && (lpNmLv->uNewState & LVIS_FOCUSED)) { LpLviElvSelection->iItem = lpNmLv->iItem; LpLviElvSelection->lParam = lpNmLv->lParam; ElvUpdateName(LpLviElvSelection); DlvShowEpisode(lpNmLv->lParam); } break; case NM_CUSTOMDRAW: /* Make unwatched episodes bold. */ { LPNMLVCUSTOMDRAW lpLvCd; lpLvCd = (LPNMLVCUSTOMDRAW)lParam; switch (lpLvCd->nmcd.dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; break; case CDDS_ITEMPREPAINT: { term_t t; extern HFONT HfBold; t = T(1); PI(t,lpLvCd->nmcd.lItemlParam) break; P("track_episodes","watched",1,t) { SelectObject(lpLvCd->nmcd.hdc, HfBold); return CDRF_NEWFONT; } break; } } break; } case NM_DBLCLK: /* Open clicked episode. */ { term_t t; t = T(1); PI(t,LpLviElvSelection->lParam) break; P("local_episodes","open_episode",1,t); break; } case NM_RETURN: /* Open all selected episodes. */ { LVITEM lvi; term_t t; extern HWND HElv; lvi.mask = LVIF_PARAM; lvi.iItem = -1; t = T(1); while ((lvi.iItem = ListView_GetNextItem( HElv, lvi.iItem, LVNI_SELECTED)) != -1) { if (!ListView_GetItem(HElv, &lvi)) goto b; PI(t,lvi.lParam) goto b; P("local_episodes","open_episode",1,t); } b: break; } case NM_RCLICK: { DWORD dwPos; extern HWND HWnd; extern HMENU HPopupMenu; dwPos = GetMessagePos(); TrackPopupMenu(HPopupMenu, TPM_RIGHTBUTTON, LOWORD(dwPos), HIWORD(dwPos), 0, HWnd, NULL); break; } } return 0; } void ElvRedraw() { RedrawWindow(HElv, NULL, NULL, RDW_ERASE|RDW_FRAME|RDW_INVALIDATE|RDW_ALLCHILDREN); } void ElvSetTop(int iItem) { int iLast; iLast = ListView_GetItemCount(HElv)-1; ListView_EnsureVisible(HElv, iLast, TRUE); ListView_EnsureVisible(HElv, iItem, TRUE); } /* Select most recent episode. */ void ElvSelectRecent() { int i, iEpisode, iItem; LVFINDINFO lvfi; term_t t; t = T(1); iItem = 0; P("track_episodes","most_recently_watched",1,t) goto s; GI(t,&iEpisode) return; i = 0; lvfi.flags = LVFI_PARAM; lvfi.lParam = iEpisode; do lvfi.lParam = iEpisode+i; while ((iItem = ListView_FindItem(HElv, -1, &lvfi)) == -1 && i++ < 100); if (iItem == -1) return; s: ListView_SetItemState(HElv, -1, LVIF_STATE, LVIS_SELECTED); ElvSetTop(iItem > 5? iItem-5: 0); ListView_SetItemState(HElv, iItem, LVIS_SELECTED|LVIS_FOCUSED, LVIS_SELECTED|LVIS_FOCUSED); LpLviElvSelection->iItem = iItem; LpLviElvSelection->lParam = iEpisode; ElvUpdateName(LpLviElvSelection); DlvShowEpisode(iEpisode); } /* Update episode list. */ void ElvUpdate() { int i, iEpisode, iEpisodes, iItem, iTopNew; LVITEM lviEpisode, lviTop; LVFINDINFO lvfiTopNew; term_t t; lviEpisode.mask = LVIF_TEXT|LVIF_PARAM; lviTop.iItem = ListView_GetTopIndex(HElv); lviTop.mask = LVIF_PARAM; ListView_GetItem(HElv, &lviTop); SendMessage(HElv, WM_SETREDRAW, FALSE, 0); ListView_DeleteAllItems(HElv); t = T(1); P("episode_data","ensure_episode_data",0,t) return; P("episode_data","episode_count",1,t) return; GI(t,&iEpisodes) return; for (iItem = 0, iEpisode = 1; iEpisode <= iEpisodes; iEpisode++) { int cb; TCHAR *tszEpisode; extern int BViewWatched; if (!BViewWatched) { term_t t; t = T(1); PI(t,iEpisode) goto ep; P("track_episodes","watched",1,t) goto ep; continue; } /* Format episode number string. */ ep: cb = 100; tszEpisode = malloc(cb*sizeof(TCHAR)); if (!tszEpisode) continue; _stprintf_s(tszEpisode, cb, TEXT("%d"), iEpisode); /* Insert item. */ lviEpisode.iItem = iItem++; lviEpisode.iSubItem = 0; lviEpisode.pszText = tszEpisode; lviEpisode.lParam = iEpisode; ListView_InsertItem(HElv, &lviEpisode); ElvUpdateName(&lviEpisode); free(tszEpisode); } /* Reset scrolling position (roughly). */ i = 0; lvfiTopNew.flags = LVFI_PARAM; do lvfiTopNew.lParam = lviTop.lParam+i; while ((iTopNew = ListView_FindItem(HElv, -1, &lvfiTopNew)) == -1 && i++ < 100); if (iTopNew != -1) ElvSetTop(iTopNew); /* Reset selection. */ if (LpLviElvSelection) ListView_SetItemState(HElv, LpLviElvSelection->iItem, LVIS_SELECTED, LVIS_SELECTED); SendMessage(HElv, WM_SETREDRAW, TRUE, 0); ElvRedraw(); } /* Update episode name. */ void ElvUpdateName(LPLVITEM lpLvi) { char *szName; int iRating; TCHAR *tszName, tszRating[10]; term_t t, t2; t = T(2); PI(t,lpLvi->lParam) return; P("episode_data","episode_title",2,t) { P("episode_data","fetch_episode_data",0,t) return; P("episode_data","episode_title",2,t) return; } GAC(t+1,&szName) return; tszName = TszFromSz(szName, CP_UTF8); if (tszName) ListView_SetItemText(HElv, lpLvi->iItem, 2, tszName); t2 = T(2); PI(t2,lpLvi->lParam) goto f; P("episode_data","episode_rating",2,t2) { ListView_SetItemText(HElv, lpLvi->iItem, 1, TEXT("")); goto f; } GI(t2+1,&iRating) goto f; _itot(iRating, tszRating, 10); ListView_SetItemText(HElv, lpLvi->iItem, 1, tszRating); f: free(tszName); }