Setting the current style from the UI is a mode that is cancelled when moving away

from the current caret position. This must be done to avoid confusing default
attributes and attributes at the current caret position, in normal use.
Style feedback now correct when caret is at the start of a paragraph (don't use
previous paragraph's style), and out-by-one style feedback bug fixed (start/end
of styled content).
Added ApplyStyle for applying a character or paragraph style.
Some coding style cleanup.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41169 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Julian Smart
2006-09-12 08:42:40 +00:00
parent 720a0aab26
commit ab14c7aa57
4 changed files with 157 additions and 75 deletions

View File

@@ -303,8 +303,8 @@ public:
bool HasParagraphSpacingAfter() const { return HasFlag(wxTEXT_ATTR_PARA_SPACING_AFTER); }
bool HasParagraphSpacingBefore() const { return HasFlag(wxTEXT_ATTR_PARA_SPACING_BEFORE); }
bool HasLineSpacing() const { return HasFlag(wxTEXT_ATTR_LINE_SPACING); }
bool HasCharacterStyleName() const { return HasFlag(wxTEXT_ATTR_CHARACTER_STYLE_NAME); }
bool HasParagraphStyleName() const { return HasFlag(wxTEXT_ATTR_PARAGRAPH_STYLE_NAME); }
bool HasCharacterStyleName() const { return HasFlag(wxTEXT_ATTR_CHARACTER_STYLE_NAME) || !m_characterStyleName.IsEmpty(); }
bool HasParagraphStyleName() const { return HasFlag(wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) || !m_paragraphStyleName.IsEmpty(); }
bool HasBulletStyle() const { return HasFlag(wxTEXT_ATTR_BULLET_STYLE); }
bool HasBulletNumber() const { return HasFlag(wxTEXT_ATTR_BULLET_NUMBER); }
bool HasBulletSymbol() const { return HasFlag(wxTEXT_ATTR_BULLET_SYMBOL); }
@@ -399,14 +399,14 @@ public:
void SetFlags(long flags) { m_flags = flags; }
void SetCharacterStyleName(const wxString& name) { m_characterStyleName = name; }
void SetParagraphStyleName(const wxString& name) { m_paragraphStyleName = name; }
void SetParagraphSpacingAfter(int spacing) { m_paragraphSpacingAfter = spacing; }
void SetParagraphSpacingBefore(int spacing) { m_paragraphSpacingBefore = spacing; }
void SetLineSpacing(int spacing) { m_lineSpacing = spacing; }
void SetBulletStyle(int style) { m_bulletStyle = style; }
void SetBulletNumber(int n) { m_bulletNumber = n; }
void SetBulletSymbol(wxChar symbol) { m_bulletSymbol = symbol; }
void SetCharacterStyleName(const wxString& name) { m_characterStyleName = name; m_flags |= wxTEXT_ATTR_CHARACTER_STYLE_NAME; }
void SetParagraphStyleName(const wxString& name) { m_paragraphStyleName = name; m_flags |= wxTEXT_ATTR_PARAGRAPH_STYLE_NAME; }
void SetParagraphSpacingAfter(int spacing) { m_paragraphSpacingAfter = spacing; m_flags |= wxTEXT_ATTR_PARA_SPACING_AFTER; }
void SetParagraphSpacingBefore(int spacing) { m_paragraphSpacingBefore = spacing; m_flags |= wxTEXT_ATTR_PARA_SPACING_BEFORE; }
void SetLineSpacing(int spacing) { m_lineSpacing = spacing; m_flags |= wxTEXT_ATTR_LINE_SPACING; }
void SetBulletStyle(int style) { m_bulletStyle = style; m_flags |= wxTEXT_ATTR_BULLET_STYLE; }
void SetBulletNumber(int n) { m_bulletNumber = n; m_flags |= wxTEXT_ATTR_BULLET_NUMBER; }
void SetBulletSymbol(wxChar symbol) { m_bulletSymbol = symbol; m_flags |= wxTEXT_ATTR_BULLET_NUMBER; }
const wxColour& GetTextColour() const { return m_colText; }
const wxColour& GetBackgroundColour() const { return m_colBack; }
@@ -449,8 +449,8 @@ public:
bool HasParagraphSpacingAfter() const { return (m_flags & wxTEXT_ATTR_PARA_SPACING_AFTER) != 0; }
bool HasParagraphSpacingBefore() const { return (m_flags & wxTEXT_ATTR_PARA_SPACING_BEFORE) != 0; }
bool HasLineSpacing() const { return (m_flags & wxTEXT_ATTR_LINE_SPACING) != 0; }
bool HasCharacterStyleName() const { return (m_flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) != 0; }
bool HasParagraphStyleName() const { return (m_flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) != 0; }
bool HasCharacterStyleName() const { return (m_flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) != 0 || !m_characterStyleName.IsEmpty(); }
bool HasParagraphStyleName() const { return (m_flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) != 0 || !m_paragraphStyleName.IsEmpty(); }
bool HasBulletStyle() const { return (m_flags & wxTEXT_ATTR_BULLET_STYLE) != 0; }
bool HasBulletNumber() const { return (m_flags & wxTEXT_ATTR_BULLET_NUMBER) != 0; }
bool HasBulletSymbol() const { return (m_flags & wxTEXT_ATTR_BULLET_SYMBOL) != 0; }

