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