Redesign launcher: modern dark UI, 4-col grid, pill filters, footer
- 640x490 window, larger cards (132x106), 4 columns - Full-width search bar in header with active-state indicator - Category filters as pill chips with gaps - Cards show surface bg + accent top bar on hover - Footer bar with app count and keyboard hints - Fix menu: pavucontrol -> alsamixer in xterm Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
daf9cb4f96
commit
4854ab85aa
2 files changed
+145
-101
No files matched your search
+144
-100
@@ -11,51 +11,55 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/* ── dimensions ─────────────────────────────────────────────────────── */
|
/* ── dimensions ─────────────────────────────────────────────────────── */
|
||||||
#define WIN_W 580
|
#define WIN_W 640
|
||||||
#define WIN_H 420
|
#define WIN_H 490
|
||||||
#define HDR_H 50
|
#define HDR_H 58
|
||||||
#define TAB_H 34
|
#define PILLS_H 42
|
||||||
#define CONTENT_Y (HDR_H + TAB_H)
|
#define CONTENT_Y (HDR_H + PILLS_H)
|
||||||
#define PAD 12
|
#define FOOTER_H 28
|
||||||
#define CARD_W 96
|
#define CARD_W 132
|
||||||
#define CARD_H 84
|
#define CARD_H 106
|
||||||
#define CARD_GAP 8
|
#define CARD_GAP 10
|
||||||
#define COLS 5
|
#define COLS 4
|
||||||
#define ICON_SZ 38
|
#define ICON_SZ 46
|
||||||
|
#define PILL_GAP 8
|
||||||
|
#define ROWS_VIS 3
|
||||||
|
|
||||||
#define GX0 ((WIN_W - (COLS * CARD_W + (COLS-1) * CARD_GAP)) / 2)
|
#define GX0 ((WIN_W - (COLS * CARD_W + (COLS-1) * CARD_GAP)) / 2)
|
||||||
#define GY0 (CONTENT_Y + PAD)
|
#define GY0 (CONTENT_Y + 12)
|
||||||
#define ROWS_VIS 3 /* rows visible before scrolling */
|
|
||||||
#define MAX_APPS 256
|
#define MAX_APPS 256
|
||||||
|
|
||||||
/* ── palette ─────────────────────────────────────────────────────────── */
|
/* ── palette ─────────────────────────────────────────────────────────── */
|
||||||
#define C_BG 0x0E1220
|
#define C_BG 0x111318
|
||||||
#define C_HDR 0x090C18
|
#define C_SURFACE 0x1A1D28
|
||||||
#define C_BORDER 0x192236
|
#define C_SURFACE_HV 0x1F2335
|
||||||
#define C_ACCENT 0x2258B0
|
#define C_BORDER 0x252A42
|
||||||
#define C_TAB_SEL 0x141E30
|
#define C_BORDER_HV 0x3A5490
|
||||||
#define C_CARD_HOV 0x131C2E
|
#define C_ACCENT 0x4B8FF0
|
||||||
#define C_CARD_BD 0x1E2E48
|
#define C_PILL_SEL 0x19305C
|
||||||
#define C_SEARCH 0x131A28
|
#define C_PILL_BD 0x2A4480
|
||||||
#define C_SEARCH_BD 0x1C2C44
|
#define C_SRCH_BG 0x161820
|
||||||
#define C_TEXT 0x8AAAC8
|
#define C_SRCH_BD 0x262C48
|
||||||
#define C_TEXT_HOV 0xE8F0FF
|
#define C_TEXT 0xC0CFF0
|
||||||
#define C_TEXT_DIM 0x344A62
|
#define C_TEXT_HOV 0xEEF2FF
|
||||||
#define C_TAB_TXT 0x486070
|
#define C_TEXT_DIM 0x3A4068
|
||||||
#define C_TAB_TSEL 0xA8C4E8
|
#define C_TEXT_CAT 0x586090
|
||||||
#define C_SCROLL_BG 0x0C1020
|
#define C_TEXT_CAT_S 0x8AAEE8
|
||||||
#define C_SCROLL_TH 0x1E3258
|
#define C_FOOTER_BG 0x0C0E14
|
||||||
|
#define C_FOOTER_TXT 0x353C62
|
||||||
|
#define C_SCROLL_BG 0x161820
|
||||||
|
#define C_SCROLL_TH 0x2C3460
|
||||||
|
|
||||||
static const unsigned long ICON_BG[] = {
|
static const unsigned long ICON_BG[] = {
|
||||||
0x1A4D88, 0x166C3C, 0x6C3018,
|
0x1A3A88, 0x0F6040, 0x7A2820, 0x501A80,
|
||||||
0x4A1A80, 0x126070, 0x6C1A38,
|
0x106070, 0x6A1A3A, 0x384C18, 0x1A3060,
|
||||||
0x365218, 0x183460,
|
0x6A4010, 0x103A60,
|
||||||
};
|
};
|
||||||
#define NICON 8
|
#define NICON 10
|
||||||
|
|
||||||
#define FONT_UI "Sans:size=9"
|
#define FONT_UI "Sans:size=9"
|
||||||
#define FONT_LOGO "Sans:size=11:weight=bold"
|
#define FONT_ICON "Sans:size=14:weight=bold"
|
||||||
#define FONT_ICON "Sans:size=13:weight=bold"
|
#define FONT_HINT "Sans:size=8"
|
||||||
#define MAX_FLT 64
|
#define MAX_FLT 64
|
||||||
|
|
||||||
typedef struct { char name[64]; char cmd[256]; char cat[32]; char icon[64]; } App;
|
typedef struct { char name[64]; char cmd[256]; char cat[32]; char icon[64]; } App;
|
||||||
@@ -171,14 +175,13 @@ static void load_apps(void) {
|
|||||||
load_desktop_dir(p);
|
load_desktop_dir(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fallback if no .desktop files (dev environment, macOS, etc.) */
|
|
||||||
if (NAPP == 0) {
|
if (NAPP == 0) {
|
||||||
static const struct { const char *n, *c, *cat; } FB[] = {
|
static const struct { const char *n, *c, *cat; } FB[] = {
|
||||||
{ "Terminal", "xterm &", "System" },
|
{ "Terminal", "xterm &", "System" },
|
||||||
{ "Files", "pcmanfm &", "System" },
|
{ "Files", "pcmanfm &", "System" },
|
||||||
{ "Text Editor", "mousepad &", "System" },
|
{ "Text Editor", "mousepad &", "System" },
|
||||||
{ "System Mon", "xterm -e htop &", "System" },
|
{ "System Mon", "xterm -e htop &", "System" },
|
||||||
{ "Display", "arandr &", "Settings" },
|
{ "Display", "arandr &", "Settings" },
|
||||||
};
|
};
|
||||||
for (int i = 0; i < (int)(sizeof(FB)/sizeof(FB[0])); i++) {
|
for (int i = 0; i < (int)(sizeof(FB)/sizeof(FB[0])); i++) {
|
||||||
snprintf(APPS[i].name, 64, "%s", FB[i].n);
|
snprintf(APPS[i].name, 64, "%s", FB[i].n);
|
||||||
@@ -196,7 +199,7 @@ typedef struct {
|
|||||||
Display *dpy; int screen;
|
Display *dpy; int screen;
|
||||||
Window root, win; GC gc;
|
Window root, win; GC gc;
|
||||||
Colormap cmap; Visual *visual;
|
Colormap cmap; Visual *visual;
|
||||||
XftFont *font_ui, *font_logo, *font_icon;
|
XftFont *font_ui, *font_icon, *font_hint;
|
||||||
int sel_cat, hov, scroll;
|
int sel_cat, hov, scroll;
|
||||||
char filter[MAX_FLT];
|
char filter[MAX_FLT];
|
||||||
int filter_len;
|
int filter_len;
|
||||||
@@ -257,28 +260,28 @@ static int nvis(L *l, int out[MAX_APPS]) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tab_layout(L *l, int widths[NCAT], int *total) {
|
static void pill_layout(L *l, int widths[NCAT], int *total) {
|
||||||
*total = 0;
|
*total = 0;
|
||||||
for (int i = 0; i < NCAT; i++) {
|
for (int i = 0; i < NCAT; i++) {
|
||||||
XGlyphInfo e;
|
XGlyphInfo e;
|
||||||
XftTextExtentsUtf8(l->dpy, l->font_ui, (FcChar8*)CATS[i], strlen(CATS[i]), &e);
|
XftTextExtentsUtf8(l->dpy, l->font_ui, (FcChar8*)CATS[i], strlen(CATS[i]), &e);
|
||||||
widths[i] = (int)e.width + 22;
|
widths[i] = (int)e.width + 24;
|
||||||
*total += widths[i];
|
*total += widths[i];
|
||||||
}
|
}
|
||||||
|
*total += (NCAT - 1) * PILL_GAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tab_at(L *l, int x, int y) {
|
static int tab_at(L *l, int x, int y) {
|
||||||
if (y < HDR_H || y >= CONTENT_Y) return -1;
|
if (y < HDR_H || y >= CONTENT_Y) return -1;
|
||||||
int w[NCAT], total; tab_layout(l, w, &total);
|
int w[NCAT], total; pill_layout(l, w, &total);
|
||||||
int tx = (WIN_W - total) / 2;
|
int tx = (WIN_W - total) / 2;
|
||||||
for (int i = 0; i < NCAT; i++) {
|
for (int i = 0; i < NCAT; i++) {
|
||||||
if (x >= tx && x < tx + w[i]) return i;
|
if (x >= tx && x < tx + w[i]) return i;
|
||||||
tx += w[i];
|
tx += w[i] + PILL_GAP;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* card index within visible slice (adjusted for scroll) */
|
|
||||||
static int card_at_vis(int x, int y) {
|
static int card_at_vis(int x, int y) {
|
||||||
if (y < CONTENT_Y) return -1;
|
if (y < CONTENT_Y) return -1;
|
||||||
int lx = x - GX0, ly = y - GY0;
|
int lx = x - GX0, ly = y - GY0;
|
||||||
@@ -328,60 +331,68 @@ found:;
|
|||||||
static void draw(L *l) {
|
static void draw(L *l) {
|
||||||
XftDraw *xd = XftDrawCreate(l->dpy, l->win, l->visual, l->cmap);
|
XftDraw *xd = XftDrawCreate(l->dpy, l->win, l->visual, l->cmap);
|
||||||
|
|
||||||
|
/* background */
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BG));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_BG));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, WIN_H);
|
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, WIN_H);
|
||||||
|
|
||||||
/* header */
|
/* ── header: search bar ─────────────────────────── */
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_HDR));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_SURFACE));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, HDR_H);
|
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, HDR_H);
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W, 2);
|
|
||||||
|
|
||||||
ds(l, xd, l->font_logo, C_ACCENT, 14, 13, "OrionOS");
|
/* search input box */
|
||||||
|
|
||||||
/* search box */
|
|
||||||
{
|
{
|
||||||
int sx = 86, sy = 10, sw = WIN_W - 86 - 14, sh = 30;
|
int sx = 16, sy = 11, sw = WIN_W - 32, sh = 36;
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SEARCH));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_SRCH_BG));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, sx, sy, sw, sh);
|
XFillRectangle(l->dpy, l->win, l->gc, sx, sy, sw, sh);
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SEARCH_BD));
|
XSetForeground(l->dpy, l->gc, mkc(l,
|
||||||
XDrawRectangle(l->dpy, l->win, l->gc, sx, sy, sw, sh);
|
l->filter_len > 0 ? C_BORDER_HV : C_SRCH_BD));
|
||||||
|
XDrawRectangle(l->dpy, l->win, l->gc, sx, sy, sw - 1, sh - 1);
|
||||||
|
|
||||||
|
/* accent left bar when active */
|
||||||
|
if (l->filter_len > 0) {
|
||||||
|
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
||||||
|
XFillRectangle(l->dpy, l->win, l->gc, sx, sy, 2, sh);
|
||||||
|
}
|
||||||
|
|
||||||
if (l->filter_len == 0) {
|
if (l->filter_len == 0) {
|
||||||
ds(l, xd, l->font_ui, C_TEXT_DIM, sx + 8, sy + 7, "Search apps...");
|
ds(l, xd, l->font_ui, C_TEXT_DIM, sx + 12, sy + 10, "Search applications...");
|
||||||
} else {
|
} else {
|
||||||
char buf[MAX_FLT + 2];
|
char buf[MAX_FLT + 2];
|
||||||
snprintf(buf, sizeof(buf), "%s|", l->filter);
|
snprintf(buf, sizeof(buf), "%s_", l->filter);
|
||||||
ds(l, xd, l->font_ui, C_TEXT_HOV, sx + 8, sy + 7, buf);
|
ds(l, xd, l->font_ui, C_TEXT_HOV, sx + 12, sy + 10, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* header bottom separator */
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||||
XDrawLine(l->dpy, l->win, l->gc, 0, HDR_H, WIN_W, HDR_H);
|
XDrawLine(l->dpy, l->win, l->gc, 0, HDR_H - 1, WIN_W, HDR_H - 1);
|
||||||
|
|
||||||
|
/* ── pills row ───────────────────────────────────── */
|
||||||
|
int pw[NCAT], ptotal; pill_layout(l, pw, &ptotal);
|
||||||
|
int px = (WIN_W - ptotal) / 2;
|
||||||
|
int py = HDR_H + (PILLS_H - 24) / 2;
|
||||||
|
|
||||||
/* category tabs */
|
|
||||||
int tw[NCAT], ttotal; tab_layout(l, tw, &ttotal);
|
|
||||||
int tx = (WIN_W - ttotal) / 2;
|
|
||||||
for (int i = 0; i < NCAT; i++) {
|
for (int i = 0; i < NCAT; i++) {
|
||||||
if (i == l->sel_cat) {
|
if (i == l->sel_cat) {
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_TAB_SEL));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_PILL_SEL));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, tx, HDR_H + 1, tw[i], TAB_H - 1);
|
XFillRectangle(l->dpy, l->win, l->gc, px, py, pw[i], 24);
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_PILL_BD));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, tx + 5, HDR_H + TAB_H - 2, tw[i] - 10, 2);
|
XDrawRectangle(l->dpy, l->win, l->gc, px, py, pw[i] - 1, 23);
|
||||||
|
ds_ctr(l, xd, l->font_ui, C_TEXT_CAT_S, px, py, pw[i], 24, CATS[i]);
|
||||||
|
} else {
|
||||||
|
ds_ctr(l, xd, l->font_ui, C_TEXT_CAT, px, py, pw[i], 24, CATS[i]);
|
||||||
}
|
}
|
||||||
ds_ctr(l, xd, l->font_ui,
|
px += pw[i] + PILL_GAP;
|
||||||
(i == l->sel_cat) ? C_TAB_TSEL : C_TAB_TXT,
|
|
||||||
tx, HDR_H, tw[i], TAB_H, CATS[i]);
|
|
||||||
tx += tw[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pills bottom separator */
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||||
XDrawLine(l->dpy, l->win, l->gc, 0, CONTENT_Y, WIN_W, CONTENT_Y);
|
XDrawLine(l->dpy, l->win, l->gc, 0, CONTENT_Y - 1, WIN_W, CONTENT_Y - 1);
|
||||||
|
|
||||||
/* app grid with scroll */
|
/* ── app grid ────────────────────────────────────── */
|
||||||
int vis[MAX_APPS];
|
int vis[MAX_APPS];
|
||||||
int nv = nvis(l, vis);
|
int nv = nvis(l, vis);
|
||||||
|
|
||||||
/* clamp scroll */
|
|
||||||
int max_scroll = (nv - ROWS_VIS * COLS + COLS - 1) / COLS;
|
int max_scroll = (nv - ROWS_VIS * COLS + COLS - 1) / COLS;
|
||||||
if (max_scroll < 0) max_scroll = 0;
|
if (max_scroll < 0) max_scroll = 0;
|
||||||
if (l->scroll > max_scroll) l->scroll = max_scroll;
|
if (l->scroll > max_scroll) l->scroll = max_scroll;
|
||||||
@@ -391,7 +402,8 @@ static void draw(L *l) {
|
|||||||
|
|
||||||
if (nv == 0) {
|
if (nv == 0) {
|
||||||
ds_ctr(l, xd, l->font_ui, C_TEXT_DIM,
|
ds_ctr(l, xd, l->font_ui, C_TEXT_DIM,
|
||||||
0, CONTENT_Y, WIN_W, WIN_H - CONTENT_Y, "No apps found");
|
0, CONTENT_Y, WIN_W, WIN_H - CONTENT_Y - FOOTER_H,
|
||||||
|
"No matching apps");
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < ROWS_VIS * COLS; i++) {
|
for (int i = 0; i < ROWS_VIS * COLS; i++) {
|
||||||
int vi = vis_start + i;
|
int vi = vis_start + i;
|
||||||
@@ -402,18 +414,29 @@ static void draw(L *l) {
|
|||||||
int cy = GY0 + row * (CARD_H + CARD_GAP);
|
int cy = GY0 + row * (CARD_H + CARD_GAP);
|
||||||
int hover = (i == l->hov);
|
int hover = (i == l->hov);
|
||||||
|
|
||||||
|
/* card background */
|
||||||
if (hover) {
|
if (hover) {
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_CARD_HOV));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_SURFACE_HV));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W, CARD_H);
|
XFillRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W, CARD_H);
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_CARD_BD));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER_HV));
|
||||||
|
XDrawRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W - 1, CARD_H - 1);
|
||||||
|
/* accent top bar on hover */
|
||||||
|
XSetForeground(l->dpy, l->gc, mkc(l, C_ACCENT));
|
||||||
|
XFillRectangle(l->dpy, l->win, l->gc, cx + 1, cy, CARD_W - 2, 2);
|
||||||
|
} else {
|
||||||
|
XSetForeground(l->dpy, l->gc, mkc(l, C_SURFACE));
|
||||||
|
XFillRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W, CARD_H);
|
||||||
|
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||||
XDrawRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W - 1, CARD_H - 1);
|
XDrawRectangle(l->dpy, l->win, l->gc, cx, cy, CARD_W - 1, CARD_H - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int app_i = vis[vi];
|
int app_i = vis[vi];
|
||||||
unsigned int h = 0;
|
unsigned int h = 0;
|
||||||
for (const char *p = APPS[app_i].name; *p; p++) h = h * 31 + (unsigned char)*p;
|
for (const char *p = APPS[app_i].name; *p; p++) h = h * 31 + (unsigned char)*p;
|
||||||
|
|
||||||
|
/* icon */
|
||||||
int ix = cx + (CARD_W - ICON_SZ) / 2;
|
int ix = cx + (CARD_W - ICON_SZ) / 2;
|
||||||
int iy = cy + 10;
|
int iy = cy + 14;
|
||||||
int icon_rendered = 0;
|
int icon_rendered = 0;
|
||||||
#ifdef HAVE_IMLIB2
|
#ifdef HAVE_IMLIB2
|
||||||
icon_rendered = render_icon(l, APPS[app_i].icon, ix, iy, ICON_SZ);
|
icon_rendered = render_icon(l, APPS[app_i].icon, ix, iy, ICON_SZ);
|
||||||
@@ -421,34 +444,57 @@ static void draw(L *l) {
|
|||||||
if (!icon_rendered) {
|
if (!icon_rendered) {
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, ICON_BG[h % NICON]));
|
XSetForeground(l->dpy, l->gc, mkc(l, ICON_BG[h % NICON]));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, ix, iy, ICON_SZ, ICON_SZ);
|
XFillRectangle(l->dpy, l->win, l->gc, ix, iy, ICON_SZ, ICON_SZ);
|
||||||
|
/* 1px darker border on icon box */
|
||||||
|
XSetForeground(l->dpy, l->gc, mkc(l, 0x000000));
|
||||||
|
XDrawRectangle(l->dpy, l->win, l->gc, ix, iy, ICON_SZ - 1, ICON_SZ - 1);
|
||||||
char letter[2] = { APPS[app_i].name[0], '\0' };
|
char letter[2] = { APPS[app_i].name[0], '\0' };
|
||||||
if (letter[0] >= 'a' && letter[0] <= 'z') letter[0] -= 32;
|
if (letter[0] >= 'a' && letter[0] <= 'z') letter[0] -= 32;
|
||||||
ds_ctr(l, xd, l->font_icon, 0xEAF0FF, ix, iy, ICON_SZ, ICON_SZ, letter);
|
ds_ctr(l, xd, l->font_icon, 0xF0F4FF,
|
||||||
|
ix, iy, ICON_SZ, ICON_SZ, letter);
|
||||||
}
|
}
|
||||||
|
|
||||||
char lbl[14];
|
/* label */
|
||||||
snprintf(lbl, sizeof(lbl), "%.12s", APPS[app_i].name);
|
char lbl[16];
|
||||||
|
snprintf(lbl, sizeof(lbl), "%.14s", APPS[app_i].name);
|
||||||
ds_ctr(l, xd, l->font_ui,
|
ds_ctr(l, xd, l->font_ui,
|
||||||
hover ? C_TEXT_HOV : C_TEXT,
|
hover ? C_TEXT_HOV : C_TEXT,
|
||||||
cx, iy + ICON_SZ + 4, CARD_W, CARD_H - ICON_SZ - 18, lbl);
|
cx, iy + ICON_SZ + 6, CARD_W, CARD_H - ICON_SZ - 24, lbl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* scrollbar */
|
/* scrollbar */
|
||||||
if (max_scroll > 0) {
|
if (max_scroll > 0) {
|
||||||
int sb_x = WIN_W - 8, sb_y = CONTENT_Y + 4;
|
int sb_x = WIN_W - 6;
|
||||||
int sb_h = WIN_H - CONTENT_Y - 8;
|
int sb_y = CONTENT_Y + 4;
|
||||||
|
int sb_h = WIN_H - CONTENT_Y - FOOTER_H - 8;
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SCROLL_BG));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_SCROLL_BG));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, sb_x, sb_y, 6, sb_h);
|
XFillRectangle(l->dpy, l->win, l->gc, sb_x, sb_y, 4, sb_h);
|
||||||
int total_rows = (nv + COLS - 1) / COLS;
|
int total_rows = (nv + COLS - 1) / COLS;
|
||||||
int thumb_h = sb_h * ROWS_VIS / total_rows;
|
int thumb_h = sb_h * ROWS_VIS / total_rows;
|
||||||
if (thumb_h < 12) thumb_h = 12;
|
if (thumb_h < 10) thumb_h = 10;
|
||||||
int thumb_y = sb_y + (sb_h - thumb_h) * l->scroll / max_scroll;
|
int thumb_y = sb_y + (sb_h - thumb_h) * l->scroll / max_scroll;
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_SCROLL_TH));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_SCROLL_TH));
|
||||||
XFillRectangle(l->dpy, l->win, l->gc, sb_x + 1, thumb_y, 4, thumb_h);
|
XFillRectangle(l->dpy, l->win, l->gc, sb_x, thumb_y, 4, thumb_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* outer border */
|
/* ── footer ──────────────────────────────────────── */
|
||||||
|
int fy = WIN_H - FOOTER_H;
|
||||||
|
XSetForeground(l->dpy, l->gc, mkc(l, C_FOOTER_BG));
|
||||||
|
XFillRectangle(l->dpy, l->win, l->gc, 0, fy, WIN_W, FOOTER_H);
|
||||||
|
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||||
|
XDrawLine(l->dpy, l->win, l->gc, 0, fy, WIN_W, fy);
|
||||||
|
|
||||||
|
/* app count left, hints right */
|
||||||
|
{
|
||||||
|
char cnt[32];
|
||||||
|
snprintf(cnt, sizeof(cnt), "%d apps", nv);
|
||||||
|
ds(l, xd, l->font_hint, C_FOOTER_TXT, 14, fy + 7, cnt);
|
||||||
|
ds_ctr(l, xd, l->font_hint, C_FOOTER_TXT,
|
||||||
|
0, fy, WIN_W, FOOTER_H,
|
||||||
|
"Return: launch Esc: close Type: filter");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* outer window border */
|
||||||
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
XSetForeground(l->dpy, l->gc, mkc(l, C_BORDER));
|
||||||
XDrawRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W - 1, WIN_H - 1);
|
XDrawRectangle(l->dpy, l->win, l->gc, 0, 0, WIN_W - 1, WIN_H - 1);
|
||||||
|
|
||||||
@@ -478,7 +524,6 @@ static void on_key(L *l, XKeyEvent *e) {
|
|||||||
l->filter[--l->filter_len] = '\0';
|
l->filter[--l->filter_len] = '\0';
|
||||||
l->scroll = 0; l->hov = -1; draw(l); return;
|
l->scroll = 0; l->hov = -1; draw(l); return;
|
||||||
}
|
}
|
||||||
/* page up/down for keyboard scroll */
|
|
||||||
if (sym == XK_Prior) { l->scroll -= ROWS_VIS; if (l->scroll < 0) l->scroll = 0; draw(l); return; }
|
if (sym == XK_Prior) { l->scroll -= ROWS_VIS; if (l->scroll < 0) l->scroll = 0; draw(l); return; }
|
||||||
if (sym == XK_Next) { l->scroll += ROWS_VIS; draw(l); return; }
|
if (sym == XK_Next) { l->scroll += ROWS_VIS; draw(l); return; }
|
||||||
|
|
||||||
@@ -506,11 +551,11 @@ int main(void) {
|
|||||||
l.visual = DefaultVisual(l.dpy, l.screen);
|
l.visual = DefaultVisual(l.dpy, l.screen);
|
||||||
|
|
||||||
l.font_ui = XftFontOpenName(l.dpy, l.screen, FONT_UI);
|
l.font_ui = XftFontOpenName(l.dpy, l.screen, FONT_UI);
|
||||||
l.font_logo = XftFontOpenName(l.dpy, l.screen, FONT_LOGO);
|
|
||||||
l.font_icon = XftFontOpenName(l.dpy, l.screen, FONT_ICON);
|
l.font_icon = XftFontOpenName(l.dpy, l.screen, FONT_ICON);
|
||||||
|
l.font_hint = XftFontOpenName(l.dpy, l.screen, FONT_HINT);
|
||||||
if (!l.font_ui) l.font_ui = XftFontOpenName(l.dpy, l.screen, "fixed:size=9");
|
if (!l.font_ui) l.font_ui = XftFontOpenName(l.dpy, l.screen, "fixed:size=9");
|
||||||
if (!l.font_logo) l.font_logo = l.font_ui;
|
|
||||||
if (!l.font_icon) l.font_icon = l.font_ui;
|
if (!l.font_icon) l.font_icon = l.font_ui;
|
||||||
|
if (!l.font_hint) l.font_hint = l.font_ui;
|
||||||
|
|
||||||
int sw = DisplayWidth(l.dpy, l.screen);
|
int sw = DisplayWidth(l.dpy, l.screen);
|
||||||
int sh = DisplayHeight(l.dpy, l.screen);
|
int sh = DisplayHeight(l.dpy, l.screen);
|
||||||
@@ -540,14 +585,13 @@ int main(void) {
|
|||||||
if (e.xexpose.count == 0) draw(&l);
|
if (e.xexpose.count == 0) draw(&l);
|
||||||
break;
|
break;
|
||||||
case ButtonPress:
|
case ButtonPress:
|
||||||
|
if (e.xbutton.button == Button4) {
|
||||||
|
l.scroll -= 1; if (l.scroll < 0) l.scroll = 0; draw(&l); break;
|
||||||
|
}
|
||||||
|
if (e.xbutton.button == Button5) {
|
||||||
|
l.scroll += 1; draw(&l); break;
|
||||||
|
}
|
||||||
{
|
{
|
||||||
/* scroll wheel */
|
|
||||||
if (e.xbutton.button == Button4) {
|
|
||||||
l.scroll -= 1; if (l.scroll < 0) l.scroll = 0; draw(&l); break;
|
|
||||||
}
|
|
||||||
if (e.xbutton.button == Button5) {
|
|
||||||
l.scroll += 1; draw(&l); break;
|
|
||||||
}
|
|
||||||
int t = tab_at(&l, e.xbutton.x, e.xbutton.y);
|
int t = tab_at(&l, e.xbutton.x, e.xbutton.y);
|
||||||
if (t >= 0) {
|
if (t >= 0) {
|
||||||
l.sel_cat = t; l.scroll = 0; l.hov = -1; draw(&l);
|
l.sel_cat = t; l.scroll = 0; l.hov = -1; draw(&l);
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ static const MenuItem MENU_ITEMS[] = {
|
|||||||
{ "──────────────────", NULL },
|
{ "──────────────────", NULL },
|
||||||
{ "Web Browser", "firefox &" },
|
{ "Web Browser", "firefox &" },
|
||||||
{ "System Monitor", "xterm -T 'System Monitor' -e htop &" },
|
{ "System Monitor", "xterm -T 'System Monitor' -e htop &" },
|
||||||
{ "Volume Control", "pavucontrol &" },
|
{ "Volume Control", "xterm -e alsamixer &" },
|
||||||
{ "Software Updates", "orionpkg &" },
|
{ "Software Updates", "orionpkg &" },
|
||||||
{ "Display Settings", "arandr &" },
|
{ "Display Settings", "arandr &" },
|
||||||
{ "──────────────────", NULL },
|
{ "──────────────────", NULL },
|
||||||
|
|||||||
Reference in new issue
Block a user