Inheritance: Rectangular
示例#1
0
 /// <summary>
 /// Adds the current control to the current focus context
 /// </summary>
 /// <param name="c">The control to add</param>
 public void Add(ConsoleControl c)
 {
     if(focusStack.Peek().Controls.Contains(c))
     {
         throw new InvalidOperationException("Item already being tracked");
     }
     focusStack.Peek().Controls.Add(c);
 }
示例#2
0
 public Dialog(ConsoleControl content)
 {
     Add(content).Fill(padding: new Thickness(0, 0, 1, 1));
     closeButton = Add(new Button() { Text = "Close (ESC)",Background = Theme.DefaultTheme.H1Color, Foreground = ConsoleColor.Black }).DockToRight(padding: 1);
     closeButton.Pressed.SubscribeForLifetime(Escape, this.LifetimeManager);
     BeforeAddedToVisualTree.SubscribeForLifetime(OnBeforeAddedToVisualTree, this.LifetimeManager);
     AddedToVisualTree.SubscribeForLifetime(OnAddedToVisualTree, this.LifetimeManager);
     RemovedFromVisualTree.SubscribeForLifetime(OnRemovedFromVisualTree, this.LifetimeManager);
 }
        public override void OnAdd(ConsoleControl parent)
        {
            base.OnAdd(parent);
            if (Width == 0) Width = parent.Width;
            if (Height == 0) Height = parent.Height;

            // start monitoring CPU and memory when added
            Task.Factory.StartNew(() => { WatchCPUAndMemory(); });
        }
示例#4
0
        public void Move(ConsoleControl control, int column, int row, int columnSpan = 1, int rowSpan = 1)
        {
            var assignment = layoutAssignments.Where(a => a.Control == control).First();

            assignment.Column     = column;
            assignment.Row        = row;
            assignment.ColumnSpan = columnSpan;
            assignment.RowSpan    = rowSpan;
            control.Bounds        = GetCellArea(assignment);
        }
示例#5
0
        private void HandleControlRemoved(ConsoleControl c)
        {
            var toRemove = layoutAssignments
                           .Where(a => a.Control == c)
                           .FirstOrDefault();

            if (toRemove != null)
            {
                layoutAssignments.Remove(toRemove);
            }
        }
示例#6
0
        public override void OnAdd(ConsoleControl parent)
        {
            base.OnAdd(parent);
            this.Foreground = parent.Foreground;
            this.Background = parent.Background;

            XAxisValueCompactFormatter = XAxisValueCompactFormatter ?? ((d) => { return(new ConsoleString(string.Format("{0:0,0.0}", d), Foreground.ForegroundColor, Foreground.BackgroundColor)); });
            YAxisValueCompactFormatter = YAxisValueCompactFormatter ?? ((d) => { return(new ConsoleString("" + string.Format("{0:0,0.0}", d), Foreground.ForegroundColor, Foreground.BackgroundColor)); });

            XAxisValueFormatter = XAxisValueFormatter ?? ((d) => { return(new ConsoleString(string.Format("{0:0,0.0}", d), Foreground.ForegroundColor, Foreground.BackgroundColor)); });
            YAxisValueFormatter = YAxisValueFormatter ?? ((d) => { return(new ConsoleString("" + string.Format("{0:0,0.0}", d), Foreground.ForegroundColor, Foreground.BackgroundColor)); });
        }
示例#7
0
 public Dialog(ConsoleControl content)
 {
     Add(content).Fill(padding: new Thickness(0, 0, 1, 1));
     closeButton = Add(new Button()
     {
         Text = "Close (ESC)", Background = Theme.DefaultTheme.H1Color, Foreground = ConsoleColor.Black
     }).DockToRight(padding: 1);
     closeButton.Activated.SubscribeForLifetime(Escape, this.LifetimeManager);
     BeforeAddedToVisualTree.SubscribeForLifetime(OnBeforeAddedToVisualTree, this.LifetimeManager);
     AddedToVisualTree.SubscribeForLifetime(OnAddedToVisualTree, this.LifetimeManager);
     RemovedFromVisualTree.SubscribeForLifetime(OnRemovedFromVisualTree, this.LifetimeManager);
 }
