Files
wxWidgets/src/richtext/richtextstyles.cpp
Julian Smart d2d0adc776 Added URL support to attribute objects and to wxRichTextCtrl,
generating a wxTextUrlEvent as appropriate.
Added outline list support and updated previews.
Added alignment support for bullets.
Added single right parenthesis support.
Added XML stylesheet reading/writing.
Changed SetBulletSymbol to SetBulletText so it can support
bullet text more generally (e.g. for cached outline list numbering)
Added wxRichTextRenderer to isolate e.g. bullet drawing and make
it customisable.
Added event handler support to wxRichTextBuffer.
Updated documentation.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42431 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2006-10-26 06:32:47 +00:00

1035 lines
29 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/richtext/richtextstyles.cpp
// Purpose: Style management for wxRichTextCtrl
// Author: Julian Smart
// Modified by:
// Created: 2005-09-30
// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_RICHTEXT
#include "wx/richtext/richtextstyles.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "wx/filename.h"
#include "wx/clipbrd.h"
#include "wx/wfstream.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)
/*!
* A definition
*/
void wxRichTextStyleDefinition::Copy(const wxRichTextStyleDefinition& def)
{
m_name = def.m_name;
m_baseStyle = def.m_baseStyle;
m_style = def.m_style;
}
bool wxRichTextStyleDefinition::Eq(const wxRichTextStyleDefinition& def) const
{
return (m_name == def.m_name && m_baseStyle == def.m_baseStyle && m_style == def.m_style);
}
/*!
* 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);
}
/*!
* 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)
{
int listLevel = FindLevelForIndent(indent);
wxRichTextAttr attr(*GetLevelAttributes(listLevel));
int oldLeftIndent = attr.GetLeftIndent();
int oldLeftSubIndent = attr.GetLeftSubIndent();
// First apply the overall paragraph style, if any
wxRichTextApplyStyle(attr, GetStyle());
// Then apply paragraph style, e.g. from paragraph style definition
wxRichTextApplyStyle(attr, 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)
{
int listLevel = FindLevelForIndent(indent);
return GetCombinedStyleForLevel(listLevel);
}
/// Combine the base and list style, using the given indent (from which
/// an appropriate level is found)
wxRichTextAttr wxRichTextListStyleDefinition::GetCombinedStyleForLevel(int listLevel)
{
wxRichTextAttr attr(*GetLevelAttributes(listLevel));
int oldLeftIndent = attr.GetLeftIndent();
int oldLeftSubIndent = attr.GetLeftSubIndent();
// Apply the overall paragraph style, if any
wxRichTextApplyStyle(attr, 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
bool wxRichTextStyleSheet::AddStyle(wxList& list, wxRichTextStyleDefinition* def)
{
if (!list.Find(def))
list.Append(def);
return true;
}
/// Remove a style
bool wxRichTextStyleSheet::RemoveStyle(wxList& list, wxRichTextStyleDefinition* def, bool deleteStyle)
{
wxList::compatibility_iterator node = list.Find(def);
if (node)
{
wxRichTextStyleDefinition* def = (wxRichTextStyleDefinition*) node->GetData();
list.Erase(node);
if (deleteStyle)
delete def;
return true;
}
else
return false;
}
/// Find a definition by name
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())
return def;
}
if (m_nextSheet && recurse)
return m_nextSheet->FindStyle(list, name, recurse);
return NULL;
}
/// Delete all styles
void wxRichTextStyleSheet::DeleteStyles()
{
WX_CLEAR_LIST(wxList, m_characterStyleDefinitions);
WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
WX_CLEAR_LIST(wxList, m_listStyleDefinitions);
}
/// 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);
}
/// 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));
}
}
/// Equality
bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
{
// TODO
return false;
}
#if wxUSE_HTML
/*!
* wxRichTextStyleListBox: a listbox to display styles.
*/
IMPLEMENT_CLASS(wxRichTextStyleListBox, wxHtmlListBox)
BEGIN_EVENT_TABLE(wxRichTextStyleListBox, wxHtmlListBox)
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)
{
Init();
Create(parent, id, pos, size, style);
}
bool wxRichTextStyleListBox::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos,
const wxSize& size, long style)
{
return wxHtmlListBox::Create(parent, id, pos, size, style);
}
wxRichTextStyleListBox::~wxRichTextStyleListBox()
{
}
/// Returns the HTML for this item
wxString wxRichTextStyleListBox::OnGetItem(size_t n) const
{
if (!GetStyleSheet())
return wxEmptyString;
wxRichTextStyleDefinition* def = GetStyle(n);
if (def)
return CreateHTML(def);
return wxEmptyString;
}
// Get style for index
wxRichTextStyleDefinition* wxRichTextStyleListBox::GetStyle(size_t i) const
{
if (!GetStyleSheet())
return NULL;
if (GetStyleType() == wxRICHTEXT_STYLE_ALL)
{
// First paragraph styles, then character, then list
if (i < GetStyleSheet()->GetParagraphStyleCount())
return GetStyleSheet()->GetParagraphStyle(i);
if ((i - GetStyleSheet()->GetParagraphStyleCount()) < GetStyleSheet()->GetCharacterStyleCount())
return GetStyleSheet()->GetCharacterStyle(i - GetStyleSheet()->GetParagraphStyleCount());
if ((i - GetStyleSheet()->GetParagraphStyleCount() - GetStyleSheet()->GetCharacterStyleCount()) < GetStyleSheet()->GetListStyleCount())
return GetStyleSheet()->GetListStyle(i - GetStyleSheet()->GetParagraphStyleCount() - GetStyleSheet()->GetCharacterStyleCount());
}
else if ((GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH) && (i < GetStyleSheet()->GetParagraphStyleCount()))
{
return GetStyleSheet()->GetParagraphStyle(i);
}
else if ((GetStyleType() == wxRICHTEXT_STYLE_CHARACTER) && (i < GetStyleSheet()->GetCharacterStyleCount()))
{
return GetStyleSheet()->GetCharacterStyle(i);
}
else if ((GetStyleType() == wxRICHTEXT_STYLE_LIST) && (i < GetStyleSheet()->GetListStyleCount()))
{
return GetStyleSheet()->GetListStyle(i);
}
return NULL;
}
/// Updates the list
void wxRichTextStyleListBox::UpdateStyles()
{
if (GetStyleSheet())
{
SetSelection(wxNOT_FOUND);
if (GetStyleType() == wxRICHTEXT_STYLE_ALL)
SetItemCount(GetStyleSheet()->GetParagraphStyleCount()+GetStyleSheet()->GetCharacterStyleCount()+GetStyleSheet()->GetListStyleCount());
else if (GetStyleType() == wxRICHTEXT_STYLE_PARAGRAPH)
SetItemCount(GetStyleSheet()->GetParagraphStyleCount());
else if (GetStyleType() == wxRICHTEXT_STYLE_CHARACTER)
SetItemCount(GetStyleSheet()->GetCharacterStyleCount());
else if (GetStyleType() == wxRICHTEXT_STYLE_LIST)
SetItemCount(GetStyleSheet()->GetListStyleCount());
Refresh();
if (GetItemCount() > 0)
{
SetSelection(0);
SendSelectedEvent();
}
}
}
// Get index for style name
int wxRichTextStyleListBox::GetIndexForStyle(const wxString& name) const
{
if (GetStyleSheet())
{
int count = GetItemCount();
int i;
for (i = 0; i < (int) count; i++)
{
wxRichTextStyleDefinition* def = GetStyle(i);
if (def->GetName() == name)
return i;
}
}
return -1;
}
/// Set selection for string
int wxRichTextStyleListBox::SetStyleSelection(const wxString& name)
{
int i = GetIndexForStyle(name);
if (i > -1)
SetSelection(i);
return i;
}
// Convert a colour to a 6-digit hex string
static wxString ColourToHexString(const wxColour& col)
{
wxString hex;
hex += wxDecToHex(col.Red());
hex += wxDecToHex(col.Green());
hex += wxDecToHex(col.Blue());
return hex;
}
/// Creates a suitable HTML fragment for a definition
wxString wxRichTextStyleListBox::CreateHTML(wxRichTextStyleDefinition* def) const
{
// TODO: indicate list format for list style types
wxString str(wxT("<table><tr>"));
if (def->GetStyle().GetLeftIndent() > 0)
{
wxClientDC dc((wxWindow*) this);
str << wxT("<td width=") << (ConvertTenthsMMToPixels(dc, def->GetStyle().GetLeftIndent())/2) << wxT("></td>");
}
str << wxT("<td nowrap>");
#ifdef __WXMSW__
int size = 3;
#else
int size = 4;
#endif
int stdFontSize = 12;
int thisFontSize = ((def->GetStyle().GetFlags() & wxTEXT_ATTR_FONT_SIZE) != 0) ? def->GetStyle().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 (def->GetStyle().GetTextColour().Ok())
str << wxT(" color=\"#") << ColourToHexString(def->GetStyle().GetTextColour()) << wxT("\"");
str << wxT(">");
bool hasBold = false;
bool hasItalic = false;
bool hasUnderline = false;
if (def->GetStyle().GetFontWeight() == wxBOLD)
hasBold = true;
if (def->GetStyle().GetFontStyle() == wxITALIC)
hasItalic = true;
if (def->GetStyle().GetFontUnderlined())
hasUnderline = true;
if (hasBold)
str << wxT("<b>");
if (hasItalic)
str << wxT("<i>");
if (hasUnderline)
str << wxT("<u>");
str += def->GetName();
if (hasUnderline)
str << wxT("</u>");
if (hasItalic)
str << wxT("</i>");
if (hasBold)
str << wxT("</b>");
str << wxT("</font>");
str += wxT("</td></tr></table>");
return str;
}
// Convert units in tends of a millimetre to device units
int wxRichTextStyleListBox::ConvertTenthsMMToPixels(wxDC& dc, int units) const
{
int ppi = dc.GetPPI().x;
// There are ppi pixels in 254.1 "1/10 mm"
double pixels = ((double) units * (double)ppi) / 254.1;
return (int) pixels;
}
void wxRichTextStyleListBox::OnLeftDown(wxMouseEvent& event)
{
wxVListBox::OnLeftDown(event);
int item = HitTest(event.GetPosition());
if (item != wxNOT_FOUND && GetApplyOnSelection())
ApplyStyle(item);
}
void wxRichTextStyleListBox::OnLeftDoubleClick(wxMouseEvent& event)
{
wxVListBox::OnLeftDown(event);
int item = HitTest(event.GetPosition());
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());
wxRichTextParagraph* para = ctrl->GetBuffer().GetParagraphAtPosition(adjustedCaretPos);
wxRichTextObject* obj = ctrl->GetBuffer().GetLeafObjectAtPosition(adjustedCaretPos);
wxString styleName;
// Take into account current default style just chosen by user
if (ctrl->IsDefaultStyleShowing())
{
if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
!ctrl->GetDefaultStyleEx().GetCharacterStyleName().IsEmpty())
styleName = ctrl->GetDefaultStyleEx().GetCharacterStyleName();
else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
!ctrl->GetDefaultStyleEx().GetParagraphStyleName().IsEmpty())
styleName = ctrl->GetDefaultStyleEx().GetParagraphStyleName();
else if ((styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
!ctrl->GetDefaultStyleEx().GetListStyleName().IsEmpty())
styleName = ctrl->GetDefaultStyleEx().GetListStyleName();
}
else if (obj && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_CHARACTER) &&
!obj->GetAttributes().GetCharacterStyleName().IsEmpty())
{
styleName = obj->GetAttributes().GetCharacterStyleName();
}
else if (para && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_PARAGRAPH) &&
!para->GetAttributes().GetParagraphStyleName().IsEmpty())
{
styleName = para->GetAttributes().GetParagraphStyleName();
}
else if (para && (styleType == wxRICHTEXT_STYLE_ALL || styleType == wxRICHTEXT_STYLE_LIST) &&
!para->GetAttributes().GetListStyleName().IsEmpty())
{
styleName = para->GetAttributes().GetListStyleName();
}
return styleName;
}
/// Auto-select from style under caret in idle time
void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
{
if (CanAutoSetSelection() && GetRichTextCtrl() && wxWindow::FindFocus() != this)
{
wxString styleName = GetStyleToShowInIdleTime(GetRichTextCtrl(), GetStyleType());
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())
{
GetRichTextCtrl()->ApplyStyle(def);
GetRichTextCtrl()->SetFocus();
}
}
}
/*!
* 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)
{
wxControl::Create(parent, id, pos, size, style);
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
if (size != wxDefaultSize)
SetBestFittingSize(size);
bool showSelector = ((style & wxRICHTEXTSTYLELIST_HIDE_TYPE_SELECTOR) == 0);
m_styleListBox = new wxRichTextStyleListBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, showSelector ? wxSIMPLE_BORDER : wxNO_BORDER);
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"));
m_styleChoice = new wxChoice(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, choices);
boxSizer->Add(m_styleListBox, 1, wxALL|wxEXPAND, 5);
boxSizer->Add(m_styleChoice, 0, wxALL|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;
}
wxRichTextStyleListCtrl::~wxRichTextStyleListCtrl()
{
}
/// 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->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;
}
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;
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)
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()
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::HitTest(event.GetPosition());
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)
{
if (GetRichTextCtrl() && !IsPopupShown() && m_stylePopup && wxWindow::FindFocus() != this)
{
wxString styleName = wxRichTextStyleListBox::GetStyleToShowInIdleTime(GetRichTextCtrl(), 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);
}
event.Skip();
}
#endif
// wxUSE_COMBOCTRL
#endif
// wxUSE_HTML
#endif
// wxUSE_RICHTEXT