2006-12-24 22:52:54 +01:00
|
|
|
|
// Copyright (c) 2005, Rodrigo Braz Monteiro
|
|
|
|
|
// All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
// Redistribution and use in source and binary forms, with or without
|
|
|
|
|
// modification, are permitted provided that the following conditions are met:
|
|
|
|
|
//
|
|
|
|
|
// * Redistributions of source code must retain the above copyright notice,
|
|
|
|
|
// this list of conditions and the following disclaimer.
|
|
|
|
|
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
|
// this list of conditions and the following disclaimer in the documentation
|
|
|
|
|
// and/or other materials provided with the distribution.
|
|
|
|
|
// * Neither the name of the Aegisub Group nor the names of its contributors
|
|
|
|
|
// may be used to endorse or promote products derived from this software
|
|
|
|
|
// without specific prior written permission.
|
|
|
|
|
//
|
|
|
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
|
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
|
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
|
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
|
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
//
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// AEGISUB
|
|
|
|
|
//
|
|
|
|
|
// Website: http://aegisub.cellosoft.com
|
|
|
|
|
// Contact: mailto:zeratul@cellosoft.com
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////
|
|
|
|
|
// Includes
|
|
|
|
|
#include "subs_edit_ctrl.h"
|
|
|
|
|
#include "subs_edit_box.h"
|
|
|
|
|
#include "options.h"
|
2006-12-25 06:43:00 +01:00
|
|
|
|
#include "subs_grid.h"
|
|
|
|
|
#include "utils.h"
|
2006-12-24 22:52:54 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////
|
|
|
|
|
// Edit box constructor
|
|
|
|
|
SubsTextEditCtrl::SubsTextEditCtrl(wxWindow* parent, wxWindowID id, const wxString& value, const wxPoint& pos, const wxSize& wsize, long style, const wxValidator& validator, const wxString& name)
|
|
|
|
|
: wxScintilla(parent, id, pos, wsize, 0, value)
|
|
|
|
|
{
|
|
|
|
|
// Set properties
|
|
|
|
|
SetWrapMode(wxSCI_WRAP_WORD);
|
|
|
|
|
SetMarginWidth(1,0);
|
2006-12-25 22:56:56 +01:00
|
|
|
|
UsePopUp(false);
|
2006-12-25 04:42:44 +01:00
|
|
|
|
|
|
|
|
|
// Set hotkeys
|
2006-12-24 22:52:54 +01:00
|
|
|
|
CmdKeyClear(wxSCI_KEY_RETURN,wxSCI_SCMOD_CTRL);
|
|
|
|
|
CmdKeyClear(wxSCI_KEY_RETURN,wxSCI_SCMOD_NULL);
|
|
|
|
|
CmdKeyClear(wxSCI_KEY_TAB,wxSCI_SCMOD_NULL);
|
|
|
|
|
CmdKeyClear(wxSCI_KEY_TAB,wxSCI_SCMOD_SHIFT);
|
|
|
|
|
CmdKeyClear('D',wxSCI_SCMOD_CTRL);
|
|
|
|
|
CmdKeyClear('L',wxSCI_SCMOD_CTRL);
|
|
|
|
|
CmdKeyClear('L',wxSCI_SCMOD_CTRL | wxSCI_SCMOD_SHIFT);
|
|
|
|
|
CmdKeyClear('T',wxSCI_SCMOD_CTRL);
|
|
|
|
|
CmdKeyClear('T',wxSCI_SCMOD_CTRL | wxSCI_SCMOD_SHIFT);
|
|
|
|
|
CmdKeyClear('U',wxSCI_SCMOD_CTRL);
|
|
|
|
|
|
|
|
|
|
// Styles
|
|
|
|
|
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
|
|
|
|
wxString fontname = Options.AsText(_T("Font Face"));
|
|
|
|
|
if (fontname != _T("")) font.SetFaceName(fontname);
|
|
|
|
|
int size = Options.AsInt(_T("Font Size"));
|
|
|
|
|
|
|
|
|
|
// Normal style
|
|
|
|
|
StyleSetFont(0,font);
|
|
|
|
|
StyleSetSize(0,size);
|
|
|
|
|
StyleSetForeground(0,Options.AsColour(_T("Syntax Highlight Normal")));
|
|
|
|
|
|
|
|
|
|
// Brackets style
|
|
|
|
|
StyleSetFont(1,font);
|
|
|
|
|
StyleSetSize(1,size);
|
|
|
|
|
StyleSetForeground(1,Options.AsColour(_T("Syntax Highlight Brackets")));
|
|
|
|
|
|
|
|
|
|
// Slashes/Parenthesis/Comma style
|
|
|
|
|
StyleSetFont(2,font);
|
|
|
|
|
StyleSetSize(2,size);
|
|
|
|
|
StyleSetForeground(2,Options.AsColour(_T("Syntax Highlight Slashes")));
|
|
|
|
|
|
|
|
|
|
// Tags style
|
|
|
|
|
StyleSetFont(3,font);
|
|
|
|
|
StyleSetSize(3,size);
|
|
|
|
|
StyleSetBold(3,true);
|
|
|
|
|
StyleSetForeground(3,Options.AsColour(_T("Syntax Highlight Tags")));
|
|
|
|
|
|
|
|
|
|
// Error style
|
|
|
|
|
StyleSetFont(4,font);
|
|
|
|
|
StyleSetSize(4,size);
|
|
|
|
|
StyleSetForeground(4,Options.AsColour(_T("Syntax Highlight Error")));
|
|
|
|
|
|
|
|
|
|
// Tag Number Parameters style
|
|
|
|
|
StyleSetFont(5,font);
|
|
|
|
|
StyleSetSize(5,size);
|
|
|
|
|
StyleSetForeground(5,Options.AsColour(_T("Syntax Highlight Numbers")));
|
|
|
|
|
|
2006-12-25 06:43:00 +01:00
|
|
|
|
// Line breaks style
|
|
|
|
|
StyleSetFont(6,font);
|
|
|
|
|
StyleSetSize(6,size);
|
|
|
|
|
StyleSetBold(6,true);
|
|
|
|
|
StyleSetForeground(6,Options.AsColour(_T("Syntax Highlight Line Break")));
|
|
|
|
|
|
2006-12-24 23:46:20 +01:00
|
|
|
|
// Misspelling indicator
|
|
|
|
|
IndicatorSetStyle(0,wxSCI_INDIC_SQUIGGLE);
|
2006-12-25 04:42:44 +01:00
|
|
|
|
IndicatorSetForeground(0,wxColour(255,0,0));
|
2006-12-24 23:46:20 +01:00
|
|
|
|
|
2006-12-24 22:52:54 +01:00
|
|
|
|
// Set spellchecker
|
|
|
|
|
spellchecker = SpellChecker::GetSpellChecker();
|
2006-12-25 22:56:56 +01:00
|
|
|
|
|
|
|
|
|
// Set thesaurus
|
|
|
|
|
thesaurus = Thesaurus::GetThesaurus();
|
2006-12-25 06:43:00 +01:00
|
|
|
|
|
|
|
|
|
// Delimiters
|
|
|
|
|
delim = _T(" .,;:!?<3F><>(){}[]\"/\\");
|
2006-12-24 22:52:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////
|
|
|
|
|
// Destructor
|
|
|
|
|
SubsTextEditCtrl::~SubsTextEditCtrl() {
|
|
|
|
|
delete spellchecker;
|
|
|
|
|
spellchecker = NULL;
|
2006-12-25 22:56:56 +01:00
|
|
|
|
delete thesaurus;
|
|
|
|
|
thesaurus = NULL;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////
|
|
|
|
|
// Style a range
|
|
|
|
|
void SubsTextEditCtrl::UpdateStyle(int start, int _length) {
|
|
|
|
|
// Styling enabled?
|
|
|
|
|
if (Options.AsBool(_T("Syntax Highlight Enabled")) == 0) return;
|
|
|
|
|
|
|
|
|
|
// Set variables
|
|
|
|
|
wxString text = GetText();
|
2006-12-24 23:46:20 +01:00
|
|
|
|
int end = start + _length;
|
|
|
|
|
if (_length < 0) end = text.Length();
|
2006-12-24 22:52:54 +01:00
|
|
|
|
|
|
|
|
|
// Begin styling
|
2006-12-25 04:42:44 +01:00
|
|
|
|
StartStyling(0,255);
|
2006-12-24 22:52:54 +01:00
|
|
|
|
int ran = 0;
|
|
|
|
|
int depth = 0;
|
|
|
|
|
int curStyle = 0;
|
2006-12-25 04:42:44 +01:00
|
|
|
|
int curPos = 0;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
wxChar curChar = 0;
|
|
|
|
|
wxChar prevChar = 0;
|
2006-12-25 06:43:00 +01:00
|
|
|
|
wxChar nextChar = 0;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
|
|
|
|
|
// Loop through
|
2006-12-24 23:46:20 +01:00
|
|
|
|
for (int i=start;i<end;i++) {
|
2006-12-24 22:52:54 +01:00
|
|
|
|
// Current/previous characters
|
|
|
|
|
prevChar = curChar;
|
|
|
|
|
curChar = text[i];
|
2006-12-25 06:43:00 +01:00
|
|
|
|
if (i<end-1) nextChar = text[i+1];
|
|
|
|
|
else nextChar = 0;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
|
|
|
|
|
// Erroneous
|
|
|
|
|
if (depth < 0 || depth > 1) {
|
2006-12-25 04:42:44 +01:00
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
|
|
|
|
curPos += ran;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
ran = 0;
|
|
|
|
|
curStyle = 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start override block
|
|
|
|
|
if (curChar == _T('{') && depth >= 0) {
|
2006-12-25 04:42:44 +01:00
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
|
|
|
|
curPos += ran;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
ran = 0;
|
|
|
|
|
depth++;
|
|
|
|
|
if (depth == 1) curStyle = 1;
|
|
|
|
|
else curStyle = 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// End override block
|
|
|
|
|
else if (curChar == _T('}') && depth <= 1) {
|
2006-12-25 04:42:44 +01:00
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
|
|
|
|
curPos += ran;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
ran = 0;
|
|
|
|
|
depth--;
|
|
|
|
|
if (depth == 0) curStyle = 1;
|
|
|
|
|
else curStyle = 4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Outside
|
2006-12-25 06:43:00 +01:00
|
|
|
|
else if (depth == 0) {
|
|
|
|
|
// Is \n, \N or \h?
|
|
|
|
|
if (curChar == _T('\\') && (nextChar == 'n' || nextChar == 'N' || nextChar == 'h')) {
|
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
2006-12-26 02:30:30 +01:00
|
|
|
|
curPos += ran;
|
2006-12-25 06:43:00 +01:00
|
|
|
|
ran = 1;
|
|
|
|
|
curStyle = 6;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Normal text
|
|
|
|
|
else if (curStyle != 0) {
|
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
|
|
|
|
curPos += ran;
|
|
|
|
|
ran = 0;
|
|
|
|
|
curStyle = 0;
|
|
|
|
|
}
|
2006-12-24 22:52:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inside
|
|
|
|
|
else if (depth == 1) {
|
|
|
|
|
// Special character
|
|
|
|
|
if (curChar == _T('\\') || curChar == _T('(') || curChar == _T(')') || curChar == _T(',')) {
|
|
|
|
|
if (curStyle != 2) {
|
2006-12-25 04:42:44 +01:00
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
|
|
|
|
curPos += ran;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
ran = 0;
|
|
|
|
|
curStyle = 2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Number
|
|
|
|
|
else if ((curChar >= '0' && curChar <= '9') || curChar == '.' || curChar == '&' || curChar == '+' || curChar == '-' || (curChar == 'H' && prevChar == '&')) {
|
|
|
|
|
if (curStyle != 5) {
|
2006-12-25 04:42:44 +01:00
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
|
|
|
|
curPos += ran;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
ran = 0;
|
|
|
|
|
curStyle = 5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Tag name
|
|
|
|
|
else if (curStyle != 3) {
|
2006-12-25 04:42:44 +01:00
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
|
|
|
|
curPos += ran;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
ran = 0;
|
|
|
|
|
curStyle = 3;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Increase ran length
|
|
|
|
|
ran++;
|
|
|
|
|
}
|
2006-12-25 04:42:44 +01:00
|
|
|
|
SetUnicodeStyling(curPos,ran,curStyle);
|
2006-12-24 23:46:20 +01:00
|
|
|
|
|
|
|
|
|
// Spell check
|
|
|
|
|
StyleSpellCheck(start,_length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-12-26 02:08:46 +01:00
|
|
|
|
///////////////////////////////////
|
|
|
|
|
// Get unicode-compatible position
|
|
|
|
|
int SubsTextEditCtrl::GetUnicodePosition(int pos) {
|
|
|
|
|
wxString string = GetText().Left(pos);
|
|
|
|
|
wxCharBuffer buffer = string.mb_str(wxConvUTF8);
|
|
|
|
|
return strlen(buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////
|
|
|
|
|
// Reverse unicode-compatible position
|
|
|
|
|
int SubsTextEditCtrl::GetReverseUnicodePosition(int pos) {
|
2006-12-26 02:20:58 +01:00
|
|
|
|
// Get UTF8
|
2006-12-26 02:08:46 +01:00
|
|
|
|
wxCharBuffer buffer = GetText().mb_str(wxConvUTF8);
|
2006-12-26 02:20:58 +01:00
|
|
|
|
|
|
|
|
|
// Limit position to it
|
|
|
|
|
if (pos > (signed)strlen(buffer)) pos = strlen(buffer);
|
|
|
|
|
|
|
|
|
|
// Get UTF8 substring
|
2006-12-26 02:08:46 +01:00
|
|
|
|
char *buf2 = new char[pos+1];
|
|
|
|
|
memcpy(buf2,buffer,pos);
|
|
|
|
|
buf2[pos] = 0;
|
2006-12-26 02:20:58 +01:00
|
|
|
|
|
|
|
|
|
// Convert back and return its length
|
2006-12-26 02:08:46 +01:00
|
|
|
|
wxString buf3(buf2,wxConvUTF8);
|
|
|
|
|
return buf3.Length();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-12-25 04:42:44 +01:00
|
|
|
|
////////////////////////
|
|
|
|
|
// Unicode-safe styling
|
|
|
|
|
void SubsTextEditCtrl::SetUnicodeStyling(int start,int length,int style) {
|
|
|
|
|
// Get the real length
|
|
|
|
|
wxString string = GetText().Mid(start,length);
|
|
|
|
|
wxCharBuffer buffer = string.mb_str(wxConvUTF8);
|
2006-12-26 02:08:46 +01:00
|
|
|
|
int len = strlen(buffer);
|
2006-12-25 04:42:44 +01:00
|
|
|
|
|
|
|
|
|
// Set styling
|
|
|
|
|
SetStyling(len,style);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-12-24 23:46:20 +01:00
|
|
|
|
///////////////
|
|
|
|
|
// Spell check
|
|
|
|
|
void SubsTextEditCtrl::StyleSpellCheck(int start, int len) {
|
|
|
|
|
// See if it has a spellchecker
|
|
|
|
|
if (!spellchecker) return;
|
|
|
|
|
|
|
|
|
|
// Variables
|
|
|
|
|
wxChar cur;
|
|
|
|
|
wxString text = GetText();
|
|
|
|
|
int curPos;
|
|
|
|
|
int lastpos = -1;
|
|
|
|
|
int end = start+len;
|
|
|
|
|
int depth = 0;
|
|
|
|
|
if (len < 0) end = text.Length();
|
|
|
|
|
wxArrayInt startPos;
|
|
|
|
|
wxArrayInt endPos;
|
|
|
|
|
bool isDelim;
|
|
|
|
|
|
|
|
|
|
// Scan
|
2006-12-25 04:42:44 +01:00
|
|
|
|
for (int i=start;i<end+1;i++) {
|
2006-12-24 23:46:20 +01:00
|
|
|
|
// Current character
|
|
|
|
|
curPos = i;
|
2006-12-25 04:42:44 +01:00
|
|
|
|
if (i < end) cur = text[i];
|
|
|
|
|
else cur = '.';
|
2006-12-24 23:46:20 +01:00
|
|
|
|
isDelim = false;
|
|
|
|
|
|
|
|
|
|
// Increase depth
|
|
|
|
|
if (cur == '{') {
|
|
|
|
|
depth++;
|
|
|
|
|
if (depth == 1) {
|
|
|
|
|
if (lastpos+1 != curPos) {
|
|
|
|
|
startPos.Add(lastpos+1);
|
|
|
|
|
endPos.Add(curPos);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Decrease depth
|
|
|
|
|
if (cur == '}') {
|
|
|
|
|
depth--;
|
|
|
|
|
if (depth == 0) {
|
|
|
|
|
lastpos = i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Wrong depth
|
|
|
|
|
if (depth != 0) continue;
|
|
|
|
|
|
|
|
|
|
// Check if it is \n or \N
|
2006-12-25 06:43:00 +01:00
|
|
|
|
if (cur == '\\' && i < end-1 && (text[i+1] == 'N' || text[i+1] == 'n' || text[i+1] == 'h')) {
|
2006-12-24 23:46:20 +01:00
|
|
|
|
isDelim = true;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for standard delimiters
|
|
|
|
|
if (delim.Find(cur) != wxNOT_FOUND) {
|
|
|
|
|
isDelim = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Is delimiter?
|
|
|
|
|
if (isDelim) {
|
|
|
|
|
if (lastpos+1 != curPos) {
|
|
|
|
|
startPos.Add(lastpos+1);
|
|
|
|
|
endPos.Add(curPos);
|
|
|
|
|
}
|
|
|
|
|
lastpos = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Style
|
|
|
|
|
int count = startPos.Count();
|
|
|
|
|
for (int i=0;i<count;i++) {
|
|
|
|
|
// Get current word
|
|
|
|
|
wxString curWord = text.Mid(startPos[i],endPos[i]-startPos[i]);
|
|
|
|
|
|
|
|
|
|
// Check if it's valid
|
|
|
|
|
if (!spellchecker->CheckWord(curWord)) {
|
2006-12-25 04:42:44 +01:00
|
|
|
|
// Get length before it
|
2006-12-26 02:08:46 +01:00
|
|
|
|
int utf8len = GetUnicodePosition(startPos[i]);
|
2006-12-25 04:42:44 +01:00
|
|
|
|
|
|
|
|
|
// Set styling
|
|
|
|
|
StartStyling(utf8len,32);
|
|
|
|
|
SetUnicodeStyling(startPos[i],endPos[i]-startPos[i],32);
|
2006-12-24 23:46:20 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-12-24 22:52:54 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////
|
|
|
|
|
// Set text to a new value
|
|
|
|
|
void SubsTextEditCtrl::SetTextTo(const wxString _text) {
|
|
|
|
|
// Setup
|
|
|
|
|
control->textEditReady = false;
|
|
|
|
|
Freeze();
|
|
|
|
|
wxString text = _text;
|
|
|
|
|
text.Replace(_T("\r\n"),_T("\\N"));
|
|
|
|
|
text.Replace(_T("\n\r"),_T("\\N"));
|
|
|
|
|
text.Replace(_T("\r"),_T("\\N"));
|
|
|
|
|
text.Replace(_T("\n"),_T("\\N"));
|
|
|
|
|
|
|
|
|
|
// Prepare
|
|
|
|
|
int from=0,to=0;
|
|
|
|
|
GetSelection(&from,&to);
|
|
|
|
|
Clear();
|
|
|
|
|
|
|
|
|
|
// Set text
|
|
|
|
|
SetText(text);
|
|
|
|
|
|
|
|
|
|
// Style
|
|
|
|
|
UpdateStyle();
|
|
|
|
|
|
|
|
|
|
// Restore selection
|
2006-12-26 02:20:58 +01:00
|
|
|
|
SetSelectionU(GetReverseUnicodePosition(from),GetReverseUnicodePosition(to));
|
2006-12-24 22:52:54 +01:00
|
|
|
|
|
|
|
|
|
// Finish
|
|
|
|
|
Thaw();
|
|
|
|
|
control->textEditReady = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////
|
|
|
|
|
// Control event table
|
|
|
|
|
BEGIN_EVENT_TABLE(SubsTextEditCtrl,wxScintilla)
|
|
|
|
|
EVT_MOUSE_EVENTS(SubsTextEditCtrl::OnMouseEvent)
|
2006-12-25 06:43:00 +01:00
|
|
|
|
|
|
|
|
|
EVT_MENU(EDIT_MENU_SPLIT_PRESERVE,SubsTextEditCtrl::OnSplitLinePreserve)
|
|
|
|
|
EVT_MENU(EDIT_MENU_SPLIT_ESTIMATE,SubsTextEditCtrl::OnSplitLineEstimate)
|
|
|
|
|
EVT_MENU(EDIT_MENU_CUT,SubsTextEditCtrl::OnCut)
|
|
|
|
|
EVT_MENU(EDIT_MENU_COPY,SubsTextEditCtrl::OnCopy)
|
|
|
|
|
EVT_MENU(EDIT_MENU_PASTE,SubsTextEditCtrl::OnPaste)
|
|
|
|
|
EVT_MENU(EDIT_MENU_UNDO,SubsTextEditCtrl::OnUndo)
|
|
|
|
|
EVT_MENU(EDIT_MENU_SELECT_ALL,SubsTextEditCtrl::OnSelectAll)
|
|
|
|
|
EVT_MENU(EDIT_MENU_ADD_TO_DICT,SubsTextEditCtrl::OnAddToDictionary)
|
|
|
|
|
EVT_MENU_RANGE(EDIT_MENU_SUGGESTIONS,EDIT_MENU_SUGGESTIONS+16,SubsTextEditCtrl::OnUseSuggestion)
|
2006-12-25 23:21:44 +01:00
|
|
|
|
EVT_MENU_RANGE(EDIT_MENU_THESAURUS_SUGS,EDIT_MENU_THESAURUS_SUGS+2000,SubsTextEditCtrl::OnUseThesaurusSuggestion)
|
2006-12-24 22:52:54 +01:00
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////
|
|
|
|
|
// Mouse event
|
|
|
|
|
void SubsTextEditCtrl::OnMouseEvent(wxMouseEvent &event) {
|
|
|
|
|
// Right click
|
|
|
|
|
if (event.ButtonUp(wxMOUSE_BTN_RIGHT)) {
|
|
|
|
|
if (control->linen >= 0) {
|
2006-12-25 06:43:00 +01:00
|
|
|
|
int pos = PositionFromPoint(event.GetPosition());
|
|
|
|
|
ShowPopupMenu(pos);
|
2006-12-24 22:52:54 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
event.Skip();
|
|
|
|
|
}
|
2006-12-25 06:43:00 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////
|
|
|
|
|
// Show popup menu
|
|
|
|
|
void SubsTextEditCtrl::ShowPopupMenu(int activePos) {
|
|
|
|
|
// Menu
|
|
|
|
|
wxMenu menu;
|
|
|
|
|
|
|
|
|
|
// Position
|
|
|
|
|
if (activePos == -1) activePos = GetCurrentPos();
|
2006-12-26 02:08:46 +01:00
|
|
|
|
activePos = GetReverseUnicodePosition(activePos);
|
2006-12-25 06:43:00 +01:00
|
|
|
|
|
2006-12-25 22:56:56 +01:00
|
|
|
|
// Get current word under cursor
|
|
|
|
|
currentWord = GetWordAtPosition(activePos);
|
|
|
|
|
currentWordPos = activePos;
|
|
|
|
|
|
2006-12-25 06:43:00 +01:00
|
|
|
|
// Spell check
|
|
|
|
|
int style = GetStyleAt(activePos);
|
2006-12-26 00:10:23 +01:00
|
|
|
|
if (spellchecker && currentWord.Length()) {
|
|
|
|
|
// Spelled right?
|
|
|
|
|
bool rightSpelling = spellchecker->CheckWord(currentWord);
|
|
|
|
|
|
2006-12-25 06:52:29 +01:00
|
|
|
|
// Set font
|
|
|
|
|
wxFont font;
|
|
|
|
|
font.SetWeight(wxFONTWEIGHT_BOLD);
|
|
|
|
|
|
2006-12-25 22:56:56 +01:00
|
|
|
|
// Get suggestions
|
|
|
|
|
sugs.Clear();
|
|
|
|
|
sugs = spellchecker->GetSuggestions(currentWord);
|
|
|
|
|
int nSugs = sugs.Count();
|
2006-12-25 06:43:00 +01:00
|
|
|
|
|
2006-12-26 00:10:23 +01:00
|
|
|
|
// Spelled wrong
|
|
|
|
|
if (!rightSpelling) {
|
|
|
|
|
// No suggestions
|
|
|
|
|
if (!nSugs) menu.Append(EDIT_MENU_SUGGESTION,_("No correction suggestions"))->Enable(false);
|
2006-12-25 06:52:29 +01:00
|
|
|
|
|
2006-12-26 00:10:23 +01:00
|
|
|
|
// Build menu
|
|
|
|
|
for (int i=0;i<nSugs;i++) menu.Append(EDIT_MENU_SUGGESTIONS+i,sugs[i])->SetFont(font);
|
|
|
|
|
|
|
|
|
|
// Append "add word"
|
2006-12-26 02:08:46 +01:00
|
|
|
|
menu.Append(EDIT_MENU_ADD_TO_DICT,wxString::Format(_("Add \"%s\" to dictionary"),currentWord.c_str()))->Enable(spellchecker->CanAddWord(currentWord));
|
2006-12-26 00:10:23 +01:00
|
|
|
|
menu.AppendSeparator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Spelled right
|
|
|
|
|
else {
|
|
|
|
|
// No suggestions
|
|
|
|
|
if (!nSugs) menu.Append(EDIT_MENU_SUGGESTION,_("No spell checker suggestions"))->Enable(false);
|
|
|
|
|
|
|
|
|
|
// Has suggestions
|
|
|
|
|
else {
|
|
|
|
|
// Build list
|
|
|
|
|
wxMenu *subMenu = new wxMenu();
|
|
|
|
|
for (int i=0;i<nSugs;i++) subMenu->Append(EDIT_MENU_SUGGESTIONS+i,sugs[i]);
|
|
|
|
|
menu.AppendSubMenu(subMenu,wxString::Format(_("Spell checker suggestions for \"%s\""),currentWord.c_str()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Separator
|
|
|
|
|
if (!thesaurus) menu.AppendSeparator();
|
|
|
|
|
}
|
2006-12-25 22:56:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Thesaurus
|
2006-12-26 00:10:23 +01:00
|
|
|
|
if (thesaurus && currentWord.Length()) {
|
2006-12-25 23:21:44 +01:00
|
|
|
|
// Get results
|
|
|
|
|
ThesaurusEntryArray result;
|
|
|
|
|
thesaurus->Lookup(currentWord,result);
|
|
|
|
|
|
|
|
|
|
// Compile list
|
2006-12-25 22:56:56 +01:00
|
|
|
|
thesSugs.Clear();
|
2006-12-25 23:21:44 +01:00
|
|
|
|
for (unsigned int i=0;i<result.size();i++) {
|
|
|
|
|
for (unsigned int j=0;j<result[i].words.Count();j++) {
|
|
|
|
|
thesSugs.Add(result[i].words[j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-12-25 22:56:56 +01:00
|
|
|
|
|
2006-12-25 23:52:21 +01:00
|
|
|
|
// Has suggestions
|
|
|
|
|
if (result.size()) {
|
2006-12-26 00:10:23 +01:00
|
|
|
|
// Set font
|
2006-12-25 23:52:21 +01:00
|
|
|
|
wxFont font;
|
|
|
|
|
font.SetStyle(wxFONTSTYLE_ITALIC);
|
|
|
|
|
|
2006-12-26 00:10:23 +01:00
|
|
|
|
// Create thesaurus menu
|
|
|
|
|
wxMenu *thesMenu = new wxMenu();
|
2006-12-25 23:21:44 +01:00
|
|
|
|
|
2006-12-26 00:10:23 +01:00
|
|
|
|
// Build menu
|
|
|
|
|
int curThesEntry = 0;
|
|
|
|
|
for (unsigned int i=0;i<result.size();i++) {
|
|
|
|
|
// Single word, insert directly
|
|
|
|
|
if (result[i].words.Count() == 1) {
|
|
|
|
|
thesMenu->Append(EDIT_MENU_THESAURUS_SUGS+curThesEntry,result[i].name);
|
2006-12-25 23:21:44 +01:00
|
|
|
|
curThesEntry++;
|
|
|
|
|
}
|
|
|
|
|
|
2006-12-26 00:10:23 +01:00
|
|
|
|
// Multiple, create submenu
|
|
|
|
|
else {
|
|
|
|
|
// Insert entries
|
|
|
|
|
wxMenu *subMenu = new wxMenu();
|
|
|
|
|
for (unsigned int j=0;j<result[i].words.Count();j++) {
|
|
|
|
|
subMenu->Append(EDIT_MENU_THESAURUS_SUGS+curThesEntry,result[i].words[j]);
|
|
|
|
|
curThesEntry++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Insert submenu
|
|
|
|
|
thesMenu->AppendSubMenu(subMenu,result[i].name);
|
|
|
|
|
}
|
2006-12-25 23:21:44 +01:00
|
|
|
|
}
|
2006-12-26 00:10:23 +01:00
|
|
|
|
|
|
|
|
|
// Thesaurus menu
|
|
|
|
|
menu.AppendSubMenu(thesMenu,wxString::Format(_("Thesaurus suggestions for \"%s\""),currentWord.c_str()));
|
2006-12-25 23:21:44 +01:00
|
|
|
|
}
|
2006-12-25 22:56:56 +01:00
|
|
|
|
|
|
|
|
|
// No suggestions
|
2006-12-25 23:21:44 +01:00
|
|
|
|
if (!result.size()) menu.Append(EDIT_MENU_THESAURUS,_("No thesaurus suggestions"))->Enable(false);
|
2006-12-25 22:56:56 +01:00
|
|
|
|
|
|
|
|
|
// Separator
|
|
|
|
|
menu.AppendSeparator();
|
2006-12-25 06:43:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
2006-12-25 06:52:29 +01:00
|
|
|
|
// Standard actions
|
|
|
|
|
menu.Append(EDIT_MENU_UNDO,_("&Undo"))->Enable(CanUndo());
|
|
|
|
|
menu.AppendSeparator();
|
|
|
|
|
menu.Append(EDIT_MENU_CUT,_("Cu&t"))->Enable(GetSelectionStart()-GetSelectionEnd() != 0);
|
|
|
|
|
menu.Append(EDIT_MENU_COPY,_("&Copy"))->Enable(GetSelectionStart()-GetSelectionEnd() != 0);
|
|
|
|
|
menu.Append(EDIT_MENU_PASTE,_("&Paste"))->Enable(CanPaste());
|
|
|
|
|
menu.AppendSeparator();
|
|
|
|
|
menu.Append(EDIT_MENU_SELECT_ALL,_("Select &All"));
|
|
|
|
|
|
|
|
|
|
// Split
|
|
|
|
|
menu.AppendSeparator();
|
|
|
|
|
menu.Append(EDIT_MENU_SPLIT_PRESERVE,_("Split at cursor (preserve times)"));
|
|
|
|
|
menu.Append(EDIT_MENU_SPLIT_ESTIMATE,_("Split at cursor (estimate times)"));
|
|
|
|
|
|
2006-12-25 06:43:00 +01:00
|
|
|
|
// Pop the menu
|
|
|
|
|
PopupMenu(&menu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////
|
|
|
|
|
// Get boundaries of word at position
|
|
|
|
|
void SubsTextEditCtrl::GetBoundsOfWordAtPosition(int pos,int &_start,int &_end) {
|
|
|
|
|
// Variables
|
|
|
|
|
wxString text = GetText();
|
|
|
|
|
int len = text.Length();
|
|
|
|
|
int lastDelimBefore = -1;
|
|
|
|
|
int firstDelimAfter = len;
|
|
|
|
|
wxChar cur,next;
|
|
|
|
|
int depth=0;
|
|
|
|
|
|
|
|
|
|
// Scan for delimiters
|
|
|
|
|
for (int i=0;i<len;i++) {
|
|
|
|
|
// Current char
|
|
|
|
|
cur = text[i];
|
|
|
|
|
if (i<len-1) next = text[i+1];
|
|
|
|
|
else next = 0;
|
|
|
|
|
|
|
|
|
|
// Depth
|
2006-12-25 23:52:21 +01:00
|
|
|
|
if (cur == '{') {
|
|
|
|
|
if (i >= pos) {
|
|
|
|
|
firstDelimAfter = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
depth++;
|
|
|
|
|
}
|
|
|
|
|
if (cur == '}') {
|
|
|
|
|
if (i < pos) {
|
|
|
|
|
lastDelimBefore = i;
|
|
|
|
|
}
|
|
|
|
|
depth--;
|
|
|
|
|
}
|
|
|
|
|
if (depth != 0) {
|
|
|
|
|
// Picked a location in invalid depth
|
|
|
|
|
if (pos == i) {
|
|
|
|
|
lastDelimBefore = -1;
|
|
|
|
|
firstDelimAfter = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2006-12-25 06:43:00 +01:00
|
|
|
|
|
|
|
|
|
// Line breaks
|
|
|
|
|
if (cur == '\\' && (next == 'N' || next == 'n' || next == 'h')) {
|
|
|
|
|
// Before
|
|
|
|
|
if (i < pos) {
|
|
|
|
|
i++;
|
|
|
|
|
lastDelimBefore = i;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for delimiters
|
|
|
|
|
if (delim.Find(cur) != wxNOT_FOUND) {
|
|
|
|
|
// Before
|
|
|
|
|
if (i < pos) lastDelimBefore = i;
|
|
|
|
|
|
|
|
|
|
// After
|
|
|
|
|
else {
|
|
|
|
|
firstDelimAfter = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set start and end
|
|
|
|
|
_start = lastDelimBefore+1;
|
|
|
|
|
_end = firstDelimAfter-1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////
|
|
|
|
|
// Get word at specified position
|
|
|
|
|
wxString SubsTextEditCtrl::GetWordAtPosition(int pos) {
|
|
|
|
|
int start,end;
|
|
|
|
|
GetBoundsOfWordAtPosition(pos,start,end);
|
|
|
|
|
return GetText().Mid(start,end-start+1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////
|
|
|
|
|
// Split line preserving times
|
|
|
|
|
void SubsTextEditCtrl::OnSplitLinePreserve (wxCommandEvent &event) {
|
|
|
|
|
int from,to;
|
|
|
|
|
GetSelection(&from, &to);
|
2006-12-26 02:30:30 +01:00
|
|
|
|
from = GetReverseUnicodePosition(from);
|
|
|
|
|
to = GetReverseUnicodePosition(to);
|
2006-12-25 06:43:00 +01:00
|
|
|
|
control->grid->SplitLine(control->linen,from,0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////////////////////////////
|
|
|
|
|
// Split line estimating times
|
|
|
|
|
void SubsTextEditCtrl::OnSplitLineEstimate (wxCommandEvent &event) {
|
|
|
|
|
int from,to;
|
|
|
|
|
GetSelection(&from, &to);
|
2006-12-26 02:30:30 +01:00
|
|
|
|
from = GetReverseUnicodePosition(from);
|
|
|
|
|
to = GetReverseUnicodePosition(to);
|
2006-12-25 06:43:00 +01:00
|
|
|
|
control->grid->SplitLine(control->linen,from,1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///////
|
|
|
|
|
// Cut
|
|
|
|
|
void SubsTextEditCtrl::OnCut(wxCommandEvent &event) {
|
|
|
|
|
Cut();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////
|
|
|
|
|
// Copy
|
|
|
|
|
void SubsTextEditCtrl::OnCopy(wxCommandEvent &event) {
|
|
|
|
|
Copy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////
|
|
|
|
|
// Paste
|
|
|
|
|
void SubsTextEditCtrl::OnPaste(wxCommandEvent &event) {
|
|
|
|
|
Paste();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////
|
|
|
|
|
// Undo
|
|
|
|
|
void SubsTextEditCtrl::OnUndo(wxCommandEvent &event) {
|
|
|
|
|
Undo();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////
|
|
|
|
|
// Select All
|
|
|
|
|
void SubsTextEditCtrl::OnSelectAll(wxCommandEvent &event) {
|
|
|
|
|
SelectAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////
|
|
|
|
|
// Add word to dictionary
|
|
|
|
|
void SubsTextEditCtrl::OnAddToDictionary(wxCommandEvent &event) {
|
|
|
|
|
if (spellchecker) spellchecker->AddWord(currentWord);
|
|
|
|
|
SetFocus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////
|
|
|
|
|
// Use suggestion
|
|
|
|
|
void SubsTextEditCtrl::OnUseSuggestion(wxCommandEvent &event) {
|
|
|
|
|
// Get suggestion
|
|
|
|
|
wxString suggestion = sugs[event.GetId()-EDIT_MENU_SUGGESTIONS];
|
|
|
|
|
|
|
|
|
|
// Get boundaries of text being replaced
|
|
|
|
|
int start,end;
|
|
|
|
|
GetBoundsOfWordAtPosition(currentWordPos,start,end);
|
|
|
|
|
|
|
|
|
|
// Replace
|
|
|
|
|
wxString text = GetText();
|
|
|
|
|
SetText(text.Left(MAX(0,start)) + suggestion + text.Mid(end+1));
|
|
|
|
|
|
|
|
|
|
// Set selection
|
2006-12-26 02:20:58 +01:00
|
|
|
|
SetSelectionU(start,start+suggestion.Length());
|
2006-12-25 06:43:00 +01:00
|
|
|
|
SetFocus();
|
|
|
|
|
}
|
2006-12-25 23:21:44 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////
|
|
|
|
|
// Use thesaurus suggestion
|
|
|
|
|
void SubsTextEditCtrl::OnUseThesaurusSuggestion(wxCommandEvent &event) {
|
|
|
|
|
// Get suggestion
|
|
|
|
|
wxString suggestion = thesSugs[event.GetId()-EDIT_MENU_THESAURUS_SUGS];
|
2006-12-25 23:30:11 +01:00
|
|
|
|
|
|
|
|
|
// Stripe suggestion of parenthesis
|
|
|
|
|
int pos = suggestion.Find(_T("("));
|
|
|
|
|
if (pos != wxNOT_FOUND) {
|
|
|
|
|
suggestion = suggestion.Left(pos-1);
|
|
|
|
|
}
|
2006-12-25 23:21:44 +01:00
|
|
|
|
|
|
|
|
|
// Get boundaries of text being replaced
|
|
|
|
|
int start,end;
|
|
|
|
|
GetBoundsOfWordAtPosition(currentWordPos,start,end);
|
|
|
|
|
|
|
|
|
|
// Replace
|
|
|
|
|
wxString text = GetText();
|
|
|
|
|
SetText(text.Left(MAX(0,start)) + suggestion + text.Mid(end+1));
|
|
|
|
|
|
|
|
|
|
// Set selection
|
2006-12-26 02:20:58 +01:00
|
|
|
|
SetSelectionU(start,start+suggestion.Length());
|
2006-12-25 23:21:44 +01:00
|
|
|
|
SetFocus();
|
|
|
|
|
}
|
2006-12-26 02:20:58 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Set selection, unicode-aware
|
|
|
|
|
void SubsTextEditCtrl::SetSelectionU(int start, int end) {
|
|
|
|
|
SetSelection(GetUnicodePosition(start),GetUnicodePosition(end));
|
|
|
|
|
}
|