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