NO

Author Topic: Control Message Bar  (Read 643 times)

Offline WiiLF23

  • Member
  • *
  • Posts: 66
Control Message Bar
« on: December 06, 2023, 07:22:57 PM »
I am attempting to port this to Pelles C. I have a full project setup and will begin conversion, does anyone have a current solution?

https://www.codeproject.com/Articles/29998/Control-Message-Bar

Cheers!



UPDATE:
It appears, it may be easier than this by handling WM_CTLCOLORSTATIC, but there is more involved and we want to allow for different controls.

Code: [Select]
...
HWND hwndMessage = CreateWindowEx(0, L"STATIC", L"Message Above ListView", WS_VISIBLE | WS_CHILD,
10, 0, 300, 50, hwndListView, NULL, GetModuleHandle(NULL), NULL);
...
case WM_CTLCOLORSTATIC:
{
int cId = GetDlgCtrlID((HWND)lParam);
if (cId == LISTVIEW_CONTROL)
{
if (hOrangeBrush == NULL)
hOrangeBrush = CreateSolidBrush(RGB(255, 165, 0));

HDC hdcStatic = (HDC)wParam;
SetBkColor(hdcStatic, RGB(255, 165, 0));
SetTextColor(hdcStatic, RGB(255, 255, 255));

return (LRESULT)hOrangeBrush;
}

return DefWindowProc(hwndListView, uMsg, wParam, lParam);
}

My goal is to allow to call a function that attaches to a control handle and reads the rect from the control handle and align in place on demand. This seems to do that without all of the MFC mess.

Regular shell32 icons.

Code: [Select]
void CreateMessageStrip(HWND hwndParent);
Code: [Select]
#define IDM_STRIP_ICON_LEFT     100
#define IDM_STRIP_ICON_CLOSE  101
#define IDM_STRIP_CONTROL       102

COLORREF bColor = RGB(255, 229, 0); // Bottom border color
COLORREF bgColor = RGB(255, 255, 192); // Background color
static HWND hwndMessageStrip = NULL;

void CreateMessageStrip(HWND hwndParent) {
RECT parentRect;
GetClientRect(hwndParent, &parentRect);

SCROLLBARINFO sbi;
sbi.cbSize = sizeof(SCROLLBARINFO);

if (GetScrollBarInfo(hwndParent, OBJID_VSCROLL, &sbi)) {
int stripWidth = parentRect.right;

if (sbi.rcScrollBar.left >= parentRect.right) {
stripWidth -= 15;
}

hwndMessageStrip = CreateWindowEx(0, L"STATIC", L"", WS_VISIBLE | WS_CHILD, 0, 0,
stripWidth, 25, hwndParent, (HMENU)IDM_STRIP_CONTROL, GetModuleHandle(NULL), NULL);
}
}

void AdjustMessageStripPosition(HWND hwndControl) {
RECT rect;
GetClientRect(hwndControl, &rect);

SCROLLBARINFO sbi;
sbi.cbSize = sizeof(SCROLLBARINFO);

if (GetScrollBarInfo(hwndControl, OBJID_VSCROLL, &sbi)) {
if (sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE) {
if (sbi.rcScrollBar.left >= rect.right) {
SetWindowPos(hwndMessageStrip, HWND_TOPMOST, rect.left, rect.top, rect.right - 15, 25, SWP_SHOWWINDOW);
} else {
SetWindowPos(hwndMessageStrip, HWND_TOPMOST, rect.left, rect.top, rect.right, 25, SWP_SHOWWINDOW);
}
}
}
}

void UpdateBgColor(COLORREF newColor, COLORREF newColor2, HWND hStrip) {
bgColor = newColor;
bColor = newColor2;

InvalidateRect(hStrip, NULL, TRUE);
UpdateWindow(hStrip);
}

void AddMessageStrip(HWND hwndMessageStrip, HICON hIcon, const wchar_t *message, int iconSize, int fontSize, int stripHeight) {
    HDC hdc = GetDC(hwndMessageStrip);

    RECT rect;
    GetClientRect(hwndMessageStrip, &rect);

    RECT stripRect = { rect.left, rect.top, rect.right, rect.top + stripHeight };

    HBRUSH hBrush = CreateSolidBrush(bgColor);
    FillRect(hdc, &stripRect, hBrush);

if (bColor) {
    HPEN hPen = CreatePen(PS_SOLID, 1, bColor);
    HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);

    MoveToEx(hdc, stripRect.left, stripRect.bottom - 1, NULL);
    LineTo(hdc, stripRect.right, stripRect.bottom - 1);

    SelectObject(hdc, hOldPen);
    DeleteObject(hPen);
}

    if (hIcon) {
        DrawIconEx(hdc, stripRect.left + 5, stripRect.top + 5, hIcon, iconSize, iconSize, 0, NULL, DI_NORMAL);
    }

    HICON hIconClose = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDM_STRIP_ICON_CLOSE), IMAGE_ICON, 0, 0, LR_SHARED);
    if (hIconClose) {
        int iconX = rect.right - 5 - iconSize;
        DrawIconEx(hdc, iconX, stripRect.top + 5, hIconClose, 16, 17, 0, NULL, DI_NORMAL);
        DestroyIcon(hIconClose);
    }

    HFONT hFont = CreateFont(fontSize, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
        DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, L"Segoe UI");

    HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
    SetTextColor(hdc, RGB(36, 36, 36));

    SetBkColor(hdc, bgColor);
    SetTextAlign(hdc, TA_LEFT);

    TextOutW(hdc, stripRect.left + 5 + iconSize + 5, stripRect.top + 5, message, wcslen(message));

    SelectObject(hdc, hOldFont);
    DeleteObject(hFont);
    DeleteObject(hBrush);
    ReleaseDC(hwndMessageStrip, hdc);
}

