Jump to content

Recommended Posts

Posted

I have had some success recently while working on the Rebar control subclass that will eventually be added to GUIDarkTheme UDF. The dark mode colors used for the background and text are working well now.

Goal:

  • Draw dotted lines over existing white (0xf0f0f0) gripper edge on bands
    • I've seen C++ projects use Polyline WinAPI used for this
    • Although other dotted line methods could be used
  • Draw chevrons when needed
    • I don't even know how to make chevrons appear in Rebar (not familiar with Rebar)
    • I've seen C++ projects use DrawText to draw chevron shape/glyph from text

I have tried a bunch of things to draw dotted lines over the existing white gripper. The only success that I ever had was only drawing on the first band. So I think that my mistake was drawing on the Rect from the whole Rebar instead of the Rect of individual bands. I don't know how to do that or how to get DC for individual bands.

If anybody can help with the dotted lines for gripper edges and chevrons, I would really appreciate it. :)

If that works out successfully, then I can add the checking of style parts after to ensure that we only draw those on bands that are using them at the time of drawing.

Some relevant C++ code from win32-darkmodelib project:

/**
 * @brief Applies custom drawing to a rebar control during `CDDS_PREPAINT`.
 *
 * Paints chevrons and 'gripper' edges for all bands if applicable.
 *
 * @param[in] lpnmcd Reference to `LPNMCUSTOMDRAW`.
 * @return `CDRF_SKIPDEFAULT` if drawing was applied.
 *
 * @see darkRebarNotifyCustomDraw()
 */
[[nodiscard]] static LRESULT prepaintRebar(const LPNMCUSTOMDRAW& lpnmcd) noexcept
{
    ::FillRect(lpnmcd->hdc, &lpnmcd->rc, dmlib::getDlgBackgroundBrush());

    REBARBANDINFO rbBand{};
    rbBand.cbSize = sizeof(REBARBANDINFO);
    rbBand.fMask = RBBIM_STYLE | RBBIM_CHEVRONLOCATION | RBBIM_CHEVRONSTATE;

    const auto nBands = static_cast<UINT>(::SendMessage(lpnmcd->hdr.hwndFrom, RB_GETBANDCOUNT, 0, 0));
    for (UINT i = 0; i < nBands; ++i)
    {
        ::SendMessage(lpnmcd->hdr.hwndFrom, RB_GETBANDINFO, static_cast<WPARAM>(i), reinterpret_cast<LPARAM>(&rbBand));

        // paints chevron
        if ((rbBand.fStyle & RBBS_USECHEVRON) == RBBS_USECHEVRON
            && (rbBand.rcChevronLocation.right - rbBand.rcChevronLocation.left) > 0)
        {
            static const int roundness = dmlib::isAtLeastWindows11() ? dmlib_paint::kWin11CornerRoundness + 1 : 0;

            const bool isHot = (rbBand.uChevronState & STATE_SYSTEM_HOTTRACKED) == STATE_SYSTEM_HOTTRACKED;
            const bool isPressed = (rbBand.uChevronState & STATE_SYSTEM_PRESSED) == STATE_SYSTEM_PRESSED;

            if (isHot)
            {
                dmlib_paint::paintRoundRect(lpnmcd->hdc, rbBand.rcChevronLocation, dmlib::getHotEdgePen(), dmlib::getHotBackgroundBrush(), roundness, roundness);
            }
            else if (isPressed)
            {
                dmlib_paint::paintRoundRect(lpnmcd->hdc, rbBand.rcChevronLocation, dmlib::getEdgePen(), dmlib::getCtrlBackgroundBrush(), roundness, roundness);
            }

            ::SetTextColor(lpnmcd->hdc, isHot ? dmlib::getTextColor() : dmlib::getDarkerTextColor());
            ::SetBkMode(lpnmcd->hdc, TRANSPARENT);

            const auto hFont = dmlib_paint::GdiObject{ lpnmcd->hdc, lpnmcd->hdr.hwndFrom };
            static constexpr UINT dtFlags = DT_CENTER | DT_TOP | DT_SINGLELINE | DT_NOCLIP | DT_NOPREFIX;
            ::DrawText(lpnmcd->hdc, dmlib_glyph::kChevron, -1, &rbBand.rcChevronLocation, dtFlags);
        }

        // paints gripper edge
        if ((rbBand.fStyle & RBBS_GRIPPERALWAYS) == RBBS_GRIPPERALWAYS
            && ((rbBand.fStyle & RBBS_FIXEDSIZE) != RBBS_FIXEDSIZE
                || (rbBand.fStyle & RBBS_NOGRIPPER) != RBBS_NOGRIPPER))
        {
            auto holdPen = static_cast<HPEN>(::SelectObject(lpnmcd->hdc, dmlib::getDarkerTextPen()));

            RECT rcBand{};
            ::SendMessage(lpnmcd->hdr.hwndFrom, RB_GETRECT, static_cast<WPARAM>(i), reinterpret_cast<LPARAM>(&rcBand));

            static constexpr LONG offset = 5;
            const std::array<POINT, 2> edges{ {
                { rcBand.left, rcBand.top + offset},
                { rcBand.left, rcBand.bottom - offset}
            } };
            ::Polyline(lpnmcd->hdc, edges.data(), static_cast<int>(edges.size()));

            ::SelectObject(lpnmcd->hdc, holdPen);
        }
    }
    return CDRF_SKIPDEFAULT;
}

 

