diff foosdk/sdk/libPPUI/CListControlHeaderImpl.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/libPPUI/CListControlHeaderImpl.h	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,266 @@
+#pragma once
+
+class CListCell;
+
+class CListControlHeaderImpl : public CListControlFontOps {
+private:
+	typedef CListControlFontOps TParent;
+public:
+	CListControlHeaderImpl() {}
+
+	BEGIN_MSG_MAP_EX(CListControlHeaderImpl)
+		MSG_WM_THEMECHANGED(OnThemeChangedPT)
+		MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
+		MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, MousePassThru);
+		MSG_WM_MOUSELEAVE(OnMouseLeave)
+		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);
+		NOTIFY_CODE_HANDLER_EX(NM_CUSTOMDRAW, OnHeaderCustomDraw);
+		MSG_WM_SETCURSOR(OnSetCursor);
+		MSG_WM_MOUSEMOVE(OnMouseMove)
+		MSG_WM_DESTROY(OnDestroy)
+		MSG_WM_ENABLE(OnEnable)
+		MSG_WM_KILLFOCUS(OnKillFocus)
+		MSG_WM_WINDOWPOSCHANGED(OnWindowPosChanged)
+		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);
+
+	static constexpr uint32_t 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, bool pad = true) 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;
+
+	void SetHeaderFont(HFONT font);
+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_stringTempFixAmpersands;
+		//! For temporary use.
+		pfc::stringcvt::string_wide_from_utf8_t<pfc::alloc_fast_aggressive> m_convertTemp;
+		//! Our DC for measuring text. Correct font pre-selected.
+		CDCHandle m_dc;
+
+		t_uint32 GetStringTempWidth();
+	};
+
+	void UpdateHeaderLayout();
+	void OnViewOriginChange(CPoint p_delta) override;
+	void RenderItemText(t_size item,const CRect & itemRect,const CRect & updateRect,CDCHandle dc, bool allowColors) override;
+	void RenderGroupHeaderText2(size_t baseItem,const CRect & headerRect,const CRect & updateRect,CDCHandle dc) override;
+	void RenderGroupOverlay(size_t baseItem, const CRect& p_groupWhole, const CRect& p_updateRect, CDCHandle p_dc) override;
+	void UpdateGroupOverlayColumnByID(groupID_t groupID, size_t subItem);
+
+	//! 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) { (void)index; }
+	//! Override to supply item labels.
+	virtual bool GetSubItemText(t_size item, t_size subItem, pfc::string_base& out) const { (void)item; (void)subItem; (void)out; return false; }
+	//! Override if you support groups.
+	virtual bool GetGroupHeaderText2(size_t baseItem, pfc::string_base& out) const { (void)baseItem; (void)out; 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 RenderGroupOverlayColumn(size_t baseItem, size_t subItem, const CRect& p_groupWhole, const CRect& p_updateRect, CDCHandle p_dc) { (void)baseItem; (void)subItem; (void)p_groupWhole; (void)p_updateRect; (void)p_dc; }
+
+	virtual void OnColumnsChanged();
+
+	virtual t_uint32 GetOptimalSubItemWidth(t_size item, t_size subItem, GetOptimalWidth_Cache & cache) const;
+
+	virtual t_uint32 GetOptimalGroupHeaderWidth2(size_t baseItem) 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 { (void)item; (void)subItem; return false; }
+	virtual void SetCellCheckState(size_t item, size_t subItem, bool value);
+	virtual bool ToggleSelectedItemsHook(const pfc::bit_array & mask) override;
+
+	virtual bool RenderCellImageTest(size_t item, size_t subItem) const { (void)item; (void)subItem; return false; }
+	virtual void RenderCellImage(size_t item, size_t subItem, CDCHandle, const CRect&) const { (void)item; (void)subItem; }
+
+	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) { (void)item; (void)subItem; return 1; }
+	virtual bool IsSubItemGrayed(size_t item, size_t subItem) { (void)item; (void)subItem; return !this->IsWindowEnabled(); }
+
+	virtual void CellTrackMouseMove(size_t item, size_t subItem, UINT msg, DWORD status, CPoint pt) { (void)item; (void)subItem; (void)msg; (void)status; (void)pt; }
+
+	// 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<int> 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;
+
+	size_t HotItem() const { return m_hotItem; }
+	size_t HotSubItem() const { return m_hotSubItem; }
+
+	virtual void RequestEditItem(size_t item, size_t subItem);
+private:
+	void OnLButtonDblClk(UINT nFlags, CPoint point);
+	void OnThemeChangedPT();
+	void OnEnable(BOOL) { Invalidate(); }
+	HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic);
+	void ProcessColumnsChange() { OnColumnsChanged();}
+	LRESULT OnSizePassThru(UINT,WPARAM,LPARAM);
+	LRESULT OnHeaderItemClick(int,LPNMHDR,BOOL&);
+	LRESULT OnHeaderCustomDraw(LPNMHDR);
+	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;
+	bool m_headerDark = false;
+	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<colRuntime_t> 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); }
+
+	virtual void HotItemChanged(size_t row, size_t column) { (void)row; (void)column; }
+	virtual void PressedItemChanged(size_t row, size_t column) { (void)row; (void)column; }
+
+	size_t m_pressedItem = SIZE_MAX, m_pressedSubItem = SIZE_MAX;
+	size_t m_hotItem = SIZE_MAX, m_hotSubItem = SIZE_MAX;
+
+private:
+	// ==== mySetCapture stuff ====
+	// SetCapture()-like functionality used for tracking of hot fields.
+	// Not a part of the API, do not reuse in subclasses.
+	void mySetCapture(CaptureProc_t proc);
+	void myReleaseCapture();
+
+	void TrackMouseLeave();
+
+	void mySetCaptureMsgHandled(BOOL v) { this->SetMsgHandled(v); }
+	CaptureProc_t m_captureProc;
+
+	void OnMouseLeave();
+	void OnKillFocus(CWindow);
+	void OnWindowPosChanged(LPWINDOWPOS);
+	LRESULT MousePassThru(UINT, WPARAM, LPARAM);
+};