Win32 Tab Control grey background - c++

I am trying to make make my ui in win32 everywhere white. The problem is that my tab control's background is not white , so the not the tab itself, but the party next to the tabs is grey.
I am handling WM_CTLCOLORSTATIC for the static controls, but it does not seems to work for the tab control.
case WM_CTLCOLORSTATIC:
{
HDC hEdit = (HDC)w_param;
SetBkMode(hEdit, TRANSPARENT);
SetTextColor(hEdit, RGB(0, 0, 0));
SetBkColor(hEdit, RGB(255, 255, 255));
// Do not return a brush created by CreateSolidBrush(...) because you'll get a memory leak
return (INT_PTR)GetStockObject(WHITE_BRUSH);
}
I hope there is an 'easy' way to make my entire ui white :)
Grz

You can not capture a message to draw on the grey background. The system draws everything in the WM_PRINTCLIENT. There is however a nice hack! The idea is from this post.
I do this (in my WM_PAINT handler):
Create a memory DC to draw into
Send a WM_PRINTCLIENT message to the tab control to get it to draw the tabs into your memory DC
Create a region which mirrors the shape of the tabs
Fill the parts of the memory DC outside this region (RGN_DIFF) with the desired background brush
Blt the result into the DC returned by BeginPaint
Call EndPaint and return, without calling the tab control's own WndProc of course :)
Step 3 is a bit fiddly as you have to know the location and shape of the tabs, but other
than that it's a pretty clean solution (see image below the following sample code). You
could probably use TransparentBlt to replace the system background colour instead.
I am using TransparentBlt in this solution:
create hdcMemTab, step 1
HBITMAP hBitmap, hBitmapOld ; //keep them till the end of the program
HDC hdcMemTab; //keep it till the end of the program
HDC hdc;
Rect rt;
hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
hdcMemTab = CreateCompatibleDC(hdc);
GetWindowRect(hwnd_Tab, &rt);
rt.right = rt.right - rt.left;
rt.bottom = rt.bottom - rt.top;
rt.left = 0;
rt.top = 0;
hBitmap = CreateCompatibleBitmap(hdc, rt.right, rt.bottom);
hBitmapOld = SelectObject(hdcMemTab, hBitmap);
DeleteDC(hdc);
In WM_PAINT of the subclassed tab control:
RECT rt, rtTab;
HDC hdc = BeginPaint(hwnd, &ps);
GetWindowRect(hwnd_Tab, &rt);
rt.right = rt.right - rt.left;
rt.bottom = rt.bottom - rt.top;
rt.left = 0;
rt.top = 0;
//step 2
SendMessage(hwnd_Tab, WM_PRINTCLIENT, (WPARAM)hdcMemTab, PRF_CLIENT);
FillRect(hdc, &rt, gBrushWhite); //gBrushWhite has the desired background color
HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
int n_items = TabCtrl_GetItemCount(hwnd_Tab);
//get tabs region, step 3
for(i = 0; i < n_items; i++){
TabCtrl_GetItemRect(hwnd_Tab, i, &rtTab);
HRGN hTabRgn = CreateRectRgn(rtTab.left, rtTab.top, rtTab.right, rt.bottom);
CombineRgn(hRgn, hRgn, hTabRgn, RGN_OR);
DeleteObject(hTabRgn);
}
GetRgnBox(hRgn, &rtTab);
DeleteObject(hRgn);
//step 5
TransparentBlt(hdc, 0, 0, rt.right, rt.bottom, hdcMemTab, 0, 0, rt.right, rt.bottom, RGB(240, 240, 240)); //(240, 240, 240) is the grey color
BitBlt(hdc, rtTab.left, rtTab.top, rtTab.right - 5, rtTab.bottom, hdcMemTab, rtTab.left, rtTab.top, SRCCOPY);
EndPaint(hwnd, &ps);
//step 6
return 0;

Sorry about my english. What I do is return 0 in WM_PRINTCLIENT message without doing anything, I mean, preventing WM_PRINTCLIENT from calling DefWindowProc. This causes the tabcontrol header to have the same background color as its parent window. The same goes for the TrackBar.
I only have it tested on windows 10, I would like to know if it works for win 7 too.

Related

Create CBitmap from CDC?