示例#8
0
        public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePath, Func <object, object> mapper, Func <object, object> reverseMapper)
        {
            this.mapper        = mapper;
            this.reverseMapper = reverseMapper;
            var exp              = ObjectPathExpression.Parse(observablePath);
            var trace            = exp.EvaluateAndTraceInfo(viewModel);
            var observableObject = trace[trace.Count - 2].Value as ObservableObject;

            var viewModelObservableProperty = trace.Last()?.MemberInfo as PropertyInfo;

            if (observableObject == null)
            {
                throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePath}' is not observable");
            }

            if (viewModelObservableProperty == null)
            {
                throw new InvalidOperationException($"Cannot resolve ViewModel property '{viewModel.GetType().FullName}.{observablePath}'");
            }

            if (mapper != null && reverseMapper != null)
            {
                if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType &&
                    viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false &&
                    viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false)
                {
                    throw new InvalidOperationException($"ViewModel type '{viewModel.GetType().FullName} property {observablePath}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} ");
                }
            }

            observableObject.SynchronizeForLifetime(trace.Last().MemberInfo.Name, () =>
            {
                var newValue = viewModelObservableProperty.GetValue(observableObject);
                if (newValue == latestValue)
                {
                    return;
                }
                latestValue = newValue;
                controlProperty.SetValue(control, mapper != null ? mapper(newValue) : newValue);
            }, control.LifetimeManager);

            control.SubscribeForLifetime(controlProperty.Name, () =>
            {
                var newValue = controlProperty.GetValue(control);
                if (newValue == latestValue)
                {
                    return;
                }
                latestValue = newValue;
                viewModelObservableProperty.SetValue(observableObject, reverseMapper != null ? reverseMapper(newValue) : newValue);
            }, control.LifetimeManager);
        }
示例#9
0
 public Dialog(ConsoleControl content)
 {
     Add(content).Fill(padding: new Thickness(0, 0, 1, 1));
     AllowEscapeToCancel = true;
     closeButton         = Add(new Button()
     {
         Text = "Close (ESC)".ToConsoleString(), Background = DefaultColors.H1Color, Foreground = ConsoleColor.Black
     }).DockToRight(padding: 1);
     closeButton.Pressed.SubscribeForLifetime(Escape, this);
     BeforeAddedToVisualTree.SubscribeForLifetime(OnBeforeAddedToVisualTree, this);
     AddedToVisualTree.SubscribeForLifetime(OnAddedToVisualTree, this);
     RemovedFromVisualTree.SubscribeForLifetime(OnRemovedFromVisualTree, this);
 }
示例#10
0
        public static T FillVertically <T>(this T child, ConsoleControl parent = null, Thickness?padding = null) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;
            var    effectivePadding = padding.HasValue ? padding.Value : new Thickness(0, 0, 0, 0);
            Action syncAction       = () =>
            {
                child.Bounds = new Rectangle(child.X, effectivePadding.Top, child.Width, parent.Height - (effectivePadding.Top + effectivePadding.Bottom));
            };

            parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            syncAction();
            return(child);
        }
示例#11
0
 /// <summary>
 /// Clears the focus, but preserves the focus index
 /// </summary>
 public void ClearFocus()
 {
     if (ConsoleApp.Current?.ShouldContinue == false)
     {
         return;
     }
     if (FocusedControl != null)
     {
         FocusedControl.HasFocus = false;
         FocusedControl.FireFocused(false);
         FocusedControl = null;
     }
 }
示例#12
0
        public static T DockToLeft <T>(this T child, ConsoleControl parent = null, int padding = 0) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;
            Action syncAction = () =>
            {
                child.X = padding;
            };

            child.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            syncAction();
            return(child);
        }
示例#13
0
        private void ComposePaintOver(ConsoleControl control)
        {
            var maxX = control.X + control.Width;
            var maxY = control.Y + control.Height;

            for (var x = control.X; x < maxX; x++)
            {
                for (var y = control.Y; y < maxY; y++)
                {
                    var controlPixel = control.Bitmap.GetPixel(x - control.X, y - control.Y).Value;
                    Bitmap.DrawPoint(controlPixel.Value, x, y);
                }
            }
        }
示例#14
0
        private void ControlAddedToVisualTree(ConsoleControl c)
        {
            c.Application = this;

            if (c is ConsolePanel)
            {
                var childPanel = c as ConsolePanel;
                childPanel.Controls.SynchronizeForLifetime((cp) => { ControlAddedToVisualTree(cp); }, (cp) => { ControlRemovedFromVisualTree(cp); }, () => { }, c.LifetimeManager);
            }

            FocusManager.Add(c);
            c.AddedToVisualTreeInternal();

            ControlAdded.Fire(c);
        }
示例#15
0
        public static T DockToBottom <T>(this T child, ConsoleControl parent = null, int padding = 0) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;
            Action syncAction = () =>
            {
                if (parent.Height == 0)
                {
                    return;
                }
                child.Y = parent.Height - child.Height - padding;
            };

            child.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            syncAction();
            return(child);
        }
