Jump to content

Recommended Posts

Posted

My GDI+ skills are next to zero and therefore I need some help with adding a curve/arc to an existing line, please. I know that there are lots of curve/arc functions related to GDI+ path and drawing but I have not been successful with them and don't fully understand.

Goal:

Draw a simple curve at the top and bottom of a single vertical line. The idea is to represent the end of a button.

Why:

I am trying to fix a Microsoft bug in their theme engine related to BS_SPLITBUTTON. Part of my fix involves adding new images to the ImageList for these splitbuttons to cover up their bugged dropdown arrow and vertical split. So I am drawing a vertical split and dropdown button of my own. The problem is that, in order to cover up MS bug, my fix unfortunately has to cut off the very end (right side) of the button border and part of the curvature.

What I have so far:

Button.png.042b4599d01c589b6c3487c35353b064.png

I just need help with adding a slight curve to the top and bottom. The curve should mimic the curvature from the opposite side of the button. the curve goes in about 3 pixels.

Please don't worry about color. Once everything is working, I will have to change the border color and background color to match the existing theme for hover, select, disabled, etc.

Thank you! :)

 

If you need to see what is being covered up, you can briefly comment out the following line (107):

_GUICtrlButton_SetSplitInfo($hWnd, $hImage, $BCSS_IMAGE, 32)

Here is my current code for this:

#include "C:\Program Files (x86)\AutoIt3\Examples\Helpfile\Extras\HelpFileInternals.au3"
#include "C:\Program Files (x86)\AutoIt3\Examples\Helpfile\Extras\WM_NOTIFY.au3"

#include <GuiButton.au3>
#include <GUIConstantsEx.au3>
#include <GuiMenu.au3>
#include <WinAPI.au3>
#include <WinAPITheme.au3>
#include <StructureConstants.au3>
#include <WindowsNotifsConstants.au3>
#include <WindowsStylesConstants.au3>
#include <GDIPlus.au3>
#include <GuiImageList.au3>
#include <ButtonConstants.au3>
#include <FontConstants.au3>
#include <APIGdiConstants.au3>
#include <GDIPlusConstants.au3>
;#include "GUIDarkTheme.au3"

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

Global $g_hBtn, $g_hBtn2

_GDIPlus_Startup()

Example()

Func Example()
    Local $hGUI = GUICreate("Button Set SplitInfo (v" & @AutoItVersion & ")", 600, 400)
    GUISetBkColor(0x191919)
    Local $iDpiRatio = Round(_WinAPI_GetDPIForWindow($hGUI) / 96, 2)
    If @error Then $iDpiRatio = 1
    ;Local $iDpiRatio = 1
    ConsoleWrite("dpi: " & $iDpiRatio & @CRLF)
    _MemoCreate(10, 100, 590, 284, $WS_VSCROLL)

;~  $g_hBtn = _GUICtrlButton_Create($hGUI, "Split Button", 10, 10, 120, 30, $BS_SPLITBUTTON)
;~  _GUICtrlButton_SetSplitInfo($g_hBtn)
    $g_hBtn2 = _GUICtrlButton_Create($hGUI, "Split Button 2", 10, 40, 180, 50, $BS_SPLITBUTTON)
