#include #include #include #include #include #include "draw.h" #include "button.h" #include "log.h" // Idea: Either make a to_draw queue where we put things we schedule to redraw // (this will also work for animations in the future) // or use some flags to trigger drawing static void layout_destroy(Layout *layout) { g_object_unref(layout->pl); g_free(layout); } Drawable *draw_create(const char *font, int height, int left_pad, int right_pad, int top_pad, double alpha) { Drawable *draw = g_malloc(sizeof(Drawable)); g_assert_nonnull(draw); log_debug("Pango loading font description '%s'", font); draw->desc = pango_font_description_from_string(font); log_debug("Pango found matching font '%s'", pango_font_description_get_family(draw->desc)); draw->height = height; draw->left_pad = left_pad; draw->right_pad = right_pad; draw->top_pad = top_pad; draw->alpha = alpha; g_assert(alpha >= 0 && alpha <= 1); draw->layouts = NULL; log_debug("Draw context created [height=%d, left_pad=%d, right_pad=%d, top_pad=%d, alpha=%.2lf]", height, left_pad, right_pad, top_pad, alpha); return draw; } void draw_paint(Drawable *draw, Window *win) { // FIXME: Does not work for scale != 1 //double scale = window_get_scale(win); double scale = 1; int screen_width, screen_height; window_get_screen_size(win, &screen_width, &screen_height); int width0 = screen_width - draw->right_pad - draw->left_pad; int width = round(width0 * scale); int height = round(draw->height * scale); cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(surface); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); int radius = height / 2; double degree = M_PI / 180.0; cairo_set_source_rgba(cr, 0.3, 0.3, 0.3, draw->alpha); // TODO: Here we should paint the shape of the bar, however there is a problem with the surface // painted in the pixmap to mask the window shape in window_paint_corners. // // This is caused by some difference between the two shapes (that should technically be the same) // which causes a mismatch between the two layers and leaves some black pixels visible //cairo_arc(cr, radius, radius, radius, 90.0 * degree, 270 * degree); //cairo_arc(cr, width - radius, radius, radius, 270 * degree, 450 * degree); //cairo_fill(cr); cairo_paint(cr); int line_w = 1 * scale; cairo_set_line_width(cr, line_w); for (GList *it = draw->layouts; it; it = it->next) { Layout *layout = it->data; int text_x = layout->x + (layout->width / 2) - (layout->text_w / 2); int text_y = layout->y + (layout->height / 2) - (layout->text_h / 2); // purple cairo_set_source_rgba(cr, 0.502, 0.168, 0.886, 1); cairo_new_sub_path(cr); cairo_arc(cr, layout->x + radius, layout->y + radius, radius, 90 * degree, 270 * degree); cairo_arc(cr, layout->x + layout->width - radius, layout->y + radius, radius, 270 * degree, 450 * degree); cairo_close_path(cr); cairo_fill(cr); cairo_set_source_rgba(cr, 0.8, 0.8, 0.8, 1); cairo_new_sub_path(cr); cairo_arc(cr, layout->x + radius, layout->y + radius, radius - line_w , 90 * degree, 270 * degree); cairo_arc(cr, layout->x + layout->width - radius, layout->y + radius, radius - line_w, 270 * degree, 450 * degree); cairo_close_path(cr); cairo_stroke(cr); cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); cairo_move_to(cr, text_x, text_y); pango_cairo_update_layout(cr, layout->pl); pango_cairo_show_layout(cr, layout->pl); } cairo_destroy(cr); // TODO: Move these somewhere else window_move(win, draw->left_pad, draw->top_pad); window_resize(win, width0, draw->height); window_paint_surface(win, surface, width, height); cairo_surface_destroy(surface); } void draw_compute_layout(Drawable *draw, GList *btns, cairo_t *cr) { g_list_free_full(draw->layouts, (GDestroyNotify)layout_destroy); draw->layouts = NULL; // FIXME: Does not work for scale != 1 //double scale = window_get_scale(win); double scale = 1; int x = 0; int height = round(draw->height * scale); int radius = height / 2; for (GList *it = btns; it; it = it->next) { Button *btn = it->data; Layout *layout = g_malloc(sizeof(Layout)); layout->btn = btn; layout->x = x; layout->y = 0; layout->pl = pango_cairo_create_layout(cr); pango_layout_set_font_description(layout->pl, draw->desc); pango_layout_set_text(layout->pl, btn->text, -1); pango_layout_set_alignment(layout->pl, PANGO_ALIGN_CENTER); int text_w, text_h; pango_layout_get_pixel_size(layout->pl, &text_w, &text_h); layout->text_w = ceil(text_w / scale); layout->text_h = ceil(text_h / scale); layout->width = btn->fixed_size ? height : layout->text_w + 2 * radius; layout->height = height; draw->layouts = g_list_append(draw->layouts, layout); int sep = 10 * scale; int line_w = 1 * scale; x += height + line_w * 2 + sep; } log_debug("Updated layouts"); } void draw_destroy(Drawable *draw) { g_list_free_full(draw->layouts, (GDestroyNotify)layout_destroy); pango_font_description_free(draw->desc); g_free(draw); } // vim: ts=4 sw=4 et