Merge in from trunk r68684 - r69046
[wxWidgets.git] / src / richtext / richtextstyles.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/richtext/richtextstyles.cpp
3 // Purpose: Style management for wxRichTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 2005-09-30
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_RICHTEXT
20
21 #include "wx/richtext/richtextstyles.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #include "wx/filename.h"
28 #include "wx/clipbrd.h"
29 #include "wx/wfstream.h"
30 #include "wx/settings.h"
31
32 #include "wx/richtext/richtextctrl.h"
33
34 IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject)
35 IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition)
36 IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition)
37 IMPLEMENT_CLASS(wxRichTextListStyleDefinition, wxRichTextParagraphStyleDefinition)
38 IMPLEMENT_CLASS(wxRichTextBoxStyleDefinition, wxRichTextStyleDefinition)
39
40 /*!
41 * A definition
42 */
43
44 void wxRichTextStyleDefinition::Copy(const wxRichTextStyleDefinition& def)
45 {
46 m_name = def.m_name;
47 m_baseStyle = def.m_baseStyle;
48 m_style = def.m_style;
49 m_description = def.m_description;
50 }
51
52 bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition& def) const
53 {
54 return (m_name == def.m_name && m_baseStyle == def.m_baseStyle && m_style == def.m_style);
55 }
56
57 /// Gets the style combined with the base style
58 wxRichTextAttr wxRichTextStyleDefinition::GetStyleMergedWithBase(const wxRichTextStyleSheet* sheet) const
59 {
60 if (m_baseStyle.IsEmpty())
61 return m_style;
62
63 bool isParaStyle = IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition));
64 bool isCharStyle = IsKindOf(CLASSINFO(wxRichTextCharacterStyleDefinition));
65 bool isListStyle = IsKindOf(CLASSINFO(wxRichTextListStyleDefinition));
66 bool isBoxStyle = IsKindOf(CLASSINFO(wxRichTextBoxStyleDefinition));
67
68 // Collect the styles, detecting loops
69 wxArrayString styleNames;
70 wxList styles;
71 const wxRichTextStyleDefinition* def = this;
72 while (def)
73 {
74 styles.Insert((wxObject*) def);
75 styleNames.Add(def->GetName());
76
77 wxString baseStyleName = def->GetBaseStyle();
78 if (!baseStyleName.IsEmpty() && styleNames.Index(baseStyleName) == wxNOT_FOUND)
79 {
80 if (isParaStyle)
81 def = sheet->FindParagraphStyle(baseStyleName);
82 else if (isCharStyle)
83 def = sheet->FindCharacterStyle(baseStyleName);
84 else if (isListStyle)
85 def = sheet->FindListStyle(baseStyleName);
86 else if (isBoxStyle)
87 def = sheet->FindBoxStyle(baseStyleName);
88 else
89 def = sheet->FindStyle(baseStyleName);
90 }
91 else
92 def = NULL;
93 }
94
95 wxRichTextAttr attr;
96 wxList::compatibility_iterator node = styles.GetFirst();
97 while (node)
98 {
99 wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
100 attr.Apply(def->GetStyle(), NULL);
101 node = node->GetNext();
102 }
103
104 return attr;
105 }
106
107 /*!
108 * Paragraph style definition
109 */
110
111 void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition& def)
112 {
113 wxRichTextStyleDefinition::Copy(def);
114
115 m_nextStyle = def.m_nextStyle;
116 }
117
118 bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition& def) const
119 {
120 return (Eq(def) && m_nextStyle == def.m_nextStyle);
121 }
122
123 /*!
124 * Box style definition
125 */
126
127 void wxRichTextBoxStyleDefinition::Copy(const wxRichTextBoxStyleDefinition& def)
128 {
129 wxRichTextStyleDefinition::Copy(def);
130 }
131
132 bool wxRichTextBoxStyleDefinition::operator ==(const wxRichTextBoxStyleDefinition& def) const
133 {
134 return (Eq(def));
135 }
136
137 /*!
138 * List style definition
139 */
140
141 void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition& def)
142 {
143 wxRichTextParagraphStyleDefinition::Copy(def);
144
145 int i;
146 for (i = 0; i < 10; i++)
147 m_levelStyles[i] = def.m_levelStyles[i];
148 }
149
150 bool wxRichTextListStyleDefinition::operator ==(const wxRichTextListStyleDefinition& def) const
151 {
152 if (!Eq(def))
153 return false;
154 int i;
155 for (i = 0; i < 10; i++)
156 if (!(m_levelStyles[i] == def.m_levelStyles[i]))
157 return false;
158
159 return true;
160 }
161
162 /// Sets/gets the attributes for the given level
163 void wxRichTextListStyleDefinition::SetLevelAttributes(int i, const wxRichTextAttr& attr)
164 {
165 wxASSERT( (i >= 0 && i < 10) );
166 if (i >= 0 && i < 10)
167 m_levelStyles[i] = attr;
168 }
169
170 const wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i) const
171 {
172 wxASSERT( (i >= 0 && i < 10) );
173 if (i >= 0 && i < 10)
174 return & m_levelStyles[i];
175 else
176 return NULL;
177 }
178
179 wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i)
180 {
181 wxASSERT( (i >= 0 && i < 10) );
182 if (i >= 0 && i < 10)
183 return & m_levelStyles[i];
184 else
185 return NULL;
186 }
187
188 /// Convenience function for setting the major attributes for a list level specification
189 void wxRichTextListStyleDefinition::SetAttributes(int i, int leftIndent, int leftSubIndent, int bulletStyle, const wxString& bulletSymbol)
190 {
191 wxASSERT( (i >= 0 && i < 10) );
192 if (i >= 0 && i < 10)
193 {
194 wxRichTextAttr attr;
195
196 attr.SetBulletStyle(bulletStyle);
197 attr.SetLeftIndent(leftIndent, leftSubIndent);
198
199 if (!bulletSymbol.IsEmpty())
200 {
201 if (bulletStyle & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)
202 attr.SetBulletText(bulletSymbol);
203 else
204 attr.SetBulletName(bulletSymbol);
205 }
206
207 m_levelStyles[i] = attr;
208 }
209 }
210
211 /// Finds the level corresponding to the given indentation
212 int wxRichTextListStyleDefinition::FindLevelForIndent(int indent) const
213 {
214 int i;
215 for (i = 0; i < 10; i++)
216 {
217 if (indent < m_levelStyles[i].GetLeftIndent())
218 {
219 if (i > 0)
220 return i - 1;
221 else
222 return 0;
223 }
224 }
225 return 9;
226 }
227
228 /// Combine the list style with a paragraph style, using the given indent (from which
229 /// an appropriate level is found)
230 wxRichTextAttr wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent, const wxRichTextAttr& paraStyle, wxRichTextStyleSheet* styleSheet)
231 {
232 int listLevel = FindLevelForIndent(indent);
233
234 wxRichTextAttr attr(*GetLevelAttributes(listLevel));
235 int oldLeftIndent = attr.GetLeftIndent();
236 int oldLeftSubIndent = attr.GetLeftSubIndent();
237
238 // First apply the overall paragraph style, if any
239 if (styleSheet)
240 attr.Apply(GetStyleMergedWithBase(styleSheet));
241 else
242 attr.Apply(GetStyle());
243
244 // Then apply paragraph style, e.g. from paragraph style definition
245 attr.Apply(paraStyle);
246
247 // We override the indents according to the list definition
248 attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
249
250 return attr;
251 }
252
253 /// Combine the base and list style, using the given indent (from which
254 /// an appropriate level is found)
255 wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyle(int indent, wxRichTextStyleSheet* styleSheet)
256 {
257 int listLevel = FindLevelForIndent(indent);
258 return GetCombinedStyleForLevel(listLevel, styleSheet);
259 }
260
261 /// Combine the base and list style, using the given indent (from which
262 /// an appropriate level is found)
263 wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel, wxRichTextStyleSheet* styleSheet)
264 {
265 wxRichTextAttr attr(*GetLevelAttributes(listLevel));
266 int oldLeftIndent = attr.GetLeftIndent();
267 int oldLeftSubIndent = attr.GetLeftSubIndent();
268
269 // Apply the overall paragraph style, if any
270 if (styleSheet)
271 attr.Apply(GetStyleMergedWithBase(styleSheet));
272 else
273 attr.Apply(GetStyle());
274
275 // We override the indents according to the list definition
276 attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
277
278 return attr;
279 }
280
281 /// Is this a numbered list?
282 bool wxRichTextListStyleDefinition::IsNumbered(int i) const
283 {
284 return (0 != (GetLevelAttributes(i)->GetFlags() &
285 (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER|wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER|
286 wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER|wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)));
287 }
288
289 /*!
290 * The style manager
291 */
292
293 IMPLEMENT_CLASS(wxRichTextStyleSheet, wxObject)
294
295 wxRichTextStyleSheet::~wxRichTextStyleSheet()
296 {
297 DeleteStyles();
298
299 if (m_nextSheet)
300 m_nextSheet->m_previousSheet = m_previousSheet;
301
302 if (m_previousSheet)
303 m_previousSheet->m_nextSheet = m_nextSheet;
304
305 m_previousSheet = NULL;
306 m_nextSheet = NULL;
307 }
308
309 /// Initialisation
310 void wxRichTextStyleSheet::Init()
311 {
312 m_previousSheet = NULL;
313 m_nextSheet = NULL;
314 }
315
316 /// Add a definition to one of the style lists
317 bool wxRichTextStyleSheet::AddStyle(wxList& list, wxRichTextStyleDefinition* def)
318 {
319 if (!list.Find(def))
320 list.Append(def);
321 return true;
322 }
323
324 /// Remove a style
325 bool wxRichTextStyleSheet::RemoveStyle(wxList& list, wxRichTextStyleDefinition* def, bool deleteStyle)
326 {
327 wxList::compatibility_iterator node = list.Find(def);
328 if (node)
329 {
330 wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
331 list.Erase(node);
332 if (deleteStyle)
333 delete def;
334 return true;
335 }
336 else
337 return false;
338 }
339
340 /// Remove a style
341 bool wxRichTextStyleSheet::RemoveStyle(wxRichTextStyleDefinition* def, bool deleteStyle)
342 {
343 if (RemoveParagraphStyle(def, deleteStyle))
344 return true;
345 if (RemoveCharacterStyle(def, deleteStyle))
346 return true;
347 if (RemoveListStyle(def, deleteStyle))
348 return true;
349 if (RemoveBoxStyle(def, deleteStyle))
350 return true;
351 return false;
352 }
353
354 /// Find a definition by name
355 wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name, bool recurse) const
356 {
357 for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
358 {
359 wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
360 if (def->GetName().Lower() == name.Lower())
361 return def;
362 }
363
364 if (m_nextSheet && recurse)
365 return m_nextSheet->FindStyle(list, name, recurse);
366
367 return NULL;
368 }
369
370 /// Delete all styles
371 void wxRichTextStyleSheet::DeleteStyles()
372 {
373 WX_CLEAR_LIST(wxList, m_characterStyleDefinitions);
374 WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
375 WX_CLEAR_LIST(wxList, m_listStyleDefinitions);
376 WX_CLEAR_LIST(wxList, m_boxStyleDefinitions);
377 }
378
379 /// Insert into list of style sheets
380 bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet* before)
381 {
382 m_previousSheet = before->m_previousSheet;
383 m_nextSheet = before;
384
385 before->m_previousSheet = this;
386 return true;
387 }
388
389 /// Append to list of style sheets
390 bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet* after)
391 {
392 wxRichTextStyleSheet* last = after;
393 while (last && last->m_nextSheet)
394 {
395 last = last->m_nextSheet;
396 }
397
398 if (last)
399 {
400 m_previousSheet = last;
401 last->m_nextSheet = this;
402
403 return true;
404 }
405 else
406 return false;
407 }
408
409 /// Unlink from the list of style sheets
410 void wxRichTextStyleSheet::Unlink()
411 {
412 if (m_previousSheet)
413 m_previousSheet->m_nextSheet = m_nextSheet;
414 if (m_nextSheet)
415 m_nextSheet->m_previousSheet = m_previousSheet;
416
417 m_previousSheet = NULL;
418 m_nextSheet = NULL;
419 }
420
421 /// Add a definition to the character style list
422 bool wxRichTextStyleSheet::AddCharacterStyle(wxRichTextCharacterStyleDefinition* def)
423 {
424 def->GetStyle().SetCharacterStyleName(def->GetName());
425 return AddStyle(m_characterStyleDefinitions, def);
426 }
427
428 /// Add a definition to the paragraph style list
429 bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition* def)
430 {
431 def->GetStyle().SetParagraphStyleName(def->GetName());
432 return AddStyle(m_paragraphStyleDefinitions, def);
433 }
434
435 /// Add a definition to the list style list
436 bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition* def)
437 {
438 def->GetStyle().SetListStyleName(def->GetName());
439 return AddStyle(m_listStyleDefinitions, def);
440 }
441
442 /// Add a definition to the box style list
443 bool wxRichTextStyleSheet::AddBoxStyle(wxRichTextBoxStyleDefinition* def)
444 {
445 def->GetStyle().SetParagraphStyleName(def->GetName());
446 return AddStyle(m_boxStyleDefinitions, def);
447 }
448
449 /// Add a definition to the appropriate style list
450 bool wxRichTextStyleSheet::AddStyle(wxRichTextStyleDefinition* def)
451 {
452 wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
453 if (listDef)
454 return AddListStyle(listDef);
455
456 wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
457 if (paraDef)
458 return AddParagraphStyle(paraDef);
459
460 wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
461 if (charDef)
462 return AddCharacterStyle(charDef);
463
464 wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition);
465 if (boxDef)
466 return AddBoxStyle(boxDef);
467
468 return false;
469 }
470
471 /// Find any definition by name
472 wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxString& name, bool recurse) const
473 {
474 wxRichTextListStyleDefinition* listDef = FindListStyle(name, recurse);
475 if (listDef)
476 return listDef;
477
478 wxRichTextParagraphStyleDefinition* paraDef = FindParagraphStyle(name, recurse);
479 if (paraDef)
480 return paraDef;
481
482 wxRichTextCharacterStyleDefinition* charDef = FindCharacterStyle(name, recurse);
483 if (charDef)
484 return charDef;
485
486 wxRichTextBoxStyleDefinition* boxDef = FindBoxStyle(name, recurse);
487 if (boxDef)
488 return boxDef;
489
490 return NULL;
491 }
492
493 /// Copy
494 void wxRichTextStyleSheet::Copy(const wxRichTextStyleSheet& sheet)
495 {
496 DeleteStyles();
497
498 wxList::compatibility_iterator node;
499
500 for (node = sheet.m_characterStyleDefinitions.GetFirst(); node; node = node->GetNext())
501 {
502 wxRichTextCharacterStyleDefinition* def = (wxRichTextCharacterStyleDefinition*) node->GetData();
503 AddCharacterStyle(new wxRichTextCharacterStyleDefinition(*def));
504 }
505
506 for (node = sheet.m_paragraphStyleDefinitions.GetFirst(); node; node = node->GetNext())
507 {
508 wxRichTextParagraphStyleDefinition* def = (wxRichTextParagraphStyleDefinition*) node->GetData();
509 AddParagraphStyle(new wxRichTextParagraphStyleDefinition(*def));
510 }
511
512 for (node = sheet.m_listStyleDefinitions.GetFirst(); node; node = node->GetNext())
513 {
514 wxRichTextListStyleDefinition* def = (wxRichTextListStyleDefinition*) node->GetData();
515 AddListStyle(new wxRichTextListStyleDefinition(*def));
516 }
517
518 for (node = sheet.m_boxStyleDefinitions.GetFirst(); node; node = node->GetNext())
519 {
520 wxRichTextBoxStyleDefinition* def = (wxRichTextBoxStyleDefinition*) node->GetData();
521 AddBoxStyle(new wxRichTextBoxStyleDefinition(*def));
522 }
523
524 SetName(sheet.GetName());
525 SetDescription(sheet.GetDescription());
526 }
527
528 /// Equality
529 bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
530 {
531 // TODO
532 return false;
533 }
534
535
536 #if wxUSE_HTML
537
538 // Functions for dealing with clashing names for different kinds of style.
539 // Returns "P", "C", "L" or "B" (paragraph, character, list or box) for
540 // style name | type.
541 static wxString wxGetRichTextStyleType(const wxString& style)
542 {
543 return style.AfterLast(wxT('|'));
544 }
545
546 static wxString wxGetRichTextStyle(const wxString& style)
547 {
548 return style.BeforeLast(wxT('|'));
549 }
550
551
552 /*!
553 * wxRichTextStyleListBox: a listbox to display styles.
554 */
555
556 IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
557
558 BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
559 EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown)
560 EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick)
561 EVT_IDLE(wxRichTextStyleListBox::OnIdle)
562 END_EVENT_TABLE()
563
564 wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
565 const wxSize& size, long style)
566 {
567 Init();
568 Create(parent, id, pos, size, style);
569 }
570
571 bool wxRichTextStyleListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
572 const wxSize& size, long style)
573 {
574 return wxHtmlListBox::Create(parent, id, pos, size, style);
575 }
576
577 wxRichTextStyleListBox::~wxRichTextStyleListBox()
578 {
579 }
580
581 /// Returns the HTML for this item
582 wxString wxRichTextStyleListBox::OnGetItem(size_t n) const
583 {
584 if (!GetStyleSheet())
585 return wxEmptyString;
586
587 wxRichTextStyleDefinition* def = GetStyle(n);
588 if (def)
589 return CreateHTML(def);
590
591 return wxEmptyString;
592 }
593
594 // Get style for index
595 wxRichTextStyleDefinition* wxRichTextStyleListBox::GetStyle(size_t i) const
596 {
597 if (!GetStyleSheet())
598 return NULL;
599
600 if (i >= m_styleNames.GetCount() /* || i < 0 */ )
601 return NULL;
602
603 wxString styleType = wxGetRichTextStyleType(m_styleNames[i]);
604 wxString style = wxGetRichTextStyle(m_styleNames[i]);
605 if (styleType == wxT("P"))
606 return GetStyleSheet()->FindParagraphStyle(style);
607 else if (styleType == wxT("C"))
608 return GetStyleSheet()->FindCharacterStyle(style);
609 else if (styleType == wxT("L"))
610 return GetStyleSheet()->FindListStyle(style);
611 else if (styleType == wxT("B"))
612 return GetStyleSheet()->FindBoxStyle(style);
613 else
614 return GetStyleSheet()->FindStyle(style);
615 }
616
617 /// Updates the list
618 void wxRichTextStyleListBox::UpdateStyles()
619 {
620 if (GetStyleSheet())
621 {
622 int oldSel = GetSelection();
623
624 SetSelection(wxNOT_FOUND);
625
626 m_styleNames.Clear();
627
628 size_t i;
629 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
630 {
631 for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
632 m_styleNames.Add(GetStyleSheet()->GetParagraphStyle(i)->GetName() + wxT("|P"));
633 }
634 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
635 {
636 for (i = 0; i < GetStyleSheet()->GetCharacterStyleCount(); i++)
637 m_styleNames.Add(GetStyleSheet()->GetCharacterStyle(i)->GetName() + wxT("|C"));
638 }
639 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_LIST)
640 {
641 for (i = 0; i < GetStyleSheet()->GetListStyleCount(); i++)
642 m_styleNames.Add(GetStyleSheet()->GetListStyle(i)->GetName() + wxT("|L"));
643 }
644 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_BOX)
645 {
646 for (i = 0; i < GetStyleSheet()->GetBoxStyleCount(); i++)
647 m_styleNames.Add(GetStyleSheet()->GetBoxStyle(i)->GetName() + wxT("|B"));
648 }
649
650 m_styleNames.Sort();
651 SetItemCount(m_styleNames.GetCount());
652
653 Refresh();
654
655 int newSel = -1;
656 if (oldSel >= 0 && oldSel < (int) GetItemCount())
657 newSel = oldSel;
658 else if (GetItemCount() > 0)
659 newSel = 0;
660
661 if (newSel >= 0)
662 {
663 SetSelection(newSel);
664 SendSelectedEvent();
665 }
666 }
667 }
668
669 // Get index for style name
670 int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const
671 {
672 wxString s(name);
673 if (GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
674 s += wxT("|P");
675 else if (GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
676 s += wxT("|C");
677 else if (GetStyleType() == wxRICHTEXT_STYLE_LIST)
678 s += wxT("|L");
679 else if (GetStyleType() == wxRICHTEXT_STYLE_BOX)
680 s += wxT("|B");
681 else
682 {
683 if (m_styleNames.Index(s + wxT("|P")) != wxNOT_FOUND)
684 s += wxT("|P");
685 else if (m_styleNames.Index(s + wxT("|C")) != wxNOT_FOUND)
686 s += wxT("|C");
687 else if (m_styleNames.Index(s + wxT("|L")) != wxNOT_FOUND)
688 s += wxT("|L");
689 else if (m_styleNames.Index(s + wxT("|B")) != wxNOT_FOUND)
690 s += wxT("|B");
691 }
692 return m_styleNames.Index(s);
693 }
694
695 /// Set selection for string
696 int wxRichTextStyleListBox::SetStyleSelection(const wxString& name)
697 {
698 int i = GetIndexForStyle(name);
699 if (i > -1)
700 SetSelection(i);
701 return i;
702 }
703
704 // Convert a colour to a 6-digit hex string
705 static wxString ColourToHexString(const wxColour& col)
706 {
707 wxString hex;
708
709 hex += wxDecToHex(col.Red());
710 hex += wxDecToHex(col.Green());
711 hex += wxDecToHex(col.Blue());
712
713 return hex;
714 }
715
716 /// Creates a suitable HTML fragment for a definition
717 wxString wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition* def) const
718 {
719 // TODO: indicate list format for list style types
720
721 wxString str;
722
723 bool isCentred = false;
724
725 wxRichTextAttr attr(def->GetStyleMergedWithBase(GetStyleSheet()));
726
727 if (attr.HasAlignment() && attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
728 isCentred = true;
729
730 if (isCentred)
731 str << wxT("<center>");
732
733
734 str << wxT("<table><tr>");
735
736 if (attr.GetLeftIndent() > 0)
737 {
738 wxClientDC dc((wxWindow*) this);
739
740 str << wxT("<td width=") << wxMin(50, (ConvertTenthsMMToPixels(dc, attr.GetLeftIndent())/2)) << wxT("></td>");
741 }
742
743 if (isCentred)
744 str << wxT("<td nowrap align=\"center\">");
745 else
746 str << wxT("<td nowrap>");
747
748 #ifdef __WXMSW__
749 int size = 2;
750 #else
751 int size = 3;
752 #endif
753
754 // Guess a standard font size
755 int stdFontSize = 0;
756
757 // First see if we have a default/normal style to base the size on
758 wxString normalTranslated(_("normal"));
759 wxString defaultTranslated(_("default"));
760 size_t i;
761 for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
762 {
763 wxRichTextStyleDefinition* d = GetStyleSheet()->GetParagraphStyle(i);
764 wxString name = d->GetName().Lower();
765 if (name.Find(wxT("normal")) != wxNOT_FOUND || name.Find(normalTranslated) != wxNOT_FOUND ||
766 name.Find(wxT("default")) != wxNOT_FOUND || name.Find(defaultTranslated) != wxNOT_FOUND)
767 {
768 wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
769 if (attr2.HasFontSize())
770 {
771 stdFontSize = attr2.GetFontSize();
772 break;
773 }
774 }
775 }
776
777 if (stdFontSize == 0)
778 {
779 // Look at sizes up to 20 points, and see which is the most common
780 wxArrayInt sizes;
781 size_t maxSize = 20;
782 for (i = 0; i <= maxSize; i++)
783 sizes.Add(0);
784 for (i = 0; i < m_styleNames.GetCount(); i++)
785 {
786 wxRichTextStyleDefinition* d = GetStyle(i);
787 if (d)
788 {
789 wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
790 if (attr2.HasFontSize())
791 {
792 if (attr2.GetFontSize() <= (int) maxSize)
793 sizes[attr2.GetFontSize()] ++;
794 }
795 }
796 }
797 int mostCommonSize = 0;
798 for (i = 0; i <= maxSize; i++)
799 {
800 if (sizes[i] > mostCommonSize)
801 mostCommonSize = i;
802 }
803 if (mostCommonSize > 0)
804 stdFontSize = mostCommonSize;
805 }
806
807 if (stdFontSize == 0)
808 stdFontSize = 12;
809
810 int thisFontSize = ((attr.GetFlags() & wxTEXT_ATTR_FONT_SIZE) != 0) ? attr.GetFontSize() : stdFontSize;
811
812 if (thisFontSize < stdFontSize)
813 size --;
814 else if (thisFontSize > stdFontSize)
815 size ++;
816
817 str += wxT("<font");
818
819 str << wxT(" size=") << size;
820
821 if (!attr.GetFontFaceName().IsEmpty())
822 str << wxT(" face=\"") << attr.GetFontFaceName() << wxT("\"");
823
824 if (attr.GetTextColour().IsOk())
825 str << wxT(" color=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
826
827 str << wxT(">");
828
829 bool hasBold = false;
830 bool hasItalic = false;
831 bool hasUnderline = false;
832
833 if (attr.GetFontWeight() == wxBOLD)
834 hasBold = true;
835 if (attr.GetFontStyle() == wxITALIC)
836 hasItalic = true;
837 if (attr.GetFontUnderlined())
838 hasUnderline = true;
839
840 if (hasBold)
841 str << wxT("<b>");
842 if (hasItalic)
843 str << wxT("<i>");
844 if (hasUnderline)
845 str << wxT("<u>");
846
847 str += def->GetName();
848
849 if (hasUnderline)
850 str << wxT("</u>");
851 if (hasItalic)
852 str << wxT("</i>");
853 if (hasBold)
854 str << wxT("</b>");
855
856 if (isCentred)
857 str << wxT("</centre>");
858
859 str << wxT("</font>");
860
861 str << wxT("</td></tr></table>");
862
863 if (isCentred)
864 str << wxT("</center>");
865
866 return str;
867 }
868
869 // Convert units in tends of a millimetre to device units
870 int wxRichTextStyleListBox::ConvertTenthsMMToPixels(wxDC& dc, int units) const
871 {
872 int ppi = dc.GetPPI().x;
873
874 // There are ppi pixels in 254.1 "1/10 mm"
875
876 double pixels = ((double) units * (double)ppi) / 254.1;
877
878 return (int) pixels;
879 }
880
881 void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
882 {
883 wxVListBox::OnLeftDown(event);
884
885 int item = VirtualHitTest(event.GetPosition().y);
886 if (item != wxNOT_FOUND && GetApplyOnSelection())
887 ApplyStyle(item);
888 }
889
890 void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent& event)
891 {
892 wxVListBox::OnLeftDown(event);
893
894 int item = VirtualHitTest(event.GetPosition().y);
895 if (item != wxNOT_FOUND && !GetApplyOnSelection())
896 ApplyStyle(item);
897 }
898
899 /// Helper for listbox and combo control
900 wxString wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl* ctrl, wxRichTextStyleType styleType)
901 {
902 int adjustedCaretPos = ctrl->GetAdjustedCaretPosition(ctrl->GetCaretPosition());
903
904 wxString styleName;
905
906 wxRichTextAttr attr;
907 ctrl->GetStyle(adjustedCaretPos, attr);
908
909 // Take into account current default style just chosen by user
910 if (ctrl->IsDefaultStyleShowing())
911 {
912 wxRichTextApplyStyle(attr, ctrl->GetDefaultStyleEx());
913
914 if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
915 !attr.GetCharacterStyleName().IsEmpty())
916 styleName = attr.GetCharacterStyleName();
917 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
918 !attr.GetParagraphStyleName().IsEmpty())
919 styleName = attr.GetParagraphStyleName();
920 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
921 !attr.GetListStyleName().IsEmpty())
922 styleName = attr.GetListStyleName();
923 // TODO: when we have a concept of focused object (text box), we'll
924 // use the paragraph style name of the focused object as the frame style name.
925 #if 0
926 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_BOX) &&
927 !attr.GetBoxStyleName().IsEmpty())
928 styleName = attr.GetBoxStyleName();
929 #endif
930 }
931 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
932 !attr.GetCharacterStyleName().IsEmpty())
933 {
934 styleName = attr.GetCharacterStyleName();
935 }
936 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
937 !attr.GetParagraphStyleName().IsEmpty())
938 {
939 styleName = attr.GetParagraphStyleName();
940 }
941 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
942 !attr.GetListStyleName().IsEmpty())
943 {
944 styleName = attr.GetListStyleName();
945 }
946
947 return styleName;
948 }
949
950 /// Auto-select from style under caret in idle time
951 void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
952 {
953 if (CanAutoSetSelection() && GetRichTextCtrl() && IsShownOnScreen() && wxWindow::FindFocus() != this)
954 {
955 wxString styleName = GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
956
957 int sel = GetSelection();
958 if (!styleName.IsEmpty())
959 {
960 // Don't do the selection if it's already set
961 if (sel == GetIndexForStyle(styleName))
962 return;
963
964 SetStyleSelection(styleName);
965 }
966 else if (sel != -1)
967 SetSelection(-1);
968 }
969 event.Skip();
970 }
971
972 /// Do selection
973 void wxRichTextStyleListBox::ApplyStyle(int item)
974 {
975 if ( item != wxNOT_FOUND )
976 {
977 wxRichTextStyleDefinition* def = GetStyle(item);
978 if (def && GetRichTextCtrl())
979 {
980 GetRichTextCtrl()->ApplyStyle(def);
981 GetRichTextCtrl()->SetFocus();
982 }
983 }
984 }
985
986 /*!
987 * wxRichTextStyleListCtrl class: manages a listbox and a choice control to
988 * switch shown style types
989 */
990
991 IMPLEMENT_CLASS(wxRichTextStyleListCtrl, wxControl)
992
993 BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl, wxControl)
994 EVT_CHOICE(wxID_ANY, wxRichTextStyleListCtrl::OnChooseType)
995 EVT_SIZE(wxRichTextStyleListCtrl::OnSize)
996 END_EVENT_TABLE()
997
998 wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
999 const wxSize& size, long style)
1000 {
1001 Init();
1002 Create(parent, id, pos, size, style);
1003 }
1004
1005 bool wxRichTextStyleListCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
1006 const wxSize& size, long style)
1007 {
1008 if ((style & wxBORDER_MASK) == wxBORDER_DEFAULT)
1009 style |= wxBORDER_THEME;
1010
1011 wxControl::Create(parent, id, pos, size, style);
1012
1013 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
1014 if (size != wxDefaultSize)
1015 SetInitialSize(size);
1016
1017 bool showSelector = ((style & wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR) == 0);
1018
1019 wxBorder listBoxStyle;
1020 if (showSelector)
1021 listBoxStyle = wxBORDER_THEME;
1022 else
1023 listBoxStyle = wxBORDER_NONE;
1024
1025 m_styleListBox = new wxRichTextStyleListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, listBoxStyle);
1026
1027 wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
1028
1029 if (showSelector)
1030 {
1031 wxArrayString choices;
1032 choices.Add(_("All styles"));
1033 choices.Add(_("Paragraph styles"));
1034 choices.Add(_("Character styles"));
1035 choices.Add(_("List styles"));
1036 choices.Add(_("Box styles"));
1037
1038 m_styleChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
1039
1040 boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 5);
1041 boxSizer->Add(m_styleChoice, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5);
1042 }
1043 else
1044 {
1045 boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 0);
1046 }
1047
1048 SetSizer(boxSizer);
1049 Layout();
1050
1051 m_dontUpdate = true;
1052
1053 if (m_styleChoice)
1054 {
1055 int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
1056 m_styleChoice->SetSelection(i);
1057 }
1058
1059 m_dontUpdate = false;
1060
1061 return true;
1062 }
1063
1064 wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
1065 {
1066
1067 }
1068
1069 /// React to style type choice
1070 void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent& event)
1071 {
1072 if (event.GetEventObject() != m_styleChoice)
1073 event.Skip();
1074 else
1075 {
1076 if (m_dontUpdate)
1077 return;
1078
1079 wxRichTextStyleListBox::wxRichTextStyleType styleType = StyleIndexToType(event.GetSelection());
1080 m_styleListBox->SetSelection(-1);
1081 m_styleListBox->SetStyleType(styleType);
1082 }
1083 }
1084
1085 /// Lay out the controls
1086 void wxRichTextStyleListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
1087 {
1088 if (GetAutoLayout())
1089 Layout();
1090 }
1091
1092 /// Get the choice index for style type
1093 int wxRichTextStyleListCtrl::StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType)
1094 {
1095 if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL)
1096 {
1097 return 0;
1098 }
1099 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH)
1100 {
1101 return 1;
1102 }
1103 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER)
1104 {
1105 return 2;
1106 }
1107 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST)
1108 {
1109 return 3;
1110 }
1111 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX)
1112 {
1113 return 4;
1114 }
1115 return 0;
1116 }
1117
1118 /// Get the style type for choice index
1119 wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::StyleIndexToType(int i)
1120 {
1121 if (i == 1)
1122 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH;
1123 else if (i == 2)
1124 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER;
1125 else if (i == 3)
1126 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST;
1127 else if (i == 4)
1128 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX;
1129
1130 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
1131 }
1132
1133 /// Associates the control with a style manager
1134 void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet* styleSheet)
1135 {
1136 if (m_styleListBox)
1137 m_styleListBox->SetStyleSheet(styleSheet);
1138 }
1139
1140 wxRichTextStyleSheet* wxRichTextStyleListCtrl::GetStyleSheet() const
1141 {
1142 if (m_styleListBox)
1143 return m_styleListBox->GetStyleSheet();
1144 else
1145 return NULL;
1146 }
1147
1148 /// Associates the control with a wxRichTextCtrl
1149 void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl* ctrl)
1150 {
1151 if (m_styleListBox)
1152 m_styleListBox->SetRichTextCtrl(ctrl);
1153 }
1154
1155 wxRichTextCtrl* wxRichTextStyleListCtrl::GetRichTextCtrl() const
1156 {
1157 if (m_styleListBox)
1158 return m_styleListBox->GetRichTextCtrl();
1159 else
1160 return NULL;
1161 }
1162
1163 /// Set/get the style type to display
1164 void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType)
1165 {
1166 if ( !m_styleListBox )
1167 return;
1168
1169 m_styleListBox->SetStyleType(styleType);
1170
1171 m_dontUpdate = true;
1172
1173 if (m_styleChoice)
1174 {
1175 int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
1176 m_styleChoice->SetSelection(i);
1177 }
1178
1179 m_dontUpdate = false;
1180 }
1181
1182 wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::GetStyleType() const
1183 {
1184 if (m_styleListBox)
1185 return m_styleListBox->GetStyleType();
1186 else
1187 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
1188 }
1189
1190 /// Updates the style list box
1191 void wxRichTextStyleListCtrl::UpdateStyles()
1192 {
1193 if (m_styleListBox)
1194 m_styleListBox->UpdateStyles();
1195 }
1196
1197 #if wxUSE_COMBOCTRL
1198
1199 /*!
1200 * Style drop-down for a wxComboCtrl
1201 */
1202
1203
1204 BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup, wxRichTextStyleListBox)
1205 EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove)
1206 EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick)
1207 END_EVENT_TABLE()
1208
1209 bool wxRichTextStyleComboPopup::Create( wxWindow* parent )
1210 {
1211 int borderStyle = GetDefaultBorder();
1212 if (borderStyle == wxBORDER_SUNKEN)
1213 borderStyle = wxBORDER_SIMPLE;
1214
1215 return wxRichTextStyleListBox::Create(parent, wxID_ANY,
1216 wxPoint(0,0), wxDefaultSize,
1217 borderStyle);
1218 }
1219
1220 void wxRichTextStyleComboPopup::SetStringValue( const wxString& s )
1221 {
1222 m_value = SetStyleSelection(s);
1223 }
1224
1225 wxString wxRichTextStyleComboPopup::GetStringValue() const
1226 {
1227 int sel = m_value;
1228 if (sel > -1)
1229 {
1230 wxRichTextStyleDefinition* def = GetStyle(sel);
1231 if (def)
1232 return def->GetName();
1233 }
1234 return wxEmptyString;
1235 }
1236
1237 //
1238 // Popup event handlers
1239 //
1240
1241 // Mouse hot-tracking
1242 void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent& event)
1243 {
1244 // Move selection to cursor if it is inside the popup
1245
1246 int itemHere = wxRichTextStyleListBox::VirtualHitTest(event.GetPosition().y);
1247 if ( itemHere >= 0 )
1248 {
1249 wxRichTextStyleListBox::SetSelection(itemHere);
1250 m_itemHere = itemHere;
1251 }
1252 event.Skip();
1253 }
1254
1255 // On mouse left, set the value and close the popup
1256 void wxRichTextStyleComboPopup::OnMouseClick(wxMouseEvent& WXUNUSED(event))
1257 {
1258 if (m_itemHere >= 0)
1259 m_value = m_itemHere;
1260
1261 // Ordering is important, so we don't dismiss this popup accidentally
1262 // by setting the focus elsewhere e.g. in ApplyStyle
1263 Dismiss();
1264
1265 if (m_itemHere >= 0)
1266 wxRichTextStyleListBox::ApplyStyle(m_itemHere);
1267 }
1268
1269 /*!
1270 * wxRichTextStyleComboCtrl
1271 * A combo for applying styles.
1272 */
1273
1274 IMPLEMENT_CLASS(wxRichTextStyleComboCtrl, wxComboCtrl)
1275
1276 BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl, wxComboCtrl)
1277 EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle)
1278 END_EVENT_TABLE()
1279
1280 bool wxRichTextStyleComboCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
1281 const wxSize& size, long style)
1282 {
1283 if (!wxComboCtrl::Create(parent, id, wxEmptyString, pos, size, style))
1284 return false;
1285
1286 SetPopupMaxHeight(400);
1287
1288 m_stylePopup = new wxRichTextStyleComboPopup;
1289
1290 SetPopupControl(m_stylePopup);
1291
1292 return true;
1293 }
1294
1295 /// Auto-select from style under caret in idle time
1296
1297 // TODO: must be able to show italic, bold, combinations
1298 // in style box. Do we have a concept of automatic, temporary
1299 // styles that are added whenever we wish to show a style
1300 // that doesn't exist already? E.g. "Bold, Italic, Underline".
1301 // Word seems to generate these things on the fly.
1302 // If there's a named style already, it uses e.g. Heading1 + Bold, Italic
1303 // If you unembolden text in a style that has bold, it uses the
1304 // term "Not bold".
1305 // TODO: order styles alphabetically. This means indexes can change,
1306 // so need a different way to specify selections, i.e. by name.
1307
1308 void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent& event)
1309 {
1310 event.Skip();
1311
1312 if ( !m_stylePopup )
1313 return;
1314
1315 wxRichTextCtrl * const richtext = GetRichTextCtrl();
1316 if ( !richtext )
1317 return;
1318
1319 if ( !IsPopupShown() && IsShownOnScreen() && wxWindow::FindFocus() != this )
1320 {
1321 wxString styleName =
1322 wxRichTextStyleListBox::GetStyleToShowInIdleTime(richtext, m_stylePopup->GetStyleType());
1323
1324 wxString currentValue = GetValue();
1325 if (!styleName.IsEmpty())
1326 {
1327 // Don't do the selection if it's already set
1328 if (currentValue == styleName)
1329 return;
1330
1331 SetValue(styleName);
1332 }
1333 else if (!currentValue.IsEmpty())
1334 SetValue(wxEmptyString);
1335 }
1336 }
1337
1338 #endif
1339 // wxUSE_COMBOCTRL
1340
1341 #endif
1342 // wxUSE_HTML
1343
1344 #endif
1345 // wxUSE_RICHTEXT