示例#16
0
        private void ComposePaintOver(ConsoleControl control)
        {
            var minX = Math.Max(control.X, 0);
            var minY = Math.Max(control.Y, 0);
            var maxX = Math.Min(Width, control.X + control.Width);
            var maxY = Math.Min(Height, control.Y + control.Height);

            for (var x = minX; x < maxX; x++)
            {
                for (var y = minY; y < maxY; y++)
                {
                    var controlPixel = control.Bitmap.GetPixel(x - control.X, y - control.Y).Value;
                    Bitmap.Pen = controlPixel.Value;
                    Bitmap.DrawPointUnsafe(x, y);
                }
            }
        }
示例#17
0
        public static T CenterVertically <T>(this T child, ConsoleControl parent = null) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;

            parent.SynchronizeForLifetime(nameof(ConsoleControl.Bounds), () =>
            {
                if (parent.Height == 0 || child.Height == 0)
                {
                    return;
                }

                var gap = parent.Height - child.Height;
                var y   = gap / 2;
                child.Y = Math.Max(0, y);
            }, parent);

            return(child);
        }
示例#18
0
        public static T DockToRight <T>(this T child, ConsoleControl parent = null, int padding = 0) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;
            Action syncAction = () =>
            {
                if (parent.Width == 0 || child.Width == 0)
                {
                    return;
                }

                child.X = parent.Width - child.Width - padding;
            };

            child.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent.LifetimeManager);
            parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent.LifetimeManager);
            syncAction();
            return(child);
        }
示例#19
0
        public static T FillHorizontally <T>(this T child, ConsoleControl parent = null, Thickness?padding = null) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;
            var    effectivePadding = padding.HasValue ? padding.Value : new Thickness(0, 0, 0, 0);
            Action syncAction       = () =>
            {
                if (parent.Width == 0)
                {
                    return;
                }

                child.Bounds = new Rectangle(effectivePadding.Left, child.Y, parent.Width - (effectivePadding.Right + effectivePadding.Left), child.Height);
            };

            parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            syncAction();
            return(child);
        }
示例#20
0
        /// <summary>
        /// Tries to set focus on the given control.
        /// </summary>
        /// <param name="newFocusControl">the control to focus.  </param>
        /// <returns>True if the focus was set or if it was already set, false if the control cannot be focused</returns>
        public bool TrySetFocus(ConsoleControl newFocusControl)
        {
            var index = focusStack.Peek().Controls.IndexOf(newFocusControl);

            if (index < 0)
            {
                return(false);
            }

            if (newFocusControl.CanFocus == false)
            {
                return(false);
            }
            else if (newFocusControl == FocusedControl)
            {
                return(true);
            }
            else
            {
                var oldFocusedControl = FocusedControl;
                if (oldFocusedControl != null)
                {
                    oldFocusedControl.HasFocus = false;
                }
                newFocusControl.HasFocus = true;
                FocusedControl           = newFocusControl;

                focusStack.Peek().FocusIndex = index;

                if (oldFocusedControl != null)
                {
                    oldFocusedControl.FireFocused(false);
                }

                if (FocusedControl != null)
                {
                    FocusedControl.FireFocused(true);
                }
                return(true);
            }
        }
示例#21
0
        internal Point CalculateRelativePosition(ConsoleControl parent)
        {
            var x = X;
            var y = Y;

            var tempParent = Parent;

            while (tempParent != null && tempParent != parent)
            {
                if (tempParent is ScrollablePanel)
                {
                    throw new InvalidOperationException("Controls within scrollable panels cannot have their relative positions calculated");
                }

                x         += tempParent.X;
                y         += tempParent.Y;
                tempParent = tempParent.Parent;
            }

            return(new Point(x, y));
        }
示例#22
0
        /// <summary>
        /// Adds the current control to the current focus context
        /// </summary>
        /// <param name="c">The control to add</param>
        internal void Add(ConsoleControl c)
        {
            if (focusStack.Peek().Controls.Contains(c))
            {
                throw new InvalidOperationException("Item already being tracked");
            }
            focusStack.Peek().Controls.Add(c);

            if (c.Id != null && c.Id == currentFocusedControlId)
            {
                c.TryFocus();
            }

            c.SubscribeForLifetime(nameof(c.CanFocus), () =>
            {
                if (c.CanFocus == false && c.HasFocus)
                {
                    TryMoveFocus();
                }
            }, c);
        }
示例#23
0
        protected void Compose(ConsoleControl control)
        {
            control.Paint();

            foreach (var filter in control.RenderFilters)
            {
                filter.Filter(control.Bitmap);
            }

            if (control.CompositionMode == CompositionMode.PaintOver)
            {
                ComposePaintOver(control);
            }
            else if (control.CompositionMode == CompositionMode.BlendBackground)
            {
                ComposeBlendBackground(control);
            }
            else
            {
                ComposeBlendVisible(control);
            }
        }
