diff options
-rw-r--r-- | c/episodelistview.cpp | 47 | ||||
-rw-r--r-- | c/main.cpp | 206 |
2 files changed, 148 insertions, 105 deletions
diff --git a/c/episodelistview.cpp b/c/episodelistview.cpp index ec8ab69..3856ce0 100644 --- a/c/episodelistview.cpp +++ b/c/episodelistview.cpp @@ -32,6 +32,7 @@ EpisodeListView::EpisodeListView(const HWND hWndParent) lvc.cx = Dpi(30); ListView_InsertColumn(hWnd, ELVSIRATING, &lvc); + /* Get saved sort-by-column setting. */ if (!Pl("cfg","get_sort",&m_iSortCol)) m_iSortCol = 1; } @@ -39,8 +40,8 @@ EpisodeListView::EpisodeListView(const HWND hWndParent) void EpisodeListView::EnsureFocusVisible() { const int iEpFocus = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED); - if (iEpFocus == -1) return; - ListView_EnsureVisible(hWnd, iEpFocus, TRUE); + if (iEpFocus != -1) + ListView_EnsureVisible(hWnd, iEpFocus, TRUE); } LRESULT EpisodeListView::HandleNotify(const LPARAM lParam) @@ -49,22 +50,26 @@ LRESULT EpisodeListView::HandleNotify(const LPARAM lParam) switch (nm->hdr.code) { case LVN_ITEMCHANGED: /* Select/focus episode. */ - if ((nm->uChanged & LVIF_STATE) && - (nm->uNewState & LVIS_FOCUSED)) { + if ((nm->uChanged & LVIF_STATE) && (nm->uNewState & LVIS_FOCUSED)) { extern DataListView* const g_dlv; UpdateItem(nm->iItem, nm->lParam); g_dlv->ShowEpisode(nm->lParam); } - break; + return 0; + case LVN_COLUMNCLICK: /* Sort by column. */ { - const int iColumn = nm->iSubItem+1; - m_iSortCol = abs(m_iSortCol) == iColumn? -m_iSortCol: iColumn; + const int iCol = nm->iSubItem+1; + + /* The sign of m_iSortCol decides the sort order. */ + m_iSortCol = abs(m_iSortCol) == iCol? -m_iSortCol: iCol; + Pl("cfg","set_sort",m_iSortCol); Sort(); ShowFocus(); - break; + return 0; } + case LVN_KEYDOWN: /* Navigate episodes by keyboard. */ { const NMLVKEYDOWN *const nm = reinterpret_cast<NMLVKEYDOWN*>(lParam); @@ -76,8 +81,9 @@ LRESULT EpisodeListView::HandleNotify(const LPARAM lParam) SelectUnwatched(1); break; } - break; + return 0; } + case NM_CUSTOMDRAW: /* Make unwatched episodes bold. */ { const NMLVCUSTOMDRAW* const nm = reinterpret_cast<NMLVCUSTOMDRAW*>(lParam); @@ -86,45 +92,46 @@ LRESULT EpisodeListView::HandleNotify(const LPARAM lParam) return CDRF_NOTIFYITEMDRAW; break; case CDDS_ITEMPREPAINT: - { - extern HFONT g_hfBold; if (!Pl("track_episodes","watched",nm->nmcd.lItemlParam)) { + extern HFONT g_hfBold; Require(SelectObject(nm->nmcd.hdc, g_hfBold)); return CDRF_NEWFONT; } break; - } } - break; + return 0; } + case NM_DBLCLK: /* Open clicked episode. */ { LVITEM lvi = {LVIF_PARAM, -1}; if (FindNextItem(&lvi, LVNI_FOCUSED)) Pl("local_episodes","open_episode_locally",lvi.lParam) || Pl("local_episodes","open_episode_online",lvi.lParam); - break; + return 0; } + case NM_RETURN: /* Open all selected episodes. */ { LVITEM lvi = {LVIF_PARAM, -1}; while (FindNextItem(&lvi, LVNI_SELECTED)) Pl("local_episodes","open_episode_locally",lvi.lParam) || Pl("local_episodes","open_episode_online",lvi.lParam); - break; + return 0; } + case NM_RCLICK: { extern HMENU g_hMenuPopup; const DWORD pos = GetMessagePos(); Require(TrackPopupMenu(g_hMenuPopup, TPM_RIGHTBUTTON, - LOWORD(pos), HIWORD(pos), 0, - m_hWndParent, nullptr)); - break; + LOWORD(pos), HIWORD(pos), 0, m_hWndParent, nullptr)); + return 0; } - } - return 0; + default: + return 0; + } } void EpisodeListView::Redraw() @@ -197,10 +197,12 @@ void InitializeMainWindow(const HWND hWnd) g_hfNormal = static_cast<HFONT>(Require(GetStockObject(DEFAULT_GUI_FONT))); /* Load bold font. */ - LOGFONT lf; - Require(GetObject(g_hfNormal, sizeof(LOGFONT), &lf)); - lf.lfWeight = FW_BOLD; - g_hfBold = Require(CreateFontIndirect(&lf)); + { + LOGFONT lf; + Require(GetObject(g_hfNormal, sizeof(LOGFONT), &lf)); + lf.lfWeight = FW_BOLD; + g_hfBold = Require(CreateFontIndirect(&lf)); + } /* Load theme functions, if available. */ if (HMODULE hModule = LoadLibrary(L"uxtheme.dll")) { @@ -215,15 +217,17 @@ void InitializeMainWindow(const HWND hWnd) /* Get saved view settings. */ Pl("cfg","get_view_watched",&g_bViewWatched); Pl("cfg","get_view_tv_original",&g_bViewTVOriginal); - - Mark m; - char* s; - if (Pl("cfg","get_limit_screenwriter",&s)) - Strcpy(g_limitScreenwriter, s); - - int dlvHeight = 0; - Pl("cfg","get_dlv_height",&dlvHeight); - g_dlv->SetHeight(dlvHeight); + { + Mark m; + char* s; + if (Pl("cfg","get_limit_screenwriter",&s)) + Strcpy(g_limitScreenwriter, s); + } + { + int dlvHeight = 0; + Pl("cfg","get_dlv_height",&dlvHeight); + g_dlv->SetHeight(dlvHeight); + } /* The global main window handle must only be set AFTER * successful initialization. */ @@ -242,73 +246,85 @@ LRESULT CALLBACK WndProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED, g_bViewWatched? MF_CHECKED: MF_UNCHECKED); CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL, g_bViewTVOriginal? MF_CHECKED: MF_UNCHECKED); CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS, g_limitScreenwriter[0]? MF_UNCHECKED: MF_CHECKED); - break; + return 0; + case WM_CLOSE: DestroyWindow(hWnd); - break; + return 0; + case WM_DESTROY: g_elv->SaveFocus(); PostQuitMessage(0); - break; + return 0; + case WM_SIZE: SendMessage(g_hWndStatus, WM_SIZE, wParam, lParam); UpdateLayout(LOWORD(lParam), HIWORD(lParam)); - break; + return 0; + case WM_GETMINMAXINFO: reinterpret_cast<MINMAXINFO*>(lParam)->ptMinTrackSize.x = Dpi(220); reinterpret_cast<MINMAXINFO*>(lParam)->ptMinTrackSize.y = Dpi(220); - break; + return 0; + case WM_THEMECHANGED: UpdateTheme(); UpdateLayout(); - break; + return 0; + case 0x02E0: /* WM_DPICHANGED */ - { + /* TODO: What does GetSystemMetrics return depending * on the DPI? Do the cached values need to be updated * when the DPI changes? */ + /* Get new DPI. */ g_dpi = HIWORD(wParam); - const RECT* const r = reinterpret_cast<RECT*>(lParam); - Prefer(SetWindowPos(hWnd, nullptr, - r->left, r->top, - r->right-r->left, - r->bottom-r->top, - SWP_NOZORDER|SWP_NOACTIVATE)); - UpdateLayout(r->right-r->left, r->bottom-r->top); - break; - } + + /* Get new window position/size. */ + { + const RECT* const r = reinterpret_cast<RECT*>(lParam); + Prefer(SetWindowPos(hWnd, nullptr, + r->left, r->top, + r->right-r->left, + r->bottom-r->top, + SWP_NOZORDER|SWP_NOACTIVATE)); + UpdateLayout(r->right-r->left, r->bottom-r->top); + } + return 0; + case WM_ACTIVATE: - switch (wParam) { - case WA_INACTIVE: + if (wParam == WA_INACTIVE) g_hWndFocus = GetFocus(); - break; - case WA_ACTIVE: - case WA_CLICKACTIVE: + else { SetFocus(g_hWndFocus); Pl("track_episodes","update_tracked_episodes"); g_elv->Redraw(); } - break; + return 0; + case WM_NOTIFY: switch (reinterpret_cast<NMHDR*>(lParam)->idFrom) { case IDC_EPISODELISTVIEW: return g_elv->HandleNotify(lParam); } - break; + return 0; + case WM_COMMAND: { const WORD command = LOWORD(wParam); switch (ID_GROUP(command)) { case IDG_MENU: HandleMainMenu(hWnd, command); - break; + return 0; case IDG_CTX: HandleContextMenu(hWnd, command); - break; + return 0; + default: + return 0; } - break; } + case WM_MENUSELECT: { /* Look up status bar tip for menu command. The tip @@ -359,25 +375,27 @@ LRESULT CALLBACK WndProc(const HWND hWnd, const UINT uMsg, const WPARAM wParam, tip = vTip[ID_INDEX(command)]; } SendMessage(g_hWndStatus, SB_SETTEXT, MAKEWPARAM(0,0), reinterpret_cast<LPARAM>(tip)); - break; + return 0; } + case WM_LBUTTONDOWN: g_dragDlv.HandleLButtonDown(); - break; + return 0; + case WM_SETCURSOR: - if (!g_dragDlv.HandleSetCursor()) { + if (g_dragDlv.HandleSetCursor()) + return 1; + else { /* Use default cursor. */ if (reinterpret_cast<HWND>(wParam) == hWnd) return DefWindowProc(hWnd, uMsg, wParam, lParam); else return 0; } - return 1; + default: return DefWindowProc(hWnd, uMsg, wParam, lParam); } - - return 0; } void HandleMainMenu(const HWND hWnd, const WORD command) @@ -386,15 +404,19 @@ void HandleMainMenu(const HWND hWnd, const WORD command) case IDM_FILE_EXIT: PostMessage(hWnd, WM_CLOSE, 0, 0); break; + case IDM_FILE_REFRESH: g_elv->Update(); break; + case IDM_FILE_FETCH_DATA: WaitFor("episode_data","update_episode_data"); break; + case IDM_FILE_FETCH_SCREENWRITERS: WaitFor("episode_data","update_screenwriters"); break; + case IDM_FILE_ABOUT: DialogBox( GetModuleHandle(nullptr), @@ -402,6 +424,7 @@ void HandleMainMenu(const HWND hWnd, const WORD command) hWnd, AboutDlgProc); break; + case IDM_VIEW_WATCHED: CheckMenuItem(GetMenu(hWnd), IDM_VIEW_WATCHED, g_bViewWatched? MF_UNCHECKED: MF_CHECKED); g_bViewWatched = !g_bViewWatched; @@ -411,6 +434,7 @@ void HandleMainMenu(const HWND hWnd, const WORD command) /* TODO: Remember last valid focus. In case of * non-existing focus, use the last valid focus. */ break; + case IDM_VIEW_TV_ORIGINAL: CheckMenuItem(GetMenu(hWnd), IDM_VIEW_TV_ORIGINAL, g_bViewTVOriginal? MF_UNCHECKED: MF_CHECKED); g_bViewTVOriginal = !g_bViewTVOriginal; @@ -418,6 +442,7 @@ void HandleMainMenu(const HWND hWnd, const WORD command) g_elv->Update(); g_elv->EnsureFocusVisible(); break; + case IDM_VIEW_OTHERS: if (g_limitScreenwriter[0]) { /* Show episodes by all screenwriters. */ CheckMenuItem(GetMenu(hWnd), IDM_VIEW_OTHERS, MF_CHECKED); @@ -448,56 +473,67 @@ void HandleContextMenu(const HWND, const WORD command) LVITEM lvi = {LVIF_PARAM, -1}; while (g_elv->FindNextItem(&lvi, LVNI_SELECTED)) { - - /* Process rate commands. */ if (ID_SUBGROUP(command) == IDG_CTX_RATE) { + /* Process rate commands. */ Pl("episode_data","rate_episode",lvi.lParam,ID_RATING(command)); g_elv->UpdateItem(lvi.iItem, lvi.lParam); - continue; - } - - /* Process other commands. */ - switch (command) { - case IDM_WATCH_LOCALLY: - if (!Pl("local_episode","open_episode_locally",lvi.lParam)) - cNotFound++; - break; - case IDM_WATCH_ONLINE: - Pl("local_episode","open_episode_online",lvi.lParam); - break; - case IDM_TOGGLE: - Pl("track_episodes","toggle_episode",lvi.lParam); - break; - case IDM_FORGET: - Pl("track_episodes","forget_episode",lvi.lParam); - Pl("track_episodes","update_tracked_episodes"); - break; - case IDM_LOOKUP: - Pl("episode_data","retract_episode",lvi.lParam); - g_elv->UpdateItem(lvi.iItem, lvi.lParam); - g_dlv->ShowEpisode(lvi.lParam); - break; - case IDM_WIKI: - Pl("episode_data","open_episode_wiki",lvi.lParam); - break; + } else { + /* Process other commands. */ + switch (command) { + case IDM_WATCH_LOCALLY: + if (!Pl("local_episode","open_episode_locally",lvi.lParam)) + cNotFound++; + break; + + case IDM_WATCH_ONLINE: + Pl("local_episode","open_episode_online",lvi.lParam); + break; + + case IDM_TOGGLE: + Pl("track_episodes","toggle_episode",lvi.lParam); + break; + + case IDM_FORGET: + Pl("track_episodes","forget_episode",lvi.lParam); + Pl("track_episodes","update_tracked_episodes"); + break; + + case IDM_LOOKUP: + Pl("episode_data","retract_episode",lvi.lParam); + g_elv->UpdateItem(lvi.iItem, lvi.lParam); + g_dlv->ShowEpisode(lvi.lParam); + break; + + case IDM_WIKI: + Pl("episode_data","open_episode_wiki",lvi.lParam); + break; + } } } g_elv->Redraw(); - if (cNotFound == 1) { - EBMessageBox(L"Episode could not be opened locally.", L"Error", MB_ICONWARNING); - } else if (cNotFound) { - wchar_t msg[64] = {0}; - Swprintf(msg, L"%d episodes could not be opened locally.", cNotFound); - EBMessageBox(msg, L"Error", MB_ICONWARNING); - } else if (ID_SUBGROUP(command) == IDG_CTX_RATE) { + + if (ID_SUBGROUP(command) == IDG_CTX_RATE) { + /* If ratings changed, the episodes may need to be resorted. */ g_elv->Sort(); g_elv->ShowFocus(); + } else if (cNotFound) { + /* Show warning if local episodes were not found. */ + if (cNotFound == 1) + EBMessageBox(L"Episode could not be opened locally.", L"Error", MB_ICONWARNING); + else { + wchar_t msg[64] = {0}; + Swprintf(msg, L"%d episodes could not be opened locally.", cNotFound); + EBMessageBox(msg, L"Error", MB_ICONWARNING); + } } } void WaitFor(const char* mod, const char* pred) { + /* WaitFor uses a thread on the Prolog side to execute a + * predicate asynchronously. */ + static WcharPtr activePred; static UINT_PTR iTimer; static atom_t aThread; @@ -546,19 +582,19 @@ INT_PTR CALLBACK AboutDlgProc(const HWND hWnd, const UINT uMsg, const WPARAM wPa switch (uMsg) { case WM_CLOSE: EndDialog(hWnd, IDOK); - break; + return TRUE; + case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: EndDialog(hWnd, IDOK); break; } - break; + return TRUE; + default: return FALSE; } - - return TRUE; } void UpdateTheme() |