diff --git a/event.c b/event.c index 446c73f..c1a08c5 100644 --- a/event.c +++ b/event.c @@ -131,11 +131,10 @@ void key_press(XEvent *ev) unsigned int state = e->state & ~(LockMask|NumlockMask); while (XCheckTypedEvent(display, KeyPress, ev)); - int i, j; Monitor *m; - for_monitors(i, m) for_spots(j) if (menu && menu->mb && menu->mb->window == e->window) + if (menu && menu->mb && menu->mb->window == e->window) { int rc = menubox_keypress(menu->mb, ev); - menubox_draw(menu->mb); + menu_update(); if (rc == -2) menu_close(); diff --git a/menu.c b/menu.c index cc67134..bc2b6d4 100644 --- a/menu.c +++ b/menu.c @@ -29,7 +29,6 @@ void menu_update() if (menu->mb) { menubox_draw(menu->mb); - menubox_show(menu->mb); } } @@ -55,12 +54,17 @@ void menu_select() if (menu->mb) { id = menubox_get_id(menu->mb); - if ((c = window_build_client(menu->items[id].window)) && c) + if (id >= 0 && (c = window_build_client(menu->items[id].window)) && c) { if (c->manage) client_activate(c); client_free(c); } + else + if (strlen(menu->mb->input->text)) + { + exec_cmd(menu->mb->input->text); + } menu_close(); } } @@ -116,7 +120,7 @@ void menu_create(int spot, int mon) menubox_moveresize(mb, x, y, w, h); menubox_key_down(mb); - menubox_draw(mb); menubox_show(mb); + menubox_draw(mb); menubox_grab(mb); } \ No newline at end of file diff --git a/menubox.c b/menubox.c index c237b5e..0dc421a 100644 --- a/menubox.c +++ b/menubox.c @@ -26,7 +26,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define MB_AUTOHEIGHT 1<<0 #define MB_AUTOWIDTH 1<<1 -#define MB_SELECTABLE 1<<2 #define MB_MINWIDTH 1<<3 typedef struct { @@ -37,8 +36,8 @@ typedef struct { unsigned int box_count, box_active; Textbox **boxes; int *ids; - XIM xim; - XIC xic; + int *show; + Textbox *input; } Menubox; void menubox_moveresize(Menubox*, short, short, short, short); @@ -49,6 +48,7 @@ Menubox* menubox_create(Window parent, unsigned long flags, short x, short y, sh Menubox *mb = calloc(1, sizeof(Menubox)); mb->boxes = (Textbox**) calloc(1, sizeof(Textbox)); mb->ids = (int*) calloc(1, sizeof(int)); + mb->show = (int*) calloc(1, sizeof(int)); mb->flags = flags; mb->parent = parent; @@ -68,18 +68,12 @@ Menubox* menubox_create(Window parent, unsigned long flags, short x, short y, sh mb->window = XCreateSimpleWindow(display, mb->parent, mb->x, mb->y, mb->w, mb->h, 0, None, cp); // calc line height - Textbox *lb = textbox_create(mb->window, TB_AUTOHEIGHT, 0, 0, 0, 0, mb->font, mb->fg_blur, mb->bg_blur, "a", NULL); - mb->line_height = lb->h; textbox_free(lb); + mb->input = textbox_create(mb->window, TB_AUTOHEIGHT|TB_EDITABLE, mb->padding, mb->padding, mb->w, 0, mb->font, mb->fg_blur, mb->bg_blur, "", "> "); + mb->line_height = mb->input->h; // auto height/width modes get handled here menubox_moveresize(mb, mb->x, mb->y, mb->w, mb->h); - if (MB_SELECTABLE) - { - mb->xim = XOpenIM(display, NULL, NULL, NULL); - mb->xic = XCreateIC(mb->xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, mb->window, XNFocusWindow, mb->window, NULL); - } - return mb; } @@ -88,7 +82,7 @@ void menubox_moveresize(Menubox *mb, short x, short y, short w, short h) int ow = w; if (mb->flags & MB_AUTOHEIGHT) - h = mb->box_count * mb->line_height + (mb->padding*2); + h = (mb->box_count+1) * mb->line_height + (mb->padding*2); if (mb->flags & MB_AUTOWIDTH) { @@ -115,9 +109,14 @@ void menubox_add(Menubox *mb, int id, char *text) mb->boxes = (Textbox**) realloc(mb->boxes, sizeof(Textbox) * mb->box_count); mb->ids = (int*) realloc(mb->ids, sizeof(int) * mb->box_count); + mb->show = (int*) realloc(mb->show, sizeof(int) * mb->box_count); - mb->boxes[slot] = textbox_create(mb->window, TB_AUTOHEIGHT|TB_AUTOWIDTH, mb->padding, mb->line_height*slot+mb->padding, mb->w-(mb->padding*2), 0, mb->font, mb->fg_blur, mb->bg_blur, text, NULL); + mb->boxes[slot] = textbox_create(mb->window, TB_AUTOHEIGHT|TB_AUTOWIDTH, + mb->padding, mb->line_height*(slot+1)+mb->padding, mb->w-(mb->padding*2), 0, + mb->font, mb->fg_blur, mb->bg_blur, text, NULL); + mb->ids[slot] = id; + mb->show[slot] = 1; if (mb->flags & (MB_AUTOWIDTH|MB_AUTOHEIGHT)) menubox_moveresize(mb, mb->x, mb->y, mb->w, mb->h); @@ -125,7 +124,7 @@ void menubox_add(Menubox *mb, int id, char *text) int menubox_get_id(Menubox *mb) { - return mb->ids[mb->box_active]; + return mb->show[mb->box_active] ? mb->ids[mb->box_active]: -1; } void menubox_grab(Menubox *mb) @@ -140,17 +139,29 @@ void menubox_grab(Menubox *mb) void menubox_draw(Menubox *mb) { - for (uint i = 0; i < mb->box_count; i++) + textbox_draw(mb->input); + int filter = strlen(mb->input->text) > 0; + + for (uint i = 0, n = 0; i < mb->box_count; i++) { - textbox_font(mb->boxes[i], mb->font, mb->box_active == i ? mb->fg_focus: mb->fg_blur, mb->box_active == i ? mb->bg_focus: mb->bg_blur); - textbox_draw(mb->boxes[i]); + if (!filter || mb->show[i]) + { + textbox_font(mb->boxes[i], mb->font, mb->box_active == i ? mb->fg_focus: mb->fg_blur, mb->box_active == i ? mb->bg_focus: mb->bg_blur); + textbox_moveresize(mb->boxes[i], mb->padding, mb->line_height*(n+1)+mb->padding, mb->w-(mb->padding*2), 0); + textbox_show(mb->boxes[i]); + textbox_draw(mb->boxes[i]); + n++; + } + else + { + textbox_hide(mb->boxes[i]); + } } } void menubox_show(Menubox *mb) { - for (uint i = 0; i < mb->box_count; i++) - textbox_show(mb->boxes[i]); + textbox_show(mb->input); XMapWindow(display, mb->window); } @@ -165,17 +176,36 @@ void menubox_free(Menubox *mb) textbox_free(mb->boxes[i]); free(mb->boxes); free(mb->ids); - - if (mb->flags & MB_SELECTABLE) - { - XDestroyIC(mb->xic); - XCloseIM(mb->xim); - } - + free(mb->show); + textbox_free(mb->input); XDestroyWindow(display, mb->window); free(mb); } +void menubox_filter(Menubox *mb) +{ + int filter = strlen(mb->input->text) > 0; + char *pattern = strdup(mb->input->text); + for (char *p = pattern; *p; *p = tolower(*p), p++); + + for (int i = 0; i < mb->box_count; i++) + { + char *subject = strdup(mb->boxes[i]->text); + for (char *p = subject; *p; *p = tolower(*p), p++); + mb->show[i] = (!filter || regex_match(pattern, subject)); + free(subject); + } + free(pattern); + + // active entry maybe filtered. step backward + while (!mb->show[mb->box_active] && mb->box_active > 0) + mb->box_active--; + + // active entry maybe filtered. step forward + while (!mb->show[mb->box_active] && mb->box_active < mb->box_count-1) + mb->box_active++; +} + void menubox_key_up(Menubox *mb) { if (mb->box_active > 0) mb->box_active--; @@ -186,16 +216,6 @@ void menubox_key_down(Menubox *mb) if (mb->box_active < mb->box_count-1) mb->box_active++; } -void menubox_key_home(Menubox *mb) -{ - mb->box_active = 0; -} - -void menubox_key_end(Menubox *mb) -{ - mb->box_active = mb->box_count-1; -} - // handle a keypress in edit mode // 0 = unhandled // 1 = handled @@ -205,17 +225,20 @@ int menubox_keypress(Menubox *mb, XEvent *ev) { KeySym key; Status stat; char pad[32]; - int len = XmbLookupString(mb->xic, &ev->xkey, pad, sizeof(pad), &key, &stat); + int len = XmbLookupString(mb->input->xic, &ev->xkey, pad, sizeof(pad), &key, &stat); pad[len] = 0; + int rc = 0; + switch (key) { - case XK_Up : menubox_key_up(mb); return 1; - case XK_Down : menubox_key_down(mb); return 1; - case XK_Home : menubox_key_home(mb); return 1; - case XK_End : menubox_key_end(mb); return 1; - case XK_Escape : return -2; - case XK_Return : return -1; + case XK_Up : { menubox_key_up(mb); rc = 1; break; } + case XK_Down : { menubox_key_down(mb); rc = 1; break; } + case XK_Escape : { rc = -2; break; } + case XK_Return : { rc = -1; break; } + default: rc = textbox_keypress(mb->input, ev); } - return 0; + + menubox_filter(mb); + return rc; } \ No newline at end of file diff --git a/textbox.c b/textbox.c index 07323af..7b0a163 100644 --- a/textbox.c +++ b/textbox.c @@ -95,9 +95,10 @@ void textbox_font(Textbox *tb, char *font, char *fg, char *bg) void textbox_extents(Textbox *tb) { int length = strlen(tb->text) + strlen(tb->prompt); - char line[length + 1]; + char *line = calloc(length + 1, sizeof(char)); sprintf(line, "%s%s", tb->prompt, tb->text); XftTextExtents8(display, tb->font, (unsigned char*)line, length, &tb->extents); + free(line); } // set the default text to display @@ -162,7 +163,6 @@ void textbox_free(Textbox *tb) void textbox_draw(Textbox *tb) { - int i; XGlyphInfo extents; GC context = XCreateGC(display, tb->window, 0, 0); @@ -172,9 +172,10 @@ void textbox_draw(Textbox *tb) // clear canvas XftDrawRect(draw, &tb->color_bg, 0, 0, tb->w, tb->h); - char *line = tb->text, + char *line = tb->text, *text = tb->text ? tb->text: "", - *prompt = tb->prompt ? tb->prompt: ""; + *prompt = tb->prompt ? tb->prompt: "", + *eline = NULL; int text_len = strlen(text); int length = text_len; @@ -190,17 +191,17 @@ void textbox_draw(Textbox *tb) length = text_len + prompt_len; cursor_offset = MIN(tb->cursor + prompt_len, length); - char eline[length + 10]; line = eline; + eline = calloc(length+10, sizeof(char)); line = eline; sprintf(line, "%s%s", prompt, text); - // replace spaces so XftTextExtents8 includes their width - for (i = 0; i < length; i++) if (isspace(line[i])) line[i] = '_'; + // replace trailing space so XftTextExtents8 includes its width + if (length > 0 && isspace(line[length-1])) line[length-1] = '.'; // calc cursor position XftTextExtents8(display, tb->font, (unsigned char*)line, cursor_offset, &extents); cursor_x = extents.width; - // restore correct text string with spaces + // restore correct text string sprintf(line, "%s%s", prompt, text); } @@ -225,6 +226,8 @@ void textbox_draw(Textbox *tb) XFreeGC(display, context); XftDrawDestroy(draw); XFreePixmap(display, canvas); + + free(eline); } // cursor handling for edit mode diff --git a/xoat.c b/xoat.c index cd3fc78..5cb0505 100644 --- a/xoat.c +++ b/xoat.c @@ -52,10 +52,10 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Display *display; +#include "regex.c" #include "atom.c" #include "textbox.c" #include "menubox.c" -#include "regex.c" #define STACK 64 #define MONITORS 3