# ControlPaint.Light and ControlPaint.Dark

• ### Question

• Hi to all,
i've started using these two functions ControlPaint.Light and ControlPaint.Dark, but i've a dubt.

What is the right range of percentage that could be applied to this functions??

0 to 1 or 1 to 100?

for example.

```BrightColor = Light(Color.red, 10)

or

BrightColor = Light(Color.red, 0.1)
```

Genko.

Saturday, December 8, 2012 2:49 PM

• Interresting.

You would have expect to see

```        If (percDarker <= 0!) Then
Return SystemColors.ControlDark
End If
If (percDarker >= 1!) Then
Return SystemColors.ControlDarkDark
End If```

as it is writen, this code can overflow

``` Return Color.FromArgb(CByte((controlDark.R - CByte((num * percDarker)))), CByte((controlDark.G - CByte((num2 * percDarker)))), CByte((controlDark.B - CByte((num3 * percDarker)))))
```

• Marked as answer by Monday, December 10, 2012 10:20 AM
Monday, December 10, 2012 10:16 AM
• The documentation clearly states that the floating point value represents a percentage.  This strongly suggests that the correct values to be passed to the method should represent a normalized value.  In other words a value that ranges from 0 to 1, a percentage.

http://msdn.microsoft.com/en-us/library/h3fxkc2x%28v=vs.100%29.aspx  ControlPaint.Dark

An inspection of the .NET Framework 4 source code confirms this.  Here is the Dark method.

```Public Shared Function Dark(ByVal baseColor As Color, ByVal percOfDarkDark As Single) As Color
Dim color As New HLSColor(baseColor)
Return color.Darker(percOfDarkDark)
End Function

```

Notice that it calls another method, HLSColor.Darker.  Here's the source code for that method.

```Public Function Darker(ByVal percDarker As Single) As Color
If Me.isSystemColors_Control Then
If (percDarker = 0!) Then
Return SystemColors.ControlDark
End If
If (percDarker = 1!) Then
Return SystemColors.ControlDarkDark
End If
Dim controlDark As Color = SystemColors.ControlDark
Dim controlDarkDark As Color = SystemColors.ControlDarkDark
Dim num As Integer = (controlDark.R - controlDarkDark.R)
Dim num2 As Integer = (controlDark.G - controlDarkDark.G)
Dim num3 As Integer = (controlDark.B - controlDarkDark.B)
Return Color.FromArgb(CByte((controlDark.R - CByte((num * percDarker)))), CByte((controlDark.G - CByte((num2 * percDarker)))), CByte((controlDark.B - CByte((num3 * percDarker)))))
End If
Dim num4 As Integer = 0
Dim num5 As Integer = Me.NewLuma(-333, True)
Return Me.ColorFromHLS(Me.hue, (num5 - CInt(((num5 - num4) * percDarker))), Me.saturation)
End Function

```

Notice the check of the passed floating point value for a value of 0 or 1, which in turn minimum and maximum values respectively. If not, the passed value is used as a multiplier toscale the output value as percentage between the minimum and maximum values.

A percentage value will always be a value between 0 and 1.

Hope this helps.

Rudy    =8^D

Mark the best replies as answers. "Fooling computers since 1971."

http://thesharpercoder.com/

• Edited by Sunday, December 9, 2012 4:34 PM
Sunday, December 9, 2012 4:34 PM

### All replies

• Hi,

just test it. I think 0 to 2 will lighten black up to white:

```        Dim c As Color = ControlPaint.Light(Color.Black, 1)
Me.BackColor = c
MessageBox.Show(c.ToString())```

... but these ranges might vary. For instance ControlPaint.Dark with a White color starts by -0.5F for no change up to +1.0f which is black...

Regards,

Thorsten

Saturday, December 8, 2012 3:23 PM
• The value represents a percentage.  Try using values between 0 and 1.

Hope this helps.

Rudy   =8^D

Mark the best replies as answers. "Fooling computers since 1971."

http://thesharpercoder.com/

Saturday, December 8, 2012 3:26 PM
• It looks like it goes from 0 to 2 on my laptop. Actually from -2 to 2.

```Public Class Form1

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
HScrollBar1.SmallChange = 1
HScrollBar1.SmallChange = 10
HScrollBar1.Maximum = 100
HScrollBar1.Value = 0

End Sub

Private Sub HScrollBar1_Scroll(sender As Object, e As ScrollEventArgs) Handles HScrollBar1.Scroll
Me.BackColor = ControlPaint.Light(Color.Red, HScrollBar1.Value / 50)
Me.Refresh()
Me.Text = HScrollBar1.Value.ToString
End Sub
End Class```

You've taught me everything I know but not everything you know.

Saturday, December 8, 2012 3:35 PM
• 2nd One,

The range is from 0 to 1.

Regards,
Dhaval Panchal
Software Engineer
(Fast Track Software Services)

Sunday, December 9, 2012 12:43 PM
• not sure about, i've tried and for me it's -0.5 to 1.5...for Dark

for light.....i don't know..

Sunday, December 9, 2012 3:59 PM
• The documentation clearly states that the floating point value represents a percentage.  This strongly suggests that the correct values to be passed to the method should represent a normalized value.  In other words a value that ranges from 0 to 1, a percentage.

http://msdn.microsoft.com/en-us/library/h3fxkc2x%28v=vs.100%29.aspx  ControlPaint.Dark

An inspection of the .NET Framework 4 source code confirms this.  Here is the Dark method.

```Public Shared Function Dark(ByVal baseColor As Color, ByVal percOfDarkDark As Single) As Color
Dim color As New HLSColor(baseColor)
Return color.Darker(percOfDarkDark)
End Function

```

Notice that it calls another method, HLSColor.Darker.  Here's the source code for that method.

