using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Interop; using System.Diagnostics; using System.Globalization; using System.Windows; using System.Windows.Documents; using System.Windows.Controls; using System.Linq; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using System.Windows.Threading; using System.Threading; namespace agree.Wpf.Util { public static class Util { public static Size DrawText(this DrawingContext dc, String s, double x, double y, Typeface f, double emSize, Brush b) { FormattedText ft = new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, f, emSize, b); dc.DrawText(ft, new Point(x, y)); return new Size(ft.Width, ft.Height); } public static Size DrawText(this DrawingContext dc, String s, Point pt, Typeface f, double emSize, Brush b) { FormattedText ft = new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, f, emSize, b); dc.DrawText(ft, pt); return new Size(ft.Width, ft.Height); } public static void DrawText(this DrawingContext dc, FormattedText ft, double x, double y) { dc.DrawText(ft, new Point(x, y)); } public static FormattedText FormattedText(this String s, Typeface f, double emSize, Brush b = null) { return new FormattedText(s, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, f, emSize, b ?? Brushes.Black); } static Size infinite_size = new Size(double.PositiveInfinity, double.PositiveInfinity); public static void SaveToPng(FrameworkElement fe, System.IO.Stream stream) { using (var ps = new HwndSource(new HwndSourceParameters())) { ps.RootVisual = VisualTreeHelper.GetParent(fe) == null ? fe : null; // Flush the dispatcher queue //var disp = Dispatcher.CurrentDispatcher; //if (disp == null) // throw new Exception(); //disp.Invoke(DispatcherPriority.SystemIdle, new Action(() => { })); fe.Measure(infinite_size); Size sz = fe.DesiredSize; DrawingVisual dv = new DrawingVisual(); using (DrawingContext ctx = dv.RenderOpen()) { VisualBrush br = new VisualBrush(fe); br.AutoLayoutContent = true; ctx.DrawRectangle(br, null, new Rect(0, 0, sz.Width, sz.Height)); } RenderTargetBitmap bitmap = new RenderTargetBitmap((int)sz.Width+2, (int)sz.Height+2, 96, 96, PixelFormats.Pbgra32); bitmap.Render(dv); //disp.Invoke(DispatcherPriority.SystemIdle, new Action(() => { })); PngBitmapEncoder encoder = new PngBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmap)); encoder.Save(stream); } } }; /// <summary> /// http://thejoyofcode.com/Generating_images_using_WPF_on_the_Server.aspx /// </summary> public class BackgroundStaDispatcher { private Dispatcher _dispatcher; static int id = 0; public BackgroundStaDispatcher(Action<Exception> exception_handler) { AutoResetEvent are = new AutoResetEvent(false); Thread thread = new Thread(() => { _dispatcher = Dispatcher.CurrentDispatcher; _dispatcher.UnhandledException += (o, e) => { exception_handler(e.Exception); if (!Debugger.IsAttached) { e.Handled = true; } }; are.Set(); Dispatcher.Run(); }); thread.Name = string.Format("BackgroundStaDispatcher({0})", (id++).ToString()); thread.SetApartmentState(ApartmentState.STA); thread.IsBackground = true; thread.Start(); are.WaitOne(); } public void Invoke(Action action) { _dispatcher.Invoke(action); } } } namespace agree.Wpf.Util { public class RoundedRectangle : Border, INotifyPropertyChanged { Rectangle r; Border mask; Grid g2; public RoundedRectangle() : this(default(UIElement)) { } public RoundedRectangle(String txt, TextWrapping wrap = TextWrapping.NoWrap) : this(new TextBlock()) { this.Text = txt; } public RoundedRectangle(UIElement el) { r = new Rectangle(); mask = new Border(); mask.Background = Brushes.White; g2 = new Grid(); g2.OpacityMask = new VisualBrush(mask); g2.Children.Add(r); if (el != null) g2.Children.Add(el); Grid g1 = new Grid(); g1.Children.Add(mask); g1.Children.Add(g2); base.BorderThickness = new Thickness(1); base.BorderBrush = Brushes.Black; base.CornerRadius = new CornerRadius(6); base.Child = g1; } public String Text { set { TextBlock tb = new TextBlock(); InnerChild = tb; tb.Text = value; tb.Foreground = Brushes.Black; tb.Padding = new Thickness(1.5); tb.TextWrapping = TextWrapping.NoWrap; } } public UIElement InnerChild { get { return g2.Children.Count > 1 ? g2.Children[1] : null; } set { while (g2.Children.Count >= 2) g2.Children.RemoveAt(1); g2.Children.Add(value); } } protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.Property == Border.CornerRadiusProperty) mask.CornerRadius = this.CornerRadius; else if (e.Property == Border.BackgroundProperty) r.Fill = this.Background; } Point pt_top_center; Point pt_bot_center; public Point TopCenter { get { return pt_top_center; } } public Point BottomCenter { get { return pt_bot_center; } } public Double Top { get { return pt_top_center.Y; } } public Double Bottom { get { return pt_bot_center.Y; } } public Double Center { get { return pt_top_center.X; } } public static readonly DependencyProperty ContainerParentProperty = DependencyProperty.RegisterAttached("ContainerParent", typeof(Boolean), typeof(RoundedRectangle), new FrameworkPropertyMetadata( false, 0, null, null, true)); public static Boolean GetTreeParent(FrameworkElement e) { return (Boolean)e.GetValue(ContainerParentProperty); } public static void SetTreeParent(FrameworkElement e, Boolean v) { e.SetValue(ContainerParentProperty, v); } FrameworkElement FindContainerParent() { FrameworkElement p = this; while ((p = p.Parent as FrameworkElement) != null) { if ((Boolean)p.GetValue(ContainerParentProperty)) return p; } return null; } protected override Size ArrangeOverride(Size finalSize) { Size sz = base.ArrangeOverride(finalSize); FrameworkElement p = FindContainerParent(); if (p != null) { Point pt; pt = TranslatePoint(new Point(sz.Width / 2, 0), p); if (!pt.Equals(pt_top_center)) { pt_top_center = pt; NotifyPropertyChanged("TopCenter"); NotifyPropertyChanged("Top"); NotifyPropertyChanged("Center"); } pt = TranslatePoint(new Point(sz.Width / 2, sz.Height), p); if (!pt.Equals(pt_bot_center)) { pt_bot_center = pt; NotifyPropertyChanged("BottomCenter"); NotifyPropertyChanged("Bottom"); } } return sz; } void NotifyPropertyChanged(String s_field) { var h = PropertyChanged; if (h != null) h(this, new PropertyChangedEventArgs(s_field)); } public event PropertyChangedEventHandler PropertyChanged; }; public class VizParseTree : StackPanel { IDerivation pce; TreeLayoutPanel tlp; public VizParseTree(ParseControl ctrl, IDerivation pce) { this.pce = pce; this.Orientation = System.Windows.Controls.Orientation.Vertical; tlp = new TreeLayoutPanel(); tlp.VerticalBuffer = 15; tlp.HorizontalBuffer = 35; tlp.HorizontalBufferSubtree = 35; tlp.Margin = new Thickness(10); tlp.Stroke = Brushes.Gray; //tree_layout_panel.SetValue(TextBlock.FontSizeProperty, 18.0); //tree_layout_panel.SetValue(TextBlock.FontFamilyProperty, new FontFamily("Arial")); CreateTreeNode(ctrl.g.nl.GetParseTree(ctrl.chart, pce)); this.Children.Add(tlp); var tb = new TextBlock(new Run(pce.UnpackedTfs.Name)); tb.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; this.Children.Add(tb); } public IDerivation ParseTree { get { return pce; } } FrameworkElement CreateTreeNode(GrammarNodeLabeler.ParseTree pt) { FrameworkElement ltn = pt.Children.Length == 0 ? (FrameworkElement) new TextBelowLabelTreeNode(pt) : new LabelTreeNode(pt.Label); tlp.Children.Add(ltn); foreach (var fe in pt.Children.Select(c => CreateTreeNode(c))) { fe.SetValue(TreeLayoutPanel.TreeParentProperty, ltn); } return ltn; } class LabelTreeNode : RoundedRectangle { public LabelTreeNode(String text) : base(text) { CornerRadius = new CornerRadius(1.5); Background = Brushes.Honeydew; HorizontalAlignment = System.Windows.HorizontalAlignment.Center; ((TextBlock)InnerChild).Padding = new Thickness(5, 0, 5, 0); } }; class TextBelowLabelTreeNode : StackPanel { public TextBelowLabelTreeNode(GrammarNodeLabeler.ParseTree pt) { this.Orientation = System.Windows.Controls.Orientation.Vertical; this.SnapsToDevicePixels = true; var ltn = new LabelTreeNode(pt.Label); ltn.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; this.Children.Add(ltn); Run r = new Run(pt.SourceText); r.FontFamily = new FontFamily("Tekton Pro"); r.FontSize = 21.0; r.FontWeight = FontWeight.FromOpenTypeWeight(100); var tb = new TextBlock(); tb.Margin = new Thickness(0, 4, 0, 0); tb.Inlines.Add(r); tb.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; this.Children.Add(tb); } }; }; }