forked from RepoMirrors/bemenu
Working pango code.
This commit is contained in:
parent
9baca87123
commit
2bf8bbfcde
@ -7,14 +7,6 @@
|
||||
#include <cairo/cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
|
||||
#ifndef MAX
|
||||
# define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
# define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
struct cairo {
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
@ -28,7 +20,7 @@ struct cairo_color {
|
||||
struct cairo_paint {
|
||||
struct cairo_color fg;
|
||||
struct cairo_color bg;
|
||||
cairo_font_extents_t fe;
|
||||
const char *font;
|
||||
|
||||
struct box {
|
||||
int32_t lx, rx; // left/right offset (pos.x - lx, box.w + rx)
|
||||
@ -42,7 +34,13 @@ struct cairo_paint {
|
||||
};
|
||||
|
||||
struct cairo_result {
|
||||
cairo_text_extents_t te;
|
||||
uint32_t x_advance;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
struct cairo_paint_result {
|
||||
uint32_t displayed;
|
||||
uint32_t height;
|
||||
};
|
||||
|
||||
static size_t blen = 0;
|
||||
@ -76,19 +74,22 @@ bm_cairo_destroy(struct cairo *cairo)
|
||||
cairo_surface_destroy(cairo->surface);
|
||||
}
|
||||
|
||||
__attribute__((unused)) static void
|
||||
bm_cairo_get_font_extents(struct cairo *cairo, const struct bm_font *font, cairo_font_extents_t *fe)
|
||||
__attribute__((unused)) static PangoLayout*
|
||||
bm_pango_get_layout(struct cairo *cairo, struct cairo_paint *paint, const char *buffer)
|
||||
{
|
||||
assert(cairo && font && fe);
|
||||
cairo_select_font_face(cairo->cr, font->name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
|
||||
cairo_set_font_size(cairo->cr, font->size);
|
||||
cairo_font_extents(cairo->cr, fe);
|
||||
PangoLayout *layout = pango_cairo_create_layout(cairo->cr);
|
||||
pango_layout_set_text(layout, buffer, -1);
|
||||
PangoFontDescription *desc = pango_font_description_from_string(paint->font);
|
||||
pango_layout_set_font_description(layout, desc);
|
||||
pango_layout_set_single_paragraph_mode(layout, 1);
|
||||
pango_font_description_free(desc);
|
||||
return layout;
|
||||
}
|
||||
|
||||
__attribute__((unused)) BM_LOG_ATTR(3, 4) static bool
|
||||
bm_cairo_get_text_extents(struct cairo *cairo, struct cairo_result *result, const char *fmt, ...)
|
||||
__attribute__((unused)) BM_LOG_ATTR(4, 5) static bool
|
||||
bm_pango_get_text_extents(struct cairo *cairo, struct cairo_paint *paint, struct cairo_result *result, const char *fmt, ...)
|
||||
{
|
||||
assert(cairo && result && fmt);
|
||||
assert(cairo && paint && result && fmt);
|
||||
memset(result, 0, sizeof(struct cairo_result));
|
||||
|
||||
va_list args;
|
||||
@ -99,7 +100,13 @@ bm_cairo_get_text_extents(struct cairo *cairo, struct cairo_result *result, cons
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
cairo_text_extents(cairo->cr, buffer, &result->te);
|
||||
PangoRectangle rect;
|
||||
PangoLayout *layout = bm_pango_get_layout(cairo, paint, buffer);
|
||||
pango_layout_get_pixel_extents(layout, &rect, NULL);
|
||||
g_object_unref(layout);
|
||||
|
||||
result->x_advance = rect.x + rect.width;
|
||||
result->height = rect.height;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -117,33 +124,29 @@ bm_cairo_draw_line(struct cairo *cairo, struct cairo_paint *paint, struct cairo_
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
PangoLayout *layout = pango_cairo_create_layout(cairo->cr);
|
||||
pango_layout_set_text(layout, buffer, -1);
|
||||
PangoFontDescription *desc = pango_font_description_from_string("Terminus 12");
|
||||
pango_layout_set_font_description(layout, desc);
|
||||
pango_font_description_free(desc);
|
||||
PangoLayout *layout = bm_pango_get_layout(cairo, paint, buffer);
|
||||
pango_cairo_update_layout(cairo->cr, layout);
|
||||
|
||||
int width, height;
|
||||
pango_layout_get_size(layout, &width, &height);
|
||||
pango_layout_get_pixel_size(layout, &width, &height);
|
||||
int base = pango_layout_get_baseline(layout) / PANGO_SCALE;
|
||||
int yoff = height - base;
|
||||
|
||||
cairo_set_source_rgba(cairo->cr, paint->bg.r, paint->bg.b, paint->bg.g, paint->bg.a);
|
||||
cairo_rectangle(cairo->cr,
|
||||
paint->pos.x - paint->box.lx, paint->pos.y - paint->box.ty,
|
||||
(paint->box.w > 0 ? paint->box.w : width / PANGO_SCALE) + paint->box.rx + paint->box.lx,
|
||||
(paint->box.h > 0 ? paint->box.h : paint->fe.height) + paint->box.by + paint->box.ty);
|
||||
(paint->box.w > 0 ? paint->box.w : width) + paint->box.rx + paint->box.lx,
|
||||
(paint->box.h > 0 ? paint->box.h : height) + paint->box.by + paint->box.ty);
|
||||
cairo_fill(cairo->cr);
|
||||
|
||||
cairo_set_source_rgba(cairo->cr, paint->fg.r, paint->fg.b, paint->fg.g, paint->fg.a);
|
||||
cairo_move_to(cairo->cr, paint->box.lx + paint->pos.x, paint->pos.y - ((height * 0.25) / PANGO_SCALE) + paint->box.ty);
|
||||
cairo_move_to(cairo->cr, paint->box.lx + paint->pos.x, paint->pos.y - yoff + paint->box.ty);
|
||||
pango_cairo_show_layout(cairo->cr, layout);
|
||||
|
||||
g_object_unref(layout);
|
||||
|
||||
cairo_text_extents_t te;
|
||||
cairo_text_extents(cairo->cr, buffer, &te);
|
||||
|
||||
te.x_advance = width / PANGO_SCALE + paint->box.rx;
|
||||
memcpy(&result->te, &te, sizeof(te));
|
||||
result->x_advance = width + paint->box.rx;
|
||||
result->height = height + paint->box.by;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -157,10 +160,16 @@ bm_cairo_color_from_menu_color(const struct bm_menu *menu, enum bm_color color,
|
||||
c->a = 1.0f;
|
||||
}
|
||||
|
||||
__attribute__((unused)) static uint32_t
|
||||
bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu)
|
||||
__attribute__((unused)) static void
|
||||
bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu, struct cairo_paint_result *out_result)
|
||||
{
|
||||
assert(cairo && menu);
|
||||
assert(cairo && menu && out_result);
|
||||
|
||||
memset(out_result, 0, sizeof(struct cairo_paint_result));
|
||||
out_result->displayed = 1;
|
||||
|
||||
char font[128];
|
||||
snprintf(font, sizeof(font), "%s %d", menu->font.name, menu->font.size);
|
||||
|
||||
struct cairo_color c;
|
||||
bm_cairo_color_from_menu_color(menu, BM_COLOR_BG, &c);
|
||||
@ -170,37 +179,42 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struc
|
||||
|
||||
struct cairo_paint paint;
|
||||
memset(&paint, 0, sizeof(paint));
|
||||
bm_cairo_get_font_extents(cairo, &menu->font, &paint.fe);
|
||||
paint.font = font;
|
||||
|
||||
struct cairo_result result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
|
||||
uint32_t title_x = 0;
|
||||
if (menu->title) {
|
||||
bm_cairo_color_from_menu_color(menu, BM_COLOR_TITLE_FG, &paint.fg);
|
||||
bm_cairo_color_from_menu_color(menu, BM_COLOR_TITLE_BG, &paint.bg);
|
||||
paint.pos = (struct pos){ result.te.x_advance, 2 };
|
||||
paint.pos = (struct pos){ result.x_advance, 2 };
|
||||
paint.box = (struct box){ 4, 8, 2, 2, 0, 0 };
|
||||
bm_cairo_draw_line(cairo, &paint, &result, "%s", menu->title);
|
||||
title_x = result.x_advance;
|
||||
}
|
||||
|
||||
bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_FG, &paint.fg);
|
||||
bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_BG, &paint.bg);
|
||||
paint.pos = (struct pos){ (menu->title ? 2 : 0) + result.te.x_advance, 2 };
|
||||
paint.pos = (struct pos){ (menu->title ? 2 : 0) + result.x_advance, 2 };
|
||||
paint.box = (struct box){ (menu->title ? 2 : 4), 0, 2, 2, width - paint.pos.x, 0 };
|
||||
bm_cairo_draw_line(cairo, &paint, &result, "%s", (menu->filter ? menu->filter : ""));
|
||||
out_result->height = result.height;
|
||||
|
||||
uint32_t count;
|
||||
struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
|
||||
uint32_t lines = (menu->lines > 0 ? menu->lines : 1);
|
||||
|
||||
uint32_t displayed = 1;
|
||||
uint32_t lines = MAX(height / (paint.fe.height + 4), 1);
|
||||
if (lines > 1) {
|
||||
/* vertical mode */
|
||||
uint32_t start_x = 0;
|
||||
if (menu->prefix) {
|
||||
bm_cairo_get_text_extents(cairo, &result, "%s ", menu->prefix);
|
||||
start_x = result.te.x_advance;
|
||||
bm_pango_get_text_extents(cairo, &paint, &result, "%s ", menu->prefix);
|
||||
start_x = result.x_advance;
|
||||
}
|
||||
|
||||
uint32_t count, cl = 1;
|
||||
struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
|
||||
for (uint32_t i = (menu->index / (lines - 1)) * (lines - 1); i < count && cl < lines; ++i) {
|
||||
uint32_t posy = out_result->height;
|
||||
for (uint32_t l = 0, i = (menu->index / lines) * lines; l < lines && i < count; ++i, ++l) {
|
||||
bool highlighted = (items[i] == bm_menu_get_highlighted_item(menu));
|
||||
|
||||
if (highlighted) {
|
||||
@ -215,27 +229,29 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struc
|
||||
}
|
||||
|
||||
if (menu->prefix && highlighted) {
|
||||
paint.pos = (struct pos){ 0, 2 + (paint.fe.height + 4) * cl++ };
|
||||
paint.pos = (struct pos){ 0, 2 + posy };
|
||||
paint.box = (struct box){ 4, 0, 2, 2, width - paint.pos.x, 0 };
|
||||
bm_cairo_draw_line(cairo, &paint, &result, "%s %s", menu->prefix, (items[i]->text ? items[i]->text : ""));
|
||||
} else {
|
||||
paint.pos = (struct pos){ 0, 2 + (paint.fe.height + 4) * cl++ };
|
||||
paint.pos = (struct pos){ 0, 2 + posy };
|
||||
paint.box = (struct box){ 4 + start_x, 0, 2, 2, width - paint.pos.x, 0 };
|
||||
bm_cairo_draw_line(cairo, &paint, &result, "%s", (items[i]->text ? items[i]->text : ""));
|
||||
}
|
||||
|
||||
++displayed;
|
||||
posy += result.height;
|
||||
out_result->height = posy + 2;
|
||||
out_result->displayed++;
|
||||
}
|
||||
} else {
|
||||
uint32_t count;
|
||||
struct bm_item **items = bm_menu_get_filtered_items(menu, &count);
|
||||
/* single-line mode */
|
||||
bm_pango_get_text_extents(cairo, &paint, &result, "lorem ipsum lorem ipsum lorem ipsum lorem");
|
||||
uint32_t cl = fmin(title_x + result.x_advance, width / 4);
|
||||
|
||||
uint32_t cl = width / 4;
|
||||
if (menu->wrap || menu->index > 0) {
|
||||
paint.pos = (struct pos){ cl, 2 };
|
||||
paint.box = (struct box){ 1, 2, 2, 2, 0, 0 };
|
||||
bm_cairo_draw_line(cairo, &paint, &result, "<");
|
||||
cl += result.te.x_advance + 1;
|
||||
cl += result.x_advance + 1;
|
||||
}
|
||||
|
||||
for (uint32_t i = menu->index; i < count && cl < width; ++i) {
|
||||
@ -255,21 +271,20 @@ bm_cairo_paint(struct cairo *cairo, uint32_t width, uint32_t height, const struc
|
||||
paint.pos = (struct pos){ cl, 2 };
|
||||
paint.box = (struct box){ 2, 4, 2, 2, 0, 0 };
|
||||
bm_cairo_draw_line(cairo, &paint, &result, "%s", (items[i]->text ? items[i]->text : ""));
|
||||
cl += result.te.x_advance + 2;
|
||||
displayed += (cl < width);
|
||||
cl += result.x_advance + 2;
|
||||
out_result->displayed += (cl < width);
|
||||
out_result->height = fmax(out_result->height, result.height);
|
||||
}
|
||||
|
||||
if (menu->wrap || menu->index + 1 < count) {
|
||||
bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_FG, &paint.fg);
|
||||
bm_cairo_color_from_menu_color(menu, BM_COLOR_FILTER_BG, &paint.bg);
|
||||
bm_cairo_get_text_extents(cairo, &result, ">");
|
||||
paint.pos = (struct pos){ width - result.te.x_advance - 2, 2 };
|
||||
bm_pango_get_text_extents(cairo, &paint, &result, ">");
|
||||
paint.pos = (struct pos){ width - result.x_advance - 2, 2 };
|
||||
paint.box = (struct box){ 1, 2, 2, 2, 0, 0 };
|
||||
bm_cairo_draw_line(cairo, &paint, &result, ">");
|
||||
}
|
||||
}
|
||||
|
||||
return displayed;
|
||||
}
|
||||
|
||||
#endif /* _BM_CAIRO_H */
|
||||
|
@ -39,10 +39,7 @@ render(const struct bm_menu *menu)
|
||||
}
|
||||
|
||||
if (wayland->input.code != wayland->input.last_code) {
|
||||
uint32_t count;
|
||||
bm_menu_get_filtered_items(menu, &count);
|
||||
uint32_t lines = (count < menu->lines ? count : menu->lines) + 1;
|
||||
bm_wl_window_render(&wayland->window, menu, lines);
|
||||
bm_wl_window_render(&wayland->window, menu);
|
||||
wayland->input.last_code = wayland->input.code;
|
||||
}
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ struct window {
|
||||
uint32_t displayed;
|
||||
|
||||
struct {
|
||||
uint32_t (*render)(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu);
|
||||
void (*render)(struct cairo *cairo, uint32_t width, uint32_t height, const struct bm_menu *menu, struct cairo_paint_result *result);
|
||||
} notify;
|
||||
};
|
||||
|
||||
@ -111,7 +111,7 @@ struct wayland {
|
||||
void bm_wl_repeat(struct wayland *wayland);
|
||||
bool bm_wl_registry_register(struct wayland *wayland);
|
||||
void bm_wl_registry_destroy(struct wayland *wayland);
|
||||
void bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines);
|
||||
void bm_wl_window_render(struct window *window, const struct bm_menu *menu);
|
||||
bool bm_wl_window_create(struct window *window, struct wl_shm *shm, struct wl_shell *shell, struct xdg_shell *xdg_shell, struct wl_surface *surface);
|
||||
void bm_wl_window_destroy(struct window *window);
|
||||
|
||||
|
@ -248,7 +248,7 @@ static const struct wl_callback_listener listener = {
|
||||
};
|
||||
|
||||
void
|
||||
bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t lines)
|
||||
bm_wl_window_render(struct window *window, const struct bm_menu *menu)
|
||||
{
|
||||
assert(window && menu);
|
||||
|
||||
@ -256,23 +256,26 @@ bm_wl_window_render(struct window *window, const struct bm_menu *menu, uint32_t
|
||||
return;
|
||||
|
||||
struct buffer *buffer;
|
||||
if (!(buffer = next_buffer(window))) {
|
||||
fprintf(stderr, "could not get next buffer");
|
||||
exit(EXIT_FAILURE);
|
||||
for (int tries = 0; tries < 2; ++tries) {
|
||||
if (!(buffer = next_buffer(window))) {
|
||||
fprintf(stderr, "could not get next buffer");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!window->notify.render)
|
||||
break;
|
||||
|
||||
struct cairo_paint_result result;
|
||||
window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu, &result);
|
||||
window->displayed = result.displayed;
|
||||
|
||||
if (window->height == result.height)
|
||||
break;
|
||||
|
||||
window->height = result.height;
|
||||
destroy_buffer(buffer);
|
||||
}
|
||||
|
||||
cairo_font_extents_t fe;
|
||||
bm_cairo_get_font_extents(&buffer->cairo, &menu->font, &fe);
|
||||
window->height = MIN(lines * (fe.height + 4), window->max_height);
|
||||
|
||||
if (window->height != buffer->height && !(buffer = next_buffer(window))) {
|
||||
fprintf(stderr, "could not get next buffer");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (window->notify.render)
|
||||
window->displayed = window->notify.render(&buffer->cairo, buffer->width, buffer->height, menu);
|
||||
|
||||
window->frame_cb = wl_surface_frame(window->surface);
|
||||
wl_callback_add_listener(window->frame_cb, &listener, window);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user