#pragma once class CListCell; class CListControlHeaderImpl : public CListControlFontOps { private: typedef CListControlFontOps TParent; public: CListControlHeaderImpl() {} BEGIN_MSG_MAP_EX(CListControlHeaderImpl) MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic); MESSAGE_HANDLER(WM_KEYDOWN,OnKeyDown); MESSAGE_HANDLER(WM_SYSKEYDOWN,OnKeyDown); MESSAGE_HANDLER_EX(WM_SIZE,OnSizePassThru); NOTIFY_CODE_HANDLER(HDN_ITEMCHANGED,OnHeaderItemChanged); NOTIFY_CODE_HANDLER(HDN_ENDDRAG,OnHeaderEndDrag); NOTIFY_CODE_HANDLER(HDN_ITEMCLICK,OnHeaderItemClick); NOTIFY_CODE_HANDLER(HDN_DIVIDERDBLCLICK,OnDividerDoubleClick); MSG_WM_SETCURSOR(OnSetCursor); MSG_WM_MOUSEMOVE(OnMouseMove) MSG_WM_DESTROY(OnDestroy) MSG_WM_ENABLE(OnEnable) CHAIN_MSG_MAP(TParent) END_MSG_MAP() typedef uint32_t cellState_t; typedef CListCell * cellType_t; int GetHeaderItemWidth( int which ); void InitializeHeaderCtrl(DWORD flags = HDS_FULLDRAG); void InitializeHeaderCtrlSortable() {InitializeHeaderCtrl(HDS_FULLDRAG | HDS_BUTTONS);} CHeaderCtrl GetHeaderCtrl() const {return m_header;} void SetSortIndicator( size_t whichColumn, bool isUp ); void ClearSortIndicator(); bool IsHeaderEnabled() const {return m_header.m_hWnd != NULL;} void ResetColumns(bool update = true); enum { columnWidthMax = (uint32_t)INT32_MAX, columnWidthAuto = UINT32_MAX, columnWidthAutoUseContent = UINT32_MAX-1, }; void AddColumn(const char * label, uint32_t widthPixels, DWORD fmtFlags = HDF_LEFT,bool update = true); //! Extended AddColumn, specifies width in pixels @ 96DPI instead of screen-specific pixels void AddColumnEx( const char * label, uint32_t widthPixelsAt96DPI, DWORD fmtFlags = HDF_LEFT, bool update = true ); //! Extended AddColumn, specifies width in Dialog Length Units (DLU), assumes parent of this list to be a dialog window. void AddColumnDLU( const char * label, uint32_t widthDLU, DWORD fmtFlags = HDF_LEFT, bool update = true ); //! Extended AddColumn, specifies width as floating-point value of pixels at 96DPI. \n //! For DPI-safe storage of user's column widths. void AddColumnF( const char * label, float widthF, DWORD fmtFlags = HDF_LEFT, bool update = true ); void AddColumnAutoWidth( const char * label, DWORD fmtFlags = HDF_LEFT, bool bUpdate = true) { AddColumn(label, columnWidthAuto, fmtFlags, bUpdate); } bool DeleteColumn(size_t index, bool updateView = true); void DeleteColumns( pfc::bit_array const & mask, bool updateView = true); void ResizeColumn(t_size index, t_uint32 widthPixels, bool updateView = true); void SetColumn( size_t which, const char * title, DWORD fmtFlags = HDF_LEFT, bool updateView = true); void GetColumnText(size_t which, pfc::string_base & out) const; uint32_t GetOptimalColumnWidth( size_t index ) const; uint32_t GetOptimalColumnWidthFixed( const char * fixedText) const; uint32_t GetColumnsBlankWidth( size_t colExclude = SIZE_MAX ) const; void SizeColumnToContent( size_t which, uint32_t minWidth ); void SizeColumnToContentFillBlank( size_t which ); //! If creating a custom headerless multi column scheme, override these to manipulate your columns virtual size_t GetColumnCount() const; virtual uint32_t GetSubItemWidth(size_t subItem) const; //! Returns column width as a floating-point value of pixels at 96DPI. \n //! For DPI-safe storage of user's column widths. float GetColumnWidthF( size_t subItem ) const; //! Indicate how many columns a specific row/column cell spans\n //! This makes sense only if the columns can't be user-reordered virtual size_t GetSubItemSpan(size_t row, size_t column) const; t_size GetSubItemOrder(t_size subItem) const; int GetItemWidth() const override; protected: CRect GetClientRectHook() const override; void RenderBackground(CDCHandle dc, CRect const& rc) override; struct GetOptimalWidth_Cache { //! For temporary use. pfc::string8_fastalloc m_stringTemp, m_stringTempUnfuckAmpersands; //! For temporary use. pfc::stringcvt::string_wide_from_utf8_t m_convertTemp; //! Our DC for measuring text. Correct font pre-selected. CDCHandle m_dc; t_uint32 GetStringTempWidth(); }; void UpdateHeaderLayout(); void OnViewOriginChange(CPoint p_delta); void SetHeaderFont(HFONT font); void RenderItemText(t_size item,const CRect & itemRect,const CRect & updateRect,CDCHandle dc, bool allowColors); void RenderGroupHeaderText(int id,const CRect & headerRect,const CRect & updateRect,CDCHandle dc); //! Converts an item/subitem rect to a rect in which the text should be rendered, removing spacing to the left/right of the text. virtual CRect GetItemTextRectHook(size_t item, size_t subItem, CRect const & itemRect) const; CRect GetItemTextRect(CRect const & itemRect) const; //! Override for custom spacing to the left/right of the text in each column. virtual t_uint32 GetColumnSpacing() const {return MulDiv(4,m_dpi.cx,96);} //! Override for column-header-click sorting. virtual void OnColumnHeaderClick(t_size index) {} //! Override to supply item labels. virtual bool GetSubItemText(t_size item, t_size subItem, pfc::string_base & out) const {return false;} //! Override if you support groups. virtual bool GetGroupHeaderText(int id, pfc::string_base & out) const {return false;} //! Override optionally. virtual void RenderSubItemText(t_size item, t_size subItem,const CRect & subItemRect,const CRect & updateRect,CDCHandle dc, bool allowColors); virtual void OnColumnsChanged(); virtual t_uint32 GetOptimalSubItemWidth(t_size item, t_size subItem, GetOptimalWidth_Cache & cache) const; virtual t_uint32 GetOptimalGroupHeaderWidth(int which) const; bool GetItemAtPointAbsEx( CPoint pt, size_t & outItem, size_t & outSubItem ) const; cellType_t GetCellTypeAtPointAbs( CPoint pt ) const; virtual cellType_t GetCellType( size_t item, size_t subItem ) const; virtual bool AllowTypeFindInCell( size_t item, size_t subItem ) const; virtual bool GetCellTypeSupported() const { return false; } // optimization hint, some expensive checks can be suppressed if cell types are not used for this view virtual bool GetCellCheckState( size_t item, size_t subItem ) const { return false; } virtual void SetCellCheckState(size_t item, size_t subItem, bool value); virtual bool ToggleSelectedItemsHook(const pfc::bit_array & mask); void RenderSubItemTextInternal(size_t subItem, const CRect & subItemRect, CDCHandle dc, const char * text, bool allowColors); t_uint32 GetOptimalColumnWidth(t_size which, GetOptimalWidth_Cache & cache) const; t_uint32 GetOptimalSubItemWidthSimple(t_size item, t_size subItem) const; void AutoColumnWidths(const pfc::bit_array & mask,bool expandLast = false); void AutoColumnWidths() {AutoColumnWidths(pfc::bit_array_true());} void AutoColumnWidth(t_size which) {AutoColumnWidths(pfc::bit_array_one(which));} virtual bool OnColumnHeaderDrag(t_size index, t_size newOrder); void OnItemClicked(t_size item, CPoint pt) override; virtual void OnSubItemClicked(t_size item, t_size subItem,CPoint pt); bool OnClickedSpecialHitTest(CPoint pt) override; bool OnClickedSpecial(DWORD status, CPoint pt) override; static bool CellTypeUsesSpecialHitTests( cellType_t ct ); CRect GetSubItemRectAbs(t_size item,t_size subItem) const; CRect GetSubItemRect(t_size item,t_size subItem) const; t_size SubItemFromPointAbs(CPoint pt) const; static bool CellTypeReactsToMouseOver( cellType_t ct ); virtual CRect CellHotRect( size_t item, size_t subItem, cellType_t ct, CRect rcCell ); CRect CellHotRect( size_t item, size_t subItem, cellType_t ct ); virtual double CellTextScale(size_t item, size_t subItem) { return 1; } virtual bool IsSubItemGrayed(size_t item, size_t subItem) { return !this->IsWindowEnabled(); } // HDF_* constants for this column, override when not using list header control. Used to control text alignment. virtual DWORD GetColumnFormat(t_size which) const; void SetColumnFormat(t_size which,DWORD format); void SetColumnSort(t_size which, bool isUp); std::vector GetColumnOrderArray() const; bool AllowScrollbar(bool vertical) const override; void RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,size_t item, uint32_t bkColor) override; void ColumnWidthFix(); // Call RecalcItemWidth() / ProcessAutoWidth() void ReloadData() override; private: void OnEnable(BOOL) { Invalidate(); } HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic); void ProcessColumnsChange() { OnColumnsChanged();} LRESULT OnSizePassThru(UINT,WPARAM,LPARAM); LRESULT OnHeaderItemClick(int,LPNMHDR,BOOL&); LRESULT OnDividerDoubleClick(int,LPNMHDR,BOOL&); LRESULT OnHeaderItemChanged(int,LPNMHDR,BOOL&); LRESULT OnHeaderEndDrag(int,LPNMHDR,BOOL&); LRESULT OnKeyDown(UINT,WPARAM,LPARAM,BOOL&); void OnDestroy(); BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message); void OnMouseMove(UINT nFlags, CPoint point); void RecalcItemWidth(); // FIXED width math void ProcessAutoWidth(); // DYNAMIC width math bool m_ownColumnsChange = false; int m_itemWidth = 0; int m_clientWidth = 0; CHeaderCtrl m_header; CStatic m_headerLine; bool HaveAutoWidthColumns() const; bool HaveAutoWidthContentColumns() const; struct colRuntime_t { bool m_autoWidth = false; bool m_autoWidthContent = false; int m_widthPixels = 0; uint32_t m_userWidth = 0; std::string m_text; bool autoWidth() const { return m_userWidth > columnWidthMax; } bool autoWidthContent() const { return m_userWidth == columnWidthAutoUseContent; } bool autoWidthPlain() const { return m_userWidth == columnWidthAuto; } }; std::vector m_colRuntime; //for group headers GdiplusScope m_gdiPlusScope; void SetPressedItem(size_t row, size_t column); void ClearPressedItem() {SetPressedItem(SIZE_MAX, SIZE_MAX);} void SetHotItem( size_t row, size_t column ); void ClearHotItem() { SetHotItem(SIZE_MAX, SIZE_MAX); } size_t m_pressedItem = SIZE_MAX, m_pressedSubItem = SIZE_MAX; size_t m_hotItem = SIZE_MAX, m_hotSubItem = SIZE_MAX; };