forked from mia/Aegisub
Move character count stuff to libaegisub
This commit is contained in:
parent
bd53302907
commit
af32733797
10 changed files with 133 additions and 80 deletions
|
@ -46,6 +46,7 @@
|
|||
<ClInclude Include="$(SrcDir)include\libaegisub\cajun\visitor.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\cajun\writer.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\calltip_provider.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\character_count.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\charset.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\charset_conv.h" />
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\charset_conv_win.h" />
|
||||
|
@ -91,6 +92,7 @@
|
|||
<ClCompile Include="$(SrcDir)common\cajun\reader.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\cajun\writer.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\calltip_provider.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\character_count.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\charset.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\charset_6937.cpp" />
|
||||
<ClCompile Include="$(SrcDir)common\charset_conv.cpp" />
|
||||
|
|
|
@ -167,6 +167,9 @@
|
|||
<ClInclude Include="$(SrcDir)include\libaegisub\file_mapping.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SrcDir)include\libaegisub\character_count.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(SrcDir)windows\lagi_pre.cpp">
|
||||
|
@ -274,6 +277,9 @@
|
|||
<ClCompile Include="$(SrcDir)common\file_mapping.cpp">
|
||||
<Filter>Source Files\Common</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SrcDir)common\character_count.cpp">
|
||||
<Filter>Source Files\Common</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="$(SrcDir)include\libaegisub\charsets.def">
|
||||
|
|
|
@ -19,6 +19,7 @@ SRC += \
|
|||
common/cajun/reader.cpp \
|
||||
common/cajun/writer.cpp \
|
||||
common/calltip_provider.cpp \
|
||||
common/character_count.cpp \
|
||||
common/charset.cpp \
|
||||
common/charset_6937.cpp \
|
||||
common/charset_conv.cpp \
|
||||
|
|
92
libaegisub/common/character_count.cpp
Normal file
92
libaegisub/common/character_count.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) 2014, 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 "libaegisub/character_count.h"
|
||||
|
||||
#include "libaegisub/ass/dialogue_parser.h"
|
||||
|
||||
#include <boost/locale/boundary.hpp>
|
||||
#include <boost/range/algorithm_ext.hpp>
|
||||
#include <unicode/uchar.h>
|
||||
#include <unicode/utf8.h>
|
||||
|
||||
namespace {
|
||||
template <typename Iterator>
|
||||
size_t count_in_range(Iterator begin, Iterator end, bool ignore_whitespace) {
|
||||
using namespace boost::locale::boundary;
|
||||
const ssegment_index characters(character, begin, end);
|
||||
if (!ignore_whitespace)
|
||||
return boost::distance(characters);
|
||||
|
||||
// characters.rule(word_any) doesn't seem to work for character indexes (everything is word_none)
|
||||
size_t count = 0;
|
||||
for (auto const& chr : characters) {
|
||||
UChar32 c;
|
||||
int i = 0;
|
||||
U8_NEXT_UNSAFE(chr.begin(), i, c);
|
||||
if (!u_isUWhiteSpace(c))
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
namespace agi {
|
||||
size_t CharacterCount(std::string const& str) {
|
||||
size_t characters = 0;
|
||||
auto pos = begin(str);
|
||||
do {
|
||||
auto it = std::find(pos, end(str), '{');
|
||||
characters += count_in_range(pos, it, true);
|
||||
if (it == end(str)) break;
|
||||
|
||||
pos = std::find(pos, end(str), '}');
|
||||
if (pos == end(str)) {
|
||||
characters += count_in_range(it, pos, true);
|
||||
break;
|
||||
}
|
||||
} while (++pos != end(str));
|
||||
|
||||
return characters;
|
||||
}
|
||||
|
||||
size_t MaxLineLength(std::string const& text, bool ignore_whitespace) {
|
||||
auto tokens = agi::ass::TokenizeDialogueBody(text);
|
||||
agi::ass::MarkDrawings(text, tokens);
|
||||
|
||||
size_t pos = 0;
|
||||
size_t max_line_length = 0;
|
||||
size_t current_line_length = 0;
|
||||
for (auto token : tokens) {
|
||||
if (token.type == agi::ass::DialogueTokenType::LINE_BREAK) {
|
||||
if (text[pos + 1] == 'h') {
|
||||
if (!ignore_whitespace)
|
||||
current_line_length += 1;
|
||||
}
|
||||
else { // N or n
|
||||
max_line_length = std::max(max_line_length, current_line_length);
|
||||
current_line_length = 0;
|
||||
}
|
||||
}
|
||||
else if (token.type == agi::ass::DialogueTokenType::TEXT)
|
||||
current_line_length += count_in_range(begin(text) + pos, begin(text) + pos + token.length, ignore_whitespace);
|
||||
|
||||
pos += token.length;
|
||||
}
|
||||
|
||||
return std::max(max_line_length, current_line_length);
|
||||
}
|
||||
}
|
23
libaegisub/include/libaegisub/character_count.h
Normal file
23
libaegisub/include/libaegisub/character_count.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright (c) 2014, 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 <string>
|
||||
|
||||
namespace agi {
|
||||
/// Get the length in characters of the longest line in the given text
|
||||
size_t MaxLineLength(std::string const& text, bool ignore_whitespace);
|
||||
size_t CharacterCount(std::string const& str);
|
||||
}
|
|
@ -21,9 +21,10 @@
|
|||
#include "compat.h"
|
||||
#include "include/aegisub/context.h"
|
||||
#include "options.h"
|
||||
#include "utils.h"
|
||||
#include "video_context.h"
|
||||
|
||||
#include <libaegisub/character_count.h>
|
||||
|
||||
#include <wx/dc.h>
|
||||
|
||||
int WidthHelper::operator()(boost::flyweight<std::string> const& str) {
|
||||
|
@ -223,28 +224,13 @@ struct GridColumnCPS final : GridColumn {
|
|||
bool RefreshOnTextChange() const override { return true; }
|
||||
|
||||
wxString Value(const AssDialogue *d, const agi::Context *) const override {
|
||||
int characters = 0;
|
||||
|
||||
int duration = d->End - d->Start;
|
||||
auto const& text = d->Text.get();
|
||||
|
||||
if (duration <= 0 || text.size() > static_cast<size_t>(duration))
|
||||
return wxS("");
|
||||
|
||||
auto pos = begin(text);
|
||||
do {
|
||||
auto it = std::find(pos, end(text), '{');
|
||||
characters += CharacterCount(pos, it, true);
|
||||
if (it == end(text)) break;
|
||||
|
||||
pos = std::find(pos, end(text), '}');
|
||||
if (pos == end(text)) {
|
||||
characters += CharacterCount(it, pos, true);
|
||||
break;
|
||||
}
|
||||
} while (++pos != end(text));
|
||||
|
||||
return std::to_wstring(characters * 1000 / duration);
|
||||
return std::to_wstring(agi::CharacterCount(text) * 1000 / duration);
|
||||
}
|
||||
|
||||
int Width(const agi::Context *c, WidthHelper &helper, bool) const override {
|
||||
|
|
|
@ -14,12 +14,11 @@
|
|||
//
|
||||
// Aegisub Project http://www.aegisub.org/
|
||||
|
||||
/// @file placeholder_ctrl.h
|
||||
/// @ingroup custom_control
|
||||
///
|
||||
|
||||
#include <wx/settings.h>
|
||||
|
||||
// Defined in osx_utils.mm
|
||||
void SetPlaceholderText(wxWindow *window, wxString const& placeholder);
|
||||
|
||||
/// @class Placeholder
|
||||
/// @brief A wrapper around a control to add placeholder text
|
||||
///
|
||||
|
|
|
@ -50,10 +50,10 @@
|
|||
#include "text_selection_controller.h"
|
||||
#include "timeedit_ctrl.h"
|
||||
#include "tooltip_manager.h"
|
||||
#include "utils.h"
|
||||
#include "validators.h"
|
||||
#include "video_context.h"
|
||||
|
||||
#include <libaegisub/character_count.h>
|
||||
#include <libaegisub/dispatch.h>
|
||||
#include <libaegisub/util.h>
|
||||
|
||||
|
@ -228,7 +228,7 @@ wxTextCtrl *SubsEditBox::MakeMarginCtrl(wxString const& tooltip, int margin, wxS
|
|||
middle_left_sizer->Add(ctrl, wxSizerFlags().Center());
|
||||
|
||||
Bind(wxEVT_TEXT, [=](wxCommandEvent&) {
|
||||
int value = mid(0, atoi(ctrl->GetValue().utf8_str()), 9999);
|
||||
int value = agi::util::mid(0, atoi(ctrl->GetValue().utf8_str()), 9999);
|
||||
SetSelectedRows([&](AssDialogue *d) { d->Margin[margin] = value; },
|
||||
commit_msg, AssFile::COMMIT_DIAG_META);
|
||||
}, ctrl->GetId());
|
||||
|
@ -587,7 +587,7 @@ void SubsEditBox::CallCommand(const char *cmd_name) {
|
|||
void SubsEditBox::UpdateCharacterCount(std::string const& text) {
|
||||
auto ignore_whitespace = OPT_GET("Subtitle/Character Counter/Ignore Whitespace")->GetBool();
|
||||
agi::dispatch::Background().Async([=]{
|
||||
size_t length = MaxLineLength(text, ignore_whitespace);
|
||||
size_t length = agi::MaxLineLength(text, ignore_whitespace);
|
||||
agi::dispatch::Main().Async([=]{
|
||||
char_count->SetValue(wxString::Format("%lu", (unsigned long)length));
|
||||
size_t limit = (size_t)OPT_GET("Subtitle/Character Limit")->GetInt();
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include "options.h"
|
||||
#include "retina_helper.h"
|
||||
|
||||
#include <libaegisub/ass/dialogue_parser.h>
|
||||
#include <libaegisub/dispatch.h>
|
||||
#include <libaegisub/fs.h>
|
||||
#include <libaegisub/log.h>
|
||||
|
@ -49,11 +48,7 @@
|
|||
#endif
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/locale/boundary.hpp>
|
||||
#include <boost/range/algorithm_ext.hpp>
|
||||
#include <map>
|
||||
#include <unicode/uchar.h>
|
||||
#include <unicode/utf8.h>
|
||||
|
||||
#include <wx/clipbrd.h>
|
||||
#include <wx/filedlg.h>
|
||||
|
@ -219,51 +214,6 @@ void CleanCache(agi::fs::path const& directory, std::string const& file_type, ui
|
|||
});
|
||||
}
|
||||
|
||||
size_t CharacterCount(std::string::const_iterator begin, std::string::const_iterator end, bool ignore_whitespace) {
|
||||
using namespace boost::locale::boundary;
|
||||
const ssegment_index characters(character, begin, end);
|
||||
if (!ignore_whitespace)
|
||||
return boost::distance(characters);
|
||||
|
||||
// characters.rule(word_any) doesn't seem to work for character indexes (everything is word_none)
|
||||
size_t count = 0;
|
||||
for (auto const& chr : characters) {
|
||||
UChar32 c;
|
||||
int i = 0;
|
||||
U8_NEXT_UNSAFE(chr.begin(), i, c);
|
||||
if (!u_isUWhiteSpace(c))
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t MaxLineLength(std::string const& text, bool ignore_whitespace) {
|
||||
auto tokens = agi::ass::TokenizeDialogueBody(text);
|
||||
agi::ass::MarkDrawings(text, tokens);
|
||||
|
||||
size_t pos = 0;
|
||||
size_t max_line_length = 0;
|
||||
size_t current_line_length = 0;
|
||||
for (auto token : tokens) {
|
||||
if (token.type == agi::ass::DialogueTokenType::LINE_BREAK) {
|
||||
if (text[pos + 1] == 'h') {
|
||||
if (!ignore_whitespace)
|
||||
current_line_length += 1;
|
||||
}
|
||||
else { // N or n
|
||||
max_line_length = std::max(max_line_length, current_line_length);
|
||||
current_line_length = 0;
|
||||
}
|
||||
}
|
||||
else if (token.type == agi::ass::DialogueTokenType::TEXT)
|
||||
current_line_length += CharacterCount(begin(text) + pos, begin(text) + pos + token.length, ignore_whitespace);
|
||||
|
||||
pos += token.length;
|
||||
}
|
||||
|
||||
return std::max(max_line_length, current_line_length);
|
||||
}
|
||||
|
||||
#ifndef __WXOSX_COCOA__
|
||||
// OS X implementation in osx_utils.mm
|
||||
void AddFullScreenButton(wxWindow *) { }
|
||||
|
|
|
@ -60,10 +60,6 @@ std::string float_to_string(double val);
|
|||
/// Algorithm from http://bob.allegronetwork.com/prog/tricks.html
|
||||
int SmallestPowerOf2(int x);
|
||||
|
||||
/// Get the length in characters of the longest line in the given text
|
||||
size_t MaxLineLength(std::string const& text, bool ignore_whitespace);
|
||||
size_t CharacterCount(std::string::const_iterator begin, std::string::const_iterator end, bool ignore_whitespace);
|
||||
|
||||
/// @brief Launch a new copy of Aegisub.
|
||||
///
|
||||
/// Contrary to what the name suggests, this does not close the currently
|
||||
|
@ -75,8 +71,6 @@ void AddFullScreenButton(wxWindow *window);
|
|||
|
||||
void SetFloatOnParent(wxWindow *window);
|
||||
|
||||
void SetPlaceholderText(wxWindow *window, wxString const& placeholder);
|
||||
|
||||
/// Forward a mouse wheel event to the window under the mouse if needed
|
||||
/// @param source The initial target of the wheel event
|
||||
/// @param evt The event
|
||||
|
|
Loading…
Reference in a new issue