aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk
diff options
context:
space:
mode:
authormarkt <markt>2007-03-03 19:35:34 (GMT)
committermarkt <markt>2007-03-03 19:35:34 (GMT)
commita233229bd854d2e925ca0f1e86846ff9fde46fcd (patch)
treea30fffa38994e8ee12096c31a256ba6b3fbfa2c6 /src/FbTk
parentd6a7bd786fd657e16c1ebad5c515d60ba1368d8a (diff)
downloadfluxbox-a233229bd854d2e925ca0f1e86846ff9fde46fcd.zip
fluxbox-a233229bd854d2e925ca0f1e86846ff9fde46fcd.tar.bz2
added support for typeahead in menus
Diffstat (limited to 'src/FbTk')
-rw-r--r--src/FbTk/ITypeAheadable.hh49
-rw-r--r--src/FbTk/Makefile.am1
-rw-r--r--src/FbTk/Menu.cc195
-rw-r--r--src/FbTk/Menu.hh17
-rw-r--r--src/FbTk/MenuItem.cc38
-rw-r--r--src/FbTk/MenuItem.hh15
-rw-r--r--src/FbTk/MenuTheme.cc4
-rw-r--r--src/FbTk/MenuTheme.hh7
-rw-r--r--src/FbTk/SearchResult.cc51
-rw-r--r--src/FbTk/SearchResult.hh53
-rw-r--r--src/FbTk/TypeAhead.hh174
11 files changed, 528 insertions, 76 deletions
diff --git a/src/FbTk/ITypeAheadable.hh b/src/FbTk/ITypeAheadable.hh
new file mode 100644
index 0000000..4a5b7cc
--- /dev/null
+++ b/src/FbTk/ITypeAheadable.hh
@@ -0,0 +1,49 @@
1// ITypeAheadable.hh for FbTk - Fluxbox Toolkit
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#ifndef FBTK_ITYPEAHEADABLE_HH
23#define FBTK_ITYPEAHEADABLE_HH
24
25#include <string>
26
27namespace FbTk {
28
29// abstract base class providing access and validation
30class ITypeAheadable {
31public:
32 virtual ~ITypeAheadable() { }
33
34 virtual const std::string &iTypeString() const = 0;
35 virtual bool isEnabled() { return true; }
36 char iTypeChar(size_t i) const { return iTypeString()[i]; }
37 bool iTypeCheckStringSize(size_t sz) const {
38 return (iTypeString().size() > sz);
39 }
40 bool iTypeCompareChar(char ch, size_t sz) const {
41 return (bool)iTypeCheckStringSize(sz) &&
42 tolower(iTypeChar(sz)) == tolower(ch);
43 }
44
45};
46
47} // end namespace FbTk
48
49#endif // FBTK_ITYPEAHEADABLE_HH
diff --git a/src/FbTk/Makefile.am b/src/FbTk/Makefile.am
index 5662370..fadc998 100644
--- a/src/FbTk/Makefile.am
+++ b/src/FbTk/Makefile.am
@@ -51,6 +51,7 @@ libFbTk_a_SOURCES = App.hh App.cc Color.cc Color.hh Command.hh \
51 MenuSeparator.hh MenuSeparator.cc \ 51 MenuSeparator.hh MenuSeparator.cc \
52 MenuIcon.hh MenuIcon.cc \ 52 MenuIcon.hh MenuIcon.cc \
53 stringstream.hh \ 53 stringstream.hh \
54 TypeAhead.hh SearchResult.hh SearchResult.cc ITypeAheadable.hh \
54 Select2nd.hh \ 55 Select2nd.hh \
55 CachedPixmap.hh CachedPixmap.cc \ 56 CachedPixmap.hh CachedPixmap.cc \
56 ${xpm_SOURCE} \ 57 ${xpm_SOURCE} \
diff --git a/src/FbTk/Menu.cc b/src/FbTk/Menu.cc
index e72b750..c60286a 100644
--- a/src/FbTk/Menu.cc
+++ b/src/FbTk/Menu.cc
@@ -110,6 +110,7 @@ Menu::Menu(MenuTheme &tm, ImageControl &imgctrl):
110 m_visible = false; 110 m_visible = false;
111 111
112 112
113 m_type_ahead.init(menuitems);
113 114
114 menu.x_move = 115 menu.x_move =
115 menu.y_move = 0; 116 menu.y_move = 0;
@@ -205,15 +206,24 @@ int Menu::insert(const FbString &label, Menu *submenu, int pos) {
205} 206}
206 207
207int Menu::insert(MenuItem *item, int pos) { 208int Menu::insert(MenuItem *item, int pos) {
209 if (item == 0)
210 return menuitems.size();
208 if (pos == -1) { 211 if (pos == -1) {
212 item->setIndex(menuitems.size());
209 menuitems.push_back(item); 213 menuitems.push_back(item);
210 } else { 214 } else {
211 menuitems.insert(menuitems.begin() + pos, item); 215 menuitems.insert(menuitems.begin() + pos, item);
216 fixMenuItemIndices();
212 } 217 }
213 m_need_update = true; // we need to redraw the menu 218 m_need_update = true; // we need to redraw the menu
214 return menuitems.size(); 219 return menuitems.size();
215} 220}
216 221
222void Menu::fixMenuItemIndices() {
223 for (size_t i = 0; i < menuitems.size(); i++)
224 menuitems[i]->setIndex(i);
225}
226
217int Menu::remove(unsigned int index) { 227int Menu::remove(unsigned int index) {
218 if (index >= menuitems.size()) { 228 if (index >= menuitems.size()) {
219#ifdef DEBUG 229#ifdef DEBUG
@@ -229,6 +239,9 @@ int Menu::remove(unsigned int index) {
229 239
230 if (item) { 240 if (item) {
231 menuitems.erase(it); 241 menuitems.erase(it);
242 // avoid O(n^2) algorithm with removeAll()
243 if (index != menuitems.size())
244 fixMenuItemIndices();
232 245
233 if (item->submenu() != 0) { 246 if (item->submenu() != 0) {
234 Menu *tmp = item->submenu(); 247 Menu *tmp = item->submenu();
@@ -257,10 +270,8 @@ int Menu::remove(unsigned int index) {
257} 270}
258 271
259void Menu::removeAll() { 272void Menu::removeAll() {
260 while (!menuitems.empty()) { 273 while (!menuitems.empty())
261 remove(0); 274 remove(menuitems.size()-1);
262 }
263 m_need_update = true;
264} 275}
265 276
266void Menu::raise() { 277void Menu::raise() {
@@ -271,55 +282,48 @@ void Menu::lower() {
271 menu.window.lower(); 282 menu.window.lower();
272} 283}
273 284
274void Menu::nextItem(int failsafe) { 285void Menu::cycleItems(bool reverse) {
275 if (menuitems.empty()) 286 Menuitems vec;
276 return; 287 if (m_type_ahead.stringSize())
277 288 vec = m_matches;
278 if (failsafe == -1) 289 else
279 failsafe = m_active_index; 290 vec = menuitems;
280 291
281 int old_active_index = m_active_index; 292 if (vec.size() < 1)
282 m_active_index += 1; 293 return;
283 if (!validIndex(m_active_index))
284 m_active_index = 0;
285 294
286 if (validIndex(old_active_index) && 295 // find the next item to select
287 menuitems[old_active_index] != 0) { 296 // this algorithm assumes menuitems are sorted properly
288 if (menuitems[old_active_index]->submenu()) { 297 int new_index = -1;
289 // we need to do this explicitly on the menu.window 298 bool passed = !validIndex(m_active_index);
290 // since it might hide the parent if we use Menu::hide 299 for (size_t i = 0; i < vec.size(); i++) {
291 menuitems[old_active_index]->submenu()->internal_hide(); 300 if (!isItemSelectable(vec[i]->getIndex()) ||
301 vec[i]->getIndex() == m_active_index)
302 continue;
303
304 // determine whether or not we've passed the active index
305 if (!passed && vec[i]->getIndex() > m_active_index) {
306 if (reverse && new_index != -1)
307 break;
308 passed = true;
292 } 309 }
293 clearItem(old_active_index);
294 }
295 310
296 if (menuitems[m_active_index] == 0) { 311 // decide if we want to keep this item
297 m_active_index = -1; 312 if (passed && !reverse) {
298 return; 313 new_index = vec[i]->getIndex();
299 } 314 break;
300 315 } else if (reverse || new_index == -1)
301 if (!isItemSelectable(m_active_index) && m_active_index != failsafe) { 316 new_index = vec[i]->getIndex();
302 nextItem(failsafe);
303 return;
304 } 317 }
305 318
306 clearItem(m_active_index); 319 if (new_index == -1)
307
308}
309
310void Menu::prevItem(int failsafe) {
311 if (menuitems.empty())
312 return; 320 return;
313 321
314 if (failsafe == -1) 322 // clear the items and close any open submenus
315 failsafe = m_active_index;
316
317 int old_active_index = m_active_index; 323 int old_active_index = m_active_index;
318 m_active_index -= 1; 324 m_active_index = new_index;
319 if (!validIndex(m_active_index)) 325 if (validIndex(old_active_index) &&
320 m_active_index = menuitems.size() - 1; 326 menuitems[old_active_index] != 0) {
321
322 if (validIndex(old_active_index)) {
323 if (menuitems[old_active_index]->submenu()) { 327 if (menuitems[old_active_index]->submenu()) {
324 // we need to do this explicitly on the menu.window 328 // we need to do this explicitly on the menu.window
325 // since it might hide the parent if we use Menu::hide 329 // since it might hide the parent if we use Menu::hide
@@ -327,19 +331,7 @@ void Menu::prevItem(int failsafe) {
327 } 331 }
328 clearItem(old_active_index); 332 clearItem(old_active_index);
329 } 333 }
330 334 clearItem(new_index);
331 if (menuitems[m_active_index] == 0) {
332 m_active_index = -1;
333 return;
334 }
335
336 if (!isItemSelectable(m_active_index) && m_active_index != failsafe) {
337 prevItem(failsafe);
338 return;
339 }
340
341 clearItem(m_active_index);
342
343} 335}
344 336
345void Menu::enterSubmenu() { 337void Menu::enterSubmenu() {
@@ -356,7 +348,7 @@ void Menu::enterSubmenu() {
356 drawSubmenu(m_active_index); 348 drawSubmenu(m_active_index);
357 submenu->grabInputFocus(); 349 submenu->grabInputFocus();
358 submenu->m_active_index = -1; // so we land on 0 after nextItem() 350 submenu->m_active_index = -1; // so we land on 0 after nextItem()
359 submenu->nextItem(); 351 submenu->cycleItems(false);
360} 352}
361 353
362void Menu::enterParent() { 354void Menu::enterParent() {
@@ -1024,34 +1016,59 @@ void Menu::keyPressEvent(XKeyEvent &event) {
1024 1016
1025 switch (ks) { 1017 switch (ks) {
1026 case XK_Up: 1018 case XK_Up:
1027 prevItem(); 1019 resetTypeAhead();
1020 cycleItems(true);
1028 break; 1021 break;
1029 case XK_Down: 1022 case XK_Down:
1030 nextItem(); 1023 resetTypeAhead();
1024 cycleItems(false);
1031 break; 1025 break;
1032 case XK_Left: // enter parent if we have one 1026 case XK_Left: // enter parent if we have one
1027 resetTypeAhead();
1033 enterParent(); 1028 enterParent();
1034 break; 1029 break;
1035 case XK_Right: // enter submenu if we have one 1030 case XK_Right: // enter submenu if we have one
1031 resetTypeAhead();
1036 enterSubmenu(); 1032 enterSubmenu();
1037 break; 1033 break;
1038 case XK_Escape: // close menu 1034 case XK_Escape: // close menu
1035 m_type_ahead.reset();
1039 hide(); 1036 hide();
1040 break; 1037 break;
1038 case XK_BackSpace:
1039 m_type_ahead.putBackSpace();
1040 drawTypeAheadItems();
1041 break;
1041 case XK_KP_Enter: 1042 case XK_KP_Enter:
1042 case XK_Return: 1043 case XK_Return:
1043 // send fake button 1 click 1044 resetTypeAhead();
1044 if (validIndex(m_active_index) && 1045 if (validIndex(m_active_index) &&
1045 isItemEnabled(m_active_index)) { 1046 isItemEnabled(m_active_index)) {
1046 if (event.state & ShiftMask) 1047 if (menuitems[m_active_index]->submenu() != 0)
1047 menuitems[m_active_index]->click(3, event.time); 1048 enterSubmenu();
1048 else 1049 else {
1049 menuitems[m_active_index]->click(1, event.time); 1050 // send fake button click
1050 m_need_update = true; 1051 int button = (event.state & ShiftMask) ? 3 : 1;
1051 updateMenu(); 1052 find(m_active_index)->click(button, event.time);
1053 m_need_update = true;
1054 updateMenu();
1055 }
1052 } 1056 }
1053 break; 1057 break;
1058 case XK_Tab:
1059 case XK_ISO_Left_Tab:
1060 m_type_ahead.seek();
1061 cycleItems((bool)(event.state & ShiftMask));
1062 drawTypeAheadItems();
1063 break;
1054 default: 1064 default:
1065 m_type_ahead.putCharacter(keychar[0]);
1066 // if current item doesn't match new search string, find the next one
1067 drawTypeAheadItems();
1068 if (!m_matches.empty() && (!validIndex(m_active_index) ||
1069 std::find(m_matches.begin(), m_matches.end(),
1070 find(m_active_index)) == m_matches.end()))
1071 cycleItems(false);
1055 break; 1072 break;
1056 } 1073 }
1057} 1074}
@@ -1151,7 +1168,7 @@ void Menu::renderForeground(FbWindow &win, FbDrawable &drawable) {
1151// thus sometimes it won't perform the actual clear operation 1168// thus sometimes it won't perform the actual clear operation
1152// nothing in here should be rendered transparently 1169// nothing in here should be rendered transparently
1153// (unless you use a caching pixmap, which I think we should avoid) 1170// (unless you use a caching pixmap, which I think we should avoid)
1154void Menu::clearItem(int index, bool clear) { 1171void Menu::clearItem(int index, bool clear, int search_index) {
1155 if (!validIndex(index)) 1172 if (!validIndex(index))
1156 return; 1173 return;
1157 1174
@@ -1160,9 +1177,16 @@ void Menu::clearItem(int index, bool clear) {
1160 int item_x = (sbl * item_w), item_y = (i * item_h); 1177 int item_x = (sbl * item_w), item_y = (i * item_h);
1161 bool highlight = (index == m_active_index && isItemSelectable(index)); 1178 bool highlight = (index == m_active_index && isItemSelectable(index));
1162 1179
1180 if (search_index < 0)
1181 // find if we need to underline the item
1182 search_index = std::find(m_matches.begin(), m_matches.end(),
1183 find(index)) - m_matches.begin();
1184
1163 // don't highlight if moving, doesn't work with alpha on 1185 // don't highlight if moving, doesn't work with alpha on
1164 if (highlight && !m_moving) { 1186 if (highlight && !m_moving) {
1165 highlightItem(index); 1187 highlightItem(index);
1188 if (search_index < (int)m_matches.size())
1189 drawLine(index, m_type_ahead.stringSize());
1166 return; 1190 return;
1167 } else if (clear) 1191 } else if (clear)
1168 menu.frame.clearArea(item_x, item_y, item_w, item_h); 1192 menu.frame.clearArea(item_x, item_y, item_w, item_h);
@@ -1173,6 +1197,9 @@ void Menu::clearItem(int index, bool clear) {
1173 item->draw(menu.frame, theme(), highlight, 1197 item->draw(menu.frame, theme(), highlight,
1174 true, false, item_x, item_y, 1198 true, false, item_x, item_y,
1175 item_w, item_h); 1199 item_w, item_h);
1200
1201 if (search_index < (int)m_matches.size())
1202 drawLine(index, m_type_ahead.stringSize());
1176} 1203}
1177 1204
1178// Area must have been cleared before calling highlight 1205// Area must have been cleared before calling highlight
@@ -1206,4 +1233,36 @@ void Menu::highlightItem(int index) {
1206 1233
1207} 1234}
1208 1235
1236void Menu::resetTypeAhead() {
1237 Menuitems vec = m_matches;
1238 Menuitems::iterator it = vec.begin();
1239 m_type_ahead.reset();
1240 m_matches.clear();
1241
1242 for (; it != vec.end(); it++)
1243 clearItem((*it)->getIndex(), true, 1);
1244}
1245
1246void Menu::drawTypeAheadItems() {
1247 // remove underlines from old matches
1248 for (size_t i = 0; i < m_matches.size(); i++)
1249 clearItem(m_matches[i]->getIndex(), true, m_matches.size());
1250
1251 m_matches = m_type_ahead.matched();
1252 for (size_t j = 0; j < m_matches.size(); j++)
1253 clearItem(m_matches[j]->getIndex(), false, j);
1254}
1255
1256// underline menuitem[index] with respect to matchstringsize size
1257void Menu::drawLine(int index, int size){
1258 if (!validIndex(index))
1259 return;
1260
1261 int sbl = index / menu.persub, i = index - (sbl * menu.persub);
1262 int item_x = (sbl * menu.item_w), item_y = (i * theme().itemHeight());
1263
1264 FbTk::MenuItem *item = find(index);
1265 item->drawLine(menu.frame, theme(), size, item_x, item_y, menu.item_w);
1266}
1267
1209}; // end namespace FbTk 1268}; // end namespace FbTk
diff --git a/src/FbTk/Menu.hh b/src/FbTk/Menu.hh
index 43b77a1..c77b0c0 100644
--- a/src/FbTk/Menu.hh
+++ b/src/FbTk/Menu.hh
@@ -41,6 +41,7 @@
41#include "MenuTheme.hh" 41#include "MenuTheme.hh"
42#include "Timer.hh" 42#include "Timer.hh"
43#include "FbString.hh" 43#include "FbString.hh"
44#include "TypeAhead.hh"
44 45
45namespace FbTk { 46namespace FbTk {
46 47
@@ -87,10 +88,8 @@ public:
87 virtual void raise(); 88 virtual void raise();
88 /// lower this window 89 /// lower this window
89 virtual void lower(); 90 virtual void lower();
90 /// select next item 91 /// cycle through menuitems
91 void nextItem(int failsafe = -1); 92 void cycleItems(bool reverse);
92 /// select previous item
93 void prevItem(int failsafe = -1);
94 void enterSubmenu(); 93 void enterSubmenu();
95 void enterParent(); 94 void enterParent();
96 95
@@ -186,7 +185,7 @@ protected:
186 int drawItem(FbDrawable &pm, unsigned int index, 185 int drawItem(FbDrawable &pm, unsigned int index,
187 bool highlight = false, 186 bool highlight = false,
188 bool exclusive_drawable = false); 187 bool exclusive_drawable = false);
189 void clearItem(int index, bool clear = true); 188 void clearItem(int index, bool clear = true, int search_index = -1);
190 void highlightItem(int index); 189 void highlightItem(int index);
191 virtual void redrawTitle(FbDrawable &pm); 190 virtual void redrawTitle(FbDrawable &pm);
192 virtual void redrawFrame(FbDrawable &pm); 191 virtual void redrawFrame(FbDrawable &pm);
@@ -209,6 +208,14 @@ private:
209 ImageControl &m_image_ctrl; 208 ImageControl &m_image_ctrl;
210 Menuitems menuitems; 209 Menuitems menuitems;
211 210
211 TypeAhead<Menuitems, MenuItem *> m_type_ahead;
212 Menuitems m_matches;
213
214 void resetTypeAhead();
215 void drawTypeAheadItems();
216 void drawLine(int index, int size);
217 void fixMenuItemIndices();
218
212 int m_screen_x, m_screen_y; 219 int m_screen_x, m_screen_y;
213 unsigned int m_screen_width, m_screen_height; 220 unsigned int m_screen_width, m_screen_height;
214 bool m_moving; ///< if we're moving/draging or not 221 bool m_moving; ///< if we're moving/draging or not
diff --git a/src/FbTk/MenuItem.cc b/src/FbTk/MenuItem.cc
index a2c3fe2..82dd155 100644
--- a/src/FbTk/MenuItem.cc
+++ b/src/FbTk/MenuItem.cc
@@ -38,6 +38,44 @@ void MenuItem::click(int button, int time) {
38 m_command->execute(); 38 m_command->execute();
39} 39}
40 40
41void MenuItem::drawLine(FbDrawable &draw, const MenuTheme &theme, size_t size,
42 int text_x, int text_y, unsigned int width) const {
43
44 unsigned int height = theme.itemHeight();
45 int bevelW = theme.bevelWidth();
46
47 int font_top = (height - theme.frameFont().height())/2;
48 int underline_height = font_top + theme.frameFont().ascent() + 2;
49 int bottom = height - bevelW - 1;
50
51 text_y += bottom > underline_height ? underline_height : bottom;
52 int text_w = theme.frameFont().textWidth(m_label.c_str(), m_label.size());
53
54 // width of the searchstring
55 size = size > m_label.length() ? m_label.length() : size;
56 std::string search_string = m_label.substr(0,size);
57 int search_string_w = theme.frameFont().textWidth(search_string.c_str(), size);
58
59 // pay attention to the text justification
60 switch(theme.frameFontJustify()) {
61 case FbTk::LEFT:
62 text_x += bevelW + height + 1;
63 break;
64 case FbTk::RIGHT:
65 text_x += width - (height + bevelW + text_w);
66 break;
67 default: //center
68 text_x += ((width + 1 - text_w) / 2);
69 break;
70 }
71
72 // avoid drawing an ugly dot
73 if (size != 0)
74 draw.drawLine(theme.frameUnderlineGC().gc(),
75 text_x, text_y, text_x + search_string_w, text_y);
76
77}
78
41void MenuItem::draw(FbDrawable &draw, 79void MenuItem::draw(FbDrawable &draw,
42 const MenuTheme &theme, 80 const MenuTheme &theme,
43 bool highlight, bool draw_foreground, bool draw_background, 81 bool highlight, bool draw_foreground, bool draw_background,
diff --git a/src/FbTk/MenuItem.hh b/src/FbTk/MenuItem.hh
index d73c270..701b624 100644
--- a/src/FbTk/MenuItem.hh
+++ b/src/FbTk/MenuItem.hh
@@ -27,6 +27,7 @@
27#include "RefCount.hh" 27#include "RefCount.hh"
28#include "Command.hh" 28#include "Command.hh"
29#include "PixmapWithMask.hh" 29#include "PixmapWithMask.hh"
30#include "ITypeAheadable.hh"
30#include "FbString.hh" 31#include "FbString.hh"
31 32
32#include <string> 33#include <string>
@@ -39,7 +40,7 @@ class MenuTheme;
39class FbDrawable; 40class FbDrawable;
40 41
41/// An interface for a menu item in Menu 42/// An interface for a menu item in Menu
42class MenuItem { 43class MenuItem : public FbTk::ITypeAheadable {
43public: 44public:
44 MenuItem() 45 MenuItem()
45 : m_label(""), 46 : m_label(""),
@@ -105,6 +106,17 @@ public:
105 virtual bool isEnabled() const { return m_enabled; } 106 virtual bool isEnabled() const { return m_enabled; }
106 virtual bool isSelected() const { return m_selected; } 107 virtual bool isSelected() const { return m_selected; }
107 virtual bool isToggleItem() const { return m_toggle_item; } 108 virtual bool isToggleItem() const { return m_toggle_item; }
109
110 // iType functions
111 virtual inline void setIndex(int index) { m_index = index; }
112 virtual inline int getIndex() { return m_index; }
113 inline const std::string &iTypeString() const { return m_label; }
114 virtual void drawLine(FbDrawable &draw,
115 const MenuTheme &theme,
116 size_t size,
117 int text_x, int text_y,
118 unsigned int width) const;
119
108 virtual unsigned int width(const MenuTheme &theme) const; 120 virtual unsigned int width(const MenuTheme &theme) const;
109 virtual unsigned int height(const MenuTheme &theme) const; 121 virtual unsigned int height(const MenuTheme &theme) const;
110 virtual void draw(FbDrawable &drawable, 122 virtual void draw(FbDrawable &drawable,
@@ -137,6 +149,7 @@ private:
137 RefCount<Command> m_command; ///< command to be executed 149 RefCount<Command> m_command; ///< command to be executed
138 bool m_enabled, m_selected; 150 bool m_enabled, m_selected;
139 bool m_toggle_item; 151 bool m_toggle_item;
152 int m_index;
140 153
141 struct Icon { 154 struct Icon {
142 std::auto_ptr<PixmapWithMask> pixmap; 155 std::auto_ptr<PixmapWithMask> pixmap;
diff --git a/src/FbTk/MenuTheme.cc b/src/FbTk/MenuTheme.cc
index c7b6d77..3b03697 100644
--- a/src/FbTk/MenuTheme.cc
+++ b/src/FbTk/MenuTheme.cc
@@ -44,6 +44,7 @@ MenuTheme::MenuTheme(int screen_num):
44 f_text(*this, "menu.frame.textColor", "Menu.Frame.TextColor"), 44 f_text(*this, "menu.frame.textColor", "Menu.Frame.TextColor"),
45 h_text(*this, "menu.hilite.textColor", "Menu.Hilite.TextColor"), 45 h_text(*this, "menu.hilite.textColor", "Menu.Hilite.TextColor"),
46 d_text(*this, "menu.frame.disableColor", "Menu.Frame.DisableColor"), 46 d_text(*this, "menu.frame.disableColor", "Menu.Frame.DisableColor"),
47 u_text(*this, "menu.frame.underlineColor", "Menu.Frame.UnderlineColor"),
47 title(*this, "menu.title", "Menu.Title"), 48 title(*this, "menu.title", "Menu.Title"),
48 frame(*this, "menu.frame", "Menu.Frame"), 49 frame(*this, "menu.frame", "Menu.Frame"),
49 hilite(*this, "menu.hilite", "Menu.Hilite"), 50 hilite(*this, "menu.hilite", "Menu.Hilite"),
@@ -67,6 +68,7 @@ MenuTheme::MenuTheme(int screen_num):
67 m_display(FbTk::App::instance()->display()), 68 m_display(FbTk::App::instance()->display()),
68 t_text_gc(RootWindow(m_display, screen_num)), 69 t_text_gc(RootWindow(m_display, screen_num)),
69 f_text_gc(RootWindow(m_display, screen_num)), 70 f_text_gc(RootWindow(m_display, screen_num)),
71 u_text_gc(RootWindow(m_display, screen_num)),
70 h_text_gc(RootWindow(m_display, screen_num)), 72 h_text_gc(RootWindow(m_display, screen_num)),
71 d_text_gc(RootWindow(m_display, screen_num)), 73 d_text_gc(RootWindow(m_display, screen_num)),
72 hilite_gc(RootWindow(m_display, screen_num)), 74 hilite_gc(RootWindow(m_display, screen_num)),
@@ -91,6 +93,7 @@ MenuTheme::MenuTheme(int screen_num):
91 93
92 t_text_gc.setForeground(*t_text); 94 t_text_gc.setForeground(*t_text);
93 f_text_gc.setForeground(*f_text); 95 f_text_gc.setForeground(*f_text);
96 u_text_gc.setForeground(*u_text);
94 h_text_gc.setForeground(*h_text); 97 h_text_gc.setForeground(*h_text);
95 d_text_gc.setForeground(*d_text); 98 d_text_gc.setForeground(*d_text);
96 hilite_gc.setForeground(hilite->color()); 99 hilite_gc.setForeground(hilite->color());
@@ -127,6 +130,7 @@ void MenuTheme::reconfigTheme() {
127 130
128 t_text_gc.setForeground(*t_text); 131 t_text_gc.setForeground(*t_text);
129 f_text_gc.setForeground(*f_text); 132 f_text_gc.setForeground(*f_text);
133 u_text_gc.setForeground(*u_text);
130 h_text_gc.setForeground(*h_text); 134 h_text_gc.setForeground(*h_text);
131 d_text_gc.setForeground(*d_text); 135 d_text_gc.setForeground(*d_text);
132 hilite_gc.setForeground(hilite->color()); 136 hilite_gc.setForeground(hilite->color());
diff --git a/src/FbTk/MenuTheme.hh b/src/FbTk/MenuTheme.hh
index da5b65c..0bb77ef 100644
--- a/src/FbTk/MenuTheme.hh
+++ b/src/FbTk/MenuTheme.hh
@@ -56,6 +56,7 @@ public:
56 ///@{ 56 ///@{
57 inline const FbTk::Color &titleTextColor() const { return *t_text; } 57 inline const FbTk::Color &titleTextColor() const { return *t_text; }
58 inline const FbTk::Color &frameTextColor() const { return *f_text; } 58 inline const FbTk::Color &frameTextColor() const { return *f_text; }
59 inline const FbTk::Color &frameUnderlineColor() const { return *u_text; }
59 inline const FbTk::Color &highlightTextColor() const { return *h_text; } 60 inline const FbTk::Color &highlightTextColor() const { return *h_text; }
60 inline const FbTk::Color &disableTextColor() const { return *d_text; } 61 inline const FbTk::Color &disableTextColor() const { return *d_text; }
61 ///@} 62 ///@}
@@ -94,11 +95,13 @@ public:
94 ///@{ 95 ///@{
95 inline const GContext &titleTextGC() const { return t_text_gc; } 96 inline const GContext &titleTextGC() const { return t_text_gc; }
96 inline const GContext &frameTextGC() const { return f_text_gc; } 97 inline const GContext &frameTextGC() const { return f_text_gc; }
98 inline const GContext &frameUnderlineGC() const { return u_text_gc; }
97 inline const GContext &hiliteTextGC() const { return h_text_gc; } 99 inline const GContext &hiliteTextGC() const { return h_text_gc; }
98 inline const GContext &disableTextGC() const { return d_text_gc; } 100 inline const GContext &disableTextGC() const { return d_text_gc; }
99 inline const GContext &hiliteGC() const { return hilite_gc; } 101 inline const GContext &hiliteGC() const { return hilite_gc; }
100 inline GContext &titleTextGC() { return t_text_gc; } 102 inline GContext &titleTextGC() { return t_text_gc; }
101 inline GContext &frameTextGC() { return f_text_gc; } 103 inline GContext &frameTextGC() { return f_text_gc; }
104 inline GContext &frameUnderlineGC() { return u_text_gc; }
102 inline GContext &hiliteTextGC() { return h_text_gc; } 105 inline GContext &hiliteTextGC() { return h_text_gc; }
103 inline GContext &disableTextGC() { return d_text_gc; } 106 inline GContext &disableTextGC() { return d_text_gc; }
104 inline GContext &hiliteGC() { return hilite_gc; } 107 inline GContext &hiliteGC() { return hilite_gc; }
@@ -139,7 +142,7 @@ public:
139 } 142 }
140 143
141private: 144private:
142 FbTk::ThemeItem<FbTk::Color> t_text, f_text, h_text, d_text; 145 FbTk::ThemeItem<FbTk::Color> t_text, f_text, h_text, d_text, u_text;
143 FbTk::ThemeItem<FbTk::Texture> title, frame, hilite; 146 FbTk::ThemeItem<FbTk::Texture> title, frame, hilite;
144 FbTk::ThemeItem<FbTk::Font> titlefont, framefont; 147 FbTk::ThemeItem<FbTk::Font> titlefont, framefont;
145 FbTk::ThemeItem<FbTk::Justify> framefont_justify, titlefont_justify; 148 FbTk::ThemeItem<FbTk::Justify> framefont_justify, titlefont_justify;
@@ -153,7 +156,7 @@ private:
153 FbTk::ThemeItem<FbTk::PixmapWithMask> m_hl_bullet_pixmap, m_hl_selected_pixmap, m_hl_unselected_pixmap; 156 FbTk::ThemeItem<FbTk::PixmapWithMask> m_hl_bullet_pixmap, m_hl_selected_pixmap, m_hl_unselected_pixmap;
154 157
155 Display *m_display; 158 Display *m_display;
156 FbTk::GContext t_text_gc, f_text_gc, h_text_gc, d_text_gc, hilite_gc; 159 FbTk::GContext t_text_gc, f_text_gc, u_text_gc, h_text_gc, d_text_gc, hilite_gc;
157 160
158 unsigned char m_alpha; 161 unsigned char m_alpha;
159 MenuMode m_menumode; 162 MenuMode m_menumode;
diff --git a/src/FbTk/SearchResult.cc b/src/FbTk/SearchResult.cc
new file mode 100644
index 0000000..3f36edc
--- /dev/null
+++ b/src/FbTk/SearchResult.cc
@@ -0,0 +1,51 @@
1// SearchResult.cc for FbTk - Fluxbox Toolkit
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#include "SearchResult.hh"
23#include <vector>
24
25namespace FbTk {
26
27void SearchResult::seek() {
28 switch (m_results.size()) {
29 case 0:
30 break;
31 case 1:
32 m_seeked_string = m_results[0]->iTypeString();
33 break;
34 default:
35 bool seekforward = true;
36 for (size_t i=1; i < m_results.size() && seekforward &&
37 m_results[0]->iTypeCheckStringSize(m_seeked_string.size()); i++) {
38 if (!m_results[i]->iTypeCompareChar(
39 m_results[0]->iTypeChar(m_seeked_string.size()),
40 m_seeked_string.size())) {
41 seekforward = false;
42 } else if (i == m_results.size() - 1) {
43 m_seeked_string += m_results[0]->iTypeChar(m_seeked_string.size());
44 i = 0;
45 }
46 }
47 break;
48 }
49}
50
51} // end namespace FbTk
diff --git a/src/FbTk/SearchResult.hh b/src/FbTk/SearchResult.hh
new file mode 100644
index 0000000..5e8852b
--- /dev/null
+++ b/src/FbTk/SearchResult.hh
@@ -0,0 +1,53 @@
1// SearchResult.hh for FbTk - Fluxbox Toolkit
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#ifndef FBTK_SEARCHRESULT_HH
23#define FBTK_SEARCHRESULT_HH
24
25#include <vector>
26#include "ITypeAheadable.hh"
27
28namespace FbTk {
29
30class SearchResult {
31public:
32 typedef std::vector < ITypeAheadable* > BaseItems;
33 typedef BaseItems::iterator BaseItemsIt;
34
35 SearchResult(const std::string &to_search_for):
36 m_seeked_string(to_search_for) { }
37
38 void add(ITypeAheadable* item) { m_results.push_back(item); }
39 size_t size() const { return m_results.size(); }
40 const BaseItems& result() const { return m_results; }
41 const std::string& seekedString() const { return m_seeked_string; }
42
43 void seek();
44
45private:
46 BaseItems m_results;
47 std::string m_seeked_string;
48
49};
50
51} // end namespace FbTk
52
53#endif // FBTK_SEARCHRESULT_HH
diff --git a/src/FbTk/TypeAhead.hh b/src/FbTk/TypeAhead.hh
new file mode 100644
index 0000000..15246b9
--- /dev/null
+++ b/src/FbTk/TypeAhead.hh
@@ -0,0 +1,174 @@
1// TypeAhead.hh for FbTk - Fluxbox Toolkit
2// Copyright (c) 2007 Fluxbox Team (fluxgen at fluxbox dot org)
3//
4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"),
6// to deal in the Software without restriction, including without limitation
7// the rights to use, copy, modify, merge, publish, distribute, sublicense,
8// and/or sell copies of the Software, and to permit persons to whom the
9// Software is furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE.
21
22#ifndef FBTK_TYPEAHEAD_HH
23#define FBTK_TYPEAHEAD_HH
24
25#include "ITypeAheadable.hh"
26#include <vector>
27#include "SearchResult.hh"
28
29namespace FbTk {
30
31template <typename Items, typename Item_Type>
32class TypeAhead {
33/*
34
35a class template can't be split into separate interface + implementation files, an interface summary is given here:
36
37public:
38 void init(Items const &items);
39
40// accessors:
41 inline int stringSize() const { return m_searchstr.size(); }
42 Items matched() const;
43
44// modifiers:
45 Items putCharacter(char ch);
46 void putBackSpace();
47 void reset()
48
49private:
50 SearchResults m_search_results;
51 std::string m_searchstr;
52 Items const *m_ref;
53
54// helper
55 void fillValues(BaseItems const &search, ValueVec &fillin) const;
56
57// reverts to searchstate before current
58 void revert();
59
60// search performs iteration and sets state
61 void search(char char_to_test);
62 void doSearch(char to_test,
63 Items const &items,
64 SearchResult &mySearchResult) const;
65 void doSearch(char to_test,
66 BaseItems const &search,
67 SearchResult &mySearchResult) const;
68*/
69
70public:
71 typedef std::vector < ITypeAheadable* > BaseItems;
72 typedef BaseItems::const_iterator BaseItemscIt;
73 typedef std::vector < SearchResult > SearchResults;
74 typedef typename Items::const_iterator ItemscIt;
75
76 void init(Items const &items) { m_ref = &items; }
77
78 inline size_t stringSize() const { return m_searchstr.size(); }
79
80 void seek() {
81 if (!m_search_results.empty())
82 m_searchstr = m_search_results.back().seekedString();
83 }
84
85 Items putCharacter(char ch) {
86 if (isprint(ch))
87 search(ch);
88 return matched();
89 }
90
91 void putBackSpace() {
92 if (!m_search_results.empty())
93 revert();
94 }
95
96 void reset() {
97 m_searchstr.clear();
98 m_search_results.clear();
99 }
100
101 Items matched() const {
102 Items last_matched;
103
104 if (!m_search_results.empty())
105 fillValues(m_search_results.back().result(), last_matched);
106 return last_matched;
107 }
108
109private:
110 SearchResults m_search_results;
111 std::string m_searchstr;
112 Items const *m_ref; // reference to vector we are operating on
113
114 void fillValues(BaseItems const &search, Items &fillin) const {
115 for (BaseItemscIt it = search.begin(); it != search.end(); it++) {
116 Item_Type tmp = dynamic_cast<Item_Type>(*it);
117 if (tmp)
118 fillin.push_back(tmp);
119 }
120 }
121
122 void revert() {
123 m_search_results.pop_back();
124 if (m_search_results.empty())
125 m_searchstr.clear();
126 else
127 m_searchstr = m_search_results.back().seekedString();
128 }
129
130 void search(char char_to_test) {
131 SearchResult mySearchResult(m_searchstr + char_to_test);
132 size_t num_items = m_ref->size();
133
134 // check if we have already a searched set
135 if (m_search_results.empty())
136 doSearch(char_to_test, *m_ref, mySearchResult);
137 else {
138 num_items = m_search_results.back().size();
139 doSearch(char_to_test, m_search_results.back().result(),
140 mySearchResult);
141 }
142
143 if (mySearchResult.size() > 0 ) {
144 if (mySearchResult.size() < num_items) {
145 mySearchResult.seek();
146 m_search_results.push_back(mySearchResult);
147 }
148 m_searchstr += char_to_test;
149 }
150 }
151
152 // iteration based on original list of items
153 void doSearch(char to_test, Items const &items,
154 SearchResult &mySearchResult) const {
155 for (ItemscIt it = items.begin(); it != items.end(); it++) {
156 if ((*it)->iTypeCompareChar(to_test, stringSize()) && (*it)->isEnabled())
157 mySearchResult.add(*it);
158 }
159 }
160
161 // iteration based on last SearchResult
162 void doSearch(char to_test, BaseItems const &search,
163 SearchResult &mySearchResult) const {
164 for (BaseItemscIt it = search.begin(); it != search.end(); it++) {
165 if ((*it)->iTypeCompareChar(to_test, stringSize()) && (*it)->isEnabled())
166 mySearchResult.add(*it);
167 }
168 }
169
170}; // end Class TypeAhead
171
172} // end namespace FbTk
173
174#endif // FBTK_TYPEAHEAD_HH