;;;
    Local $hWnd = $g_hBtn2
    _WinAPI_SetWindowTheme($hWnd, "DarkMode_Explorer", "Button")
    Local $iButtonHeight = _WinAPI_GetWindowHeight($hWnd)
    ConsoleWrite("button height: " & $iButtonHeight & @CRLF)
    ;_GUICtrlButton_SetSplitInfo($hWnd, -1, $BCSS_IMAGE)
    ;_GUICtrlButton_SetSplitInfo($hWnd, -1, $BCSS_STRETCH, 13, 13)
    Local $aInfo =_GUICtrlButton_GetSplitInfo($hWnd)
    ConsoleWrite("width: " & $aInfo[2] & @CRLF)
    ConsoleWrite("height: " & $aInfo[3] & @CRLF)

    Local $iSizeW = 32
    Local $iSizeH = $iButtonHeight - 4 ; button height minus 4
    Local $hImage = _GUIImageList_Create($iSizeW, $iSizeH)


    Local $iW = 32, $iH = $iSizeH
    Local $hBitmap = _GDIPlus_BitmapCreateFromScan0($iW, $iH)
    Local $hBmpCtxt = _GDIPlus_ImageGetGraphicsContext($hBitmap)     ;get the graphics context of the bitmap
    _GDIPlus_GraphicsSetSmoothingMode($hBmpCtxt, $GDIP_SMOOTHINGMODE_HIGHQUALITY)
    _GDIPlus_GraphicsClear($hBmpCtxt, 0xFF333333) ; change later to 333333
    Local $hPath = _GDIPlus_PathCreate()
    _GDIPlus_PathAddLine($hPath, 1, 2, 1, $iH - 3) ; vertical split
    _GDIPlus_PathCloseFigure($hPath)
    Local $hPath2 = _GDIPlus_PathCreate()
    _GDIPlus_PathAddLine($hPath2, $iW - 1, 1, $iW - 1, $iH - 1) ; button border fix <<<< need help with curve here
    _GDIPlus_PathCloseFigure($hPath2)
    Local $hPen = _GDIPlus_PenCreate(0xFFa0a0a0, 1)
    Local $hPen2 = _GDIPlus_PenCreate(0xFF9b9b9b, 1)
    _GDIPlus_GraphicsDrawPath($hBmpCtxt, $hPath, $hPen)
    _GDIPlus_GraphicsDrawPath($hBmpCtxt, $hPath2, $hPen2)

    Local $hDC = _GDIPlus_GraphicsGetDC($hBmpCtxt)
    Local $hFont = _WinAPI_CreateFont(Round(12 * $iDpiRatio), 0, 0, 0, 400, False, False, False, $DEFAULT_CHARSET, _
        $OUT_DEFAULT_PRECIS, $CLIP_DEFAULT_PRECIS, $DEFAULT_QUALITY, 0, 'Segoe MDL2 Assets')
    Local $hOldFont = _WinAPI_SelectObject($hDC, $hFont)
    _WinAPI_SetTextColor($hDC, _WinAPI_SwitchColor(0xFFFFFF))
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    Local $tRECT = _WinAPI_CreateRectEx(0, 0, $iW, $iH)
    Local $iTextFlags = BitOR($DT_SINGLELINE, $DT_CENTER, $DT_NOCLIP, $DT_VCENTER)
    _WinAPI_DrawText($hDC, ChrW(0xEDDC), $tRECT, $iTextFlags)
    _GDIPlus_GraphicsReleaseDC($hBmpCtxt, $hDC)

    _WinAPI_SelectObject($hDC, $hOldFont)
    _WinAPI_DeleteObject($hFont)

    _GDIPlus_PenDispose($hPen)
    _GDIPlus_PenDispose($hPen2)
    _GDIPlus_PathDispose($hPath)
    _GDIPlus_PathDispose($hPath2)

    Local $hHBMP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBitmap)

    _GUIImageList_Add($hImage, $hHBMP) ; normal
    _GUIImageList_Add($hImage, $hHBMP) ; hover
    _GUIImageList_Add($hImage, $hHBMP) ; click
    _GUIImageList_Add($hImage, $hHBMP) ; disabled
    _GUIImageList_Add($hImage, $hHBMP) ; focus


    ;_GUIImageList_Add($hImage, _WinAPI_CreateSolidBitmap($hWnd, 0xFF0000, $iSize, $iSize)) ; normal
    ;_GUIImageList_Add($hImage, _WinAPI_CreateSolidBitmap($hWnd, 0x00FF00, $iSize, $iSize)) ; hover
    ;_GUIImageList_Add($hImage, _WinAPI_CreateSolidBitmap($hWnd, 0x0000FF, $iSize, $iSize)) ; click
    ;_GUIImageList_Add($hImage, _WinAPI_CreateSolidBitmap($hWnd, 0x333333, $iSize, $iSize)) ; disabled
    ;_GUIImageList_Add($hImage, _WinAPI_CreateSolidBitmap($hWnd, 0x808080, $iSize, $iSize)) ; focus

    _GUICtrlButton_SetSplitInfo($hWnd, $hImage, $BCSS_IMAGE, 32)
    ;_GUICtrlButton_SetSplitInfo($hWnd, $hImage, BitOR($BCSS_IMAGE, $BCSS_NOSPLIT)) ; remove split
    ;_GUICtrlButton_SetSplitInfo($hWnd, -1, $BCSS_NOSPLIT)
    Local $aInfo =_GUICtrlButton_GetSplitInfo($hWnd)
    ConsoleWrite("width: " & $aInfo[2] & @CRLF)
    ConsoleWrite("height: " & $aInfo[3] & @CRLF)
    ConsoleWrite("imagelist: " & $aInfo[0] & @CRLF)
    ConsoleWrite("imagelist count custom: " & _GUIImageList_GetImageCount($aInfo[0]) & @CRLF)
    ;WinSetState($hWnd, "", @SW_DISABLE)
