summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c180
-rw-r--r--ui.c211
-rw-r--r--ui.h8
3 files changed, 188 insertions, 211 deletions
diff --git a/main.c b/main.c
index 108c275..111aeed 100644
--- a/main.c
+++ b/main.c
@@ -2,9 +2,6 @@
* a simple fuzzy-selection menu made with Xlib
*/
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-#include <X11/XKBlib.h>
#include <stdio.h>
#define ARENA_IMPL
@@ -13,6 +10,7 @@
#include "arena.h"
#include "dynarr.h"
#include "str.h"
+#include "ui.h"
typedef DYNARR(char) DynStr;
@@ -27,128 +25,100 @@ umod(int a, int b)
}
int
-main(int argc, char **argv)
+txt_insert(DynStr *s, int i, Str ins)
{
- Display *dsp = XOpenDisplay("");
- int scr = DefaultScreen(dsp);
- unsigned long fg = BlackPixel(dsp, scr);
- unsigned long bg = WhitePixel(dsp, scr);
-
- XSizeHints szhint = { 0 };
- szhint.width = 350;
- szhint.height = 250;
- szhint.flags = PSize;
-
- Window win = XCreateSimpleWindow(
- dsp,
- DefaultRootWindow(dsp),
- szhint.x, szhint.y,
- szhint.width, szhint.height,
- 5 /* border width */,
- fg, bg);
-
- char title[] = "xmenu";
- XSetStandardProperties(dsp, win, title, title,
- None, argv, argc, &szhint);
-
- GC gc = XCreateGC(dsp, win, 0, 0);
- XSetBackground(dsp, gc, bg);
- XSetForeground(dsp, gc, fg);
-
- XSelectInput(dsp, win, ButtonPressMask | KeyPressMask | ExposureMask);
- XMapRaised(dsp, win);
+ DA_FIT(s, s->n + ins.n);
+ if (i < s->n) {
+ memmove(s->v + i + ins.n, s->v + i, s->n - i);
+ }
+ memcpy(s->v + i, ins.s, ins.n);
+ s->n += ins.n;
+ return i + ins.n;
+}
- Font freg = XLoadFont(dsp, "-*-new century schoolbook-medium-r-*-*-24-*-*-*-*-*-*-*");
- Font fital = XLoadFont(dsp, "-*-new century schoolbook-medium-i-*-*-24-*-*-*-*-*-*-*");
+int
+txt_delete(DynStr *s, int i, int n)
+{
+ if (n > i) n = i;
+ if (n > 0) {
+ memmove(s->v + i - n, s->v + i, s->n - i);
+ s->n -= n;
+ }
+ return i - n;
+}
- /* see Xft(3) */
+int
+main(int argc, char **argv)
+{
+ ui_init(argc, argv);
DynStr input = { 0 };
-
+ int inpi = 0;
int seli = 0;
-
- const char *optv[] = { "she shit on my thang until i vomit", "what", "who are you", "why are you", "where'd you come from" };
+ Str optv[] = {
+ S("she shit on my thang until i vomit"),
+ S("what"),
+ S("who are you"),
+ S("why are you"),
+ S("where'd you come from")
+ };
int optc = sizeof optv / sizeof *optv;
-
- for (;;) {
- XEvent ev;
- KeySym key;
- XNextEvent(dsp, &ev);
+ if (!optc) goto done;
+ for (UiEvent ev; ui_wait_event(&ev); ) {
switch (ev.type) {
- case KeyPress: {
- char kbuf[32];
- KeyCode kc = ev.xkey.keycode;
- KeySym sym = XkbKeycodeToKeysym(dsp, kc, 0,
- !!(ev.xkey.state & ShiftMask));
- int rune = ksym_to_unicode(sym);
- switch (sym) {
- case XK_Escape:
+ case UI_KEY_DOWN:
+ switch (ev.key.key) {
+ case UIK_ESCAPE:
goto done;
- case XK_BackSpace:
- if (input.n > 0) input.n--;
- goto draw;
- case XK_Return:
- input.n = 0;
+ case UIK_BACKSPACE:
+ inpi = txt_delete(&input, inpi, 1);
goto draw;
- case XK_Down:
+ case UIK_RETURN: {
+ Str o = optv[seli];
+ printf("%.*s\n", (int)o.n, o.s);
+ } goto done;
+ case UIK_DOWN:
seli = umod(seli + 1, optc);
goto draw;
- case XK_Up:
+ case UIK_UP:
seli = umod(seli - 1, optc);
goto draw;
- default: {
- int n = XLookupString(&ev.xkey, kbuf, 10, &key, 0);
- if (!n) break;
- DA_PUSH_MULT(&input, kbuf, n);
+ case UIK_LEFT:
+ if (inpi > 0) inpi--;
+ goto draw;
+ case UIK_RIGHT:
+ if (inpi < input.n) inpi++;
+ goto draw;
+ case UIK_HOME:
+ inpi = 0;
+ goto draw;
+ case UIK_END:
+ inpi = input.n;
+ goto draw;
+ default:
+ if (!ev.key.strn) break;
+ inpi = txt_insert(&input, inpi, (Str) { ev.key.str, ev.key.strn });
seli = 0;
goto draw;
- } break;
}
- } break;
- case Expose: {
- draw:;
- XWindowAttributes attr;
- XClearWindow(dsp, win);
- XGetWindowAttributes(dsp, win, &attr);
- //XGetSizeHints(dsp, win, &szhint);
- XSetFont(dsp, gc, fital);
- int w = XTextWidth(XQueryFont(dsp, XGContextFromGC(gc)), input.v, input.n);
- DA_PUSH(&input, '_');
- XDrawString(dsp, win, gc, 16, 24, input.v, input.n);
- input.n--;
- XSetFont(dsp, gc, freg);
- for (int i = 0; i < optc; i++) {
- if (i == seli) {
- int w = XTextWidth(XQueryFont(dsp,
- XGContextFromGC(gc)),
- optv[i], strlen(optv[i]));
- XFillRectangle(dsp, win, gc,
- 16, 28 + i * 24 + 8,
- w, 24);
- XSetForeground(dsp, gc, bg);
- XDrawString(dsp, win, gc,
- 16, 48 + i * 24 + 8,
- optv[i], strlen(optv[i]));
- XSetForeground(dsp, gc, fg);
- } else {
- XDrawString(dsp, win, gc,
- 16, 48 + i * 24 + 8,
- optv[i], strlen(optv[i]));
- }
-
- }
- } break;
- /* TODO: figure out quit events */
+ break;
+ case UI_REDRAW:
+ draw:
+ ui_draw(
+ (Str) { input.v, input.n },
+ inpi,
+ seli,
+ optv,
+ optc
+ );
+ break;
+ default:
+ break;
}
}
-done: ;
-
- XUnloadFont(dsp, freg);
- XUnloadFont(dsp, fital);
- XFreeGC(dsp, gc);
- XDestroyWindow(dsp, win);
- XCloseDisplay(dsp);
+done:
+ ui_fini();
return 0;
}
diff --git a/ui.c b/ui.c
index 542cb8b..aa3bad6 100644
--- a/ui.c
+++ b/ui.c
@@ -7,34 +7,34 @@
#include <X11/XKBlib.h>
#include <stdio.h>
+#include "ui.h"
#include "dynarr.h"
-typedef DYNARR(char) DynStr;
+static Display *dsp;
+static Window win;
+static int scr;
+static unsigned long fg, bg;
+static XSizeHints szhint;
+static GC gc;
-int
-umod(int a, int b)
-{
- if (a < 0) {
- return b + a % b;
- } else {
- return a % b;
- }
-}
+static Font freg, fital;
-int
-main(int argc, char **argv)
+/* TODO: center menu on screen */
+
+void
+ui_init(int argc, char **argv)
{
- Display *dsp = XOpenDisplay("");
- int scr = DefaultScreen(dsp);
- unsigned long fg = BlackPixel(dsp, scr);
- unsigned long bg = WhitePixel(dsp, scr);
+ dsp = XOpenDisplay("");
+ scr = DefaultScreen(dsp);
+ fg = BlackPixel(dsp, scr);
+ bg = WhitePixel(dsp, scr);
- XSizeHints szhint = { 0 };
+ szhint = (XSizeHints) { 0 };
szhint.width = 350;
szhint.height = 250;
szhint.flags = PSize;
- Window win = XCreateSimpleWindow(
+ win = XCreateSimpleWindow(
dsp,
DefaultRootWindow(dsp),
szhint.x, szhint.y,
@@ -42,108 +42,111 @@ main(int argc, char **argv)
5 /* border width */,
fg, bg);
+ /* TODO: replace with modern XSetWMProperties */
char title[] = "xmenu";
XSetStandardProperties(dsp, win, title, title,
None, argv, argc, &szhint);
- GC gc = XCreateGC(dsp, win, 0, 0);
+ gc = XCreateGC(dsp, win, 0, 0);
XSetBackground(dsp, gc, bg);
XSetForeground(dsp, gc, fg);
XSelectInput(dsp, win, ButtonPressMask | KeyPressMask | ExposureMask);
XMapRaised(dsp, win);
- Font freg = XLoadFont(dsp, "-*-new century schoolbook-medium-r-*-*-24-*-*-*-*-*-*-*");
- Font fital = XLoadFont(dsp, "-*-new century schoolbook-medium-i-*-*-24-*-*-*-*-*-*-*");
-
- /* see Xft(3) */
-
- DynStr input = { 0 };
-
- int seli = 0;
-
- const char *optv[] = { "she shit on my thang until i vomit", "what", "who are you", "why are you", "where'd you come from" };
- int optc = sizeof optv / sizeof *optv;
-
- for (;;) {
- XEvent ev;
- KeySym key;
- XNextEvent(dsp, &ev);
- switch (ev.type) {
- case KeyPress: {
- char kbuf[32];
- KeyCode kc = ev.xkey.keycode;
- KeySym sym = XkbKeycodeToKeysym(dsp, kc, 0,
- !!(ev.xkey.state & ShiftMask));
- int rune = ksym_to_unicode(sym);
- switch (sym) {
- case XK_Escape:
- goto done;
- case XK_BackSpace:
- if (input.n > 0) input.n--;
- goto draw;
- case XK_Return:
- input.n = 0;
- goto draw;
- case XK_Down:
- seli = umod(seli + 1, optc);
- goto draw;
- case XK_Up:
- seli = umod(seli - 1, optc);
- goto draw;
- default: {
- int n = XLookupString(&ev.xkey, kbuf, 10, &key, 0);
- if (!n) break;
- DA_PUSH_MULT(&input, kbuf, n);
- seli = 0;
- goto draw;
- } break;
- }
- } break;
- case Expose: {
- draw:;
- XWindowAttributes attr;
- XClearWindow(dsp, win);
- XGetWindowAttributes(dsp, win, &attr);
- //XGetSizeHints(dsp, win, &szhint);
- XSetFont(dsp, gc, fital);
- int w = XTextWidth(XQueryFont(dsp, XGContextFromGC(gc)), input.v, input.n);
- DA_PUSH(&input, '_');
- XDrawString(dsp, win, gc, 16, 24, input.v, input.n);
- input.n--;
- XSetFont(dsp, gc, freg);
- for (int i = 0; i < optc; i++) {
- if (i == seli) {
- int w = XTextWidth(XQueryFont(dsp,
- XGContextFromGC(gc)),
- optv[i], strlen(optv[i]));
- XFillRectangle(dsp, win, gc,
- 16, 28 + i * 24 + 8,
- w, 24);
- XSetForeground(dsp, gc, bg);
- XDrawString(dsp, win, gc,
- 16, 48 + i * 24 + 8,
- optv[i], strlen(optv[i]));
- XSetForeground(dsp, gc, fg);
- } else {
- XDrawString(dsp, win, gc,
- 16, 48 + i * 24 + 8,
- optv[i], strlen(optv[i]));
- }
-
- }
- } break;
- /* TODO: figure out quit events */
- }
+ freg = XLoadFont(dsp, "-*-new century schoolbook-medium-r-*-*-24-*-*-*-*-*-*-*");
+ fital = XLoadFont(dsp, "-*-new century schoolbook-medium-i-*-*-24-*-*-*-*-*-*-*");
+}
+
+UiKey
+xksym_to_uik(KeySym sym)
+{
+ switch (sym) {
+ case XK_Escape: return UIK_ESCAPE;
+ case XK_BackSpace: return UIK_BACKSPACE;
+ case XK_Up: return UIK_UP;
+ case XK_Down: return UIK_DOWN;
+ case XK_Left: return UIK_LEFT;
+ case XK_Right: return UIK_RIGHT;
+ case XK_Return: return UIK_RETURN;
+ case XK_Home: return UIK_HOME;
+ case XK_End: return UIK_END;
+ case XK_Page_Down: return UIK_PGDN;
+ case XK_Page_Up: return UIK_PGUP;
+ default: return UIK_UNKNOWN;
+ }
+}
+
+int
+ui_wait_event(UiEvent *e)
+{
+ XEvent ev;
+ KeySym sym;
+ XNextEvent(dsp, &ev);
+ switch (ev.type) {
+ case KeyPress:
+ e->type = UI_KEY_DOWN;
+ e->key.strn = XLookupString(&ev.xkey, e->key.str, 10, &sym, 0);
+ e->key.key = xksym_to_uik(sym);
+ return 1;
+ case KeyRelease:
+ e->type = UI_KEY_UP;
+ e->key.strn = XLookupString(&ev.xkey, e->key.str, 10, &sym, 0);
+ e->key.key = xksym_to_uik(sym);
+ return 1;
+ case Expose:
+ e->type = UI_REDRAW;
+ return 1;
}
+ fprintf(stderr, "[Unknown event %d]\n", ev.type);
+ return 0;
+}
-done: ;
+void
+ui_draw(Str input, int inpi, int seli, Str *optv, int optc)
+{
+ XWindowAttributes attr;
+ XClearWindow(dsp, win);
+ XGetWindowAttributes(dsp, win, &attr);
+
+ /* draw input */
+
+ XSetFont(dsp, gc, fital);
+ XDrawString(dsp, win, gc, 16, 24, input.s, input.n);
+ XFontStruct *f = XQueryFont(dsp, XGContextFromGC(gc));
+ int w = XTextWidth(f, input.s, inpi);
+ XDrawLine(dsp, win, gc, 16 + w, 24 - f->ascent, 16 + w, 24 + f->descent);
+
+ /* draw options */
+
+ XSetFont(dsp, gc, freg);
+ for (int i = 0; i < optc; i++) {
+ if (i == seli) {
+ int w = XTextWidth(XQueryFont(dsp,
+ XGContextFromGC(gc)),
+ optv[i].s, optv[i].n);
+ XFillRectangle(dsp, win, gc,
+ 16, 28 + i * 24 + 8,
+ w, 24);
+ XSetForeground(dsp, gc, bg);
+ XDrawString(dsp, win, gc,
+ 16, 48 + i * 24 + 8,
+ optv[i].s, optv[i].n);
+ XSetForeground(dsp, gc, fg);
+ } else {
+ XDrawString(dsp, win, gc,
+ 16, 48 + i * 24 + 8,
+ optv[i].s, optv[i].n);
+ }
+ }
+}
+void
+ui_fini(void)
+{
XUnloadFont(dsp, freg);
XUnloadFont(dsp, fital);
XFreeGC(dsp, gc);
XDestroyWindow(dsp, win);
XCloseDisplay(dsp);
-
- return 0;
}
diff --git a/ui.h b/ui.h
index 9263a28..25ac537 100644
--- a/ui.h
+++ b/ui.h
@@ -1,6 +1,8 @@
#ifndef UI_H
#define UI_H
+#include "str.h"
+
typedef enum {
UI_REDRAW,
UI_KEY_DOWN,
@@ -8,6 +10,8 @@ typedef enum {
} UiEventType;
typedef enum {
+ UIK_ESCAPE,
+ UIK_BACKSPACE,
UIK_UP,
UIK_DOWN,
UIK_LEFT,
@@ -33,9 +37,9 @@ typedef struct {
};
} UiEvent;
-void ui_init(void);
+void ui_init(int argc, char **argv);
void ui_fini(void);
-void ui_draw(Str input, int seli, Str *opt, int optn);
+void ui_draw(Str input, int inpi, int seli, Str *optv, int optc);
int ui_wait_event(UiEvent *e);
#endif