forked from mia/Aegisub
Add basic characters-per-second column to the grid
This commit is contained in:
parent
393d1dd269
commit
867eaae7a8
4 changed files with 89 additions and 56 deletions
|
@ -93,10 +93,10 @@ BaseGrid::BaseGrid(wxWindow* parent, agi::Context *context)
|
||||||
: wxWindow(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxSUNKEN_BORDER)
|
: wxWindow(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS | wxSUNKEN_BORDER)
|
||||||
, scrollBar(new wxScrollBar(this, GRID_SCROLLBAR, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL))
|
, scrollBar(new wxScrollBar(this, GRID_SCROLLBAR, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL))
|
||||||
, seek_listener(context->videoController->AddSeekListener(std::bind(&BaseGrid::Refresh, this, false, nullptr)))
|
, seek_listener(context->videoController->AddSeekListener(std::bind(&BaseGrid::Refresh, this, false, nullptr)))
|
||||||
, headerNames({
|
, headerNames({{
|
||||||
_("#"), _("L"), _("Start"), _("End"), _("Style"), _("Actor"),
|
_("#"), _("L"), _("Start"), _("End"), _("CPS"), _("Style"), _("Actor"),
|
||||||
_("Effect"), _("Left"), _("Right"), _("Vert"), _("Text")
|
_("Effect"), _("Left"), _("Right"), _("Vert"), _("Text")
|
||||||
})
|
}})
|
||||||
, context(context)
|
, context(context)
|
||||||
{
|
{
|
||||||
scrollBar->SetScrollbar(0,10,100,10);
|
scrollBar->SetScrollbar(0,10,100,10);
|
||||||
|
@ -163,8 +163,10 @@ void BaseGrid::OnSubtitlesCommit(int type) {
|
||||||
}
|
}
|
||||||
if (type & AssFile::COMMIT_DIAG_TIME)
|
if (type & AssFile::COMMIT_DIAG_TIME)
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
else if (type & AssFile::COMMIT_DIAG_TEXT)
|
else if (type & AssFile::COMMIT_DIAG_TEXT) {
|
||||||
|
RefreshRect(wxRect(cps_col_x, 0, cps_col_w, GetClientSize().GetHeight()), false);
|
||||||
RefreshRect(wxRect(text_col_x, 0, text_col_w, GetClientSize().GetHeight()), false);
|
RefreshRect(wxRect(text_col_x, 0, text_col_w, GetClientSize().GetHeight()), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseGrid::OnSubtitlesOpen() {
|
void BaseGrid::OnSubtitlesOpen() {
|
||||||
|
@ -219,6 +221,8 @@ void BaseGrid::UpdateStyle() {
|
||||||
std::vector<bool> column_array(OPT_GET("Subtitle/Grid/Column")->GetListBool());
|
std::vector<bool> column_array(OPT_GET("Subtitle/Grid/Column")->GetListBool());
|
||||||
assert(column_array.size() <= showCol.size());
|
assert(column_array.size() <= showCol.size());
|
||||||
boost::copy(column_array, std::begin(showCol));
|
boost::copy(column_array, std::begin(showCol));
|
||||||
|
for (size_t i : boost::irange(column_array.size(), showCol.size()))
|
||||||
|
showCol[i] = true;
|
||||||
|
|
||||||
for (int i : boost::irange(0, column_count))
|
for (int i : boost::irange(0, column_count))
|
||||||
headerWidth[i] = dc.GetTextExtent(headerNames[i]).GetWidth();
|
headerWidth[i] = dc.GetTextExtent(headerNames[i]).GetWidth();
|
||||||
|
@ -285,7 +289,7 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
|
||||||
cs.SetWidth(cs.GetWidth() - scrollBar->GetSize().GetWidth());
|
cs.SetWidth(cs.GetWidth() - scrollBar->GetSize().GetWidth());
|
||||||
|
|
||||||
// Find which columns need to be repainted
|
// Find which columns need to be repainted
|
||||||
bool paint_columns[11] = {0};
|
bool paint_columns[column_count] = {0};
|
||||||
for (wxRegionIterator region(GetUpdateRegion()); region; ++region) {
|
for (wxRegionIterator region(GetUpdateRegion()); region; ++region) {
|
||||||
wxRect updrect = region.GetRect();
|
wxRect updrect = region.GetRect();
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
@ -398,7 +402,7 @@ void BaseGrid::DrawImage(wxDC &dc, bool paint_columns[]) {
|
||||||
int top = dy + (lineHeight - ext.GetHeight()) / 2;
|
int top = dy + (lineHeight - ext.GetHeight()) / 2;
|
||||||
|
|
||||||
// Centered columns
|
// Centered columns
|
||||||
if (!(j == 4 || j == 5 || j == 6 || j == 10)) {
|
if (!(j == 5 || j == 6 || j == 7 || j == 11)) {
|
||||||
left += (colWidth[j] - 6 - ext.GetWidth()) / 2;
|
left += (colWidth[j] - 6 - ext.GetWidth()) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +428,7 @@ void BaseGrid::DrawImage(wxDC &dc, bool paint_columns[]) {
|
||||||
// Draw grid columns
|
// Draw grid columns
|
||||||
int dx = 0;
|
int dx = 0;
|
||||||
dc.SetPen(grid_pen);
|
dc.SetPen(grid_pen);
|
||||||
for (int i = 0; i < 10; ++i) {
|
for (int i : boost::irange(0, column_count - 1)) {
|
||||||
dx += colWidth[i];
|
dx += colWidth[i];
|
||||||
dc.DrawLine(dx, 0, dx, maxH);
|
dc.DrawLine(dx, 0, dx, maxH);
|
||||||
}
|
}
|
||||||
|
@ -443,36 +447,57 @@ void BaseGrid::GetRowStrings(int row, AssDialogue *line, bool *paint_columns, wx
|
||||||
if (paint_columns[2]) strings[2] = to_wx(line->Start.GetAssFormated());
|
if (paint_columns[2]) strings[2] = to_wx(line->Start.GetAssFormated());
|
||||||
if (paint_columns[3]) strings[3] = to_wx(line->End.GetAssFormated());
|
if (paint_columns[3]) strings[3] = to_wx(line->End.GetAssFormated());
|
||||||
}
|
}
|
||||||
if (paint_columns[4]) strings[4] = to_wx(line->Style);
|
if (paint_columns[5]) strings[5] = to_wx(line->Style);
|
||||||
if (paint_columns[5]) strings[5] = to_wx(line->Actor);
|
if (paint_columns[6]) strings[6] = to_wx(line->Actor);
|
||||||
if (paint_columns[6]) strings[6] = to_wx(line->Effect);
|
if (paint_columns[7]) strings[7] = to_wx(line->Effect);
|
||||||
if (paint_columns[7]) strings[7] = line->Margin[0] ? wxString(std::to_wstring(line->Margin[0])) : wxString();
|
if (paint_columns[8]) strings[8] = line->Margin[0] ? wxString(std::to_wstring(line->Margin[0])) : wxString();
|
||||||
if (paint_columns[8]) strings[8] = line->Margin[1] ? wxString(std::to_wstring(line->Margin[1])) : wxString();
|
if (paint_columns[9]) strings[9] = line->Margin[1] ? wxString(std::to_wstring(line->Margin[1])) : wxString();
|
||||||
if (paint_columns[9]) strings[9] = line->Margin[2] ? wxString(std::to_wstring(line->Margin[2])) : wxString();
|
if (paint_columns[10]) strings[10] = line->Margin[2] ? wxString(std::to_wstring(line->Margin[2])) : wxString();
|
||||||
|
|
||||||
if (paint_columns[10]) {
|
if (paint_columns[4]) {
|
||||||
strings[10].clear();
|
int characters = 0;
|
||||||
|
|
||||||
|
auto const& text = line->Text.get();
|
||||||
|
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));
|
||||||
|
|
||||||
|
int duration = line->End - line->Start;
|
||||||
|
strings[4] = std::to_wstring(duration > 0 ? characters * 1000 / duration : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (paint_columns[11]) {
|
||||||
|
strings[11].clear();
|
||||||
|
|
||||||
// Show overrides
|
// Show overrides
|
||||||
if (!replace)
|
if (!replace)
|
||||||
strings[10] = to_wx(line->Text);
|
strings[11] = to_wx(line->Text);
|
||||||
// Hidden overrides
|
// Hidden overrides
|
||||||
else {
|
else {
|
||||||
strings[10].reserve(line->Text.get().size());
|
strings[11].reserve(line->Text.get().size());
|
||||||
size_t start = 0, pos;
|
size_t start = 0, pos;
|
||||||
while ((pos = line->Text.get().find('{', start)) != std::string::npos) {
|
while ((pos = line->Text.get().find('{', start)) != std::string::npos) {
|
||||||
strings[10] += to_wx(line->Text.get().substr(start, pos - start));
|
strings[11] += to_wx(line->Text.get().substr(start, pos - start));
|
||||||
strings[10] += rep_char;
|
strings[11] += rep_char;
|
||||||
start = line->Text.get().find('}', pos);
|
start = line->Text.get().find('}', pos);
|
||||||
if (start != std::string::npos) ++start;
|
if (start != std::string::npos) ++start;
|
||||||
}
|
}
|
||||||
if (start != std::string::npos)
|
if (start != std::string::npos)
|
||||||
strings[10] += to_wx(line->Text.get().substr(start));
|
strings[11] += to_wx(line->Text.get().substr(start));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cap length and set text
|
// Cap length and set text
|
||||||
if (strings[10].size() > 512)
|
if (strings[11].size() > 512)
|
||||||
strings[10] = strings[10].Left(512) + "...";
|
strings[11] = strings[11].Left(512) + "...";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +506,7 @@ void BaseGrid::OnSize(wxSizeEvent &) {
|
||||||
|
|
||||||
int w, h;
|
int w, h;
|
||||||
GetClientSize(&w, &h);
|
GetClientSize(&w, &h);
|
||||||
colWidth[10] = text_col_w = w - text_col_x;
|
colWidth[11] = text_col_w = w - text_col_x;
|
||||||
|
|
||||||
Refresh(false);
|
Refresh(false);
|
||||||
}
|
}
|
||||||
|
@ -618,6 +643,7 @@ void BaseGrid::OnContextMenu(wxContextMenuEvent &evt) {
|
||||||
_("Layer"),
|
_("Layer"),
|
||||||
_("Start"),
|
_("Start"),
|
||||||
_("End"),
|
_("End"),
|
||||||
|
_("Characters per Second"),
|
||||||
_("Style"),
|
_("Style"),
|
||||||
_("Actor"),
|
_("Actor"),
|
||||||
_("Effect"),
|
_("Effect"),
|
||||||
|
@ -627,7 +653,7 @@ void BaseGrid::OnContextMenu(wxContextMenuEvent &evt) {
|
||||||
};
|
};
|
||||||
|
|
||||||
wxMenu menu;
|
wxMenu menu;
|
||||||
for (int i : boost::irange(0, column_count))
|
for (size_t i : boost::irange<size_t>(0, boost::size(strings)))
|
||||||
menu.Append(MENU_SHOW_COL + i, strings[i], "", wxITEM_CHECK)->Check(showCol[i]);
|
menu.Append(MENU_SHOW_COL + i, strings[i], "", wxITEM_CHECK)->Check(showCol[i]);
|
||||||
PopupMenu(&menu);
|
PopupMenu(&menu);
|
||||||
}
|
}
|
||||||
|
@ -735,33 +761,33 @@ void BaseGrid::SetColumnWidths() {
|
||||||
colWidth[1] = layerLen;
|
colWidth[1] = layerLen;
|
||||||
colWidth[2] = startLen;
|
colWidth[2] = startLen;
|
||||||
colWidth[3] = endLen;
|
colWidth[3] = endLen;
|
||||||
colWidth[4] = styleLen;
|
colWidth[4] = 1;
|
||||||
colWidth[5] = actorLen;
|
colWidth[5] = styleLen;
|
||||||
colWidth[6] = effectLen;
|
colWidth[6] = actorLen;
|
||||||
|
colWidth[7] = effectLen;
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
colWidth[i + 7] = showMargin[i] ? marginLen : 0;
|
colWidth[i + 8] = showMargin[i] ? marginLen : 0;
|
||||||
colWidth[10] = 1;
|
colWidth[11] = 1;
|
||||||
|
|
||||||
// Hide columns
|
// Hide columns and ensure every visible column is at least as big as its
|
||||||
for (size_t i : boost::irange(0u, showCol.size())) {
|
// header plus padding
|
||||||
|
for (size_t i : boost::irange<size_t>(0u, showCol.size())) {
|
||||||
if (!showCol[i])
|
if (!showCol[i])
|
||||||
colWidth[i] = 0;
|
colWidth[i] = 0;
|
||||||
}
|
else if (colWidth[i])
|
||||||
|
|
||||||
// Ensure every visible column is at least as big as its header plus padding
|
|
||||||
for (size_t i : boost::irange(0u, showCol.size())) {
|
|
||||||
if (colWidth[i])
|
|
||||||
colWidth[i] = 10 + std::max(colWidth[i], headerWidth[i]);
|
colWidth[i] = 10 + std::max(colWidth[i], headerWidth[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set size of last
|
// Set size of last
|
||||||
int total = std::accumulate(colWidth.begin(), colWidth.end(), 0);
|
int total = std::accumulate(colWidth.begin(), colWidth.end(), 0);
|
||||||
colWidth[10] = std::max(w - total, 0);
|
colWidth[11] = std::max(w - total, 0);
|
||||||
|
|
||||||
time_cols_x = colWidth[0] + colWidth[1];
|
time_cols_x = colWidth[0] + colWidth[1];
|
||||||
time_cols_w = colWidth[2] + colWidth[3];
|
time_cols_w = colWidth[2] + colWidth[3] + colWidth[4];
|
||||||
|
cps_col_x = time_cols_x + colWidth[2] + colWidth[3];
|
||||||
|
cps_col_w = colWidth[4];
|
||||||
text_col_x = total;
|
text_col_x = total;
|
||||||
text_col_w = colWidth[10];
|
text_col_w = colWidth[11];
|
||||||
}
|
}
|
||||||
|
|
||||||
AssDialogue *BaseGrid::GetDialogue(int n) const {
|
AssDialogue *BaseGrid::GetDialogue(int n) const {
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace agi {
|
||||||
class AssDialogue;
|
class AssDialogue;
|
||||||
|
|
||||||
class BaseGrid final : public wxWindow {
|
class BaseGrid final : public wxWindow {
|
||||||
static const int column_count = 11;
|
static const int column_count = 12;
|
||||||
|
|
||||||
std::vector<agi::signal::Connection> connections;
|
std::vector<agi::signal::Connection> connections;
|
||||||
int lineHeight = 1; ///< Height of a line in pixels in the current font
|
int lineHeight = 1; ///< Height of a line in pixels in the current font
|
||||||
|
@ -96,6 +96,8 @@ class BaseGrid final : public wxWindow {
|
||||||
int time_cols_w; ///< Width of the two times columns
|
int time_cols_w; ///< Width of the two times columns
|
||||||
int text_col_x; ///< Left edge of the text column
|
int text_col_x; ///< Left edge of the text column
|
||||||
int text_col_w; ///< Width of the text column
|
int text_col_w; ///< Width of the text column
|
||||||
|
int cps_col_x; ///< Left edge of the cps column
|
||||||
|
int cps_col_w; ///< Width of the cps column
|
||||||
|
|
||||||
std::array<bool, column_count - 1> showCol; ///< Column visibility mask (Text can't be hidden)
|
std::array<bool, column_count - 1> showCol; ///< Column visibility mask (Text can't be hidden)
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,24 @@ 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) {
|
size_t MaxLineLength(std::string const& text, bool ignore_whitespace) {
|
||||||
auto tokens = agi::ass::TokenizeDialogueBody(text);
|
auto tokens = agi::ass::TokenizeDialogueBody(text);
|
||||||
agi::ass::MarkDrawings(text, tokens);
|
agi::ass::MarkDrawings(text, tokens);
|
||||||
|
@ -237,22 +255,8 @@ size_t MaxLineLength(std::string const& text, bool ignore_whitespace) {
|
||||||
current_line_length = 0;
|
current_line_length = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (token.type == agi::ass::DialogueTokenType::TEXT) {
|
else if (token.type == agi::ass::DialogueTokenType::TEXT)
|
||||||
using namespace boost::locale::boundary;
|
current_line_length += CharacterCount(begin(text) + pos, begin(text) + pos + token.length, ignore_whitespace);
|
||||||
const ssegment_index characters(character, begin(text) + pos, begin(text) + pos + token.length);
|
|
||||||
if (!ignore_whitespace)
|
|
||||||
current_line_length += boost::distance(characters);
|
|
||||||
else {
|
|
||||||
// characters.rule(word_any) doesn't seem to work for character indexes (everything is word_none)
|
|
||||||
for (auto const& chr : characters) {
|
|
||||||
UChar32 c;
|
|
||||||
int i = 0;
|
|
||||||
U8_NEXT_UNSAFE(chr.begin(), i, c);
|
|
||||||
if (!u_isUWhiteSpace(c))
|
|
||||||
++current_line_length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pos += token.length;
|
pos += token.length;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ int SmallestPowerOf2(int x);
|
||||||
|
|
||||||
/// Get the length in characters of the longest line in the given text
|
/// 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 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.
|
/// @brief Launch a new copy of Aegisub.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in a new issue