Push more of the painting logic into the grid column classes

This commit is contained in:
Thomas Goyne 2014-04-21 07:50:19 -07:00
parent 6e0160d730
commit a1a289c4c0
4 changed files with 95 additions and 77 deletions

View File

@ -69,6 +69,7 @@ BaseGrid::BaseGrid(wxWindow* parent, agi::Context *context)
, scrollBar(new wxScrollBar(this, GRID_SCROLLBAR, wxDefaultPosition, wxDefaultSize, wxSB_VERTICAL))
, context(context)
, columns(GetGridColumns())
, columns_visible(OPT_GET("Subtitle/Grid/Column")->GetListBool())
, seek_listener(context->videoController->AddSeekListener([&] { Refresh(false); }))
{
scrollBar->SetScrollbar(0,10,100,10);
@ -81,6 +82,11 @@ BaseGrid::BaseGrid(wxWindow* parent, agi::Context *context)
SetBackgroundStyle(wxBG_STYLE_PAINT);
for (size_t i : agi::util::range(std::min(columns_visible.size(), columns.size()))) {
if (!columns_visible[i])
columns[i]->SetVisible(false);
}
UpdateStyle();
OnHighlightVisibleChange(*OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame"));
@ -151,11 +157,14 @@ void BaseGrid::OnSubtitlesSave() {
void BaseGrid::OnShowColMenu(wxCommandEvent &event) {
int item = event.GetId() - MENU_SHOW_COL;
column_shown[item] = !column_shown[item];
bool new_value = !columns_visible[item];
OPT_SET("Subtitle/Grid/Column")->SetListBool(std::vector<bool>(std::begin(column_shown), std::end(column_shown)));
columns_visible[item] = new_value;
OPT_SET("Subtitle/Grid/Column")->SetListBool(columns_visible);
columns[item]->SetVisible(new_value);
SetColumnWidths();
Refresh(false);
}
@ -188,15 +197,6 @@ void BaseGrid::UpdateStyle() {
row_colors.SelectedComment.SetColour(to_wx(OPT_GET("Colour/Subtitle Grid/Background/Selected Comment")->GetColor()));
row_colors.LeftCol.SetColour(to_wx(OPT_GET("Colour/Subtitle Grid/Left Column")->GetColor()));
// Set column widths
std::vector<bool> column_array(OPT_GET("Subtitle/Grid/Column")->GetListBool());
column_shown.assign(column_array.begin(), column_array.end());
column_shown.resize(columns.size(), true);
column_header_widths.resize(columns.size());
for (size_t i : agi::util::range(columns.size()))
column_header_widths[i] = dc.GetTextExtent(columns[i]->Header()).GetWidth();
SetColumnWidths();
AdjustScrollbar();
@ -255,20 +255,23 @@ void BaseGrid::SelectRow(int row, bool addToSelected, bool select) {
void BaseGrid::OnPaint(wxPaintEvent &) {
// Find which columns need to be repainted
std::vector<GridColumn *> paint_columns;
std::vector<char> paint_columns;
paint_columns.resize(columns.size(), false);
bool any = false;
for (wxRegionIterator region(GetUpdateRegion()); region; ++region) {
wxRect updrect = region.GetRect();
int x = 0;
for (size_t i : agi::util::range(columns.size())) {
if (updrect.x < x + column_widths[i] && updrect.x + updrect.width > x && column_widths[i])
paint_columns.push_back(columns[i].get());
else
paint_columns.push_back(nullptr);
x += column_widths[i];
int width = columns[i]->Width();
if (width && updrect.x < x + width && updrect.x + updrect.width > x) {
paint_columns[i] = true;
any = true;
}
x += width;
}
}
if (paint_columns.empty()) return;
if (!any) return;
int w = 0;
int h = 0;
@ -284,7 +287,7 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
// Draw labels
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(row_colors.LeftCol);
dc.DrawRectangle(0, lineHeight, column_widths[0], h-lineHeight);
dc.DrawRectangle(0, lineHeight, columns[0]->Width(), h-lineHeight);
// Row colors
wxColour text_standard(to_wx(OPT_GET("Colour/Subtitle Grid/Standard")->GetColor()));
@ -301,7 +304,7 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
int left = x + 4;
if (columns[col]->Centered()) {
wxSize ext = dc.GetTextExtent(str);
left += (column_widths[col] - 6 - ext.GetWidth()) / 2;
left += (columns[col]->Width() - 6 - ext.GetWidth()) / 2;
}
dc.DrawText(str, left, y + 2);
@ -317,7 +320,7 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
for (size_t i : agi::util::range(columns.size())) {
if (paint_columns[i])
paint_text(columns[i]->Header(), x, 0, i);
x += column_widths[i];
x += columns[i]->Width();
}
dc.SetPen(grid_pen);
@ -325,10 +328,11 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
}
// Paint the rows
int drawPerScreen = h/lineHeight + 1;
int nDraw = mid(0, drawPerScreen, GetRows() - yPos);
const int drawPerScreen = h/lineHeight + 1;
const int nDraw = mid(0, drawPerScreen, GetRows() - yPos);
const int grid_x = columns[0]->Width();
auto active_line = context->selectionController->GetActiveLine();
const auto active_line = context->selectionController->GetActiveLine();
auto const& selection = context->selectionController->GetSelectedSet();
for (int i : agi::util::range(nDraw)) {
@ -345,6 +349,13 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
else if (OPT_GET("Subtitle/Grid/Highlight Subtitles in Frame")->GetBool() && IsDisplayed(curDiag))
color = row_colors.Visible;
// Draw row background color
if (color != row_colors.Default) {
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(color);
dc.DrawRectangle(grid_x, (i + 1) * lineHeight + 1, w, lineHeight);
}
if (active_line != curDiag && curDiag->CollidesWith(active_line))
dc.SetTextForeground(text_collision);
else if (inSel)
@ -352,22 +363,13 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
else
dc.SetTextForeground(text_standard);
// Draw row background color
if (color != row_colors.Default) {
dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(color);
dc.DrawRectangle(column_widths[0], (i + 1) * lineHeight + 1, w, lineHeight);
}
// Draw text
int x = 0;
int y = (i + 1) * lineHeight;
for (size_t j : agi::util::range(columns.size())) {
if (column_widths[j] == 0) continue;
if (paint_columns[j])
paint_text(columns[j]->Value(curDiag, context), x, y, j);
x += column_widths[j];
columns[j]->Paint(dc, x + 4, y + 2, curDiag, context);
x += columns[j]->Width();
}
// Draw grid
@ -381,14 +383,15 @@ void BaseGrid::OnPaint(wxPaintEvent &) {
int maxH = (nDraw + 1) * lineHeight;
int x = 0;
dc.SetPen(grid_pen);
for (int width : column_widths) {
x += width;
for (auto const& column : columns) {
x += column->Width();
if (x < w)
dc.DrawLine(x, 0, x, maxH);
}
dc.DrawLine(0, 0, 0, maxH);
dc.DrawLine(w - 1, 0, w - 1, maxH);
dc.DrawLine(w, 0, w, maxH);
}
if (active_line && active_line->Row >= yPos && active_line->Row < yPos + nDraw) {
dc.SetPen(wxPen(to_wx(OPT_GET("Colour/Subtitle Grid/Active Border")->GetColor())));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
@ -531,7 +534,7 @@ void BaseGrid::OnContextMenu(wxContextMenuEvent &evt) {
wxMenu menu;
for (size_t i : agi::util::range(columns.size())) {
if (columns[i]->CanHide())
menu.Append(MENU_SHOW_COL + i, columns[i]->Description(), "", wxITEM_CHECK)->Check(!!column_shown[i]);
menu.Append(MENU_SHOW_COL + i, columns[i]->Description(), "", wxITEM_CHECK)->Check(columns[i]->Visible());
}
PopupMenu(&menu);
}
@ -579,25 +582,15 @@ void BaseGrid::SetColumnWidths() {
wxClientDC dc(this);
dc.SetFont(font);
WidthHelper helper{dc, std::unordered_map<boost::flyweight<std::string>, int>{}};
column_widths.clear();
for (auto i : agi::util::range(columns.size())) {
if (!column_shown[i])
column_widths.push_back(0);
else {
int width = columns[i]->Width(context, helper);
if (width) // 10 is an arbitrary amount of padding
width = 10 + std::max(width, column_header_widths[i]);
column_widths.push_back(width);
}
}
text_refresh_rects.clear();
int x = 0;
for (auto i : agi::util::range(columns.size())) {
if (columns[i]->RefreshOnTextChange() && column_widths[i])
text_refresh_rects.emplace_back(x, 0, column_widths[i], h);
WidthHelper helper{dc, std::unordered_map<boost::flyweight<std::string>, int>{}};
for (auto const& column : columns) {
column->UpdateWidth(context, helper);
if (column->Width() && column->RefreshOnTextChange())
text_refresh_rects.emplace_back(x, 0, column->Width(), h);
x += column->Width();
}
}

View File

@ -39,7 +39,7 @@ namespace agi {
class OptionValue;
}
class AssDialogue;
struct GridColumn;
class GridColumn;
class BaseGrid final : public wxWindow {
std::vector<agi::signal::Connection> connections;
@ -59,9 +59,7 @@ class BaseGrid final : public wxWindow {
agi::Context *context; ///< Associated project context
std::vector<std::unique_ptr<GridColumn>> columns;
std::vector<int> column_widths;
std::vector<int> column_header_widths;
std::vector<char> column_shown;
std::vector<bool> columns_visible;
std::vector<wxRect> text_refresh_rects;

View File

@ -44,6 +44,24 @@ int WidthHelper::operator()(wxString const& str) {
return dc.GetTextExtent(str).GetWidth();
}
void GridColumn::UpdateWidth(const agi::Context *c, WidthHelper &helper) {
if (!visible) {
width = 0;
return;
}
width = Width(c, helper);
if (width) // 10 is an arbitrary amount of padding
width = 10 + std::max(width, helper(Header()));
}
void GridColumn::Paint(wxDC &dc, int x, int y, const AssDialogue *d, const agi::Context *c) const {
wxString str = Value(d, c);
if (Centered())
x += (width - 6 - dc.GetTextExtent(str).GetWidth()) / 2;
dc.DrawText(str, x, y);
}
namespace {
#define COLUMN_HEADER(value) \
private: const wxString header = value; \
@ -233,7 +251,6 @@ public:
bool RefreshOnTextChange() const override { return true; }
wxString Value(const AssDialogue *d, const agi::Context *) const override {
int duration = d->End - d->Start;
auto const& text = d->Text.get();
@ -255,18 +272,15 @@ public:
};
class GridColumnText final : public GridColumn {
int override_mode;
const agi::OptionValue *override_mode;
wxString replace_char;
agi::signal::Connection override_mode_connection;
agi::signal::Connection replace_char_connection;
public:
GridColumnText()
: override_mode(OPT_GET("Subtitle/Grid/Hide Overrides")->GetInt())
: override_mode(OPT_GET("Subtitle/Grid/Hide Overrides"))
, replace_char(to_wx(OPT_GET("Subtitle/Grid/Hide Overrides Char")->GetString()))
, override_mode_connection(OPT_SUB("Subtitle/Grid/Hide Overrides",
[&](agi::OptionValue const& v) { override_mode = v.GetInt(); }))
, replace_char_connection(OPT_SUB("Subtitle/Grid/Hide Overrides Char",
[&](agi::OptionValue const& v) { replace_char = to_wx(v.GetString()); }))
{
@ -280,23 +294,25 @@ public:
wxString Value(const AssDialogue *d, const agi::Context *) const override {
wxString str;
int mode = override_mode->GetInt();
// Show overrides
if (override_mode == 0)
if (mode == 0)
str = to_wx(d->Text);
// Hidden overrides
else {
str.reserve(d->Text.get().size());
auto const& text = d->Text.get();
str.reserve(text.size());
size_t start = 0, pos;
while ((pos = d->Text.get().find('{', start)) != std::string::npos) {
str += to_wx(d->Text.get().substr(start, pos - start));
if (override_mode == 1)
while ((pos = text.find('{', start)) != std::string::npos) {
str += to_wx(text.substr(start, pos - start));
if (mode == 1)
str += replace_char;
start = d->Text.get().find('}', pos);
start = text.find('}', pos);
if (start != std::string::npos) ++start;
}
if (start != std::string::npos)
str += to_wx(d->Text.get().substr(start));
str += to_wx(text.substr(start));
}
// Cap length and set text

View File

@ -43,20 +43,31 @@ struct WidthHelper {
int operator()(wxString const& str);
};
struct GridColumn {
class GridColumn {
protected:
int width = 0;
bool visible = true;
virtual int Width(const agi::Context *c, WidthHelper &helper) const = 0;
virtual wxString Value(const AssDialogue *d, const agi::Context *c) const = 0;
public:
virtual ~GridColumn() = default;
virtual bool Centered() const = 0;
virtual bool Centered() const { return false; }
virtual bool CanHide() const { return true; }
virtual bool RefreshOnTextChange() const { return false; }
virtual wxString const& Header() const = 0;
virtual wxString const& Description() const = 0;
virtual void Paint(wxDC &dc, int x, int y, const AssDialogue *d, const agi::Context *c) const;
virtual wxString Value(const AssDialogue *d, const agi::Context * = nullptr) const = 0;
virtual int Width(const agi::Context *c, WidthHelper &helper) const = 0;
int Width() const { return width; }
bool Visible() const { return visible; }
virtual void UpdateWidth(const agi::Context *c, WidthHelper &helper);
virtual void SetByFrame(bool /* by_frame */) { }
void SetVisible(bool new_value) { visible = new_value; }
};
std::vector<std::unique_ptr<GridColumn>> GetGridColumns();