VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "cwLabel"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
'Please look into the comments of cwHelloWorld, to get a more commented
'"for beginners" introducion, on how to implement a very simple widget.
'Nonetheless the cwLabel here is also not "utterly complicated", but more complete.
Option Explicit

Private mCaption As String
Private mSingleLine As Boolean
Private mAlignment As AlignmentConstants
Private mInnerSpace As Long
Private mVAlign As Long
Private mBorderWidth As Long

'****---- Start of cwImplementation-Conventions ----****
Private WithEvents W As cWidgetBase
Attribute W.VB_VarHelpID = -1

Private Sub Class_Initialize()
  Set W = New cWidgetBase '<- this is required in each cwImplementation...
  
  'some default-inits on our Widget-internal, local 'm' Variables
  mBorderWidth = 1
  mAlignment = vbLeftJustify
  mInnerSpace = 1 '1 Pixel Offset for the Text-Rendering - independent from (and additionally to) the BorderSize)
  
  '...and the following "W-Defaults-adaptions" are done individually (as needed for the control in question)
  W.SetClientAreaOffsets mBorderWidth, mBorderWidth, mBorderWidth, mBorderWidth '<- this defines a widget-client-area
  W.CanGetFocus = False 'this way the Label will not be respected in the "Focus-Switch-Chain"
End Sub

Public Property Get Widget() As cWidgetBase
  Set Widget = W
End Property
Public Property Get Widgets() As cWidgets
  Set Widgets = W.Widgets
End Property
'****---- End of cwImplementation-Conventions ----****


'OK, let's implement our small Label-Widget, starting with its Caption-Property
Public Property Get Caption() As String
  Caption = mCaption
End Property
Public Property Let Caption(ByVal NewValue As String)
  If mCaption = NewValue Then Exit Property
  mCaption = NewValue
  W.Refresh 'a change of the Caption will require a Redraw, so let's signal that over W
End Property

Public Property Get Alignment() As AlignmentConstants
  Alignment = mAlignment
End Property
Public Property Let Alignment(ByVal NewValue As AlignmentConstants)
  If mAlignment = NewValue Then Exit Property
  mAlignment = NewValue
  W.Refresh 'a change of the horizontal Alignment will require a Redraw, so let's signal that over W
End Property

Public Property Get VAlign() As Long
  VAlign = mVAlign
End Property
Public Property Let VAlign(ByVal NewValue As Long)
  If mVAlign = NewValue Then Exit Property
  mVAlign = NewValue
  W.Refresh 'a change of the vertical Alignment will require a Redraw, so let's signal that over W
End Property

Public Property Get BorderWidth() As Long
  BorderWidth = mBorderWidth
End Property
Public Property Let BorderWidth(ByVal NewValue As Long)
  If mBorderWidth = NewValue Then Exit Property
  mBorderWidth = NewValue
  W.SetClientAreaOffsets mBorderWidth, mBorderWidth, mBorderWidth, mBorderWidth
  W.Refresh 'a change of the BorderWidth will require a Redraw, so let's signal that over W
End Property

Public Property Get InnerSpace() As Long
  InnerSpace = mInnerSpace
End Property
Public Property Let InnerSpace(ByVal NewValue As Long)
  If mInnerSpace = NewValue Then Exit Property
  mInnerSpace = NewValue
  W.Refresh 'a change of the InnerSpace will require a Redraw, so let's signal that over W
End Property

Public Property Get SingleLine() As Boolean
  SingleLine = mSingleLine
End Property
Public Property Let SingleLine(ByVal NewValue As Boolean)
  If mSingleLine = NewValue Then Exit Property
  mSingleLine = NewValue
  W.Refresh 'a change of the SingleLine-Mode will require a Redraw, so let's signal that over W
End Property


'we now could also implement Font-Properties directly at the Level of *this*
'cwClass'-Interface here - by just mapping against W.FontName, W.FontSize etc. -
'but I'd consider it good practise, if we would let all the stuff alone, which is already
'available behind the "W as cWidgetBase"-interface (and can be accessed from outside over
'the: cwYourImplementation.Widget-Property, which needs to be there in either case on *any*
'cw...Widget.
'Other than in VBs UserControls (which is using the term 'UserControl' internally),
'we can access this "Win-Event-Driven-BaseObject" (our W) without any problems also from
'outside (over the already mentioned Widget-Property)... where in VBs normal UserControls, the
'"hand-out" of the internal 'UserControl'-Helper-Variable is not possible (without some tricks)

'Ok, our Label has got our Public Properties now - and the Font-Stuff can
'be changed from outside per:
'MyLabel.Widget.FontName = "New Name"
'as well as such things here (Widget-Method-Calls, in case you have to move the label):
'MyLabel.Widget.Move X, Y, ..., ...
'...
'So let's proceed with the Paint-Event and the Drawing-stuff now


Private Sub W_Paint(CC As dhCairo.cCairoContext, ByVal xAbs As Single, ByVal yAbs As Single, ByVal DX As Single, ByVal DY As Single, UserObj As Object)
  Draw CC, W.AbsLeft - xAbs, W.AbsTop - yAbs 'here we just delegate to our internal Drawing-Routine...
  
  'the small diff-calculation above is, to provide the "Private Sub Draw" below with correct Client-Coords
  'also in those cases, when the Widget is placed (partially or fully) outside the Clip-Region of its Parent.
  'In a normal Widget-Implementation as here, the above Line which calculates the differences between W.Abs___ and _Abs
  'is fully sufficient - but sometimes, in case you want to do "special stuff" with regards to the behaviour
  'of a Widget, when it is dragged "over the borders" of its parents clip-region (e.g. a resize of the
  'widget instead of a "plain clipped movement" - and then you'd have the needed "overlap-values" already at hand here
End Sub

Private Sub Draw(CC As cCairoContext, ByVal X As Single, ByVal Y As Single)
  'draw the rectangular Outline of our Label and (if needed) also Fill it
  CC.SetLineWidth mBorderWidth
  CC.Rectangle X, Y, W.Width, W.Height, True '<-- note the last optional Param, which ensures a Pixel-aligned drawing inside the Widgets-Bounds
    If W.BackColor <> -1 Then
      CC.SetSourceColor W.BackColor, W.Alpha
      CC.Fill True
    End If
    CC.SetSourceColor W.BorderColor, W.Alpha
  CC.Stroke
  
  'and here the Text-Out
  CC.SelectFont W.FontName, W.FontSize, W.ForeColor, W.FontBold, W.FontItalic
  CC.DrawText X + W.OffsetLeft, Y + W.OffsetTop, W.ScaleWidth, W.ScaleHeight, mCaption, mSingleLine, mAlignment, mInnerSpace, mVAlign
End Sub

