/////////////////////////////////////////////////////////////////////////////
-// Name: richtextstyles.cpp
+// Name: src/richtext/richtextstyles.cpp
// Purpose: Style management for wxRichTextCtrl
// Author: Julian Smart
-// Modified by:
+// Modified by:
// Created: 2005-09-30
-// RCS-ID:
+// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/filename.h"
#include "wx/clipbrd.h"
#include "wx/wfstream.h"
-#include "wx/module.h"
+#include "wx/settings.h"
#include "wx/richtext/richtextctrl.h"
IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject)
IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition)
IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition)
+IMPLEMENT_CLASS(wxRichTextListStyleDefinition, wxRichTextParagraphStyleDefinition)
+IMPLEMENT_CLASS(wxRichTextBoxStyleDefinition, wxRichTextStyleDefinition)
+
+/*!
+ * A definition
+ */
+
+void wxRichTextStyleDefinition::Copy(const wxRichTextStyleDefinition& def)
+{
+ m_name = def.m_name;
+ m_baseStyle = def.m_baseStyle;
+ m_style = def.m_style;
+ m_description = def.m_description;
+ m_properties = def.m_properties;
+}
+
+bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition& def) const
+{
+ return (m_name == def.m_name && m_baseStyle == def.m_baseStyle && m_style == def.m_style && m_properties == def.m_properties);
+}
+
+/// Gets the style combined with the base style
+wxRichTextAttr wxRichTextStyleDefinition::GetStyleMergedWithBase(const wxRichTextStyleSheet* sheet) const
+{
+ if (m_baseStyle.IsEmpty())
+ return m_style;
+
+ bool isParaStyle = IsKindOf(wxCLASSINFO(wxRichTextParagraphStyleDefinition));
+ bool isCharStyle = IsKindOf(wxCLASSINFO(wxRichTextCharacterStyleDefinition));
+ bool isListStyle = IsKindOf(wxCLASSINFO(wxRichTextListStyleDefinition));
+ bool isBoxStyle = IsKindOf(wxCLASSINFO(wxRichTextBoxStyleDefinition));
+
+ // Collect the styles, detecting loops
+ wxArrayString styleNames;
+ wxList styles;
+ const wxRichTextStyleDefinition* def = this;
+ while (def)
+ {
+ styles.Insert((wxObject*) def);
+ styleNames.Add(def->GetName());
+
+ wxString baseStyleName = def->GetBaseStyle();
+ if (!baseStyleName.IsEmpty() && styleNames.Index(baseStyleName) == wxNOT_FOUND)
+ {
+ if (isParaStyle)
+ def = sheet->FindParagraphStyle(baseStyleName);
+ else if (isCharStyle)
+ def = sheet->FindCharacterStyle(baseStyleName);
+ else if (isListStyle)
+ def = sheet->FindListStyle(baseStyleName);
+ else if (isBoxStyle)
+ def = sheet->FindBoxStyle(baseStyleName);
+ else
+ def = sheet->FindStyle(baseStyleName);
+ }
+ else
+ def = NULL;
+ }
+
+ wxRichTextAttr attr;
+ wxList::compatibility_iterator node = styles.GetFirst();
+ while (node)
+ {
+ wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
+ attr.Apply(def->GetStyle(), NULL);
+ node = node->GetNext();
+ }
+
+ return attr;
+}
+
+/*!
+ * Paragraph style definition
+ */
+
+void wxRichTextParagraphStyleDefinition::Copy(const wxRichTextParagraphStyleDefinition& def)
+{
+ wxRichTextStyleDefinition::Copy(def);
+
+ m_nextStyle = def.m_nextStyle;
+}
+
+bool wxRichTextParagraphStyleDefinition::operator ==(const wxRichTextParagraphStyleDefinition& def) const
+{
+ return (Eq(def) && m_nextStyle == def.m_nextStyle);
+}
+
+/*!
+ * Box style definition
+ */
+
+void wxRichTextBoxStyleDefinition::Copy(const wxRichTextBoxStyleDefinition& def)
+{
+ wxRichTextStyleDefinition::Copy(def);
+}
+
+bool wxRichTextBoxStyleDefinition::operator ==(const wxRichTextBoxStyleDefinition& def) const
+{
+ return (Eq(def));
+}
+
+/*!
+ * List style definition
+ */
+
+void wxRichTextListStyleDefinition::Copy(const wxRichTextListStyleDefinition& def)
+{
+ wxRichTextParagraphStyleDefinition::Copy(def);
+
+ int i;
+ for (i = 0; i < 10; i++)
+ m_levelStyles[i] = def.m_levelStyles[i];
+}
+
+bool wxRichTextListStyleDefinition::operator ==(const wxRichTextListStyleDefinition& def) const
+{
+ if (!Eq(def))
+ return false;
+ int i;
+ for (i = 0; i < 10; i++)
+ if (!(m_levelStyles[i] == def.m_levelStyles[i]))
+ return false;
+
+ return true;
+}
+
+/// Sets/gets the attributes for the given level
+void wxRichTextListStyleDefinition::SetLevelAttributes(int i, const wxRichTextAttr& attr)
+{
+ wxASSERT( (i >= 0 && i < 10) );
+ if (i >= 0 && i < 10)
+ m_levelStyles[i] = attr;
+}
+
+const wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i) const
+{
+ wxASSERT( (i >= 0 && i < 10) );
+ if (i >= 0 && i < 10)
+ return & m_levelStyles[i];
+ else
+ return NULL;
+}
+
+wxRichTextAttr* wxRichTextListStyleDefinition::GetLevelAttributes(int i)
+{
+ wxASSERT( (i >= 0 && i < 10) );
+ if (i >= 0 && i < 10)
+ return & m_levelStyles[i];
+ else
+ return NULL;
+}
+
+/// Convenience function for setting the major attributes for a list level specification
+void wxRichTextListStyleDefinition::SetAttributes(int i, int leftIndent, int leftSubIndent, int bulletStyle, const wxString& bulletSymbol)
+{
+ wxASSERT( (i >= 0 && i < 10) );
+ if (i >= 0 && i < 10)
+ {
+ wxRichTextAttr attr;
+
+ attr.SetBulletStyle(bulletStyle);
+ attr.SetLeftIndent(leftIndent, leftSubIndent);
+
+ if (!bulletSymbol.IsEmpty())
+ {
+ if (bulletStyle & wxTEXT_ATTR_BULLET_STYLE_SYMBOL)
+ attr.SetBulletText(bulletSymbol);
+ else
+ attr.SetBulletName(bulletSymbol);
+ }
+
+ m_levelStyles[i] = attr;
+ }
+}
+
+/// Finds the level corresponding to the given indentation
+int wxRichTextListStyleDefinition::FindLevelForIndent(int indent) const
+{
+ int i;
+ for (i = 0; i < 10; i++)
+ {
+ if (indent < m_levelStyles[i].GetLeftIndent())
+ {
+ if (i > 0)
+ return i - 1;
+ else
+ return 0;
+ }
+ }
+ return 9;
+}
+
+/// Combine the list style with a paragraph style, using the given indent (from which
+/// an appropriate level is found)
+wxRichTextAttr wxRichTextListStyleDefinition::CombineWithParagraphStyle(int indent, const wxRichTextAttr& paraStyle, wxRichTextStyleSheet* styleSheet)
+{
+ int listLevel = FindLevelForIndent(indent);
+
+ wxRichTextAttr attr(*GetLevelAttributes(listLevel));
+ int oldLeftIndent = attr.GetLeftIndent();
+ int oldLeftSubIndent = attr.GetLeftSubIndent();
+
+ // First apply the overall paragraph style, if any
+ if (styleSheet)
+ attr.Apply(GetStyleMergedWithBase(styleSheet));
+ else
+ attr.Apply(GetStyle());
+
+ // Then apply paragraph style, e.g. from paragraph style definition
+ attr.Apply(paraStyle);
+
+ // We override the indents according to the list definition
+ attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
+
+ return attr;
+}
+
+/// Combine the base and list style, using the given indent (from which
+/// an appropriate level is found)
+wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyle(int indent, wxRichTextStyleSheet* styleSheet)
+{
+ int listLevel = FindLevelForIndent(indent);
+ return GetCombinedStyleForLevel(listLevel, styleSheet);
+}
+
+/// Combine the base and list style, using the given indent (from which
+/// an appropriate level is found)
+wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel, wxRichTextStyleSheet* styleSheet)
+{
+ wxRichTextAttr attr(*GetLevelAttributes(listLevel));
+ int oldLeftIndent = attr.GetLeftIndent();
+ int oldLeftSubIndent = attr.GetLeftSubIndent();
+
+ // Apply the overall paragraph style, if any
+ if (styleSheet)
+ attr.Apply(GetStyleMergedWithBase(styleSheet));
+ else
+ attr.Apply(GetStyle());
+
+ // We override the indents according to the list definition
+ attr.SetLeftIndent(oldLeftIndent, oldLeftSubIndent);
+
+ return attr;
+}
+
+/// Is this a numbered list?
+bool wxRichTextListStyleDefinition::IsNumbered(int i) const
+{
+ return (0 != (GetLevelAttributes(i)->GetFlags() &
+ (wxTEXT_ATTR_BULLET_STYLE_ARABIC|wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER|wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER|
+ wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER|wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER)));
+}
/*!
* The style manager
IMPLEMENT_CLASS(wxRichTextStyleSheet, wxObject)
+wxRichTextStyleSheet::~wxRichTextStyleSheet()
+{
+ DeleteStyles();
+
+ if (m_nextSheet)
+ m_nextSheet->m_previousSheet = m_previousSheet;
+
+ if (m_previousSheet)
+ m_previousSheet->m_nextSheet = m_nextSheet;
+
+ m_previousSheet = NULL;
+ m_nextSheet = NULL;
+}
+
/// Initialisation
void wxRichTextStyleSheet::Init()
{
+ m_previousSheet = NULL;
+ m_nextSheet = NULL;
}
/// Add a definition to one of the style lists
return false;
}
+/// Remove a style
+bool wxRichTextStyleSheet::RemoveStyle(wxRichTextStyleDefinition* def, bool deleteStyle)
+{
+ if (RemoveParagraphStyle(def, deleteStyle))
+ return true;
+ if (RemoveCharacterStyle(def, deleteStyle))
+ return true;
+ if (RemoveListStyle(def, deleteStyle))
+ return true;
+ if (RemoveBoxStyle(def, deleteStyle))
+ return true;
+ return false;
+}
+
/// Find a definition by name
-wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name) const
+wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxList& list, const wxString& name, bool recurse) const
{
for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
{
wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
- if (def->GetName().Lower() == name.Lower())
+ if (def->GetName() == name)
return def;
}
- return NULL;
+
+ if (m_nextSheet && recurse)
+ return m_nextSheet->FindStyle(list, name, recurse);
+
+ return NULL;
}
/// Delete all styles
{
WX_CLEAR_LIST(wxList, m_characterStyleDefinitions);
WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
+ WX_CLEAR_LIST(wxList, m_listStyleDefinitions);
+ WX_CLEAR_LIST(wxList, m_boxStyleDefinitions);
+}
+
+/// Insert into list of style sheets
+bool wxRichTextStyleSheet::InsertSheet(wxRichTextStyleSheet* before)
+{
+ m_previousSheet = before->m_previousSheet;
+ m_nextSheet = before;
+
+ before->m_previousSheet = this;
+ return true;
+}
+
+/// Append to list of style sheets
+bool wxRichTextStyleSheet::AppendSheet(wxRichTextStyleSheet* after)
+{
+ wxRichTextStyleSheet* last = after;
+ while (last && last->m_nextSheet)
+ {
+ last = last->m_nextSheet;
+ }
+
+ if (last)
+ {
+ m_previousSheet = last;
+ last->m_nextSheet = this;
+
+ return true;
+ }
+ else
+ return false;
+}
+
+/// Unlink from the list of style sheets
+void wxRichTextStyleSheet::Unlink()
+{
+ if (m_previousSheet)
+ m_previousSheet->m_nextSheet = m_nextSheet;
+ if (m_nextSheet)
+ m_nextSheet->m_previousSheet = m_previousSheet;
+
+ m_previousSheet = NULL;
+ m_nextSheet = NULL;
+}
+
+/// Add a definition to the character style list
+bool wxRichTextStyleSheet::AddCharacterStyle(wxRichTextCharacterStyleDefinition* def)
+{
+ def->GetStyle().SetCharacterStyleName(def->GetName());
+ return AddStyle(m_characterStyleDefinitions, def);
+}
+
+/// Add a definition to the paragraph style list
+bool wxRichTextStyleSheet::AddParagraphStyle(wxRichTextParagraphStyleDefinition* def)
+{
+ def->GetStyle().SetParagraphStyleName(def->GetName());
+ return AddStyle(m_paragraphStyleDefinitions, def);
+}
+
+/// Add a definition to the list style list
+bool wxRichTextStyleSheet::AddListStyle(wxRichTextListStyleDefinition* def)
+{
+ def->GetStyle().SetListStyleName(def->GetName());
+ return AddStyle(m_listStyleDefinitions, def);
+}
+
+/// Add a definition to the box style list
+bool wxRichTextStyleSheet::AddBoxStyle(wxRichTextBoxStyleDefinition* def)
+{
+ def->GetStyle().GetTextBoxAttr().SetBoxStyleName(def->GetName());
+ return AddStyle(m_boxStyleDefinitions, def);
+}
+
+/// Add a definition to the appropriate style list
+bool wxRichTextStyleSheet::AddStyle(wxRichTextStyleDefinition* def)
+{
+ wxRichTextListStyleDefinition* listDef = wxDynamicCast(def, wxRichTextListStyleDefinition);
+ if (listDef)
+ return AddListStyle(listDef);
+
+ wxRichTextParagraphStyleDefinition* paraDef = wxDynamicCast(def, wxRichTextParagraphStyleDefinition);
+ if (paraDef)
+ return AddParagraphStyle(paraDef);
+
+ wxRichTextCharacterStyleDefinition* charDef = wxDynamicCast(def, wxRichTextCharacterStyleDefinition);
+ if (charDef)
+ return AddCharacterStyle(charDef);
+
+ wxRichTextBoxStyleDefinition* boxDef = wxDynamicCast(def, wxRichTextBoxStyleDefinition);
+ if (boxDef)
+ return AddBoxStyle(boxDef);
+
+ return false;
+}
+
+/// Find any definition by name
+wxRichTextStyleDefinition* wxRichTextStyleSheet::FindStyle(const wxString& name, bool recurse) const
+{
+ wxRichTextListStyleDefinition* listDef = FindListStyle(name, recurse);
+ if (listDef)
+ return listDef;
+
+ wxRichTextParagraphStyleDefinition* paraDef = FindParagraphStyle(name, recurse);
+ if (paraDef)
+ return paraDef;
+
+ wxRichTextCharacterStyleDefinition* charDef = FindCharacterStyle(name, recurse);
+ if (charDef)
+ return charDef;
+
+ wxRichTextBoxStyleDefinition* boxDef = FindBoxStyle(name, recurse);
+ if (boxDef)
+ return boxDef;
+
+ return NULL;
+}
+
+/// Copy
+void wxRichTextStyleSheet::Copy(const wxRichTextStyleSheet& sheet)
+{
+ DeleteStyles();
+
+ wxList::compatibility_iterator node;
+
+ for (node = sheet.m_characterStyleDefinitions.GetFirst(); node; node = node->GetNext())
+ {
+ wxRichTextCharacterStyleDefinition* def = (wxRichTextCharacterStyleDefinition*) node->GetData();
+ AddCharacterStyle(new wxRichTextCharacterStyleDefinition(*def));
+ }
+
+ for (node = sheet.m_paragraphStyleDefinitions.GetFirst(); node; node = node->GetNext())
+ {
+ wxRichTextParagraphStyleDefinition* def = (wxRichTextParagraphStyleDefinition*) node->GetData();
+ AddParagraphStyle(new wxRichTextParagraphStyleDefinition(*def));
+ }
+
+ for (node = sheet.m_listStyleDefinitions.GetFirst(); node; node = node->GetNext())
+ {
+ wxRichTextListStyleDefinition* def = (wxRichTextListStyleDefinition*) node->GetData();
+ AddListStyle(new wxRichTextListStyleDefinition(*def));
+ }
+
+ for (node = sheet.m_boxStyleDefinitions.GetFirst(); node; node = node->GetNext())
+ {
+ wxRichTextBoxStyleDefinition* def = (wxRichTextBoxStyleDefinition*) node->GetData();
+ AddBoxStyle(new wxRichTextBoxStyleDefinition(*def));
+ }
+
+ SetName(sheet.GetName());
+ SetDescription(sheet.GetDescription());
+ m_properties = sheet.m_properties;
+}
+
+/// Equality
+bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
+{
+ // TODO
+ return false;
}
+
#if wxUSE_HTML
+
+// Functions for dealing with clashing names for different kinds of style.
+// Returns "P", "C", "L" or "B" (paragraph, character, list or box) for
+// style name | type.
+static wxString wxGetRichTextStyleType(const wxString& style)
+{
+ return style.AfterLast(wxT('|'));
+}
+
+static wxString wxGetRichTextStyle(const wxString& style)
+{
+ return style.BeforeLast(wxT('|'));
+}
+
+
/*!
- * wxRichTextStyleListBox class declaration
- * A listbox to display styles.
+ * wxRichTextStyleListBox: a listbox to display styles.
*/
IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
- EVT_LISTBOX(wxID_ANY, wxRichTextStyleListBox::OnSelect)
EVT_LEFT_DOWN(wxRichTextStyleListBox::OnLeftDown)
+ EVT_LEFT_DCLICK(wxRichTextStyleListBox::OnLeftDoubleClick)
+ EVT_IDLE(wxRichTextStyleListBox::OnIdle)
END_EVENT_TABLE()
wxRichTextStyleListBox::wxRichTextStyleListBox(wxWindow* parent, wxWindowID id, const wxPoint& pos,
- const wxSize& size, long style): wxHtmlListBox(parent, id, pos, size, style)
+ const wxSize& size, long style)
+{
+ Init();
+ Create(parent, id, pos, size, style);
+}
+
+bool wxRichTextStyleListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
+ const wxSize& size, long style)
{
- m_styleSheet = NULL;
- m_richTextCtrl = NULL;
+ return wxHtmlListBox::Create(parent, id, pos, size, style);
}
wxRichTextStyleListBox::~wxRichTextStyleListBox()
if (!GetStyleSheet())
return wxEmptyString;
- // First paragraph styles, then character
- if (n < GetStyleSheet()->GetParagraphStyleCount())
- {
- wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->GetParagraphStyle(n);
-
- wxString str = CreateHTML(def);
- return str;
- }
-
- if ((n - GetStyleSheet()->GetParagraphStyleCount()) < GetStyleSheet()->GetCharacterStyleCount())
- {
- wxRichTextCharacterStyleDefinition* def = GetStyleSheet()->GetCharacterStyle(n - GetStyleSheet()->GetParagraphStyleCount());
+ wxRichTextStyleDefinition* def = GetStyle(n);
+ if (def)
+ return CreateHTML(def);
- wxString str = CreateHTML(def);
- return str;
- }
return wxEmptyString;
}
if (!GetStyleSheet())
return NULL;
- // First paragraph styles, then character
- if (i < GetStyleSheet()->GetParagraphStyleCount())
- return GetStyleSheet()->GetParagraphStyle(i);
-
- if ((i - GetStyleSheet()->GetParagraphStyleCount()) < GetStyleSheet()->GetCharacterStyleCount())
- return GetStyleSheet()->GetCharacterStyle(i - GetStyleSheet()->GetParagraphStyleCount());
+ if (i >= m_styleNames.GetCount() /* || i < 0 */ )
+ return NULL;
- return NULL;
+ wxString styleType = wxGetRichTextStyleType(m_styleNames[i]);
+ wxString style = wxGetRichTextStyle(m_styleNames[i]);
+ if (styleType == wxT("P"))
+ return GetStyleSheet()->FindParagraphStyle(style);
+ else if (styleType == wxT("C"))
+ return GetStyleSheet()->FindCharacterStyle(style);
+ else if (styleType == wxT("L"))
+ return GetStyleSheet()->FindListStyle(style);
+ else if (styleType == wxT("B"))
+ return GetStyleSheet()->FindBoxStyle(style);
+ else
+ return GetStyleSheet()->FindStyle(style);
}
/// Updates the list
{
if (GetStyleSheet())
{
- SetItemCount(GetStyleSheet()->GetParagraphStyleCount()+GetStyleSheet()->GetCharacterStyleCount());
+ int oldSel = GetSelection();
+
+ SetSelection(wxNOT_FOUND);
+
+ m_styleNames.Clear();
+
+ size_t i;
+ if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
+ {
+ for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
+ m_styleNames.Add(GetStyleSheet()->GetParagraphStyle(i)->GetName() + wxT("|P"));
+ }
+ if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
+ {
+ for (i = 0; i < GetStyleSheet()->GetCharacterStyleCount(); i++)
+ m_styleNames.Add(GetStyleSheet()->GetCharacterStyle(i)->GetName() + wxT("|C"));
+ }
+ if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_LIST)
+ {
+ for (i = 0; i < GetStyleSheet()->GetListStyleCount(); i++)
+ m_styleNames.Add(GetStyleSheet()->GetListStyle(i)->GetName() + wxT("|L"));
+ }
+ if (GetStyleType() == wxRICHTEXT_STYLE_ALL || GetStyleType() == wxRICHTEXT_STYLE_BOX)
+ {
+ for (i = 0; i < GetStyleSheet()->GetBoxStyleCount(); i++)
+ m_styleNames.Add(GetStyleSheet()->GetBoxStyle(i)->GetName() + wxT("|B"));
+ }
+
+ m_styleNames.Sort();
+ SetItemCount(m_styleNames.GetCount());
+
+ Refresh();
+
+ int newSel = -1;
+ if (oldSel >= 0 && oldSel < (int) GetItemCount())
+ newSel = oldSel;
+ else if (GetItemCount() > 0)
+ newSel = 0;
+
+ if (newSel >= 0)
+ {
+ SetSelection(newSel);
+ SendSelectedEvent();
+ }
+ }
+ else
+ {
+ m_styleNames.Clear();
+ SetSelection(wxNOT_FOUND);
+ SetItemCount(0);
Refresh();
}
}
+// Get index for style name
+int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const
+{
+ wxString s(name);
+ if (GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
+ s += wxT("|P");
+ else if (GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
+ s += wxT("|C");
+ else if (GetStyleType() == wxRICHTEXT_STYLE_LIST)
+ s += wxT("|L");
+ else if (GetStyleType() == wxRICHTEXT_STYLE_BOX)
+ s += wxT("|B");
+ else
+ {
+ if (m_styleNames.Index(s + wxT("|P")) != wxNOT_FOUND)
+ s += wxT("|P");
+ else if (m_styleNames.Index(s + wxT("|C")) != wxNOT_FOUND)
+ s += wxT("|C");
+ else if (m_styleNames.Index(s + wxT("|L")) != wxNOT_FOUND)
+ s += wxT("|L");
+ else if (m_styleNames.Index(s + wxT("|B")) != wxNOT_FOUND)
+ s += wxT("|B");
+ }
+ return m_styleNames.Index(s);
+}
+
+/// Set selection for string
+int wxRichTextStyleListBox::SetStyleSelection(const wxString& name)
+{
+ int i = GetIndexForStyle(name);
+ if (i > -1)
+ {
+ SetSelection(i);
+ if (!IsVisible(i))
+ ScrollToRow(i);
+ }
+ return i;
+}
+
// Convert a colour to a 6-digit hex string
static wxString ColourToHexString(const wxColour& col)
{
/// Creates a suitable HTML fragment for a definition
wxString wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition* def) const
{
- wxString str(wxT("<table><tr>"));
+ // TODO: indicate list format for list style types
+
+ wxString str;
+
+ bool isCentred = false;
+
+ wxRichTextAttr attr(def->GetStyleMergedWithBase(GetStyleSheet()));
+
+ if (attr.HasAlignment() && attr.GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
+ isCentred = true;
+
+ if (isCentred)
+ str << wxT("<center>");
+
+
+ str << wxT("<table><tr>");
- if (def->GetStyle().GetLeftIndent() > 0)
+ if (attr.GetLeftIndent() > 0)
{
wxClientDC dc((wxWindow*) this);
- str << wxT("<td width=") << ConvertTenthsMMToPixels(dc, def->GetStyle().GetLeftIndent()) << wxT("></td>");
+ str << wxT("<td width=") << wxMin(50, (ConvertTenthsMMToPixels(dc, attr.GetLeftIndent())/2)) << wxT("></td>");
}
- str << wxT("<td nowrap>");
+ if (isCentred)
+ str << wxT("<td nowrap align=\"center\">");
+ else
+ str << wxT("<td nowrap>");
+
+#ifdef __WXMSW__
+ int size = 2;
+#else
+ int size = 3;
+#endif
- int size = 5;
+ // Guess a standard font size
+ int stdFontSize = 0;
- // Standard size is 12, say
- size += 12 - def->GetStyle().GetFontSize();
+ // First see if we have a default/normal style to base the size on
+ wxString normalTranslated(_("normal"));
+ wxString defaultTranslated(_("default"));
+ size_t i;
+ for (i = 0; i < GetStyleSheet()->GetParagraphStyleCount(); i++)
+ {
+ wxRichTextStyleDefinition* d = GetStyleSheet()->GetParagraphStyle(i);
+ wxString name = d->GetName().Lower();
+ if (name.Find(wxT("normal")) != wxNOT_FOUND || name.Find(normalTranslated) != wxNOT_FOUND ||
+ name.Find(wxT("default")) != wxNOT_FOUND || name.Find(defaultTranslated) != wxNOT_FOUND)
+ {
+ wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
+ if (attr2.HasFontPointSize())
+ {
+ stdFontSize = attr2.GetFontSize();
+ break;
+ }
+ }
+ }
+
+ if (stdFontSize == 0)
+ {
+ // Look at sizes up to 20 points, and see which is the most common
+ wxArrayInt sizes;
+ size_t maxSize = 20;
+ for (i = 0; i <= maxSize; i++)
+ sizes.Add(0);
+ for (i = 0; i < m_styleNames.GetCount(); i++)
+ {
+ wxRichTextStyleDefinition* d = GetStyle(i);
+ if (d)
+ {
+ wxRichTextAttr attr2(d->GetStyleMergedWithBase(GetStyleSheet()));
+ if (attr2.HasFontPointSize())
+ {
+ if (attr2.GetFontSize() <= (int) maxSize)
+ sizes[attr2.GetFontSize()] ++;
+ }
+ }
+ }
+ int mostCommonSize = 0;
+ for (i = 0; i <= maxSize; i++)
+ {
+ if (sizes[i] > mostCommonSize)
+ mostCommonSize = i;
+ }
+ if (mostCommonSize > 0)
+ stdFontSize = mostCommonSize;
+ }
+
+ if (stdFontSize == 0)
+ stdFontSize = 12;
+
+ int thisFontSize = attr.HasFontPointSize() ? attr.GetFontSize() : stdFontSize;
+
+ if (thisFontSize < stdFontSize)
+ size --;
+ else if (thisFontSize > stdFontSize)
+ size ++;
str += wxT("<font");
str << wxT(" size=") << size;
- if (!def->GetStyle().GetFontFaceName().IsEmpty())
- str << wxT(" face=\"") << def->GetStyle().GetFontFaceName() << wxT("\"");
+ if (!attr.GetFontFaceName().IsEmpty())
+ str << wxT(" face=\"") << attr.GetFontFaceName() << wxT("\"");
- if (def->GetStyle().GetTextColour().Ok())
- str << wxT(" color=\"#") << ColourToHexString(def->GetStyle().GetTextColour()) << wxT("\"");
+ if (attr.GetTextColour().IsOk())
+ str << wxT(" color=\"#") << ColourToHexString(attr.GetTextColour()) << wxT("\"");
str << wxT(">");
bool hasItalic = false;
bool hasUnderline = false;
- if (def->GetStyle().GetFontWeight() == wxBOLD)
+ if (attr.GetFontWeight() == wxFONTWEIGHT_BOLD)
hasBold = true;
- if (def->GetStyle().GetFontStyle() == wxITALIC)
+ if (attr.GetFontStyle() == wxFONTSTYLE_ITALIC)
hasItalic = true;
- if (def->GetStyle().GetFontUnderlined())
+ if (attr.GetFontUnderlined())
hasUnderline = true;
if (hasBold)
if (hasBold)
str << wxT("</b>");
+ if (isCentred)
+ str << wxT("</centre>");
+
str << wxT("</font>");
- str += wxT("</td></tr></table>");
+ str << wxT("</td></tr></table>");
+
+ if (isCentred)
+ str << wxT("</center>");
+
return str;
}
return (int) pixels;
}
-/// React to selection
-void wxRichTextStyleListBox::OnSelect(wxCommandEvent& WXUNUSED(event))
+void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
{
+ wxVListBox::OnLeftDown(event);
+
+ int item = VirtualHitTest(event.GetPosition().y);
+ if (item != wxNOT_FOUND && GetApplyOnSelection())
+ ApplyStyle(item);
+}
+
+void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent& event)
+{
+ wxVListBox::OnLeftDown(event);
+
+ int item = VirtualHitTest(event.GetPosition().y);
+ if (item != wxNOT_FOUND && !GetApplyOnSelection())
+ ApplyStyle(item);
+}
+
+/// Helper for listbox and combo control
+wxString wxRichTextStyleListBox::GetStyleToShowInIdleTime(wxRichTextCtrl* ctrl, wxRichTextStyleType styleType)
+{
+ int adjustedCaretPos = ctrl->GetAdjustedCaretPosition(ctrl->GetCaretPosition());
+
+ wxString styleName;
+
+ wxRichTextAttr attr;
+ ctrl->GetStyle(adjustedCaretPos, attr);
+
+ // Take into account current default style just chosen by user
+ if (ctrl->IsDefaultStyleShowing())
+ {
+ wxRichTextApplyStyle(attr, ctrl->GetDefaultStyleEx());
+
+ if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
+ !attr.GetCharacterStyleName().IsEmpty())
+ styleName = attr.GetCharacterStyleName();
+ else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
+ !attr.GetParagraphStyleName().IsEmpty())
+ styleName = attr.GetParagraphStyleName();
+ else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
+ !attr.GetListStyleName().IsEmpty())
+ styleName = attr.GetListStyleName();
+ // TODO: when we have a concept of focused object (text box), we'll
+ // use the paragraph style name of the focused object as the frame style name.
#if 0
- wxRichTextStyleDefinition* def = GetStyle(event.GetSelection());
- if (def)
+ else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_BOX) &&
+ !attr.GetBoxStyleName().IsEmpty())
+ styleName = attr.GetBoxStyleName();
+#endif
+ }
+ else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
+ !attr.GetCharacterStyleName().IsEmpty())
{
- wxMessageBox(def->GetName());
+ styleName = attr.GetCharacterStyleName();
}
-#endif
+ else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
+ !attr.GetParagraphStyleName().IsEmpty())
+ {
+ styleName = attr.GetParagraphStyleName();
+ }
+ else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
+ !attr.GetListStyleName().IsEmpty())
+ {
+ styleName = attr.GetListStyleName();
+ }
+
+ return styleName;
}
-void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
+/// Auto-select from style under caret in idle time
+void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
{
- wxVListBox::OnLeftDown(event);
+ if (CanAutoSetSelection() && GetRichTextCtrl() && IsShownOnScreen() && wxWindow::FindFocus() != this)
+ {
+ wxString styleName = GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
- int item = HitTest(event.GetPosition());
+ int sel = GetSelection();
+ if (!styleName.IsEmpty())
+ {
+ // Don't do the selection if it's already set
+ if (sel == GetIndexForStyle(styleName))
+ return;
+ SetStyleSelection(styleName);
+ }
+ else if (sel != -1)
+ SetSelection(-1);
+ }
+ event.Skip();
+}
+
+/// Do selection
+void wxRichTextStyleListBox::ApplyStyle(int item)
+{
if ( item != wxNOT_FOUND )
{
wxRichTextStyleDefinition* def = GetStyle(item);
if (def && GetRichTextCtrl())
{
- wxRichTextRange range(m_richTextCtrl->GetInsertionPoint(), m_richTextCtrl->GetInsertionPoint());
-
- // Flags are defined within each definition, so only certain
- // attributes are applied.
- wxRichTextAttr attr(def->GetStyle());
-
- if (m_richTextCtrl->HasSelection())
- m_richTextCtrl->SetStyle(m_richTextCtrl->GetSelectionRange(), attr);
- else
- m_richTextCtrl->SetDefaultStyle(attr);
-
- m_richTextCtrl->SetFocus();
+ GetRichTextCtrl()->ApplyStyle(def);
+ GetRichTextCtrl()->SetFocus();
}
}
}
-#if 0
-wxColour wxRichTextStyleListBox::GetSelectedTextColour(const wxColour& colFg) const
+/*!
+ * wxRichTextStyleListCtrl class: manages a listbox and a choice control to
+ * switch shown style types
+ */
+
+IMPLEMENT_CLASS(wxRichTextStyleListCtrl, wxControl)
+
+BEGIN_EVENT_TABLE(wxRichTextStyleListCtrl, wxControl)
+ EVT_CHOICE(wxID_ANY, wxRichTextStyleListCtrl::OnChooseType)
+ EVT_SIZE(wxRichTextStyleListCtrl::OnSize)
+END_EVENT_TABLE()
+
+wxRichTextStyleListCtrl::wxRichTextStyleListCtrl(wxWindow* parent, wxWindowID id, const wxPoint& pos,
+ const wxSize& size, long style)
+{
+ Init();
+ Create(parent, id, pos, size, style);
+}
+
+bool wxRichTextStyleListCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
+ const wxSize& size, long style)
{
- return *wxBLACK;
+ if ((style & wxBORDER_MASK) == wxBORDER_DEFAULT)
+ style |= wxBORDER_THEME;
+
+ wxControl::Create(parent, id, pos, size, style);
+
+ SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
+ if (size != wxDefaultSize)
+ SetInitialSize(size);
+
+ bool showSelector = ((style & wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR) == 0);
+
+ wxBorder listBoxStyle;
+ if (showSelector)
+ listBoxStyle = wxBORDER_THEME;
+ else
+ listBoxStyle = wxBORDER_NONE;
+
+ m_styleListBox = new wxRichTextStyleListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, listBoxStyle);
+
+ wxBoxSizer* boxSizer = new wxBoxSizer(wxVERTICAL);
+
+ if (showSelector)
+ {
+ wxArrayString choices;
+ choices.Add(_("All styles"));
+ choices.Add(_("Paragraph styles"));
+ choices.Add(_("Character styles"));
+ choices.Add(_("List styles"));
+ choices.Add(_("Box styles"));
+
+ m_styleChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
+
+ boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 5);
+ boxSizer->Add(m_styleChoice, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND, 5);
+ }
+ else
+ {
+ boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 0);
+ }
+
+ SetSizer(boxSizer);
+ Layout();
+
+ m_dontUpdate = true;
+
+ if (m_styleChoice)
+ {
+ int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
+ m_styleChoice->SetSelection(i);
+ }
+
+ m_dontUpdate = false;
+
+ return true;
}
-wxColour wxRichTextStyleListBox::GetSelectedTextBgColour(const wxColour& colBg) const
+wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
{
- return *wxWHITE;
+
}
+
+/// React to style type choice
+void wxRichTextStyleListCtrl::OnChooseType(wxCommandEvent& event)
+{
+ if (event.GetEventObject() != m_styleChoice)
+ event.Skip();
+ else
+ {
+ if (m_dontUpdate)
+ return;
+
+ wxRichTextStyleListBox::wxRichTextStyleType styleType = StyleIndexToType(event.GetSelection());
+ m_styleListBox->SetSelection(-1);
+ m_styleListBox->SetStyleType(styleType);
+ }
+}
+
+/// Lay out the controls
+void wxRichTextStyleListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
+{
+ if (GetAutoLayout())
+ Layout();
+}
+
+/// Get the choice index for style type
+int wxRichTextStyleListCtrl::StyleTypeToIndex(wxRichTextStyleListBox::wxRichTextStyleType styleType)
+{
+ if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL)
+ {
+ return 0;
+ }
+ else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH)
+ {
+ return 1;
+ }
+ else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER)
+ {
+ return 2;
+ }
+ else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST)
+ {
+ return 3;
+ }
+ else if (styleType == wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX)
+ {
+ return 4;
+ }
+ return 0;
+}
+
+/// Get the style type for choice index
+wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::StyleIndexToType(int i)
+{
+ if (i == 1)
+ return wxRichTextStyleListBox::wxRICHTEXT_STYLE_PARAGRAPH;
+ else if (i == 2)
+ return wxRichTextStyleListBox::wxRICHTEXT_STYLE_CHARACTER;
+ else if (i == 3)
+ return wxRichTextStyleListBox::wxRICHTEXT_STYLE_LIST;
+ else if (i == 4)
+ return wxRichTextStyleListBox::wxRICHTEXT_STYLE_BOX;
+
+ return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
+}
+
+/// Associates the control with a style manager
+void wxRichTextStyleListCtrl::SetStyleSheet(wxRichTextStyleSheet* styleSheet)
+{
+ if (m_styleListBox)
+ m_styleListBox->SetStyleSheet(styleSheet);
+}
+
+wxRichTextStyleSheet* wxRichTextStyleListCtrl::GetStyleSheet() const
+{
+ if (m_styleListBox)
+ return m_styleListBox->GetStyleSheet();
+ else
+ return NULL;
+}
+
+/// Associates the control with a wxRichTextCtrl
+void wxRichTextStyleListCtrl::SetRichTextCtrl(wxRichTextCtrl* ctrl)
+{
+ if (m_styleListBox)
+ m_styleListBox->SetRichTextCtrl(ctrl);
+}
+
+wxRichTextCtrl* wxRichTextStyleListCtrl::GetRichTextCtrl() const
+{
+ if (m_styleListBox)
+ return m_styleListBox->GetRichTextCtrl();
+ else
+ return NULL;
+}
+
+/// Set/get the style type to display
+void wxRichTextStyleListCtrl::SetStyleType(wxRichTextStyleListBox::wxRichTextStyleType styleType)
+{
+ if ( !m_styleListBox )
+ return;
+
+ m_styleListBox->SetStyleType(styleType);
+
+ m_dontUpdate = true;
+
+ if (m_styleChoice)
+ {
+ int i = StyleTypeToIndex(m_styleListBox->GetStyleType());
+ m_styleChoice->SetSelection(i);
+ }
+
+ m_dontUpdate = false;
+}
+
+wxRichTextStyleListBox::wxRichTextStyleType wxRichTextStyleListCtrl::GetStyleType() const
+{
+ if (m_styleListBox)
+ return m_styleListBox->GetStyleType();
+ else
+ return wxRichTextStyleListBox::wxRICHTEXT_STYLE_ALL;
+}
+
+/// Updates the style list box
+void wxRichTextStyleListCtrl::UpdateStyles()
+{
+ if (m_styleListBox)
+ m_styleListBox->UpdateStyles();
+}
+
+#if wxUSE_COMBOCTRL
+
+/*!
+ * Style drop-down for a wxComboCtrl
+ */
+
+
+BEGIN_EVENT_TABLE(wxRichTextStyleComboPopup, wxRichTextStyleListBox)
+ EVT_MOTION(wxRichTextStyleComboPopup::OnMouseMove)
+ EVT_LEFT_DOWN(wxRichTextStyleComboPopup::OnMouseClick)
+END_EVENT_TABLE()
+
+bool wxRichTextStyleComboPopup::Create( wxWindow* parent )
+{
+ int borderStyle = GetDefaultBorder();
+ if (borderStyle == wxBORDER_SUNKEN || borderStyle == wxBORDER_NONE)
+ borderStyle = wxBORDER_THEME;
+
+ return wxRichTextStyleListBox::Create(parent, wxID_ANY,
+ wxPoint(0,0), wxDefaultSize,
+ borderStyle);
+}
+
+void wxRichTextStyleComboPopup::SetStringValue( const wxString& s )
+{
+ m_value = SetStyleSelection(s);
+}
+
+wxString wxRichTextStyleComboPopup::GetStringValue() const
+{
+ int sel = m_value;
+ if (sel > -1)
+ {
+ wxRichTextStyleDefinition* def = GetStyle(sel);
+ if (def)
+ return def->GetName();
+ }
+ return wxEmptyString;
+}
+
+//
+// Popup event handlers
+//
+
+// Mouse hot-tracking
+void wxRichTextStyleComboPopup::OnMouseMove(wxMouseEvent& event)
+{
+ // Move selection to cursor if it is inside the popup
+
+ int itemHere = wxRichTextStyleListBox::VirtualHitTest(event.GetPosition().y);
+ if ( itemHere >= 0 )
+ {
+ wxRichTextStyleListBox::SetSelection(itemHere);
+ m_itemHere = itemHere;
+ }
+ event.Skip();
+}
+
+// On mouse left, set the value and close the popup
+void wxRichTextStyleComboPopup::OnMouseClick(wxMouseEvent& WXUNUSED(event))
+{
+ if (m_itemHere >= 0)
+ m_value = m_itemHere;
+
+ // Ordering is important, so we don't dismiss this popup accidentally
+ // by setting the focus elsewhere e.g. in ApplyStyle
+ Dismiss();
+
+ if (m_itemHere >= 0)
+ wxRichTextStyleListBox::ApplyStyle(m_itemHere);
+}
+
+/*!
+ * wxRichTextStyleComboCtrl
+ * A combo for applying styles.
+ */
+
+IMPLEMENT_CLASS(wxRichTextStyleComboCtrl, wxComboCtrl)
+
+BEGIN_EVENT_TABLE(wxRichTextStyleComboCtrl, wxComboCtrl)
+ EVT_IDLE(wxRichTextStyleComboCtrl::OnIdle)
+END_EVENT_TABLE()
+
+bool wxRichTextStyleComboCtrl::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
+ const wxSize& size, long style)
+{
+ if (!wxComboCtrl::Create(parent, id, wxEmptyString, pos, size, style))
+ return false;
+
+ SetPopupMaxHeight(400);
+
+ m_stylePopup = new wxRichTextStyleComboPopup;
+
+ SetPopupControl(m_stylePopup);
+
+ return true;
+}
+
+/// Auto-select from style under caret in idle time
+
+// TODO: must be able to show italic, bold, combinations
+// in style box. Do we have a concept of automatic, temporary
+// styles that are added whenever we wish to show a style
+// that doesn't exist already? E.g. "Bold, Italic, Underline".
+// Word seems to generate these things on the fly.
+// If there's a named style already, it uses e.g. Heading1 + Bold, Italic
+// If you unembolden text in a style that has bold, it uses the
+// term "Not bold".
+// TODO: order styles alphabetically. This means indexes can change,
+// so need a different way to specify selections, i.e. by name.
+
+void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent& event)
+{
+ event.Skip();
+
+ if ( !m_stylePopup )
+ return;
+
+ wxRichTextCtrl * const richtext = GetRichTextCtrl();
+ if ( !richtext )
+ return;
+
+ if ( !IsPopupShown() && IsShownOnScreen() && wxWindow::FindFocus() != this )
+ {
+ wxString styleName =
+ wxRichTextStyleListBox::GetStyleToShowInIdleTime(richtext, m_stylePopup->GetStyleType());
+
+ wxString currentValue = GetValue();
+ if (!styleName.IsEmpty())
+ {
+ // Don't do the selection if it's already set
+ if (currentValue == styleName)
+ return;
+
+ SetValue(styleName);
+ }
+ else if (!currentValue.IsEmpty())
+ SetValue(wxEmptyString);
+ }
+}
+
#endif
+ // wxUSE_COMBOCTRL
#endif
// wxUSE_HTML
#endif
// wxUSE_RICHTEXT
-