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