Jump to content

Recommended Posts

Posted

This is a continuation of a script from @Nine from the Round buttons thread by @ioa747.

My intention is to share this script back in that thread but the text color part is not working and therefore I did not want to pollute that thread asking for help. I'd rather get it sorted out and working 100% before sharing it there.

Also, I've seen requests recently for flat, rectangle buttons and this may help for that user. I'm also likely going to use this because it's quite great. Any script from Nine is always great.

So the part that is not working is changing the text color of the buttons with _WinAPI_SetTextColor. Clearly it's an area that I am not familiar with. Anyway, I put a comment line with (not working) in the areas where it is not working.

If someone can help with the text color part, please, that would be fantastic. Thank you. :)

; From Nine
; Modified by WildByDesign

#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <FrameConstants.au3>

#include <guibutton.au3>

; DPI awareness
DllCall("User32.dll", "bool", "SetProcessDpiAwarenessContext" , "HWND", "DPI_AWARENESS_CONTEXT" -2)

Global Const $tagNMCUSTOMDRAWINFO = $tagNMHDR & ";dword DrawStage;handle hdc;" & $tagRECT & ";dword_ptr ItemSpec;uint ItemState;lparam lItemParam;"
Global $idButton

Global $iBackColorDef = 0x404040
Global $iBackColorHot = 0x808080
Global $iBackColorSel = 0x606060
Global $iBackColorDis = 0x000000

Global $iTextColorDef = 0xFFFFFF
Global $iTextColorDis = 0xA0A0A0

Example()

Func Example()
    Local $hGUI = GUICreate("Example")
    GUISetBkColor(0x202020)
    $idButton = GUICtrlCreateButton("Test", 100, 100, 100, 30)

    GUICtrlSendMsg($idButton, $WM_CHANGEUISTATE, 65537, 0)

    GUIRegisterMsg($WM_NOTIFY, WM_NOTIFY)
    GUISetState()

    While True
        Switch GUIGetMsg()
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $idButton
            ConsoleWrite("Button was pressed" & @CRLF)
        EndSwitch
    WEnd
EndFunc   ;==>Example

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local $hBrush
    Local $tInfo = DllStructCreate($tagNMCUSTOMDRAWINFO, $lParam)
    If $tInfo.IDFrom = $idButton And $tInfo.Code = $NM_CUSTOMDRAW And $tInfo.DrawStage = $CDDS_PREPAINT Then
        Local $tRECT = DllStructCreate($tagRECT, DllStructGetPtr($tInfo, "left"))
        If BitAND($tInfo.ItemState, $CDIS_HOT) Then
            ; set hot track back color
            $hBrush = _WinAPI_CreateSolidBrush($iBackColorHot)
            ; set default text color (not working)
            _WinAPI_SetTextColor($tInfo.hDC, $iTextColorDef)
        EndIf
        If BitAND($tInfo.ItemState, $CDIS_SELECTED) Then
            ; set selected back color
            $hBrush = _WinAPI_CreateSolidBrush($iBackColorSel)
            ; set default text color (not working)
            _WinAPI_SetTextColor($tInfo.hDC, $iTextColorDef)
        EndIf
        If BitAND($tInfo.ItemState, $CDIS_DISABLED) Then
            ; set disabled back color
            $hBrush = _WinAPI_CreateSolidBrush($iBackColorDis)
            ; set disabled text color (not working)
            _WinAPI_SetTextColor($tInfo.hDC, $iTextColorDis)
        EndIf
        If Not BitAND($tInfo.ItemState, $CDIS_HOT) And Not BitAND($tInfo.ItemState, $CDIS_SELECTED) Then
            $hBrush = _WinAPI_CreateSolidBrush($iBackColorDef)
        EndIf
        _WinAPI_FillRect($tInfo.hDC, $tRECT, $hBrush)
        _WinAPI_DeleteObject($hBrush)
    EndIf
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

Posted

