diff foosdk/sdk/libPPUI/CListControl-Cells.cpp @ 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/CListControl-Cells.cpp	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,345 @@
+#include "stdafx.h"
+#include "CListControl.h"
+#include "CListControlHeaderImpl.h"
+#include "CListControl-Cells.h"
+#include "PaintUtils.h"
+#include "GDIUtils.h"
+#include <vsstyle.h>
+#include "InPlaceEdit.h"
+#include "DarkMode.h"
+
+#define PRETEND_CLASSIC_THEME 0
+
+
+#if PRETEND_CLASSIC_THEME
+#define IsThemePartDefined(A,B,C) false
+#endif
+
+LONG CListCell::AccRole() {
+	return ROLE_SYSTEM_LISTITEM;
+}
+
+void RenderCheckbox( HTHEME theme, CDCHandle dc, CRect rcCheckBox, unsigned stateFlags, bool bRadio ) {
+
+	const int part = bRadio ? BP_RADIOBUTTON : BP_CHECKBOX;
+
+	const bool bDisabled = (stateFlags & CListCell::cellState_disabled) != 0;
+	const bool bPressed = (stateFlags & CListCell::cellState_pressed ) != 0;
+	const bool bHot = ( stateFlags & CListCell::cellState_hot ) != 0;
+
+	if (theme != NULL && IsThemePartDefined(theme, part, 0)) {
+		int state = 0;
+		if (bDisabled) {
+			state = bPressed ? CBS_CHECKEDDISABLED : CBS_UNCHECKEDDISABLED;
+		} else if ( bHot ) {
+			state = bPressed ? CBS_CHECKEDHOT : CBS_UNCHECKEDHOT;
+		} else {
+			state = bPressed ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL;
+		}
+
+		CSize size;
+		if (SUCCEEDED(GetThemePartSize(theme, dc, part, state, rcCheckBox, TS_TRUE, &size))) {
+			if (size.cx <= rcCheckBox.Width() && size.cy <= rcCheckBox.Height()) {
+				CRect rc = rcCheckBox;
+				rc.left += ( rc.Width() - size.cx ) / 2;
+				rc.top += ( rc.Height() - size.cy ) / 2;
+				rc.right = rc.left + size.cx;
+				rc.bottom = rc.top + size.cy;
+				DrawThemeBackground(theme, dc, part, state, rc, &rc);
+				return;
+			}
+		}
+	}
+
+	auto DPI = QueryContextDPI(dc);
+	CSize size(MulDiv(13, DPI.cx, 96), MulDiv(13, DPI.cy, 96));
+	CSize sizeBig = rcCheckBox.Size();
+	if (sizeBig.cx >= size.cx && sizeBig.cy >= size.cy) {
+		CPoint center = rcCheckBox.CenterPoint();
+		rcCheckBox.left = center.x - size.cx / 2; rcCheckBox.right = rcCheckBox.left + size.cx;
+		rcCheckBox.top = center.y - size.cy / 2; rcCheckBox.bottom = rcCheckBox.top + size.cy;
+	}
+	
+	int stateEx = bRadio ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK;
+	if ( bPressed ) stateEx |= DFCS_CHECKED;
+	if ( bDisabled ) stateEx |= DFCS_INACTIVE;
+	else if ( bHot ) stateEx |= DFCS_HOT;
+	DrawFrameControl(dc, rcCheckBox, DFC_BUTTON, stateEx);
+}
+
+void RenderButton( HTHEME theme, CDCHandle dc, CRect rcButton, CRect rcUpdate, uint32_t cellState ) {
+
+	const int part = BP_PUSHBUTTON;
+
+	enum {
+		stNormal = PBS_NORMAL,
+		stHot = PBS_HOT,
+		stDisabled = PBS_DISABLED,
+		stPressed = PBS_PRESSED,
+	};
+
+	int state = 0;
+	if (cellState & CListCell::cellState_disabled) state = stDisabled;
+	if ( cellState & CListCell::cellState_pressed ) state = stPressed;
+	else if ( cellState & CListCell::cellState_hot ) state = stHot;
+	else state = stNormal;
+
+	CRect rcClient  = rcButton;
+
+	if (theme != NULL && IsThemePartDefined(theme, part, 0)) {
+		DrawThemeBackground(theme, dc, part, state, rcClient, &rcUpdate);
+	} else {
+		int stateEx = DFCS_BUTTONPUSH;
+		switch (state) {
+		case stPressed: stateEx |= DFCS_PUSHED; break;
+		case stDisabled: stateEx |= DFCS_INACTIVE; break;
+		}
+		DrawFrameControl(dc, rcClient, DFC_BUTTON, stateEx);
+	}
+}
+
+bool CListCell::ApplyTextStyle( LOGFONT & font, double scale, uint32_t ) { 
+	if ( scale != 1.0 ) {
+		font.lfHeight = pfc::rint32( font.lfHeight * scale );
+		return true;
+	} else {
+		return false;
+	}
+}
+
+void CListCell_Text::DrawContent( DrawContentArg_t const & arg ) {
+	const auto fgWas = arg.dc.GetTextColor();
+	CDCHandle dc = arg.dc;
+	if ((arg.cellState & cellState_disabled) != 0 && arg.allowColors) {
+		dc.SetTextColor(DarkMode::GetSysColor(COLOR_GRAYTEXT, arg.darkMode));
+	}
+	
+	CRect clip = arg.rcText;
+
+	if (arg.imageRenderer && clip.Width() > clip.Height() ) {
+		CRect rcImage = clip; rcImage.right = rcImage.left + clip.Height();
+		arg.imageRenderer(dc, rcImage);
+		clip.left = rcImage.right;
+	}
+
+	const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat);
+	dc.DrawText( arg.text, (int)wcslen(arg.text), clip, format | DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER  );
+
+	dc.SetTextColor(fgWas);
+}
+
+void CListCell_TextColors::DrawContent( DrawContentArg_t const & arg ) {
+	CDCHandle dc = arg.dc;
+	
+	CRect clip = arg.rcText;
+
+	const uint32_t fgWas = dc.GetTextColor();
+
+	const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat);
+	const t_uint32 bk = dc.GetBkColor();
+	const t_uint32 fg = fgWas;
+	const t_uint32 hl = (arg.allowColors ? arg.colorHighlight : fg);
+	const t_uint32 colors[3] = { PaintUtils::BlendColor(bk, fg, 33), fg, hl };
+
+	PaintUtils::TextOutColorsEx(dc, arg.text, clip, format, colors);
+
+	dc.SetTextColor(fgWas);
+}
+
+void CListCell_MultiText::DrawContent( DrawContentArg_t const & arg ) {
+	CDCHandle dc = arg.dc;
+
+	const int textLen = (int) wcslen( arg.text );
+
+	CRect clip = arg.rcText;
+
+	const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat) | DT_NOPREFIX | DT_VCENTER ;
+
+	CRect rcDraw = clip;
+	dc.DrawText(arg.text, textLen, rcDraw, format | DT_CALCRECT);
+	auto txSize = rcDraw.Size();
+	rcDraw = clip;
+	if ( txSize.cy < rcDraw.Height() ) {
+		int sub = rcDraw.Height() - txSize.cy;
+		rcDraw.top += sub/2;
+		rcDraw.bottom = rcDraw.top + txSize.cy;
+	}
+	dc.DrawText(arg.text, textLen, rcDraw, format);
+}
+
+bool CListCell_Hyperlink::ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) {
+	bool rv = __super::ApplyTextStyle(font, scale, state);
+
+	if ( state & cellState_hot ) {
+		font.lfUnderline = TRUE;
+		rv = true;
+	}
+
+	return rv;
+}
+
+HCURSOR CListCell_Hyperlink::HotCursor() {
+	return LoadCursor(NULL, IDC_HAND);
+}
+
+LONG CListCell_Hyperlink::AccRole() {
+	return ROLE_SYSTEM_LINK;
+}
+
+void CListCell_Hyperlink::DrawContent( DrawContentArg_t const & arg ) {
+
+	CDCHandle dc = arg.dc;
+
+	const uint32_t fgWas = dc.GetTextColor();
+
+	const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat);
+	if (arg.allowColors) dc.SetTextColor( arg.colorHighlight );
+	// const t_uint32 bk = dc.GetBkColor();
+
+	CRect rc = arg.rcText;
+	dc.DrawText(arg.text, (int) wcslen(arg.text), rc, format | DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER );
+
+	dc.SetTextColor(fgWas);
+}
+
+LONG CListCell_Button::AccRole() {
+	return ROLE_SYSTEM_PUSHBUTTON;
+}
+
+void CListCell_Button::DrawContent( DrawContentArg_t const & arg ) {
+
+	CDCHandle dc = arg.dc;
+
+	const bool bPressed = (arg.cellState & cellState_pressed) != 0;
+	const bool bHot = (arg.cellState & cellState_hot) != 0;
+
+	
+	if ( !m_lite || bHot || bPressed ) {
+		RenderButton( arg.theme, dc, arg.rcHot, arg.rcHot, arg.cellState );
+	}
+
+	CRect clip = arg.rcText;
+
+	dc.DrawText(arg.text, (int) wcslen(arg.text), clip, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_CENTER);
+}
+
+bool CListCell_ButtonGlyph::ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) {
+	return __super::ApplyTextStyle(font, scale * 1.3, state);
+}
+
+static CRect CheckBoxRect(CRect rc) {
+	if (rc.Width() > rc.Height()) {
+		rc.right = rc.left + rc.Height();
+	}
+	return rc;
+}
+
+LONG CListCell_Checkbox::AccRole()  {
+	return m_radio ? ROLE_SYSTEM_RADIOBUTTON : ROLE_SYSTEM_CHECKBUTTON;
+}
+
+CRect CListCell_Checkbox::HotRect( CRect rc ) {
+	return CheckBoxRect( rc );
+}
+
+void CListCell_Checkbox::DrawContent( DrawContentArg_t const & arg ) {
+	
+	CDCHandle dc = arg.dc;
+	
+	// const bool bPressed = (arg.cellState & cellState_pressed) != 0;
+	// const bool bHot = (arg.cellState & cellState_hot) != 0;
+	
+
+	// CRect clip = arg.rcText;
+
+	const uint32_t fgWas = dc.GetTextColor();
+
+	if (arg.subItemRect.Width() > arg.subItemRect.Height() ) {
+		CRect rcCheckbox = arg.subItemRect;
+		rcCheckbox.right = rcCheckbox.left + rcCheckbox.Height();
+		RenderCheckbox(arg.theme, dc, rcCheckbox, arg.cellState, m_radio );
+		CRect rcText = arg.subItemRect;
+		rcText.left = rcCheckbox.right;
+		if (arg.cellState & cellState_disabled) {
+			dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT));
+		}
+
+		if (arg.imageRenderer && rcText.Width() > rcText.Height()) {
+			CRect rcImage = rcText; rcImage.right = rcImage.left + rcImage.Height();
+			arg.imageRenderer(dc, rcImage);
+			rcText.left = rcImage.right;
+		}
+
+		dc.DrawText(arg.text, (int) wcslen(arg.text), rcText, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_LEFT);
+	} else {
+		RenderCheckbox(arg.theme, dc, arg.subItemRect, arg.cellState, m_radio );
+	}
+
+	dc.SetTextColor(fgWas);
+}
+
+void CListCell_Text_FixedColor::DrawContent(DrawContentArg_t const & arg) {
+	if (arg.allowColors) {
+		SetTextColorScope scope(arg.dc, m_col);
+		__super::DrawContent(arg);
+	} else {
+		__super::DrawContent(arg);
+	}
+}
+
+uint32_t CListCell_Combo::EditFlags() {
+	return InPlaceEdit::KFlagCombo;
+}
+
+void CListCell_Combo::DrawContent(DrawContentArg_t const & arg) {
+	CDCHandle dc = arg.dc;
+
+	const bool bDisabled = (arg.cellState & CListCell::cellState_disabled) != 0;
+	const bool bPressed = (arg.cellState & cellState_pressed) != 0;
+	const bool bHot = (arg.cellState & cellState_hot) != 0;
+
+	const int part = CP_DROPDOWNBUTTONRIGHT;
+
+	const HTHEME theme = arg.theme;
+
+	const int w = MulDiv(16, GetDeviceCaps(dc, LOGPIXELSX), 96);
+	CRect rcText = arg.rcText;
+	if (theme != NULL && IsThemePartDefined(theme, part, 0)) {
+		int state = CBXSR_NORMAL;
+		if (bDisabled) {
+			state = CBXSR_DISABLED;
+		} else if (bPressed) {
+			state = CBXSR_PRESSED;
+		} else if (bHot) {
+			state = CBXSR_HOT;
+		}
+
+		CSize size;
+		CRect rcCombo = arg.subItemRect;
+		if (w < rcCombo.Width()) {
+			rcCombo.left = rcCombo.right - w;
+			DrawThemeBackground(theme, dc, part, state, rcCombo, &rcCombo);
+			if (rcCombo.left < rcText.right ) rcText.right = rcCombo.left;
+		}
+	} else {
+		CRect rcCombo = arg.subItemRect;
+		if (w < rcCombo.Width()) {
+			rcCombo.left = rcCombo.right - w;
+			if (rcCombo.left < rcText.right) rcText.right = rcCombo.left;
+
+			if (bHot) {
+				DrawFrameControl(dc, rcCombo, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_HOT);
+			}
+			dc.DrawText(L"˅", 1, rcCombo, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
+		}
+
+	}
+
+	DrawContentArg_t arg2 = arg;
+	arg2.rcText = rcText;
+	PFC_SINGLETON(CListCell_Text).DrawContent(arg2);
+}
+
+LONG CListCell_Combo::AccRole() {
+	return ROLE_SYSTEM_DROPLIST;
+}
\ No newline at end of file