示例#24
0
        public static T CenterVertically <T>(this T child, ConsoleControl parent = null) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;

            parent.SynchronizeForLifetime(nameof(ConsoleControl.Bounds), () =>
            {
                if (child == ConsoleApp.Current.LayoutRoot)
                {
                }

                if (parent.Height == 0 || child.Height == 0)
                {
                    return;
                }

                var gap = parent.Height - child.Height;
                var y   = gap / 2;
                child.Y = y;
            }, parent.LifetimeManager);

            return(child);
        }
示例#25
0
        public static T CenterHorizontally <T>(this T child, ConsoleControl parent = null) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;

            Action syncAction = () =>
            {
                if (parent.Width == 0 || child.Width == 0)
                {
                    return;
                }

                var gap = parent.Width - child.Width;
                var x   = gap / 2;
                child.X = Math.Max(0, x);
            };

            parent.SynchronizeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            child.SynchronizeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            syncAction();

            return(child);
        }
示例#26
0
        private void ComposeBlendBackground(ConsoleControl control)
        {
            var minX = Math.Max(control.X, 0);
            var minY = Math.Max(control.Y, 0);
            var maxX = Math.Min(Width, control.X + control.Width);
            var maxY = Math.Min(Height, control.Y + control.Height);

            for (var x = minX; x < maxX; x++)
            {
                for (var y = minY; y < maxY; y++)
                {
                    var controlPixel = control.Bitmap.GetPixel(x - control.X, y - control.Y).Value;

                    if (controlPixel?.BackgroundColor != ConsoleString.DefaultBackgroundColor)
                    {
                        Bitmap.Pen = controlPixel.Value;
                        Bitmap.DrawPointUnsafe(x, y);
                    }
                    else
                    {
                        var myPixel = Bitmap.GetPixel(x, y).Value;
                        if (myPixel.HasValue && myPixel.Value.BackgroundColor != ConsoleString.DefaultBackgroundColor)
                        {
                            var composedValue = new ConsoleCharacter(controlPixel.Value.Value, controlPixel.Value.ForegroundColor, myPixel.Value.BackgroundColor);
                            Bitmap.Pen = composedValue;
                            Bitmap.DrawPointUnsafe(x, y);
                        }
                        else
                        {
                            Bitmap.Pen = controlPixel.Value;
                            Bitmap.DrawPointUnsafe(x, y);
                        }
                    }
                }
            }
        }
示例#27
0
        public static T Fill <T>(this T child, ConsoleControl parent = null, Thickness?padding = null) where T : ConsoleControl
        {
            parent = parent ?? child.Parent;
            var    effectivePadding = padding.HasValue ? padding.Value : new Thickness(0, 0, 0, 0);
            Action syncAction       = () =>
            {
                if (parent.Width == 0 || parent.Height == 0)
                {
                    return;
                }

                var newBounds = new Rectangle(new Point(0, 0), parent.Size);
                newBounds.X     += effectivePadding.Left;
                newBounds.Width -= effectivePadding.Left;
                newBounds.Width -= effectivePadding.Right;

                newBounds.Y      += effectivePadding.Top;
                newBounds.Height -= effectivePadding.Top;
                newBounds.Height -= effectivePadding.Bottom;

                if (newBounds.Width < 0)
                {
                    newBounds.Width = 0;
                }
                if (newBounds.Height < 0)
                {
                    newBounds.Height = 0;
                }

                child.Bounds = newBounds;
            };

            parent.SubscribeForLifetime(nameof(ConsoleControl.Bounds), syncAction, parent);
            syncAction();
            return(child);
        }
示例#28
0
        private void ComposeBlendVisible(ConsoleControl control)
        {
            var minX = Math.Max(control.X, 0);
            var minY = Math.Max(control.Y, 0);
            var maxX = Math.Min(Width, control.X + control.Width);
            var maxY = Math.Min(Height, control.Y + control.Height);

            for (var x = minX; x < maxX; x++)
            {
                for (var y = minY; y < maxY; y++)
                {
                    var controlPixel = control.Bitmap.GetPixel(x - control.X, y - control.Y);

                    var controlPixelHasRenderableContent = IsVisibleOnMyPanel(controlPixel);


                    if (controlPixelHasRenderableContent)
                    {
                        Bitmap.Pen = controlPixel.Value.Value;
                        Bitmap.DrawPointUnsafe(x, y);
                    }
                }
            }
        }