Sadly you cannot modify the font of a button with NM_CUSTOMDRAW.  As per MSDN, you need to inform the parent with CDRF_NEWFONT (This occurs when dwDrawStage equals CDDS_ITEMPREPAINT).  To tell that you want an item prepaint, you need to use CDRF_NOTIFYITEMDRAW (This occurs when dwDrawStage equals CDDS_PREPAINT).  However the use CDRF_NOTIFYITEMDRAW does not trigger a new drawing stage with a button, as buttons don't have item...

 

Posted

Thanks for confirming. I just tried to combine your NM_CUSTOMDRAW / WM_NOTIFY method with Matty's BS_OWNERDRAW / WM_DRAWITEM method. His works well for coloring the buttons and text, but lacks the ability to color the button on mouse hover. Yours does all of the button states quite well but lacks the text coloring, unfortunately.

So I tried my best to combine the best of both, but it doesn't seem like it can work. I assume that WM_NOTIFY just doesn't trigger for _GUICtrl*_Create UDF functions. I used _WinAPI_GetDlgCtrlID() to obtain the control ID from the button handle but I wasn't able to get it to work properly in the end.

There is so much potential with both methods but it seems that we may out of luck.

  • Solution
Posted (edited)

But you could hack the NM_CUSTOMDRAW.  Not so great but it is working :

; From Nine
#include <GUIConstants.au3>
#include <WindowsConstants.au3>
#include <StructureConstants.au3>
#include <WinAPI.au3>
#include <FrameConstants.au3>

Global Const $tagNMCUSTOMDRAWINFO = $tagNMHDR & ";dword DrawStage;handle hdc;" & $tagRECT & ";dword_ptr ItemSpec;uint ItemState;lparam lItemParam;"
Global $idBut

Example()

Func Example()
  Local $hGUI = GUICreate("Example")
  $idBut = GUICtrlCreateButton("Test", 10, 10, 100, 30)
  GUICtrlCreateButton("Standard", 10, 50, 100, 30)

  GUIRegisterMsg($WM_NOTIFY, WM_NOTIFY)
  GUISetState()

  While True
    Switch GUIGetMsg()
      Case $GUI_EVENT_CLOSE
        ExitLoop
      Case $idBut
        ConsoleWrite("Button was pressed" & @CRLF)
    EndSwitch
  WEnd
EndFunc   ;==>Example

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
  Local $tInfo = DllStructCreate($tagNMCUSTOMDRAWINFO, $lParam)
  If $tInfo.IDFrom = $idBut And $tInfo.Code = $NM_CUSTOMDRAW Then
    Local $tRECT = DllStructCreate($tagRECT, DllStructGetPtr($tInfo, "left"))
    Switch $tInfo.DrawStage
      Case $CDDS_PREPAINT
        _WinAPI_DrawFrameControl($tInfo.hDC, $tRECT, $DFC_BUTTON, (BitAND($tInfo.ItemState, $CDIS_SELECTED) ? $DFCS_PUSHED : 0) + $DFCS_BUTTONPUSH)
        _WinAPI_InflateRect($tRECT, -3, -3)
        Local $hBrush = _WinAPI_CreateSolidBrush(BitAND($tInfo.ItemState, $CDIS_HOT) ? 0xCDEF : 0xAAAA)
        _WinAPI_FillRect($tInfo.hDC, $tRECT, $hBrush)
        _WinAPI_DeleteObject($hBrush)
        Return $CDRF_NOTIFYPOSTPAINT
      Case $CDDS_POSTPAINT
        _WinAPI_InflateRect($tRECT, -6, -6)
        _WinAPI_SetTextColor($tInfo.hDC, 0xFFFFFF)
        _WinAPI_SetBkColor($tInfo.hDC, BitAND($tInfo.ItemState, $CDIS_HOT) ? 0xCDEF : 0xAAAA)
        _WinAPI_DrawText($tInfo.hDC, GUICtrlRead($tInfo.IDFrom), $tRECT, BitOR($DT_CENTER, $DT_VCENTER))
    EndSwitch
  EndIf
  Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY

 

Edited by Nine
better code
Posted
3 hours ago, Nine said:

But you could hack the NM_CUSTOMDRAW.  Not so great but it is working :

Whether it is a hack or not, it seems to do a fantastic job. Thank you so much for helping.

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
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...