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