```Public Function Darker(ByVal percDarker As Single) As Color
If Me.isSystemColors_Control Then
If (percDarker = 0!) Then
Return SystemColors.ControlDark
End If
If (percDarker = 1!) Then
Return SystemColors.ControlDarkDark
End If
Dim controlDark As Color = SystemColors.ControlDark
Dim controlDarkDark As Color = SystemColors.ControlDarkDark
Dim num As Integer = (controlDark.R - controlDarkDark.R)
Dim num2 As Integer = (controlDark.G - controlDarkDark.G)
Dim num3 As Integer = (controlDark.B - controlDarkDark.B)
Return Color.FromArgb(CByte((controlDark.R - CByte((num * percDarker)))), CByte((controlDark.G - CByte((num2 * percDarker)))), CByte((controlDark.B - CByte((num3 * percDarker)))))
End If
Dim num4 As Integer = 0
Dim num5 As Integer = Me.NewLuma(-333, True)
Return Me.ColorFromHLS(Me.hue, (num5 - CInt(((num5 - num4) * percDarker))), Me.saturation)
End Function

```

Notice the check of the passed floating point value for a value of 0 or 1, which in turn minimum and maximum values respectively. If not, the passed value is used as a multiplier toscale the output value as percentage between the minimum and maximum values.

A percentage value will always be a value between 0 and 1.

Hope this helps.

Rudy    =8^D

Mark the best replies as answers. "Fooling computers since 1971."

http://thesharpercoder.com/

• Edited by Sunday, December 9, 2012 4:34 PM
Sunday, December 9, 2012 4:34 PM
• Interresting.

You would have expect to see

```        If (percDarker <= 0!) Then
Return SystemColors.ControlDark
End If
If (percDarker >= 1!) Then
Return SystemColors.ControlDarkDark
End If```

as it is writen, this code can overflow

``` Return Color.FromArgb(CByte((controlDark.R - CByte((num * percDarker)))), CByte((controlDark.G - CByte((num2 * percDarker)))), CByte((controlDark.B - CByte((num3 * percDarker)))))
```

• Marked as answer by Monday, December 10, 2012 10:20 AM
Monday, December 10, 2012 10:16 AM

• as it is writen, this code can overflow

``` Return Color.FromArgb(CByte((controlDark.R - CByte((num * percDarker)))), CByte((controlDark.G - CByte((num2 * percDarker)))), CByte((controlDark.B - CByte((num3 * percDarker)))))
```

I haven't worked out the logic, but first glance says you're probably right.  But, wouldn't adding the greater/less than check slow it down significantly, compared to not making the check?  I guess the designers decided to assign responsibility of ensuring that the "percentage" value passed to the method is within the range of 0 to 1 onto the consumer.

A ProgressBar shows a somewhat similar design mindset when it comes to writing to the Value property: no bounds checking is made to ensure that the Value the consumer assigns is within the limits defined by the Min and Max value properties.

Rudy   =8^D

Mark the best replies as answers. "Fooling computers since 1971."

http://thesharpercoder.com/

Monday, December 10, 2012 4:29 PM
• ProgressBar throw when the values are out of bounds

```Public Property Value As Integer
Get
Return Me.value
End Get
Set(ByVal value As Integer)
If (Me.value <> value) Then
If (value >= Me.minimum AndAlso value <= Me.maximum) Then
Me.value = value
Me.UpdatePos()
Else
Dim str As Object() = New Object(4)
str(0) = "Value"
str(1) = value.ToString(CultureInfo.CurrentCulture)
str(2) = "'minimum'"
str(3) = "'maximum'"
Throw New ArgumentOutOfRangeException("Value", SR.GetString("InvalidBoundArgument", str))
End If
End If
End Set
End Property```

• Edited by Monday, December 10, 2012 8:54 PM
Monday, December 10, 2012 8:53 PM
• @Crazypennie

Exactly my point. Take another look at the code you posted!

An exception is thrown when the passed value is out of range.  The responsibility for not throwing an exception is put on the consumer.   When an out of range value is passed, it is not swallowed up, corrected for, or otherwise ignored.  In both cases, an exception is thrown.

Your posted sample with the greater/less than checks, handles out of range values for the consumer without their direct knowledge.  I think that is not necessarily a good thing.  I think it is a bad thing to do to the consumer.  When they make a mistake, let them know about it, instead of sweeping it away under the rug.

The ProgressBar.PerformStep method will never through an exception, however.  I find it to be my preferred method of updating a progressbar control.

Rudy   =8^D

Mark the best replies as answers. "Fooling computers since 1971."

http://thesharpercoder.com/

Wednesday, December 12, 2012 4:40 PM
• The problem I see with the Darker implementation can be describe like this

- Ok, the function is expecting a value between 0 and 1 but it will not block any value out of this range.

- therefore a user can mistakably pass as example 99 ( thinking 99%). And the function can be succesful as darkening the control with this value many times  ... until the internal computation  "percDarker * num"   overflows when casted as byte.

- The exception that the user will get is NOT gonna be "ArgumentOutOfRangeException" as it should be, but an "OverflowException" which will not give him any hint about the fact that he is using a value out of the expected range.

-Since the user is not aware of this internal multiplication and not aware of his mistake, for him, he will find the function unstable

---------------------

In the case of the progressBar, the exception returned when the values are wrong is  "ArgumentOutOfRangeException" ... as it should be

• Edited by Wednesday, December 12, 2012 7:33 PM
Wednesday, December 12, 2012 7:30 PM
• If a person passes a value of 99 to a method that is asking for a percentage value, then all mistakes and any misconceptions are their own.

Mark the best replies as answers. "Fooling computers since 1971."

http://thesharpercoder.com/

Thursday, December 13, 2012 5:54 PM