Exemple #1
0
        /// <summary>
        /// 文字列の折り返しを行います。
        /// このメソッドの呼び出しにより、WrappingValid プロパティが true に設定されます。
        /// このメソッドでは、LF (\n) を見つけた場合、LF を基準とした分割をまず行います。
        /// なお、このメソッドは CR (\r) には対応しておらず、
        /// Text プロパティへの設定において CR を除去した文字列を内部で管理しています。
        /// 続いて、このメソッドでは、空白文字を基準とした分割を行います。
        /// ここで、このメソッドが認識する空白文字は半角空白文字のみであり、
        /// 全角空白文字には対応しません。
        /// 最後に、基準にできる空白文字が見つからない場合は、
        /// ClientWidth プロパティが示す幅に収まるように強制的に分割します。
        /// </summary>
        public void Wrap()
        {
            if (WrappingValid)
            {
                return;
            }

            measuredSize      = Vector2.Zero;
            MaxMeasuredHeight = 0;
            lines.Clear();

            // Font 不明、Text が空ならばサイズ 0 とします。
            if (font == null || charArray == null || charArray.Length == 0)
            {
                measuredSize  = Vector2.Zero;
                WrappingValid = true;
                return;
            }

            // 文字数 1 ならば折り返せないため、そのまま測定して返します。
            // コンテナ幅が不明な場合も折り返せないため、そのまま測定して返します。
            if (text.Length == 1 || clientWidth <= 0 || float.IsNaN(clientWidth))
            {
                lines.Add(new WrappedTextLine(0, text.Length));
                measuredSize  = font.MeasureString(text) * fontStretch;
                WrappingValid = true;
                return;
            }

            if (builder == null)
            {
                builder = new StringBuilder();
            }
            builder.Length = 0;

            int     charIndex      = 0;
            int     startIndex     = 0;
            int     lastSpaceIndex = -1;
            Vector2 size           = new Vector2();

            while (charIndex < charArray.Length)
            {
                var c = charArray[charIndex];

                // LF を見つけたら強制折り返しさせます。
                // LF ではない場合は文字を追加して測定し、改行するかどうかを判定します。
                if (c == '\n')
                {
                    lastSpaceIndex = -1;
                }
                else
                {
                    builder.Append(c);

                    size = font.MeasureString(builder) * fontStretch;
                    // clientWidth 未満ならばその行を継続します。
                    if (size.X <= clientWidth)
                    {
                        if (c == ' ')
                        {
                            lastSpaceIndex = charIndex;
                        }
                        charIndex++;
                        continue;
                    }

                    if (0 <= lastSpaceIndex)
                    {
                        // スペースを見つけていたならば、その最後のスペースの位置まで戻します。
                        charIndex      = lastSpaceIndex + 1;
                        builder.Length = charIndex - startIndex;
                        lastSpaceIndex = -1;
                    }
                    else
                    {
                        // スペースを見つけていないならば、1 文字前に戻します。
                        charIndex--;

                        if (charIndex == 0)
                        {
                            // 改行できないほどに ClientWidth が小さいならば、
                            // 改行処理を中断します。
                            measuredSize  = Vector2.Zero;
                            WrappingValid = true;
                            return;
                        }

                        // 対象文字についても 1 文字前に戻します。
                        builder.Length = builder.Length - 1;
                    }
                }

                // 行を測定します。
                // 改行のみが行われたなどの空行の場合は測定をスキップします。
                if (0 < builder.Length)
                {
                    size              = font.MeasureString(builder) * fontStretch;
                    measuredSize.X    = Math.Max(measuredSize.X, size.X);
                    MaxMeasuredHeight = Math.Max(MaxMeasuredHeight, size.Y);
                }
                // 折り返し範囲を記録します。
                lines.Add(new WrappedTextLine(startIndex, charIndex - startIndex));
                // LF で折り返した場合はインデックスを進めます。
                if (c == '\n')
                {
                    charIndex++;
                }

                builder.Length = 0;
                startIndex     = charIndex;
            }
            // 最後の 1 行を測定します。
            size              = font.MeasureString(builder) * fontStretch;
            measuredSize.X    = Math.Max(measuredSize.X, size.X);
            MaxMeasuredHeight = Math.Max(MaxMeasuredHeight, size.Y);
            // 折り返し範囲を記録します。
            var lastElement = new WrappedTextLine(startIndex, charIndex - startIndex);

            lines.Add(lastElement);

            // 最大の行の高さから行全体の高さを決定します。
            measuredSize.Y = lines.Count * MaxMeasuredHeight;

            WrappingValid = true;
        }
