* TabControl.cs: Show the tooltip depending on the value
[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 // This has become a monster class for all things text measuring and drawing.
30 //
31 // The public API is MeasureText/DrawText, which uses GDI on Win32, and
32 // GDI+ on other platforms.
33 //
34 // There is an internal API MeasureTextInternal/DrawTextInternal, which allows
35 // you to pass a flag of whether to use GDI or GDI+.  This is used mainly for
36 // controls that have the UseCompatibleTextRendering flag.
37 //
38 // There are also thread-safe versions of MeasureString/MeasureCharacterRanges
39 // for things that want to measure strings without having a Graphics object.
40
41 using System.Drawing;
42 using System.Runtime.InteropServices;
43 using System.Text;
44 using System.Drawing.Text;
45
46 namespace System.Windows.Forms
47 {
48 #if NET_2_0
49         public sealed 
50 #endif
51         class TextRenderer
52         {
53                 private TextRenderer ()
54                 {
55                 }
56
57                 #region Public Methods
58 #if NET_2_0
59                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor)
60                 {
61                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, false);
62                 }
63
64                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor)
65                 {
66                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
67                 }
68
69                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor)
70                 {
71                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, false);
72                 }
73 #endif
74
75 #if NET_2_0
76                 public
77 #else
78                 internal
79 #endif
80                 static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags)
81                 {
82                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, false);
83                 }
84
85 #if NET_2_0
86                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor)
87                 {
88                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, false);
89                 }
90 #endif
91
92                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags)
93                 {
94                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, false);
95                 }
96
97 #if NET_2_0
98                 public static void DrawText (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags)
99                 {
100                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, flags, false);
101                 }
102
103                 public static void DrawText (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags)
104                 {
105                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, flags, false);
106                 }
107 #endif
108
109 #if NET_2_0
110                 public
111 #else
112                 internal
113 #endif
114                 static Size MeasureText (string text, Font font)
115                 {
116                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, false);
117                 }
118
119 #if NET_2_0
120                 public static Size MeasureText (IDeviceContext dc, string text, Font font)
121                 {
122                         return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, false);
123                 }
124
125                 public static Size MeasureText (string text, Font font, Size proposedSize)
126                 {
127                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, false);
128                 }
129
130                 public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize)
131                 {
132                         return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, false);
133                 }
134
135                 public static Size MeasureText (string text, Font font, Size proposedSize, TextFormatFlags flags)
136                 {
137                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, false);
138                 }
139
140                 public static Size MeasureText (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags)
141                 {
142                         return MeasureTextInternal (dc, text, font, proposedSize, flags, false);
143                 }
144 #endif
145                 #endregion
146
147                 #region Internal Methods That Do Stuff
148 #if NET_2_0
149                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
150 #else
151                 internal static void DrawTextInternal (Graphics dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
152 #endif
153                 {
154                         if (dc == null)
155                                 throw new ArgumentNullException ("dc");
156
157                         if (text == null || text.Length == 0)
158                                 return;
159
160                         // We use MS GDI API's unless told not to, or we aren't on Windows
161                         if (!useDrawString && !XplatUI.RunningOnUnix) {
162                                 if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter || (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
163                                         flags |= TextFormatFlags.SingleLine;
164
165                                 // Calculate the text bounds (there is often padding added)
166                                 Rectangle new_bounds = PadRectangle (bounds, flags);
167                                 new_bounds.Offset ((int)(dc as Graphics).Transform.OffsetX, (int)(dc as Graphics).Transform.OffsetY);
168
169                                 IntPtr hdc = IntPtr.Zero;
170                                 bool clear_clip_region = false;
171                                 
172                                 // If we need to use the graphics clipping region, add it to our hdc
173                                 if ((flags & TextFormatFlags.PreserveGraphicsClipping) == TextFormatFlags.PreserveGraphicsClipping) {
174                                         Graphics graphics = (Graphics)dc;
175                                         Region clip_region = graphics.Clip;
176                                         
177                                         if (!clip_region.IsInfinite (graphics)) {
178                                                 IntPtr hrgn = clip_region.GetHrgn (graphics);
179                                                 hdc = dc.GetHdc ();
180                                                 SelectClipRgn (hdc, hrgn);
181                                                 DeleteObject (hrgn);
182                                                 
183                                                 clear_clip_region = true;
184                                         }
185                                 }
186                                 
187                                 if (hdc == IntPtr.Zero)
188                                         hdc = dc.GetHdc ();
189                                         
190                                 // Set the fore color
191                                 if (foreColor != Color.Empty)
192                                         SetTextColor (hdc, ColorTranslator.ToWin32 (foreColor));
193
194                                 // Set the back color
195                                 if (backColor != Color.Transparent && backColor != Color.Empty) {
196                                         SetBkMode (hdc, 2);     //1-Transparent, 2-Opaque
197                                         SetBkColor (hdc, ColorTranslator.ToWin32 (backColor));
198                                 }
199                                 else {
200                                         SetBkMode (hdc, 1);     //1-Transparent, 2-Opaque
201                                 }
202
203                                 XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new_bounds);
204
205                                 IntPtr prevobj;
206
207                                 if (font != null) {
208                                         prevobj = SelectObject (hdc, font.ToHfont ());
209                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
210                                         prevobj = SelectObject (hdc, prevobj);
211                                         DeleteObject (prevobj);
212                                 }
213                                 else {
214                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
215                                 }
216
217                                 if (clear_clip_region)
218                                         SelectClipRgn (hdc, IntPtr.Zero);
219
220 #if NET_2_0
221                                 dc.ReleaseHdc ();
222 #else
223                                 dc.ReleaseHdc (hdc);
224 #endif
225                         }
226                         // Use Graphics.DrawString as a fallback method
227                         else {
228                                 Graphics g;
229                                 IntPtr hdc = IntPtr.Zero;
230                                 
231                                 if (dc is Graphics)
232                                         g = (Graphics)dc;
233                                 else {
234                                         hdc = dc.GetHdc ();
235                                         g = Graphics.FromHdc (hdc);
236                                 }
237
238                                 StringFormat sf = FlagsToStringFormat (flags);
239
240                                 Rectangle new_bounds = PadDrawStringRectangle (bounds, flags);
241
242                                 g.DrawString (text, font, ThemeEngine.Current.ResPool.GetSolidBrush (foreColor), new_bounds, sf);
243
244                                 if (!(dc is Graphics)) {
245                                         g.Dispose ();
246 #if NET_2_0
247                                         dc.ReleaseHdc ();
248 #else
249                                         if (hdc != IntPtr.Zero) dc.ReleaseHdc (hdc);
250 #endif
251                                 }
252                         }
253                 }
254
255 #if NET_2_0
256                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
257 #else
258                 internal static Size MeasureTextInternal (Graphics dc, string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
259 #endif
260                 {
261                         if (!useMeasureString && !XplatUI.RunningOnUnix) {
262                                 // Tell DrawText to calculate size instead of draw
263                                 flags |= (TextFormatFlags)1024;         // DT_CALCRECT
264
265                                 IntPtr hdc = dc.GetHdc ();
266
267                                 XplatUIWin32.RECT r = XplatUIWin32.RECT.FromRectangle (new Rectangle (Point.Empty, proposedSize));
268
269                                 IntPtr prevobj;
270
271                                 if (font != null) {
272                                         prevobj = SelectObject (hdc, font.ToHfont ());
273                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
274                                         prevobj = SelectObject (hdc, prevobj);
275                                         DeleteObject (prevobj);
276                                 }
277                                 else {
278                                         Win32DrawText (hdc, text, text.Length, ref r, (int)flags);
279                                 }
280
281 #if NET_2_0
282                                 dc.ReleaseHdc ();
283 #else
284                                 dc.ReleaseHdc (hdc);
285 #endif
286
287                                 // Really, I am just making something up here, which as far as I can tell, MS
288                                 // just makes something up as well.  This will require lots of tweaking to match MS.  :(
289                                 Size retval = r.ToRectangle ().Size;
290
291                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0) {
292                                         retval.Width += 6;
293                                         retval.Width += (int)retval.Height / 8;
294                                 }
295
296                                 return retval;
297                         }
298                         else {
299                         StringFormat sf = FlagsToStringFormat (flags);
300
301                                 Size retval;
302                                 
303                                 if (dc is Graphics)
304                                         retval = (dc as Graphics).MeasureString (text, font, proposedSize.Width == 0 ? Int32.MaxValue : proposedSize.Width, sf).ToSize ();
305                                 else
306                                         retval = TextRenderer.MeasureString (text, font, proposedSize.Width == 0 ? Int32.MaxValue : proposedSize.Width, sf).ToSize ();
307
308                                 if (retval.Width > 0 && (flags & TextFormatFlags.NoPadding) == 0)
309                                         retval.Width += 9;
310
311                                 return retval;
312                         }
313                 }
314                 #endregion
315
316 #region Internal Methods That Are Just Overloads
317 #if NET_2_0
318                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, bool useDrawString)
319                 {
320                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, TextFormatFlags.Default, useDrawString);
321                 }
322
323                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, bool useDrawString)
324                 {
325                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
326                 }
327
328                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, bool useDrawString)
329                 {
330                         DrawTextInternal (dc, text, font, pt, foreColor, backColor, TextFormatFlags.Default, useDrawString);
331                 }
332
333                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, TextFormatFlags flags, bool useDrawString)
334                 {
335                         DrawTextInternal (dc, text, font, pt, foreColor, Color.Transparent, flags, useDrawString);
336                 }
337
338                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, Color backColor, bool useDrawString)
339                 {
340                         DrawTextInternal (dc, text, font, bounds, foreColor, backColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter, useDrawString);
341                 }
342
343                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
344 #else
345                 internal static void DrawTextInternal (Graphics dc, string text, Font font, Rectangle bounds, Color foreColor, TextFormatFlags flags, bool useDrawString)
346 #endif
347                 {
348                         DrawTextInternal (dc, text, font, bounds, foreColor, Color.Transparent, flags, useDrawString);
349                 }
350
351                 internal static Size MeasureTextInternal (string text, Font font, bool useMeasureString)
352                 {
353                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
354                 }
355
356                 internal static void DrawTextInternal (IDeviceContext dc, string text, Font font, Point pt, Color foreColor, Color backColor, TextFormatFlags flags, bool useDrawString)
357                 {
358                         Size sz = MeasureTextInternal (dc, text, font, useDrawString);
359                         DrawTextInternal (dc, text, font, new Rectangle (pt, sz), foreColor, backColor, flags, useDrawString);
360                 }
361
362                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, bool useMeasureString)
363                 {
364                         return MeasureTextInternal (dc, text, font, Size.Empty, TextFormatFlags.Default, useMeasureString);
365                 }
366
367 #if NET_2_0
368                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, bool useMeasureString)
369                 {
370                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
371                 }
372
373                 internal static Size MeasureTextInternal (IDeviceContext dc, string text, Font font, Size proposedSize, bool useMeasureString)
374                 {
375                         return MeasureTextInternal (dc, text, font, proposedSize, TextFormatFlags.Default, useMeasureString);
376                 }
377
378 #endif
379                 internal static Size MeasureTextInternal (string text, Font font, Size proposedSize, TextFormatFlags flags, bool useMeasureString)
380                 {
381                         return MeasureTextInternal (Hwnd.GraphicsContext, text, font, proposedSize, flags, useMeasureString);
382                 }
383 #endregion
384
385                 #region Thread-Safe Static Graphics Methods
386                 internal static SizeF MeasureString (string text, Font font)
387                 {
388                         return Hwnd.GraphicsContext.MeasureString (text, font);
389                 }
390
391                 internal static SizeF MeasureString (string text, Font font, int width)
392                 {
393                         return Hwnd.GraphicsContext.MeasureString (text, font, width);
394                 }
395
396                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea)
397                 {
398                         return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea);
399                 }
400
401                 internal static SizeF MeasureString (string text, Font font, int width, StringFormat format)
402                 {
403                         return Hwnd.GraphicsContext.MeasureString (text, font, width, format);
404                 }
405
406                 internal static SizeF MeasureString (string text, Font font, PointF origin, StringFormat stringFormat)
407                 {
408                         return Hwnd.GraphicsContext.MeasureString (text, font, origin, stringFormat);
409                 }
410
411                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat)
412                 {
413                         return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat);
414                 }
415
416                 internal static SizeF MeasureString (string text, Font font, SizeF layoutArea, StringFormat stringFormat, out int charactersFitted, out int linesFilled)
417                 {
418                         return Hwnd.GraphicsContext.MeasureString (text, font, layoutArea, stringFormat, out charactersFitted, out linesFilled);
419                 }
420
421                 internal static Region[] MeasureCharacterRanges (string text, Font font, RectangleF layoutRect, StringFormat stringFormat)
422                 {
423                         return Hwnd.GraphicsContext.MeasureCharacterRanges (text, font, layoutRect, stringFormat);
424                 }
425                 
426                 internal static SizeF GetDpi ()
427                 {
428                         return new SizeF (Hwnd.GraphicsContext.DpiX, Hwnd.GraphicsContext.DpiY);
429                 }
430                 #endregion
431                 
432 #region Private Methods
433                 private static StringFormat FlagsToStringFormat (TextFormatFlags flags)
434                 {
435                         StringFormat sf = new StringFormat ();
436
437                         // Translation table: http://msdn.microsoft.com/msdnmag/issues/06/03/TextRendering/default.aspx?fig=true#fig4
438
439                         // Horizontal Alignment
440                         if ((flags & TextFormatFlags.HorizontalCenter) == TextFormatFlags.HorizontalCenter)
441                                 sf.Alignment = StringAlignment.Center;
442                         else if ((flags & TextFormatFlags.Right) == TextFormatFlags.Right)
443                                 sf.Alignment = StringAlignment.Far;
444                         else
445                                 sf.Alignment = StringAlignment.Near;
446
447                         // Vertical Alignment
448                         if ((flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom)
449                                 sf.LineAlignment = StringAlignment.Far;
450                         else if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter)
451                                 sf.LineAlignment = StringAlignment.Center;
452                         else
453                                 sf.LineAlignment = StringAlignment.Near;
454
455                         // Ellipsis
456                         if ((flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis)
457                                 sf.Trimming = StringTrimming.EllipsisCharacter;
458                         else if ((flags & TextFormatFlags.PathEllipsis) == TextFormatFlags.PathEllipsis)
459                                 sf.Trimming = StringTrimming.EllipsisPath;
460                         else if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis)
461                                 sf.Trimming = StringTrimming.EllipsisWord;
462                         else
463                                 sf.Trimming = StringTrimming.Character;
464
465                         // Hotkey Prefix
466                         if ((flags & TextFormatFlags.NoPrefix) == TextFormatFlags.NoPrefix)
467                                 sf.HotkeyPrefix = HotkeyPrefix.None;
468                         else if ((flags & TextFormatFlags.HidePrefix) == TextFormatFlags.HidePrefix)
469                                 sf.HotkeyPrefix = HotkeyPrefix.Hide;
470                         else
471                                 sf.HotkeyPrefix = HotkeyPrefix.Show;
472
473                         // Text Padding
474                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding)
475                                 sf.FormatFlags |= StringFormatFlags.FitBlackBox;
476
477                         // Text Wrapping
478                         if ((flags & TextFormatFlags.SingleLine) == TextFormatFlags.SingleLine)
479                                 sf.FormatFlags |= StringFormatFlags.NoWrap;
480                         else if ((flags & TextFormatFlags.TextBoxControl) == TextFormatFlags.TextBoxControl)
481                                 sf.FormatFlags |= StringFormatFlags.LineLimit;
482
483                         // Other Flags
484                         //if ((flags & TextFormatFlags.RightToLeft) == TextFormatFlags.RightToLeft)
485                         //        sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
486                         if ((flags & TextFormatFlags.NoClipping) == TextFormatFlags.NoClipping)
487                                 sf.FormatFlags |= StringFormatFlags.NoClip;
488
489                         return sf;
490                 }
491
492                 private static Rectangle PadRectangle (Rectangle r, TextFormatFlags flags)
493                 {
494                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
495                                 r.X += 3;
496                                 r.Width -= 3;
497                         }
498                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
499                                 r.Width -= 4;
500                         }
501                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
502                                 r.X += 2;
503                                 r.Width -= 2;
504                         }
505                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
506                                 r.Width -= 4;
507                         }
508                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
509                                 r.Y += 1;
510                         }
511
512                         return r;
513                 }
514
515                 private static Rectangle PadDrawStringRectangle (Rectangle r, TextFormatFlags flags)
516                 {
517                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == 0 && (flags & TextFormatFlags.HorizontalCenter) == 0) {
518                                 r.X += 1;
519                                 r.Width -= 1;
520                         }
521                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Right) == TextFormatFlags.Right) {
522                                 r.Width -= 4;
523                         }
524                         if ((flags & TextFormatFlags.NoPadding) == TextFormatFlags.NoPadding) {
525                                 r.X -= 2;
526                         }
527                         if ((flags & TextFormatFlags.NoPadding) == 0 && (flags & TextFormatFlags.Bottom) == TextFormatFlags.Bottom) {
528                                 r.Y += 1;
529                         }
530                         if ((flags & TextFormatFlags.LeftAndRightPadding) == TextFormatFlags.LeftAndRightPadding) {
531                                 r.X += 2;
532                                 r.Width -= 2;
533                         }
534                         if ((flags & TextFormatFlags.WordEllipsis) == TextFormatFlags.WordEllipsis || (flags & TextFormatFlags.EndEllipsis) == TextFormatFlags.EndEllipsis || (flags & TextFormatFlags.WordBreak) == TextFormatFlags.WordBreak) {
535                                 r.Width -= 4;
536                         }
537                         if ((flags & TextFormatFlags.VerticalCenter) == TextFormatFlags.VerticalCenter) {
538                                 r.Y += 1;
539                         }
540
541                         return r;
542                 }
543 #endregion
544
545 #region DllImports (Windows)
546                 [DllImport ("user32", CharSet = CharSet.Unicode, EntryPoint = "DrawText")]
547                 static extern int Win32DrawText (IntPtr hdc, string lpStr, int nCount, ref XplatUIWin32.RECT lpRect, int wFormat);
548
549                 [DllImport ("gdi32")]
550                 static extern int SetTextColor (IntPtr hdc, int crColor);
551
552                 [DllImport ("gdi32")]
553                 static extern IntPtr SelectObject (IntPtr hDC, IntPtr hObject);
554
555                 [DllImport ("gdi32")]
556                 static extern int SetBkColor (IntPtr hdc, int crColor);
557
558                 [DllImport ("gdi32")]
559                 static extern int SetBkMode (IntPtr hdc, int iBkMode);
560
561                 [DllImport ("gdi32")]
562                 static extern bool DeleteObject (IntPtr objectHandle);
563
564                 [DllImport("gdi32")]
565                 static extern bool SelectClipRgn(IntPtr hdc, IntPtr hrgn);
566 #endregion
567         }
568 }