comparison 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
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #include "stdafx.h"
2 #include "CListControl.h"
3 #include "CListControlHeaderImpl.h"
4 #include "CListControl-Cells.h"
5 #include "PaintUtils.h"
6 #include "GDIUtils.h"
7 #include <vsstyle.h>
8 #include "InPlaceEdit.h"
9 #include "DarkMode.h"
10
11 #define PRETEND_CLASSIC_THEME 0
12
13
14 #if PRETEND_CLASSIC_THEME
15 #define IsThemePartDefined(A,B,C) false
16 #endif
17
18 LONG CListCell::AccRole() {
19 return ROLE_SYSTEM_LISTITEM;
20 }
21
22 void RenderCheckbox( HTHEME theme, CDCHandle dc, CRect rcCheckBox, unsigned stateFlags, bool bRadio ) {
23
24 const int part = bRadio ? BP_RADIOBUTTON : BP_CHECKBOX;
25
26 const bool bDisabled = (stateFlags & CListCell::cellState_disabled) != 0;
27 const bool bPressed = (stateFlags & CListCell::cellState_pressed ) != 0;
28 const bool bHot = ( stateFlags & CListCell::cellState_hot ) != 0;
29
30 if (theme != NULL && IsThemePartDefined(theme, part, 0)) {
31 int state = 0;
32 if (bDisabled) {
33 state = bPressed ? CBS_CHECKEDDISABLED : CBS_UNCHECKEDDISABLED;
34 } else if ( bHot ) {
35 state = bPressed ? CBS_CHECKEDHOT : CBS_UNCHECKEDHOT;
36 } else {
37 state = bPressed ? CBS_CHECKEDNORMAL : CBS_UNCHECKEDNORMAL;
38 }
39
40 CSize size;
41 if (SUCCEEDED(GetThemePartSize(theme, dc, part, state, rcCheckBox, TS_TRUE, &size))) {
42 if (size.cx <= rcCheckBox.Width() && size.cy <= rcCheckBox.Height()) {
43 CRect rc = rcCheckBox;
44 rc.left += ( rc.Width() - size.cx ) / 2;
45 rc.top += ( rc.Height() - size.cy ) / 2;
46 rc.right = rc.left + size.cx;
47 rc.bottom = rc.top + size.cy;
48 DrawThemeBackground(theme, dc, part, state, rc, &rc);
49 return;
50 }
51 }
52 }
53
54 auto DPI = QueryContextDPI(dc);
55 CSize size(MulDiv(13, DPI.cx, 96), MulDiv(13, DPI.cy, 96));
56 CSize sizeBig = rcCheckBox.Size();
57 if (sizeBig.cx >= size.cx && sizeBig.cy >= size.cy) {
58 CPoint center = rcCheckBox.CenterPoint();
59 rcCheckBox.left = center.x - size.cx / 2; rcCheckBox.right = rcCheckBox.left + size.cx;
60 rcCheckBox.top = center.y - size.cy / 2; rcCheckBox.bottom = rcCheckBox.top + size.cy;
61 }
62
63 int stateEx = bRadio ? DFCS_BUTTONRADIO : DFCS_BUTTONCHECK;
64 if ( bPressed ) stateEx |= DFCS_CHECKED;
65 if ( bDisabled ) stateEx |= DFCS_INACTIVE;
66 else if ( bHot ) stateEx |= DFCS_HOT;
67 DrawFrameControl(dc, rcCheckBox, DFC_BUTTON, stateEx);
68 }
69
70 void RenderButton( HTHEME theme, CDCHandle dc, CRect rcButton, CRect rcUpdate, uint32_t cellState ) {
71
72 const int part = BP_PUSHBUTTON;
73
74 enum {
75 stNormal = PBS_NORMAL,
76 stHot = PBS_HOT,
77 stDisabled = PBS_DISABLED,
78 stPressed = PBS_PRESSED,
79 };
80
81 int state = 0;
82 if (cellState & CListCell::cellState_disabled) state = stDisabled;
83 if ( cellState & CListCell::cellState_pressed ) state = stPressed;
84 else if ( cellState & CListCell::cellState_hot ) state = stHot;
85 else state = stNormal;
86
87 CRect rcClient = rcButton;
88
89 if (theme != NULL && IsThemePartDefined(theme, part, 0)) {
90 DrawThemeBackground(theme, dc, part, state, rcClient, &rcUpdate);
91 } else {
92 int stateEx = DFCS_BUTTONPUSH;
93 switch (state) {
94 case stPressed: stateEx |= DFCS_PUSHED; break;
95 case stDisabled: stateEx |= DFCS_INACTIVE; break;
96 }
97 DrawFrameControl(dc, rcClient, DFC_BUTTON, stateEx);
98 }
99 }
100
101 bool CListCell::ApplyTextStyle( LOGFONT & font, double scale, uint32_t ) {
102 if ( scale != 1.0 ) {
103 font.lfHeight = pfc::rint32( font.lfHeight * scale );
104 return true;
105 } else {
106 return false;
107 }
108 }
109
110 void CListCell_Text::DrawContent( DrawContentArg_t const & arg ) {
111 const auto fgWas = arg.dc.GetTextColor();
112 CDCHandle dc = arg.dc;
113 if ((arg.cellState & cellState_disabled) != 0 && arg.allowColors) {
114 dc.SetTextColor(DarkMode::GetSysColor(COLOR_GRAYTEXT, arg.darkMode));
115 }
116
117 CRect clip = arg.rcText;
118
119 if (arg.imageRenderer && clip.Width() > clip.Height() ) {
120 CRect rcImage = clip; rcImage.right = rcImage.left + clip.Height();
121 arg.imageRenderer(dc, rcImage);
122 clip.left = rcImage.right;
123 }
124
125 const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat);
126 dc.DrawText( arg.text, (int)wcslen(arg.text), clip, format | DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER );
127
128 dc.SetTextColor(fgWas);
129 }
130
131 void CListCell_TextColors::DrawContent( DrawContentArg_t const & arg ) {
132 CDCHandle dc = arg.dc;
133
134 CRect clip = arg.rcText;
135
136 const uint32_t fgWas = dc.GetTextColor();
137
138 const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat);
139 const t_uint32 bk = dc.GetBkColor();
140 const t_uint32 fg = fgWas;
141 const t_uint32 hl = (arg.allowColors ? arg.colorHighlight : fg);
142 const t_uint32 colors[3] = { PaintUtils::BlendColor(bk, fg, 33), fg, hl };
143
144 PaintUtils::TextOutColorsEx(dc, arg.text, clip, format, colors);
145
146 dc.SetTextColor(fgWas);
147 }
148
149 void CListCell_MultiText::DrawContent( DrawContentArg_t const & arg ) {
150 CDCHandle dc = arg.dc;
151
152 const int textLen = (int) wcslen( arg.text );
153
154 CRect clip = arg.rcText;
155
156 const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat) | DT_NOPREFIX | DT_VCENTER ;
157
158 CRect rcDraw = clip;
159 dc.DrawText(arg.text, textLen, rcDraw, format | DT_CALCRECT);
160 auto txSize = rcDraw.Size();
161 rcDraw = clip;
162 if ( txSize.cy < rcDraw.Height() ) {
163 int sub = rcDraw.Height() - txSize.cy;
164 rcDraw.top += sub/2;
165 rcDraw.bottom = rcDraw.top + txSize.cy;
166 }
167 dc.DrawText(arg.text, textLen, rcDraw, format);
168 }
169
170 bool CListCell_Hyperlink::ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) {
171 bool rv = __super::ApplyTextStyle(font, scale, state);
172
173 if ( state & cellState_hot ) {
174 font.lfUnderline = TRUE;
175 rv = true;
176 }
177
178 return rv;
179 }
180
181 HCURSOR CListCell_Hyperlink::HotCursor() {
182 return LoadCursor(NULL, IDC_HAND);
183 }
184
185 LONG CListCell_Hyperlink::AccRole() {
186 return ROLE_SYSTEM_LINK;
187 }
188
189 void CListCell_Hyperlink::DrawContent( DrawContentArg_t const & arg ) {
190
191 CDCHandle dc = arg.dc;
192
193 const uint32_t fgWas = dc.GetTextColor();
194
195 const t_uint32 format = PaintUtils::DrawText_TranslateHeaderAlignment(arg.hdrFormat);
196 if (arg.allowColors) dc.SetTextColor( arg.colorHighlight );
197 // const t_uint32 bk = dc.GetBkColor();
198
199 CRect rc = arg.rcText;
200 dc.DrawText(arg.text, (int) wcslen(arg.text), rc, format | DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER );
201
202 dc.SetTextColor(fgWas);
203 }
204
205 LONG CListCell_Button::AccRole() {
206 return ROLE_SYSTEM_PUSHBUTTON;
207 }
208
209 void CListCell_Button::DrawContent( DrawContentArg_t const & arg ) {
210
211 CDCHandle dc = arg.dc;
212
213 const bool bPressed = (arg.cellState & cellState_pressed) != 0;
214 const bool bHot = (arg.cellState & cellState_hot) != 0;
215
216
217 if ( !m_lite || bHot || bPressed ) {
218 RenderButton( arg.theme, dc, arg.rcHot, arg.rcHot, arg.cellState );
219 }
220
221 CRect clip = arg.rcText;
222
223 dc.DrawText(arg.text, (int) wcslen(arg.text), clip, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_CENTER);
224 }
225
226 bool CListCell_ButtonGlyph::ApplyTextStyle( LOGFONT & font, double scale, uint32_t state ) {
227 return __super::ApplyTextStyle(font, scale * 1.3, state);
228 }
229
230 static CRect CheckBoxRect(CRect rc) {
231 if (rc.Width() > rc.Height()) {
232 rc.right = rc.left + rc.Height();
233 }
234 return rc;
235 }
236
237 LONG CListCell_Checkbox::AccRole() {
238 return m_radio ? ROLE_SYSTEM_RADIOBUTTON : ROLE_SYSTEM_CHECKBUTTON;
239 }
240
241 CRect CListCell_Checkbox::HotRect( CRect rc ) {
242 return CheckBoxRect( rc );
243 }
244
245 void CListCell_Checkbox::DrawContent( DrawContentArg_t const & arg ) {
246
247 CDCHandle dc = arg.dc;
248
249 // const bool bPressed = (arg.cellState & cellState_pressed) != 0;
250 // const bool bHot = (arg.cellState & cellState_hot) != 0;
251
252
253 // CRect clip = arg.rcText;
254
255 const uint32_t fgWas = dc.GetTextColor();
256
257 if (arg.subItemRect.Width() > arg.subItemRect.Height() ) {
258 CRect rcCheckbox = arg.subItemRect;
259 rcCheckbox.right = rcCheckbox.left + rcCheckbox.Height();
260 RenderCheckbox(arg.theme, dc, rcCheckbox, arg.cellState, m_radio );
261 CRect rcText = arg.subItemRect;
262 rcText.left = rcCheckbox.right;
263 if (arg.cellState & cellState_disabled) {
264 dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT));
265 }
266
267 if (arg.imageRenderer && rcText.Width() > rcText.Height()) {
268 CRect rcImage = rcText; rcImage.right = rcImage.left + rcImage.Height();
269 arg.imageRenderer(dc, rcImage);
270 rcText.left = rcImage.right;
271 }
272
273 dc.DrawText(arg.text, (int) wcslen(arg.text), rcText, DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER | DT_LEFT);
274 } else {
275 RenderCheckbox(arg.theme, dc, arg.subItemRect, arg.cellState, m_radio );
276 }
277
278 dc.SetTextColor(fgWas);
279 }
280
281 void CListCell_Text_FixedColor::DrawContent(DrawContentArg_t const & arg) {
282 if (arg.allowColors) {
283 SetTextColorScope scope(arg.dc, m_col);
284 __super::DrawContent(arg);
285 } else {
286 __super::DrawContent(arg);
287 }
288 }
289
290 uint32_t CListCell_Combo::EditFlags() {
291 return InPlaceEdit::KFlagCombo;
292 }
293
294 void CListCell_Combo::DrawContent(DrawContentArg_t const & arg) {
295 CDCHandle dc = arg.dc;
296
297 const bool bDisabled = (arg.cellState & CListCell::cellState_disabled) != 0;
298 const bool bPressed = (arg.cellState & cellState_pressed) != 0;
299 const bool bHot = (arg.cellState & cellState_hot) != 0;
300
301 const int part = CP_DROPDOWNBUTTONRIGHT;
302
303 const HTHEME theme = arg.theme;
304
305 const int w = MulDiv(16, GetDeviceCaps(dc, LOGPIXELSX), 96);
306 CRect rcText = arg.rcText;
307 if (theme != NULL && IsThemePartDefined(theme, part, 0)) {
308 int state = CBXSR_NORMAL;
309 if (bDisabled) {
310 state = CBXSR_DISABLED;
311 } else if (bPressed) {
312 state = CBXSR_PRESSED;
313 } else if (bHot) {
314 state = CBXSR_HOT;
315 }
316
317 CSize size;
318 CRect rcCombo = arg.subItemRect;
319 if (w < rcCombo.Width()) {
320 rcCombo.left = rcCombo.right - w;
321 DrawThemeBackground(theme, dc, part, state, rcCombo, &rcCombo);
322 if (rcCombo.left < rcText.right ) rcText.right = rcCombo.left;
323 }
324 } else {
325 CRect rcCombo = arg.subItemRect;
326 if (w < rcCombo.Width()) {
327 rcCombo.left = rcCombo.right - w;
328 if (rcCombo.left < rcText.right) rcText.right = rcCombo.left;
329
330 if (bHot) {
331 DrawFrameControl(dc, rcCombo, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_HOT);
332 }
333 dc.DrawText(L"˅", 1, rcCombo, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
334 }
335
336 }
337
338 DrawContentArg_t arg2 = arg;
339 arg2.rcText = rcText;
340 PFC_SINGLETON(CListCell_Text).DrawContent(arg2);
341 }
342
343 LONG CListCell_Combo::AccRole() {
344 return ROLE_SYSTEM_DROPLIST;
345 }