示例#29
0
 /// <summary>
 /// Removes the given control from the layout
 /// </summary>
 /// <param name="control">the control to remove</param>
 public void Remove(ConsoleControl control)
 {
     ProtectedPanel.Controls.Remove(control);
 }
示例#30
0
 private void ScrollableControls_Added(ConsoleControl c)
 {
     c.SubscribeForLifetime(nameof(Bounds), UpdateScrollbars, c.LifetimeManager);
 }
示例#31
0
 private void Controls_Added(ConsoleControl obj)
 {
     obj.SynchronizeForLifetime(nameof(Bounds), RedoLayout, Controls.GetMembershipLifetime(obj));
 }
示例#32
0
 public virtual void OnAdd(ConsoleControl parent)
 {
     if(Added != null)
     {
         Added();
     }
 }
示例#33
0
        private static void ParseControlAttributes(ConsoleControl control, ParserContext context)
        {
            foreach (var attribute in context.CurrentElement.Attributes)
            {
                var extensions = control.GetType().Attrs<MarkupExtensionAttribute>().Where(a => a.AttributeName == attribute.Name);

                if(extensions.Count() > 1)
                {
                    throw new InvalidOperationException("More than 1 extension registered for property "+attribute.Name);
                }
                else if(extensions.Count() == 1)
                {
                    extensions.First().Processor.Process(context);
                }
                else
                {
                    var propertyInfo = control.GetType().GetProperty(attribute.Name);
                    var methodInfo = control.GetType().GetMethod(attribute.Name);
                    if (propertyInfo.GetGetMethod() == null || propertyInfo.GetSetMethod() == null)
                    {
                        if (propertyInfo.PropertyType == typeof(Event))
                        {
                            // there is special handling for events downstream so let this through
                        }
                        else
                        {
                            throw new InvalidOperationException($"Property {control.GetType().FullName}.{attribute.Name} does not have a public getter and setter");
                        }
                    }

                    SetPropertyFromTextValue(context, control, propertyInfo, attribute.Value);
                }
            }
        }
示例#34
0
        private bool ControlRemovedFromVisualTreeRecursive(ConsoleControl c)
        {
            bool focusChanged = false;

            if (c is ConsolePanel)
            {
                foreach (var child in (c as ConsolePanel).Controls)
                {
                    focusChanged = ControlRemovedFromVisualTreeRecursive(child) || focusChanged;
                }
            }

            if (FocusManager.FocusedControl == c)
            {
                FocusManager.ClearFocus();
                focusChanged = true;
            }

            FocusManager.Remove(c);

            c.RemovedFromVisualTreeInternal();
            c.Application = null;
            ControlRemoved.Fire(c);
            c.Dispose();
            return focusChanged;
        }
示例#35
0
        private void ControlAddedToVisualTree(ConsoleControl c)
        {
            c.Application = this;

            if (c is ConsolePanel)
            {
                var childPanel = c as ConsolePanel;
                childPanel.Controls.SynchronizeForLifetime((cp) => { ControlAddedToVisualTree(cp); }, (cp) => { ControlRemovedFromVisualTree(cp); }, () => { }, c.LifetimeManager);
            }

            FocusManager.Add(c);
            c.AddedToVisualTreeInternal();

            ControlAdded.Fire(c);
        }
示例#36
0
        /// <summary>
        /// Tries to set focus on the given control.
        /// </summary>
        /// <param name="newFocusControl">the control to focus.  </param>
        /// <returns>True if the focus was set or if it was already set, false if the control cannot be focused</returns>
        public bool TrySetFocus(ConsoleControl newFocusControl)
        {
            var index = focusStack.Peek().Controls.IndexOf(newFocusControl);
            if (index < 0)
            {
                throw new InvalidOperationException("The given control is not in the control tree");
            }

            if(newFocusControl.CanFocus == false)
            {
                return false;
            }
            else  if(newFocusControl == FocusedControl)
            {
                return true;
            }
            else
            {
                if (FocusedControl != null)
                {
                    ClearFocus();
                }

                newFocusControl.HasFocus = true;
                FocusedControl = newFocusControl;
                focusStack.Peek().FocusIndex = index;

                if (FocusedControl != null)
                {
                    FocusedControl.FireFocused(true);
                }
                return true;
            }
        }
示例#37
0
 private void ScrollableControls_Added(ConsoleControl c)
 {
     c.SubscribeForLifetime(nameof(Bounds), UpdateScrollbars, c.LifetimeManager);
 }
示例#38
0
 public virtual void OnRemove(ConsoleControl parent)
 {
     if(Removed != null)
     {
         Removed();
     }
 }
