#if wxUSE_RICHTEXT
#include "wx/richtext/richtextctrl.h"
+#include "wx/richtext/richtextstyles.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
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);
RecreateBuffer(size);
SetCursor(wxCursor(wxCURSOR_IBEAM));
-
+
if (!value.IsEmpty())
SetValue(value);
m_fullLayoutTime = 0;
m_fullLayoutSavedPosition = 0;
m_delayedLayoutThreshold = wxRICHTEXT_DEFAULT_DELAYED_LAYOUT_THRESHOLD;
+ m_caretPositionForDefaultStyle = -2;
}
/// Call Freeze to prevent refresh
m_buffer.Reset();
m_buffer.SetDirty(true);
m_caretPosition = -1;
+ m_caretPositionForDefaultStyle = -2;
m_caretAtLineStart = false;
m_selectionRange.SetRange(-2, -2);
+ SetScrollbars(0, 0, 0, 0, 0, 0);
+
if (m_freezeCount == 0)
{
SetupScrollbars();
SetupScrollbars();
}
- GetBuffer().Draw(dc, GetBuffer().GetRange(), GetSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
+ GetBuffer().Draw(dc, GetBuffer().GetRange(), GetInternalSelectionRange(), drawingArea, 0 /* descent */, 0 /* flags */);
}
if (GetCaret())
DeleteSelectedContent(& newPos);
- GetBuffer().InsertNewlineWithUndo(newPos+1, this);
+ GetBuffer().InsertNewlineWithUndo(newPos+1, this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_RETURN,
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();
int ppuX, ppuY;
GetScrollPixelsPerUnit(& ppuX, & ppuY);
- int startX, startY;
- GetViewStart(& startX, & startY);
- startX = 0;
- startY = startY * ppuY;
+ int startXUnits, startYUnits;
+ GetViewStart(& startXUnits, & startYUnits);
+ int startY = startYUnits * ppuY;
int sx = 0, sy = 0;
GetVirtualSize(& sx, & sy);
- sx = 0;
+ int sxUnits = 0;
+ int syUnits = 0;
if (ppuY != 0)
- sy = sy/ppuY;
+ syUnits = sy/ppuY;
wxRect rect = line->GetRect();
// Make it scroll so this item is at the bottom
// of the window
int y = rect.y - (clientSize.y - rect.height);
- y = (int) (0.5 + y/ppuY);
+ int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
+
+ // If we're still off the screen, scroll another line down
+ if ((rect.y + rect.height) > (clientSize.y + (yUnits*ppuY)))
+ yUnits ++;
- if (startY != y)
+ if (startYUnits != yUnits)
{
- SetScrollbars(ppuX, ppuY, sx, sy, 0, y);
+ SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
scrolled = true;
}
}
// Make it scroll so this item is at the top
// of the window
int y = rect.y ;
- y = (int) (0.5 + y/ppuY);
+ int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
- if (startY != y)
+ if (startYUnits != yUnits)
{
- SetScrollbars(ppuX, ppuY, sx, sy, 0, y);
+ SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
scrolled = true;
}
}
// Make it scroll so this item is at the top
// of the window
int y = rect.y ;
- y = (int) (0.5 + y/ppuY);
+ int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
- if (startY != y)
+ if (startYUnits != yUnits)
{
- SetScrollbars(ppuX, ppuY, sx, sy, 0, y);
+ SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
scrolled = true;
}
}
// Make it scroll so this item is at the bottom
// of the window
int y = rect.y - (clientSize.y - rect.height);
- y = (int) (0.5 + y/ppuY);
+ int yUnits = (int) (0.5 + ((float) y)/(float) ppuY);
- if (startY != y)
+ // If we're still off the screen, scroll another line down
+ if ((rect.y + rect.height) > (clientSize.y + (yUnits*ppuY)))
+ yUnits ++;
+
+ if (startYUnits != yUnits)
{
- SetScrollbars(ppuX, ppuY, sx, sy, 0, y);
+ SetScrollbars(ppuX, ppuY, sxUnits, syUnits, 0, yUnits);
scrolled = true;
}
}
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();
}
// TODO: reimplement scrolling so we scroll by line, not by fixed number
// of pixels. See e.g. wxVScrolledWindow for ideas.
- int pixelsPerUnit = 5; // 10;
+ int pixelsPerUnit = 5;
wxSize clientSize = GetClientSize();
int maxHeight = GetBuffer().GetCachedSize().y;
- int unitsY = maxHeight/pixelsPerUnit;
+ // Round up so we have at least maxHeight pixels
+ int unitsY = (int) (((float)maxHeight/(float)pixelsPerUnit) + 0.5);
int startX = 0, startY = 0;
if (!atTop)
GetViewStart(& startX, & startY);
int maxPositionX = 0; // wxMax(sz.x - clientSize.x, 0);
- int maxPositionY = (wxMax(maxHeight - clientSize.y, 0))/pixelsPerUnit;
+ int maxPositionY = (int) ((((float)(wxMax((unitsY*pixelsPerUnit) - clientSize.y, 0)))/((float)pixelsPerUnit)) + 0.5);
// Move to previous scroll position if
// possible
// file IO functions
// ----------------------------------------------------------------------------
-bool wxRichTextCtrl::LoadFile(const wxString& filename, int type)
+#if !wxRICHTEXT_DERIVES_FROM_TEXTCTRLBASE
+bool wxRichTextCtrl::LoadFile(const wxString& filename, int fileType)
{
- bool success = GetBuffer().LoadFile(filename, type);
+ return DoLoadFile(filename, fileType);
+}
+
+bool wxRichTextCtrl::SaveFile(const wxString& filename, int fileType)
+{
+ wxString filenameToUse = filename.empty() ? m_filename : filename;
+ if ( filenameToUse.empty() )
+ {
+ // what kind of message to give? is it an error or a program bug?
+ wxLogDebug(wxT("Can't save textctrl to file without filename."));
+
+ return false;
+ }
+
+ return DoSaveFile(filenameToUse, fileType);
+}
+#endif
+
+bool wxRichTextCtrl::DoLoadFile(const wxString& filename, int fileType)
+{
+ bool success = GetBuffer().LoadFile(filename, fileType);
if (success)
m_filename = filename;
}
}
-bool wxRichTextCtrl::SaveFile(const wxString& filename, int type)
+bool wxRichTextCtrl::DoSaveFile(const wxString& filename, int fileType)
{
- wxString filenameToUse = filename.empty() ? m_filename : filename;
- if ( filenameToUse.empty() )
- {
- // what kind of message to give? is it an error or a program bug?
- wxLogDebug(wxT("Can't save textctrl to file without filename."));
-
- return false;
- }
-
- if (GetBuffer().SaveFile(filenameToUse, type))
+ if (GetBuffer().SaveFile(filename, fileType))
{
- m_filename = filenameToUse;
+ m_filename = filename;
DiscardEdits();
return true;
-
}
wxLogError(_("The text couldn't be saved."));
void wxRichTextCtrl::SelectAll()
{
- SetSelection(0, GetLastPosition());
+ SetSelection(0, GetLastPosition()+1);
m_selectionAnchor = -1;
}
{
wxClientDC dc((wxRichTextCtrl*) this);
((wxRichTextCtrl*)this)->PrepareDC(dc);
-
+
// Buffer uses logical position (relative to start of buffer)
// so convert
wxPoint pt2 = GetLogicalPoint(pt);
wxString wxRichTextCtrl::GetRange(long from, long to) const
{
- return GetBuffer().GetTextForRange(wxRichTextRange(from, to));
+ // Public API for range is different from internals
+ return GetBuffer().GetTextForRange(wxRichTextRange(from, to-1));
}
void wxRichTextCtrl::SetValue(const wxString& value)
void wxRichTextCtrl::DoWriteText(const wxString& value, bool WXUNUSED(selectionOnly))
{
- GetBuffer().InsertTextWithUndo(m_caretPosition+1, value, this);
+ wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Unix);
+
+ GetBuffer().InsertTextWithUndo(m_caretPosition+1, valueDos, this);
}
void wxRichTextCtrl::AppendText(const wxString& text)
{
if (CanCopy())
{
- wxRichTextRange range = GetSelectionRange();
+ wxRichTextRange range = GetInternalSelectionRange();
GetBuffer().CopyToClipboard(range);
}
}
{
if (CanCut())
{
- wxRichTextRange range = GetSelectionRange();
+ wxRichTextRange range = GetInternalSelectionRange();
GetBuffer().CopyToClipboard(range);
DeleteSelectedContent();
{
*from = m_selectionRange.GetStart();
*to = m_selectionRange.GetEnd();
+ if ((*to) != -1 && (*to) != -2)
+ (*to) ++;
}
bool wxRichTextCtrl::IsEditable() const
if ( (from == -1) && (to == -1) )
{
from = 0;
- to = GetLastPosition();
+ to = GetLastPosition()+1;
}
DoSetSelection(from, to);
void wxRichTextCtrl::DoSetSelection(long from, long to, bool WXUNUSED(scrollCaret))
{
m_selectionAnchor = from;
- m_selectionRange.SetRange(from, to);
+ m_selectionRange.SetRange(from, to-1);
Refresh(false);
PositionCaret();
}
void wxRichTextCtrl::DiscardEdits()
{
+ m_caretPositionForDefaultStyle = -2;
m_buffer.Modify(false);
m_buffer.GetCommandProcessor()->ClearCommands();
}
bool wxRichTextCtrl::SetStyle(long start, long end, const wxTextAttrEx& style)
{
- return GetBuffer().SetStyle(wxRichTextRange(start, end), style);
+ return GetBuffer().SetStyle(wxRichTextRange(start, end-1), style);
}
bool wxRichTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
{
- return GetBuffer().SetStyle(wxRichTextRange(start, end), wxTextAttrEx(style));
+ return GetBuffer().SetStyle(wxRichTextRange(start, end-1), wxTextAttrEx(style));
}
bool wxRichTextCtrl::SetStyle(const wxRichTextRange& range, const wxRichTextAttr& style)
{
- return GetBuffer().SetStyle(range, style);
+ return GetBuffer().SetStyle(range.ToInternal(), style);
}
bool wxRichTextCtrl::SetDefaultStyle(const wxTextAttrEx& style)
const wxTextAttr& wxRichTextCtrl::GetDefaultStyle() const
{
- return GetBuffer().GetDefaultStyle();
+ return GetBuffer().GetDefaultStyle();
}
-bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style) const
+bool wxRichTextCtrl::GetStyle(long position, wxTextAttr& style)
{
- wxTextAttrEx attr;
+ wxTextAttrEx attr(style);
if (GetBuffer().GetStyle(position, attr))
{
style = attr;
return false;
}
-bool wxRichTextCtrl::GetStyle(long position, wxTextAttrEx& style) const
+bool wxRichTextCtrl::GetStyle(long position, wxTextAttrEx& style)
{
return GetBuffer().GetStyle(position, style);
}
-bool wxRichTextCtrl::GetStyle(long position, wxRichTextAttr& style) const
+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)
{
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;
}
}
/// Is all of the selection bold?
-bool wxRichTextCtrl::IsSelectionBold() const
+bool wxRichTextCtrl::IsSelectionBold()
{
if (HasSelection())
{
wxRichTextAttr attr;
- wxRichTextRange range = GetSelectionRange();
+ wxRichTextRange range = GetInternalSelectionRange();
attr.SetFlags(wxTEXT_ATTR_FONT_WEIGHT);
attr.SetFontWeight(wxBOLD);
// 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;
}
}
}
/// Is all of the selection italics?
-bool wxRichTextCtrl::IsSelectionItalics() const
+bool wxRichTextCtrl::IsSelectionItalics()
{
if (HasSelection())
{
- wxRichTextRange range = GetSelectionRange();
+ wxRichTextRange range = GetInternalSelectionRange();
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_ITALIC);
attr.SetFontStyle(wxITALIC);
// 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;
}
}
}
/// Is all of the selection underlined?
-bool wxRichTextCtrl::IsSelectionUnderlined() const
+bool wxRichTextCtrl::IsSelectionUnderlined()
{
if (HasSelection())
{
- wxRichTextRange range = GetSelectionRange();
+ wxRichTextRange range = GetInternalSelectionRange();
wxRichTextAttr attr;
attr.SetFlags(wxTEXT_ATTR_FONT_UNDERLINE);
attr.SetFontUnderlined(true);
// 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();
}
}
if (HasSelection())
return SetStyle(GetSelectionRange(), attr);
else
- SetDefaultStyle(attr);
+ SetAndShowDefaultStyle(attr);
return true;
}
if (HasSelection())
return SetStyle(GetSelectionRange(), attr);
else
- SetDefaultStyle(attr);
+ SetAndShowDefaultStyle(attr);
return true;
}
if (HasSelection())
return SetStyle(GetSelectionRange(), attr);
else
- SetDefaultStyle(attr);
+ SetAndShowDefaultStyle(attr);
return true;
}
/// Is all of the selection aligned according to the specified flag?
-bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment) const
+bool wxRichTextCtrl::IsSelectionAligned(wxTextAttrAlignment alignment)
{
if (HasSelection())
{
- wxRichTextRange range = GetSelectionRange();
+ wxRichTextRange range = GetInternalSelectionRange();
wxRichTextAttr attr;
attr.SetAlignment(alignment);
{
wxRichTextParagraph* para = GetBuffer().GetParagraphAtPosition(GetCaretPosition()+1);
if (para)
- return SetStyle(para->GetRange(), attr);
+ return SetStyle(para->GetRange().FromInternal(), attr);
}
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);
+}
+
+/// 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()
{
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 wxRICHTEXT_USE_DYNAMIC_STYLES
+ if (GetUncombinedStyle(pos, attr))
+#else
+ if (GetStyle(pos, attr))
+#endif
{
SetDefaultStyle(attr);
return true;
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;
+}
+
+/// Get/set the selection range in character positions. -1, -1 means no selection.
+/// The range is in API convention, i.e. a single character selection is denoted
+/// by (n, n+1)
+wxRichTextRange wxRichTextCtrl::GetSelectionRange() const
+{
+ wxRichTextRange range = GetInternalSelectionRange();
+ if (range != wxRichTextRange(-2,-2) && range != wxRichTextRange(-1,-1))
+ range.SetEnd(range.GetEnd() + 1);
+ return range;
+}
+
+void wxRichTextCtrl::SetSelectionRange(const wxRichTextRange& range)
+{
+ wxRichTextRange range1(range);
+ if (range1 != wxRichTextRange(-2,-2) && range1 != wxRichTextRange(-1,-1) )
+ range1.SetEnd(range1.GetEnd() - 1);
+
+ wxASSERT( range1.GetStart() > range1.GetEnd() );
+
+ SetInternalSelectionRange(range1);
+}
+
#endif
// wxUSE_RICHTEXT