2007-01-02 Mike Kestner <mkestner@novell.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / TextRenderer.cs
1 //
2 // TextRenderer.cs
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Copyright (c) 2006 Novell, Inc.
24 //
25 // Authors:
26 //      Jonathan Pobst (monkey@jpobst.com)
27 //
28
29 #if NET_2_0
30 using System.Drawing;
31 using System.Runtime.InteropServices;
32 using System.Text;
33 using System.Drawing.Text;
34
35 namespace System.Windows.Forms
36 {
37         public sealed class TextRenderer
38         {
39                 private TextRenderer ()
40                 {
41                 }
42                 
43                 #region Public Methods
44                 [MonoTODO("This should be correct for Windows, other platforms need a more accurate fallback method than the one provided")]
45                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags)
46                 {
47                         if (text == null || text.Length == 0)
48                                 return;
49                                 
50                         if (Environment.OSVersion.Platform == PlatformID.Win32NT || Environment.OSVersion.Platform == PlatformID.Win32Windows) {
51                                 Rectangle new_bounds = bounds;
52                                 new_bounds.Offset ((int)(dc as Graphics).Transform.OffsetX + 0, (int)(dc as Graphics).Transform.OffsetY + 0);
53                                 IntPtr hdc = dc.GetHdc ();
54
55                                 SetTextColor (hdc, ColorTranslator.ToWin32 (foreColor));
56                                 SetBkMode (hdc, 1);     //1-Transparent, 2-Opaque
57
58                                 VisualStyles.UXTheme.RECT r = VisualStyles.UXTheme.RECT.FromRectangle (new_bounds);
59
60                                 if (font != null)
61                                         SelectObject (hdc, font.ToHfont ());
62
63                                 DrawText (hdc, text, text.Length, ref r, (int)flags);
64                                 dc.ReleaseHdc ();
65                         }
66                         else {
67                                 Graphics g;
68
69                                 if (dc is Graphics)
70                                         g = (Graphics)dc;
71                                 else
72                                         g = Graphics.FromHdc (dc.GetHdc ());
73
74                                 StringFormat sf = FlagsToStringFormat (flags);
75
76                                 using (Brush b = new SolidBrush (foreColor))
77                                         g.DrawString (text, font, b, bounds, sf);
78
79                                 if (!(dc is Graphics)) {
80                                         g.Dispose ();
81                                         dc.ReleaseHdc ();
82                                 }
83                         }
84                 }
85
86                 [MonoTODO ("This should be correct for Windows, other platforms need a more accurate fallback method than the one provided")]
87                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags)
88                 {
89                         if (Environment.OSVersion.Platform == PlatformID.Win32NT || Environment.OSVersion.Platform == PlatformID.Win32Windows) {
90                                 IntPtr hdc = dc.GetHdc ();
91
92                                 SetTextColor (hdc, ColorTranslator.ToWin32 (foreColor));
93                                 SetBkMode (hdc, 1);     //1-Transparent, 2-Opaque
94
95                                 Size sz = MeasureText(text, font);
96                                 
97                                 VisualStyles.UXTheme.RECT r = new System.Windows.Forms.VisualStyles.UXTheme.RECT(pt.X, pt.Y, pt.X + sz.Width, pt.Y + sz.Height);
98
99                                 if (font != null)
100                                         SelectObject (hdc, font.ToHfont ());
101
102                                 DrawText (hdc, text, text.Length, ref r, (int)flags);
103                                 dc.ReleaseHdc ();
104                         }
105                         else {
106                                 Graphics g;
107
108                                 if (dc is Graphics)
109                                         g = (Graphics)dc;
110                                 else
111                                         g = Graphics.FromHdc (dc.GetHdc ());
112
113                                 StringFormat sf = FlagsToStringFormat (flags);
114
115                                 using (Brush b = new SolidBrush (foreColor))
116                                         g.DrawString (text, font, b, pt, sf);
117
118                                 if (!(dc is Graphics)) {
119                                         g.Dispose ();
120                                         dc.ReleaseHdc ();
121                                 }
122                         }
123                 }
124
125                 [MonoTODO ("This should be correct for Windows, other platforms need a more accurate fallback method than the one provided")]
126                 public static Size MeasureText (string text, Font font)
127                 {
128                         if (Environment.OSVersion.Platform == PlatformID.Win32NT || Environment.OSVersion.Platform == PlatformID.Win32Windows) {
129                                 Bitmap b = new Bitmap (5, 5);
130                                 Graphics g = Graphics.FromImage (b);
131                                 
132                                 IntPtr hdc = g.GetHdc ();
133
134                                 if (font != null)
135                                         SelectObject (hdc, font.ToHfont ());
136                                         
137                                 VisualStyles.UXTheme.SIZE text_size = new System.Windows.Forms.VisualStyles.UXTheme.SIZE();
138
139                                 GetTextExtentPoint32 (hdc, text, text.Length, out text_size);
140                                 
141                                 g.ReleaseHdc();
142                                 
143                                 Size retval = text_size.ToSize();
144                                 //retval.Height += 4;
145                                 if (retval.Width > 0) retval.Width += 6;
146                                 return retval;
147                         }
148                         else {
149                                 Bitmap b = new Bitmap (5, 5);
150                                 Graphics g = Graphics.FromImage (b);
151
152                                 Size retval = g.MeasureString(text,font).ToSize();
153                                 if (retval.Width > 0) retval.Width += 6;
154                                 return retval;  
155                         }
156                 }
157
158                 [MonoTODO ("This should be correct for Windows, other platforms need a more accurate fallback method than the one provided")]
159                 public static Size MeasureText (string text, Font font, Size proposedSize, TextFormatFlags flags)
160                 {
161                         if (Environment.OSVersion.Platform == PlatformID.Win32NT || Environment.OSVersion.Platform == PlatformID.Win32Windows) {
162                                 if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix)
163                                 {
164                                         text = text.Replace ("&", "");
165                                 }
166                                 
167                                 Bitmap b = new Bitmap (5, 5);
168                                 Graphics g = Graphics.FromImage (b);
169
170                                 IntPtr hdc = g.GetHdc ();
171
172                                 if (font != null)
173                                         SelectObject (hdc, font.ToHfont ());
174
175                                 VisualStyles.UXTheme.SIZE text_size = new System.Windows.Forms.VisualStyles.UXTheme.SIZE ();
176
177                                 GetTextExtentPoint32 (hdc, text, text.Length, out text_size);
178
179                                 g.ReleaseHdc ();
180
181                                 Size retval = text_size.ToSize ();
182                                 //retval.Height += 4;
183                                 if (retval.Width > 0) retval.Width += 6;
184                                 return retval;
185                         }
186                         else {
187                                 Bitmap b = new Bitmap (5, 5);
188                                 Graphics g = Graphics.FromImage (b);
189
190                                 Size retval = g.MeasureString (text, font).ToSize ();
191                                 if (retval.Width > 0) retval.Width += 6;
192                                 return retval;
193                         }
194                 }
195                 #endregion
196
197                 #region Private Methods
198                 private static StringFormat FlagsToStringFormat (TextFormatFlags flags)
199                 {
200                         StringFormat sf = new StringFormat ();
201
202                         // Translation table: http://msdn.microsoft.com/msdnmag/issues/06/03/TextRendering/default.aspx?fig=true#fig4
203
204                         // Horizontal Alignment
205                         if ((flags & TextFormatFlags.HorizontalCenter) == TextFormatFlags.HorizontalCenter)
206                                 sf.Alignment = StringAlignment.Center;
207                         else if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right)
208                                 sf.Alignment = StringAlignment.Far;
209                         else
210                                 sf.Alignment = StringAlignment.Near;
211
212                         // Vertical Alignment
213                         if ((flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
214                                 sf.LineAlignment = StringAlignment.Far;
215                         else if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter)
216                                 sf.LineAlignment = StringAlignment.Center;
217                         else
218                                 sf.LineAlignment = StringAlignment.Near;
219
220                         // Ellipsis
221                         if ((flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis)
222                                 sf.Trimming = StringTrimming.EllipsisCharacter;
223                         else if ((flags & TextFormatFlags.PathEllipsis) == TextFormatFlags.PathEllipsis)
224                                 sf.Trimming = StringTrimming.EllipsisPath;
225                         else if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis)
226                                 sf.Trimming = StringTrimming.EllipsisWord;
227                         else
228                                 sf.Trimming = StringTrimming.Character;
229
230                         // Hotkey Prefix
231                         if ((flags & TextFormatFlags.NoPrefix) == TextFormatFlags.NoPrefix)
232                                 sf.HotkeyPrefix = HotkeyPrefix.None;
233                         else if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix)
234                                 sf.HotkeyPrefix = HotkeyPrefix.Hide;
235                         else
236                                 sf.HotkeyPrefix = HotkeyPrefix.Show;
237
238                         // Text Padding
239                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding)
240                                 sf.FormatFlags |= StringFormatFlags.FitBlackBox;
241
242                         // Text Wrapping
243                         if ((flags & TextFormatFlags.SingleLine) == TextFormatFlags.SingleLine)
244                                 sf.FormatFlags |= StringFormatFlags.NoWrap;
245                         else if ((flags & TextFormatFlags.TextBoxControl) == TextFormatFlags.TextBoxControl)
246                                 sf.FormatFlags |= StringFormatFlags.LineLimit;
247
248                         // Other Flags
249                         if ((flags & TextFormatFlags.RightToLeft) == TextFormatFlags.RightToLeft)
250                                 sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
251                         if ((flags & TextFormatFlags.NoClipping) == TextFormatFlags.NoClipping)
252                                 sf.FormatFlags |= StringFormatFlags.NoClip;
253                         sf.FormatFlags |= StringFormatFlags.NoClip;
254
255                         return sf;
256                 }
257                 #endregion
258
259                 #region DllImports (Windows)
260                 [DllImport ("user32", CharSet = CharSet.Unicode)]
261                 static extern int DrawText (IntPtr hdc, string lpStr, int nCount, ref VisualStyles.UXTheme.RECT lpRect, int wFormat);
262
263                 [DllImport ("gdi32")]
264                 static extern int SetTextColor (IntPtr hdc, int crColor);
265
266                 [DllImport ("gdi32")]
267                 private extern static IntPtr SelectObject (IntPtr hDC, IntPtr hObject);
268
269                 //[DllImport ("gdi32")]
270                 //static extern int SetBkColor (IntPtr hdc, int crColor);
271
272                 [DllImport ("gdi32")]
273                 static extern int SetBkMode (IntPtr hdc, int iBkMode);
274
275                 //[DllImport ("gdi32")]
276                 //static extern bool GetTextExtentExPoint (IntPtr hdc, string lpszStr, int cchString, int nMaxExtent, IntPtr lpnFit, IntPtr alpDx, out VisualStyles.UXTheme.SIZE lpSize);
277
278                 [DllImport ("gdi32")]
279                 static extern bool GetTextExtentPoint32 (IntPtr hdc, string lpString, int cbString, out VisualStyles.UXTheme.SIZE lpSize);
280                 #endregion
281         }
282
283 }
284 #endif