source: 2014/24/EemeliK/Zombieland/Jypeli/Font.cs @ 5974

Revision 5974, 7.9 KB checked in by empaheik, 4 years ago (diff)
Line 
1using System;
2using System.Diagnostics;
3using Microsoft.Xna.Framework.Graphics;
4using System.Text;
5
6using XnaRectangle = Microsoft.Xna.Framework.Rectangle;
7using XnaV2 = Microsoft.Xna.Framework.Vector2;
8using XnaColor = Microsoft.Xna.Framework.Color;
9
10namespace Jypeli
11{
12    internal enum ContentSource
13    {
14        GameContent,
15        ResourceContent,
16    }
17
18
19    /// <summary>
20    /// Fontti.
21    /// </summary>
22    public class Font
23    {
24        /// <summary>
25        /// OletusFontti.
26        /// </summary>
27        public static readonly Font Default = new Font( "MediumFont", ContentSource.ResourceContent );
28
29        /// <summary>
30        /// Pieni oletusfontti.
31        /// </summary>
32        public static readonly Font DefaultSmall = new Font( "SmallFont", ContentSource.ResourceContent );
33
34        /// <summary>
35        /// Suuri oletusfontti.
36        /// </summary>
37        public static readonly Font DefaultLarge = new Font( "LargeFont", ContentSource.ResourceContent );
38
39        /// <summary>
40        /// Paksunnettu oletusfontti.
41        /// </summary>
42        public static readonly Font DefaultBold = new Font( "MediumFontBold", ContentSource.ResourceContent );
43
44        /// <summary>
45        /// Paksunnettu pieni oletusfontti.
46        /// </summary>
47        public static readonly Font DefaultSmallBold = new Font( "SmallFontBold", ContentSource.ResourceContent );
48
49        /// <summary>
50        /// Paksunnettu suuri oletusfontti.
51        /// </summary>
52        public static readonly Font DefaultLargeBold = new Font( "LargeFontBold", ContentSource.ResourceContent );
53
54        private SpriteFont xnaFont;
55        private string name;
56        private ContentSource source;
57        private Vector[] charsizes;
58
59        internal SpriteFont XnaFont
60        {
61            get { DoLoad(); return xnaFont; }
62        }
63
64        /// <summary>
65        /// Merkin leveys.
66        /// </summary>
67        public double CharacterWidth
68        {
69            get { return XnaFont.MeasureString( "X" ).X; }
70        }
71
72        /// <summary>
73        /// Merkin korkeus.
74        /// </summary>
75        public double CharacterHeight
76        {
77            get { return XnaFont.MeasureString( "X" ).Y; }
78        }
79
80        internal Font( string name, ContentSource source )
81        {
82            this.xnaFont = null;
83            this.charsizes = null;
84            this.name = name;
85            this.source = source;
86        }
87
88        internal Font( SpriteFont xnaFont )
89        {
90            this.xnaFont = xnaFont;
91            this.charsizes = new Vector[xnaFont.Characters.Count];
92            this.name = null;
93            this.source = ContentSource.ResourceContent;
94        }
95
96        private void DoLoad()
97        {
98            if ( xnaFont == null )
99            {
100                if ( source == ContentSource.ResourceContent )
101                    xnaFont = Game.ResourceContent.Load<SpriteFont>( name );
102                else
103                    xnaFont = Game.Instance.Content.Load<SpriteFont>( name );
104
105                charsizes = new Vector[xnaFont.Characters.Count];
106            }
107        }
108
109        /// <summary>
110        /// Palauttaa annetun merkin koon tässä fontissa.
111        /// </summary>
112        /// <param name="c">Merkki</param>
113        /// <returns>Kokovektori, nollavektori jos merkkiä ei ole määritelty</returns>
114        public Vector GetCharacterSize( char c )
115        {
116            int index = XnaFont.Characters.IndexOf( c );
117            if ( index < 0 ) return Vector.Zero;
118
119            if ( charsizes[index] == Vector.Zero )
120            {
121                XnaV2 xnaSize = XnaFont.MeasureString( c.ToString() );
122                charsizes[index] = new Vector( xnaSize.X, xnaSize.Y );
123            }
124
125            return charsizes[index];
126        }
127
128        /// <summary>
129        /// Katkaisee merkkijonon loppupäästä niin että se sopii annettuun
130        /// pikselileveyteen fontilla kirjoitettuna.
131        /// </summary>
132        /// <param name="str">Merkkijono</param>
133        /// <param name="maxLineWidth">Maksimipikselimäärä merkkijonolle</param>
134        /// <returns></returns>
135        public string TruncateText( string str, double maxLineWidth )
136        {
137            StringBuilder builder = new StringBuilder( str );
138            double realWidth = XnaFont.MeasureString( str ).X;
139
140            while ( realWidth > maxLineWidth )
141            {
142                builder.Remove( builder.Length - 1, 1 );
143                realWidth = XnaFont.MeasureString( builder ).X;
144            }
145
146            return builder.ToString();
147        }
148
149        private static void appendLine(StringBuilder dest, StringBuilder line)
150        {
151            if ( dest.Length > 0 ) dest.Append( "\n" );
152            line.RemoveLeading( c => Char.IsWhiteSpace( c ) );
153            line.PutTo( dest );
154        }
155
156        /// <summary>
157        /// Rivittää tekstin.
158        /// </summary>
159        /// <param name="text">Rivitettävä teksti.</param>
160        /// <param name="softLineWidth">Leveys jonka jälkeen seuraava sana rivitetään seuraavalle riville.</param>
161        /// <param name="hardLineWidth">Leveys jonka jälkeen sana katkaistaan keskeltä.</param>
162        public string WrapText( string text, double softLineWidth, double hardLineWidth )
163        {
164            if ( softLineWidth <= 0 || hardLineWidth <= 0 )
165            {
166                throw new ArgumentException( "Width must be positive." );
167            }
168
169            StringBuilder src = new StringBuilder( text );
170            StringBuilder word = new StringBuilder();
171            StringBuilder line = new StringBuilder();
172            StringBuilder dest = new StringBuilder();
173            double lineWidth = 0;
174
175            while ( src.Length > 0 || word.Length > 0 )
176            {
177                if (word.Length == 0)
178                    src.TakeFirstWord( word );
179
180                var wordWidth = XnaFont.MeasureString( word ).X;
181
182                if ( lineWidth + wordWidth > hardLineWidth )
183                {
184                    int wi = FindWrapIndex( word, hardLineWidth - lineWidth, false );
185                    word.PutTo( line, 0, wi + 1 );
186                    appendLine( dest, line );
187                    lineWidth = 0;
188                }
189                else if ( lineWidth + wordWidth > softLineWidth )
190                {
191                    appendLine( dest, line );
192                    word.PutTo( line );
193                    lineWidth = 0;
194                }
195                else
196                {
197                    word.PutTo( line );
198                    lineWidth += wordWidth;
199                }
200            }
201
202            if ( line.Length > 0 )
203                appendLine( dest, line );
204
205            return dest.ToString();
206        }
207
208        /// <summary>
209        /// Etsii katkaisuindeksin merkkijonolle merkki kerrallaan.
210        /// Välilyönneillä ei ole erikoisasemaaa.
211        /// </summary>
212        /// <param name="text">Merkkijono</param>
213        /// <param name="maxWidth">Maksimileveys pikseleinä</param>
214        /// <param name="fromRight">Oikealta vasemmalle (oletus vasemmalta oikealle)</param>
215        /// <returns>Katkaisukohdan indeksi</returns>
216        private int FindWrapIndex( StringBuilder text, double maxWidth, bool fromRight )
217        {
218            double currentWidth = -XnaFont.Spacing;
219            int i = fromRight ? text.Length - 1 : 0;
220            int step = fromRight ? -1 : 1;
221
222            //for ( int i = 0; i < text.Length; i++ )
223            while ( ( fromRight && i >= 0 ) || ( !fromRight && i < text.Length ) )
224            {
225                currentWidth += XnaFont.Spacing + GetCharacterSize( text[i] ).X;
226                if ( currentWidth >= maxWidth ) return i;
227                i += step;
228            }
229
230            return fromRight ? -1 : text.Length;
231        }
232    }
233}
Note: See TracBrowser for help on using the repository browser.