4#include "Stroika/Frameworks/StroikaPreComp.h"
13#include "Stroika/Foundation/Execution/Throw.h"
21using namespace Stroika::Frameworks;
22using namespace Stroika::Frameworks::Led;
24#if qStroika_Platform_Windows
32#if qStroika_Platform_Windows
34#define qUseGetCharPlacementToImage_ 1
37#if qStroika_Platform_Windows
42#ifndef qUseDIBSectionForOffscreenBitmap_
43#define qUseDIBSectionForOffscreenBitmap_ 1
47#if qStroika_Platform_Windows
48inline bool operator== (PALETTEENTRY lhs, COLORREF rhs)
50 return RGB (lhs.peRed, lhs.peGreen, lhs.peBlue) == rhs;
54#if !qStroika_Frameworks_Led_HaveWindowsDIBDefined
60#if qStroika_Platform_Windows
62const bool kRunning32BitGDI =
true;
64const bool kRunning32BitGDI = ((::GetVersion () & 0x80000000) == 0);
68#if qStroika_Platform_Windows
69inline void Win32_GetTextExtentExPoint (HDC hdc,
const Led_tChar* str,
size_t nChars,
int maxExtent, LPINT lpnFit, LPINT alpDx, LPSIZE lpSize)
71 Require (nChars <
static_cast<size_t> (numeric_limits<int>::max ()));
72 Verify (::GetTextExtentExPointW (hdc, str,
static_cast<int> (nChars), maxExtent, lpnFit, alpDx, lpSize));
74inline void Win32_GetTextExtentPoint (HDC hdc,
const Led_tChar* str,
int nChars, LPSIZE lpSize)
76 Verify (::GetTextExtentPointW (hdc, str, nChars, lpSize));
78inline void Win32_TextOut (HDC hdc,
int xStart,
int yStart,
const Led_tChar* str,
int nChars)
80 Verify (::TextOutW (hdc, xStart, yStart, str, nChars));
85 inline bool IS_WIN30_DIB (
const Led_DIB* dib)
89 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
90 return Led_ByteSwapFromWindows (hdr.biSize) ==
sizeof (BITMAPINFOHEADER);
92 inline size_t DIBNumColors (
const Led_DIB* dib)
96 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
103 if (IS_WIN30_DIB (dib)) {
104 unsigned long clrUsed = Led_ByteSwapFromWindows (hdr.biClrUsed);
113 unsigned short bitCount = IS_WIN30_DIB (dib) ? Led_ByteSwapFromWindows (hdr.biBitCount)
114 : Led_ByteSwapFromWindows (((const BITMAPCOREHEADER*)dib)->bcBitCount);
130#if qStroika_Platform_Windows
133 inline RGBQUAD mkRGBQuad (COLORREF c)
136 r.rgbBlue = GetBValue (c);
137 r.rgbGreen = GetGValue (c);
138 r.rgbRed = GetRValue (c);
142 inline void MaybeAddColorRefToTable_ (RGBQUAD colorTable[256],
size_t* iP, COLORREF c)
144 Assert (
sizeof (RGBQUAD) ==
sizeof (COLORREF));
145 COLORREF* ct =
reinterpret_cast<COLORREF*
> (colorTable);
146 if (find (ct, ct + *iP, c) == ct + *iP and c != RGB (255, 255, 255)) {
147 colorTable[*iP] = mkRGBQuad (c);
152 void CreateStandardColorTable (RGBQUAD colorTable[256], COLORREF c1 = RGB (0, 0, 0), COLORREF c2 = RGB (0, 0, 0),
153 COLORREF c3 = RGB (0, 0, 0), COLORREF c4 = RGB (0, 0, 0))
158 (void)::memset (colorTable, 0,
sizeof (RGBQUAD) * 256);
160 const BYTE kColorSpecVals[] = {0, 32, 64, 128, 192, 255};
161 const size_t kColorSpecValCnt =
sizeof (kColorSpecVals) /
sizeof (kColorSpecVals[0]);
172 for (; i < 256; ++i) {
173 colorTable[i].rgbRed = kColorSpecVals[redIdx];
174 colorTable[i].rgbGreen = kColorSpecVals[greenIdx];
175 colorTable[i].rgbBlue = kColorSpecVals[blueIdx];
177 if (blueIdx >= kColorSpecValCnt) {
180 if (greenIdx >= kColorSpecValCnt) {
183 if (redIdx >= kColorSpecValCnt) {
184 Assert (i == kColorSpecValCnt * kColorSpecValCnt * kColorSpecValCnt - 1);
197 size_t nColorsLeft = 255 - i;
198 Assert (nColorsLeft == 41);
202 MaybeAddColorRefToTable_ (colorTable, &i, c1);
203 MaybeAddColorRefToTable_ (colorTable, &i, c2);
204 MaybeAddColorRefToTable_ (colorTable, &i, c3);
205 MaybeAddColorRefToTable_ (colorTable, &i, c4);
207 nColorsLeft = 255 - i;
208 Assert (nColorsLeft > 0);
210 size_t aveSpace = 255 / nColorsLeft;
212 BYTE startAt =
static_cast<BYTE
> (aveSpace);
213 while (i < 254 and startAt < 255) {
214 COLORREF c = RGB (startAt, startAt, startAt);
215 Assert (
sizeof (RGBQUAD) ==
sizeof (COLORREF));
216 COLORREF* ct =
reinterpret_cast<COLORREF*
> (colorTable);
217 if (find (ct, ct + i, c) == ct + i) {
218 colorTable[i] = mkRGBQuad (c);
222 startAt +=
static_cast<BYTE
> (aveSpace);
225 Assert (nColorsLeft == 255 - i);
227 Assert (nColorsLeft < 5);
228 Assert (nColorsLeft >= 1);
230 for (; i <= 255; ++i) {
231 colorTable[i].rgbRed =
static_cast<BYTE
> (i);
232 colorTable[i].rgbGreen =
static_cast<BYTE
> (i);
233 colorTable[i].rgbBlue =
static_cast<BYTE
> (i);
237 HPALETTE CreatePaletteForColorTable (
const RGBQUAD colorTable[256])
243 LPLOGPALETTE lplgPal =
reinterpret_cast<LPLOGPALETTE
> (
static_cast<char*
> (palBuf));
245 lplgPal->palVersion = 0x300;
246 lplgPal->palNumEntries = 256;
248 for (
size_t i = 0; i <= 255; ++i) {
249 lplgPal->palPalEntry[i].peRed = colorTable[i].rgbRed;
250 lplgPal->palPalEntry[i].peGreen = colorTable[i].rgbGreen;
251 lplgPal->palPalEntry[i].peBlue = colorTable[i].rgbBlue;
252 lplgPal->palPalEntry[i].peFlags = 0;
254 return ::CreatePalette (lplgPal);
257 HPALETTE CreateStandardPalette (COLORREF c1, COLORREF c2, COLORREF c3, COLORREF c4)
259 RGBQUAD colorTable[256];
260 CreateStandardColorTable (colorTable, c1, c2, c3, c4);
261 return CreatePaletteForColorTable (colorTable);
264 HBITMAP Create8BitDIBSection (HDC refDC, DWORD dwX, DWORD dwY,
const RGBQUAD* colorTable =
nullptr, LPBYTE* ppBits =
nullptr)
266 LPBYTE ignored =
nullptr;
267 if (ppBits ==
nullptr) {
271 const WORD wBits = 8;
273 RGBQUAD colorTableBuf[256];
274 if (colorTable ==
nullptr) {
275 CreateStandardColorTable (colorTableBuf);
276 colorTable = colorTableBuf;
280 size_t nInfoSize =
sizeof (BITMAPINFOHEADER) +
sizeof (RGBQUAD) * (1 << wBits);
282 LPBITMAPINFO pbmi =
reinterpret_cast<LPBITMAPINFO
> (
static_cast<char*
> (bmiBuf));
283 (void)::memset (pbmi, 0, nInfoSize);
284 pbmi->bmiHeader.biSize =
sizeof (BITMAPINFOHEADER);
285 pbmi->bmiHeader.biWidth = dwX;
286 pbmi->bmiHeader.biHeight = dwY;
287 pbmi->bmiHeader.biPlanes = 1;
288 pbmi->bmiHeader.biBitCount = wBits;
289 pbmi->bmiHeader.biCompression = BI_RGB;
291 for (
int i = 0; i < 256; ++i) {
292 pbmi->bmiColors[i].rgbRed = colorTable[i].rgbRed;
293 pbmi->bmiColors[i].rgbGreen = colorTable[i].rgbGreen;
294 pbmi->bmiColors[i].rgbBlue = colorTable[i].rgbBlue;
295 pbmi->bmiColors[i].rgbReserved = 0;
297 pbmi->bmiHeader.biClrUsed = 256;
299 return ::CreateDIBSection (refDC, pbmi, DIB_RGB_COLORS, (
void**)ppBits,
nullptr, 0);
302 HBITMAP Create16BitDIBSection (HDC refDC, DWORD dwX, DWORD dwY)
305 size_t nInfoSize =
sizeof (BITMAPINFOHEADER) + 3 *
sizeof (DWORD);
307 LPBITMAPINFO pbmi =
reinterpret_cast<LPBITMAPINFO
> (
static_cast<char*
> (bmiBuf));
308 (void)::memset (pbmi, 0, nInfoSize);
309 pbmi->bmiHeader.biSize =
sizeof (BITMAPINFOHEADER);
310 pbmi->bmiHeader.biWidth = dwX;
311 pbmi->bmiHeader.biHeight = dwY;
312 pbmi->bmiHeader.biPlanes = 1;
313 pbmi->bmiHeader.biBitCount = 16;
317 LPDWORD pMasks = (LPDWORD)(pbmi->bmiColors);
318 pMasks[0] = 0x00007c00;
319 pMasks[1] = 0x000003e0;
320 pMasks[2] = 0x0000001f;
321 pbmi->bmiHeader.biCompression = BI_BITFIELDS;
324 return ::CreateDIBSection (refDC, pbmi, DIB_RGB_COLORS, (
void**)&pBits,
nullptr, 0);
327 HBITMAP Create32BitDIBSection (HDC refDC, DWORD dwX, DWORD dwY)
330 size_t nInfoSize =
sizeof (BITMAPINFOHEADER) + 3 *
sizeof (DWORD);
332 LPBITMAPINFO pbmi =
reinterpret_cast<LPBITMAPINFO
> (
static_cast<char*
> (bmiBuf));
333 (void)::memset (pbmi, 0, nInfoSize);
334 pbmi->bmiHeader.biSize =
sizeof (BITMAPINFOHEADER);
335 pbmi->bmiHeader.biWidth = dwX;
336 pbmi->bmiHeader.biHeight = dwY;
337 pbmi->bmiHeader.biPlanes = 1;
338 pbmi->bmiHeader.biBitCount = 32;
342 LPDWORD pMasks = (LPDWORD)(pbmi->bmiColors);
343 pMasks[0] = 0x00ff0000;
344 pMasks[1] = 0x0000ff00;
345 pMasks[2] = 0x000000ff;
346 pbmi->bmiHeader.biCompression = BI_BITFIELDS;
349 return ::CreateDIBSection (refDC, pbmi, DIB_RGB_COLORS, (
void**)&pBits,
nullptr, 0);
354#if qStroika_Platform_Windows
360BOOL Bitmap::CreateCompatibleBitmap (HDC hdc, DistanceType nWidth, DistanceType nHeight)
362 Assert (m_hObject ==
nullptr);
363 m_hObject = ::CreateCompatibleBitmap (hdc, nWidth, nHeight);
364 fImageSize = Led_Size (nHeight, nWidth);
365 return (m_hObject !=
nullptr);
368BOOL Bitmap::CreateCompatibleDIBSection (HDC hdc, DistanceType nWidth, DistanceType nHeight)
371 Require (m_hObject ==
nullptr);
374 fImageSize = Led_Size (nHeight, nWidth);
376 int deviceDepth = ::GetDeviceCaps (hdc, BITSPIXEL) * ::GetDeviceCaps (hdc, PLANES);
377 if (deviceDepth > 16) {
380 else if (deviceDepth <= 8) {
385 m_hObject = Create8BitDIBSection (hdc, nWidth, nHeight);
388 m_hObject = Create16BitDIBSection (hdc, nWidth, nHeight);
391 m_hObject = Create32BitDIBSection (hdc, nWidth, nHeight);
396 return m_hObject !=
nullptr;
399void Bitmap::LoadBitmap (HINSTANCE hInstance, LPCTSTR lpBitmapName)
401 Require (m_hObject ==
nullptr);
402 m_hObject = ::LoadBitmap (hInstance, lpBitmapName);
403 Execution::ThrowIfNull (m_hObject);
406 Verify (::GetObject (m_hObject,
sizeof (BITMAP), (LPVOID)&bm));
407 fImageSize = Led_Size (bm.bmHeight, bm.bmWidth);
421const Color Color::kWhite =
Color (Color::kColorValueMax, Color::kColorValueMax, Color::kColorValueMax);
422const Color Color::kRed =
Color (Color::kColorValueMax, 0, 0);
423const Color Color::kGreen =
Color (0, Color::kColorValueMax / 2, 0);
424const Color Color::kBlue =
Color (0, 0, Color::kColorValueMax);
425const Color Color::kCyan =
Color (0, Color::kColorValueMax, Color::kColorValueMax);
426const Color Color::kMagenta =
Color (Color::kColorValueMax, 0, Color::kColorValueMax);
427const Color Color::kYellow =
Color (Color::kColorValueMax, Color::kColorValueMax, 0);
428const Color Color::kMaroon =
Color (Color::kColorValueMax / 2, 0, 0);
429const Color Color::kOlive =
Color (Color::kColorValueMax / 2, Color::kColorValueMax / 2, 0);
430const Color Color::kNavyBlue =
Color (0, 0, Color::kColorValueMax / 2);
431const Color Color::kPurple =
Color (Color::kColorValueMax / 2, 0, Color::kColorValueMax / 2);
432const Color Color::kTeal =
Color (0, Color::kColorValueMax / 2, Color::kColorValueMax / 2);
433const Color Color::kGray =
Color (Color::kColorValueMax / 2, Color::kColorValueMax / 2, Color::kColorValueMax / 2);
434const Color Color::kSilver =
Color (Color::kColorValueMax * 3 / 4, Color::kColorValueMax * 3 / 4, Color::kColorValueMax * 3 / 4);
435const Color Color::kDarkGreen =
Color (0, (Color::kColorValueMax / 256) * 100, 0);
436const Color Color::kLimeGreen =
Color (0, Color::kColorValueMax, 0);
437const Color Color::kFuchsia = Color::kMagenta;
438const Color Color::kAqua = Color::kCyan;
450void FontSpecification::SetFontName (
const SDKString& fontName)
452#if qStroika_Platform_Windows
453 Characters::CString::Copy (fFontInfo.lfFaceName, std::size (fFontInfo.lfFaceName), fontName.c_str ());
454 fFontInfo.lfCharSet = DEFAULT_CHARSET;
458#if qStroika_Platform_Windows
461 Characters::CString::Copy (fName, std::size (fName),
from);
465void FontSpecification::SetFontNameSpecifier (FontNameSpecifier fontNameSpecifier)
467#if qStroika_Platform_Windows
468 Characters::CString::Copy (fFontInfo.lfFaceName, std::size (fFontInfo.lfFaceName), fontNameSpecifier.fName);
469 fFontInfo.lfCharSet = DEFAULT_CHARSET;
473#if qStroika_Platform_Windows
474struct FontSelectionInfo {
475 FontSelectionInfo (BYTE desiredCharset)
476 : fDesiredCharset (desiredCharset)
477 , fUsesBestCharset (false)
479 , fIsANSI_VAR_Font (false)
480 , fIsGoodBackupCharset (false)
481 , fIsFavoriteForCharset (false)
482 , fIsVariablePitch (false)
483 , fStartsWithAt (false)
485 memset (&fBestFont, 0,
sizeof (fBestFont));
487 BYTE fDesiredCharset;
489 bool fUsesBestCharset;
491 bool fIsANSI_VAR_Font;
492 bool fIsGoodBackupCharset;
493 bool fIsFavoriteForCharset;
494 bool fIsVariablePitch;
496 inline int Score ()
const
499 if (fUsesBestCharset) {
505 if (fIsANSI_VAR_Font) {
508 if (fIsGoodBackupCharset) {
511 if (fIsFavoriteForCharset) {
514 if (fIsVariablePitch) {
524static int FAR PASCAL EnumFontCallback (
const LOGFONT* lplf,
const TEXTMETRIC* , DWORD fontType, LPARAM arg)
528 FontSelectionInfo& result = *(FontSelectionInfo*)arg;
530 static LOGFONT theANSILogFont;
531 if (theANSILogFont.lfFaceName[0] ==
'\0') {
532 HFONT xxx = HFONT (::GetStockObject (ANSI_VAR_FONT));
533 Verify (::GetObject (xxx,
sizeof theANSILogFont, &theANSILogFont));
536 FontSelectionInfo potentialResult = result;
537 memcpy (&potentialResult.fBestFont, lplf, sizeof (LOGFONT));
539 if (potentialResult.fDesiredCharset == DEFAULT_CHARSET) {
540 potentialResult.fUsesBestCharset = bool (lplf->lfCharSet == theANSILogFont.lfCharSet);
543 potentialResult.fUsesBestCharset = bool (lplf->lfCharSet == potentialResult.fDesiredCharset);
545 potentialResult.fIsTT = bool (fontType & TRUETYPE_FONTTYPE);
546 potentialResult.fIsANSI_VAR_Font = ::_tcscmp (lplf->lfFaceName, theANSILogFont.lfFaceName) == 0;
547 potentialResult.fIsGoodBackupCharset = (lplf->lfCharSet == DEFAULT_CHARSET or lplf->lfCharSet == theANSILogFont.lfCharSet);
549 switch (potentialResult.fDesiredCharset) {
550 case SHIFTJIS_CHARSET: {
551 if (potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS P Gothic")} or
552 potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS Gothic")} or
553 potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS PGothic")}) {
554 potentialResult.fIsFavoriteForCharset =
true;
557 case CHINESEBIG5_CHARSET: {
558 if (potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MS HEI")} or
559 potentialResult.fBestFont.lfFaceName ==
SDKString{Led_SDK_TCHAROF (
"MingLiU")}) {
560 potentialResult.fIsFavoriteForCharset =
true;
565 potentialResult.fIsVariablePitch = lplf->lfPitchAndFamily & VARIABLE_PITCH;
566 potentialResult.fStartsWithAt = lplf->lfFaceName[0] ==
'@';
568 if (potentialResult.Score () > result.Score ()) {
569 result = potentialResult;
578 static bool sDefaultFontValid =
false;
580 if (not sDefaultFontValid) {
581#if qStroika_Platform_Windows
582 sDefaultFont = GetStaticDefaultFont (DEFAULT_CHARSET);
584#if qStroika_Platform_Windows
585 sDefaultFont.SetTextColor (Led_GetTextColor ());
587 sDefaultFontValid =
true;
589 return (sDefaultFont);
592#if qStroika_Platform_Windows
608 FontSelectionInfo selectedFont (charSet);
609 WindowDC screenDC (
nullptr);
611 ::EnumFontFamilies (screenDC.m_hDC,
nullptr, EnumFontCallback,
reinterpret_cast<LPARAM
> (&selectedFont));
613 ::EnumFontFamilies (screenDC.m_hDC,
nullptr,
reinterpret_cast<FONTENUMPROC
> (EnumFontCallback),
reinterpret_cast<LPARAM
> (&selectedFont));
615 fooo.LightSetOSRep (selectedFont.fBestFont);
620 static LOGFONT theANSILogFont;
621 if (theANSILogFont.lfFaceName[0] ==
'\0') {
622 HFONT xxx = HFONT (::GetStockObject (ANSI_VAR_FONT));
623 Verify (::GetObject (xxx,
sizeof theANSILogFont, &theANSILogFont));
625 fooo.SetPointSize (min (max (
FontSpecification (theANSILogFont).GetPointSize (),
static_cast<unsigned short> (8)),
626 static_cast<unsigned short> (14)));
629 defaultFont.MergeIn (fooo);
630 defaultFont.SetTextColor (Led_GetTextColor ());
631 return (defaultFont);
640IncrementalFontSpecification Led::Intersection (
const IncrementalFontSpecification& lhs,
const IncrementalFontSpecification& rhs)
642 IncrementalFontSpecification result = lhs;
646 if (not lhs.GetFontNameSpecifier_Valid () or not rhs.GetFontNameSpecifier_Valid () or
647 lhs.GetFontNameSpecifier () != rhs.GetFontNameSpecifier ()) {
648 result.InvalidateFontNameSpecifier ();
654 if (not lhs.GetStyle_Bold_Valid () or not rhs.GetStyle_Bold_Valid () or lhs.GetStyle_Bold () != rhs.GetStyle_Bold ()) {
655 result.InvalidateStyle_Bold ();
659 if (not lhs.GetStyle_Italic_Valid () or not rhs.GetStyle_Italic_Valid () or lhs.GetStyle_Italic () != rhs.GetStyle_Italic ()) {
660 result.InvalidateStyle_Italic ();
664 if (not lhs.GetStyle_Underline_Valid () or not rhs.GetStyle_Underline_Valid () or lhs.GetStyle_Underline () != rhs.GetStyle_Underline ()) {
665 result.InvalidateStyle_Underline ();
669 if (not lhs.GetStyle_SubOrSuperScript_Valid () or not rhs.GetStyle_SubOrSuperScript_Valid () or
670 lhs.GetStyle_SubOrSuperScript () != rhs.GetStyle_SubOrSuperScript ()) {
671 result.InvalidateStyle_SubOrSuperScript ();
674#if qStroika_Platform_Windows
676 if (not lhs.GetStyle_Strikeout_Valid () or not rhs.GetStyle_Strikeout_Valid () or lhs.GetStyle_Strikeout () != rhs.GetStyle_Strikeout ()) {
677 result.InvalidateStyle_Strikeout ();
684 if (not lhs.GetTextColor_Valid () or not rhs.GetTextColor_Valid () or lhs.GetTextColor () != rhs.GetTextColor ()) {
685 result.InvalidateTextColor ();
694 bool needsInval =
false;
695 if (lhs.GetPointSizeIncrement_Valid () != rhs.GetPointSizeIncrement_Valid () or
696 (lhs.GetPointSizeIncrement_Valid () and lhs.GetPointSizeIncrement () != rhs.GetPointSizeIncrement ())) {
699 if (lhs.GetPointSize_Valid () != rhs.GetPointSize_Valid () or (lhs.GetPointSize_Valid () and lhs.GetPointSize () != rhs.GetPointSize ())) {
703 result.InvalidatePointSize ();
710#if qStroika_Platform_Windows
716class Tablet::RecolorHelper {
718 RecolorHelper (HDC baseHDC, Led_Size size,
Color hilightBackColor,
Color hilightForeColor,
Color oldBackColor,
Color oldForeColor);
722 static RecolorHelper* CheckCacheAndReconstructIfNeeded (RecolorHelper* _THIS_, HDC baseHDC, Led_Size size,
Color hilightBackColor,
726 nonvirtual
void DoRecolor (
const Led_Rect& hilightArea);
729 nonvirtual
void DoRecolor_SimpleDSTINVERT (
const Led_Rect& hilightArea);
730 nonvirtual
void DoRecolor_SimplePATINVERT (
const Led_Rect& hilightArea);
733 nonvirtual
void DoRecolor_CopyTo8BitManualMungePixAndBack (
const Led_Rect& hilightArea);
736 nonvirtual
void MakeMappingTable ();
739 uint8_t fMappingTable[256];
742 nonvirtual uint8_t FindClosestColorInColorTable_ (COLORREF c)
const;
745 nonvirtual COLORREF MapColor (COLORREF c)
const;
746 nonvirtual COLORREF MapColor (RGBQUAD c)
const;
751 RGBQUAD fColorTable[256];
754 size_t fDibDataByteCount;
757 COLORREF fHilightBackColor;
758 COLORREF fHilightForeColor;
759 COLORREF fOldBackColor;
760 COLORREF fOldForeColor;
762COLORREF Tablet::RecolorHelper::MapColor (COLORREF c)
const
765 fIntrp = (float)(255 - GetRValue (c)) / 256.0f;
766 BYTE red =
static_cast<BYTE
> (GetRValue (fHilightBackColor) + fIntrp * GetRValue (fHilightForeColor) - fIntrp * GetRValue (fHilightBackColor));
768 fIntrp = (float)(255 - GetGValue (c)) / 256.0f;
769 BYTE green =
static_cast<BYTE
> (GetGValue (fHilightBackColor) + fIntrp * GetGValue (fHilightForeColor) - fIntrp * GetGValue (fHilightBackColor));
771 fIntrp = (float)(255 - GetBValue (c)) / 256.0f;
772 BYTE blue =
static_cast<BYTE
> (GetBValue (fHilightBackColor) + fIntrp * GetBValue (fHilightForeColor) - fIntrp * GetBValue (fHilightBackColor));
773 return RGB (red, green, blue);
775inline COLORREF Tablet::RecolorHelper::MapColor (RGBQUAD c)
const
777 return MapColor (RGB (c.rgbRed, c.rgbGreen, c.rgbBlue));
780Tablet::RecolorHelper::RecolorHelper (HDC baseHDC, Led_Size size,
Color hilightBackColor,
Color hilightForeColor,
Color oldBackColor,
Color oldForeColor)
783 , fDibDataByteCount (0)
788 , fDibSection (nullptr)
789 , fOldBitmap (nullptr)
790 , fHilightBackColor (hilightBackColor.GetOSRep ())
791 , fHilightForeColor (hilightForeColor.GetOSRep ())
792 , fOldBackColor (oldBackColor.GetOSRep ())
793 , fOldForeColor (oldForeColor.GetOSRep ())
795 CreateStandardColorTable (fColorTable, fHilightBackColor, fHilightForeColor, fOldBackColor, fOldForeColor);
796 fDibSection = Create8BitDIBSection (baseHDC, size.h, size.v, fColorTable, &fDibData);
798 Verify (::GetObject (fDibSection,
sizeof (BITMAP), &bm) ==
sizeof (BITMAP));
799 fDibDataByteCount = bm.bmWidthBytes * bm.bmHeight;
800 fHMemDC = ::CreateCompatibleDC (fBaseDC);
801 fOldBitmap =
reinterpret_cast<HBITMAP
> (::SelectObject (fHMemDC, fDibSection));
805Tablet::RecolorHelper::~RecolorHelper ()
807 if (fDibSection !=
nullptr) {
808 ::SelectObject (fHMemDC, fOldBitmap);
809 ::DeleteDC (fHMemDC);
810 ::DeleteObject (fDibSection);
814Tablet::RecolorHelper* Tablet::RecolorHelper::CheckCacheAndReconstructIfNeeded (RecolorHelper* _THIS_, HDC baseHDC, Led_Size size,
Color hilightBackColor,
817 if (_THIS_ ==
nullptr or size.h > _THIS_->fSize.h or size.v > _THIS_->fSize.v or baseHDC != _THIS_->fBaseDC or
818 hilightBackColor.GetOSRep () != _THIS_->fHilightBackColor or hilightForeColor.GetOSRep () != _THIS_->fHilightForeColor or
819 oldBackColor.GetOSRep () != _THIS_->fOldBackColor or oldForeColor.GetOSRep () != _THIS_->fOldForeColor) {
820 Led_Size areaSize = size;
821 if (_THIS_ !=
nullptr) {
822 areaSize.v = max (size.v, _THIS_->fSize.v);
823 areaSize.h = max (size.h, _THIS_->fSize.h);
825 RecolorHelper* tmp =
new RecolorHelper (baseHDC, areaSize, hilightBackColor, hilightForeColor, oldBackColor, oldForeColor);
832void Tablet::RecolorHelper::MakeMappingTable ()
834 for (
size_t i = 0; i < 256; ++i) {
835 fMappingTable[i] = FindClosestColorInColorTable_ (MapColor (fColorTable[i]));
839uint8_t Tablet::RecolorHelper::FindClosestColorInColorTable_ (COLORREF c)
const
843 unsigned int closestDistance = 0xffffffff;
844 for (
size_t i = 0; i < 256; ++i) {
845 unsigned int thisDist = Distance_Squared (c, RGB (fColorTable[i].rgbRed, fColorTable[i].rgbGreen, fColorTable[i].rgbBlue));
846 if (thisDist < closestDistance) {
847 closest =
static_cast<uint8_t
> (i);
848 closestDistance = thisDist;
849 if (closestDistance == 0) {
857void Tablet::RecolorHelper::DoRecolor (
const Led_Rect& hilightArea)
859 HPALETTE hPal =
nullptr;
860 HPALETTE hOldPal =
nullptr;
861 bool isPaletteDevice = !!(::GetDeviceCaps (fBaseDC, RASTERCAPS) & RC_PALETTE);
862 if (isPaletteDevice) {
866 hPal = CreatePaletteForColorTable (fColorTable);
867 Execution::ThrowIfNull (hPal);
868 hOldPal = ::SelectPalette (fBaseDC, hPal, TRUE);
869 ::RealizePalette (fBaseDC);
872 DoRecolor_CopyTo8BitManualMungePixAndBack (hilightArea);
874 if (isPaletteDevice) {
875 if (hOldPal !=
nullptr) {
876 ::SelectPalette (fBaseDC, hOldPal, TRUE);
878 ::DeleteObject (hPal);
882void Tablet::RecolorHelper::DoRecolor_SimpleDSTINVERT (
const Led_Rect& hilightArea)
887 ::BitBlt (fBaseDC, hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (), fBaseDC, hilightArea.left,
888 hilightArea.top, DSTINVERT);
891void Tablet::RecolorHelper::DoRecolor_SimplePATINVERT (
const Led_Rect& hilightArea)
895 Color useColor = Color::kWhite -
Color (fHilightBackColor);
896 HGDIOBJ oldPen = ::SelectObject (fBaseDC, ::GetStockObject (NULL_PEN));
897 Brush backgroundBrush (useColor.GetOSRep ());
898 HGDIOBJ oldBrush = ::SelectObject (fBaseDC, backgroundBrush);
899 ::BitBlt (fBaseDC, hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (), fBaseDC, hilightArea.left,
900 hilightArea.top, PATINVERT);
901 (void)::SelectObject (fBaseDC, oldPen);
902 (void)::SelectObject (fBaseDC, oldBrush);
905void Tablet::RecolorHelper::DoRecolor_CopyTo8BitManualMungePixAndBack (
const Led_Rect& hilightArea)
913 ::BitBlt (fHMemDC, 0, 0, hilightArea.GetWidth (), hilightArea.GetHeight (), fBaseDC, hilightArea.left, hilightArea.top, SRCCOPY);
934 const unsigned char* kMappingTable = fMappingTable;
935 unsigned char* dataStart = fDibData;
936 unsigned char* dataEnd = dataStart + fDibDataByteCount;
937 for (
unsigned char* i = dataStart; i < dataEnd; ++i) {
938 *i = kMappingTable[*i];
943 ::BitBlt (fBaseDC, hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (), fHMemDC, 0, 0, SRCCOPY);
947#if qStroika_Frameworks_Led_SupportGDI
953#if qStroika_Platform_Windows
954Tablet::Tablet (HDC hdc, Tablet::OwnDCControl ownsDC)
956 , fRecolorHelper (nullptr)
958 , m_bPrinting (false)
968#if qStroika_Platform_Windows
969 delete fRecolorHelper;
970 if (m_hDC !=
nullptr and fOwnsDC == eOwnsDC) {
971 ::DeleteDC (Detach ());
981Led_Point Tablet::CvtFromTWIPS (TWIPS_Point from)
const
983 return Led_Point{CvtFromTWIPSV (from.v), CvtFromTWIPSH (from.h)};
991TWIPS_Point Tablet::CvtToTWIPS (Led_Point from)
const
993 return TWIPS_Point{CvtToTWIPSV (from.v), CvtToTWIPSH (from.h)};
1001Led_Rect Tablet::CvtFromTWIPS (TWIPS_Rect from)
const
1003 return Led_Rect{CvtFromTWIPS (from.GetOrigin ()), Led_Size (CvtFromTWIPS (from.GetSize ()))};
1011TWIPS_Rect Tablet::CvtToTWIPS (Led_Rect from)
const
1013 return TWIPS_Rect{CvtToTWIPS (from.GetOrigin ()), CvtToTWIPS (Led_Point (from.GetSize ()))};
1021void Tablet::ScrollBitsAndInvalRevealed (
const Led_Rect& windowRect, CoordinateType scrollVBy)
1023#if qStroika_Platform_Windows
1024 RECT gdiMoveRect = AsRECT (windowRect);
1027 HWND w = GetWindow ();
1028 Execution::ThrowIfNull (w);
1029 ::ScrollWindow (w, 0, scrollVBy, &gdiMoveRect, &gdiMoveRect);
1039void Tablet::FrameRegion (
const Region& r,
const Color& c)
1041#if qStroika_Platform_Windows
1042 Brush brush = Brush (c.GetOSRep ());
1043 (void)::FrameRgn (*
this, r, brush, 1, 1);
1057void Tablet::FrameRectangle (
const Led_Rect& r,
Color c, DistanceType borderWidth)
1063 Led_Rect topBar = Led_Rect (r.top, r.left, borderWidth, r.GetWidth ());
1064 Led_Rect leftBar = Led_Rect (r.top, r.left, r.GetHeight (), borderWidth);
1065 EraseBackground_SolidHelper (topBar, c);
1066 EraseBackground_SolidHelper (leftBar, c);
1067 EraseBackground_SolidHelper (topBar + Led_Point (r.GetHeight () - borderWidth, 0), c);
1068 EraseBackground_SolidHelper (leftBar + Led_Point (0, r.GetWidth () - borderWidth), c);
1079void Tablet::MeasureText (
const FontMetrics& precomputedFontMetrics,
const Led_tChar* text,
size_t nTChars, DistanceType* charLocations)
1084#if qStroika_Platform_Windows
1085 DistanceType kMaxTextWidthResult = kRunning32BitGDI ? 0x7fffffff : 0x7fff;
1086 if (IsPrinting ()) {
1088 SIZE ve = GetViewportExt ();
1089 SIZE we = GetWindowExt ();
1090 kMaxTextWidthResult = ::MulDiv (kMaxTextWidthResult, we.cx, ve.cx) - 1;
1093 size_t kMaxChars = kMaxTextWidthResult / precomputedFontMetrics.GetMaxCharacterWidth ();
1094 Assert (kMaxChars > 1);
1096 DistanceType runningCharCount = 0;
1097 for (
size_t charsToGo = nTChars; charsToGo > 0;) {
1098 size_t i = nTChars - charsToGo;
1099 Assert (i < nTChars);
1101 while (text[i] ==
'\t') {
1102 Assert (charsToGo > 0);
1104 charLocations[i] = runningCharCount;
1106 if (--charsToGo == 0) {
1110 if (charsToGo == 0) {
1114 size_t charsThisTime = min (charsToGo, kMaxChars);
1115 for (
size_t tabIndex = 1; tabIndex < charsThisTime; tabIndex++) {
1116 if (text[i + tabIndex] ==
'\t') {
1117 charLocations[i + tabIndex] = runningCharCount;
1118 charsThisTime = tabIndex;
1123#if qStroika_Platform_Windows
1125 Assert (
sizeof (
int) ==
sizeof (DistanceType));
1127 Win32_GetTextExtentExPoint (m_hAttribDC, &text[i], charsThisTime, kMaxTextWidthResult,
nullptr, (
int*)&charLocations[i], &size);
1128 for (
size_t j = 0; j < charsThisTime; ++j) {
1129 charLocations[i + j] += runningCharCount;
1133 runningCharCount = charLocations[i + charsThisTime - 1];
1135 Assert (charsToGo >= charsThisTime);
1136 charsToGo -= charsThisTime;
1140#if qStroika_Platform_Windows && 0
1148 int lastWidth = (nTChars == 1) ? charLocations[0] : (charLocations[nTChars - 1] - charLocations[nTChars - 2]);
1151 Win32_GetTextExtentPoint (m_hAttribDC, &text[nTChars - 1], 1, &size);
1152 int sbWidth = size.cx;
1153 if (sbWidth != lastWidth) {
1154 charLocations[nTChars - 1] = ((nTChars == 1) ? 0 : charLocations[nTChars - 2]) + sbWidth;
1162 for (
size_t i = 0; i < nTChars; ++i) {
1163 Ensure (d <= charLocations[i]);
1164 d = charLocations[i];
1179void Tablet::TabbedTextOut ([[maybe_unused]]
const FontMetrics& precomputedFontMetrics,
const Led_tChar* text,
size_t nBytes,
1180 [[maybe_unused]] TextDirection direction, Led_Point outputAt, CoordinateType hTabOrigin,
1181 const TabStopList& tabStopList, DistanceType* amountDrawn, CoordinateType hScrollOffset)
1183 DistanceType widthSoFar = 0;
1184 const Led_tChar* textCursor = text;
1185 const Led_tChar* textEnd = text + nBytes;
1186 while (textCursor < textEnd) {
1188 const Led_tChar* nextTabAt = textCursor;
1189 for (; nextTabAt < textEnd;) {
1190 if (*nextTabAt ==
'\t') {
1197#if qStroika_Platform_Windows
1198 int oldBkMode = SetBkMode (TRANSPARENT);
1200 if (direction == eLeftToRight) {
1201 Win32_TextOut (m_hDC,
static_cast<int> (outputAt.h + widthSoFar - hScrollOffset),
static_cast<int> (outputAt.v), textCursor,
1202 static_cast<int> (nextTabAt - textCursor));
1210 if (amountDrawn !=
nullptr or (nextTabAt < textEnd)) {
1212 Win32_GetTextExtentPoint (m_hAttribDC, textCursor,
static_cast<int> (nextTabAt - textCursor), &size);
1213 widthSoFar += size.cx;
1221#if qUseGetCharPlacementToImage_
1223 size_t len = nextTabAt - textCursor;
1225 GCP_RESULTSW gcpResult;
1226 memset (&gcpResult, 0,
sizeof (gcpResult));
1227 gcpResult.lStructSize =
sizeof (GCP_RESULTS);
1228 gcpResult.lpGlyphs = glyphs.data ();
1229 gcpResult.nGlyphs =
static_cast<UINT
> (len);
1230 if (::GetCharacterPlacementW (m_hDC, textCursor,
static_cast<int> (len), 0, &gcpResult, GCP_GLYPHSHAPE | GCP_LIGATE) != 0) {
1231 Verify (::ExtTextOutW (m_hDC, outputAt.h + widthSoFar - hScrollOffset, outputAt.v, ETO_GLYPH_INDEX,
nullptr,
1232 gcpResult.lpGlyphs, gcpResult.nGlyphs,
nullptr));
1233 goto Succeeded_But_Need_To_Adjust_Width;
1239 size_t len = nextTabAt - textCursor;
1242 Verify (::ExtTextOutW (m_hDC, outputAt.h + widthSoFar - hScrollOffset, outputAt.v, 0,
nullptr, textCursor,
1243 static_cast<UINT
> (len),
nullptr));
1246 Succeeded_But_Need_To_Adjust_Width:
1253 if (amountDrawn !=
nullptr or (nextTabAt < textEnd)) {
1255 Win32_GetTextExtentPoint (m_hAttribDC, textCursor,
static_cast<int> (nextTabAt - textCursor), &size);
1256 widthSoFar += size.cx;
1260 (void)SetBkMode (oldBkMode);
1264 if (nextTabAt < textEnd) {
1265 DistanceType thisTabWidth;
1267 DistanceType curOutputAtZeroBased = (outputAt.h - hTabOrigin) + widthSoFar;
1268 DistanceType tabStop = tabStopList.ComputeTabStopAfterPosition (
this, curOutputAtZeroBased);
1269 thisTabWidth = tabStop - curOutputAtZeroBased;
1270 Assert (thisTabWidth >= 0);
1273 widthSoFar += thisTabWidth;
1276 textCursor = nextTabAt;
1278 if (amountDrawn !=
nullptr) {
1279 *amountDrawn = widthSoFar;
1283void Tablet::SetBackColor (
const Color& backColor)
1285#if qStroika_Platform_Windows
1286 SetBkColor (backColor.GetOSRep ());
1290void Tablet::SetForeColor (
const Color& foreColor)
1292#if qStroika_Platform_Windows
1293 SetTextColor (foreColor.GetOSRep ());
1302void Tablet::EraseBackground_SolidHelper (
const Led_Rect& eraseRect,
const Color& eraseColor)
1304 if (not eraseRect.IsEmpty ()) {
1305#if qStroika_Platform_Windows
1306 Led_Rect eraser = eraseRect;
1307 Brush backgroundBrush (eraseColor.GetOSRep ());
1308 GDI_Obj_Selector pen (
this, ::GetStockObject (NULL_PEN));
1309 GDI_Obj_Selector brush (
this, backgroundBrush);
1312 Rectangle (AsRECT (eraser));
1328void Tablet::HilightArea_SolidHelper (
const Led_Rect& hilightArea, [[maybe_unused]]
Color hilightBackColor,
1329 [[maybe_unused]]
Color hilightForeColor,
Color oldBackColor, [[maybe_unused]]
Color oldForeColor)
1331 if (not hilightArea.IsEmpty ()) {
1332#if qStroika_Platform_Windows
1336 if (hilightBackColor.GetOSRep () == Color::kBlack.GetOSRep () and hilightForeColor.GetOSRep () == Color::kWhite.GetOSRep () and
1337 oldBackColor.GetOSRep () == Color::kWhite.GetOSRep () and oldForeColor.GetOSRep () == Color::kBlack.GetOSRep ()) {
1342 BitBlt (hilightArea.left, hilightArea.top, hilightArea.GetWidth (), hilightArea.GetHeight (),
this, hilightArea.left,
1343 hilightArea.top, DSTINVERT);
1347 fRecolorHelper = RecolorHelper::CheckCacheAndReconstructIfNeeded (fRecolorHelper, m_hDC,
1348 Led_Size (hilightArea.GetHeight (), hilightArea.GetWidth ()),
1349 hilightBackColor, hilightForeColor, oldBackColor, oldForeColor);
1350 fRecolorHelper->DoRecolor (hilightArea);
1352 static RecolorHelper* recolorHelper =
nullptr;
1353 recolorHelper = RecolorHelper::CheckCacheAndReconstructIfNeeded (recolorHelper, m_hDC,
1354 Led_Size (hilightArea.GetHeight (), hilightArea.GetWidth ()),
1355 hilightBackColor, hilightForeColor, oldBackColor, oldForeColor);
1356 recolorHelper->DoRecolor (hilightArea);
1370void Tablet::HilightArea_SolidHelper (
const Region& hilightArea, [[maybe_unused]]
Color hilightBackColor, [[maybe_unused]]
Color hilightForeColor,
1371 [[maybe_unused]]
Color oldBackColor, [[maybe_unused]]
Color oldForeColor)
1373 if (not hilightArea.IsEmpty ()) {
1374#if qStroika_Platform_Windows
1384FontMetrics Tablet::GetFontMetrics ()
const
1386#if qStroika_Platform_Windows
1389 Verify (::GetTextMetrics (m_hAttribDC, &tms) != 0);
1399#if qStroika_Platform_Windows
1400OffscreenTablet::OT::OT (HDC hdc, Tablet::OwnDCControl ownsDC)
1401 : inherited (hdc, ownsDC)
1411OffscreenTablet::OffscreenTablet ()
1412 : fOrigTablet (nullptr)
1413 , fOffscreenRect (Led_Rect (0, 0, 0, 0))
1414 , fOffscreenTablet (nullptr)
1415#if qStroika_Platform_Windows
1418 , fOldBitmapInDC (nullptr)
1423OffscreenTablet::~OffscreenTablet ()
1425#if qStroika_Platform_Windows
1426 if (fOldBitmapInDC !=
nullptr) {
1427 (void)fMemDC.SelectObject (fOldBitmapInDC);
1438void OffscreenTablet::Setup (Tablet* origTablet)
1440 Require (fOrigTablet ==
nullptr);
1443 fOrigTablet = origTablet;
1444#if qStroika_Platform_Windows
1445 if (fMemDC.CreateCompatibleDC (fOrigTablet)) {
1446 fOffscreenTablet = &fMemDC;
1457Tablet* OffscreenTablet::PrepareRect (
const Led_Rect& currentRowRect, DistanceType extraToAddToBottomOfRect)
1459 Tablet* result = fOrigTablet;
1460#if qStroika_Platform_Windows
1461 if (fOffscreenTablet !=
nullptr) {
1462 fOffscreenRect = currentRowRect;
1463 fOffscreenRect.bottom += extraToAddToBottomOfRect;
1465 if (fMemoryBitmap ==
nullptr or (fOffscreenRect.GetSize () != fMemoryBitmap.GetImageSize ())) {
1468 if (fOldBitmapInDC !=
nullptr) {
1469 (void)fMemDC.SelectObject (fOldBitmapInDC);
1471 fMemoryBitmap.DeleteObject ();
1472#if qUseDIBSectionForOffscreenBitmap_
1473 if (fMemoryBitmap.CreateCompatibleDIBSection (fOrigTablet->m_hDC, fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight ()) == 0) {
1474 fOffscreenTablet =
nullptr;
1477 if (fMemoryBitmap.CreateCompatibleBitmap (fOrigTablet->m_hDC, fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight ()) == 0) {
1478 fOffscreenTablet =
nullptr;
1481 if (fOffscreenTablet !=
nullptr) {
1482 fOldBitmapInDC = fMemDC.SelectObject (fMemoryBitmap);
1483 if (fOldBitmapInDC ==
nullptr) {
1484 fOffscreenTablet =
nullptr;
1488 if (fOffscreenTablet !=
nullptr) {
1489 result = fOffscreenTablet;
1491 if (fOffscreenTablet !=
nullptr) {
1492 fMemDC.SetWindowOrg (fOffscreenRect.left, fOffscreenRect.top);
1504void OffscreenTablet::BlastBitmapToOrigTablet ()
1506 if (fOffscreenTablet !=
nullptr) {
1507#if qStroika_Platform_Windows
1508 Tablet* screenDC = fOrigTablet;
1509 screenDC->BitBlt (fOffscreenRect.left, fOffscreenRect.top, fOffscreenRect.GetWidth (), fOffscreenRect.GetHeight (),
1510 fOffscreenTablet, fOffscreenRect.left, fOffscreenRect.top, SRCCOPY);
1516#if qStroika_Frameworks_Led_SupportGDI
1523InstalledFonts::InstalledFonts (FilterOptions filterOptions)
1524 : fFilterOptions (filterOptions)
1527#if qStroika_Platform_Windows
1529 memset (&lf, 0,
sizeof (LOGFONT));
1530 lf.lfCharSet = DEFAULT_CHARSET;
1531 WindowDC screenDC (
nullptr);
1532 ::EnumFontFamiliesEx (screenDC.m_hDC, &lf, (FONTENUMPROC)FontFamilyAdderProc,
reinterpret_cast<LPARAM
> (
this), 0);
1533 sort (fFontNames.begin (), fFontNames.end ());
1534 vector<SDKString>::iterator rest = unique (fFontNames.begin (), fFontNames.end ());
1535 fFontNames.erase (rest, fFontNames.end ());
1541#if qStroika_Platform_Windows
1542BOOL FAR PASCAL InstalledFonts::FontFamilyAdderProc (ENUMLOGFONTEX* pelf, NEWTEXTMETRICEX* ,
int fontType, LPVOID pThis)
1544 InstalledFonts* thisP =
reinterpret_cast<InstalledFonts*
> (pThis);
1546 if (thisP->fFilterOptions & eSkipRasterFonts) {
1549 if (fontType & RASTER_FONTTYPE)
1552 if (thisP->fFilterOptions & eSkipAtSignFonts) {
1553 if (pelf->elfLogFont.lfFaceName[0] ==
'@')
1556 thisP->fFontNames.push_back (pelf->elfLogFont.lfFaceName);
1562#if qStroika_Frameworks_Led_SupportGDI
1570Globals* Globals::sThe =
nullptr;
1573class Globals::_Global_DESTRUCTOR_ {
1575 ~_Global_DESTRUCTOR_ ()
1577 delete (Globals::sThe);
1578 Globals::sThe =
nullptr;
1580} sTheLed_GDIGlobalsDESTRUCTOR_;
1586 InvalidateGlobals ();
1589void Globals::InvalidateGlobals ()
1593#if qStroika_Platform_Windows
1594 WindowDC screenDC (
nullptr);
1595 fLogPixelsH = ::GetDeviceCaps (screenDC, LOGPIXELSX);
1596 fLogPixelsV = ::GetDeviceCaps (screenDC, LOGPIXELSY);
1601#if qStroika_Frameworks_Led_SupportGDI
1607void Led::AddRectangleToRegion (Led_Rect addRect, Region* toRgn)
1610 *toRgn = *toRgn + Region (addRect);
1624Led_Size Led::Led_GetDIBImageSize (
const Led_DIB* dib)
1627 Assert (
sizeof (BITMAPINFOHEADER) == 40);
1628 Assert (
sizeof (BITMAPCOREHEADER) == 12);
1629 Assert (
sizeof (RGBTRIPLE) == 3);
1631 if (IS_WIN30_DIB (dib)) {
1632 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
1633 return (Led_Size (abs (Led_ByteSwapFromWindows (hdr.biHeight)), abs (Led_ByteSwapFromWindows (hdr.biWidth))));
1636 const BITMAPCOREHEADER& hdr = *(
reinterpret_cast<const BITMAPCOREHEADER*
> (dib));
1637 return (Led_Size (Led_ByteSwapFromWindows (hdr.bcHeight), Led_ByteSwapFromWindows (hdr.bcWidth)));
1646size_t Led::Led_GetDIBPalletByteCount (
const Led_DIB* dib)
1657 if (IS_WIN30_DIB (dib)) {
1658 size_t byteCount = DIBNumColors (dib) *
sizeof (RGBQUAD);
1659 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
1661 if (Led_ByteSwapFromWindows (hdr.biCompression) == BI_BITFIELDS) {
1662#if qStroika_Platform_Windows
1663 Assert (
sizeof (DWORD) ==
sizeof (
unsigned int));
1665 Assert (4 ==
sizeof (
unsigned int));
1666 byteCount += 3 *
sizeof (
unsigned int);
1671 Assert (
sizeof (RGBTRIPLE) == 3);
1672 return (DIBNumColors (dib) *
sizeof (RGBTRIPLE));
1685size_t Led::Led_GetDIBImageRowByteCount (
const Led_DIB* dib)
1688 Led_Size imageSize = Led_GetDIBImageSize (dib);
1689 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
1691 unsigned short bitCount = Led_ByteSwapFromWindows (hdr.biBitCount);
1692 return (((imageSize.h * bitCount + 31) & ~31) >> 3);
1704size_t Led::Led_GetDIBImageByteCount (
const Led_DIB* dib)
1707 Led_Size imageSize = Led_GetDIBImageSize (dib);
1708 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
1709 size_t byteCount = Led_ByteSwapFromWindows (hdr.biSize);
1711 byteCount += Led_GetDIBPalletByteCount (dib);
1713 unsigned long imageByteSize = Led_ByteSwapFromWindows (hdr.biSizeImage);
1714 if (imageByteSize == 0) {
1715 unsigned short bitCount = Led_ByteSwapFromWindows (hdr.biBitCount);
1718 imageByteSize = imageSize.v * (((imageSize.h * bitCount + 31) & ~31) >> 3);
1720 byteCount += imageByteSize;
1734Led_DIB* Led::Led_CloneDIB (
const Led_DIB* dib)
1737 size_t nBytes = Led_GetDIBImageByteCount (dib);
1738 Led_DIB* newDIB =
reinterpret_cast<Led_DIB*
> (
new char[nBytes]);
1739 (void)::memcpy (newDIB, dib, nBytes);
1752const void* Led::Led_GetDIBBitsPointer (
const Led_DIB* dib)
1755 const BITMAPINFOHEADER& hdr = dib->bmiHeader;
1756 return reinterpret_cast<const char*
> (dib) + Led_ByteSwapFromWindows (hdr.biSize) + Led_GetDIBPalletByteCount (dib);
1759#if qStroika_Platform_Windows
1765Led_DIB* Led::Led_DIBFromHBITMAP (HDC hDC, HBITMAP hbm)
1769 Verify (::GetObject (hbm,
sizeof (BITMAP), (LPVOID)&bm));
1771 Led_DIB* dibResult =
nullptr;
1773 BITMAPINFOHEADER bmiHdr;
1774 memset (&bmiHdr, 0,
sizeof (bmiHdr));
1775 bmiHdr.biSize =
sizeof (BITMAPINFOHEADER);
1776 bmiHdr.biWidth = bm.bmWidth;
1777 bmiHdr.biHeight = bm.bmHeight;
1778 bmiHdr.biPlanes = 1;
1779 bmiHdr.biBitCount = 24;
1780 bmiHdr.biCompression = BI_RGB;
1781 bmiHdr.biSizeImage = ((((bmiHdr.biWidth * bmiHdr.biBitCount) + 31) & ~31) >> 3) * bmiHdr.biHeight;
1782 size_t nBytes = Led_GetDIBImageByteCount (
reinterpret_cast<Led_DIB*
> (&bmiHdr));
1783 dibResult =
reinterpret_cast<Led_DIB*
> (
new char[nBytes]);
1784 Assert (nBytes >
sizeof (BITMAPINFOHEADER));
1786 (void)::memcpy (dibResult, &bmiHdr,
sizeof (bmiHdr));
1787 DISABLE_COMPILER_MSC_WARNING_END (6386)
1790 [[maybe_unused]]
int nScanLinesCopied =
1791 ::GetDIBits (hDC, hbm, 0, dibResult->bmiHeader.biHeight,
1792 reinterpret_cast<char*
> (dibResult) + Led_GetDIBPalletByteCount (dibResult) +
sizeof (BITMAPINFOHEADER), dibResult, DIB_RGB_COLORS);
1793 Assert (nScanLinesCopied == dibResult->bmiHeader.biHeight);
1798#if qStroika_Frameworks_Led_ProvideIMESupport
1806IME* IME::sThe =
nullptr;
1808#ifndef qUseNewIMECode_
1809#define qUseNewIMECode_ 1
1813class IME::_Global_DESTRUCTOR_ {
1815 ~_Global_DESTRUCTOR_ ()
1818 IME::sThe =
nullptr;
1820} sTheIME_DESTRUCTOR_;
1823 : fSendIMEMessageProc (nullptr)
1824 , fIMEEnableProc (nullptr)
1825 , fImmGetContext (nullptr)
1826 , fImmSetCompositionFont (nullptr)
1827 , fImmReleaseContext (nullptr)
1828 , fImmGetCompositionStringW (nullptr)
1829 , fImmSetCompositionWindow (nullptr)
1830 , fImmSetOpenStatus (nullptr)
1831 , fWinNlsAvailable (false)
1835 Assert (sThe ==
nullptr);
1839 const char IMEPROCNAME[] =
"SendIMEMessageExW";
1841 const char IMEPROCNAME[] =
"SendIMEMessageExA";
1843 HINSTANCE hNLS = ::GetModuleHandle (_T (
"USER32.DLL"));
1844 if (hNLS !=
nullptr) {
1845 fSendIMEMessageProc = (LRESULT (FAR PASCAL*) (HWND, DWORD))::GetProcAddress (hNLS, IMEPROCNAME);
1846 fIMEEnableProc = (BOOL (FAR PASCAL*) (HWND, BOOL))::GetProcAddress (hNLS,
"WINNLSEnableIME");
1848 fWinNlsAvailable = fSendIMEMessageProc !=
nullptr and fIMEEnableProc !=
nullptr;
1850 HINSTANCE hIMM = ::GetModuleHandle (_T (
"IMM32.DLL"));
1851 if (hIMM !=
nullptr) {
1853 constexpr char ImmSetCompositionFontNAME[] =
"ImmSetCompositionFontW";
1855 constexpr char ImmSetCompositionFontNAME[] =
"ImmSetCompositionFontA";
1857 fImmGetContext = (HIMC (FAR PASCAL*) (HWND))::GetProcAddress (hIMM,
"ImmGetContext");
1858 fImmSetCompositionFont = (BOOL (FAR PASCAL*) (HIMC,
const LOGFONT*))::GetProcAddress (hIMM, ImmSetCompositionFontNAME);
1859 fImmReleaseContext = (BOOL (FAR PASCAL*) (HWND, HIMC))::GetProcAddress (hIMM,
"ImmReleaseContext");
1860 fImmGetCompositionStringW = (LONG (FAR PASCAL*) (HIMC, DWORD, LPVOID, DWORD))::GetProcAddress (hIMM,
"ImmGetCompositionStringW");
1861 fImmSetCompositionWindow = (BOOL (FAR PASCAL*) (HIMC,
const void*))::GetProcAddress (hIMM,
"ImmSetCompositionWindow");
1862 fImmSetOpenStatus = (BOOL (FAR PASCAL*) (HIMC, BOOL))::GetProcAddress (hIMM,
"ImmSetOpenStatus");
1866void IME::NotifyPosition (HWND hWnd,
const SHORT x,
const SHORT y)
1868 if (x != fLastX || y != fLastY) {
1869 UpdatePosition (hWnd, x, y);
1873void IME::NotifyOfFontChange (HWND hWnd,
const LOGFONT& lf)
1875 if (fImmGetContext !=
nullptr and fImmSetCompositionFont !=
nullptr and fImmReleaseContext !=
nullptr) {
1877 if ((hImc = fImmGetContext (hWnd)) != NULL) {
1878 fImmSetCompositionFont (hImc, &lf);
1879 fImmReleaseContext (hWnd, hImc);
1885void IME::SendSimpleMessage (HWND hWnd, UINT fnc, WPARAM wParam)
1887 if (fSendIMEMessageProc !=
nullptr) {
1888 HANDLE hime = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_LOWER | GMEM_DDESHARE, (DWORD)
sizeof (IMESTRUCT));
1891 lpime = (LPIMESTRUCT)GlobalLock (hime);
1895 if (lpime ==
nullptr) {
1900 lpime->wParam = wParam;
1901 fSendIMEMessageProc (hWnd, (LONG)hime);
1902 wParam = lpime->wParam;
1903 ::GlobalUnlock (hime);
1904 ::GlobalFree (hime);
1909void IME::IMEOn (HWND hWnd)
1912 if (fImmGetContext !=
nullptr and fImmSetOpenStatus !=
nullptr and fImmReleaseContext !=
nullptr) {
1914 if ((hImc = fImmGetContext (hWnd)) != NULL) {
1915 Verify (fImmSetOpenStatus (hImc,
true));
1916 fImmReleaseContext (hWnd, hImc);
1920 SendSimpleMessage (hWnd, IME_SETOPEN, 1);
1924void IME::IMEOff (HWND hWnd)
1927 if (fImmGetContext !=
nullptr and fImmSetOpenStatus !=
nullptr and fImmReleaseContext !=
nullptr) {
1929 if ((hImc = fImmGetContext (hWnd)) != NULL) {
1930 Verify (fImmSetOpenStatus (hImc,
false));
1931 fImmReleaseContext (hWnd, hImc);
1935 SendSimpleMessage (hWnd, IME_SETOPEN, 0);
1939void IME::UpdatePosition (
const HWND hWnd,
const SHORT x,
const SHORT y)
1941 if (fSendIMEMessageProc !=
nullptr) {
1943 if (fImmGetContext !=
nullptr and fImmSetCompositionWindow !=
nullptr and fImmReleaseContext !=
nullptr) {
1945 if ((hImc = fImmGetContext (hWnd)) != NULL) {
1946 COMPOSITIONFORM compForm;
1947 memset (&compForm, 0,
sizeof (compForm));
1948 compForm.dwStyle = CFS_FORCE_POSITION;
1949 compForm.ptCurrentPos.x = x;
1950 compForm.ptCurrentPos.y = y;
1951 Verify (fImmSetCompositionWindow (hImc, &compForm));
1952 fImmReleaseContext (hWnd, hImc);
1958 HANDLE hime = ::GlobalAlloc (GMEM_MOVEABLE | GMEM_LOWER | GMEM_DDESHARE, (DWORD)
sizeof (IMESTRUCT));
1959 LPIMESTRUCT lpime =
nullptr;
1960 if (hime !=
nullptr) {
1961 lpime = (LPIMESTRUCT)GlobalLock (hime);
1967 if (lpime ==
nullptr) {
1971 lpime->fnc = IME_SETCONVERSIONWINDOW;
1972 lpime->wParam = MCW_WINDOW;
1974 lpime->dchSource = 0;
1976 lpime->lParam1 = MAKELONG (x, y);
1977 lpime->lParam2 = 0L;
1978 lpime->lParam3 = 0L;
1982 short ret = fSendIMEMessageProc (hWnd, (LONG)hime);
1983 ret = ret ? 0 : (short)lpime->wParam;
1985 ::GlobalUnlock (hime);
1986 ::GlobalFree (hime);
1994 if (fImmGetContext !=
nullptr and fImmSetCompositionFont !=
nullptr and fImmReleaseContext !=
nullptr) {
1995 HFONT hFont =
nullptr;
1996 if ((hFont = (HFONT)::SendMessage (hWnd, WM_GETFONT, 0, 0L)) !=
nullptr) {
1998 if (::GetObject (hFont,
sizeof (LOGFONT), &lFont)) {
2000 if ((hImc = fImmGetContext (hWnd)) != NULL) {
2001 fImmSetCompositionFont (hImc, &lFont);
2002 fImmReleaseContext (hWnd, hImc);
2010wstring IME::GetCompositionResultStringW (HWND hWnd)
2013 if (fImmGetCompositionStringW !=
nullptr and fImmGetContext !=
nullptr and fImmReleaseContext !=
nullptr) {
2015 if ((hImc = fImmGetContext (hWnd)) != 0) {
2016 wchar_t curIMEString[2048];
2017 LONG nChars = fImmGetCompositionStringW (hImc, GCS_RESULTSTR, curIMEString,
static_cast<DWORD
> (std::size (curIMEString)));
2019 nChars /=
sizeof (wchar_t);
2020 if (nChars >= 0 and
static_cast<size_t> (nChars) < std::size (curIMEString)) {
2021 curIMEString[nChars] =
'\0';
2024 curIMEString[0] =
'\0';
2026 result = curIMEString;
2027 fImmReleaseContext (hWnd, hImc);
2034Led_Rect Led::CenterRectInRect (
const Led_Rect& r,
const Led_Rect& centerIn)
2036 CoordinateType xLeft = (centerIn.left + centerIn.right) / 2 - r.GetWidth () / 2;
2037 CoordinateType yTop = (centerIn.top + centerIn.bottom) / 2 - r.GetHeight () / 2;
2038 return Led_Rect (yTop, xLeft, r.GetHeight (), r.GetWidth ());
2041#if qStroika_Platform_Windows
2042void Led::Led_CenterWindowInParent (HWND w)
2044 Assert (::IsWindow (w));
2045 HWND hWndCenter = ::GetWindow (w, GW_OWNER);
2046 if (hWndCenter ==
nullptr) {
2047 hWndCenter = ::GetDesktopWindow ();
2049 Assert (::IsWindow (hWndCenter));
2053 ::GetWindowRect (w, &rcDlg);
2055 ::GetWindowRect (hWndCenter, &rcCenter);
2058 int xLeft = (rcCenter.left + rcCenter.right) / 2 - AsLedRect (rcDlg).GetWidth () / 2;
2059 int yTop = (rcCenter.top + rcCenter.bottom) / 2 - AsLedRect (rcDlg).GetHeight () / 2;
2062 ::SetWindowPos (w,
nullptr, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define RequireNotNull(p)
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
basic_string< SDKChar > SDKString
DISABLE_COMPILER_MSC_WARNING_START(4996)
conditional_t< qStroika_Foundation_Characters_SDKUseswchar_t, wchar_t, char > SDKChar