aboutsummaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorfluxgen <fluxgen>2003-06-24 10:22:42 (GMT)
committerfluxgen <fluxgen>2003-06-24 10:22:42 (GMT)
commit489af9787c89c1ee390deb39b280fcc7df727f93 (patch)
tree181829f163cdae9216ada83761fc8cb235a687dc /util
parentfc5de0455e1d99b6b89168ab3c9b973360791d68 (diff)
downloadfluxbox-489af9787c89c1ee390deb39b280fcc7df727f93.zip
fluxbox-489af9787c89c1ee390deb39b280fcc7df727f93.tar.bz2
emacs keybindings and tab completion, thanks David J Burger
Diffstat (limited to 'util')
-rw-r--r--util/fbrun/FbRun.cc279
-rw-r--r--util/fbrun/FbRun.hh26
2 files changed, 242 insertions, 63 deletions
diff --git a/util/fbrun/FbRun.cc b/util/fbrun/FbRun.cc
index 992255f..334414b 100644
--- a/util/fbrun/FbRun.cc
+++ b/util/fbrun/FbRun.cc
@@ -1,5 +1,5 @@
1// FbRun.hh 1// FbRun.cc
2// Copyright (c) 2002 Henrik Kinnunen (fluxgen@linuxmail.org) 2// Copyright (c) 2002-2003 Henrik Kinnunen (fluxgen<at>users.sourceforge.net)
3// 3//
4// Permission is hereby granted, free of charge, to any person obtaining a 4// Permission is hereby granted, free of charge, to any person obtaining a
5// copy of this software and associated documentation files (the "Software"), 5// copy of this software and associated documentation files (the "Software"),
@@ -19,7 +19,7 @@
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE. 20// DEALINGS IN THE SOFTWARE.
21 21
22// $Id: FbRun.cc,v 1.11 2003/04/27 02:26:21 rathnor Exp $ 22// $Id: FbRun.cc,v 1.12 2003/06/24 10:22:42 fluxgen Exp $
23 23
24#include "FbRun.hh" 24#include "FbRun.hh"
25 25
@@ -50,13 +50,17 @@ FbRun::FbRun(int x, int y, size_t width):
50 m_end(false), 50 m_end(false),
51 m_current_history_item(0), 51 m_current_history_item(0),
52 m_cursor(XCreateFontCursor(FbTk::App::instance()->display(), XC_xterm)), 52 m_cursor(XCreateFontCursor(FbTk::App::instance()->display(), XC_xterm)),
53 m_cursor_pos(0) { 53 m_start_pos(0),
54 XDefineCursor(FbTk::App::instance()->display(), m_win.window(), m_cursor); 54 m_end_pos(0),
55 m_cursor_pos(0)
56{
57 m_win.setCursor(m_cursor);
55 // setting nomaximize in local resize 58 // setting nomaximize in local resize
56 resize(width, m_font.height()); 59 resize(width, m_font.height());
57 FbTk::EventManager::instance()->registerEventHandler(*this, m_win.window()); 60 FbTk::EventManager::instance()->registerEventHandler(*this, m_win.window());
58} 61}
59 62
63
60FbRun::~FbRun() { 64FbRun::~FbRun() {
61 hide(); 65 hide();
62 FbTk::EventManager::instance()->unregisterEventHandler(m_win.window()); 66 FbTk::EventManager::instance()->unregisterEventHandler(m_win.window());
@@ -71,7 +75,7 @@ void FbRun::run(const std::string &command) {
71 } 75 }
72 76
73 hide(); // hide gui 77 hide(); // hide gui
74 78
75 // save command history to file 79 // save command history to file
76 if (m_runtext.size() != 0) { // no need to save empty command 80 if (m_runtext.size() != 0) { // no need to save empty command
77 // open file in append mode 81 // open file in append mode
@@ -129,7 +133,6 @@ void FbRun::setBackground(const FbTk::Color &color) {
129 redrawLabel(); 133 redrawLabel();
130} 134}
131 135
132
133void FbRun::setText(const string &text) { 136void FbRun::setText(const string &text) {
134 m_runtext = text; 137 m_runtext = text;
135 redrawLabel(); 138 redrawLabel();
@@ -144,7 +147,7 @@ void FbRun::move(int x, int y) {
144} 147}
145 148
146void FbRun::resize(size_t width, size_t height) { 149void FbRun::resize(size_t width, size_t height) {
147 m_win.resize(width, height); 150 m_win.resize(width, height);
148 setNoMaximize(); 151 setNoMaximize();
149} 152}
150 153
@@ -167,49 +170,79 @@ void FbRun::drawString(int x, int y,
167 const char *text, size_t len) { 170 const char *text, size_t len) {
168 assert(m_gc); 171 assert(m_gc);
169 172
170 // check right boundary and adjust text drawing 173 m_font.drawText(m_win.window(), DefaultScreen(m_display), m_gc, text + m_start_pos, m_end_pos - m_start_pos, x, y - 2);
171 size_t text_width = m_font.textWidth(text, len);
172 size_t startpos = 0;
173 if (text_width > m_win.width()) {
174 for (; startpos < len; ++startpos) {
175 if (m_font.textWidth(text+startpos, len-startpos) < m_win.width())
176 break;
177 }
178 }
179
180 m_font.drawText(m_win.window(), DefaultScreen(m_display), m_gc, text + startpos, len-startpos, x, y - 2);
181 int cursor_pos = m_font.textWidth(text + m_cursor_pos, len - startpos) + 1;
182 // draw cursor position 174 // draw cursor position
183 XDrawLine(FbTk::App::instance()->display(), m_win.window(), m_gc, 175 int cursor_pos = m_font.textWidth(text + m_start_pos, m_cursor_pos) + 1;
184 cursor_pos, 0, 176 m_win.drawLine(m_gc, cursor_pos, 0, cursor_pos, m_font.height());
185 cursor_pos, m_font.height());
186} 177}
187 178
188void FbRun::keyPressEvent(XKeyEvent &ke) { 179void FbRun::keyPressEvent(XKeyEvent &ke) {
189 KeySym ks; 180 KeySym ks;
190 char keychar[1]; 181 char keychar[1];
191 XLookupString(&ke, keychar, 1, &ks, 0); 182 XLookupString(&ke, keychar, 1, &ks, 0);
192 if (ks == XK_Escape) { 183 // a modifier key by itself doesn't do anything
193 m_end = true; 184 if (IsModifierKey(ks)) return;
194 hide(); 185
195 FbTk::App::instance()->end(); // end program 186 if (ke.state) { // a modifier key is down
196 } else if (ks == XK_Return) { 187 if (ke.state == ControlMask) {
197 run(m_runtext); 188 switch (ks) {
198 m_runtext = ""; // clear text 189 case XK_b:
199 } else if (ks == XK_BackSpace) { 190 cursorLeft();
200 if (m_runtext.size() != 0) { // we can't erase what we don't have ;) 191 break;
201 m_runtext.erase(m_runtext.size()-1); 192 case XK_f:
202 redrawLabel(); 193 cursorRight();
203 m_cursor_pos--; 194 break;
195 case XK_p:
196 prevHistoryItem();
197 break;
198 case XK_n:
199 nextHistoryItem();
200 break;
201 case XK_a:
202 cursorHome();
203 break;
204 case XK_e:
205 cursorEnd();
206 break;
207 case XK_d:
208 deleteForward();
209 break;
210 case XK_k:
211 killToEnd();
212 break;
213 }
214 } else if (ke.state == (Mod1Mask | ShiftMask)) {
215 switch (ks) {
216 case XK_less:
217 firstHistoryItem();
218 break;
219 case XK_greater:
220 lastHistoryItem();
221 break;
222 }
223 } else if (ke.state == ShiftMask) {
224 if (isprint(keychar[0]))insertCharacter(ks, keychar);
204 } 225 }
205 } else if (! IsModifierKey(ks) && !IsCursorKey(ks)) { // insert normal character at cursor pos 226 } else { // no modifier key
206 char in_char[2] = {keychar[0], 0};
207 m_runtext.insert(m_cursor_pos, in_char);
208 m_cursor_pos++;
209 redrawLabel();
210 } else if (IsCursorKey(ks)) {
211
212 switch (ks) { 227 switch (ks) {
228 case XK_Escape:
229 m_end = true;
230 hide();
231 FbTk::App::instance()->end(); // end program
232 break;
233 case XK_Return:
234 run(m_runtext);
235 m_runtext = ""; // clear text
236 break;
237 case XK_BackSpace:
238 backspace();
239 break;
240 case XK_Home:
241 cursorHome();
242 break;
243 case XK_End:
244 cursorEnd();
245 break;
213 case XK_Up: 246 case XK_Up:
214 prevHistoryItem(); 247 prevHistoryItem();
215 break; 248 break;
@@ -222,18 +255,20 @@ void FbRun::keyPressEvent(XKeyEvent &ke) {
222 case XK_Right: 255 case XK_Right:
223 cursorRight(); 256 cursorRight();
224 break; 257 break;
258 case XK_Tab:
259 tabCompleteHistory();
260 break;
261 default:
262 if (isprint(keychar[0])) insertCharacter(ks, keychar);
225 } 263 }
226 redrawLabel();
227 } else if (ks == XK_End) {
228 m_cursor_pos = m_runtext.size() - 1;
229 } 264 }
265 redrawLabel();
230} 266}
231 267
232void FbRun::exposeEvent(XExposeEvent &ev) { 268void FbRun::exposeEvent(XExposeEvent &ev) {
233 redrawLabel(); 269 redrawLabel();
234} 270}
235 271
236
237void FbRun::setNoMaximize() { 272void FbRun::setNoMaximize() {
238 // we don't need to maximize this window 273 // we don't need to maximize this window
239 XSizeHints sh; 274 XSizeHints sh;
@@ -246,32 +281,160 @@ void FbRun::setNoMaximize() {
246} 281}
247 282
248void FbRun::prevHistoryItem() { 283void FbRun::prevHistoryItem() {
249 284 if (m_history.size() == 0 || m_current_history_item == 0) {
250 if (m_current_history_item > 0 && m_history.size() > 0) 285 XBell(m_display, 0);
286 } else {
251 m_current_history_item--; 287 m_current_history_item--;
252 if (m_current_history_item < m_history.size())
253 m_runtext = m_history[m_current_history_item]; 288 m_runtext = m_history[m_current_history_item];
289 m_cursor_pos = m_end_pos = m_runtext.size();
290 adjustStartPos();
291 }
254} 292}
255 293
256void FbRun::nextHistoryItem() { 294void FbRun::nextHistoryItem() {
257 m_current_history_item++; 295 if (m_current_history_item == m_history.size()) {
258 if (m_current_history_item >= m_history.size()) { 296 XBell(m_display, 0);
259 m_current_history_item = m_history.size(); 297 } else {
260 m_runtext = ""; 298 m_current_history_item++;
261 return; 299 if (m_current_history_item == m_history.size()) {
262 } else 300 m_current_history_item = m_history.size();
301 m_runtext = "";
302 m_start_pos = m_cursor_pos = m_end_pos = 0;
303 } else {
304 m_runtext = m_history[m_current_history_item];
305 m_cursor_pos = m_end_pos = m_runtext.size();
306 adjustStartPos();
307 }
308 }
309}
310
311void FbRun::firstHistoryItem() {
312 if (m_history.size() == 0 || m_current_history_item == 0) {
313 XBell(m_display, 0);
314 } else {
315 m_current_history_item = 0;
263 m_runtext = m_history[m_current_history_item]; 316 m_runtext = m_history[m_current_history_item];
317 m_cursor_pos = m_end_pos = m_runtext.size();
318 adjustStartPos();
319 }
320}
264 321
322void FbRun::lastHistoryItem() {
323 // actually one past the end
324 if (m_history.size() == 0) {
325 XBell(m_display, 0);
326 } else {
327 m_current_history_item = m_history.size();
328 m_runtext = "";
329 m_start_pos = m_cursor_pos = m_end_pos = 0;
330 }
265} 331}
266 332
333void FbRun::tabCompleteHistory() {
334 if (m_current_history_item == 0) {
335 XBell(m_display, 0);
336 } else {
337 int history_item = m_current_history_item - 1;
338 string prefix = m_runtext.substr(0, m_cursor_pos);
339 while (history_item > - 1) {
340 if (m_history[history_item].find(prefix) == 0) {
341 m_current_history_item = history_item;
342 m_runtext = m_history[m_current_history_item];
343 adjustEndPos();
344 break;
345 }
346 history_item--;
347 }
348 if (history_item == -1) XBell(m_display, 0);
349 }
350}
267 351
268void FbRun::cursorLeft() { 352void FbRun::cursorLeft() {
269 if (m_cursor_pos > 0) 353 if (m_cursor_pos)
270 m_cursor_pos--; 354 m_cursor_pos--;
355 else if (m_start_pos) {
356 m_start_pos--;
357 adjustEndPos();
358 }
271} 359}
272 360
273void FbRun::cursorRight() { 361void FbRun::cursorRight() {
362 if (m_start_pos + m_cursor_pos < m_end_pos)
363 m_cursor_pos++;
364 else if (m_end_pos < m_runtext.size()) {
365 m_cursor_pos++;
366 m_end_pos++;
367 adjustStartPos();
368 }
369}
370
371void FbRun::cursorHome() {
372 m_start_pos = m_cursor_pos = 0;
373 adjustEndPos();
374}
375
376void FbRun::cursorEnd() {
377 m_cursor_pos = m_end_pos = m_runtext.size();
378 adjustStartPos();
379}
380
381void FbRun::backspace() {
382 if (m_start_pos || m_cursor_pos) {
383 m_runtext.erase(m_start_pos + m_cursor_pos - 1, 1);
384 if (m_cursor_pos)
385 m_cursor_pos--;
386 else
387 m_start_pos--;
388 adjustEndPos();
389 }
390}
391
392void FbRun::deleteForward() {
393 if (m_start_pos + m_cursor_pos < m_end_pos) {
394 m_runtext.erase(m_start_pos + m_cursor_pos, 1);
395 adjustEndPos();
396 }
397}
398
399void FbRun::killToEnd() {
400 if (m_start_pos + m_cursor_pos < m_end_pos) {
401 m_runtext.erase(m_start_pos + m_cursor_pos);
402 adjustEndPos();
403 }
404}
405
406void FbRun::insertCharacter(KeySym ks, char *keychar) {
407 char in_char[2] = {keychar[0], 0};
408 m_runtext.insert(m_start_pos + m_cursor_pos, in_char);
274 m_cursor_pos++; 409 m_cursor_pos++;
275 if (m_cursor_pos >= m_runtext.size()) 410 m_end_pos++;
276 m_cursor_pos = m_runtext.size() - 1; 411 if (m_start_pos + m_cursor_pos < m_end_pos)
412 adjustEndPos();
413 else
414 adjustStartPos();
415}
416
417void FbRun::adjustEndPos() {
418 m_end_pos = m_runtext.size();
419 const char *text = m_runtext.c_str();
420 int text_width = m_font.textWidth(text + m_start_pos, m_end_pos - m_start_pos);
421 while (text_width > m_win.width()) {
422 m_end_pos--;
423 text_width = m_font.textWidth(text + m_start_pos, m_end_pos - m_start_pos);
424 }
425}
426
427void FbRun::adjustStartPos() {
428 const char *text = m_runtext.c_str();
429 int text_width = m_font.textWidth(text + m_start_pos, m_end_pos - m_start_pos);
430 if (text_width < m_win.width()) return;
431 int start_pos = 0;
432 text_width = m_font.textWidth(text + start_pos, m_end_pos - start_pos);
433 while (text_width > m_win.width()) {
434 start_pos++;
435 text_width = m_font.textWidth(text + start_pos, m_end_pos - start_pos);
436 }
437 // adjust m_cursor_pos according relative to change to m_start_pos
438 m_cursor_pos -= start_pos - m_start_pos;
439 m_start_pos = start_pos;
277} 440}
diff --git a/util/fbrun/FbRun.hh b/util/fbrun/FbRun.hh
index 29a9afd..a92ca90 100644
--- a/util/fbrun/FbRun.hh
+++ b/util/fbrun/FbRun.hh
@@ -19,7 +19,7 @@
19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20// DEALINGS IN THE SOFTWARE. 20// DEALINGS IN THE SOFTWARE.
21 21
22// $Id: FbRun.hh,v 1.9 2003/03/22 11:31:43 fluxgen Exp $ 22// $Id: FbRun.hh,v 1.10 2003/06/24 10:22:42 fluxgen Exp $
23 23
24#ifndef FBRUN_HH 24#ifndef FBRUN_HH
25#define FBRUN_HH 25#define FBRUN_HH
@@ -71,7 +71,7 @@ public:
71 void exposeEvent(XExposeEvent &ev); 71 void exposeEvent(XExposeEvent &ev);
72 void keyPressEvent(XKeyEvent &ev); 72 void keyPressEvent(XKeyEvent &ev);
73 ///@} 73 ///@}
74 74
75private: 75private:
76 void nextHistoryItem(); 76 void nextHistoryItem();
77 void prevHistoryItem(); 77 void prevHistoryItem();
@@ -79,11 +79,23 @@ private:
79 void cursorRight(); 79 void cursorRight();
80 void drawString(int x, int y, const char *text, size_t len); 80 void drawString(int x, int y, const char *text, size_t len);
81 void getSize(size_t &width, size_t &height); 81 void getSize(size_t &width, size_t &height);
82 void createWindow(int x, int y, size_t width, size_t height); 82 void createWindow(int x, int y, size_t width, size_t height);
83 void redrawLabel(); 83 void redrawLabel();
84 /// set no maximizable for this window 84 /// set no maximizable for this window
85 void setNoMaximize(); 85 void setNoMaximize();
86 86
87 void cursorHome();
88 void cursorEnd();
89 void backspace();
90 void deleteForward();
91 void killToEnd();
92 void insertCharacter(KeySym ks, char *keychar);
93 void adjustStartPos();
94 void adjustEndPos();
95 void firstHistoryItem();
96 void lastHistoryItem();
97 void tabCompleteHistory();
98
87 FbTk::Font m_font; ///< font used to draw command text 99 FbTk::Font m_font; ///< font used to draw command text
88 FbTk::FbWindow m_win; ///< toplevel window 100 FbTk::FbWindow m_win; ///< toplevel window
89 Display *m_display; ///< display connection 101 Display *m_display; ///< display connection
@@ -95,7 +107,11 @@ private:
95 size_t m_current_history_item; ///< holds current position in command history 107 size_t m_current_history_item; ///< holds current position in command history
96 std::string m_history_file; ///< holds filename for command history file 108 std::string m_history_file; ///< holds filename for command history file
97 Cursor m_cursor; 109 Cursor m_cursor;
98 int m_cursor_pos; 110
111 int m_start_pos; ///< start position of portion of text to display
112 int m_cursor_pos; ///< relative to m_start_pos
113 int m_end_pos; ///< end postition of portion of text to display
114
99}; 115};
100 116
101#endif // FBRUN_HH 117#endif // FBRUN_HH