aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-08-10 01:23:05 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-08-10 01:31:39 +0200
commit618f9bcf02ed8291e352cfea09f8f207930d5af4 (patch)
treeffb80b0862e09560fc16a302dc63b1363942b333
parent49e859c0d2bf41fa648e0da45a6d5b114b0d2240 (diff)
downloadEpisodeBrowser-618f9bcf02ed8291e352cfea09f8f207930d5af4.tar.gz
Improve structure.
-rw-r--r--c/episodelistview.cpp47
-rw-r--r--c/main.cpp206
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()
diff --git a/c/main.cpp b/c/main.cpp
index 60504b2..1d5bf7b 100644
--- a/c/main.cpp
+++ b/c/main.cpp
@@ -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()