Exemple #2
0
        /// <summary>
        /// 文字列の折り返しを行います。
        /// このメソッドの呼び出しにより、WrappingValid プロパティが true に設定されます。
        /// このメソッドでは、LF (\n) を見つけた場合、LF を基準とした分割をまず行います。
        /// なお、このメソッドは CR (\r) には対応しておらず、
        /// Text プロパティへの設定において CR を除去した文字列を内部で管理しています。
        /// 続いて、このメソッドでは、空白文字を基準とした分割を行います。
        /// ここで、このメソッドが認識する空白文字は半角空白文字のみであり、
        /// 全角空白文字には対応しません。
        /// 最後に、基準にできる空白文字が見つからない場合は、
        /// ClientWidth プロパティが示す幅に収まるように強制的に分割します。
        /// </summary>
        public void Wrap()
        {
            if (WrappingValid) return;

            measuredSize = Vector2.Zero;
            MaxMeasuredHeight = 0;
            lines.Clear();

            // Font 不明、Text が空ならばサイズ 0 とします。
            if (font == null || charArray == null || charArray.Length == 0)
            {
                measuredSize = Vector2.Zero;
                WrappingValid = true;
                return;
            }

            // 文字数 1 ならば折り返せないため、そのまま測定して返します。
            // コンテナ幅が不明な場合も折り返せないため、そのまま測定して返します。
            if (text.Length == 1 || clientWidth <= 0 || float.IsNaN(clientWidth))
            {
                lines.Add(new WrappedTextLine(0, text.Length));
                measuredSize = font.MeasureString(text) * fontStretch;
                WrappingValid = true;
                return;
            }

            if (builder == null) builder = new StringBuilder();
            builder.Length = 0;

            int charIndex = 0;
            int startIndex = 0;
            int lastSpaceIndex = -1;
            Vector2 size = new Vector2();
            while (charIndex < charArray.Length)
            {
                var c = charArray[charIndex];

                // LF を見つけたら強制折り返しさせます。
                // LF ではない場合は文字を追加して測定し、改行するかどうかを判定します。
                if (c == '\n')
                {
                    lastSpaceIndex = -1;
                }
                else
                {
                    builder.Append(c);

                    size = font.MeasureString(builder) * fontStretch;
                    // clientWidth 未満ならばその行を継続します。
                    if (size.X <= clientWidth)
                    {
                        if (c == ' ') lastSpaceIndex = charIndex;
                        charIndex++;
                        continue;
                    }

                    if (0 <= lastSpaceIndex)
                    {
                        // スペースを見つけていたならば、その最後のスペースの位置まで戻します。
                        charIndex = lastSpaceIndex + 1;
                        builder.Length = charIndex - startIndex;
                        lastSpaceIndex = -1;
                    }
                    else
                    {
                        // スペースを見つけていないならば、1 文字前に戻します。
                        charIndex--;

                        if (charIndex == 0)
                        {
                            // 改行できないほどに ClientWidth が小さいならば、
                            // 改行処理を中断します。
                            measuredSize = Vector2.Zero;
                            WrappingValid = true;
                            return;
                        }

                        // 対象文字についても 1 文字前に戻します。
                        builder.Length = builder.Length - 1;
                    }
                }

                // 行を測定します。
                // 改行のみが行われたなどの空行の場合は測定をスキップします。
                if (0 < builder.Length)
                {
                    size = font.MeasureString(builder) * fontStretch;
                    measuredSize.X = Math.Max(measuredSize.X, size.X);
                    MaxMeasuredHeight = Math.Max(MaxMeasuredHeight, size.Y);
                }
                // 折り返し範囲を記録します。
                lines.Add(new WrappedTextLine(startIndex, charIndex - startIndex));
                // LF で折り返した場合はインデックスを進めます。
                if (c == '\n') charIndex++;

                builder.Length = 0;
                startIndex = charIndex;
            }
            // 最後の 1 行を測定します。
            size = font.MeasureString(builder) * fontStretch;
            measuredSize.X = Math.Max(measuredSize.X, size.X);
            MaxMeasuredHeight = Math.Max(MaxMeasuredHeight, size.Y);
            // 折り返し範囲を記録します。
            var lastElement = new WrappedTextLine(startIndex, charIndex - startIndex);
            lines.Add(lastElement);

            // 最大の行の高さから行全体の高さを決定します。
            measuredSize.Y = lines.Count * MaxMeasuredHeight;

            WrappingValid = true;
        }