using MaterialDesignThemes.Wpf;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
using Tango.PMR.Printing;
namespace Tango.MachineStudio.Developer.Controls
{
public class JobOutlineControl : Control
{
#region members
private Size _sizeControl = new Size(0, 0);
ScrollViewer _parentScrollViewer = null;
public struct LevelOffset
{
public const double level_0 = 0.0;
public const double level_1 = 10.0;
public const double level_2 = 20.0;
public const double level_3 = 37.0;
public const double level_4 = 50.0;
public const double level_5 = 60.0;
public const double level_6 = 77.0;
public const double level_7 = 90.0;
public const double level_8 = 100.0;
}
private double _verticalOffset = 0;
private double _viewportHeight = 0;
private const double HEADER_FONT_HEIGHT = 35;
private const double TITLE_FONT_HEIGHT = 22;
private const double SUB_TITLE_FONT_HEIGHT = 19;
private const double NORMAL_FONT_HEIGHT = 17;
private const double WIDTH = 330;
#endregion members
public JobOutlineControl() : base()
{
Unloaded += JobOutlineControl_Unloaded;
DataContextChanged += JobOutlineControl_DataContextChanged;
Width = WIDTH;
}
private void JobOutlineControl_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (_parentScrollViewer != null)
{
_parentScrollViewer.ScrollToTop();
}
InvalidateVisual();
}
#region events
private void JobOutlineControl_Unloaded(object sender, RoutedEventArgs e)
{
if (_parentScrollViewer == null)
{
_parentScrollViewer.ScrollChanged -= ScrollViewer_ScrollChanged;
}
}
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (e.VerticalChange == 0.0)
return;
_verticalOffset = _parentScrollViewer.VerticalOffset;
_viewportHeight = _parentScrollViewer.ViewportHeight;
InvalidateVisual();
}
#endregion events
#region render
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
if (!(DataContext is JobTicket job)) return;
if (_parentScrollViewer == null)
{
_parentScrollViewer = this.FindAncestor<ScrollViewer>();
_parentScrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
}
else if (_viewportHeight == 0)
{
_viewportHeight = _parentScrollViewer.ActualHeight;
}
_sizeControl = new Size();
_sizeControl.Height += 10;
DrawHeaderText(drawingContext, "JOB OUTLINE", 30, LevelOffset.level_0);
_sizeControl.Height += HEADER_FONT_HEIGHT;
_sizeControl.Height += 20;
DrawHeaderText(drawingContext, "BASIC", 17, LevelOffset.level_0);
_sizeControl.Height += TITLE_FONT_HEIGHT;
_sizeControl.Height += 5.0;
var basicProps = GetNameValueList(job);
foreach (var prop in basicProps)
{
DrawNameValueText(drawingContext, prop, LevelOffset.level_1, PackIconKind.Pencil);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
//JobTicket.Spool
if (job.Spool != null)
{
_sizeControl.Height += 20;
DrawHeaderText(drawingContext, "SPOOL", 17, LevelOffset.level_0);
_sizeControl.Height += TITLE_FONT_HEIGHT;
_sizeControl.Height += 5.0;
basicProps = GetNameValueList(job.Spool);
foreach (var prop in basicProps)
{
DrawNameValueText(drawingContext, prop, LevelOffset.level_1, PackIconKind.Pencil);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
}
//JobTicket.ProcessParameters
if (job.ProcessParameters != null)
{
_sizeControl.Height += 20;
DrawHeaderText(drawingContext, "PROCESS PARAMETERS", 17, LevelOffset.level_0);
_sizeControl.Height += TITLE_FONT_HEIGHT;
_sizeControl.Height += 5.0;
basicProps = GetNameValueList(job.ProcessParameters);
foreach (var prop in basicProps)
{
DrawNameValueText(drawingContext, prop, LevelOffset.level_1, PackIconKind.Settings);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
}
//JobTicket.ThreadParameters
if (job.ThreadParameters != null)
{
_sizeControl.Height += 20;
DrawHeaderText(drawingContext, "THREAD PARAMETERS", 17, LevelOffset.level_0);
_sizeControl.Height += TITLE_FONT_HEIGHT;
_sizeControl.Height += 5.0;
basicProps = GetNameValueList(job.ThreadParameters);
foreach (var prop in basicProps)
{
DrawNameValueText(drawingContext, prop, LevelOffset.level_1, PackIconKind.Settings);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
}
//JobTicket.HeadCleaningParameters
if (job.HeadCleaningParameters != null)
{
_sizeControl.Height += 20;
DrawHeaderText(drawingContext, "HEAD CLEANING PARAMETERS", 17, LevelOffset.level_0);
_sizeControl.Height += TITLE_FONT_HEIGHT;
_sizeControl.Height += 5.0;
basicProps = GetNameValueList(job.HeadCleaningParameters);
foreach (var prop in basicProps)
{
DrawNameValueText(drawingContext, prop, LevelOffset.level_1, PackIconKind.Settings);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
}
//JobTicket.Segments
if (job.Segments != null)
{
_sizeControl.Height += 20;
DrawHeaderText(drawingContext, "SEGMENTS", 17, LevelOffset.level_0);
_sizeControl.Height += TITLE_FONT_HEIGHT;
_sizeControl.Height += 10.0;
int index = 0;
foreach (JobSegment seg in job.Segments)
{
DrawHeaderText(drawingContext, string.Format("#{0} SEGMENT", ++index), 14, LevelOffset.level_1);
_sizeControl.Height += SUB_TITLE_FONT_HEIGHT;
basicProps = GetNameValueList(seg);
foreach (var prop in basicProps)
{
DrawNameValueText(drawingContext, prop, LevelOffset.level_2, PackIconKind.Pencil);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
//BrushStops
DrawHeaderText(drawingContext, "BRUSH STOPS", 12, LevelOffset.level_3);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
int indexBrush = 0;
foreach (JobBrushStop brushstop in seg.BrushStops)
{
_sizeControl.Height += 5.0;
DrawHeaderText(drawingContext, string.Format("#{0} STOP", ++indexBrush), 11, LevelOffset.level_4);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
var brushStops = GetNameValueList(brushstop);
foreach (var brushstopprop in brushStops)
{
DrawNameValueText(drawingContext, brushstopprop, LevelOffset.level_5, PackIconKind.Pencil);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
DrawHeaderText(drawingContext, "DISPENSERS", 12, LevelOffset.level_6);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
_sizeControl.Height += 5.0;
int indexDispenser = 0;
foreach (JobDispenser disp in brushstop.Dispensers)
{
DrawHeaderText(drawingContext, string.Format("#{0} DISPENSER", ++indexDispenser), 11, LevelOffset.level_6);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
var dispProperties = GetNameValueList(disp);
foreach (var dispprop in dispProperties)
{
DrawNameValueText(drawingContext, dispprop, LevelOffset.level_7, PackIconKind.ArrowRightBoldCircle);
_sizeControl.Height += NORMAL_FONT_HEIGHT;
}
}
}
}
}
if (Height != _sizeControl.Height)
{
Height = _sizeControl.Height;
}
}
public IEnumerable<Tuple<String, String>> GetNameValueList(object value)
{
if (value != null)
{
var properties = value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => (!x.PropertyType.IsClass && !typeof(IEnumerable).IsAssignableFrom(x.PropertyType)) || x.PropertyType == typeof(String)).ToList();
return properties.Select(x => new Tuple<string, string>(x.Name, x.GetValue(value).ToString()));
}
else
{
return null;
}
}
#endregion render
#region drawing
protected void DrawNameValueText(DrawingContext drawingContext, Tuple<string, string> text, double levelOfOffset, PackIconKind? icon)
{
if (IsInViewPort())
{
FormattedText formattedName = new FormattedText(text.Item1 + ": ", System.Globalization.CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal),
12, Foreground);
DrawIconTextIfVisible(drawingContext, levelOfOffset, formattedName, icon);
double widthOfNameText = formattedName.WidthIncludingTrailingWhitespace + 17 + levelOfOffset;//17 pix for draw icon before text
FormattedText formattedValue = new FormattedText(text.Item2, System.Globalization.CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.SemiBold, FontStretches.Normal),
12, Foreground);
DrawIconTextIfVisible(drawingContext, widthOfNameText, formattedValue);
_sizeControl.Width = Math.Max(_sizeControl.Width, (widthOfNameText + formattedValue.WidthIncludingTrailingWhitespace));
}
}
private bool IsInViewPort()
{
return (_sizeControl.Height >= _verticalOffset && _sizeControl.Height <= (_verticalOffset + _viewportHeight + 5));
}
protected void DrawHeaderText(DrawingContext drawingContext, string text, int fontSize, double levelOfOffset)
{
if (IsInViewPort())
{
FormattedText formattedtext = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, System.Windows.FlowDirection.LeftToRight, new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.SemiBold, FontStretches.Normal),
fontSize, Foreground);
DrawIconTextIfVisible(drawingContext, levelOfOffset, formattedtext);
_sizeControl.Width = Math.Max(_sizeControl.Width, (formattedtext.Width + levelOfOffset));
}
}
private void DrawIconTextIfVisible(DrawingContext drawingContext, double levelOfOffset, FormattedText formattedText, PackIconKind? icon = null)
{
if (icon is PackIconKind)
{
DrawIcon(drawingContext, (PackIconKind)icon, new Point(levelOfOffset, _sizeControl.Height));
levelOfOffset += 17;
}
drawingContext.DrawText(formattedText, new Point(levelOfOffset, _sizeControl.Height));
}
private void DrawIcon(DrawingContext drawingContext, PackIconKind kind, Point point)
{
GeometryGroup group = GetGeometryByIcon(kind);
SetGeometryPosition(group, point);
drawingContext.DrawGeometry(Foreground, new Pen(Brushes.White, 1), group);
}
private GeometryGroup GetGeometryByIcon(PackIconKind kind)
{
PackIcon icon = new PackIcon { Kind = kind };
Geometry geometry = Geometry.Parse(icon.Data);
GeometryGroup group = new GeometryGroup();
group.Children.Add(geometry);
TransformGroup tg = new TransformGroup();
tg.Children.Add(new ScaleTransform()
{
ScaleX = 10d / geometry.Bounds.Width,
ScaleY = 10d / geometry.Bounds.Height,
});
tg.Children.Add(new TranslateTransform() { });
group.Transform = tg;
return group;
}
private void SetGeometryPosition(GeometryGroup group, Point point)
{
TransformGroup tg = group.Transform as TransformGroup;
(tg.Children[1] as TranslateTransform).X = point.X;
(tg.Children[1] as TranslateTransform).Y = point.Y + 1;
}
#endregion drawing
}
}