Fixed bugs in, and added operators and copy constructors to, style

sheet classes.
Now merges base, paragraph and content styles dynamically on
display or layout so that we can distinguish between them. This
means appling a paragraph style that has character formatting
doesn't wipe out the original content formatting. The old-style
static method can be enabled by setting wxRICHTEXT_USE_DYNAMIC_STYLES
to 0 in richtextbuffer.h.
The default style is initially empty, so that adding text
reflects the base and paragraph styles. Setting the default style
doesn't merge with the previous setting, but BeginStyle does.
Adding new paragraphs is now sensitive to the previous paragraph's
style and also whether its style has a next-paragraph style indication.
Added wxRichTextCtrl::ApplyStyleSheet which reapplies styles to
paragraphs with named styles.
Added style application command to sample to demonstrate how
styles can be changed and reapplied without affecting content
character formatting.
Fixed some range bugs in UI feedback and clipboard copying and pasting.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41501 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart 2006-09-29 08:53:23 +00:00
parent 81c330c6f0
commit fe5aa22c17
7 changed files with 765 additions and 129 deletions

View File

@ -102,6 +102,10 @@
#include "wx/cmdproc.h"
#include "wx/txtstrm.h"
// Experimental dynamic styles to avoid user-specific character styles from being
// overwritten by paragraph styles.
#define wxRICHTEXT_USE_DYNAMIC_STYLES 1
/*!
* File types
*/
@ -161,6 +165,13 @@ class WXDLLIMPEXP_RICHTEXT wxTextAttrEx;
#define wxRICHTEXT_FORMATTED 0x01
#define wxRICHTEXT_UNFORMATTED 0x02
/*!
* Flags for text insertion
*/
#define wxRICHTEXT_INSERT_NONE 0x00
#define wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE 0x01
/*!
* Extra formatting flags not in wxTextAttr
*/
@ -378,6 +389,9 @@ public:
// Assignment from a wxTextAttrEx object.
void operator= (const wxTextAttrEx& attr);
// Equality test
bool operator== (const wxRichTextAttr& attr) const;
// Making a wxTextAttrEx object.
operator wxTextAttrEx () const ;
@ -853,13 +867,13 @@ public:
virtual void Reset();
/// Convenience function to add a paragraph of text
virtual wxRichTextRange AddParagraph(const wxString& text);
virtual wxRichTextRange AddParagraph(const wxString& text, wxTextAttrEx* paraStyle = NULL);
/// Convenience function to add an image
virtual wxRichTextRange AddImage(const wxImage& image);
virtual wxRichTextRange AddImage(const wxImage& image, wxTextAttrEx* paraStyle = NULL);
/// Adds multiple paragraphs, based on newlines.
virtual wxRichTextRange AddParagraphs(const wxString& text);
virtual wxRichTextRange AddParagraphs(const wxString& text, wxTextAttrEx* paraStyle = NULL);
/// Get the line at the given position. If caretPosition is true, the position is
/// a caret position, which is normally a smaller number.
@ -916,10 +930,18 @@ public:
virtual bool SetStyle(const wxRichTextRange& range, const wxRichTextAttr& style, bool withUndo = true);
virtual bool SetStyle(const wxRichTextRange& range, const wxTextAttrEx& style, bool withUndo = true);
/// Get the text attributes for this position.
/// Get the conbined text attributes for this position.
virtual bool GetStyle(long position, wxTextAttrEx& style);
virtual bool GetStyle(long position, wxRichTextAttr& style);
/// Get the content (uncombined) attributes for this position.
virtual bool GetUncombinedStyle(long position, wxTextAttrEx& style);
virtual bool GetUncombinedStyle(long position, wxRichTextAttr& style);
/// Implementation helper for GetStyle. If combineStyles is true, combine base, paragraph and
/// context attributes.
virtual bool DoGetStyle(long position, wxTextAttrEx& style, bool combineStyles = true);
/// Test if this whole range has character attributes of the specified kind. If any
/// of the attributes are different within the range, the test fails. You
/// can use this to implement, for example, bold button updating. style must have
@ -945,6 +967,9 @@ public:
/// Make a copy of the fragment corresponding to the given range, putting it in 'fragment'.
virtual bool CopyFragment(const wxRichTextRange& range, wxRichTextFragment& fragment);
/// Apply the style sheet to the buffer, for example if the styles have changed.
virtual bool ApplyStyleSheet(wxRichTextStyleSheet* styleSheet);
/// Copy
void Copy(const wxRichTextParagraphLayoutBox& obj);
@ -1161,7 +1186,7 @@ public:
// Implementation
/// Apply paragraph styles such as centering to the wrapped lines
virtual void ApplyParagraphStyle(const wxRect& rect);
virtual void ApplyParagraphStyle(const wxTextAttrEx& attr, const wxRect& rect);
/// Insert text at the given position
virtual bool InsertText(long pos, const wxString& text);
@ -1196,6 +1221,13 @@ public:
/// Clear remaining unused line objects, if any
bool ClearUnusedLines(int lineCount);
/// Get combined attributes of the base style, paragraph style and character style. We use this to dynamically
/// retrieve the actual style.
wxTextAttrEx GetCombinedAttributes(const wxTextAttr& contentStyle) const;
/// Get combined attributes of the base style and paragraph style.
wxTextAttrEx GetCombinedAttributes() const;
protected:
/// The lines that make up the wrapped paragraph
wxRichTextLineList m_cachedLines;
@ -1269,7 +1301,7 @@ public:
/// Clone
virtual wxRichTextObject* Clone() const { return new wxRichTextPlainText(*this); }
private:
bool DrawTabbedString(wxDC& dc,const wxRect& rect,wxString& str, wxCoord& x, wxCoord& y, bool selected);
bool DrawTabbedString(wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect, wxString& str, wxCoord& x, wxCoord& y, bool selected);
protected:
wxString m_text;
@ -1623,13 +1655,13 @@ public:
virtual wxRichTextObject* Clone() const { return new wxRichTextBuffer(*this); }
/// Submit command to insert the given text
bool InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl);
bool InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags = 0);
/// Submit command to insert a newline
bool InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl);
bool InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl, int flags = 0);
/// Submit command to insert the given image
bool InsertImageWithUndo(long pos, const wxRichTextImageBlock& imageBlock, wxRichTextCtrl* ctrl);
bool InsertImageWithUndo(long pos, const wxRichTextImageBlock& imageBlock, wxRichTextCtrl* ctrl, int flags = 0);
/// Submit command to delete this range
bool DeleteRangeWithUndo(const wxRichTextRange& range, long initialCaretPosition, long newCaretPositon, wxRichTextCtrl* ctrl);
@ -1638,6 +1670,11 @@ public:
void Modify(bool modify = true) { m_modified = modify; }
bool IsModified() const { return m_modified; }
/// Get the style that is appropriate for a new paragraph at this position.
/// If the previous paragraph has a paragraph style name, look up the next-paragraph
/// style.
wxRichTextAttr GetStyleForNewParagraph(long pos, bool caretPosition = false) const;
/// Dumps contents of buffer for debugging purposes
virtual void Dump();
virtual void Dump(wxTextOutputStream& stream) { wxRichTextParagraphLayoutBox::Dump(stream); }

View File

