diff options
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | c/CMakeLists.txt | 10 | ||||
-rw-r--r-- | c/data.cpp | 44 | ||||
-rw-r--r-- | c/data.h | 5 | ||||
-rw-r--r-- | c/datalistview.cpp | 7 | ||||
-rw-r--r-- | c/debug.cpp | 2 | ||||
-rw-r--r-- | c/drag.cpp (renamed from c/layout.cpp) | 58 | ||||
-rw-r--r-- | c/drag.h (renamed from c/layout.h) | 10 | ||||
-rw-r--r-- | c/episodelistview.cpp | 19 | ||||
-rw-r--r-- | c/ext.cpp | 17 | ||||
-rw-r--r-- | c/ext.h | 8 | ||||
-rw-r--r-- | c/listview.cpp | 8 | ||||
-rw-r--r-- | c/main.cpp | 79 | ||||
-rw-r--r-- | c/test.cpp | 16 | ||||
-rw-r--r-- | c/test.h | 3 | ||||
-rw-r--r-- | c/win32.cpp (renamed from c/win.cpp) | 4 | ||||
-rw-r--r-- | c/win32.h (renamed from c/win.h) | 10 | ||||
-rw-r--r-- | c/window.h | 50 |
18 files changed, 188 insertions, 166 deletions
@@ -26,8 +26,6 @@ episodelistview.cpp,h Defines the interface to the episode list view. datalistview.cpp,h Defines the interface to the data list view. -layout.cpp,h - Handles the placement of child windows. resource.rc Defines menu and dialog window resources. resource.h @@ -43,7 +41,7 @@ data.cpp,h >> Miscellanea << -win.cpp,h +win32.cpp,h Helpers for interacting with the Win32 API. util.h Utility functions. diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt index 35af6ec..cd86f08 100644 --- a/c/CMakeLists.txt +++ b/c/CMakeLists.txt @@ -20,23 +20,23 @@ target_sources(EpisodeBrowser PRIVATE datalistview.h debug.cpp debug.h + drag.cpp + drag.h episodelistview.cpp episodelistview.h ext.cpp ext.h - layout.cpp - layout.h listview.cpp listview.h main.cpp - main.h resource.h resource.rc test.cpp test.h util.h - win.cpp - win.h + win32.cpp + win32.h + window.h ) if (CMAKE_GENERATOR MATCHES "Visual Studio") @@ -5,12 +5,12 @@ #include <libxml/HTMLtree.h> #include <libxml/xpath.h> -#include "resource.h" #include "data.h" #include "episodelistview.h" -#include "main.h" +#include "resource.h" #include "util.h" -#include "win.h" +#include "win32.h" +#include "window.h" UniqueOk<htmlParserCtxtPtr, xmlFreeParserCtxt> RemoteParserCtxt(const wchar_t* wszUrl, const char* szUrl) { @@ -88,9 +88,10 @@ enum Signal : unsigned char ABORT = 1<<2 /* Main -> fetch: exit prematurely! */ }; -void WaitFor(void (*f)(unsigned char*)) +static Window* s_window; + +void WaitFor(Window& window, void (*f)(unsigned char*)) { - extern Window* g_window; static unsigned char sig = READY; static UINT_PTR iTimer = 0; @@ -102,13 +103,13 @@ void WaitFor(void (*f)(unsigned char*)) KillTimer(nullptr, iTimer); i = 0; sig = READY; /* Reset signals. */ - g_window->elv.Update(); /* Reset status bar. */ - EnableMenuItem(GetMenu(g_window->hWnd), IDM_FILE_FETCH_CANCEL, MF_GRAYED); + s_window->elv.Update(); /* Reset status bar. */ + EnableMenuItem(GetMenu(s_window->hWnd), IDM_FILE_FETCH_CANCEL, MF_GRAYED); } else { /* Animate ellipsis in status bar. */ static const wchar_t* text[] = {L".", L"..", L"...", L""}; i = (i+1)%(sizeof(text)/sizeof(*text)); - Status(text[i], 1); + s_window->Status(text[i], 1); } }; @@ -118,7 +119,7 @@ void WaitFor(void (*f)(unsigned char*)) while (!(sig & READY)) Sleep(100); sig = 0; - EnableMenuItem(GetMenu(g_window->hWnd), IDM_FILE_FETCH_CANCEL, MF_ENABLED); + EnableMenuItem(GetMenu(s_window->hWnd), IDM_FILE_FETCH_CANCEL, MF_ENABLED); try { f(&sig); sig |= DONE; @@ -132,7 +133,7 @@ void WaitFor(void (*f)(unsigned char*)) /* Null indicates that any active task should be cancelled. */ if (!f) { sig |= ABORT; - EnableMenuItem(GetMenu(g_window->hWnd), IDM_FILE_FETCH_CANCEL, MF_GRAYED); + EnableMenuItem(GetMenu(s_window->hWnd), IDM_FILE_FETCH_CANCEL, MF_GRAYED); return; } @@ -146,8 +147,9 @@ void WaitFor(void (*f)(unsigned char*)) return; } + s_window = &window; std::thread(procThread, f).detach(); - Status(L".", 1); + s_window->Status(L".", 1); Prefer(iTimer = SetTimer(nullptr, iTimer, 500, procTimer)); } @@ -180,8 +182,6 @@ void FetchData(unsigned char* sig) throw std::runtime_error("could not find remote episode information"); for (int i = 0; i < nodes->nodeNr; i++) { - extern Window* g_window; - if (*sig & ABORT) return; @@ -189,8 +189,8 @@ void FetchData(unsigned char* sig) if (xmlChildElementCount(node) != 8) throw std::runtime_error("unexpected remote data format"); - ElvDataA& e = g_window->fvElv.At(i); - DlvDataA& d = g_window->fvDlv.At(i); + ElvDataA& e = s_window->fvElv.At(i); + DlvDataA& d = s_window->fvDlv.At(i); /* Each datum is contained within a specific cell in * the row. The child element count above ensures that @@ -222,8 +222,6 @@ void FetchData(unsigned char* sig) void FetchScreenwriters(unsigned char* sig) { - extern Window* g_window; - /* Screenwriters are expensive to fetch, so we try to avoid * fetching screenwriters for episodes that already have a * screenwriter. Additionally, in the same session, we don't @@ -231,18 +229,18 @@ void FetchScreenwriters(unsigned char* sig) * already tried to fetch screenwriters. We keep track of * these states using the iLast variable. */ static int iLast = -1; - int iMax = g_window->cfg.cEp-1; + int iMax = s_window->cfg.cEp-1; /* Find the last episode that has a screenwriter. */ if (iLast == -1) - for (size_t i = 0; i < g_window->fvDlv.c; i++) - if (const DlvDataA& d = g_window->fvDlv[i]; !d.date[0]) { + for (size_t i = 0; i < s_window->fvDlv.c; i++) + if (const DlvDataA& d = s_window->fvDlv[i]; !d.date[0]) { iMax = i-1; break; } else if (d.screenwriter[0]) iLast = i; - FINALLY { Status(L""); }; + FINALLY { s_window->Status(L""); }; /* Fetch screenwriters for the rest of the episodes. */ const wchar_t prefix[] = L"https://www.detectiveconanworld.com"; @@ -257,10 +255,10 @@ void FetchScreenwriters(unsigned char* sig) wchar_t msg[48]; Swprintf(msg, L"Fetching screenwriter for episode %d...", iLast+1); - Status(msg); + s_window->Status(msg); /* Retrieve URL for episode's wiki page. */ - DlvDataA& d = g_window->fvDlv[iLast]; + DlvDataA& d = s_window->fvDlv[iLast]; Wcscpy(Buf(url)+Len(prefix), d.wiki); /* Retrieve screenwriter from HTML. */ @@ -6,7 +6,7 @@ #include <libxml/xmlerror.h> #include "util.h" -#include "win.h" +#include "win32.h" struct XmlError : public std::exception { @@ -26,7 +26,8 @@ void FetchData(unsigned char* sig); void FetchScreenwriters(unsigned char* sig); /* Wait for thread. */ -void WaitFor(void (*f)(unsigned char*)); +struct Window; +void WaitFor(Window& window, void (*f)(unsigned char*)); /* The structs ending with A are written as-is to disk. As such, they * should be regarded as immutable. If the format needs to be changed diff --git a/c/datalistview.cpp b/c/datalistview.cpp index cdd8189..92fc05c 100644 --- a/c/datalistview.cpp +++ b/c/datalistview.cpp @@ -3,13 +3,12 @@ #include <windows.h> #include <commctrl.h> -#include "resource.h" #include "data.h" #include "datalistview.h" #include "episodelistview.h" #include "listview.h" -#include "layout.h" -#include "main.h" +#include "resource.h" +#include "window.h" DataListView::DataListView(Window& parent) : ListView(parent, reinterpret_cast<HMENU>(IDC_DATALISTVIEW), LVS_NOCOLUMNHEADER) @@ -81,7 +80,7 @@ void DataListView::ShowEpisode(const int iEpisode) } } - UpdateLayout(); + parent.UpdateLayout(); LVFINDINFO lvfi; lvfi.flags = LVFI_PARAM; diff --git a/c/debug.cpp b/c/debug.cpp index e8a9d6e..3e20d73 100644 --- a/c/debug.cpp +++ b/c/debug.cpp @@ -3,7 +3,7 @@ #include <windows.h> #include "debug.h" -#include "win.h" +#include "win32.h" struct Avg { int id; diff --git a/c/layout.cpp b/c/drag.cpp index e817b23..b92429a 100644 --- a/c/layout.cpp +++ b/c/drag.cpp @@ -1,42 +1,10 @@ #include <windows.h> -#include "episodelistview.h" #include "datalistview.h" -#include "layout.h" -#include "main.h" -#include "win.h" - -extern Window* g_window; -extern HWND g_hWndStatus; - -void UpdateLayout(int w, int h) -{ - if (!g_hWndStatus) return; - - RECT rc, rrStatus; - if (w && h) rc = {0, 0, w, h}; - else Require(GetClientRect(g_window->hWnd, &rc)); - Require(GetRelativeRect(g_hWndStatus, &rrStatus)); - - SendMessageW(g_window->hWnd, WM_SETREDRAW, FALSE, 0); - - /* Resize list views. */ - const long pad = EBIsThemeActive()? Dpi(6): 0; /* Add padding in modern themes. */ - const long cyDlv = rrStatus.top-g_window->dlv.Height()-pad; - Require(SetWindowRect(g_window->dlv.hWnd, pad, cyDlv, rc.right-pad, rrStatus.top-pad)); - Require(SetWindowRect(g_window->elv.hWnd, pad, pad, rc.right-pad, cyDlv-pad)); - g_window->dlv.ResizeColumns(rc.right-pad-pad); - g_window->elv.ResizeColumns(rc.right-pad-pad); - - /* Resize status bar parts. */ - const int aParts[] = {rc.right-Dpi(55), rc.right}; - SendMessageW(g_hWndStatus, SB_SETPARTS, - sizeof(aParts), reinterpret_cast<LPARAM>(aParts)); - - SendMessageW(g_window->hWnd, WM_SETREDRAW, TRUE, 0); - RedrawWindow(g_window->hWnd, nullptr, nullptr, - RDW_ERASE|RDW_FRAME|RDW_INVALIDATE|RDW_ALLCHILDREN); -} +#include "drag.h" +#include "episodelistview.h" +#include "win32.h" +#include "window.h" bool Dragger::IsDouble(const long time, const POINT& pt) { @@ -92,7 +60,7 @@ bool Dragger::HandleSetCursor() bool DlvDragger::InDragArea(const int x, const int y) const { RECT rrDlv; - Require(GetRelativeRect(g_window->dlv.hWnd, &rrDlv)); + Require(GetRelativeRect(parent.dlv.hWnd, &rrDlv)); const int pad = EBIsThemeActive()? Dpi(6): 0; const int extra = EBIsThemeActive()? 0: Dpi(2); @@ -104,26 +72,26 @@ bool DlvDragger::InDragArea(const int x, const int y) const void DlvDragger::Drag(const int, const int y) const { RECT rrDlv; - Require(GetRelativeRect(g_window->dlv.hWnd, &rrDlv)); + Require(GetRelativeRect(parent.dlv.hWnd, &rrDlv)); if (y < Dpi(50) || y > rrDlv.bottom-Dpi(20)) return; int h; h = rrDlv.bottom-y; - g_window->dlv.SetHeight(h); - UpdateLayout(); - RedrawWindow(g_window->hWnd, nullptr, nullptr, + parent.dlv.SetHeight(h); + parent.UpdateLayout(); + RedrawWindow(parent.hWnd, nullptr, nullptr, RDW_ERASE|RDW_FRAME|RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_UPDATENOW); } void DlvDragger::Reset() const { - g_window->dlv.SetHeight(0); - g_window->cfg.heightDlv = 0; - UpdateLayout(); + parent.dlv.SetHeight(0); + parent.cfg.heightDlv = 0; + parent.UpdateLayout(); } void DlvDragger::Done() const { - g_window->cfg.heightDlv = g_window->dlv.Height(); + parent.cfg.heightDlv = parent.dlv.Height(); } @@ -1,14 +1,8 @@ -#ifndef LAYOUT_H -#define LAYOUT_H +#ifndef DRAG_H +#define DRAG_H #include <windows.h> -#include "win.h" - -/* Given main window's width and height, set appropriate positions and - * sizes for child windows. */ -void UpdateLayout(int w = 0, int h = 0); - /* Dragger objects implement draggable portions of the client area, * such as the split between two list views. HandleLButtonDown and * HandleSetCursor are called by relevant window procedures upon diff --git a/c/episodelistview.cpp b/c/episodelistview.cpp index ea4849f..29c015b 100644 --- a/c/episodelistview.cpp +++ b/c/episodelistview.cpp @@ -3,15 +3,15 @@ #include <windows.h> #include <commctrl.h> -#include "resource.h" #include "data.h" #include "datalistview.h" #include "episodelistview.h" #include "ext.h" #include "listview.h" -#include "main.h" +#include "resource.h" #include "util.h" -#include "win.h" +#include "win32.h" +#include "window.h" EpisodeListView::EpisodeListView(Window& parent) : ListView(parent, reinterpret_cast<HMENU>(IDC_EPISODELISTVIEW), 0) @@ -66,12 +66,12 @@ void EpisodeListView::HandleContextMenu(const WORD command) /* Process other commands. */ switch (command) { case IDM_WATCH_LOCALLY: - if(!OpenLocally(lvi.lParam)) + if(!OpenLocally(parent.cfg, parent.fvElv.At(lvi.lParam-1))) cNotFound++; break; case IDM_WATCH_ONLINE: - OpenOnline(lvi.lParam); + OpenOnline(parent.cfg, lvi.lParam); break; case IDM_TOGGLE: @@ -79,7 +79,7 @@ void EpisodeListView::HandleContextMenu(const WORD command) break; case IDM_WIKI: - OpenWiki(lvi.lParam); + OpenWiki(parent.fvDlv.At(lvi.lParam-1)); break; } } @@ -176,15 +176,14 @@ LRESULT EpisodeListView::HandleNotify(const LPARAM lParam) { LVITEM lvi = {LVIF_PARAM, -1}; while (FindNextItem(&lvi, LVNI_SELECTED)) - OpenLocally(lvi.lParam) || OpenOnline(lvi.lParam); + OpenLocally(parent.cfg, parent.fvElv.At(lvi.lParam-1)) || OpenOnline(parent.cfg, lvi.lParam); return 0; } case NM_RCLICK: { - extern HMENU g_hMenuPopup; const DWORD pos = GetMessagePos(); - Require(TrackPopupMenu(g_hMenuPopup, TPM_RIGHTBUTTON, + Require(TrackPopupMenu(parent.hMenuPopup, TPM_RIGHTBUTTON, LOWORD(pos), HIWORD(pos), 0, parent.hWnd, nullptr)); return 0; } @@ -415,7 +414,7 @@ void EpisodeListView::Update() /* Show number of displayed items in status bar. */ wchar_t disp[16]; Swprintf(disp, L"%d", cItem); - Status(disp, 1); + parent.Status(disp, 1); } Sort(); @@ -3,14 +3,12 @@ #include <string_view> #include "data.h" -#include "main.h" +#include "window.h" -extern Window* g_window; - -bool OpenOnline(int iEp) +bool OpenOnline(const CfgA& cfg, int iEp) { - wchar_t url[sizeof(g_window->cfg.url)+4]; - Swprintf(url, L"%s%d", g_window->cfg.url, iEp); + wchar_t url[sizeof(cfg.url)+4]; + Swprintf(url, L"%s%d", cfg.url, iEp); INT_PTR r = reinterpret_cast<INT_PTR>( ShellExecuteW(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL)); if (r <= 32) @@ -18,9 +16,8 @@ bool OpenOnline(int iEp) return true; } -bool OpenWiki(int iEp) +bool OpenWiki(const DlvDataA& d) { - const DlvDataA& d = g_window->fvDlv.At(iEp-1); wchar_t url[sizeof(d.wiki)+35]; Swprintf(url, L"https://www.detectiveconanworld.com%s", d.wiki); INT_PTR r = reinterpret_cast<INT_PTR>( @@ -110,10 +107,10 @@ static bool FindMatchingFile(wchar_t (&file)[MAX_PATH], const wchar_t* const roo return false; } -bool OpenLocally(int iEp) +bool OpenLocally(CfgA& cfg, const ElvDataA& e) { wchar_t file[MAX_PATH]; - if (FindMatchingFile(file, g_window->cfg.root, g_window->fvElv.At(iEp-1).siEp)) { + if (FindMatchingFile(file, cfg.root, e.siEp)) { INT_PTR r = reinterpret_cast<INT_PTR>( ShellExecuteW(nullptr, L"open", file, nullptr, nullptr, SW_SHOWNORMAL)); if (r <= 32) @@ -1,8 +1,10 @@ #ifndef EXT_H #define EXT_H -bool OpenOnline(int iEp); -bool OpenWiki(int iEp); -bool OpenLocally(int iEp); +#include "data.h" + +bool OpenOnline(const CfgA& cfg, int iEp); +bool OpenWiki(const DlvDataA& d); +bool OpenLocally(CfgA& cfg, const ElvDataA& e); #endif diff --git a/c/listview.cpp b/c/listview.cpp index 6074707..03a65ae 100644 --- a/c/listview.cpp +++ b/c/listview.cpp @@ -1,10 +1,10 @@ #include <windows.h> #include <commctrl.h> +#include "drag.h" #include "listview.h" -#include "layout.h" -#include "main.h" -#include "win.h" +#include "win32.h" +#include "window.h" /* Actual window procedure for all list views, which calls the * appropriate WndProc member function. */ @@ -66,7 +66,7 @@ LRESULT CALLBACK ListView::WndProc(const HWND hWnd, const UINT uMsg, case WM_NOTIFY: switch (reinterpret_cast<NMHDR*>(lParam)->code) { case HDN_ENDTRACK: - UpdateLayout(); + parent.UpdateLayout(); return TRUE; } break; @@ -4,14 +4,14 @@ #include <commctrl.h> #include <libxml/xmlversion.h> -#include "debug.h" -#include "resource.h" #include "datalistview.h" +#include "debug.h" +#include "drag.h" #include "episodelistview.h" -#include "layout.h" -#include "main.h" +#include "resource.h" #include "test.h" #include "util.h" +#include "window.h" #ifdef _DEBUG #define XMAIN 30 @@ -21,10 +21,6 @@ #define YMAIN CW_USEDEFAULT #endif -/* main.cpp defines all global (non-template) variables used in the - * program. `extern' is used to access them from other files, when - * need be. */ - /* Looked-up constants. */ int g_dpi = 96; @@ -36,26 +32,19 @@ HFONT g_hfBold; HCURSOR g_hcArrow = LoadCursorW(nullptr, IDC_ARROW); HCURSOR g_hcSizeNs = LoadCursorW(nullptr, IDC_SIZENS); -/* Menus. */ -HMENU g_hMenuPopup; - -/* Windows. */ -HWND g_hWndFocus; -HWND g_hWndStatus; +/* Main window object. */ +Window* g_window; /* Optional Windows functions. */ BOOL (__stdcall *IsThemeActive)(); HRESULT (__stdcall *SetWindowTheme)(HWND, const wchar_t*, const wchar_t*); -/* Main window object. */ -Window* g_window; - /* Initialize important global state on parent window creation. */ static void InitializeMainWindow(HWND) noexcept; /* Process parent window commands. */ static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); /* Handle messages to Help > About dialog. */ -INT_PTR CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); +static INT_PTR CALLBACK AboutDlgProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain( _In_ const HINSTANCE hInstance, @@ -99,7 +88,7 @@ int WINAPI WinMain( XMAIN, YMAIN, 0, 0, nullptr, nullptr, hInstance, nullptr)); - g_hWndStatus = Require(CreateWindowExW( + g_window->hWndStatus = Require(CreateWindowExW( 0, STATUSCLASSNAME, nullptr, @@ -115,7 +104,7 @@ int WINAPI WinMain( g_window->elv.RestoreFocus(); #ifdef _DEBUG - RunTests(); + RunTests(*g_window); #endif MSG msg; @@ -167,10 +156,6 @@ static void InitializeMainWindow_(const HWND hWnd) SetWindowTheme = (decltype(SetWindowTheme))(void*)GetProcAddress(hModule, "SetWindowTheme"); } - /* Load context menu. */ - g_hMenuPopup = Require(LoadMenuW(nullptr, MAKEINTRESOURCE(IDR_POPUPMENU))); - g_hMenuPopup = Require(GetSubMenu(g_hMenuPopup, 0)); - g_window = new Window(hWnd); } @@ -235,7 +220,7 @@ LRESULT CALLBACK Window::WndProc(const HWND hWnd, const UINT uMsg, const WPARAM return 0; case WM_SIZE: - SendMessage(g_hWndStatus, WM_SIZE, wParam, lParam); + SendMessage(hWndStatus, WM_SIZE, wParam, lParam); UpdateLayout(LOWORD(lParam), HIWORD(lParam)); return 0; @@ -272,9 +257,9 @@ LRESULT CALLBACK Window::WndProc(const HWND hWnd, const UINT uMsg, const WPARAM case WM_ACTIVATE: if (wParam == WA_INACTIVE) - g_hWndFocus = GetFocus(); + hWndFocus = GetFocus(); else { - SetFocus(g_hWndFocus); + SetFocus(hWndFocus); /* TODO: Update tracked episodes. */ elv.Redraw(); } @@ -387,16 +372,16 @@ void Window::HandleMainMenu(const HWND hWnd, const WORD command) case IDM_FILE_FETCH_DATA: { - WaitFor(FetchData); + WaitFor(*this, FetchData); break; } case IDM_FILE_FETCH_SCREENWRITERS: - WaitFor(FetchScreenwriters); + WaitFor(*this, FetchScreenwriters); break; case IDM_FILE_FETCH_CANCEL: - WaitFor(nullptr); + WaitFor(*this, nullptr); break; case IDM_FILE_ABOUT: @@ -441,6 +426,40 @@ void Window::HandleMainMenu(const HWND hWnd, const WORD command) } } +void Window::Status(const wchar_t* msg, unsigned short i) +{ + SendMessage(hWndStatus, SB_SETTEXT, MAKEWPARAM(i, 0), reinterpret_cast<LPARAM>(msg)); +} + +void Window::UpdateLayout(int w, int h) +{ + if (!hWndStatus) return; + + RECT rc, rrStatus; + if (w && h) rc = {0, 0, w, h}; + else Require(GetClientRect(hWnd, &rc)); + Require(GetRelativeRect(hWndStatus, &rrStatus)); + + SendMessageW(hWnd, WM_SETREDRAW, FALSE, 0); + + /* Resize list views. */ + const long pad = EBIsThemeActive()? Dpi(6): 0; /* Add padding in modern themes. */ + const long cyDlv = rrStatus.top-dlv.Height()-pad; + Require(SetWindowRect(dlv.hWnd, pad, cyDlv, rc.right-pad, rrStatus.top-pad)); + Require(SetWindowRect(elv.hWnd, pad, pad, rc.right-pad, cyDlv-pad)); + dlv.ResizeColumns(rc.right-pad-pad); + elv.ResizeColumns(rc.right-pad-pad); + + /* Resize status bar parts. */ + const int aParts[] = {rc.right-Dpi(55), rc.right}; + SendMessageW(hWndStatus, SB_SETPARTS, + sizeof(aParts), reinterpret_cast<LPARAM>(aParts)); + + SendMessageW(hWnd, WM_SETREDRAW, TRUE, 0); + RedrawWindow(hWnd, nullptr, nullptr, + RDW_ERASE|RDW_FRAME|RDW_INVALIDATE|RDW_ALLCHILDREN); +} + void Window::UpdateTheme() { if (IsThemeActive) { @@ -4,11 +4,11 @@ #include "data.h" #include "episodelistview.h" #include "ext.h" -#include "main.h" #include "util.h" -#include "win.h" +#include "win32.h" +#include "window.h" -extern Window* g_window; +Window* s_window; struct Test { @@ -36,8 +36,8 @@ TESTS TEST(IO) { - ElvDataA& e1_0 = g_window->fvElv.At(5); - ElvDataA& e2_0 = g_window->fvElv.At(9); + ElvDataA& e1_0 = s_window->fvElv.At(5); + ElvDataA& e2_0 = s_window->fvElv.At(9); /* Write two ElvDataA structs to disk. */ { @@ -91,7 +91,7 @@ TESTS // TEST(MigrateCfg) // { // FileView<CfgB> fvb = FileView<CfgB>::Initialized(L"cfgb.dat", 1); -// CfgA* a = &g_window->cfg; +// CfgA* a = &s_window->cfg; // CfgB* b = fvb+0; // #define CPY(member) b->member = a->member; @@ -113,8 +113,10 @@ TESTS // } }; -int RunTests() +int RunTests(Window& window) { + s_window = &window; + const Test tests[] = { StrcpyWithSmallerDestination(), //IO(), @@ -1,6 +1,7 @@ #ifndef TEST_H #define TEST_H -int RunTests(); +struct Window; +int RunTests(Window& window); #endif @@ -4,9 +4,9 @@ #include <windows.h> #include <wininet.h> -#include "main.h" #include "util.h" -#include "win.h" +#include "win32.h" +#include "window.h" std::wstring WideFromNarrow(const std::string_view src, const int cp) { @@ -1,5 +1,5 @@ -#ifndef WIN_H -#define WIN_H +#ifndef WIN32_H +#define WIN32_H #include <optional> #include <string_view> @@ -144,10 +144,4 @@ inline HRESULT EBSetWindowTheme(const HWND hWnd, const wchar_t* const pszSubAppN return SetWindowTheme? SetWindowTheme(hWnd, pszSubAppName, pszSubIdList): 0; } -inline void Status(const wchar_t* msg, unsigned short i = 0) -{ - extern HWND g_hWndStatus; - SendMessage(g_hWndStatus, SB_SETTEXT, MAKEWPARAM(i,0), reinterpret_cast<LPARAM>(msg)); -} - #endif diff --git a/c/window.h b/c/window.h new file mode 100644 index 0000000..5cdffe4 --- /dev/null +++ b/c/window.h @@ -0,0 +1,50 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include <windows.h> + +#include "data.h" +#include "datalistview.h" +#include "drag.h" +#include "episodelistview.h" +#include "resource.h" +#include "win32.h" + +struct Window +{ + HWND hWnd; + HWND hWndFocus = nullptr; + HWND hWndStatus = nullptr; + HMENU hMenuPopup = Require(GetSubMenu(Require(LoadMenuW(nullptr, MAKEINTRESOURCE(IDR_POPUPMENU))), 0)); + + /* File views. */ + FileView<CfgA> fvCfg = FileView<CfgA>::Initialized(L"cfg.dat", 1); + CfgA& cfg = fvCfg.At(0); + FileView<ElvDataA> fvElv{L"elvdata.dat", cfg.cEp+128u}; + FileView<DlvDataA> fvDlv{L"dlvdata.dat", cfg.cEp+128u}; + + /* Layout handlers. */ + DlvDragger dragDlv = DlvDragger(*this); + + /* Child window objects. */ + DataListView dlv = DataListView(*this); + EpisodeListView elv = EpisodeListView(*this); + + inline Window(HWND hWnd) : hWnd(hWnd) {} + LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); + + /* Given main window's width and height, set appropriate + * positions and sizes for child windows. */ + void UpdateLayout(int w = 0, int h = 0); + + /* Process main menu commands. */ + void HandleMainMenu(HWND, WORD); + + /* Display text in status bar. */ + void Status(const wchar_t* msg, unsigned short i = 0); + + /* Try to style application according to current Windows theme. */ + void UpdateTheme(); +}; + +#endif |