show font encoding as well; use a splitter to allow resizing the windows
[wxWidgets.git] / samples / font / font.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: font.cpp
3 // Purpose: wxFont demo
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 30.09.99
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 // for all others, include the necessary headers (this file is usually all you
20 // need because it includes almost all <standard< wxWindows headers
21 #ifndef WX_PRECOMP
22 #include <wx/wx.h>
23
24 #include <wx/log.h>
25 #endif
26
27 #include <wx/choicdlg.h>
28 #include <wx/fontdlg.h>
29 #include <wx/fontenum.h>
30 #include <wx/fontmap.h>
31 #include <wx/encconv.h>
32 #include <wx/splitter.h>
33 #include <wx/textfile.h>
34
35 // ----------------------------------------------------------------------------
36 // private classes
37 // ----------------------------------------------------------------------------
38
39 // Define a new application type, each program should derive a class from wxApp
40 class MyApp : public wxApp
41 {
42 public:
43 // override base class virtuals
44 // ----------------------------
45
46 // this one is called on application startup and is a good place for the app
47 // initialization (doing it here and not in the ctor allows to have an error
48 // return: if OnInit() returns false, the application terminates)
49 virtual bool OnInit();
50 };
51
52 // MyCanvas is a canvas on which we show the font sample
53 class MyCanvas: public wxWindow
54 {
55 public:
56 MyCanvas( wxWindow *parent );
57 ~MyCanvas();
58
59 // accessors for the frame
60 const wxFont& GetTextFont() const { return m_font; }
61 const wxColour& GetColour() const { return m_colour; }
62 void SetTextFont(const wxFont& font) { m_font = font; }
63 void SetColour(const wxColour& colour) { m_colour = colour; }
64
65 // event handlers
66 void OnPaint( wxPaintEvent &event );
67
68 private:
69 wxColour m_colour;
70 wxFont m_font;
71
72 DECLARE_EVENT_TABLE()
73 };
74
75 // Define a new frame type: this is going to be our main frame
76 class MyFrame : public wxFrame
77 {
78 public:
79 // ctor(s)
80 MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
81
82 // accessors
83 MyCanvas *GetCanvas() const { return m_canvas; }
84
85 // event handlers (these functions should _not_ be virtual)
86 void OnQuit(wxCommandEvent& event);
87 void OnAbout(wxCommandEvent& event);
88 void OnIncFont(wxCommandEvent& event) { DoResizeFont(+2); }
89 void OnDecFont(wxCommandEvent& event) { DoResizeFont(-2); }
90
91 void OnViewMsg(wxCommandEvent& event);
92 void OnSelectFont(wxCommandEvent& event);
93 void OnEnumerateFamiliesForEncoding(wxCommandEvent& event);
94 void OnEnumerateFamilies(wxCommandEvent& WXUNUSED(event))
95 { DoEnumerateFamilies(FALSE); }
96 void OnEnumerateFixedFamilies(wxCommandEvent& WXUNUSED(event))
97 { DoEnumerateFamilies(TRUE); }
98 void OnEnumerateEncodings(wxCommandEvent& event);
99
100 void OnCheckNativeToFromString(wxCommandEvent& event);
101
102 protected:
103 bool DoEnumerateFamilies(bool fixedWidthOnly,
104 wxFontEncoding encoding = wxFONTENCODING_SYSTEM,
105 bool silent = FALSE);
106
107 void DoResizeFont(int diff);
108 void DoChangeFont(const wxFont& font, const wxColour& col = wxNullColour);
109
110 size_t m_fontSize; // in points
111
112 wxTextCtrl *m_textctrl;
113 MyCanvas *m_canvas;
114
115 private:
116 // any class wishing to process wxWindows events must use this macro
117 DECLARE_EVENT_TABLE()
118 };
119
120 // ----------------------------------------------------------------------------
121 // constants
122 // ----------------------------------------------------------------------------
123
124 // IDs for the controls and the menu commands
125 enum
126 {
127 // menu items
128 Font_Quit = 1,
129 Font_About,
130 Font_ViewMsg,
131 Font_IncSize,
132 Font_DecSize,
133 Font_Choose = 100,
134 Font_EnumFamiliesForEncoding,
135 Font_EnumFamilies,
136 Font_EnumFixedFamilies,
137 Font_EnumEncodings,
138 Font_CheckNativeToFromString,
139 Font_Max
140 };
141
142 // ----------------------------------------------------------------------------
143 // event tables and other macros for wxWindows
144 // ----------------------------------------------------------------------------
145
146 // the event tables connect the wxWindows events with the functions (event
147 // handlers) which process them. It can be also done at run-time, but for the
148 // simple menu events like this the static method is much simpler.
149 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
150 EVT_MENU(Font_Quit, MyFrame::OnQuit)
151 EVT_MENU(Font_About, MyFrame::OnAbout)
152 EVT_MENU(Font_IncSize, MyFrame::OnIncFont)
153 EVT_MENU(Font_DecSize, MyFrame::OnDecFont)
154 EVT_MENU(Font_ViewMsg, MyFrame::OnViewMsg)
155 EVT_MENU(Font_Choose, MyFrame::OnSelectFont)
156 EVT_MENU(Font_EnumFamiliesForEncoding, MyFrame::OnEnumerateFamiliesForEncoding)
157 EVT_MENU(Font_EnumFamilies, MyFrame::OnEnumerateFamilies)
158 EVT_MENU(Font_EnumFixedFamilies, MyFrame::OnEnumerateFixedFamilies)
159 EVT_MENU(Font_EnumEncodings, MyFrame::OnEnumerateEncodings)
160 EVT_MENU(Font_CheckNativeToFromString, MyFrame::OnCheckNativeToFromString)
161 END_EVENT_TABLE()
162
163 // Create a new application object: this macro will allow wxWindows to create
164 // the application object during program execution (it's better than using a
165 // static object for many reasons) and also declares the accessor function
166 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
167 // not wxApp)
168 IMPLEMENT_APP(MyApp)
169
170 // ============================================================================
171 // implementation
172 // ============================================================================
173
174 // ----------------------------------------------------------------------------
175 // the application class
176 // ----------------------------------------------------------------------------
177
178 // `Main program' equivalent: the program execution "starts" here
179 bool MyApp::OnInit()
180 {
181 // Create the main application window
182 MyFrame *frame = new MyFrame("Font wxWindows demo",
183 wxPoint(50, 50), wxSize(450, 340));
184
185 // Show it and tell the application that it's our main window
186 frame->Show(TRUE);
187 SetTopWindow(frame);
188
189 // success: wxApp::OnRun() will be called which will enter the main message
190 // loop and the application will run. If we returned FALSE here, the
191 // application would exit immediately.
192 return TRUE;
193 }
194
195 // ----------------------------------------------------------------------------
196 // main frame
197 // ----------------------------------------------------------------------------
198
199 // frame constructor
200 MyFrame::MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size)
201 : wxFrame((wxFrame *)NULL, -1, title, pos, size), m_textctrl(NULL)
202 {
203 m_fontSize = 12;
204
205 // create a menu bar
206 wxMenu *menuFile = new wxMenu;
207
208 menuFile->Append(Font_ViewMsg, "&View...\tCtrl-V",
209 "View an email message file");
210 menuFile->AppendSeparator();
211 menuFile->Append(Font_About, "&About...\tCtrl-A", "Show about dialog");
212 menuFile->AppendSeparator();
213 menuFile->Append(Font_Quit, "E&xit\tAlt-X", "Quit this program");
214
215 wxMenu *menuFont = new wxMenu;
216 menuFont->Append(Font_IncSize, "&Increase font size by 2 points\tCtrl-I");
217 menuFont->Append(Font_DecSize, "&Decrease font size by 2 points\tCtrl-D");
218 menuFont->AppendSeparator();
219 menuFont->Append(Font_Choose, "&Select font...\tCtrl-S",
220 "Select a standard font");
221 menuFont->AppendSeparator();
222 menuFont->Append(Font_EnumFamilies, "Enumerate font &families\tCtrl-F");
223 menuFont->Append(Font_EnumFixedFamilies,
224 "Enumerate fi&xed font families\tCtrl-X");
225 menuFont->Append(Font_EnumEncodings,
226 "Enumerate &encodings\tCtrl-E");
227 menuFont->Append(Font_EnumFamiliesForEncoding,
228 "Find font for en&coding...\tCtrl-C",
229 "Find font families for given encoding");
230 menuFont->AppendSeparator();
231 menuFont->Append(Font_CheckNativeToFromString,
232 "Check Native Font Info To/From String");
233
234 // now append the freshly created menu to the menu bar...
235 wxMenuBar *menuBar = new wxMenuBar;
236 menuBar->Append(menuFile, "&File");
237 menuBar->Append(menuFont, "F&ont");
238
239 // ... and attach this menu bar to the frame
240 SetMenuBar(menuBar);
241
242 wxSplitterWindow *splitter = new wxSplitterWindow(this);
243
244 m_textctrl = new wxTextCtrl(splitter, -1,
245 "Paste text here to see how it looks\n"
246 "like in the given font",
247 wxDefaultPosition, wxDefaultSize,
248 wxTE_MULTILINE);
249
250 m_canvas = new MyCanvas(splitter);
251
252 splitter->SplitHorizontally(m_textctrl, m_canvas, 100);
253
254 // create a status bar just for fun (by default with 1 pane only)
255 CreateStatusBar();
256 SetStatusText("Welcome to wxWindows font demo!");
257 }
258
259 // --------------------------------------------------------
260
261 class MyEncodingEnumerator : public wxFontEnumerator
262 {
263 public:
264 MyEncodingEnumerator()
265 { m_n = 0; }
266
267 const wxString& GetText() const
268 { return m_text; }
269
270 protected:
271 virtual bool OnFontEncoding(const wxString& facename,
272 const wxString& encoding)
273 {
274 wxString text;
275 text.Printf(wxT("Encoding %d: %s (available in facename '%s')\n"),
276 ++m_n, encoding.c_str(), facename.c_str());
277 m_text += text;
278 return TRUE;
279 }
280
281 private:
282 size_t m_n;
283 wxString m_text;
284 };
285
286 void MyFrame::OnEnumerateEncodings(wxCommandEvent& WXUNUSED(event))
287 {
288 MyEncodingEnumerator fontEnumerator;
289
290 fontEnumerator.EnumerateEncodings();
291
292 wxLogMessage(wxT("Enumerating all available encodings:\n%s"),
293 fontEnumerator.GetText().c_str());
294 }
295
296 // -------------------------------------------------------------
297
298 class MyFontEnumerator : public wxFontEnumerator
299 {
300 public:
301 bool GotAny() const
302 { return !m_facenames.IsEmpty(); }
303
304 const wxArrayString& GetFacenames() const
305 { return m_facenames; }
306
307 protected:
308 virtual bool OnFacename(const wxString& facename)
309 {
310 m_facenames.Add(facename);
311 return TRUE;
312 }
313
314 private:
315 wxArrayString m_facenames;
316 } fontEnumerator;
317
318 bool MyFrame::DoEnumerateFamilies(bool fixedWidthOnly,
319 wxFontEncoding encoding,
320 bool silent)
321 {
322 MyFontEnumerator fontEnumerator;
323
324 fontEnumerator.EnumerateFacenames(encoding, fixedWidthOnly);
325
326 if ( fontEnumerator.GotAny() )
327 {
328 int nFacenames = fontEnumerator.GetFacenames().GetCount();
329 if ( !silent )
330 {
331 wxLogStatus(this, wxT("Found %d %sfonts"),
332 nFacenames, fixedWidthOnly ? wxT("fixed width ") : wxT(""));
333 }
334
335 wxString facename;
336 if ( silent )
337 {
338 // choose the first
339 facename = fontEnumerator.GetFacenames().Item(0);
340 }
341 else
342 {
343 // let the user choose
344 wxString *facenames = new wxString[nFacenames];
345 int n;
346 for ( n = 0; n < nFacenames; n++ )
347 facenames[n] = fontEnumerator.GetFacenames().Item(n);
348
349 n = wxGetSingleChoiceIndex("Choose a facename", "Font demo",
350 nFacenames, facenames, this);
351
352 if ( n != -1 )
353 facename = facenames[n];
354
355 delete [] facenames;
356 }
357
358 if ( !facename.IsEmpty() )
359 {
360 wxFont font(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
361 wxFONTWEIGHT_NORMAL, FALSE, facename, encoding);
362
363 DoChangeFont(font);
364 }
365
366 return TRUE;
367 }
368 else if ( !silent )
369 {
370 wxLogWarning(wxT("No such fonts found."));
371 }
372
373 return FALSE;
374 }
375
376 void MyFrame::OnEnumerateFamiliesForEncoding(wxCommandEvent& WXUNUSED(event))
377 {
378 static wxFontEncoding encodings[] =
379 {
380 wxFONTENCODING_ISO8859_1,
381 wxFONTENCODING_ISO8859_2,
382 wxFONTENCODING_ISO8859_5,
383 wxFONTENCODING_ISO8859_7,
384 wxFONTENCODING_ISO8859_15,
385 wxFONTENCODING_KOI8,
386 wxFONTENCODING_CP1250,
387 wxFONTENCODING_CP1251,
388 wxFONTENCODING_CP1252,
389 };
390
391 static const wxString encodingNames[] =
392 {
393 "Western European (ISO-8859-1)",
394 "Central European (ISO-8859-2)",
395 "Cyrillic (ISO-8859-5)",
396 "Greek (ISO-8859-7)",
397 "Western European with Euro (ISO-8859-15)",
398 "KOI8-R",
399 "Windows Central European (CP 1250)",
400 "Windows Cyrillic (CP 1251)",
401 "Windows Western European (CP 1252)",
402 };
403
404 int n = wxGetSingleChoiceIndex("Choose an encoding", "Font demo",
405 WXSIZEOF(encodingNames),
406 encodingNames,
407 this);
408
409 if ( n != -1 )
410 {
411 DoEnumerateFamilies(FALSE, encodings[n]);
412 }
413 }
414
415 void MyFrame::OnCheckNativeToFromString(wxCommandEvent& WXUNUSED(event))
416 {
417 wxString fontInfo = m_canvas->GetTextFont().GetNativeFontInfoDesc();
418
419 if ( fontInfo.IsEmpty() )
420 {
421 wxLogError(wxT("Native font info string is empty!"));
422 }
423 else
424 {
425 wxFont *font = wxFont::New(fontInfo);
426 if ( fontInfo != font->GetNativeFontInfoDesc() )
427 wxLogError(wxT("wxNativeFontInfo ToString()/FromString() broken!"));
428 else
429 wxLogError(wxT("wxNativeFontInfo works: %s"), fontInfo.c_str());
430 delete font;
431 }
432 }
433
434 void MyFrame::DoResizeFont(int diff)
435 {
436 wxFont fontOld = m_canvas->GetTextFont();
437
438 DoChangeFont(
439 wxFont(
440 fontOld.GetPointSize() + diff,
441 fontOld.GetFamily(),
442 fontOld.GetStyle(),
443 fontOld.GetWeight(),
444 fontOld.GetUnderlined(),
445 fontOld.GetFaceName(),
446 fontOld.GetEncoding()
447 )
448 );
449 }
450
451 void MyFrame::DoChangeFont(const wxFont& font, const wxColour& col)
452 {
453 m_canvas->SetTextFont(font);
454 if ( col.Ok() )
455 m_canvas->SetColour(col);
456 m_canvas->Refresh();
457
458 m_textctrl->SetFont(font);
459 if ( col.Ok() )
460 m_textctrl->SetForegroundColour(col);
461 }
462
463 void MyFrame::OnSelectFont(wxCommandEvent& WXUNUSED(event))
464 {
465 wxFontData data;
466 data.SetInitialFont(m_canvas->GetTextFont());
467 data.SetColour(m_canvas->GetColour());
468
469 wxFontDialog dialog(this, &data);
470 if ( dialog.ShowModal() == wxID_OK )
471 {
472 wxFontData retData = dialog.GetFontData();
473 wxFont font = retData.GetChosenFont();
474 wxColour colour = retData.GetColour();
475
476 DoChangeFont(font, colour);
477 }
478 }
479
480 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
481 {
482 // TRUE is to force the frame to close
483 Close(TRUE);
484 }
485
486 void MyFrame::OnViewMsg(wxCommandEvent& WXUNUSED(event))
487 {
488 // first, choose the file
489 static wxString s_dir, s_file;
490 wxFileDialog dialog(this, "Open an email message file",
491 s_dir, s_file);
492 if ( dialog.ShowModal() != wxID_OK )
493 return;
494
495 // save for the next time
496 s_dir = dialog.GetDirectory();
497 s_file = dialog.GetFilename();
498
499 wxString filename = dialog.GetPath();
500
501 // load it and search for Content-Type header
502 wxTextFile file(filename);
503 if ( !file.Open() )
504 return;
505
506 wxString charset;
507
508 static const char *prefix = "Content-Type: text/plain; charset=";
509 const size_t len = strlen(prefix);
510
511 size_t n, count = file.GetLineCount();
512 for ( n = 0; n < count; n++ )
513 {
514 wxString line = file[n];
515
516 if ( !line )
517 {
518 // if it is an email message, headers are over, no need to parse
519 // all the file
520 break;
521 }
522
523 if ( line.Left(len) == prefix )
524 {
525 // found!
526 const wxChar *pc = line.c_str() + len;
527 if ( *pc == '"' )
528 pc++;
529
530 while ( *pc && *pc != '"' )
531 {
532 charset += *pc++;
533 }
534
535 break;
536 }
537 }
538
539 if ( !charset )
540 {
541 wxLogError(wxT("The file '%s' doesn't contain charset information."),
542 filename.c_str());
543
544 return;
545 }
546
547 // ok, now get the corresponding encoding
548 wxFontEncoding fontenc = wxTheFontMapper->CharsetToEncoding(charset);
549 if ( fontenc == wxFONTENCODING_SYSTEM )
550 {
551 wxLogError(wxT("Charset '%s' is unsupported."), charset.c_str());
552 return;
553 }
554
555 m_textctrl->LoadFile(filename);
556
557 if ( fontenc == wxFONTENCODING_UTF8 ||
558 !wxTheFontMapper->IsEncodingAvailable(fontenc) )
559 {
560 // try to find some similar encoding:
561 wxFontEncoding encAlt;
562 if ( wxTheFontMapper->GetAltForEncoding(fontenc, &encAlt) )
563 {
564 wxEncodingConverter conv;
565
566 if (conv.Init(fontenc, encAlt))
567 {
568 fontenc = encAlt;
569 m_textctrl -> SetValue(conv.Convert(m_textctrl -> GetValue()));
570 }
571 else
572 {
573 wxLogWarning(wxT("Cannot convert from '%s' to '%s'."),
574 wxFontMapper::GetEncodingDescription(fontenc).c_str(),
575 wxFontMapper::GetEncodingDescription(encAlt).c_str());
576 }
577 }
578 else
579 wxLogWarning(wxT("No fonts for encoding '%s' on this system."),
580 wxFontMapper::GetEncodingDescription(fontenc).c_str());
581 }
582
583 // and now create the correct font
584 if ( !DoEnumerateFamilies(FALSE, fontenc, TRUE /* silent */) )
585 {
586 wxFont font(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL,
587 wxFONTWEIGHT_NORMAL, FALSE /* !underlined */,
588 wxEmptyString /* facename */, fontenc);
589 if ( font.Ok() )
590 {
591 DoChangeFont(font);
592 }
593 else
594 {
595 wxLogWarning(wxT("No fonts for encoding '%s' on this system."),
596 wxFontMapper::GetEncodingDescription(fontenc).c_str());
597 }
598 }
599 }
600
601 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
602 {
603 wxMessageBox("wxWindows font demo\n"
604 "(c) 1999 Vadim Zeitlin",
605 "About Font",
606 wxOK | wxICON_INFORMATION, this);
607 }
608
609 // ----------------------------------------------------------------------------
610 // MyCanvas
611 // ----------------------------------------------------------------------------
612
613 BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
614 EVT_PAINT(MyCanvas::OnPaint)
615 END_EVENT_TABLE()
616
617 MyCanvas::MyCanvas( wxWindow *parent )
618 : wxWindow( parent, -1 ),
619 m_colour(*wxRED), m_font(*wxNORMAL_FONT)
620 {
621 }
622
623 MyCanvas::~MyCanvas()
624 {
625 }
626
627 void MyCanvas::OnPaint( wxPaintEvent &WXUNUSED(event) )
628 {
629 wxPaintDC dc(this);
630 PrepareDC(dc);
631
632 // set background
633 dc.SetBackground(wxBrush(wxT("white"), wxSOLID));
634 dc.Clear();
635
636 // output the font name/info
637 wxString fontInfo;
638 fontInfo.Printf(wxT("Font size is %d points, family is %s, encoding is '%s', style %s, weight %s"),
639 m_font.GetPointSize(),
640 m_font.GetFamilyString().c_str(),
641 wxTheFontMapper->
642 GetEncodingDescription(m_font.GetEncoding()).c_str(),
643 m_font.GetStyleString().c_str(),
644 m_font.GetWeightString().c_str());
645
646 dc.DrawText(fontInfo, 5, 5);
647
648 if ( m_font.Ok() )
649 {
650 wxString fontDesc = m_font.GetNativeFontInfoDesc();
651 dc.SetFont(m_font);
652 fontInfo.Printf(wxT("Native font info: %s"), fontDesc.c_str());
653 dc.DrawText(fontInfo, 5, 5 + dc.GetCharHeight());
654 }
655
656 // prepare to draw the font
657 dc.SetFont(m_font);
658 dc.SetTextForeground(m_colour);
659
660 // the size of one cell (char + small margin)
661 int w = dc.GetCharWidth() + 5,
662 h = dc.GetCharHeight() + 4;
663
664 // the origin for our table
665 int x = 5,
666 y = 2*h;
667
668 // print all font symbols from 32 to 256 in 7 rows of 32 chars each
669 for ( int i = 1; i < 8; i++ )
670 {
671 for ( int j = 0; j < 32; j++ )
672 {
673 dc.DrawText(wxChar(32*i + j), x + w*j, y + h*i);
674 }
675 }
676
677 // draw the lines between them
678 dc.SetPen(wxPen(wxColour("blue"), 1, wxSOLID));
679 int l;
680
681 // horizontal
682 y += h;
683 for ( l = 0; l < 8; l++ )
684 {
685 int yl = y + h*l - 2;
686 dc.DrawLine(x - 2, yl, x + 32*w - 2, yl);
687 }
688
689 // and vertical
690 for ( l = 0; l < 33; l++ )
691 {
692 int xl = x + w*l - 2;
693 dc.DrawLine(xl, y, xl, y + 7*h - 2);
694 }
695 }