]> git.saurik.com Git - wxWidgets.git/blob - samples/richtext/richtext.cpp
Don't document private event handlers in doc/view frame classes.
[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 #include "wx/stopwatch.h"
38
39 #if wxUSE_FILESYSTEM
40 #include "wx/filesys.h"
41 #include "wx/fs_mem.h"
42 #endif
43
44 #if wxUSE_HELP
45 #include "wx/cshelp.h"
46 #endif
47
48 #ifndef __WXMSW__
49 #include "../sample.xpm"
50 #endif
51
52 #include "bitmaps/smiley.xpm"
53 // #include "bitmaps/idea.xpm"
54 #include "bitmaps/zebra.xpm"
55
56 #include "bitmaps/open.xpm"
57 #include "bitmaps/save.xpm"
58 #include "bitmaps/copy.xpm"
59 #include "bitmaps/cut.xpm"
60 #include "bitmaps/paste.xpm"
61 #include "bitmaps/undo.xpm"
62 #include "bitmaps/redo.xpm"
63 #include "bitmaps/bold.xpm"
64 #include "bitmaps/italic.xpm"
65 #include "bitmaps/underline.xpm"
66
67 #include "bitmaps/alignleft.xpm"
68 #include "bitmaps/alignright.xpm"
69 #include "bitmaps/centre.xpm"
70 #include "bitmaps/font.xpm"
71 #include "bitmaps/indentless.xpm"
72 #include "bitmaps/indentmore.xpm"
73
74 #include "wx/richtext/richtextctrl.h"
75 #include "wx/richtext/richtextstyles.h"
76 #include "wx/richtext/richtextxml.h"
77 #include "wx/richtext/richtexthtml.h"
78 #include "wx/richtext/richtextformatdlg.h"
79 #include "wx/richtext/richtextsymboldlg.h"
80 #include "wx/richtext/richtextstyledlg.h"
81 #include "wx/richtext/richtextprint.h"
82 #include "wx/richtext/richtextimagedlg.h"
83
84 // ----------------------------------------------------------------------------
85 // resources
86 // ----------------------------------------------------------------------------
87
88 // ----------------------------------------------------------------------------
89 // private classes
90 // ----------------------------------------------------------------------------
91
92 // Define a new application type, each program should derive a class from wxApp
93 class MyRichTextCtrl: public wxRichTextCtrl
94 {
95 public:
96 MyRichTextCtrl( wxWindow* parent, wxWindowID id = -1, const wxString& value = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
97 long style = wxRE_MULTILINE, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxTextCtrlNameStr):
98 wxRichTextCtrl(parent, id, value, pos, size, style, validator, name)
99 {
100 m_lockId = 0;
101 m_locked = false;
102 }
103
104 void SetLockId(long id) { m_lockId = id; }
105 long GetLockId() const { return m_lockId; }
106
107 void BeginLock() { m_lockId ++; m_locked = true; }
108 void EndLock() { m_locked = false; }
109 bool IsLocked() const { return m_locked; }
110
111 static void SetEnhancedDrawingHandler();
112
113 /**
114 Prepares the content just before insertion (or after buffer reset). Called by the same function in wxRichTextBuffer.
115 Currently is only called if undo mode is on.
116 */
117 virtual void PrepareContent(wxRichTextParagraphLayoutBox& container);
118
119 /**
120 Can we delete this range?
121 Sends an event to the control.
122 */
123 virtual bool CanDeleteRange(wxRichTextParagraphLayoutBox& container, const wxRichTextRange& range) const;
124
125 /**
126 Can we insert content at this position?
127 Sends an event to the control.
128 */
129 virtual bool CanInsertContent(wxRichTextParagraphLayoutBox& container, long pos) const;
130
131 long m_lockId;
132 bool m_locked;
133 };
134
135 // Define a new application type, each program should derive a class from wxApp
136 class MyApp : public wxApp
137 {
138 public:
139 // override base class virtuals
140 // ----------------------------
141
142 // this one is called on application startup and is a good place for the app
143 // initialization (doing it here and not in the ctor allows to have an error
144 // return: if OnInit() returns false, the application terminates)
145 virtual bool OnInit();
146 virtual int OnExit();
147
148 void CreateStyles();
149
150 wxRichTextStyleSheet* GetStyleSheet() const { return m_styleSheet; }
151 wxRichTextPrinting* GetPrinting() const { return m_printing; }
152
153 wxRichTextStyleSheet* m_styleSheet;
154 wxRichTextPrinting* m_printing;
155 };
156
157 // Define a new frame type: this is going to be our main frame
158 class MyFrame : public wxFrame
159 {
160 public:
161 // ctor(s)
162 MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
163 const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE);
164
165 // event handlers (these functions should _not_ be virtual)
166 void OnQuit(wxCommandEvent& event);
167 void OnAbout(wxCommandEvent& event);
168
169 void OnOpen(wxCommandEvent& event);
170 void OnSave(wxCommandEvent& event);
171 void OnSaveAs(wxCommandEvent& event);
172
173 void OnBold(wxCommandEvent& event);
174 void OnItalic(wxCommandEvent& event);
175 void OnUnderline(wxCommandEvent& event);
176
177 void OnStrikethrough(wxCommandEvent& event);
178 void OnSuperscript(wxCommandEvent& event);
179 void OnSubscript(wxCommandEvent& event);
180
181 void OnUpdateBold(wxUpdateUIEvent& event);
182 void OnUpdateItalic(wxUpdateUIEvent& event);
183 void OnUpdateUnderline(wxUpdateUIEvent& event);
184 void OnUpdateStrikethrough(wxUpdateUIEvent& event);
185 void OnUpdateSuperscript(wxUpdateUIEvent& event);
186 void OnUpdateSubscript(wxUpdateUIEvent& event);
187
188 void OnAlignLeft(wxCommandEvent& event);
189 void OnAlignCentre(wxCommandEvent& event);
190 void OnAlignRight(wxCommandEvent& event);
191
192 void OnUpdateAlignLeft(wxUpdateUIEvent& event);
193 void OnUpdateAlignCentre(wxUpdateUIEvent& event);
194 void OnUpdateAlignRight(wxUpdateUIEvent& event);
195
196 void OnIndentMore(wxCommandEvent& event);
197 void OnIndentLess(wxCommandEvent& event);
198
199 void OnFont(wxCommandEvent& event);
200 void OnImage(wxCommandEvent& event);
201 void OnUpdateImage(wxUpdateUIEvent& event);
202 void OnParagraph(wxCommandEvent& event);
203 void OnFormat(wxCommandEvent& event);
204 void OnUpdateFormat(wxUpdateUIEvent& event);
205
206 void OnInsertSymbol(wxCommandEvent& event);
207
208 void OnLineSpacingHalf(wxCommandEvent& event);
209 void OnLineSpacingDouble(wxCommandEvent& event);
210 void OnLineSpacingSingle(wxCommandEvent& event);
211
212 void OnParagraphSpacingMore(wxCommandEvent& event);
213 void OnParagraphSpacingLess(wxCommandEvent& event);
214
215 void OnNumberList(wxCommandEvent& event);
216 void OnBulletsAndNumbering(wxCommandEvent& event);
217 void OnItemizeList(wxCommandEvent& event);
218 void OnRenumberList(wxCommandEvent& event);
219 void OnPromoteList(wxCommandEvent& event);
220 void OnDemoteList(wxCommandEvent& event);
221 void OnClearList(wxCommandEvent& event);
222
223 void OnReload(wxCommandEvent& event);
224
225 void OnViewHTML(wxCommandEvent& event);
226
227 void OnSwitchStyleSheets(wxCommandEvent& event);
228 void OnManageStyles(wxCommandEvent& event);
229
230 void OnInsertURL(wxCommandEvent& event);
231 void OnURL(wxTextUrlEvent& event);
232 void OnStyleSheetReplacing(wxRichTextEvent& event);
233
234 void OnPrint(wxCommandEvent& event);
235 void OnPreview(wxCommandEvent& event);
236 void OnPageSetup(wxCommandEvent& event);
237
238 void OnInsertImage(wxCommandEvent& event);
239 protected:
240
241 // Forward command events to the current rich text control, if any
242 bool ProcessEvent(wxEvent& event);
243
244 // Write text
245 void WriteInitialText();
246
247 private:
248 // any class wishing to process wxWidgets events must use this macro
249 DECLARE_EVENT_TABLE()
250
251 MyRichTextCtrl* m_richTextCtrl;
252 };
253
254 // ----------------------------------------------------------------------------
255 // constants
256 // ----------------------------------------------------------------------------
257
258 // IDs for the controls and the menu commands
259 enum
260 {
261 // menu items
262 ID_Quit = wxID_EXIT,
263 ID_About = wxID_ABOUT,
264
265 ID_FORMAT_BOLD = 100,
266 ID_FORMAT_ITALIC,
267 ID_FORMAT_UNDERLINE,
268 ID_FORMAT_STRIKETHROUGH,
269 ID_FORMAT_SUPERSCRIPT,
270 ID_FORMAT_SUBSCRIPT,
271 ID_FORMAT_FONT,
272 ID_FORMAT_IMAGE,
273 ID_FORMAT_PARAGRAPH,
274 ID_FORMAT_CONTENT,
275
276 ID_RELOAD,
277
278 ID_INSERT_SYMBOL,
279 ID_INSERT_URL,
280 ID_INSERT_IMAGE,
281
282 ID_FORMAT_ALIGN_LEFT,
283 ID_FORMAT_ALIGN_CENTRE,
284 ID_FORMAT_ALIGN_RIGHT,
285
286 ID_FORMAT_INDENT_MORE,
287 ID_FORMAT_INDENT_LESS,
288
289 ID_FORMAT_PARAGRAPH_SPACING_MORE,
290 ID_FORMAT_PARAGRAPH_SPACING_LESS,
291
292 ID_FORMAT_LINE_SPACING_HALF,
293 ID_FORMAT_LINE_SPACING_DOUBLE,
294 ID_FORMAT_LINE_SPACING_SINGLE,
295
296 ID_FORMAT_NUMBER_LIST,
297 ID_FORMAT_BULLETS_AND_NUMBERING,
298 ID_FORMAT_ITEMIZE_LIST,
299 ID_FORMAT_RENUMBER_LIST,
300 ID_FORMAT_PROMOTE_LIST,
301 ID_FORMAT_DEMOTE_LIST,
302 ID_FORMAT_CLEAR_LIST,
303
304 ID_VIEW_HTML,
305 ID_SWITCH_STYLE_SHEETS,
306 ID_MANAGE_STYLES,
307
308 ID_PRINT,
309 ID_PREVIEW,
310 ID_PAGE_SETUP,
311
312 ID_RICHTEXT_CTRL,
313 ID_RICHTEXT_STYLE_LIST,
314 ID_RICHTEXT_STYLE_COMBO
315 };
316
317 // ----------------------------------------------------------------------------
318 // event tables and other macros for wxWidgets
319 // ----------------------------------------------------------------------------
320
321 // the event tables connect the wxWidgets events with the functions (event
322 // handlers) which process them. It can be also done at run-time, but for the
323 // simple menu events like this the static method is much simpler.
324 BEGIN_EVENT_TABLE(MyFrame, wxFrame)
325 EVT_MENU(ID_Quit, MyFrame::OnQuit)
326 EVT_MENU(ID_About, MyFrame::OnAbout)
327
328 EVT_MENU(wxID_OPEN, MyFrame::OnOpen)
329 EVT_MENU(wxID_SAVE, MyFrame::OnSave)
330 EVT_MENU(wxID_SAVEAS, MyFrame::OnSaveAs)
331
332 EVT_MENU(ID_FORMAT_BOLD, MyFrame::OnBold)
333 EVT_MENU(ID_FORMAT_ITALIC, MyFrame::OnItalic)
334 EVT_MENU(ID_FORMAT_UNDERLINE, MyFrame::OnUnderline)
335
336 EVT_MENU(ID_FORMAT_STRIKETHROUGH, MyFrame::OnStrikethrough)
337 EVT_MENU(ID_FORMAT_SUPERSCRIPT, MyFrame::OnSuperscript)
338 EVT_MENU(ID_FORMAT_SUBSCRIPT, MyFrame::OnSubscript)
339
340 EVT_UPDATE_UI(ID_FORMAT_BOLD, MyFrame::OnUpdateBold)
341 EVT_UPDATE_UI(ID_FORMAT_ITALIC, MyFrame::OnUpdateItalic)
342 EVT_UPDATE_UI(ID_FORMAT_UNDERLINE, MyFrame::OnUpdateUnderline)
343
344 EVT_UPDATE_UI(ID_FORMAT_STRIKETHROUGH, MyFrame::OnUpdateStrikethrough)
345 EVT_UPDATE_UI(ID_FORMAT_SUPERSCRIPT, MyFrame::OnUpdateSuperscript)
346 EVT_UPDATE_UI(ID_FORMAT_SUBSCRIPT, MyFrame::OnUpdateSubscript)
347
348 EVT_MENU(ID_FORMAT_ALIGN_LEFT, MyFrame::OnAlignLeft)
349 EVT_MENU(ID_FORMAT_ALIGN_CENTRE, MyFrame::OnAlignCentre)
350 EVT_MENU(ID_FORMAT_ALIGN_RIGHT, MyFrame::OnAlignRight)
351
352 EVT_UPDATE_UI(ID_FORMAT_ALIGN_LEFT, MyFrame::OnUpdateAlignLeft)
353 EVT_UPDATE_UI(ID_FORMAT_ALIGN_CENTRE, MyFrame::OnUpdateAlignCentre)
354 EVT_UPDATE_UI(ID_FORMAT_ALIGN_RIGHT, MyFrame::OnUpdateAlignRight)
355
356 EVT_MENU(ID_FORMAT_FONT, MyFrame::OnFont)
357 EVT_MENU(ID_FORMAT_IMAGE, MyFrame::OnImage)
358 EVT_MENU(ID_FORMAT_PARAGRAPH, MyFrame::OnParagraph)
359 EVT_MENU(ID_FORMAT_CONTENT, MyFrame::OnFormat)
360 EVT_UPDATE_UI(ID_FORMAT_CONTENT, MyFrame::OnUpdateFormat)
361 EVT_UPDATE_UI(ID_FORMAT_FONT, MyFrame::OnUpdateFormat)
362 EVT_UPDATE_UI(ID_FORMAT_IMAGE, MyFrame::OnUpdateImage)
363 EVT_UPDATE_UI(ID_FORMAT_PARAGRAPH, MyFrame::OnUpdateFormat)
364 EVT_MENU(ID_FORMAT_INDENT_MORE, MyFrame::OnIndentMore)
365 EVT_MENU(ID_FORMAT_INDENT_LESS, MyFrame::OnIndentLess)
366
367 EVT_MENU(ID_FORMAT_LINE_SPACING_HALF, MyFrame::OnLineSpacingHalf)
368 EVT_MENU(ID_FORMAT_LINE_SPACING_SINGLE, MyFrame::OnLineSpacingSingle)
369 EVT_MENU(ID_FORMAT_LINE_SPACING_DOUBLE, MyFrame::OnLineSpacingDouble)
370
371 EVT_MENU(ID_FORMAT_PARAGRAPH_SPACING_MORE, MyFrame::OnParagraphSpacingMore)
372 EVT_MENU(ID_FORMAT_PARAGRAPH_SPACING_LESS, MyFrame::OnParagraphSpacingLess)
373
374 EVT_MENU(ID_RELOAD, MyFrame::OnReload)
375
376 EVT_MENU(ID_INSERT_SYMBOL, MyFrame::OnInsertSymbol)
377 EVT_MENU(ID_INSERT_URL, MyFrame::OnInsertURL)
378 EVT_MENU(ID_INSERT_IMAGE, MyFrame::OnInsertImage)
379
380 EVT_MENU(ID_FORMAT_NUMBER_LIST, MyFrame::OnNumberList)
381 EVT_MENU(ID_FORMAT_BULLETS_AND_NUMBERING, MyFrame::OnBulletsAndNumbering)
382 EVT_MENU(ID_FORMAT_ITEMIZE_LIST, MyFrame::OnItemizeList)
383 EVT_MENU(ID_FORMAT_RENUMBER_LIST, MyFrame::OnRenumberList)
384 EVT_MENU(ID_FORMAT_PROMOTE_LIST, MyFrame::OnPromoteList)
385 EVT_MENU(ID_FORMAT_DEMOTE_LIST, MyFrame::OnDemoteList)
386 EVT_MENU(ID_FORMAT_CLEAR_LIST, MyFrame::OnClearList)
387
388 EVT_MENU(ID_VIEW_HTML, MyFrame::OnViewHTML)
389 EVT_MENU(ID_SWITCH_STYLE_SHEETS, MyFrame::OnSwitchStyleSheets)
390 EVT_MENU(ID_MANAGE_STYLES, MyFrame::OnManageStyles)
391
392 EVT_MENU(ID_PRINT, MyFrame::OnPrint)
393 EVT_MENU(ID_PREVIEW, MyFrame::OnPreview)
394 EVT_MENU(ID_PAGE_SETUP, MyFrame::OnPageSetup)
395
396 EVT_TEXT_URL(wxID_ANY, MyFrame::OnURL)
397 EVT_RICHTEXT_STYLESHEET_REPLACING(wxID_ANY, MyFrame::OnStyleSheetReplacing)
398 END_EVENT_TABLE()
399
400 // Create a new application object: this macro will allow wxWidgets to create
401 // the application object during program execution (it's better than using a
402 // static object for many reasons) and also implements the accessor function
403 // wxGetApp() which will return the reference of the right type (i.e. MyApp and
404 // not wxApp)
405 IMPLEMENT_APP(MyApp)
406
407 // ============================================================================
408 // implementation
409 // ============================================================================
410
411 // ----------------------------------------------------------------------------
412 // the application class
413 // ----------------------------------------------------------------------------
414
415 // 'Main program' equivalent: the program execution "starts" here
416 bool MyApp::OnInit()
417 {
418 if ( !wxApp::OnInit() )
419 return false;
420
421 #if wxUSE_HELP
422 wxHelpProvider::Set(new wxSimpleHelpProvider);
423 #endif
424
425 m_styleSheet = new wxRichTextStyleSheet;
426 m_printing = new wxRichTextPrinting(wxT("Test Document"));
427
428 m_printing->SetFooterText(wxT("@TITLE@"), wxRICHTEXT_PAGE_ALL, wxRICHTEXT_PAGE_CENTRE);
429 m_printing->SetFooterText(wxT("Page @PAGENUM@"), wxRICHTEXT_PAGE_ALL, wxRICHTEXT_PAGE_RIGHT);
430
431 CreateStyles();
432
433 MyRichTextCtrl::SetEnhancedDrawingHandler();
434
435 // Add extra handlers (plain text is automatically added)
436 wxRichTextBuffer::AddHandler(new wxRichTextXMLHandler);
437 wxRichTextBuffer::AddHandler(new wxRichTextHTMLHandler);
438
439 // Add image handlers
440 #if wxUSE_LIBPNG
441 wxImage::AddHandler( new wxPNGHandler );
442 #endif
443
444 #if wxUSE_LIBJPEG
445 wxImage::AddHandler( new wxJPEGHandler );
446 #endif
447
448 #if wxUSE_GIF
449 wxImage::AddHandler( new wxGIFHandler );
450 #endif
451
452 #if wxUSE_FILESYSTEM
453 wxFileSystem::AddHandler( new wxMemoryFSHandler );
454 #endif
455
456 // create the main application window
457 MyFrame *frame = new MyFrame(wxT("wxRichTextCtrl Sample"), wxID_ANY, wxDefaultPosition, wxSize(700, 600));
458
459 m_printing->SetParentWindow(frame);
460
461 // and show it (the frames, unlike simple controls, are not shown when
462 // created initially)
463 frame->Show(true);
464
465 // success: wxApp::OnRun() will be called which will enter the main message
466 // loop and the application will run. If we returned false here, the
467 // application would exit immediately.
468 return true;
469 }
470
471 int MyApp::OnExit()
472 {
473 delete m_printing;
474 delete m_styleSheet;
475
476 return 0;
477 }
478
479 void MyApp::CreateStyles()
480 {
481 // Paragraph styles
482
483 wxFont romanFont(12, wxROMAN, wxNORMAL, wxNORMAL);
484 wxFont swissFont(12, wxSWISS, wxNORMAL, wxNORMAL);
485
486 wxRichTextParagraphStyleDefinition* normalPara = new wxRichTextParagraphStyleDefinition(wxT("Normal"));
487 wxRichTextAttr normalAttr;
488 normalAttr.SetFontFaceName(romanFont.GetFaceName());
489 normalAttr.SetFontSize(12);
490 // Let's set all attributes for this style
491 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|
492 wxTEXT_ATTR_PARA_SPACING_BEFORE|wxTEXT_ATTR_PARA_SPACING_AFTER|wxTEXT_ATTR_LINE_SPACING|
493 wxTEXT_ATTR_BULLET_STYLE|wxTEXT_ATTR_BULLET_NUMBER);
494 normalPara->SetStyle(normalAttr);
495
496 m_styleSheet->AddParagraphStyle(normalPara);
497
498 wxRichTextParagraphStyleDefinition* indentedPara = new wxRichTextParagraphStyleDefinition(wxT("Indented"));
499 wxRichTextAttr indentedAttr;
500 indentedAttr.SetFontFaceName(romanFont.GetFaceName());
501 indentedAttr.SetFontSize(12);
502 indentedAttr.SetLeftIndent(100, 0);
503 // We only want to affect indentation
504 indentedAttr.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT);
505 indentedPara->SetStyle(indentedAttr);
506
507 m_styleSheet->AddParagraphStyle(indentedPara);
508
509 wxRichTextParagraphStyleDefinition* indentedPara2 = new wxRichTextParagraphStyleDefinition(wxT("Red Bold Indented"));
510 wxRichTextAttr indentedAttr2;
511 indentedAttr2.SetFontFaceName(romanFont.GetFaceName());
512 indentedAttr2.SetFontSize(12);
513 indentedAttr2.SetFontWeight(wxFONTWEIGHT_BOLD);
514 indentedAttr2.SetTextColour(*wxRED);
515 indentedAttr2.SetFontSize(12);
516 indentedAttr2.SetLeftIndent(100, 0);
517 // We want to affect indentation, font and text colour
518 indentedAttr2.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT|wxTEXT_ATTR_FONT|wxTEXT_ATTR_TEXT_COLOUR);
519 indentedPara2->SetStyle(indentedAttr2);
520
521 m_styleSheet->AddParagraphStyle(indentedPara2);
522
523 wxRichTextParagraphStyleDefinition* flIndentedPara = new wxRichTextParagraphStyleDefinition(wxT("First Line Indented"));
524 wxRichTextAttr flIndentedAttr;
525 flIndentedAttr.SetFontFaceName(swissFont.GetFaceName());
526 flIndentedAttr.SetFontSize(12);
527 flIndentedAttr.SetLeftIndent(100, -100);
528 // We only want to affect indentation
529 flIndentedAttr.SetFlags(wxTEXT_ATTR_LEFT_INDENT|wxTEXT_ATTR_RIGHT_INDENT);
530 flIndentedPara->SetStyle(flIndentedAttr);
531
532 m_styleSheet->AddParagraphStyle(flIndentedPara);
533
534 // Character styles
535
536 wxRichTextCharacterStyleDefinition* boldDef = new wxRichTextCharacterStyleDefinition(wxT("Bold"));
537 wxRichTextAttr boldAttr;
538 boldAttr.SetFontFaceName(romanFont.GetFaceName());
539 boldAttr.SetFontSize(12);
540 boldAttr.SetFontWeight(wxFONTWEIGHT_BOLD);
541 // We only want to affect boldness
542 boldAttr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
543 boldDef->SetStyle(boldAttr);
544
545 m_styleSheet->AddCharacterStyle(boldDef);
546
547 wxRichTextCharacterStyleDefinition* italicDef = new wxRichTextCharacterStyleDefinition(wxT("Italic"));
548 wxRichTextAttr italicAttr;
549 italicAttr.SetFontFaceName(romanFont.GetFaceName());
550 italicAttr.SetFontSize(12);
551 italicAttr.SetFontStyle(wxFONTSTYLE_ITALIC);
552 // We only want to affect italics
553 italicAttr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
554 italicDef->SetStyle(italicAttr);
555
556 m_styleSheet->AddCharacterStyle(italicDef);
557
558 wxRichTextCharacterStyleDefinition* redDef = new wxRichTextCharacterStyleDefinition(wxT("Red Bold"));
559 wxRichTextAttr redAttr;
560 redAttr.SetFontFaceName(romanFont.GetFaceName());
561 redAttr.SetFontSize(12);
562 redAttr.SetFontWeight(wxFONTWEIGHT_BOLD);
563 redAttr.SetTextColour(*wxRED);
564 // We only want to affect colour, weight and face
565 redAttr.SetFlags(wxTEXT_ATTR_FONT_FACE|wxTEXT_ATTR_FONT_WEIGHT|wxTEXT_ATTR_TEXT_COLOUR);
566 redDef->SetStyle(redAttr);
567
568 m_styleSheet->AddCharacterStyle(redDef);
569
570 wxRichTextListStyleDefinition* bulletList = new wxRichTextListStyleDefinition(wxT("Bullet List 1"));
571 int i;
572 for (i = 0; i < 10; i++)
573 {
574 wxString bulletText;
575 if (i == 0)
576 bulletText = wxT("standard/circle");
577 else if (i == 1)
578 bulletText = wxT("standard/square");
579 else if (i == 2)
580 bulletText = wxT("standard/circle");
581 else if (i == 3)
582 bulletText = wxT("standard/square");
583 else
584 bulletText = wxT("standard/circle");
585
586 bulletList->SetAttributes(i, (i+1)*60, 60, wxTEXT_ATTR_BULLET_STYLE_STANDARD, bulletText);
587 }
588
589 m_styleSheet->AddListStyle(bulletList);
590
591 wxRichTextListStyleDefinition* numberedList = new wxRichTextListStyleDefinition(wxT("Numbered List 1"));
592 for (i = 0; i < 10; i++)
593 {
594 long numberStyle;
595 if (i == 0)
596 numberStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
597 else if (i == 1)
598 numberStyle = wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER|wxTEXT_ATTR_BULLET_STYLE_PARENTHESES;
599 else if (i == 2)
600 numberStyle = wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER|wxTEXT_ATTR_BULLET_STYLE_PARENTHESES;
601 else if (i == 3)
602 numberStyle = wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER|wxTEXT_ATTR_BULLET_STYLE_PARENTHESES;
603 else
604 numberStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
605
606 numberStyle |= wxTEXT_ATTR_BULLET_STYLE_ALIGN_RIGHT;
607
608 numberedList->SetAttributes(i, (i+1)*60, 60, numberStyle);
609 }
610
611 m_styleSheet->AddListStyle(numberedList);
612
613 wxRichTextListStyleDefinition* outlineList = new wxRichTextListStyleDefinition(wxT("Outline List 1"));
614 for (i = 0; i < 10; i++)
615 {
616 long numberStyle;
617 if (i < 4)
618 numberStyle = wxTEXT_ATTR_BULLET_STYLE_OUTLINE|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
619 else
620 numberStyle = wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_PERIOD;
621
622 outlineList->SetAttributes(i, (i+1)*120, 120, numberStyle);
623 }
624
625 m_styleSheet->AddListStyle(outlineList);
626 }
627
628 // ----------------------------------------------------------------------------
629 // main frame
630 // ----------------------------------------------------------------------------
631
632 // frame constructor
633 MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
634 const wxSize& size, long style)
635 : wxFrame(NULL, id, title, pos, size, style)
636 {
637 // set the frame icon
638 SetIcon(wxICON(sample));
639
640 // create a menu bar
641 wxMenu *fileMenu = new wxMenu;
642
643 // the "About" item should be in the help menu
644 wxMenu *helpMenu = new wxMenu;
645 helpMenu->Append(ID_About, wxT("&About\tF1"), wxT("Show about dialog"));
646
647 fileMenu->Append(wxID_OPEN, wxT("&Open\tCtrl+O"), wxT("Open a file"));
648 fileMenu->Append(wxID_SAVE, wxT("&Save\tCtrl+S"), wxT("Save a file"));
649 fileMenu->Append(wxID_SAVEAS, wxT("&Save As...\tF12"), wxT("Save to a new file"));
650 fileMenu->AppendSeparator();
651 fileMenu->Append(ID_RELOAD, wxT("&Reload Text\tF2"), wxT("Reload the initial text"));
652 fileMenu->AppendSeparator();
653 fileMenu->Append(ID_PAGE_SETUP, wxT("Page Set&up..."), wxT("Page setup"));
654 fileMenu->Append(ID_PRINT, wxT("&Print...\tCtrl+P"), wxT("Print"));
655 fileMenu->Append(ID_PREVIEW, wxT("Print Pre&view"), wxT("Print preview"));
656 fileMenu->AppendSeparator();
657 fileMenu->Append(ID_VIEW_HTML, wxT("&View as HTML"), wxT("View HTML"));
658 fileMenu->AppendSeparator();
659 fileMenu->Append(ID_Quit, wxT("E&xit\tAlt+X"), wxT("Quit this program"));
660
661 wxMenu* editMenu = new wxMenu;
662 editMenu->Append(wxID_UNDO, _("&Undo\tCtrl+Z"));
663 editMenu->Append(wxID_REDO, _("&Redo\tCtrl+Y"));
664 editMenu->AppendSeparator();
665 editMenu->Append(wxID_CUT, _("Cu&t\tCtrl+X"));
666 editMenu->Append(wxID_COPY, _("&Copy\tCtrl+C"));
667 editMenu->Append(wxID_PASTE, _("&Paste\tCtrl+V"));
668
669 editMenu->AppendSeparator();
670 editMenu->Append(wxID_SELECTALL, _("Select A&ll\tCtrl+A"));
671 #if 0
672 editMenu->AppendSeparator();
673 editMenu->Append(wxID_FIND, _("&Find...\tCtrl+F"));
674 editMenu->Append(stID_FIND_REPLACE, _("&Replace...\tCtrl+R"));
675 #endif
676
677 wxMenu* formatMenu = new wxMenu;
678 formatMenu->AppendCheckItem(ID_FORMAT_BOLD, _("&Bold\tCtrl+B"));
679 formatMenu->AppendCheckItem(ID_FORMAT_ITALIC, _("&Italic\tCtrl+I"));
680 formatMenu->AppendCheckItem(ID_FORMAT_UNDERLINE, _("&Underline\tCtrl+U"));
681 formatMenu->AppendSeparator();
682 formatMenu->AppendCheckItem(ID_FORMAT_STRIKETHROUGH, _("Stri&kethrough"));
683 formatMenu->AppendCheckItem(ID_FORMAT_SUPERSCRIPT, _("Superscrip&t"));
684 formatMenu->AppendCheckItem(ID_FORMAT_SUBSCRIPT, _("Subscrip&t"));
685 formatMenu->AppendSeparator();
686 formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_LEFT, _("L&eft Align"));
687 formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_RIGHT, _("&Right Align"));
688 formatMenu->AppendCheckItem(ID_FORMAT_ALIGN_CENTRE, _("&Centre"));
689 formatMenu->AppendSeparator();
690 formatMenu->Append(ID_FORMAT_INDENT_MORE, _("Indent &More"));
691 formatMenu->Append(ID_FORMAT_INDENT_LESS, _("Indent &Less"));
692 formatMenu->AppendSeparator();
693 formatMenu->Append(ID_FORMAT_PARAGRAPH_SPACING_MORE, _("Increase Paragraph &Spacing"));
694 formatMenu->Append(ID_FORMAT_PARAGRAPH_SPACING_LESS, _("Decrease &Paragraph Spacing"));
695 formatMenu->AppendSeparator();
696 formatMenu->Append(ID_FORMAT_LINE_SPACING_SINGLE, _("Normal Line Spacing"));
697 formatMenu->Append(ID_FORMAT_LINE_SPACING_HALF, _("1.5 Line Spacing"));
698 formatMenu->Append(ID_FORMAT_LINE_SPACING_DOUBLE, _("Double Line Spacing"));
699 formatMenu->AppendSeparator();
700 formatMenu->Append(ID_FORMAT_FONT, _("&Font..."));
701 formatMenu->Append(ID_FORMAT_IMAGE, _("Image Property"));
702 formatMenu->Append(ID_FORMAT_PARAGRAPH, _("&Paragraph..."));
703 formatMenu->Append(ID_FORMAT_CONTENT, _("Font and Pa&ragraph...\tShift+Ctrl+F"));
704 formatMenu->AppendSeparator();
705 formatMenu->Append(ID_SWITCH_STYLE_SHEETS, _("&Switch Style Sheets"));
706 formatMenu->Append(ID_MANAGE_STYLES, _("&Manage Styles"));
707
708 wxMenu* listsMenu = new wxMenu;
709 listsMenu->Append(ID_FORMAT_BULLETS_AND_NUMBERING, _("Bullets and &Numbering..."));
710 listsMenu->AppendSeparator();
711 listsMenu->Append(ID_FORMAT_NUMBER_LIST, _("Number List"));
712 listsMenu->Append(ID_FORMAT_ITEMIZE_LIST, _("Itemize List"));
713 listsMenu->Append(ID_FORMAT_RENUMBER_LIST, _("Renumber List"));
714 listsMenu->Append(ID_FORMAT_PROMOTE_LIST, _("Promote List Items"));
715 listsMenu->Append(ID_FORMAT_DEMOTE_LIST, _("Demote List Items"));
716 listsMenu->Append(ID_FORMAT_CLEAR_LIST, _("Clear List Formatting"));
717
718 wxMenu* insertMenu = new wxMenu;
719 insertMenu->Append(ID_INSERT_SYMBOL, _("&Symbol...\tCtrl+I"));
720 insertMenu->Append(ID_INSERT_URL, _("&URL..."));
721 insertMenu->Append(ID_INSERT_IMAGE, _("&Image..."));
722
723 // now append the freshly created menu to the menu bar...
724 wxMenuBar *menuBar = new wxMenuBar();
725 menuBar->Append(fileMenu, wxT("&File"));
726 menuBar->Append(editMenu, wxT("&Edit"));
727 menuBar->Append(formatMenu, wxT("F&ormat"));
728 menuBar->Append(listsMenu, wxT("&Lists"));
729 menuBar->Append(insertMenu, wxT("&Insert"));
730 menuBar->Append(helpMenu, wxT("&Help"));
731
732 // ... and attach this menu bar to the frame
733 SetMenuBar(menuBar);
734
735 // create a status bar just for fun (by default with 1 pane only)
736 // but don't create it on limited screen space (WinCE)
737 bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA;
738
739 #if wxUSE_STATUSBAR
740 if ( !is_pda )
741 {
742 CreateStatusBar(2);
743 SetStatusText(wxT("Welcome to wxRichTextCtrl!"));
744 }
745 #endif
746
747 wxToolBar* toolBar = CreateToolBar();
748
749 toolBar->AddTool(wxID_OPEN, wxEmptyString, wxBitmap(open_xpm), _("Open"));
750 toolBar->AddTool(wxID_SAVEAS, wxEmptyString, wxBitmap(save_xpm), _("Save"));
751 toolBar->AddSeparator();
752 toolBar->AddTool(wxID_CUT, wxEmptyString, wxBitmap(cut_xpm), _("Cut"));
753 toolBar->AddTool(wxID_COPY, wxEmptyString, wxBitmap(copy_xpm), _("Copy"));
754 toolBar->AddTool(wxID_PASTE, wxEmptyString, wxBitmap(paste_xpm), _("Paste"));
755 toolBar->AddSeparator();
756 toolBar->AddTool(wxID_UNDO, wxEmptyString, wxBitmap(undo_xpm), _("Undo"));
757 toolBar->AddTool(wxID_REDO, wxEmptyString, wxBitmap(redo_xpm), _("Redo"));
758 toolBar->AddSeparator();
759 toolBar->AddCheckTool(ID_FORMAT_BOLD, wxEmptyString, wxBitmap(bold_xpm), wxNullBitmap, _("Bold"));
760 toolBar->AddCheckTool(ID_FORMAT_ITALIC, wxEmptyString, wxBitmap(italic_xpm), wxNullBitmap, _("Italic"));
761 toolBar->AddCheckTool(ID_FORMAT_UNDERLINE, wxEmptyString, wxBitmap(underline_xpm), wxNullBitmap, _("Underline"));
762 toolBar->AddSeparator();
763 toolBar->AddCheckTool(ID_FORMAT_ALIGN_LEFT, wxEmptyString, wxBitmap(alignleft_xpm), wxNullBitmap, _("Align Left"));
764 toolBar->AddCheckTool(ID_FORMAT_ALIGN_CENTRE, wxEmptyString, wxBitmap(centre_xpm), wxNullBitmap, _("Centre"));
765 toolBar->AddCheckTool(ID_FORMAT_ALIGN_RIGHT, wxEmptyString, wxBitmap(alignright_xpm), wxNullBitmap, _("Align Right"));
766 toolBar->AddSeparator();
767 toolBar->AddTool(ID_FORMAT_INDENT_LESS, wxEmptyString, wxBitmap(indentless_xpm), _("Indent Less"));
768 toolBar->AddTool(ID_FORMAT_INDENT_MORE, wxEmptyString, wxBitmap(indentmore_xpm), _("Indent More"));
769 toolBar->AddSeparator();
770 toolBar->AddTool(ID_FORMAT_FONT, wxEmptyString, wxBitmap(font_xpm), _("Font"));
771 toolBar->AddTool(ID_FORMAT_IMAGE, wxString("Im"), wxBitmap(font_xpm), _("Image Property"));
772
773 wxRichTextStyleComboCtrl* combo = new wxRichTextStyleComboCtrl(toolBar, ID_RICHTEXT_STYLE_COMBO, wxDefaultPosition, wxSize(200, -1));
774 toolBar->AddControl(combo);
775
776 toolBar->Realize();
777
778 wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, GetClientSize(), wxSP_LIVE_UPDATE);
779
780 wxFont textFont = wxFont(12, wxROMAN, wxNORMAL, wxNORMAL);
781 wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD);
782 wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL);
783
784 m_richTextCtrl = new MyRichTextCtrl(splitter, ID_RICHTEXT_CTRL, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxWANTS_CHARS);
785 wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL);
786
787 m_richTextCtrl->SetFont(font);
788
789 m_richTextCtrl->SetMargins(10, 10);
790
791 m_richTextCtrl->SetStyleSheet(wxGetApp().GetStyleSheet());
792
793 combo->SetStyleSheet(wxGetApp().GetStyleSheet());
794 combo->SetRichTextCtrl(m_richTextCtrl);
795 combo->UpdateStyles();
796
797 wxRichTextStyleListCtrl* styleListCtrl = new wxRichTextStyleListCtrl(splitter, ID_RICHTEXT_STYLE_LIST);
798
799 wxSize display = wxGetDisplaySize();
800 if ( is_pda && ( display.GetWidth() < display.GetHeight() ) )
801 {
802 splitter->SplitHorizontally(m_richTextCtrl, styleListCtrl);
803 }
804 else
805 {
806 splitter->SplitVertically(m_richTextCtrl, styleListCtrl, 500);
807 }
808
809 splitter->UpdateSize();
810
811 styleListCtrl->SetStyleSheet(wxGetApp().GetStyleSheet());
812 styleListCtrl->SetRichTextCtrl(m_richTextCtrl);
813 styleListCtrl->UpdateStyles();
814
815 WriteInitialText();
816 }
817
818 // Write text
819 void MyFrame::WriteInitialText()
820 {
821 MyRichTextCtrl& r = *m_richTextCtrl;
822
823 r.SetDefaultStyle(wxRichTextAttr());
824
825 // Add some locked content first - needs Undo to be enabled
826 {
827 r.BeginLock();
828 r.WriteText(wxString(wxT("This is a locked object.")));
829 r.EndLock();
830
831 r.WriteText(wxString(wxT(" This is unlocked text. ")));
832
833 r.BeginLock();
834 r.WriteText(wxString(wxT("More locked content.")));
835 r.EndLock();
836 r.Newline();
837
838 // Flush the Undo buffer
839 r.GetCommandProcessor()->ClearCommands();
840 }
841
842 r.BeginSuppressUndo();
843
844 r.Freeze();
845
846 r.BeginParagraphSpacing(0, 20);
847
848 r.BeginAlignment(wxTEXT_ALIGNMENT_CENTRE);
849 r.BeginBold();
850
851 r.BeginFontSize(14);
852
853 wxString lineBreak = (wxChar) 29;
854
855 r.WriteText(wxString(wxT("Welcome to wxRichTextCtrl, a wxWidgets control")) + lineBreak + wxT("for editing and presenting styled text and images\n"));
856 r.EndFontSize();
857
858 r.BeginItalic();
859 r.WriteText(wxT("by Julian Smart"));
860 r.EndItalic();
861
862 r.EndBold();
863 r.Newline();
864
865 r.WriteImage(wxBitmap(zebra_xpm));
866
867 r.Newline();
868 r.Newline();
869
870 r.EndAlignment();
871
872 r.BeginAlignment(wxTEXT_ALIGNMENT_LEFT);
873 wxRichTextAttr imageAttr;
874 imageAttr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_LEFT);
875 r.WriteText(wxString(wxT("This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side. This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side. This is a simple test for a floating left image test. The zebra image should be placed at the left side of the current buffer and all the text should flow around it at the right side.")));
876 r.WriteImage(wxBitmap(zebra_xpm), wxBITMAP_TYPE_PNG, imageAttr);
877
878 imageAttr.GetTextBoxAttr().GetTop().SetValue(200);
879 imageAttr.GetTextBoxAttr().GetTop().SetUnits(wxTEXT_ATTR_UNITS_PIXELS);
880 imageAttr.GetTextBoxAttr().SetFloatMode(wxTEXT_BOX_ATTR_FLOAT_RIGHT);
881 r.WriteImage(wxBitmap(zebra_xpm), wxBITMAP_TYPE_PNG, imageAttr);
882 r.WriteText(wxString(wxT("This is a simple test for a floating right image test. The zebra image should be placed at the right side of the current buffer and all the text should flow around it at the left side. This is a simple test for a floating left image test. The zebra image should be placed at the right side of the current buffer and all the text should flow around it at the left side. This is a simple test for a floating left image test. The zebra image should be placed at the right side of the current buffer and all the text should flow around it at the left side.")));
883 r.EndAlignment();
884 r.Newline();
885
886 r.WriteText(wxT("What can you do with this thing? "));
887
888 r.WriteImage(wxBitmap(smiley_xpm));
889 r.WriteText(wxT(" Well, you can change text "));
890
891 r.BeginTextColour(wxColour(255, 0, 0));
892 r.WriteText(wxT("colour, like this red bit."));
893 r.EndTextColour();
894
895 wxRichTextAttr backgroundColourAttr;
896 backgroundColourAttr.SetBackgroundColour(*wxGREEN);
897 backgroundColourAttr.SetTextColour(wxColour(0, 0, 255));
898 r.BeginStyle(backgroundColourAttr);
899 r.WriteText(wxT(" And this blue on green bit."));
900 r.EndStyle();
901
902 r.WriteText(wxT(" Naturally you can make things "));
903 r.BeginBold();
904 r.WriteText(wxT("bold "));
905 r.EndBold();
906 r.BeginItalic();
907 r.WriteText(wxT("or italic "));
908 r.EndItalic();
909 r.BeginUnderline();
910 r.WriteText(wxT("or underlined."));
911 r.EndUnderline();
912
913 r.BeginFontSize(14);
914 r.WriteText(wxT(" Different font sizes on the same line is allowed, too."));
915 r.EndFontSize();
916
917 r.WriteText(wxT(" Next we'll show an indented paragraph."));
918
919 r.Newline();
920
921 r.BeginLeftIndent(60);
922 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."));
923 r.Newline();
924
925 r.EndLeftIndent();
926
927 r.WriteText(wxT("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40)."));
928
929 r.Newline();
930
931 r.BeginLeftIndent(100, -40);
932
933 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."));
934 r.Newline();
935
936 r.EndLeftIndent();
937
938 r.WriteText(wxT("Numbered bullets are possible, again using subindents:"));
939 r.Newline();
940
941 r.BeginNumberedBullet(1, 100, 60);
942 r.WriteText(wxT("This is my first item. Note that wxRichTextCtrl can apply numbering and bullets automatically based on list styles, but this list is formatted explicitly by setting indents."));
943 r.Newline();
944 r.EndNumberedBullet();
945
946 r.BeginNumberedBullet(2, 100, 60);
947 r.WriteText(wxT("This is my second item."));
948 r.Newline();
949 r.EndNumberedBullet();
950
951 r.WriteText(wxT("The following paragraph is right-indented:"));
952 r.Newline();
953
954 r.BeginRightIndent(200);
955
956 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."));
957 r.Newline();
958
959 r.EndRightIndent();
960
961 r.WriteText(wxT("The following paragraph is right-aligned with 1.5 line spacing:"));
962 r.Newline();
963
964 r.BeginAlignment(wxTEXT_ALIGNMENT_RIGHT);
965 r.BeginLineSpacing(wxTEXT_ATTR_LINE_SPACING_HALF);
966 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."));
967 r.Newline();
968 r.EndLineSpacing();
969 r.EndAlignment();
970
971 wxArrayInt tabs;
972 tabs.Add(400);
973 tabs.Add(600);
974 tabs.Add(800);
975 tabs.Add(1000);
976 wxRichTextAttr attr;
977 attr.SetFlags(wxTEXT_ATTR_TABS);
978 attr.SetTabs(tabs);
979 r.SetDefaultStyle(attr);
980
981 r.WriteText(wxT("This line contains tabs:\tFirst tab\tSecond tab\tThird tab"));
982 r.Newline();
983
984 r.WriteText(wxT("Other notable features of wxRichTextCtrl include:"));
985 r.Newline();
986
987 r.BeginSymbolBullet(wxT('*'), 100, 60);
988 r.WriteText(wxT("Compatibility with wxTextCtrl API"));
989 r.Newline();
990 r.EndSymbolBullet();
991
992 r.BeginSymbolBullet(wxT('*'), 100, 60);
993 r.WriteText(wxT("Easy stack-based BeginXXX()...EndXXX() style setting in addition to SetStyle()"));
994 r.Newline();
995 r.EndSymbolBullet();
996
997 r.BeginSymbolBullet(wxT('*'), 100, 60);
998 r.WriteText(wxT("XML loading and saving"));
999 r.Newline();
1000 r.EndSymbolBullet();
1001
1002 r.BeginSymbolBullet(wxT('*'), 100, 60);
1003 r.WriteText(wxT("Undo/Redo, with batching option and Undo suppressing"));
1004 r.Newline();
1005 r.EndSymbolBullet();
1006
1007 r.BeginSymbolBullet(wxT('*'), 100, 60);
1008 r.WriteText(wxT("Clipboard copy and paste"));
1009 r.Newline();
1010 r.EndSymbolBullet();
1011
1012 r.BeginSymbolBullet(wxT('*'), 100, 60);
1013 r.WriteText(wxT("wxRichTextStyleSheet with named character and paragraph styles, and control for applying named styles"));
1014 r.Newline();
1015 r.EndSymbolBullet();
1016
1017 r.BeginSymbolBullet(wxT('*'), 100, 60);
1018 r.WriteText(wxT("A design that can easily be extended to other content types, ultimately with text boxes, tables, controls, and so on"));
1019 r.Newline();
1020 r.EndSymbolBullet();
1021
1022 // Make a style suitable for showing a URL
1023 wxRichTextAttr urlStyle;
1024 urlStyle.SetTextColour(*wxBLUE);
1025 urlStyle.SetFontUnderlined(true);
1026
1027 r.WriteText(wxT("wxRichTextCtrl can also display URLs, such as this one: "));
1028 r.BeginStyle(urlStyle);
1029 r.BeginURL(wxT("http://www.wxwidgets.org"));
1030 r.WriteText(wxT("The wxWidgets Web Site"));
1031 r.EndURL();
1032 r.EndStyle();
1033 r.WriteText(wxT(". Click on the URL to generate an event."));
1034
1035 r.Newline();
1036
1037 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!\n"));
1038
1039 r.EndParagraphSpacing();
1040 #if 1
1041
1042 {
1043 // Add a text box
1044
1045 r.Newline();
1046
1047 wxRichTextAttr attr;
1048 attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
1049 attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
1050 attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
1051 attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(20, wxTEXT_ATTR_UNITS_PIXELS);
1052
1053 attr.GetTextBoxAttr().GetBorder().SetColour(*wxBLACK);
1054 attr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
1055 attr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
1056
1057 wxRichTextBox* textBox = r.WriteTextBox(attr);
1058 r.SetFocusObject(textBox);
1059
1060 r.WriteText(wxT("This is a text box. Just testing! Once more unto the breach, dear friends, once more..."));
1061
1062 r.SetFocusObject(NULL); // Set the focus back to the main buffer
1063 r.SetInsertionPointEnd();
1064 }
1065 #endif
1066 #if 1
1067 {
1068 // Add a table
1069
1070 r.Newline();
1071
1072 wxRichTextAttr attr;
1073 attr.GetTextBoxAttr().GetMargins().GetLeft().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
1074 attr.GetTextBoxAttr().GetMargins().GetTop().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
1075 attr.GetTextBoxAttr().GetMargins().GetRight().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
1076 attr.GetTextBoxAttr().GetMargins().GetBottom().SetValue(5, wxTEXT_ATTR_UNITS_PIXELS);
1077 attr.GetTextBoxAttr().GetPadding() = attr.GetTextBoxAttr().GetMargins();
1078
1079 attr.GetTextBoxAttr().GetBorder().SetColour(*wxBLACK);
1080 attr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
1081 attr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
1082
1083 wxRichTextAttr cellAttr = attr;
1084 cellAttr.GetTextBoxAttr().GetWidth().SetValue(200, wxTEXT_ATTR_UNITS_PIXELS);
1085 cellAttr.GetTextBoxAttr().GetHeight().SetValue(150, wxTEXT_ATTR_UNITS_PIXELS);
1086
1087 wxRichTextTable* table = r.WriteTable(3, 2, attr, cellAttr);
1088 int i, j;
1089 for (j = 0; j < table->GetRowCount(); j++)
1090 {
1091 for (i = 0; i < table->GetColumnCount(); i++)
1092 {
1093 wxString msg = wxString::Format(wxT("This is cell %d, %d"), (j+1), (i+1));
1094 r.SetFocusObject(table->GetCell(j, i));
1095 r.WriteText(msg);
1096 }
1097 }
1098 r.SetFocusObject(NULL); // Set the focus back to the main buffer
1099 r.SetInsertionPointEnd();
1100 }
1101 #endif
1102
1103 r.Thaw();
1104
1105 r.EndSuppressUndo();
1106 }
1107
1108 // event handlers
1109
1110 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
1111 {
1112 // true is to force the frame to close
1113 Close(true);
1114 }
1115
1116 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
1117 {
1118 wxString msg;
1119 msg.Printf( wxT("This is a demo for wxRichTextCtrl, a control for editing styled text.\n(c) Julian Smart, 2005"));
1120 wxMessageBox(msg, wxT("About wxRichTextCtrl Sample"), wxOK | wxICON_INFORMATION, this);
1121 }
1122
1123 // Forward command events to the current rich text control, if any
1124 bool MyFrame::ProcessEvent(wxEvent& event)
1125 {
1126 if (event.IsCommandEvent() && !event.IsKindOf(CLASSINFO(wxChildFocusEvent)))
1127 {
1128 // Problem: we can get infinite recursion because the events
1129 // climb back up to this frame, and repeat.
1130 // Assume that command events don't cause another command event
1131 // to be called, so we can rely on inCommand not being overwritten
1132
1133 static int s_eventType = 0;
1134 static wxWindowID s_id = 0;
1135
1136 if (s_id != event.GetId() && s_eventType != event.GetEventType())
1137 {
1138 s_eventType = event.GetEventType();
1139 s_id = event.GetId();
1140
1141 wxWindow* focusWin = wxFindFocusDescendant(this);
1142 if (focusWin && focusWin->GetEventHandler()->ProcessEvent(event))
1143 {
1144 //s_command = NULL;
1145 s_eventType = 0;
1146 s_id = 0;
1147 return true;
1148 }
1149
1150 s_eventType = 0;
1151 s_id = 0;
1152 }
1153 else
1154 {
1155 return false;
1156 }
1157 }
1158
1159 return wxFrame::ProcessEvent(event);
1160 }
1161
1162 void MyFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
1163 {
1164 wxString path;
1165 wxString filename;
1166 wxArrayInt fileTypes;
1167
1168 wxString filter = wxRichTextBuffer::GetExtWildcard(false, false, & fileTypes);
1169 if (!filter.empty())
1170 filter += wxT("|");
1171 filter += wxT("All files (*.*)|*.*");
1172
1173 wxFileDialog dialog(this,
1174 _("Choose a filename"),
1175 path,
1176 filename,
1177 filter,
1178 wxFD_OPEN);
1179
1180 if (dialog.ShowModal() == wxID_OK)
1181 {
1182 wxString path = dialog.GetPath();
1183
1184 if (!path.empty())
1185 {
1186 int filterIndex = dialog.GetFilterIndex();
1187 int fileType = (filterIndex < (int) fileTypes.GetCount())
1188 ? fileTypes[filterIndex]
1189 : wxRICHTEXT_TYPE_TEXT;
1190 m_richTextCtrl->LoadFile(path, fileType);
1191 }
1192 }
1193 }
1194
1195 void MyFrame::OnSave(wxCommandEvent& event)
1196 {
1197 if (m_richTextCtrl->GetFilename().empty())
1198 {
1199 OnSaveAs(event);
1200 return;
1201 }
1202 m_richTextCtrl->SaveFile();
1203 }
1204
1205 void MyFrame::OnSaveAs(wxCommandEvent& WXUNUSED(event))
1206 {
1207 wxString filter = wxRichTextBuffer::GetExtWildcard(false, true);
1208 wxString path;
1209 wxString filename;
1210
1211 wxFileDialog dialog(this,
1212 _("Choose a filename"),
1213 path,
1214 filename,
1215 filter,
1216 wxFD_SAVE);
1217
1218 if (dialog.ShowModal() == wxID_OK)
1219 {
1220 wxString path = dialog.GetPath();
1221
1222 if (!path.empty())
1223 {
1224 wxBusyCursor busy;
1225 wxStopWatch stopwatch;
1226
1227 m_richTextCtrl->SaveFile(path);
1228
1229 long t = stopwatch.Time();
1230 wxLogDebug(wxT("Saving took %ldms"), t);
1231 wxMessageBox(wxString::Format(wxT("Saving took %ldms"), t));
1232 }
1233 }
1234 }
1235
1236 void MyFrame::OnBold(wxCommandEvent& WXUNUSED(event))
1237 {
1238 m_richTextCtrl->ApplyBoldToSelection();
1239 }
1240
1241 void MyFrame::OnItalic(wxCommandEvent& WXUNUSED(event))
1242 {
1243 m_richTextCtrl->ApplyItalicToSelection();
1244 }
1245
1246 void MyFrame::OnUnderline(wxCommandEvent& WXUNUSED(event))
1247 {
1248 m_richTextCtrl->ApplyUnderlineToSelection();
1249 }
1250
1251 void MyFrame::OnStrikethrough(wxCommandEvent& WXUNUSED(event))
1252 {
1253 m_richTextCtrl->ApplyTextEffectToSelection(wxTEXT_ATTR_EFFECT_STRIKETHROUGH);
1254 }
1255
1256 void MyFrame::OnSuperscript(wxCommandEvent& WXUNUSED(event))
1257 {
1258 m_richTextCtrl->ApplyTextEffectToSelection(wxTEXT_ATTR_EFFECT_SUPERSCRIPT);
1259 }
1260
1261 void MyFrame::OnSubscript(wxCommandEvent& WXUNUSED(event))
1262 {
1263 m_richTextCtrl->ApplyTextEffectToSelection(wxTEXT_ATTR_EFFECT_SUBSCRIPT);
1264 }
1265
1266
1267 void MyFrame::OnUpdateBold(wxUpdateUIEvent& event)
1268 {
1269 event.Check(m_richTextCtrl->IsSelectionBold());
1270 }
1271
1272 void MyFrame::OnUpdateItalic(wxUpdateUIEvent& event)
1273 {
1274 event.Check(m_richTextCtrl->IsSelectionItalics());
1275 }
1276
1277 void MyFrame::OnUpdateUnderline(wxUpdateUIEvent& event)
1278 {
1279 event.Check(m_richTextCtrl->IsSelectionUnderlined());
1280 }
1281
1282 void MyFrame::OnUpdateStrikethrough(wxUpdateUIEvent& event)
1283 {
1284 event.Check(m_richTextCtrl->DoesSelectionHaveTextEffectFlag(wxTEXT_ATTR_EFFECT_STRIKETHROUGH));
1285 }
1286
1287 void MyFrame::OnUpdateSuperscript(wxUpdateUIEvent& event)
1288 {
1289 event.Check(m_richTextCtrl->DoesSelectionHaveTextEffectFlag(wxTEXT_ATTR_EFFECT_SUPERSCRIPT));
1290 }
1291
1292 void MyFrame::OnUpdateSubscript(wxUpdateUIEvent& event)
1293 {
1294 event.Check(m_richTextCtrl->DoesSelectionHaveTextEffectFlag(wxTEXT_ATTR_EFFECT_SUBSCRIPT));
1295 }
1296
1297 void MyFrame::OnAlignLeft(wxCommandEvent& WXUNUSED(event))
1298 {
1299 m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_LEFT);
1300 }
1301
1302 void MyFrame::OnAlignCentre(wxCommandEvent& WXUNUSED(event))
1303 {
1304 m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_CENTRE);
1305 }
1306
1307 void MyFrame::OnAlignRight(wxCommandEvent& WXUNUSED(event))
1308 {
1309 m_richTextCtrl->ApplyAlignmentToSelection(wxTEXT_ALIGNMENT_RIGHT);
1310 }
1311
1312 void MyFrame::OnUpdateAlignLeft(wxUpdateUIEvent& event)
1313 {
1314 event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_LEFT));
1315 }
1316
1317 void MyFrame::OnUpdateAlignCentre(wxUpdateUIEvent& event)
1318 {
1319 event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_CENTRE));
1320 }
1321
1322 void MyFrame::OnUpdateAlignRight(wxUpdateUIEvent& event)
1323 {
1324 event.Check(m_richTextCtrl->IsSelectionAligned(wxTEXT_ALIGNMENT_RIGHT));
1325 }
1326
1327 void MyFrame::OnFont(wxCommandEvent& WXUNUSED(event))
1328 {
1329 wxRichTextRange range;
1330 if (m_richTextCtrl->HasSelection())
1331 range = m_richTextCtrl->GetSelectionRange();
1332 else
1333 range = wxRichTextRange(0, m_richTextCtrl->GetLastPosition()+1);
1334
1335 int pages = wxRICHTEXT_FORMAT_FONT;
1336
1337 wxRichTextFormattingDialog formatDlg(pages, this);
1338 formatDlg.GetStyle(m_richTextCtrl, range);
1339
1340 if (formatDlg.ShowModal() == wxID_OK)
1341 {
1342 formatDlg.ApplyStyle(m_richTextCtrl, range, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_OPTIMIZE|wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY);
1343 }
1344
1345 // Old method using wxFontDialog
1346 #if 0
1347 if (!m_richTextCtrl->HasSelection())
1348 return;
1349
1350 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1351 wxFontData fontData;
1352
1353 wxRichTextAttr attr;
1354 attr.SetFlags(wxTEXT_ATTR_FONT);
1355
1356 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1357 fontData.SetInitialFont(attr.GetFont());
1358
1359 wxFontDialog dialog(this, fontData);
1360 if (dialog.ShowModal() == wxID_OK)
1361 {
1362 fontData = dialog.GetFontData();
1363 attr.SetFlags(wxTEXT_ATTR_FONT);
1364 attr.SetFont(fontData.GetChosenFont());
1365 if (attr.GetFont().IsOk())
1366 {
1367 m_richTextCtrl->SetStyle(range, attr);
1368 }
1369 }
1370 #endif
1371 }
1372
1373 void MyFrame::OnImage(wxCommandEvent& WXUNUSED(event))
1374 {
1375 wxRichTextRange range;
1376 wxASSERT(m_richTextCtrl->HasSelection());
1377
1378 range = m_richTextCtrl->GetSelectionRange();
1379 wxASSERT(range.ToInternal().GetLength() == 1);
1380
1381 wxRichTextImage* image = wxDynamicCast(m_richTextCtrl->GetFocusObject()->GetLeafObjectAtPosition(range.GetStart()), wxRichTextImage);
1382 if (image)
1383 {
1384 wxRichTextObjectPropertiesDialog imageDlg(image, this);
1385
1386 if (imageDlg.ShowModal() == wxID_OK)
1387 {
1388 imageDlg.ApplyStyle(m_richTextCtrl);
1389 }
1390 }
1391 }
1392
1393 void MyFrame::OnParagraph(wxCommandEvent& WXUNUSED(event))
1394 {
1395 wxRichTextRange range;
1396 if (m_richTextCtrl->HasSelection())
1397 range = m_richTextCtrl->GetSelectionRange();
1398 else
1399 range = wxRichTextRange(0, m_richTextCtrl->GetLastPosition()+1);
1400
1401 int pages = wxRICHTEXT_FORMAT_INDENTS_SPACING|wxRICHTEXT_FORMAT_TABS|wxRICHTEXT_FORMAT_BULLETS;
1402
1403 wxRichTextFormattingDialog formatDlg(pages, this);
1404 formatDlg.GetStyle(m_richTextCtrl, range);
1405
1406 if (formatDlg.ShowModal() == wxID_OK)
1407 {
1408 formatDlg.ApplyStyle(m_richTextCtrl, range);
1409 }
1410 }
1411
1412 void MyFrame::OnFormat(wxCommandEvent& WXUNUSED(event))
1413 {
1414 wxRichTextRange range;
1415 if (m_richTextCtrl->HasSelection())
1416 range = m_richTextCtrl->GetSelectionRange();
1417 else
1418 range = wxRichTextRange(0, m_richTextCtrl->GetLastPosition()+1);
1419
1420 int pages = wxRICHTEXT_FORMAT_FONT|wxRICHTEXT_FORMAT_INDENTS_SPACING|wxRICHTEXT_FORMAT_TABS|wxRICHTEXT_FORMAT_BULLETS;
1421
1422 wxRichTextFormattingDialog formatDlg(pages, this);
1423 formatDlg.GetStyle(m_richTextCtrl, range);
1424
1425 if (formatDlg.ShowModal() == wxID_OK)
1426 {
1427 formatDlg.ApplyStyle(m_richTextCtrl, range);
1428 }
1429 }
1430
1431 void MyFrame::OnUpdateFormat(wxUpdateUIEvent& event)
1432 {
1433 event.Enable(m_richTextCtrl->HasSelection());
1434 }
1435
1436 void MyFrame::OnUpdateImage(wxUpdateUIEvent& event)
1437 {
1438 wxRichTextRange range;
1439 wxRichTextObject *obj;
1440
1441 range = m_richTextCtrl->GetSelectionRange();
1442 if (range.ToInternal().GetLength() == 1)
1443 {
1444 obj = m_richTextCtrl->GetFocusObject()->GetLeafObjectAtPosition(range.GetStart());
1445 if (obj && obj->IsKindOf(CLASSINFO(wxRichTextImage)))
1446 {
1447 event.Enable(true);
1448 return;
1449 }
1450 }
1451
1452 event.Enable(false);
1453 }
1454
1455 void MyFrame::OnIndentMore(wxCommandEvent& WXUNUSED(event))
1456 {
1457 wxRichTextAttr attr;
1458 attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
1459
1460 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1461 {
1462 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1463 if (m_richTextCtrl->HasSelection())
1464 range = m_richTextCtrl->GetSelectionRange();
1465
1466 attr.SetLeftIndent(attr.GetLeftIndent() + 100);
1467
1468 attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
1469 m_richTextCtrl->SetStyle(range, attr);
1470 }
1471 }
1472
1473 void MyFrame::OnIndentLess(wxCommandEvent& WXUNUSED(event))
1474 {
1475 wxRichTextAttr attr;
1476 attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
1477
1478 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1479 {
1480 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1481 if (m_richTextCtrl->HasSelection())
1482 range = m_richTextCtrl->GetSelectionRange();
1483
1484 if (attr.GetLeftIndent() > 0)
1485 {
1486 attr.SetLeftIndent(wxMax(0, attr.GetLeftIndent() - 100));
1487
1488 m_richTextCtrl->SetStyle(range, attr);
1489 }
1490 }
1491 }
1492
1493 void MyFrame::OnLineSpacingHalf(wxCommandEvent& WXUNUSED(event))
1494 {
1495 wxRichTextAttr attr;
1496 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1497
1498 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1499 {
1500 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1501 if (m_richTextCtrl->HasSelection())
1502 range = m_richTextCtrl->GetSelectionRange();
1503
1504 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1505 attr.SetLineSpacing(15);
1506
1507 m_richTextCtrl->SetStyle(range, attr);
1508 }
1509 }
1510
1511 void MyFrame::OnLineSpacingDouble(wxCommandEvent& WXUNUSED(event))
1512 {
1513 wxRichTextAttr attr;
1514 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1515
1516 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1517 {
1518 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1519 if (m_richTextCtrl->HasSelection())
1520 range = m_richTextCtrl->GetSelectionRange();
1521
1522 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1523 attr.SetLineSpacing(20);
1524
1525 m_richTextCtrl->SetStyle(range, attr);
1526 }
1527 }
1528
1529 void MyFrame::OnLineSpacingSingle(wxCommandEvent& WXUNUSED(event))
1530 {
1531 wxRichTextAttr attr;
1532 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1533
1534 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1535 {
1536 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1537 if (m_richTextCtrl->HasSelection())
1538 range = m_richTextCtrl->GetSelectionRange();
1539
1540 attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
1541 attr.SetLineSpacing(0); // Can also use 10
1542
1543 m_richTextCtrl->SetStyle(range, attr);
1544 }
1545 }
1546
1547 void MyFrame::OnParagraphSpacingMore(wxCommandEvent& WXUNUSED(event))
1548 {
1549 wxRichTextAttr attr;
1550 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1551
1552 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1553 {
1554 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1555 if (m_richTextCtrl->HasSelection())
1556 range = m_richTextCtrl->GetSelectionRange();
1557
1558 attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() + 20);
1559
1560 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1561 m_richTextCtrl->SetStyle(range, attr);
1562 }
1563 }
1564
1565 void MyFrame::OnParagraphSpacingLess(wxCommandEvent& WXUNUSED(event))
1566 {
1567 wxRichTextAttr attr;
1568 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1569
1570 if (m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr))
1571 {
1572 wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
1573 if (m_richTextCtrl->HasSelection())
1574 range = m_richTextCtrl->GetSelectionRange();
1575
1576 if (attr.GetParagraphSpacingAfter() >= 20)
1577 {
1578 attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() - 20);
1579
1580 attr.SetFlags(wxTEXT_ATTR_PARA_SPACING_AFTER);
1581 m_richTextCtrl->SetStyle(range, attr);
1582 }
1583 }
1584 }
1585
1586 void MyFrame::OnReload(wxCommandEvent& WXUNUSED(event))
1587 {
1588 m_richTextCtrl->Clear();
1589 WriteInitialText();
1590 }
1591
1592 void MyFrame::OnViewHTML(wxCommandEvent& WXUNUSED(event))
1593 {
1594 wxDialog dialog(this, wxID_ANY, _("HTML"), wxDefaultPosition, wxSize(500, 400), wxDEFAULT_DIALOG_STYLE);
1595
1596 wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
1597 dialog.SetSizer(boxSizer);
1598
1599 wxHtmlWindow* win = new wxHtmlWindow(& dialog, wxID_ANY, wxDefaultPosition, wxSize(500, 400), wxSUNKEN_BORDER);
1600 boxSizer->Add(win, 1, wxALL, 5);
1601
1602 wxButton* cancelButton = new wxButton(& dialog, wxID_CANCEL, wxT("&Close"));
1603 boxSizer->Add(cancelButton, 0, wxALL|wxCENTRE, 5);
1604
1605 wxString text;
1606 wxStringOutputStream strStream(& text);
1607
1608 wxRichTextHTMLHandler htmlHandler;
1609 htmlHandler.SetFlags(wxRICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY);
1610
1611 wxArrayInt fontSizeMapping;
1612 fontSizeMapping.Add(7);
1613 fontSizeMapping.Add(9);
1614 fontSizeMapping.Add(11);
1615 fontSizeMapping.Add(12);
1616 fontSizeMapping.Add(14);
1617 fontSizeMapping.Add(22);
1618 fontSizeMapping.Add(100);
1619
1620 htmlHandler.SetFontSizeMapping(fontSizeMapping);
1621
1622 if (htmlHandler.SaveFile(& m_richTextCtrl->GetBuffer(), strStream))
1623 {
1624 win->SetPage(text);
1625 }
1626
1627 boxSizer->Fit(& dialog);
1628
1629 dialog.ShowModal();
1630
1631 // Now delete the temporary in-memory images
1632 htmlHandler.DeleteTemporaryImages();
1633 }
1634
1635 // Demonstrates how you can change the style sheets and have the changes
1636 // reflected in the control content without wiping out character formatting.
1637
1638 void MyFrame::OnSwitchStyleSheets(wxCommandEvent& WXUNUSED(event))
1639 {
1640 static wxRichTextStyleSheet* gs_AlternateStyleSheet = NULL;
1641
1642 wxRichTextStyleListCtrl *styleList = (wxRichTextStyleListCtrl*) FindWindow(ID_RICHTEXT_STYLE_LIST);
1643 wxRichTextStyleComboCtrl* styleCombo = (wxRichTextStyleComboCtrl*) FindWindow(ID_RICHTEXT_STYLE_COMBO);
1644
1645 wxRichTextStyleSheet* sheet = m_richTextCtrl->GetStyleSheet();
1646
1647 // One-time creation of an alternate style sheet
1648 if (!gs_AlternateStyleSheet)
1649 {
1650 gs_AlternateStyleSheet = new wxRichTextStyleSheet(*sheet);
1651
1652 // Make some modifications
1653 for (int i = 0; i < (int) gs_AlternateStyleSheet->GetParagraphStyleCount(); i++)
1654 {
1655 wxRichTextParagraphStyleDefinition* def = gs_AlternateStyleSheet->GetParagraphStyle(i);
1656
1657 if (def->GetStyle().HasTextColour())
1658 def->GetStyle().SetTextColour(*wxBLUE);
1659
1660 if (def->GetStyle().HasAlignment())
1661 {
1662 if (def->GetStyle().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
1663 def->GetStyle().SetAlignment(wxTEXT_ALIGNMENT_RIGHT);
1664 else if (def->GetStyle().GetAlignment() == wxTEXT_ALIGNMENT_LEFT)
1665 def->GetStyle().SetAlignment(wxTEXT_ALIGNMENT_CENTRE);
1666 }
1667 if (def->GetStyle().HasLeftIndent())
1668 {
1669 def->GetStyle().SetLeftIndent(def->GetStyle().GetLeftIndent() * 2);
1670 }
1671 }
1672 }
1673
1674 // Switch sheets
1675 wxRichTextStyleSheet* tmp = gs_AlternateStyleSheet;
1676 gs_AlternateStyleSheet = sheet;
1677 sheet = tmp;
1678
1679 m_richTextCtrl->SetStyleSheet(sheet);
1680 m_richTextCtrl->ApplyStyleSheet(sheet); // Makes the control reflect the new style definitions
1681
1682 styleList->SetStyleSheet(sheet);
1683 styleList->UpdateStyles();
1684
1685 styleCombo->SetStyleSheet(sheet);
1686 styleCombo->UpdateStyles();
1687 }
1688
1689 void MyFrame::OnManageStyles(wxCommandEvent& WXUNUSED(event))
1690 {
1691 wxRichTextStyleSheet* sheet = m_richTextCtrl->GetStyleSheet();
1692
1693 int flags = wxRICHTEXT_ORGANISER_CREATE_STYLES|wxRICHTEXT_ORGANISER_EDIT_STYLES;
1694
1695 wxRichTextStyleOrganiserDialog dlg(flags, sheet, NULL, this, wxID_ANY, _("Style Manager"));
1696 dlg.ShowModal();
1697 }
1698
1699 void MyFrame::OnInsertSymbol(wxCommandEvent& WXUNUSED(event))
1700 {
1701 wxRichTextAttr attr;
1702 attr.SetFlags(wxTEXT_ATTR_FONT);
1703 m_richTextCtrl->GetStyle(m_richTextCtrl->GetInsertionPoint(), attr);
1704
1705 wxString currentFontName;
1706 if (attr.HasFont() && attr.GetFont().IsOk())
1707 currentFontName = attr.GetFont().GetFaceName();
1708
1709 // Don't set the initial font in the dialog (so the user is choosing
1710 // 'normal text', i.e. the current font) but do tell the dialog
1711 // what 'normal text' is.
1712
1713 wxSymbolPickerDialog dlg(wxT("*"), wxEmptyString, currentFontName, this);
1714
1715 if (dlg.ShowModal() == wxID_OK)
1716 {
1717 if (dlg.HasSelection())
1718 {
1719 long insertionPoint = m_richTextCtrl->GetInsertionPoint();
1720
1721 m_richTextCtrl->WriteText(dlg.GetSymbol());
1722
1723 if (!dlg.UseNormalFont())
1724 {
1725 wxFont font(attr.GetFont());
1726 font.SetFaceName(dlg.GetFontName());
1727 attr.SetFont(font);
1728 m_richTextCtrl->SetStyle(insertionPoint, insertionPoint+1, attr);
1729 }
1730 }
1731 }
1732 }
1733
1734 void MyFrame::OnNumberList(wxCommandEvent& WXUNUSED(event))
1735 {
1736 if (m_richTextCtrl->HasSelection())
1737 {
1738 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1739 m_richTextCtrl->SetListStyle(range, wxT("Numbered List 1"), wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_RENUMBER);
1740 }
1741 }
1742
1743 void MyFrame::OnBulletsAndNumbering(wxCommandEvent& WXUNUSED(event))
1744 {
1745 wxRichTextStyleSheet* sheet = m_richTextCtrl->GetStyleSheet();
1746
1747 int flags = wxRICHTEXT_ORGANISER_BROWSE_NUMBERING;
1748
1749 wxRichTextStyleOrganiserDialog dlg(flags, sheet, m_richTextCtrl, this, wxID_ANY, _("Bullets and Numbering"));
1750 if (dlg.ShowModal() == wxID_OK)
1751 {
1752 if (dlg.GetSelectedStyleDefinition())
1753 dlg.ApplyStyle();
1754 }
1755 }
1756
1757 void MyFrame::OnItemizeList(wxCommandEvent& WXUNUSED(event))
1758 {
1759 if (m_richTextCtrl->HasSelection())
1760 {
1761 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1762 m_richTextCtrl->SetListStyle(range, wxT("Bullet List 1"));
1763 }
1764 }
1765
1766 void MyFrame::OnRenumberList(wxCommandEvent& WXUNUSED(event))
1767 {
1768 if (m_richTextCtrl->HasSelection())
1769 {
1770 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1771 m_richTextCtrl->NumberList(range, NULL, wxRICHTEXT_SETSTYLE_WITH_UNDO|wxRICHTEXT_SETSTYLE_RENUMBER);
1772 }
1773 }
1774
1775 void MyFrame::OnPromoteList(wxCommandEvent& WXUNUSED(event))
1776 {
1777 if (m_richTextCtrl->HasSelection())
1778 {
1779 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1780 m_richTextCtrl->PromoteList(1, range, NULL);
1781 }
1782 }
1783
1784 void MyFrame::OnDemoteList(wxCommandEvent& WXUNUSED(event))
1785 {
1786 if (m_richTextCtrl->HasSelection())
1787 {
1788 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1789 m_richTextCtrl->PromoteList(-1, range, NULL);
1790 }
1791 }
1792
1793 void MyFrame::OnClearList(wxCommandEvent& WXUNUSED(event))
1794 {
1795 if (m_richTextCtrl->HasSelection())
1796 {
1797 wxRichTextRange range = m_richTextCtrl->GetSelectionRange();
1798 m_richTextCtrl->ClearListStyle(range);
1799 }
1800 }
1801
1802 void MyFrame::OnInsertURL(wxCommandEvent& WXUNUSED(event))
1803 {
1804 wxString url = wxGetTextFromUser(_("URL:"), _("Insert URL"));
1805 if (!url.IsEmpty())
1806 {
1807 // Make a style suitable for showing a URL
1808 wxRichTextAttr urlStyle;
1809 urlStyle.SetTextColour(*wxBLUE);
1810 urlStyle.SetFontUnderlined(true);
1811
1812 m_richTextCtrl->BeginStyle(urlStyle);
1813 m_richTextCtrl->BeginURL(url);
1814 m_richTextCtrl->WriteText(url);
1815 m_richTextCtrl->EndURL();
1816 m_richTextCtrl->EndStyle();
1817 }
1818 }
1819
1820 void MyFrame::OnInsertImage(wxCommandEvent& WXUNUSED(event))
1821 {
1822 wxFileDialog dialog(this, _("Choose an image"), "", "", "BMP and GIF files (*.bmp;*.gif)|*.bmp;*.gif|PNG files (*.png)|*.png");
1823 if (dialog.ShowModal() == wxID_OK)
1824 {
1825 wxString path = dialog.GetPath();
1826 m_richTextCtrl->WriteImage(path, wxBITMAP_TYPE_ANY);
1827 }
1828 }
1829
1830 void MyFrame::OnURL(wxTextUrlEvent& event)
1831 {
1832 wxMessageBox(event.GetString());
1833 }
1834
1835 // Veto style sheet replace events when loading from XML, since we want
1836 // to keep the original style sheet.
1837 void MyFrame::OnStyleSheetReplacing(wxRichTextEvent& event)
1838 {
1839 event.Veto();
1840 }
1841
1842 void MyFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
1843 {
1844 wxGetApp().GetPrinting()->PrintBuffer(m_richTextCtrl->GetBuffer());
1845 }
1846
1847 void MyFrame::OnPreview(wxCommandEvent& WXUNUSED(event))
1848 {
1849 wxGetApp().GetPrinting()->PreviewBuffer(m_richTextCtrl->GetBuffer());
1850 }
1851
1852 void MyFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
1853 {
1854 wxDialog dialog(this, wxID_ANY, wxT("Testing"), wxPoint(10, 10), wxSize(400, 300), wxDEFAULT_DIALOG_STYLE);
1855
1856 wxNotebook* nb = new wxNotebook(& dialog, wxID_ANY, wxPoint(5, 5), wxSize(300, 250));
1857 wxPanel* panel = new wxPanel(nb, wxID_ANY, wxDefaultPosition, wxDefaultSize);
1858 wxPanel* panel2 = new wxPanel(nb, wxID_ANY, wxDefaultPosition, wxDefaultSize);
1859
1860 new wxRichTextCtrl(panel, wxID_ANY, wxEmptyString, wxPoint(5, 5), wxSize(200, 150), wxVSCROLL|wxTE_READONLY);
1861 nb->AddPage(panel, wxT("Page 1"));
1862
1863 new wxRichTextCtrl(panel2, wxID_ANY, wxEmptyString, wxPoint(5, 5), wxSize(200, 150), wxVSCROLL|wxTE_READONLY);
1864 nb->AddPage(panel2, wxT("Page 2"));
1865
1866 new wxButton(& dialog, wxID_OK, wxT("OK"), wxPoint(5, 180));
1867
1868 dialog.ShowModal();
1869
1870 // wxGetApp().GetPrinting()->PageSetup();
1871 }
1872
1873 void MyRichTextCtrl::PrepareContent(wxRichTextParagraphLayoutBox& container)
1874 {
1875 if (IsLocked())
1876 {
1877 // Lock all content that's about to be added to the control
1878 wxRichTextObjectList::compatibility_iterator node = container.GetChildren().GetFirst();
1879 while (node)
1880 {
1881 wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
1882 if (para)
1883 {
1884 wxRichTextObjectList::compatibility_iterator childNode = para->GetChildren().GetFirst();
1885 while (childNode)
1886 {
1887 wxRichTextObject* obj = childNode->GetData();
1888 obj->GetProperties().SetProperty(wxT("Lock"), m_lockId);
1889
1890 childNode = childNode->GetNext();
1891 }
1892 }
1893 node = node->GetNext();
1894 }
1895 }
1896 }
1897
1898 bool MyRichTextCtrl::CanDeleteRange(wxRichTextParagraphLayoutBox& container, const wxRichTextRange& range) const
1899 {
1900 long i;
1901 for (i = range.GetStart(); i < range.GetEnd(); i++)
1902 {
1903 wxRichTextObject* obj = container.GetLeafObjectAtPosition(i);
1904 if (obj && obj->GetProperties().HasProperty(wxT("Lock")))
1905 {
1906 return false;
1907 }
1908 }
1909 return true;
1910 }
1911
1912 bool MyRichTextCtrl::CanInsertContent(wxRichTextParagraphLayoutBox& container, long pos) const
1913 {
1914 wxRichTextObject* child1 = container.GetLeafObjectAtPosition(pos);
1915 wxRichTextObject* child2 = container.GetLeafObjectAtPosition(pos-1);
1916
1917 long lock1 = -1, lock2 = -1;
1918
1919 if (child1 && child1->GetProperties().HasProperty(wxT("Lock")))
1920 lock1 = child1->GetProperties().GetPropertyLong(wxT("Lock"));
1921 if (child2 && child2->GetProperties().HasProperty(wxT("Lock")))
1922 lock2 = child2->GetProperties().GetPropertyLong(wxT("Lock"));
1923
1924 if (lock1 != -1 && lock1 == lock2)
1925 return false;
1926
1927 // Don't allow insertion before a locked object if it's at the beginning of the buffer.
1928 if (pos == 0 && lock1 != -1)
1929 return false;
1930
1931 return true;
1932 }
1933
1934
1935 class wxRichTextEnhancedDrawingHandler: public wxRichTextDrawingHandler
1936 {
1937 public:
1938 wxRichTextEnhancedDrawingHandler()
1939 {
1940 SetName(wxT("enhanceddrawing"));
1941 m_lockBackgroundColour = wxColour(220, 220, 220);
1942 }
1943
1944 /**
1945 Returns @true if this object has virtual attributes that we can provide.
1946 */
1947 virtual bool HasVirtualAttributes(wxRichTextObject* obj) const;
1948
1949 /**
1950 Provides virtual attributes that we can provide.
1951 */
1952 virtual bool GetVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const;
1953
1954 wxColour m_lockBackgroundColour;
1955 };
1956
1957 bool wxRichTextEnhancedDrawingHandler::HasVirtualAttributes(wxRichTextObject* obj) const
1958 {
1959 return obj->GetProperties().HasProperty(wxT("Lock"));
1960 }
1961
1962 bool wxRichTextEnhancedDrawingHandler::GetVirtualAttributes(wxRichTextAttr& attr, wxRichTextObject* obj) const
1963 {
1964 if (obj->GetProperties().HasProperty(wxT("Lock")))
1965 {
1966 attr.SetBackgroundColour(m_lockBackgroundColour);
1967 return true;
1968 }
1969 return false;
1970 }
1971
1972 void MyRichTextCtrl::SetEnhancedDrawingHandler()
1973 {
1974 wxRichTextBuffer::AddDrawingHandler(new wxRichTextEnhancedDrawingHandler);
1975 }