示例#39
0
            public ViewModelBinding(ConsoleControl control, PropertyInfo controlProperty, ObservableObject viewModel, string observablePropertyName)
            {
                var viewModelObservableProperty = viewModel.GetType().GetProperty(observablePropertyName);

                if (viewModelObservableProperty.PropertyType != controlProperty.PropertyType &&
                    viewModelObservableProperty.PropertyType.IsSubclassOf(controlProperty.PropertyType) == false &&
                    viewModelObservableProperty.PropertyType.GetInterfaces().Contains(controlProperty.PropertyType) == false)
                {
                    throw new InvalidOperationException($"ViewModel property '{viewModel.GetType().FullName}.{observablePropertyName}' of type {viewModelObservableProperty.PropertyType.FullName} is not compatible with control property '{controlProperty.DeclaringType.FullName}.{controlProperty.Name}' of type {controlProperty.PropertyType.FullName} ");
                }

                viewModel.SynchronizeForLifetime(observablePropertyName, () =>
                {
                    var newValue = viewModelObservableProperty.GetValue(viewModel);
                    if (newValue == latestValue) return;
                    latestValue = newValue;
                    controlProperty.SetValue(control, newValue);
                }, control.LifetimeManager);

                control.SubscribeForLifetime(controlProperty.Name, () =>
                {
                    var newValue = controlProperty.GetValue(control);
                    if (newValue == latestValue) return;
                    latestValue = newValue;
                    viewModelObservableProperty.SetValue(viewModel, newValue);
                }, control.LifetimeManager);
            }
示例#40
0
 /// <summary>
 /// Removes the control from all focus contexts
 /// </summary>
 /// <param name="c">The control to remove</param>
 public void Remove(ConsoleControl c)
 {
     foreach(var context in focusStack)
     {
         context.Controls.Remove(c);
     }
 }
示例#41
0
 protected virtual (int X, int Y) Transform(ConsoleControl c) => (c.X, c.Y);
示例#42
0
        public void SetFocus(ConsoleControl newFocusControl)
        {
            var index = focusableControls.IndexOf(newFocusControl);
            if (index < 0) throw new InvalidOperationException("The given control is not in the control tree");

            if (newFocusControl != focusedControl)
            {
                if (focusedControl != null)
                {
                    focusedControl.HasFocus = false;
                    focusedControl.FireFocused(false);
                }

                focusedControl = newFocusControl;
                focusedControl.HasFocus = true;
                focusIndex = index;

                if (focusedControl != null) focusedControl.FireFocused(true);
            }
        }
示例#43
0
 private void ControlRemovedFromVisualTree(ConsoleControl c)
 {
     if (ControlRemovedFromVisualTreeRecursive(c))
     {
         FocusManager.TryRestoreFocus();
     }
 }
示例#44
0
 /// <summary>
 /// Clears the focus, but preserves the focus index
 /// </summary>
 public void ClearFocus()
 {
     FocusedControl.HasFocus = false;
     FocusedControl.FireFocused(false);
     FocusedControl = null;
 }
示例#45
0
        private static void SetPropertyFromTextValue(ParserContext context, ConsoleControl control, PropertyInfo property, string textValue)
        {
            bool isObservable = textValue.StartsWith("{") && textValue.EndsWith("}");

            if (isObservable)
            {
                var observablePropertyName = textValue.Substring(1, textValue.Length - 2);
                var viewModelObservable = context.CurrentViewModel as ObservableObject;
                if (viewModelObservable == null) throw new InvalidOperationException("View model is not observable");
                new ViewModelBinding(control, property, viewModelObservable, observablePropertyName);
            }
            else if(property.HasAttr<MarkupPropertyAttribute>())
            {
                property.Attr<MarkupPropertyAttribute>().Processor.Process(context);
            }
            else if (property.PropertyType == typeof(string))
            {
                property.SetValue(control, textValue);
            }
            else if (property.PropertyType == typeof(ConsoleString))
            {
                property.SetValue(control, new ConsoleString(textValue));
            }
            else if (property.PropertyType.IsEnum)
            {
                var enumVal = Enum.Parse(property.PropertyType, textValue);
                property.SetValue(control, enumVal);
            }
            else if (property.PropertyType == typeof(Event))
            {
                Event ev = property.GetValue(control) as Event;
                var target = context.CurrentViewModel;
                Action handler = () =>
                {
                    var method = target.GetType().GetMethod(textValue, new Type[0]);
                    if (method != null)
                    {
                        method.Invoke(target, new object[0]);
                    }
                    else
                    {
                        var action = target.GetType().GetProperty(textValue);
                        if (action == null || action.PropertyType != typeof(Action))
                        {
                            throw new InvalidOperationException("Not a method or action");
                        }

                        ((Action)action.GetValue(target)).Invoke();
                    }
                };

                ev.SubscribeForLifetime(handler, control.LifetimeManager);
            }
            else
            {
                var parseMethod = property.PropertyType.GetMethod("Parse", new Type[] { typeof(string) });
                var parsed = parseMethod.Invoke(null, new object[] { textValue });
                property.SetValue(control, parsed);
            }
        }
