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.
|
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// Aegisub Project http://www.aegisub.org/
|
2006-12-24 22:52:54 +01:00
|
|
|
//
|
2009-07-29 07:43:02 +02:00
|
|
|
// $Id$
|
|
|
|
|
|
|
|
/// @file subs_edit_ctrl.cpp
|
|
|
|
/// @brief Main subtitle editing text control
|
|
|
|
/// @ingroup main_ui
|
|
|
|
///
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2009-01-04 07:31:48 +01:00
|
|
|
#include "config.h"
|
|
|
|
|
2009-09-10 15:06:40 +02:00
|
|
|
#ifndef AGI_PRE
|
2010-07-20 05:11:11 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
#include <functional>
|
|
|
|
#else
|
|
|
|
#include <tr1/functional>
|
|
|
|
#endif
|
2007-01-01 05:53:55 +01:00
|
|
|
#include <wx/intl.h>
|
2009-09-10 15:06:40 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ass_dialogue.h"
|
2010-05-21 03:13:36 +02:00
|
|
|
#include "compat.h"
|
|
|
|
#include "main.h"
|
2010-08-02 08:31:38 +02:00
|
|
|
#include "include/aegisub/spellchecker.h"
|
2010-12-08 04:36:10 +01:00
|
|
|
#include "selection_controller.h"
|
2009-09-10 15:06:40 +02:00
|
|
|
#include "subs_edit_box.h"
|
2010-07-20 05:11:11 +02:00
|
|
|
#include "subs_edit_ctrl.h"
|
2006-12-25 06:43:00 +01:00
|
|
|
#include "subs_grid.h"
|
2010-07-20 05:11:11 +02:00
|
|
|
#include "thesaurus.h"
|
2006-12-25 06:43:00 +01:00
|
|
|
#include "utils.h"
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2010-07-20 05:11:11 +02:00
|
|
|
/// Event ids
|
|
|
|
enum {
|
|
|
|
EDIT_MENU_SPLIT_PRESERVE = 1400,
|
|
|
|
EDIT_MENU_SPLIT_ESTIMATE,
|
|
|
|
EDIT_MENU_CUT,
|
|
|
|
EDIT_MENU_COPY,
|
|
|
|
EDIT_MENU_PASTE,
|
|
|
|
EDIT_MENU_SELECT_ALL,
|
|
|
|
EDIT_MENU_ADD_TO_DICT,
|
|
|
|
EDIT_MENU_SUGGESTION,
|
|
|
|
EDIT_MENU_SUGGESTIONS,
|
|
|
|
EDIT_MENU_THESAURUS = 1450,
|
|
|
|
EDIT_MENU_THESAURUS_SUGS,
|
|
|
|
EDIT_MENU_DIC_LANGUAGE = 1600,
|
|
|
|
EDIT_MENU_DIC_LANGS,
|
|
|
|
EDIT_MENU_THES_LANGUAGE = 1700,
|
|
|
|
EDIT_MENU_THES_LANGS
|
|
|
|
};
|
|
|
|
|
|
|
|
SubsTextEditCtrl::SubsTextEditCtrl(wxWindow* parent, wxSize wsize, long style, SubtitlesGrid *grid)
|
2011-09-29 06:38:15 +02:00
|
|
|
: ScintillaTextCtrl(parent, -1, "", wxDefaultPosition, wsize, style)
|
2010-08-02 08:31:38 +02:00
|
|
|
, spellchecker(SpellCheckerFactory::GetSpellChecker())
|
2010-07-20 05:11:11 +02:00
|
|
|
, thesaurus(Thesaurus::GetThesaurus())
|
|
|
|
, grid(grid)
|
2006-12-24 22:52:54 +01:00
|
|
|
{
|
|
|
|
// Set properties
|
2007-04-22 01:16:38 +02:00
|
|
|
SetWrapMode(wxSTC_WRAP_WORD);
|
2006-12-24 22:52:54 +01:00
|
|
|
SetMarginWidth(1,0);
|
2006-12-25 22:56:56 +01:00
|
|
|
UsePopUp(false);
|
2007-01-03 22:49:13 +01:00
|
|
|
SetStyles();
|
2006-12-25 04:42:44 +01:00
|
|
|
|
|
|
|
// Set hotkeys
|
2007-04-22 01:16:38 +02:00
|
|
|
CmdKeyClear(wxSTC_KEY_RETURN,wxSTC_SCMOD_CTRL);
|
|
|
|
CmdKeyClear(wxSTC_KEY_RETURN,wxSTC_SCMOD_NORM);
|
|
|
|
CmdKeyClear(wxSTC_KEY_TAB,wxSTC_SCMOD_NORM);
|
|
|
|
CmdKeyClear(wxSTC_KEY_TAB,wxSTC_SCMOD_SHIFT);
|
|
|
|
CmdKeyClear('D',wxSTC_SCMOD_CTRL);
|
|
|
|
CmdKeyClear('L',wxSTC_SCMOD_CTRL);
|
|
|
|
CmdKeyClear('L',wxSTC_SCMOD_CTRL | wxSTC_SCMOD_SHIFT);
|
|
|
|
CmdKeyClear('T',wxSTC_SCMOD_CTRL);
|
|
|
|
CmdKeyClear('T',wxSTC_SCMOD_CTRL | wxSTC_SCMOD_SHIFT);
|
|
|
|
CmdKeyClear('U',wxSTC_SCMOD_CTRL);
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2007-01-02 19:09:56 +01:00
|
|
|
// Prototypes for call tips
|
2007-01-02 19:15:17 +01:00
|
|
|
tipProtoN = -1;
|
2011-09-28 21:43:11 +02:00
|
|
|
proto.Add("move(x1,y1,x2,y2)");
|
|
|
|
proto.Add("move(x1,y1,x2,y2,startTime,endTime)");
|
|
|
|
proto.Add("fn;FontName");
|
|
|
|
proto.Add("bord;Width");
|
|
|
|
proto.Add("xbord;Width");
|
|
|
|
proto.Add("ybord;Width");
|
|
|
|
proto.Add("shad;Depth");
|
|
|
|
proto.Add("xshad;Depth");
|
|
|
|
proto.Add("yshad;Depth");
|
|
|
|
proto.Add("be;Strength");
|
|
|
|
proto.Add("blur;Strength");
|
|
|
|
proto.Add("fscx;Scale");
|
|
|
|
proto.Add("fscy;Scale");
|
|
|
|
proto.Add("fsp;Spacing");
|
|
|
|
proto.Add("fs;FontSize");
|
|
|
|
proto.Add("fe;Encoding");
|
|
|
|
proto.Add("frx;Angle");
|
|
|
|
proto.Add("fry;Angle");
|
|
|
|
proto.Add("frz;Angle");
|
|
|
|
proto.Add("fr;Angle");
|
|
|
|
proto.Add("pbo;Offset");
|
|
|
|
proto.Add("clip(command)");
|
|
|
|
proto.Add("clip(scale,command)");
|
|
|
|
proto.Add("clip(x1,y1,x2,y2)");
|
|
|
|
proto.Add("iclip(command)");
|
|
|
|
proto.Add("iclip(scale,command)");
|
|
|
|
proto.Add("iclip(x1,y1,x2,y2)");
|
|
|
|
proto.Add("t(acceleration,tags)");
|
|
|
|
proto.Add("t(startTime,endTime,tags)");
|
|
|
|
proto.Add("t(startTime,endTime,acceleration,tags)");
|
|
|
|
proto.Add("pos(x,y)");
|
|
|
|
proto.Add("p;Exponent");
|
|
|
|
proto.Add("org(x,y)");
|
|
|
|
proto.Add("fade(startAlpha,middleAlpha,endAlpha,startIn,endIn,startOut,endOut)");
|
|
|
|
proto.Add("fad(startTime,endTime)");
|
|
|
|
proto.Add("c;Colour");
|
|
|
|
proto.Add("1c;Colour");
|
|
|
|
proto.Add("2c;Colour");
|
|
|
|
proto.Add("3c;Colour");
|
|
|
|
proto.Add("4c;Colour");
|
|
|
|
proto.Add("alpha;Alpha");
|
|
|
|
proto.Add("1a;Alpha");
|
|
|
|
proto.Add("2a;Alpha");
|
|
|
|
proto.Add("3a;Alpha");
|
|
|
|
proto.Add("4a;Alpha");
|
|
|
|
proto.Add("an;Alignment");
|
|
|
|
proto.Add("a;Alignment");
|
|
|
|
proto.Add("b;Weight");
|
|
|
|
proto.Add("i;1/0");
|
|
|
|
proto.Add("u;1/0");
|
|
|
|
proto.Add("s;1/0");
|
|
|
|
proto.Add("kf;Duration");
|
|
|
|
proto.Add("ko;Duration");
|
|
|
|
proto.Add("k;Duration");
|
|
|
|
proto.Add("K;Duration");
|
|
|
|
proto.Add("q;WrapStyle");
|
|
|
|
proto.Add("r;Style");
|
|
|
|
proto.Add("fax;Factor");
|
|
|
|
proto.Add("fay;Factor");
|
2010-07-20 05:11:11 +02:00
|
|
|
|
|
|
|
using namespace std::tr1;
|
|
|
|
|
|
|
|
Bind(wxEVT_COMMAND_MENU_SELECTED, function<void (wxCommandEvent &)>(bind(&SubsTextEditCtrl::Cut, this)), EDIT_MENU_CUT);
|
|
|
|
Bind(wxEVT_COMMAND_MENU_SELECTED, function<void (wxCommandEvent &)>(bind(&SubsTextEditCtrl::Copy, this)), EDIT_MENU_COPY);
|
|
|
|
Bind(wxEVT_COMMAND_MENU_SELECTED, function<void (wxCommandEvent &)>(bind(&SubsTextEditCtrl::Paste, this)), EDIT_MENU_PASTE);
|
|
|
|
Bind(wxEVT_COMMAND_MENU_SELECTED, function<void (wxCommandEvent &)>(bind(&SubsTextEditCtrl::SelectAll, this)), EDIT_MENU_SELECT_ALL);
|
|
|
|
|
|
|
|
Bind(wxEVT_STC_STYLENEEDED, &SubsTextEditCtrl::UpdateCallTip, this);
|
2010-08-26 20:38:37 +02:00
|
|
|
|
2011-08-31 06:17:37 +02:00
|
|
|
Bind(wxEVT_CONTEXT_MENU, &SubsTextEditCtrl::OnContextMenu, this);
|
|
|
|
|
2010-12-07 20:09:15 +01:00
|
|
|
OPT_SUB("Subtitle/Edit Box/Font Face", &SubsTextEditCtrl::SetStyles, this);
|
|
|
|
OPT_SUB("Subtitle/Edit Box/Font Size", &SubsTextEditCtrl::SetStyles, this);
|
2011-09-28 21:44:34 +02:00
|
|
|
Subscribe("Normal");
|
|
|
|
Subscribe("Comment");
|
|
|
|
Subscribe("Drawing");
|
|
|
|
Subscribe("Brackets");
|
|
|
|
Subscribe("Slashes");
|
|
|
|
Subscribe("Tags");
|
|
|
|
Subscribe("Error");
|
|
|
|
Subscribe("Parameters");
|
|
|
|
Subscribe("Line Break");
|
|
|
|
Subscribe("Karaoke Template");
|
|
|
|
Subscribe("Karaoke Variable");
|
|
|
|
|
|
|
|
OPT_SUB("Subtitle/Highlight/Syntax", &SubsTextEditCtrl::UpdateStyle, this);
|
2010-08-26 20:38:37 +02:00
|
|
|
static wxStyledTextEvent evt;
|
2010-12-07 20:09:15 +01:00
|
|
|
OPT_SUB("App/Call Tips", &SubsTextEditCtrl::UpdateCallTip, this, ref(evt));
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
|
|
|
|
2010-08-26 20:38:37 +02:00
|
|
|
|
2006-12-24 22:52:54 +01:00
|
|
|
SubsTextEditCtrl::~SubsTextEditCtrl() {
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
void SubsTextEditCtrl::Subscribe(std::string const& name) {
|
|
|
|
OPT_SUB("Colour/Subtitle/Syntax/" + name, &SubsTextEditCtrl::SetStyles, this);
|
|
|
|
OPT_SUB("Colour/Subtitle/Syntax/Background/" + name, &SubsTextEditCtrl::SetStyles, this);
|
|
|
|
OPT_SUB("Colour/Subtitle/Syntax/Bold/" + name, &SubsTextEditCtrl::SetStyles, this);
|
|
|
|
}
|
|
|
|
|
2007-04-22 01:16:38 +02:00
|
|
|
BEGIN_EVENT_TABLE(SubsTextEditCtrl,wxStyledTextCtrl)
|
2007-01-14 00:34:04 +01:00
|
|
|
EVT_KILL_FOCUS(SubsTextEditCtrl::OnLoseFocus)
|
2007-01-02 06:00:55 +01:00
|
|
|
|
|
|
|
EVT_MENU(EDIT_MENU_SPLIT_PRESERVE,SubsTextEditCtrl::OnSplitLinePreserve)
|
|
|
|
EVT_MENU(EDIT_MENU_SPLIT_ESTIMATE,SubsTextEditCtrl::OnSplitLineEstimate)
|
|
|
|
EVT_MENU(EDIT_MENU_ADD_TO_DICT,SubsTextEditCtrl::OnAddToDictionary)
|
|
|
|
EVT_MENU_RANGE(EDIT_MENU_SUGGESTIONS,EDIT_MENU_THESAURUS-1,SubsTextEditCtrl::OnUseSuggestion)
|
2010-07-20 05:11:11 +02:00
|
|
|
EVT_MENU_RANGE(EDIT_MENU_THESAURUS_SUGS,EDIT_MENU_DIC_LANGUAGE-1,SubsTextEditCtrl::OnUseSuggestion)
|
2007-01-02 06:00:55 +01:00
|
|
|
EVT_MENU_RANGE(EDIT_MENU_DIC_LANGS,EDIT_MENU_THES_LANGUAGE-1,SubsTextEditCtrl::OnSetDicLanguage)
|
|
|
|
EVT_MENU_RANGE(EDIT_MENU_THES_LANGS,EDIT_MENU_THES_LANGS+100,SubsTextEditCtrl::OnSetThesLanguage)
|
|
|
|
END_EVENT_TABLE()
|
|
|
|
|
2007-01-14 00:34:04 +01:00
|
|
|
void SubsTextEditCtrl::OnLoseFocus(wxFocusEvent &event) {
|
|
|
|
CallTipCancel();
|
|
|
|
event.Skip();
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
enum {
|
|
|
|
STYLE_NORMAL = 0,
|
|
|
|
STYLE_COMMENT,
|
|
|
|
STYLE_DRAWING,
|
|
|
|
STYLE_OVERRIDE,
|
|
|
|
STYLE_PUNCTUATION,
|
|
|
|
STYLE_TAG,
|
|
|
|
STYLE_ERROR,
|
|
|
|
STYLE_PARAMETER,
|
|
|
|
STYLE_LINE_BREAK,
|
|
|
|
STYLE_KARAOKE_TEMPLATE,
|
|
|
|
STYLE_KARAOKE_VARIABLE
|
|
|
|
};
|
|
|
|
|
|
|
|
void SubsTextEditCtrl::SetStyle(int id, wxFont &font, std::string const& name) {
|
|
|
|
StyleSetFont(id, font);
|
|
|
|
StyleSetBold(id, OPT_GET("Colour/Subtitle/Syntax/Bold/" + name)->GetBool());
|
|
|
|
StyleSetForeground(id, lagi_wxColour(OPT_GET("Colour/Subtitle/Syntax/" + name)->GetColour()));
|
|
|
|
const agi::OptionValue *background = OPT_GET("Colour/Subtitle/Syntax/Background/" + name);
|
|
|
|
if (background->GetType() == agi::OptionValue::Type_Colour)
|
|
|
|
StyleSetBackground(id, lagi_wxColour(background->GetColour()));
|
|
|
|
}
|
|
|
|
|
2007-01-03 22:49:13 +01:00
|
|
|
void SubsTextEditCtrl::SetStyles() {
|
|
|
|
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
2009-12-27 20:49:27 +01:00
|
|
|
font.SetEncoding(wxFONTENCODING_DEFAULT); // this solves problems with some fonts not working properly
|
2010-05-21 03:13:36 +02:00
|
|
|
wxString fontname = lagi_wxString(OPT_GET("Subtitle/Edit Box/Font Face")->GetString());
|
2010-07-20 05:11:11 +02:00
|
|
|
if (!fontname.empty()) font.SetFaceName(fontname);
|
2011-09-28 21:44:34 +02:00
|
|
|
font.SetPointSize(OPT_GET("Subtitle/Edit Box/Font Size")->GetInt());
|
|
|
|
|
|
|
|
SetStyle(STYLE_NORMAL, font, "Normal");
|
|
|
|
SetStyle(STYLE_COMMENT, font, "Comment");
|
|
|
|
SetStyle(STYLE_DRAWING, font, "Drawing");
|
|
|
|
SetStyle(STYLE_OVERRIDE, font, "Brackets");
|
|
|
|
SetStyle(STYLE_PUNCTUATION, font, "Slashes");
|
|
|
|
SetStyle(STYLE_TAG, font, "Tags");
|
|
|
|
SetStyle(STYLE_ERROR, font, "Error");
|
|
|
|
SetStyle(STYLE_PARAMETER, font, "Parameters");
|
|
|
|
SetStyle(STYLE_LINE_BREAK, font, "Line Break");
|
|
|
|
SetStyle(STYLE_KARAOKE_TEMPLATE, font, "Karaoke Template");
|
|
|
|
SetStyle(STYLE_KARAOKE_VARIABLE, font, "Karaoke Variable");
|
2007-08-06 16:29:43 +02:00
|
|
|
|
2007-01-03 22:49:13 +01:00
|
|
|
// Misspelling indicator
|
2007-04-22 01:16:38 +02:00
|
|
|
IndicatorSetStyle(0,wxSTC_INDIC_SQUIGGLE);
|
2007-01-03 22:49:13 +01:00
|
|
|
IndicatorSetForeground(0,wxColour(255,0,0));
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
void SubsTextEditCtrl::UpdateStyle() {
|
|
|
|
StartStyling(0,255);
|
|
|
|
|
|
|
|
std::string text = STD_STR(GetText());
|
2011-08-27 08:52:35 +02:00
|
|
|
|
2010-08-26 20:38:37 +02:00
|
|
|
if (!OPT_GET("Subtitle/Highlight/Syntax")->GetBool()) {
|
2011-09-28 21:44:34 +02:00
|
|
|
SetStyling(text.size(), 0);
|
2010-08-26 20:38:37 +02:00
|
|
|
return;
|
|
|
|
}
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
if (text.empty()) return;
|
|
|
|
|
2007-08-29 00:52:23 +02:00
|
|
|
// Check if it's a template line
|
2010-07-20 05:11:11 +02:00
|
|
|
AssDialogue *diag = grid->GetActiveLine();
|
2011-09-28 21:43:11 +02:00
|
|
|
bool templateLine = diag && diag->Comment && diag->Effect.Lower().StartsWith("template");
|
2007-08-29 00:52:23 +02:00
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
bool in_parens = false;
|
|
|
|
bool in_unparened_arg = false;
|
|
|
|
bool in_draw_mode = false;
|
|
|
|
bool in_ovr = false;
|
|
|
|
bool in_karaoke_template = false;
|
2007-08-29 00:52:23 +02:00
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
int range_len = 0;
|
|
|
|
int style = STYLE_NORMAL;
|
|
|
|
|
|
|
|
char cur_char = 0;
|
|
|
|
char next_char = text[0];
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
size_t eat_chars = 0;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < text.size(); ++i) {
|
2006-12-24 22:52:54 +01:00
|
|
|
// Current/previous characters
|
2011-09-28 21:44:34 +02:00
|
|
|
char prev_char = cur_char;
|
|
|
|
cur_char = next_char;
|
|
|
|
next_char = i + 1 < text.size() ? text[i + 1] : 0;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
if (eat_chars > 0) {
|
|
|
|
++range_len;
|
|
|
|
--eat_chars;
|
|
|
|
continue;
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
int new_style = style;
|
|
|
|
|
2006-12-24 22:52:54 +01:00
|
|
|
// Start override block
|
2011-09-28 21:44:34 +02:00
|
|
|
if (cur_char == '{') {
|
|
|
|
new_style = in_ovr ? STYLE_ERROR : STYLE_OVERRIDE;
|
|
|
|
in_ovr = true;
|
|
|
|
in_parens = false;
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
|
|
|
// End override block
|
2011-09-28 21:44:34 +02:00
|
|
|
else if (cur_char == '}') {
|
|
|
|
new_style = in_ovr ? STYLE_OVERRIDE : STYLE_ERROR;
|
|
|
|
in_ovr = false;
|
2007-08-06 16:29:43 +02:00
|
|
|
}
|
2011-09-28 21:44:34 +02:00
|
|
|
// Start karaoke template
|
|
|
|
else if (templateLine && style != STYLE_KARAOKE_TEMPLATE && cur_char == '!') {
|
|
|
|
new_style = STYLE_KARAOKE_TEMPLATE;
|
|
|
|
in_karaoke_template = true;
|
|
|
|
}
|
|
|
|
// End karaoke template
|
|
|
|
else if (style == STYLE_KARAOKE_TEMPLATE && cur_char == '!') {
|
|
|
|
in_karaoke_template = false;
|
|
|
|
}
|
|
|
|
// Continue karaoke template
|
|
|
|
else if (in_karaoke_template) {
|
|
|
|
// Do nothing and just continue the karaoke template style
|
|
|
|
}
|
|
|
|
// Start karaoke template variable
|
|
|
|
else if (templateLine && style != STYLE_KARAOKE_TEMPLATE && cur_char == '$') {
|
|
|
|
new_style = STYLE_KARAOKE_VARIABLE;
|
|
|
|
}
|
|
|
|
// Continue karaoke template variable
|
|
|
|
else if (style == STYLE_KARAOKE_VARIABLE && ((cur_char >= 'A' && cur_char <= 'Z') || (cur_char >= 'a' && cur_char <= 'z') || cur_char == '_')) {
|
|
|
|
// Do nothing and just continue the karaoke variable style
|
|
|
|
}
|
|
|
|
// Plain text
|
|
|
|
else if (!in_ovr) {
|
2006-12-25 06:43:00 +01:00
|
|
|
// Is \n, \N or \h?
|
2011-09-28 21:44:34 +02:00
|
|
|
if (cur_char == '\\' && (next_char == 'n' || next_char == 'N' || next_char == 'h')) {
|
|
|
|
new_style = STYLE_LINE_BREAK;
|
|
|
|
eat_chars = 1;
|
2006-12-25 06:43:00 +01:00
|
|
|
}
|
2011-09-28 21:44:34 +02:00
|
|
|
else if (in_draw_mode)
|
|
|
|
new_style = STYLE_DRAWING;
|
|
|
|
else
|
|
|
|
new_style = STYLE_NORMAL;
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
2011-09-28 21:44:34 +02:00
|
|
|
// Inside override tag
|
|
|
|
else {
|
2006-12-24 22:52:54 +01:00
|
|
|
// Special character
|
2011-09-28 21:44:34 +02:00
|
|
|
if (cur_char == '\\' || cur_char == '(' || cur_char == ')' || cur_char == ',') {
|
|
|
|
new_style = STYLE_PUNCTUATION;
|
|
|
|
in_unparened_arg = false;
|
|
|
|
|
|
|
|
if (style == STYLE_TAG && cur_char == '(')
|
|
|
|
in_parens = true;
|
|
|
|
// This is technically wrong for nested tags, but it doesn't
|
|
|
|
// matter as \t doesn't have any arguments after the subtag(s)
|
|
|
|
else if (cur_char == ')')
|
|
|
|
in_parens = false;
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
2011-09-28 21:44:34 +02:00
|
|
|
// Beginning of a tag
|
|
|
|
else if (prev_char == '\\') {
|
|
|
|
new_style = STYLE_TAG;
|
|
|
|
// \r and \fn are special as their argument is an
|
|
|
|
// unparenthesized string
|
|
|
|
if (cur_char == 'r')
|
|
|
|
in_unparened_arg = true;
|
|
|
|
else if (cur_char == 'f' && next_char == 'n') {
|
|
|
|
eat_chars = 1;
|
|
|
|
in_unparened_arg = true;
|
2007-01-02 03:24:23 +01:00
|
|
|
}
|
2011-09-28 21:44:34 +02:00
|
|
|
// For \p we need to check if it's entering or leaving draw mode
|
|
|
|
// Luckily draw mode can't be set in the style, so no argument
|
|
|
|
// always means leave draw mode
|
|
|
|
else if (cur_char == 'p' && (next_char < 'a' || next_char > 'z')) {
|
|
|
|
in_draw_mode = false;
|
|
|
|
for (size_t idx = i + 1; idx < text.size(); ++idx) {
|
|
|
|
char c = text[idx];
|
|
|
|
// I have no idea why one would use leading zeros for
|
|
|
|
// the scale, but vsfilter allows it
|
|
|
|
if (c >= '1' && c <= '9')
|
|
|
|
in_draw_mode = true;
|
|
|
|
else if (c != '0')
|
|
|
|
break;
|
2007-01-02 03:33:42 +01:00
|
|
|
}
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
2011-09-28 21:44:34 +02:00
|
|
|
// All tags start with letters or numbers
|
|
|
|
else if (cur_char < '0' || (cur_char > '9' && cur_char < 'A') || (cur_char > 'Z' && cur_char < 'a') || cur_char > 'z')
|
|
|
|
new_style = STYLE_ERROR;
|
|
|
|
}
|
|
|
|
else if ((in_parens && style != STYLE_TAG) || in_unparened_arg || (style == STYLE_TAG && ((cur_char < 'A' || cur_char > 'z') || (cur_char > 'Z' && cur_char < 'a')))) {
|
|
|
|
new_style = STYLE_PARAMETER;
|
|
|
|
}
|
2011-10-26 04:48:08 +02:00
|
|
|
else if (style != STYLE_TAG && style != STYLE_PARAMETER && style != STYLE_ERROR) {
|
2011-09-28 21:44:34 +02:00
|
|
|
new_style = STYLE_COMMENT;
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
if (new_style != style) {
|
|
|
|
SetStyling(range_len, style);
|
|
|
|
style = new_style;
|
|
|
|
range_len = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
++range_len;
|
2006-12-24 22:52:54 +01:00
|
|
|
}
|
2011-09-28 21:44:34 +02:00
|
|
|
SetStyling(range_len, style);
|
|
|
|
StyleSpellCheck();
|
2007-01-02 06:00:55 +01:00
|
|
|
}
|
|
|
|
|
Note: This was done using a script! it's far from perfect but 95% of the work has been done already formatting-wise.
Document all functions, class, struct, union, enum, macro, variable, typedefs. This isn't the actual document in itself but empty documentation using any old documentation if it was there.
This was done using exuberant ctags to get tag info, then a TCL script to parse/remove old comments and convert them into Doxygen-style.
Some notes:
* Anything labeled 'DOCME' needs to be documented, @param and @return have been left blank as it would be annoying to delete the 'DOCME' from every one of those.
* Some multiline comments may have been munged into single line comments
* Leave the /// comments above global variables with a space, if they're harder to read then we'll be less likey to use them.
* Enum comments can go after the enumeration itself '[value] /// comment'
* include/aegisub/*.h haven't been converted yet, this will be done in a later commit
* Some documentation blocks are in the wrong place, in the .h when it should be in the .cpp, or vice versa.
See http://devel.aegisub.org/wiki/Doxygen for some details on Doxygen and a 'style guide'.
Originally committed to SVN as r3312.
2009-07-30 00:59:22 +02:00
|
|
|
/// @brief Update call tip
|
2010-07-20 05:11:11 +02:00
|
|
|
void SubsTextEditCtrl::UpdateCallTip(wxStyledTextEvent &) {
|
2011-10-10 22:59:04 +02:00
|
|
|
UpdateStyle();
|
|
|
|
|
2010-05-21 03:13:36 +02:00
|
|
|
if (!OPT_GET("App/Call Tips")->GetBool()) return;
|
2007-01-02 23:10:45 +01:00
|
|
|
|
2007-01-02 06:00:55 +01:00
|
|
|
// Get position and text
|
|
|
|
const unsigned int pos = GetReverseUnicodePosition(GetCurrentPos());
|
|
|
|
wxString text = GetText();
|
|
|
|
|
2007-01-02 19:09:56 +01:00
|
|
|
// Find the start and end of current tag
|
2007-01-02 06:00:55 +01:00
|
|
|
wxChar curChar = 0;
|
2007-01-02 19:09:56 +01:00
|
|
|
wxChar prevChar = 0;
|
2007-01-02 06:00:55 +01:00
|
|
|
int depth = 0;
|
|
|
|
int inDepth = 0;
|
|
|
|
int tagStart = -1;
|
|
|
|
int tagEnd = -1;
|
2007-01-02 19:09:56 +01:00
|
|
|
for (unsigned int i=0;i<text.Length()+1;i++) {
|
2007-01-02 06:00:55 +01:00
|
|
|
// Get character
|
2007-01-02 19:09:56 +01:00
|
|
|
if (i<text.Length()) curChar = text[i];
|
|
|
|
else curChar = 0;
|
2007-01-02 06:00:55 +01:00
|
|
|
|
|
|
|
// Change depth
|
2010-07-20 05:11:11 +02:00
|
|
|
if (curChar == '{') {
|
2007-01-02 06:00:55 +01:00
|
|
|
depth++;
|
|
|
|
continue;
|
|
|
|
}
|
2010-07-20 05:11:11 +02:00
|
|
|
if (curChar == '}') {
|
2007-01-02 06:00:55 +01:00
|
|
|
depth--;
|
2007-01-02 19:09:56 +01:00
|
|
|
if (i >= pos && depth == 0) {
|
|
|
|
tagEnd = i-1;
|
2007-01-02 06:00:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Outside
|
|
|
|
if (depth == 0) {
|
|
|
|
tagStart = -1;
|
|
|
|
if (i == pos) break;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Inside overrides
|
|
|
|
if (depth == 1) {
|
|
|
|
// Inner depth
|
|
|
|
if (tagStart != -1) {
|
2010-07-20 05:11:11 +02:00
|
|
|
if (curChar == '(') inDepth++;
|
|
|
|
else if (curChar == ')') inDepth--;
|
2007-01-02 06:00:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Not inside parenthesis
|
|
|
|
if (inDepth == 0) {
|
2011-09-28 21:43:11 +02:00
|
|
|
if (prevChar == '\\') {
|
2007-01-02 06:00:55 +01:00
|
|
|
// Found start
|
|
|
|
if (i <= pos) tagStart = i;
|
|
|
|
|
|
|
|
// Found end
|
|
|
|
else {
|
2007-01-02 19:09:56 +01:00
|
|
|
tagEnd = i-2;
|
2007-01-02 06:00:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-01-02 19:09:56 +01:00
|
|
|
|
|
|
|
// Previous character
|
|
|
|
prevChar = curChar;
|
2007-01-02 06:00:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate length
|
|
|
|
int len;
|
|
|
|
if (tagEnd != -1) len = tagEnd - tagStart + 1;
|
|
|
|
else len = text.Length() - tagStart;
|
|
|
|
|
|
|
|
// No tag available
|
2007-01-02 19:09:56 +01:00
|
|
|
int textLen = text.Length();
|
|
|
|
unsigned int posInTag = pos - tagStart;
|
2007-04-04 22:42:44 +02:00
|
|
|
if (tagStart+len > textLen || len <= 0 || tagStart < 0) {
|
2007-01-02 06:00:55 +01:00
|
|
|
CallTipCancel();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Current tag
|
|
|
|
wxString tag = text.Mid(tagStart,len);
|
|
|
|
|
|
|
|
// Metrics in tag
|
|
|
|
int tagCommas = 0;
|
|
|
|
int tagParenthesis = 0;
|
|
|
|
int parN = 0;
|
|
|
|
int parPos = -1;
|
|
|
|
bool gotName = false;
|
|
|
|
wxString tagName = tag;
|
|
|
|
for (unsigned int i=0;i<tag.Length();i++) {
|
|
|
|
wxChar curChar = tag[i];
|
2007-01-02 19:09:56 +01:00
|
|
|
bool isEnd = false;
|
2007-01-02 06:00:55 +01:00
|
|
|
|
|
|
|
// Commas
|
2010-07-20 05:11:11 +02:00
|
|
|
if (curChar == ',') {
|
2007-01-02 06:00:55 +01:00
|
|
|
tagCommas++;
|
|
|
|
parN++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parenthesis
|
2010-07-20 05:11:11 +02:00
|
|
|
else if (curChar == '(') {
|
2007-01-02 19:09:56 +01:00
|
|
|
tagParenthesis++;
|
|
|
|
parN++;
|
|
|
|
}
|
2010-07-20 05:11:11 +02:00
|
|
|
else if (curChar == ')') {
|
2007-01-02 06:00:55 +01:00
|
|
|
tagParenthesis++;
|
|
|
|
parN++;
|
2007-01-02 19:09:56 +01:00
|
|
|
isEnd = true;
|
2007-01-02 06:00:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tag name
|
|
|
|
if (parN == 1 && !gotName) {
|
|
|
|
tagName = tag.Left(i);
|
|
|
|
gotName = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parameter it's on
|
2007-01-02 19:09:56 +01:00
|
|
|
if (i == posInTag) {
|
|
|
|
parPos = parN;
|
2010-07-20 05:11:11 +02:00
|
|
|
if (curChar == ',' || curChar == '(' || curChar == ')') {
|
2007-01-02 19:09:56 +01:00
|
|
|
parPos--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (isEnd) {
|
|
|
|
parN = 1000;
|
|
|
|
break;
|
|
|
|
}
|
2007-01-02 06:00:55 +01:00
|
|
|
}
|
|
|
|
if (parPos == -1) parPos = parN;
|
|
|
|
|
|
|
|
// Tag name
|
|
|
|
if (tagName.IsEmpty()) {
|
|
|
|
CallTipCancel();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find matching prototype
|
|
|
|
wxString useProto;
|
2007-01-02 19:09:56 +01:00
|
|
|
wxString cleanProto;
|
|
|
|
wxString protoName;
|
2007-01-24 04:54:32 +01:00
|
|
|
int protoN = 0;
|
2007-01-02 19:09:56 +01:00
|
|
|
bool semiProto = false;
|
2007-01-02 06:00:55 +01:00
|
|
|
for (unsigned int i=0;i<proto.Count();i++) {
|
2007-01-02 19:09:56 +01:00
|
|
|
// Get prototype name
|
2010-07-20 05:11:11 +02:00
|
|
|
int div = proto[i].Find(';');
|
2007-01-02 19:09:56 +01:00
|
|
|
if (div != wxNOT_FOUND) protoName = proto[i].Left(div);
|
|
|
|
else {
|
2010-07-20 05:11:11 +02:00
|
|
|
div = proto[i].Find('(');
|
2007-01-02 19:09:56 +01:00
|
|
|
protoName = proto[i].Left(div);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fix name
|
|
|
|
semiProto = false;
|
|
|
|
cleanProto = proto[i];
|
2010-07-20 05:11:11 +02:00
|
|
|
if (cleanProto.Freq(';') > 0) {
|
2011-09-28 21:43:11 +02:00
|
|
|
cleanProto.Replace(";","");
|
2007-01-02 19:09:56 +01:00
|
|
|
semiProto = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prototype match
|
|
|
|
wxString temp;
|
|
|
|
if (semiProto) temp = tagName.Left(protoName.Length());
|
|
|
|
else temp = tagName;
|
|
|
|
if (protoName == temp) {
|
|
|
|
// Parameter count match
|
2010-07-20 05:11:11 +02:00
|
|
|
if (proto[i].Freq(',') >= tagCommas) {
|
2007-01-02 19:09:56 +01:00
|
|
|
// Found
|
2007-01-02 06:00:55 +01:00
|
|
|
useProto = proto[i];
|
2007-01-02 19:15:17 +01:00
|
|
|
protoN = i;
|
2007-01-02 06:00:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No matching prototype
|
|
|
|
if (useProto.IsEmpty()) {
|
|
|
|
CallTipCancel();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-01-02 19:09:56 +01:00
|
|
|
// Parameter number for tags without "(),"
|
|
|
|
if (semiProto && parPos == 0 && posInTag >= protoName.Length()) parPos = 1;
|
|
|
|
|
2007-01-02 06:00:55 +01:00
|
|
|
// Highlight start/end
|
|
|
|
int highStart = useProto.Length();
|
|
|
|
int highEnd = -1;
|
|
|
|
parN = 0;
|
2007-01-02 19:09:56 +01:00
|
|
|
int delta = 0;
|
2007-01-02 06:00:55 +01:00
|
|
|
for (unsigned int i=0;i<useProto.Length();i++) {
|
|
|
|
wxChar curChar = useProto[i];
|
2010-07-20 05:11:11 +02:00
|
|
|
if (i == 0 || curChar == ',' || curChar == ';' || curChar == '(' || curChar == ')') {
|
|
|
|
if (curChar == ';') delta++;
|
2007-01-02 19:09:56 +01:00
|
|
|
if (parN == parPos) highStart = i+1-delta;
|
2007-01-02 06:00:55 +01:00
|
|
|
else if (parN == parPos+1) highEnd = i;
|
|
|
|
parN++;
|
|
|
|
}
|
|
|
|
}
|
2007-01-02 19:09:56 +01:00
|
|
|
if (highStart <= 1) highStart = 0;
|
2007-01-02 06:00:55 +01:00
|
|
|
if (highEnd == -1) highEnd = useProto.Length();
|
|
|
|
|
|
|
|
// Calltip is over
|
2007-01-24 04:54:32 +01:00
|
|
|
if (highStart == (signed) useProto.Length()) {
|
2007-01-02 06:00:55 +01:00
|
|
|
CallTipCancel();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Show calltip
|
2007-01-02 19:15:17 +01:00
|
|
|
if (!CallTipActive() || tipProtoN != protoN) CallTipShow(GetUnicodePosition(tagStart),cleanProto);
|
|
|
|
tipProtoN = protoN;
|
2007-01-02 06:00:55 +01:00
|
|
|
CallTipSetHighlight(highStart,highEnd);
|
2006-12-24 23:46:20 +01:00
|
|
|
}
|
|
|
|
|
2011-09-28 21:44:34 +02:00
|
|
|
void SubsTextEditCtrl::StyleSpellCheck() {
|
2010-07-20 05:11:11 +02:00
|
|
|
if (!spellchecker.get()) return;
|
2006-12-24 23:46:20 +01:00
|
|
|
|
2007-04-14 17:26:46 +02:00
|
|
|
// Results
|
2006-12-24 23:46:20 +01:00
|
|
|
wxString text = GetText();
|
2007-04-14 17:26:46 +02:00
|
|
|
IntPairVector results;
|
2011-09-28 21:44:34 +02:00
|
|
|
GetWordBoundaries(text,results);
|
2006-12-24 23:46:20 +01:00
|
|
|
|
|
|
|
// Style
|
2007-04-14 17:26:46 +02:00
|
|
|
int count = results.size();
|
2006-12-24 23:46:20 +01:00
|
|
|
for (int i=0;i<count;i++) {
|
|
|
|
// Get current word
|
2007-04-14 17:26:46 +02:00
|
|
|
int s = results[i].first;
|
|
|
|
int e = results[i].second;
|
|
|
|
wxString curWord = text.Mid(s,e-s);
|
2006-12-24 23:46:20 +01:00
|
|
|
|
|
|
|
// Check if it's valid
|
|
|
|
if (!spellchecker->CheckWord(curWord)) {
|
2011-09-28 21:44:34 +02:00
|
|
|
StartUnicodeStyling(s,32);
|
2007-04-14 17:26:46 +02:00
|
|
|
SetUnicodeStyling(s,e-s,32);
|
|
|
|
}
|
|
|
|
}
|
2008-06-01 05:44:41 +02:00
|
|
|
|
|
|
|
// It seems like wxStyledTextCtrl wants you to finish styling at the end of the text.
|
|
|
|
// I don't really understand why, it's not documented anywhere I can find, but this fixes bug #595.
|
|
|
|
StartUnicodeStyling(text.Length(), 0);
|
|
|
|
SetUnicodeStyling(text.Length(), 0, 0);
|
2007-04-14 17:26:46 +02:00
|
|
|
}
|
|
|
|
|
2010-07-20 05:11:11 +02:00
|
|
|
void SubsTextEditCtrl::SetTextTo(wxString text) {
|
|
|
|
SetEvtHandlerEnabled(false);
|
2006-12-24 22:52:54 +01:00
|
|
|
Freeze();
|
|
|
|
|
|
|
|
int from=0,to=0;
|
|
|
|
GetSelection(&from,&to);
|
|
|
|
|
|
|
|
SetText(text);
|
|
|
|
UpdateStyle();
|
|
|
|
|
|
|
|
// Restore selection
|
2011-10-10 22:59:04 +02:00
|
|
|
SetSelectionU(GetReverseUnicodePosition(from), GetReverseUnicodePosition(to));
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2010-07-20 05:11:11 +02:00
|
|
|
SetEvtHandlerEnabled(true);
|
2006-12-24 22:52:54 +01:00
|
|
|
Thaw();
|
|
|
|
}
|
|
|
|
|
2011-10-10 22:59:04 +02:00
|
|
|
|
|
|
|
void SubsTextEditCtrl::Paste() {
|
|
|
|
wxString data;
|
|
|
|
if (wxTheClipboard->Open()) {
|
|
|
|
if (wxTheClipboard->IsSupported(wxDF_TEXT)) {
|
|
|
|
wxTextDataObject rawdata;
|
|
|
|
wxTheClipboard->GetData(rawdata);
|
|
|
|
data = rawdata.GetText();
|
|
|
|
}
|
|
|
|
wxTheClipboard->Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
data.Replace("\r\n", "\\N");
|
|
|
|
data.Replace("\n", "\\N");
|
|
|
|
data.Replace("\r", "\\N");
|
|
|
|
|
|
|
|
int from = GetReverseUnicodePosition(GetSelectionStart());
|
|
|
|
int to = GetReverseUnicodePosition(GetSelectionEnd());
|
|
|
|
|
|
|
|
wxString old = GetText();
|
|
|
|
SetText(old.Left(from) + data + old.Mid(to));
|
|
|
|
|
|
|
|
int sel_start = GetUnicodePosition(from + data.size());
|
|
|
|
SetSelectionStart(sel_start);
|
|
|
|
SetSelectionEnd(sel_start);
|
|
|
|
UpdateStyle();
|
|
|
|
}
|
|
|
|
|
2011-08-31 06:17:37 +02:00
|
|
|
void SubsTextEditCtrl::OnContextMenu(wxContextMenuEvent &event) {
|
|
|
|
if (!grid->GetActiveLine())
|
|
|
|
return;
|
2006-12-24 22:52:54 +01:00
|
|
|
|
2011-08-31 06:17:37 +02:00
|
|
|
wxPoint pos = event.GetPosition();
|
|
|
|
int activePos;
|
|
|
|
if (pos == wxDefaultPosition) {
|
|
|
|
activePos = GetCurrentPos();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
activePos = PositionFromPoint(ScreenToClient(pos));
|
|
|
|
}
|
2006-12-25 06:43:00 +01:00
|
|
|
|
|
|
|
wxMenu menu;
|
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
|
|
|
currentWord = GetWordAtPosition(activePos);
|
|
|
|
currentWordPos = activePos;
|
|
|
|
|
2010-07-20 05:11:11 +02:00
|
|
|
if (spellchecker.get() && currentWord.Length()) {
|
2006-12-26 00:10:23 +01:00
|
|
|
bool rightSpelling = spellchecker->CheckWord(currentWord);
|
|
|
|
|
2006-12-25 06:52:29 +01:00
|
|
|
wxFont font;
|
|
|
|
font.SetWeight(wxFONTWEIGHT_BOLD);
|
|
|
|
|
2006-12-25 22:56:56 +01:00
|
|
|
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
|
|
|
if (!rightSpelling) {
|
2010-07-20 05:11:11 +02:00
|
|
|
if (!nSugs) {
|
|
|
|
menu.Append(EDIT_MENU_SUGGESTION,_("No correction suggestions"))->Enable(false);
|
|
|
|
}
|
2006-12-25 06:52:29 +01:00
|
|
|
|
2007-01-03 23:05:43 +01:00
|
|
|
for (int i=0;i<nSugs;i++) {
|
2010-01-10 17:15:31 +01:00
|
|
|
wxMenuItem *itm = new wxMenuItem(&menu, EDIT_MENU_SUGGESTIONS+i, sugs[i]);
|
2009-07-25 20:45:30 +02:00
|
|
|
#ifdef __WINDOWS__
|
2007-01-03 23:05:43 +01:00
|
|
|
itm->SetFont(font);
|
|
|
|
#endif
|
2010-01-10 17:15:31 +01:00
|
|
|
menu.Append(itm);
|
2007-01-03 23:05:43 +01:00
|
|
|
}
|
2006-12-26 00:10:23 +01:00
|
|
|
|
|
|
|
// Append "add word"
|
2010-01-21 01:24:59 +01:00
|
|
|
wxString add_to_dict_text(_("Add \"%s\" to dictionary"));
|
2011-09-28 21:43:11 +02:00
|
|
|
add_to_dict_text.Replace("%s", currentWord);
|
2010-01-21 01:24:59 +01:00
|
|
|
menu.Append(EDIT_MENU_ADD_TO_DICT,add_to_dict_text)->Enable(spellchecker->CanAddWord(currentWord));
|
2006-12-26 00:10:23 +01:00
|
|
|
}
|
|
|
|
// Spelled right
|
|
|
|
else {
|
2010-07-20 05:11:11 +02:00
|
|
|
if (!nSugs) {
|
|
|
|
menu.Append(EDIT_MENU_SUGGESTION,_("No spell checker suggestions"))->Enable(false);
|
|
|
|
}
|
2006-12-26 00:10:23 +01:00
|
|
|
else {
|
|
|
|
// Build list
|
|
|
|
wxMenu *subMenu = new wxMenu();
|
|
|
|
for (int i=0;i<nSugs;i++) subMenu->Append(EDIT_MENU_SUGGESTIONS+i,sugs[i]);
|
2011-09-28 21:43:48 +02:00
|
|
|
menu.Append(-1,wxString::Format(_("Spell checker suggestions for \"%s\""),currentWord), subMenu);
|
2006-12-26 00:10:23 +01:00
|
|
|
}
|
|
|
|
}
|
2007-01-02 00:47:09 +01:00
|
|
|
|
2010-11-18 04:00:08 +01:00
|
|
|
wxArrayString langs = spellchecker->GetLanguageList();
|
2010-05-21 03:13:36 +02:00
|
|
|
wxString curLang = lagi_wxString(OPT_GET("Tool/Spell Checker/Language")->GetString());
|
2007-01-02 00:47:09 +01:00
|
|
|
|
|
|
|
// Languages
|
|
|
|
wxMenu *languageMenu = new wxMenu();
|
|
|
|
wxMenuItem *cur;
|
|
|
|
wxString name;
|
|
|
|
const wxLanguageInfo *info;
|
|
|
|
|
|
|
|
// Insert "Disable"
|
|
|
|
cur = languageMenu->AppendCheckItem(EDIT_MENU_DIC_LANGS,_("Disable"));
|
|
|
|
if (curLang.IsEmpty()) cur->Check();
|
|
|
|
|
|
|
|
// Each language found
|
|
|
|
for (unsigned int i=0;i<langs.Count();i++) {
|
|
|
|
info = wxLocale::FindLanguageInfo(langs[i]);
|
|
|
|
if (info) name = info->Description;
|
|
|
|
else name = langs[i];
|
|
|
|
cur = languageMenu->AppendCheckItem(EDIT_MENU_DIC_LANGS+i+1,name);
|
|
|
|
if (langs[i] == curLang) cur->Check();
|
2007-01-01 05:53:55 +01:00
|
|
|
}
|
2007-01-02 00:47:09 +01:00
|
|
|
|
|
|
|
// Append language list
|
2007-01-03 22:51:09 +01:00
|
|
|
menu.Append(-1,_("Spell checker language"), languageMenu);
|
2007-01-01 05:53:55 +01:00
|
|
|
menu.AppendSeparator();
|
2006-12-25 22:56:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Thesaurus
|
2010-07-20 05:11:11 +02:00
|
|
|
if (thesaurus.get() && 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
|
|
|
if (result.size()) {
|
|
|
|
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
|
2007-01-03 22:51:09 +01:00
|
|
|
thesMenu->Append(-1, result[i].name, subMenu);
|
2006-12-26 00:10:23 +01:00
|
|
|
}
|
2006-12-25 23:21:44 +01:00
|
|
|
}
|
2006-12-26 00:10:23 +01:00
|
|
|
|
|
|
|
// Thesaurus menu
|
2010-01-21 01:24:59 +01:00
|
|
|
wxString thes_suggestion_text(_("Thesaurus suggestions for \"%s\""));
|
2011-09-28 21:43:11 +02:00
|
|
|
thes_suggestion_text.Replace("%s", currentWord);
|
2010-01-21 01:24:59 +01:00
|
|
|
menu.Append(-1,thes_suggestion_text,thesMenu);
|
|
|
|
|
2006-12-25 23:21:44 +01:00
|
|
|
}
|
2006-12-25 22:56:56 +01:00
|
|
|
|
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
|
|
|
|
2007-01-01 06:15:05 +01:00
|
|
|
wxArrayString langs = thesaurus->GetLanguageList(); // This probably should be cached...
|
2010-05-21 03:13:36 +02:00
|
|
|
wxString curLang = lagi_wxString(OPT_GET("Tool/Thesaurus/Language")->GetString());
|
2007-01-02 00:47:09 +01:00
|
|
|
|
|
|
|
// Languages
|
|
|
|
wxMenu *languageMenu = new wxMenu();
|
|
|
|
wxMenuItem *cur;
|
|
|
|
wxString name;
|
|
|
|
const wxLanguageInfo *info;
|
|
|
|
|
|
|
|
// Insert "Disable"
|
|
|
|
cur = languageMenu->AppendCheckItem(EDIT_MENU_THES_LANGS,_("Disable"));
|
|
|
|
if (curLang.IsEmpty()) cur->Check();
|
|
|
|
|
|
|
|
// Each language found
|
|
|
|
for (unsigned int i=0;i<langs.Count();i++) {
|
|
|
|
info = wxLocale::FindLanguageInfo(langs[i]);
|
|
|
|
if (info) name = info->Description;
|
|
|
|
else name = langs[i];
|
|
|
|
cur = languageMenu->AppendCheckItem(EDIT_MENU_THES_LANGS+i+1,name);
|
|
|
|
if (langs[i] == curLang) cur->Check();
|
2007-01-01 06:15:05 +01:00
|
|
|
}
|
|
|
|
|
2007-01-02 00:47:09 +01:00
|
|
|
// Append language list
|
2007-01-03 22:51:09 +01:00
|
|
|
menu.Append(-1, _("Thesaurus language"), languageMenu);
|
2006-12-25 22:56:56 +01:00
|
|
|
menu.AppendSeparator();
|
2006-12-25 06:43:00 +01:00
|
|
|
}
|
|
|
|
|
2006-12-25 06:52:29 +01:00
|
|
|
// Standard actions
|
|
|
|
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
|
|
|
PopupMenu(&menu);
|
|
|
|
}
|
|
|
|
|
2010-07-20 05:11:11 +02:00
|
|
|
void SubsTextEditCtrl::OnSplitLinePreserve (wxCommandEvent &) {
|
2006-12-25 06:43:00 +01:00
|
|
|
int from,to;
|
|
|
|
GetSelection(&from, &to);
|
2006-12-26 02:30:30 +01:00
|
|
|
from = GetReverseUnicodePosition(from);
|
2010-07-20 05:11:11 +02:00
|
|
|
grid->SplitLine(grid->GetActiveLine(),from,0);
|
2006-12-25 06:43:00 +01:00
|
|
|
}
|
|
|
|
|
2010-07-20 05:11:11 +02:00
|
|
|
void SubsTextEditCtrl::OnSplitLineEstimate (wxCommandEvent &) {
|
2006-12-25 06:43:00 +01:00
|
|
|
int from,to;
|
|
|
|
GetSelection(&from, &to);
|
2006-12-26 02:30:30 +01:00
|
|
|
from = GetReverseUnicodePosition(from);
|
2010-07-20 05:11:11 +02:00
|
|
|
grid->SplitLine(grid->GetActiveLine(),from,1);
|
2006-12-25 06:43:00 +01:00
|
|
|
}
|
|
|
|
|
2010-07-20 05:11:11 +02:00
|
|
|
void SubsTextEditCtrl::OnAddToDictionary(wxCommandEvent &) {
|
|
|
|
if (spellchecker.get()) spellchecker->AddWord(currentWord);
|
2008-01-14 03:01:50 +01:00
|
|
|
UpdateStyle();
|
2006-12-25 06:43:00 +01:00
|
|
|
SetFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SubsTextEditCtrl::OnUseSuggestion(wxCommandEvent &event) {
|
2010-07-20 05:11:11 +02:00
|
|
|
wxString suggestion;
|
|
|
|
int sugIdx = event.GetId() - EDIT_MENU_THESAURUS_SUGS;
|
|
|
|
if (sugIdx >= 0) {
|
|
|
|
suggestion = thesSugs[sugIdx];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
suggestion = sugs[event.GetId() - EDIT_MENU_SUGGESTIONS];
|
|
|
|
}
|
2006-12-25 23:30:11 +01:00
|
|
|
|
|
|
|
// Stripe suggestion of parenthesis
|
2011-09-28 21:43:11 +02:00
|
|
|
int pos = suggestion.Find("(");
|
2006-12-25 23:30:11 +01:00
|
|
|
if (pos != wxNOT_FOUND) {
|
|
|
|
suggestion = suggestion.Left(pos-1);
|
|
|
|
}
|
2010-07-20 05:11:11 +02:00
|
|
|
|
2006-12-25 23:21:44 +01:00
|
|
|
// Get boundaries of text being replaced
|
|
|
|
int start,end;
|
|
|
|
GetBoundsOfWordAtPosition(currentWordPos,start,end);
|
|
|
|
|
|
|
|
wxString text = GetText();
|
2010-12-31 22:03:03 +01:00
|
|
|
SetText(text.Left(std::max(0,start)) + suggestion + text.Mid(end+1));
|
2006-12-25 23:21:44 +01:00
|
|
|
|
|
|
|
// 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
|
|
|
|
2007-01-01 05:53:55 +01:00
|
|
|
void SubsTextEditCtrl::OnSetDicLanguage(wxCommandEvent &event) {
|
|
|
|
wxArrayString langs = spellchecker->GetLanguageList();
|
|
|
|
|
|
|
|
// Set dictionary
|
2007-01-02 00:47:09 +01:00
|
|
|
int index = event.GetId() - EDIT_MENU_DIC_LANGS - 1;
|
2011-09-28 21:44:34 +02:00
|
|
|
if (index >= 0) {
|
|
|
|
spellchecker->SetLanguage(langs[index]);
|
|
|
|
OPT_SET("Tool/Spell Checker/Language")->SetString(STD_STR(langs[index]));
|
|
|
|
}
|
2007-01-01 05:53:55 +01:00
|
|
|
|
|
|
|
UpdateStyle();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SubsTextEditCtrl::OnSetThesLanguage(wxCommandEvent &event) {
|
|
|
|
wxArrayString langs = thesaurus->GetLanguageList();
|
|
|
|
|
|
|
|
// Set language
|
2007-01-02 00:47:09 +01:00
|
|
|
int index = event.GetId() - EDIT_MENU_THES_LANGS - 1;
|
2011-09-28 21:44:34 +02:00
|
|
|
if (index >= 0) {
|
|
|
|
thesaurus->SetLanguage(langs[index]);
|
|
|
|
OPT_SET("Tool/Thesaurus/Language")->SetString(STD_STR(langs[index]));
|
|
|
|
}
|
2007-01-01 05:53:55 +01:00
|
|
|
|
|
|
|
UpdateStyle();
|
|
|
|
}
|