]> git.saurik.com Git - wxWidgets.git/blame - src/richtext/richtextstyles.cpp
Fix wxHtmlHelpData::SetTempDir() to behave correctly without trailing slash.
[wxWidgets.git] / src / richtext / richtextstyles.cpp
CommitLineData
5d7836c4 1/////////////////////////////////////////////////////////////////////////////
61399247 2// Name: src/richtext/richtextstyles.cpp
5d7836c4
JS
3// Purpose: Style management for wxRichTextCtrl
4// Author: Julian Smart
61399247 5// Modified by:
5d7836c4 6// Created: 2005-09-30
5d7836c4
JS
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__
fe5aa22c 15 #pragma hdrstop
5d7836c4
JS
16#endif
17
b01ca8b6
JS
18#if wxUSE_RICHTEXT
19
20#include "wx/richtext/richtextstyles.h"
21
5d7836c4 22#ifndef WX_PRECOMP
fe5aa22c 23 #include "wx/wx.h"
5d7836c4
JS
24#endif
25
5d7836c4
JS
26#include "wx/filename.h"
27#include "wx/clipbrd.h"
28#include "wx/wfstream.h"
38f833b1 29#include "wx/settings.h"
5d7836c4 30
5d7836c4
JS
31#include "wx/richtext/richtextctrl.h"
32
33IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject)
34IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition)
35IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition)
38f833b1 36IMPLEMENT_CLASS(wxRichTextListStyleDefinition, wxRichTextParagraphStyleDefinition)
603f702b 37IMPLEMENT_CLASS(wxRichTextBoxStyleDefinition, wxRichTextStyleDefinition)
5d7836c4 38
fe5aa22c
JS
39/*!
40 * A definition
41 */
42
43void wxRichTextStyleDefinition::Copy(const wxRichTextStyleDefinition& def)
44{
45 m_name = def.m_name;
46 m_baseStyle = def.m_baseStyle;
47 m_style = def.m_style;
42688aea 48 m_description = def.m_description;
c6182d48 49 m_properties = def.m_properties;
fe5aa22c
JS
50}
51
52bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition& def) const
53{
c6182d48 54 return (m_name == def.m_name && m_baseStyle == def.m_baseStyle && m_style == def.m_style && m_properties == def.m_properties);
fe5aa22c
JS
55}
56
336d8ae9 57/// Gets the style combined with the base style
24777478 58wxRichTextAttr wxRichTextStyleDefinition::GetStyleMergedWithBase(const wxRichTextStyleSheet* sheet) const
336d8ae9 59{
519884a0
JS
60 if (m_baseStyle.IsEmpty())
61 return m_style;
ce00f59b 62
80a46597
VZ
63 bool isParaStyle = IsKindOf(wxCLASSINFO(wxRichTextParagraphStyleDefinition));
64 bool isCharStyle = IsKindOf(wxCLASSINFO(wxRichTextCharacterStyleDefinition));
65 bool isListStyle = IsKindOf(wxCLASSINFO(wxRichTextListStyleDefinition));
66 bool isBoxStyle = IsKindOf(wxCLASSINFO(wxRichTextBoxStyleDefinition));
6d531430 67
519884a0
JS
68 // Collect the styles, detecting loops
69 wxArrayString styleNames;
70 wxList styles;
71 const wxRichTextStyleDefinition* def = this;
72 while (def)
336d8ae9 73 {
519884a0
JS
74 styles.Insert((wxObject*) def);
75 styleNames.Add(def->GetName());
ce00f59b 76
519884a0
JS
77 wxString baseStyleName = def->GetBaseStyle();
78 if (!baseStyleName.IsEmpty() && styleNames.Index(baseStyleName) == wxNOT_FOUND)
6d531430
JS
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 }
519884a0
JS
91 else
92 def = NULL;
336d8ae9 93 }
ce00f59b 94
519884a0
JS
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 }
ce00f59b 103
519884a0 104 return attr;
336d8ae9
VZ
105}
106
fe5aa22c
JS
107/*!
108 * Paragraph style definition
109 */
110
111void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition& def)
112{
113 wxRichTextStyleDefinition::Copy(def);
114
115 m_nextStyle = def.m_nextStyle;
116}
117
118bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition& def) const
119{
120 return (Eq(def) && m_nextStyle == def.m_nextStyle);
121}
122
603f702b
JS
123/*!
124 * Box style definition
125 */
126
127void wxRichTextBoxStyleDefinition::Copy(const wxRichTextBoxStyleDefinition& def)
128{
129 wxRichTextStyleDefinition::Copy(def);
130}
131
132bool wxRichTextBoxStyleDefinition::operator ==(const wxRichTextBoxStyleDefinition& def) const
133{
134 return (Eq(def));
135}
136
38f833b1
JS
137/*!
138 * List style definition
139 */
140
141void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition& def)
142{
143 wxRichTextParagraphStyleDefinition::Copy(def);
41a85215 144
38f833b1
JS
145 int i;
146 for (i = 0; i < 10; i++)
147 m_levelStyles[i] = def.m_levelStyles[i];
148}
149
150bool 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;
41a85215 158
38f833b1
JS
159 return true;
160}
161
162/// Sets/gets the attributes for the given level
24777478 163void wxRichTextListStyleDefinition::SetLevelAttributes(int i, const wxRichTextAttr& attr)
38f833b1
JS
164{
165 wxASSERT( (i >= 0 && i < 10) );
166 if (i >= 0 && i < 10)
167 m_levelStyles[i] = attr;
168}
169
24777478 170const wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i) const
38f833b1
JS
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
24777478 179wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i)
38f833b1
JS
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
189void 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 {
24777478 194 wxRichTextAttr attr;
41a85215 195
38f833b1
JS
196 attr.SetBulletStyle(bulletStyle);
197 attr.SetLeftIndent(leftIndent, leftSubIndent);
198
199 if (!bulletSymbol.IsEmpty())
d2d0adc7
JS
200 {
201 if (bulletStyle & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)
202 attr.SetBulletText(bulletSymbol);
203 else
204 attr.SetBulletName(bulletSymbol);
205 }
41a85215
WS
206
207 m_levelStyles[i] = attr;
208 }
38f833b1
JS
209}
210
211/// Finds the level corresponding to the given indentation
212int 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)
24777478 230wxRichTextAttr wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent, const wxRichTextAttr& paraStyle, wxRichTextStyleSheet* styleSheet)
38f833b1
JS
231{
232 int listLevel = FindLevelForIndent(indent);
41a85215 233
24777478 234 wxRichTextAttr attr(*GetLevelAttributes(listLevel));
38f833b1
JS
235 int oldLeftIndent = attr.GetLeftIndent();
236 int oldLeftSubIndent = attr.GetLeftSubIndent();
237
41a85215 238 // First apply the overall paragraph style, if any
336d8ae9
VZ
239 if (styleSheet)
240 attr.Apply(GetStyleMergedWithBase(styleSheet));
241 else
242 attr.Apply(GetStyle());
38f833b1
JS
243
244 // Then apply paragraph style, e.g. from paragraph style definition
336d8ae9 245 attr.Apply(paraStyle);
41a85215 246
38f833b1
JS
247 // We override the indents according to the list definition
248 attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
41a85215 249
38f833b1
JS
250 return attr;
251}
252
253/// Combine the base and list style, using the given indent (from which
254/// an appropriate level is found)
24777478 255wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyle(int indent, wxRichTextStyleSheet* styleSheet)
38f833b1
JS
256{
257 int listLevel = FindLevelForIndent(indent);
336d8ae9 258 return GetCombinedStyleForLevel(listLevel, styleSheet);
38f833b1
JS
259}
260
261/// Combine the base and list style, using the given indent (from which
262/// an appropriate level is found)
24777478 263wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel, wxRichTextStyleSheet* styleSheet)
38f833b1 264{
24777478 265 wxRichTextAttr attr(*GetLevelAttributes(listLevel));
38f833b1
JS
266 int oldLeftIndent = attr.GetLeftIndent();
267 int oldLeftSubIndent = attr.GetLeftSubIndent();
268
41a85215 269 // Apply the overall paragraph style, if any
336d8ae9
VZ
270 if (styleSheet)
271 attr.Apply(GetStyleMergedWithBase(styleSheet));
272 else
273 attr.Apply(GetStyle());
38f833b1
JS
274
275 // We override the indents according to the list definition
276 attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
41a85215 277
38f833b1
JS
278 return attr;
279}
280
281/// Is this a numbered list?
282bool 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
5d7836c4
JS
289/*!
290 * The style manager
291 */
292
293IMPLEMENT_CLASS(wxRichTextStyleSheet, wxObject)
294
38f833b1
JS
295wxRichTextStyleSheet::~wxRichTextStyleSheet()
296{
297 DeleteStyles();
298
299 if (m_nextSheet)
300 m_nextSheet->m_previousSheet = m_previousSheet;
41a85215 301
38f833b1
JS
302 if (m_previousSheet)
303 m_previousSheet->m_nextSheet = m_nextSheet;
41a85215 304
38f833b1
JS
305 m_previousSheet = NULL;
306 m_nextSheet = NULL;
307}
308
5d7836c4
JS
309/// Initialisation
310void wxRichTextStyleSheet::Init()
311{
38f833b1
JS
312 m_previousSheet = NULL;
313 m_nextSheet = NULL;
5d7836c4
JS
314}
315
316/// Add a definition to one of the style lists
317bool 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
325bool wxRichTextStyleSheet::RemoveStyle(wxList& list, wxRichTextStyleDefinition* def, bool deleteStyle)
326{
09f14108 327 wxList::compatibility_iterator node = list.Find(def);
5d7836c4
JS
328 if (node)
329 {
330 wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
09f14108 331 list.Erase(node);
5d7836c4
JS
332 if (deleteStyle)
333 delete def;
334 return true;
335 }
336 else
337 return false;
338}
339
336d8ae9
VZ
340/// Remove a style
341bool 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;
603f702b
JS
349 if (RemoveBoxStyle(def, deleteStyle))
350 return true;
336d8ae9
VZ
351 return false;
352}
353
5d7836c4 354/// Find a definition by name
38f833b1 355wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name, bool recurse) const
5d7836c4 356{
09f14108 357 for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
5d7836c4
JS
358 {
359 wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
23a9a87c 360 if (def->GetName() == name)
5d7836c4
JS
361 return def;
362 }
41a85215 363
38f833b1
JS
364 if (m_nextSheet && recurse)
365 return m_nextSheet->FindStyle(list, name, recurse);
366
61399247 367 return NULL;
5d7836c4
JS
368}
369
370/// Delete all styles
371void wxRichTextStyleSheet::DeleteStyles()
372{
373 WX_CLEAR_LIST(wxList, m_characterStyleDefinitions);
374 WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
38f833b1 375 WX_CLEAR_LIST(wxList, m_listStyleDefinitions);
603f702b 376 WX_CLEAR_LIST(wxList, m_boxStyleDefinitions);
38f833b1
JS
377}
378
379/// Insert into list of style sheets
380bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet* before)
381{
382 m_previousSheet = before->m_previousSheet;
383 m_nextSheet = before;
41a85215 384
38f833b1
JS
385 before->m_previousSheet = this;
386 return true;
387}
388
389/// Append to list of style sheets
390bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet* after)
391{
392 wxRichTextStyleSheet* last = after;
393 while (last && last->m_nextSheet)
394 {
395 last = last->m_nextSheet;
396 }
41a85215 397
38f833b1
JS
398 if (last)
399 {
400 m_previousSheet = last;
401 last->m_nextSheet = this;
41a85215 402
38f833b1
JS
403 return true;
404 }
405 else
406 return false;
407}
408
409/// Unlink from the list of style sheets
410void 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;
41a85215 416
38f833b1
JS
417 m_previousSheet = NULL;
418 m_nextSheet = NULL;
5d7836c4
JS
419}
420
fe5aa22c
JS
421/// Add a definition to the character style list
422bool 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
429bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition* def)
430{
431 def->GetStyle().SetParagraphStyleName(def->GetName());
432 return AddStyle(m_paragraphStyleDefinitions, def);
433}
434
38f833b1
JS
435/// Add a definition to the list style list
436bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition* def)
437{
438 def->GetStyle().SetListStyleName(def->GetName());
439 return AddStyle(m_listStyleDefinitions, def);
440}
441
603f702b
JS
442/// Add a definition to the box style list
443bool wxRichTextStyleSheet::AddBoxStyle(wxRichTextBoxStyleDefinition* def)
444{
1199fbd4 445 def->GetStyle().GetTextBoxAttr().SetBoxStyleName(def->GetName());
603f702b
JS
446 return AddStyle(m_boxStyleDefinitions, def);
447}
448
336d8ae9
VZ
449/// Add a definition to the appropriate style list
450bool 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);
3706bae0 463
603f702b
JS
464 wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition);
465 if (boxDef)
466 return AddBoxStyle(boxDef);
467
336d8ae9
VZ
468 return false;
469}
470
471/// Find any definition by name
472wxRichTextStyleDefinition* 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;
3706bae0 485
603f702b
JS
486 wxRichTextBoxStyleDefinition* boxDef = FindBoxStyle(name, recurse);
487 if (boxDef)
488 return boxDef;
489
3706bae0 490 return NULL;
336d8ae9
VZ
491}
492
fe5aa22c
JS
493/// Copy
494void 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 }
38f833b1
JS
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 }
3706bae0 517
603f702b
JS
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
42688aea
JS
524 SetName(sheet.GetName());
525 SetDescription(sheet.GetDescription());
c6182d48 526 m_properties = sheet.m_properties;
fe5aa22c
JS
527}
528
529/// Equality
530bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
531{
532 // TODO
533 return false;
534}
535
536
5d7836c4 537#if wxUSE_HTML
6d531430
JS
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.
542static wxString wxGetRichTextStyleType(const wxString& style)
543{
544 return style.AfterLast(wxT('|'));
545}
546
547static wxString wxGetRichTextStyle(const wxString& style)
548{
549 return style.BeforeLast(wxT('|'));
550}
551
552
5d7836c4 553/*!
38f833b1 554 * wxRichTextStyleListBox: a listbox to display styles.
5d7836c4
JS
555 */
556
557IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
558
559BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
5d7836c4 560 EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown)
38f833b1 561 EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick)
e637208a 562 EVT_IDLE(wxRichTextStyleListBox::OnIdle)
5d7836c4
JS
563END_EVENT_TABLE()
564
565wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
e637208a 566 const wxSize& size, long style)
5d7836c4 567{
e637208a
JS
568 Init();
569 Create(parent, id, pos, size, style);
570}
571
572bool 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);
5d7836c4
JS
576}
577
578wxRichTextStyleListBox::~wxRichTextStyleListBox()
579{
580}
581
582/// Returns the HTML for this item
583wxString wxRichTextStyleListBox::OnGetItem(size_t n) const
584{
585 if (!GetStyleSheet())
586 return wxEmptyString;
41a85215 587
38f833b1
JS
588 wxRichTextStyleDefinition* def = GetStyle(n);
589 if (def)
590 return CreateHTML(def);
5d7836c4 591
5d7836c4
JS
592 return wxEmptyString;
593}
594
595// Get style for index
596wxRichTextStyleDefinition* wxRichTextStyleListBox::GetStyle(size_t i) const
597{
598 if (!GetStyleSheet())
599 return NULL;
3706bae0 600
8a8e9df8 601 if (i >= m_styleNames.GetCount() /* || i < 0 */ )
486dd03a 602 return NULL;
5d7836c4 603
6d531430
JS
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);
5d7836c4
JS
616}
617
618/// Updates the list
619void wxRichTextStyleListBox::UpdateStyles()
620{
621 if (GetStyleSheet())
622 {
02aa812c
JS
623 int oldSel = GetSelection();
624
dadd4f55 625 SetSelection(wxNOT_FOUND);
3706bae0 626
486dd03a 627 m_styleNames.Clear();
3706bae0 628
486dd03a
JS
629 size_t i;
630 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
631 {
632 for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
6d531430 633 m_styleNames.Add(GetStyleSheet()->GetParagraphStyle(i)->GetName() + wxT("|P"));
486dd03a
JS
634 }
635 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
636 {
637 for (i = 0; i < GetStyleSheet()->GetCharacterStyleCount(); i++)
6d531430 638 m_styleNames.Add(GetStyleSheet()->GetCharacterStyle(i)->GetName() + wxT("|C"));
486dd03a
JS
639 }
640 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_LIST)
641 {
642 for (i = 0; i < GetStyleSheet()->GetListStyleCount(); i++)
6d531430 643 m_styleNames.Add(GetStyleSheet()->GetListStyle(i)->GetName() + wxT("|L"));
486dd03a 644 }
603f702b
JS
645 if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_BOX)
646 {
647 for (i = 0; i < GetStyleSheet()->GetBoxStyleCount(); i++)
6d531430 648 m_styleNames.Add(GetStyleSheet()->GetBoxStyle(i)->GetName() + wxT("|B"));
603f702b 649 }
3706bae0 650
486dd03a
JS
651 m_styleNames.Sort();
652 SetItemCount(m_styleNames.GetCount());
41a85215 653
5d7836c4 654 Refresh();
dadd4f55 655
02aa812c
JS
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)
dadd4f55 663 {
02aa812c 664 SetSelection(newSel);
dadd4f55 665 SendSelectedEvent();
41a85215 666 }
5d7836c4 667 }
3ef12fd2
JS
668 else
669 {
670 m_styleNames.Clear();
671 SetSelection(wxNOT_FOUND);
672 SetItemCount(0);
673 Refresh();
674 }
5d7836c4
JS
675}
676
e637208a
JS
677// Get index for style name
678int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const
679{
6d531430
JS
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);
e637208a
JS
701}
702
703/// Set selection for string
704int wxRichTextStyleListBox::SetStyleSelection(const wxString& name)
705{
706 int i = GetIndexForStyle(name);
707 if (i > -1)
be8d847d 708 {
e637208a 709 SetSelection(i);
be8d847d 710 if (!IsVisible(i))
14722c43 711 ScrollToRow(i);
be8d847d 712 }
e637208a
JS
713 return i;
714}
715
5d7836c4
JS
716// Convert a colour to a 6-digit hex string
717static 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
729wxString wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition* def) const
730{
38f833b1
JS
731 // TODO: indicate list format for list style types
732
380a5dd8
JS
733 wxString str;
734
735 bool isCentred = false;
3706bae0 736
24777478 737 wxRichTextAttr attr(def->GetStyleMergedWithBase(GetStyleSheet()));
380a5dd8 738
336d8ae9 739 if (attr.HasAlignment() && attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
380a5dd8
JS
740 isCentred = true;
741
8836dcaa
JS
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
380a5dd8
JS
748 if (isCentred)
749 str << wxT("<center>");
750
8836dcaa
JS
751 str << wxT("<table");
752 if (attr.GetBackgroundColour().Ok())
753 str << wxT(" bgcolor=\"#") << ColourToHexString(attr.GetBackgroundColour()) << wxT("\"");
3706bae0 754
8836dcaa 755 str << wxT("><tr>");
5d7836c4 756
336d8ae9 757 if (attr.GetLeftIndent() > 0)
5d7836c4
JS
758 {
759 wxClientDC dc((wxWindow*) this);
760
336d8ae9 761 str << wxT("<td width=") << wxMin(50, (ConvertTenthsMMToPixels(dc, attr.GetLeftIndent())/2)) << wxT("></td>");
5d7836c4
JS
762 }
763
380a5dd8
JS
764 if (isCentred)
765 str << wxT("<td nowrap align=\"center\">");
766 else
767 str << wxT("<td nowrap>");
5d7836c4 768
dadd4f55 769#ifdef __WXMSW__
e2d0875a 770 int size = 2;
dadd4f55 771#else
e2d0875a 772 int size = 3;
dadd4f55
JS
773#endif
774
03647350 775 // Guess a standard font size
e2d0875a
JS
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;
6d531430 782 for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
e2d0875a 783 {
6d531430
JS
784 wxRichTextStyleDefinition* d = GetStyleSheet()->GetParagraphStyle(i);
785 wxString name = d->GetName().Lower();
03647350 786 if (name.Find(wxT("normal")) != wxNOT_FOUND || name.Find(normalTranslated) != wxNOT_FOUND ||
6d531430 787 name.Find(wxT("default")) != wxNOT_FOUND || name.Find(defaultTranslated) != wxNOT_FOUND)
03647350 788 {
6d531430 789 wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
32423dd8 790 if (attr2.HasFontPointSize())
03647350 791 {
6d531430
JS
792 stdFontSize = attr2.GetFontSize();
793 break;
03647350
VZ
794 }
795 }
796 }
e2d0875a
JS
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 {
6d531430 807 wxRichTextStyleDefinition* d = GetStyle(i);
e2d0875a
JS
808 if (d)
809 {
810 wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
32423dd8 811 if (attr2.HasFontPointSize())
e2d0875a
JS
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;
03647350 823 }
e2d0875a
JS
824 if (mostCommonSize > 0)
825 stdFontSize = mostCommonSize;
826 }
827
828 if (stdFontSize == 0)
03647350 829 stdFontSize = 12;
e2d0875a 830
32423dd8 831 int thisFontSize = attr.HasFontPointSize() ? attr.GetFontSize() : stdFontSize;
5d7836c4 832
dadd4f55 833 if (thisFontSize < stdFontSize)
dadd4f55 834 size --;
e2d0875a
JS
835 else if (thisFontSize > stdFontSize)
836 size ++;
5d7836c4
JS
837
838 str += wxT("<font");
839
840 str << wxT(" size=") << size;
841
336d8ae9
VZ
842 if (!attr.GetFontFaceName().IsEmpty())
843 str << wxT(" face=\"") << attr.GetFontFaceName() << wxT("\"");
5d7836c4 844
a1b806b9 845 if (attr.GetTextColour().IsOk())
336d8ae9 846 str << wxT(" color=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
5d7836c4 847
8836dcaa
JS
848 if (attr.GetBackgroundColour().Ok())
849 str << wxT(" bgcolor=\"#") << ColourToHexString(attr.GetBackgroundColour()) << wxT("\"");
850
5d7836c4
JS
851 str << wxT(">");
852
853 bool hasBold = false;
854 bool hasItalic = false;
855 bool hasUnderline = false;
856
43f4e852 857 if (attr.GetFontWeight() == wxFONTWEIGHT_BOLD)
5d7836c4 858 hasBold = true;
43f4e852 859 if (attr.GetFontStyle() == wxFONTSTYLE_ITALIC)
5d7836c4 860 hasItalic = true;
336d8ae9 861 if (attr.GetFontUnderlined())
5d7836c4
JS
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
380a5dd8
JS
880 if (isCentred)
881 str << wxT("</centre>");
882
5d7836c4
JS
883 str << wxT("</font>");
884
380a5dd8
JS
885 str << wxT("</td></tr></table>");
886
887 if (isCentred)
888 str << wxT("</center>");
889
8836dcaa 890 str << wxT("</body></html>");
5d7836c4
JS
891 return str;
892}
893
894// Convert units in tends of a millimetre to device units
895int 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
5d7836c4
JS
906void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
907{
908 wxVListBox::OnLeftDown(event);
909
6eff83b8 910 int item = VirtualHitTest(event.GetPosition().y);
86015e55
JS
911 if (item != wxNOT_FOUND && GetApplyOnSelection())
912 ApplyStyle(item);
e637208a 913}
5d7836c4 914
38f833b1 915void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent& event)
e637208a 916{
38f833b1 917 wxVListBox::OnLeftDown(event);
fe5aa22c 918
6eff83b8 919 int item = VirtualHitTest(event.GetPosition().y);
38f833b1
JS
920 if (item != wxNOT_FOUND && !GetApplyOnSelection())
921 ApplyStyle(item);
922}
e637208a 923
38f833b1
JS
924/// Helper for listbox and combo control
925wxString wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl* ctrl, wxRichTextStyleType styleType)
926{
927 int adjustedCaretPos = ctrl->GetAdjustedCaretPosition(ctrl->GetCaretPosition());
e637208a 928
38f833b1
JS
929 wxString styleName;
930
24777478 931 wxRichTextAttr attr;
3f239e37
JS
932 ctrl->GetStyle(adjustedCaretPos, attr);
933
38f833b1
JS
934 // Take into account current default style just chosen by user
935 if (ctrl->IsDefaultStyleShowing())
936 {
3706bae0
JS
937 wxRichTextApplyStyle(attr, ctrl->GetDefaultStyleEx());
938
38f833b1 939 if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
3706bae0
JS
940 !attr.GetCharacterStyleName().IsEmpty())
941 styleName = attr.GetCharacterStyleName();
38f833b1 942 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
3706bae0
JS
943 !attr.GetParagraphStyleName().IsEmpty())
944 styleName = attr.GetParagraphStyleName();
38f833b1 945 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
3706bae0
JS
946 !attr.GetListStyleName().IsEmpty())
947 styleName = attr.GetListStyleName();
603f702b
JS
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
38f833b1 955 }
3f239e37
JS
956 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
957 !attr.GetCharacterStyleName().IsEmpty())
38f833b1 958 {
3f239e37 959 styleName = attr.GetCharacterStyleName();
38f833b1 960 }
3f239e37
JS
961 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
962 !attr.GetParagraphStyleName().IsEmpty())
38f833b1 963 {
3f239e37 964 styleName = attr.GetParagraphStyleName();
38f833b1 965 }
3f239e37
JS
966 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
967 !attr.GetListStyleName().IsEmpty())
38f833b1 968 {
3f239e37 969 styleName = attr.GetListStyleName();
38f833b1 970 }
41a85215 971
38f833b1
JS
972 return styleName;
973}
974
975/// Auto-select from style under caret in idle time
976void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
977{
3570a1c6 978 if (CanAutoSetSelection() && GetRichTextCtrl() && IsShownOnScreen() && wxWindow::FindFocus() != this)
38f833b1
JS
979 {
980 wxString styleName = GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
61399247 981
e637208a
JS
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;
5d7836c4 988
e637208a
JS
989 SetStyleSelection(styleName);
990 }
991 else if (sel != -1)
992 SetSelection(-1);
993 }
994 event.Skip();
995}
5d7836c4 996
e637208a 997/// Do selection
86015e55 998void wxRichTextStyleListBox::ApplyStyle(int item)
e637208a
JS
999{
1000 if ( item != wxNOT_FOUND )
1001 {
1002 wxRichTextStyleDefinition* def = GetStyle(item);
1003 if (def && GetRichTextCtrl())
1004 {
1005 GetRichTextCtrl()->ApplyStyle(def);
1006 GetRichTextCtrl()->SetFocus();
5d7836c4
JS
1007 }
1008 }
1009}
1010
38f833b1
JS
1011/*!
1012 * wxRichTextStyleListCtrl class: manages a listbox and a choice control to
1013 * switch shown style types
1014 */
1015
1016IMPLEMENT_CLASS(wxRichTextStyleListCtrl, wxControl)
1017
1018BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl, wxControl)
1019 EVT_CHOICE(wxID_ANY, wxRichTextStyleListCtrl::OnChooseType)
1020 EVT_SIZE(wxRichTextStyleListCtrl::OnSize)
1021END_EVENT_TABLE()
1022
1023wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
1024 const wxSize& size, long style)
5d7836c4 1025{
38f833b1
JS
1026 Init();
1027 Create(parent, id, pos, size, style);
5d7836c4
JS
1028}
1029
38f833b1
JS
1030bool wxRichTextStyleListCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
1031 const wxSize& size, long style)
5d7836c4 1032{
2fce6547
JS
1033 if ((style & wxBORDER_MASK) == wxBORDER_DEFAULT)
1034 style |= wxBORDER_THEME;
1035
38f833b1 1036 wxControl::Create(parent, id, pos, size, style);
41a85215 1037
38f833b1 1038 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
dadd4f55 1039 if (size != wxDefaultSize)
170acdc9 1040 SetInitialSize(size);
41a85215 1041
dadd4f55 1042 bool showSelector = ((style & wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR) == 0);
41a85215 1043
2fce6547
JS
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);
dadd4f55
JS
1051
1052 wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
41a85215 1053
dadd4f55 1054 if (showSelector)
41a85215 1055 {
dadd4f55
JS
1056 wxArrayString choices;
1057 choices.Add(_("All styles"));
1058 choices.Add(_("Paragraph styles"));
1059 choices.Add(_("Character styles"));
1060 choices.Add(_("List styles"));
603f702b 1061 choices.Add(_("Box styles"));
41a85215 1062
dadd4f55 1063 m_styleChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
41a85215 1064
dadd4f55 1065 boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 5);
a047aff2 1066 boxSizer->Add(m_styleChoice, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5);
dadd4f55
JS
1067 }
1068 else
1069 {
1070 boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 0);
1071 }
41a85215 1072
dadd4f55
JS
1073 SetSizer(boxSizer);
1074 Layout();
38f833b1
JS
1075
1076 m_dontUpdate = true;
dadd4f55
JS
1077
1078 if (m_styleChoice)
41a85215 1079 {
dadd4f55
JS
1080 int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
1081 m_styleChoice->SetSelection(i);
1082 }
41a85215 1083
38f833b1 1084 m_dontUpdate = false;
41a85215 1085
38f833b1
JS
1086 return true;
1087}
1088
1089wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
1090{
41a85215 1091
38f833b1
JS
1092}
1093
1094/// React to style type choice
1095void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent& event)
1096{
1097 if (event.GetEventObject() != m_styleChoice)
1098 event.Skip();
1099 else
1100 {
1101 if (m_dontUpdate)
1102 return;
41a85215 1103
38f833b1 1104 wxRichTextStyleListBox::wxRichTextStyleType styleType = StyleIndexToType(event.GetSelection());
02aa812c 1105 m_styleListBox->SetSelection(-1);
38f833b1
JS
1106 m_styleListBox->SetStyleType(styleType);
1107 }
1108}
1109
1110/// Lay out the controls
1111void wxRichTextStyleListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
1112{
1113 if (GetAutoLayout())
1114 Layout();
1115}
1116
1117/// Get the choice index for style type
1118int 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 }
603f702b
JS
1136 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX)
1137 {
1138 return 4;
1139 }
38f833b1
JS
1140 return 0;
1141}
1142
1143/// Get the style type for choice index
1144wxRichTextStyleListBox::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;
603f702b
JS
1152 else if (i == 4)
1153 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX;
38f833b1
JS
1154
1155 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
1156}
1157
1158/// Associates the control with a style manager
1159void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet* styleSheet)
1160{
1161 if (m_styleListBox)
1162 m_styleListBox->SetStyleSheet(styleSheet);
1163}
1164
1165wxRichTextStyleSheet* 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
1174void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl* ctrl)
1175{
1176 if (m_styleListBox)
1177 m_styleListBox->SetRichTextCtrl(ctrl);
1178}
1179
1180wxRichTextCtrl* 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
1189void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType)
1190{
cd5dea50
VZ
1191 if ( !m_styleListBox )
1192 return;
1193
1194 m_styleListBox->SetStyleType(styleType);
38f833b1
JS
1195
1196 m_dontUpdate = true;
1197
1198 if (m_styleChoice)
41a85215 1199 {
38f833b1
JS
1200 int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
1201 m_styleChoice->SetSelection(i);
1202 }
41a85215 1203
38f833b1
JS
1204 m_dontUpdate = false;
1205}
1206
1207wxRichTextStyleListBox::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
1216void wxRichTextStyleListCtrl::UpdateStyles()
1217{
1218 if (m_styleListBox)
41a85215 1219 m_styleListBox->UpdateStyles();
5d7836c4 1220}
5d7836c4 1221
e637208a
JS
1222#if wxUSE_COMBOCTRL
1223
1224/*!
1225 * Style drop-down for a wxComboCtrl
1226 */
1227
1228
1229BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup, wxRichTextStyleListBox)
1230 EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove)
1231 EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick)
1232END_EVENT_TABLE()
1233
a047aff2
JS
1234bool wxRichTextStyleComboPopup::Create( wxWindow* parent )
1235{
44cc96a8 1236 int borderStyle = GetDefaultBorder();
9b794421
JS
1237 if (borderStyle == wxBORDER_SUNKEN || borderStyle == wxBORDER_NONE)
1238 borderStyle = wxBORDER_THEME;
a047aff2
JS
1239
1240 return wxRichTextStyleListBox::Create(parent, wxID_ANY,
1241 wxPoint(0,0), wxDefaultSize,
1242 borderStyle);
1243}
1244
e637208a
JS
1245void wxRichTextStyleComboPopup::SetStringValue( const wxString& s )
1246{
1247 m_value = SetStyleSelection(s);
1248}
1249
1250wxString 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
1267void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent& event)
1268{
1269 // Move selection to cursor if it is inside the popup
1270
6eff83b8 1271 int itemHere = wxRichTextStyleListBox::VirtualHitTest(event.GetPosition().y);
e637208a
JS
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
1281void 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
86015e55 1287 // by setting the focus elsewhere e.g. in ApplyStyle
e637208a
JS
1288 Dismiss();
1289
1290 if (m_itemHere >= 0)
86015e55 1291 wxRichTextStyleListBox::ApplyStyle(m_itemHere);
e637208a
JS
1292}
1293
1294/*!
1295 * wxRichTextStyleComboCtrl
1296 * A combo for applying styles.
1297 */
1298
1299IMPLEMENT_CLASS(wxRichTextStyleComboCtrl, wxComboCtrl)
1300
1301BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl, wxComboCtrl)
1302 EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle)
1303END_EVENT_TABLE()
1304
1305bool 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
1333void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent& event)
1334{
ecb7235d
VZ
1335 event.Skip();
1336
1337 if ( !m_stylePopup )
1338 return;
1339
1340 wxRichTextCtrl * const richtext = GetRichTextCtrl();
1341 if ( !richtext )
1342 return;
1343
3570a1c6 1344 if ( !IsPopupShown() && IsShownOnScreen() && wxWindow::FindFocus() != this )
e637208a 1345 {
ecb7235d
VZ
1346 wxString styleName =
1347 wxRichTextStyleListBox::GetStyleToShowInIdleTime(richtext, m_stylePopup->GetStyleType());
41a85215 1348
e637208a
JS
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 }
e637208a
JS
1361}
1362
1363#endif
1364 // wxUSE_COMBOCTRL
1365
5d7836c4
JS
1366#endif
1367 // wxUSE_HTML
1368
1369#endif
1370 // wxUSE_RICHTEXT