Mercurial > foo_out_sdl
comparison foosdk/sdk/libPPUI/PaintUtils.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 <vsstyle.h> | |
| 3 | |
| 4 #include "PaintUtils.h" | |
| 5 #include "gdiplus_helpers.h" | |
| 6 | |
| 7 #include "GDIUtils.h" | |
| 8 #include "win32_op.h" | |
| 9 #include "wtl-pp.h" | |
| 10 | |
| 11 namespace PaintUtils { | |
| 12 static t_uint16 extractChannel16(t_uint32 p_color,int p_which) throw() { | |
| 13 return (t_uint16)( ((p_color >> (p_which * 8)) & 0xFF) << 8 ); | |
| 14 } | |
| 15 | |
| 16 static t_uint8 extractbyte(t_uint32 p_val,t_size p_which) throw() { | |
| 17 return (t_uint8) ( (p_val >> (p_which * 8)) & 0xFF ); | |
| 18 } | |
| 19 | |
| 20 t_uint32 BlendColorEx(t_uint32 p_color1, t_uint32 p_color2, double mix) throw() { | |
| 21 PFC_ASSERT(mix >= 0 && mix <= 1); | |
| 22 t_uint32 ret = 0; | |
| 23 for(t_size walk = 0; walk < 3; ++walk) { | |
| 24 int val1 = extractbyte(p_color1,walk), val2 = extractbyte(p_color2,walk); | |
| 25 int val = val1 + pfc::rint32((val2 - val1) * mix); | |
| 26 ret |= (t_uint32)val << (walk * 8); | |
| 27 } | |
| 28 return ret; | |
| 29 } | |
| 30 t_uint32 BlendColor(t_uint32 p_color1, t_uint32 p_color2, int p_percentage) throw() { | |
| 31 PFC_ASSERT(p_percentage <= 100); | |
| 32 t_uint32 ret = 0; | |
| 33 for(t_size walk = 0; walk < 3; ++walk) { | |
| 34 int val1 = extractbyte(p_color1,walk), val2 = extractbyte(p_color2,walk); | |
| 35 int val = val1 + MulDiv(val2 - val1,p_percentage,100); | |
| 36 ret |= (t_uint32)val << (walk * 8); | |
| 37 } | |
| 38 return ret; | |
| 39 } | |
| 40 t_uint32 DriftColor(t_uint32 p_color,unsigned p_delta,bool p_direction) throw() { | |
| 41 t_uint32 ret = 0; | |
| 42 for(t_size walk = 0; walk < 3; ++walk) { | |
| 43 unsigned val = extractbyte(p_color,walk); | |
| 44 if (p_direction) val = 0xFF - val; | |
| 45 if (val < p_delta) val = p_delta; | |
| 46 val += p_delta; | |
| 47 if (val > 0xFF) val = 0xFF; | |
| 48 if (p_direction) val = 0xFF - val; | |
| 49 ret |= (t_uint32)val << (walk * 8); | |
| 50 } | |
| 51 return ret; | |
| 52 } | |
| 53 | |
| 54 void FillVertexColor(TRIVERTEX & p_vertex,t_uint32 p_color,t_uint16 p_alpha) throw() { | |
| 55 p_vertex.Red = extractChannel16(p_color,0); | |
| 56 p_vertex.Green = extractChannel16(p_color,1); | |
| 57 p_vertex.Blue = extractChannel16(p_color,2); | |
| 58 p_vertex.Alpha = p_alpha; | |
| 59 } | |
| 60 | |
| 61 void FillRectSimple(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_color) throw() { | |
| 62 p_dc.FillSolidRect(p_rect, p_color); | |
| 63 } | |
| 64 | |
| 65 void GradientFillRect(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_color1, t_uint32 p_color2, bool p_horizontal) throw() { | |
| 66 TRIVERTEX verticies[2]; | |
| 67 GRADIENT_RECT element = {0,1}; | |
| 68 FillVertexColor(verticies[0],p_color1); | |
| 69 FillVertexColor(verticies[1],p_color2); | |
| 70 verticies[0].x = p_rect.left; verticies[0].y = p_rect.top; | |
| 71 verticies[1].x = p_rect.right; verticies[1].y = p_rect.bottom; | |
| 72 p_dc.GradientFill(verticies,tabsize(verticies),&element,1,p_horizontal ? GRADIENT_FILL_RECT_H : GRADIENT_FILL_RECT_V); | |
| 73 } | |
| 74 | |
| 75 void GradientSplitRect(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_bkColor, t_uint32 p_gradientColor,int p_splitPercent) throw() { | |
| 76 const long split = p_rect.top + MulDiv(p_rect.Height(),p_splitPercent,100); | |
| 77 CRect rcTemp; | |
| 78 rcTemp = p_rect; | |
| 79 rcTemp.bottom = split; | |
| 80 GradientFillRect(p_dc,rcTemp,p_bkColor,p_gradientColor,false); | |
| 81 rcTemp = p_rect; | |
| 82 rcTemp.top = split; | |
| 83 GradientFillRect(p_dc,rcTemp,p_gradientColor,p_bkColor,false); | |
| 84 } | |
| 85 | |
| 86 void GradientBar(CDCHandle p_dc,const CRect & p_rect,t_uint32 p_exterior, t_uint32 p_interior, int p_percentage) throw() { | |
| 87 const int gradientPix = MulDiv(p_rect.Height(),p_percentage,100); | |
| 88 CRect rcTemp; | |
| 89 | |
| 90 rcTemp = p_rect; | |
| 91 rcTemp.bottom = rcTemp.top + gradientPix; | |
| 92 GradientFillRect(p_dc,rcTemp,p_exterior,p_interior,false); | |
| 93 | |
| 94 rcTemp = p_rect; | |
| 95 rcTemp.top += gradientPix; rcTemp.bottom -= gradientPix; | |
| 96 FillRectSimple(p_dc,rcTemp,p_interior); | |
| 97 | |
| 98 rcTemp = p_rect; | |
| 99 rcTemp.top = rcTemp.bottom - gradientPix; | |
| 100 GradientFillRect(p_dc,rcTemp,p_interior,p_exterior,false); | |
| 101 } | |
| 102 | |
| 103 void RenderItemBackground(CDCHandle p_dc,const CRect & p_itemRect,t_size p_item,t_uint32 p_color) throw() { | |
| 104 const DWORD bkColor_base = p_color; | |
| 105 const DWORD bkColor = DriftColor(bkColor_base,3, (p_item&1) != 0); | |
| 106 | |
| 107 //GradientSplitRect(p_dc,p_itemRect,bkColor,BlendColor(bkColor,textColor,7),80); | |
| 108 GradientBar(p_dc,p_itemRect,bkColor_base,bkColor,10); | |
| 109 } | |
| 110 | |
| 111 double Luminance(t_uint32 color) throw() { | |
| 112 double r = extractbyte(color,0), g = extractbyte(color,1), b = extractbyte(color,2); | |
| 113 return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255.0; | |
| 114 //return (r * 0.3 + g * 0.59 + b * 0.11) / 255.0; | |
| 115 } | |
| 116 t_uint32 DetermineTextColor(t_uint32 bk) throw() { | |
| 117 double l = Luminance(bk); | |
| 118 if ( l > 0.6 ) { | |
| 119 return 0; // black | |
| 120 } else { | |
| 121 return 0xFFFFFF; // white | |
| 122 } | |
| 123 } | |
| 124 | |
| 125 void AddRectToRgn(HRGN p_rgn,CRect const & p_rect) throw() { | |
| 126 CRgn temp; | |
| 127 WIN32_OP_D( temp.CreateRectRgnIndirect(p_rect) != NULL ); | |
| 128 CRgnHandle(p_rgn).CombineRgn(temp,RGN_OR); | |
| 129 } | |
| 130 | |
| 131 void FocusRect2(CDCHandle dc, CRect const & rect, COLORREF bkColor) throw() { | |
| 132 COLORREF txColor = DetermineTextColor( bkColor ); | |
| 133 COLORREF useColor = BlendColor(bkColor, txColor, 50); | |
| 134 CDCBrush brush(dc, useColor); | |
| 135 WIN32_OP_D( dc.FrameRect(rect,brush) ); | |
| 136 } | |
| 137 void FocusRect(CDCHandle dc, CRect const & rect) throw() { | |
| 138 CDCBrush brush(dc, 0x7F7F7F); | |
| 139 WIN32_OP_D( dc.FrameRect(rect,brush) ); | |
| 140 //dc.DrawFocusRect(rect); | |
| 141 } | |
| 142 | |
| 143 namespace TrackBar { | |
| 144 void DrawThumb(HTHEME theme,HDC dc,int state,const RECT * rcThumb, const RECT * rcUpdate) { | |
| 145 if (theme == NULL) { | |
| 146 RECT blah = *rcThumb; | |
| 147 int flags = DFCS_BUTTONPUSH; | |
| 148 switch(state) { | |
| 149 case TUS_NORMAL: | |
| 150 break; | |
| 151 case TUS_DISABLED: | |
| 152 flags |= DFCS_INACTIVE; | |
| 153 break; | |
| 154 case TUS_PRESSED: | |
| 155 flags |= DFCS_PUSHED; | |
| 156 break; | |
| 157 } | |
| 158 DrawFrameControl(dc,&blah,DFC_BUTTON,flags); | |
| 159 } else { | |
| 160 DrawThemeBackground(theme,dc,TKP_THUMB,state,rcThumb,rcUpdate); | |
| 161 } | |
| 162 } | |
| 163 void DrawTrack(HTHEME theme,HDC dc,const RECT * rcTrack, const RECT * rcUpdate) { | |
| 164 if (theme == NULL) { | |
| 165 RECT blah = *rcTrack; | |
| 166 DrawFrameControl(dc,&blah,DFC_BUTTON,DFCS_BUTTONPUSH|DFCS_PUSHED); | |
| 167 } else { | |
| 168 DrawThemeBackground(theme,dc,TKP_TRACK,TKS_NORMAL,rcTrack,rcUpdate); | |
| 169 } | |
| 170 } | |
| 171 void DrawTrack2(HDC p_dc, const CRect& rcTrack, const CRect& rcUpdate, COLORREF clrHighlight, COLORREF clrShadow) { | |
| 172 CRect rc(*rcTrack); | |
| 173 #if 1 | |
| 174 CDCHandle dc(p_dc); | |
| 175 SelectObjectScope scope(dc, GetStockObject(DC_PEN)); | |
| 176 dc.SetDCPenColor(clrHighlight); | |
| 177 dc.MoveTo(rc.left, rc.bottom); | |
| 178 dc.LineTo(rc.right, rc.bottom); | |
| 179 dc.LineTo(rc.right, rc.top); | |
| 180 dc.SetDCPenColor(clrShadow); | |
| 181 dc.LineTo(rc.left, rc.top); | |
| 182 dc.LineTo(rc.left, rc.bottom); | |
| 183 #else | |
| 184 try { | |
| 185 Gdiplus::Point points[] = { Gdiplus::Point(rc.left, rc.bottom), Gdiplus::Point(rc.right, rc.bottom), Gdiplus::Point(rc.right, rc.top), Gdiplus::Point(rc.left, rc.top)}; | |
| 186 GdiplusErrorHandler eh; | |
| 187 Gdiplus::Graphics graphics(p_dc); | |
| 188 eh << graphics.GetLastStatus(); | |
| 189 Gdiplus::Color c; | |
| 190 c.SetFromCOLORREF(clrHighlight); | |
| 191 Gdiplus::Pen penHL(c); | |
| 192 c.SetFromCOLORREF(clrShadow); | |
| 193 Gdiplus::Pen penSH(c); | |
| 194 eh << graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); | |
| 195 eh << graphics.DrawLine(&penHL, points[0], points[1]); | |
| 196 eh << graphics.DrawLine(&penHL, points[1], points[2]); | |
| 197 eh << graphics.DrawLine(&penSH, points[2], points[3]); | |
| 198 eh << graphics.DrawLine(&penSH, points[3], points[0]); | |
| 199 } catch (std::exception const& e) { | |
| 200 (void)e; | |
| 201 PFC_ASSERT(!"???"); | |
| 202 // console::print(e.what()); | |
| 203 } | |
| 204 #endif | |
| 205 } | |
| 206 void DrawTrackVolume2(HDC p_dc, const CRect& rcTrack, const CRect& rcUpdate, COLORREF clrHighlight, COLORREF clrShadow) { | |
| 207 CRect rc(rcTrack); | |
| 208 | |
| 209 try { | |
| 210 Gdiplus::Point points[] = { Gdiplus::Point(rc.left, rc.bottom), Gdiplus::Point(rc.right, rc.bottom), Gdiplus::Point(rc.right, rc.top) }; | |
| 211 GdiplusErrorHandler eh; | |
| 212 Gdiplus::Graphics graphics(p_dc); | |
| 213 eh << graphics.GetLastStatus(); | |
| 214 Gdiplus::Color c; | |
| 215 c.SetFromCOLORREF(clrHighlight); | |
| 216 Gdiplus::Pen penHL(c); | |
| 217 c.SetFromCOLORREF(clrShadow); | |
| 218 Gdiplus::Pen penSH(c); | |
| 219 eh << graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); | |
| 220 //graphics.DrawPolygon(&pen,points,tabsize(points)); | |
| 221 eh << graphics.DrawLine(&penSH, points[0], points[0] + Gdiplus::Point(0, -1)); | |
| 222 eh << graphics.DrawLine(&penHL, points[0], points[1]); | |
| 223 eh << graphics.DrawLine(&penHL, points[1], points[2]); | |
| 224 eh << graphics.DrawLine(&penSH, points[2], points[0] + Gdiplus::Point(0, -1)); | |
| 225 } catch (std::exception const& e) { | |
| 226 (void)e; | |
| 227 PFC_ASSERT(!"???"); | |
| 228 // console::print(e.what()); | |
| 229 } | |
| 230 } | |
| 231 void DrawTrackVolume(HTHEME theme,HDC p_dc,const CRect & rcTrack, const CRect & rcUpdate) { | |
| 232 (void)theme; // disregarded | |
| 233 DrawTrackVolume2(p_dc, rcTrack, rcUpdate, GetSysColor(COLOR_BTNHIGHLIGHT), GetSysColor(COLOR_BTNSHADOW)); | |
| 234 } | |
| 235 } | |
| 236 | |
| 237 void DrawSmoothedLine(HDC dc, CPoint pt1, CPoint pt2, COLORREF col, double width) { | |
| 238 try { | |
| 239 Gdiplus::Point points[] = { Gdiplus::Point(pt1.x,pt1.y), Gdiplus::Point(pt2.x,pt2.y) }; | |
| 240 GdiplusErrorHandler eh; | |
| 241 Gdiplus::Graphics graphics(dc); | |
| 242 eh << graphics.GetLastStatus(); | |
| 243 Gdiplus::Color c; | |
| 244 c.SetFromCOLORREF( col ); | |
| 245 Gdiplus::Pen pen(c, (Gdiplus::REAL)( width )); | |
| 246 eh << graphics.SetSmoothingMode(Gdiplus::SmoothingModeHighQuality); | |
| 247 //graphics.DrawPolygon(&pen,points,tabsize(points)); | |
| 248 eh << graphics.DrawLine(&pen, points[0], points[1]); | |
| 249 } catch(std::exception const & e) { | |
| 250 (void) e; | |
| 251 PFC_ASSERT(!"???"); | |
| 252 // console::print(e.what()); | |
| 253 } | |
| 254 } | |
| 255 | |
| 256 | |
| 257 | |
| 258 static int get_text_width(HDC dc,const TCHAR * src,int len) { | |
| 259 if (len<=0) return 0; | |
| 260 else { | |
| 261 SIZE goatse; | |
| 262 GetTextExtentPoint32(dc,src,len,&goatse); | |
| 263 return goatse.cx; | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 static t_uint32 TextOutColors_TranslateColor(const t_uint32 colors[3], int offset) { | |
| 268 const double v = (double)offset / 3.0; | |
| 269 if (v <= -1) return colors[0]; | |
| 270 else if (v < 0) return BlendColorEx(colors[0], colors[1], v + 1); | |
| 271 else if (v == 0) return colors[1]; | |
| 272 else if (v < 1) return BlendColorEx(colors[1], colors[2], v); | |
| 273 else return colors[2]; | |
| 274 } | |
| 275 | |
| 276 void TextOutColors_StripCodesAppend(pfc::string_formatter & out, const char * in) { | |
| 277 t_size done = 0, walk = 0; | |
| 278 for(;;) { | |
| 279 if (in[walk] == 0) { | |
| 280 if (walk > done) out.add_string_nc(in + done, walk - done); | |
| 281 return; | |
| 282 } | |
| 283 if ((unsigned)in[walk] < 32) { | |
| 284 if (walk > done) {out.add_string_nc(in + done, walk - done);} | |
| 285 done = walk + 1; | |
| 286 } | |
| 287 ++walk; | |
| 288 } | |
| 289 } | |
| 290 void TextOutColors_StripCodes(pfc::string_formatter & out, const char * in) { | |
| 291 out.reset(); TextOutColors_StripCodesAppend(out, in); | |
| 292 } | |
| 293 | |
| 294 static bool IsControlChar(TCHAR c) { | |
| 295 return (unsigned)c < 32; | |
| 296 } | |
| 297 static int MatchTruncat(HDC dc, int & pixels, const TCHAR * text, int textLen) { | |
| 298 int min = 0, max = textLen; | |
| 299 int minWidth = 0; | |
| 300 while(min + 1 < max) { | |
| 301 const int probe = (min + max) / 2; | |
| 302 CSize size; | |
| 303 WIN32_OP( GetTextExtentPoint32(dc, text, probe, &size) ); | |
| 304 if (size.cx <= pixels) {min = probe; minWidth = size.cx;} | |
| 305 else max = probe; | |
| 306 } | |
| 307 pixels = minWidth; | |
| 308 return min; | |
| 309 } | |
| 310 static int TruncatHeadroom(HDC dc) { | |
| 311 CSize size; | |
| 312 WIN32_OP( GetTextExtentPoint32(dc, _T("\x2026"), 1, &size) ); | |
| 313 return size.cx; | |
| 314 } | |
| 315 static void ExtTextOut_Truncat(HDC dc, int x, int y, CRect const & clip, const TCHAR * text, int textLen) { | |
| 316 int width = pfc::max_t<int>(0, clip.right - x - TruncatHeadroom(dc)); | |
| 317 int truncat = MatchTruncat(dc, width, text, textLen); | |
| 318 WIN32_OP( ExtTextOut(dc, x, y, ETO_CLIPPED, &clip, text, truncat, NULL) ); | |
| 319 WIN32_OP( ExtTextOut(dc, x + width, y, ETO_CLIPPED, &clip, _T("\x2026"), 1, NULL) ); | |
| 320 | |
| 321 | |
| 322 } | |
| 323 bool TextContainsCodes(const TCHAR * src) { | |
| 324 for(;;) { | |
| 325 if (*src == 0) return false; | |
| 326 if ((unsigned)*src < 32) return true; | |
| 327 ++src; | |
| 328 } | |
| 329 } | |
| 330 void TextOutColorsEx(HDC dc,const TCHAR * src,const CRect & target,DWORD flags,const t_uint32 colors[3]) { | |
| 331 if (!TextContainsCodes(src)) { | |
| 332 SetTextColorScope cs(dc, colors[1]); | |
| 333 CRect rc(target); | |
| 334 CDCHandle(dc).DrawText(src,(int)_tcslen(src),rc,DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | flags); | |
| 335 } else { | |
| 336 const CSize textSize = PaintUtils::TextOutColors_CalcSize(dc, src); | |
| 337 CPoint origin = target.TopLeft(); | |
| 338 origin.y = (target.top + target.bottom - textSize.cy) / 2; | |
| 339 switch(flags & (DT_LEFT | DT_RIGHT | DT_CENTER)) { | |
| 340 case DT_LEFT: | |
| 341 break; | |
| 342 case DT_RIGHT: | |
| 343 if (textSize.cx < target.Width()) origin.x = target.right - textSize.cx; | |
| 344 break; | |
| 345 case DT_CENTER: | |
| 346 if (textSize.cx < target.Width()) origin.x = (target.right + target.left - textSize.cx) / 2; | |
| 347 break; | |
| 348 } | |
| 349 TextOutColors(dc, src, (int)_tcslen(src), origin, target, colors); | |
| 350 } | |
| 351 } | |
| 352 void TextOutColors(HDC dc,const TCHAR * src,int len,CPoint offset,const CRect & clip,const t_uint32 colors[3], int tabWidthTotal, int tabWidthDiv) { | |
| 353 SetTextAlign(dc,TA_LEFT); | |
| 354 SetBkMode(dc,TRANSPARENT); | |
| 355 | |
| 356 | |
| 357 int walk = 0; | |
| 358 int position = offset.x; | |
| 359 int colorOffset = 0; | |
| 360 int tabs = 0; | |
| 361 int positionTabDelta = 0; | |
| 362 | |
| 363 for(;;) { | |
| 364 int base = walk; | |
| 365 while(walk < len && !IsControlChar(src[walk])) ++walk; | |
| 366 if (walk>base) { | |
| 367 SetTextColor(dc,TextOutColors_TranslateColor(colors, colorOffset)); | |
| 368 int width = get_text_width(dc,src+base,walk-base); | |
| 369 if (position + width > clip.right) { | |
| 370 ExtTextOut_Truncat(dc, position, offset.y, clip, src + base, walk - base); | |
| 371 return; | |
| 372 } | |
| 373 WIN32_OP( ExtTextOut(dc,position,offset.y,ETO_CLIPPED,&clip,src+base,walk-base,0) ); | |
| 374 position += width; | |
| 375 } | |
| 376 if (walk>=len) break; | |
| 377 | |
| 378 while(walk < len && IsControlChar(src[walk])) { | |
| 379 if (src[walk] == TextOutColors_Dim) --colorOffset; | |
| 380 else if (src[walk] == TextOutColors_Highlight) ++colorOffset; | |
| 381 else if (src[walk] == '\t') { | |
| 382 int newDelta = MulDiv(++tabs, tabWidthTotal, tabWidthDiv); | |
| 383 position += newDelta - positionTabDelta; | |
| 384 positionTabDelta = newDelta; | |
| 385 } | |
| 386 walk++; | |
| 387 } | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 CSize TextOutColors_CalcSize(HDC dc, const TCHAR * src) { | |
| 392 CSize acc(0,0); | |
| 393 for(int walk = 0;;) { | |
| 394 const int done = walk; | |
| 395 while(!IsControlChar(src[walk])) ++walk; | |
| 396 if (walk > done) { | |
| 397 CSize temp; | |
| 398 WIN32_OP( GetTextExtentPoint32(dc,src + done, walk - done, &temp) ); | |
| 399 acc.cx += temp.cx; pfc::max_acc(acc.cy, temp.cy); | |
| 400 } | |
| 401 if (src[walk] == 0) return acc; | |
| 402 while(src[walk] != 0 && IsControlChar(src[walk])) ++walk; | |
| 403 } | |
| 404 } | |
| 405 t_uint32 TextOutColors_CalcWidth(HDC dc, const TCHAR * src) { | |
| 406 t_uint32 acc = 0; | |
| 407 for(int walk = 0;;) { | |
| 408 const int done = walk; | |
| 409 while(!IsControlChar(src[walk])) ++walk; | |
| 410 acc += get_text_width(dc, src + done, walk - done); | |
| 411 if (src[walk] == 0) return acc; | |
| 412 while(src[walk] != 0 && IsControlChar(src[walk])) ++walk; | |
| 413 } | |
| 414 } | |
| 415 | |
| 416 pfc::string TextOutColors_ImportScript(pfc::string script) { | |
| 417 pfc::string_formatter temp; TextOutColors_ImportScript(temp, script.ptr()); return temp.get_ptr(); | |
| 418 } | |
| 419 void TextOutColors_ImportScript(pfc::string_base & out, const char * in) { | |
| 420 out.reset(); | |
| 421 for(;;) { | |
| 422 t_size delta; t_uint32 c; | |
| 423 delta = pfc::utf8_decode_char(in, c); | |
| 424 if (delta == 0) break; | |
| 425 switch(c) { | |
| 426 case '>': | |
| 427 c = PaintUtils::TextOutColors_Highlight; | |
| 428 break; | |
| 429 case '<': | |
| 430 c = PaintUtils::TextOutColors_Dim; | |
| 431 break; | |
| 432 } | |
| 433 out.add_char(c); | |
| 434 in += delta; | |
| 435 } | |
| 436 } | |
| 437 t_uint32 DrawText_TranslateHeaderAlignment(t_uint32 val) { | |
| 438 switch(val & HDF_JUSTIFYMASK) { | |
| 439 case HDF_LEFT: | |
| 440 default: | |
| 441 return DT_LEFT; | |
| 442 case HDF_RIGHT: | |
| 443 return DT_RIGHT; | |
| 444 case HDF_CENTER: | |
| 445 return DT_CENTER; | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 void RenderButton(HWND wnd_, HDC dc_, CRect rcUpdate, bool bPressed) { | |
| 450 CDCHandle dc(dc_); CWindow wnd(wnd_); | |
| 451 CTheme theme; theme.OpenThemeData(wnd, L"BUTTON"); | |
| 452 | |
| 453 RelayEraseBkgnd(wnd, wnd.GetParent(), dc); | |
| 454 | |
| 455 const int part = BP_PUSHBUTTON; | |
| 456 | |
| 457 enum { | |
| 458 stNormal = PBS_NORMAL, | |
| 459 stHot = PBS_HOT, | |
| 460 stDisabled = PBS_DISABLED, | |
| 461 stPressed = PBS_PRESSED, | |
| 462 }; | |
| 463 | |
| 464 int state = 0; | |
| 465 if (!wnd.IsWindowEnabled()) state = stDisabled; | |
| 466 else if (bPressed) state = stPressed; | |
| 467 else state = stNormal; | |
| 468 | |
| 469 CRect rcClient; WIN32_OP_D( wnd.GetClientRect(rcClient) ); | |
| 470 | |
| 471 if (theme != NULL && IsThemePartDefined(theme, part, 0)) { | |
| 472 DrawThemeBackground(theme, dc, part, state, rcClient, &rcUpdate); | |
| 473 } else { | |
| 474 int stateEx = DFCS_BUTTONPUSH; | |
| 475 switch(state) { | |
| 476 case stPressed: stateEx |= DFCS_PUSHED; break; | |
| 477 case stDisabled: stateEx |= DFCS_INACTIVE; break; | |
| 478 } | |
| 479 DrawFrameControl(dc, rcClient, DFC_BUTTON, stateEx); | |
| 480 } | |
| 481 } | |
| 482 | |
| 483 | |
| 484 void PaintSeparatorControl(HWND wnd_) { | |
| 485 CWindow wnd(wnd_); | |
| 486 CPaintDC dc(wnd); | |
| 487 TCHAR buffer[512] = {}; | |
| 488 wnd.GetWindowText(buffer, _countof(buffer)); | |
| 489 const int txLen = (int) pfc::strlen_max_t(buffer, _countof(buffer)); | |
| 490 CRect contentRect; | |
| 491 WIN32_OP_D(wnd.GetClientRect(contentRect)); | |
| 492 | |
| 493 dc.SetTextColor(GetSysColor(COLOR_WINDOWTEXT)); | |
| 494 dc.SetBkMode(TRANSPARENT); | |
| 495 | |
| 496 { | |
| 497 CBrushHandle brush = (HBRUSH)wnd.GetParent().SendMessage(WM_CTLCOLORSTATIC, (WPARAM)(HDC)dc, (LPARAM)wnd.m_hWnd); | |
| 498 if (brush != NULL) dc.FillRect(contentRect, brush); | |
| 499 } | |
| 500 SelectObjectScope scopeFont(dc, wnd.GetFont()); | |
| 501 | |
| 502 if (txLen > 0) { | |
| 503 CRect rcText(contentRect); | |
| 504 if (!wnd.IsWindowEnabled()) { | |
| 505 dc.SetTextColor(GetSysColor(COLOR_GRAYTEXT)); | |
| 506 } | |
| 507 WIN32_OP_D(dc.DrawText(buffer, txLen, rcText, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE | DT_VCENTER | DT_LEFT) > 0); | |
| 508 // WIN32_OP_D( dc.GrayString(NULL, NULL, (LPARAM) buffer, txLen, rcText.left, rcText.top, rcText.Width(), rcText.Height() ) ); | |
| 509 } | |
| 510 | |
| 511 SIZE txSize, probeSize; | |
| 512 const TCHAR probe[] = _T("#"); | |
| 513 if (dc.GetTextExtent(buffer, txLen, &txSize) && dc.GetTextExtent(probe, _countof(probe), &probeSize)) { | |
| 514 int spacing = txSize.cx > 0 ? (probeSize.cx / 4) : 0; | |
| 515 if (txSize.cx + spacing < contentRect.Width()) { | |
| 516 const CPoint center = contentRect.CenterPoint(); | |
| 517 CRect rcEdge(contentRect.left + txSize.cx + spacing, center.y, contentRect.right, contentRect.bottom); | |
| 518 WIN32_OP_D(dc.DrawEdge(rcEdge, EDGE_ETCHED, BF_TOP)); | |
| 519 } | |
| 520 } | |
| 521 } | |
| 522 } | |
| 523 |
