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)
, scrollBar(new wxScrollBar(this, GRID_SCROLLBAR, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL))
, seek_listener(context->videoController->AddSeekListener(std::bind(&BaseGrid::Refresh, this, false, nullptr)))
, headerNames({
_("#"), _("L"), _("Start"), _("End"), _("Style"), _("Actor"),
, headerNames({{
_("#"), _("L"), _("Start"), _("End"), _("CPS"), _("Style"), _("Actor"),
_("Effect"), _("Left"), _("Right"), _("Vert"), _("Text")
})
}})
, context(context)
{
scrollBar->SetScrollbar(0,10,100,10);
@ -163,9 +163,11 @@ void BaseGrid::OnSubtitlesCommit(int type) {
}
if (type & AssFile::COMMIT_DIAG_TIME)
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);
}
}
void BaseGrid::OnSubtitlesOpen() {
ScrollTo(context->ass->GetUIStateAsInt("Scroll Position"));
@ -219,6 +221,8 @@ void BaseGrid::UpdateStyle() {
std::vector<bool> column_array(OPT_GET("Subtitle/Grid/Column")->GetListBool());
assert(column_array.size() <= showCol.size());
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))
headerWidth[i] = dc.GetTextExtent(headerNames[i]).GetWidth();
@ -285,7 +289,7 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
cs.SetWidth(cs.GetWidth() - scrollBar->GetSize().GetWidth());
// Find which columns need to be repainted
bool paint_columns[11] = {0};
bool paint_columns[column_count] = {0};
for (wxRegionIterator region(GetUpdateRegion()); region; ++region) {
wxRect updrect = region.GetRect();
int x = 0;
@ -398,7 +402,7 @@ void BaseGrid::DrawImage(wxDC &dc, bool paint_columns[]) {
int top = dy + (lineHeight - ext.GetHeight()) / 2;
// 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;
}
@ -424,7 +428,7 @@ void BaseGrid::DrawImage(wxDC &dc, bool paint_columns[]) {
// Draw grid columns
int dx = 0;
dc.SetPen(grid_pen);
for (int i = 0; i < 10; ++i) {
for (int i : boost::irange(0, column_count - 1)) {
dx += colWidth[i];
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[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->Actor);
if (paint_columns[6]) strings[6] = 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[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[5]) strings[5] = to_wx(line->Style);
if (paint_columns[6]) strings[6] = to_wx(line->Actor);
if (paint_columns[7]) strings[7] = to_wx(line->Effect);
if (paint_columns[8]) strings[8] = line->Margin[0] ? wxString(std::to_wstring(line->Margin[0])) : wxString();
if (paint_columns[9]) strings[9] = line->Margin[1] ? wxString(std::to_wstring(line->Margin[1])) : wxString();
if (paint_columns[10]) strings[10] = line->Margin[2] ? wxString(std::to_wstring(line->Margin[2])) : wxString();
if (paint_columns[10]) {
strings[10].clear();
if (paint_columns[4]) {
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
if (!replace)
strings[10] = to_wx(line->Text);
strings[11] = to_wx(line->Text);
// Hidden overrides
else {
strings[10].reserve(line->Text.get().size());
strings[11].reserve(line->Text.get().size());
size_t start = 0, pos;
while ((pos = line->Text.get().find('{', start)) != std::string::npos) {
strings[10] += to_wx(line->Text.get().substr(start, pos - start));
strings[10] += rep_char;
strings[11] += to_wx(line->Text.get().substr(start, pos - start));
strings[11] += rep_char;
start = line->Text.get().find('}', pos);
if (start != std::string::npos) ++start;
}
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
if (strings[10].size() > 512)
strings[10] = strings[10].Left(512) + "...";
if (strings[11].size() > 512)
strings[11] = strings[11].Left(512) + "...";
}
}
@ -481,7 +506,7 @@ void BaseGrid::OnSize(wxSizeEvent &) {
int 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);
}
@ -618,6 +643,7 @@ void BaseGrid::OnContextMenu(wxContextMenuEvent &evt) {
_("Layer"),
_("Start"),
_("End"),
_("Characters per Second"),
_("Style"),
_("Actor"),
_("Effect"),
@ -627,7 +653,7 @@ void BaseGrid::OnContextMenu(wxContextMenuEvent &evt) {
};
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]);
PopupMenu(&menu);
}
@ -735,33 +761,33 @@ void BaseGrid::SetColumnWidths() {
colWidth[1] = layerLen;
colWidth[2] = startLen;
colWidth[3] = endLen;
colWidth[4] = styleLen;
colWidth[5] = actorLen;
colWidth[6] = effectLen;
colWidth[4] = 1;
colWidth[5] = styleLen;
colWidth[6] = actorLen;
colWidth[7] = effectLen;
for (int i = 0; i < 3; i++)
colWidth[i + 7] = showMargin[i] ? marginLen : 0;
colWidth[10] = 1;
colWidth[i + 8] = showMargin[i] ? marginLen : 0;
colWidth[11] = 1;
// Hide columns
for (size_t i : boost::irange(0u, showCol.size())) {
// Hide columns and ensure every visible column is at least as big as its
// header plus padding
for (size_t i : boost::irange<size_t>(0u, showCol.size())) {
if (!showCol[i])
colWidth[i] = 0;
}
// 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])
else if (colWidth[i])
colWidth[i] = 10 + std::max(colWidth[i], headerWidth[i]);
}
// Set size of last
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_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_w = colWidth[10];
text_col_w = colWidth[11];
}
AssDialogue *BaseGrid::GetDialogue(int n) const {

View file

@ -46,7 +46,7 @@ namespace agi {
class AssDialogue;
class BaseGrid final : public wxWindow {
static const int column_count = 11;
static const int column_count = 12;
std::vector<agi::signal::Connection> connections;
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 text_col_x; ///< Left edge 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)

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) {
auto tokens = agi::ass::TokenizeDialogueBody(text);
agi::ass::MarkDrawings(text, tokens);
@ -237,22 +255,8 @@ size_t MaxLineLength(std::string const& text, bool ignore_whitespace) {
current_line_length = 0;
}
}
else if (token.type == agi::ass::DialogueTokenType::TEXT) {
using namespace boost::locale::boundary;
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;
}
}
}
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;
}

View file

@ -62,6 +62,7 @@ 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.
///