LuminositySlider Control

This element is one more control from the ColorPicker constituent controls bug in addition to the published in my recent posts.

LuminositySlider control is designed as the selector of the Color with the HSL Color model Luminosity ranging from 0 to 1. It’s the extension of the Slider control.

LuminositySlider is provided with the reference Color through the BaseColor Dependency Property. It displays that reference Color gradient starting from the reference Color with the Luminosity set to 0 up to the Color with the Luminosity of 1.

That is the sample:

At the top is the RainbowSlider allowing to select the BaseColor for two LuminositySliders (horizontal and vertical) below it.

LuminositySlider has read-only SelectedColor Dependency Property used to get the value of the Color selected. This property value is synchronized with Minimum, Maximum and Value properties values of the parent Slider control. The caller can set the desired luminance value from the code as follows:

Value = Luminance * (Maximum - Minimum) + Minimum;

When the SelectedColor changes the LuminositySlider raises the SelectedColorChanged event.

The direction the Luminosity value changes depends on the value of IsDirectionReversed property. If it’s false (the default) the minimum Luminosity is at the left or at the bottom of the control depending on the orientation.

The code

You can download the code and the samples here:

http://cid-39d56f0c7a08d703.skydrive.live.com/embedrowdetail.aspx/.Public/WPFGears/WPFGears.zip

The archive contains my WPFGears library with samples, tests, etc. It’s the Visual Studio 2008 SP1 solution targeted to .NET Framework 3.5.

You’ll find LuminositySliderSample project there. LuminositySlider element code is in the WPFGears library project ColorPickerControls folder.

Regards,
Oleg V. Polikarpotchkin

Technorati Теги: ,,,
Posted in Uncategorized | Leave a comment

RainbowBox Element

This element is the one more control from the ColorPicker constituent controls bug in addition to the published in my recent posts.

RainbowBox element is designed as the tool to select a Color from the color spectrum and is close to the one in the Windows Common Color dialog. It extends the FrameworkElement.

The horizontal color spectrum is overlaid by the vertical gradient ranging from transparent color to Gray color. That is the sample.

You select the color with the color selector (small white circle with black border). You can drag it with the mouse or just click anywhere on the RainbowBox element surface. You can provide you own color selector drawing with the RainbowBox.Selector Dependency Property.

Read-only SelectedColor Dependency Property of the RainbowBox used to get the value of the Color selected. User can change the SelectedColor property from its code using the SelectorPosition property. The SelectorPosition property gets or sets the selector position normalized to [0,1 0,1] rectangle. Another way to change the SelectedColor property from the code is the RainbowBox.TrySetSelectedColor method. It gets the color argument and tries to find that color in the Rainbow. On success it sets the selector position accordingly and returns true; otherwise it returns false. When the SelectedColor changes the RainbowBox raises the SelectedColorChanged event.

The Rainbow Dependency Property allows to get or set the color spectrum. It’s of the GradientStopCollection type i.e. represents the sequence of colors along with the position of the color in the spectrum. By default the spectrum is the sequence of equally spaced Red, Orange, Yellow, Green, Blue, Indigo, Violet, Red colors. When the Rainbow property changes the RainbowBox tries to find the current SelectedColor value in the new Rainbow. On success it sets the selector position accordingly; otherwise it sets the selector position to the top-left corner and changes its SelectedColor to the value corresponding to that position.

The code

You can download the code and the samples here:

http://cid-39d56f0c7a08d703.skydrive.live.com/embedrowdetail.aspx/.Public/WPFGears/WPFGears.zip

The archive contains my WPFGears library with samples, tests, etc. It’s the Visual Studio 2008 SP1 solution targeted to .NET Framework 3.5.

You’ll find RainbowBoxSample project there. RainbowBox element code is in the WPFGears library project ColorPickerControls folder.

Regards,
Oleg V. Polikarpotchkin

Technorati Теги: ,,,
Posted in Uncategorized | Leave a comment

ColorSaturationBox Element

This element is one more control from the ColorPicker constituent controls bug in addition to ones published in my recent posts.

ColorSaturationBox element is designed as the tool to select a Color from the mix of some Color with the White and Black colors. It extends the FrameworkElement. The idea of this element is borrowed from the Uncommon Dialogs: Font Chooser & Color Picker Dialogs article.