@ -188,6 +188,12 @@ public:
virtual bool GetStyle(long position, wxTextAttr& style);
virtual bool GetStyle(long position, wxTextAttrEx& style);
virtual bool GetStyle(long position, wxRichTextAttr& style);
/// Get the content (uncombined) attributes for this position.
virtual bool GetUncombinedStyle(long position, wxTextAttr& style);
virtual bool GetUncombinedStyle(long position, wxTextAttrEx& style);
virtual bool GetUncombinedStyle(long position, wxRichTextAttr& style);
virtual bool SetDefaultStyle(const wxTextAttrEx& style);
virtual bool SetDefaultStyle(const wxTextAttr& style);
@ -530,6 +536,9 @@ public:
void SetStyleSheet(wxRichTextStyleSheet* styleSheet) { GetBuffer().SetStyleSheet(styleSheet); }
wxRichTextStyleSheet* GetStyleSheet() const { return GetBuffer().GetStyleSheet(); }
/// Apply the style sheet to the buffer, for example if the styles have changed.
bool ApplyStyleSheet(wxRichTextStyleSheet* styleSheet = NULL);
// Command handlers
void Command(wxCommandEvent& event);
@ -595,8 +604,6 @@ public:
/// Scrolling
void OnScroll(wxScrollWinEvent& event);
// Implementation
/// Set font, and also default attributes
virtual bool SetFont(const wxFont& font);
@ -717,6 +724,8 @@ public:
SetCaretPositionForDefaultStyle(GetCaretPosition());
}
// Implementation
#if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
WX_FORWARD_TO_SCROLL_HELPER()
#endif
@ -845,4 +854,3 @@ typedef void (wxEvtHandler::*wxRichTextEventFunction)(wxRichTextEvent&);
#endif
// _WX_RICHTEXTCTRL_H_

View File

@ -47,10 +47,15 @@ public:
// Constructors
wxRichTextStyleDefinition(const wxRichTextStyleDefinition& def) { Copy(def); }
wxRichTextStyleDefinition(const wxString& name = wxEmptyString) { Init(); m_name = name; }
virtual ~wxRichTextStyleDefinition() {}
void Init() {}
void Copy(const wxRichTextStyleDefinition& def);
bool Eq(const wxRichTextStyleDefinition& def) const;
void operator =(const wxRichTextStyleDefinition& def) { Copy(def); }
bool operator ==(const wxRichTextStyleDefinition& def) const { return Eq(def); }
/// The name of the style.
void SetName(const wxString& name) { m_name = name; }
@ -82,6 +87,7 @@ public:
// Constructors
wxRichTextCharacterStyleDefinition(const wxRichTextCharacterStyleDefinition& def): wxRichTextStyleDefinition(def) {}
wxRichTextCharacterStyleDefinition(const wxString& name = wxEmptyString):
wxRichTextStyleDefinition(name) {}
virtual ~wxRichTextCharacterStyleDefinition() {}
@ -100,6 +106,7 @@ public:
// Constructors
wxRichTextParagraphStyleDefinition(const wxRichTextParagraphStyleDefinition& def): wxRichTextStyleDefinition(def) { m_nextStyle = def.m_nextStyle; }
wxRichTextParagraphStyleDefinition(const wxString& name = wxEmptyString):
wxRichTextStyleDefinition(name) {}
virtual ~wxRichTextParagraphStyleDefinition() {}
@ -108,6 +115,10 @@ public:
void SetNextStyle(const wxString& name) { m_nextStyle = name; }
const wxString& GetNextStyle() const { return m_nextStyle; }
void Copy(const wxRichTextParagraphStyleDefinition& def);
void operator =(const wxRichTextParagraphStyleDefinition& def) { Copy(def); }
bool operator ==(const wxRichTextParagraphStyleDefinition& def) const;
protected:
/// The next style to use when adding a paragraph after this style.
@ -124,29 +135,39 @@ class WXDLLIMPEXP_RICHTEXT wxRichTextStyleSheet: public wxObject
public:
/// Constructors
wxRichTextStyleSheet(const wxRichTextStyleSheet& sheet) { Copy(sheet); }
wxRichTextStyleSheet() { Init(); }
virtual ~wxRichTextStyleSheet() { DeleteStyles(); }
/// Initialisation
void Init();
/// Copy
void Copy(const wxRichTextStyleSheet& sheet);
/// Assignment
void operator=(const wxRichTextStyleSheet& sheet) { Copy(sheet); }
/// Equality
bool operator==(const wxRichTextStyleSheet& sheet) const;
/// Add a definition to the character style list
bool AddCharacterStyle(wxRichTextCharacterStyleDefinition* def) { return AddStyle(m_characterStyleDefinitions, def); }
bool AddCharacterStyle(wxRichTextCharacterStyleDefinition* def);
/// Add a definition to the paragraph style list
bool AddParagraphStyle(wxRichTextParagraphStyleDefinition* def) { return AddStyle(m_paragraphStyleDefinitions, def); }
bool AddParagraphStyle(wxRichTextParagraphStyleDefinition* def);
/// Remove a character style
bool RemoveCharacterStyle(wxRichTextStyleDefinition* def, bool deleteStyle = false) { return RemoveStyle(m_characterStyleDefinitions, def, deleteStyle); }
/// Remove a paragraph style
bool RemoveParagraphStyle(wxRichTextStyleDefinition* def, bool deleteStyle = false) { return RemoveStyle(m_characterStyleDefinitions, def, deleteStyle); }
bool RemoveParagraphStyle(wxRichTextStyleDefinition* def, bool deleteStyle = false) { return RemoveStyle(m_paragraphStyleDefinitions, def, deleteStyle); }
/// Find a character definition by name
wxRichTextCharacterStyleDefinition* FindCharacterStyle(const wxString& name) const { return (wxRichTextCharacterStyleDefinition*) FindStyle(m_characterStyleDefinitions, name); }
/// Find a paragraph definition by name
wxRichTextParagraphStyleDefinition* FindParagraphStyle(const wxString& name) const { return (wxRichTextParagraphStyleDefinition*) FindStyle(m_characterStyleDefinitions, name); }
wxRichTextParagraphStyleDefinition* FindParagraphStyle(const wxString& name) const { return (wxRichTextParagraphStyleDefinition*) FindStyle(m_paragraphStyleDefinitions, name); }
/// Return the number of character styes.
size_t GetCharacterStyleCount() const { return m_characterStyleDefinitions.GetCount(); }

View File