LRESULT CALLBACK ListViewWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {
        case WM_NOTIFY: {
            NMHDR* nmhdr = (NMHDR*)lParam;
            if (nmhdr->code == NM_CUSTOMDRAW) {
                NMLVCUSTOMDRAW* lvcd = (NMLVCUSTOMDRAW*)lParam;

                switch (lvcd->nmcd.dwDrawStage) {
                    case CDDS_PREPAINT:
                        InvalidateRect(hwndMessageStrip, NULL, TRUE);
                        return CDRF_NOTIFYITEMDRAW;

                    default:
                        break;
                }
            } else if (nmhdr->code == HDN_BEGINTRACK) {
                return TRUE;
            }
        }
        break;

case WM_MOUSEMOVE:
{
    HWND hStrip = GetDlgItem(hwnd, IDM_STRIP_CONTROL);

POINT cursorPos;
GetCursorPos(&cursorPos);
ScreenToClient(hStrip, &cursorPos);

RECT rectMessageStrip;
GetClientRect(hStrip, &rectMessageStrip);

if (PtInRect(&rectMessageStrip, cursorPos)) {
    UpdateBgColor(RGB(255, 228, 146), RGB(237, 211, 6), hStrip);
} else {
    UpdateBgColor(RGB(255, 255, 192), RGB(255, 229, 0), hStrip);
}

    break;
}

        case WM_CTLCOLORSTATIC: {
int stripHeight = 27; // Strip height
int iconSize = 16, fontSize = 16; // Icont size, Font size
            HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDM_STRIP_ICON_LEFT), IMAGE_ICON, 0, 0, LR_SHARED); // Label icon
wchar_t *stripMessage = L"This is a BETA version. You may experience bugs."; // Label text

            AddMessageStrip(hwnd, hIcon, stripMessage, iconSize, fontSize, stripHeight);
return (LRESULT)GetStockObject(NULL_BRUSH);
        }

        default:
            return CallWindowProc(oldListViewWndProc, hwnd, msg, wParam, lParam);
    }

    return 0;
}

Handle in main dialog, as to reset state when cursor is outside
Code: [Select]
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case WM_MOUSEMOVE:
{
HWND hStrip = GetDlgItem(hwndListView, IDM_STRIP_CONTROL);

POINT cursorPos;
GetCursorPos(&cursorPos);
ScreenToClient(hStrip, &cursorPos);

RECT rectMessageStrip;
GetClientRect(hStrip, &rectMessageStrip);

if (!PtInRect(&rectMessageStrip, cursorPos)) {
UpdateBgColor(RGB(255, 255, 192), RGB(255, 229, 0), hStrip);
}

break;

}
}

break;

Certainly not as close to the original MFC version. Several issues at play.

EDIT:
Icon sizing issue fixed with DrawIconEx()



Next, is implementing the close procedure, and implementing font updates (complete)



It supports
- horizontal scrolling
- left/right vertical scrollbars
- customizing colors, sizes, icon
- mouseover/mouseout transition

That is my rewrite without actually porting the mess. Simple subclass, and a function to call.

Does anyone have a better way to achieve this?

It would be nice to actually paint the strip onto any control handle, as to avoid the parent controls columns from leaking through the strip. Due to that, we handle HDN_BEGINTRACK and return TRUE to prevent resizing events but cursor still appears to want to resize in appearance.

Dragging the columns while over the strip also shows as a leak in either case (you will notice this).

UPDATE:
I've decided to implement mouseover effects for the strip to change backgrounds and border, and reset when mouse is out of region. It's a little choppy.



« Last Edit: December 08, 2023, 01:04:29 AM by WiiLF23 »

Offline Vortex

  • Member
  • *
  • Posts: 802
    • http://www.vortex.masmcode.com
Re: Control Message Bar
« Reply #1 on: December 06, 2023, 08:34:02 PM »
Hi WiiLF23,

It loolks like that the source code is C++, what are the issues while trying to convert the code to C?
Code it... That's all...

Offline WiiLF23

  • Member
  • *
  • Posts: 66
Re: Control Message Bar
« Reply #2 on: December 06, 2023, 10:20:29 PM »
Attempting to convert, but due to the complexity I tried to rewrite but it is not the same effect, as it is not drawn in the controls non-client area. Hoping for a solution.
« Last Edit: December 08, 2023, 11:31:15 PM by WiiLF23 »