#ifndef LAYOUT_H #define LAYOUT_H #include #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 * WM_(NC)LBUTTONDOWN and WM_SETCURSOR. */ struct Dragger { bool HandleLButtonDown(); bool HandleSetCursor(); protected: bool IsDown() const; bool IsDouble(const long time, const POINT& pt); virtual bool InDragArea(int x, int y) const; /* Perform drag, resizing relevant windows. */ virtual void Drag(int x, int y) const; /* Reset dragger to automatic position. */ virtual void Reset() const; /* Called after drag, when mouse button is released. */ virtual void Done() const; private: bool m_bActive = false; long m_time0 = 0; POINT m_pt0 = {0, 0}; }; /* DlvDragger implements the draggable split between the data list * view and the episode list view. */ struct DlvDragger : public Dragger { private: bool InDragArea(int x, int y) const override; void Drag(int x, int y) const override; void Reset() const override; void Done() const override; }; /* Below follows the implementation of the non-virtual member * functions of Dragger, on which derived objects rely. */ inline bool Dragger::IsDouble(const long time, const POINT& pt) { const bool dbl = time-m_time0 <= static_cast(GetDoubleClickTime()) && abs(pt.x-m_pt0.x) <= Metric && abs(pt.y-m_pt0.y) <= Metric; m_time0 = time; m_pt0 = std::move(pt); return dbl; } inline bool Dragger::IsDown() const { return GetKeyState(VK_LBUTTON) & 0x8000; } inline bool Dragger::HandleLButtonDown() { extern HWND g_hWnd; POINT pt; Require(GetRelativeCursorPos(g_hWnd, &pt)); if (!InDragArea(pt.x, pt.y)) return false; if (IsDouble(GetMessageTime(), pt)) { m_bActive = false; Reset(); } else m_bActive = true; return m_bActive; } inline bool Dragger::HandleSetCursor() { extern HWND g_hWnd; POINT pt; Require(GetRelativeCursorPos(g_hWnd, &pt)); extern HCURSOR g_hcSizeNs; bool r = true; if (InDragArea(pt.x, pt.y)) SetCursor(g_hcSizeNs); else r = false; if (!m_bActive) return r; Drag(pt.x, pt.y); if (!IsDown()) { m_bActive = false; Done(); } return r; } #endif