#ifndef LAYOUT_H #define LAYOUT_H #include #include "datalistview.h" #include "pl.h" #include "win.h" 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. HandleDown and HandleMove * are called by relevant window procedures upon WM_(NC)LBUTTONDOWN * and WM_SETCURSOR. */ struct Dragger { bool HandleDown(); bool HandleMove(); protected: bool IsDown(); bool IsDouble(); virtual bool InDragArea(int x, int y); virtual void Drag(int x, int y); virtual void Done(); /* Reset dragger to automatic position. */ virtual void Reset(); private: bool m_bActive = false; long m_time = 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) override; void Drag(int x, int y) override; void Reset() override; void Done() override; }; inline bool Dragger::IsDouble() { const long time = GetMessageTime(); const bool dbl = time-m_time <= static_cast(GetDoubleClickTime()); m_time = time; return dbl; } inline bool Dragger::IsDown() { return GetKeyState(VK_LBUTTON) & 0x8000; } inline bool Dragger::HandleDown() { extern HWND g_hWnd; POINT pt; Require(GetRelativeCursorPos(g_hWnd, &pt)); if (!InDragArea(pt.x, pt.y)) return false; if (IsDouble()) { m_bActive = false; Reset(); } else m_bActive = true; return m_bActive; } inline bool Dragger::HandleMove() { 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