しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

XAML の Path の表示位置やサイズを調整するツールを作りました

Metro Studio で出力される Path だと AppBarButton の Icon として利用しづらい

・・・ないものは作るしかない!ということで WPF正規化するツールを作ってみました

f:id:matatabi_ux:20140123060825p:plain

こんな感じで右上の窓に Path の Data プロパティの文字列を張り付けてサイズや余白を調整すると、右上の Data 文字列が更新されます

調整が終わったら、「Copy」ボタンでクリップボードにコピーして XAML に埋め込めば OK というわけです

ソースは GitHub にアップしてます

tatsuji-kuroyanagi/PathNormalizeTool · GitHub

ちなみに Path の Data プロパティは文字列を直接設定することができません

なので次のように Data 文字列を解析して Geometry インスタンスを生成しています

        /// <summary>
        /// Path Data
        /// </summary>
        public string PathData
        {
            get { return this.pathData; }
            set
            {
                this.Set<string>("PathData", ref this.pathData, value);
                this.Geometry = Geometry.Parse(this.pathData);
                this.Width = (this.Geometry.Bounds.Right - this.Geometry.Bounds.Left);
                this.Height = (this.Geometry.Bounds.Bottom - this.Geometry.Bounds.Top);
                this.UpdatePathData();
                this.RaisePropertyChanged("PathData");
                this.RaisePropertyChanged("IsInputted");
            }
        }

残念ながら Geometry.Parse() メソッドは Windows ストアアプリにはないみたいです;

あとは Width や Height、Margin の入力値に応じて、こんな感じで Segment をごにょごにょすればできました!

        /// <summary>
        /// Path の整形
        /// </summary>
        public void UpdatePathData()
        {
            try
            {
                if (this.Geometry == null)
                {
                    return;
                }

                var pathGeometory = (this.Geometry.Clone() as StreamGeometry).GetFlattenedPathGeometry();
                var scaled = new PathGeometry();
                double scaleX = (this.Geometry.Bounds.Right - this.Geometry.Bounds.Left) / this.Width;
                double scaleY = (this.Geometry.Bounds.Bottom - this.Geometry.Bounds.Top) / this.Height;


                foreach (var figure in pathGeometory.Figures)
                {
                    var newFigure = new PathFigure();


                    newFigure.StartPoint = new Point(
                        ((figure.StartPoint.X - this.Geometry.Bounds.Left) / scaleX) + this.Left,
                        ((figure.StartPoint.Y - this.Geometry.Bounds.Top) / scaleY) + this.Top
                        );
                    foreach (PolyLineSegment segment in figure.Segments)
                    {
                        var newSegment = new PolyLineSegment();
                        foreach (var point in segment.Points)
                        {
                            newSegment.Points.Add(new Point(
                                ((point.X - this.Geometry.Bounds.Left) / scaleX) + this.Left,
                                ((point.Y - this.Geometry.Bounds.Top) / scaleY) + this.Top
                                ));
                        }
                        newFigure.Segments.Add(newSegment);
                    }
                    scaled.Figures.Add(newFigure);
                }
                scaled.Freeze();
                this.pathData = scaled.ToString();
                this.RaisePropertyChanged("PathData");
                this.PathGeometry = scaled;
            }
            catch (Exception)
            {
            }
        }

大量の正規化は難しいですがちょっとした調整だったら使える・・・ですかね?