Using C++/MFC and GDI (not GDI+), the overall goal is to create an patterned HBRUSH, which will be used in OnCtlColor to outline an edit control in red, with the ability to turn the outline on and off. To do this, you attach a bitmap to an HBRUSH using CreatePatternBrush. Here is the code for doing that, using a stored bitmap resource:
CDialog::OnInitDialog();
BOOL ok = redBoxBitmap.LoadBitmap(MAKEINTRESOURCE(IDB_mespe_EditBox_Red));
ok = redBoxBrush.CreatePatternBrush(&redBoxBitmap);
and in OnCtlColor
HBRUSH CModelEditorSpecies::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr;
int ctrlID=pWnd->GetDlgCtrlID();
if(ctrlID==IDC_MyEditControl)
hbr=(HBRUSH) redBoxBrush;
else
hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
return hbr;
}
The above code all works as desired. However, it depends on the bitmap being sized to the edit control. What I need now is the ability to create the bitmap within the C++ program, sized to the client area of the control, which depends on both the design size of the control (in the dialog editor), and the user's setting of text size in Windows 10 settings.
I cannot find a straightforward way of either constructing a bitmap, or, better, creating an empty one of the proper size (can do), selecting it into a CDC (can do), drawing the red box into it (can do), then extracting the update bitmap from the CDC (how to do?).
Can anyone suggest either how to create the bitmap programmatically, or suggest a better method of getting an edit control boxed in red when the program calls for that?
Added in response to #Constantine Georgiou's answer of 3/9:
New code:
CBitmap redBoxBitmap; // member variables of class CModelEditorSpecies
CBrush redBoxBrush;
BOOL CModelEditorSpecies::OnInitDialog()
{
CDialog::OnInitDialog();
BOOL ok;
CRect r; defaultSpecies1Ctrl.GetClientRect(&r);
xx(r.Width(), r.Height()/*, redBoxBrush*/);
ok = redBoxBrush.CreatePatternBrush(&redBoxBitmap);
//...
}
void CModelEditorSpecies::xx(const int w, const int h)
{
CDC *pDC=GetDC();
redBoxBitmap.CreateCompatibleBitmap(pDC, w, h);
// Create a red pen
CPen redPen;
redPen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
// Draw the bitmap - red pen & default background brush
CBitmap *pOldBitmap=pDC->SelectObject(&redBoxBitmap);
pDC->SelectObject(&redPen);
CBrush editBoxBrush;
editBoxBrush.CreateSysColorBrush(COLOR_WINDOW);
pDC->SelectObject(&editBoxBrush);
pDC->Rectangle(0, 0, w, h);
pDC->SelectObject(pOldBitmap);
// Create the edit-control custom brush
redBoxBrush.CreatePatternBrush(&redBoxBitmap);
return;
}
This code produces an all-black edit control, as if the bitmap being used were monochrome. That would be expected if drawing in the dc does not affect the bitmap, or, if drawing in a dc-compatible bitmap does not use the colors in redPen and editBoxBrush, as suggested by #IInspectable.
Here's how to create the brush - used the Win32 functions instead of their MFC wrappers, but you can figure it out.
BOOL CModelEditorSpecies::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Get edit-control's size
RECT rc;
GetDlgItem(IDC_MyEditControl)->GetClientRect(&rc);
// Create the bitmap and a memory-DC
HDC hDC = ::GetDC(HWND_DESKTOP);
HDC mDC = CreateCompatibleDC(hDC);
HBITMAP hBmp = CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
::ReleaseDC(HWND_DESKTOP, hDC);
// Create a red pen
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
// Draw the bitmap - red pen & default background brush
HBITMAP hOldBmp = (HBITMAP) SelectObject(mDC, hBmp);
HPEN hOldPen = (HPEN) SelectObject(mDC, hPen);
HBRUSH hOldBr = (HBRUSH) SelectObject(mDC, GetSysColorBrush(COLOR_WINDOW));
Rectangle(mDC, rc.left, rc.top, rc.right, rc.bottom);
SelectObject(mDC, hOldBr);
SelectObject(mDC, hOldPen);
SelectObject(mDC, hOldBmp);
// Create the edit-control custom brush
redBoxBrush = CreatePatternBrush(hBmp);
// Clean-up - the SysColorBrush doesn't need to be deleted
DeleteObject(hPen);
DeleteObject(hBmp);
DeleteDC(mDC);
return TRUE;
}
HBRUSH CModelEditorSpecies::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
return (nCtlColor == CTLCOLOR_EDIT && pWnd->GetDlgCtrlID() == IDC_MyEditControl) ?
redBoxBrush : CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
}
Also check the alternatives I suggested in the comments. This one will be drawing into the edit-control's client area.
EDIT:
The code I posted above does work, and after it runs all left is the HBRUSH handle (pattern-brush for your edit box). I can't see why you insist using the MFC wrappers instead. They are "higher-level" thin wrappers, so... "thin" actually, that you still have to perform almost exactly the same operations (create, select into a DC, perfrom some drawing operation, select out of the DC) as the GDI ones. The only operation you don't need to perform is delete the resource (the object's destructor will call DeleteObject() for you).
Anyways, if you prefer MFC over GDI, let's see what's wrong with your code. It has quite a few issues:
First and foremost, you need a memory DC to draw on a bitmap, the window DC you get by calling GetDC() draws on a window's surface.
The DC you get by calling GetDC() must be returned to the system (ReleaseDC()), because pDC is just a pointer, and the compiler won't call the destructor.
The objects you select into a DC must be selected out before it is destroyed, otherwise memory-leaks may be occurring.
So your code should be changed as shown below:
void CModelEditorSpecies::xx()
{
CRect r;
GetDlgItem(IDC_MyEditControl)->GetClientRect(&r);
// Create the bitmap and a memory-DC
CBitmap redBoxBitmap;
CDC mDC, *pDC = GetDC();
redBoxBitmap.CreateCompatibleBitmap(pDC, r.Width(), r.Height());
mDC.CreateCompatibleDC(pDC);
ReleaseDC(pDC);
// Create a red pen and get the default background brush
CPen redPen;
redPen.CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
CBrush editBoxBrush;
editBoxBrush.CreateSysColorBrush(COLOR_WINDOW);
// Draw the bitmap - red pen & default background brush
CBitmap *pOldBitmap = mDC.SelectObject(&redBoxBitmap);
CPen *pOldPen = mDC.SelectObject(&redPen);
CBrush *pOldBrush =mDC.SelectObject(&editBoxBrush);
mDC.Rectangle(r);
mDC.SelectObject(pOldBrush);
mDC.SelectObject(pOldPen);
mDC.SelectObject(pOldBitmap);
// Create the edit-control custom brush
redBoxBrush.CreatePatternBrush(&redBoxBitmap);
}
It's basically the same as the GDI version.

How to maintain transparency when writing text on a Windows System Tray icon from unmanaged C program

I have a MFC C++ (unmanaged) Windows application that uses a “standard” icon in the System Tray. This icon was created & edited using Visual Studio and is 32x32 pixels with only 4bit colour (according to VS's Resource Editor).
With Visual Studio, I also set a transparent background (shown as white in the “before” image).
I wish to dynamically change the icon by writing 2 digits (1-99) on top of it.
Using the code below (based on that in this question: How to draw text with transparency using GDI?) to superimpose “55” in yellow on the icon, it works except that the transparency disappears (it appears black in the “after” image and on the System Tray). My actual code differs very very slightly in that the font size (20), font name (Courier New), text colour (yellow - RGB(255, 255, 0)) and the numeric value (55) are run-time variables rather than fixed values.
Any suggestions on how to make the background remain transparent as far as the System Tray is concerned gratefully received.
These images have been captured using MS’s Snipping tool with the image open in MS Paint as a 32x32 icon wouldn't be very visible as-is.
Before Image:
After image:
Code:
void CreateNewIcon(HICON &hNewIcon, HICON hBackgroundIcon)
{
::DestroyIcon(hNewIcon);
// First create font
LOGFONT lf = { 0 };
lf.lfHeight = -20;
lf.lfWeight = FW_BOLD;
lf.lfOutPrecision = OUT_TT_PRECIS;
lf.lfQuality = CLEARTYPE_QUALITY;
wmemset(lf.lfFaceName, 0, LF_FACESIZE);
lstrcpy(lf.lfFaceName, L"Courier New");
HFONT hFont = ::CreateFontIndirect(&lf);
ICONINFO ii = { 0 };
::GetIconInfo(hBackgroundIcon, &ii);
BITMAP bm = { 0 };
::GetObject(ii.hbmColor, sizeof(bm), &bm);
SIZE szBmp = { bm.bmWidth, bm.bmHeight };
HDC hDc = ::GetDC(NULL);
HDC hMemDC = ::CreateCompatibleDC(hDc);
HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor);
HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont);
::SetBkMode(hMemDC, TRANSPARENT);
::SetTextColor(hMemDC, RGB(255, 255, 0));
::TextOut(hMemDC, 0, 8, L"55", 2);
::SelectObject(hMemDC, hOldFont);
::SelectObject(hMemDC, hOldBmp);
// We need a simple mask bitmap for the icon
HBITMAP hBmpMsk = ::CreateBitmap(szBmp.cx, szBmp.cy, 1, 1, NULL);
ICONINFO ii2 = { 0 };
ii2.fIcon = TRUE;
ii2.hbmColor = ii.hbmColor;
ii2.hbmMask = hBmpMsk;
// Create updated icon
hNewIcon = ::CreateIconIndirect(&ii2);
// Cleanup
::DeleteObject(hBmpMsk);
::DeleteDC(hMemDC);
::ReleaseDC(NULL, hDc);
::DeleteObject(ii.hbmColor);
::DeleteObject(ii.hbmMask);
::DeleteObject(hFont);
}
There are multiple issues with our code:
You are trying to draw cleartype-quality text over transparent icon part. But cleartype font rendering must be performed over opaque background because it needs to inspect background color. So you should switch to Anitialiased quality (or to not antialiased quality) or provide opaque background for your text.
When you create hBmpMsk you skip it's content initialization by supplying NULL for bits pointer, so resulting icon will actually have completely random transparency. You need to fill this mask bitmat appropriately.
Also you probably need to switch to higher bit depth because monochrome bitmap mask can't handle semitransparent parts of antialiased text.
update
I think you should draw cleartype text but with opaque background, then get text rectangle using something like GetTextExtentPoint32, then copy data from the original bitmap mask into hBmpMsk and then finally fill white (text) rectangle on it so the new icon will preserve transparency from original and has opaque text block.
Thanks for all the help from VTT without which I wouldn't have been able to get this far. This appears to work for me.
void CreateNewIcon(HICON &hNewIcon, HICON hBackgroundIcon)
{
::DestroyIcon(hNewIcon);
HDC hDc = ::GetDC(NULL);
HDC hMemDC = ::CreateCompatibleDC(hDc);
// Load up background icon
ICONINFO ii = { 0 };
::GetIconInfo(hBackgroundIcon, &ii);
HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor);
// Create font
LOGFONT lf = { 0 };
lf.lfHeight = -20;
lf.lfWeight = FW_BOLD;
lf.lfOutPrecision = OUT_TT_PRECIS;
lf.lfQuality = ANTIALIASED_QUALITY;
wmemset(lf.lfFaceName, 0, LF_FACESIZE);
lstrcpy(lf.lfFaceName, L"Courier New");
HFONT hFont = ::CreateFontIndirect(&lf);
HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont);
// Write text
::SetBkMode(hMemDC, TRANSPARENT);
::SetTextColor(hMemDC, RGB(255, 255, 0));
::TextOut(hMemDC, 0, 8, L"55", 2);
// Set up mask
HDC hMaskDC = ::CreateCompatibleDC(hDc);
HGDIOBJ hOldMaskBmp = ::SelectObject(hMaskDC, ii.hbmMask);
// Also write text on here
HGDIOBJ hOldMaskFont = ::SelectObject(hMaskDC, hFont);
::SetBkMode(hMaskDC, TRANSPARENT);
::SetTextColor(hMaskDC, RGB(255, 255, 0));
::TextOut(hMaskDC, 0, 8, L"55", 2);
// Get handle to create mask bitmap
HBITMAP hMaskBmp = (HBITMAP)::SelectObject(hMaskDC, hOldMaskBmp);
// Use new icon bitmap with text and new mask bitmap with text
ICONINFO ii2 = { 0 };
ii2.fIcon = TRUE;
ii2.hbmMask = hMaskBmp;
ii2.hbmColor = ii.hbmColor;
// Create updated icon
hNewIcon = ::CreateIconIndirect(&ii2);
// Cleanup bitmap mask
::DeleteObject(hMaskBmp);
::DeleteDC(hMaskDC);
// Cleanup font
::SelectObject(hMaskDC, hOldMaskFont);
::SelectObject(hMemDC, hOldFont);
::DeleteObject(hFont);
// Release background bitmap
::SelectObject(hMemDC, hOldBmp);
// Delete background icon bitmap info
::DeleteObject(ii.hbmColor);
::DeleteObject(ii.hbmMask);
::DeleteDC(hMemDC);
::ReleaseDC(NULL, hDc);
}

