aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk/Menu.cc
diff options
context:
space:
mode:
authorMathias Gumz <akira@fluxbox.org>2015-02-05 20:30:44 (GMT)
committerMathias Gumz <akira@fluxbox.org>2015-02-05 20:30:44 (GMT)
commit0da4be2a0114d4419ceb70a4c6b6342f8fd79852 (patch)
tree371575758618de52415c823f756346cb3e1a5bb4 /src/FbTk/Menu.cc
parente79228cc08ee1d0d20d7ef27103a5d167fb8f133 (diff)
downloadfluxbox-0da4be2a0114d4419ceb70a4c6b6342f8fd79852.zip
fluxbox-0da4be2a0114d4419ceb70a4c6b6342f8fd79852.tar.bz2
Feature: different MenuSearch modes
Fluxbox now supports three MenuSearch modes: * NoWhere - essentially "disabling" the menu search. * Somewhere - the search string matches somewhere. * ItemStart - the search string matches at the start of a menu item. The default value is "ItemStart", just in the good old times. As long as this feature is not configurable via the menu it would irritate users with distinct muscle memory who type without thinking OR checking the visual feedback: they would trigger items they did not intent to trigger after years of the old behavior. Once this feature get's an entry in the config menu the default value might change.
Diffstat (limited to 'src/FbTk/Menu.cc')
-rw-r--r--src/FbTk/Menu.cc134
1 files changed, 1 insertions, 133 deletions
diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc
index 539c72c..cfbf049 100644
--- a/src/FbTk/Menu.cc
+++ b/src/FbTk/Menu.cc
@@ -69,143 +69,11 @@ void renderMenuPixmap(Pixmap& pm, FbTk::FbWindow* win, int width, int height, co
69 } 69 }
70} 70}
71 71
72
73// finds 'pattern' in 'text', case insensitive.
74// returns position or std::string::npos if not found.
75//
76// implements Boyer–Moore–Horspool
77size_t search_string(const std::string& text, const std::string& pattern) {
78
79 if (pattern.empty()) {
80 return 0;
81 }
82 if (text.empty() || pattern.size() > text.size()) {
83 return std::string::npos;
84 }
85
86 size_t t;
87 size_t tlen = text.size();
88
89 // simple case, no need to be too clever
90 if (pattern.size() == 1) {
91 int b = std::tolower(pattern[0]);
92 for (t = 0; t < tlen; t++) {
93 if (b == std::tolower(text[t])) {
94 return t;
95 }
96 }
97 return std::string::npos;
98 }
99
100
101 size_t plast = pattern.size() - 1;
102 size_t p;
103
104 // prepare skip-table
105 //
106 size_t skip[256];
107 for (p = 0; p < sizeof(skip)/sizeof(skip[0]); p++) {
108 skip[p] = plast + 1;
109 }
110 for (p = 0; p < plast; p++) {
111 skip[std::tolower(pattern[p])] = plast - p;
112 }
113
114 // match
115 for (t = 0; t + plast < tlen; ) {
116 for (p = plast; std::tolower(text[t+p]) == std::tolower(pattern[p]); p--) {
117 if (p == 0) {
118 return t+p;
119 }
120 }
121 t += skip[std::tolower(text[t+p])];
122 }
123
124 return std::string::npos;
125}
126
127} // end of anonymous namespace 72} // end of anonymous namespace
128 73
129 74
130namespace FbTk { 75namespace FbTk {
131 76
132// a small helper which applies search operations on a list of MenuItems*.
133// the former incarnation of this class was FbTk::TypeAhead in combination with
134// the now non-existent FbTk::SearchResults, but the complexity of these
135// are not needed for our use case. as a bonus we have less lose parts
136// flying around.
137class FbTk::Menu::TypeSearch {
138public:
139 TypeSearch(std::vector<FbTk::MenuItem*>& items) : m_items(items) { }
140
141 size_t size() const { return pattern.size(); }
142 void clear() { pattern.clear(); }
143 void add(char c) { pattern.push_back(c); }
144 void backspace() {
145 size_t s = pattern.size();
146 if (s > 0) {
147 pattern.erase(s - 1, 1);
148 }
149 }
150
151 // is 'pattern' matching something?
152 bool has_match() {
153 size_t l = m_items.size();
154 size_t i;
155 for (i = 0; i < l; i++) {
156 if (!m_items[i]->isEnabled())
157 continue;
158 if (search_string(m_items[i]->iTypeString(), pattern) != std::string::npos) {
159 return true;
160 }
161 }
162 return false;
163 }
164
165 // would 'the_pattern' match something?
166 bool would_match(const std::string& the_pattern) {
167 size_t l = m_items.size();
168 size_t i;
169 for (i = 0; i < l; i++) {
170 if (!m_items[i]->isEnabled())
171 continue;
172 if (search_string(m_items[i]->iTypeString(), the_pattern) != std::string::npos) {
173 return true;
174 }
175 }
176 return false;
177 }
178
179 size_t num_matches() {
180 size_t l = m_items.size();
181 size_t i, n;
182 for (i = 0, n = 0; i < l; i++) {
183 if (!m_items[i]->isEnabled())
184 continue;
185 if (search_string(m_items[i]->iTypeString(), pattern) != std::string::npos) {
186 n++;
187 }
188 }
189 return n;
190 }
191
192
193 // returns true if m_text matches against m_items[i] and stores
194 // the position where it matches in the string
195 bool get_match(size_t i, size_t& idx) {
196 if (i > m_items.size()) {
197 return false;
198 }
199 idx = search_string(m_items[i]->iTypeString(), pattern);
200 return idx != std::string::npos;
201 }
202
203 std::string pattern;
204private:
205 const std::vector<FbTk::MenuItem*>& m_items;
206};
207
208
209 77
210Menu* s_shown = 0; // if there's a menu open at all 78Menu* s_shown = 0; // if there's a menu open at all
211Menu* s_focused = 0; // holds currently focused menu 79Menu* s_focused = 0; // holds currently focused menu
@@ -250,7 +118,7 @@ Menu::Menu(FbTk::ThemeProxy<MenuTheme> &tm, ImageControl &imgctrl):
250 m_internal_menu = false; 118 m_internal_menu = false;
251 m_state.moving = m_state.closing = m_state.torn = m_state.visible = false; 119 m_state.moving = m_state.closing = m_state.torn = m_state.visible = false;
252 120
253 m_search.reset(new TypeSearch(m_items)); 121 m_search.reset(new MenuSearch(m_items));
254 122
255 m_x_move = m_y_move = 0; 123 m_x_move = m_y_move = 0;
256 m_which_sub = -1; 124 m_which_sub = -1;