| |
| |
| |
| |
| |
| int graphInit(Graph *g, App *app) { |
| LOGDBG("graph: init"); |
| |
| CLEARFROM(g, app); |
| g->app = app; |
| |
| enum { |
| F = 0xffffu, |
| B = 0x9000u, |
| D = 0x7000u, |
| Q = 0x4000u }; |
| static const XRenderColor renderColors[GC_COUNT] = { |
| { 0, 0, Q, F }, |
| { 0, 0, D, F }, |
| { 0, 0, B, F }, |
| { 0, 0, F, F }, |
| { B, 0, F, F }, |
| { F, F, 0, F }, |
| { F, F, 0, F }, |
| { F, F, 0, F }, |
| { F, F, 0, F } }; |
| |
| static const char *fonts[] = FONTS; |
| static const int sizes[FONT_MAX_SIZES] = FONT_SIZES; |
| |
| LOGDBG("graph: init: create XftDraw"); |
| g->draw = XftDrawCreate( |
| g->app->dpy, |
| g->app->win, |
| DefaultVisual(g->app->dpy, g->app->screen), |
| DefaultColormap(g->app->dpy, g->app->screen) ); |
| if (!g->draw) |
| return LOGERR("graph: init: cannot create XftDraw"); |
| |
| LOGDBG("graph: init: open fonts"); |
| char buf[1024] = {}; |
| for(int i = 0; i < FONT_MAX_SIZES; ++i) { |
| if (!sizes[i]) break; |
| for(int j = 0; j < COUNTOF(fonts); ++j) { |
| snprintf(buf, sizeof(buf), "%s:size=%d", fonts[j], sizes[i]); |
| LOGDBG("graph: init: try open font [%s]", buf); |
| g->fonts[g->fontsCnt] = XftFontOpenName(g->app->dpy, g->app->screen, buf); |
| if (g->fonts[g->fontsCnt]) { |
| ++g->fontsCnt; |
| break; |
| } else { |
| LOGDBG("graph: init: cannot open font [%s]", buf); |
| } |
| } |
| } |
| |
| if (!g->fontsCnt) { |
| LOGERR("graph: init: cannot open any font"); |
| XftDrawDestroy(g->draw); |
| CLEARFROM(g, app); |
| return 0; |
| } |
| |
| LOGDBG("graph: init: allocate colors"); |
| for(int i = 0; i < GC_COUNT; ++i) { |
| XftColorAllocValue( |
| g->app->dpy, |
| DefaultVisual(g->app->dpy, g->app->screen), |
| DefaultColormap(g->app->dpy, g->app->screen), |
| &renderColors[i], |
| &g->colors[i] ); |
| } |
| |
| return 1; |
| } |
| |
| |
| void graphDeinit(Graph *g) { |
| LOGDBG("graph: deinit"); |
| for(int i = 0; i < GC_COUNT; ++i) |
| XftColorFree( |
| g->app->dpy, |
| DefaultVisual(g->app->dpy, g->app->screen), |
| DefaultColormap(g->app->dpy, g->app->screen), |
| &g->colors[i] ); |
| for(int i = 0; i < g->fontsCnt; ++i) |
| XftFontClose(g->app->dpy, g->fonts[i]); |
| XftDrawDestroy(g->draw); |
| } |
| |
| |
| void graphResize(Graph *g) |
| { } |
| |
| |
| void graphDrawBackgound(Graph *g, int x, int y, int w, int h) { |
| XftDrawRect(g->draw, &g->colors[GC_WINDOW], x, y, w, h); |
| } |
| |
| |
| void graphDrawButton(Graph *g, int x, int y, int w, int h, int active, int highlight) { |
| GraphStyle s = active == 1 ? GC_BUTTON_ACTIVE |
| : active == 2 ? GC_BUTTON_ACTIVE2 |
| : highlight ? GC_BUTTON_HIGHTLIGHT |
| : GC_BUTTON_INACTIVE; |
| XftDrawRect(g->draw, &g->colors[s], x, y, w, h); |
| } |
| |
| |
| |
| void textLayoutInit(TextLayout *tl, Graph *g, const char *text) { |
| CLEARFROM(tl, g); |
| tl->g = g; |
| |
| tl->len = text ? strlen(text) : 0; |
| tl->text = text; |
| if (!tl->len) |
| return; |
| |
| for(int i = 0; i < tl->g->fontsCnt; ++i) { |
| XGlyphInfo e = {}; |
| XftTextExtentsUtf8(g->app->dpy, g->fonts[i], (const FcChar8*)tl->text, tl->len, &e); |
| |
| int asc = tl->g->fonts[i]->ascent; |
| int desc = tl->g->fonts[i]->descent; |
| int w = e.width; |
| int minw = asc + asc/3; |
| int h = asc + desc; |
| |
| tl->sizes[i].x = e.x - w/2; |
| tl->sizes[i].y = asc/2; |
| tl->sizes[i].w = w < minw ? minw : w; |
| tl->sizes[i].h = h; |
| } |
| } |
| |
| |
| void textLayoutDeinit(TextLayout *tl) |
| { CLEARFROM(tl, g); } |
| |
| |
| void textLayoutDraw(TextLayout *tl, int x, int y, int w, int h, int active, int highlight) { |
| if (!tl->len) return; |
| GraphStyle s = active == 1 ? GC_TEXT_ACTIVE |
| : active == 2 ? GC_TEXT_ACTIVE2 |
| : highlight ? GC_TEXT_HIGHTLIGHT |
| : GC_TEXT_INACTIVE; |
| |
| |
| int i; |
| for(i = tl->g->fontsCnt - 1; i > 0; --i) |
| if (tl->sizes[i].w <= w && tl->sizes[i].h <= h) break; |
| |
| XftDrawStringUtf8( |
| tl->g->draw, |
| &tl->g->colors[s], |
| tl->g->fonts[i], |
| x + tl->sizes[i].x, |
| y + tl->sizes[i].y, |
| (const FcChar8*)tl->text, |
| tl->len ); |
| } |
| |