added a way to create fonts with specified pixel size
[wxWidgets.git] / src / common / fontcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/fontcmn.cpp
3 // Purpose: implementation of wxFontBase methods
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 20.09.99
7 // RCS-ID: $Id$
8 // Copyright: (c) wxWidgets team
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "fontbase.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/font.h"
33 #include "wx/intl.h"
34 #endif // WX_PRECOMP
35
36 #include "wx/gdicmn.h"
37
38 #if defined(__WXMSW__)
39 #include "wx/msw/private.h" // includes windows.h for LOGFONT
40 #include "wx/msw/winundef.h"
41 #endif
42
43 #include "wx/fontutil.h" // for wxNativeFontInfo
44 #include "wx/fontmap.h"
45
46 #include "wx/tokenzr.h"
47
48 // ============================================================================
49 // implementation
50 // ============================================================================
51
52 // ----------------------------------------------------------------------------
53 // helper functions
54 // ----------------------------------------------------------------------------
55
56 static void AdjustFontSize(wxFont font, wxDC& dc, const wxSize& pixelSize)
57 {
58 int currentSize = font.GetPointSize();
59 int largestGood;
60 int smallestBad;
61
62 bool initialGoodFound = false;
63 bool initialBadFound = false;
64
65 while (currentSize > 0)
66 {
67 dc.SetFont(font);
68
69 // if currentSize (in points) results in a font that is smaller
70 // than required by pixelSize it is considered a good size
71 if (dc.GetCharHeight() <= pixelSize.GetHeight() &&
72 (!pixelSize.GetWidth() ||
73 dc.GetCharWidth() <= pixelSize.GetWidth()))
74 {
75 largestGood = currentSize;
76 initialGoodFound = true;
77 }
78 else
79 {
80 smallestBad = currentSize;
81 initialBadFound = true;
82 }
83 if (!initialGoodFound)
84 {
85 currentSize /= 2;
86 }
87 else if (!initialBadFound)
88 {
89 currentSize *= 2;
90 }
91 else
92 {
93 int distance = smallestBad - largestGood;
94 if (distance == 1)
95 break;
96
97 currentSize = largestGood + distance / 2;
98 }
99
100 font.SetPointSize(currentSize);
101 }
102
103 if (currentSize != largestGood)
104 font.SetPointSize(largestGood);
105 }
106
107 // ----------------------------------------------------------------------------
108 // wxFontBase
109 // ----------------------------------------------------------------------------
110
111 wxFontEncoding wxFontBase::ms_encodingDefault = wxFONTENCODING_SYSTEM;
112
113 /* static */
114 void wxFontBase::SetDefaultEncoding(wxFontEncoding encoding)
115 {
116 // GetDefaultEncoding() should return something != wxFONTENCODING_DEFAULT
117 // and, besides, using this value here doesn't make any sense
118 wxCHECK_RET( encoding != wxFONTENCODING_DEFAULT,
119 _T("can't set default encoding to wxFONTENCODING_DEFAULT") );
120
121 ms_encodingDefault = encoding;
122 }
123
124 wxFontBase::~wxFontBase()
125 {
126 // this destructor is required for Darwin
127 }
128
129 /* static */
130 wxFont *wxFontBase::New(int size,
131 int family,
132 int style,
133 int weight,
134 bool underlined,
135 const wxString& face,
136 wxFontEncoding encoding)
137 {
138 return new wxFont(size, family, style, weight, underlined, face, encoding);
139 }
140
141 static inline int flags2Style(int flags)
142 {
143 return flags & wxFONTFLAG_ITALIC
144 ? wxFONTSTYLE_ITALIC
145 : flags & wxFONTFLAG_SLANT
146 ? wxFONTSTYLE_SLANT
147 : wxFONTSTYLE_NORMAL;
148 }
149
150 static inline int flags2Weight(int flags)
151 {
152 return flags & wxFONTFLAG_LIGHT
153 ? wxFONTWEIGHT_LIGHT
154 : flags & wxFONTFLAG_BOLD
155 ? wxFONTWEIGHT_BOLD
156 : wxFONTWEIGHT_NORMAL;
157 }
158
159 static inline bool flags2Underlined(int flags)
160 {
161 return (flags & wxFONTFLAG_UNDERLINED) != 0;
162 }
163
164 /* static */
165 wxFont *wxFontBase::New(int pointSize,
166 wxFontFamily family,
167 int flags,
168 const wxString& face,
169 wxFontEncoding encoding)
170 {
171 return New(pointSize, family, flags2Style(flags), flags2Weight(flags),
172 flags2Underlined(flags), face, encoding);
173 }
174
175 /* static */
176 wxFont *wxFontBase::New(const wxSize& pixelSize,
177 int family,
178 int style,
179 int weight,
180 bool underlined,
181 const wxString& face,
182 wxFontEncoding encoding)
183 {
184 #if defined(__WXMSW__)
185 return new wxFont(pixelSize, family, style, weight, underlined,
186 face, encoding);
187 #else
188 wxFont * ret = New(10, family, style, weight, underlined, face, encoding);
189 wxScreenDC dc;
190 ret->AdjustFontSize(*(wxFont *)this, dc, pixelSize);
191 return ret;
192 #endif
193 }
194
195 /* static */
196 wxFont *wxFontBase::New(const wxSize& pixelSize,
197 wxFontFamily family,
198 int flags,
199 const wxString& face,
200 wxFontEncoding encoding)
201 {
202 return New(pixelSize, family, flags2Style(flags), flags2Weight(flags),
203 flags2Underlined(flags), face, encoding);
204 }
205
206 wxSize wxFontBase::GetPixelSize() const
207 {
208 wxScreenDC dc;
209 dc.SetFont(*(wxFont *)this);
210 return wxSize(dc.GetCharWidth(), dc.GetCharHeight());
211 }
212
213 bool wxFontBase::IsUsingSizeInPixels() const
214 {
215 return false;
216 }
217
218 void wxFontBase::SetPixelSize( const wxSize& pixelSize )
219 {
220 wxScreenDC dc;
221 AdjustFontSize(*(wxFont *)this, dc, pixelSize);
222 }
223
224 /* static */
225 wxFont *wxFontBase::New(const wxNativeFontInfo& info)
226 {
227 return new wxFont(info);
228 }
229
230 /* static */
231 wxFont *wxFontBase::New(const wxString& strNativeFontDesc)
232 {
233 wxNativeFontInfo fontInfo;
234 if ( !fontInfo.FromString(strNativeFontDesc) )
235 return new wxFont(*wxNORMAL_FONT);
236
237 return New(fontInfo);
238 }
239
240 bool wxFontBase::IsFixedWidth() const
241 {
242 return GetFamily() == wxFONTFAMILY_TELETYPE;
243 }
244
245 void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info)
246 {
247 #ifdef wxNO_NATIVE_FONTINFO
248 SetPointSize(info.pointSize);
249 SetFamily(info.family);
250 SetStyle(info.style);
251 SetWeight(info.weight);
252 SetUnderlined(info.underlined);
253 SetFaceName(info.faceName);
254 SetEncoding(info.encoding);
255 #else
256 (void)info;
257 #endif
258 }
259
260 wxString wxFontBase::GetNativeFontInfoDesc() const
261 {
262 wxString fontDesc;
263 const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
264 if ( fontInfo )
265 {
266 fontDesc = fontInfo->ToString();
267 }
268
269 return fontDesc;
270 }
271
272 wxString wxFontBase::GetNativeFontInfoUserDesc() const
273 {
274 wxString fontDesc;
275 const wxNativeFontInfo *fontInfo = GetNativeFontInfo();
276 if ( fontInfo )
277 {
278 fontDesc = fontInfo->ToUserString();
279 }
280
281 return fontDesc;
282 }
283
284 void wxFontBase::SetNativeFontInfo(const wxString& info)
285 {
286 wxNativeFontInfo fontInfo;
287 if ( !info.empty() && fontInfo.FromString(info) )
288 {
289 SetNativeFontInfo(fontInfo);
290 }
291 }
292
293 void wxFontBase::SetNativeFontInfoUserDesc(const wxString& info)
294 {
295 wxNativeFontInfo fontInfo;
296 if ( !info.empty() && fontInfo.FromUserString(info) )
297 {
298 SetNativeFontInfo(fontInfo);
299 }
300 }
301
302 wxFont& wxFont::operator=(const wxFont& font)
303 {
304 if ( this != &font )
305 Ref(font);
306
307 return (wxFont &)*this;
308 }
309
310 bool wxFontBase::operator==(const wxFont& font) const
311 {
312 // either it is the same font, i.e. they share the same common data or they
313 // have different ref datas but still describe the same font
314 return GetFontData() == font.GetFontData() ||
315 (
316 Ok() == font.Ok() &&
317 GetPointSize() == font.GetPointSize() &&
318 GetFamily() == font.GetFamily() &&
319 GetStyle() == font.GetStyle() &&
320 GetWeight() == font.GetWeight() &&
321 GetUnderlined() == font.GetUnderlined() &&
322 GetFaceName() == font.GetFaceName() &&
323 GetEncoding() == font.GetEncoding()
324 );
325 }
326
327 bool wxFontBase::operator!=(const wxFont& font) const
328 {
329 return !(*this == font);
330 }
331
332 wxString wxFontBase::GetFamilyString() const
333 {
334 wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") );
335
336 switch ( GetFamily() )
337 {
338 case wxDECORATIVE: return wxT("wxDECORATIVE");
339 case wxROMAN: return wxT("wxROMAN");
340 case wxSCRIPT: return wxT("wxSCRIPT");
341 case wxSWISS: return wxT("wxSWISS");
342 case wxMODERN: return wxT("wxMODERN");
343 case wxTELETYPE: return wxT("wxTELETYPE");
344 default: return wxT("wxDEFAULT");
345 }
346 }
347
348 wxString wxFontBase::GetStyleString() const
349 {
350 wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") );
351
352 switch ( GetStyle() )
353 {
354 case wxNORMAL: return wxT("wxNORMAL");
355 case wxSLANT: return wxT("wxSLANT");
356 case wxITALIC: return wxT("wxITALIC");
357 default: return wxT("wxDEFAULT");
358 }
359 }
360
361 wxString wxFontBase::GetWeightString() const
362 {
363 wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") );
364
365 switch ( GetWeight() )
366 {
367 case wxNORMAL: return wxT("wxNORMAL");
368 case wxBOLD: return wxT("wxBOLD");
369 case wxLIGHT: return wxT("wxLIGHT");
370 default: return wxT("wxDEFAULT");
371 }
372 }
373
374 // ----------------------------------------------------------------------------
375 // wxNativeFontInfo
376 // ----------------------------------------------------------------------------
377
378 #ifdef wxNO_NATIVE_FONTINFO
379
380 // These are the generic forms of FromString()/ToString.
381 //
382 // convert to/from the string representation: format is
383 // version;pointsize;family;style;weight;underlined;facename;encoding
384
385 bool wxNativeFontInfo::FromString(const wxString& s)
386 {
387 long l;
388
389 wxStringTokenizer tokenizer(s, _T(";"));
390
391 wxString token = tokenizer.GetNextToken();
392 //
393 // Ignore the version for now
394 //
395
396 token = tokenizer.GetNextToken();
397 if ( !token.ToLong(&l) )
398 return false;
399 pointSize = (int)l;
400
401 token = tokenizer.GetNextToken();
402 if ( !token.ToLong(&l) )
403 return false;
404 family = (wxFontFamily)l;
405
406 token = tokenizer.GetNextToken();
407 if ( !token.ToLong(&l) )
408 return false;
409 style = (wxFontStyle)l;
410
411 token = tokenizer.GetNextToken();
412 if ( !token.ToLong(&l) )
413 return false;
414 weight = (wxFontWeight)l;
415
416 token = tokenizer.GetNextToken();
417 if ( !token.ToLong(&l) )
418 return false;
419 underlined = l != 0;
420
421 faceName = tokenizer.GetNextToken();
422
423 #ifndef __WXMAC__
424 if( !faceName )
425 return false;
426 #endif
427
428 token = tokenizer.GetNextToken();
429 if ( !token.ToLong(&l) )
430 return false;
431 encoding = (wxFontEncoding)l;
432
433 return true;
434 }
435
436 wxString wxNativeFontInfo::ToString() const
437 {
438 wxString s;
439
440 s.Printf(_T("%d;%d;%d;%d;%d;%d;%s;%d"),
441 0, // version
442 pointSize,
443 family,
444 (int)style,
445 (int)weight,
446 underlined,
447 faceName.GetData(),
448 (int)encoding);
449
450 return s;
451 }
452
453 void wxNativeFontInfo::Init()
454 {
455 pointSize = 0;
456 family = wxFONTFAMILY_DEFAULT;
457 style = wxFONTSTYLE_NORMAL;
458 weight = wxFONTWEIGHT_NORMAL;
459 underlined = false;
460 faceName.clear();
461 encoding = wxFONTENCODING_DEFAULT;
462 }
463
464 int wxNativeFontInfo::GetPointSize() const
465 {
466 return pointSize;
467 }
468
469 wxFontStyle wxNativeFontInfo::GetStyle() const
470 {
471 return style;
472 }
473
474 wxFontWeight wxNativeFontInfo::GetWeight() const
475 {
476 return weight;
477 }
478
479 bool wxNativeFontInfo::GetUnderlined() const
480 {
481 return underlined;
482 }
483
484 wxString wxNativeFontInfo::GetFaceName() const
485 {
486 return faceName;
487 }
488
489 wxFontFamily wxNativeFontInfo::GetFamily() const
490 {
491 return family;
492 }
493
494 wxFontEncoding wxNativeFontInfo::GetEncoding() const
495 {
496 return encoding;
497 }
498
499 void wxNativeFontInfo::SetPointSize(int pointsize)
500 {
501 pointSize = pointsize;
502 }
503
504 void wxNativeFontInfo::SetStyle(wxFontStyle style_)
505 {
506 style = style_;
507 }
508
509 void wxNativeFontInfo::SetWeight(wxFontWeight weight_)
510 {
511 weight = weight_;
512 }
513
514 void wxNativeFontInfo::SetUnderlined(bool underlined_)
515 {
516 underlined = underlined_;
517 }
518
519 void wxNativeFontInfo::SetFaceName(wxString facename_)
520 {
521 faceName = facename_;
522 }
523
524 void wxNativeFontInfo::SetFamily(wxFontFamily family_)
525 {
526 family = family_;
527 }
528
529 void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding_)
530 {
531 encoding = encoding_;
532 }
533
534 #endif // generic wxNativeFontInfo implementation
535
536 // conversion to/from user-readable string: this is used in the generic
537 // versions and under MSW as well because there is no standard font description
538 // format there anyhow (but there is a well-defined standard for X11 fonts used
539 // by wxGTK and wxMotif)
540
541 #if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__)
542
543 wxString wxNativeFontInfo::ToUserString() const
544 {
545 wxString desc;
546
547 // first put the adjectives, if any - this is English-centric, of course,
548 // but what else can we do?
549 if ( GetUnderlined() )
550 {
551 desc << _("underlined ");
552 }
553
554 switch ( GetWeight() )
555 {
556 default:
557 wxFAIL_MSG( _T("unknown font weight") );
558 // fall through
559
560 case wxFONTWEIGHT_NORMAL:
561 break;
562
563 case wxFONTWEIGHT_LIGHT:
564 desc << _("light ");
565 break;
566
567 case wxFONTWEIGHT_BOLD:
568 desc << _("bold ");
569 break;
570 }
571
572 switch ( GetStyle() )
573 {
574 default:
575 wxFAIL_MSG( _T("unknown font style") );
576 // fall through
577
578 case wxFONTSTYLE_NORMAL:
579 break;
580
581 // we don't distinguish between the two for now anyhow...
582 case wxFONTSTYLE_ITALIC:
583 case wxFONTSTYLE_SLANT:
584 desc << _("italic");
585 break;
586 }
587
588 wxString face = GetFaceName();
589 if ( !face.empty() )
590 {
591 desc << _T(' ') << face;
592 }
593
594 int size = GetPointSize();
595 if ( size != wxNORMAL_FONT->GetPointSize() )
596 {
597 desc << _T(' ') << size;
598 }
599
600 #if wxUSE_FONTMAP
601 wxFontEncoding enc = GetEncoding();
602 if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM )
603 {
604 desc << _T(' ') << wxFontMapper::Get()->GetEncodingName(enc);
605 }
606 #endif // wxUSE_FONTMAP
607
608 return desc;
609 }
610
611 bool wxNativeFontInfo::FromUserString(const wxString& s)
612 {
613 // reset to the default state
614 Init();
615
616 // parse a more or less free form string
617 //
618 // TODO: we should handle at least the quoted facenames
619 wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK);
620
621 wxString face;
622 unsigned long size;
623
624 #if wxUSE_FONTMAP
625 wxFontEncoding encoding;
626 #endif // wxUSE_FONTMAP
627
628 while ( tokenizer.HasMoreTokens() )
629 {
630 wxString token = tokenizer.GetNextToken();
631
632 // normalize it
633 token.Trim(true).Trim(false).MakeLower();
634
635 // look for the known tokens
636 if ( token == _T("underlined") || token == _("underlined") )
637 {
638 SetUnderlined(true);
639 }
640 else if ( token == _T("light") || token == _("light") )
641 {
642 SetWeight(wxFONTWEIGHT_LIGHT);
643 }
644 else if ( token == _T("bold") || token == _("bold") )
645 {
646 SetWeight(wxFONTWEIGHT_BOLD);
647 }
648 else if ( token == _T("italic") || token == _("italic") )
649 {
650 SetStyle(wxFONTSTYLE_ITALIC);
651 }
652 else if ( token.ToULong(&size) )
653 {
654 SetPointSize(size);
655 }
656 #if wxUSE_FONTMAP
657 else if ( (encoding = wxFontMapper::Get()->CharsetToEncoding(token, false))
658 != wxFONTENCODING_DEFAULT )
659 {
660 SetEncoding(encoding);
661 }
662 #endif // wxUSE_FONTMAP
663 else // assume it is the face name
664 {
665 if ( !face.empty() )
666 {
667 face += _T(' ');
668 }
669
670 face += token;
671
672 // skip the code which resets face below
673 continue;
674 }
675
676 // if we had had the facename, we shouldn't continue appending tokens
677 // to it (i.e. "foo bold bar" shouldn't result in the facename "foo
678 // bar")
679 if ( !face.empty() )
680 {
681 SetFaceName(face);
682 face.clear();
683 }
684 }
685
686 // we might not have flushed it inside the loop
687 if ( !face.empty() )
688 {
689 SetFaceName(face);
690 }
691
692 return true;
693 }
694
695 #endif // generic or wxMSW or wxOS2
696