SetStyle/GetStyle corrections
[wxWidgets.git] / samples / richtext / richtext.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: samples/richtext/richtext.cpp
3 // Purpose: wxWidgets rich text editor sample
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2005-10-02
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx/wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 // for all others, include the necessary headers (this file is usually all you
28 // need because it includes almost all "standard" wxWidgets headers)
29 #ifndef WX_PRECOMP
30 #include "wx/wx.h"
31 #endif
32
33 #include "wx/fontdlg.h"
34 #include "wx/splitter.h"
35 #include "wx/sstream.h"
36 #include "wx/html/htmlwin.h"
37
38 #include "bitmaps/sample.xpm"
39 #include "bitmaps/smiley.xpm"
40 // #include "bitmaps/idea.xpm"
41 #include "bitmaps/zebra.xpm"
42
43 #include "bitmaps/open.xpm"
44 #include "bitmaps/save.xpm"
45 #include "bitmaps/copy.xpm"
46 #include "bitmaps/cut.xpm"
47 #include "bitmaps/paste.xpm"
48 #include "bitmaps/undo.xpm"
49 #include "bitmaps/redo.xpm"
50 #include "bitmaps/bold.xpm"
51 #include "bitmaps/italic.xpm"
52 #include "bitmaps/underline.xpm"
53
54 #include "bitmaps/alignleft.xpm"
55 #include "bitmaps/alignright.xpm"
56 #include "bitmaps/centre.xpm"
57 #include "bitmaps/font.xpm"
58 #include "bitmaps/indentless.xpm"
59 #include "bitmaps/indentmore.xpm"
60
61 #include "wx/richtext/richtextctrl.h"
62 #include "wx/richtext/richtextstyles.h"
63 #include "wx/richtext/richtextxml.h"
64 #include "wx/richtext/richtexthtml.h"
65
66 // ----------------------------------------------------------------------------
67 // resources
68 // ----------------------------------------------------------------------------
69
70 // ----------------------------------------------------------------------------
71 // private classes
72 // ----------------------------------------------------------------------------
73
74 // Define a new application type, each program should derive a class from wxApp
75 class MyApp : public wxApp
76 {
77 public:
78 // override base class virtuals
79 // ----------------------------
80
81 // this one is called on application startup and is a good place for the app
82 // initialization (doing it here and not in the ctor allows to have an error
83 // return: if OnInit() returns false, the application terminates)
84 virtual bool OnInit();
85 virtual int OnExit();
86
87 void CreateStyles();
88
89 wxRichTextStyleSheet* GetStyleSheet() const { return m_styleSheet; }
90
91 wxRichTextStyleSheet* m_styleSheet;
92 };
93
94 // Define a new frame type: this is going to be our main frame
95 class MyFrame : public wxFrame
96 {
97 public:
98 // ctor(s)
99 MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
100 const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
101
102 // event handlers (these functions should _not_ be virtual)
103 void OnQuit(wxCommandEvent& event);
104 void OnAbout(wxCommandEvent& event);
105
106 void OnOpen(wxCommandEvent& event);
107 void OnSave(wxCommandEvent& event);
108 void OnSaveAs(wxCommandEvent& event);
109
110 void OnBold(wxCommandEvent& event);
111 void OnItalic(wxCommandEvent& event);
112 void OnUnderline(wxCommandEvent& event);
113
114 void OnUpdateBold(wxUpdateUIEvent& event);
115 void OnUpdateItalic(wxUpdateUIEvent& event);
116 void OnUpdateUnderline(wxUpdateUIEvent& event);
117
118 void OnAlignLeft(wxCommandEvent& event);
119 void OnAlignCentre(wxCommandEvent& event);
120 void OnAlignRight(wxCommandEvent& event);
121
122 void OnUpdateAlignLeft(wxUpdateUIEvent& event);
123 void OnUpdateAlignCentre(wxUpdateUIEvent& event);
124 void OnUpdateAlignRight(wxUpdateUIEvent& event);
125
126 void OnFont(wxCommandEvent& event);
127 void OnIndentMore(wxCommandEvent& event);
128 void OnIndentLess(wxCommandEvent& event);
129
130 void OnLineSpacingHalf(wxCommandEvent& event);
131 void OnLineSpacingDouble(wxCommandEvent& event);
132 void OnLineSpacingSingle(wxCommandEvent& event);
133
134 void OnParagraphSpacingMore(wxCommandEvent& event);
135 void OnParagraphSpacingLess(wxCommandEvent& event);
136
137 void OnViewHTML(wxCommandEvent& event);
138
139 // Forward command events to the current rich text control, if any
140 bool ProcessEvent(wxEvent& event);
141
142 private:
143 // any class wishing to process wxWidgets events must use this macro
144 DECLARE_EVENT_TABLE()
145
146 wxRichTextCtrl* m_richTextCtrl;
147 };
148
149 // ----------------------------------------------------------------------------
150 // constants
151 // ----------------------------------------------------------------------------
152
153 // IDs for the controls and the menu commands
154 enum
155 {
156 // menu items
157 ID_Quit = wxID_EXIT,
158 ID_About = wxID_ABOUT,
159
160 ID_FORMAT_BOLD = 100,
161 ID_FORMAT_ITALIC,
162 ID_FORMAT_UNDERLINE,
163 ID_FORMAT_FONT,
164
165 ID_FORMAT_ALIGN_LEFT,
166 ID_FORMAT_ALIGN_CENTRE,
167 ID_FORMAT_ALIGN_RIGHT,
168
169 ID_FORMAT_INDENT_MORE,
170 ID_FORMAT_INDENT_LESS,
171
172 ID_FORMAT_PARAGRAPH_SPACING_MORE,
173 ID_FORMAT_PARAGRAPH_SPACING_LESS,
174
175 ID_FORMAT_LINE_SPACING_HALF,
176 ID_FORMAT_LINE_SPACING_DOUBLE,
177 ID_FORMAT_LINE_SPACING_SINGLE,
178
179 ID_VIEW_HTML
180 };
181
182 // ----------------------------------------------------------------------------
183 // event tables and other macros for wxWidgets
184 // ----------------------------------------------------------------------------
185
186 // the event tables connect the wxWidgets events with the functions (event
187 // handlers) which process them. It can be also done at run-time, but for the
188 // simple menu events like this the static method is much simpler.
189 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
190 EVT_MENU(ID_Quit, MyFrame::OnQuit)
191 EVT_MENU(ID_About, MyFrame::OnAbout)
192
193 EVT_MENU(wxID_OPEN, MyFrame::OnOpen)
194 EVT_MENU(wxID_SAVE, MyFrame::OnSave)
195 EVT_MENU(wxID_SAVEAS, MyFrame::OnSaveAs)
196
197 EVT_MENU(ID_FORMAT_BOLD, MyFrame::OnBold)
198 EVT_MENU(ID_FORMAT_ITALIC, MyFrame::OnItalic)
199 EVT_MENU(ID_FORMAT_UNDERLINE, MyFrame::OnUnderline)
200
201 EVT_UPDATE_UI(ID_FORMAT_BOLD, MyFrame::OnUpdateBold)
202 EVT_UPDATE_UI(ID_FORMAT_ITALIC, MyFrame::OnUpdateItalic)
203 EVT_UPDATE_UI(ID_FORMAT_UNDERLINE, MyFrame::OnUpdateUnderline)
204
205 EVT_MENU(ID_FORMAT_ALIGN_LEFT, MyFrame::OnAlignLeft)
206 EVT_MENU(ID_FORMAT_ALIGN_CENTRE, MyFrame::OnAlignCentre)
207 EVT_MENU(ID_FORMAT_ALIGN_RIGHT, MyFrame::OnAlignRight)
208
209 EVT_UPDATE_UI(ID_FORMAT_ALIGN_LEFT, MyFrame::OnUpdateAlignLeft)
210 EVT_UPDATE_UI(ID_FORMAT_ALIGN_CENTRE, MyFrame::OnUpdateAlignCentre)
211 EVT_UPDATE_UI(ID_FORMAT_ALIGN_RIGHT, MyFrame::OnUpdateAlignRight)
212
213 EVT_MENU(ID_FORMAT_FONT, MyFrame::OnFont)
214 EVT_MENU(ID_FORMAT_INDENT_MORE, MyFrame::OnIndentMore)
215 EVT_MENU(ID_FORMAT_INDENT_LESS, MyFrame::OnIndentLess)
216
217 EVT_MENU(ID_FORMAT_LINE_SPACING_HALF, MyFrame::OnLineSpacingHalf)
218 EVT_MENU(ID_FORMAT_LINE_SPACING_SINGLE, MyFrame::OnLineSpacingSingle)
219 EVT_MENU(ID_FORMAT_LINE_SPACING_DOUBLE, MyFrame::OnLineSpacingDouble)
220
221 EVT_MENU(ID_FORMAT_PARAGRAPH_SPACING_MORE, MyFrame::OnParagraphSpacingMore)
222 EVT_MENU(ID_FORMAT_PARAGRAPH_SPACING_LESS, MyFrame::OnParagraphSpacingLess)
223
224 EVT_MENU(ID_VIEW_HTML, MyFrame::OnViewHTML)
225 END_EVENT_TABLE()
226
227 // Create a new application object: this macro will allow wxWidgets to create
228 // the application object during program execution (it's better than using a
229 // static object for many reasons) and also implements the accessor function
230 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
231 // not wxApp)
232 IMPLEMENT_APP(MyApp)
233
234 // ============================================================================
235 // implementation
236 // ============================================================================
237
238 // ----------------------------------------------------------------------------
239 // the application class
240 // ----------------------------------------------------------------------------
241
242 // 'Main program' equivalent: the program execution "starts" here
243 bool MyApp::OnInit()
244 {
245 m_styleSheet = new wxRichTextStyleSheet;
246
247 CreateStyles();
248
249 // Add extra handlers (plain text is automatically added)
250 wxRichTextBuffer::AddHandler(new wxRichTextXMLHandler);
251 wxRichTextBuffer::AddHandler(new wxRichTextHTMLHandler);
252
253 // Add image handlers
254 #if wxUSE_LIBPNG
255 wxImage::AddHandler( new wxPNGHandler );
256 #endif
257
258 #if wxUSE_LIBJPEG
259 wxImage::AddHandler( new wxJPEGHandler );
260 #endif
261
262 #if wxUSE_GIF
263 wxImage::AddHandler( new wxGIFHandler );
264 #endif
265
266 // create the main application window
267 MyFrame *frame = new MyFrame(_T("wxRichTextCtrl Sample"), wxID_ANY, wxDefaultPosition, wxSize(600, 500));
268
269 // and show it (the frames, unlike simple controls, are not shown when
270 // created initially)
271 frame->Show(true);
272
273 // success: wxApp::OnRun() will be called which will enter the main message
274 // loop and the application will run. If we returned false here, the
275 // application would exit immediately.
276 return true;
277 }
278
279 int MyApp::OnExit()
280 {
281 delete m_styleSheet;
282 return 0;
283 }
284
285 void MyApp::CreateStyles()
286 {
287 // Paragraph styles
288
289 wxFont romanFont(12, wxROMAN, wxNORMAL, wxNORMAL);
290 wxFont swissFont(12, wxSWISS, wxNORMAL, wxNORMAL);
291
292 wxRichTextParagraphStyleDefinition* normalPara = new wxRichTextParagraphStyleDefinition(wxT("Normal"));
293 wxRichTextAttr normalAttr;
294 normalAttr.SetFontFaceName(romanFont.GetFaceName());
295 normalAttr.SetFontSize(12);
296 // Let's set all attributes for this style
297 normalAttr.SetFlags(wxTEXT_ATTR_FONT | wxTEXT_ATTR_BACKGROUND_COLOUR | wxTEXT_ATTR_TEXT_COLOUR|wxTEXT_ATTR_ALIGNMENT|wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT|wxTEXT_ATTR_TABS|
298 wxTEXT_ATTR_PARA_SPACING_BEFORE|wxTEXT_ATTR_PARA_SPACING_AFTER|wxTEXT_ATTR_LINE_SPACING|
299 wxTEXT_ATTR_BULLET_STYLE|wxTEXT_ATTR_BULLET_NUMBER);
300 normalPara->SetStyle(normalAttr);
301
302 m_styleSheet->AddParagraphStyle(normalPara);
303
304 wxRichTextParagraphStyleDefinition* indentedPara = new wxRichTextParagraphStyleDefinition(wxT("Indented"));
305 wxRichTextAttr indentedAttr;
306 indentedAttr.SetFontFaceName(romanFont.GetFaceName());
307 indentedAttr.SetFontSize(12);
308 indentedAttr.SetLeftIndent(100, 0);
309 // We only want to affect indentation
310 indentedAttr.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT);
311 indentedPara->SetStyle(indentedAttr);
312
313 m_styleSheet->AddParagraphStyle(indentedPara);
314
315 wxRichTextParagraphStyleDefinition* indentedPara2 = new wxRichTextParagraphStyleDefinition(wxT("Red Bold Indented"));
316 wxRichTextAttr indentedAttr2;
317 indentedAttr2.SetFontFaceName(romanFont.GetFaceName());
318 indentedAttr2.SetFontSize(12);
319 indentedAttr2.SetFontWeight(wxBOLD);
320 indentedAttr2.SetTextColour(*wxRED);
321 indentedAttr2.SetFontSize(12);
322 indentedAttr2.SetLeftIndent(100, 0);
323 // We want to affect indentation, font and text colour
324 indentedAttr2.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT|wxTEXT_ATTR_FONT|wxTEXT_ATTR_TEXT_COLOUR);
325 indentedPara2->SetStyle(indentedAttr2);
326
327 m_styleSheet->AddParagraphStyle(indentedPara2);
328
329 wxRichTextParagraphStyleDefinition* flIndentedPara = new wxRichTextParagraphStyleDefinition(wxT("First Line Indented"));
330 wxRichTextAttr flIndentedAttr;
331 flIndentedAttr.SetFontFaceName(swissFont.GetFaceName());
332 flIndentedAttr.SetFontSize(12);
333 flIndentedAttr.SetLeftIndent(100, -100);
334 // We only want to affect indentation
335 flIndentedAttr.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT);
336 flIndentedPara->SetStyle(flIndentedAttr);
337
338 m_styleSheet->AddParagraphStyle(flIndentedPara);
339
340 // Character styles
341
342 wxRichTextCharacterStyleDefinition* boldDef = new wxRichTextCharacterStyleDefinition(wxT("Bold"));
343 wxRichTextAttr boldAttr;
344 boldAttr.SetFontFaceName(romanFont.GetFaceName());
345 boldAttr.SetFontSize(12);
346 boldAttr.SetFontWeight(wxBOLD);
347 // We only want to affect boldness
348 boldAttr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
349 boldDef->SetStyle(boldAttr);
350
351 m_styleSheet->AddCharacterStyle(boldDef);
352
353 wxRichTextCharacterStyleDefinition* italicDef = new wxRichTextCharacterStyleDefinition(wxT("Italic"));
354 wxRichTextAttr italicAttr;
355 italicAttr.SetFontFaceName(romanFont.GetFaceName());
356 italicAttr.SetFontSize(12);
357 italicAttr.SetFontStyle(wxITALIC);
358 // We only want to affect italics
359 italicAttr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
360 italicDef->SetStyle(italicAttr);
361
362 m_styleSheet->AddCharacterStyle(italicDef);
363
364 wxRichTextCharacterStyleDefinition* redDef = new wxRichTextCharacterStyleDefinition(wxT("Red Bold"));
365 wxRichTextAttr redAttr;
366 redAttr.SetFontFaceName(romanFont.GetFaceName());
367 redAttr.SetFontSize(12);
368 redAttr.SetFontWeight(wxBOLD);
369 redAttr.SetTextColour(*wxRED);
370 // We only want to affect colour, weight and face
371 redAttr.SetFlags(wxTEXT_ATTR_FONT_FACE|wxTEXT_ATTR_FONT_WEIGHT|wxTEXT_ATTR_TEXT_COLOUR);
372 redDef->SetStyle(redAttr);
373
374 m_styleSheet->AddCharacterStyle(redDef);
375 }
376
377 // ----------------------------------------------------------------------------
378 // main frame
379 // ----------------------------------------------------------------------------
380
381 // frame constructor
382 MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
383 const wxSize& size, long style)
384 : wxFrame(NULL, id, title, pos, size, style)
385 {
386 // set the frame icon
387 SetIcon(sample_xpm);
388
389 // create a menu bar
390 wxMenu *fileMenu = new wxMenu;
391
392 // the "About" item should be in the help menu
393 wxMenu *helpMenu = new wxMenu;
394 helpMenu->Append(ID_About, _T("&About...\tF1"), _T("Show about dialog"));
395
396 fileMenu->Append(wxID_OPEN, _T("&Open\tCtrl+O"), _T("Open a file"));
397 fileMenu->Append(wxID_SAVE, _T("&Save\tCtrl+S"), _T("Save a file"));
398 fileMenu->Append(wxID_SAVEAS, _T("&Save As...\tF12"), _T("Save to a new file"));
399 fileMenu->AppendSeparator();
400 fileMenu->Append(ID_VIEW_HTML, _T("&View as HTML"), _T("View HTML"));
401 fileMenu->AppendSeparator();
402 fileMenu->Append(ID_Quit, _T("E&xit\tAlt+X"), _T("Quit this program"));
403
404 wxMenu* editMenu = new wxMenu;
405 editMenu->Append(wxID_UNDO, _("&Undo\tCtrl+Z"));
406 editMenu->Append(wxID_REDO, _("&Redo\tCtrl+Y"));
407 editMenu->AppendSeparator();
408 editMenu->Append(wxID_CUT, _("Cu&t\tCtrl+X"));
409 editMenu->Append(wxID_COPY, _("&Copy\tCtrl+C"));
410 editMenu->Append(wxID_PASTE, _("&Paste\tCtrl+V"));
411
412 editMenu->Append(wxID_CLEAR, _("&Delete\tDel"));
413
414 editMenu->AppendSeparator();
415 editMenu->Append(wxID_SELECTALL, _("Select A&ll\tCtrl+A"));
416 #if 0
417 editMenu->AppendSeparator();
418 editMenu->Append(wxID_FIND, _("&Find...\tCtrl+F"));
419 editMenu->Append(stID_FIND_REPLACE, _("&Replace...\tCtrl+R"));
420 #endif
421
422 wxMenu* formatMenu = new wxMenu;
423 formatMenu->AppendCheckItem(ID_FORMAT_BOLD, _("&Bold\tCtrl+B"));
424 formatMenu->AppendCheckItem(ID_FORMAT_ITALIC, _("&Italic\tCtrl+I"));
425 formatMenu->AppendCheckItem(ID_FORMAT_UNDERLINE, _("&Underline\tCtrl+U"));
426 formatMenu->AppendSeparator();
427 formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_LEFT, _("L&eft Align"));
428 formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_RIGHT, _("&Right Align"));
429 formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_CENTRE, _("&Centre"));
430 formatMenu->AppendSeparator();
431 formatMenu->Append(ID_FORMAT_INDENT_MORE, _("Indent &More"));
432 formatMenu->Append(ID_FORMAT_INDENT_LESS, _("Indent &Less"));
433 formatMenu->AppendSeparator();
434 formatMenu->Append(ID_FORMAT_PARAGRAPH_SPACING_MORE, _("Increase Paragraph &Spacing"));
435 formatMenu->Append(ID_FORMAT_PARAGRAPH_SPACING_LESS, _("Decrease &Paragraph Spacing"));
436 formatMenu->AppendSeparator();
437 formatMenu->Append(ID_FORMAT_LINE_SPACING_SINGLE, _("Normal Line Spacing"));
438 formatMenu->Append(ID_FORMAT_LINE_SPACING_HALF, _("1.5 Line Spacing"));
439 formatMenu->Append(ID_FORMAT_LINE_SPACING_DOUBLE, _("Double Line Spacing"));
440 formatMenu->AppendSeparator();
441 formatMenu->Append(ID_FORMAT_FONT, _("&Font..."));
442
443 // now append the freshly created menu to the menu bar...
444 wxMenuBar *menuBar = new wxMenuBar();
445 menuBar->Append(fileMenu, _T("&File"));
446 menuBar->Append(editMenu, _T("&Edit"));
447 menuBar->Append(formatMenu, _T("F&ormat"));
448 menuBar->Append(helpMenu, _T("&Help"));
449
450 // ... and attach this menu bar to the frame
451 SetMenuBar(menuBar);
452
453 // create a status bar just for fun (by default with 1 pane only)
454 #if wxUSE_STATUSBAR
455 CreateStatusBar(2);
456 SetStatusText(_T("Welcome to wxRichTextCtrl!"));
457 #endif
458
459 wxToolBar* toolBar = CreateToolBar();
460
461 toolBar->AddTool(wxID_OPEN, wxBitmap(open_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Open"));
462 toolBar->AddTool(wxID_SAVEAS, wxBitmap(save_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Save"));
463 toolBar->AddSeparator();
464 toolBar->AddTool(wxID_CUT, wxBitmap(cut_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Cut"));
465 toolBar->AddTool(wxID_COPY, wxBitmap(copy_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Copy"));
466 toolBar->AddTool(wxID_PASTE, wxBitmap(paste_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Paste"));
467 toolBar->AddSeparator();
468 toolBar->AddTool(wxID_UNDO, wxBitmap(undo_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Undo"));
469 toolBar->AddTool(wxID_REDO, wxBitmap(redo_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Redo"));
470 toolBar->AddSeparator();
471 toolBar->AddTool(ID_FORMAT_BOLD, wxBitmap(bold_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Bold"));
472 toolBar->AddTool(ID_FORMAT_ITALIC, wxBitmap(italic_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Italic"));
473 toolBar->AddTool(ID_FORMAT_UNDERLINE, wxBitmap(underline_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Underline"));
474 toolBar->AddSeparator();
475 toolBar->AddTool(ID_FORMAT_ALIGN_LEFT, wxBitmap(alignleft_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Align Left"));
476 toolBar->AddTool(ID_FORMAT_ALIGN_CENTRE, wxBitmap(centre_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Centre"));
477 toolBar->AddTool(ID_FORMAT_ALIGN_RIGHT, wxBitmap(alignright_xpm), wxNullBitmap, true, -1, -1, (wxObject *) NULL, _("Align Right"));
478 toolBar->AddSeparator();
479 toolBar->AddTool(ID_FORMAT_INDENT_LESS, wxBitmap(indentless_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Indent Less"));
480 toolBar->AddTool(ID_FORMAT_INDENT_MORE, wxBitmap(indentmore_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Indent More"));
481 toolBar->AddSeparator();
482 toolBar->AddTool(ID_FORMAT_FONT, wxBitmap(font_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Font"));
483
484 toolBar->Realize();
485
486 wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, GetClientSize(), wxSP_NO_XP_THEME|wxSP_3D|wxSP_LIVE_UPDATE);
487
488 wxFont textFont = wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
489 wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD);
490 wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL);
491
492 m_richTextCtrl = new wxRichTextCtrl(splitter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS);
493 wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL);
494
495 m_richTextCtrl->SetFont(font);
496
497 wxRichTextStyleListBox* styleListBox = new wxRichTextStyleListBox(splitter, wxID_ANY);
498 splitter->SplitVertically(m_richTextCtrl, styleListBox, 400);
499
500 splitter->UpdateSize();
501
502 styleListBox->SetStyleSheet(wxGetApp().GetStyleSheet());
503 styleListBox->SetRichTextCtrl(m_richTextCtrl);
504 styleListBox->UpdateStyles();
505
506 wxRichTextCtrl& r = *m_richTextCtrl;
507
508 r.BeginSuppressUndo();
509
510 r.BeginParagraphSpacing(0, 20);
511
512 r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
513 r.BeginBold();
514
515 r.BeginFontSize(14);
516 r.WriteText(wxT("Welcome to wxRichTextCtrl, a wxWidgets control for editing and presenting styled text and images"));
517 r.EndFontSize();
518 r.Newline();
519
520 r.BeginItalic();
521 r.WriteText(wxT("by Julian Smart"));
522 r.EndItalic();
523
524 r.EndBold();
525
526 r.Newline();
527 r.WriteImage(wxBitmap(zebra_xpm));
528
529 r.EndAlignment();
530
531 r.Newline();
532 r.Newline();
533
534 r.WriteText(wxT("What can you do with this thing? "));
535 r.WriteImage(wxBitmap(smiley_xpm));
536 r.WriteText(wxT(" Well, you can change text "));
537
538 r.BeginTextColour(wxColour(255, 0, 0));
539 r.WriteText(wxT("colour, like this red bit."));
540 r.EndTextColour();
541
542 r.BeginTextColour(wxColour(0, 0, 255));
543 r.WriteText(wxT(" And this blue bit."));
544 r.EndTextColour();
545
546 r.WriteText(wxT(" Naturally you can make things "));
547 r.BeginBold();
548 r.WriteText(wxT("bold "));
549 r.EndBold();
550 r.BeginItalic();
551 r.WriteText(wxT("or italic "));
552 r.EndItalic();
553 r.BeginUnderline();
554 r.WriteText(wxT("or underlined."));
555 r.EndUnderline();
556
557 r.BeginFontSize(14);
558 r.WriteText(wxT(" Different font sizes on the same line is allowed, too."));
559 r.EndFontSize();
560
561 r.WriteText(wxT(" Next we'll show an indented paragraph."));
562
563 r.BeginLeftIndent(60);
564 r.Newline();
565
566 r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
567 r.EndLeftIndent();
568
569 r.Newline();
570
571 r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40)."));
572
573 r.BeginLeftIndent(100, -40);
574 r.Newline();
575
576 r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
577 r.EndLeftIndent();
578
579 r.Newline();
580
581 r.WriteText(wxT("Numbered bullets are possible, again using subindents:"));
582
583 r.BeginNumberedBullet(1, 100, 60);
584 r.Newline();
585
586 r.WriteText(wxT("This is my first item. Note that wxRichTextCtrl doesn't automatically do numbering, but this will be added later."));
587 r.EndNumberedBullet();
588
589 r.BeginNumberedBullet(2, 100, 60);
590 r.Newline();
591
592 r.WriteText(wxT("This is my second item."));
593 r.EndNumberedBullet();
594
595 r.Newline();
596
597 r.WriteText(wxT("The following paragraph is right-indented:"));
598
599 r.BeginRightIndent(200);
600 r.Newline();
601
602 r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
603 r.EndRightIndent();
604
605 r.Newline();
606
607 r.WriteText(wxT("The following paragraph is right-aligned with 1.5 line spacing:"));
608
609 r.BeginAlignment(wxTEXT_ALIGNMENT_RIGHT);
610 r.BeginLineSpacing(wxTEXT_ATTR_LINE_SPACING_HALF);
611 r.Newline();
612
613 r.WriteText(wxT("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable."));
614 r.EndLineSpacing();
615 r.EndAlignment();
616
617 wxArrayInt tabs;
618 tabs.Add(400);
619 tabs.Add(600);
620 tabs.Add(800);
621 tabs.Add(1000);
622 wxTextAttrEx attr;
623 attr.SetFlags(wxTEXT_ATTR_TABS);
624 attr.SetTabs(tabs);
625 r.SetDefaultStyle(attr);
626
627 r.Newline();
628 r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab"));
629
630 r.Newline();
631 r.WriteText(wxT("Other notable features of wxRichTextCtrl include:"));
632
633 r.BeginSymbolBullet(wxT('*'), 100, 60);
634 r.Newline();
635 r.WriteText(wxT("Compatibility with wxTextCtrl API"));
636 r.EndSymbolBullet();
637
638 r.BeginSymbolBullet(wxT('*'), 100, 60);
639 r.Newline();
640 r.WriteText(wxT("Easy stack-based BeginXXX()...EndXXX() style setting in addition to SetStyle()"));
641 r.EndSymbolBullet();
642
643 r.BeginSymbolBullet(wxT('*'), 100, 60);
644 r.Newline();
645 r.WriteText(wxT("XML loading and saving"));
646 r.EndSymbolBullet();
647
648 r.BeginSymbolBullet(wxT('*'), 100, 60);
649 r.Newline();
650 r.WriteText(wxT("Undo/Redo, with batching option and Undo suppressing"));
651 r.EndSymbolBullet();
652
653 r.BeginSymbolBullet(wxT('*'), 100, 60);
654 r.Newline();
655 r.WriteText(wxT("Clipboard copy and paste"));
656 r.EndSymbolBullet();
657
658 r.BeginSymbolBullet(wxT('*'), 100, 60);
659 r.Newline();
660 r.WriteText(wxT("wxRichTextStyleSheet with named character and paragraph styles, and control for applying named styles"));
661 r.EndSymbolBullet();
662
663 r.BeginSymbolBullet(wxT('*'), 100, 60);
664 r.Newline();
665 r.WriteText(wxT("A design that can easily be extended to other content types, ultimately with text boxes, tables, controls, and so on"));
666 r.EndSymbolBullet();
667
668 r.Newline();
669
670 r.WriteText(wxT("Note: this sample content was generated programmatically from within the MyFrame constructor in the demo. The images were loaded from inline XPMs. Enjoy wxRichTextCtrl!"));
671
672 r.EndParagraphSpacing();
673
674 r.EndSuppressUndo();
675 }
676
677
678 // event handlers
679
680 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
681 {
682 // true is to force the frame to close
683 Close(true);
684 }
685
686 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
687 {
688 wxString msg;
689 msg.Printf( _T("This is a demo for wxRichTextCtrl, a control for editing styled text.\n(c) Julian Smart, 2005"));
690 wxMessageBox(msg, _T("About wxRichTextCtrl Sample"), wxOK | wxICON_INFORMATION, this);
691 }
692
693 // Forward command events to the current rich text control, if any
694 bool MyFrame::ProcessEvent(wxEvent& event)
695 {
696 if (event.IsCommandEvent() && !event.IsKindOf(CLASSINFO(wxChildFocusEvent)))
697 {
698 // Problem: we can get infinite recursion because the events
699 // climb back up to this frame, and repeat.
700 // Assume that command events don't cause another command event
701 // to be called, so we can rely on inCommand not being overwritten
702
703 static int s_eventType = 0;
704 static wxWindowID s_id = 0;
705
706 if (s_id != event.GetId() && s_eventType != event.GetEventType())
707 {
708 s_eventType = event.GetEventType();
709 s_id = event.GetId();
710
711 wxWindow* focusWin = wxFindFocusDescendant(this);
712 if (focusWin && focusWin->ProcessEvent(event))
713 {
714 //s_command = NULL;
715 s_eventType = 0;
716 s_id = 0;
717 return true;
718 }
719
720 s_eventType = 0;
721 s_id = 0;
722 }
723 else
724 {
725 return false;
726 }
727 }
728
729 return wxFrame::ProcessEvent(event);
730 }
731
732 void MyFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
733 {
734 wxString path;
735 wxString filename;
736 wxArrayInt fileTypes;
737
738 wxString filter = wxRichTextBuffer::GetExtWildcard(false, false, & fileTypes);
739 if (!filter.empty())
740 filter += wxT("|");
741 filter += wxT("All files (*.*)|*.*");
742
743 wxFileDialog dialog(this,
744 _("Choose a filename"),
745 path,
746 filename,
747 filter,
748 wxFD_OPEN);
749
750 if (dialog.ShowModal() == wxID_OK)
751 {
752 wxString path = dialog.GetPath();
753
754 if (!path.empty())
755 {
756 int filterIndex = dialog.GetFilterIndex();
757 int fileType = (filterIndex < (int) fileTypes.GetCount())
758 ? fileTypes[filterIndex]
759 : wxRICHTEXT_TYPE_TEXT;
760 m_richTextCtrl->LoadFile(path, fileType);
761 }
762 }
763 }
764
765 void MyFrame::OnSave(wxCommandEvent& event)
766 {
767 if (m_richTextCtrl->GetFilename().empty())
768 {
769 OnSaveAs(event);
770 return;
771 }
772 m_richTextCtrl->SaveFile();
773 }
774
775 void MyFrame::OnSaveAs(wxCommandEvent& WXUNUSED(event))
776 {
777 wxString filter = wxRichTextBuffer::GetExtWildcard(false, true);
778 wxString path;
779 wxString filename;
780
781 wxFileDialog dialog(this,
782 _("Choose a filename"),
783 path,
784 filename,
785 filter,
786 wxFD_SAVE);
787
788 if (dialog.ShowModal() == wxID_OK)
789 {
790 wxString path = dialog.GetPath();
791
792 if (!path.empty())
793 {
794 m_richTextCtrl->SaveFile(path);
795 }
796 }
797 }
798
799 void MyFrame::OnBold(wxCommandEvent& WXUNUSED(event))
800 {
801 m_richTextCtrl->ApplyBoldToSelection();
802 }
803
804 void MyFrame::OnItalic(wxCommandEvent& WXUNUSED(event))
805 {
806 m_richTextCtrl->ApplyItalicToSelection();
807 }
808
809 void MyFrame::OnUnderline(wxCommandEvent& WXUNUSED(event))
810 {
811 m_richTextCtrl->ApplyUnderlineToSelection();
812 }
813
814
815 void MyFrame::OnUpdateBold(wxUpdateUIEvent& event)
816 {
817 event.Check(m_richTextCtrl->IsSelectionBold());
818 }
819
820 void MyFrame::OnUpdateItalic(wxUpdateUIEvent& event)
821 {
822 event.Check(m_richTextCtrl->IsSelectionItalics());
823 }
824
825 void MyFrame::OnUpdateUnderline(wxUpdateUIEvent& event)
826 {
827 event.Check(m_richTextCtrl->IsSelectionUnderlined());
828 }
829
830 void MyFrame::OnAlignLeft(wxCommandEvent& WXUNUSED(event))
831 {
832 m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_LEFT);
833 }
834
835 void MyFrame::OnAlignCentre(wxCommandEvent& WXUNUSED(event))
836 {
837 m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_CENTRE);
838 }
839
840 void MyFrame::OnAlignRight(wxCommandEvent& WXUNUSED(event))
841 {
842 m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_RIGHT);
843 }
844
845 void MyFrame::OnUpdateAlignLeft(wxUpdateUIEvent& event)
846 {
847 event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_LEFT));
848 }
849
850 void MyFrame::OnUpdateAlignCentre(wxUpdateUIEvent& event)
851 {
852 event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_CENTRE));
853 }
854
855 void MyFrame::OnUpdateAlignRight(wxUpdateUIEvent& event)
856 {
857 event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_RIGHT));
858 }
859
860 void MyFrame::OnFont(wxCommandEvent& WXUNUSED(event))
861 {
862 if (!m_richTextCtrl->HasSelection())
863 return;
864
865 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
866 wxFontData fontData;
867
868 wxTextAttrEx attr;
869 attr.SetFlags(wxTEXT_ATTR_FONT);
870
871 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
872 fontData.SetInitialFont(attr.GetFont());
873
874 wxFontDialog dialog(this, fontData);
875 if (dialog.ShowModal() == wxID_OK)
876 {
877 fontData = dialog.GetFontData();
878 attr.SetFlags(wxTEXT_ATTR_FONT);
879 attr.SetFont(fontData.GetChosenFont());
880 if (attr.GetFont().Ok())
881 {
882 m_richTextCtrl->SetStyle(range, attr);
883 }
884 }
885 }
886
887 void MyFrame::OnIndentMore(wxCommandEvent& WXUNUSED(event))
888 {
889 wxTextAttrEx attr;
890 attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
891
892 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
893 {
894 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
895 if (m_richTextCtrl->HasSelection())
896 range = m_richTextCtrl->GetSelectionRange();
897
898 wxFontData fontData;
899 attr.SetLeftIndent(attr.GetLeftIndent() + 100);
900
901 attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
902 m_richTextCtrl->SetStyle(range, attr);
903 }
904 }
905
906 void MyFrame::OnIndentLess(wxCommandEvent& WXUNUSED(event))
907 {
908 wxTextAttrEx attr;
909 attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
910
911 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
912 {
913 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
914 if (m_richTextCtrl->HasSelection())
915 range = m_richTextCtrl->GetSelectionRange();
916
917 if (attr.GetLeftIndent() >= 100)
918 {
919 wxFontData fontData;
920 attr.SetLeftIndent(attr.GetLeftIndent() - 100);
921
922 m_richTextCtrl->SetStyle(range, attr);
923 }
924 }
925 }
926
927 void MyFrame::OnLineSpacingHalf(wxCommandEvent& WXUNUSED(event))
928 {
929 wxTextAttrEx attr;
930 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
931
932 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
933 {
934 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
935 if (m_richTextCtrl->HasSelection())
936 range = m_richTextCtrl->GetSelectionRange();
937
938 wxFontData fontData;
939 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
940 attr.SetLineSpacing(15);
941
942 m_richTextCtrl->SetStyle(range, attr);
943 }
944 }
945
946 void MyFrame::OnLineSpacingDouble(wxCommandEvent& WXUNUSED(event))
947 {
948 wxTextAttrEx attr;
949 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
950
951 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
952 {
953 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
954 if (m_richTextCtrl->HasSelection())
955 range = m_richTextCtrl->GetSelectionRange();
956
957 wxFontData fontData;
958 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
959 attr.SetLineSpacing(20);
960
961 m_richTextCtrl->SetStyle(range, attr);
962 }
963 }
964
965 void MyFrame::OnLineSpacingSingle(wxCommandEvent& WXUNUSED(event))
966 {
967 wxTextAttrEx attr;
968 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
969
970 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
971 {
972 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
973 if (m_richTextCtrl->HasSelection())
974 range = m_richTextCtrl->GetSelectionRange();
975
976 wxFontData fontData;
977 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
978 attr.SetLineSpacing(0); // Can also use 10
979
980 m_richTextCtrl->SetStyle(range, attr);
981 }
982 }
983
984 void MyFrame::OnParagraphSpacingMore(wxCommandEvent& WXUNUSED(event))
985 {
986 wxTextAttrEx attr;
987 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
988
989 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
990 {
991 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
992 if (m_richTextCtrl->HasSelection())
993 range = m_richTextCtrl->GetSelectionRange();
994
995 wxFontData fontData;
996 attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() + 20);
997
998 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
999 m_richTextCtrl->SetStyle(range, attr);
1000 }
1001 }
1002
1003 void MyFrame::OnParagraphSpacingLess(wxCommandEvent& WXUNUSED(event))
1004 {
1005 wxTextAttrEx attr;
1006 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1007
1008 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1009 {
1010 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1011 if (m_richTextCtrl->HasSelection())
1012 range = m_richTextCtrl->GetSelectionRange();
1013
1014 if (attr.GetParagraphSpacingAfter() >= 20)
1015 {
1016 wxFontData fontData;
1017 attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() - 20);
1018
1019 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1020 m_richTextCtrl->SetStyle(range, attr);
1021 }
1022 }
1023 }
1024
1025 void MyFrame::OnViewHTML(wxCommandEvent& WXUNUSED(event))
1026 {
1027 wxDialog dialog(this, wxID_ANY, _("HTML"), wxDefaultPosition, wxSize(500, 400), wxDEFAULT_DIALOG_STYLE);
1028
1029 wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
1030 dialog.SetSizer(boxSizer);
1031
1032 wxHtmlWindow* win = new wxHtmlWindow(& dialog, wxID_ANY, wxDefaultPosition, wxSize(500, 400), wxSUNKEN_BORDER);
1033 boxSizer->Add(win, 1, wxALL, 5);
1034
1035 wxButton* cancelButton = new wxButton(& dialog, wxID_CANCEL, wxT("&Close"));
1036 boxSizer->Add(cancelButton, 0, wxALL|wxCENTRE, 5);
1037
1038 wxString text;
1039 wxStringOutputStream strStream(& text);
1040
1041 wxRichTextHTMLHandler htmlHandler;
1042 if (htmlHandler.SaveFile(& m_richTextCtrl->GetBuffer(), strStream))
1043 {
1044 win->SetPage(text);
1045 }
1046
1047 boxSizer->Fit(& dialog);
1048
1049 dialog.ShowModal();
1050 }