示例#46
0
文件: Form.cs 项目: hbre/PowerArgs
        /// <summary>
        /// Autogenerates form options for the given object by reflecting on its properties. All public properties with getters
        /// and setters will be included in the form unless it has the FormIgnore attribute on it. This method supports strings,
        /// ints, and enums.
        ///
        /// The form will be configured to two way bind all the form elements to the property values.
        /// </summary>
        /// <param name="o">The object to create form options for</param>
        /// <param name="labelColumnPercentage">the label column percentage to use</param>
        /// <returns></returns>
        public static FormOptions FromObject(object o, double labelColumnPercentage = .25)
        {
            var properties = o.GetType().GetProperties().Where(p => p.HasAttr <FormIgnoreAttribute>() == false && p.GetSetMethod() != null && p.GetGetMethod() != null).ToList();

            var ret = new FormOptions()
            {
                Elements = new ObservableCollection <FormElement>(),
                LabelColumnPercentage = labelColumnPercentage,
            };

            foreach (var property in properties)
            {
                if (o is IObservableObject && property.Name == nameof(IObservableObject.SuppressEqualChanges))
                {
                    continue;
                }

                ConsoleControl editControl = null;
                if (property.HasAttr <FormReadOnlyAttribute>() == false && property.PropertyType == typeof(string))
                {
                    var value   = (string)property.GetValue(o);
                    var textBox = new TextBox()
                    {
                        Foreground = ConsoleColor.White, Value = value == null ? ConsoleString.Empty : value.ToString().ToWhite()
                    };
                    textBox.SynchronizeForLifetime(nameof(textBox.Value), () => property.SetValue(o, textBox.Value.ToString()), textBox);
                    (o as IObservableObject)?.SynchronizeForLifetime(property.Name, () =>
                    {
                        var valueRead = property.GetValue(o);
                        if (valueRead is ICanBeAConsoleString)
                        {
                            textBox.Value = (valueRead as ICanBeAConsoleString).ToConsoleString();
                        }
                        else
                        {
                            textBox.Value = (valueRead + "").ToWhite();
                        }
                    }, textBox);
                    editControl = textBox;
                }
                else if (property.HasAttr <FormReadOnlyAttribute>() == false && property.PropertyType == typeof(int))
                {
                    if (property.HasAttr <FormSliderAttribute>())
                    {
                        var value  = (int)property.GetValue(o);
                        var slider = property.Attr <FormSliderAttribute>().Factory();
                        slider.Value = value;
                        slider.SynchronizeForLifetime(nameof(slider.Value), () =>
                        {
                            property.SetValue(o, (int)slider.Value);
                        }, slider);
                        (o as IObservableObject)?.SynchronizeForLifetime(property.Name, () =>
                        {
                            var valueRead = (int)property.GetValue(o);
                            slider.Value  = valueRead;
                        }, slider);
                        editControl = slider;
                    }
                    else
                    {
                        var value   = (int)property.GetValue(o);
                        var textBox = new TextBox()
                        {
                            Foreground = ConsoleColor.White, Value = value.ToString().ToWhite()
                        };
                        textBox.SynchronizeForLifetime(nameof(textBox.Value), () =>
                        {
                            if (textBox.Value.Length == 0)
                            {
                                textBox.Value = "0".ToConsoleString();
                            }
                            if (textBox.Value.Length > 0 && int.TryParse(textBox.Value.ToString(), out int result))
                            {
                                property.SetValue(o, result);
                            }
                            else if (textBox.Value.Length > 0)
                            {
                                textBox.Value = property.GetValue(o).ToString().ToWhite();
                            }
                        }, textBox);
                        (o as IObservableObject)?.SynchronizeForLifetime(property.Name, () =>
                        {
                            var valueRead = property.GetValue(o);
                            if (valueRead is ICanBeAConsoleString)
                            {
                                textBox.Value = (valueRead as ICanBeAConsoleString).ToConsoleString();
                            }
                            else
                            {
                                textBox.Value = (valueRead + "").ToConsoleString();
                            }
                        }, textBox);

                        textBox.AddedToVisualTree.SubscribeForLifetime(() =>
                        {
                            var previouslyFocusedControl = textBox.Application.FocusManager.FocusedControl;

                            var emptyStringAction = new Action(() =>
                            {
                                if (previouslyFocusedControl == textBox && textBox.Application.FocusManager.FocusedControl != textBox)
                                {
                                    if (textBox.Value.Length == 0)
                                    {
                                        textBox.Value = "0".ToConsoleString();
                                        property.SetValue(o, 0);
                                    }
                                }

                                previouslyFocusedControl = textBox.Application.FocusManager.FocusedControl;
                            });

                            textBox.Application.FocusManager.SubscribeForLifetime(nameof(FocusManager.FocusedControl), emptyStringAction, textBox);
                        }, textBox);

                        editControl = textBox;
                    }
                }
                else if (property.HasAttr <FormReadOnlyAttribute>() == false && property.PropertyType.IsEnum)
                {
                    var options = new List <DialogOption>();
                    foreach (var val in Enum.GetValues(property.PropertyType))
                    {
                        var enumField = property.PropertyType.GetField(Enum.GetName(property.PropertyType, val));
                        var display   = enumField.HasAttr <FormLabelAttribute>() ? enumField.Attr <FormLabelAttribute>().Label.ToConsoleString() : (val + "").ToConsoleString();

                        options.Add(new DialogOption()
                        {
                            DisplayText = display,
                            Id          = val.ToString(),
                            Value       = val,
                        });
                    }

                    var dropdown = new Dropdown(options);
                    dropdown.Width = Math.Min(40, options.Select(option => option.DisplayText.Length).Max() + 8);
                    dropdown.SubscribeForLifetime(nameof(dropdown.Value), () => property.SetValue(o, dropdown.Value.Value), dropdown);
                    (o as IObservableObject)?.SynchronizeForLifetime(property.Name, () => dropdown.Value = options.Where(option => option.Value.Equals(property.GetValue(o))).Single(), dropdown);
                    editControl = dropdown;
                }
                else if (property.HasAttr <FormReadOnlyAttribute>() == false && property.PropertyType == typeof(RGB))
                {
                    var dropdown = new ColorPicker();
                    dropdown.Width = Math.Min(40, Enums.GetEnumValues <ConsoleColor>().Select(option => option.ToString().Length).Max() + 8);
                    dropdown.SubscribeForLifetime(nameof(dropdown.Value), () => property.SetValue(o, dropdown.Value), dropdown);
                    (o as IObservableObject)?.SynchronizeForLifetime(property.Name, () => dropdown.Value = (RGB)(property.GetValue(o)), dropdown);
                    editControl = dropdown;
                }
                else if (property.HasAttr <FormReadOnlyAttribute>() == false && property.PropertyType == typeof(bool))
                {
                    var toggle = new ToggleControl();

                    if (property.HasAttr <FormYesNoAttribute>())
                    {
                        toggle.OnLabel  = " Yes ";
                        toggle.OffLabel = " No  ";
                    }

                    toggle.SubscribeForLifetime(nameof(toggle.On), () => property.SetValue(o, toggle.On), toggle);
                    (o as IObservableObject)?.SynchronizeForLifetime(property.Name, () => toggle.On = (bool)property.GetValue(o), toggle);
                    editControl = toggle;
                }
                else
                {
                    var value       = property.GetValue(o);
                    var valueString = value != null?value.ToString().ToDarkGray() : "<null>".ToDarkGray();

                    var valueLabel = new Label()
                    {
                        CanFocus = true, Text = valueString + " (read only)".ToDarkGray()
                    };
                    (o as IObservableObject)?.SynchronizeForLifetime(property.Name, () => valueLabel.Text = (property.GetValue(o) + "").ToConsoleString() + " (read only)".ToDarkGray(), valueLabel);

                    editControl = valueLabel;
                }

                if (property.HasAttr <FormWidth>())
                {
                    editControl.Width = property.Attr <FormWidth>().Width;
                }

                ret.Elements.Add(new FormElement()
                {
                    Label        = property.HasAttr <FormLabelAttribute>() ? property.Attr <FormLabelAttribute>().Label.ToYellow() : property.Name.ToYellow(),
                    ValueControl = editControl
                });
            }

            return(ret);
        }
示例#47
0
        internal Point CalculateRelativePosition(ConsoleControl parent)
        {
            var x = X;
            var y = Y;

            var tempParent = Parent;
            while (tempParent != null && tempParent != parent)
            {
                if (tempParent is ScrollablePanel)
            {
                    throw new InvalidOperationException("Controls within scrollable panels cannot have their relative positions calculated");
                }

                x += tempParent.X;
                y += tempParent.Y;
                tempParent = tempParent.Parent;
            }

            return new Point(x, y);
        }
示例#48
0
 private void Commands_Removed(ConsoleControl c)
 {
     Layout.StackHorizontally(1, Controls);
 }