The color surface to select color from is the superposition of some color gradients. Roughly it consists of

  1. Vertical BaseColor-Black gradient.
  2. Vertical White-Black gradient with Horizontal Opacity mask gradient.

BaseColor is the variable reference color you can get or set with the BaseColor Dependency Property.

That is the sample.

The ColorSaturationBox element is at the top-left window corner. At right of it is the RainbowSlider (see here) used to select the value of BaseColor. The SelectedColor sample is at the right-top corner. Below it the SelectedColor components are displayed in numbers.

You select the color with the color selector (small white circle with black border). You can drag it with the mouse or just click anywhere on the ColorSaturationBox element surface. A propos, you can provide you own color selector drawing with the ColorSaturationBox.Selector Dependency Property.

Read-only ColorSaturationBox.SelectedColor Dependency Property used to get the value of the Color selected. User can change the SelectedColor property from its code using the SelectorPosition property. The SelectorPosition property gets or sets the selector position normalized to [0,1 0,1] rectangle. When the SelectedColor changes the ColorSaturationBox raises the SelectedColorChanged event.

The code

You can download the code and the samples here:

http://cid-39d56f0c7a08d703.skydrive.live.com/embedrowdetail.aspx/.Public/WPFGears/WPFGears.zip

The archive contains my WPFGears library with samples, tests, etc. It’s the Visual Studio 2008 SP1 solution targeted to .NET Framework 3.5.

You’ll find ColorSaturationSample project there. ColorSaturationBox element code is in the WPFGears library project ColorPickerControls folder.

Regards,
Oleg V. Polikarpotchkin

Technorati Теги: ,,
Posted in Uncategorized | Leave a comment

RainbowSlider Control

Yesterday I’ve posted the article on the OpacitySlider Control. The RainbowSlider is one else control to the bug of Color Picker related components.

RainbowSlider control is designed as the mean to select a Color from the color spectrum given. It’s the extension of the Slider control.

RainbowSlider control overrides the default template of the parent Slider control and looks like follows:

i.e. its style redefines the slider background and the constituent Thumb control template.

As you can see at the figure above the RainbowSlider control takes into account the parent Slider control Orientation property and can be presented as the horizontal or the vertical bar.

Read-only SelectedColor Dependency Property of the RainbowSlider used to get the value of the Color selected. This property value is synchronized with Minimum, Maximum and Value properties values of the parent Slider control. To set the SelectedColor value the caller can set the Value property value to the position of the color in the spectrum (linear interpolation over the Rainbow color sequence involved). Another way to change the SelectedColor property from the code is the RainbowSlider.TrySetSelectedColor method. It gets the color argument and tries to find that color in the Rainbow. On success it sets the selector position accordingly and returns true; otherwise it returns false. When the SelectedColor changes the RainbowSlider raises the SelectedColorChanged event.

The Rainbow Dependency Property allows to get or set the color spectrum. It’s of the GradientStopCollection type i.e. represents the sequence of colors along with the position of the color in the spectrum. By default the spectrum is the sequence of equally spaced Red, Orange, Yellow, Lime, Blue, Indigo, Violet, Red colors. When the Rainbow property changes the RainbowSlider tries to find the current SelectedColor value in the new Rainbow. On success it sets the selector position accordingly; otherwise it sets the selector position to the minimum and changes its SelectedColor to the value corresponding to that position.

The direction the SelectedColor value changes depends on the value of IsDirectionReversed property. If it’s false (the default) the initial spectrum color is at the left or at the bottom of the control depending on the orientation.

The code

You can download the code and the samples here:

http://cid-39d56f0c7a08d703.skydrive.live.com/embedrowdetail.aspx/.Public/WPFGears/WPFGears.zip

The archive contains my WPFGears library with samples, tests, etc. It’s the Visual Studio 2008 SP1 solution targeted to .NET Framework 3.5.

You’ll find RainbowSliderSample project there. RainbowSlider element code is in the WPFGears library project ColorPickerControls folder.

Regards,
Oleg V. Polikarpotchkin

Technorati Теги: ,,,
Posted in Uncategorized | Leave a comment

OpacitySlider Control