;;;

    _SendMessage($g_hBtn2, $WM_CHANGEUISTATE, 65537, 0)

    GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
    _WM_NOTIFY_Register($_g_idLst_Memo)

    ;_GUIDarkTheme_ApplyDark($hGUI)

    GUISetState(@SW_SHOW)

    Local $aInfo = _GUICtrlButton_GetSplitInfo($g_hBtn)
    _MemoWrite("Split Info" & @CRLF & "----------------")
    For $x = 0 To 3
        _MemoWrite("$ainfo[" & $x & "] = " & $aInfo[$x])
    Next
    _MemoWrite("Split Info" & @CRLF & "----------------")

    While 1
        Switch GUIGetMsg()
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd

    _GDIPlus_Shutdown()

    Exit
EndFunc   ;==>Example

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam
    Local Const $BCN_HOTITEMCHANGE = -1249
    Local $tagNMBHOTITEM = $tagNMHDR & ";dword dwFlags"
    Local $tNMBHOTITEM = DllStructCreate($tagNMBHOTITEM, $lParam)
    Local $iCode = DllStructGetData($tNMBHOTITEM, "Code")
    Local $hWndFrom = DllStructGetData($tNMBHOTITEM, "hWndFrom")
    Local $iFlags = DllStructGetData($tNMBHOTITEM, "dwFlags")
    Local $sText = ""

    Switch $iCode
        Case $BCN_HOTITEMCHANGE ; Win XP and Above
            $sText = "Text=" & _GUICtrlButton_GetText($hWndFrom)
            If BitAND($iFlags, 0x10) = 0x10 Then
                _WM_NOTIFY_DebugEvent("$BCN_HOTITEMCHANGE - Entering", $tagNMBHOTITEM, $lParam, "IDFrom", $sText)
            ElseIf BitAND($iFlags, 0x20) = 0x20 Then
                _WM_NOTIFY_DebugEvent("$BCN_HOTITEMCHANGE - Leaving", $tagNMBHOTITEM, $lParam, "IDFrom", $sText)
            EndIf
        Case $BCN_DROPDOWN
            _WM_NOTIFY_DebugEvent("$BCN_DROPDOWN", $tagNMBHOTITEM, $lParam, "IDFrom", "")
            _Popup_Menu($hWndFrom)
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

Func _Popup_Menu($hCtrl)
    Local $hMenu
    Local Enum $e_idOpen = 1000, $e_idSave, $e_idInfo
    $hMenu = _GUICtrlMenu_CreatePopup()
    _GUICtrlMenu_InsertMenuItem($hMenu, 0, "Open", $e_idOpen)
    _GUICtrlMenu_InsertMenuItem($hMenu, 1, "Save", $e_idSave)
    _GUICtrlMenu_InsertMenuItem($hMenu, 3, "", 0)
    _GUICtrlMenu_InsertMenuItem($hMenu, 3, "Info", $e_idInfo)
    Switch _GUICtrlMenu_TrackPopupMenu($hMenu, $hCtrl, -1, -1, 1, 1, 2)
        Case $e_idOpen
            _MemoWrite("Open - Selected")
            _GUICtrlButton_SetText($g_hBtn2, "Open")
        Case $e_idSave
            _MemoWrite("Save - Selected")
            _GUICtrlButton_SetText($g_hBtn2, "Save")
        Case $e_idInfo
            _MemoWrite("Info - Selected")
            _GUICtrlButton_SetText($g_hBtn2, "Info")
    EndSwitch
    _GUICtrlMenu_DestroyMenu($hMenu)
EndFunc   ;==>_Popup_Menu

; React on a button click
Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg
    Local $iCode = BitShift($wParam, 16)
    Local $hCtrl = $lParam
    Local $sCode, $sText

    Switch $hCtrl
        Case $g_hBtn, $g_hBtn2
            Switch $iCode
                Case $BN_CLICKED
                    $sCode = "$BN_CLICKED"
                Case $BN_PAINT
                    $sCode = "$BN_PAINT"
                Case $BN_PUSHED
                    $sCode = "$BN_PUSHED"
                Case $BN_HILITE
                    $sCode = "$BN_HILITE"
                Case $BN_UNPUSHED
                    $sCode = "$BN_UNPUSHED"
                Case $BN_UNHILITE
                    $sCode = "$BN_UNHILITE"
                Case $BN_DISABLE
                    $sCode = "$BN_DISABLE"
                Case $BN_DBLCLK
                    $sCode = "$BN_DBLCLK"
                Case $BN_DOUBLECLICKED
                    $sCode = "$BN_DOUBLECLICKED"
                Case $BN_SETFOCUS
                    $sCode = "$BN_SETFOCUS"
                Case $BN_KILLFOCUS
                    $sCode = "$BN_KILLFOCUS"
            EndSwitch
            $sText = "Text=" & _GUICtrlButton_GetText($hCtrl)
            _WM_NOTIFY_DebugEvent($sCode, $tagNMHDR, $lParam, "Handle", $sText)
            Return 0 ; Only workout clicking on the button
    EndSwitch
    ; Proceed the default AutoIt3 internal message commands.
    ; You also can complete let the line out.
    ; !!! But only 'Return' (without any value) will not proceed
    ; the default AutoIt3-message in the future !!!
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_COMMAND

