It's possible to colourize true buttons in Windows, its a lot of work.
and the callback i use (written more than 10 years ago), i never get crash (i also use gdiplus to colorise buttons)
Code: Select all
Procedure.i Gdiplus_Window_Callback(Window, Message, wParam, lParam)
;///////////////////////////////////////////////////////////////////////////////////////////////////
;//
;// FONCTION: Gdiplus_Window_Callback()
;//
;// BUT: Callback dessinant les boutons couleur
;//
;// PARAMS: Window, Message, wParam, lParam
;//
;// RETOURNE: L'adresse de la procedure d'origine ou la procedure par défaut
;//
;///////////////////////////////////////////////////////////////////////////////////////////////////
Protected stateID, partID, ButtonText.s
Protected BoutonStyle, TexteStyle, textWidth, textHeight, Font
Protected TextColor, Color1, Color2, SavedDC
Protected rc_Interior.RECT, rc_InteriorF.RECTF, rc_ThemeContent.rect
Protected *di.DRAWITEMSTRUCT
Protected *token, *gfx, *brush, *OriginProc
Protected Alpha_Value, hBmpTampon, hdcMem, solidBrush
If ListSize(Gdiplus_Window_SubClassing_Infos()) = 0
ProcedureReturn DefWindowProc_(window, message, wParam, lParam)
EndIf
ForEach (Gdiplus_Window_SubClassing_Infos())
;// on se positionne sur le bon élément
If Gdiplus_Window_SubClassing_Infos()\Gdiplus_SubClassed_Window = Window
Break
EndIf
Next
*OriginProc = GetProp_(Window, Gdiplus_Window_SubClassing_Infos()\Gdiplus_SubClassed_WindowString$)
If *OriginProc = 0
ProcedureReturn DefWindowProc_(window, message, wParam, lParam)
EndIf
*di = lParam
If *di
Select Message
Case #WM_DRAWITEM
If *di\CtlType = #ODT_BUTTON
hdcMem = CreateCompatibleDC_(*di\hDC)
If hdcMem = 0
ProcedureReturn CallWindowProc_(*OriginProc,Window, Message, wParam, lParam)
EndIf
hBmpTampon = CreateCompatibleBitmap_(*di\hDC, GetDeviceCaps_(*di\hDC, #HORZRES), GetDeviceCaps_(*di\hDC, #VERTRES))
If hBmpTampon = 0
DeleteDC_(hdcMem)
ProcedureReturn CallWindowProc_(*OriginProc,Window, Message, wParam, lParam)
EndIf
;// sélectionne l'élément de la Map correspondant au bouton à dessiner, + teste l'initialisation de GDI+ etc.
If ((*GLB_Gdiplus_token <> -1) And GLB_hTheme And MapSize(GLB_Bouton()) And FindMapElement(GLB_Bouton(), Str(GadgetID(*di\CtlID))) = #False)
DeleteDC_(hdcMem)
DeleteObject_(hBmpTampon)
ProcedureReturn CallWindowProc_(*OriginProc,Window, Message, wParam, lParam)
EndIf
;// sélectionne le bmp dans le dc
SelectObject_(hdcMem, hBmpTampon)
If *GdipCreateFromHDC(hdcMem, @*gfx) = #Ok
;// sauvegarde du dc
SavedDC = SaveDC_(*di\hDC)
If GLB_Bouton()\Gdiplus_ButtonStyle = #Button_oldStyle
If *di\itemState & #ODS_DISABLED
partID = #DFC_BUTTON
stateID = #DFCS_BUTTONPUSH|#DFCS_FLAT|#DFCS_INACTIVE
Alpha_Value = 255
TextColor = GetSysColor_(#COLOR_GRAYTEXT)
Color1 = GetSysColor_(#COLOR_BTNFACE)
Color2 = GetSysColor_(#COLOR_BTNFACE)
ElseIf *di\itemState & #ODS_SELECTED
partID = #DFC_BUTTON
stateID = #DFCS_BUTTONPUSH|#DFCS_FLAT|#DFCS_PUSHED
Alpha_Value = GLB_Bouton()\Selected_Alpha
TextColor = GLB_Bouton()\Selected_TextColor
Color1 = GLB_Bouton()\Selected_BackGround_UpperColor
Color2 = GLB_Bouton()\Selected_BackGround_LowerColor
Else
partID = #DFC_BUTTON
stateID = #DFCS_BUTTONPUSH|#DFCS_FLAT
If GLB_Bouton()\IsMouseOver
Alpha_Value = GLB_Bouton()\MouseOver_Alpha
TextColor = GLB_Bouton()\MouseOver_TextColor
Color1 = GLB_Bouton()\MouseOver_BackGround_UpperColor
Color2 = GLB_Bouton()\MouseOver_BackGround_LowerColor
Else
Alpha_Value = GLB_Bouton()\Normal_Alpha
TextColor = GLB_Bouton()\Normal_TextColor
Color1 = GLB_Bouton()\Normal_BackGround_UpperColor
Color2 = GLB_Bouton()\Normal_BackGround_LowerColor
EndIf
EndIf
Else ;// GLB_Bouton()\Gdiplus_ButtonStyle = #Button_XPStyle
If *di\itemState & #ODS_DISABLED
; Debug "#ODS_DISABLED"
; Debug #PBS_DISABLED
partID = #BP_PUSHBUTTON
stateID = #PBS_DISABLED
Alpha_Value = GLB_Bouton()\Normal_Alpha
Alpha_Value = 80
TextColor = GLB_Bouton()\Normal_TextColor
; TextColor = GetSysColor_(#COLOR_GRAYTEXT)
; TextColor = $B1A2A2 ;$838383
; Color1 = GetSysColor_(#COLOR_BTNFACE)
; Color2 = GetSysColor_(#COLOR_BTNFACE)
; Color1 = GLB_Bouton()\Normal_BackGround_UpperColor
Color2 = GLB_Bouton()\Normal_BackGround_LowerColor
Color1 = Color2
ElseIf *di\itemState & #ODS_SELECTED
; Debug #PBS_PRESSED
partID = #BP_PUSHBUTTON
stateID = #PBS_PRESSED
Alpha_Value = GLB_Bouton()\Selected_Alpha
TextColor = GLB_Bouton()\Selected_TextColor
Color1 = GLB_Bouton()\Selected_BackGround_UpperColor
Color2 = GLB_Bouton()\Selected_BackGround_LowerColor
Else
partID = #BP_PUSHBUTTON
stateID = #PBS_NORMAL
; Debug #PBS_NORMAL
If GLB_Bouton()\IsMouseOver
Alpha_Value = GLB_Bouton()\MouseOver_Alpha
TextColor = GLB_Bouton()\MouseOver_TextColor
Color1 = GLB_Bouton()\MouseOver_BackGround_UpperColor
Color2 = GLB_Bouton()\MouseOver_BackGround_LowerColor
Else
Alpha_Value = GLB_Bouton()\Normal_Alpha
TextColor = GLB_Bouton()\Normal_TextColor
Color1 = GLB_Bouton()\Normal_BackGround_UpperColor
Color2 = GLB_Bouton()\Normal_BackGround_LowerColor
EndIf
EndIf
EndIf
If GLB_Bouton()\Gdiplus_ButtonStyle = #Button_XPStyle
;// on redessine le bouton
If IsThemeBackgroundPartiallyTransparent_(GLB_hTheme, partID, stateID)
DrawThemeParentBackground_(*di\hwndItem, hdcMem, *di\rcItem)
EndIf
DrawThemeBackground_(GLB_hTheme, hdcMem, partID, stateID, *di\rcItem, 0)
GetThemeBackgroundContentRect_(GLB_hTheme, *di\hDC, partID, stateID, *di\rcItem, @rc_ThemeContent)
rc_Interior = rc_ThemeContent
ElseIf GLB_Bouton()\Gdiplus_ButtonStyle = #Button_oldStyle
DrawFrameControl_(hdcMem, *di\rcItem, partID, stateID)
rc_Interior = *di\rcItem
InflateRect_(rc_Interior, -GetSystemMetrics_(#SM_CXEDGE), -GetSystemMetrics_(#SM_CYEDGE))
Else ;// GLB_Bouton()\Gdiplus_ButtonStyle = #Button_ThickFrame
GetThemeBackgroundContentRect_(GLB_hTheme, hdcMem, partID, stateID, *di\rcItem, @rc_ThemeContent)
rc_Interior = rc_ThemeContent
solidBrush = CreateSolidBrush_(GLB_Bouton()\Gdiplus_ThickFrameColor)
If solidBrush
FillRect_(hdcMem, *di\rcItem, solidBrush)
DeleteObject_(solidBrush)
EndIf
EndIf
Select GLB_Bouton()\LinearGradientMode
Case #LinearGradientModehorizontal
rc_InteriorF\x = rc_Interior\left
rc_InteriorF\y = rc_Interior\top+1
rc_InteriorF\Width = rc_Interior\right - rc_Interior\left -2
rc_InteriorF\Height = rc_Interior\bottom - rc_Interior\top-2
*GdipCreateLineBrushFromRect(@rc_InteriorF, Gdiplus_ARGB(Color1, Alpha_Value), Gdiplus_ARGB(Color2, Alpha_Value), GLB_Bouton()\LinearGradientMode, #WrapModeTile, @*brush)
*GdipFillRectangle(*gfx, *brush, rc_InteriorF\x+1, rc_InteriorF\y, rc_InteriorF\Width, rc_InteriorF\Height)
Default ;/ #LinearGradientModeVertical, #LinearGradientModeForwardDiagonal, #LinearGradientModeBackwardDiagonal
If GLB_Bouton()\Gdiplus_ButtonStyle = #Button_oldStyle
rc_InteriorF\x = rc_Interior\left+1
rc_InteriorF\y = rc_Interior\top+1
rc_InteriorF\Height = rc_Interior\bottom - rc_Interior\top-1
rc_InteriorF\Width = rc_Interior\right - rc_Interior\left -2
*GdipCreateLineBrushFromRect(@rc_InteriorF, Gdiplus_ARGB(Color1, Alpha_Value), Gdiplus_ARGB(Color2, Alpha_Value), GLB_Bouton()\LinearGradientMode, #WrapModeTile, @*brush)
*GdipFillRectangle(*gfx, *brush, rc_InteriorF\x, rc_InteriorF\y, rc_InteriorF\Width, rc_InteriorF\Height-1)
Else
; Debug "Default"
rc_InteriorF\x = rc_Interior\left
rc_InteriorF\y = rc_Interior\top
rc_InteriorF\Height = rc_Interior\bottom - rc_Interior\top
rc_InteriorF\Width = rc_Interior\right - rc_Interior\left
*GdipCreateLineBrushFromRect(@rc_InteriorF, Gdiplus_ARGB(Color1, Alpha_Value), Gdiplus_ARGB(Color2, Alpha_Value), GLB_Bouton()\LinearGradientMode, #WrapModeTile, @*brush)
rc_InteriorF\x = rc_Interior\left+1
rc_InteriorF\y = rc_Interior\top+1
rc_InteriorF\Height = rc_Interior\bottom - rc_Interior\top-2
rc_InteriorF\Width = rc_Interior\right - rc_Interior\left -2
*GdipFillRectangle(*gfx, *brush, rc_InteriorF\x, rc_InteriorF\y, rc_InteriorF\Width, rc_InteriorF\Height)
EndIf
EndSelect
;// destruction de la brush
Gdiplus_DelBrush(*brush)
;// écriture du texte du bouton
ButtonText = GetGadgetText(*di\CtlID)
If Len(ButtonText)
;// couleur texte , fond transparent
SetTextColor_(hdcMem, TextColor)
SetBkMode_(hdcMem, #TRANSPARENT)
Font = GetGadgetFont(*di\CtlID)
If Font
SelectObject_(hdcMem, Font)
EndIf
;// lecture du style du bouton
BoutonStyle = GetWindowLongPtr_(*di\hwndItem, #GWL_STYLE)
If BoutonStyle & #BS_RIGHT
TexteStyle | #DT_RIGHT
ElseIf BoutonStyle & #BS_LEFT
TexteStyle | #DT_LEFT
Else
TexteStyle | #DT_CENTER
EndIf
If (Not(BoutonStyle & #BS_MULTILINE))
TexteStyle | #DT_SINGLELINE | #DT_WORDBREAK | #DT_VCENTER
rc_Interior\right-1
Else
TexteStyle | #DT_WORDBREAK
;// calcul du rectangle du texte à centrer et centrage
DrawText_(hdcMem, @ButtonText, -1, @rc_Interior, #DT_CALCRECT | TexteStyle)
textWidth = rc_Interior\right - rc_Interior\left
textHeight = rc_Interior\bottom - rc_Interior\top
rc_Interior\left = ((*di\rcItem\right - *di\rcItem\left) - (rc_Interior\right - rc_Interior\left)) / 2
rc_Interior\right = rc_Interior\left + textWidth
rc_Interior\top = (*di\rcItem\bottom - *di\rcItem\top - textheight) / 2
rc_Interior\bottom = rc_Interior\top + textheight
EndIf
;// on écrit le texte
DrawTextEx_(hdcMem, ButtonText, -1, @rc_Interior, TexteStyle | #DT_EXPANDTABS , 0)
;// on copie le hDC de la mémoire vers celui du bouton
BitBlt_(*di\hDC, 0, 0, *di\rcItem\right - *di\rcItem\left, *di\rcItem\bottom - *di\rcItem\top, hdcMem, 0, 0, #SRCCOPY)
EndIf
DeleteDC_(hdcMem)
DeleteObject_(hBmpTampon)
Gdiplus_DelGraphics(*gfx)
If SavedDC
RestoreDC_(*di\hDC, SavedDC)
EndIf
ProcedureReturn #True
EndIf
EndIf
EndSelect
EndIf
ProcedureReturn CallWindowProc_(*OriginProc,Window, Message, wParam, lParam)
EndProcedure