decided to look into rendering round and transparent buttons on Windows Mobile Phone. While I've personally never had interest in making my buttons round or transparent I've heard enough developers voice frustrations with this, so I decided to look for a better way to do it. I looked at the solutions that were available. For all of the solutions I found the button rendering code had to be fed information about the appearance of the parent on which it was rendered. If the button were on a solid background then the button code needed to find out the background color. If the button were being rendered on a windows that used an image for the background then it needed the image (or image brush) so that it could fill in the "invisible" areas. I wanted a method that didn't require information from the parent.
Let me first demonstrate the problem. I've created a button and overrode its rendering by using both an owner drawn button and a subclassed button. The results were identical. When the program runs the parent window renders in every area except for the areas occupied by the button. After the main window renders the buttons are allowed to render. For these buttons I rendered a round rectangle and some text. The corners are our problem area. The button's rendering should not fall outside the round rectangle. We need for the parent window to render in this area, but it won't because it's not going to render over other controls.

I considered seeing if there were any way to override the clipping region for the rectangle with a complex region. But on Windows Mobile clompex clipping regions can only be composed of rectangles (on the desktop they can be composed of arbitrary shapes). Unless I wanted to approximate a curve with a series of rectangles I won't be able to get an appropriate clipping region (and I have performance and memory concerns on approximating a curve with rectangles).
The next strategy was to force the parent to render over the area that was occupied by the buttons. On the desktop you can do this by removing the WS_CLIPCHILDREN style. But this style seems to be permanently set on Windows Mobile. After several failed attempts of trying to force the parent to render I finally found a method that works. If a control is invisible then it's presence doesn't occlude the parent's rendering. So I tried to hid the button during it's rendering, render the parent, unhide the button and render it. It worked.

So I achieved the desired result. Now the question is whether or not I should be doing things this way? I'm not sure. So I'm asking a question in the MSDN forums. If you have any suggestions or comments head over to the forum and sound off. The code for drawing my button is below. The complete project is attached to this post.
BOOL DrawButton(HWND hWnd)
{
HDC hdc = GetDC(hWnd);
RECT clientRect;
RECT textRect;
RECT drawTextRect;
TCHAR szWindowText[100];
int width, height;
int marginX, marginY;
HWND hParent = GetParent(hWnd);
if(hParent!=NULL)
{
RECT buttonRect;
POINT upperLEft;
POINT lowerRight;
GetWindowRect(hWnd,&buttonRect);
ShowWindow(hWnd,SW_HIDE);
upperLEft.x = buttonRect.left;
upperLEft.y = buttonRect.top;
lowerRight.x = buttonRect.right;
lowerRight.y = buttonRect.bottom;
ScreenToClient(hParent, &upperLEft);
ScreenToClient(hParent, &lowerRight);
POINT p;
buttonRect.top = upperLEft.y;
buttonRect.left = upperLEft.x;
buttonRect.bottom = lowerRight.y;
buttonRect.right = lowerRight.x;
InvalidateRect(hParent, &buttonRect, FALSE);
SendMessage(hParent,WM_PAINT, 0, 0);
ShowWindow(hWnd,SW_SHOW);
InvalidateRect(hWnd,NULL,FALSE);
}
GetClientRect(hWnd,&clientRect);
CopyMemory(&textRect, &clientRect, sizeof(RECT));
width = clientRect.right - clientRect.left;
height = clientRect.bottom - clientRect.top;
marginX = width / 20;
marginY = height / 20;
GetWindowText(hWnd, szWindowText, 100);
RoundRect(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, 40, 40);
//RoundRect(hdc, clientRect.left+marginX, clientRect.top+marginY, clientRect.right-marginX, clientRect.top+(height/2), 40, 40);
DrawText(hdc, szWindowText, -1, &textRect, DT_END_ELLIPSIS|DT_CENTER|DT_CALCRECT);
drawTextRect.top = (height - textRect.bottom) / 2;
drawTextRect.left = (width - textRect.right) / 2;
drawTextRect.right = drawTextRect.left + textRect.right;
drawTextRect.bottom = drawTextRect.top + textRect.bottom;
DrawText(hdc, szWindowText, -1, &drawTextRect, DT_END_ELLIPSIS|DT_CENTER);
ValidateRect(hWnd, NULL);
ReleaseDC(hWnd, hdc);
return TRUE;
}
Tags: