Added a couple of text effects
[wxWidgets.git] / src / richtext / richtextstyles.cpp
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 // RCS-ID: $Id$
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__
16 #pragma hdrstop
17 #endif
18
19 #if wxUSE_RICHTEXT
20
21 #include "wx/richtext/richtextstyles.h"
22
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #include "wx/filename.h"
28 #include "wx/clipbrd.h"
29 #include "wx/wfstream.h"
30 #include "wx/settings.h"
31
32 #include "wx/richtext/richtextctrl.h"
33
34 IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject)
35 IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition)
36 IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition)
37 IMPLEMENT_CLASS(wxRichTextListStyleDefinition, wxRichTextParagraphStyleDefinition)
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 }
50
51 bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition& def) const
52 {
53 return (m_name == def.m_name && m_baseStyle == def.m_baseStyle && m_style == def.m_style);
54 }
55
56 /*!
57 * Paragraph style definition
58 */
59
60 void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition& def)
61 {
62 wxRichTextStyleDefinition::Copy(def);
63
64 m_nextStyle = def.m_nextStyle;
65 }
66
67 bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition& def) const
68 {
69 return (Eq(def) && m_nextStyle == def.m_nextStyle);
70 }
71
72 /*!
73 * List style definition
74 */
75
76 void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition& def)
77 {
78 wxRichTextParagraphStyleDefinition::Copy(def);
79
80 int i;
81 for (i = 0; i < 10; i++)
82 m_levelStyles[i] = def.m_levelStyles[i];
83 }
84
85 bool wxRichTextListStyleDefinition::operator ==(const wxRichTextListStyleDefinition& def) const
86 {
87 if (!Eq(def))
88 return false;
89 int i;
90 for (i = 0; i < 10; i++)
91 if (!(m_levelStyles[i] == def.m_levelStyles[i]))
92 return false;
93
94 return true;
95 }
96
97 /// Sets/gets the attributes for the given level
98 void wxRichTextListStyleDefinition::SetLevelAttributes(int i, const wxRichTextAttr& attr)
99 {
100 wxASSERT( (i >= 0 && i < 10) );
101 if (i >= 0 && i < 10)
102 m_levelStyles[i] = attr;
103 }
104
105 const wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i) const
106 {
107 wxASSERT( (i >= 0 && i < 10) );
108 if (i >= 0 && i < 10)
109 return & m_levelStyles[i];
110 else
111 return NULL;
112 }
113
114 wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i)
115 {
116 wxASSERT( (i >= 0 && i < 10) );
117 if (i >= 0 && i < 10)
118 return & m_levelStyles[i];
119 else
120 return NULL;
121 }
122
123 /// Convenience function for setting the major attributes for a list level specification
124 void wxRichTextListStyleDefinition::SetAttributes(int i, int leftIndent, int leftSubIndent, int bulletStyle, const wxString& bulletSymbol)
125 {
126 wxASSERT( (i >= 0 && i < 10) );
127 if (i >= 0 && i < 10)
128 {
129 wxRichTextAttr attr;
130
131 attr.SetBulletStyle(bulletStyle);
132 attr.SetLeftIndent(leftIndent, leftSubIndent);
133
134 if (!bulletSymbol.IsEmpty())
135 {
136 if (bulletStyle & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)
137 attr.SetBulletText(bulletSymbol);
138 else
139 attr.SetBulletName(bulletSymbol);
140 }
141
142 m_levelStyles[i] = attr;
143 }
144 }
145
146 /// Finds the level corresponding to the given indentation
147 int wxRichTextListStyleDefinition::FindLevelForIndent(int indent) const
148 {
149 int i;
150 for (i = 0; i < 10; i++)
151 {
152 if (indent < m_levelStyles[i].GetLeftIndent())
153 {
154 if (i > 0)
155 return i - 1;
156 else
157 return 0;
158 }
159 }
160 return 9;
161 }
162
163 /// Combine the list style with a paragraph style, using the given indent (from which
164 /// an appropriate level is found)
165 wxRichTextAttr wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent, const wxRichTextAttr& paraStyle)
166 {
167 int listLevel = FindLevelForIndent(indent);
168
169 wxRichTextAttr attr(*GetLevelAttributes(listLevel));
170 int oldLeftIndent = attr.GetLeftIndent();
171 int oldLeftSubIndent = attr.GetLeftSubIndent();
172
173 // First apply the overall paragraph style, if any
174 wxRichTextApplyStyle(attr, GetStyle());
175
176 // Then apply paragraph style, e.g. from paragraph style definition
177 wxRichTextApplyStyle(attr, paraStyle);
178
179 // We override the indents according to the list definition
180 attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
181
182 return attr;
183 }
184
185 /// Combine the base and list style, using the given indent (from which
186 /// an appropriate level is found)
187 wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyle(int indent)
188 {
189 int listLevel = FindLevelForIndent(indent);
190 return GetCombinedStyleForLevel(listLevel);
191 }
192
193 /// Combine the base and list style, using the given indent (from which
194 /// an appropriate level is found)
195 wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel)
196 {
197 wxRichTextAttr attr(*GetLevelAttributes(listLevel));
198 int oldLeftIndent = attr.GetLeftIndent();
199 int oldLeftSubIndent = attr.GetLeftSubIndent();
200
201 // Apply the overall paragraph style, if any
202 wxRichTextApplyStyle(attr, GetStyle());
203
204 // We override the indents according to the list definition
205 attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
206
207 return attr;
208 }
209
210 /// Is this a numbered list?
211 bool wxRichTextListStyleDefinition::IsNumbered(int i) const
212 {
213 return (0 != (GetLevelAttributes(i)->GetFlags() &
214 (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER|wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER|
215 wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER|wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)));
216 }
217
218 /*!
219 * The style manager
220 */
221
222 IMPLEMENT_CLASS(wxRichTextStyleSheet, wxObject)
223
224 wxRichTextStyleSheet::~wxRichTextStyleSheet()
225 {
226 DeleteStyles();
227
228 if (m_nextSheet)
229 m_nextSheet->m_previousSheet = m_previousSheet;
230
231 if (m_previousSheet)
232 m_previousSheet->m_nextSheet = m_nextSheet;
233
234 m_previousSheet = NULL;
235 m_nextSheet = NULL;
236 }
237
238 /// Initialisation
239 void wxRichTextStyleSheet::Init()
240 {
241 m_previousSheet = NULL;
242 m_nextSheet = NULL;
243 }
244
245 /// Add a definition to one of the style lists
246 bool wxRichTextStyleSheet::AddStyle(wxList& list, wxRichTextStyleDefinition* def)
247 {
248 if (!list.Find(def))
249 list.Append(def);
250 return true;
251 }
252
253 /// Remove a style
254 bool wxRichTextStyleSheet::RemoveStyle(wxList& list, wxRichTextStyleDefinition* def, bool deleteStyle)
255 {
256 wxList::compatibility_iterator node = list.Find(def);
257 if (node)
258 {
259 wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
260 list.Erase(node);
261 if (deleteStyle)
262 delete def;
263 return true;
264 }
265 else
266 return false;
267 }
268
269 /// Find a definition by name
270 wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name, bool recurse) const
271 {
272 for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
273 {
274 wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
275 if (def->GetName().Lower() == name.Lower())
276 return def;
277 }
278
279 if (m_nextSheet && recurse)
280 return m_nextSheet->FindStyle(list, name, recurse);
281
282 return NULL;
283 }
284
285 /// Delete all styles
286 void wxRichTextStyleSheet::DeleteStyles()
287 {
288 WX_CLEAR_LIST(wxList, m_characterStyleDefinitions);
289 WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
290 WX_CLEAR_LIST(wxList, m_listStyleDefinitions);
291 }
292
293 /// Insert into list of style sheets
294 bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet* before)
295 {
296 m_previousSheet = before->m_previousSheet;
297 m_nextSheet = before;
298
299 before->m_previousSheet = this;
300 return true;
301 }
302
303 /// Append to list of style sheets
304 bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet* after)
305 {
306 wxRichTextStyleSheet* last = after;
307 while (last && last->m_nextSheet)
308 {
309 last = last->m_nextSheet;
310 }
311
312 if (last)
313 {
314 m_previousSheet = last;
315 last->m_nextSheet = this;
316
317 return true;
318 }
319 else
320 return false;
321 }
322
323 /// Unlink from the list of style sheets
324 void wxRichTextStyleSheet::Unlink()
325 {
326 if (m_previousSheet)
327 m_previousSheet->m_nextSheet = m_nextSheet;
328 if (m_nextSheet)
329 m_nextSheet->m_previousSheet = m_previousSheet;
330
331 m_previousSheet = NULL;
332 m_nextSheet = NULL;
333 }
334
335 /// Add a definition to the character style list
336 bool wxRichTextStyleSheet::AddCharacterStyle(wxRichTextCharacterStyleDefinition* def)
337 {
338 def->GetStyle().SetCharacterStyleName(def->GetName());
339 return AddStyle(m_characterStyleDefinitions, def);
340 }
341
342 /// Add a definition to the paragraph style list
343 bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition* def)
344 {
345 def->GetStyle().SetParagraphStyleName(def->GetName());
346 return AddStyle(m_paragraphStyleDefinitions, def);
347 }
348
349 /// Add a definition to the list style list
350 bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition* def)
351 {
352 def->GetStyle().SetListStyleName(def->GetName());
353 return AddStyle(m_listStyleDefinitions, def);
354 }
355
356 /// Copy
357 void wxRichTextStyleSheet::Copy(const wxRichTextStyleSheet& sheet)
358 {
359 DeleteStyles();
360
361 wxList::compatibility_iterator node;
362
363 for (node = sheet.m_characterStyleDefinitions.GetFirst(); node; node = node->GetNext())
364 {
365 wxRichTextCharacterStyleDefinition* def = (wxRichTextCharacterStyleDefinition*) node->GetData();
366 AddCharacterStyle(new wxRichTextCharacterStyleDefinition(*def));
367 }
368
369 for (node = sheet.m_paragraphStyleDefinitions.GetFirst(); node; node = node->GetNext())
370 {
371 wxRichTextParagraphStyleDefinition* def = (wxRichTextParagraphStyleDefinition*) node->GetData();
372 AddParagraphStyle(new wxRichTextParagraphStyleDefinition(*def));
373 }
374
375 for (node = sheet.m_listStyleDefinitions.GetFirst(); node; node = node->GetNext())
376 {
377 wxRichTextListStyleDefinition* def = (wxRichTextListStyleDefinition*) node->GetData();
378 AddListStyle(new wxRichTextListStyleDefinition(*def));
379 }
380
381 SetName(sheet.GetName());
382 SetDescription(sheet.GetDescription());
383 }
384
385 /// Equality
386 bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
387 {
388 // TODO
389 return false;
390 }
391
392
393 #if wxUSE_HTML
394 /*!
395 * wxRichTextStyleListBox: a listbox to display styles.
396 */
397
398 IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
399
400 BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
401 EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown)
402 EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick)
403 EVT_IDLE(wxRichTextStyleListBox::OnIdle)
404 END_EVENT_TABLE()
405
406 wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
407 const wxSize& size, long style)
408 {
409 Init();
410 Create(parent, id, pos, size, style);
411 }
412
413 bool wxRichTextStyleListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
414 const wxSize& size, long style)
415 {
416 return wxHtmlListBox::Create(parent, id, pos, size, style);
417 }
418
419 wxRichTextStyleListBox::~wxRichTextStyleListBox()
420 {
421 }
422
423 /// Returns the HTML for this item
424 wxString wxRichTextStyleListBox::OnGetItem(size_t n) const
425 {
426 if (!GetStyleSheet())
427 return wxEmptyString;
428
429 wxRichTextStyleDefinition* def = GetStyle(n);
430 if (def)
431 return CreateHTML(def);
432
433 return wxEmptyString;
434 }
435
436 // Get style for index
437 wxRichTextStyleDefinition* wxRichTextStyleListBox::GetStyle(size_t i) const
438 {
439 if (!GetStyleSheet())
440 return NULL;
441
442 if (GetStyleType() == wxRICHTEXT_STYLE_ALL)
443 {
444 // First paragraph styles, then character, then list
445 if (i < GetStyleSheet()->GetParagraphStyleCount())
446 return GetStyleSheet()->GetParagraphStyle(i);
447
448 if ((i - GetStyleSheet()->GetParagraphStyleCount()) < GetStyleSheet()->GetCharacterStyleCount())
449 return GetStyleSheet()->GetCharacterStyle(i - GetStyleSheet()->GetParagraphStyleCount());
450
451 if ((i - GetStyleSheet()->GetParagraphStyleCount() - GetStyleSheet()->GetCharacterStyleCount()) < GetStyleSheet()->GetListStyleCount())
452 return GetStyleSheet()->GetListStyle(i - GetStyleSheet()->GetParagraphStyleCount() - GetStyleSheet()->GetCharacterStyleCount());
453 }
454 else if ((GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH) && (i < GetStyleSheet()->GetParagraphStyleCount()))
455 {
456 return GetStyleSheet()->GetParagraphStyle(i);
457 }
458 else if ((GetStyleType() == wxRICHTEXT_STYLE_CHARACTER) && (i < GetStyleSheet()->GetCharacterStyleCount()))
459 {
460 return GetStyleSheet()->GetCharacterStyle(i);
461 }
462 else if ((GetStyleType() == wxRICHTEXT_STYLE_LIST) && (i < GetStyleSheet()->GetListStyleCount()))
463 {
464 return GetStyleSheet()->GetListStyle(i);
465 }
466
467 return NULL;
468 }
469
470 /// Updates the list
471 void wxRichTextStyleListBox::UpdateStyles()
472 {
473 if (GetStyleSheet())
474 {
475 SetSelection(wxNOT_FOUND);
476
477 if (GetStyleType() == wxRICHTEXT_STYLE_ALL)
478 SetItemCount(GetStyleSheet()->GetParagraphStyleCount()+GetStyleSheet()->GetCharacterStyleCount()+GetStyleSheet()->GetListStyleCount());
479 else if (GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
480 SetItemCount(GetStyleSheet()->GetParagraphStyleCount());
481 else if (GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
482 SetItemCount(GetStyleSheet()->GetCharacterStyleCount());
483 else if (GetStyleType() == wxRICHTEXT_STYLE_LIST)
484 SetItemCount(GetStyleSheet()->GetListStyleCount());
485
486 Refresh();
487
488 if (GetItemCount() > 0)
489 {
490 SetSelection(0);
491 SendSelectedEvent();
492 }
493 }
494 }
495
496 // Get index for style name
497 int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const
498 {
499 if (GetStyleSheet())
500 {
501 int count = GetItemCount();
502
503 int i;
504 for (i = 0; i < (int) count; i++)
505 {
506 wxRichTextStyleDefinition* def = GetStyle(i);
507 if (def->GetName() == name)
508 return i;
509 }
510 }
511 return -1;
512 }
513
514 /// Set selection for string
515 int wxRichTextStyleListBox::SetStyleSelection(const wxString& name)
516 {
517 int i = GetIndexForStyle(name);
518 if (i > -1)
519 SetSelection(i);
520 return i;
521 }
522
523 // Convert a colour to a 6-digit hex string
524 static wxString ColourToHexString(const wxColour& col)
525 {
526 wxString hex;
527
528 hex += wxDecToHex(col.Red());
529 hex += wxDecToHex(col.Green());
530 hex += wxDecToHex(col.Blue());
531
532 return hex;
533 }
534
535 /// Creates a suitable HTML fragment for a definition
536 wxString wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition* def) const
537 {
538 // TODO: indicate list format for list style types
539
540 wxString str(wxT("<table><tr>"));
541
542 if (def->GetStyle().GetLeftIndent() > 0)
543 {
544 wxClientDC dc((wxWindow*) this);
545
546 str << wxT("<td width=") << (ConvertTenthsMMToPixels(dc, def->GetStyle().GetLeftIndent())/2) << wxT("></td>");
547 }
548
549 str << wxT("<td nowrap>");
550
551 #ifdef __WXMSW__
552 int size = 3;
553 #else
554 int size = 4;
555 #endif
556
557 int stdFontSize = 12;
558 int thisFontSize = ((def->GetStyle().GetFlags() & wxTEXT_ATTR_FONT_SIZE) != 0) ? def->GetStyle().GetFontSize() : stdFontSize;
559
560 if (thisFontSize < stdFontSize)
561 size ++;
562 else if (thisFontSize > stdFontSize)
563 size --;
564
565 str += wxT("<font");
566
567 str << wxT(" size=") << size;
568
569 if (!def->GetStyle().GetFontFaceName().IsEmpty())
570 str << wxT(" face=\"") << def->GetStyle().GetFontFaceName() << wxT("\"");
571
572 if (def->GetStyle().GetTextColour().Ok())
573 str << wxT(" color=\"#") << ColourToHexString(def->GetStyle().GetTextColour()) << wxT("\"");
574
575 str << wxT(">");
576
577 bool hasBold = false;
578 bool hasItalic = false;
579 bool hasUnderline = false;
580
581 if (def->GetStyle().GetFontWeight() == wxBOLD)
582 hasBold = true;
583 if (def->GetStyle().GetFontStyle() == wxITALIC)
584 hasItalic = true;
585 if (def->GetStyle().GetFontUnderlined())
586 hasUnderline = true;
587
588 if (hasBold)
589 str << wxT("<b>");
590 if (hasItalic)
591 str << wxT("<i>");
592 if (hasUnderline)
593 str << wxT("<u>");
594
595 str += def->GetName();
596
597 if (hasUnderline)
598 str << wxT("</u>");
599 if (hasItalic)
600 str << wxT("</i>");
601 if (hasBold)
602 str << wxT("</b>");
603
604 str << wxT("</font>");
605
606 str += wxT("</td></tr></table>");
607 return str;
608 }
609
610 // Convert units in tends of a millimetre to device units
611 int wxRichTextStyleListBox::ConvertTenthsMMToPixels(wxDC& dc, int units) const
612 {
613 int ppi = dc.GetPPI().x;
614
615 // There are ppi pixels in 254.1 "1/10 mm"
616
617 double pixels = ((double) units * (double)ppi) / 254.1;
618
619 return (int) pixels;
620 }
621
622 void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
623 {
624 wxVListBox::OnLeftDown(event);
625
626 int item = HitTest(event.GetPosition());
627 if (item != wxNOT_FOUND && GetApplyOnSelection())
628 ApplyStyle(item);
629 }
630
631 void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent& event)
632 {
633 wxVListBox::OnLeftDown(event);
634
635 int item = HitTest(event.GetPosition());
636 if (item != wxNOT_FOUND && !GetApplyOnSelection())
637 ApplyStyle(item);
638 }
639
640 /// Helper for listbox and combo control
641 wxString wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl* ctrl, wxRichTextStyleType styleType)
642 {
643 int adjustedCaretPos = ctrl->GetAdjustedCaretPosition(ctrl->GetCaretPosition());
644
645 wxRichTextParagraph* para = ctrl->GetBuffer().GetParagraphAtPosition(adjustedCaretPos);
646 wxRichTextObject* obj = ctrl->GetBuffer().GetLeafObjectAtPosition(adjustedCaretPos);
647
648 wxString styleName;
649
650 // Take into account current default style just chosen by user
651 if (ctrl->IsDefaultStyleShowing())
652 {
653 if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
654 !ctrl->GetDefaultStyleEx().GetCharacterStyleName().IsEmpty())
655 styleName = ctrl->GetDefaultStyleEx().GetCharacterStyleName();
656 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
657 !ctrl->GetDefaultStyleEx().GetParagraphStyleName().IsEmpty())
658 styleName = ctrl->GetDefaultStyleEx().GetParagraphStyleName();
659 else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
660 !ctrl->GetDefaultStyleEx().GetListStyleName().IsEmpty())
661 styleName = ctrl->GetDefaultStyleEx().GetListStyleName();
662 }
663 else if (obj && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
664 !obj->GetAttributes().GetCharacterStyleName().IsEmpty())
665 {
666 styleName = obj->GetAttributes().GetCharacterStyleName();
667 }
668 else if (para && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
669 !para->GetAttributes().GetParagraphStyleName().IsEmpty())
670 {
671 styleName = para->GetAttributes().GetParagraphStyleName();
672 }
673 else if (para && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
674 !para->GetAttributes().GetListStyleName().IsEmpty())
675 {
676 styleName = para->GetAttributes().GetListStyleName();
677 }
678
679 return styleName;
680 }
681
682 /// Auto-select from style under caret in idle time
683 void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
684 {
685 if (CanAutoSetSelection() && GetRichTextCtrl() && wxWindow::FindFocus() != this)
686 {
687 wxString styleName = GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
688
689 int sel = GetSelection();
690 if (!styleName.IsEmpty())
691 {
692 // Don't do the selection if it's already set
693 if (sel == GetIndexForStyle(styleName))
694 return;
695
696 SetStyleSelection(styleName);
697 }
698 else if (sel != -1)
699 SetSelection(-1);
700 }
701 event.Skip();
702 }
703
704 /// Do selection
705 void wxRichTextStyleListBox::ApplyStyle(int item)
706 {
707 if ( item != wxNOT_FOUND )
708 {
709 wxRichTextStyleDefinition* def = GetStyle(item);
710 if (def && GetRichTextCtrl())
711 {
712 GetRichTextCtrl()->ApplyStyle(def);
713 GetRichTextCtrl()->SetFocus();
714 }
715 }
716 }
717
718 /*!
719 * wxRichTextStyleListCtrl class: manages a listbox and a choice control to
720 * switch shown style types
721 */
722
723 IMPLEMENT_CLASS(wxRichTextStyleListCtrl, wxControl)
724
725 BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl, wxControl)
726 EVT_CHOICE(wxID_ANY, wxRichTextStyleListCtrl::OnChooseType)
727 EVT_SIZE(wxRichTextStyleListCtrl::OnSize)
728 END_EVENT_TABLE()
729
730 wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
731 const wxSize& size, long style)
732 {
733 Init();
734 Create(parent, id, pos, size, style);
735 }
736
737 bool wxRichTextStyleListCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
738 const wxSize& size, long style)
739 {
740 wxControl::Create(parent, id, pos, size, style);
741
742 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
743 if (size != wxDefaultSize)
744 SetInitialSize(size);
745
746 bool showSelector = ((style & wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR) == 0);
747
748 m_styleListBox = new wxRichTextStyleListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, showSelector ? wxSIMPLE_BORDER : wxNO_BORDER);
749
750 wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
751
752 if (showSelector)
753 {
754 wxArrayString choices;
755 choices.Add(_("All styles"));
756 choices.Add(_("Paragraph styles"));
757 choices.Add(_("Character styles"));
758 choices.Add(_("List styles"));
759
760 m_styleChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
761
762 boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 5);
763 boxSizer->Add(m_styleChoice, 0, wxALL|wxEXPAND, 5);
764 }
765 else
766 {
767 boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 0);
768 }
769
770 SetSizer(boxSizer);
771 Layout();
772
773 m_dontUpdate = true;
774
775 if (m_styleChoice)
776 {
777 int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
778 m_styleChoice->SetSelection(i);
779 }
780
781 m_dontUpdate = false;
782
783 return true;
784 }
785
786 wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
787 {
788
789 }
790
791 /// React to style type choice
792 void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent& event)
793 {
794 if (event.GetEventObject() != m_styleChoice)
795 event.Skip();
796 else
797 {
798 if (m_dontUpdate)
799 return;
800
801 wxRichTextStyleListBox::wxRichTextStyleType styleType = StyleIndexToType(event.GetSelection());
802 m_styleListBox->SetStyleType(styleType);
803 }
804 }
805
806 /// Lay out the controls
807 void wxRichTextStyleListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
808 {
809 if (GetAutoLayout())
810 Layout();
811 }
812
813 /// Get the choice index for style type
814 int wxRichTextStyleListCtrl::StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType)
815 {
816 if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL)
817 {
818 return 0;
819 }
820 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH)
821 {
822 return 1;
823 }
824 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER)
825 {
826 return 2;
827 }
828 else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST)
829 {
830 return 3;
831 }
832 return 0;
833 }
834
835 /// Get the style type for choice index
836 wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::StyleIndexToType(int i)
837 {
838 if (i == 1)
839 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH;
840 else if (i == 2)
841 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER;
842 else if (i == 3)
843 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST;
844
845 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
846 }
847
848 /// Associates the control with a style manager
849 void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet* styleSheet)
850 {
851 if (m_styleListBox)
852 m_styleListBox->SetStyleSheet(styleSheet);
853 }
854
855 wxRichTextStyleSheet* wxRichTextStyleListCtrl::GetStyleSheet() const
856 {
857 if (m_styleListBox)
858 return m_styleListBox->GetStyleSheet();
859 else
860 return NULL;
861 }
862
863 /// Associates the control with a wxRichTextCtrl
864 void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl* ctrl)
865 {
866 if (m_styleListBox)
867 m_styleListBox->SetRichTextCtrl(ctrl);
868 }
869
870 wxRichTextCtrl* wxRichTextStyleListCtrl::GetRichTextCtrl() const
871 {
872 if (m_styleListBox)
873 return m_styleListBox->GetRichTextCtrl();
874 else
875 return NULL;
876 }
877
878 /// Set/get the style type to display
879 void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType)
880 {
881 if (m_styleListBox)
882 m_styleListBox->SetStyleType(styleType);
883
884 m_dontUpdate = true;
885
886 if (m_styleChoice)
887 {
888 int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
889 m_styleChoice->SetSelection(i);
890 }
891
892 m_dontUpdate = false;
893 }
894
895 wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::GetStyleType() const
896 {
897 if (m_styleListBox)
898 return m_styleListBox->GetStyleType();
899 else
900 return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
901 }
902
903 /// Updates the style list box
904 void wxRichTextStyleListCtrl::UpdateStyles()
905 {
906 if (m_styleListBox)
907 m_styleListBox->UpdateStyles();
908 }
909
910 #if wxUSE_COMBOCTRL
911
912 /*!
913 * Style drop-down for a wxComboCtrl
914 */
915
916
917 BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup, wxRichTextStyleListBox)
918 EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove)
919 EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick)
920 END_EVENT_TABLE()
921
922 void wxRichTextStyleComboPopup::SetStringValue( const wxString& s )
923 {
924 m_value = SetStyleSelection(s);
925 }
926
927 wxString wxRichTextStyleComboPopup::GetStringValue() const
928 {
929 int sel = m_value;
930 if (sel > -1)
931 {
932 wxRichTextStyleDefinition* def = GetStyle(sel);
933 if (def)
934 return def->GetName();
935 }
936 return wxEmptyString;
937 }
938
939 //
940 // Popup event handlers
941 //
942
943 // Mouse hot-tracking
944 void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent& event)
945 {
946 // Move selection to cursor if it is inside the popup
947
948 int itemHere = wxRichTextStyleListBox::HitTest(event.GetPosition());
949 if ( itemHere >= 0 )
950 {
951 wxRichTextStyleListBox::SetSelection(itemHere);
952 m_itemHere = itemHere;
953 }
954 event.Skip();
955 }
956
957 // On mouse left, set the value and close the popup
958 void wxRichTextStyleComboPopup::OnMouseClick(wxMouseEvent& WXUNUSED(event))
959 {
960 if (m_itemHere >= 0)
961 m_value = m_itemHere;
962
963 // Ordering is important, so we don't dismiss this popup accidentally
964 // by setting the focus elsewhere e.g. in ApplyStyle
965 Dismiss();
966
967 if (m_itemHere >= 0)
968 wxRichTextStyleListBox::ApplyStyle(m_itemHere);
969 }
970
971 /*!
972 * wxRichTextStyleComboCtrl
973 * A combo for applying styles.
974 */
975
976 IMPLEMENT_CLASS(wxRichTextStyleComboCtrl, wxComboCtrl)
977
978 BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl, wxComboCtrl)
979 EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle)
980 END_EVENT_TABLE()
981
982 bool wxRichTextStyleComboCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
983 const wxSize& size, long style)
984 {
985 if (!wxComboCtrl::Create(parent, id, wxEmptyString, pos, size, style))
986 return false;
987
988 SetPopupMaxHeight(400);
989
990 m_stylePopup = new wxRichTextStyleComboPopup;
991
992 SetPopupControl(m_stylePopup);
993
994 return true;
995 }
996
997 /// Auto-select from style under caret in idle time
998
999 // TODO: must be able to show italic, bold, combinations
1000 // in style box. Do we have a concept of automatic, temporary
1001 // styles that are added whenever we wish to show a style
1002 // that doesn't exist already? E.g. "Bold, Italic, Underline".
1003 // Word seems to generate these things on the fly.
1004 // If there's a named style already, it uses e.g. Heading1 + Bold, Italic
1005 // If you unembolden text in a style that has bold, it uses the
1006 // term "Not bold".
1007 // TODO: order styles alphabetically. This means indexes can change,
1008 // so need a different way to specify selections, i.e. by name.
1009
1010 void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent& event)
1011 {
1012 if (GetRichTextCtrl() && !IsPopupShown() && m_stylePopup && wxWindow::FindFocus() != this)
1013 {
1014 wxString styleName = wxRichTextStyleListBox::GetStyleToShowInIdleTime(GetRichTextCtrl(), m_stylePopup->GetStyleType());
1015
1016 wxString currentValue = GetValue();
1017 if (!styleName.IsEmpty())
1018 {
1019 // Don't do the selection if it's already set
1020 if (currentValue == styleName)
1021 return;
1022
1023 SetValue(styleName);
1024 }
1025 else if (!currentValue.IsEmpty())
1026 SetValue(wxEmptyString);
1027 }
1028 event.Skip();
1029 }
1030
1031 #endif
1032 // wxUSE_COMBOCTRL
1033
1034 #endif
1035 // wxUSE_HTML
1036
1037 #endif
1038 // wxUSE_RICHTEXT