OpacitySlider control is designed as the Opacity value selector. It’s the extension of the Slider control.

Read-write SelectedOpacity Dependency Property of the OpacitySlider control allows to get or set the value of Opacity. It’s of the double type and its value is in the [0,1] range (0 means transparent, 1 – opaque, the default).

OpacitySlider SelectedOpacity property value is synchronized with Minimum, Maximum and Value properties values of the parent Slider control. To get or set the Opacity value the caller can use both OpacitySlider and Value properties taking into account the simple relation:

SelectedOpacity = 1.0 - (Value - Minimum) / (Maximum - Minimum);

OpacitySlider control overrides the default template of the parent Slider control and looks like follows:

i.e. its style redefines the slider background and the constituent Thumb control template.

As you can see at the figure above the OpacitySlider control takes into account the parent Slider control Orientation property and can be presented as the horizontal or the vertical bar.

The direction the Opacity value changes depends on the value of IsDirectionReversed property. If it’s false (the default) the maximum opacity as at the left or at the bottom of the control depending on the orientation.

The code

You can download the code and the samples here:

http://cid-39d56f0c7a08d703.skydrive.live.com/embedrowdetail.aspx/.Public/WPFGears/WPFGears.zip

The archive contains my WPFGears library with samples, tests, etc. It’s the Visual Studio 2008 SP1 solution targeted to .NET Framework 3.5.

You’ll find OpacitySliderSample project there.OpacitySlider control code is in the WPFGears library project ColorPickerControls folder.

Regards,
Oleg V. Polikarpotchkin

Technorati Теги: ,,,,
Posted in Uncategorized | Leave a comment

Math Value Converters

Yesterday I’ve posted the topic on Math Expression Interpreter. It’s handy to use for Math calculations with WPF Value Converters. See the code below.

