Add basic characters-per-second column to the grid

This commit is contained in:
Thomas Goyne 2014-04-17 18:22:07 -07:00
parent 393d1dd269
commit 867eaae7a8
4 changed files with 89 additions and 56 deletions

View file

@ -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 {

View file

@ -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)

View file

@ -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;
} }

View file

@ -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.
/// ///