flickering when updating ellipse after fillrect in c++ win32

All the action happens in c++ win32 application.
currently used rect fill method (redrawing quite often so it flickers):
RECT r;
PAINTSTRUCT ps;
RECT mRect;
brush_real = CreateSolidBrush(RGB(0, 0, 0));
{
dc = GetDC(GetDlgItem(hwnd, 1));
GetClientRect(GetDlgItem(hwnd, 1), &mRect);
FillRect(dc, &mRect, brush_real);
HBRUSH circleBrush = CreateSolidBrush(RGB(Roriginal, Goriginal, Boriginal)), oldBrush;
oldBrush = (HBRUSH)SelectObject(dc, circleBrush);
Ellipse(dc, mRect.left, mRect.top, mRect.right, mRect.bottom);
SelectObject(dc, oldBrush);
ReleaseDC(GetDlgItem(hwnd, 1), dc);
DeleteObject(oldBrush);
DeleteObject(circleBrush);
}
DeleteObject(brush_real);
this doesn't works fully as intended, because ellipse draw flickers when drawed after fillrect(which fills black background), i didn't yet figured out how to fill background once and for good on object initialization in dialog.
What could you offer ?

Creating a transparent window in C++ Win32

I'm creating what should be a very simple Win32 C++ app whose sole purpose it to ONLY display a semi-transparent PNG. The window shouldn't have any chrome, and all the opacity should be controlled in the PNG itself.
My problem is that the window doesn't repaint when the content under the window changes, so the transparent areas of the PNG are "stuck" with what was under the window when the application was initially started.
Here's the line where I setup the new window:
hWnd = CreateWindowEx(WS_EX_TOPMOST, szWindowClass, szTitle, WS_POPUP, 0, height/2 - 20, 40, 102, NULL, NULL, hInstance, 0);
For the call to RegisterClassEx, I have this set for the background:
wcex.hbrBackground = (HBRUSH)0;
Here is my handler for WM_PAINT message:
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
Gdiplus::Graphics graphics(hdc);
graphics.DrawImage(*m_pBitmap, 0, 0);
EndPaint(hWnd, &ps);
break;
}
One thing to note is that the application is always docked to the left of the screen and doesn't move. But, what's underneath the application may change as the user opens, closes or moves windows under it.
When the application first starts, it looks perfect. The transparent (and simi-transparent) parts of the PNG show through perfectly. BUT, when the background underneath the application changes, the background DOESN'T update, it just stays the same from when the application first started. In fact, WM_PAINT (or WM_ERASEBKGND does not get called when the background changes).
I've been playing with this for quite a while and have gotten close to getting 100% right, but not quite there. For instance, I've tried setting the background to (HBRUSH) NULL_BRUSH and I've tried handling WM_ERASEBKGND.
What can be done to get the window to repaint when the contents under it changes?
I was able to do exactly what I wanted by using the code from Part 1 and Part 2 of this series:
Displaying a Splash Screen with C++
Part 1: Creating a HBITMAP archive
Part 2: Displaying the window archive
Those blog posts are talking about displaying a splash screen in Win32 C++, but it was almost identical to what I needed to do. I believe the part that I was missing was that instead of just painting the PNG to the window using GDI+, I needed to use the UpdateLayeredWindow function with the proper BLENDFUNCTION parameter. I'll paste the SetSplashImage method below, which can be found in Part 2 in the link above:
void SetSplashImage(HWND hwndSplash, HBITMAP hbmpSplash)
{
// get the size of the bitmap
BITMAP bm;
GetObject(hbmpSplash, sizeof(bm), &bm);
SIZE sizeSplash = { bm.bmWidth, bm.bmHeight };
// get the primary monitor's info
POINT ptZero = { 0 };
HMONITOR hmonPrimary = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
MONITORINFO monitorinfo = { 0 };
monitorinfo.cbSize = sizeof(monitorinfo);
GetMonitorInfo(hmonPrimary, &monitorinfo);
// center the splash screen in the middle of the primary work area
const RECT & rcWork = monitorinfo.rcWork;
POINT ptOrigin;
ptOrigin.x = 0;
ptOrigin.y = rcWork.top + (rcWork.bottom - rcWork.top - sizeSplash.cy) / 2;
// create a memory DC holding the splash bitmap
HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcMem, hbmpSplash);
// use the source image's alpha channel for blending
BLENDFUNCTION blend = { 0 };
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
// paint the window (in the right location) with the alpha-blended bitmap
UpdateLayeredWindow(hwndSplash, hdcScreen, &ptOrigin, &sizeSplash,
hdcMem, &ptZero, RGB(0, 0, 0), &blend, ULW_ALPHA);
// delete temporary objects
SelectObject(hdcMem, hbmpOld);
DeleteDC(hdcMem);
ReleaseDC(NULL, hdcScreen);
}
Use the SetLayeredWindowAttributesarchive function, this allows you to set a mask color that will become transparent, thus allowing the background to show through.
You will also need to configure your window with the layered flag, e.g.:
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
After that it's fairly simple:
// Make red pixels transparent:
SetLayeredWindowAttributes(hwnd, RGB(255,0,0), 0, LWA_COLORKEY);
When your PNG contains semi-transparent pixels that you want to blend with the background, this becomes more complicated. You could try looking at the approach in this CodeProject article:
Cool, Semi-transparent and Shaped Dialogs with Standard Controls for Windows 2000 and Above