View File

@@ -20,7 +20,7 @@
#include "wx/caret.h"
#if wxCHECK_VERSION(2,7,0)
#define wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE 0
#define wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE 1
#else
#define wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE 0
#endif
@@ -29,6 +29,8 @@
#include "wx/textctrl.h"
#endif
class WXDLLIMPEXP_RICHTEXT wxRichTextStyleDefinition;
/*!
* Styles and flags
*/
@@ -508,6 +510,9 @@ public:
/// Apply alignment to the selection
virtual bool ApplyAlignmentToSelection(wxTextAttrAlignment alignment);
/// Apply a named style to the selection
virtual void ApplyStyle(wxRichTextStyleDefinition* def);
/// Set style sheet, if any.
void SetStyleSheet(wxRichTextStyleSheet* styleSheet) { GetBuffer().SetStyleSheet(styleSheet); }
wxRichTextStyleSheet* GetStyleSheet() const { return GetBuffer().GetStyleSheet(); }
@@ -630,6 +635,11 @@ public:
void SetCaretPosition(long position, bool showAtLineStart = false) ;
long GetCaretPosition() const { return m_caretPosition; }
/// The adjusted caret position is the character position adjusted to take
/// into account whether we're at the start of a paragraph, in which case
/// style information should be taken from the next position, not current one.
long GetAdjustedCaretPosition(long caretPos) const;
/// Move caret one visual step forward: this may mean setting a flag
/// and keeping the same position if we're going from the end of one line
/// to the start of the next, which may be the exact same caret position.
@@ -673,6 +683,27 @@ public:
/// Returns the first visible position in the current view
long GetFirstVisiblePosition() const;
/// Returns the caret position since the default formatting was changed. As
/// soon as this position changes, we no longer reflect the default style
/// in the UI. A value of -2 means that we should only reflect the style of the
/// content under the caret.
long GetCaretPositionForDefaultStyle() const { return m_caretPositionForDefaultStyle; }
/// Set the caret position for the default style that the user is selecting.
void SetCaretPositionForDefaultStyle(long pos) { m_caretPositionForDefaultStyle = pos; }
/// Should the UI reflect the default style chosen by the user, rather than the style under
/// the caret?
bool IsDefaultStyleShowing() const { return m_caretPositionForDefaultStyle != -2; }
/// Convenience function that tells the control to start reflecting the default
/// style, since the user is changing it.
void SetAndShowDefaultStyle(const wxRichTextAttr& attr)
{
SetDefaultStyle(attr);
SetCaretPositionForDefaultStyle(GetCaretPosition());
}
#if wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
WX_FORWARD_TO_SCROLL_HELPER()
#endif
@@ -703,6 +734,11 @@ private:
/// first caret position).
long m_caretPosition;
/// Caret position when the default formatting has been changed. As
/// soon as this position changes, we no longer reflect the default style
/// in the UI.
long m_caretPositionForDefaultStyle;
/// Selection range in character positions. -2, -2 means no selection.
wxRichTextRange m_selectionRange;

View File

