static gboolean gtk_notification_draw (GtkWidget *widget, cairo_t *cr) { GtkNotification *notification = GTK_NOTIFICATION (widget); GtkNotificationPrivate *priv = notification->priv; GtkStyleContext *context; GdkRectangle rect; int inner_radius; if (gtk_cairo_should_draw_window (cr, priv->bin_window)) { gtk_widget_get_allocation (widget, &rect); context = gtk_widget_get_style_context(widget); inner_radius = 5; draw_shadow_box (cr, rect, SHADOW_OFFSET_X + inner_radius, SHADOW_OFFSET_X + inner_radius, SHADOW_OFFSET_Y + inner_radius, 0.8); gtk_style_context_save (context); gtk_render_background (context, cr, SHADOW_OFFSET_X, 0, gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X, gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y); gtk_render_frame (context,cr, SHADOW_OFFSET_X, 0, gtk_widget_get_allocated_width (widget) - 2 *SHADOW_OFFSET_X, gtk_widget_get_allocated_height (widget) - SHADOW_OFFSET_Y); gtk_style_context_restore (context); if (GTK_WIDGET_CLASS (gtk_notification_parent_class)->draw) GTK_WIDGET_CLASS (gtk_notification_parent_class)->draw(widget, cr); } return FALSE; }
static void draw_horizontal_scrollbar (GtkWidget *widget, cairo_t *cr, gint x, gint y, gint width, gint height, gint position, GtkStateFlags state) { GtkStyleContext *scrollbar_context; GtkStyleContext *trough_context; GtkStyleContext *slider_context; /* This information is taken from the GtkScrollbar docs, see "CSS nodes" */ const char *path[3] = { "scrollbar.horizontal", "trough", "slider" }; scrollbar_context = get_style (NULL, path[0]); trough_context = get_style (scrollbar_context, path[1]); slider_context = get_style (trough_context, path[2]); gtk_style_context_set_state (scrollbar_context, state); gtk_style_context_set_state (trough_context, state); gtk_style_context_set_state (slider_context, state); gtk_render_background (trough_context, cr, x, y, width, height); gtk_render_frame (trough_context, cr, x, y, width, height); gtk_render_slider (slider_context, cr, x + position, y + 1, 30, height - 2, GTK_ORIENTATION_HORIZONTAL); g_object_unref (slider_context); g_object_unref (trough_context); g_object_unref (scrollbar_context); }
static void gtk_do_render_handle (GtkStyleContext *context, cairo_t *cr, gdouble x, gdouble y, gdouble width, gdouble height) { GtkCssImageBuiltinType type; gtk_render_background (context, cr, x, y, width, height); gtk_render_frame (context, cr, x, y, width, height); if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_PANE_SEPARATOR)) { type = GTK_CSS_IMAGE_BUILTIN_PANE_SEPARATOR; } else { type = GTK_CSS_IMAGE_BUILTIN_HANDLE; } gtk_css_style_render_icon (gtk_style_context_lookup_style (context), cr, x, y, width, height, type); }
static gboolean draw_arrow_cb (GtkWidget *widget, cairo_t *cr, gpointer data) { GncItemEdit *item_edit = GNC_ITEM_EDIT (data); GtkStyleContext *context = gtk_widget_get_style_context (widget); gint width = gtk_widget_get_allocated_width (widget); gint height = gtk_widget_get_allocated_height (widget); gint size; gtk_render_background (context, cr, 0, 0, width, height); gtk_style_context_add_class (context, GTK_STYLE_CLASS_ARROW); size = MIN(width / 2, height / 2); if (item_edit->popup_toggle.arrow_down == 0) gtk_render_arrow (context, cr, 0, (width - size)/2, (height - size)/2, size); else gtk_render_arrow (context, cr, G_PI, (width - size)/2, (height - size)/2, size); return FALSE; }
/** * gd_create_symbolic_icon: * @name: * * Returns: (transfer full): */ GIcon * gd_create_symbolic_icon (const gchar *name, gint base_size) { gchar *symbolic_name; GIcon *icon, *retval = NULL; cairo_surface_t *surface; cairo_t *cr; GtkStyleContext *style; GtkWidgetPath *path; GdkPixbuf *pixbuf; GtkIconTheme *theme; GtkIconInfo *info; gint bg_size; gint emblem_size; gint total_size; total_size = base_size / 2; bg_size = MAX (total_size / 2, _BG_MIN_SIZE); emblem_size = MAX (bg_size - 8, _EMBLEM_MIN_SIZE); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, total_size, total_size); cr = cairo_create (surface); style = gtk_style_context_new (); path = gtk_widget_path_new (); gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); gtk_style_context_set_path (style, path); gtk_widget_path_unref (path); gtk_style_context_add_class (style, "documents-icon-bg"); gtk_render_background (style, cr, (total_size - bg_size) / 2, (total_size - bg_size) / 2, bg_size, bg_size); symbolic_name = g_strconcat (name, "-symbolic", NULL); icon = g_themed_icon_new_with_default_fallbacks (symbolic_name); g_free (symbolic_name); theme = gtk_icon_theme_get_default(); info = gtk_icon_theme_lookup_by_gicon (theme, icon, emblem_size, GTK_ICON_LOOKUP_FORCE_SIZE); g_object_unref (icon); if (info == NULL) goto out; pixbuf = gtk_icon_info_load_symbolic_for_context (info, style, NULL, NULL); gtk_icon_info_free (info); if (pixbuf == NULL) goto out; gtk_render_icon (style, cr, pixbuf, (total_size - emblem_size) / 2, (total_size - emblem_size) / 2); g_object_unref (pixbuf); retval = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, total_size, total_size)); out: g_object_unref (style); cairo_surface_destroy (surface); cairo_destroy (cr); return retval; }
/** * gd_create_collection_icon: * @base_size: * @pixbufs: (element-type GdkPixbuf): * * Returns: (transfer full): */ GIcon * gd_create_collection_icon (gint base_size, GList *pixbufs) { cairo_surface_t *surface; GIcon *retval; cairo_t *cr; GtkStyleContext *context; GtkWidgetPath *path; gint padding, tile_size, scale_size; gint pix_width, pix_height; gint idx, cur_x, cur_y; GList *l; GdkPixbuf *pix; /* TODO: do not hardcode 4, but scale to another layout if more * pixbufs are provided. */ padding = MAX (floor (base_size / 10), 4); tile_size = (base_size - (3 * padding)) / 2; context = gtk_style_context_new (); gtk_style_context_add_class (context, "documents-collection-icon"); path = gtk_widget_path_new (); gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); gtk_style_context_set_path (context, path); gtk_widget_path_unref (path); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, base_size, base_size); cr = cairo_create (surface); gtk_render_background (context, cr, 0, 0, base_size, base_size); l = pixbufs; idx = 0; cur_x = padding; cur_y = padding; while (l != NULL && idx < 4) { pix = l->data; pix_width = gdk_pixbuf_get_width (pix); pix_height = gdk_pixbuf_get_height (pix); scale_size = MIN (pix_width, pix_height); cairo_save (cr); cairo_translate (cr, cur_x, cur_y); cairo_rectangle (cr, 0, 0, tile_size, tile_size); cairo_clip (cr); cairo_scale (cr, (gdouble) tile_size / (gdouble) scale_size, (gdouble) tile_size / (gdouble) scale_size); gdk_cairo_set_source_pixbuf (cr, pix, 0, 0); cairo_paint (cr); cairo_restore (cr); if ((idx % 2) == 0) { cur_x += tile_size + padding; } else { cur_x = padding; cur_y += tile_size + padding; } idx++; l = l->next; } retval = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, base_size, base_size)); cairo_surface_destroy (surface); cairo_destroy (cr); g_object_unref (context); return retval; }
GIcon * photos_utils_create_collection_icon (gint base_size, GList *pixbufs) { cairo_surface_t *surface; /* TODO: use g_autoptr */ cairo_t *cr; /* TODO: use g_autoptr */ GdkPixbuf *pix; GIcon *ret_val; GList *l; g_autoptr (GtkStyleContext) context = NULL; g_autoptr (GtkWidgetPath) path = NULL; gint cur_x; gint cur_y; gint padding; gint pix_height; gint pix_width; gint scale_size; gint tile_size; guint idx; guint n_grid; guint n_pixbufs; guint n_tiles; n_pixbufs = g_list_length (pixbufs); if (n_pixbufs < 3) { n_grid = 1; n_tiles = 1; } else { n_grid = 2; n_tiles = 4; } padding = MAX (base_size / 10, 4); tile_size = (base_size - ((n_grid + 1) * padding)) / n_grid; context = gtk_style_context_new (); gtk_style_context_add_class (context, "photos-collection-icon"); path = gtk_widget_path_new (); gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); gtk_style_context_set_path (context, path); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, base_size, base_size); cr = cairo_create (surface); gtk_render_background (context, cr, 0, 0, base_size, base_size); l = pixbufs; idx = 0; cur_x = padding; cur_y = padding; while (l != NULL && idx < n_tiles) { pix = l->data; pix_width = gdk_pixbuf_get_width (pix); pix_height = gdk_pixbuf_get_height (pix); scale_size = MIN (pix_width, pix_height); cairo_save (cr); cairo_translate (cr, cur_x, cur_y); cairo_rectangle (cr, 0, 0, tile_size, tile_size); cairo_clip (cr); cairo_scale (cr, (gdouble) tile_size / (gdouble) scale_size, (gdouble) tile_size / (gdouble) scale_size); gdk_cairo_set_source_pixbuf (cr, pix, 0, 0); cairo_paint (cr); cairo_restore (cr); idx++; l = l->next; if ((idx % n_grid) == 0) { cur_x = padding; cur_y += tile_size + padding; } else { cur_x += tile_size + padding; } } ret_val = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, base_size, base_size)); cairo_surface_destroy (surface); cairo_destroy (cr); return ret_val; }
static gboolean gstyle_color_widget_draw (GtkWidget *widget, cairo_t *cr) { GstyleColorWidget *self = (GstyleColorWidget *)widget; GtkStyleContext *style_context; GdkRectangle margin_box; GdkRectangle border_box; cairo_matrix_t matrix; GdkRGBA bg_color = {0}; gint radius; g_assert (GSTYLE_IS_COLOR_WIDGET (self)); g_assert (cr != NULL); style_context = gtk_widget_get_style_context (GTK_WIDGET (self)); gtk_widget_get_allocation (widget, &margin_box); margin_box.x = margin_box.y = 0; gstyle_utils_get_rect_resized_box (margin_box, &margin_box, &self->cached_margin); gstyle_utils_get_rect_resized_box (margin_box, &border_box, &self->cached_border); cairo_save (cr); if (self->color != NULL) { gtk_style_context_get (style_context, gtk_style_context_get_state (style_context), "border-radius", &radius, NULL); gstyle_color_fill_rgba (self->color, &bg_color); if (self->filter_func != NULL) self->filter_func (&bg_color, &bg_color, self->filter_user_data); cairo_new_path (cr); draw_cairo_round_box (cr, border_box, radius, radius, radius, radius); } else cairo_rectangle (cr, border_box.x, border_box.y, border_box.width, border_box.height); cairo_clip_preserve (cr); cairo_set_source_rgb (cr, 0.20, 0.20, 0.20); cairo_paint (cr); cairo_set_source_rgb (cr, 0.80, 0.80, 0.80); cairo_matrix_init_scale (&matrix, 0.1, 0.1); cairo_matrix_translate (&matrix, -border_box.x, -border_box.y); cairo_pattern_set_matrix (self->checkered_pattern, &matrix); cairo_mask (cr, self->checkered_pattern); if (self->color != NULL) { gdk_cairo_set_source_rgba (cr, &bg_color); cairo_fill (cr); } else gtk_render_background (style_context, cr, border_box.x, border_box.y, border_box.width, border_box.height); cairo_restore (cr); gtk_render_frame (gtk_widget_get_style_context (widget), cr, margin_box.x, margin_box.y, margin_box.width, margin_box.height); return GTK_WIDGET_CLASS (gstyle_color_widget_parent_class)->draw (widget, cr); }
static void gnc_header_draw_offscreen (GncHeader *header) { SheetBlockStyle *style = header->style; Table *table = header->sheet->table; VirtualLocation virt_loc; VirtualCell *vcell; guint32 color_type; GtkStyleContext *stylectxt = gtk_widget_get_style_context (GTK_WIDGET(header)); GdkRGBA color; int row_offset; CellBlock *cb; int i; cairo_t *cr; virt_loc.vcell_loc.virt_row = 0; virt_loc.vcell_loc.virt_col = 0; virt_loc.phys_row_offset = 0; virt_loc.phys_col_offset = 0; gtk_style_context_save (stylectxt); // Get the background color type and apply the css class color_type = gnc_table_get_bg_color (table, virt_loc, NULL); gnucash_get_style_classes (header->sheet, stylectxt, color_type); if (header->surface) cairo_surface_destroy (header->surface); header->surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, header->width, header->height); cr = cairo_create (header->surface); // Fill background color of header gtk_render_background (stylectxt, cr, 0, 0, header->width, header->height); gdk_rgba_parse (&color, "black"); cairo_set_source_rgb (cr, color.red, color.green, color.blue); cairo_rectangle (cr, 0.5, 0.5, header->width - 1.0, header->height - 1.0); cairo_set_line_width (cr, 1.0); cairo_stroke (cr); // Draw bottom horizontal line, makes bottom line thicker cairo_move_to (cr, 0.5, header->height - 1.5); cairo_line_to (cr, header->width - 1.0, header->height - 1.5); cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_set_line_width (cr, 1.0); cairo_stroke (cr); /*font = gnucash_register_font;*/ vcell = gnc_table_get_virtual_cell (table, table->current_cursor_loc.vcell_loc); cb = vcell ? vcell->cellblock : NULL; row_offset = 0; for (i = 0; i < style->nrows; i++) { int col_offset = 0; int h = 0, j; virt_loc.phys_row_offset = i; /* TODO: This routine is duplicated in several places. Can we abstract at least the cell drawing routine? That way we'll be sure everything is drawn consistently, and cut down on maintenance issues. */ for (j = 0; j < style->ncols; j++) { CellDimensions *cd; double text_x, text_y, text_w, text_h; BasicCell *cell; const char *text; int w; PangoLayout *layout; virt_loc.phys_col_offset = j; cd = gnucash_style_get_cell_dimensions (style, i, j); h = cd->pixel_height; if (header->in_resize && (j == header->resize_col)) w = header->resize_col_width; else w = cd->pixel_width; cell = gnc_cellblock_get_cell (cb, i, j); if (!cell || !cell->cell_name) { col_offset += w; continue; } cairo_rectangle (cr, col_offset - 0.5, row_offset + 0.5, w, h); cairo_set_line_width (cr, 1.0); cairo_stroke (cr); virt_loc.vcell_loc = table->current_cursor_loc.vcell_loc; text = gnc_table_get_label (table, virt_loc); if (!text) text = ""; layout = gtk_widget_create_pango_layout (GTK_WIDGET (header->sheet), text); switch (gnc_table_get_align (table, virt_loc)) { default: case CELL_ALIGN_LEFT: pango_layout_set_alignment (layout, PANGO_ALIGN_LEFT); break; case CELL_ALIGN_RIGHT: pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); break; case CELL_ALIGN_CENTER: pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); break; } text_x = col_offset + CELL_HPADDING; text_y = row_offset + 1; text_w = MAX (0, w - (2 * CELL_HPADDING)); text_h = h - 2; cairo_save (cr); cairo_rectangle (cr, text_x, text_y, text_w, text_h); cairo_clip (cr); gtk_render_layout (stylectxt, cr, text_x, text_y, layout); cairo_restore (cr); g_object_unref (layout); col_offset += w; } row_offset += h; } gtk_style_context_restore (stylectxt); cairo_destroy (cr); }
static gboolean dt_iop_zonesystem_preview_draw(GtkWidget *widget, cairo_t *crf, dt_iop_module_t *self) { const int inset = DT_PIXEL_APPLY_DPI(2); GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; dt_iop_zonesystem_gui_data_t *g = (dt_iop_zonesystem_gui_data_t *)self->gui_data; dt_iop_zonesystem_params_t *p = (dt_iop_zonesystem_params_t *)self->params; cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); /* clear background */ GtkStyleContext *context = gtk_widget_get_style_context(self->expander); gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height); width -= 2 * inset; height -= 2 * inset; cairo_translate(cr, inset, inset); dt_pthread_mutex_lock(&g->lock); if(g->in_preview_buffer && g->out_preview_buffer && self->enabled) { /* calculate the zonemap */ float zonemap[MAX_ZONE_SYSTEM_SIZE] = { -1 }; _iop_zonesystem_calculate_zonemap(p, zonemap); /* let's generate a pixbuf from pixel zone buffer */ guchar *image = g_malloc_n((size_t)4 * g->preview_width * g->preview_height, sizeof(guchar)); guchar *buffer = g->mouse_over_output_zones ? g->out_preview_buffer : g->in_preview_buffer; for(int k = 0; k < g->preview_width * g->preview_height; k++) { int zone = 255 * CLIP(((1.0 / (p->size - 1)) * buffer[k])); image[4 * k + 2] = (g->hilite_zone && buffer[k] == g->zone_under_mouse) ? 255 : zone; image[4 * k + 1] = (g->hilite_zone && buffer[k] == g->zone_under_mouse) ? 255 : zone; image[4 * k + 0] = (g->hilite_zone && buffer[k] == g->zone_under_mouse) ? 0 : zone; } dt_pthread_mutex_unlock(&g->lock); const int wd = g->preview_width, ht = g->preview_height; const float scale = fminf(width / (float)wd, height / (float)ht); const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wd); cairo_surface_t *surface = cairo_image_surface_create_for_data(image, CAIRO_FORMAT_RGB24, wd, ht, stride); cairo_translate(cr, width / 2.0, height / 2.0f); cairo_scale(cr, scale, scale); cairo_translate(cr, -.5f * wd, -.5f * ht); cairo_rectangle(cr, DT_PIXEL_APPLY_DPI(1), DT_PIXEL_APPLY_DPI(1), wd - DT_PIXEL_APPLY_DPI(2), ht - DT_PIXEL_APPLY_DPI(2)); cairo_set_source_surface(cr, surface, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD); cairo_fill_preserve(cr); cairo_surface_destroy(surface); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0)); cairo_set_source_rgb(cr, .1, .1, .1); cairo_stroke(cr); g_free(image); } else { dt_pthread_mutex_unlock(&g->lock); // draw a big, subdued dt logo if(g->image) { GdkRGBA *color; gtk_style_context_get(context, gtk_widget_get_state_flags(self->expander), "background-color", &color, NULL); cairo_set_source_surface(cr, g->image, (width - g->image_width) * 0.5, (height - g->image_height) * 0.5); cairo_rectangle(cr, 0, 0, width, height); cairo_set_operator(cr, CAIRO_OPERATOR_HSL_LUMINOSITY); cairo_fill_preserve(cr); cairo_set_operator(cr, CAIRO_OPERATOR_DARKEN); cairo_set_source_rgb(cr, color->red + 0.02, color->green + 0.02, color->blue + 0.02); cairo_fill_preserve(cr); cairo_set_operator(cr, CAIRO_OPERATOR_LIGHTEN); cairo_set_source_rgb(cr, color->red - 0.02, color->green - 0.02, color->blue - 0.02); cairo_fill(cr); gdk_rgba_free(color); } } cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }
static gboolean digital_clock_draw(GtkWidget * w, cairo_t * cr) { DigitalClock *dclock = DIGITAL_CLOCK(w); DigitalClockPriv*priv=dclock->priv; struct timeval tv; if (gettimeofday(&tv, NULL) == -1) { g_critical("gettimeofday() failed!"); } time_t now = tv.tv_sec; // time_t now = time (NULL); struct tm *now_tm = localtime(&now); double width, height, fontsiz; width = (double) priv->width; height = (double)priv->height; fontsiz = (double) priv->fsiz; static gboolean draw_colon; static int now_sec = -1; static int last_msec=-1; // cairo_scale(cr,width,height); // cairo_set_source_rgb (cr, 1, 1, 1); // cairo_paint (cr); gtk_render_background(gtk_widget_get_style_context(w), cr, 0, 0, priv->width, priv->height); if (priv->sensitive || time_val_is_null(priv->time_val)) { if(!priv->blink||last_msec<=500)//||now_sec!=now_tm->tm_sec) draw_colon=TRUE; else draw_colon=FALSE; if (priv->show_sec) { if (draw_colon) sprintf(priv->time_val, "%02d:%02d:%02d", now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec); else sprintf(priv->time_val, "%02d %02d %02d", now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec); if (priv->show_msec) { sprintf(priv->time_val+ 8, ".%d", (int) (tv.tv_usec / 1000.0 + 0.5)); } } else { if (draw_colon) sprintf(priv->time_val, "%02d:%02d", now_tm->tm_hour, now_tm->tm_min); else sprintf(priv->time_val, "%02d %02d", now_tm->tm_hour, now_tm->tm_min); } // now_sec = now_tm->tm_sec; } last_msec=(int) (tv.tv_usec / 1000.0 + 0.5); // printf("Time::[%s].%03u %06u\n", TimeStr,last_msec,tv.tv_usec); cairo_select_font_face(cr, priv->font, CAIRO_FONT_SLANT_NORMAL,CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, fontsiz); cairo_text_extents_t extents; if (priv->show_sec) { cairo_text_extents(cr, "00:00:00", &extents); if (priv->show_msec) cairo_text_extents(cr, "00:00:00.000", &extents); } else cairo_text_extents(cr, "00:00", &extents); double x = width / 2 - extents.width / 2 - extents.x_bearing; double y = height / 2 - extents.height / 2 - extents.y_bearing; cairo_set_source_rgb(cr, 0, 0, 0); cairo_move_to(cr, x, y); cairo_show_text(cr, priv->time_val); return TRUE; }
static gboolean swatch_draw (GtkWidget *widget, cairo_t *cr) { GtkColorSwatch *swatch = (GtkColorSwatch*)widget; gdouble width, height; GtkStyleContext *context; GtkStateFlags state; GtkIconTheme *theme; GtkBorder border, padding; GdkRectangle rect; GtkIconInfo *icon_info = NULL; theme = gtk_icon_theme_get_default (); context = gtk_widget_get_style_context (widget); state = gtk_style_context_get_state (context); width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); gtk_render_background (context, cr, 0, 0, width, height); if (swatch->priv->has_color) { cairo_pattern_t *pattern; cairo_matrix_t matrix; gtk_render_content_path (context, cr, 0, 0, width, height); if (swatch->priv->use_alpha) { cairo_save (cr); cairo_clip_preserve (cr); cairo_set_source_rgb (cr, 0.33, 0.33, 0.33); cairo_fill_preserve (cr); pattern = _gtk_color_chooser_get_checkered_pattern (); cairo_matrix_init_scale (&matrix, 0.125, 0.125); cairo_pattern_set_matrix (pattern, &matrix); cairo_set_source_rgb (cr, 0.66, 0.66, 0.66); cairo_mask (cr, pattern); cairo_pattern_destroy (pattern); cairo_restore (cr); gdk_cairo_set_source_rgba (cr, &swatch->priv->color); } else { cairo_set_source_rgb (cr, swatch->priv->color.red, swatch->priv->color.green, swatch->priv->color.blue); } cairo_fill (cr); } gtk_render_frame (context, cr, 0, 0, width, height); if (swatch->priv->icon) { icon_info = gtk_icon_theme_lookup_icon (theme, swatch->priv->icon, PIXBUF_SIZE, GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_USE_BUILTIN); } else if ((state & GTK_STATE_FLAG_SELECTED) != 0) { GIcon *gicon; gicon = g_themed_icon_new ("object-select-symbolic"); /* fallback for themes that don't have object-select-symbolic */ g_themed_icon_append_name (G_THEMED_ICON (gicon), "gtk-apply"); icon_info = gtk_icon_theme_lookup_by_gicon (theme, gicon, PIXBUF_SIZE, GTK_ICON_LOOKUP_GENERIC_FALLBACK | GTK_ICON_LOOKUP_USE_BUILTIN); g_object_unref (gicon); } /* now draw the overlay image */ gtk_style_context_get_border (context, state, &border); gtk_style_context_get_padding (context, state, &padding); rect.width = width - (border.left + border.right + padding.left + padding.right); rect.height = height - (border.top + border.bottom + padding.top + padding.bottom); rect.x = border.left + padding.left; rect.y = border.top + padding.top; gtk_style_context_save (context); gtk_style_context_add_class (context, "overlay"); gtk_render_background (context, cr, rect.x, rect.y, rect.width, rect.height); gtk_render_frame (context, cr, rect.x, rect.y, rect.width, rect.height); if (icon_info != NULL) { GdkPixbuf *pixbuf; pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info, context, NULL, NULL); if (pixbuf != NULL) { gtk_render_icon (context, cr, pixbuf, rect.x + (rect.width - gdk_pixbuf_get_width (pixbuf)) / 2, rect.y + (rect.height - gdk_pixbuf_get_height (pixbuf)) / 2); g_object_unref (pixbuf); } g_object_unref (icon_info); } if (gtk_widget_has_visible_focus (widget)) { gtk_render_focus (context, cr, 0, 0, width, height); } gtk_style_context_restore (context); return FALSE; }
static void gtk_level_bar_draw_fill_discrete (GtkLevelBar *self, cairo_t *cr, cairo_rectangle_int_t *fill_area) { GtkWidget *widget = GTK_WIDGET (self); GtkStyleContext *context; gint num_blocks, i; gint block_width, block_height; gint block_draw_width, block_draw_height; GtkBorder block_margin; cairo_rectangle_int_t block_area; context = gtk_widget_get_style_context (widget); gtk_level_bar_get_min_block_size (self, &block_width, &block_height); block_area = *fill_area; num_blocks = (gint) round (self->priv->max_value) - (gint) round (self->priv->min_value); if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) block_width = MAX (block_width, (gint) floor (block_area.width / num_blocks)); else block_height = MAX (block_height, (gint) floor (block_area.height / num_blocks)); gtk_style_context_save_to_node (context, self->priv->block_node[0]); gtk_style_context_get_margin (context, gtk_style_context_get_state (context), &block_margin); gtk_style_context_restore (context); block_draw_width = block_width - block_margin.left - block_margin.right; block_draw_height = block_height - block_margin.top - block_margin.bottom; if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) { block_draw_height = MAX (block_draw_height, block_area.height - block_margin.top - block_margin.bottom); block_area.y += block_margin.top; } else { block_draw_width = MAX (block_draw_width, block_area.width - block_margin.left - block_margin.right); block_area.x += block_margin.left; } for (i = 0; i < num_blocks; i++) { if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) block_area.x += block_margin.left; else block_area.y += block_margin.top; gtk_style_context_save_to_node (context, self->priv->block_node[i]); gtk_render_background (context, cr, block_area.x, block_area.y, block_draw_width, block_draw_height); gtk_render_frame (context, cr, block_area.x, block_area.y, block_draw_width, block_draw_height); gtk_style_context_restore (context); if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) block_area.x += block_draw_width + block_margin.right; else block_area.y += block_draw_height + block_margin.bottom; } }
static void gtk_level_bar_draw_fill_continuous (GtkLevelBar *self, cairo_t *cr, cairo_rectangle_int_t *fill_area) { GtkWidget *widget = GTK_WIDGET (self); GtkStyleContext *context; cairo_rectangle_int_t base_area, block_area; GtkBorder block_margin; gdouble fill_percentage; gboolean inverted; inverted = self->priv->inverted; if (gtk_widget_get_direction (GTK_WIDGET (self)) == GTK_TEXT_DIR_RTL) { if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) inverted = !inverted; } context = gtk_widget_get_style_context (widget); /* render the empty (unfilled) part */ gtk_style_context_save_to_node (context, self->priv->block_node[inverted ? 0 : 1]); gtk_style_context_get_margin (context, gtk_style_context_get_state (context), &block_margin); base_area = *fill_area; base_area.x += block_margin.left; base_area.y += block_margin.top; base_area.width -= block_margin.left + block_margin.right; base_area.height -= block_margin.top + block_margin.bottom; gtk_render_background (context, cr, base_area.x, base_area.y, base_area.width, base_area.height); gtk_render_frame (context, cr, base_area.x, base_area.y, base_area.width, base_area.height); gtk_style_context_restore (context); /* now render the filled part on top of it */ block_area = base_area; fill_percentage = (self->priv->cur_value - self->priv->min_value) / (self->priv->max_value - self->priv->min_value); if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) { block_area.width = (gint) floor (block_area.width * fill_percentage); if (inverted) block_area.x += base_area.width - block_area.width; } else { block_area.height = (gint) floor (block_area.height * fill_percentage); if (inverted) block_area.y += base_area.height - block_area.height; } gtk_style_context_save_to_node (context, self->priv->block_node[inverted ? 1 : 0]); gtk_render_background (context, cr, block_area.x, block_area.y, block_area.width, block_area.height); gtk_render_frame (context, cr, block_area.x, block_area.y, block_area.width, block_area.height); gtk_style_context_restore (context); }
static gboolean _togglebutton_draw(GtkWidget *widget, cairo_t *cr) { g_return_val_if_fail(widget != NULL, FALSE); g_return_val_if_fail(DTGTK_IS_TOGGLEBUTTON(widget), FALSE); GtkDarktableToggleButton *button = DTGTK_TOGGLEBUTTON(widget); GtkStateFlags state = gtk_widget_get_state_flags(widget); GdkRGBA bg_color, fg_color; GtkStyleContext *context = gtk_widget_get_style_context(widget); if(button->icon_flags & CPF_CUSTOM_BG) bg_color = button->bg; else gtk_style_context_get_background_color(context, state, &bg_color); if(button->icon_flags & CPF_CUSTOM_FG) fg_color = button->fg; else gtk_style_context_get_color(context, state, &fg_color); /* fetch flags */ int flags = DTGTK_TOGGLEBUTTON(widget)->icon_flags; /* set inner border */ int border = DT_PIXEL_APPLY_DPI((flags & CPF_DO_NOT_USE_BORDER) ? 2 : 6); /* update active state paint flag */ gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); if(active) flags |= CPF_ACTIVE; else flags &= ~(CPF_ACTIVE); /* prelight */ if(state & GTK_STATE_FLAG_PRELIGHT) flags |= CPF_PRELIGHT; else flags &= ~CPF_PRELIGHT; /* begin cairo drawing */ GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width; int height = allocation.height; /* draw standard button background if not transparent nor flat styled */ if((flags & CPF_STYLE_FLAT)) { if(flags & CPF_PRELIGHT || flags & CPF_ACTIVE) { cairo_rectangle(cr, 0, 0, width, height); gdk_cairo_set_source_rgba(cr, &bg_color); cairo_fill(cr); } } else if(!(flags & CPF_BG_TRANSPARENT)) { /* draw default boxed button */ gtk_render_background(context, cr, 0, 0, width, height); if(!(flags & CPF_DO_NOT_USE_BORDER)) gtk_render_frame(context, cr, 0, 0, width, height); } /* create pango text settings if label exists */ PangoLayout *layout = NULL; int pw = 0, ph = 0; const gchar *text = gtk_button_get_label(GTK_BUTTON(widget)); if(text) { layout = pango_cairo_create_layout(cr); pango_layout_set_font_description(layout, darktable.bauhaus->pango_font_desc); pango_cairo_context_set_resolution(pango_layout_get_context(layout), darktable.gui->dpi); pango_layout_set_text(layout, text, -1); pango_layout_get_pixel_size(layout, &pw, &ph); } gdk_cairo_set_source_rgba(cr, &fg_color); /* draw icon */ if(DTGTK_TOGGLEBUTTON(widget)->icon) { // if (flags & CPF_IGNORE_FG_STATE) // state = GTK_STATE_NORMAL; int icon_width = text ? height - (border * 2) : width - (border * 2); int icon_height = height - (border * 2); if(icon_width > 0 && icon_height > 0) { if(text) DTGTK_TOGGLEBUTTON(widget) ->icon(cr, border, border, height - (border * 2), height - (border * 2), flags); else DTGTK_TOGGLEBUTTON(widget) ->icon(cr, border, border, width - (border * 2), height - (border * 2), flags); } } /* draw label */ if(text) { int lx = DT_PIXEL_APPLY_DPI(2), ly = ((height / 2.0) - (ph / 2.0)); // if (DTGTK_TOGGLEBUTTON (widget)->icon) lx += width; // GdkRectangle t={x,y,x+width,y+height}; // gtk_paint_layout(style,gtk_widget_get_window(widget), // state,TRUE,&t,widget,"togglebutton",lx,ly,layout); cairo_translate(cr, lx, ly); pango_cairo_show_layout(cr, layout); g_object_unref(layout); } return FALSE; }
/** * gd_create_collection_icon: * @base_size: * @pixbufs: (element-type GdkPixbuf): * * Returns: (transfer full): */ GIcon * gd_create_collection_icon (gint base_size, GList *pixbufs) { cairo_surface_t *surface; GIcon *retval; cairo_t *cr; GtkStyleContext *context; GtkWidgetPath *path; GtkBorder tile_border; gint padding, tile_size; gint idx, cur_x, cur_y; GList *l; context = gtk_style_context_new (); gtk_style_context_add_class (context, "documents-collection-icon"); path = gtk_widget_path_new (); gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); gtk_style_context_set_path (context, path); gtk_widget_path_unref (path); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, base_size, base_size); cr = cairo_create (surface); /* Render the thumbnail itself */ gtk_render_background (context, cr, 0, 0, base_size, base_size); gtk_render_frame (context, cr, 0, 0, base_size, base_size); /* Now, render the tiles inside */ gtk_style_context_remove_class (context, "documents-collection-icon"); gtk_style_context_add_class (context, "documents-collection-icon-tile"); /* TODO: do not hardcode 4, but scale to another layout if more * pixbufs are provided. */ padding = MAX (floor (base_size / 10), 4); gtk_style_context_get_border (context, GTK_STATE_FLAG_NORMAL, &tile_border); tile_size = (base_size - (3 * padding)) / 2 - MAX (tile_border.left + tile_border.right, tile_border.top + tile_border.bottom); l = pixbufs; idx = 0; cur_x = padding; cur_y = padding; while (l != NULL && idx < 4) { GdkPixbuf *pix; gboolean is_thumbnail; gint pix_width, pix_height, scale_size; pix = l->data; is_thumbnail = (gdk_pixbuf_get_option (pix, "-documents-has-thumb") != NULL); /* Only draw a box for thumbnails */ if (is_thumbnail) { gtk_render_background (context, cr, cur_x, cur_y, tile_size + tile_border.left + tile_border.right, tile_size + tile_border.top + tile_border.bottom); gtk_render_frame (context, cr, cur_x, cur_y, tile_size + tile_border.left + tile_border.right, tile_size + tile_border.top + tile_border.bottom); } pix_width = gdk_pixbuf_get_width (pix); pix_height = gdk_pixbuf_get_height (pix); scale_size = MIN (pix_width, pix_height); cairo_save (cr); cairo_translate (cr, cur_x + tile_border.left, cur_y + tile_border.top); cairo_rectangle (cr, 0, 0, tile_size, tile_size); cairo_clip (cr); cairo_scale (cr, (gdouble) tile_size / (gdouble) scale_size, (gdouble) tile_size / (gdouble) scale_size); gdk_cairo_set_source_pixbuf (cr, pix, 0, 0); cairo_paint (cr); cairo_restore (cr); if ((idx % 2) == 0) { cur_x += tile_size + padding + tile_border.left + tile_border.right; } else { cur_x = padding; cur_y += tile_size + padding + tile_border.top + tile_border.bottom; } idx++; l = l->next; } retval = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, base_size, base_size)); cairo_surface_destroy (surface); cairo_destroy (cr); g_object_unref (context); return retval; }
static gboolean gtk_tearoff_menu_item_draw (GtkWidget *widget, cairo_t *cr) { GtkMenuItem *menu_item; GtkStateFlags state; GtkStyleContext *context; GtkBorder padding; gint x, y, width, height; gint right_max; guint border_width; GtkTextDirection direction; GtkWidget *parent; gdouble angle; menu_item = GTK_MENU_ITEM (widget); context = gtk_widget_get_style_context (widget); direction = gtk_widget_get_direction (widget); state = gtk_widget_get_state_flags (widget); border_width = gtk_container_get_border_width (GTK_CONTAINER (menu_item)); x = border_width; y = border_width; width = gtk_widget_get_allocated_width (widget) - border_width * 2; height = gtk_widget_get_allocated_height (widget) - border_width * 2; right_max = x + width; gtk_style_context_save (context); gtk_style_context_set_state (context, state); gtk_style_context_get_padding (context, state, &padding); if (state & GTK_STATE_FLAG_PRELIGHT) { gtk_render_background (context, cr, x, y, width, height); gtk_render_frame (context, cr, x, y, width, height); } parent = gtk_widget_get_parent (widget); if (GTK_IS_MENU (parent) && gtk_menu_get_tearoff_state (GTK_MENU (parent))) { gint arrow_x; if (menu_item->priv->toggle_size > ARROW_SIZE) { if (direction == GTK_TEXT_DIR_LTR) { arrow_x = x + (menu_item->priv->toggle_size - ARROW_SIZE)/2; angle = (3 * G_PI) / 2; } else { arrow_x = x + width - menu_item->priv->toggle_size + (menu_item->priv->toggle_size - ARROW_SIZE)/2; angle = G_PI / 2; } x += menu_item->priv->toggle_size + BORDER_SPACING; } else { if (direction == GTK_TEXT_DIR_LTR) { arrow_x = ARROW_SIZE / 2; angle = (3 * G_PI) / 2; } else { arrow_x = x + width - 2 * ARROW_SIZE + ARROW_SIZE / 2; angle = G_PI / 2; } x += 2 * ARROW_SIZE; } gtk_render_arrow (context, cr, angle, arrow_x, height / 2 - 5, ARROW_SIZE); } while (x < right_max) { gint x1, x2; if (direction == GTK_TEXT_DIR_LTR) { x1 = x; x2 = MIN (x + TEAR_LENGTH, right_max); } else { x1 = right_max - x; x2 = MAX (right_max - x - TEAR_LENGTH, 0); } gtk_render_line (context, cr, x1, y + (height - padding.bottom) / 2, x2, y + (height - padding.bottom) / 2); x += 2 * TEAR_LENGTH; } gtk_style_context_restore (context); return FALSE; }
static gboolean sushi_font_widget_draw (GtkWidget *drawing_area, cairo_t *cr) { SushiFontWidget *self = SUSHI_FONT_WIDGET (drawing_area); SushiFontWidgetPrivate *priv = self->priv; gint *sizes = NULL, n_sizes, alpha_size, title_size, pos_y = 0, i; cairo_font_face_t *font; FT_Face face = priv->face; GtkStyleContext *context; GdkRGBA color; GtkBorder padding; GtkStateFlags state; gint allocated_width, allocated_height; if (face == NULL) goto end; context = gtk_widget_get_style_context (drawing_area); state = gtk_style_context_get_state (context); allocated_width = gtk_widget_get_allocated_width (drawing_area); allocated_height = gtk_widget_get_allocated_height (drawing_area); gtk_render_background (context, cr, 0, 0, allocated_width, allocated_height); gtk_style_context_get_color (context, state, &color); gtk_style_context_get_padding (context, state, &padding); gdk_cairo_set_source_rgba (cr, &color); sizes = build_sizes_table (face, &n_sizes, &alpha_size, &title_size); font = cairo_ft_font_face_create_for_ft_face (face, 0); cairo_set_font_face (cr, font); cairo_font_face_destroy (font); /* draw text */ if (self->priv->font_name != NULL) { cairo_set_font_size (cr, title_size); draw_string (self, cr, padding, self->priv->font_name, &pos_y); } if (pos_y > allocated_height) goto end; pos_y += SECTION_SPACING / 2; cairo_set_font_size (cr, alpha_size); if (self->priv->lowercase_text != NULL) draw_string (self, cr, padding, self->priv->lowercase_text, &pos_y); if (pos_y > allocated_height) goto end; if (self->priv->uppercase_text != NULL) draw_string (self, cr, padding, self->priv->uppercase_text, &pos_y); if (pos_y > allocated_height) goto end; if (self->priv->punctuation_text != NULL) draw_string (self, cr, padding, self->priv->punctuation_text, &pos_y); if (pos_y > allocated_height) goto end; pos_y += SECTION_SPACING; for (i = 0; i < n_sizes; i++) { cairo_set_font_size (cr, sizes[i]); if (self->priv->sample_string != NULL) draw_string (self, cr, padding, self->priv->sample_string, &pos_y); if (pos_y > allocated_height) break; } end: g_free (sizes); return FALSE; }
static gboolean gtk_switch_draw (GtkWidget *widget, cairo_t *cr) { GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv; GtkStyleContext *context; GdkRectangle handle; PangoLayout *layout; PangoFontDescription *desc; const PangoFontDescription *style_desc; PangoRectangle rect; gint label_x, label_y; GtkStateFlags state; GtkBorder padding; gint focus_width, focus_pad; gint x, y, width, height; gint font_size, style_font_size; gtk_widget_style_get (widget, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL); context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); if (priv->is_active) state |= GTK_STATE_FLAG_ACTIVE; gtk_style_context_save (context); gtk_style_context_set_state (context, state); gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_style_context_get_padding (context, state, &padding); gtk_style_context_restore (context); x = 0; y = 0; width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); if (gtk_widget_has_focus (widget)) gtk_render_focus (context, cr, x, y, width, height); x += focus_width + focus_pad; y += focus_width + focus_pad; width -= 2 * (focus_width + focus_pad); height -= 2 * (focus_width + focus_pad); gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); gtk_style_context_set_state (context, state); gtk_render_background (context, cr, x, y, width, height); gtk_render_frame (context, cr, x, y, width, height); width -= padding.left + padding.right; height -= padding.top + padding.bottom; x += padding.left; y += padding.top; handle.y = y; handle.width = width / 2; handle.height = height; /* Translators: if the "on" state label requires more than three * glyphs then use MEDIUM VERTICAL BAR (U+2759) as the text for * the state */ layout = gtk_widget_create_pango_layout (widget, C_("switch", "ON")); /* FIXME: this should be really done in the theme, but overriding font size * from it doesn't currently work. So we have to hardcode this here and * below for the "OFF" label. */ desc = pango_font_description_new (); style_desc = gtk_style_context_get_font (context, state); style_font_size = pango_font_description_get_size (style_desc); font_size = MAX (style_font_size - 1 * PANGO_SCALE, ceil (style_font_size * PANGO_SCALE_SMALL)); pango_font_description_set_size (desc, font_size); pango_layout_set_font_description (layout, desc); pango_layout_get_extents (layout, NULL, &rect); pango_extents_to_pixels (&rect, NULL); label_x = x + ((width / 2) - rect.width) / 2; label_y = y + (height - rect.height) / 2; gtk_render_layout (context, cr, label_x, label_y, layout); g_object_unref (layout); /* Translators: if the "off" state label requires more than three * glyphs then use WHITE CIRCLE (U+25CB) as the text for the state */ layout = gtk_widget_create_pango_layout (widget, C_("switch", "OFF")); pango_layout_set_font_description (layout, desc); pango_layout_get_extents (layout, NULL, &rect); pango_extents_to_pixels (&rect, NULL); label_x = x + (width / 2) + ((width / 2) - rect.width) / 2; label_y = y + (height - rect.height) / 2; gtk_render_layout (context, cr, label_x, label_y, layout); g_object_unref (layout); if (priv->is_dragging) handle.x = x + priv->handle_x; else if (priv->is_active) handle.x = x + width - handle.width; else handle.x = x; gtk_style_context_restore (context); gtk_switch_paint_handle (widget, cr, &handle); pango_font_description_free (desc); return FALSE; }
GIcon * photos_utils_create_symbolic_icon_for_scale (const gchar *name, gint base_size, gint scale) { g_autoptr (GIcon) icon = NULL; GIcon *ret_val = NULL; g_autoptr (GdkPixbuf) pixbuf = NULL; g_autoptr (GtkIconInfo) info = NULL; GtkIconTheme *theme; g_autoptr (GtkStyleContext) style = NULL; g_autoptr (GtkWidgetPath) path = NULL; cairo_surface_t *icon_surface = NULL; /* TODO: use g_autoptr */ cairo_surface_t *surface; /* TODO: use g_autoptr */ cairo_t *cr; /* TODO: use g_autoptr */ g_autofree gchar *symbolic_name = NULL; const gint bg_size = 24; const gint emblem_margin = 4; gint emblem_pos; gint emblem_size; gint total_size; gint total_size_scaled; total_size = base_size / 2; total_size_scaled = total_size * scale; emblem_size = bg_size - emblem_margin * 2; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, total_size_scaled, total_size_scaled); cairo_surface_set_device_scale (surface, (gdouble) scale, (gdouble) scale); cr = cairo_create (surface); style = gtk_style_context_new (); path = gtk_widget_path_new (); gtk_widget_path_append_type (path, GTK_TYPE_ICON_VIEW); gtk_style_context_set_path (style, path); gtk_style_context_add_class (style, "photos-icon-bg"); gtk_render_background (style, cr, total_size - bg_size, total_size - bg_size, bg_size, bg_size); symbolic_name = g_strconcat (name, "-symbolic", NULL); icon = g_themed_icon_new_with_default_fallbacks (symbolic_name); theme = gtk_icon_theme_get_default(); info = gtk_icon_theme_lookup_by_gicon_for_scale (theme, icon, emblem_size, scale, GTK_ICON_LOOKUP_FORCE_SIZE); if (info == NULL) goto out; pixbuf = gtk_icon_info_load_symbolic_for_context (info, style, NULL, NULL); if (pixbuf == NULL) goto out; icon_surface = gdk_cairo_surface_create_from_pixbuf (pixbuf, scale, NULL); emblem_pos = total_size - emblem_size - emblem_margin; gtk_render_icon_surface (style, cr, icon_surface, emblem_pos, emblem_pos); ret_val = G_ICON (gdk_pixbuf_get_from_surface (surface, 0, 0, total_size_scaled, total_size_scaled)); out: cairo_surface_destroy (icon_surface); cairo_surface_destroy (surface); cairo_destroy (cr); return ret_val; }
static gboolean budgie_popover_draw(GtkWidget *widget, cairo_t *cr, gboolean draw) { BudgiePopover *self = BUDGIE_POPOVER(widget); GtkStyleContext *style; GtkAllocation alloc; GtkPositionType gap_side; GdkRGBA color; gdouble x, y, tail_height, gap_width; gdouble margin, width, height, gap1, gap2; x = 0; y = 0; tail_height = 12; gap_width = 24; margin = 11; x += margin; y += margin; style = gtk_widget_get_style_context(widget); gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME); gtk_widget_get_allocation(widget, &alloc); /* Have parent class do drawing, so we gain shadows */ ((GtkWidgetClass*)budgie_popover_parent_class)->draw(widget, cr); /* Remove height of tail, and margin, from our rendered size */ width = alloc.width; height = alloc.height - tail_height; height -= margin; width -= margin*2; cairo_set_operator(cr, CAIRO_OPERATOR_OVER); gap1 = (alloc.width/2)-(gap_width/2); gap1 = self->widg_x; gap2 = gap1 + gap_width; gap2 -= margin; gap_side = self->top == TRUE ? GTK_POS_TOP : GTK_POS_BOTTOM; /* Render a gap in the bottom center for our arrow */ gtk_render_frame_gap(style, cr, x, y, width, height, gap_side, gap1, gap2); /* Fill in the background (pre-clip) */ gtk_render_background(style, cr, x, y, width, height); /* Clip to the tail, fill in the arrow background */ cairo_save(cr); if (self->top) budgie_tail_path(cr, gap1, gap_width, y-margin, tail_height, self->top); else budgie_tail_path(cr, gap1, gap_width, height+margin, tail_height, self->top); cairo_clip(cr); if (self->top) gtk_render_background(style, cr, x, y-tail_height, alloc.width, alloc.height); else gtk_render_background(style, cr, x, y, alloc.width, alloc.height); cairo_restore(cr); /* Draw in the border */ gtk_style_context_get_border_color(style, gtk_widget_get_state_flags(widget), &color); gdk_cairo_set_source_rgba(cr, &color); cairo_set_line_width(cr, 1); if (self->top) budgie_tail_path(cr, gap1, gap_width, y-margin, tail_height, self->top); else budgie_tail_path(cr, gap1, gap_width, height+margin, tail_height, self->top); cairo_stroke(cr); /* Draw children */ gtk_container_propagate_draw(GTK_CONTAINER(widget), gtk_bin_get_child(GTK_BIN(widget)), cr); return TRUE; }
static gboolean gtk_bubble_window_draw (GtkWidget *widget, cairo_t *cr) { GtkStyleContext *context; GtkAllocation allocation; GtkWidget *child; GtkBorder border; GdkRGBA border_color; gint rect_x1, rect_x2, rect_y1, rect_y2; gint initial_x, initial_y, final_x, final_y; gint gap_start, gap_end; GtkPositionType gap_side; GtkStateFlags state; context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); gtk_widget_get_allocation (widget, &allocation); if (gtk_widget_is_composited (widget)) { cairo_save (cr); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source_rgba (cr, 0, 0, 0, 0); cairo_paint (cr); cairo_restore (cr); } gtk_bubble_window_get_rect_coords (GTK_BUBBLE_WINDOW (widget), &rect_x1, &rect_y1, &rect_x2, &rect_y2); /* Render the rect background */ gtk_render_background (context, cr, rect_x1, rect_y1, rect_x2 - rect_x1, rect_y2 - rect_y1); gtk_bubble_window_get_gap_coords (GTK_BUBBLE_WINDOW (widget), &initial_x, &initial_y, NULL, NULL, &final_x, &final_y, &gap_side); if (POS_IS_VERTICAL (gap_side)) { gap_start = initial_x; gap_end = final_x; } else { gap_start = initial_y; gap_end = final_y; } /* Now render the frame, without the gap for the arrow tip */ gtk_render_frame_gap (context, cr, rect_x1, rect_y1, rect_x2 - rect_x1, rect_y2 - rect_y1, gap_side, gap_start, gap_end); /* Clip to the arrow shape */ cairo_save (cr); gtk_bubble_window_apply_tail_path (GTK_BUBBLE_WINDOW (widget), cr); cairo_clip (cr); /* Render the arrow background */ gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height); /* Render the border of the arrow tip */ gtk_style_context_get_border (context, state, &border); if (border.bottom > 0) { gtk_style_context_get_border_color (context, state, &border_color); gtk_bubble_window_apply_tail_path (GTK_BUBBLE_WINDOW (widget), cr); gdk_cairo_set_source_rgba (cr, &border_color); cairo_set_line_width (cr, border.bottom); cairo_stroke (cr); } /* We're done */ cairo_restore (cr); child = gtk_bin_get_child (GTK_BIN (widget)); if (child) gtk_container_propagate_draw (GTK_CONTAINER (widget), child, cr); return TRUE; }
static void draw_month_grid (GcalYearView *year_view, GtkWidget *widget, cairo_t *cr, gint month_nr, gint *weeks_counter) { GcalYearViewPrivate *priv = year_view->priv; GtkStyleContext *context; GtkStateFlags state_flags; PangoLayout *layout, *slayout; PangoFontDescription *font_desc, *sfont_desc; GdkRGBA color; gint layout_width, layout_height, i, j, sw; gint x, y, column, row, box_side, box_padding_top, box_padding_start; gint days_delay, days, shown_rows, sunday_idx; gchar *str, *nr_day, *nr_week; gboolean selected_day; cairo_save (cr); context = gtk_widget_get_style_context (widget); state_flags = gtk_widget_get_state_flags (widget); sw = 1 - 2 * priv->k; box_side = priv->navigator_grid->box_side; x = priv->navigator_grid->coordinates[month_nr].x; y = priv->navigator_grid->coordinates[month_nr].y; gtk_style_context_get (context, state_flags | GTK_STATE_FLAG_SELECTED, "font", &sfont_desc, NULL); slayout = gtk_widget_create_pango_layout (widget, NULL); pango_layout_set_font_description (slayout, sfont_desc); /* header */ gtk_style_context_save (context); gtk_style_context_add_class (context, "header"); str = g_strdup (gcal_get_month_name (month_nr)); gtk_style_context_get (context, state_flags, "font", &font_desc, NULL); layout = gtk_widget_create_pango_layout (widget, str); pango_layout_set_font_description (layout, font_desc); pango_layout_get_pixel_size (layout, &layout_width, &layout_height); gtk_render_layout (context, cr, x + (box_side * 8 - layout_width) / 2, y + (box_side - layout_height) / 2, layout); gtk_render_background (context, cr, x + (box_side * 8 - layout_width) / 2, y + (box_side - layout_height) / 2, layout_width, layout_width); pango_font_description_free (font_desc); g_free (str); gtk_style_context_restore (context); /* separator line */ gtk_style_context_save (context); gtk_style_context_add_class (context, "lines"); gtk_style_context_get_color (context, state_flags, &color); cairo_set_line_width (cr, 0.2); gdk_cairo_set_source_rgba (cr, &color); cairo_move_to (cr, x + box_side / 2, y + box_side + 0.4); cairo_rel_line_to (cr, 7 * box_side, 0); cairo_stroke (cr); gtk_style_context_restore (context); /* days */ gtk_style_context_save (context); gtk_style_context_add_class (context, "days"); gtk_style_context_get (context, state_flags, "font", &font_desc, NULL); pango_layout_set_font_description (layout, font_desc); days_delay = (time_day_of_week (1, month_nr, priv->date->year) - priv->first_weekday + 7) % 7; days = days_delay + icaltime_days_in_month (month_nr + 1, priv->date->year); shown_rows = ceil (days / 7.0); sunday_idx = priv->k * 6 + sw * ((7 - priv->first_weekday) % 7); for (i = 0; i < 7 * shown_rows; i++) { column = i % 7; row = i / 7; j = 7 * ((i + 7 * priv->k) / 7) + sw * (i % 7) + (1 - priv->k); if (j <= days_delay) continue; else if (j > days) continue; j -= days_delay; nr_day = g_strdup_printf ("%d", j); pango_layout_set_text (layout, nr_day, -1); pango_layout_get_pixel_size (layout, &layout_width, &layout_height); box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0; box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0; selected_day = FALSE; if (priv->selected_data->start_day != 0) { ButtonData selected_data = *(priv->selected_data); order_selected_data (&selected_data); if (month_nr > selected_data.start_month && month_nr < selected_data.end_month) { selected_day = TRUE; } else if (month_nr == selected_data.start_month && month_nr == selected_data.end_month) { selected_day = j >= selected_data.start_day && j <= selected_data.end_day; } else if (month_nr == selected_data.start_month && j >= selected_data.start_day) { selected_day = TRUE; } else if (month_nr == selected_data.end_month && j <= selected_data.end_day) { selected_day = TRUE; } } if (priv->date->year == priv->current_date->year && month_nr + 1 == priv->current_date->month && j == priv->current_date->day) { PangoLayout *clayout; PangoFontDescription *cfont_desc; gtk_style_context_save (context); gtk_style_context_add_class (context, "current"); clayout = gtk_widget_create_pango_layout (widget, nr_day); gtk_style_context_get (context, state_flags, "font", &cfont_desc, NULL); pango_layout_set_font_description (clayout, cfont_desc); pango_layout_get_pixel_size (clayout, &layout_width, &layout_height); box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0; box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0; /* FIXME: hardcoded padding of the number background */ gtk_render_background (context, cr, box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width - 2.0, box_side * (row + 1) + y + box_padding_top - 1.0, layout_width + 4.0, layout_height + 2.0); gtk_render_layout (context, cr, box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width, box_side * (row + 1) + y + box_padding_top, clayout); gtk_style_context_restore (context); pango_font_description_free (cfont_desc); g_object_unref (clayout); } else if (selected_day) { gtk_style_context_set_state (context, state_flags | GTK_STATE_FLAG_SELECTED); pango_layout_set_text (slayout, nr_day, -1); pango_layout_get_pixel_size (slayout, &layout_width, &layout_height); box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0; box_padding_start = (box_side - layout_width) / 2 > 0 ? (box_side - layout_width) / 2 : 0; gtk_render_layout (context, cr, box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width, box_side * (row + 1) + y + box_padding_top, slayout); gtk_style_context_set_state (context, state_flags); } else if (column == sunday_idx) { gtk_style_context_save (context); gtk_style_context_add_class (context, "sunday"); gtk_render_layout (context, cr, box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width, box_side * (row + 1) + y + box_padding_top, layout); gtk_style_context_restore (context); } else { gtk_render_layout (context, cr, box_side * (column + 0.5 + priv->k) + x + sw * box_padding_start - priv->k * layout_width, box_side * (row + 1) + y + box_padding_top, layout); } g_free (nr_day); } pango_font_description_free (font_desc); gtk_style_context_restore (context); /* week numbers */ gtk_style_context_save (context); gtk_style_context_add_class (context, "week-numbers"); gtk_style_context_get (context, state_flags, "font", &font_desc, NULL); pango_layout_set_font_description (layout, font_desc); for (i = 0; i < shown_rows; i++) { if (i == 0) { if (days_delay == 0) *weeks_counter = *weeks_counter + 1; } else *weeks_counter = *weeks_counter + 1; nr_week = g_strdup_printf ("%d", *weeks_counter); pango_layout_set_text (layout, nr_week, -1); pango_layout_get_pixel_size (layout, &layout_width, &layout_height); box_padding_top = (box_side - layout_height) / 2 > 0 ? (box_side - layout_height) / 2 : 0; box_padding_start = ((box_side / 2) - layout_width) / 2 > 0 ? ((box_side / 2) - layout_width) / 2 : 0; gtk_render_layout (context, cr, x + sw * box_padding_start + priv->k * (8 * box_side - layout_width), box_side * (i + 1) + y + box_padding_top, layout); g_free (nr_week); } gtk_style_context_restore (context); pango_font_description_free (sfont_desc); g_object_unref (slayout); pango_font_description_free (font_desc); g_object_unref (layout); cairo_restore (cr); }
static gboolean _lib_histogram_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_lib_histogram_t *d = (dt_lib_histogram_t *)self->data; dt_develop_t *dev = darktable.develop; uint32_t *hist = dev->histogram; float hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR ? dev->histogram_max : logf(1.0 + dev->histogram_max); const int inset = DT_HIST_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, allocation.width, allocation.height); cairo_translate(cr, 4 * inset, inset); width -= 2 * 4 * inset; height -= 2 * inset; if(d->mode_x == 0) { d->color_w = 0.06 * width; d->button_spacing = 0.01 * width; d->button_h = 0.06 * width; d->button_y = d->button_spacing; d->mode_w = d->color_w; d->mode_x = width - 3 * (d->color_w + d->button_spacing) - (d->mode_w + d->button_spacing); d->red_x = width - 3 * (d->color_w + d->button_spacing); d->green_x = width - 2 * (d->color_w + d->button_spacing); d->blue_x = width - (d->color_w + d->button_spacing); } // TODO: probably this should move to the configure-event callback! That would be future proof if we ever // (again) allow to resize the side panels. const gint stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); // this code assumes that the first expose comes before the first (preview) pipe is processed and that the // size of the widget doesn't change! if(dev->histogram_waveform_width == 0) { dev->histogram_waveform = (uint32_t *)calloc(height * stride / 4, sizeof(uint32_t)); dev->histogram_waveform_stride = stride; dev->histogram_waveform_height = height; dev->histogram_waveform_width = width; // return TRUE; // there are enough expose events following ... } #if 1 // draw shadow around float alpha = 1.0f; cairo_set_line_width(cr, 0.2); for(int k = 0; k < inset; k++) { cairo_rectangle(cr, -k, -k, width + 2 * k, height + 2 * k); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.5f; cairo_fill(cr); } cairo_set_line_width(cr, 1.0); #else cairo_set_line_width(cr, 1.0); cairo_set_source_rgb(cr, .1, .1, .1); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); #endif cairo_rectangle(cr, 0, 0, width, height); cairo_clip(cr); cairo_set_source_rgb(cr, .3, .3, .3); cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); if(d->highlight == 1) { cairo_set_source_rgb(cr, .5, .5, .5); cairo_rectangle(cr, 0, 0, .2 * width, height); cairo_fill(cr); } else if(d->highlight == 2) { cairo_set_source_rgb(cr, .5, .5, .5); cairo_rectangle(cr, 0.2 * width, 0, width, height); cairo_fill(cr); } // draw grid cairo_set_line_width(cr, .4); cairo_set_source_rgb(cr, .1, .1, .1); if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM) dt_draw_waveform_lines(cr, 0, 0, width, height); else dt_draw_grid(cr, 4, 0, 0, width, height); if(hist_max > 0.0f) { cairo_save(cr); if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM) { // make the color channel selector work: uint8_t *buf = (uint8_t *)malloc(sizeof(uint8_t) * height * stride); uint8_t mask[3] = { d->blue, d->green, d->red }; memcpy(buf, dev->histogram_waveform, sizeof(uint8_t) * height * stride); for(int y = 0; y < height; y++) for(int x = 0; x < width; x++) for(int k = 0; k < 3; k++) { buf[y * stride + x * 4 + k] *= mask[k]; } cairo_surface_t *source = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, width, height, stride); cairo_set_source_surface(cr, source, 0.0, 0.0); cairo_set_operator(cr, CAIRO_OPERATOR_ADD); cairo_paint(cr); cairo_surface_destroy(source); free(buf); } else { // cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); cairo_translate(cr, 0, height); cairo_scale(cr, width / 63.0, -(height - 10) / hist_max); cairo_set_operator(cr, CAIRO_OPERATOR_ADD); // cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_set_line_width(cr, 1.); if(d->red) { cairo_set_source_rgba(cr, 1., 0., 0., 0.2); dt_draw_histogram_8(cr, hist, 0, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR); } if(d->green) { cairo_set_source_rgba(cr, 0., 1., 0., 0.2); dt_draw_histogram_8(cr, hist, 1, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR); } if(d->blue) { cairo_set_source_rgba(cr, 0., 0., 1., 0.2); dt_draw_histogram_8(cr, hist, 2, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR); } cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); // cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); } cairo_restore(cr); } cairo_set_source_rgb(cr, .25, .25, .25); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); PangoLayout *layout; PangoRectangle ink; PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc); pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); layout = pango_cairo_create_layout(cr); pango_font_description_set_absolute_size(desc, .1 * height * PANGO_SCALE); pango_layout_set_font_description(layout, desc); char exifline[50]; dt_image_print_exif(&dev->image_storage, exifline, 50); pango_layout_set_text(layout, exifline, -1); pango_layout_get_pixel_extents(layout, &ink, NULL); cairo_move_to(cr, .02 * width, .98 * height - ink.height - ink.y); cairo_save(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0)); cairo_set_source_rgba(cr, 1, 1, 1, 0.3); pango_cairo_layout_path(cr, layout); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, .25, .25, .25); cairo_fill(cr); cairo_restore(cr); // buttons to control the display of the histogram: linear/log, r, g, b if(d->highlight != 0) { _draw_mode_toggle(cr, d->mode_x, d->button_y, d->mode_w, d->button_h, dev->histogram_type); cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4); _draw_color_toggle(cr, d->red_x, d->button_y, d->color_w, d->button_h, d->red); cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.4); _draw_color_toggle(cr, d->green_x, d->button_y, d->color_w, d->button_h, d->green); cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4); _draw_color_toggle(cr, d->blue_x, d->button_y, d->color_w, d->button_h, d->blue); } cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); pango_font_description_free(desc); g_object_unref(layout); return TRUE; }
static void ag_chart_renderer_render(GtkCellRenderer *renderer, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) { AgChartRendererPrivate *priv = ag_chart_renderer_get_instance_private( AG_CHART_RENDERER(renderer) ); int margin; GtkStyleContext *context = gtk_widget_get_style_context(widget); GdkPixbuf *pixbuf; gtk_style_context_save(context); gtk_style_context_add_class(context, "ag-chart-renderer"); if (priv->css_class) { gtk_style_context_add_class(context, priv->css_class); } cairo_save(cr); gdk_cairo_rectangle(cr, cell_area); cairo_clip(cr); cairo_translate(cr, cell_area->x, cell_area->y); margin = MAX( AG_CHART_RENDERER_TILE_MARGIN, (int)((cell_area->width - AG_CHART_RENDERER_TILE_SIZE) / 2) ); g_object_get(renderer, "pixbuf", &pixbuf, NULL); if (pixbuf != NULL) { GdkRectangle area = { margin, margin, AG_CHART_RENDERER_TILE_SIZE, AG_CHART_RENDERER_TILE_SIZE }; GTK_CELL_RENDERER_CLASS(ag_chart_renderer_parent_class)->render( renderer, cr, widget, &area, &area, flags ); } else { gtk_render_frame( context, cr, margin, margin, AG_CHART_RENDERER_TILE_SIZE, AG_CHART_RENDERER_TILE_SIZE ); gtk_render_background( context, cr, margin, margin, AG_CHART_RENDERER_TILE_SIZE, AG_CHART_RENDERER_TILE_SIZE ); } gtk_style_context_restore(context); if (priv->toggle_visible) { gint xpad, ypad, x_offset, check_x, check_y; gtk_cell_renderer_get_padding( GTK_CELL_RENDERER(renderer), &xpad, &ypad ); if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL) { x_offset = xpad; } else { x_offset = cell_area->width - AG_CHART_RENDERER_CHECK_ICON_SIZE - xpad; } check_x = x_offset; check_y = cell_area->height - AG_CHART_RENDERER_CHECK_ICON_SIZE - ypad; gtk_style_context_save(context); gtk_style_context_add_class(context, GTK_STYLE_CLASS_CHECK); if (priv->checked) { gtk_style_context_set_state(context, GTK_STATE_FLAG_CHECKED); } gtk_render_background( context, cr, check_x, check_y, AG_CHART_RENDERER_CHECK_ICON_SIZE, AG_CHART_RENDERER_CHECK_ICON_SIZE ); gtk_render_frame( context, cr, check_x, check_y, AG_CHART_RENDERER_CHECK_ICON_SIZE, AG_CHART_RENDERER_CHECK_ICON_SIZE ); gtk_render_check( context, cr, check_x, check_y, AG_CHART_RENDERER_CHECK_ICON_SIZE, AG_CHART_RENDERER_CHECK_ICON_SIZE ); gtk_style_context_restore(context); } cairo_restore(cr); }
static void gtk_level_bar_draw_fill_discrete (GtkLevelBar *self, cairo_t *cr, gboolean inverted, cairo_rectangle_int_t *fill_area) { GtkWidget *widget = GTK_WIDGET (self); GtkStyleContext *context = gtk_widget_get_style_context (widget); GtkStateFlags flags = gtk_widget_get_state_flags (widget); gint num_blocks, num_filled, idx; gint block_width, block_height; gint block_draw_width, block_draw_height; GtkBorder block_margin; cairo_rectangle_int_t block_area; gtk_level_bar_get_min_block_size (self, &block_width, &block_height); block_area = *fill_area; num_blocks = gtk_level_bar_get_num_blocks (self); num_filled = (gint) round (self->priv->cur_value) - (gint) round (self->priv->min_value); if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) block_width = MAX (block_width, (gint) floor (block_area.width / num_blocks)); else block_height = MAX (block_height, (gint) floor (block_area.height / num_blocks)); gtk_style_context_save (context); gtk_style_context_add_class (context, STYLE_CLASS_FILL_BLOCK); gtk_style_context_get_margin (context, flags, &block_margin); block_draw_width = block_width - block_margin.left - block_margin.right; block_draw_height = block_height - block_margin.top - block_margin.bottom; if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) { block_draw_height = MAX (block_draw_height, block_area.height - block_margin.top - block_margin.bottom); block_area.y += block_margin.top; if (inverted) block_area.x += block_area.width - block_draw_width; } else { block_draw_width = MAX (block_draw_width, block_area.width - block_margin.left - block_margin.right); block_area.x += block_margin.left; if (inverted) block_area.y += block_area.height - block_draw_height; } for (idx = 0; idx < num_blocks; idx++) { if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) { if (inverted) block_area.x -= block_margin.right; else block_area.x += block_margin.left; } else { if (inverted) block_area.y -= block_margin.bottom; else block_area.y += block_margin.top; } if (idx > num_filled - 1) gtk_style_context_add_class (context, STYLE_CLASS_EMPTY_FILL_BLOCK); gtk_render_background (context, cr, block_area.x, block_area.y, block_draw_width, block_draw_height); gtk_render_frame (context, cr, block_area.x, block_area.y, block_draw_width, block_draw_height); if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) { if (inverted) block_area.x -= block_draw_width + block_margin.left; else block_area.x += block_draw_width + block_margin.right; } else { if (inverted) block_area.y -= block_draw_height + block_margin.top; else block_area.y += block_draw_height + block_margin.bottom; } } gtk_style_context_restore (context); }
static void gtk_level_bar_draw_fill_continuous (GtkLevelBar *self, cairo_t *cr, gboolean inverted, cairo_rectangle_int_t *fill_area) { GtkWidget *widget = GTK_WIDGET (self); GtkStyleContext *context = gtk_widget_get_style_context (widget); GtkStateFlags flags = gtk_widget_get_state_flags (widget); cairo_rectangle_int_t base_area, block_area; GtkBorder block_margin; gdouble fill_percentage; gtk_style_context_save (context); gtk_style_context_add_class (context, STYLE_CLASS_FILL_BLOCK); gtk_style_context_get_margin (context, flags, &block_margin); /* render the empty (unfilled) part */ base_area = *fill_area; base_area.x += block_margin.left; base_area.y += block_margin.top; base_area.width -= block_margin.left + block_margin.right; base_area.height -= block_margin.top + block_margin.bottom; gtk_style_context_add_class (context, STYLE_CLASS_EMPTY_FILL_BLOCK); gtk_render_background (context, cr, base_area.x, base_area.y, base_area.width, base_area.height); gtk_render_frame (context, cr, base_area.x, base_area.y, base_area.width, base_area.height); gtk_style_context_remove_class (context, STYLE_CLASS_EMPTY_FILL_BLOCK); /* now render the filled part on top of it */ block_area = base_area; fill_percentage = (self->priv->cur_value - self->priv->min_value) / (self->priv->max_value - self->priv->min_value); if (self->priv->orientation == GTK_ORIENTATION_HORIZONTAL) { block_area.width = (gint) floor (block_area.width * fill_percentage); if (inverted) block_area.x += base_area.width - block_area.width; } else { block_area.height = (gint) floor (block_area.height * fill_percentage); if (inverted) block_area.y += base_area.height - block_area.height; } gtk_render_background (context, cr, block_area.x, block_area.y, block_area.width, block_area.height); gtk_render_frame (context, cr, block_area.x, block_area.y, block_area.width, block_area.height); gtk_style_context_restore (context); }
/* This code was originally rendering anti-aliased using X primitives, and * now has been switched to draw anti-aliased using cairo. In general, the * closest correspondence between X rendering and cairo rendering is given * by offsetting the geometry by 0.5 pixels in both directions before rendering * with cairo. This is because X samples at the upper left corner of the * pixel while cairo averages over the entire pixel. However, in the cases * where the X rendering was an exact rectangle with no "jaggies" * we need to be a bit careful about applying the offset. We want to produce * the exact same pixel-aligned rectangle, rather than a rectangle with * fuzz around the edges. */ static void draw_op_draw_with_env (const MetaDrawOp *op, GtkStyleContext *context, cairo_t *cr, const MetaDrawInfo *info, MetaPositionExprEnv *env) { GdkRGBA color; cairo_save (cr); cairo_set_line_width (cr, 1.0); switch (op->type) { case META_DRAW_LINE: { gdouble x1, x2, y1, y2; meta_color_spec_render (op->data.line.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); if (op->data.line.width > 0) cairo_set_line_width (cr, op->data.line.width); if (op->data.line.dash_on_length > 0 && op->data.line.dash_off_length > 0) { double dash_list[2]; dash_list[0] = op->data.line.dash_on_length; dash_list[1] = op->data.line.dash_off_length; cairo_set_dash (cr, dash_list, 2, 0); } x1 = meta_draw_spec_parse_x_position (op->data.line.x1, env); y1 = meta_draw_spec_parse_y_position (op->data.line.y1, env); if (!op->data.line.x2 && !op->data.line.y2 && op->data.line.width == 0) { cairo_rectangle (cr, x1, y1, 1, 1); cairo_fill (cr); } else { if (op->data.line.x2) x2 = meta_draw_spec_parse_x_position (op->data.line.x2, env); else x2 = x1; if (op->data.line.y2) y2 = meta_draw_spec_parse_y_position (op->data.line.y2, env); else y2 = y1; /* This is one of the cases where we are matching the exact * pixel aligned rectangle produced by X; for zero-width lines * the generic algorithm produces the right result so we don't * need to handle them here. */ if ((y1 == y2 || x1 == x2) && op->data.line.width != 0) { double offset = op->data.line.width % 2 ? .5 : 0; if (y1 == y2) { cairo_move_to (cr, x1, y1 + offset); cairo_line_to (cr, x2, y2 + offset); } else { cairo_move_to (cr, x1 + offset, y1); cairo_line_to (cr, x2 + offset, y2); } } else { /* zero-width lines include both end-points in X, unlike wide lines */ if (op->data.line.width == 0) cairo_set_line_cap (cr, CAIRO_LINE_CAP_SQUARE); cairo_move_to (cr, x1 + .5, y1 + .5); cairo_line_to (cr, x2 + .5, y2 + .5); } cairo_stroke (cr); } } break; case META_DRAW_RECTANGLE: { gdouble rx, ry, rwidth, rheight; meta_color_spec_render (op->data.rectangle.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); rx = meta_draw_spec_parse_x_position (op->data.rectangle.x, env); ry = meta_draw_spec_parse_y_position (op->data.rectangle.y, env); rwidth = meta_draw_spec_parse_size (op->data.rectangle.width, env); rheight = meta_draw_spec_parse_size (op->data.rectangle.height, env); /* Filled and stroked rectangles are the other cases * we pixel-align to X rasterization */ if (op->data.rectangle.filled) { cairo_rectangle (cr, rx, ry, rwidth, rheight); cairo_fill (cr); } else { cairo_rectangle (cr, rx + .5, ry + .5, rwidth, rheight); cairo_stroke (cr); } } break; case META_DRAW_ARC: { gdouble rx, ry, rwidth, rheight; double start_angle, end_angle; double center_x, center_y; meta_color_spec_render (op->data.arc.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); rx = meta_draw_spec_parse_x_position (op->data.arc.x, env); ry = meta_draw_spec_parse_y_position (op->data.arc.y, env); rwidth = meta_draw_spec_parse_size (op->data.arc.width, env); rheight = meta_draw_spec_parse_size (op->data.arc.height, env); start_angle = op->data.arc.start_angle * (M_PI / 180.) - (.5 * M_PI); /* start at 12 instead of 3 oclock */ end_angle = start_angle + op->data.arc.extent_angle * (M_PI / 180.); center_x = rx + (double)rwidth / 2. + .5; center_y = ry + (double)rheight / 2. + .5; cairo_save (cr); cairo_translate (cr, center_x, center_y); cairo_scale (cr, (double)rwidth / 2., (double)rheight / 2.); if (op->data.arc.extent_angle >= 0) cairo_arc (cr, 0, 0, 1, start_angle, end_angle); else cairo_arc_negative (cr, 0, 0, 1, start_angle, end_angle); cairo_restore (cr); if (op->data.arc.filled) { cairo_line_to (cr, center_x, center_y); cairo_fill (cr); } else cairo_stroke (cr); } break; case META_DRAW_CLIP: break; case META_DRAW_TINT: { gdouble rx, ry, rwidth, rheight; rx = meta_draw_spec_parse_x_position (op->data.tint.x, env); ry = meta_draw_spec_parse_y_position (op->data.tint.y, env); rwidth = meta_draw_spec_parse_size (op->data.tint.width, env); rheight = meta_draw_spec_parse_size (op->data.tint.height, env); meta_color_spec_render (op->data.tint.color_spec, context, &color); meta_alpha_gradient_spec_render (op->data.tint.alpha_spec, color, cr, rx, ry, rwidth, rheight); } break; case META_DRAW_GRADIENT: { gdouble rx, ry, rwidth, rheight; rx = meta_draw_spec_parse_x_position (op->data.gradient.x, env); ry = meta_draw_spec_parse_y_position (op->data.gradient.y, env); rwidth = meta_draw_spec_parse_size (op->data.gradient.width, env); rheight = meta_draw_spec_parse_size (op->data.gradient.height, env); meta_gradient_spec_render (op->data.gradient.gradient_spec, op->data.gradient.alpha_spec, cr, context, rx, ry, rwidth, rheight); } break; case META_DRAW_IMAGE: { gdouble scale; gdouble rx, ry, rwidth, rheight; cairo_surface_t *surface; scale = info->scale; cairo_scale (cr, 1.0 / scale, 1.0 / scale); if (op->data.image.pixbuf) { env->object_width = gdk_pixbuf_get_width (op->data.image.pixbuf); env->object_height = gdk_pixbuf_get_height (op->data.image.pixbuf); } rwidth = meta_draw_spec_parse_size (op->data.image.width, env) * scale; rheight = meta_draw_spec_parse_size (op->data.image.height, env) * scale; surface = draw_op_as_surface (op, context, info, rwidth, rheight); if (surface) { rx = meta_draw_spec_parse_x_position (op->data.image.x, env) * scale; ry = meta_draw_spec_parse_y_position (op->data.image.y, env) * scale; cairo_set_source_surface (cr, surface, rx, ry); if (op->data.image.alpha_spec) { cairo_pattern_t *pattern; cairo_translate (cr, rx, ry); cairo_scale (cr, rwidth, rheight); pattern = meta_alpha_gradient_spec_get_mask (op->data.image.alpha_spec); cairo_mask (cr, pattern); cairo_pattern_destroy (pattern); } else { cairo_paint (cr); } cairo_surface_destroy (surface); } } break; case META_DRAW_GTK_ARROW: { gdouble rx, ry, rwidth, rheight; double angle = 0, size; rx = meta_draw_spec_parse_x_position (op->data.gtk_arrow.x, env); ry = meta_draw_spec_parse_y_position (op->data.gtk_arrow.y, env); rwidth = meta_draw_spec_parse_size (op->data.gtk_arrow.width, env); rheight = meta_draw_spec_parse_size (op->data.gtk_arrow.height, env); size = MAX(rwidth, rheight); switch (op->data.gtk_arrow.arrow) { case GTK_ARROW_UP: angle = 0; break; case GTK_ARROW_RIGHT: angle = M_PI / 2; break; case GTK_ARROW_DOWN: angle = M_PI; break; case GTK_ARROW_LEFT: angle = 3 * M_PI / 2; break; case GTK_ARROW_NONE: return; default: break; } gtk_style_context_set_state (context, op->data.gtk_arrow.state); gtk_render_arrow (context, cr, angle, rx, ry, size); } break; case META_DRAW_GTK_BOX: { gdouble rx, ry, rwidth, rheight; rx = meta_draw_spec_parse_x_position (op->data.gtk_box.x, env); ry = meta_draw_spec_parse_y_position (op->data.gtk_box.y, env); rwidth = meta_draw_spec_parse_size (op->data.gtk_box.width, env); rheight = meta_draw_spec_parse_size (op->data.gtk_box.height, env); gtk_style_context_set_state (context, op->data.gtk_box.state); gtk_render_background (context, cr, rx, ry, rwidth, rheight); gtk_render_frame (context, cr, rx, ry, rwidth, rheight); } break; case META_DRAW_GTK_VLINE: { gdouble rx, ry1, ry2; rx = meta_draw_spec_parse_x_position (op->data.gtk_vline.x, env); ry1 = meta_draw_spec_parse_y_position (op->data.gtk_vline.y1, env); ry2 = meta_draw_spec_parse_y_position (op->data.gtk_vline.y2, env); gtk_style_context_set_state (context, op->data.gtk_vline.state); gtk_render_line (context, cr, rx, ry1, rx, ry2); } break; case META_DRAW_ICON: { gdouble rx, ry, rwidth, rheight; cairo_surface_t *surface; rwidth = meta_draw_spec_parse_size (op->data.icon.width, env); rheight = meta_draw_spec_parse_size (op->data.icon.height, env); surface = draw_op_as_surface (op, context, info, rwidth, rheight); if (surface) { rx = meta_draw_spec_parse_x_position (op->data.icon.x, env); ry = meta_draw_spec_parse_y_position (op->data.icon.y, env); cairo_set_source_surface (cr, surface, rx, ry); if (op->data.icon.alpha_spec) { cairo_pattern_t *pattern; cairo_translate (cr, rx, ry); cairo_scale (cr, rwidth, rheight); pattern = meta_alpha_gradient_spec_get_mask (op->data.icon.alpha_spec); cairo_mask (cr, pattern); cairo_pattern_destroy (pattern); } else { cairo_paint (cr); } cairo_surface_destroy (surface); } } break; case META_DRAW_TITLE: if (info->title_layout) { gdouble rx, ry; PangoRectangle ink_rect, logical_rect; meta_color_spec_render (op->data.title.color_spec, context, &color); gdk_cairo_set_source_rgba (cr, &color); rx = meta_draw_spec_parse_x_position (op->data.title.x, env); ry = meta_draw_spec_parse_y_position (op->data.title.y, env); if (op->data.title.ellipsize_width) { gdouble ellipsize_width; int right_bearing; ellipsize_width = meta_draw_spec_parse_x_position (op->data.title.ellipsize_width, env); /* HACK: meta_draw_spec_parse_x_position adds in env->rect.x, subtract out again */ ellipsize_width -= env->rect.x; pango_layout_set_width (info->title_layout, -1); pango_layout_get_pixel_extents (info->title_layout, &ink_rect, &logical_rect); /* Pango's idea of ellipsization is with respect to the logical rect. * correct for this, by reducing the ellipsization width by the overflow * of the un-ellipsized text on the right... it's always the visual * right we want regardless of bidi, since since the X we pass in to * cairo_move_to() is always the left edge of the line. */ right_bearing = (ink_rect.x + ink_rect.width) - (logical_rect.x + logical_rect.width); right_bearing = MAX (right_bearing, 0); ellipsize_width -= right_bearing; ellipsize_width = MAX (ellipsize_width, 0); /* Only ellipsizing when necessary is a performance optimization - * pango_layout_set_width() will force a relayout if it isn't the * same as the current width of -1. */ if (ellipsize_width < logical_rect.width) pango_layout_set_width (info->title_layout, PANGO_SCALE * ellipsize_width); } else if (rx - env->rect.x + env->title_width >= env->rect.width) { const double alpha_margin = 30.0; int text_space = env->rect.x + env->rect.width - (rx - env->rect.x) - env->right_width; double startalpha = 1.0 - (alpha_margin/((double)text_space)); cairo_pattern_t *linpat; linpat = cairo_pattern_create_linear (rx, ry, text_space, env->title_height); cairo_pattern_add_color_stop_rgba (linpat, 0, color.red, color.green, color.blue, color.alpha); cairo_pattern_add_color_stop_rgba (linpat, startalpha, color.red, color.green, color.blue, color.alpha); cairo_pattern_add_color_stop_rgba (linpat, 1, color.red, color.green, color.blue, 0); cairo_set_source(cr, linpat); cairo_pattern_destroy(linpat); } cairo_move_to (cr, rx, ry); pango_cairo_show_layout (cr, info->title_layout); /* Remove any ellipsization we might have set; will short-circuit * if the width is already -1 */ pango_layout_set_width (info->title_layout, -1); } break; case META_DRAW_OP_LIST: { MetaRectangleDouble d_rect; d_rect.x = meta_draw_spec_parse_x_position (op->data.op_list.x, env); d_rect.y = meta_draw_spec_parse_y_position (op->data.op_list.y, env); d_rect.width = meta_draw_spec_parse_size (op->data.op_list.width, env); d_rect.height = meta_draw_spec_parse_size (op->data.op_list.height, env); meta_draw_op_list_draw_with_style (op->data.op_list.op_list, context, cr, info, d_rect); } break; case META_DRAW_TILE: { gdouble rx, ry, rwidth, rheight; gdouble tile_xoffset, tile_yoffset; MetaRectangleDouble tile; rx = meta_draw_spec_parse_x_position (op->data.tile.x, env); ry = meta_draw_spec_parse_y_position (op->data.tile.y, env); rwidth = meta_draw_spec_parse_size (op->data.tile.width, env); rheight = meta_draw_spec_parse_size (op->data.tile.height, env); cairo_save (cr); cairo_rectangle (cr, rx, ry, rwidth, rheight); cairo_clip (cr); tile_xoffset = meta_draw_spec_parse_x_position (op->data.tile.tile_xoffset, env); tile_yoffset = meta_draw_spec_parse_y_position (op->data.tile.tile_yoffset, env); /* tile offset should not include x/y */ tile_xoffset -= env->rect.x; tile_yoffset -= env->rect.y; tile.width = meta_draw_spec_parse_size (op->data.tile.tile_width, env); tile.height = meta_draw_spec_parse_size (op->data.tile.tile_height, env); tile.x = rx - tile_xoffset; while (tile.x < (rx + rwidth)) { tile.y = ry - tile_yoffset; while (tile.y < (ry + rheight)) { meta_draw_op_list_draw_with_style (op->data.tile.op_list, context, cr, info, tile); tile.y += tile.height; } tile.x += tile.width; } cairo_restore (cr); } break; default: break; } cairo_restore (cr); }
static gboolean gtk_switch_draw (GtkWidget *widget, cairo_t *cr) { GtkSwitchPrivate *priv = GTK_SWITCH (widget)->priv; GtkStyleContext *context; GdkRectangle handle; PangoLayout *layout; PangoRectangle rect; gint label_x, label_y; GtkBorder padding; GtkStateFlags state; gint x, y, width, height; context = gtk_widget_get_style_context (widget); state = gtk_widget_get_state_flags (widget); gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); gtk_style_context_get_padding (context, state, &padding); gtk_style_context_restore (context); x = 0; y = 0; width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); gtk_style_context_save (context); gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); gtk_render_background (context, cr, x, y, width, height); gtk_render_frame (context, cr, x, y, width, height); width -= padding.left + padding.right; height -= padding.top + padding.bottom; x += padding.left; y += padding.top; handle.y = y; handle.width = width / 2; handle.height = height; /* Translators: if the "on" state label requires more than three * glyphs then use MEDIUM VERTICAL BAR (U+2759) as the text for * the state */ layout = gtk_widget_create_pango_layout (widget, C_("switch", "ON")); pango_layout_get_extents (layout, NULL, &rect); pango_extents_to_pixels (&rect, NULL); label_x = x + ((width / 2) - rect.width) / 2; label_y = y + (height - rect.height) / 2; gtk_render_layout (context, cr, label_x, label_y, layout); g_object_unref (layout); /* Translators: if the "off" state label requires more than three * glyphs then use WHITE CIRCLE (U+25CB) as the text for the state */ layout = gtk_widget_create_pango_layout (widget, C_("switch", "OFF")); pango_layout_get_extents (layout, NULL, &rect); pango_extents_to_pixels (&rect, NULL); label_x = x + (width / 2) + ((width / 2) - rect.width) / 2; label_y = y + (height - rect.height) / 2; gtk_render_layout (context, cr, label_x, label_y, layout); g_object_unref (layout); if (priv->is_dragging) handle.x = x + priv->handle_x; else if (priv->is_active) handle.x = x + width - handle.width; else handle.x = x; gtk_style_context_restore (context); gtk_switch_paint_handle (widget, cr, &handle); if (gtk_widget_has_visible_focus (widget)) { gint focus_width, focus_pad, pad; gtk_widget_style_get (widget, "focus-line-width", &focus_width, "focus-padding", &focus_pad, NULL); pad = focus_pad + focus_width; gtk_render_focus (context, cr, handle.x + pad, handle.y + pad, handle.width - pad*2, handle.height - pad*2); } return FALSE; }
static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_lib_navigation_t *d = (dt_lib_navigation_t *)self->data; const int inset = DT_NAVIGATION_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int width = allocation.width, height = allocation.height; dt_develop_t *dev = darktable.develop; /* double buffering of image data: only take new data if valid */ if(dev->preview_pipe->backbuf && dev->preview_status == DT_DEV_PIXELPIPE_VALID) { /* re-allocate in case of changed image dimensions */ if(d->buffer == NULL || dev->preview_pipe->backbuf_width != d->wd || dev->preview_pipe->backbuf_height != d->ht) { g_free(d->buffer); d->wd = dev->preview_pipe->backbuf_width; d->ht = dev->preview_pipe->backbuf_height; d->buffer = g_malloc0((size_t)d->wd * d->ht * 4 * sizeof(unsigned char)); } /* update buffer if new data is available */ if(d->buffer && dev->preview_pipe->input_timestamp > d->timestamp) { dt_pthread_mutex_t *mutex = &dev->preview_pipe->backbuf_mutex; dt_pthread_mutex_lock(mutex); memcpy(d->buffer, dev->preview_pipe->backbuf, (size_t)d->wd * d->ht * 4 * sizeof(unsigned char)); d->timestamp = dev->preview_pipe->input_timestamp; dt_pthread_mutex_unlock(mutex); } } /* get the current style */ cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); GtkStyleContext *context = gtk_widget_get_style_context(widget); gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height); width -= 2 * inset; height -= 2 * inset; cairo_translate(cr, inset, inset); /* draw navigation image if available */ if(d->buffer) { cairo_save(cr); const int wd = d->wd; const int ht = d->ht; const float scale = fminf(width / (float)wd, height / (float)ht); const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wd); cairo_surface_t *surface = cairo_image_surface_create_for_data(d->buffer, CAIRO_FORMAT_RGB24, wd, ht, stride); cairo_translate(cr, width / 2.0, height / 2.0f); cairo_scale(cr, scale, scale); cairo_translate(cr, -.5f * wd, -.5f * ht); // draw shadow around float alpha = 1.0f; for(int k = 0; k < 4; k++) { cairo_rectangle(cr, -k / scale, -k / scale, wd + 2 * k / scale, ht + 2 * k / scale); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.6f; cairo_fill(cr); } cairo_rectangle(cr, 0, 0, wd - 2, ht - 1); cairo_set_source_surface(cr, surface, 0, 0); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST); cairo_fill(cr); cairo_surface_destroy(surface); // draw box where we are dt_dev_zoom_t zoom = dt_control_get_dev_zoom(); int closeup = dt_control_get_dev_closeup(); float zoom_x = dt_control_get_dev_zoom_x(); float zoom_y = dt_control_get_dev_zoom_y(); const float min_scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, closeup ? 2.0 : 1.0, 0); const float cur_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0); // avoid numerical instability for small resolutions: double h, w; if(cur_scale > min_scale) { float boxw = 1, boxh = 1; dt_dev_check_zoom_bounds(darktable.develop, &zoom_x, &zoom_y, zoom, closeup, &boxw, &boxh); cairo_translate(cr, wd * (.5f + zoom_x), ht * (.5f + zoom_y)); cairo_set_source_rgb(cr, 0., 0., 0.); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.f / scale)); boxw *= wd; boxh *= ht; cairo_rectangle(cr, -boxw / 2 - 1, -boxh / 2 - 1, boxw + 2, boxh + 2); cairo_stroke(cr); cairo_set_source_rgb(cr, 1., 1., 1.); cairo_rectangle(cr, -boxw / 2, -boxh / 2, boxw, boxh); cairo_stroke(cr); } cairo_restore(cr); if(fabsf(cur_scale - min_scale) > 0.001f) { /* Zoom % */ PangoLayout *layout; PangoRectangle ink; PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc); pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); layout = pango_cairo_create_layout(cr); const float fontsize = DT_PIXEL_APPLY_DPI(11); pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE); pango_layout_set_font_description(layout, desc); cairo_translate(cr, 0, height); cairo_set_source_rgba(cr, 1., 1., 1., 0.5); cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND); char zoomline[5]; snprintf(zoomline, sizeof(zoomline), "%.0f%%", cur_scale * 100); pango_layout_set_text(layout, zoomline, -1); pango_layout_get_pixel_extents(layout, &ink, NULL); h = d->zoom_h = ink.height; w = d->zoom_w = ink.width; cairo_move_to(cr, width - w - h * 1.1 - ink.x, - fontsize); cairo_save(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0)); GdkRGBA *color; gtk_style_context_get(context, gtk_widget_get_state_flags(widget), "background-color", &color, NULL); gdk_cairo_set_source_rgba(cr, color); pango_cairo_layout_path(cr, layout); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_fill(cr); cairo_restore(cr); gdk_rgba_free(color); pango_font_description_free(desc); g_object_unref(layout); } else { // draw the zoom-to-fit icon cairo_translate(cr, 0, height); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); static int height = -1; if(height == -1) { PangoLayout *layout; PangoRectangle ink; PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc); pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); layout = pango_cairo_create_layout(cr); pango_font_description_set_absolute_size(desc, DT_PIXEL_APPLY_DPI(11) * PANGO_SCALE); pango_layout_set_font_description(layout, desc); pango_layout_set_text(layout, "100%", -1); // dummy text, just to get the height pango_layout_get_pixel_extents(layout, &ink, NULL); height = ink.height; pango_font_description_free(desc); g_object_unref(layout); } h = d->zoom_h = height; w = h * 1.5; float sp = h * 0.6; d->zoom_w = w + sp; cairo_move_to(cr, width - w - h - sp, -1.0 * h); cairo_rectangle(cr, width - w - h - sp, -1.0 * h, w, h); cairo_set_source_rgb(cr, 0.2, 0.2, 0.2); cairo_fill(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0)); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_move_to(cr, width - w * 0.8 - h - sp, -1.0 * h); cairo_line_to(cr, width - w - h - sp, -1.0 * h); cairo_line_to(cr, width - w - h - sp, -0.7 * h); cairo_stroke(cr); cairo_move_to(cr, width - w - h - sp, -0.3 * h); cairo_line_to(cr, width - w - h - sp, 0); cairo_line_to(cr, width - w * 0.8 - h - sp, 0); cairo_stroke(cr); cairo_move_to(cr, width - w * 0.2 - h - sp, 0); cairo_line_to(cr, width - h - sp, 0); cairo_line_to(cr, width - h - sp, -0.3 * h); cairo_stroke(cr); cairo_move_to(cr, width - h - sp, -0.7 * h); cairo_line_to(cr, width - h - sp, -1.0 * h); cairo_line_to(cr, width - w * 0.2 - h - sp, -1.0 * h); cairo_stroke(cr); } cairo_move_to(cr, width - 0.95 * h, -0.9 * h); cairo_line_to(cr, width - 0.05 * h, -0.9 * h); cairo_line_to(cr, width - 0.5 * h, -0.1 * h); cairo_fill(cr); } /* blit memsurface into widget */ cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }