Added separators
Now lines without labels in the input generate a menu separator.
This commit is contained in:
parent
a80fee227a
commit
7fbd1c5ed0
4
README
4
README
|
@ -22,5 +22,7 @@ build and install dwm (if necessary as root).
|
||||||
xmenu receives as input a menu specification where each line is a menu
|
xmenu receives as input a menu specification where each line is a menu
|
||||||
entry. Each line can be indented with tabs to represent nested menus.
|
entry. Each line can be indented with tabs to represent nested menus.
|
||||||
Each line is made out of a label and a command separated by any number
|
Each line is made out of a label and a command separated by any number
|
||||||
of tabs.
|
of tabs. Lines without labels are menu separators.
|
||||||
|
|
||||||
|
See the script ./xmenu.sh for an example of how xmenu can be used to
|
||||||
|
draw a simple menu with submenus and separators.
|
||||||
|
|
40
xmenu.c
40
xmenu.c
|
@ -43,7 +43,8 @@ struct ScreenGeometry {
|
||||||
struct Item {
|
struct Item {
|
||||||
char *label;
|
char *label;
|
||||||
char *output;
|
char *output;
|
||||||
int y; /* only y is necessary, item's x is always 0 relative to the menu*/
|
int y;
|
||||||
|
int h;
|
||||||
struct Item *next;
|
struct Item *next;
|
||||||
struct Menu *submenu;
|
struct Menu *submenu;
|
||||||
};
|
};
|
||||||
|
@ -199,11 +200,17 @@ allocitem(const char *label, const char *output)
|
||||||
|
|
||||||
if ((item = malloc(sizeof *item)) == NULL)
|
if ((item = malloc(sizeof *item)) == NULL)
|
||||||
err(1, "malloc");
|
err(1, "malloc");
|
||||||
|
if (*label == '\0') {
|
||||||
|
item->label = NULL;
|
||||||
|
item->output = NULL;
|
||||||
|
} else {
|
||||||
if ((item->label = strdup(label)) == NULL)
|
if ((item->label = strdup(label)) == NULL)
|
||||||
err(1, "strdup");
|
err(1, "strdup");
|
||||||
if ((item->output = strdup(output)) == NULL)
|
if ((item->output = strdup(output)) == NULL)
|
||||||
err(1, "strdup");
|
err(1, "strdup");
|
||||||
|
}
|
||||||
item->y = 0;
|
item->y = 0;
|
||||||
|
item->h = item->label ? geom.itemh : geom.separator;
|
||||||
item->next = NULL;
|
item->next = NULL;
|
||||||
item->submenu = NULL;
|
item->submenu = NULL;
|
||||||
|
|
||||||
|
@ -343,7 +350,7 @@ calcmenu(struct Menu *menu)
|
||||||
/* calculate items positions and menu height */
|
/* calculate items positions and menu height */
|
||||||
for (item = menu->list; item != NULL; item = item->next) {
|
for (item = menu->list; item != NULL; item = item->next) {
|
||||||
item->y = menu->h;
|
item->y = menu->h;
|
||||||
if (*item->label == '\0') /* height for separator item */
|
if (item->label == NULL) /* height for separator item */
|
||||||
menu->h += geom.separator;
|
menu->h += geom.separator;
|
||||||
else
|
else
|
||||||
menu->h += geom.itemh;
|
menu->h += geom.itemh;
|
||||||
|
@ -403,7 +410,7 @@ getmenuitem(Window win, int y,
|
||||||
for (menu = currmenu; menu != NULL; menu = menu->parent) {
|
for (menu = currmenu; menu != NULL; menu = menu->parent) {
|
||||||
if (menu->win == win) {
|
if (menu->win == win) {
|
||||||
for (item = menu->list; item != NULL; item = item->next) {
|
for (item = menu->list; item != NULL; item = item->next) {
|
||||||
if (y >= item->y && y <= item->y + geom.itemh) {
|
if (y >= item->y && y <= item->y + item->h) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -443,40 +450,39 @@ drawmenu(void)
|
||||||
struct Item *item;
|
struct Item *item;
|
||||||
|
|
||||||
for (menu = currmenu; menu != NULL; menu = menu->parent) {
|
for (menu = currmenu; menu != NULL; menu = menu->parent) {
|
||||||
size_t nitems; /* number of items before current item */
|
|
||||||
|
|
||||||
nitems = 0;
|
|
||||||
for (item = menu->list; item != NULL; item = item->next) {
|
for (item = menu->list; item != NULL; item = item->next) {
|
||||||
unsigned long *color;
|
unsigned long *color;
|
||||||
size_t labellen;
|
size_t labellen;
|
||||||
int labelx, labely;
|
int labelx, labely;
|
||||||
int y;
|
|
||||||
|
|
||||||
/* determine item color */
|
/* determine item color */
|
||||||
if (item == menu->selected)
|
if (item->label == NULL)
|
||||||
|
color = dc.decoration;
|
||||||
|
else if (item == menu->selected)
|
||||||
color = dc.pressed;
|
color = dc.pressed;
|
||||||
else
|
else
|
||||||
color = dc.unpressed;
|
color = dc.unpressed;
|
||||||
|
|
||||||
/* calculate item's y position */
|
|
||||||
y = nitems * geom.itemh;
|
|
||||||
|
|
||||||
/* draw item box */
|
/* draw item box */
|
||||||
XSetForeground(dpy, dc.gc, color[ColorBG]);
|
XSetForeground(dpy, dc.gc, color[ColorBG]);
|
||||||
XFillRectangle(dpy, menu->win, dc.gc, 0, y,
|
XFillRectangle(dpy, menu->win, dc.gc, 0, item->y,
|
||||||
geom.itemw, geom.itemh);
|
geom.itemw, item->h);
|
||||||
|
|
||||||
|
/* continue if item is a separator */
|
||||||
|
if (item->label == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
/* draw item label */
|
/* draw item label */
|
||||||
labellen = strlen(item->label);
|
labellen = strlen(item->label);
|
||||||
labelx = 0 + dc.fonth;
|
labelx = 0 + dc.fonth;
|
||||||
labely = y + dc.fonth + geom.itemb;
|
labely = item->y + dc.fonth + geom.itemb;
|
||||||
XSetForeground(dpy, dc.gc, color[ColorFG]);
|
XSetForeground(dpy, dc.gc, color[ColorFG]);
|
||||||
XDrawString(dpy, menu->win, dc.gc, labelx, labely, item->label, labellen);
|
XDrawString(dpy, menu->win, dc.gc, labelx, labely, item->label, labellen);
|
||||||
|
|
||||||
/* draw triangle, if item contains a submenu */
|
/* draw triangle, if item contains a submenu */
|
||||||
if (item->submenu != NULL) {
|
if (item->submenu != NULL) {
|
||||||
int trianglex = geom.itemw - (geom.itemb + dc.fonth);
|
int trianglex = geom.itemw - (geom.itemb + dc.fonth);
|
||||||
int triangley = y + geom.itemb;
|
int triangley = item->y + geom.itemb;
|
||||||
|
|
||||||
XPoint triangle[] = {
|
XPoint triangle[] = {
|
||||||
{trianglex, triangley},
|
{trianglex, triangley},
|
||||||
|
@ -488,8 +494,6 @@ drawmenu(void)
|
||||||
XFillPolygon(dpy, menu->win, dc.gc, triangle, LEN(triangle),
|
XFillPolygon(dpy, menu->win, dc.gc, triangle, LEN(triangle),
|
||||||
Convex, CoordModeOrigin);
|
Convex, CoordModeOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
nitems++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -527,6 +531,8 @@ run(void)
|
||||||
case ButtonRelease:
|
case ButtonRelease:
|
||||||
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
|
getmenuitem(ev.xbutton.window, ev.xbutton.y, &menu, &item);
|
||||||
if (menu != NULL && item != NULL) {
|
if (menu != NULL && item != NULL) {
|
||||||
|
if (item->label == NULL)
|
||||||
|
break; /* ignore separators */
|
||||||
if (item->submenu != NULL) {
|
if (item->submenu != NULL) {
|
||||||
setcurrmenu(item->submenu);
|
setcurrmenu(item->submenu);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user