; #FUNCTION# ====================================================================================================================
; Author.........: UEZ
; ===============================================================================================================================
Func _WinAPI_GetDPIForWindow($hWnd)
    Local $aResult = DllCall('user32.dll', "uint", "GetDpiForWindow", "hwnd", $hWnd) ;requires Win10 v1607+ / no server support
    If Not IsArray($aResult) Or @error Then Return SetError(1, @extended, 0)
    If Not $aResult[0] Then Return SetError(2, @extended, 0)
    Return $aResult[0]
EndFunc   ;==>_WinAPI_GetDPIForWindow

 

  • Solution
Posted

Try:

...
    Local $hPath2 = _GDIPlus_PathCreate()
    _GDIPlus_PathAddArc($hPath2, $iW - 6, 0, 5, 5, 270, 90)
    _GDIPlus_PathAddLine($hPath2, $iW - 1, 5, $iW - 1, $iH - 6) ; button border fix <<<< need help with curve here
    _GDIPlus_PathAddArc($hPath2, $iW - 6, $iH - 6, 5, 5, 0, 90)
    Local $hPen = _GDIPlus_PenCreate(0xFFa0a0a0, 1)
    Local $hPen2 = _GDIPlus_PenCreate(0xFF9b9b9b, 1)
    _GDIPlus_GraphicsDrawPath($hBmpCtxt, $hPath, $hPen)
    _GDIPlus_GraphicsDrawPath($hBmpCtxt, $hPath2, $hPen2)
...

 

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Posted

Can you draw entire rouned rectangle at once?

Func _GDIPlus_PathAddRoundedRect($hPath, $nX, $nY, $nWidth, $nHeight, $nRadius)
    ;when adding arc $nX and $nY are coordinates of the entire circle, not only the coordinates of the arc segment

    Local $fP2X=$nX+$nRadius, $fP2y=$nY
    Local $fP3X=$nX+$nWidth-$nRadius, $fP3Y=$nY
    Local $fP4X=$nX+$nWidth-2*$nRadius, $fP4Y=$fP2y
    Local $fP5X=$nX+$nWidth, $fP5Y=$ny+$nRadius
    Local $fP6X=$fP5X, $fP5Y=$nY+$nHeight-$nRadius
    Local $fP7X=$fP4X, $fP7Y=$nY+$nHeight-2*$nRadius
    Local $fP8X=$fP7X+$nRadius, $fP8Y=$nY+$nHeight
    Local $fP9Y=$fP8Y-2*$nRadius

    _GDIPlus_PathStartFigure($hPath)
    _GDIPlus_PathAddArc($hPath,$nX,$nY,2*$nRadius,2*$nRadius,180,90)

    _GDIPlus_PathAddLine($hPath,$fP2X,$fP2Y,$fP3X,$fP3Y)

    _GDIPlus_PathAddArc($hPath,$fP4X,$fP4Y,2*$nRadius,2*$nRadius,270,90)

    _GDIPlus_PathAddLine($hPath,$fP5X,$fP5Y,$fP6X,$fP5Y)

    _GDIPlus_PathAddArc($hPath,$fP7X,$fP7Y,2*$nRadius,2*$nRadius,0,90)

    _GDIPlus_PathAddLine($hPath,$fP8X,$fP8Y, $fP2X, $fP8Y)
    _GDIPlus_PathAddArc($hPath,$nX,$fP9Y,2*$nRadius,2*$nRadius,90,90)
    _GDIPlus_PathCloseFigure($hPath)
EndFunc

 

Posted
1 hour ago, Polar said:

Hi, is the button okay like this?

This is very close. Thank you for trying. I appreciate your time. :)

1 hour ago, UEZ said:

Try:

This is perfect. Thank you so much. 😎

1 hour ago, ahmet said:

Can you draw entire rouned rectangle at once?

Doing the whole rectangle would probably make it easier. But unfortunately I don't think that we can do that because the right side of the splitbutton often gets a different background and border color for different states (hover, clicked, etc.). Thank you for sharing that code though, I appreciate it. :)

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...