]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: font.cpp | |
3 | // Purpose: | |
4 | // Author: Robert Roebling | |
5 | // Id: $Id$ | |
6 | // Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem | |
7 | // Licence: wxWindows licence | |
8 | ///////////////////////////////////////////////////////////////////////////// | |
9 | ||
10 | #ifdef __GNUG__ | |
11 | #pragma implementation "font.h" | |
12 | #endif | |
13 | ||
14 | #include "wx/font.h" | |
15 | #include "wx/utils.h" | |
16 | #include "wx/log.h" | |
17 | #include <strings.h> | |
18 | ||
19 | #include "gdk/gdk.h" | |
20 | ||
21 | //----------------------------------------------------------------------------- | |
22 | // local data | |
23 | //----------------------------------------------------------------------------- | |
24 | ||
25 | /* | |
26 | extern wxFontNameDirectory *wxTheFontNameDirectory; | |
27 | */ | |
28 | ||
29 | //----------------------------------------------------------------------------- | |
30 | // wxFont | |
31 | //----------------------------------------------------------------------------- | |
32 | ||
33 | class wxFontRefData: public wxObjectRefData | |
34 | { | |
35 | public: | |
36 | ||
37 | wxFontRefData(); | |
38 | wxFontRefData( const wxFontRefData& data ); | |
39 | ~wxFontRefData(); | |
40 | ||
41 | wxList m_scaled_xfonts; | |
42 | int m_pointSize; | |
43 | int m_family, m_style, m_weight; | |
44 | bool m_underlined; | |
45 | wxString m_faceName; | |
46 | ||
47 | bool m_byXFontName; | |
48 | GdkFont *m_font; | |
49 | ||
50 | friend wxFont; | |
51 | }; | |
52 | ||
53 | wxFontRefData::wxFontRefData() : m_scaled_xfonts(wxKEY_INTEGER) | |
54 | { | |
55 | m_byXFontName = FALSE; | |
56 | m_pointSize = 12; | |
57 | m_family = wxSWISS; | |
58 | m_style = wxNORMAL; | |
59 | m_weight = wxNORMAL; | |
60 | m_underlined = FALSE; | |
61 | m_font = (GdkFont *) NULL; | |
62 | } | |
63 | ||
64 | wxFontRefData::wxFontRefData( const wxFontRefData& data ) : m_scaled_xfonts(wxKEY_INTEGER) | |
65 | { | |
66 | m_byXFontName = FALSE; | |
67 | m_pointSize = data.m_pointSize; | |
68 | m_family = data.m_family; | |
69 | m_style = data.m_style; | |
70 | m_weight = data.m_weight; | |
71 | m_underlined = data.m_underlined; | |
72 | m_faceName = data.m_faceName; | |
73 | m_font = (GdkFont *) NULL; | |
74 | if (data.m_font) m_font = gdk_font_ref( data.m_font ); | |
75 | } | |
76 | ||
77 | wxFontRefData::~wxFontRefData() | |
78 | { | |
79 | wxNode *node = m_scaled_xfonts.First(); | |
80 | while (node) | |
81 | { | |
82 | GdkFont *font = (GdkFont*)node->Data(); | |
83 | wxNode *next = node->Next(); | |
84 | gdk_font_unref( font ); | |
85 | node = next; | |
86 | } | |
87 | if (m_font) gdk_font_unref( m_font ); | |
88 | } | |
89 | ||
90 | //----------------------------------------------------------------------------- | |
91 | ||
92 | #define M_FONTDATA ((wxFontRefData *)m_refData) | |
93 | ||
94 | IMPLEMENT_DYNAMIC_CLASS(wxFont, wxGDIObject) | |
95 | ||
96 | wxFont::wxFont() | |
97 | { | |
98 | if (wxTheFontList) wxTheFontList->Append( this ); | |
99 | } | |
100 | ||
101 | wxFont::wxFont( char *xFontName ) | |
102 | { | |
103 | if (!xFontName) return; | |
104 | ||
105 | m_refData = new wxFontRefData(); | |
106 | ||
107 | M_FONTDATA->m_byXFontName = TRUE; | |
108 | M_FONTDATA->m_font = gdk_font_load( xFontName ); | |
109 | } | |
110 | ||
111 | wxFont::wxFont( int pointSize, int family, int style, int weight, bool underlined, const wxString& face ) | |
112 | { | |
113 | m_refData = new wxFontRefData(); | |
114 | ||
115 | if (family == wxDEFAULT) | |
116 | M_FONTDATA->m_family = wxSWISS; | |
117 | else | |
118 | M_FONTDATA->m_family = family; | |
119 | ||
120 | if (!face.IsEmpty()) M_FONTDATA->m_faceName = face; | |
121 | ||
122 | if (style == wxDEFAULT) | |
123 | M_FONTDATA->m_style = wxNORMAL; | |
124 | else | |
125 | M_FONTDATA->m_style = style; | |
126 | ||
127 | if (weight == wxDEFAULT) | |
128 | M_FONTDATA->m_weight = wxNORMAL; | |
129 | else | |
130 | M_FONTDATA->m_weight = weight; | |
131 | ||
132 | if (pointSize == wxDEFAULT) | |
133 | M_FONTDATA->m_pointSize = 12; | |
134 | else | |
135 | M_FONTDATA->m_pointSize = pointSize; | |
136 | ||
137 | M_FONTDATA->m_underlined = underlined; | |
138 | ||
139 | if (wxTheFontList) wxTheFontList->Append( this ); | |
140 | ||
141 | } | |
142 | ||
143 | wxFont::wxFont( const wxFont& font ) | |
144 | { | |
145 | Ref( font ); | |
146 | ||
147 | if (wxTheFontList) wxTheFontList->Append( this ); | |
148 | } | |
149 | ||
150 | wxFont::~wxFont() | |
151 | { | |
152 | if (wxTheFontList) wxTheFontList->DeleteObject( this ); | |
153 | } | |
154 | ||
155 | wxFont& wxFont::operator = ( const wxFont& font ) | |
156 | { | |
157 | if (*this == font) return (*this); | |
158 | Ref( font ); | |
159 | return *this; | |
160 | } | |
161 | ||
162 | bool wxFont::operator == ( const wxFont& font ) const | |
163 | { | |
164 | return m_refData == font.m_refData; | |
165 | } | |
166 | ||
167 | bool wxFont::operator != ( const wxFont& font ) const | |
168 | { | |
169 | return m_refData != font.m_refData; | |
170 | } | |
171 | ||
172 | bool wxFont::Ok() const | |
173 | { | |
174 | return (m_refData != NULL); | |
175 | } | |
176 | ||
177 | int wxFont::GetPointSize() const | |
178 | { | |
179 | wxCHECK_MSG( Ok(), 0, _T("invalid font") ); | |
180 | ||
181 | return M_FONTDATA->m_pointSize; | |
182 | } | |
183 | ||
184 | wxString wxFont::GetFaceName() const | |
185 | { | |
186 | wxCHECK_MSG( Ok(), _T(""), _T("invalid font") ); | |
187 | ||
188 | return M_FONTDATA->m_faceName; | |
189 | } | |
190 | ||
191 | int wxFont::GetFamily() const | |
192 | { | |
193 | wxCHECK_MSG( Ok(), 0, _T("invalid font") ); | |
194 | ||
195 | return M_FONTDATA->m_family; | |
196 | } | |
197 | ||
198 | wxString wxFont::GetFamilyString() const | |
199 | { | |
200 | wxCHECK_MSG( Ok(), _T("wxDEFAULT"), _T("invalid font") ); | |
201 | ||
202 | switch (M_FONTDATA->m_family) | |
203 | { | |
204 | case wxDECORATIVE: return wxString(_T("wxDECORATIVE")); | |
205 | case wxROMAN: return wxString(_T("wxROMAN")); | |
206 | case wxSCRIPT: return wxString(_T("wxSCRIPT")); | |
207 | case wxSWISS: return wxString(_T("wxSWISS")); | |
208 | case wxMODERN: return wxString(_T("wxMODERN")); | |
209 | case wxTELETYPE: return wxString(_T("wxTELETYPE")); | |
210 | default: return _T("wxDEFAULT"); | |
211 | } | |
212 | ||
213 | return "wxDEFAULT"; | |
214 | } | |
215 | ||
216 | int wxFont::GetStyle() const | |
217 | { | |
218 | wxCHECK_MSG( Ok(), 0, _T("invalid font") ); | |
219 | ||
220 | return M_FONTDATA->m_style; | |
221 | } | |
222 | ||
223 | wxString wxFont::GetStyleString() const | |
224 | { | |
225 | wxCHECK_MSG( Ok(), _T("wxDEFAULT"), _T("invalid font") ); | |
226 | ||
227 | switch (M_FONTDATA->m_style) | |
228 | { | |
229 | case wxNORMAL: return wxString(_T("wxNORMAL")); | |
230 | case wxSLANT: return wxString(_T("wxSLANT")); | |
231 | case wxITALIC: return wxString(_T("wxITALIC")); | |
232 | default: return wxString(_T("wxDEFAULT")); | |
233 | } | |
234 | ||
235 | return wxString(_T("wxDEFAULT")); | |
236 | } | |
237 | ||
238 | int wxFont::GetWeight() const | |
239 | { | |
240 | wxCHECK_MSG( Ok(), 0, _T("invalid font") ); | |
241 | ||
242 | return M_FONTDATA->m_weight; | |
243 | } | |
244 | ||
245 | wxString wxFont::GetWeightString() const | |
246 | { | |
247 | wxCHECK_MSG( Ok(), _T("wxDEFAULT"), _T("invalid font") ); | |
248 | ||
249 | switch (M_FONTDATA->m_weight) | |
250 | { | |
251 | case wxNORMAL: return wxString(_T("wxNORMAL")); | |
252 | case wxBOLD: return wxString(_T("wxBOLD")); | |
253 | case wxLIGHT: return wxString(_T("wxLIGHT")); | |
254 | default: return wxString(_T("wxDEFAULT")); | |
255 | } | |
256 | ||
257 | return wxString(_T("wxDEFAULT")); | |
258 | } | |
259 | ||
260 | bool wxFont::GetUnderlined() const | |
261 | { | |
262 | wxCHECK_MSG( Ok(), FALSE, _T("invalid font") ); | |
263 | ||
264 | return M_FONTDATA->m_underlined; | |
265 | } | |
266 | ||
267 | void wxFont::Unshare() | |
268 | { | |
269 | if (!m_refData) | |
270 | { | |
271 | m_refData = new wxFontRefData(); | |
272 | } | |
273 | else | |
274 | { | |
275 | wxFontRefData* ref = new wxFontRefData(*(wxFontRefData*)m_refData); | |
276 | UnRef(); | |
277 | m_refData = ref; | |
278 | } | |
279 | } | |
280 | ||
281 | void wxFont::SetPointSize(int pointSize) | |
282 | { | |
283 | Unshare(); | |
284 | ||
285 | M_FONTDATA->m_pointSize = pointSize; | |
286 | } | |
287 | ||
288 | void wxFont::SetFamily(int family) | |
289 | { | |
290 | Unshare(); | |
291 | ||
292 | M_FONTDATA->m_family = family; | |
293 | } | |
294 | ||
295 | void wxFont::SetStyle(int style) | |
296 | { | |
297 | Unshare(); | |
298 | ||
299 | M_FONTDATA->m_style = style; | |
300 | } | |
301 | ||
302 | void wxFont::SetWeight(int weight) | |
303 | { | |
304 | Unshare(); | |
305 | ||
306 | M_FONTDATA->m_weight = weight; | |
307 | } | |
308 | ||
309 | void wxFont::SetFaceName(const wxString& faceName) | |
310 | { | |
311 | Unshare(); | |
312 | ||
313 | M_FONTDATA->m_faceName = faceName; | |
314 | } | |
315 | ||
316 | void wxFont::SetUnderlined(bool underlined) | |
317 | { | |
318 | Unshare(); | |
319 | ||
320 | M_FONTDATA->m_underlined = underlined; | |
321 | } | |
322 | ||
323 | //----------------------------------------------------------------------------- | |
324 | // get internal representation of font | |
325 | //----------------------------------------------------------------------------- | |
326 | ||
327 | static GdkFont *wxLoadQueryNearestFont( int point_size, int family, int style, int weight, | |
328 | bool underlined, const wxString &facename ); | |
329 | ||
330 | GdkFont *wxFont::GetInternalFont( float scale ) const | |
331 | { | |
332 | if (!Ok()) | |
333 | { | |
334 | wxFAIL_MSG( _T("invalid font") ); | |
335 | return (GdkFont*) NULL; | |
336 | } | |
337 | ||
338 | /* short cut if the special X font constructor has been used */ | |
339 | if (M_FONTDATA->m_byXFontName) return M_FONTDATA->m_font; | |
340 | ||
341 | long int_scale = long(scale * 100.0 + 0.5); /* key for fontlist */ | |
342 | int point_scale = (M_FONTDATA->m_pointSize * 10 * int_scale) / 100; | |
343 | GdkFont *font = (GdkFont *) NULL; | |
344 | ||
345 | wxNode *node = M_FONTDATA->m_scaled_xfonts.Find(int_scale); | |
346 | if (node) | |
347 | { | |
348 | font = (GdkFont*)node->Data(); | |
349 | } | |
350 | else | |
351 | { | |
352 | /* | |
353 | if ((int_scale == 100) && | |
354 | (M_FONTDATA->m_family == wxSWISS) && | |
355 | (M_FONTDATA->m_style == wxNORMAL) && | |
356 | (M_FONTDATA->m_pointSize == 12) && | |
357 | (M_FONTDATA->m_weight == wxNORMAL) && | |
358 | (M_FONTDATA->m_underlined == FALSE)) | |
359 | { | |
360 | font = gdk_font_load( "-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*" ); | |
361 | } | |
362 | else | |
363 | */ | |
364 | { | |
365 | font = wxLoadQueryNearestFont( point_scale, M_FONTDATA->m_family, M_FONTDATA->m_style, | |
366 | M_FONTDATA->m_weight, M_FONTDATA->m_underlined, M_FONTDATA->m_faceName ); | |
367 | } | |
368 | M_FONTDATA->m_scaled_xfonts.Append( int_scale, (wxObject*)font ); | |
369 | } | |
370 | ||
371 | if (!font) | |
372 | { | |
373 | wxLogError(_T("could not load any font")); | |
374 | } | |
375 | ||
376 | return font; | |
377 | } | |
378 | ||
379 | //----------------------------------------------------------------------------- | |
380 | // local utilities to find a X font | |
381 | //----------------------------------------------------------------------------- | |
382 | ||
383 | static GdkFont*wxLoadQueryFont( int pointSize, int family, int style, int weight, | |
384 | bool underlined, const wxString &facename ) | |
385 | { | |
386 | wxChar *xfamily = (wxChar*) NULL; | |
387 | wxChar *xstyle = (wxChar*) NULL; | |
388 | wxChar *xweight = (wxChar*) NULL; | |
389 | ||
390 | switch (family) | |
391 | { | |
392 | case wxDECORATIVE: xfamily = _T("lucida"); break; | |
393 | case wxROMAN: xfamily = _T("times"); break; | |
394 | case wxMODERN: xfamily = _T("courier"); break; | |
395 | case wxSWISS: xfamily = _T("helvetica"); break; | |
396 | case wxTELETYPE: xfamily = _T("lucidatypewriter"); break; | |
397 | case wxSCRIPT: xfamily = _T("utopia"); break; | |
398 | default: xfamily = _T("*"); | |
399 | } | |
400 | ||
401 | if (!facename.IsEmpty()) | |
402 | { | |
403 | wxSprintf( wxBuffer, _T("-*-%s-*-*-normal-*-*-*-*-*-*-*-*-*"), facename.c_str() ); | |
404 | GdkFont *test = gdk_font_load( wxConvCurrent->cWX2MB(wxBuffer) ); | |
405 | if (test) | |
406 | { | |
407 | gdk_font_unref( test ); | |
408 | xfamily = WXSTRINGCAST facename; | |
409 | } | |
410 | } | |
411 | ||
412 | switch (style) | |
413 | { | |
414 | case wxITALIC: xstyle = _T("i"); break; | |
415 | case wxSLANT: xstyle = _T("o"); break; | |
416 | case wxNORMAL: xstyle = _T("r"); break; | |
417 | default: xstyle = _T("*"); break; | |
418 | } | |
419 | switch (weight) | |
420 | { | |
421 | case wxBOLD: xweight = _T("bold"); break; | |
422 | case wxLIGHT: | |
423 | case wxNORMAL: xweight = _T("medium"); break; | |
424 | default: xweight = _T("*"); break; | |
425 | } | |
426 | ||
427 | wxSprintf( wxBuffer, _T("-*-%s-%s-%s-normal-*-*-%d-*-*-*-*-*-*"), | |
428 | xfamily, xweight, xstyle, pointSize); | |
429 | ||
430 | return gdk_font_load( wxConvCurrent->cWX2MB(wxBuffer) ); | |
431 | } | |
432 | ||
433 | static GdkFont *wxLoadQueryNearestFont( int point_size, int family, int style, int weight, | |
434 | bool underlined, const wxString &facename ) | |
435 | { | |
436 | GdkFont *font = wxLoadQueryFont( point_size, family, style, weight, underlined, facename ); | |
437 | ||
438 | if (!font) | |
439 | { | |
440 | /* search up and down by stepsize 10 */ | |
441 | int max_size = point_size + 20 * (1 + (point_size/180)); | |
442 | int min_size = point_size - 20 * (1 + (point_size/180)); | |
443 | ||
444 | int i; | |
445 | ||
446 | /* Search for smaller size (approx.) */ | |
447 | for (i=point_size-10; !font && i >= 10 && i >= min_size; i -= 10) | |
448 | font = wxLoadQueryFont(i, family, style, weight, underlined, facename ); | |
449 | ||
450 | /* Search for larger size (approx.) */ | |
451 | for (i=point_size+10; !font && i <= max_size; i += 10) | |
452 | font = wxLoadQueryFont( i, family, style, weight, underlined, facename ); | |
453 | ||
454 | /* Try default family */ | |
455 | if (!font && family != wxDEFAULT) | |
456 | font = wxLoadQueryFont( point_size, wxDEFAULT, style, weight, underlined, facename ); | |
457 | ||
458 | /* Bogus font */ | |
459 | if (!font) | |
460 | font = wxLoadQueryFont(120, wxDEFAULT, wxNORMAL, wxNORMAL, underlined, facename ); | |
461 | } | |
462 | ||
463 | return font; | |
464 | } | |
465 | ||
466 | /* | |
467 | ||
468 | //----------------------------------------------------------------------------- | |
469 | // face names and index functions | |
470 | //----------------------------------------------------------------------------- | |
471 | ||
472 | static char *font_defaults[] = { | |
473 | "FamilyDefault", "Default", | |
474 | "FamilyRoman", "Roman", | |
475 | "FamilyDecorative", "Decorative", | |
476 | "FamilyModern", "Modern", | |
477 | "FamilyTeletype", "Teletype", | |
478 | "FamilySwiss", "Swiss", | |
479 | "FamilyScript", "Script", | |
480 | ||
481 | "AfmMedium", "", | |
482 | "AfmBold", "Bo", | |
483 | "AfmLight", "", | |
484 | "AfmStraight", "", | |
485 | "AfmItalic", "${AfmSlant}", | |
486 | "AfmSlant", "O", | |
487 | "AfmRoman", "Ro", | |
488 | "AfmTimes", "Times", | |
489 | "AfmHelvetica", "Helv", | |
490 | "AfmCourier", "Cour", | |
491 | ||
492 | "Afm___", "${AfmTimes,$[weight],$[style]}", | |
493 | ||
494 | "AfmTimes__", "${AfmTimes}${Afm$[weight]}${Afm$[style]}", | |
495 | "AfmTimesMediumStraight", "${AfmTimes}${AfmRoman}", | |
496 | "AfmTimesLightStraight", "${AfmTimes}${AfmRoman}", | |
497 | "AfmTimes_Italic", "${AfmTimes}$[weight]${AfmItalic}", | |
498 | "AfmTimes_Slant", "${AfmTimes}$[weight]${AfmItalic}", | |
499 | ||
500 | "AfmSwiss__", "${AfmHelvetica}${Afm$[weight]}${Afm$[style]}", | |
501 | "AfmModern__", "${AfmCourier}${Afm$[weight]}${Afm$[style]}", | |
502 | ||
503 | "AfmTeletype__", "${AfmModern,$[weight],$[style]}", | |
504 | ||
505 | "PostScriptMediumStraight", "", | |
506 | "PostScriptMediumItalic", "-Oblique", | |
507 | "PostScriptMediumSlant", "-Oblique", | |
508 | "PostScriptLightStraight", "", | |
509 | "PostScriptLightItalic", "-Oblique", | |
510 | "PostScriptLightSlant", "-Oblique", | |
511 | "PostScriptBoldStraight", "-Bold", | |
512 | "PostScriptBoldItalic", "-BoldOblique", | |
513 | "PostScriptBoldSlant", "-BoldOblique", | |
514 | ||
515 | #if WX_NORMALIZED_PS_FONTS | |
516 | "PostScript___", "${PostScriptTimes,$[weight],$[style]}", | |
517 | #else | |
518 | "PostScriptRoman__", "${PostScriptTimes,$[weight],$[style]}", | |
519 | "PostScript___", "LucidaSans${PostScript$[weight]$[style]}", | |
520 | #endif | |
521 | ||
522 | "PostScriptTimesMedium", "", | |
523 | "PostScriptTimesLight", "", | |
524 | "PostScriptTimesBold", "Bold", | |
525 | ||
526 | "PostScriptTimes__", "Times${PostScript$[weight]$[style]}", | |
527 | "PostScriptTimesMediumStraight", "Times-Roman", | |
528 | "PostScriptTimesLightStraight", "Times-Roman", | |
529 | "PostScriptTimes_Slant", "Times-${PostScriptTimes$[weight]}Italic", | |
530 | "PostScriptTimes_Italic", "Times-${PostScriptTimes$[weight]}Italic", | |
531 | ||
532 | "PostScriptSwiss__", "Helvetica${PostScript$[weight]$[style]}", | |
533 | "PostScriptModern__", "Courier${PostScript$[weight]$[style]}", | |
534 | ||
535 | "PostScriptTeletype__", "${PostScriptModern,$[weight],$[style]}", | |
536 | ||
537 | #if !WX_NORMALIZED_PS_FONTS | |
538 | "PostScriptScript__", "Zapf-Chancery-MediumItalic", | |
539 | #endif | |
540 | ||
541 | "ScreenMedium", "medium", | |
542 | "ScreenBold", "bold", | |
543 | "ScreenLight", "light", | |
544 | "ScreenStraight", "r", | |
545 | "ScreenItalic", "i", | |
546 | "ScreenSlant", "o", | |
547 | ||
548 | "ScreenDefaultBase", "*-times", | |
549 | ||
550 | "ScreenRomanBase", "*-times", | |
551 | "ScreenDecorativeBase", "*-helvetica", | |
552 | "ScreenModernBase", "*-courier", | |
553 | "ScreenTeletypeBase", "*-lucidatypewriter", | |
554 | "ScreenSwissBase", "*-lucida", | |
555 | "ScreenScriptBase", "*-zapfchancery", | |
556 | ||
557 | "ScreenStdSuffix", "-${Screen$[weight]}-${Screen$[style]}" | |
558 | "-normal-*-*-%d-*-*-*-*-*-*", | |
559 | ||
560 | "Screen___", | |
561 | "-${ScreenDefaultBase}${ScreenStdSuffix}", | |
562 | "ScreenRoman__", | |
563 | "-${ScreenRomanBase}${ScreenStdSuffix}", | |
564 | "ScreenDecorative__", | |
565 | "-${ScreenDecorativeBase}${ScreenStdSuffix}", | |
566 | "ScreenModern__", | |
567 | "-${ScreenModernBase}${ScreenStdSuffix}", | |
568 | "ScreenTeletype__", | |
569 | "-${ScreenTeletypeBase}${ScreenStdSuffix}", | |
570 | "ScreenSwiss__", | |
571 | "-${ScreenSwissBase}${ScreenStdSuffix}", | |
572 | "ScreenScript__", | |
573 | "-${ScreenScriptBase}${ScreenStdSuffix}", | |
574 | (char *) NULL | |
575 | }; | |
576 | ||
577 | enum {wxWEIGHT_NORMAL, wxWEIGHT_BOLD, wxWEIGHT_LIGHT, wxNUM_WEIGHTS}; | |
578 | enum {wxSTYLE_NORMAL, wxSTYLE_ITALIC, wxSTYLE_SLANT, wxNUM_STYLES}; | |
579 | ||
580 | static int WCoordinate(int w) | |
581 | { | |
582 | switch (w) | |
583 | { | |
584 | case wxBOLD: return wxWEIGHT_BOLD; | |
585 | case wxLIGHT: return wxWEIGHT_LIGHT; | |
586 | case wxNORMAL: | |
587 | default: return wxWEIGHT_NORMAL; | |
588 | } | |
589 | }; | |
590 | ||
591 | static int SCoordinate(int s) | |
592 | { | |
593 | switch (s) | |
594 | { | |
595 | case wxITALIC: return wxSTYLE_ITALIC; | |
596 | case wxSLANT: return wxSTYLE_SLANT; | |
597 | case wxNORMAL: | |
598 | default: return wxSTYLE_NORMAL; | |
599 | } | |
600 | }; | |
601 | ||
602 | //----------------------------------------------------------------------------- | |
603 | // wxSuffixMap | |
604 | //----------------------------------------------------------------------------- | |
605 | ||
606 | class wxSuffixMap | |
607 | { | |
608 | public: | |
609 | ~wxSuffixMap(); | |
610 | ||
611 | inline char *GetName(int weight, int style) | |
612 | { | |
613 | return ( map [WCoordinate(weight)] [SCoordinate(style)] ); | |
614 | } | |
615 | ||
616 | char *map[wxNUM_WEIGHTS][wxNUM_STYLES]; | |
617 | void Initialize(const char *, const char *); | |
618 | }; | |
619 | ||
620 | static void SearchResource(const char *prefix, const char **names, int count, char **v) | |
621 | { | |
622 | int k, i, j; | |
623 | char resource[1024], **defaults, *internal; | |
624 | ||
625 | k = 1 << count; | |
626 | ||
627 | *v = (char *) NULL; | |
628 | internal = (char *) NULL; | |
629 | ||
630 | for (i = 0; i < k; i++) | |
631 | { | |
632 | strcpy(resource, prefix); | |
633 | for (j = 0; j < count; j++) | |
634 | { | |
635 | // upon failure to find a matching fontname | |
636 | // in the default fonts above, we substitute more | |
637 | // and more values by _ so that at last ScreenMyFontBoldNormal | |
638 | // would turn into Screen___ and this will then get | |
639 | // converted to -${ScreenDefaultBase}${ScreenStdSuffix} | |
640 | ||
641 | if (!(i & (1 << j))) | |
642 | strcat(resource, names[j]); | |
643 | else | |
644 | strcat(resource, "_"); | |
645 | } | |
646 | ||
647 | // we previously search the Xt-resources here | |
648 | ||
649 | if (!internal) | |
650 | { | |
651 | defaults = font_defaults; | |
652 | while (*defaults) | |
653 | { | |
654 | if (!strcmp(*defaults, resource)) | |
655 | { | |
656 | internal = defaults[1]; | |
657 | break; | |
658 | } | |
659 | defaults += 2; | |
660 | } | |
661 | } | |
662 | } | |
663 | ||
664 | if (internal) | |
665 | { | |
666 | if ((strcmp(internal,"-${ScreenDefaultBase}${ScreenStdSuffix}") == 0) && | |
667 | (strcmp(names[0], "Default") != 0)) | |
668 | { | |
669 | // we did not find any font name in the standard list. | |
670 | // this can (hopefully does) mean that someone supplied | |
671 | // the facename in the wxFont constructor so we insert | |
672 | // it here | |
673 | ||
674 | strcpy( resource,"-*-" ); // any producer | |
675 | strcat( resource, names[0] ); // facename | |
676 | strcat( resource, "${ScreenStdSuffix}" ); // add size params later on | |
677 | *v = copystring(resource); | |
678 | } | |
679 | else | |
680 | { | |
681 | *v = copystring(internal); | |
682 | } | |
683 | } | |
684 | } | |
685 | ||
686 | wxSuffixMap::~wxSuffixMap() | |
687 | { | |
688 | int k, j; | |
689 | ||
690 | for (k = 0; k < wxNUM_WEIGHTS; ++k) | |
691 | for (j = 0; j < wxNUM_STYLES; ++j) | |
692 | if (map[k][j]) | |
693 | { | |
694 | delete[] map[k][j]; | |
695 | map[k][j] = (char *) NULL; | |
696 | } | |
697 | } | |
698 | ||
699 | void wxSuffixMap::Initialize(const char *resname, const char *devresname) | |
700 | { | |
701 | const char *weight, *style; | |
702 | char *v; | |
703 | int i, j, k; | |
704 | const char *names[3]; | |
705 | ||
706 | for (k = 0; k < wxNUM_WEIGHTS; k++) | |
707 | { | |
708 | switch (k) | |
709 | { | |
710 | case wxWEIGHT_NORMAL: weight = "Medium"; break; | |
711 | case wxWEIGHT_LIGHT: weight = "Light"; break; | |
712 | case wxWEIGHT_BOLD: | |
713 | default: weight = "Bold"; | |
714 | } | |
715 | for (j = 0; j < wxNUM_STYLES; j++) | |
716 | { | |
717 | switch (j) | |
718 | { | |
719 | case wxSTYLE_NORMAL: style = "Straight"; break; | |
720 | case wxSTYLE_ITALIC: style = "Italic"; break; | |
721 | case wxSTYLE_SLANT: | |
722 | default: style = "Slant"; | |
723 | } | |
724 | names[0] = resname; | |
725 | names[1] = weight; | |
726 | names[2] = style; | |
727 | ||
728 | SearchResource(devresname, names, 3, &v); | |
729 | ||
730 | // Expand macros in the found string: | |
731 | found: | |
732 | int len, closer = 0, startpos = 0; | |
733 | ||
734 | len = (v ? strlen(v) : 0); | |
735 | for (i = 0; i < len; i++) | |
736 | { | |
737 | if (v[i] == '$' && ((v[i+1] == '[') || (v[i+1] == '{'))) | |
738 | { | |
739 | startpos = i; | |
740 | closer = (v[i+1] == '[') ? ']' : '}'; | |
741 | ++i; | |
742 | } | |
743 | else if (v[i] == closer) | |
744 | { | |
745 | int newstrlen; | |
746 | const char *r = (char *) NULL; bool delete_r = FALSE; | |
747 | char *name; | |
748 | ||
749 | name = v + startpos + 2; | |
750 | v[i] = 0; | |
751 | ||
752 | if (closer == '}') | |
753 | { | |
754 | int i, count, len; | |
755 | char **names; | |
756 | ||
757 | for (i = 0, count = 1; name[i]; i++) | |
758 | if (name[i] == ',') | |
759 | count++; | |
760 | ||
761 | len = i; | |
762 | ||
763 | names = new char*[count]; | |
764 | names[0] = name; | |
765 | for (i = 0, count = 1; i < len; i++) | |
766 | if (name[i] == ',') | |
767 | { | |
768 | names[count++] = name + i + 1; | |
769 | name[i] = 0; | |
770 | } | |
771 | ||
772 | SearchResource("", (const char **)names, count, (char **)&r); | |
773 | delete_r = (r != 0); | |
774 | delete[] names; | |
775 | ||
776 | if (!r) | |
777 | { | |
778 | for (i = 0; i < len; i++) | |
779 | if (!name[i]) | |
780 | name[i] = ','; | |
781 | r = ""; | |
782 | wxLogError( "Bad resource name in font lookup." ); | |
783 | } | |
784 | } else if (!strcmp(name, "weight")) { | |
785 | r = weight; | |
786 | } else if (!strcmp(name, "style")) { | |
787 | r = style; | |
788 | } else if (!strcmp(name, "family")) { | |
789 | r = resname; | |
790 | } else { | |
791 | r = ""; | |
792 | wxLogError( "Bad font macro name." ); | |
793 | } | |
794 | ||
795 | // add r to v | |
796 | newstrlen = strlen(r); | |
797 | char *naya = new char[startpos + newstrlen + len - i]; | |
798 | memcpy(naya, v, startpos); | |
799 | memcpy(naya + startpos, r, newstrlen); | |
800 | memcpy(naya + startpos + newstrlen, v + i + 1, len - i); | |
801 | if (delete_r) | |
802 | delete[] (char*)r; | |
803 | delete[] v; | |
804 | v = naya; | |
805 | ||
806 | goto found; | |
807 | } | |
808 | } | |
809 | // We have a final value: | |
810 | map[k][j] = v; | |
811 | } | |
812 | } | |
813 | } | |
814 | ||
815 | //----------------------------------------------------------------------------- | |
816 | // wxFontNameItem | |
817 | //----------------------------------------------------------------------------- | |
818 | ||
819 | class wxFontNameItem : public wxObject | |
820 | { | |
821 | DECLARE_DYNAMIC_CLASS(wxFontNameItem) | |
822 | public: | |
823 | wxFontNameItem(const char *name, int id, int family); | |
824 | ~wxFontNameItem(); | |
825 | ||
826 | inline char* GetScreenName(int w, int s) {return screen.GetName(w, s);} | |
827 | inline char* GetPostScriptName(int w, int s) {return printing.GetName(w, s);} | |
828 | inline char* GetAFMName(int w, int s) {return afm.GetName(w, s);} | |
829 | inline char* GetName() {return name;} | |
830 | inline int GetFamily() {return family;} | |
831 | inline int GetId() {return id;} | |
832 | inline bool IsRoman() {return isroman;} | |
833 | #if defined(__WXDEBUG__) | |
834 | void Dump(ostream& str); | |
835 | #endif | |
836 | ||
837 | int id; | |
838 | int family; | |
839 | char *name; | |
840 | wxSuffixMap screen, printing, afm; | |
841 | bool isroman; | |
842 | }; | |
843 | ||
844 | IMPLEMENT_ABSTRACT_CLASS(wxFontNameItem, wxObject) | |
845 | ||
846 | wxFontNameItem::wxFontNameItem(const char *Name, int Id, int Family) | |
847 | { | |
848 | name = copystring(Name); | |
849 | id = Id; | |
850 | family = Family; | |
851 | ||
852 | screen. Initialize(name, "Screen"); | |
853 | printing.Initialize(name, "PostScript"); | |
854 | afm. Initialize(name, "Afm"); | |
855 | } | |
856 | ||
857 | wxFontNameItem::~wxFontNameItem() | |
858 | { | |
859 | if (name) | |
860 | delete[] name; | |
861 | name = (char *) NULL; | |
862 | } | |
863 | ||
864 | #if defined(__WXDEBUG__) | |
865 | void wxFontNameItem::Dump(ostream& str) | |
866 | { | |
867 | str << "wxFontNameItem(" << name << ")"; | |
868 | } | |
869 | #endif | |
870 | ||
871 | //----------------------------------------------------------------------------- | |
872 | // wxFontDirectory | |
873 | //----------------------------------------------------------------------------- | |
874 | ||
875 | IMPLEMENT_DYNAMIC_CLASS(wxFontNameDirectory, wxObject) | |
876 | ||
877 | wxFontNameDirectory::wxFontNameDirectory() | |
878 | { | |
879 | table = new wxHashTable(wxKEY_INTEGER, 20); | |
880 | nextFontId = -1; | |
881 | } | |
882 | ||
883 | wxFontNameDirectory::~wxFontNameDirectory() | |
884 | { | |
885 | // Cleanup wxFontNameItems allocated | |
886 | table->BeginFind(); | |
887 | wxNode *node = table->Next(); | |
888 | while (node) | |
889 | { | |
890 | wxFontNameItem *item = (wxFontNameItem*)node->Data(); | |
891 | delete item; | |
892 | node = table->Next(); | |
893 | } | |
894 | delete table; | |
895 | } | |
896 | ||
897 | int wxFontNameDirectory::GetNewFontId() | |
898 | { | |
899 | return (nextFontId--); | |
900 | } | |
901 | ||
902 | void wxFontNameDirectory::Initialize() | |
903 | { | |
904 | Initialize(wxDEFAULT, wxDEFAULT, "Default"); | |
905 | Initialize(wxDECORATIVE, wxDECORATIVE, "Decorative"); | |
906 | Initialize(wxROMAN, wxROMAN, "Roman"); | |
907 | Initialize(wxMODERN, wxMODERN, "Modern"); | |
908 | Initialize(wxTELETYPE, wxTELETYPE, "Teletype"); | |
909 | Initialize(wxSWISS, wxSWISS, "Swiss"); | |
910 | Initialize(wxSCRIPT, wxSCRIPT, "Script"); | |
911 | } | |
912 | ||
913 | void wxFontNameDirectory::Initialize(int fontid, int family, const char *resname) | |
914 | { | |
915 | char *fam, resource[256]; | |
916 | ||
917 | sprintf(resource, "Family%s", resname); | |
918 | SearchResource((const char *)resource, (const char **) NULL, 0, (char **)&fam); | |
919 | ||
920 | if (fam) | |
921 | { | |
922 | if (!strcmp(fam, "Default")) family = wxDEFAULT; | |
923 | else if (!strcmp(fam, "Roman")) family = wxROMAN; | |
924 | else if (!strcmp(fam, "Decorative")) family = wxDECORATIVE; | |
925 | else if (!strcmp(fam, "Modern")) family = wxMODERN; | |
926 | else if (!strcmp(fam, "Teletype")) family = wxTELETYPE; | |
927 | else if (!strcmp(fam, "Swiss")) family = wxSWISS; | |
928 | else if (!strcmp(fam, "Script")) family = wxSCRIPT; | |
929 | delete[] fam; // free resource | |
930 | } | |
931 | table->Put(fontid, new wxFontNameItem(resname, fontid, family)); | |
932 | } | |
933 | ||
934 | int wxFontNameDirectory::FindOrCreateFontId(const char *name, int family) | |
935 | { | |
936 | int id; | |
937 | ||
938 | // font exists -> return id | |
939 | if ( (id = GetFontId(name)) ) return id; | |
940 | ||
941 | // create new font | |
942 | Initialize(id=GetNewFontId(), family, name); | |
943 | return id; | |
944 | } | |
945 | ||
946 | char *wxFontNameDirectory::GetScreenName(int fontid, int weight, int style) | |
947 | { | |
948 | wxFontNameItem *item = (wxFontNameItem*)table->Get(fontid); // find font | |
949 | if (item) | |
950 | return item->GetScreenName(weight, style); | |
951 | ||
952 | // font does not exist | |
953 | return (char *) NULL; | |
954 | } | |
955 | ||
956 | char *wxFontNameDirectory::GetPostScriptName(int fontid, int weight, int style) | |
957 | { | |
958 | wxFontNameItem *item = (wxFontNameItem*)table->Get(fontid); // find font | |
959 | if (item) | |
960 | return item->GetPostScriptName(weight, style); | |
961 | ||
962 | // font does not exist | |
963 | return (char *) NULL; | |
964 | } | |
965 | ||
966 | char *wxFontNameDirectory::GetAFMName(int fontid, int weight, int style) | |
967 | { | |
968 | wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); // find font | |
969 | if (item) | |
970 | return item->GetAFMName(weight, style); | |
971 | // font does not exist | |
972 | return (char *) NULL; | |
973 | } | |
974 | ||
975 | char *wxFontNameDirectory::GetFontName(int fontid) | |
976 | { | |
977 | wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); // find font | |
978 | if (item) | |
979 | return item->GetName(); | |
980 | ||
981 | // font does not exist | |
982 | return (char *) NULL; | |
983 | } | |
984 | ||
985 | int wxFontNameDirectory::GetFontId(const char *name) | |
986 | { | |
987 | wxNode *node; | |
988 | ||
989 | table->BeginFind(); | |
990 | ||
991 | while ( (node = table->Next()) ) | |
992 | { | |
993 | wxFontNameItem *item = (wxFontNameItem*)node->Data(); | |
994 | if (!strcmp(name, item->name)) | |
995 | return item->id; | |
996 | } | |
997 | ||
998 | // font does not exist | |
999 | return 0; | |
1000 | } | |
1001 | ||
1002 | int wxFontNameDirectory::GetFamily(int fontid) | |
1003 | { | |
1004 | wxFontNameItem *item = (wxFontNameItem *)table->Get(fontid); | |
1005 | ||
1006 | if (item) | |
1007 | return item->family; | |
1008 | ||
1009 | // font does not exist | |
1010 | return wxDEFAULT; | |
1011 | } | |
1012 | ||
1013 | */ |