Rotate Text by 90 degrees with GDI

I want to draw text to a GDI Surface and rotate this text by 90 degrees counter clockwise. I would prefer to use DrawText to draw the text because it supports carriage return. I tried to use a font with lfEscapement (see the code below) but the line is not rotated - one line gets rendered over the other. Is there any possibility to rotate the text? Or to render without rotation and rotate the whole device context?
Normal text layout:
Rotated (desired result):
case WM_PAINT:
{
hdc = BeginPaint(hWnd, &ps);
LOGFONT lf = {0};
HANDLE hFont;
ZeroMemory(&lf, sizeof(LOGFONT));
lf.lfWeight = FW_NORMAL;
lstrcpy(lf.lfFaceName, _T("Tahoma"));
lf.lfEscapement = 90;
lf.lfHeight = 30;
hFont = CreateFontIndirect (&lf);
hFont = (HFONT)SelectObject (ps.hdc, hFont);
RECT RectBody = {10,lf.lfHeight+10,::GetSystemMetrics(SM_CXSCREEN)-10,::GetSystemMetrics(SM_CYSCREEN)-lf.lfHeight-20};
{
ScopedLock lock(me->m_mutex);
DrawText (ps.hdc, me->GetMessageString().c_str(), (int)me->GetMessageString().length(), &RectBody, 0);
}
hFont = (HFONT)SelectObject (ps.hdc, hFont);
DeleteObject (hFont);
EndPaint(hWnd, &ps);
break;
}
lf.lfEscapement = 90;
That should be 900 to get the text vertical, units are 0.1 degrees.
Your plan to let DrawText take care of the line breaks is going to fall flat I'm afraid. I could not convince it to align the text properly. It aligns on the last line, not the first. Some code to play with:
wchar_t* msg = L"Hello\r\nworld";
RECT rcMeasure = {0, 0, 400, 0};
DrawTextEx(hdc, msg, -1, &rcMeasure, DT_CALCRECT, 0);
RECT rcDraw = {10, 30, 10 + rcMeasure.bottom - rcMeasure.top, 30 + rcMeasure.right - rcMeasure.left };
FillRect(hdc, &rcDraw, (HBRUSH) (COLOR_WINDOW+2));
SetTextAlign(hdc, TA_TOP | TA_CENTER);
DrawTextEx(hdc, msg, -1, &rcDraw, DT_BOTTOM, 0);
I think I tried all alignment options.
I have the impression that this link answers your question, but using ExtTextOut, and not DrawText
http://www.codeproject.com/KB/GDI/textrotation.aspx
it's not GDI+ it's MFC but they are close.