@@ -2955,27 +2955,13 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
// (a) All selected.
if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
{/*
// Draw all selected
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
wxCoord w, h;
dc.GetTextExtent(stringChunk, & w, & h);
wxRect selRect(x, rect.y, w, rect.GetHeight());
dc.DrawRectangle(selRect);
dc.SetTextForeground(*wxWHITE);
dc.SetBackgroundMode(wxTRANSPARENT);
dc.DrawText(stringChunk, x, y);*/
{
DrawTabbedString(dc, rect,stringChunk, x, y, true);
}
// (b) None selected.
else if (selectionRange.GetEnd() < range.GetStart() || selectionRange.GetStart() > range.GetEnd())
{
// Draw all unselected
/*
dc.SetTextForeground(GetAttributes().GetTextColour());
dc.SetBackgroundMode(wxTRANSPARENT);
dc.DrawText(stringChunk, x, y);*/
DrawTabbedString(dc, rect,stringChunk, x, y, false);
}
else
@@ -2994,13 +2980,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
if (fragmentLen < 0)
wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 - offset), (int)fragmentLen);
wxString stringFragment = m_text.Mid(r1 - offset, fragmentLen);
/*
dc.SetTextForeground(GetAttributes().GetTextColour());
dc.DrawText(stringFragment, x, y);
wxCoord w, h;
dc.GetTextExtent(stringFragment, & w, & h);
x += w;*/
DrawTabbedString(dc, rect,stringFragment, x, y, false);
}
@@ -3014,18 +2994,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
if (fragmentLen < 0)
wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 - offset), (int)fragmentLen);
wxString stringFragment = m_text.Mid(s1 - offset, fragmentLen);
/*
wxCoord w, h;
dc.GetTextExtent(stringFragment, & w, & h);
wxRect selRect(x, rect.y, w, rect.GetHeight());
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.DrawRectangle(selRect);
dc.SetTextForeground(*wxWHITE);
dc.DrawText(stringFragment, x, y);
x += w;*/
DrawTabbedString(dc, rect,stringFragment, x, y, true);
}
@@ -3039,9 +3008,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
if (fragmentLen < 0)
wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 - offset), (int)fragmentLen);
wxString stringFragment = m_text.Mid(s2 - offset, fragmentLen);
/*
dc.SetTextForeground(GetAttributes().GetTextColour());
dc.DrawText(stringFragment, x, y);*/
DrawTabbedString(dc, rect,stringFragment, x, y, false);
}
}
@@ -3052,43 +3019,57 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
bool wxRichTextPlainText::DrawTabbedString(wxDC& dc,const wxRect& rect,wxString& str, wxCoord& x, wxCoord& y, bool selected)
{
wxArrayInt tab_array = GetAttributes().GetTabs();
if(tab_array.IsEmpty()){// create a default tab list at 10 mm each.
for( int i = 0; i < 20; ++i){
if (tab_array.IsEmpty())
{
// create a default tab list at 10 mm each.
for (int i = 0; i < 20; ++i)
{
tab_array.Add(i*100);
}
}
int map_mode = dc.GetMapMode();
dc.SetMapMode(wxMM_LOMETRIC );
int num_tabs = tab_array.GetCount();
for( int i = 0; i < num_tabs; ++i){
for (int i = 0; i < num_tabs; ++i)
{
tab_array[i] = dc.LogicalToDeviceXRel(tab_array[i]);
}
dc.SetMapMode(map_mode );
int next_tab_pos = -1;
int tab_pos = -1;
wxCoord w, h;
if(selected){
if(selected)
{
dc.SetBrush(*wxBLACK_BRUSH);
dc.SetPen(*wxBLACK_PEN);
dc.SetTextForeground(*wxWHITE);
dc.SetBackgroundMode(wxTRANSPARENT);
}
else{
else
{
dc.SetTextForeground(GetAttributes().GetTextColour());
dc.SetBackgroundMode(wxTRANSPARENT);
}
while(str.Find(wxT('\t')) >= 0){// the string has a tab
while (str.Find(wxT('\t')) >= 0)
{
// the string has a tab
// break up the string at the Tab
wxString stringChunk = str.BeforeFirst(wxT('\t'));
str = str.AfterFirst(wxT('\t'));
dc.GetTextExtent(stringChunk, & w, & h);
tab_pos = x + w;
bool not_found = true;
for( int i = 0; i < num_tabs && not_found; ++i){
for (int i = 0; i < num_tabs && not_found; ++i)
{
next_tab_pos = tab_array.Item(i);
if( next_tab_pos > tab_pos){
if (next_tab_pos > tab_pos)
{
not_found = false;
if(selected){
if (selected)
{
w = next_tab_pos - x;
wxRect selRect(x, rect.y, w, rect.GetHeight());
dc.DrawRectangle(selRect);
@@ -3100,7 +3081,8 @@ bool wxRichTextPlainText::DrawTabbedString(wxDC& dc,const wxRect& rect,wxString&
}
dc.GetTextExtent(str, & w, & h);
if(selected){
if (selected)
{
wxRect selRect(x, rect.y, w, rect.GetHeight());
dc.DrawRectangle(selRect);
}
@@ -3149,27 +3131,33 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
wxString stringChunk = m_text.Mid(startPos, (size_t) len);
wxCoord w, h;
int width = 0;
if(stringChunk.Find(wxT('\t')) >= 0){// the string has a tab
if (stringChunk.Find(wxT('\t')) >= 0)
{
// the string has a tab
wxArrayInt tab_array = GetAttributes().GetTabs();
if(tab_array.IsEmpty())
if (tab_array.IsEmpty())
{
// create a default tab list at 10 mm each.
for( int i = 0; i < 20; ++i)
for (int i = 0; i < 20; ++i)
{
tab_array.Add(i*100);
}
}
int map_mode = dc.GetMapMode();
dc.SetMapMode(wxMM_LOMETRIC );
int num_tabs = tab_array.GetCount();
for( int i = 0; i < num_tabs; ++i)
for (int i = 0; i < num_tabs; ++i)
{
tab_array[i] = dc.LogicalToDeviceXRel(tab_array[i]);
}
dc.SetMapMode(map_mode );
int next_tab_pos = -1;
while(stringChunk.Find(wxT('\t')) >= 0){// the string has a tab
while (stringChunk.Find(wxT('\t')) >= 0)
{
// the string has a tab
// break up the string at the Tab
wxString stringFragment = stringChunk.BeforeFirst(wxT('\t'));
stringChunk = stringChunk.AfterFirst(wxT('\t'));
@@ -3177,9 +3165,11 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
width += w;
int absolute_width = width + position.x;
bool not_found = true;
for( int i = 0; i < num_tabs && not_found; ++i){
for (int i = 0; i < num_tabs && not_found; ++i)
{
next_tab_pos = tab_array.Item(i);
if( next_tab_pos > absolute_width){
if (next_tab_pos > absolute_width)
{
not_found = false;
width = next_tab_pos - position.x;
}

View File

@@ -19,6 +19,7 @@
#if wxUSE_RICHTEXT
#include "wx/richtext/richtextctrl.h"
#include "wx/richtext/richtextstyles.h"
#ifndef WX_PRECOMP
#include "wx/settings.h"
@@ -186,6 +187,7 @@ void wxRichTextCtrl::Init()
m_fullLayoutTime = 0;
m_fullLayoutSavedPosition = 0;
m_delayedLayoutThreshold = wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD;
m_caretPositionForDefaultStyle = -2;
}
/// Call Freeze to prevent refresh
@@ -212,6 +214,7 @@ void wxRichTextCtrl::Clear()
m_buffer.Reset();
m_buffer.SetDirty(true);
m_caretPosition = -1;
m_caretPositionForDefaultStyle = -2;
m_caretAtLineStart = false;
m_selectionRange.SetRange(-2, -2);
@@ -1428,6 +1431,15 @@ void wxRichTextCtrl::OnIdle(wxIdleEvent& event)
ShowPosition(m_fullLayoutSavedPosition);
Refresh(false);
}
if (m_caretPositionForDefaultStyle != -2)
{
// If the caret position has changed, no longer reflect the default style
// in the UI.
if (GetCaretPosition() != m_caretPositionForDefaultStyle)
m_caretPositionForDefaultStyle = -2;
}
event.Skip();
}
@@ -1968,6 +1980,7 @@ void wxRichTextCtrl::MarkDirty()
void wxRichTextCtrl::DiscardEdits()
{
m_caretPositionForDefaultStyle = -2;
m_buffer.Modify(false);
m_buffer.GetCommandProcessor()->ClearCommands();
}
@@ -2420,9 +2433,12 @@ bool wxRichTextCtrl::IsSelectionBold() const
// to see what the effect would be if we started typing.
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
if (GetStyle(GetCaretPosition()+1, attr))
long pos = GetAdjustedCaretPosition(GetCaretPosition());
if (GetStyle(pos, attr))
{
wxRichTextApplyStyle(attr, GetDefaultStyleEx());
if (IsDefaultStyleShowing())
wxRichTextApplyStyle(attr, GetDefaultStyleEx());
return attr.GetFontWeight() == wxBOLD;
}
}
@@ -2447,9 +2463,12 @@ bool wxRichTextCtrl::IsSelectionItalics() const
// to see what the effect would be if we started typing.
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
if (GetStyle(GetCaretPosition()+1, attr))
long pos = GetAdjustedCaretPosition(GetCaretPosition());
if (GetStyle(pos, attr))
{
wxRichTextApplyStyle(attr, GetDefaultStyleEx());
if (IsDefaultStyleShowing())
wxRichTextApplyStyle(attr, GetDefaultStyleEx());
return attr.GetFontStyle() == wxITALIC;
}
}
@@ -2474,9 +2493,12 @@ bool wxRichTextCtrl::IsSelectionUnderlined() const
// to see what the effect would be if we started typing.
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
if (GetStyle(GetCaretPosition()+1, attr))
long pos = GetAdjustedCaretPosition(GetCaretPosition());
if (GetStyle(pos, attr))
{
wxRichTextApplyStyle(attr, GetDefaultStyleEx());
if (IsDefaultStyleShowing())
wxRichTextApplyStyle(attr, GetDefaultStyleEx());
return attr.GetFontUnderlined();
}
}
@@ -2493,7 +2515,7 @@ bool wxRichTextCtrl::ApplyBoldToSelection()
if (HasSelection())
return SetStyle(GetSelectionRange(), attr);
else
SetDefaultStyle(attr);
SetAndShowDefaultStyle(attr);
return true;
}
@@ -2507,7 +2529,7 @@ bool wxRichTextCtrl::ApplyItalicToSelection()
if (HasSelection())
return SetStyle(GetSelectionRange(), attr);
else
SetDefaultStyle(attr);
SetAndShowDefaultStyle(attr);
return true;
}
@@ -2521,7 +2543,7 @@ bool wxRichTextCtrl::ApplyUnderlineToSelection()
if (HasSelection())
return SetStyle(GetSelectionRange(), attr);
else
SetDefaultStyle(attr);
SetAndShowDefaultStyle(attr);
return true;
}
@@ -2562,13 +2584,35 @@ bool wxRichTextCtrl::ApplyAlignmentToSelection(wxTextAttrAlignment alignment)
return true;
}
/// Apply a named style to the selection
void wxRichTextCtrl::ApplyStyle(wxRichTextStyleDefinition* def)
{
// Flags are defined within each definition, so only certain
// attributes are applied.
wxRichTextAttr attr(def->GetStyle());
// Make sure the attr has the style name
if (def->IsKindOf(CLASSINFO(wxRichTextParagraphStyleDefinition)))
attr.SetParagraphStyleName(def->GetName());
else
attr.SetCharacterStyleName(def->GetName());
if (HasSelection())
SetStyle(GetSelectionRange(), attr);
else
SetAndShowDefaultStyle(attr);
}
/// Sets the default style to the style under the cursor
bool wxRichTextCtrl::SetDefaultStyleToCursorStyle()
{
wxTextAttrEx attr;
attr.SetFlags(wxTEXT_ATTR_CHARACTER);
if (GetStyle(GetCaretPosition(), attr))
// If at the start of a paragraph, use the next position.
long pos = GetAdjustedCaretPosition(GetCaretPosition());
if (GetStyle(pos, attr))
{
SetDefaultStyle(attr);
return true;
@@ -2587,5 +2631,17 @@ long wxRichTextCtrl::GetFirstVisiblePosition() const
return 0;
}
/// The adjusted caret position is the character position adjusted to take
/// into account whether we're at the start of a paragraph, in which case
/// style information should be taken from the next position, not current one.
long wxRichTextCtrl::GetAdjustedCaretPosition(long caretPos) const
{
wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(caretPos+1);
if (para && (caretPos+1 == para->GetRange().GetStart()))
caretPos ++;
return caretPos;
}
#endif
// wxUSE_RICHTEXT