Here is my current Rebar subclass testing code:

#include <WinAPIGdi.au3>
#include <WinAPITheme.au3>
#include <WindowsNotifsConstants.au3>
#include <ToolbarConstants.au3>
#include <RebarConstants.au3>
#include <AutoItConstants.au3>
#include <GuiComboBox.au3>
#include <GUIConstantsEx.au3>
#include <GuiDateTimePicker.au3>
#include <GuiEdit.au3>
#include <GuiReBar.au3>
#include <GuiToolbar.au3>
#include <StructureConstants.au3>
#include <WinAPIConstants.au3>
#include <WindowsStylesConstants.au3>
#include <APIGdiConstants.au3>

; Initialize System DPI awareness
DllCall("user32.dll", "bool", "SetProcessDpiAwarenessContext", @AutoItX64 ? "int64" : "int", -2)

Global Const $TBCDRF_USECDCOLORS = 0x800000

Global Const $tagNMTBCUSTOMDRAW = $tagNMHDR & ";dword dwDrawStage;handle hdc;" & $tagRECT & ";dword_ptr dwItemSpec;uint uItemState;lparam lItemlParam;" & _
    "ptr hbrMonoDither;ptr hbrLines;ptr hpenLines;dword clrText;dword clrMark;dword clrTextHighlight;dword clrBtnFace;dword clrBtnHighlight;dword clrHighlightHotTrack;" & _
    "long TextLeft;long TextTop;long TextRight;long TextBottom;int nStringBkMode;int nHLStringBkMode;int iListGap;"

Global $g_hReBar, $hGui

Example()