@ -139,6 +139,8 @@ public:
void OnViewHTML(wxCommandEvent& event);
void OnSwitchStyleSheets(wxCommandEvent& event);
// Forward command events to the current rich text control, if any
bool ProcessEvent(wxEvent& event);
@ -179,7 +181,12 @@ enum
ID_FORMAT_LINE_SPACING_DOUBLE,
ID_FORMAT_LINE_SPACING_SINGLE,
ID_VIEW_HTML
ID_VIEW_HTML,
ID_SWITCH_STYLE_SHEETS,
ID_RICHTEXT_CTRL,
ID_RICHTEXT_STYLE_LIST,
ID_RICHTEXT_STYLE_COMBO
};
// ----------------------------------------------------------------------------
@ -225,6 +232,7 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_FORMAT_PARAGRAPH_SPACING_LESS, MyFrame::OnParagraphSpacingLess)
EVT_MENU(ID_VIEW_HTML, MyFrame::OnViewHTML)
EVT_MENU(ID_SWITCH_STYLE_SHEETS, MyFrame::OnSwitchStyleSheets)
END_EVENT_TABLE()
// Create a new application object: this macro will allow wxWidgets to create
@ -442,6 +450,8 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
formatMenu->Append(ID_FORMAT_LINE_SPACING_DOUBLE, _("Double Line Spacing"));
formatMenu->AppendSeparator();
formatMenu->Append(ID_FORMAT_FONT, _("&Font..."));
formatMenu->AppendSeparator();
formatMenu->Append(ID_SWITCH_STYLE_SHEETS, _("&Switch Style Sheets"));
// now append the freshly created menu to the menu bar...
wxMenuBar *menuBar = new wxMenuBar();
@ -490,7 +500,7 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
toolBar->AddSeparator();
toolBar->AddTool(ID_FORMAT_FONT, wxBitmap(font_xpm), wxNullBitmap, false, -1, -1, (wxObject *) NULL, _("Font"));
wxRichTextStyleComboCtrl* combo = new wxRichTextStyleComboCtrl(toolBar, wxID_ANY, wxDefaultPosition, wxSize(200, -1));
wxRichTextStyleComboCtrl* combo = new wxRichTextStyleComboCtrl(toolBar, ID_RICHTEXT_STYLE_COMBO, wxDefaultPosition, wxSize(200, -1));
toolBar->AddControl(combo);
toolBar->Realize();
@ -501,16 +511,18 @@ MyFrame::MyFrame(const wxString& title, wxWindowID id, const wxPoint& pos,
wxFont boldFont = wxFont(12, wxROMAN, wxNORMAL, wxBOLD);
wxFont italicFont = wxFont(12, wxROMAN, wxITALIC, wxNORMAL);
m_richTextCtrl = new wxRichTextCtrl(splitter, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS);
m_richTextCtrl = new wxRichTextCtrl(splitter, ID_RICHTEXT_CTRL, wxEmptyString, wxDefaultPosition, wxSize(200, 200), wxVSCROLL|wxHSCROLL|wxNO_BORDER|wxWANTS_CHARS);
wxFont font(12, wxROMAN, wxNORMAL, wxNORMAL);
m_richTextCtrl->SetFont(font);
m_richTextCtrl->SetStyleSheet(wxGetApp().GetStyleSheet());
combo->SetStyleSheet(wxGetApp().GetStyleSheet());
combo->SetRichTextCtrl(m_richTextCtrl);
combo->UpdateStyles();
wxRichTextStyleListBox* styleListBox = new wxRichTextStyleListBox(splitter, wxID_ANY);
wxRichTextStyleListBox* styleListBox = new wxRichTextStyleListBox(splitter, ID_RICHTEXT_STYLE_LIST);
wxSize display = wxGetDisplaySize();
if ( is_pda && ( display.GetWidth() < display.GetHeight() ) )
@ -1073,3 +1085,58 @@ void MyFrame::OnViewHTML(wxCommandEvent& WXUNUSED(event))
dialog.ShowModal();
}
// Demonstrates how you can change the style sheets and have the changes
// reflected in the control content without wiping out character formatting.
void MyFrame::OnSwitchStyleSheets(wxCommandEvent& WXUNUSED(event))
{
static wxRichTextStyleSheet* gs_AlternateStyleSheet = NULL;
wxRichTextCtrl* ctrl = (wxRichTextCtrl*) FindWindow(ID_RICHTEXT_CTRL);
wxRichTextStyleListBox* styleList = (wxRichTextStyleListBox*) FindWindow(ID_RICHTEXT_STYLE_LIST);
wxRichTextStyleComboCtrl* styleCombo = (wxRichTextStyleComboCtrl*) FindWindow(ID_RICHTEXT_STYLE_COMBO);
wxRichTextStyleSheet* sheet = ctrl->GetStyleSheet();
// One-time creation of an alternate style sheet
if (!gs_AlternateStyleSheet)
{
gs_AlternateStyleSheet = new wxRichTextStyleSheet(*sheet);
// Make some modifications
for (int i = 0; i < (int) gs_AlternateStyleSheet->GetParagraphStyleCount(); i++)
{
wxRichTextParagraphStyleDefinition* def = gs_AlternateStyleSheet->GetParagraphStyle(i);
if (def->GetStyle().HasTextColour())
def->GetStyle().SetTextColour(*wxBLUE);
if (def->GetStyle().HasAlignment())
{
if (def->GetStyle().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
def->GetStyle().SetAlignment(wxTEXT_ALIGNMENT_RIGHT);
else if (def->GetStyle().GetAlignment() == wxTEXT_ALIGNMENT_LEFT)
def->GetStyle().SetAlignment(wxTEXT_ALIGNMENT_CENTRE);
}
if (def->GetStyle().HasLeftIndent())
{
def->GetStyle().SetLeftIndent(def->GetStyle().GetLeftIndent() * 2);
}
}
}
// Switch sheets
wxRichTextStyleSheet* tmp = gs_AlternateStyleSheet;
gs_AlternateStyleSheet = sheet;
sheet = tmp;
ctrl->SetStyleSheet(sheet);
ctrl->ApplyStyleSheet(sheet); // Makes the control reflect the new style definitions
styleList->SetStyleSheet(sheet);
styleList->UpdateStyles();
styleCombo->SetStyleSheet(sheet);
styleCombo->UpdateStyles();
}

View File

@ -81,11 +81,12 @@ void wxRichTextObject::Copy(const wxRichTextObject& obj)
m_range = obj.m_range;
m_attributes = obj.m_attributes;
m_descent = obj.m_descent;
/*
if (!m_attributes.GetFont().Ok())
wxLogDebug(wxT("No font!"));
if (!obj.m_attributes.GetFont().Ok())
wxLogDebug(wxT("Parent has no font!"));
*/
}
void wxRichTextObject::SetMargins(int margin)
@ -221,7 +222,9 @@ void wxRichTextCompositeObject::Copy(const wxRichTextCompositeObject& obj)
while (node)
{
wxRichTextObject* child = node->GetData();
m_children.Append(child->Clone());
wxRichTextObject* newChild = child->Clone();
newChild->SetParent(this);
m_children.Append(newChild);
node = node->GetNext();
}
@ -869,16 +872,23 @@ wxSize wxRichTextParagraphLayoutBox::GetLineSizeAtPosition(long pos, bool caretP
/// Convenience function to add a paragraph of text
wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraph(const wxString& text)
wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraph(const wxString& text, wxTextAttrEx* paraStyle)
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
// Don't use the base style, just the default style, and the base style will
// be combined at display time
wxTextAttrEx style(GetDefaultStyle());
#else
wxTextAttrEx style(GetAttributes());
// Apply default style. If the style has no attributes set,
// then the attributes will remain the 'basic style' (i.e. the
// layout box's style).
wxRichTextApplyStyle(style, GetDefaultStyle());
#endif
wxRichTextParagraph* para = new wxRichTextParagraph(text, this, & style);
if (paraStyle)
para->SetAttributes(*paraStyle);
AppendChild(para);
@ -889,9 +899,15 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraph(const wxString& text)
}
/// Adds multiple paragraphs, based on newlines.
wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text)
wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text, wxTextAttrEx* paraStyle)
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
// Don't use the base style, just the default style, and the base style will
// be combined at display time
wxTextAttrEx style(GetDefaultStyle());
#else
wxTextAttrEx style(GetAttributes());
//wxLogDebug("Initial style = %s", style.GetFont().GetFaceName());
//wxLogDebug("Initial size = %d", style.GetFont().GetPointSize());
@ -902,6 +918,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
//wxLogDebug("Style after applying default style = %s", style.GetFont().GetFaceName());
//wxLogDebug("Size after applying default style = %d", style.GetFont().GetPointSize());
#endif
wxRichTextParagraph* firstPara = NULL;
wxRichTextParagraph* lastPara = NULL;
@ -916,6 +933,8 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
if (ch == wxT('\n') || ch == wxT('\r'))
{
wxRichTextParagraph* para = new wxRichTextParagraph(line, this, & style);
if (paraStyle)
para->SetAttributes(*paraStyle);
AppendChild(para);
if (!firstPara)
@ -931,6 +950,9 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
if (!line.empty())
{
lastPara = new wxRichTextParagraph(line, this, & style);
if (paraStyle)
lastPara->SetAttributes(*paraStyle);
//wxLogDebug("Para Face = %s", lastPara->GetAttributes().GetFont().GetFaceName());
AppendChild(lastPara);
}
@ -952,19 +974,28 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
}
/// Convenience function to add an image
wxRichTextRange wxRichTextParagraphLayoutBox::AddImage(const wxImage& image)
wxRichTextRange wxRichTextParagraphLayoutBox::AddImage(const wxImage& image, wxTextAttrEx* paraStyle)
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
// Don't use the base style, just the default style, and the base style will
// be combined at display time
wxTextAttrEx style(GetDefaultStyle());
#else
wxTextAttrEx style(GetAttributes());
// Apply default style. If the style has no attributes set,
// then the attributes will remain the 'basic style' (i.e. the
// layout box's style).
wxRichTextApplyStyle(style, GetDefaultStyle());
#endif
wxRichTextParagraph* para = new wxRichTextParagraph(this, & style);
AppendChild(para);
para->AppendChild(new wxRichTextImage(image, this));
if (paraStyle)
para->SetAttributes(*paraStyle);
UpdateRanges();
SetDirty(true);
@ -1112,7 +1143,9 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm
if (finalPara->GetChildCount() == 0)
{
wxRichTextPlainText* text = new wxRichTextPlainText(wxEmptyString);
#if !wxRICHTEXT_USE_DYNAMIC_STYLES
text->SetAttributes(finalPara->GetAttributes());
#endif
finalPara->AppendChild(text);
}
@ -1387,8 +1420,8 @@ wxString wxRichTextParagraphLayoutBox::GetTextForRange(const wxRichTextRange& ra
wxRichTextObject* child = node->GetData();
if (!child->GetRange().IsOutside(range))
{
if (lineCount > 0)
text += wxT("\n");
// if (lineCount > 0)
// text += wxT("\n");
wxRichTextRange childRange = range;
childRange.LimitTo(child->GetRange());
@ -1396,6 +1429,9 @@ wxString wxRichTextParagraphLayoutBox::GetTextForRange(const wxRichTextRange& ra
text += childText;
if (childRange.GetEnd() == child->GetRange().GetEnd())
text += wxT("\n");
lineCount ++;
}
node = node->GetNext();
@ -1557,7 +1593,15 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
if (paragraphStyle)
wxRichTextApplyStyle(newPara->GetAttributes(), style);
#if wxRICHTEXT_USE_DYNAMIC_STYLES
// If applying paragraph styles dynamically, don't change the text objects' attributes
// since they will computed as needed. Only apply the character styling if it's _only_
// character styling. This policy is subject to change and might be put under user control.
if (!paragraphStyle && characterStyle && range.GetStart() != newPara->GetRange().GetEnd())
#else
if (characterStyle && range.GetStart() != newPara->GetRange().GetEnd())
#endif
{
wxRichTextRange childRange(range);
childRange.LimitTo(newPara->GetRange());
@ -1635,44 +1679,102 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
/// Get the text attributes for this position.
bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxTextAttrEx& style)
{
wxRichTextObject* obj wxDUMMY_INITIALIZE(NULL);
return DoGetStyle(position, style, true);
}
if (style.IsParagraphStyle())
obj = GetParagraphAtPosition(position);
else
obj = GetLeafObjectAtPosition(position);
if (obj)
/// Get the text attributes for this position.
bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxRichTextAttr& style)
{
style = obj->GetAttributes();
wxTextAttrEx textAttrEx(style);
if (GetStyle(position, textAttrEx))
{
style = textAttrEx;
return true;
}
else
return false;
}
/// Get the text attributes for this position.
bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxRichTextAttr& style)
/// Get the content (uncombined) attributes for this position.
bool wxRichTextParagraphLayoutBox::GetUncombinedStyle(long position, wxTextAttrEx& style)
{
return DoGetStyle(position, style, false);
}
bool wxRichTextParagraphLayoutBox::GetUncombinedStyle(long position, wxRichTextAttr& style)
{
wxTextAttrEx textAttrEx(style);
if (GetUncombinedStyle(position, textAttrEx))
{
style = textAttrEx;
return true;
}
else
return false;
}
/// Implementation helper for GetStyle. If combineStyles is true, combine base, paragraph and
/// context attributes.
bool wxRichTextParagraphLayoutBox::DoGetStyle(long position, wxTextAttrEx& style, bool combineStyles)
{
wxRichTextObject* obj wxDUMMY_INITIALIZE(NULL);
if (style.IsParagraphStyle())
{
obj = GetParagraphAtPosition(position);
else
obj = GetLeafObjectAtPosition(position);
if (obj)
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
if (combineStyles)
{
// Start with the base style
style = GetAttributes();
// Apply the paragraph style
wxRichTextApplyStyle(style, obj->GetAttributes());
}
else
style = obj->GetAttributes();
#else
style = obj->GetAttributes();
#endif
return true;
}
else
return false;
}
else
{
obj = GetLeafObjectAtPosition(position);
if (obj)
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
if (combineStyles)
{
wxRichTextParagraph* para = wxDynamicCast(obj->GetParent(), wxRichTextParagraph);
style = para ? para->GetCombinedAttributes(obj->GetAttributes()) : obj->GetAttributes();
}
else
style = obj->GetAttributes();
#else
style = obj->GetAttributes();
#endif
return true;
}
else
return false;
}
return false;
}
/// Set default style
bool wxRichTextParagraphLayoutBox::SetDefaultStyle(const wxTextAttrEx& style)
{
// I don't think the default style should be combined with the previous
// default style.
m_defaultAttributes = style;
#if 0
// keep the old attributes if the new style doesn't specify them unless the
// new style is empty - then reset m_defaultStyle (as there is no other way
// to do it)
@ -1680,7 +1782,7 @@ bool wxRichTextParagraphLayoutBox::SetDefaultStyle(const wxTextAttrEx& style)
m_defaultAttributes = style;
else
m_defaultAttributes = wxTextAttrEx::CombineEx(style, m_defaultAttributes, NULL);
#endif
return true;
}
@ -1715,7 +1817,12 @@ bool wxRichTextParagraphLayoutBox::HasCharacterAttributes(const wxRichTextRange&
if (!child->GetRange().IsOutside(range) && child->IsKindOf(CLASSINFO(wxRichTextPlainText)))
{
foundCount ++;
if (wxTextAttrEqPartial(child->GetAttributes(), style, style.GetFlags()))
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxTextAttrEx textAttr = para->GetCombinedAttributes(child->GetAttributes());
#else
const wxTextAttrEx& textAttr = child->GetAttributes();
#endif
if (wxTextAttrEqPartial(textAttr, style, style.GetFlags()))
matchingCount ++;
}
@ -1759,8 +1866,16 @@ bool wxRichTextParagraphLayoutBox::HasParagraphAttributes(const wxRichTextRange&
if (!para->GetRange().IsOutside(range))
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxTextAttrEx textAttr = GetAttributes();
// Apply the paragraph style
wxRichTextApplyStyle(textAttr, para->GetAttributes());
#else
const wxTextAttrEx& textAttr = para->GetAttributes();
#endif
foundCount ++;
if (wxTextAttrEqPartial(para->GetAttributes(), style, style.GetFlags()))
if (wxTextAttrEqPartial(textAttr, style, style.GetFlags()))
matchingCount ++;
}
}
@ -1829,6 +1944,40 @@ wxRichTextRange wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagrap
return range;
}
/// Apply the style sheet to the buffer, for example if the styles have changed.
bool wxRichTextParagraphLayoutBox::ApplyStyleSheet(wxRichTextStyleSheet* styleSheet)
{
wxASSERT(styleSheet != NULL);
if (!styleSheet)
return false;
int foundCount = 0;
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
wxRichTextParagraph* para = wxDynamicCast(node->GetData(), wxRichTextParagraph);
wxASSERT (para != NULL);
if (para)
{
if (!para->GetAttributes().GetParagraphStyleName().IsEmpty())
{
wxRichTextParagraphStyleDefinition* def = styleSheet->FindParagraphStyle(para->GetAttributes().GetParagraphStyleName());
if (def)
{
para->GetAttributes() = def->GetStyle();
foundCount ++;
}
}
}
node = node->GetNext();
}
return foundCount != 0;
}
/*!
* wxRichTextFragment class declaration
* This is a lind of paragraph layout box used for storing
@ -1886,18 +2035,24 @@ wxRichTextParagraph::~wxRichTextParagraph()
/// Draw the item
bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), const wxRichTextRange& selectionRange, const wxRect& WXUNUSED(rect), int WXUNUSED(descent), int style)
{
// Draw the bullet, if any
if (GetAttributes().GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
{
if (GetAttributes().GetLeftSubIndent() != 0)
{
int spaceBeforePara = ConvertTenthsMMToPixels(dc, GetAttributes().GetParagraphSpacingBefore());
// int spaceAfterPara = ConvertTenthsMMToPixels(dc, GetAttributes().GetParagraphSpacingAfter());
int leftIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetLeftIndent());
// int leftSubIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetLeftSubIndent());
// int rightIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetRightIndent());
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxTextAttrEx attr = GetCombinedAttributes();
#else
const wxTextAttrEx& attr = GetAttributes();
#endif
if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_BITMAP)
// Draw the bullet, if any
if (attr.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
{
if (attr.GetLeftSubIndent() != 0)
{
int spaceBeforePara = ConvertTenthsMMToPixels(dc, attr.GetParagraphSpacingBefore());
// int spaceAfterPara = ConvertTenthsMMToPixels(dc, attr.GetParagraphSpacingAfter());
int leftIndent = ConvertTenthsMMToPixels(dc, attr.GetLeftIndent());
// int leftSubIndent = ConvertTenthsMMToPixels(dc, attr.GetLeftSubIndent());
// int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
if (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_BITMAP)
{
// TODO
}
@ -1906,11 +2061,11 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range),
wxString bulletText = GetBulletText();
if (!bulletText.empty())
{
if (GetAttributes().GetFont().Ok())
dc.SetFont(GetAttributes().GetFont());
if (attr.GetFont().Ok())
dc.SetFont(attr.GetFont());
if (GetAttributes().GetTextColour().Ok())
dc.SetTextForeground(GetAttributes().GetTextColour());
if (attr.GetTextColour().Ok())
dc.SetTextForeground(attr.GetTextColour());
dc.SetBackgroundMode(wxTRANSPARENT);
@ -1994,29 +2149,35 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range),
/// Lay the item out
bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxTextAttrEx attr = GetCombinedAttributes();
#else
const wxTextAttrEx& attr = GetAttributes();
#endif
// ClearLines();
// Increase the size of the paragraph due to spacing
int spaceBeforePara = ConvertTenthsMMToPixels(dc, GetAttributes().GetParagraphSpacingBefore());
int spaceAfterPara = ConvertTenthsMMToPixels(dc, GetAttributes().GetParagraphSpacingAfter());
int leftIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetLeftIndent());
int leftSubIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetLeftSubIndent());
int rightIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetRightIndent());
int spaceBeforePara = ConvertTenthsMMToPixels(dc, attr.GetParagraphSpacingBefore());
int spaceAfterPara = ConvertTenthsMMToPixels(dc, attr.GetParagraphSpacingAfter());
int leftIndent = ConvertTenthsMMToPixels(dc, attr.GetLeftIndent());
int leftSubIndent = ConvertTenthsMMToPixels(dc, attr.GetLeftSubIndent());
int rightIndent = ConvertTenthsMMToPixels(dc, attr.GetRightIndent());
int lineSpacing = 0;
// Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc.
if (GetAttributes().GetLineSpacing() > 10 && GetAttributes().GetFont().Ok())
if (attr.GetLineSpacing() > 10 && attr.GetFont().Ok())
{
dc.SetFont(GetAttributes().GetFont());
lineSpacing = (ConvertTenthsMMToPixels(dc, dc.GetCharHeight()) * GetAttributes().GetLineSpacing())/10;
dc.SetFont(attr.GetFont());
lineSpacing = (ConvertTenthsMMToPixels(dc, dc.GetCharHeight()) * attr.GetLineSpacing())/10;
}
// Available space for text on each line differs.
int availableTextSpaceFirstLine = rect.GetWidth() - leftIndent - rightIndent;
// Bullets start the text at the same position as subsequent lines
if (GetAttributes().GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
if (attr.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
availableTextSpaceFirstLine -= leftSubIndent;
int availableTextSpaceSubsequentLines = rect.GetWidth() - leftIndent - rightIndent - leftSubIndent;
@ -2027,7 +2188,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
// If we have a bullet in this paragraph, the start position for the first line's text
// is actually leftIndent + leftSubIndent.
if (GetAttributes().GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
if (attr.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
startPositionFirstLine = startPositionSubsequentLines;
//bool restrictWidth = wxRichTextHasStyle(style, wxRICHTEXT_FIXED_WIDTH);
@ -2175,8 +2336,8 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
if (lineHeight == 0)
{
if (GetAttributes().GetFont().Ok())
dc.SetFont(GetAttributes().GetFont());
if (attr.GetFont().Ok())
dc.SetFont(attr.GetFont());
lineHeight = dc.GetCharHeight();
}
if (maxDescent == 0)
@ -2196,7 +2357,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
ClearUnusedLines(lineCount);
// Apply styles to wrapped lines
ApplyParagraphStyle(rect);
ApplyParagraphStyle(attr, rect);
SetCachedSize(wxSize(maxWidth, currentPosition.y + spaceBeforePara + spaceAfterPara));
@ -2206,9 +2367,9 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
}
/// Apply paragraph styles, such as centering, to wrapped lines
void wxRichTextParagraph::ApplyParagraphStyle(const wxRect& rect)
void wxRichTextParagraph::ApplyParagraphStyle(const wxTextAttrEx& attr, const wxRect& rect)
{
if (!GetAttributes().HasAlignment())
if (!attr.HasAlignment())
return;
wxRichTextLineList::compatibility_iterator node = m_cachedLines.GetFirst();
@ -2220,12 +2381,12 @@ void wxRichTextParagraph::ApplyParagraphStyle(const wxRect& rect)
wxSize size = line->GetSize();
// centering, right-justification
if (GetAttributes().HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE)
{
pos.x = (rect.GetWidth() - size.x)/2 + pos.x;
line->SetPosition(pos);
}
else if (GetAttributes().HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
else if (attr.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT)
{
pos.x = rect.GetRight() - size.x;
line->SetPosition(pos);
@ -2873,6 +3034,39 @@ bool wxRichTextParagraph::ClearUnusedLines(int lineCount)
return true;
}
/// Get combined attributes of the base style, paragraph style and character style. We use this to dynamically
/// retrieve the actual style.
wxTextAttrEx wxRichTextParagraph::GetCombinedAttributes(const wxTextAttr& contentStyle) const
{
wxTextAttrEx attr;
wxRichTextBuffer* buf = wxDynamicCast(GetParent(), wxRichTextBuffer);
if (buf)
{
attr = buf->GetBasicStyle();
wxRichTextApplyStyle(attr, GetAttributes());
}
else
attr = GetAttributes();
wxRichTextApplyStyle(attr, contentStyle);
return attr;
}
/// Get combined attributes of the base style and paragraph style.
wxTextAttrEx wxRichTextParagraph::GetCombinedAttributes() const
{
wxTextAttrEx attr;
wxRichTextBuffer* buf = wxDynamicCast(GetParent(), wxRichTextBuffer);
if (buf)
{
attr = buf->GetBasicStyle();
wxRichTextApplyStyle(attr, GetAttributes());
}
else
attr = GetAttributes();
return attr;
}
/*!
* wxRichTextLine
@ -2937,6 +3131,15 @@ wxRichTextPlainText::wxRichTextPlainText(const wxString& text, wxRichTextObject*
/// Draw the item
bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int descent, int WXUNUSED(style))
{
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxRichTextParagraph* para = wxDynamicCast(GetParent(), wxRichTextParagraph);
wxASSERT (para != NULL);
wxTextAttrEx textAttr(para ? para->GetCombinedAttributes(GetAttributes()) : GetAttributes());
#else
wxTextAttrEx textAttr(GetAttributes());
#endif
int offset = GetRange().GetStart();
long len = range.GetLength();
@ -2950,19 +3153,19 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
// Test for the optimized situations where all is selected, or none
// is selected.
if (GetAttributes().GetFont().Ok())
dc.SetFont(GetAttributes().GetFont());
if (textAttr.GetFont().Ok())
dc.SetFont(textAttr.GetFont());
// (a) All selected.
if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
{
DrawTabbedString(dc, rect,stringChunk, x, y, true);
DrawTabbedString(dc, textAttr, rect, stringChunk, x, y, true);
}
// (b) None selected.
else if (selectionRange.GetEnd() < range.GetStart() || selectionRange.GetStart() > range.GetEnd())
{
// Draw all unselected
DrawTabbedString(dc, rect,stringChunk, x, y, false);
DrawTabbedString(dc, textAttr, rect, stringChunk, x, y, false);
}
else
{
@ -2981,7 +3184,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 - offset), (int)fragmentLen);
wxString stringFragment = m_text.Mid(r1 - offset, fragmentLen);
DrawTabbedString(dc, rect,stringFragment, x, y, false);
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
}
// 2. Selected chunk, if any.
@ -2995,7 +3198,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 - offset), (int)fragmentLen);
wxString stringFragment = m_text.Mid(s1 - offset, fragmentLen);
DrawTabbedString(dc, rect,stringFragment, x, y, true);
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, true);
}
// 3. Remaining unselected chunk, if any
@ -3009,16 +3212,16 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 - offset), (int)fragmentLen);
wxString stringFragment = m_text.Mid(s2 - offset, fragmentLen);
DrawTabbedString(dc, rect,stringFragment, x, y, false);
DrawTabbedString(dc, textAttr, rect, stringFragment, x, y, false);
}
}
return true;
}
bool wxRichTextPlainText::DrawTabbedString(wxDC& dc,const wxRect& rect,wxString& str, wxCoord& x, wxCoord& y, bool selected)
bool wxRichTextPlainText::DrawTabbedString(wxDC& dc, const wxTextAttrEx& attr, const wxRect& rect,wxString& str, wxCoord& x, wxCoord& y, bool selected)
{
wxArrayInt tab_array = GetAttributes().GetTabs();
wxArrayInt tab_array = attr.GetTabs();
if (tab_array.IsEmpty())
{
// create a default tab list at 10 mm each.
@ -3049,7 +3252,7 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc,const wxRect& rect,wxString&
}
else
{
dc.SetTextForeground(GetAttributes().GetTextColour());
dc.SetTextForeground(attr.GetTextColour());
dc.SetBackgroundMode(wxTRANSPARENT);
}
@ -3091,11 +3294,21 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc,const wxRect& rect,wxString&
return true;
}
/// Lay the item out
bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXUNUSED(style))
{
if (GetAttributes().GetFont().Ok())
dc.SetFont(GetAttributes().GetFont());
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxRichTextParagraph* para = wxDynamicCast(GetParent(), wxRichTextParagraph);
wxASSERT (para != NULL);
wxTextAttrEx textAttr(para ? para->GetCombinedAttributes(GetAttributes()) : GetAttributes());
#else
wxTextAttrEx textAttr(GetAttributes());
#endif
if (textAttr.GetFont().Ok())
dc.SetFont(textAttr.GetFont());
wxCoord w, h;
dc.GetTextExtent(m_text, & w, & h, & m_descent);
@ -3119,12 +3332,21 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
if (!range.IsWithin(GetRange()))
return false;
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxRichTextParagraph* para = wxDynamicCast(GetParent(), wxRichTextParagraph);
wxASSERT (para != NULL);
wxTextAttrEx textAttr(para ? para->GetCombinedAttributes(GetAttributes()) : GetAttributes());
#else
wxTextAttrEx textAttr(GetAttributes());
#endif
// Always assume unformatted text, since at this level we have no knowledge
// of line breaks - and we don't need it, since we'll calculate size within
// formatted text by doing it in chunks according to the line ranges
if (GetAttributes().GetFont().Ok())
dc.SetFont(GetAttributes().GetFont());
if (textAttr.GetFont().Ok())
dc.SetFont(textAttr.GetFont());
int startPos = range.GetStart() - GetRange().GetStart();
long len = range.GetLength();
@ -3134,7 +3356,7 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
if (stringChunk.Find(wxT('\t')) >= 0)
{
// the string has a tab
wxArrayInt tab_array = GetAttributes().GetTabs();
wxArrayInt tab_array = textAttr.GetTabs();
if (tab_array.IsEmpty())
{
// create a default tab list at 10 mm each.
@ -3322,12 +3544,28 @@ void wxRichTextBuffer::Reset()
}
/// Submit command to insert the given text
bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl)
bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags)
{
wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Text"), wxRICHTEXT_INSERT, this, ctrl, false);
action->GetNewParagraphs().AddParagraphs(text);
if (action->GetNewParagraphs().GetChildCount() == 1)
wxTextAttrEx* p = NULL;
wxTextAttrEx paraAttr;
if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
{
paraAttr = GetStyleForNewParagraph(pos);
if (!paraAttr.IsDefault())
p = & paraAttr;
}
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxTextAttrEx attr(GetDefaultStyle());
#else
wxTextAttrEx attr(GetBasicStyle());
wxRichTextApplyStyle(attr, GetDefaultStyle());
#endif
action->GetNewParagraphs().AddParagraphs(text, p);
if (action->GetNewParagraphs().GetChildCount() == 1 && text.Find(wxT("\n")) == wxNOT_FOUND)
action->GetNewParagraphs().SetPartialParagraph(true);
action->SetPosition(pos);
@ -3341,12 +3579,25 @@ bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRich
}
/// Submit command to insert the given text
bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl)
bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl, int flags)
{
wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Text"), wxRICHTEXT_INSERT, this, ctrl, false);
wxTextAttrEx* p = NULL;
wxTextAttrEx paraAttr;
if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
{
paraAttr = GetStyleForNewParagraph(pos);
if (!paraAttr.IsDefault())
p = & paraAttr;
}
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxTextAttrEx attr(GetDefaultStyle());
#else
wxTextAttrEx attr(GetBasicStyle());
wxRichTextApplyStyle(attr, GetDefaultStyle());
#endif
wxRichTextParagraph* newPara = new wxRichTextParagraph(wxEmptyString, this, & attr);
action->GetNewParagraphs().AppendChild(newPara);
@ -3354,6 +3605,9 @@ bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl)
action->GetNewParagraphs().SetPartialParagraph(false);
action->SetPosition(pos);
if (p)
newPara->SetAttributes(*p);
// Set the range we'll need to delete in Undo
action->SetRange(wxRichTextRange(pos, pos));
@ -3363,14 +3617,30 @@ bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl)
}
/// Submit command to insert the given image
bool wxRichTextBuffer::InsertImageWithUndo(long pos, const wxRichTextImageBlock& imageBlock, wxRichTextCtrl* ctrl)
bool wxRichTextBuffer::InsertImageWithUndo(long pos, const wxRichTextImageBlock& imageBlock, wxRichTextCtrl* ctrl, int flags)
{
wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Image"), wxRICHTEXT_INSERT, this, ctrl, false);
wxTextAttrEx* p = NULL;
wxTextAttrEx paraAttr;
if (flags & wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE)
{
paraAttr = GetStyleForNewParagraph(pos);
if (!paraAttr.IsDefault())
p = & paraAttr;
}
#if wxRICHTEXT_USE_DYNAMIC_STYLES
wxTextAttrEx attr(GetDefaultStyle());
#else
wxTextAttrEx attr(GetBasicStyle());
wxRichTextApplyStyle(attr, GetDefaultStyle());
#endif
wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
if (p)
newPara->SetAttributes(*p);
wxRichTextImage* imageObject = new wxRichTextImage(imageBlock, newPara);
newPara->AppendChild(imageObject);
action->GetNewParagraphs().AppendChild(newPara);
@ -3388,6 +3658,39 @@ bool wxRichTextBuffer::InsertImageWithUndo(long pos, const wxRichTextImageBlock&
return true;
}
/// Get the style that is appropriate for a new paragraph at this position.
/// If the previous paragraph has a paragraph style name, look up the next-paragraph
/// style.
wxRichTextAttr wxRichTextBuffer::GetStyleForNewParagraph(long pos, bool caretPosition) const
{
wxRichTextParagraph* para = GetParagraphAtPosition(pos, caretPosition);
if (para)
{
if (!para->GetAttributes().GetParagraphStyleName().IsEmpty() && GetStyleSheet())
{
wxRichTextParagraphStyleDefinition* paraDef = GetStyleSheet()->FindParagraphStyle(para->GetAttributes().GetParagraphStyleName());
if (paraDef && !paraDef->GetNextStyle().IsEmpty())
{
wxRichTextParagraphStyleDefinition* nextParaDef = GetStyleSheet()->FindParagraphStyle(paraDef->GetNextStyle());
if (nextParaDef)
return nextParaDef->GetStyle();
}
}
wxRichTextAttr attr(para->GetAttributes());
int flags = attr.GetFlags();
// Eliminate character styles
flags &= ( (~ wxTEXT_ATTR_FONT) |
(~ wxTEXT_ATTR_TEXT_COLOUR) |
(~ wxTEXT_ATTR_BACKGROUND_COLOUR) );
attr.SetFlags(flags);
return attr;
}
else
return wxRichTextAttr();
}
/// Submit command to delete this range
bool wxRichTextBuffer::DeleteRangeWithUndo(const wxRichTextRange& range, long initialCaretPosition, long WXUNUSED(newCaretPositon), wxRichTextCtrl* ctrl)
{
@ -4611,22 +4914,43 @@ bool wxRichTextApplyStyle(wxTextAttrEx& destStyle, const wxTextAttrEx& style)
wxFont font = destStyle.GetFont();
if (style.GetFlags() & wxTEXT_ATTR_FONT_FACE)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_FACE);
font.SetFaceName(style.GetFont().GetFaceName());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_SIZE)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_SIZE);
font.SetPointSize(style.GetFont().GetPointSize());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_ITALIC)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_ITALIC);
font.SetStyle(style.GetFont().GetStyle());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_WEIGHT)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_WEIGHT);
font.SetWeight(style.GetFont().GetWeight());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_UNDERLINE)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_UNDERLINE);
font.SetUnderlined(style.GetFont().GetUnderlined());
}
if (font != destStyle.GetFont())
{
int oldFlags = destStyle.GetFlags();
destStyle.SetFont(font);
destStyle.SetFlags(oldFlags);
}
}
if ( style.GetTextColour().Ok() && style.HasTextColour())
@ -4685,7 +5009,6 @@ bool wxRichTextApplyStyle(wxRichTextAttr& destStyle, const wxTextAttrEx& style)
bool wxRichTextApplyStyle(wxTextAttrEx& destStyle, const wxRichTextAttr& style)
{
// Whole font. Avoiding setting individual attributes if possible, since
// it recreates the font each time.
if ((style.GetFlags() & (wxTEXT_ATTR_FONT)) == (wxTEXT_ATTR_FONT))
@ -4698,22 +5021,43 @@ bool wxRichTextApplyStyle(wxTextAttrEx& destStyle, const wxRichTextAttr& style)
wxFont font = destStyle.GetFont();
if (style.GetFlags() & wxTEXT_ATTR_FONT_FACE)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_FACE);
font.SetFaceName(style.GetFontFaceName());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_SIZE)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_SIZE);
font.SetPointSize(style.GetFontSize());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_ITALIC)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_ITALIC);
font.SetStyle(style.GetFontStyle());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_WEIGHT)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_WEIGHT);
font.SetWeight(style.GetFontWeight());
}
if (style.GetFlags() & wxTEXT_ATTR_FONT_UNDERLINE)
{
destStyle.SetFlags(destStyle.GetFlags() | wxTEXT_ATTR_FONT_UNDERLINE);
font.SetUnderlined(style.GetFontUnderlined());
}
if (font != destStyle.GetFont())
{
int oldFlags = destStyle.GetFlags();
destStyle.SetFont(font);
destStyle.SetFlags(oldFlags);
}
}
if ( style.GetTextColour().Ok() && style.HasTextColour())
@ -4867,6 +5211,33 @@ wxRichTextAttr::operator wxTextAttrEx () const
return attr;
}
// Equality test
bool wxRichTextAttr::operator== (const wxRichTextAttr& attr) const
{
return GetFlags() == attr.GetFlags() &&
GetTextColour() == attr.GetTextColour() &&
GetBackgroundColour() == attr.GetBackgroundColour() &&
GetAlignment() == attr.GetAlignment() &&
GetLeftIndent() == attr.GetLeftIndent() &&
GetLeftSubIndent() == attr.GetLeftSubIndent() &&
GetRightIndent() == attr.GetRightIndent() &&
//GetTabs() == attr.GetTabs() &&
GetParagraphSpacingAfter() == attr.GetParagraphSpacingAfter() &&
GetParagraphSpacingBefore() == attr.GetParagraphSpacingBefore() &&
GetLineSpacing() == attr.GetLineSpacing() &&
GetCharacterStyleName() == attr.GetCharacterStyleName() &&
GetParagraphStyleName() == attr.GetParagraphStyleName() &&
m_fontSize == attr.m_fontSize &&
m_fontStyle == attr.m_fontStyle &&
m_fontWeight == attr.m_fontWeight &&
m_fontUnderlined == attr.m_fontUnderlined &&
m_fontFaceName == attr.m_fontFaceName;
}
// Copy to a wxTextAttr
void wxRichTextAttr::CopyTo(wxTextAttrEx& attr) const
{
@ -4877,7 +5248,6 @@ void wxRichTextAttr::CopyTo(wxTextAttrEx& attr) const
attr.SetLeftIndent(GetLeftIndent(), GetLeftSubIndent());
attr.SetRightIndent(GetRightIndent());
attr.SetFont(CreateFont());
attr.SetFlags(GetFlags()); // Important: set after SetFont, since SetFont sets flags
attr.SetParagraphSpacingAfter(m_paragraphSpacingAfter);
attr.SetParagraphSpacingBefore(m_paragraphSpacingBefore);
@ -4888,6 +5258,7 @@ void wxRichTextAttr::CopyTo(wxTextAttrEx& attr) const
attr.SetCharacterStyleName(m_characterStyleName);
attr.SetParagraphStyleName(m_paragraphStyleName);
attr.SetFlags(GetFlags()); // Important: set after SetFont and others, since they set flags
}
// Create font from font attributes.

View File

@ -22,11 +22,8 @@
#include "wx/richtext/richtextstyles.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#include "wx/settings.h"
#include "wx/menu.h"
#include "wx/intl.h"
#include "wx/log.h"
#include "wx/stopwatch.h"
#endif
#include "wx/textfile.h"
@ -145,10 +142,13 @@ bool wxRichTextCtrl::Create( wxWindow* parent, wxWindowID id, const wxString& va
attributes.SetBackgroundColour(*wxWHITE);
attributes.SetAlignment(wxTEXT_ALIGNMENT_LEFT);
attributes.SetFlags(wxTEXT_ATTR_ALL);
SetDefaultStyle(attributes);
SetBasicStyle(attributes);
// The default attributes will be merged with base attributes, so
// can be empty to begin with
wxTextAttrEx defaultAttributes;
SetDefaultStyle(defaultAttributes);
SetBackgroundColour(*wxWHITE);
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
@ -466,7 +466,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
DeleteSelectedContent(& newPos);
GetBuffer().InsertNewlineWithUndo(newPos+1, this);
GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_RETURN,
@ -545,7 +545,7 @@ void wxRichTextCtrl::OnChar(wxKeyEvent& event)
DeleteSelectedContent(& newPos);
wxString str = (wxChar) event.GetKeyCode();
GetBuffer().InsertTextWithUndo(newPos+1, str, this);
GetBuffer().InsertTextWithUndo(newPos+1, str, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
EndBatchUndo();
@ -1744,6 +1744,7 @@ void wxRichTextCtrl::WriteText(const wxString& value)
void wxRichTextCtrl::DoWriteText(const wxString& value, bool WXUNUSED(selectionOnly))
{
wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Unix);
GetBuffer().InsertTextWithUndo(m_caretPosition+1, valueDos, this);
}
@ -1811,7 +1812,7 @@ void wxRichTextCtrl::Copy()
{
if (CanCopy())
{
wxRichTextRange range = GetSelectionRange();
wxRichTextRange range = GetInternalSelectionRange();
GetBuffer().CopyToClipboard(range);
}
}
@ -1820,7 +1821,7 @@ void wxRichTextCtrl::Cut()
{
if (CanCut())
{
wxRichTextRange range = GetSelectionRange();
wxRichTextRange range = GetInternalSelectionRange();
GetBuffer().CopyToClipboard(range);
DeleteSelectedContent();
@ -2258,7 +2259,7 @@ const wxTextAttr& wxRichTextCtrl::GetDefaultStyle() const
bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style)
{
wxTextAttrEx attr;
wxTextAttrEx attr(style);
if (GetBuffer().GetStyle(position, attr))
{
style = attr;
@ -2278,6 +2279,30 @@ bool wxRichTextCtrl::GetStyle(long position, wxRichTextAttr& style)
return GetBuffer().GetStyle(position, style);
}
/// Get the content (uncombined) attributes for this position.
bool wxRichTextCtrl::GetUncombinedStyle(long position, wxTextAttr& style)
{
wxTextAttrEx attr(style);
if (GetBuffer().GetUncombinedStyle(position, attr))
{
style = attr;
return true;
}
else
return false;
}
bool wxRichTextCtrl::GetUncombinedStyle(long position, wxTextAttrEx& style)
{
return GetBuffer().GetUncombinedStyle(position, style);
}
bool wxRichTextCtrl::GetUncombinedStyle(long position, wxRichTextAttr& style)
{
return GetBuffer().GetUncombinedStyle(position, style);
}
/// Set font, and also the buffer attributes
bool wxRichTextCtrl::SetFont(const wxFont& font)
{
@ -2290,7 +2315,15 @@ bool wxRichTextCtrl::SetFont(const wxFont& font)
wxTextAttrEx attr = GetBuffer().GetAttributes();
attr.SetFont(font);
GetBuffer().SetBasicStyle(attr);
#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
// Don't set the default style, since it will be inherited from
// the basic style.
GetBuffer().SetDefaultStyle(attr);
#endif
GetBuffer().Invalidate(wxRICHTEXT_ALL);
Refresh(false);
return true;
}
@ -2508,8 +2541,8 @@ bool wxRichTextCtrl::IsSelectionUnderlined()
// to see what the effect would be if we started typing.
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
long pos = GetAdjustedCaretPosition(GetCaretPosition());
if (GetStyle(pos, attr))
{
if (IsDefaultStyleShowing())
@ -2618,6 +2651,24 @@ void wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def)
SetAndShowDefaultStyle(attr);
}
/// Apply the style sheet to the buffer, for example if the styles have changed.
bool wxRichTextCtrl::ApplyStyleSheet(wxRichTextStyleSheet* styleSheet)
{
if (!styleSheet)
styleSheet = GetBuffer().GetStyleSheet();
if (!styleSheet)
return false;
if (GetBuffer().ApplyStyleSheet(styleSheet))
{
GetBuffer().Invalidate(wxRICHTEXT_ALL);
Refresh(false);
return true;
}
else
return false;
}
/// Sets the default style to the style under the cursor
bool wxRichTextCtrl::SetDefaultStyleToCursorStyle()
{
@ -2627,7 +2678,11 @@ bool wxRichTextCtrl::SetDefaultStyleToCursorStyle()
// If at the start of a paragraph, use the next position.
long pos = GetAdjustedCaretPosition(GetCaretPosition());
#if wxRICHTEXT_USE_DYNAMIC_STYLES
if (GetUncombinedStyle(pos, attr))
#else
if (GetStyle(pos, attr))
#endif
{
SetDefaultStyle(attr);
return true;

View File

@ -21,8 +21,7 @@
#include "wx/richtext/richtextstyles.h"
#ifndef WX_PRECOMP
#include "wx/dcclient.h"
#include "wx/module.h"
#include "wx/wx.h"
#endif
#include "wx/filename.h"
@ -35,6 +34,38 @@ IMPLEMENT_CLASS(wxRichTextStyleDefinition, wxObject)
IMPLEMENT_CLASS(wxRichTextCharacterStyleDefinition, wxRichTextStyleDefinition)
IMPLEMENT_CLASS(wxRichTextParagraphStyleDefinition, wxRichTextStyleDefinition)
/*!
* 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);
}
/*!
* The style manager
*/
@ -89,6 +120,48 @@ void wxRichTextStyleSheet::DeleteStyles()
WX_CLEAR_LIST(wxList, m_paragraphStyleDefinitions);
}
/// 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);
}
/// 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));
}
}
/// Equality
bool wxRichTextStyleSheet::operator==(const wxRichTextStyleSheet& WXUNUSED(sheet)) const
{
// TODO
return false;
}
#if wxUSE_HTML
/*!
* wxRichTextStyleListBox class declaration
@ -316,8 +389,10 @@ void wxRichTextStyleListBox::OnIdle(wxIdleEvent& event)
{
if (CanAutoSetSelection() && GetRichTextCtrl())
{
wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(GetRichTextCtrl()->GetCaretPosition());
wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(GetRichTextCtrl()->GetCaretPosition());
int adjustedCaretPos = GetRichTextCtrl()->GetAdjustedCaretPosition(GetRichTextCtrl()->GetCaretPosition());
wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(adjustedCaretPos);
wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(adjustedCaretPos);
wxString styleName;
@ -483,8 +558,10 @@ void wxRichTextStyleComboCtrl::OnIdle(wxIdleEvent& event)
{
if (GetRichTextCtrl() && !IsPopupShown())
{
wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(GetRichTextCtrl()->GetCaretPosition());
wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(GetRichTextCtrl()->GetCaretPosition());
int adjustedCaretPos = GetRichTextCtrl()->GetAdjustedCaretPosition(GetRichTextCtrl()->GetCaretPosition());
wxRichTextParagraph* para = GetRichTextCtrl()->GetBuffer().GetParagraphAtPosition(adjustedCaretPos);
wxRichTextObject* obj = GetRichTextCtrl()->GetBuffer().GetLeafObjectAtPosition(adjustedCaretPos);
wxString styleName;