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
;
52 bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition
& def
) const
54 return (m_name
== def
.m_name
&& m_baseStyle
== def
.m_baseStyle
&& m_style
== def
.m_style
);
57 /// Gets the style combined with the base style
58 wxRichTextAttr
wxRichTextStyleDefinition::GetStyleMergedWithBase(const wxRichTextStyleSheet
* sheet
) const
60 if (m_baseStyle
.IsEmpty())
63 // Collect the styles, detecting loops
64 wxArrayString styleNames
;
66 const wxRichTextStyleDefinition
* def
= this;
69 styles
.Insert((wxObject
*) def
);
70 styleNames
.Add(def
->GetName());
72 wxString baseStyleName
= def
->GetBaseStyle();
73 if (!baseStyleName
.IsEmpty() && styleNames
.Index(baseStyleName
) == wxNOT_FOUND
)
74 def
= sheet
->FindStyle(baseStyleName
);
80 wxList::compatibility_iterator node
= styles
.GetFirst();
83 wxRichTextStyleDefinition
* def
= (wxRichTextStyleDefinition
*) node
->GetData();
84 attr
.Apply(def
->GetStyle(), NULL
);
85 node
= node
->GetNext();
92 * Paragraph style definition
95 void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition
& def
)
97 wxRichTextStyleDefinition::Copy(def
);
99 m_nextStyle
= def
.m_nextStyle
;
102 bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition
& def
) const
104 return (Eq(def
) && m_nextStyle
== def
.m_nextStyle
);
108 * Box style definition
111 void wxRichTextBoxStyleDefinition::Copy(const wxRichTextBoxStyleDefinition
& def
)
113 wxRichTextStyleDefinition::Copy(def
);
116 bool wxRichTextBoxStyleDefinition::operator ==(const wxRichTextBoxStyleDefinition
& def
) const
122 * List style definition
125 void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition
& def
)
127 wxRichTextParagraphStyleDefinition::Copy(def
);
130 for (i
= 0; i
< 10; i
++)
131 m_levelStyles
[i
] = def
.m_levelStyles
[i
];
134 bool wxRichTextListStyleDefinition::operator ==(const wxRichTextListStyleDefinition
& def
) const
139 for (i
= 0; i
< 10; i
++)
140 if (!(m_levelStyles
[i
] == def
.m_levelStyles
[i
]))
146 /// Sets/gets the attributes for the given level
147 void wxRichTextListStyleDefinition::SetLevelAttributes(int i
, const wxRichTextAttr
& attr
)
149 wxASSERT( (i
>= 0 && i
< 10) );
150 if (i
>= 0 && i
< 10)
151 m_levelStyles
[i
] = attr
;
154 const wxRichTextAttr
* wxRichTextListStyleDefinition::GetLevelAttributes(int i
) const
156 wxASSERT( (i
>= 0 && i
< 10) );
157 if (i
>= 0 && i
< 10)
158 return & m_levelStyles
[i
];
163 wxRichTextAttr
* wxRichTextListStyleDefinition::GetLevelAttributes(int i
)
165 wxASSERT( (i
>= 0 && i
< 10) );
166 if (i
>= 0 && i
< 10)
167 return & m_levelStyles
[i
];
172 /// Convenience function for setting the major attributes for a list level specification
173 void wxRichTextListStyleDefinition::SetAttributes(int i
, int leftIndent
, int leftSubIndent
, int bulletStyle
, const wxString
& bulletSymbol
)
175 wxASSERT( (i
>= 0 && i
< 10) );
176 if (i
>= 0 && i
< 10)
180 attr
.SetBulletStyle(bulletStyle
);
181 attr
.SetLeftIndent(leftIndent
, leftSubIndent
);
183 if (!bulletSymbol
.IsEmpty())
185 if (bulletStyle
& wxTEXT_ATTR_BULLET_STYLE_SYMBOL
)
186 attr
.SetBulletText(bulletSymbol
);
188 attr
.SetBulletName(bulletSymbol
);
191 m_levelStyles
[i
] = attr
;
195 /// Finds the level corresponding to the given indentation
196 int wxRichTextListStyleDefinition::FindLevelForIndent(int indent
) const
199 for (i
= 0; i
< 10; i
++)
201 if (indent
< m_levelStyles
[i
].GetLeftIndent())
212 /// Combine the list style with a paragraph style, using the given indent (from which
213 /// an appropriate level is found)
214 wxRichTextAttr
wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent
, const wxRichTextAttr
& paraStyle
, wxRichTextStyleSheet
* styleSheet
)
216 int listLevel
= FindLevelForIndent(indent
);
218 wxRichTextAttr
attr(*GetLevelAttributes(listLevel
));
219 int oldLeftIndent
= attr
.GetLeftIndent();
220 int oldLeftSubIndent
= attr
.GetLeftSubIndent();
222 // First apply the overall paragraph style, if any
224 attr
.Apply(GetStyleMergedWithBase(styleSheet
));
226 attr
.Apply(GetStyle());
228 // Then apply paragraph style, e.g. from paragraph style definition
229 attr
.Apply(paraStyle
);
231 // We override the indents according to the list definition
232 attr
.SetLeftIndent(oldLeftIndent
, oldLeftSubIndent
);
237 /// Combine the base and list style, using the given indent (from which
238 /// an appropriate level is found)
239 wxRichTextAttr
wxRichTextListStyleDefinition::GetCombinedStyle(int indent
, wxRichTextStyleSheet
* styleSheet
)
241 int listLevel
= FindLevelForIndent(indent
);
242 return GetCombinedStyleForLevel(listLevel
, styleSheet
);
245 /// Combine the base and list style, using the given indent (from which
246 /// an appropriate level is found)
247 wxRichTextAttr
wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel
, wxRichTextStyleSheet
* styleSheet
)
249 wxRichTextAttr
attr(*GetLevelAttributes(listLevel
));
250 int oldLeftIndent
= attr
.GetLeftIndent();
251 int oldLeftSubIndent
= attr
.GetLeftSubIndent();
253 // Apply the overall paragraph style, if any
255 attr
.Apply(GetStyleMergedWithBase(styleSheet
));
257 attr
.Apply(GetStyle());
259 // We override the indents according to the list definition
260 attr
.SetLeftIndent(oldLeftIndent
, oldLeftSubIndent
);
265 /// Is this a numbered list?
266 bool wxRichTextListStyleDefinition::IsNumbered(int i
) const
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
)));
277 IMPLEMENT_CLASS(wxRichTextStyleSheet
, wxObject
)
279 wxRichTextStyleSheet::~wxRichTextStyleSheet()
284 m_nextSheet
->m_previousSheet
= m_previousSheet
;
287 m_previousSheet
->m_nextSheet
= m_nextSheet
;
289 m_previousSheet
= NULL
;
294 void wxRichTextStyleSheet::Init()
296 m_previousSheet
= NULL
;
300 /// Add a definition to one of the style lists
301 bool wxRichTextStyleSheet::AddStyle(wxList
& list
, wxRichTextStyleDefinition
* def
)
309 bool wxRichTextStyleSheet::RemoveStyle(wxList
& list
, wxRichTextStyleDefinition
* def
, bool deleteStyle
)
311 wxList::compatibility_iterator node
= list
.Find(def
);
314 wxRichTextStyleDefinition
* def
= (wxRichTextStyleDefinition
*) node
->GetData();
325 bool wxRichTextStyleSheet::RemoveStyle(wxRichTextStyleDefinition
* def
, bool deleteStyle
)
327 if (RemoveParagraphStyle(def
, deleteStyle
))
329 if (RemoveCharacterStyle(def
, deleteStyle
))
331 if (RemoveListStyle(def
, deleteStyle
))
333 if (RemoveBoxStyle(def
, deleteStyle
))
338 /// Find a definition by name
339 wxRichTextStyleDefinition
* wxRichTextStyleSheet::FindStyle(const wxList
& list
, const wxString
& name
, bool recurse
) const
341 for (wxList::compatibility_iterator node
= list
.GetFirst(); node
; node
= node
->GetNext())
343 wxRichTextStyleDefinition
* def
= (wxRichTextStyleDefinition
*) node
->GetData();
344 if (def
->GetName().Lower() == name
.Lower())
348 if (m_nextSheet
&& recurse
)
349 return m_nextSheet
->FindStyle(list
, name
, recurse
);
354 /// Delete all styles
355 void wxRichTextStyleSheet::DeleteStyles()
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
);
363 /// Insert into list of style sheets
364 bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet
* before
)
366 m_previousSheet
= before
->m_previousSheet
;
367 m_nextSheet
= before
;
369 before
->m_previousSheet
= this;
373 /// Append to list of style sheets
374 bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet
* after
)
376 wxRichTextStyleSheet
* last
= after
;
377 while (last
&& last
->m_nextSheet
)
379 last
= last
->m_nextSheet
;
384 m_previousSheet
= last
;
385 last
->m_nextSheet
= this;
393 /// Unlink from the list of style sheets
394 void wxRichTextStyleSheet::Unlink()
397 m_previousSheet
->m_nextSheet
= m_nextSheet
;
399 m_nextSheet
->m_previousSheet
= m_previousSheet
;
401 m_previousSheet
= NULL
;
405 /// Add a definition to the character style list
406 bool wxRichTextStyleSheet::AddCharacterStyle(wxRichTextCharacterStyleDefinition
* def
)
408 def
->GetStyle().SetCharacterStyleName(def
->GetName());
409 return AddStyle(m_characterStyleDefinitions
, def
);
412 /// Add a definition to the paragraph style list
413 bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition
* def
)
415 def
->GetStyle().SetParagraphStyleName(def
->GetName());
416 return AddStyle(m_paragraphStyleDefinitions
, def
);
419 /// Add a definition to the list style list
420 bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition
* def
)
422 def
->GetStyle().SetListStyleName(def
->GetName());
423 return AddStyle(m_listStyleDefinitions
, def
);
426 /// Add a definition to the box style list
427 bool wxRichTextStyleSheet::AddBoxStyle(wxRichTextBoxStyleDefinition
* def
)
429 def
->GetStyle().SetParagraphStyleName(def
->GetName());
430 return AddStyle(m_boxStyleDefinitions
, def
);
433 /// Add a definition to the appropriate style list
434 bool wxRichTextStyleSheet::AddStyle(wxRichTextStyleDefinition
* def
)
436 wxRichTextListStyleDefinition
* listDef
= wxDynamicCast(def
, wxRichTextListStyleDefinition
);
438 return AddListStyle(listDef
);
440 wxRichTextParagraphStyleDefinition
* paraDef
= wxDynamicCast(def
, wxRichTextParagraphStyleDefinition
);
442 return AddParagraphStyle(paraDef
);
444 wxRichTextCharacterStyleDefinition
* charDef
= wxDynamicCast(def
, wxRichTextCharacterStyleDefinition
);
446 return AddCharacterStyle(charDef
);
448 wxRichTextBoxStyleDefinition
* boxDef
= wxDynamicCast(def
, wxRichTextBoxStyleDefinition
);
450 return AddBoxStyle(boxDef
);
455 /// Find any definition by name
456 wxRichTextStyleDefinition
* wxRichTextStyleSheet::FindStyle(const wxString
& name
, bool recurse
) const
458 wxRichTextListStyleDefinition
* listDef
= FindListStyle(name
, recurse
);
462 wxRichTextParagraphStyleDefinition
* paraDef
= FindParagraphStyle(name
, recurse
);
466 wxRichTextCharacterStyleDefinition
* charDef
= FindCharacterStyle(name
, recurse
);
470 wxRichTextBoxStyleDefinition
* boxDef
= FindBoxStyle(name
, recurse
);
478 void wxRichTextStyleSheet::Copy(const wxRichTextStyleSheet
& sheet
)
482 wxList::compatibility_iterator node
;
484 for (node
= sheet
.m_characterStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
486 wxRichTextCharacterStyleDefinition
* def
= (wxRichTextCharacterStyleDefinition
*) node
->GetData();
487 AddCharacterStyle(new wxRichTextCharacterStyleDefinition(*def
));
490 for (node
= sheet
.m_paragraphStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
492 wxRichTextParagraphStyleDefinition
* def
= (wxRichTextParagraphStyleDefinition
*) node
->GetData();
493 AddParagraphStyle(new wxRichTextParagraphStyleDefinition(*def
));
496 for (node
= sheet
.m_listStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
498 wxRichTextListStyleDefinition
* def
= (wxRichTextListStyleDefinition
*) node
->GetData();
499 AddListStyle(new wxRichTextListStyleDefinition(*def
));
502 for (node
= sheet
.m_boxStyleDefinitions
.GetFirst(); node
; node
= node
->GetNext())
504 wxRichTextBoxStyleDefinition
* def
= (wxRichTextBoxStyleDefinition
*) node
->GetData();
505 AddBoxStyle(new wxRichTextBoxStyleDefinition(*def
));
508 SetName(sheet
.GetName());
509 SetDescription(sheet
.GetDescription());
513 bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet
& WXUNUSED(sheet
)) const
522 * wxRichTextStyleListBox: a listbox to display styles.
525 IMPLEMENT_CLASS(wxRichTextStyleListBox
, wxHtmlListBox
)
527 BEGIN_EVENT_TABLE(wxRichTextStyleListBox
, wxHtmlListBox
)
528 EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown
)
529 EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick
)
530 EVT_IDLE(wxRichTextStyleListBox::OnIdle
)
533 wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
534 const wxSize
& size
, long style
)
537 Create(parent
, id
, pos
, size
, style
);
540 bool wxRichTextStyleListBox::Create(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
541 const wxSize
& size
, long style
)
543 return wxHtmlListBox::Create(parent
, id
, pos
, size
, style
);
546 wxRichTextStyleListBox::~wxRichTextStyleListBox()
550 /// Returns the HTML for this item
551 wxString
wxRichTextStyleListBox::OnGetItem(size_t n
) const
553 if (!GetStyleSheet())
554 return wxEmptyString
;
556 wxRichTextStyleDefinition
* def
= GetStyle(n
);
558 return CreateHTML(def
);
560 return wxEmptyString
;
563 // Get style for index
564 wxRichTextStyleDefinition
* wxRichTextStyleListBox::GetStyle(size_t i
) const
566 if (!GetStyleSheet())
569 if (i
>= m_styleNames
.GetCount() /* || i < 0 */ )
572 return GetStyleSheet()->FindStyle(m_styleNames
[i
]);
576 void wxRichTextStyleListBox::UpdateStyles()
580 int oldSel
= GetSelection();
582 SetSelection(wxNOT_FOUND
);
584 m_styleNames
.Clear();
587 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH
)
589 for (i
= 0; i
< GetStyleSheet()->GetParagraphStyleCount(); i
++)
590 m_styleNames
.Add(GetStyleSheet()->GetParagraphStyle(i
)->GetName());
592 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_CHARACTER
)
594 for (i
= 0; i
< GetStyleSheet()->GetCharacterStyleCount(); i
++)
595 m_styleNames
.Add(GetStyleSheet()->GetCharacterStyle(i
)->GetName());
597 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_LIST
)
599 for (i
= 0; i
< GetStyleSheet()->GetListStyleCount(); i
++)
600 m_styleNames
.Add(GetStyleSheet()->GetListStyle(i
)->GetName());
602 if (GetStyleType() == wxRICHTEXT_STYLE_ALL
|| GetStyleType() == wxRICHTEXT_STYLE_BOX
)
604 for (i
= 0; i
< GetStyleSheet()->GetBoxStyleCount(); i
++)
605 m_styleNames
.Add(GetStyleSheet()->GetBoxStyle(i
)->GetName());
609 SetItemCount(m_styleNames
.GetCount());
614 if (oldSel
>= 0 && oldSel
< (int) GetItemCount())
616 else if (GetItemCount() > 0)
621 SetSelection(newSel
);
627 // Get index for style name
628 int wxRichTextStyleListBox::GetIndexForStyle(const wxString
& name
) const
630 return m_styleNames
.Index(name
);
633 /// Set selection for string
634 int wxRichTextStyleListBox::SetStyleSelection(const wxString
& name
)
636 int i
= GetIndexForStyle(name
);
642 // Convert a colour to a 6-digit hex string
643 static wxString
ColourToHexString(const wxColour
& col
)
647 hex
+= wxDecToHex(col
.Red());
648 hex
+= wxDecToHex(col
.Green());
649 hex
+= wxDecToHex(col
.Blue());
654 /// Creates a suitable HTML fragment for a definition
655 wxString
wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition
* def
) const
657 // TODO: indicate list format for list style types
661 bool isCentred
= false;
663 wxRichTextAttr
attr(def
->GetStyleMergedWithBase(GetStyleSheet()));
665 if (attr
.HasAlignment() && attr
.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
)
669 str
<< wxT("<center>");
672 str
<< wxT("<table><tr>");
674 if (attr
.GetLeftIndent() > 0)
676 wxClientDC
dc((wxWindow
*) this);
678 str
<< wxT("<td width=") << wxMin(50, (ConvertTenthsMMToPixels(dc
, attr
.GetLeftIndent())/2)) << wxT("></td>");
682 str
<< wxT("<td nowrap align=\"center\">");
684 str
<< wxT("<td nowrap>");
692 // Guess a standard font size
695 // First see if we have a default/normal style to base the size on
696 wxString
normalTranslated(_("normal"));
697 wxString
defaultTranslated(_("default"));
699 for (i
= 0; i
< m_styleNames
.GetCount(); i
++)
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
)
705 wxRichTextStyleDefinition
* d
= GetStyleSheet()->FindStyle(m_styleNames
[i
]);
708 wxRichTextAttr
attr2(d
->GetStyleMergedWithBase(GetStyleSheet()));
709 if (attr2
.HasFontSize())
711 stdFontSize
= attr2
.GetFontSize();
718 if (stdFontSize
== 0)
720 // Look at sizes up to 20 points, and see which is the most common
723 for (i
= 0; i
<= maxSize
; i
++)
725 for (i
= 0; i
< m_styleNames
.GetCount(); i
++)
727 wxRichTextStyleDefinition
* d
= GetStyleSheet()->FindStyle(m_styleNames
[i
]);
730 wxRichTextAttr
attr2(d
->GetStyleMergedWithBase(GetStyleSheet()));
731 if (attr2
.HasFontSize())
733 if (attr2
.GetFontSize() <= (int) maxSize
)
734 sizes
[attr2
.GetFontSize()] ++;
738 int mostCommonSize
= 0;
739 for (i
= 0; i
<= maxSize
; i
++)
741 if (sizes
[i
] > mostCommonSize
)
744 if (mostCommonSize
> 0)
745 stdFontSize
= mostCommonSize
;
748 if (stdFontSize
== 0)
751 int thisFontSize
= ((attr
.GetFlags() & wxTEXT_ATTR_FONT_SIZE
) != 0) ? attr
.GetFontSize() : stdFontSize
;
753 if (thisFontSize
< stdFontSize
)
755 else if (thisFontSize
> stdFontSize
)
760 str
<< wxT(" size=") << size
;
762 if (!attr
.GetFontFaceName().IsEmpty())
763 str
<< wxT(" face=\"") << attr
.GetFontFaceName() << wxT("\"");
765 if (attr
.GetTextColour().Ok())
766 str
<< wxT(" color=\"#") << ColourToHexString(attr
.GetTextColour()) << wxT("\"");
770 bool hasBold
= false;
771 bool hasItalic
= false;
772 bool hasUnderline
= false;
774 if (attr
.GetFontWeight() == wxBOLD
)
776 if (attr
.GetFontStyle() == wxITALIC
)
778 if (attr
.GetFontUnderlined())
788 str
+= def
->GetName();
798 str
<< wxT("</centre>");
800 str
<< wxT("</font>");
802 str
<< wxT("</td></tr></table>");
805 str
<< wxT("</center>");
810 // Convert units in tends of a millimetre to device units
811 int wxRichTextStyleListBox::ConvertTenthsMMToPixels(wxDC
& dc
, int units
) const
813 int ppi
= dc
.GetPPI().x
;
815 // There are ppi pixels in 254.1 "1/10 mm"
817 double pixels
= ((double) units
* (double)ppi
) / 254.1;
822 void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent
& event
)
824 wxVListBox::OnLeftDown(event
);
826 int item
= VirtualHitTest(event
.GetPosition().y
);
827 if (item
!= wxNOT_FOUND
&& GetApplyOnSelection())
831 void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent
& event
)
833 wxVListBox::OnLeftDown(event
);
835 int item
= VirtualHitTest(event
.GetPosition().y
);
836 if (item
!= wxNOT_FOUND
&& !GetApplyOnSelection())
840 /// Helper for listbox and combo control
841 wxString
wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl
* ctrl
, wxRichTextStyleType styleType
)
843 int adjustedCaretPos
= ctrl
->GetAdjustedCaretPosition(ctrl
->GetCaretPosition());
848 ctrl
->GetStyle(adjustedCaretPos
, attr
);
850 // Take into account current default style just chosen by user
851 if (ctrl
->IsDefaultStyleShowing())
853 wxRichTextApplyStyle(attr
, ctrl
->GetDefaultStyleEx());
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.
867 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_BOX
) &&
868 !attr
.GetBoxStyleName().IsEmpty())
869 styleName
= attr
.GetBoxStyleName();
872 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_CHARACTER
) &&
873 !attr
.GetCharacterStyleName().IsEmpty())
875 styleName
= attr
.GetCharacterStyleName();
877 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_PARAGRAPH
) &&
878 !attr
.GetParagraphStyleName().IsEmpty())
880 styleName
= attr
.GetParagraphStyleName();
882 else if ((styleType
== wxRICHTEXT_STYLE_ALL
|| styleType
== wxRICHTEXT_STYLE_LIST
) &&
883 !attr
.GetListStyleName().IsEmpty())
885 styleName
= attr
.GetListStyleName();
891 /// Auto-select from style under caret in idle time
892 void wxRichTextStyleListBox::OnIdle(wxIdleEvent
& event
)
894 if (CanAutoSetSelection() && GetRichTextCtrl() && IsShownOnScreen() && wxWindow::FindFocus() != this)
896 wxString styleName
= GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
898 int sel
= GetSelection();
899 if (!styleName
.IsEmpty())
901 // Don't do the selection if it's already set
902 if (sel
== GetIndexForStyle(styleName
))
905 SetStyleSelection(styleName
);
914 void wxRichTextStyleListBox::ApplyStyle(int item
)
916 if ( item
!= wxNOT_FOUND
)
918 wxRichTextStyleDefinition
* def
= GetStyle(item
);
919 if (def
&& GetRichTextCtrl())
921 GetRichTextCtrl()->ApplyStyle(def
);
922 GetRichTextCtrl()->SetFocus();
928 * wxRichTextStyleListCtrl class: manages a listbox and a choice control to
929 * switch shown style types
932 IMPLEMENT_CLASS(wxRichTextStyleListCtrl
, wxControl
)
934 BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl
, wxControl
)
935 EVT_CHOICE(wxID_ANY
, wxRichTextStyleListCtrl::OnChooseType
)
936 EVT_SIZE(wxRichTextStyleListCtrl::OnSize
)
939 wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
940 const wxSize
& size
, long style
)
943 Create(parent
, id
, pos
, size
, style
);
946 bool wxRichTextStyleListCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
947 const wxSize
& size
, long style
)
949 if ((style
& wxBORDER_MASK
) == wxBORDER_DEFAULT
)
950 style
|= wxBORDER_THEME
;
952 wxControl::Create(parent
, id
, pos
, size
, style
);
954 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
955 if (size
!= wxDefaultSize
)
956 SetInitialSize(size
);
958 bool showSelector
= ((style
& wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR
) == 0);
960 wxBorder listBoxStyle
;
962 listBoxStyle
= wxBORDER_THEME
;
964 listBoxStyle
= wxBORDER_NONE
;
966 m_styleListBox
= new wxRichTextStyleListBox(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, listBoxStyle
);
968 wxBoxSizer
* boxSizer
= new wxBoxSizer(wxVERTICAL
);
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"));
979 m_styleChoice
= new wxChoice(this, wxID_ANY
, wxDefaultPosition
, wxDefaultSize
, choices
);
981 boxSizer
->Add(m_styleListBox
, 1, wxALL
|wxEXPAND
, 5);
982 boxSizer
->Add(m_styleChoice
, 0, wxLEFT
|wxRIGHT
|wxBOTTOM
|wxEXPAND
, 5);
986 boxSizer
->Add(m_styleListBox
, 1, wxALL
|wxEXPAND
, 0);
996 int i
= StyleTypeToIndex(m_styleListBox
->GetStyleType());
997 m_styleChoice
->SetSelection(i
);
1000 m_dontUpdate
= false;
1005 wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
1010 /// React to style type choice
1011 void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent
& event
)
1013 if (event
.GetEventObject() != m_styleChoice
)
1020 wxRichTextStyleListBox::wxRichTextStyleType styleType
= StyleIndexToType(event
.GetSelection());
1021 m_styleListBox
->SetSelection(-1);
1022 m_styleListBox
->SetStyleType(styleType
);
1026 /// Lay out the controls
1027 void wxRichTextStyleListCtrl::OnSize(wxSizeEvent
& WXUNUSED(event
))
1029 if (GetAutoLayout())
1033 /// Get the choice index for style type
1034 int wxRichTextStyleListCtrl::StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType
)
1036 if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL
)
1040 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH
)
1044 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER
)
1048 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST
)
1052 else if (styleType
== wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX
)
1059 /// Get the style type for choice index
1060 wxRichTextStyleListBox::wxRichTextStyleType
wxRichTextStyleListCtrl::StyleIndexToType(int i
)
1063 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH
;
1065 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER
;
1067 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST
;
1069 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX
;
1071 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL
;
1074 /// Associates the control with a style manager
1075 void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet
* styleSheet
)
1078 m_styleListBox
->SetStyleSheet(styleSheet
);
1081 wxRichTextStyleSheet
* wxRichTextStyleListCtrl::GetStyleSheet() const
1084 return m_styleListBox
->GetStyleSheet();
1089 /// Associates the control with a wxRichTextCtrl
1090 void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl
* ctrl
)
1093 m_styleListBox
->SetRichTextCtrl(ctrl
);
1096 wxRichTextCtrl
* wxRichTextStyleListCtrl::GetRichTextCtrl() const
1099 return m_styleListBox
->GetRichTextCtrl();
1104 /// Set/get the style type to display
1105 void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType
)
1107 if ( !m_styleListBox
)
1110 m_styleListBox
->SetStyleType(styleType
);
1112 m_dontUpdate
= true;
1116 int i
= StyleTypeToIndex(m_styleListBox
->GetStyleType());
1117 m_styleChoice
->SetSelection(i
);
1120 m_dontUpdate
= false;
1123 wxRichTextStyleListBox::wxRichTextStyleType
wxRichTextStyleListCtrl::GetStyleType() const
1126 return m_styleListBox
->GetStyleType();
1128 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL
;
1131 /// Updates the style list box
1132 void wxRichTextStyleListCtrl::UpdateStyles()
1135 m_styleListBox
->UpdateStyles();
1141 * Style drop-down for a wxComboCtrl
1145 BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup
, wxRichTextStyleListBox
)
1146 EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove
)
1147 EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick
)
1150 bool wxRichTextStyleComboPopup::Create( wxWindow
* parent
)
1152 int borderStyle
= GetDefaultBorder();
1153 if (borderStyle
== wxBORDER_SUNKEN
)
1154 borderStyle
= wxBORDER_SIMPLE
;
1156 return wxRichTextStyleListBox::Create(parent
, wxID_ANY
,
1157 wxPoint(0,0), wxDefaultSize
,
1161 void wxRichTextStyleComboPopup::SetStringValue( const wxString
& s
)
1163 m_value
= SetStyleSelection(s
);
1166 wxString
wxRichTextStyleComboPopup::GetStringValue() const
1171 wxRichTextStyleDefinition
* def
= GetStyle(sel
);
1173 return def
->GetName();
1175 return wxEmptyString
;
1179 // Popup event handlers
1182 // Mouse hot-tracking
1183 void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent
& event
)
1185 // Move selection to cursor if it is inside the popup
1187 int itemHere
= wxRichTextStyleListBox::VirtualHitTest(event
.GetPosition().y
);
1188 if ( itemHere
>= 0 )
1190 wxRichTextStyleListBox::SetSelection(itemHere
);
1191 m_itemHere
= itemHere
;
1196 // On mouse left, set the value and close the popup
1197 void wxRichTextStyleComboPopup::OnMouseClick(wxMouseEvent
& WXUNUSED(event
))
1199 if (m_itemHere
>= 0)
1200 m_value
= m_itemHere
;
1202 // Ordering is important, so we don't dismiss this popup accidentally
1203 // by setting the focus elsewhere e.g. in ApplyStyle
1206 if (m_itemHere
>= 0)
1207 wxRichTextStyleListBox::ApplyStyle(m_itemHere
);
1211 * wxRichTextStyleComboCtrl
1212 * A combo for applying styles.
1215 IMPLEMENT_CLASS(wxRichTextStyleComboCtrl
, wxComboCtrl
)
1217 BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl
, wxComboCtrl
)
1218 EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle
)
1221 bool wxRichTextStyleComboCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxPoint
& pos
,
1222 const wxSize
& size
, long style
)
1224 if (!wxComboCtrl::Create(parent
, id
, wxEmptyString
, pos
, size
, style
))
1227 SetPopupMaxHeight(400);
1229 m_stylePopup
= new wxRichTextStyleComboPopup
;
1231 SetPopupControl(m_stylePopup
);
1236 /// Auto-select from style under caret in idle time
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
1246 // TODO: order styles alphabetically. This means indexes can change,
1247 // so need a different way to specify selections, i.e. by name.
1249 void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent
& event
)
1253 if ( !m_stylePopup
)
1256 wxRichTextCtrl
* const richtext
= GetRichTextCtrl();
1260 if ( !IsPopupShown() && IsShownOnScreen() && wxWindow::FindFocus() != this )
1262 wxString styleName
=
1263 wxRichTextStyleListBox::GetStyleToShowInIdleTime(richtext
, m_stylePopup
->GetStyleType());
1265 wxString currentValue
= GetValue();
1266 if (!styleName
.IsEmpty())
1268 // Don't do the selection if it's already set
1269 if (currentValue
== styleName
)
1272 SetValue(styleName
);
1274 else if (!currentValue
.IsEmpty())
1275 SetValue(wxEmptyString
);