public void Build(ExpressionModel model)
 {
     if (model != null)
     {
         View content = BuildView(model.Expression, model);
         SetContent(content);
     }
 }
 public ExpressionView(ExpressionModel model, double width, double height, double maxScale)
     : base(width, height)
 {
     MaxScale = maxScale;
     SelectionTextColor = new Color(40, 175, 100);
     SelectionBackgroundColor = new Color(230, 230, 230);
     Build(model);
 }
        static void Main(string[] args)
        {
            ExpressionModel model = new ExpressionModel("b^-2");
            model.Select(model.Expression.GetNodesRecursive().ElementAt(0));
            model.Select(model.Expression.GetNodesRecursive().ElementAt(1));
            model.Selection.ForEach((selected) => selected.PrettyPrint());
            model.Identities.ForEach((id) => id.Result.PrettyPrint());

            // Template for testing Size
            ExpressionModel model2 = new ExpressionModel("a*(1-b)");
            model2.Expression.PrettyPrint();
            Console.WriteLine(model2.Expression.Size);
            //

            Console.WriteLine("Done");
            Console.ReadKey();
        }
        public View BuildView(ExpressionBase expression, ExpressionModel model)
        {
            // Find the type of the root of the expression-tree

            // Only the first case is commented fully. The rest is only commented if they do something special
            // To check if the root is a type, we try to cast it and check if its null
            UnaryMinusExpression minusExpression = expression as UnaryMinusExpression;
            if(minusExpression != null) // Root is minus-expression
            {
                View view = BuildView(minusExpression.Expression, model); // Call BuildView recursively with next level of expression
                view.BackgroundColor = ReferenceEquals(model.Selected, expression) ? SelectionBackgroundColor : new Color();  // set backgoundcolor

                OperatorView operatorView = new OperatorView(minusExpression.Type); // Instantiate a operatorView with a minus, to be rendered to screen
                operatorView.Width = NUMVAR_SIZE / 2; // Position and size after preset constants
                operatorView.Height = NUMVAR_SIZE;
                operatorView.Baseline = NUMVAR_SIZE / 2;
                operatorView.OnClick = () => model.Select(minusExpression); // When minus is clicked, select it
                operatorView.LineColor = expression.Selected ? new Color(39, 174, 97) : new Color(0, 0, 0);
                operatorView.LineWidth = NUMVAR_SIZE / 15;

                view.X = operatorView.Width; // Put rest of expression on the right of the minus
                operatorView.Y = view.Baseline - operatorView.Baseline;

                View minusView = new CompositeView(operatorView.Width + view.Width, view.Height) { operatorView, view }; // Join the minus and the rest of the expressionView
                minusView.Baseline = view.Baseline; // Minus has same baseline as the rest
                minusView.BackgroundColor = ReferenceEquals(model.Selected, expression) ? SelectionBackgroundColor : new Color(); // If minus is selected it has another backgroundcolor

                return minusView;
            }

            BinaryOperatorExpression operatorExpression = expression as BinaryOperatorExpression;
            if (operatorExpression != null)
            {
                View left = BuildView(operatorExpression.Left, model);
                View right = BuildView(operatorExpression.Right, model);
                OperatorView operatorView = new OperatorView(operatorExpression.Type);
                switch (operatorExpression.Type) //Switch on the type of operator
                {
                    case OperatorType.Divide:
                        // Divide needs to place right under left and put a line between.
                        double width = System.Math.Max(left.Width, right.Width) + NUMVAR_SIZE;
                        operatorView.Width = width;
                        operatorView.Height = NUMVAR_SIZE / 1.5;
                        operatorView.Y = left.Height;
                        operatorView.Baseline = NUMVAR_SIZE / 2;
                        operatorView.OnClick = () => model.Select(expression);
                        operatorView.LineWidth = NUMVAR_SIZE / 12;
                        operatorView.LineColor = expression.Selected ? new Color(39, 174, 97) : new Color(0, 0, 0);

                        right.Y = left.Height + operatorView.Height;
                        left.X = (width - left.Width) / 2;
                        right.X = (width - right.Width) / 2;

                        CompositeView fraction = new CompositeView(width, left.Height + operatorView.Height + right.Height)
                        {
                            left,
                            operatorView,
                            right
                        };
                        fraction.Baseline = operatorView.Y + operatorView.Height / 2;
                        fraction.BackgroundColor = ReferenceEquals(model.Selected, expression) ? SelectionBackgroundColor : new Color();
                        return fraction;
                    case OperatorType.Power:
                        // Power lifts right a bit
                        right.X = left.Width;
                        left.Y = right.Height - NUMVAR_SIZE / 2; // Lift right
                        CompositeView exponent = new CompositeView(right.X + right.Width, left.Y + left.Height)
                        {
                            left,
                            right
                        };
                        exponent.Baseline = left.Y + left.Baseline;
                        exponent.BackgroundColor = ReferenceEquals(model.Selected, expression) ? SelectionBackgroundColor : new Color();
                        return exponent;
                }
            }
            VariadicOperatorExpression variadicExpression = expression as VariadicOperatorExpression;
            if (variadicExpression != null)
            {
                List<View> views = new List<View>();
                double offsetX = 0;
                double height = 0;
                double maxBaseline = NUMVAR_SIZE / 2;
                // Variadic may have more than 2 "sides"
                foreach (ExpressionBase expr in variadicExpression)
                {
                    View operand;
                    if (views.Count != 0)
                    {
                        UnaryMinusExpression minus = expr as UnaryMinusExpression;
                        OperatorView operatorView;
                        if (variadicExpression.Type == OperatorType.Add && minus != null)
                        {
                            operatorView = new OperatorView(OperatorType.Subtract);
                            operand = BuildView(minus.Expression, model);
                            operand.BackgroundColor = ReferenceEquals(model.Selected, expr) ? SelectionBackgroundColor : new Color();
                            operatorView.BackgroundColor = operand.BackgroundColor;
                            operatorView.OnClick = () => model.Select(minus);
                            operatorView.LineColor = minus.Selected ? SelectionTextColor : new Color(0, 0, 0);
                        }
                        else
                        {
                            operatorView = new OperatorView(variadicExpression.Type);
                            operand = BuildView(expr, model);
                        }
                        operatorView.X = offsetX;
                        operatorView.Width = (variadicExpression.Type == OperatorType.Multiply ? 0.5 : 1.5)  * NUMVAR_SIZE;
                        operatorView.Height = NUMVAR_SIZE;
                        operatorView.Baseline = NUMVAR_SIZE / 2;
                        operatorView.LineWidth = NUMVAR_SIZE / (variadicExpression.Type == OperatorType.Multiply ? 25 : 15);
                        views.Add(operatorView);
                        offsetX += operatorView.Width;
                    }
                    else
                    {
                        operand = BuildView(expr, model);
                    }
                    if (ReferenceEquals(expr.Parent, model.Selected) && (expr.Selected || expr.GetNodesRecursive().Any((n) => n.Selected)))
                    {
                        operand.BackgroundColor = SelectionBackgroundColor;
                    }

                    maxBaseline = System.Math.Max(maxBaseline, operand.Baseline);
                    operand.X = offsetX;
                    offsetX += operand.Width;
                    views.Add(operand);
                }
                foreach (View view in views) // Join all the views
                {
                    view.Y = maxBaseline - view.Baseline;
                    height = System.Math.Max(height, view.Y + view.Height);
                }
                return new CompositeView(offsetX, height) { Children = views, Baseline = maxBaseline };
            }
            // TODO: Comment this
            DelimiterExpression delimiterExpression = expression as DelimiterExpression;
            if(delimiterExpression != null)
            {
                View view = BuildView(delimiterExpression.Expression, model);
                view.X = view.Height / 3;
                view.Y = NUMVAR_SIZE / 8;
                ParenthesisView left = new ParenthesisView(ParenthesisType.Left) { OnClick = () => model.Select(expression), Width = view.Height / 3, Height = view.Height + NUMVAR_SIZE / 4 };
                ParenthesisView right = new ParenthesisView(ParenthesisType.Right) { OnClick = () => model.Select(expression), X = view.Width + view.Height / 3, Width = view.Height / 3, Height = view.Height + NUMVAR_SIZE / 4 };

                View compositeView = new CompositeView(view.Width + view.Height / 1.5, view.Height + NUMVAR_SIZE / 4)
                {
                    left,
                    view,
                    right
                };
                left.LineWidth = NUMVAR_SIZE / 15;
                right.LineWidth = NUMVAR_SIZE / 15;
                left.LineColor = expression.Selected ? SelectionTextColor : new Color(0, 0, 0);
                right.LineColor = expression.Selected ? SelectionTextColor : new Color(0, 0, 0);
                compositeView.Baseline = view.Y + view.Baseline;
                compositeView.BackgroundColor = ReferenceEquals(model.Selected, expression) ? SelectionBackgroundColor : new Color();
                return compositeView;
            }
            // TODO: Comment this
            FunctionExpression functionExpression = expression as FunctionExpression;
            if(functionExpression != null && functionExpression.Function == "sqrt")
            {
                View view = BuildView(functionExpression.Expression, model);
                SqrtView sqrtView = new SqrtView();
                sqrtView.OnClick = () => model.Select(expression);
                sqrtView.SignWidth = view.Height / 2;
                sqrtView.TopHeight = NUMVAR_SIZE / 2;
                sqrtView.LineWidth = NUMVAR_SIZE / 12;
                sqrtView.Width = view.Width + sqrtView.SignWidth + NUMVAR_SIZE / 4;
                sqrtView.LineColor = expression.Selected ? SelectionTextColor : new Color(0, 0, 0);
                sqrtView.Height = view.Height + sqrtView.TopHeight;
                view.X = sqrtView.SignWidth + NUMVAR_SIZE / 8;
                view.Y = sqrtView.TopHeight;
                View compositeView = new CompositeView(sqrtView.Width, sqrtView.Height)
                {
                    sqrtView,
                    view,
                };
                compositeView.Baseline = view.Baseline + sqrtView.TopHeight;
                compositeView.BackgroundColor = ReferenceEquals(model.Selected, expression) ? SelectionBackgroundColor : new Color();
                return compositeView;
            }
            return new LabelView(expression.ToString())
            {
                OnClick = () => model.Select(expression),
                Width = 3 * NUMVAR_SIZE / 5 * (expression.ToString().Length + 0.25),
                Height = NUMVAR_SIZE,
                Baseline = NUMVAR_SIZE / 2,
                TextColor = expression.Selected ? new Color(39, 174, 97) : new Color(0, 0, 0),
                BackgroundColor = ReferenceEquals(model.Selected, expression) ? SelectionBackgroundColor : new Color()
            };
        }
 public void Update(ExpressionModel model)
 {
     Build(model);
     if (OnChanged != null)
     {
         OnChanged();
     }
 }
 private void onExpressionChanged(ExpressionModel model)
 {
     ProgressBar.CurrentValue = model.Expression.Size;
     User.CurrentLevel.CurrentExpression = model.Expression.ToString();
     if (ProgressBar.ActivatedStarPercentages().Count() > User.CurrentLevel.Stars)
     {
         UpdateLevelData();
     }
     if (OnChanged != null)
     {
         OnChanged(this);
     }
 }
        /// <summary>
        /// Sets up the model to complete the level.
        /// </summary>
        /// <param name="level">The desired level.</param>
        /// <param name="category">The desired category.</param>
        public void SetLevel(int level, int category)
        {
            User.CurrentLevelIndex = level;
            User.CurrentCategoryIndex = category;
            ExpressionSerializer serializer = new ExpressionSerializer();
            int endValue = serializer.Deserialize(User.Categories[category][level].StarExpressions.Last()).Size;
            int startValue = serializer.Deserialize(User.Categories[category][level].StartExpression).Size;
            int currentValue = serializer.Deserialize(User.Categories[category][level].CurrentExpression).Size;
            ProgressBar = new ProgressbarStar(startValue, endValue, currentValue);
            StarExpressions = new List<ExpressionBase>();

            foreach (string starExpression in User.CurrentLevel.StarExpressions)
            {
                ExpressionBase starExpressionBase = serializer.Deserialize(starExpression);
                StarExpressions.Add(starExpressionBase);
                ProgressBar.Add(starExpressionBase.Size);
            }
            ExprModel = new ExpressionModel(User.Categories[category][level].CurrentExpression, (m) => onExpressionChanged(m),
                Rules.ExponentToProductRule, Rules.ProductToExponentRule,
                Rules.VariableWithNegativeExponent, Rules.ReverseVariableWithNegativeExponent, Rules.ExponentProduct,
                Rules.CommonPowerParenthesisRule, Rules.ReverseCommonPowerParenthesisRule, Rules.SplittingFractions, Rules.ProductParenthesis,
                Rules.ReverseProductParenthesis, Rules.ParenthesisPowerRule, Rules.FractionToProductRule, Rules.SquareRootRule,
                Rules.RemoveParenthesisRule, Rules.ProductOfConstantAndFraction, Rules.FactorizeUnaryMinus, Rules.FactorizationRule,
                Rules.MultiplyOneRule, Rules.AddFractionWithCommonDenominatorRule, Rules.RemoveNull, Rules.MultiplyByNull,
                Rules.CalculateVariadicRule, Rules.CalculateBinaryRule, Rules.MultiplyMinusRule, Rules.DivisionEqualsOneRule, Rules.ProductOfFractions, Rules.VariablesEqualNull);
            UpdateLevelData();
            onExpressionChanged(ExprModel);
        }