aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk/MenuSearch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbTk/MenuSearch.cc')
-rw-r--r--src/FbTk/MenuSearch.cc221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/FbTk/MenuSearch.cc b/src/FbTk/MenuSearch.cc
new file mode 100644
index 0000000..da903f4
--- /dev/null
+++ b/src/FbTk/MenuSearch.cc
@@ -0,0 +1,221 @@
1#include "MenuSearch.hh"
2#include "MenuItem.hh"
3#include "StringUtil.hh"
4#include "Resource.hh"
5
6namespace {
7
8size_t search_str_nowhere(const std::string& text, const std::string& pattern) {
9 return std::string::npos;
10}
11
12// finds 'pattern' at beginning of 'text'
13size_t search_str_textstart(const std::string& text, const std::string& pattern) {
14
15 size_t l = std::min(text.size(), pattern.size());
16 if (l == 0) {
17 return std::string::npos;
18 }
19
20 size_t i;
21 for (i = l; i > 0; i--) {
22 if (std::tolower(text[i-1]) != std::tolower(pattern[i-1])) {
23 return std::string::npos;
24 }
25 }
26
27 return i;
28}
29
30// finds 'pattern' in 'text', case insensitive.
31// returns position or std::string::npos if not found.
32//
33// implements Boyer–Moore–Horspool
34size_t search_str_bmh(const std::string& text, const std::string& pattern) {
35
36 if (pattern.empty()) {
37 return 0;
38 }
39 if (text.empty() || pattern.size() > text.size()) {
40 return std::string::npos;
41 }
42
43 size_t t;
44 size_t tlen = text.size();
45
46 // simple case, no need to be too clever
47 if (pattern.size() == 1) {
48 int b = std::tolower(pattern[0]);
49 for (t = 0; t < tlen; t++) {
50 if (b == std::tolower(text[t])) {
51 return t;
52 }
53 }
54 return std::string::npos;
55 }
56
57
58 size_t plast = pattern.size() - 1;
59 size_t p;
60
61 // prepare skip-table
62 //
63 size_t skip[256];
64 for (p = 0; p < sizeof(skip)/sizeof(skip[0]); p++) {
65 skip[p] = plast + 1;
66 }
67 for (p = 0; p < plast; p++) {
68 skip[std::tolower(pattern[p])] = plast - p;
69 }
70
71 // match
72 for (t = 0; t + plast < tlen; ) {
73 for (p = plast; std::tolower(text[t+p]) == std::tolower(pattern[p]); p--) {
74 if (p == 0) {
75 return t+p;
76 }
77 }
78 t += skip[std::tolower(text[t+p])];
79 }
80
81 return std::string::npos;
82}
83
84
85// actually search function, depends on Mode
86size_t (*search_str)(const std::string&, const std::string&) = search_str_textstart;
87
88} // anonymous
89
90
91
92namespace FbTk {
93
94
95void MenuSearch::setMode(MenuSearch::Mode m) {
96 if (m == NOWHERE) {
97 search_str = search_str_nowhere;
98 } else if (m == SOMEWHERE) {
99 search_str = search_str_bmh;
100 } else {
101 search_str = search_str_textstart;
102 }
103}
104
105
106
107MenuSearch::MenuSearch(const std::vector<FbTk::MenuItem*>& items) :
108 m_items(items) {
109}
110
111size_t MenuSearch::size() const {
112 return pattern.size();
113}
114
115void MenuSearch::clear() {
116 pattern.clear();
117}
118
119void MenuSearch::add(char c) {
120 pattern.push_back(c);
121}
122
123void MenuSearch::backspace() {
124 size_t s = pattern.size();
125 if (s > 0) {
126 pattern.erase(s - 1, 1);
127 }
128}
129
130// is 'pattern' matching something?
131bool MenuSearch::has_match() {
132 size_t l = m_items.size();
133 size_t i;
134 for (i = 0; i < l; i++) {
135 if (!m_items[i]->isEnabled())
136 continue;
137 if (search_str(m_items[i]->iTypeString(), pattern) != std::string::npos) {
138 return true;
139 }
140 }
141 return false;
142}
143
144// would 'the_pattern' match something?
145bool MenuSearch::would_match(const std::string& the_pattern) {
146 size_t l = m_items.size();
147 size_t i;
148 for (i = 0; i < l; i++) {
149 if (!m_items[i]->isEnabled())
150 continue;
151 if (search_str(m_items[i]->iTypeString(), the_pattern) != std::string::npos) {
152 return true;
153 }
154 }
155 return false;
156}
157
158size_t MenuSearch::num_matches() {
159 size_t l = m_items.size();
160 size_t i, n;
161 for (i = 0, n = 0; i < l; i++) {
162 if (!m_items[i]->isEnabled())
163 continue;
164 if (search_str(m_items[i]->iTypeString(), pattern) != std::string::npos) {
165 n++;
166 }
167 }
168 return n;
169}
170
171
172// returns true if m_text matches against m_items[i] and stores
173// the position where it matches in the string. an empty
174// 'pattern' always matches
175bool MenuSearch::get_match(size_t i, size_t& idx) {
176 if (i > m_items.size()) {
177 return false;
178 }
179
180 if (pattern.empty())
181 return true;
182
183 idx = search_str(m_items[i]->iTypeString(), pattern);
184 return idx != std::string::npos;
185}
186
187
188
189
190//
191// resource-implementation related
192
193template<>
194std::string FbTk::Resource<FbTk::MenuSearch::Mode>::getString() const {
195
196 switch (m_value) {
197 case FbTk::MenuSearch::NOWHERE:
198 return "nowhere";
199 case FbTk::MenuSearch::SOMEWHERE:
200 return "somewhere";
201 default:
202 return "itemstart";
203 };
204}
205
206template<>
207void FbTk::Resource<FbTk::MenuSearch::Mode>::setFromString(const char *strval) {
208
209 std::string val = FbTk::StringUtil::toLower(strval);
210 if (val == "nowhere") {
211 m_value = FbTk::MenuSearch::NOWHERE;
212 } else if (val == "somewhere") {
213 m_value = FbTk::MenuSearch::SOMEWHERE;
214 } else {
215 setDefaultValue();
216 }
217
218 std::cerr << "** " << val << " " << m_value << "\n";
219}
220
221}