Skip to content

Commit b128755

Browse files
authored
Merge pull request #37 from Tom94/regex
Add regex toggle for more advanced image filtering
2 parents 8dd6a48 + 2965720 commit b128755

File tree

5 files changed

+66
-29
lines changed

5 files changed

+66
-29
lines changed

include/tev/Common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ std::string toUpper(std::string str);
7373

7474
bool endsWith(const std::string& str, const std::string& ending);
7575

76-
bool matches(std::string text, std::string filter);
76+
bool matches(std::string text, std::string filter, bool isRegex);
7777

7878
void drawTextWithShadow(NVGcontext* ctx, float x, float y, std::string text, float shadowAlpha = 1.0f);
7979

include/tev/ImageViewer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class ImageViewer : public nanogui::Screen {
9191
void resizeToFitAllImages();
9292
bool setFilter(const std::string& filter);
9393

94+
bool useRegex();
95+
void setUseRegex(bool value);
96+
9497
void maximize();
9598
bool isMaximized();
9699
void toggleMaximized();
@@ -168,6 +171,7 @@ class ImageViewer : public nanogui::Screen {
168171
MultiGraph* mHistogram;
169172

170173
nanogui::TextBox* mFilter;
174+
nanogui::Button* mRegexButton;
171175

172176
// Buttons which require a current image to be meaningful.
173177
std::vector<nanogui::Button*> mCurrentImageButtons;

src/Common.cpp

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <algorithm>
99
#include <cctype>
1010
#include <map>
11+
#include <regex>
1112

1213
#ifdef _WIN32
1314
# include <Shlobj.h>
@@ -52,31 +53,44 @@ bool endsWith(const string& str, const string& ending) {
5253
return str.rfind(ending) == str.length() - ending.length();
5354
}
5455

55-
bool matches(string text, string filter) {
56-
if (filter.empty()) {
57-
return true;
58-
}
56+
bool matches(string text, string filter, bool isRegex) {
57+
auto matchesFuzzy = [](string text, string filter) {
58+
if (filter.empty()) {
59+
return true;
60+
}
5961

60-
// Perform matching on lowercase strings
61-
text = toLower(text);
62-
filter = toLower(filter);
62+
// Perform matching on lowercase strings
63+
text = toLower(text);
64+
filter = toLower(filter);
6365

64-
auto words = split(filter, ", ");
65-
// We don't want people entering multiple spaces in a row to match everything.
66-
words.erase(remove(begin(words), end(words), ""), end(words));
66+
auto words = split(filter, ", ");
67+
// We don't want people entering multiple spaces in a row to match everything.
68+
words.erase(remove(begin(words), end(words), ""), end(words));
6769

68-
if (words.empty()) {
69-
return true;
70-
}
70+
if (words.empty()) {
71+
return true;
72+
}
7173

72-
// Match every word of the filter separately.
73-
for (const auto& word : words) {
74-
if (text.find(word) != string::npos) {
74+
// Match every word of the filter separately.
75+
for (const auto& word : words) {
76+
if (text.find(word) != string::npos) {
77+
return true;
78+
}
79+
}
80+
81+
return false;
82+
};
83+
84+
auto matchesRegex = [](string text, string filter) {
85+
if (filter.empty()) {
7586
return true;
7687
}
77-
}
7888

79-
return false;
89+
regex searchRegex{filter, std::regex_constants::ECMAScript | std::regex_constants::icase};
90+
return regex_search(text, searchRegex);
91+
};
92+
93+
return isRegex ? matchesRegex(text, filter) : matchesFuzzy(text, filter);
8094
}
8195

8296
void drawTextWithShadow(NVGcontext* ctx, float x, float y, string text, float shadowAlpha) {

src/Image.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ void Image::readStbi() {
199199

200200
for (auto& channel : channels) {
201201
string name = channel.name();
202-
if (matches(name, mChannelSelector)) {
202+
if (matches(name, mChannelSelector, false)) {
203203
mChannels.emplace(move(name), move(channel));
204204
}
205205
}
@@ -238,7 +238,7 @@ void Image::readExr() {
238238
const Imf::ChannelList& imfChannels = part.header().channels();
239239

240240
for (Imf::ChannelList::ConstIterator c = imfChannels.begin(); c != imfChannels.end(); ++c) {
241-
if (matches(c.name(), mChannelSelector)) {
241+
if (matches(c.name(), mChannelSelector, false)) {
242242
partIdx = i;
243243
goto l_foundPart;
244244
}
@@ -326,7 +326,7 @@ void Image::readExr() {
326326
set<string> layerNames;
327327

328328
for (Imf::ChannelList::ConstIterator c = imfChannels.begin(); c != imfChannels.end(); ++c) {
329-
if (matches(c.name(), mChannelSelector)) {
329+
if (matches(c.name(), mChannelSelector, false)) {
330330
rawChannels.emplace_back(c.name(), c.channel().type);
331331
layerNames.insert(Channel::head(c.name()));
332332
}

src/ImageViewer.cpp

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ ImageViewer::ImageViewer(shared_ptr<Ipc> ipc, shared_ptr<SharedQueue<ImageAdditi
258258
// Fuzzy filter of open images
259259
{
260260
panel = new Widget{mSidebarLayout};
261-
panel->setLayout(new BoxLayout{Orientation::Vertical, Alignment::Fill, 5});
261+
panel->setLayout(new GridLayout{Orientation::Horizontal, 2, Alignment::Fill, 5, 2});
262262

263263
mFilter = new TextBox{panel, ""};
264264
mFilter->setEditable(true);
@@ -267,14 +267,23 @@ ImageViewer::ImageViewer(shared_ptr<Ipc> ipc, shared_ptr<SharedQueue<ImageAdditi
267267
return setFilter(filter);
268268
});
269269

270-
mFilter->setPlaceholder("Enter text to filter images");
270+
mFilter->setPlaceholder("Find");
271271
mFilter->setTooltip(tfm::format(
272272
"Filters visible images and layers according to a supplied string. "
273273
"The string must have the format 'image:layer'. "
274274
"Only images whose name contains 'image' and layers whose name contains 'layer' will be visible.\n\n"
275275
"Keyboard shortcut:\n%s+P",
276276
HelpWindow::COMMAND
277277
));
278+
279+
mRegexButton = new Button{panel, "", ENTYPO_ICON_SEARCH};
280+
mRegexButton->setTooltip("Treat filter as regular expression");
281+
mRegexButton->setPushed(false);
282+
mRegexButton->setFlags(Button::ToggleButton);
283+
mRegexButton->setFontSize(15);
284+
mRegexButton->setChangeCallback([this](bool value) {
285+
setUseRegex(value);
286+
});
278287
}
279288

280289
// Playback controls
@@ -1136,6 +1145,15 @@ bool ImageViewer::setFilter(const string& filter) {
11361145
return true;
11371146
}
11381147

1148+
bool ImageViewer::useRegex() {
1149+
return mRegexButton->pushed();
1150+
}
1151+
1152+
void ImageViewer::setUseRegex(bool value) {
1153+
mRegexButton->setPushed(value);
1154+
mRequiresFilterUpdate = true;
1155+
}
1156+
11391157
void ImageViewer::maximize() {
11401158
glfwMaximizeWindow(mGLFWWindow);
11411159
}
@@ -1270,11 +1288,11 @@ void ImageViewer::updateFilter() {
12701288
// This is the case if the image name matches the image part
12711289
// and at least one of the image's layers matches the layer part.
12721290
auto doesImageMatch = [&](const shared_ptr<Image>& image) {
1273-
bool doesMatch = matches(image->name(), imagePart);
1291+
bool doesMatch = matches(image->name(), imagePart, useRegex());
12741292
if (doesMatch) {
12751293
bool anyLayersMatch = false;
12761294
for (const auto& layer : image->layers()) {
1277-
if (matches(layer, layerPart)) {
1295+
if (matches(layer, layerPart, useRegex())) {
12781296
anyLayersMatch = true;
12791297
break;
12801298
}
@@ -1350,7 +1368,7 @@ void ImageViewer::updateFilter() {
13501368
selectImage(nthVisibleImage(0));
13511369
}
13521370

1353-
if (mCurrentReference && !matches(mCurrentReference->name(), imagePart)) {
1371+
if (mCurrentReference && !matches(mCurrentReference->name(), imagePart, useRegex())) {
13541372
selectReference(nullptr);
13551373
}
13561374
}
@@ -1362,13 +1380,13 @@ void ImageViewer::updateFilter() {
13621380
const auto& buttons = mLayerButtonContainer->children();
13631381
for (Widget* button : buttons) {
13641382
ImageButton* ib = dynamic_cast<ImageButton*>(button);
1365-
ib->setVisible(matches(ib->caption(), layerPart));
1383+
ib->setVisible(matches(ib->caption(), layerPart, useRegex()));
13661384
if (ib->visible()) {
13671385
ib->setId(id++);
13681386
}
13691387
}
13701388

1371-
if (!matches(mCurrentLayer, layerPart)) {
1389+
if (!matches(mCurrentLayer, layerPart, useRegex())) {
13721390
selectLayer(nthVisibleLayer(0));
13731391
}
13741392
}
@@ -1383,6 +1401,7 @@ void ImageViewer::updateLayout() {
13831401
mSidebar->setFixedHeight(mSize.y() - footerHeight);
13841402

13851403
mHelpButton->setPosition(Vector2i{mSidebar->fixedWidth() - 38, 5});
1404+
mFilter->setFixedWidth(mSidebar->fixedWidth() - 50);
13861405
mSidebarLayout->setFixedWidth(mSidebar->fixedWidth());
13871406

13881407
mVerticalScreenSplit->setFixedSize(mSize);

0 commit comments

Comments
 (0)