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