|
1
|
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 } |