diff --git a/build/Aegisub/Aegisub.vcxproj b/build/Aegisub/Aegisub.vcxproj
index 76209cdae..c0e935cef 100644
--- a/build/Aegisub/Aegisub.vcxproj
+++ b/build/Aegisub/Aegisub.vcxproj
@@ -156,6 +156,7 @@
+
diff --git a/build/Aegisub/Aegisub.vcxproj.filters b/build/Aegisub/Aegisub.vcxproj.filters
index ca09046ad..458dc1fe4 100644
--- a/build/Aegisub/Aegisub.vcxproj.filters
+++ b/build/Aegisub/Aegisub.vcxproj.filters
@@ -549,6 +549,9 @@
Features
+
+ Utilities
+
@@ -1040,9 +1043,6 @@
ASS
-
- Audio\Providers
-
Commands
@@ -1093,4 +1093,4 @@
-
+
\ No newline at end of file
diff --git a/src/base_grid.cpp b/src/base_grid.cpp
index 1d3801c96..25f9f6197 100644
--- a/src/base_grid.cpp
+++ b/src/base_grid.cpp
@@ -45,6 +45,7 @@
#include "subs_controller.h"
#include "video_controller.h"
+#include
#include
#include
@@ -598,15 +599,17 @@ void BaseGrid::SetColumnWidths() {
text_refresh_rects.clear();
int x = 0;
- WidthHelper helper{dc, std::unordered_map, int>{}};
- helper.widths.reserve(prev_unique_string_widths);
+ if (!width_helper)
+ width_helper = agi::make_unique();
+ width_helper->SetDC(&dc);
+
for (auto const& column : columns) {
- column->UpdateWidth(context, helper);
+ column->UpdateWidth(context, *width_helper);
if (column->Width() && column->RefreshOnTextChange())
text_refresh_rects.emplace_back(x, 0, column->Width(), h);
x += column->Width();
}
- prev_unique_string_widths = helper.widths.size();
+ width_helper->Age();
}
AssDialogue *BaseGrid::GetDialogue(int n) const {
diff --git a/src/base_grid.h b/src/base_grid.h
index 86ca3071d..366189588 100644
--- a/src/base_grid.h
+++ b/src/base_grid.h
@@ -30,6 +30,7 @@
#include
#include
+#include
#include
#include
@@ -39,6 +40,7 @@ namespace agi {
}
class AssDialogue;
class GridColumn;
+class WidthHelper;
class BaseGrid final : public wxWindow {
std::vector connections;
@@ -57,7 +59,7 @@ class BaseGrid final : public wxWindow {
int active_row = -1;
- size_t prev_unique_string_widths = 0;
+ std::unique_ptr width_helper;
/// Rows which are visible on the current video frame
std::vector visible_rows;
diff --git a/src/flyweight_hash.h b/src/flyweight_hash.h
new file mode 100644
index 000000000..3eb3afff2
--- /dev/null
+++ b/src/flyweight_hash.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, Thomas Goyne
+//
+// 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/
+
+#pragma once
+
+#include
+
+namespace std {
+ template
+ struct hash> {
+ size_t operator()(boost::flyweight const& ss) const {
+ return hash()(&ss.get());
+ }
+ };
+}
diff --git a/src/grid_column.cpp b/src/grid_column.cpp
index 757966b93..289ea79b3 100644
--- a/src/grid_column.cpp
+++ b/src/grid_column.cpp
@@ -27,39 +27,52 @@
#include
+void WidthHelper::Age() {
+ for (auto it = begin(widths), e = end(widths); it != e; ) {
+ if (it->second.age == age)
+ ++it;
+ else
+ it = widths.erase(it);
+ }
+ ++age;
+}
+
int WidthHelper::operator()(boost::flyweight const& str) {
if (str.get().empty()) return 0;
auto it = widths.find(str);
- if (it != end(widths)) return it->second;
+ if (it != end(widths)) {
+ it->second.age = age;
+ return it->second.width;
+ }
#ifdef _WIN32
wxMBConvUTF8 conv;
size_t len = conv.ToWChar(nullptr, 0, str.get().c_str(), str.get().size());
scratch.resize(len);
conv.ToWChar(const_cast(scratch.wx_str()), len, str.get().c_str(), str.get().size());
- int width = dc.GetTextExtent(scratch).GetWidth();
+ int width = dc->GetTextExtent(scratch).GetWidth();
#else
- int width = dc.GetTextExtent(to_wx(str)).GetWidth();
+ int width = dc->GetTextExtent(to_wx(str)).GetWidth();
#endif
- widths[str] = width;
+ widths[str] = {width, age};
return width;
}
int WidthHelper::operator()(std::string const& str) {
- return dc.GetTextExtent(to_wx(str)).GetWidth();
+ return dc->GetTextExtent(to_wx(str)).GetWidth();
}
int WidthHelper::operator()(wxString const& str) {
- return dc.GetTextExtent(str).GetWidth();
+ return dc->GetTextExtent(str).GetWidth();
}
int WidthHelper::operator()(const char *str) {
- return dc.GetTextExtent(wxString::FromUTF8(str)).GetWidth();
+ return dc->GetTextExtent(wxString::FromUTF8(str)).GetWidth();
}
int WidthHelper::operator()(const wchar_t *str) {
- return dc.GetTextExtent(str).GetWidth();
+ return dc->GetTextExtent(str).GetWidth();
}
void GridColumn::UpdateWidth(const agi::Context *c, WidthHelper &helper) {
diff --git a/src/grid_column.h b/src/grid_column.h
index 54497610b..16b70f2a9 100644
--- a/src/grid_column.h
+++ b/src/grid_column.h
@@ -14,7 +14,8 @@
//
// Aegisub Project http://www.aegisub.org/
-#include
+#include "flyweight_hash.h"
+
#include
#include
#include
@@ -25,19 +26,21 @@ class wxDC;
class wxString;
namespace agi { struct Context; }
-namespace std {
- template
- struct hash> {
- size_t operator()(boost::flyweight const& ss) const {
- return hash()(&ss.get());
- }
+class WidthHelper {
+ struct Entry {
+ int width;
+ int age;
};
-}
-
-struct WidthHelper {
- wxDC &dc;
- std::unordered_map, int> widths;
+ int age = 0;
+ wxDC *dc = nullptr;
+ std::unordered_map, Entry> widths;
+#ifdef _WIN32
wxString scratch;
+#endif
+
+public:
+ void SetDC(wxDC *dc) { this->dc = dc; }
+ void Age();
int operator()(boost::flyweight const& str);
int operator()(std::string const& str);
diff --git a/src/subs_edit_box.cpp b/src/subs_edit_box.cpp
index 7ed9111bc..c19b2f9c8 100644
--- a/src/subs_edit_box.cpp
+++ b/src/subs_edit_box.cpp
@@ -40,6 +40,7 @@
#include "command/command.h"
#include "compat.h"
#include "dialog_style_editor.h"
+#include "flyweight_hash.h"
#include "include/aegisub/context.h"
#include "include/aegisub/hotkey.h"
#include "initial_line_state.h"
@@ -69,15 +70,6 @@
#include
#include
-namespace std {
- template
- struct hash> {
- size_t operator()(boost::flyweight const& ss) const {
- return hash()(&ss.get());
- }
- };
-}
-
namespace {
/// Work around wxGTK's fondness for generating events from ChangeValue