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