www.pudn.com > TurboPadSource.tar.gz > stextctrl.cpp
/**
* \file Styled Text Control implementation
*
* Implementation of STextCtrl functions.
*/
#include "stextctrl.h"
STextCtrl::STextCtrl(CPtr parent, wxWindowID id,
const wxPoint &pos, const wxSize& size, long style)
: wxStyledTextCtrl(parent, id, pos, size, style),
findFlags(0), braceLoc(-1), recording(false)
{
InitOptions();
InitMargins();
InitDefaultStyles();
wxAcceleratorEntry accEntry[3];
accEntry[0].Set(wxACCEL_CTRL, (int) WXK_RETURN, Txt_AutoComplete);
accEntry[1].Set(wxACCEL_CTRL, (int) WXK_F3, Txt_FindWord);
accEntry[2].Set(wxACCEL_SHIFT | wxACCEL_CTRL, (int) WXK_F3, Txt_FindPreviousWord);
wxAcceleratorTable accTable(3, accEntry);
SetAcceleratorTable(accTable);
SetFocus();
}
void STextCtrl::BlockCommentSelection(const wxString &comment)
{
int lines = LinesSelected();
int cline = GetCurrentLine();
BeginUndoAction();
for (int i = cline; i <= cline + lines; i++)
InsertText(PositionFromLine(i), comment);
EndUndoAction();
}
void STextCtrl::CharAdded(wxStyledTextEvent &event)
{
char chr = event.GetKey();
int currentLine = GetCurrentLine();
if (recording)
mac.Add(chr);
if (chr == '\r' || chr == '\n')
{
int lineInd = 0;
if (currentLine > 0)
lineInd = GetLineIndentation(currentLine-1);
if ((GetLine(currentLine-1).Contains('{') && !GetLine(currentLine-1).Contains('}')
&& GetParent()->GetHil() != "Pascal")
|| (GetGrandParent()->GetSyntax()->HasIndentationWord(GetLine(currentLine-1))))
lineInd += GetTabWidth();
if ((GetGrandParent()->GetSyntax()->HasIndentationWord(GetLine(currentLine-2)))
&& !GetLine(currentLine-2).Contains('{')
&& !GetLine(currentLine-1).Contains('{')
&& GetParent()->GetHil() != "Pascal")
lineInd -= GetTabWidth();
SetLineIndentation(currentLine, lineInd);
GotoPos(PositionFromLine(currentLine) + lineInd);
return;
}
// Don't auto-indent comments.
if (GetParent()->GetHil() == "Pascal") return;
if (chr == '{' && !GetGrandParent()->GetSyntax()->HasIndentationWord(GetLine(currentLine))
&& !GetLine(GetCurrentLine()-1).Contains('{'))
SetLineIndentation(currentLine, GetLineIndentation(currentLine-1));
if (chr == '}')
{
Colourise(GetCurrentPos()-1, GetCurrentPos());
int pos = BraceMatch(GetCurrentPos()-1);
SetLineIndentation(currentLine, GetLineIndentation(LineFromPosition(pos)));
}
}
bool STextCtrl::FindCurrentWord(bool findNext = true)
{
wxString findText;
if (findNext)
{
if (HasSelection())
{
findText = GetSelectedText();
return FindNextOccurence(findText, 0);
}
else
{
findText = GetTextUnderCursor();
return FindNextOccurence(findText, wxSTC_FIND_WHOLEWORD);
}
}
else if (!findNext)
{
if (HasSelection())
{
findText = GetSelectedText();
return FindPreviousOccurence(findText, 0);
}
else
{
findText = GetTextUnderCursor();
return FindPreviousOccurence(findText, wxSTC_FIND_WHOLEWORD);
}
}
return false;
}
void STextCtrl::FindWord(wxCommandEvent &event)
{
FindCurrentWord();
}
void STextCtrl::FindPreviousWord(wxCommandEvent &event)
{
FindCurrentWord(false);
}
bool STextCtrl::FindNext()
{
return FindNextOccurence(findString, findFlags);
}
bool STextCtrl::FindPrevious()
{
return FindPreviousOccurence(findString, findFlags);
}
// \todo Merge FindNextOccurence and FindPreviousOccurence into FindOccurence
bool STextCtrl::FindNextOccurence(const wxString &findStr, int flags = 0)
{
findString = findStr;
findFlags = flags;
int targetStart = GetCurrentPos();
if (GetSelectedText() == findStr)
targetStart = GetSelectionEnd();
SetTargetStart(targetStart);
SetTargetEnd(GetLength());
SetSearchFlags(flags);
if (SearchInTarget(findStr) != -1)
{
SetSelection(GetTargetStart(), GetTargetEnd());
EnsureCaretVisible();
return true;
}
else
return false;
}
bool STextCtrl::FindPreviousOccurence(const wxString &findStr, int flags = 0)
{
findString = findStr;
findFlags = flags;
int targetStart = GetCurrentPos();
if (GetSelectedText() == findStr)
targetStart = (GetSelectionStart() GetSelectionEnd())-1;
SetTargetStart(targetStart);
SetTargetEnd(0);
SetSearchFlags(flags);
if (SearchInTarget(findStr) != -1)
{
SetSelection(GetTargetStart(), GetTargetEnd());
EnsureCaretVisible();
return true;
}
else
return false;
}
inline PPtr STextCtrl::GetGrandParent()
{
return GetParent()->GetParent();
}
inline CPtr STextCtrl::GetParent()
{
return static_cast (wxStyledTextCtrl::GetParent());
}
void STextCtrl::GetSelection(int &from, int &to)
{
from = GetSelectionStart();
to = GetSelectionEnd();
}
wxString STextCtrl::GetTextUnderCursor()
{
int startpos, endpos;
startpos = WordStartPosition(GetCurrentPos(), true);
endpos = WordEndPosition(GetCurrentPos(), true);
return GetTextRange(startpos, endpos);
}
wxString STextCtrl::GetTextUnderCursor(int &startPos, int &endPos)
{
startPos = WordStartPosition(GetCurrentPos(), true);
endPos = WordEndPosition(GetCurrentPos(), true);
return GetTextRange(startPos, endPos);
}
inline bool STextCtrl::IsBrace(char brace)
{
return brace == '{' || brace == '}' ||
brace == '[' || brace == ']' ||
brace == '(' || brace == ')';
}
inline void STextCtrl::InitDefaultStyles()
{
wxFont font (10, wxMODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false,
"Courier New", wxFONTENCODING_SYSTEM);
StyleSetFont(wxSTC_STYLE_DEFAULT, font);
StyleSetBold(wxSTC_STYLE_BRACELIGHT, true);
StyleSetBold(wxSTC_STYLE_BRACEBAD, true);
StyleSetForeground(wxSTC_STYLE_DEFAULT, wxColour(0, 0, 0));
StyleSetForeground(wxSTC_STYLE_LINENUMBER, wxColour(0, 0, 0));
StyleSetForeground(wxSTC_STYLE_BRACELIGHT, wxColour(0, 0, 255));
StyleSetForeground(wxSTC_STYLE_BRACEBAD, wxColour(255, 0, 0));
StyleSetForeground(wxSTC_STYLE_BRACEBAD, wxColour(255, 0, 0));
}
inline void STextCtrl::InitMargins()
{
SetMarginWidth(0, TextWidth(wxSTC_STYLE_LINENUMBER, "9999999"));
SetMarginType(0, 1);
SetMarginType(1, wxSTC_MARGIN_SYMBOL);
SetMarginMask(1, ~wxSTC_MASK_FOLDERS);
SetMarginSensitive(1, true);
SetMarginWidth(1, 16);
SetMarginType(2, wxSTC_MARGIN_SYMBOL);
SetMarginMask(2, wxSTC_MASK_FOLDERS);
SetMarginSensitive(2, true);
SetMarginWidth(2, 16);
MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, "white", "black");
MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, "white", "black");
MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL,wxSTC_MARK_TCORNER, "white", "black");
MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, "white", "black");
MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID,wxSTC_MARK_BOXMINUSCONNECTED, "white", "black");
MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, "white", "black");
MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, "white", "black");
MarkerDefine(0, wxSTC_MARK_CIRCLE, wxColour(0, 0, 0), wxColour(128, 255, 255));
}
inline void STextCtrl::InitOptions()
{
AutoCompSetChooseSingle(true);
SetUseTabs(false);
SetTabWidth(4);
SetBackSpaceUnIndents(true);
SetModEventMask(wxSTC_MOD_INSERTTEXT | wxSTC_MOD_DELETETEXT
| wxSTC_MOD_BEFOREINSERT | wxSTC_MOD_BEFOREDELETE);
SetProperty("fold", "1");
SetProperty("fold.comment", "1");
SetProperty("fold.comment.python", "1");
SetProperty("fold.compact", "1");
SetProperty("fold.html", "1");
SetProperty("fold.html.preprocessor", "1");
SetProperty("fold.preprocessor", "1");
SetProperty("fold.quotes.python", "1");
SetProperty("tab.timmy.whinge.level", "1");
}
inline int STextCtrl::LinesSelected()
{
return LineFromPosition(GetSelectionEnd()) - LineFromPosition(GetSelectionStart());
}
bool STextCtrl::LoadFile(const wxString& fileName)
{
wxFile file(fileName);
wxString st;
ClearAll();
char* buff = st.GetWriteBuf(file.Length());
file.Read(buff, file.Length());
st.UngetWriteBuf();
if (st.Contains('\n') && !st.Contains('\r')) // Unix text file
SetEOL(LF);
else if (st.Contains('\r') && !st.Contains('\n')) // Mac text file
SetEOL(CR);
else // Windows text file
SetEOL(CRLF);
InsertText(0, st);
EmptyUndoBuffer();
return true;
}
void STextCtrl::MacroRecord(wxStyledTextEvent &event)
{
mac.Add(event.GetMessage());
}
void STextCtrl::MakeLower()
{
BeginUndoAction();
int start, end;
GetSelection(start, end);
wxString sel = GetSelectedText();
sel.MakeLower();
ReplaceText(start, end, sel);
EndUndoAction();
}
void STextCtrl::MakeUpper()
{
BeginUndoAction();
int start, end;
GetSelection(start, end);
wxString sel = GetSelectedText();
sel.MakeUpper();
ReplaceText(start, end, sel);
EndUndoAction();
}
void STextCtrl::MarginClicked(wxStyledTextEvent &event)
{
if (event.GetMargin() == 1) // The bookmark margin was clicked
{
int line = LineFromPosition(event.GetPosition());
ToggleBookMark(line);
}
if (event.GetMargin() == 2) // The fold margin was clicked
{
int line = LineFromPosition(event.GetPosition());
if (GetFoldLevel(line) & wxSTC_FOLDLEVELHEADERFLAG)
ToggleFold(line);
}
}
void STextCtrl::Modified(wxStyledTextEvent &event)
{
wxString title = GetParent()->GetTitle();
int currentStatus = GetGrandParent()->GetWindowStatus()->GetStatus();
if (!title.Contains('*') && currentStatus != OpeningWindows)
GetParent()->SetTitle(title + '*');
GetGrandParent()->UpdateMenus(); // \todo Optimize this code.
}
void STextCtrl::PlayMacro(const wxArrayInt ¯o)
{
for (unsigned int i = 0; i < macro.GetCount(); i++)
{
if (macro[i] < 255)
AddText((char) macro[i]);
else
CmdKeyExecute(macro[i]);
}
}
void STextCtrl::PosChange(wxStyledTextEvent &event)
{
if (IsBrace(GetPreviousChar()))
{
braceLoc = BraceMatch(GetCurrentPos()-1);
if (braceLoc != -1)
{
BraceHighlight(GetCurrentPos()-1, braceLoc);
Colourise(braceLoc, braceLoc+1);
}
else
{
BraceBadLight(GetCurrentPos()-1);
braceLoc = GetCurrentPos()-1;
}
}
else if (IsBrace(GetCurrentChar()))
{
braceLoc = BraceMatch(GetCurrentPos());
if (braceLoc != -1)
{
BraceHighlight(GetCurrentPos(), braceLoc);
Colourise(braceLoc, braceLoc+1);
}
else
{
BraceBadLight(GetCurrentPos());
braceLoc = GetCurrentPos();
}
}
else
{
if (braceLoc != -1) // Position has moved and a brace was being highlighted
{ // but the caret is no longer next to the brace
BraceHighlight(-1, -1);
if ((braceLoc+1) < GetLength()) Colourise(braceLoc, braceLoc+1);
if (BraceMatch(braceLoc) != -1 && BraceMatch(braceLoc)+1 < GetLength())
Colourise(BraceMatch(braceLoc), BraceMatch(braceLoc)+1);
braceLoc = -1;
}
}
// \todo Remove this call to UpdateMenus and find a faster way to do the same thing
GetGrandParent()->UpdateMenus();
GetParent()->UpdatePos();
}
void STextCtrl::Remove(int from, int to)
{
SetTargetStart(from to);
SetTargetEnd(to >? from);
ReplaceTarget("");
}
void STextCtrl::RemoveAllBookMarks()
{
MarkerDeleteAll(0);
}
void STextCtrl::Replace(const wxString &findStr, const wxString &replaceStr, int flags)
{
replaceString = replaceStr;
if (!HasSelection())
{
wxBell();
return;
}
if (flags & wxSTC_FIND_MATCHCASE && GetSelectedText() != findStr)
{
wxBell();
return;
}
else if (GetSelectedText().Lower() != findStr.Lower())
{
wxBell();
return;
}
ReplaceSelection(replaceStr);
FindNextOccurence(findStr, flags);
}
void STextCtrl::ReplaceAll(const wxString &findStr, const wxString &replaceStr, int flags)
{
replaceString = replaceStr;
int find;
BeginUndoAction();
SetTargetStart(GetCurrentPos()-1);
SetTargetEnd(GetLength());
SetSearchFlags(flags);
do
{
find = SearchInTarget(findStr);
if (find != -1)
{
ReplaceTarget(replaceStr);
SetTargetStart(GetTargetEnd());
SetTargetEnd(GetLength());
}
}
while (find != -1);
EndUndoAction();
}
void STextCtrl::ReplaceText(int from, int to, const wxString& value)
{
Remove(from, to);
InsertText(from, value);
}
void STextCtrl::SetEOL(int eolMode)
{
if (GetEOLMode() != eolMode)
{
ConvertEOLs(eolMode);
SetEOLMode(eolMode);
}
}
bool STextCtrl::SaveFile(const wxString& fileName)
{
if (!GetModify()) return false; // Don't do anything if the file wasn't modified
wxFile file;
wxString st;
if (!file.Exists(fileName))
file.Create(fileName);
file.Open(fileName, wxFile::write);
st = GetText();
file.Write(st);
file.Close();
SetSavePoint();
return true;
}
void STextCtrl::ShowAutoComplete(wxCommandEvent &event)
{
wxSortedArrayString comp;
wxString complist, word;
wxString cword = GetTextUnderCursor();
int loc, end;
SetTargetStart(0);
SetTargetEnd(GetLength());
SetSearchFlags(wxSTC_FIND_WORDSTART + wxSTC_FIND_MATCHCASE);
for (;;)
{
loc = SearchInTarget(cword);
if (loc == -1) break;
end = WordEndPosition(loc, true);
word = GetTextRange(GetTargetStart(), end);
if (comp.Index(word) == wxNOT_FOUND && word != cword)
comp.Add(word);
SetTargetStart(end);
SetTargetEnd(GetLength());
}
// Convert the wxSortedArrayString to a sorted string delimited by spaces
for (unsigned int i = 0; i < comp.GetCount(); i++)
{
complist += comp[i];
if (i != comp.GetCount() - 1) complist += ' '; // Pad every word with spaces except the last
}
if (complist != "")
AutoCompShow(cword.length(), complist);
}
void STextCtrl::ShowMatchingBrace(int pos)
{
if (IsBrace(GetPreviousChar()))
GotoPos(BraceMatch(pos-1));
else if (IsBrace(GetCurrentChar()))
GotoPos(BraceMatch(pos)+1);
else
wxBell();
}
void STextCtrl::ShowNextBookMark(int line)
{
if (MarkerGet(line) & (1 << 0)) line++;
int nextMarker = MarkerNext(line, 1 << 0);
if (nextMarker == -1 && (MarkerNext(0, 1 << 0) != -1))
nextMarker = MarkerNext(0, 1 << 0);
if (nextMarker != -1) GotoLine(nextMarker);
}
void STextCtrl::ShowPreviousBookMark(int line)
{
if (MarkerGet(line) & (1 << 0)) line--;
int previousMarker = MarkerPrevious(line, 1 << 0);
if (previousMarker == -1 && (MarkerPrevious(GetLastLine(), 1 << 0) != -1))
previousMarker = MarkerPrevious(GetLastLine(), 1 << 0);
if (previousMarker != -1) GotoLine(previousMarker);
}
void STextCtrl::SortSelection()
{
if (HasSelection())
{
BeginUndoAction();
wxArrayString lines;
int firstLine = LineFromPosition(GetSelectionStart());
int lastLine = LineFromPosition(GetSelectionEnd());
for (int i = firstLine; i <= lastLine; i++)
lines.Add(GetTextRange(PositionFromLine(i), GetLineEndPosition(i)));
lines.Sort();
for (int i = firstLine; i <= lastLine; i++)
{
SetTargetStart(PositionFromLine(i));
SetTargetEnd(PositionFromLine(i)+LineLength(i)); // This code is very slow. \todo Optimize this.
// If this is the last line don't add an extra newline character
if (i == lastLine && lastLine == GetLineCount()-1) ReplaceTarget(lines[i-firstLine]);
else ReplaceTarget(lines[i-firstLine]+'\n');
}
SetSelection(GetSelectionStart(), GetLineEndPosition(lastLine));
EndUndoAction();
}
}
void STextCtrl::StreamCommentSelection(const wxString &streamStart, const wxString &streamEnd)
{
int selStart, selEnd;
GetSelection(selStart, selEnd);
BeginUndoAction();
InsertText(selStart, streamStart);
// Allocate space for the first comment
InsertText(selEnd + streamStart.length(), streamEnd);
EndUndoAction();
}
void STextCtrl::ToggleBookMark(int line)
{
if (MarkerGet(line) & (1 << 0))
MarkerDelete(line, 0);
else
MarkerAdd(line, 0);
}
void STextCtrl::ToggleMacroRecord()
{
if (!recording)
{
mac.Empty();
StartRecord();
recording = true;
}
else
{
StopRecord();
recording = false;
#ifdef __WXDEBUG__
wxTextFile f("C:\\Macro.mac");
if (!f.Exists()) f.Create();
f.Open();
wxString command;
f.AddLine("--Start Macro--");
for (unsigned int i = 0; i < mac.GetCount(); i++)
{
if (mac[i] == 2170) continue; // Don't need char added notifications
command = "";
command << mac[i];
f.AddLine(command);
}
f.AddLine("--End Macro--");
f.Write();
f.Close();
#endif
}
}
BEGIN_EVENT_TABLE(STextCtrl, wxStyledTextCtrl)
EVT_MENU(Txt_AutoComplete, STextCtrl::ShowAutoComplete)
EVT_MENU(Txt_FindWord, STextCtrl::FindWord)
EVT_MENU(Txt_FindPreviousWord, STextCtrl::FindPreviousWord)
EVT_STC_CHANGE(-1, STextCtrl::Modified)
EVT_STC_CHARADDED(-1, STextCtrl::CharAdded)
EVT_STC_MACRORECORD(-1, STextCtrl::MacroRecord)
EVT_STC_MARGINCLICK (-1, STextCtrl::MarginClicked)
EVT_STC_UPDATEUI(-1, STextCtrl::PosChange)
END_EVENT_TABLE()