diff --git a/README.md b/README.md index 81edf13..505cb11 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ The x86 (32-bit) Windows binaries can be downloaded [here](https://github.com/ma # Changelog * 0.5 (planned) - * [ ] Populate status bar with useful messages + * Fix bug, when closing current tab, the next tab doesn't render + * Show page numbers on status bar + * [ ] Add more status bar functionality * [ ] Add zooming capability * 0.4 diff --git a/src/common.cpp b/src/common.cpp index 85ae9ec..54cd137 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -109,6 +109,22 @@ void pdfv::w::openWeb(LPCWSTR url) noexcept ::ShellExecuteW(nullptr, L"open", url, nullptr, nullptr, SW_SHOWNORMAL); } +bool pdfv::w::status::setParts(HWND statusbar, const std::vector & edges) noexcept +{ + // Number of edges can't be greater than 256 + if (edges.size() > 256) [[unlikely]] + { + return false; + } + return ::SendMessageW(statusbar, SB_SETPARTS, edges.size(), reinterpret_cast(edges.data())) ? true : false; +} +bool pdfv::w::status::setText(HWND statusbar, int idx, DrawOp drawop, LPCWSTR str) noexcept +{ + return ::SendMessageW(statusbar, SB_SETTEXT, idx | int(drawop), reinterpret_cast(str)) ? true : false; +} + + + [[nodiscard]] pdfv::ArgVecT pdfv::getArgs(LPWSTR cmdLine, int & argc) noexcept { diff --git a/src/common.hpp b/src/common.hpp index 49ceadf..06e4aa9 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -24,6 +24,7 @@ #include "version.hpp" #include "resource.hpp" #include "safeptr.hpp" +#include "enumhelper.hpp" #define APP_DEFSIZE_X 350 #define APP_DEFSIZE_Y 200 @@ -257,7 +258,31 @@ namespace pdfv template using SafeHDC = w::Safeptr; + namespace status + { + bool setParts(HWND statusbar, const std::vector & edges) noexcept; + + enum class DrawOp : int + { + def = 0, + noBorders = SBT_NOBORDERS, + ownerDraw = SBT_OWNERDRAW, + popOut = SBT_POPOUT, + rtlReading = SBT_RTLREADING, + rightToLeftReading = rtlReading, + noTabParsing = SBT_NOTABPARSING, + }; + using DrawingOperation = DrawOp; + + bool setText(HWND statusbar, int idx, DrawOp drawop, LPCWSTR str) noexcept; + + } } + + // Enable operator overloads on Drawing operations + template<> struct Enumhelper_enabler + { + }; using ArgVecT = w::Safeptr< wchar_t **, diff --git a/src/concepts.hpp b/src/concepts.hpp index e973a09..e0c7d32 100644 --- a/src/concepts.hpp +++ b/src/concepts.hpp @@ -92,4 +92,14 @@ namespace pdfv::concepts */ template concept pointer = std::is_pointer_v; + + + template + concept enum_concept = std::is_enum_v; + + template + concept enum_nonclass = enum_concept && std::is_convertible_v>; + + template + concept enum_class = enum_concept && !std::is_convertible_v>; } diff --git a/src/enumhelper.hpp b/src/enumhelper.hpp new file mode 100644 index 0000000..a7d32c9 --- /dev/null +++ b/src/enumhelper.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include "concepts.hpp" + +namespace pdfv +{ + template + struct Enumhelper_enabler; + + template + using UnderT = std::underlying_type_t; + + template + [[nodiscard]] constexpr Enum operator|(Enum lhs, Enum rhs) noexcept requires std::is_constructible_v> + { + return Enum{ UnderT(lhs) | UnderT(rhs) }; + } + template + [[nodiscard]] constexpr Enum operator&(Enum lhs, Enum rhs) noexcept requires std::is_constructible_v> + { + return Enum{ UnderT(lhs) & UnderT(rhs) }; + } + template + [[nodiscard]] constexpr Enum operator^(Enum lhs, Enum rhs) noexcept requires std::is_constructible_v> + { + return Enum{ UnderT(lhs) ^ UnderT(rhs) }; + } + + template + [[nodiscard]] constexpr bool operator!(Enum lhs) noexcept requires std::is_constructible_v> + { + return !UnderT(lhs); + } + template + [[nodiscard]] constexpr Enum operator~(Enum lhs) noexcept requires std::is_constructible_v> + { + return Enum{ ~UnderT(lhs) }; + } +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 3a8052f..7885d2a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -7,12 +7,12 @@ pdfv::MainWindow pdfv::MainWindow::mwnd; [[nodiscard]] bool pdfv::MainWindow::intersectsTabClose() noexcept { - auto p{ w::getCur(this->m_hwnd) }; + auto p{ w::getCur(this->getHandle()) }; for (std::size_t i = 0; i < this->m_tabs.size(); ++i) { RECT r; - TabCtrl_GetItemRect(this->m_tabs.m_tabshwnd, i, &r); + TabCtrl_GetItemRect(this->m_tabs.getHandle(), i, &r); auto closeR{ Tabs::s_calcCloseButton(r) }; if (p.x >= closeR.left && p.x <= closeR.right && @@ -39,6 +39,12 @@ void pdfv::MainWindow::aboutBox() noexcept ); } +void pdfv::MainWindow::setStatusParts() const noexcept +{ + auto w{ this->m_usableArea.x }; + w::status::setParts(this->m_statushwnd, { w - dip(200, dpi.x), w - dip(17, dpi.x) }); +} + pdfv::MainWindow::MainWindow() noexcept { DEBUGPRINT("pdfv::MainWindow::MainWindow()\n"); @@ -168,7 +174,7 @@ pdfv::MainWindow::~MainWindow() noexcept this->m_hInst, const_cast(fname) ); - if (this->m_hwnd == nullptr) [[unlikely]] + if (this->getHandle() == nullptr) [[unlikely]] { error::lastErr = error::window; return false; @@ -177,20 +183,20 @@ pdfv::MainWindow::~MainWindow() noexcept // Add "about" to system menu (menu when caption bar is right-clicked) if (this->m_helpAvailable) [[likely]] { - auto hSysMenu{ ::GetSystemMenu(this->m_hwnd, false) }; + auto hSysMenu{ ::GetSystemMenu(this->getHandle(), false) }; ::InsertMenuW(hSysMenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); ::InsertMenuW(hSysMenu, 6, MF_BYPOSITION, IDM_HELP_ABOUT, L"&About"); } else [[unlikely]] { - ::EnableMenuItem(::GetMenu(this->m_hwnd), IDM_HELP_ABOUT, MF_DISABLED); + ::EnableMenuItem(::GetMenu(this->getHandle()), IDM_HELP_ABOUT, MF_DISABLED); } this->m_hAccelerators = ::LoadAcceleratorsW(this->m_hInst, MAKEINTRESOURCEW(IDR_ACCELERATOR1)); - ::ShowWindow(this->m_hwnd, nCmdShow); + ::ShowWindow(this->getHandle(), nCmdShow); // Good practise - ::UpdateWindow(this->m_hwnd); - + ::UpdateWindow(this->getHandle()); + return true; } @@ -235,9 +241,9 @@ int pdfv::MainWindow::msgLoop() const noexcept } else [[likely]] { - if (!::TranslateAcceleratorW(this->m_hwnd, this->m_hAccelerators, &msg)) + if (!::TranslateAcceleratorW(this->getHandle(), this->m_hAccelerators, &msg)) { - if (!::IsDialogMessageW(this->m_hwnd, &msg)) + if (!::IsDialogMessageW(this->getHandle(), &msg)) { ::TranslateMessage(&msg); ::DispatchMessageW(&msg); @@ -251,9 +257,9 @@ int pdfv::MainWindow::msgLoop() const noexcept void pdfv::MainWindow::close() const noexcept { - if (this->m_hwnd != nullptr) [[likely]] + if (this->getHandle() != nullptr) [[likely]] { - ::SendMessageW(this->m_hwnd, WM_CLOSE, 0, 0); + ::SendMessageW(this->getHandle(), WM_CLOSE, 0, 0); } } @@ -261,24 +267,24 @@ void pdfv::MainWindow::close() const noexcept void pdfv::MainWindow::enable(bool enable) const noexcept { DEBUGPRINT("pdfv::MainWindow::enable(%d)\n", enable); - ::EnableWindow(this->m_hwnd, enable); + ::EnableWindow(this->getHandle(), enable); } void pdfv::MainWindow::setTitle(std::wstring_view newTitle) { DEBUGPRINT("pdfv::MainWindow::setTitle(%p)\n", static_cast(newTitle.data())); this->m_title = newTitle; - ::SetWindowTextW(this->m_hwnd, this->m_title.c_str()); + ::SetWindowTextW(this->getHandle(), this->m_title.c_str()); } int pdfv::MainWindow::message(LPCWSTR message, LPCWSTR msgtitle, UINT type) const noexcept { DEBUGPRINT("pdfv::MainWindow::message(%p, %p, %u)\n", static_cast(message), static_cast(msgtitle), type); - return ::MessageBoxW(this->m_hwnd, message, msgtitle, type); + return ::MessageBoxW(this->getHandle(), message, msgtitle, type); } int pdfv::MainWindow::message(LPCWSTR message, UINT type) const noexcept { DEBUGPRINT("pdfv::MainWindow::message(%p, %u)\n", static_cast(message), type); - return ::MessageBoxW(this->m_hwnd, message, this->m_title.c_str(), type); + return ::MessageBoxW(this->getHandle(), message, this->m_title.c_str(), type); } LRESULT CALLBACK pdfv::MainWindow::windowProc(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp) noexcept @@ -423,7 +429,7 @@ void pdfv::MainWindow::wOnCommand(WPARAM wp) noexcept switch (LOWORD(wp)) { case IDM_FILE_OPEN: - if (std::wstring file; this->m_openDialog.open(this->m_hwnd, file)) + if (std::wstring file; this->m_openDialog.open(this->getHandle(), file)) { // Open the PDF this->openPdfFile(file); @@ -436,7 +442,7 @@ void pdfv::MainWindow::wOnCommand(WPARAM wp) noexcept } mwnd.m_keyDown[L'W'] = true; // Close current tab - ::SendMessageW(this->m_hwnd, WM_COMMAND, IDM_LIMIT + this->m_tabs.m_tabindex, 0); + ::SendMessageW(this->getHandle(), WM_COMMAND, IDM_LIMIT + this->m_tabs.m_tabindex, 0); break; case IDM_FILE_EXIT: this->close(); @@ -655,6 +661,7 @@ void pdfv::MainWindow::wOnSize() noexcept DEBUGPRINT("pdfv::MainWindow::wOnSize()\n"); this->m_usableArea = w::getCliR(this->getHandle()); + this->m_totalArea = w::getWinR(this->getHandle()); this->m_border = this->m_totalArea - this->m_usableArea; this->m_border.y -= this->m_menuSize; @@ -662,6 +669,9 @@ void pdfv::MainWindow::wOnSize() noexcept auto statusr{ w::getCliR(this->m_statushwnd) }; this->m_tabs.resize(this->m_usableArea - xy{ 0, statusr.bottom - statusr.top }); w::resize(this->m_statushwnd, 0, 0); + + // Set status bar parts + this->setStatusParts(); } void pdfv::MainWindow::wOnCreate(HWND hwnd, LPARAM lp) noexcept { @@ -695,6 +705,9 @@ void pdfv::MainWindow::wOnCreate(HWND hwnd, LPARAM lp) noexcept clir = w::getCliR(hwnd); auto statusr{ w::getCliR(this->m_statushwnd) }; + + this->setStatusParts(); + clir.bottom = clir.top + (clir.bottom - clir.top) - (statusr.bottom - statusr.top); this->m_tabs = Tabs(hwnd, this->getHinst(), clir); @@ -765,17 +778,17 @@ void pdfv::MainWindow::wOnCopydata(LPARAM lp) noexcept void pdfv::MainWindow::wOnBringToFront() noexcept { DEBUGPRINT("pdfv::MainWindow::wOnBringToFront()\n"); - ::ShowWindow(this->m_hwnd, SW_RESTORE); + ::ShowWindow(this->getHandle(), SW_RESTORE); HWND topWnd{ ::GetForegroundWindow() }; - DWORD dwMyID { ::GetWindowThreadProcessId(this->m_hwnd, nullptr) }; + DWORD dwMyID { ::GetWindowThreadProcessId(this->getHandle(), nullptr) }; DWORD dwCurID{ ::GetWindowThreadProcessId(topWnd, nullptr) }; ::AttachThreadInput(dwCurID, dwMyID, TRUE); - ::SetWindowPos(this->m_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); - ::SetWindowPos(this->m_hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); - ::SetForegroundWindow(this->m_hwnd); - ::SetFocus(this->m_hwnd); - ::SetActiveWindow(this->m_hwnd); + ::SetWindowPos(this->getHandle(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE); + ::SetWindowPos(this->getHandle(), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); + ::SetForegroundWindow(this->getHandle()); + ::SetFocus(this->getHandle()); + ::SetActiveWindow(this->getHandle()); ::AttachThreadInput(dwCurID, dwMyID, FALSE); } @@ -804,7 +817,7 @@ INT_PTR CALLBACK pdfv::MainWindow::aboutProc(HWND hwnd, UINT uMsg, WPARAM wp, LP // Re-position about box auto r1{ w::getWinR(hwnd) }; - auto r2{ w::getWinR(self->m_hwnd) }; + auto r2{ w::getWinR(self->getHandle()) }; // Move dialog to the center of parent window w::moveWin( diff --git a/src/mainwindow.hpp b/src/mainwindow.hpp index 741e1e8..d325ed8 100644 --- a/src/mainwindow.hpp +++ b/src/mainwindow.hpp @@ -64,6 +64,8 @@ namespace pdfv void aboutBox() noexcept; std::wstring m_aboutText{ DEFAULT_ABOUT_TEXT }; + void setStatusParts() const noexcept; + public: // // A singleton instance of the class supported by a private constructor @@ -119,6 +121,10 @@ namespace pdfv { return this->m_hwnd; } + [[nodiscard]] constexpr HWND getStatusHandle() const noexcept + { + return this->m_statushwnd; + } [[nodiscard]] constexpr HINSTANCE getHinst() const noexcept { return this->m_wcex.hInstance; diff --git a/src/tabs.cpp b/src/tabs.cpp index 0c27593..9f410cb 100644 --- a/src/tabs.cpp +++ b/src/tabs.cpp @@ -92,6 +92,7 @@ void pdfv::TabObject::updatePDF() noexcept { DEBUGPRINT("pdfv::TabObject::updatePDF()\n"); this->updateScrollbar(); + this->updatePageCounter(); } LRESULT CALLBACK pdfv::TabObject::tabObjectProcHub(HWND hwnd, UINT uMsg, WPARAM wp, LPARAM lp) @@ -209,6 +210,7 @@ LRESULT pdfv::TabObject::tabObjectProc(UINT uMsg, WPARAM wp, LPARAM lp) this->page = yNewPos; this->second.pageLoad(this->page + 1); + this->updatePageCounter(); w::redraw(this->tabhandle); SCROLLINFO si{}; @@ -233,6 +235,9 @@ LRESULT pdfv::TabObject::tabObjectProc(UINT uMsg, WPARAM wp, LPARAM lp) ::DestroyWindow(this->tabhandle); this->tabhandle = nullptr; break; + case WM_CREATE: + this->updatePageCounter(); + break; default: return ::DefWindowProcW(this->tabhandle, uMsg, wp, lp); } @@ -257,6 +262,20 @@ void pdfv::TabObject::updateScrollbar() noexcept ::SetScrollInfo(this->tabhandle, SB_VERT, &si, TRUE); } } +void pdfv::TabObject::updatePageCounter() const noexcept +{ + if (this->second.pdfExists()) + { + setText( + window.getStatusHandle(), 1, w::status::DrawOp::def, + (std::wstring(L"Page: ") + std::to_wstring(this->second.pageGetNum()) + L'/' + std::to_wstring(this->second.pageGetCount())).c_str() + ); + } + else + { + setText(window.getStatusHandle(), 1, w::status::DrawOp::def, L"Page: NA"); + } +} pdfv::Tabs::Tabs(HWND hwnd, HINSTANCE hInst, RECT size) noexcept : m_parent(hwnd) @@ -521,6 +540,7 @@ void pdfv::Tabs::selChange() noexcept { this->m_tabs[oldidx]->show(false); this->resize(this->m_size); - this->m_tabs[this->m_tabindex]->show(); } + this->m_tabs[this->m_tabindex]->show(); + this->m_tabs[this->m_tabindex]->updatePageCounter(); } diff --git a/src/tabs.hpp b/src/tabs.hpp index dc00287..5864e38 100644 --- a/src/tabs.hpp +++ b/src/tabs.hpp @@ -63,6 +63,7 @@ namespace pdfv LRESULT tabObjectProc(UINT uMsg, WPARAM wp, LPARAM lp); void updateScrollbar() noexcept; + void updatePageCounter() const noexcept; }; class Tabs