1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/richtext/richtextstyles.cpp
3 // Purpose: Style management for wxRichTextCtrl
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
21 #include "wx/richtext/richtextstyles.h"
27 #include "wx/filename.h"
28 #include "wx/clipbrd.h"
29 #include "wx/wfstream.h"
30 #include "wx/settings.h"
32 #include "wx/richtext/richtextctrl.h"
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
)
44 void wxRichTextStyleDefinition::Copy(const wxRichTextStyleDefinition
& def
)
47 m_baseStyle
= def
.m_baseStyle
;
48 m_style
= def
.m_style
;
49 m_description
= def
.m_description
;
50 m_properties
= def
.m_properties
;
53 bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition
& def
) const
55 return (m_name
== def
.m_name
&& m_baseStyle
== def
.m_baseStyle
&& m_style
== def
.m_style
&& m_properties
== def
.m_properties
);
58 /// Gets the style combined with the base style
59 wxRichTextAttr
wxRichTextStyleDefinition::GetStyleMergedWithBase(const wxRichTextStyleSheet
* sheet
) const
61 if (m_baseStyle
.IsEmpty())
64 bool isParaStyle
= IsKindOf(wxCLASSINFO(wxRichTextParagraphStyleDefinition
));
65 bool isCharStyle
= IsKindOf(wxCLASSINFO(wxRichTextCharacterStyleDefinition
));
66 bool isListStyle
= IsKindOf(wxCLASSINFO(wxRichTextListStyleDefinition
));
67 bool isBoxStyle
= IsKindOf(wxCLASSINFO(wxRichTextBoxStyleDefinition
));
69 // Collect the styles, detecting loops
70 wxArrayString styleNames
;
72 const wxRichTextStyleDefinition
* def
= this;
75 styles
.Insert((wxObject
*) def
);
76 styleNames
.Add(def
->GetName());
78 wxString baseStyleName
= def
->GetBaseStyle();
79 if (!baseStyleName
.IsEmpty() && styleNames
.Index(baseStyleName
) == wxNOT_FOUND
)
82 def
= sheet
->FindParagraphStyle(baseStyleName
);
84 def
= sheet
->FindCharacterStyle(baseStyleName
);
86 def
= sheet
->FindListStyle(baseStyleName
);
88 def
= sheet
->FindBoxStyle(baseStyleName
);
90 def
= sheet
->FindStyle(baseStyleName
);
97 wxList::compatibility_iterator node
= styles
.GetFirst();
100 wxRichTextStyleDefinition
* def
= (wxRichTextStyleDefinition
*) node
->GetData();
101 attr
.Apply(def
->GetStyle(), NULL
);
102 node
= node
->GetNext();
109 * Paragraph style definition
112 void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition
& def
)
114 wxRichTextStyleDefinition::Copy(def
);
116 m_nextStyle
= def
.m_nextStyle
;
119 bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition
& def
) const
121 return (Eq(def
) && m_nextStyle
== def
.m_nextStyle
);
125 * Box style definition
128 void wxRichTextBoxStyleDefinition::Copy(const wxRichTextBoxStyleDefinition
& def
)
130 wxRichTextStyleDefinition::Copy(def
);
133 bool wxRichTextBoxStyleDefinition::operator ==(const wxRichTextBoxStyleDefinition
& def
) const
139 * List style definition
142 void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition
& def
)
144 wxRichTextParagraphStyleDefinition::Copy(def
);
147 for (i
= 0; i
< 10; i
++)
148 m_levelStyles
[i
] = def
.m_levelStyles
[i
];
151 bool wxRichTextListStyleDefinition::operator ==(const wxRichTextListStyleDefinition
& def
) const
156 for (i
= 0; i
< 10; i
++)
157 if (!(m_levelStyles
[i
] == def
.m_levelStyles
[i
]))
163 /// Sets/gets the attributes for the given level
164 void wxRichTextListStyleDefinition::SetLevelAttributes(int i
, const wxRichTextAttr
& attr
)
166 wxASSERT( (i
>= 0 && i
< 10) );
167 if (i
>= 0 && i
< 10)
168 m_levelStyles
[i
] = attr
;
171 const wxRichTextAttr
* wxRichTextListStyleDefinition::GetLevelAttributes(int i
) const
173 wxASSERT( (i
>= 0 && i
< 10) );
174 if (i
>= 0 && i
< 10)
175 return & m_levelStyles
[i
];
180 wxRichTextAttr
* wxRichTextListStyleDefinition::GetLevelAttributes(int i
)
182 wxASSERT( (i
>= 0 && i
< 10) );
183 if (i
>= 0 && i
< 10)
184 return & m_levelStyles
[i
];
189 /// Convenience function for setting the major attributes for a list level specification
190 void wxRichTextListStyleDefinition::SetAttributes(int i
, int leftIndent
, int leftSubIndent
, int bulletStyle
, const wxString
& bulletSymbol
)
192 wxASSERT( (i
>= 0 && i
< 10) );
193 if (i
>= 0 && i
< 10)
197 attr
.SetBulletStyle(bulletStyle
);
198 attr
.SetLeftIndent(leftIndent
, leftSubIndent
);
200 if (!bulletSymbol
.IsEmpty())
202 if (bulletStyle
& wxTEXT_ATTR_BULLET_STYLE_SYMBOL
)
203 attr
.SetBulletText(bulletSymbol
);
205 attr
.SetBulletName(bulletSymbol
);
208 m_levelStyles
[i
] = attr
;
212 /// Finds the level corresponding to the given indentation
213 int wxRichTextListStyleDefinition::FindLevelForIndent(int indent
) const
216 for (i
= 0; i
< 10; i
++)
218 if (indent
< m_levelStyles
[i
].GetLeftIndent())
229 /// Combine the list style with a paragraph style, using the given indent (from which
230 /// an appropriate level is found)
231 wxRichTextAttr
wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent
, const wxRichTextAttr
& paraStyle
, wxRichTextStyleSheet
* styleSheet
)
233 int listLevel
= FindLevelForIndent(indent
);
235 wxRichTextAttr
attr(*GetLevelAttributes(listLevel
));
236 int oldLeftIndent
= attr
.GetLeftIndent();
237 int oldLeftSubIndent
= attr
.GetLeftSubIndent();
239 // First apply the overall paragraph style, if any
241 attr
.Apply(GetStyleMergedWithBase(styleSheet
));
243 attr
.Apply(GetStyle());
245 // Then apply paragraph style, e.g. from paragraph style definition
246 attr
.Apply(paraStyle
);
248 // We override the indents according to the list definition
249 attr
.SetLeftIndent(oldLeftIndent
, oldLeftSubIndent
);
254 /// Combine the base and list style, using the given indent (from which
255 /// an appropriate level is found)
256 wxRichTextAttr
wxRichTextListStyleDefinition::GetCombinedStyle(int indent
, wxRichTextStyleSheet
* styleSheet
)
258 int listLevel
= FindLevelForIndent(indent
);
259 return GetCombinedStyleForLevel(listLevel
, styleSheet
);
262 /// Combine the base and list style, using the given indent (from which
263 /// an appropriate level is found)
264 wxRichTextAttr
wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel
, wxRichTextStyleSheet
* styleSheet
)
266 wxRichTextAttr
attr(*GetLevelAttributes(listLevel
));
267 int oldLeftIndent
= attr
.GetLeftIndent();
268 int oldLeftSubIndent
= attr
.GetLeftSubIndent();
270 // Apply the overall paragraph style, if any
272 attr
.Apply(GetStyleMergedWithBase(styleSheet
));
274 attr
.Apply(GetStyle());
276 // We override the indents according to the list definition
277 attr
.SetLeftIndent(oldLeftIndent
, oldLeftSubIndent
);
282 /// Is this a numbered list?
283 bool wxRichTextListStyleDefinition::IsNumbered(int i
) const
285 return (0 != (GetLevelAttributes(i
)->GetFlags() &
286 (wxTEXT_ATTR_BULLET_STYLE_ARABIC
|wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER
|wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER
|
287 wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER
|wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER
)));
294 IMPLEMENT_CLASS(wxRichTextStyleSheet
, wxObject
)
296 wxRichTextStyleSheet::~wxRichTextStyleSheet()
301 m_nextSheet
->m_previousSheet
= m_previousSheet
;
304 m_previousSheet
->m_nextSheet
= m_nextSheet
;
306 m_previousSheet
= NULL
;
311 void wxRichTextStyleSheet::Init()
313 m_previousSheet
= NULL
;
317 /// Add a definition to one of the style lists
318 bool wxRichTextStyleSheet::AddStyle(wxList
& list
, wxRichTextStyleDefinition
* def
)
326 bool wxRichTextStyleSheet::RemoveStyle(wxList
& list
, wxRichTextStyleDefinition
* def
, bool deleteStyle
)
328 wxList::compatibility_iterator node
= list
.Find(def
);
331 wxRichTextStyleDefinition
* def
= (wxRichTextStyleDefinition
*) node
->GetData();
342 bool wxRichTextStyleSheet::RemoveStyle(wxRichTextStyleDefinition
* def
, bool deleteStyle
)
344 if (RemoveParagraphStyle(def
, deleteStyle
))
346 if (RemoveCharacterStyle(def
, deleteStyle
))
348 if (RemoveListStyle(def
, deleteStyle
))
350 if (RemoveBoxStyle(def
, deleteStyle
))
355 /// Find a definition by name
356 wxRichTextStyleDefinition
* wxRichTextStyleSheet::FindStyle(const wxList
& list
, const wxString
& name
, bool recurse
) const
358 for (wxList::compatibility_iterator node
= list
.GetFirst(); node
; node
= node
->GetNext())
360 wxRichTextStyleDefinition
* def
= (wxRichTextStyleDefinition
*) node
->GetData();
361 if (def
->GetName() == name
)
365 if (m_nextSheet
&& recurse
)
366 return m_nextSheet
->FindStyle(list
, name
, recurse
);
371 /// Delete all styles
372 void wxRichTextStyleSheet::DeleteStyles()
374 WX_CLEAR_LIST(wxList
, m_characterStyleDefinitions
);
375 WX_CLEAR_LIST(wxList
, m_paragraphStyleDefinitions
);
376 WX_CLEAR_LIST(wxList
, m_listStyleDefinitions
);
377 WX_CLEAR_LIST(wxList
, m_boxStyleDefinitions
);
380 /// Insert into list of style sheets
381 bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet
* before
)
383 m_previousSheet
= before
->m_previousSheet
;
384 m_nextSheet
= before
;
386 before
->m_previousSheet
= this;
390 /// Append to list of style sheets
391 bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet
* after
)
393 wxRichTextStyleSheet
* last
= after
;
394 while (last
&& last
->m_nextSheet
)
396 last
= last
->m_nextSheet
;
401 m_previousSheet
= last
;
402 last
->m_nextSheet
= this;
410 /// Unlink from the list of style sheets
411 void wxRichTextStyleSheet::Unlink()
414 m_previousSheet
->m_nextSheet
= m_nextSheet
;
416 m_nextSheet
->m_previousSheet
= m_previousSheet
;
418 m_previousSheet
= NULL
;
422 /// Add a definition to the character style list
423 bool wxRichTextStyleSheet::AddCharacterStyle(wxRichTextCharacterStyleDefinition
* def
)
425 def
->GetStyle().SetCharacterStyleName(def
->GetName());
426 return AddStyle(m_characterStyleDefinitions
, def
);
429 /// Add a definition to the paragraph style list
430 bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition
* def
)
432 def
->GetStyle().SetParagraphStyleName(def
->GetName());
433 return AddStyle(m_paragraphStyleDefinitions
, def
);
436 /// Add a definition to the list style list
437 bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition
* def
)
439 def
->GetStyle().SetListStyleName(def
->GetName());
440 return AddStyle(m_listStyleDefinitions
, def
);
443 /// Add a definition to the box style list
444 bool wxRichTextStyleSheet::AddBoxStyle(wxRichTextBoxStyleDefinition
* def
)
446 def
->GetStyle().GetTextBoxAttr().SetBoxStyleName(def
->GetName());
447 return AddStyle(m_boxStyleDefinitions
, def
);
450 /// Add a definition to the appropriate style list
451 bool wxRichTextStyleSheet::AddStyle(wxRichTextStyleDefinition
* def
)
453 wxRichTextListStyleDefinition
* listDef
= wxDynamicCast(def
, wxRichTextListStyleDefinition
);
455 return AddListStyle(listDef
);
457 wxRichTextParagraphStyleDefinition
* paraDef
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
);
459 return AddParagraphStyle(paraDef
);
461 wxRichTextCharacterStyleDefinition
* charDef
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
);
463 return AddCharacterStyle(charDef
);
465 wxRichTextBoxStyleDefinition
* boxDef
= wxDynamicCast(def
, wxRichTextBoxStyleDefinition
);
467 return AddBoxStyle(boxDef
);
472 /// Find any definition by name
473 wxRichTextStyleDefinition
* wxRichTextStyleSheet::FindStyle(const wxString
& name
, bool recurse
) const
475 wxRichTextListStyleDefinition
* listDef
= FindListStyle(name
, recurse
);
479 wxRichTextParagraphStyleDefinition
* paraDef
= FindParagraphStyle(name
, recurse
);
483 wxRichTextCharacterStyleDefinition
* charDef
= FindCharacterStyle(name
, recurse
);
487 wxRichTextBoxStyleDefinition
* boxDef
= FindBoxStyle(name
, recurse
);
495 void wxRichTextStyleSheet::Copy(const wxRichTextStyleSheet
& sheet
)
499 wxList::compatibility_iterator node
;
501 for (node
= sheet
.m_characterStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
503 wxRichTextCharacterStyleDefinition
* def
= (wxRichTextCharacterStyleDefinition
*) node
->GetData();
504 AddCharacterStyle(new wxRichTextCharacterStyleDefinition(*def
));
507 for (node
= sheet
.m_paragraphStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
509 wxRichTextParagraphStyleDefinition
* def
= (wxRichTextParagraphStyleDefinition
*) node
->GetData();
510 AddParagraphStyle(new wxRichTextParagraphStyleDefinition(*def
));
513 for (node
= sheet
.m_listStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
515 wxRichTextListStyleDefinition
* def
= (wxRichTextListStyleDefinition
*) node
->GetData();
516 AddListStyle(new wxRichTextListStyleDefinition(*def
));
519 for (node
= sheet
.m_boxStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
521 wxRichTextBoxStyleDefinition
* def
= (wxRichTextBoxStyleDefinition
*) node
->GetData();
522 AddBoxStyle(new wxRichTextBoxStyleDefinition(*def
));
525 SetName(sheet
.GetName());
526 SetDescription(sheet
.GetDescription());
527 m_properties
= sheet
.m_properties
;
531 bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet
& WXUNUSED(sheet
)) const
540 // Functions for dealing with clashing names for different kinds of style.
541 // Returns "P", "C", "L" or "B" (paragraph, character, list or box) for
542 // style name | type.
543 static wxString
wxGetRichTextStyleType(const wxString
& style
)
545 return style
.AfterLast(wxT('|'));
548 static wxString
wxGetRichTextStyle(const wxString
& style
)
550 return style
.BeforeLast(wxT('|'));
555 * wxRichTextStyleListBox: a listbox to display styles.
558 IMPLEMENT_CLASS(wxRichTextStyleListBox
, wxHtmlListBox
)
560 BEGIN_EVENT_TABLE(wxRichTextStyleListBox
, wxHtmlListBox
)
561 EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown
)
562 EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick
)
563 EVT_IDLE(wxRichTextStyleListBox::OnIdle
)
566 wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
567 const wxSize
& size
, long style
)
570 Create(parent
, id
, pos
, size
, style
);
573 bool wxRichTextStyleListBox::Create(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
574 const wxSize
& size
, long style
)
576 return wxHtmlListBox::Create(parent
, id
, pos
, size
, style
);
579 wxRichTextStyleListBox::~wxRichTextStyleListBox()
583 /// Returns the HTML for this item
584 wxString
wxRichTextStyleListBox::OnGetItem(size_t n
) const
586 if (!GetStyleSheet())
587 return wxEmptyString
;
589 wxRichTextStyleDefinition
* def
= GetStyle(n
);
591 return CreateHTML(def
);
593 return wxEmptyString
;
596 // Get style for index
597 wxRichTextStyleDefinition
* wxRichTextStyleListBox::GetStyle(size_t i
) const
599 if (!GetStyleSheet())
602 if (i
>= m_styleNames
.GetCount() /* || i < 0 */ )
605 wxString styleType
= wxGetRichTextStyleType(m_styleNames
[i
]);
606 wxString style
= wxGetRichTextStyle(m_styleNames
[i
]);
607 if (styleType
== wxT("P"))
608 return GetStyleSheet()->FindParagraphStyle(style
);
609 else if (styleType
== wxT("C"))
610 return GetStyleSheet()->FindCharacterStyle(style
);
611 else if (styleType
== wxT("L"))
612 return GetStyleSheet()->FindListStyle(style
);
613 else if (styleType
== wxT("B"))
614 return GetStyleSheet()->FindBoxStyle(style
);
616 return GetStyleSheet()->FindStyle(style
);
620 void wxRichTextStyleListBox::UpdateStyles()
624 int oldSel
= GetSelection();
626 SetSelection(wxNOT_FOUND
);
628 m_styleNames
.Clear();
631 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH
)
633 for (i
= 0; i
< GetStyleSheet()->GetParagraphStyleCount(); i
++)
634 m_styleNames
.Add(GetStyleSheet()->GetParagraphStyle(i
)->GetName() + wxT("|P"));
636 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_CHARACTER
)
638 for (i
= 0; i
< GetStyleSheet()->GetCharacterStyleCount(); i
++)
639 m_styleNames
.Add(GetStyleSheet()->GetCharacterStyle(i
)->GetName() + wxT("|C"));
641 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_LIST
)
643 for (i
= 0; i
< GetStyleSheet()->GetListStyleCount(); i
++)
644 m_styleNames
.Add(GetStyleSheet()->GetListStyle(i
)->GetName() + wxT("|L"));
646 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_BOX
)
648 for (i
= 0; i
< GetStyleSheet()->GetBoxStyleCount(); i
++)
649 m_styleNames
.Add(GetStyleSheet()->GetBoxStyle(i
)->GetName() + wxT("|B"));
653 SetItemCount(m_styleNames
.GetCount());
658 if (oldSel
>= 0 && oldSel
< (int) GetItemCount())
660 else if (GetItemCount() > 0)
665 SetSelection(newSel
);
671 m_styleNames
.Clear();
672 SetSelection(wxNOT_FOUND
);
678 // Get index for style name
679 int wxRichTextStyleListBox::GetIndexForStyle(const wxString
& name
) const
682 if (GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH
)
684 else if (GetStyleType() == wxRICHTEXT_STYLE_CHARACTER
)
686 else if (GetStyleType() == wxRICHTEXT_STYLE_LIST
)
688 else if (GetStyleType() == wxRICHTEXT_STYLE_BOX
)
692 if (m_styleNames
.Index(s
+ wxT("|P")) != wxNOT_FOUND
)
694 else if (m_styleNames
.Index(s
+ wxT("|C")) != wxNOT_FOUND
)
696 else if (m_styleNames
.Index(s
+ wxT("|L")) != wxNOT_FOUND
)
698 else if (m_styleNames
.Index(s
+ wxT("|B")) != wxNOT_FOUND
)
701 return m_styleNames
.Index(s
);
704 /// Set selection for string
705 int wxRichTextStyleListBox::SetStyleSelection(const wxString
& name
)
707 int i
= GetIndexForStyle(name
);
717 // Convert a colour to a 6-digit hex string
718 static wxString
ColourToHexString(const wxColour
& col
)
722 hex
+= wxDecToHex(col
.Red());
723 hex
+= wxDecToHex(col
.Green());
724 hex
+= wxDecToHex(col
.Blue());
729 /// Creates a suitable HTML fragment for a definition
730 wxString
wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition
* def
) const
732 // TODO: indicate list format for list style types
736 bool isCentred
= false;
738 wxRichTextAttr
attr(def
->GetStyleMergedWithBase(GetStyleSheet()));
740 if (attr
.HasAlignment() && attr
.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
)
743 str
<< wxT("<html><head></head>");
745 if (attr
.GetBackgroundColour().Ok())
746 str
<< wxT(" bgcolor=\"#") << ColourToHexString(attr
.GetBackgroundColour()) << wxT("\"");
750 str
<< wxT("<center>");
752 str
<< wxT("<table");
753 if (attr
.GetBackgroundColour().Ok())
754 str
<< wxT(" bgcolor=\"#") << ColourToHexString(attr
.GetBackgroundColour()) << wxT("\"");
758 if (attr
.GetLeftIndent() > 0)
760 wxClientDC
dc((wxWindow
*) this);
762 str
<< wxT("<td width=") << wxMin(50, (ConvertTenthsMMToPixels(dc
, attr
.GetLeftIndent())/2)) << wxT("></td>");
766 str
<< wxT("<td nowrap align=\"center\">");
768 str
<< wxT("<td nowrap>");
776 // Guess a standard font size
779 // First see if we have a default/normal style to base the size on
780 wxString
normalTranslated(_("normal"));
781 wxString
defaultTranslated(_("default"));
783 for (i
= 0; i
< GetStyleSheet()->GetParagraphStyleCount(); i
++)
785 wxRichTextStyleDefinition
* d
= GetStyleSheet()->GetParagraphStyle(i
);
786 wxString name
= d
->GetName().Lower();
787 if (name
.Find(wxT("normal")) != wxNOT_FOUND
|| name
.Find(normalTranslated
) != wxNOT_FOUND
||
788 name
.Find(wxT("default")) != wxNOT_FOUND
|| name
.Find(defaultTranslated
) != wxNOT_FOUND
)
790 wxRichTextAttr
attr2(d
->GetStyleMergedWithBase(GetStyleSheet()));
791 if (attr2
.HasFontPointSize())
793 stdFontSize
= attr2
.GetFontSize();
799 if (stdFontSize
== 0)
801 // Look at sizes up to 20 points, and see which is the most common
804 for (i
= 0; i
<= maxSize
; i
++)
806 for (i
= 0; i
< m_styleNames
.GetCount(); i
++)
808 wxRichTextStyleDefinition
* d
= GetStyle(i
);
811 wxRichTextAttr
attr2(d
->GetStyleMergedWithBase(GetStyleSheet()));
812 if (attr2
.HasFontPointSize())
814 if (attr2
.GetFontSize() <= (int) maxSize
)
815 sizes
[attr2
.GetFontSize()] ++;
819 int mostCommonSize
= 0;
820 for (i
= 0; i
<= maxSize
; i
++)
822 if (sizes
[i
] > mostCommonSize
)
825 if (mostCommonSize
> 0)
826 stdFontSize
= mostCommonSize
;
829 if (stdFontSize
== 0)
832 int thisFontSize
= attr
.HasFontPointSize() ? attr
.GetFontSize() : stdFontSize
;
834 if (thisFontSize
< stdFontSize
)
836 else if (thisFontSize
> stdFontSize
)
841 str
<< wxT(" size=") << size
;
843 if (!attr
.GetFontFaceName().IsEmpty())
844 str
<< wxT(" face=\"") << attr
.GetFontFaceName() << wxT("\"");
846 if (attr
.GetTextColour().IsOk())
847 str
<< wxT(" color=\"#") << ColourToHexString(attr
.GetTextColour()) << wxT("\"");
849 if (attr
.GetBackgroundColour().Ok())
850 str
<< wxT(" bgcolor=\"#") << ColourToHexString(attr
.GetBackgroundColour()) << wxT("\"");
854 bool hasBold
= false;
855 bool hasItalic
= false;
856 bool hasUnderline
= false;
858 if (attr
.GetFontWeight() == wxFONTWEIGHT_BOLD
)
860 if (attr
.GetFontStyle() == wxFONTSTYLE_ITALIC
)
862 if (attr
.GetFontUnderlined())
872 str
+= def
->GetName();
882 str
<< wxT("</centre>");
884 str
<< wxT("</font>");
886 str
<< wxT("</td></tr></table>");
889 str
<< wxT("</center>");
891 str
<< wxT("</body></html>");
895 // Convert units in tends of a millimetre to device units
896 int wxRichTextStyleListBox::ConvertTenthsMMToPixels(wxDC
& dc
, int units
) const
898 int ppi
= dc
.GetPPI().x
;
900 // There are ppi pixels in 254.1 "1/10 mm"
902 double pixels
= ((double) units
* (double)ppi
) / 254.1;
907 void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent
& event
)
909 wxVListBox::OnLeftDown(event
);
911 int item
= VirtualHitTest(event
.GetPosition().y
);
912 if (item
!= wxNOT_FOUND
&& GetApplyOnSelection())
916 void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent
& event
)
918 wxVListBox::OnLeftDown(event
);
920 int item
= VirtualHitTest(event
.GetPosition().y
);
921 if (item
!= wxNOT_FOUND
&& !GetApplyOnSelection())
925 /// Helper for listbox and combo control
926 wxString
wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl
* ctrl
, wxRichTextStyleType styleType
)
928 int adjustedCaretPos
= ctrl
->GetAdjustedCaretPosition(ctrl
->GetCaretPosition());
933 ctrl
->GetStyle(adjustedCaretPos
, attr
);
935 // Take into account current default style just chosen by user
936 if (ctrl
->IsDefaultStyleShowing())
938 wxRichTextApplyStyle(attr
, ctrl
->GetDefaultStyleEx());
940 if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_CHARACTER
) &&
941 !attr
.GetCharacterStyleName().IsEmpty())
942 styleName
= attr
.GetCharacterStyleName();
943 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_PARAGRAPH
) &&
944 !attr
.GetParagraphStyleName().IsEmpty())
945 styleName
= attr
.GetParagraphStyleName();
946 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_LIST
) &&
947 !attr
.GetListStyleName().IsEmpty())
948 styleName
= attr
.GetListStyleName();
949 // TODO: when we have a concept of focused object (text box), we'll
950 // use the paragraph style name of the focused object as the frame style name.
952 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_BOX
) &&
953 !attr
.GetBoxStyleName().IsEmpty())
954 styleName
= attr
.GetBoxStyleName();
957 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_CHARACTER
) &&
958 !attr
.GetCharacterStyleName().IsEmpty())
960 styleName
= attr
.GetCharacterStyleName();
962 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_PARAGRAPH
) &&
963 !attr
.GetParagraphStyleName().IsEmpty())
965 styleName
= attr
.GetParagraphStyleName();
967 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_LIST
) &&
968 !attr
.GetListStyleName().IsEmpty())
970 styleName
= attr
.GetListStyleName();
976 /// Auto-select from style under caret in idle time
977 void wxRichTextStyleListBox::OnIdle(wxIdleEvent
& event
)
979 if (CanAutoSetSelection() && GetRichTextCtrl() && IsShownOnScreen() && wxWindow::FindFocus() != this)
981 wxString styleName
= GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
983 int sel
= GetSelection();
984 if (!styleName
.IsEmpty())
986 // Don't do the selection if it's already set
987 if (sel
== GetIndexForStyle(styleName
))
990 SetStyleSelection(styleName
);
999 void wxRichTextStyleListBox::ApplyStyle(int item
)
1001 if ( item
!= wxNOT_FOUND
)
1003 wxRichTextStyleDefinition
* def
= GetStyle(item
);
1004 if (def
&& GetRichTextCtrl())
1006 GetRichTextCtrl()->ApplyStyle(def
);
1007 GetRichTextCtrl()->SetFocus();
1013 * wxRichTextStyleListCtrl class: manages a listbox and a choice control to
1014 * switch shown style types
1017 IMPLEMENT_CLASS(wxRichTextStyleListCtrl
, wxControl
)
1019 BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl
, wxControl
)
1020 EVT_CHOICE(wxID_ANY
, wxRichTextStyleListCtrl::OnChooseType
)
1021 EVT_SIZE(wxRichTextStyleListCtrl::OnSize
)
1024 wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
1025 const wxSize
& size
, long style
)
1028 Create(parent
, id
, pos
, size
, style
);
1031 bool wxRichTextStyleListCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
1032 const wxSize
& size
, long style
)
1034 if ((style
& wxBORDER_MASK
) == wxBORDER_DEFAULT
)
1035 style
|= wxBORDER_THEME
;
1037 wxControl::Create(parent
, id
, pos
, size
, style
);
1039 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
1040 if (size
!= wxDefaultSize
)
1041 SetInitialSize(size
);
1043 bool showSelector
= ((style
& wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR
) == 0);
1045 wxBorder listBoxStyle
;
1047 listBoxStyle
= wxBORDER_THEME
;
1049 listBoxStyle
= wxBORDER_NONE
;
1051 m_styleListBox
= new wxRichTextStyleListBox(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, listBoxStyle
);
1053 wxBoxSizer
* boxSizer
= new wxBoxSizer(wxVERTICAL
);
1057 wxArrayString choices
;
1058 choices
.Add(_("All styles"));
1059 choices
.Add(_("Paragraph styles"));
1060 choices
.Add(_("Character styles"));
1061 choices
.Add(_("List styles"));
1062 choices
.Add(_("Box styles"));
1064 m_styleChoice
= new wxChoice(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, choices
);
1066 boxSizer
->Add(m_styleListBox
, 1, wxALL
|wxEXPAND
, 5);
1067 boxSizer
->Add(m_styleChoice
, 0, wxLEFT
|wxRIGHT
|wxBOTTOM
|wxEXPAND
, 5);
1071 boxSizer
->Add(m_styleListBox
, 1, wxALL
|wxEXPAND
, 0);
1077 m_dontUpdate
= true;
1081 int i
= StyleTypeToIndex(m_styleListBox
->GetStyleType());
1082 m_styleChoice
->SetSelection(i
);
1085 m_dontUpdate
= false;
1090 wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
1095 /// React to style type choice
1096 void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent
& event
)
1098 if (event
.GetEventObject() != m_styleChoice
)
1105 wxRichTextStyleListBox::wxRichTextStyleType styleType
= StyleIndexToType(event
.GetSelection());
1106 m_styleListBox
->SetSelection(-1);
1107 m_styleListBox
->SetStyleType(styleType
);
1111 /// Lay out the controls
1112 void wxRichTextStyleListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
))
1114 if (GetAutoLayout())
1118 /// Get the choice index for style type
1119 int wxRichTextStyleListCtrl::StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType
)
1121 if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL
)
1125 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH
)
1129 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER
)
1133 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST
)
1137 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX
)
1144 /// Get the style type for choice index
1145 wxRichTextStyleListBox::wxRichTextStyleType
wxRichTextStyleListCtrl::StyleIndexToType(int i
)
1148 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH
;
1150 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER
;
1152 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST
;
1154 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX
;
1156 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL
;
1159 /// Associates the control with a style manager
1160 void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet
* styleSheet
)
1163 m_styleListBox
->SetStyleSheet(styleSheet
);
1166 wxRichTextStyleSheet
* wxRichTextStyleListCtrl::GetStyleSheet() const
1169 return m_styleListBox
->GetStyleSheet();
1174 /// Associates the control with a wxRichTextCtrl
1175 void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl
* ctrl
)
1178 m_styleListBox
->SetRichTextCtrl(ctrl
);
1181 wxRichTextCtrl
* wxRichTextStyleListCtrl::GetRichTextCtrl() const
1184 return m_styleListBox
->GetRichTextCtrl();
1189 /// Set/get the style type to display
1190 void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType
)
1192 if ( !m_styleListBox
)
1195 m_styleListBox
->SetStyleType(styleType
);
1197 m_dontUpdate
= true;
1201 int i
= StyleTypeToIndex(m_styleListBox
->GetStyleType());
1202 m_styleChoice
->SetSelection(i
);
1205 m_dontUpdate
= false;
1208 wxRichTextStyleListBox::wxRichTextStyleType
wxRichTextStyleListCtrl::GetStyleType() const
1211 return m_styleListBox
->GetStyleType();
1213 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL
;
1216 /// Updates the style list box
1217 void wxRichTextStyleListCtrl::UpdateStyles()
1220 m_styleListBox
->UpdateStyles();
1226 * Style drop-down for a wxComboCtrl
1230 BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup
, wxRichTextStyleListBox
)
1231 EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove
)
1232 EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick
)
1235 bool wxRichTextStyleComboPopup::Create( wxWindow
* parent
)
1237 int borderStyle
= GetDefaultBorder();
1238 if (borderStyle
== wxBORDER_SUNKEN
|| borderStyle
== wxBORDER_NONE
)
1239 borderStyle
= wxBORDER_THEME
;
1241 return wxRichTextStyleListBox::Create(parent
, wxID_ANY
,
1242 wxPoint(0,0), wxDefaultSize
,
1246 void wxRichTextStyleComboPopup::SetStringValue( const wxString
& s
)
1248 m_value
= SetStyleSelection(s
);
1251 wxString
wxRichTextStyleComboPopup::GetStringValue() const
1256 wxRichTextStyleDefinition
* def
= GetStyle(sel
);
1258 return def
->GetName();
1260 return wxEmptyString
;
1264 // Popup event handlers
1267 // Mouse hot-tracking
1268 void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent
& event
)
1270 // Move selection to cursor if it is inside the popup
1272 int itemHere
= wxRichTextStyleListBox::VirtualHitTest(event
.GetPosition().y
);
1273 if ( itemHere
>= 0 )
1275 wxRichTextStyleListBox::SetSelection(itemHere
);
1276 m_itemHere
= itemHere
;
1281 // On mouse left, set the value and close the popup
1282 void wxRichTextStyleComboPopup::OnMouseClick(wxMouseEvent
& WXUNUSED(event
))
1284 if (m_itemHere
>= 0)
1285 m_value
= m_itemHere
;
1287 // Ordering is important, so we don't dismiss this popup accidentally
1288 // by setting the focus elsewhere e.g. in ApplyStyle
1291 if (m_itemHere
>= 0)
1292 wxRichTextStyleListBox::ApplyStyle(m_itemHere
);
1296 * wxRichTextStyleComboCtrl
1297 * A combo for applying styles.
1300 IMPLEMENT_CLASS(wxRichTextStyleComboCtrl
, wxComboCtrl
)
1302 BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl
, wxComboCtrl
)
1303 EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle
)
1306 bool wxRichTextStyleComboCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
1307 const wxSize
& size
, long style
)
1309 if (!wxComboCtrl::Create(parent
, id
, wxEmptyString
, pos
, size
, style
))
1312 SetPopupMaxHeight(400);
1314 m_stylePopup
= new wxRichTextStyleComboPopup
;
1316 SetPopupControl(m_stylePopup
);
1321 /// Auto-select from style under caret in idle time
1323 // TODO: must be able to show italic, bold, combinations
1324 // in style box. Do we have a concept of automatic, temporary
1325 // styles that are added whenever we wish to show a style
1326 // that doesn't exist already? E.g. "Bold, Italic, Underline".
1327 // Word seems to generate these things on the fly.
1328 // If there's a named style already, it uses e.g. Heading1 + Bold, Italic
1329 // If you unembolden text in a style that has bold, it uses the
1331 // TODO: order styles alphabetically. This means indexes can change,
1332 // so need a different way to specify selections, i.e. by name.
1334 void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent
& event
)
1338 if ( !m_stylePopup
)
1341 wxRichTextCtrl
* const richtext
= GetRichTextCtrl();
1345 if ( !IsPopupShown() && IsShownOnScreen() && wxWindow::FindFocus() != this )
1347 wxString styleName
=
1348 wxRichTextStyleListBox::GetStyleToShowInIdleTime(richtext
, m_stylePopup
->GetStyleType());
1350 wxString currentValue
= GetValue();
1351 if (!styleName
.IsEmpty())
1353 // Don't do the selection if it's already set
1354 if (currentValue
== styleName
)
1357 SetValue(styleName
);
1359 else if (!currentValue
.IsEmpty())
1360 SetValue(wxEmptyString
);