Func Example()
    $hGui = GUICreate("Rebar Create (v" & @AutoItVersion & ")", 400, 396, -1, -1, $WS_OVERLAPPEDWINDOW)
    GUISetBkColor(0x202020)


    ; create the rebar control
    $g_hReBar = _GUICtrlRebar_Create($hGui, BitOR($CCS_TOP, $WS_BORDER, $RBS_VARHEIGHT, $RBS_AUTOSIZE, $RBS_BANDBORDERS))

    _GUICtrlRebar_SetColorScheme($g_hReBar, 0x383838, 0x383838)

    ; create a toolbar to put in the rebar
    Local $hToolbar = _GUICtrlToolbar_Create($hGui, BitOR($TBSTYLE_FLAT, $CCS_NORESIZE, $CCS_NOPARENTALIGN))
    _GUICtrlToolbar_SetColorScheme($hToolbar, 0x383838, 0x383838)
    _GUICtrlToolbar_SetStyleTransparent($hToolbar, False)

    ; Add standard system bitmaps
    _GUICtrlToolbar_AddBitmap($hToolbar, 1, -1, $IDB_STD_LARGE_COLOR)

    ; Add strings
    Local $aStrings[4]
    $aStrings[0] = _GUICtrlToolbar_AddString($hToolbar, "&New")
    $aStrings[1] = _GUICtrlToolbar_AddString($hToolbar, "&Open")
    $aStrings[2] = _GUICtrlToolbar_AddString($hToolbar, "&Save")
    $aStrings[3] = _GUICtrlToolbar_AddString($hToolbar, "&Help")

    ; Add buttons
    Local Enum $e_idNew = 1000, $e_idOpen, $e_idSave, $e_idHelp
    _GUICtrlToolbar_AddButton($hToolbar, $e_idNew, $STD_FILENEW, $aStrings[0])
    _GUICtrlToolbar_AddButton($hToolbar, $e_idOpen, $STD_FILEOPEN, $aStrings[1])
    _GUICtrlToolbar_AddButton($hToolbar, $e_idSave, $STD_FILESAVE, $aStrings[2], $BTNS_CHECK)
    _GUICtrlToolbar_AddButtonSep($hToolbar)
    _GUICtrlToolbar_AddButton($hToolbar, $e_idHelp, $STD_HELP, $aStrings[3])

    ; create a combobox to put in the rebar
    Local $hCombo = _GUICtrlComboBox_Create($hGui, "", 0, 0, 120)

    _GUICtrlComboBox_BeginUpdate($hCombo)
    _GUICtrlComboBox_AddDir($hCombo, @WindowsDir & "\*.exe")
    _GUICtrlComboBox_EndUpdate($hCombo)

    ; create a date time picker to put in the rebar
    Local $hDTP = _GUICtrlDTP_Create($hGui, 0, 0, 190)

    ; create a input box to put in the rebar
    Local $hInput = _GUICtrlEdit_Create($hGui, "Input control", 0, 0, 120, 20, 0)

    ; add band with control
    _GUICtrlRebar_AddBand($g_hReBar, $hCombo, 120, 200, "Dir *.exe")

    ; add band with date time picker
    _GUICtrlRebar_AddBand($g_hReBar, $hDTP, 120)

    ; add band with toolbar to beginning of rebar
    _GUICtrlRebar_AddToolBarBand($g_hReBar, $hToolbar, "", 0)

    ;add another control
    _GUICtrlRebar_AddBand($g_hReBar, $hInput, 120, 200, "Name:")

    _WinAPI_SetWindowTheme($g_hReBar, "", "")

    GUIRegisterMsg($WM_NOTIFY, WM_NOTIFY)
    GUISetState(@SW_SHOW)


    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                Exit
        EndSwitch
    WEnd
