forked from mia/Aegisub
Extract calltip logic from the edit ctrl to libaegisub
This commit is contained in:
parent
e4d6b8661b
commit
238356406f
8 changed files with 266 additions and 264 deletions
|
@ -92,6 +92,7 @@
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\background_runner.h" />
|
<ClInclude Include="$(SrcDir)include\libaegisub\background_runner.h" />
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\color.h" />
|
<ClInclude Include="$(SrcDir)include\libaegisub\color.h" />
|
||||||
<ClInclude Include="$(SrcDir)include\libaegisub\spellchecker.h" />
|
<ClInclude Include="$(SrcDir)include\libaegisub\spellchecker.h" />
|
||||||
|
<ClInclude Include="..\..\libaegisub\include\libaegisub\calltip_provider.h" />
|
||||||
<ClInclude Include="..\..\libaegisub\include\libaegisub\of_type_adaptor.h" />
|
<ClInclude Include="..\..\libaegisub\include\libaegisub\of_type_adaptor.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -123,6 +124,7 @@
|
||||||
<ClCompile Include="$(SrcDir)ass\dialogue_parser.cpp" />
|
<ClCompile Include="$(SrcDir)ass\dialogue_parser.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)common\color.cpp" />
|
<ClCompile Include="$(SrcDir)common\color.cpp" />
|
||||||
<ClCompile Include="$(SrcDir)common\parser.cpp" />
|
<ClCompile Include="$(SrcDir)common\parser.cpp" />
|
||||||
|
<ClCompile Include="..\..\libaegisub\common\calltip_provider.cpp" />
|
||||||
<ClCompile Include="..\..\libaegisub\common\io.cpp" />
|
<ClCompile Include="..\..\libaegisub\common\io.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -137,6 +137,9 @@
|
||||||
<ClInclude Include="..\..\libaegisub\include\libaegisub\of_type_adaptor.h">
|
<ClInclude Include="..\..\libaegisub\include\libaegisub\of_type_adaptor.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\libaegisub\include\libaegisub\calltip_provider.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="$(SrcDir)windows\lagi_pre.cpp">
|
<ClCompile Include="$(SrcDir)windows\lagi_pre.cpp">
|
||||||
|
@ -220,6 +223,9 @@
|
||||||
<ClCompile Include="..\..\libaegisub\common\io.cpp">
|
<ClCompile Include="..\..\libaegisub\common\io.cpp">
|
||||||
<Filter>Source Files\Common</Filter>
|
<Filter>Source Files\Common</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\libaegisub\common\calltip_provider.cpp">
|
||||||
|
<Filter>Source Files\Common</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="$(SrcDir)include\libaegisub\charsets.def">
|
<None Include="$(SrcDir)include\libaegisub\charsets.def">
|
||||||
|
|
|
@ -20,6 +20,7 @@ SRC += \
|
||||||
common/cajun/elements.cpp \
|
common/cajun/elements.cpp \
|
||||||
common/cajun/reader.cpp \
|
common/cajun/reader.cpp \
|
||||||
common/cajun/writer.cpp \
|
common/cajun/writer.cpp \
|
||||||
|
common/calltip_provider.cpp \
|
||||||
common/charset.cpp \
|
common/charset.cpp \
|
||||||
common/charset_6937.cpp \
|
common/charset_6937.cpp \
|
||||||
common/charset_conv.cpp \
|
common/charset_conv.cpp \
|
||||||
|
|
|
@ -59,7 +59,8 @@ class SyntaxHighlighter {
|
||||||
char *outptr = (char *)&chr;
|
char *outptr = (char *)&chr;
|
||||||
size_t outlen = sizeof chr;
|
size_t outlen = sizeof chr;
|
||||||
|
|
||||||
if (iconv(utf8_to_utf32, &inptr, &inlen, &outptr, &outlen) != 1)
|
iconv(utf8_to_utf32, &inptr, &inlen, &outptr, &outlen);
|
||||||
|
if (outlen != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
char_len = len - inlen;
|
char_len = len - inlen;
|
||||||
|
@ -105,7 +106,7 @@ public:
|
||||||
SyntaxHighlighter(std::string const& text, agi::SpellChecker *spellchecker)
|
SyntaxHighlighter(std::string const& text, agi::SpellChecker *spellchecker)
|
||||||
: text(text)
|
: text(text)
|
||||||
, spellchecker(spellchecker)
|
, spellchecker(spellchecker)
|
||||||
, utf8_to_utf32(iconv_open("utf-32", "utf-8"), iconv_close)
|
, utf8_to_utf32(iconv_open("utf-32le", "utf-8"), iconv_close)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
TokenVec Highlight(TokenVec const& tokens, bool template_line) {
|
TokenVec Highlight(TokenVec const& tokens, bool template_line) {
|
||||||
|
|
186
aegisub/libaegisub/common/calltip_provider.cpp
Normal file
186
aegisub/libaegisub/common/calltip_provider.cpp
Normal file
|
@ -0,0 +1,186 @@
|
||||||
|
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
//
|
||||||
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
|
#include "libaegisub/calltip_provider.h"
|
||||||
|
|
||||||
|
#include "libaegisub/ass/dialogue_parser.h"
|
||||||
|
|
||||||
|
#include <boost/range.hpp>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct proto_lit {
|
||||||
|
const char *name;
|
||||||
|
bool has_parens;
|
||||||
|
const char *args;
|
||||||
|
};
|
||||||
|
|
||||||
|
proto_lit calltip_protos[] = {
|
||||||
|
{ "move", true, "X1\0Y1\0X2\0Y2\0" },
|
||||||
|
{ "move", true, "X1\0Y1\0X2\0Y2\0Start Time\0End Time\0" },
|
||||||
|
{ "fn", false, "Font Name\0" },
|
||||||
|
{ "bord", false, "Width\0" },
|
||||||
|
{ "xbord", false, "Width\0" },
|
||||||
|
{ "ybord", false, "Width\0" },
|
||||||
|
{ "shad", false, "Depth\0" },
|
||||||
|
{ "xshad", false, "Depth\0" },
|
||||||
|
{ "yshad", false, "Depth\0" },
|
||||||
|
{ "be", false, "Strength\0" },
|
||||||
|
{ "blur", false, "Strength\0" },
|
||||||
|
{ "fscx", false, "Scale\0" },
|
||||||
|
{ "fscy", false, "Scale\0" },
|
||||||
|
{ "fsp", false, "Spacing\0" },
|
||||||
|
{ "fs", false, "Font Size\0" },
|
||||||
|
{ "fe", false, "Encoding\0" },
|
||||||
|
{ "frx", false, "Angle\0" },
|
||||||
|
{ "fry", false, "Angle\0" },
|
||||||
|
{ "frz", false, "Angle\0" },
|
||||||
|
{ "fr", false, "Angle\0" },
|
||||||
|
{ "pbo", false, "Offset\0" },
|
||||||
|
{ "clip", true, "Command\0" },
|
||||||
|
{ "clip", true, "Scale\0Command\0" },
|
||||||
|
{ "clip", true, "X1\0Y1\0X2\0Y2\0" },
|
||||||
|
{ "iclip", true, "Command\0" },
|
||||||
|
{ "iclip", true, "Scale\0Command\0" },
|
||||||
|
{ "iclip", true, "X1\0Y1\0X2\0Y2\0" },
|
||||||
|
{ "t", true, "Acceleration\0Tags\0" },
|
||||||
|
{ "t", true, "Start Time\0End Time\0Tags\0" },
|
||||||
|
{ "t", true, "Start Time\0End Time\0Acceleration\0Tags\0" },
|
||||||
|
{ "pos", true, "X\0Y\0" },
|
||||||
|
{ "p", false, "Exponent\0" },
|
||||||
|
{ "org", true, "X\0Y\0" },
|
||||||
|
{ "fade", true, "Start Alpha\0Middle Alpha\0End Alpha\0Start In\0End In\0Start Out\0End Out\0" },
|
||||||
|
{ "fad", true, "Start Time\0End Time\0" },
|
||||||
|
{ "c", false, "Colour\0" },
|
||||||
|
{ "1c", false, "Colour\0" },
|
||||||
|
{ "2c", false, "Colour\0" },
|
||||||
|
{ "3c", false, "Colour\0" },
|
||||||
|
{ "4c", false, "Colour\0" },
|
||||||
|
{ "alpha", false, "Alpha\0" },
|
||||||
|
{ "1a", false, "Alpha\0" },
|
||||||
|
{ "2a", false, "Alpha\0" },
|
||||||
|
{ "3a", false, "Alpha\0" },
|
||||||
|
{ "4a", false, "Alpha\0" },
|
||||||
|
{ "an", false, "Alignment\0" },
|
||||||
|
{ "a", false, "Alignment\0" },
|
||||||
|
{ "b", false, "Weight\0" },
|
||||||
|
{ "i", false, "1/0\0" },
|
||||||
|
{ "u", false, "1/0\0" },
|
||||||
|
{ "s", false, "1/0\0" },
|
||||||
|
{ "kf", false, "Duration\0" },
|
||||||
|
{ "ko", false, "Duration\0" },
|
||||||
|
{ "k", false, "Duration\0" },
|
||||||
|
{ "K", false, "Duration\0" },
|
||||||
|
{ "q", false, "Wrap Style\0" },
|
||||||
|
{ "r", false, "Style\0" },
|
||||||
|
{ "fax", false, "Factor\0" },
|
||||||
|
{ "fay", false, "Factor\0" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace agi {
|
||||||
|
CalltipProvider::CalltipProvider() {
|
||||||
|
for (auto proto : calltip_protos) {
|
||||||
|
CalltipProto p;
|
||||||
|
std::string tag_name = proto.name;
|
||||||
|
p.text = '\\' + tag_name;
|
||||||
|
if (proto.has_parens)
|
||||||
|
p.text += '(';
|
||||||
|
|
||||||
|
for (const char *arg = proto.args; *arg; ) {
|
||||||
|
size_t start = p.text.size();
|
||||||
|
p.text += arg;
|
||||||
|
size_t end = p.text.size();
|
||||||
|
if (proto.has_parens)
|
||||||
|
p.text += ',';
|
||||||
|
|
||||||
|
arg += end - start + 1;
|
||||||
|
p.args.emplace_back(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace trailing comma
|
||||||
|
if (proto.has_parens)
|
||||||
|
p.text.back() = ')';
|
||||||
|
|
||||||
|
protos.emplace(std::move(tag_name), std::move(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Calltip CalltipProvider::GetCalltip(std::vector<ass::DialogueToken> const& tokens, std::string const& text, size_t pos) {
|
||||||
|
namespace dt = ass::DialogueTokenType;
|
||||||
|
|
||||||
|
Calltip ret = { "", 0, 0, 0 };
|
||||||
|
|
||||||
|
size_t idx = 0;
|
||||||
|
size_t tag_name_idx = 0;
|
||||||
|
size_t commas = 0;
|
||||||
|
for (; idx < tokens.size() && pos >= tokens[idx].length; ++idx) {
|
||||||
|
switch (tokens[idx].type) {
|
||||||
|
case dt::COMMENT:
|
||||||
|
case dt::OVR_END:
|
||||||
|
tag_name_idx = 0;
|
||||||
|
break;
|
||||||
|
case dt::TAG_NAME:
|
||||||
|
tag_name_idx = idx;
|
||||||
|
commas = 0;
|
||||||
|
break;
|
||||||
|
case dt::ARG_SEP:
|
||||||
|
++commas;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
pos -= tokens[idx].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Either didn't hit a tag or the override block ended before reaching the
|
||||||
|
// current position
|
||||||
|
if (tag_name_idx == 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
// Find the prototype for this tag
|
||||||
|
size_t tag_name_start = 0;
|
||||||
|
for (size_t i = 0; i < tag_name_idx; ++i)
|
||||||
|
tag_name_start += tokens[i].length;
|
||||||
|
auto it = protos.equal_range(text.substr(tag_name_start, tokens[tag_name_idx].length));
|
||||||
|
|
||||||
|
// If there's multiple overloads, check how many total arguments we have
|
||||||
|
// and pick the one with the least args >= current arg count
|
||||||
|
if (distance(it.first, it.second) > 1) {
|
||||||
|
size_t args = commas + 1;
|
||||||
|
for (size_t i = idx; i < tokens.size(); ++i) {
|
||||||
|
int type = tokens[i].type;
|
||||||
|
if (type == dt::ARG_SEP)
|
||||||
|
++args;
|
||||||
|
else if (type != dt::ARG && type != dt::WHITESPACE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (it.first != it.second && args > it.first->second.args.size())
|
||||||
|
++it.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown tag or too many arguments
|
||||||
|
if (it.first == it.second || it.first->second.args.size() <= commas)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret.text = it.first->second.text;
|
||||||
|
ret.highlight_start = it.first->second.args[commas].first;
|
||||||
|
ret.highlight_end = it.first->second.args[commas].second;
|
||||||
|
ret.tag_position = tag_name_start;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
46
aegisub/libaegisub/include/libaegisub/calltip_provider.h
Normal file
46
aegisub/libaegisub/include/libaegisub/calltip_provider.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
|
||||||
|
//
|
||||||
|
// Permission to use, copy, modify, and distribute this software for any
|
||||||
|
// purpose with or without fee is hereby granted, provided that the above
|
||||||
|
// copyright notice and this permission notice appear in all copies.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
//
|
||||||
|
// Aegisub Project http://www.aegisub.org/
|
||||||
|
|
||||||
|
#ifndef LAGI_PRE
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace agi {
|
||||||
|
namespace ass { struct DialogueToken; }
|
||||||
|
|
||||||
|
struct Calltip {
|
||||||
|
std::string text; ///< Text of the calltip
|
||||||
|
size_t highlight_start; ///< Start index of the current parameter in text
|
||||||
|
size_t highlight_end; ///< End index of the current parameter in text
|
||||||
|
size_t tag_position; ///< Start index of the tag in the input line
|
||||||
|
};
|
||||||
|
|
||||||
|
class CalltipProvider {
|
||||||
|
struct CalltipProto {
|
||||||
|
std::string text;
|
||||||
|
std::vector<std::pair<size_t, size_t>> args;
|
||||||
|
};
|
||||||
|
std::multimap<std::string, CalltipProto> protos;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CalltipProvider();
|
||||||
|
|
||||||
|
/// Get the calltip to show for the given cursor position in the text
|
||||||
|
Calltip GetCalltip(std::vector<ass::DialogueToken> const& tokens, std::string const& text, size_t pos);
|
||||||
|
};
|
||||||
|
}
|
|
@ -57,6 +57,7 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
#include <libaegisub/ass/dialogue_parser.h>
|
#include <libaegisub/ass/dialogue_parser.h>
|
||||||
|
#include <libaegisub/calltip_provider.h>
|
||||||
#include <libaegisub/spellchecker.h>
|
#include <libaegisub/spellchecker.h>
|
||||||
|
|
||||||
/// Event ids
|
/// Event ids
|
||||||
|
@ -82,6 +83,7 @@ SubsTextEditCtrl::SubsTextEditCtrl(wxWindow* parent, wxSize wsize, long style, a
|
||||||
: ScintillaTextCtrl(parent, -1, "", wxDefaultPosition, wsize, style)
|
: ScintillaTextCtrl(parent, -1, "", wxDefaultPosition, wsize, style)
|
||||||
, spellchecker(SpellCheckerFactory::GetSpellChecker())
|
, spellchecker(SpellCheckerFactory::GetSpellChecker())
|
||||||
, context(context)
|
, context(context)
|
||||||
|
, calltip_position(0)
|
||||||
{
|
{
|
||||||
// Set properties
|
// Set properties
|
||||||
SetWrapMode(wxSTC_WRAP_WORD);
|
SetWrapMode(wxSTC_WRAP_WORD);
|
||||||
|
@ -101,68 +103,6 @@ SubsTextEditCtrl::SubsTextEditCtrl(wxWindow* parent, wxSize wsize, long style, a
|
||||||
CmdKeyClear('T',wxSTC_SCMOD_CTRL | wxSTC_SCMOD_SHIFT);
|
CmdKeyClear('T',wxSTC_SCMOD_CTRL | wxSTC_SCMOD_SHIFT);
|
||||||
CmdKeyClear('U',wxSTC_SCMOD_CTRL);
|
CmdKeyClear('U',wxSTC_SCMOD_CTRL);
|
||||||
|
|
||||||
// Prototypes for call tips
|
|
||||||
tipProtoN = -1;
|
|
||||||
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");
|
|
||||||
|
|
||||||
using std::bind;
|
using std::bind;
|
||||||
|
|
||||||
Bind(wxEVT_CHAR_HOOK, &SubsTextEditCtrl::OnKeyDown, this);
|
Bind(wxEVT_CHAR_HOOK, &SubsTextEditCtrl::OnKeyDown, this);
|
||||||
|
@ -292,211 +232,27 @@ void SubsTextEditCtrl::UpdateCallTip(wxStyledTextEvent &) {
|
||||||
|
|
||||||
if (!OPT_GET("App/Call Tips")->GetBool()) return;
|
if (!OPT_GET("App/Call Tips")->GetBool()) return;
|
||||||
|
|
||||||
// Get position and text
|
if (!calltip_provider)
|
||||||
const unsigned int pos = GetReverseUnicodePosition(GetCurrentPos());
|
calltip_provider.reset(new agi::CalltipProvider);
|
||||||
wxString text = GetText();
|
|
||||||
|
|
||||||
// Find the start and end of current tag
|
std::string text = GetTextRaw().data();
|
||||||
wxChar prevChar = 0;
|
auto tokens = agi::ass::TokenizeDialogueBody(text);
|
||||||
int depth = 0;
|
int pos = GetCurrentPos();
|
||||||
int inDepth = 0;
|
|
||||||
int tagStart = -1;
|
|
||||||
int tagEnd = -1;
|
|
||||||
for (unsigned int i=0;i<text.Length()+1;i++) {
|
|
||||||
wxChar curChar = i < text.size() ? text[i] : 0;
|
|
||||||
|
|
||||||
// Change depth
|
agi::Calltip new_calltip = calltip_provider->GetCalltip(tokens, text, GetCurrentPos());
|
||||||
if (curChar == '{') {
|
|
||||||
depth++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (curChar == '}') {
|
|
||||||
depth--;
|
|
||||||
if (i >= pos && depth == 0) {
|
|
||||||
tagEnd = i-1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Outside
|
if (new_calltip.text.empty()) {
|
||||||
if (depth == 0) {
|
|
||||||
tagStart = -1;
|
|
||||||
if (i == pos) break;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inside overrides
|
|
||||||
if (depth == 1) {
|
|
||||||
// Inner depth
|
|
||||||
if (tagStart != -1) {
|
|
||||||
if (curChar == '(') inDepth++;
|
|
||||||
else if (curChar == ')') inDepth--;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not inside parenthesis
|
|
||||||
if (inDepth == 0) {
|
|
||||||
if (prevChar == '\\') {
|
|
||||||
// Found start
|
|
||||||
if (i <= pos) tagStart = i;
|
|
||||||
|
|
||||||
// Found end
|
|
||||||
else {
|
|
||||||
tagEnd = i-2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Previous character
|
|
||||||
prevChar = curChar;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate length
|
|
||||||
int len;
|
|
||||||
if (tagEnd != -1) len = tagEnd - tagStart + 1;
|
|
||||||
else len = text.Length() - tagStart;
|
|
||||||
|
|
||||||
// No tag available
|
|
||||||
int textLen = text.Length();
|
|
||||||
unsigned int posInTag = pos - tagStart;
|
|
||||||
if (tagStart+len > textLen || len <= 0 || tagStart < 0) {
|
|
||||||
CallTipCancel();
|
CallTipCancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current tag
|
if (!CallTipActive() || calltip_position != new_calltip.tag_position || calltip_text != new_calltip.text)
|
||||||
wxString tag = text.Mid(tagStart,len);
|
CallTipShow(new_calltip.tag_position, to_wx(new_calltip.text));
|
||||||
|
|
||||||
// Metrics in tag
|
calltip_position = new_calltip.tag_position;
|
||||||
int tagCommas = 0;
|
calltip_text = new_calltip.text;
|
||||||
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];
|
|
||||||
bool isEnd = false;
|
|
||||||
|
|
||||||
// Commas
|
CallTipSetHighlight(new_calltip.highlight_start, new_calltip.highlight_end);
|
||||||
if (curChar == ',') {
|
|
||||||
tagCommas++;
|
|
||||||
parN++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parenthesis
|
|
||||||
else if (curChar == '(') {
|
|
||||||
tagParenthesis++;
|
|
||||||
parN++;
|
|
||||||
}
|
|
||||||
else if (curChar == ')') {
|
|
||||||
tagParenthesis++;
|
|
||||||
parN++;
|
|
||||||
isEnd = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag name
|
|
||||||
if (parN == 1 && !gotName) {
|
|
||||||
tagName = tag.Left(i);
|
|
||||||
gotName = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parameter it's on
|
|
||||||
if (i == posInTag) {
|
|
||||||
parPos = parN;
|
|
||||||
if (curChar == ',' || curChar == '(' || curChar == ')') {
|
|
||||||
parPos--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (isEnd) {
|
|
||||||
parN = 1000;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parPos == -1) parPos = parN;
|
|
||||||
|
|
||||||
// Tag name
|
|
||||||
if (tagName.IsEmpty()) {
|
|
||||||
CallTipCancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find matching prototype
|
|
||||||
wxString useProto;
|
|
||||||
wxString cleanProto;
|
|
||||||
wxString protoName;
|
|
||||||
int protoN = 0;
|
|
||||||
bool semiProto = false;
|
|
||||||
for (unsigned int i=0;i<proto.Count();i++) {
|
|
||||||
// Get prototype name
|
|
||||||
int div = proto[i].Find(';');
|
|
||||||
if (div != wxNOT_FOUND) protoName = proto[i].Left(div);
|
|
||||||
else {
|
|
||||||
div = proto[i].Find('(');
|
|
||||||
protoName = proto[i].Left(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix name
|
|
||||||
semiProto = false;
|
|
||||||
cleanProto = proto[i];
|
|
||||||
if (cleanProto.Freq(';') > 0) {
|
|
||||||
cleanProto.Replace(";","");
|
|
||||||
semiProto = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prototype match
|
|
||||||
wxString temp;
|
|
||||||
if (semiProto) temp = tagName.Left(protoName.Length());
|
|
||||||
else temp = tagName;
|
|
||||||
if (protoName == temp) {
|
|
||||||
// Parameter count match
|
|
||||||
if (proto[i].Freq(',') >= tagCommas) {
|
|
||||||
// Found
|
|
||||||
useProto = proto[i];
|
|
||||||
protoN = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No matching prototype
|
|
||||||
if (useProto.IsEmpty()) {
|
|
||||||
CallTipCancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parameter number for tags without "(),"
|
|
||||||
if (semiProto && parPos == 0 && posInTag >= protoName.Length()) parPos = 1;
|
|
||||||
|
|
||||||
// Highlight start/end
|
|
||||||
int highStart = useProto.Length();
|
|
||||||
int highEnd = -1;
|
|
||||||
parN = 0;
|
|
||||||
int delta = 0;
|
|
||||||
for (unsigned int i=0;i<useProto.Length();i++) {
|
|
||||||
wxChar curChar = useProto[i];
|
|
||||||
if (i == 0 || curChar == ',' || curChar == ';' || curChar == '(' || curChar == ')') {
|
|
||||||
if (curChar == ';') delta++;
|
|
||||||
if (parN == parPos) highStart = i+1-delta;
|
|
||||||
else if (parN == parPos+1) highEnd = i;
|
|
||||||
parN++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (highStart <= 1) highStart = 0;
|
|
||||||
if (highEnd == -1) highEnd = useProto.Length();
|
|
||||||
|
|
||||||
// Calltip is over
|
|
||||||
if (highStart == (signed) useProto.Length()) {
|
|
||||||
CallTipCancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show calltip
|
|
||||||
if (!CallTipActive() || tipProtoN != protoN) CallTipShow(GetUnicodePosition(tagStart),cleanProto);
|
|
||||||
tipProtoN = protoN;
|
|
||||||
CallTipSetHighlight(highStart,highEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubsTextEditCtrl::SetTextTo(wxString text) {
|
void SubsTextEditCtrl::SetTextTo(wxString text) {
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
class SubsEditBox;
|
class SubsEditBox;
|
||||||
class Thesaurus;
|
class Thesaurus;
|
||||||
namespace agi {
|
namespace agi {
|
||||||
|
class CalltipProvider;
|
||||||
class SpellChecker;
|
class SpellChecker;
|
||||||
struct Context;
|
struct Context;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +58,8 @@ class SubsTextEditCtrl : public ScintillaTextCtrl {
|
||||||
/// Backend thesaurus to use
|
/// Backend thesaurus to use
|
||||||
agi::scoped_ptr<Thesaurus> thesaurus;
|
agi::scoped_ptr<Thesaurus> thesaurus;
|
||||||
|
|
||||||
|
agi::scoped_ptr<agi::CalltipProvider> calltip_provider;
|
||||||
|
|
||||||
/// Project context, for splitting lines
|
/// Project context, for splitting lines
|
||||||
agi::Context *context;
|
agi::Context *context;
|
||||||
|
|
||||||
|
@ -72,11 +75,12 @@ class SubsTextEditCtrl : public ScintillaTextCtrl {
|
||||||
/// Thesaurus suggestions for the last right-clicked word
|
/// Thesaurus suggestions for the last right-clicked word
|
||||||
std::vector<std::string> thesSugs;
|
std::vector<std::string> thesSugs;
|
||||||
|
|
||||||
/// Calltip prototypes
|
/// Text of the currently shown calltip, to avoid flickering from
|
||||||
wxArrayString proto;
|
/// pointlessly reshowing the current tip
|
||||||
|
std::string calltip_text;
|
||||||
|
|
||||||
/// Last show calltip, to avoid flickering the currently active one
|
/// Position of the currently show calltip
|
||||||
int tipProtoN;
|
size_t calltip_position;
|
||||||
|
|
||||||
void OnContextMenu(wxContextMenuEvent &);
|
void OnContextMenu(wxContextMenuEvent &);
|
||||||
void OnAddToDictionary(wxCommandEvent &event);
|
void OnAddToDictionary(wxCommandEvent &event);
|
||||||
|
|
Loading…
Reference in a new issue