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