EndFunc   ;==>Example

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $tTool = DllStructCreate($tagNMTBCUSTOMDRAW, $lParam)
    If $tTool.Code <> $NM_CUSTOMDRAW Then Return $GUI_RUNDEFMSG

    Local $dwDrawStage = $tTool.dwDrawStage
    Local $sClass = _WinAPI_GetClassName($tTool.hWndFrom)
    Switch $sClass
        Case "ReBarWindow32"
            Switch $dwDrawStage
                Case $CDDS_PREPAINT
                    Local $hBrush = _WinAPI_CreateSolidBrush(0x383838)
                    Local $tRect = DllStructCreate($tagRECT, DllStructGetPtr($tTool, "left"))
                    _WinAPI_FillRect($tTool.hdc, $tRect, $hBrush)
                    _WinAPI_DeleteObject($hBrush)
                    Return $CDRF_NOTIFYITEMDRAW

                Case $CDDS_ITEMPREPAINT
                    _WinAPI_SetTextColor($tTool.hdc, 0xFFFFFF)
                    _WinAPI_SetBkMode($tTool.hdc, $TRANSPARENT)
                    Return $CDRF_NEWFONT
            EndSwitch

        Case "ToolbarWindow32"
            Switch $dwDrawStage
                Case $CDDS_PREPAINT
                    Local $hBrush = _WinAPI_CreateSolidBrush(0x383838)
                    Local $tRect = DllStructCreate($tagRECT, DllStructGetPtr($tTool, "left"))
                    _WinAPI_FillRect($tTool.hdc, $tRect, $hBrush)
                    _WinAPI_DeleteObject($hBrush)
                    Return $CDRF_NOTIFYITEMDRAW

                Case $CDDS_ITEMPREPAINT
                    Local $iState = $tTool.uItemState

                    If BitAND($iState, $CDIS_HOT) Then
                        $tTool.clrText = 0xFFFFFF
                        $tTool.clrTextHighlight = 0xFFFFFF

                        Local $tRect = DllStructCreate($tagRECT, DllStructGetPtr($tTool, "left"))
                        Local $hPen = _WinAPI_CreatePen($PS_SOLID, 1, 0x121212)
                        Local $hOldPen = _WinAPI_SelectObject($tTool.hdc, $hPen)
                        Local $hBrush = _WinAPI_CreateSolidBrush(BitAND($iState, $CDIS_SELECTED) ? 0x484848 : 0x606060)
                        Local $hObj = _WinAPI_SelectObject($tTool.hdc, $hBrush)
                        _WinAPI_InflateRect($tRect, 0, -2)
                        _WinAPI_RoundRect($tTool.hdc, $tRect, 8, 8)
                        _WinAPI_SelectObject($tTool.hdc, $hObj)
                        _WinAPI_SelectObject($tTool.hdc, $hOldPen)
                        _WinAPI_DeleteObject($hBrush)
                        _WinAPI_DeleteObject($hPen)

                        ; clear item state or else this will not work
                        $tTool.uItemState = Null

                        Return $TBCDRF_USECDCOLORS
                    EndIf

                    If BitAND($iState, $CDIS_CHECKED) Then
                        $tTool.clrText = 0xFFFFFF
                        $tTool.clrTextHighlight = 0xFFFFFF

                        Local $tRect = DllStructCreate($tagRECT, DllStructGetPtr($tTool, "left"))
                        Local $hPen = _WinAPI_CreatePen($PS_SOLID, 1, 0x121212)
                        Local $hOldPen = _WinAPI_SelectObject($tTool.hdc, $hPen)
                        Local $hBrush = _WinAPI_CreateSolidBrush(BitAND($iState, $CDIS_SELECTED) ? 0x484848 : 0x606060)
                        Local $hObj = _WinAPI_SelectObject($tTool.hdc, $hBrush)
                        _WinAPI_InflateRect($tRect, 0, -2)
                        _WinAPI_RoundRect($tTool.hdc, $tRect, 8, 8)
                        _WinAPI_SelectObject($tTool.hdc, $hObj)
                        _WinAPI_SelectObject($tTool.hdc, $hOldPen)
                        _WinAPI_DeleteObject($hBrush)
                        _WinAPI_DeleteObject($hPen)

                        ; clear item state or else this will not work
                        $tTool.uItemState = Null

                        Return $TBCDRF_USECDCOLORS
                    EndIf

                    If Not BitAND($iState, $CDIS_DISABLED) Then
                        $tTool.clrText = 0xFFFFFF
                        $tTool.clrTextHighlight = 0xFFFFFF

                        Return $TBCDRF_USECDCOLORS
                    EndIf

            EndSwitch
        
        Case Else
            Return $GUI_RUNDEFMSG
    EndSwitch

    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...