'CHAMELEON BUTTON copyright 2001-2002 by gonchuki E -mail: gonchuki@ yahoo.es
'This is not the normal Cham button - Brian Lai chose to edit it and get everything he thought was useless out of the control.
'Removed functions:
'many styles, focus rect function, special effects, colour schemes, soft bevel, mask colour toggle, greyscale, hand pointer
'Edited functions:
'mouseover leaking problem. now it doesn't (except when in Windows 32-bit button mode)
Private Declare Function SetPixel Lib "gdi32" Alias "SetPixelV" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long
Private Declare Function GetSysColor Lib "user32" (ByVal nIndex As Long) As Long
Private Const COLOR_HIGHLIGHT = 13
Private Const COLOR_BTNFACE = 15
Private Const COLOR_BTNSHADOW = 16
Private Const COLOR_BTNTEXT = 18
Private Const COLOR_BTNHIGHLIGHT = 20
Private Const COLOR_BTNDKSHADOW = 21
Private Const COLOR_BTNLIGHT = 22
Private Declare Function OleTranslateColor Lib "oleaut32.dll" (ByVal lOleColor As Long, ByVal lHPalette As Long, lColorRef As Long) As Long
Private Declare Function SetTextColor Lib "gdi32" (ByVal hdc As Long, ByVal crColor As Long) As Long
Private Declare Function DrawText Lib "user32" Alias "DrawTextA" (ByVal hdc As Long, ByVal lpStr As String, ByVal nCount As Long, lpRect As RECT, ByVal wFormat As Long) As Long
Private Const DT_CALCRECT = &H400
Private Const DT_WORDBREAK = &H10
Private Const DT_CENTER = &H1 Or DT_WORDBREAK Or &H4
Private Declare Function CreateSolidBrush Lib "gdi32" (ByVal crColor As Long) As Long
Private Declare Function FillRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
Private Declare Function FrameRect Lib "user32" (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, lpPoint As POINTAPI) As Long
Private Declare Function LineTo Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function CreatePen Lib "gdi32" (ByVal nPenStyle As Long, ByVal nWidth As Long, ByVal crColor As Long) As Long
Private Const PS_SOLID = 0
Private Declare Function CreateRectRgn Lib "gdi32" (ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Private Declare Function CombineRgn Lib "gdi32" (ByVal hDestRgn As Long, ByVal hSrcRgn1 As Long, ByVal hSrcRgn2 As Long, ByVal nCombineMode As Long) As Long
Private Declare Function SetWindowRgn Lib "user32" (ByVal hWnd As Long, ByVal hRgn As Long, ByVal bRedraw As Long) As Long
Private Const RGN_DIFF = 4
Private Declare Function GetClientRect Lib "user32" (ByVal hWnd As Long, lpRect As RECT) As Long
Private Declare Function InflateRect Lib "user32" (lpRect As RECT, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function OffsetRect Lib "user32" (lpRect As RECT, ByVal X As Long, ByVal Y As Long) As Long
Private Declare Function CopyRect Lib "user32" (lpDestRect As RECT, lpSourceRect As RECT) As Long
Private Declare Function WindowFromPoint Lib "user32" (ByVal xPoint As Long, ByVal yPoint As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function SetCapture Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetDC Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetParent Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, ByVal nStartScan As Long, ByVal nNumScans As Long, lpBits As Any, lpBI As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function SetDIBitsToDevice Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal dx As Long, ByVal dy As Long, ByVal SrcX As Long, ByVal SrcY As Long, ByVal Scan As Long, ByVal NumScans As Long, Bits As Any, BitsInfo As BITMAPINFO, ByVal wUsage As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DrawIconEx Lib "user32" (ByVal hdc As Long, ByVal xLeft As Long, ByVal yTop As Long, ByVal hIcon As Long, ByVal cxWidth As Long, ByVal cyWidth As Long, ByVal istepIfAniCur As Long, ByVal hbrFlickerFreeDraw As Long, ByVal diFlags As Long) As Long
Private Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type POINTAPI
X As Long
Y As Long
End Type
Private Type BITMAPINFOHEADER
biSize As Long
biWidth As Long
biHeight As Long
biPlanes As Integer
biBitCount As Integer
biCompression As Long
biSizeImage As Long
biXPelsPerMeter As Long
biYPelsPerMeter As Long
biClrUsed As Long
biClrImportant As Long
End Type
Private Type RGBTRIPLE
rgbBlue As Byte
rgbGreen As Byte
rgbRed As Byte
End Type
Private Type BITMAPINFO
bmiHeader As BITMAPINFOHEADER
bmiColors As RGBTRIPLE
End Type
Public Enum ButtonTypes
[Windows 32-bit] = 2 'the classic windows button
[Java metal] = 5 'there are also other styles but not so different from windows one
[Simple Flat] = 7 'the standard flat button seen on toolbars
[Flat Highlight] = 8 'again the flat button but this one has no border until the mouse is over it
[Office XP] = 9 'the new Office XP button
End Enum
Public Enum ColorTypes
[Use Windows] = 1
[Custom] = 2
End Enum
Public Enum PicPositions
cbLeft = 0
cbRight = 1
cbTop = 2
cbBottom = 3
cbBackground = 4
End Enum
'events
Public Event Click()
Attribute Click.VB_MemberFlags = "200"
Public Event MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
Public Event MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Public Event MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
Public Event KeyPress(KeyAscii As Integer)
Public Event KeyDown(KeyCode As Integer, Shift As Integer)
Public Event KeyUp(KeyCode As Integer, Shift As Integer)
Public Event MouseOver()
Public Event MouseOut()
Public Event OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single)
'variables
Private MyButtonType As ButtonTypes
Private MyColorType As ColorTypes
Private PicPosition As PicPositions
Private He As Long 'the height of the button
Private Wi As Long 'the width of the button
Private BackC As Long 'back color
Private BackO As Long 'back color when mouse is over
Private ForeC As Long 'fore color
Private ForeO As Long 'fore color when mouse is over
Private MaskC As Long 'mask color
Private OXPb As Long, OXPf As Long
Private picNormal As StdPicture, picHover As StdPicture
Private pDC As Long, pBM As Long, oBM As Long 'used for the treansparent button
Private elTex As String 'current text
Private rc As RECT, rc2 As RECT, rc3 As RECT, fc As POINTAPI 'text and focus rect locations
Private picPT As POINTAPI, picSZ As POINTAPI 'picture Position & Size
Private rgnNorm As Long
Private LastButton As Byte, LastKeyDown As Byte
Private isEnabled As Boolean
Private HasFocus As Boolean
Private cFace As Long, cLight As Long, cHighLight As Long, cShadow As Long, cDarkShadow As Long, cText As Long, cTextO As Long, cFaceO As Long, cMask As Long, XPFace As Long
Private lastStat As Byte, TE As String, isShown As Boolean 'used to avoid unnecessary repaints
Private isOver As Boolean, inLoop As Boolean
Private captOpt As Long
Private isCheckbox As Boolean, cValue As Boolean
Private Sub OverTimer_Timer()
On Error Resume Next
If Not isMouseOver Then
OverTimer.Enabled = False
isOver = False
Call Redraw(0, True)
RaiseEvent MouseOut
End If
End Sub
Private Sub UserControl_AccessKeyPress(KeyAscii As Integer)
On Error Resume Next
LastButton = 1
Call UserControl_Click
End Sub
Private Sub UserControl_AmbientChanged(PropertyName As String)
On Error Resume Next
If Not MyColorType = [Custom] Then
Call SetColors
Call Redraw(lastStat, True)
End If
End Sub
Private Sub UserControl_Click()
On Error Resume Next
If LastButton = 1 And isEnabled Then
If isCheckbox Then cValue = Not cValue
Call Redraw(0, True) 'be sure that the normal status is drawn
UserControl.Refresh
RaiseEvent Click
End If
End Sub
Private Sub UserControl_DblClick()
On Error Resume Next
If LastButton = 1 Then
Call UserControl_MouseDown(1, 0, 0, 0)
SetCapture hWnd
End If
End Sub
Private Sub UserControl_GotFocus()
On Error Resume Next
HasFocus = True
Call Redraw(lastStat, True)
End Sub
Private Sub UserControl_Hide()
On Error Resume Next
isShown = False
End Sub
Private Sub UserControl_Initialize()
On Error Resume Next
'this makes the control to be slow, remark this line if the "not redrawing" problem is not important for you: ie, you intercept the Load_Event (with breakpoint or messageBox) and the button does not repaint...
isShown = True
End Sub
Private Sub UserControl_KeyDown(KeyCode As Integer, Shift As Integer)
On Error Resume Next
RaiseEvent KeyDown(KeyCode, Shift)
LastKeyDown = KeyCode
Select Case KeyCode
Case 32 'spacebar pressed
Call Redraw(2, False)
Case 39, 40 'right and down arrows
SendKeys "{Tab}"
Case 37, 38 'left and up arrows
SendKeys "+{Tab}"
End Select
End Sub
Private Sub UserControl_KeyPress(KeyAscii As Integer)
On Error Resume Next
RaiseEvent KeyPress(KeyAscii)
End Sub
Private Sub UserControl_KeyUp(KeyCode As Integer, Shift As Integer)
RaiseEvent KeyUp(KeyCode, Shift)
If (KeyCode = 32) And (LastKeyDown = 32) Then 'spacebar pressed, and not cancelled by the user
On Error Resume Next
If isCheckbox Then cValue = Not cValue
Call Redraw(0, False)
UserControl.Refresh
RaiseEvent Click
End If
End Sub
Private Sub UserControl_LostFocus()
On Error Resume Next
HasFocus = False
Call Redraw(lastStat, True)
End Sub
Private Sub UserControl_InitProperties()
On Error Resume Next
isEnabled = True
elTex = Ambient.DisplayName
Set UserControl.Font = Ambient.Font
MyButtonType = [Windows 32-bit]
MyColorType = [Use Windows]
Call SetColors
BackC = cFace: BackO = BackC
ForeC = cText: ForeO = ForeC
MaskC = &HC0C0C0
Call CalcTextRects
End Sub
Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
On Error Resume Next
RaiseEvent MouseDown(Button, Shift, X, Y)
LastButton = Button
If Button <> 2 Then Call Redraw(2, False)
End Sub
Private Sub UserControl_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
On Error Resume Next
RaiseEvent MouseMove(Button, Shift, X, Y)
If Button < 2 Then
If Not isMouseOver Then
'we are outside the button
Call Redraw(0, False)
Else
'we are inside the button
If Button = 0 And Not isOver Then
OverTimer.Enabled = True
isOver = True
Call Redraw(0, True)
RaiseEvent MouseOver
ElseIf Button = 1 Then
isOver = True
Call Redraw(2, False)
isOver = False
End If
End If
End If
End Sub
Private Sub UserControl_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
If MyButtonType = [Simple Flat] Then DrawFrame cHighLight, cShadow, 0, 0, False, True
Case 9 'Office XP
Call DrawCaption(4)
End Select
Call DrawPictures(2)
End If
End With
If isOver And MyColorType = Custom Then BackC = tempCol: SetColors
End Sub
Private Sub DrawRectangle(ByVal X As Long, ByVal Y As Long, ByVal Width As Long, ByVal Height As Long, ByVal Color As Long, Optional OnlyBorder As Boolean = False)
On Error Resume Next
Dim bRECT As RECT
Dim hBrush As Long
bRECT.Left = X
bRECT.Top = Y
bRECT.Right = X + Width
bRECT.Bottom = Y + Height
hBrush = CreateSolidBrush(Color)
If OnlyBorder Then
FrameRect UserControl.hdc, bRECT, hBrush
Else
FillRect UserControl.hdc, bRECT, hBrush
End If
DeleteObject hBrush
End Sub
Private Sub DrawLine(ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long, ByVal Color As Long)
On Error Resume Next
'a fast way to draw lines
Dim pt As POINTAPI
Dim oldPen As Long, hPen As Long
With UserControl
hPen = CreatePen(PS_SOLID, 1, Color)
oldPen = SelectObject(.hdc, hPen)
MoveToEx .hdc, X1, Y1, pt
LineTo .hdc, X2, Y2
SelectObject .hdc, oldPen
DeleteObject hPen
End With
End Sub
Private Sub DrawFrame(ByVal ColHigh As Long, ByVal ColDark As Long, ByVal ColLight As Long, ByVal ColShadow As Long, ByVal ExtraOffset As Boolean, Optional ByVal Flat As Boolean = False)
On Error Resume Next
'a very fast way to draw windows-like frames
Dim pt As POINTAPI
Dim frHe As Long, frWi As Long, frXtra As Long
frHe = He - 1 + ExtraOffset: frWi = Wi - 1 + ExtraOffset: frXtra = Abs(ExtraOffset)
With UserControl
'=============================
If ButtonType = [Windows 32-bit] Then Call DeleteObject(SelectObject(.hdc, CreatePen(PS_SOLID, 1, ColHigh)))
'=============================
MoveToEx .hdc, frXtra, frHe, pt
LineTo .hdc, frXtra, frXtra
LineTo .hdc, frWi, frXtra
'=============================
If ButtonType = [Windows 32-bit] Then Call DeleteObject(SelectObject(.hdc, CreatePen(PS_SOLID, 1, ColDark)))
'=============================
LineTo .hdc, frWi, frHe
LineTo .hdc, frXtra - 1, frHe
MoveToEx .hdc, frXtra + 1, frHe - 1, pt
If Flat Then Exit Sub
'=============================
If ButtonType = [Windows 32-bit] Then Call DeleteObject(SelectObject(.hdc, CreatePen(PS_SOLID, 1, ColLight)))
'=============================
LineTo .hdc, frXtra + 1, frXtra + 1
LineTo .hdc, frWi - 1, frXtra + 1
'=============================
If ButtonType = [Windows 32-bit] Then Call DeleteObject(SelectObject(.hdc, CreatePen(PS_SOLID, 1, ColShadow)))
'=============================
LineTo .hdc, frWi - 1, frHe - 1
LineTo .hdc, frXtra, frHe - 1
End With
End Sub
Private Sub mSetPixel(ByVal X As Long, ByVal Y As Long, ByVal Color As Long)
On Error Resume Next
Call SetPixel(UserControl.hdc, X, Y, Color)
End Sub
Private Sub SetColors()
On Error Resume Next
'this function sets the colors taken as a base to build
'all the other colors and styles.
If MyColorType = Custom Then
cFace = ConvertFromSystemColor(BackC)
cFaceO = ConvertFromSystemColor(BackO)
cText = ConvertFromSystemColor(ForeC)
cTextO = ConvertFromSystemColor(ForeO)
cShadow = ShiftColor(cFace, -&H40)
cLight = ShiftColor(cFace, &H1F)
cHighLight = ShiftColor(cFace, &H2F) 'it should be 3F but it looks too lighter
cDarkShadow = ShiftColor(cFace, -&HC0)
OXPb = ShiftColor(cFace, -&H80)
OXPf = cFace
Else
'if MyColorType is 1 or has not been set then use windows colors
cFace = GetSysColor(COLOR_BTNFACE)
cFaceO = cFace
cShadow = GetSysColor(COLOR_BTNSHADOW)
cLight = GetSysColor(COLOR_BTNLIGHT)
cDarkShadow = GetSysColor(COLOR_BTNDKSHADOW)
cHighLight = GetSysColor(COLOR_BTNHIGHLIGHT)
cText = GetSysColor(COLOR_BTNTEXT)
cTextO = cText
OXPb = GetSysColor(COLOR_HIGHLIGHT)
OXPf = ShiftColorOXP(OXPb)
End If
cMask = ConvertFromSystemColor(MaskC)
XPFace = ShiftColor(cFace, &H30, False)
End Sub
Private Sub MakeRegion()
On Error Resume Next
'this function creates the regions to "cut" the UserControl
'so it will be transparent in certain areas
Dim rgn1 As Long, rgn2 As Long
DeleteObject rgnNorm
rgnNorm = CreateRectRgn(0, 0, Wi, He)
rgn2 = CreateRectRgn(0, 0, 0, 0)
Select Case MyButtonType
Case 1, 5 'Windows 16-bit, Java
rgn1 = CreateRectRgn(0, He, 1, He - 1)
CombineRgn rgn2, rgnNorm, rgn1, RGN_DIFF
DeleteObject rgn1
rgn1 = CreateRectRgn(Wi, 0, Wi - 1, 1)
CombineRgn rgnNorm, rgn2, rgn1, RGN_DIFF
DeleteObject rgn1
If MyButtonType <> 5 Then 'the above was common code
rgn1 = CreateRectRgn(0, 0, 1, 1)
CombineRgn rgn2, rgnNorm, rgn1, RGN_DIFF
DeleteObject rgn1
rgn1 = CreateRectRgn(Wi, He, Wi - 1, He - 1)
CombineRgn rgnNorm, rgn2, rgn1, RGN_DIFF
DeleteObject rgn1
End If
End Select
DeleteObject rgn2
End Sub
Private Sub SetAccessKeys()
On Error Resume Next
'this is a TRUE access keys parser
'the basic rule is that if an ampersand is followed by another,
' a single ampersand is drawn and this is not the access key.
' So we continue searching for another possible access key.
' I only do a second pass because no one writes text like "Me & them & everyone"
' so the caption prop should be "Me && them && &everyone", this is rubbish and a
' search like this would only waste time
Dim ampersandPos As Long
'we first clear the AccessKeys property, and will be filled if one is found
If picNormal Is Nothing And picHover Is Nothing Then Exit Sub
If (Trim$(elTex) <> "") And (PicPosition <> 4) Then 'if there is no caption, or we have the picture as background, then we put the picture at the center of the button
Select Case PicPosition
Case 0 'left
picPT.X = rc.Left - picSZ.X - 4
picPT.Y = (He - picSZ.Y) \ 2
Case 1 'right
picPT.X = rc.Right + 4
picPT.Y = (He - picSZ.Y) \ 2
Case 2 'top
picPT.X = (Wi - picSZ.X) \ 2
picPT.Y = rc.Top - picSZ.Y - 2
Case 3 'bottom
picPT.X = (Wi - picSZ.X) \ 2
picPT.Y = rc.Bottom + 2
End Select
Else 'center the picture
picPT.X = (Wi - picSZ.X) \ 2
picPT.Y = (He - picSZ.Y) \ 2
End If
End Sub
Private Sub TransBlt(ByVal DstDC As Long, ByVal DstX As Long, ByVal DstY As Long, ByVal DstW As Long, ByVal DstH As Long, ByVal SrcPic As StdPicture, Optional ByVal TransColor As Long = -1, Optional ByVal BrushColor As Long = -1, Optional ByVal MonoMask As Boolean = False, Optional ByVal isGreyscale As Boolean = False, Optional ByVal XPBlend As Boolean = False)
On Error Resume Next
If DstW = 0 Or DstH = 0 Then Exit Sub
Dim B As Long, H As Long, F As Long, I As Long, newW As Long
Dim TmpDC As Long, TmpBmp As Long, TmpObj As Long
Dim Sr2DC As Long, Sr2Bmp As Long, Sr2Obj As Long
Dim Data1() As RGBTRIPLE, Data2() As RGBTRIPLE
Dim Info As BITMAPINFO, BrushRGB As RGBTRIPLE, gCol As Long
Dim SrcDC As Long, tObj As Long, ttt As Long
SrcDC = CreateCompatibleDC(hdc)
If DstW < 0 Then DstW = UserControl.ScaleX(SrcPic.Width, 8, UserControl.ScaleMode)
If DstH < 0 Then DstH = UserControl.ScaleY(SrcPic.Height, 8, UserControl.ScaleMode)
If SrcPic.Type = 1 Then 'check if it's an icon or a bitmap
tObj = SelectObject(SrcDC, SrcPic)
Else
Dim br As RECT, hBrush As Long: br.Right = DstW: br.Bottom = DstH