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