/// <summary>
/// Converts the input value to other value using the string
/// parameter value as the math expression.
/// </summary>
public class MathConverter : IValueConverter
{
    #region IValueConverter Members
    /// <summary>
    /// Converts the input <paramref name="value"/> to other value using the string
    /// <paramref name="parameter"/> value as the math expression.
    /// </summary>
    /// <param name="value">The value produced by the binding source.</param>
    /// <param name="targetType">Output value type.</param>
    /// <param name="parameter">Math expression string.</param>
    /// <param name="culture">The culture used to convert to/form double values.</param>
    /// <returns>Either the value calculated by the expression given in <paramref name="parameter"/>
    /// or <see cref="DependencyProperty.UnsetValue"/>.</returns>
    public object Convert(object value, Type targetType, object parameter
        , CultureInfo culture)
    {
        if (value == null || parameter == null || !(parameter is string))
            return DependencyProperty.UnsetValue;
        try
        {
            Expression interpreter = new Expression(parameter as string);

            // Expression parameter.
            double expressionParameter;
            if (value is string)
                expressionParameter = double.Parse(value as string, culture.NumberFormat);
            else
                expressionParameter = (double)System.Convert.ChangeType(value, typeof(double)
                    , culture.NumberFormat);
            
            double result = interpreter.Evaluate(new double[] { expressionParameter });
            
            // The result to the target type
            if (double.IsNaN(result) || double.IsInfinity(result))
            {
                if (targetType == typeof(double))
                    return result;
                else if (targetType == typeof(float))
                {
                    if (double.IsNaN(result))
                        return float.NaN;
                    else if (double.IsPositiveInfinity(result))
                        return float.PositiveInfinity;
                    else if (double.IsNegativeInfinity(result))
                        return float.NegativeInfinity;
                }

                return DependencyProperty.UnsetValue;
            }

            return System.Convert.ChangeType(result, targetType, culture.NumberFormat);
        }
        catch (Exception)
        {
            return DependencyProperty.UnsetValue;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter
        , CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    #endregion IValueConverter Members
}

/// <summary>
/// Converts the input array of values to other value using the string
/// parameter value as the math expression.
/// </summary>
public class MathMultiConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members
    /// <summary>
    /// Converts the input <paramref name="values"/> to other value using the string
    /// <paramref name="parameter"/> value as the math expression.
    /// </summary>
    /// <param name="values">The value array produced by the binding source.</param>
    /// <param name="targetType">Output value type.</param>
    /// <param name="parameter">Math expression string.</param>
    /// <param name="culture">The culture used to convert to/form double values.</param>
    /// <returns>Either the value calculated by the expression given in <paramref name="parameter"/>
    /// or <see cref="DependencyProperty.UnsetValue"/>.</returns>
    public object Convert(object[] values, Type targetType, object parameter
        , CultureInfo culture)
    {
        if (values == null || parameter == null || !(parameter is string))
            return DependencyProperty.UnsetValue;
        try
        {
            Expression interpreter = new Expression(parameter as string);

            // Expression parameters array.
            double[] expressionParameters = new double[values.Length];
            for (int i = 0; i < values.Length; i++)
            {
                if (values[i] is string)
                    expressionParameters[i] = double.Parse(values[i] as string, culture.NumberFormat);
                else
                    expressionParameters[i] = (double)System.Convert.ChangeType(values[i]
                        , typeof(double), culture.NumberFormat);
            }
            
            double result = interpreter.Evaluate(expressionParameters);

            // The result to the target type
            if (double.IsNaN(result) || double.IsInfinity(result))
            {
                if (targetType == typeof(double))
                    return result;
                else if (targetType == typeof(float))
                {
                    if (double.IsNaN(result))
                        return float.NaN;
                    else if (double.IsPositiveInfinity(result))
                        return float.PositiveInfinity;
                    else if (double.IsNegativeInfinity(result))
                        return float.NegativeInfinity;
                }

                return DependencyProperty.UnsetValue;
            }
            return System.Convert.ChangeType(result, targetType, culture.NumberFormat);
        }
        catch (Exception)
        {
            return DependencyProperty.UnsetValue;
        }
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter
        , CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    #endregion IMultiValueConverter Members
}

 

The first one is for use with the regular Binding class, and the second is for the MultiBinding.

Regards,
Oleg V. Polikarpotchkin

Posted in Uncategorized | 1 Comment

Math Expressions Interpreter

Introduction

I’ve ported from C++ to C# my old expression interpreter. It’s written from scratch without any parser generators like, say, ANTLR. Maybe it isn’t the modern approach but I’m using this code during last twenty years or so.

Basics

An expression contains parameters, numeric and predefined symbolic constants, predefined functions calls.

All elements type is treated as double. Evaluation result is also double (having, possibly, special values NaN, INF, -INF).

Samples:

  • (1+2)*5
  • 2*sqrt(4)
  • if({0}-4,{0}-10,33,{0}+10)

Usage

Expression class constructor takes an expression string as a parameter and parses it into the tree of operations. Exceptions of some types could be thrown during parsing.

Then the expression could be evaluated multiple times with different parameters set with the Evaluate method. Evaluation is always successful (doesn’t throws exceptions) although the result could be one of the double type special values mentioned above.

Constants

An expression can contain numeric literals and predefined symbolic constants (like "PI").

The decimal point is used as the separator in literals. Scientific notation ‘e’ or ‘E’ can be used.

Predefined Constants

The following symbolic constant names are defined:

  1. Natural logarithm base "e" = 2.71…
  2. "PI" = 3.14…
  3. Not-a-number value "NaN".
  4. Positive infinity "Inf".
  5. Negative infinity "NInf".

Constant names are case-insensitive.

Parameters

Expression parameters (variables) are denoted with the placeholder syntax {index} like in the string.Format method format string. The ‘index’ is the parameter position in the array passed to the Evaluate method call. If the parameter at the specified index is missed the NaN value used.

Operations

Operations priorities are as follows (the top is highest).

  1. Function calls and parentheses ().
  2. Unary plus (+) and minus (-).
  3. Exponentiation (^).
  4. Multiplication (*), division (/), modulus (%).
  5. Addition (+) and subtraction (-).

Parentheses

Any level parentheses used to group the operations.

Function calls

All functions return double value and can have one or more arguments. Syntax: function(arg1, arg2, …). Argument itself also could be an expression. Some functions can have variable argument count.

Unary plus and minus

Unary plus is ignored. Unary minus is right associative, i.e. –x means (-(-x)). When Unary minus is applied to an infinity its sign changes to the opposite (e.g. Inf becomes NInf and vice versa).

Exponentiation

Pow function analog. The operation is right associative, i.e. x^y^z means (x^(y^z)).

Any values except NaN powered to 0 equal to 1. NaN at any power equal to NaN.

Multiplication, division, modulus

These operations are left associative, i.e. x*y/z means ((x*y)/z).

Addition and subtraction

These operations are left associative, i.e. x+y-z means ((x+y)-z).

Functions

Function names are case-insensitive.

Conditional Functions

Conditional functions allow emulate a branching in the intrinsically linear expression syntax.

First argument value of any conditional function is compared to the branching condition defined by that function. Depending on the comparison result one of the other arguments is calculated.

Branching by sign (If)

If function has 4 or 5 arguments.

If(cond, var1, var2, var3)

or

If(cond, var1, var2, var3, spec)

If function checks the cond argument has a special value. If so, two variants are possible:

  • If the spec argument exists it’s calculated.
  • Otherwise the function returns the value of cond, i.e. NaN, Inf or NInf.

If the cond argument doesn’t have a special value, If function calculates and returns the value of one of three arguments.

  1. var1 on cond < 0
  2. var2 on cond == 0
  3. var3 on cond > 0

Branching by special value (IfNotFinite)

IfNotFinite function has 2 or 3 arguments.

IfNotFinite(cond, spec)

or

IfNotFinite(cond, spec, var)

If the cond argument has a special value the function calculates and returns the spec argument value. Otherwise, if var argument exists the function calculates and returns it. Else it returns the cond value.

Branching by NaN (IfNaN)

IfNaN function has 2 or 3 arguments.

IfNaN(cond, spec)

or

IfNaN(cond, spec, var)

If the cond argument value is NaN the function calculates and returns the spec argument value. Otherwise, if var argument exists the function calculates and returns it. Else it returns the cond value.

Branching by Infinity (IfInf)

IfInf function has 2 or 3 arguments.

IfInf(cond, spec)

or

IfInf(cond, spec, var)

If the cond argument value is Inf or NInf the function calculates and returns the spec argument value. Otherwise, if var argument exists the function calculates and returns it. Else it returns the cond value.

Branching by Positive Infinity (IfPInf)

IfPInf function has 2 or 3 arguments.

IfPInf(cond, spec)

or

IfPInf(cond, spec, var)

If the cond argument value is Inf the function calculates and returns the spec argument value. Otherwise, if var argument exists the function calculates and returns it. Else it returns the cond value.

Branching by Negative Infinity (IfNInf)

IfNInf function has 2 or 3 arguments.

IfNInf(cond, spec)

or

IfNInf(cond, spec, var)

If the cond argument value is NInf the function calculates and returns the spec argument value. Otherwise, if var argument exists the function calculates and returns it. Else it returns the cond value.

Math Functions

Absolute value Abs

Abs has one argument and returns its absolute value. The same is applied to the negative infinity: Inf is returned in place of NInf.

Square root Sqrt

Sqrt has one argument and returns its square root. The square root of negative number, including negative infinity, and NaN, is NaN. The square root of Inf is Inf.

The Sqrt(x) is the analog of Pow(x, 0.5).

Exponentiation Pow

Pow has two arguments and returns the first argument raised to the power of the second argument. It’s the analog of ^ operation.

Any value except NaN at the power of 0 is equal to 1. NaN at any power is equal to NaN.

Logarithms

Log and Log10 functions has one argument. Logarithm of 0 is equal to NInf. Logarithm of negative argument is NaN.

Thrigonometric functions

Sin, Cos and Tan functions has one argument. If the argument has any special value the result will be NaN.

Reverse thrigonometric functions

Asin, Acos and Atan functions has one argument and return the angle value in radians or a special value.

If Asin or Acos argument is outside of [-1,1] or has a special value the result will be NaN.

If Atan argument has a special value the result will be:

  1. NaN for NaN
  2. pi/2 for Inf
  3. -pi/2 for NInf

Hyperbolic functions

Sinh, Cosh and Tanh functions has one argument.

The code

You can download the code here:

http://cid-39d56f0c7a08d703.skydrive.live.com/embedrow.aspx/.Public/Expression/Expression030609.zip

 

Regards,
Oleg V. Polikarpotchkin

Posted in Uncategorized | Leave a comment