NO

Author Topic: Non-rectangular windows with SetWindowRgn  (Read 5004 times)

Sanguis

  • Guest
Non-rectangular windows with SetWindowRgn
« on: February 20, 2007, 05:23:46 PM »
Hello everyone,

In my new app I'm trying to make circle-round windows.
Here ye the code:
Code: [Select]
bool InitRoundButtons(void)
{
    /* Register the ROUNDBUTTON class */
    WNDCLASS wc = {
        CS_OWNDC|CS_NOCLOSE, RoundButtonProc, 0, 0,
        hinst /* Globally defined */, NULL, LoadCursor(NULL, IDC_ARROW),
        NULL, NULL, "ROUNDBUTTON"
    };
    return (bool) RegisterClass(&wc);
}

HWND CreateRoundButton(int x, int y, int dm /* Diameter */, HBITMAP hbmp)
{
 /* Create one round button with the rb class ("ROUNDBUTTON").
    This is actually a round window that looks like a button and acts
    like it. The RoundButtonProc handles the messages */
    HWND hbttn = CreateWindowEx(WS_EX_TOPMOST|WS_EX_TOOLWINDOW,
                                "ROUNDBUTTON", NULL, WS_POPUP|WS_VISIBLE,
                                x, y, dm + 5, dm + 5, NULL, NULL, GetVplInst(), NULL);
                                /* + 5 for the framing */
    if (!hbttn) return NULL;
    /* Now we'll paint the window */
    HRGN hrgn;
    HBRUSH hbr;
    HDC hdc;
    /* Paint the bitmap on circle region */
    hrgn = CreateEllipticRgn(x, y, x + dm, y + dm);
    hbr  = CreatePatternBrush(hbmp);
    hdc  = GetDC(hbttn);
    SelectObject(hdc, hbr);
    if (!PaintRgn(hdc, hrgn)) {
        DestroyWindow(hbttn);
        DeleteObject(hbr);
        return NULL;
    }
    DeleteObject(hbr);
    /* Yeah, I should replace this with a call to PaintRoundButton(). Ah, well */
    /* Draw its borders */
    hbr = CreateSolidBrush(RGB(120, 115, 149)); /* Nice color */
    FrameRgn(hdc, hrgn, hbr, 1, 2);
    /* Map the window into that circle */
    if (SetWindowRgn(hbttn, hrgn, true)) {
        return hbttn;
    }
    DestroyRoundButton(hbttn);
    return NULL;
}

void DestroyRoundButton(HWND hbttn)
{
    /*** THIS FUNCTION IS NOT COMPLETE YET ***/
    /* Delete the window and the GDI handles */
    HRGN hrgn = NULL;
    GetWindowRgn(hbttn, hrgn);
    DeleteObject(hrgn);
    DestroyWindow(hbttn);
}

bool PaintRoundButton(HWND hbttn)
{
    HRGN hrgn = NULL;
    if (GetWindowRgn(hbttn, hrgn)) {
        HDC hdc = GetDC(hbttn);
        /* Fill the region */
        PaintRgn(hdc, hrgn);
        /* Draw its borders */
        HBRUSH hbr = CreateSolidBrush(RGB(120, 115, 149));
        bool ret = FrameRgn(hdc, hrgn, hbr, 1, 2);
        DeleteObject(hbr);
        return ret;
    }
    return false;
}

LRESULT CALLBACK RoundButtonProc(HWND hwnd, uint msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg) {
            case WM_CREATE:
                break;

            case WM_PAINT: {
                PAINTSTRUCT ps;
                BeginPaint(hwnd, &ps);
                /* Paint the button's bitmap */
                PaintRoundButton(hwnd);
                EndPaint(hwnd, &ps);
                break;
            }

            case WM_CLOSE:
                /* DeleteObject() the regions */
                DestroyRoundButton(hwnd);
                break;

            default:
                return DefWindowProc(hwnd, msg, wparam, lparam);
    }
    return 0;
}

Yeah, the code is messy - although I thought that should work.
Well, it didn't. The following code:
Code: [Select]
HWND hbttn = CreateRoundButton(5, 5, 104, A_BITMAP);

works fine but if x is like 50 and y too the circle only gets painted half or I can't see it.

I'm probably missing something, but I've searched the Win32 Help manual and MSDN and I can't find any samples... (I'm quite new to extensive GDI programming :mrgreen:).

Any help appreciated!

ivanhv

  • Guest
Non-rectangular windows with SetWindowRgn
« Reply #1 on: March 10, 2007, 12:00:32 AM »
I haven't tested the code, but when you create the region:

hrgn = CreateEllipticRgn(x, y, x + dm, y + dm);

I think it should be:

hrgn = CreateEllipticRgn(0, 0, dm, dm);

because when you set this region as the one for your window, GDI will consider the region coordinates as relative to your window (the round button) and not its container. That 'd explain why you only see half the button when x and y are 50... 50 is approximately 104 / 2.

I could be wrong at this, but why don't you try? Your code is not compilable as it is... next time, send a whole compilable text, please. It's easier to test full code than to try to assemble different pieces of code for testing.

Sanguis

  • Guest
Non-rectangular windows with SetWindowRgn
« Reply #2 on: March 10, 2007, 03:48:26 PM »
Thanks for the response!
That did the trick.