void application_draw(cairo_t *cr, int width, int height) // draw onto the main window using cairo // width is the actual width of the main window // height is the actual height of the main window #define FIELD_SIZE 20 #define CIRCLE_RADIUS 6 { int i,x, y, pin, xNum, xLabel, xWiringPi; char str[16]; // printf("application_draw called\n"); // set the backgrond color cairo_rectangle(cr, 0.0, 0.0, width, height); cairo_set_source_rgb(cr, 0.93, 0.93, 0.93); cairo_fill(cr); cairo_set_font_size(cr, 11); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_set_line_width (cr, 1); cairo_rectangle (cr, width / 2 - (9 * FIELD_SIZE), 12, 18 * FIELD_SIZE, 22 * FIELD_SIZE); y = 26; x = (width / 2) - ((3 * FIELD_SIZE) / 2); cairo_move_to(cr, x, y); cairo_show_text(cr, "pi-gpio"); x = (width / 2) - ((18 * FIELD_SIZE) / 2) + 6; cairo_move_to(cr, x, y); cairo_show_text(cr, "wirPi"); x = (width / 2) - ((11 * FIELD_SIZE) / 2) - 6; cairo_move_to(cr, x, y); cairo_show_text(cr, "pin name"); x = (width / 2) + ((7 * FIELD_SIZE) / 2) - 6; cairo_move_to(cr, x, y); cairo_show_text(cr, "pin name"); x = (width / 2) + ((14 * FIELD_SIZE) / 2) + 4; cairo_move_to(cr, x, y); cairo_show_text(cr, "wirPi"); cairo_move_to(cr, width / 2 - (9 * FIELD_SIZE), 12 + FIELD_SIZE); cairo_line_to(cr, width / 2 + (9 * FIELD_SIZE), 12 + FIELD_SIZE); cairo_move_to(cr, width / 2 - (7 * FIELD_SIZE), 12); cairo_line_to(cr, width / 2 - (7 * FIELD_SIZE), 12 + (22 * FIELD_SIZE)); cairo_move_to(cr, width / 2 - (2 * FIELD_SIZE), 12); cairo_line_to(cr, width / 2 - (2 * FIELD_SIZE), 12 + (22 * FIELD_SIZE)); cairo_move_to(cr, width / 2 + (2 * FIELD_SIZE), 12); cairo_line_to(cr, width / 2 + (2 * FIELD_SIZE), 12 + (22 * FIELD_SIZE)); cairo_move_to(cr, width / 2 + (7 * FIELD_SIZE), 12); cairo_line_to(cr, width / 2 + (7 * FIELD_SIZE), 12 + (22 * FIELD_SIZE)); for (pin = 1; pin <= 40; pin++) { if (pin % 2) { x = (width / 2) - (FIELD_SIZE / 2); xNum = x - FIELD_SIZE - 6; xLabel = x - (6 * FIELD_SIZE) - 6; xWiringPi = (width / 2) - ((18 * FIELD_SIZE) / 2) + 12; } else { x = (width / 2) + (FIELD_SIZE / 2); xNum = x + FIELD_SIZE - 8; xLabel = x + (2 * FIELD_SIZE) - 2; xWiringPi = (width / 2) + ((14 * FIELD_SIZE) / 2) + 12; } y = FIELD_SIZE + 12 + (((pin + 1) / 2) * FIELD_SIZE); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_move_to(cr, xNum, y + 4); sprintf(str, "%2d", pin); cairo_show_text(cr, str); cairo_stroke (cr); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); // black cairo_move_to(cr, x + CIRCLE_RADIUS, y); cairo_arc(cr, x, y, CIRCLE_RADIUS, 0, 2 * M_PI); if (pinConfig[pin].value) { cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1.0, 0.0, 0.0); // fill red cairo_fill(cr); } else if (pinConfig[pin].wiringPiPin >= 0) { cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.5, 0.0, 0.0); // fill dark red cairo_fill(cr); } cairo_stroke (cr); if (pinConfig[pin].wiringPiPin >= 0) cairo_set_source_rgb(cr, 0.0, 0.5, 0.0); // dark green else cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); // black cairo_move_to(cr, xLabel, y + 4); cairo_show_text(cr, pinConfig[pin].name); if (pinConfig[pin].wiringPiPin >= 0) { sprintf(str, "%2d", pinConfig[pin].wiringPiPin); cairo_move_to(cr, xWiringPi, y + 4); cairo_show_text(cr, str); } } cairo_stroke (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 gboolean _lib_navigation_expose_callback(GtkWidget *widget, GdkEventExpose *event, 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; if(dev->preview_status != DT_DEV_PIXELPIPE_VALID) return FALSE; /* get the current style */ GtkStyle *style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), NULL, "GtkWidget", GTK_TYPE_WIDGET); if(!style) style = gtk_rc_get_style(widget); cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); /* fill background */ cairo_set_source_rgb(cr, style->bg[0].red / 65535.0, style->bg[0].green / 65535.0, style->bg[0].blue / 65535.0); cairo_paint(cr); width -= 2 * inset; height -= 2 * inset; cairo_translate(cr, inset, inset); /* draw navigation image if available */ if(dev->preview_pipe->backbuf && (dev->preview_status == DT_DEV_PIXELPIPE_VALID)) { dt_pthread_mutex_t *mutex = &dev->preview_pipe->backbuf_mutex; dt_pthread_mutex_lock(mutex); const int wd = dev->preview_pipe->backbuf_width; const int ht = dev->preview_pipe->backbuf_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(dev->preview_pipe->backbuf, 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); dt_pthread_mutex_unlock(mutex); // 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, 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); } if(fabsf(cur_scale - min_scale) > 0.001f) { /* Zoom % */ cairo_identity_matrix(cr); cairo_translate(cr, 0, height); cairo_set_source_rgba(cr, 1., 1., 1., 0.5); cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, DT_PIXEL_APPLY_DPI(11)); char zoomline[5]; snprintf(zoomline, sizeof(zoomline), "%.0f%%", cur_scale * 100); cairo_text_extents_t ext; cairo_text_extents(cr, zoomline, &ext); h = d->zoom_h = ext.height; w = d->zoom_w = ext.width; cairo_move_to(cr, width - w - h * 1.1, 0); cairo_save(cr); cairo_set_line_width(cr, 2.0); cairo_set_source_rgb(cr, style->bg[0].red / 65535.0, style->bg[0].green / 65535.0, style->bg[0].blue / 65535.0); cairo_text_path(cr, zoomline); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_fill(cr); cairo_restore(cr); } else { // draw the zoom-to-fit icon cairo_identity_matrix(cr); cairo_translate(cr, 0, height); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_text_extents_t ext; cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cr, DT_PIXEL_APPLY_DPI(11)); cairo_text_extents(cr, "100%", &ext); // dummy text, just to get the height h = d->zoom_h = ext.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_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_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_surface(cr_pixmap, cst, 0, 0); cairo_paint(cr_pixmap); cairo_destroy(cr_pixmap); cairo_surface_destroy(cst); return TRUE; }
static void polygon_view_draw (PolygonView *self, cairo_t *cr) { polygon_t *polygon; gdouble sf_x, sf_y, sf; gdouble mid, dim; gdouble x0, y0; box_t extents; extents = self->extents; mid = (extents.p2.x + extents.p1.x) / 2.; dim = (extents.p2.x - extents.p1.x) / 2. * 1.25; sf_x = self->widget.allocation.width / dim / 2; mid = (extents.p2.y + extents.p1.y) / 2.; dim = (extents.p2.y - extents.p1.y) / 2. * 1.25; sf_y = self->widget.allocation.height / dim / 2; sf = MIN (sf_x, sf_y); mid = (extents.p2.x + extents.p1.x) / 2.; dim = sf_x / sf * (extents.p2.x - extents.p1.x) / 2. * 1.25; x0 = mid - dim; mid = (extents.p2.y + extents.p1.y) / 2.; dim = sf_y / sf * (extents.p2.y - extents.p1.y) / 2. * 1.25; y0 = mid - dim; if (self->pixmap_width != self->widget.allocation.width || self->pixmap_height != self->widget.allocation.height) { cairo_surface_destroy (self->pixmap); self->pixmap = pixmap_create (self, cairo_get_target (cr)); self->pixmap_width = self->widget.allocation.width; self->pixmap_height = self->widget.allocation.height; } cairo_set_source_surface (cr, self->pixmap, 0, 0); cairo_paint (cr); if (self->polygons == NULL) return; /* draw a zoom view of the area around the mouse */ if (1) { double zoom = self->mag_zoom; int size = self->mag_size; int mag_x = self->mag_x; int mag_y = self->mag_y; if (1) { if (self->px + size < self->widget.allocation.width/2) mag_x = self->px + size/4; else mag_x = self->px - size/4 - size; mag_y = self->py - size/2; if (mag_y < 0) mag_y = 0; if (mag_y + size > self->widget.allocation.height) mag_y = self->widget.allocation.height - size; } cairo_save (cr); { /* bottom right */ cairo_rectangle (cr, mag_x, mag_y, size, size); cairo_stroke_preserve (cr); cairo_set_source_rgb (cr, 1, 1, 1); cairo_fill_preserve (cr); cairo_clip (cr); /* compute roi in extents */ cairo_translate (cr, mag_x + size/2, mag_y + size/2); cairo_save (cr); { cairo_scale (cr, zoom, zoom); cairo_translate (cr, -(self->px / sf + x0), -(self->py /sf + y0)); for (polygon = self->polygons; polygon; polygon = polygon->next) { if (polygon->num_edges == 0) continue; draw_polygon (cr, polygon, zoom); } if (highlight != -1) { cairo_move_to (cr, extents.p1.x, highlight); cairo_line_to (cr, extents.p2.x, highlight); cairo_set_source_rgb (cr, 0, .7, 0); cairo_save (cr); cairo_identity_matrix (cr); cairo_set_line_width (cr, 1.); cairo_stroke (cr); cairo_restore (cr); } } cairo_restore (cr); /* grid */ cairo_save (cr); { int i; cairo_translate (cr, -zoom*fmod (self->px/sf + x0, 1.), -zoom*fmod (self->py/sf + y0, 1.)); zoom /= 2; for (i = -size/2/zoom; i <= size/2/zoom + 1; i+=2) { cairo_move_to (cr, zoom*i, -size/2); cairo_line_to (cr, zoom*i, size/2 + zoom); cairo_move_to (cr, -size/2, zoom*i); cairo_line_to (cr, size/2 + zoom, zoom*i); } zoom *= 2; cairo_set_source_rgba (cr, .7, .7, .7, .5); cairo_set_line_width (cr, 1.); cairo_stroke (cr); for (i = -size/2/zoom - 1; i <= size/2/zoom + 1; i++) { cairo_move_to (cr, zoom*i, -size/2); cairo_line_to (cr, zoom*i, size/2 + zoom); cairo_move_to (cr, -size/2, zoom*i); cairo_line_to (cr, size/2 + zoom, zoom*i); } cairo_set_source_rgba (cr, .1, .1, .1, .5); cairo_set_line_width (cr, 2.); cairo_stroke (cr); } cairo_restore (cr); } cairo_restore (cr); } }
void gfxContext::Stroke() { cairo_stroke_preserve(mCairo); }
/* This file is part of darktable, copyright (c) 2009--2011 johannes hanika. copyright (c) 2012 tobias ellinghaus. copyright (c) 2014 henrik andersson. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. darktable is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with darktable. If not, see <http://www.gnu.org/licenses/>. */ #include "bauhaus/bauhaus.h" #include "common/camera_control.h" #include "common/darktable.h" #include "common/image_cache.h" #include "common/mipmap_cache.h" #include "control/conf.h" #include "control/control.h" #include "control/jobs.h" #include "dtgtk/button.h" #include "gui/accelerators.h" #include "gui/gtk.h" #include "gui/guides.h" #include "libs/lib.h" #include "libs/lib_api.h" #include <gdk/gdkkeysyms.h> typedef enum dt_lib_live_view_flip_t { FLAG_FLIP_NONE = 0, FLAG_FLIP_HORIZONTAL = 1<<0, FLAG_FLIP_VERTICAL = 1<<1, FLAG_FLIP_BOTH = FLAG_FLIP_HORIZONTAL|FLAG_FLIP_VERTICAL } dt_lib_live_view_flip_t; typedef enum dt_lib_live_view_overlay_t { OVERLAY_NONE = 0, OVERLAY_SELECTED, OVERLAY_ID } dt_lib_live_view_overlay_t; #define HANDLE_SIZE 0.02 static const cairo_operator_t _overlay_modes[] = { CAIRO_OPERATOR_OVER, CAIRO_OPERATOR_XOR, CAIRO_OPERATOR_ADD, CAIRO_OPERATOR_SATURATE #if(CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)) , CAIRO_OPERATOR_MULTIPLY, CAIRO_OPERATOR_SCREEN, CAIRO_OPERATOR_OVERLAY, CAIRO_OPERATOR_DARKEN, CAIRO_OPERATOR_LIGHTEN, CAIRO_OPERATOR_COLOR_DODGE, CAIRO_OPERATOR_COLOR_BURN, CAIRO_OPERATOR_HARD_LIGHT, CAIRO_OPERATOR_SOFT_LIGHT, CAIRO_OPERATOR_DIFFERENCE, CAIRO_OPERATOR_EXCLUSION, CAIRO_OPERATOR_HSL_HUE, CAIRO_OPERATOR_HSL_SATURATION, CAIRO_OPERATOR_HSL_COLOR, CAIRO_OPERATOR_HSL_LUMINOSITY #endif }; DT_MODULE(1) typedef struct dt_lib_live_view_t { int imgid; int splitline_rotation; double overlay_x0, overlay_x1, overlay_y0, overlay_y1; double splitline_x, splitline_y; // 0..1 gboolean splitline_dragging; GtkWidget *live_view, *live_view_zoom, *rotate_ccw, *rotate_cw, *flip; GtkWidget *focus_out_small, *focus_out_big, *focus_in_small, *focus_in_big; GtkWidget *guide_selector, *flip_guides, *guides_widgets; GList *guides_widgets_list; GtkWidget *overlay, *overlay_id_box, *overlay_id, *overlay_mode, *overlay_splitline; } dt_lib_live_view_t; static void guides_presets_set_visibility(dt_lib_live_view_t *lib, int which) { if(which == 0) { gtk_widget_set_no_show_all(lib->guides_widgets, TRUE); gtk_widget_hide(lib->guides_widgets); gtk_widget_set_no_show_all(lib->flip_guides, TRUE); gtk_widget_hide(lib->flip_guides); } else { GtkWidget *widget = g_list_nth_data(lib->guides_widgets_list, which - 1); if(widget) { gtk_widget_set_no_show_all(lib->guides_widgets, FALSE); gtk_widget_show_all(lib->guides_widgets); gtk_stack_set_visible_child(GTK_STACK(lib->guides_widgets), widget); } else { gtk_widget_set_no_show_all(lib->guides_widgets, TRUE); gtk_widget_hide(lib->guides_widgets); } gtk_widget_set_no_show_all(lib->flip_guides, FALSE); gtk_widget_show_all(lib->flip_guides); } // TODO: add a support_flip flag to guides to hide the flip gui? } static void guides_presets_changed(GtkWidget *combo, dt_lib_live_view_t *lib) { int which = dt_bauhaus_combobox_get(combo); guides_presets_set_visibility(lib, which); } static void overlay_changed(GtkWidget *combo, dt_lib_live_view_t *lib) { int which = dt_bauhaus_combobox_get(combo); if(which == OVERLAY_NONE) { gtk_widget_set_visible(GTK_WIDGET(lib->overlay_mode), FALSE); gtk_widget_set_visible(GTK_WIDGET(lib->overlay_splitline), FALSE); } else { gtk_widget_set_visible(GTK_WIDGET(lib->overlay_mode), TRUE); gtk_widget_set_visible(GTK_WIDGET(lib->overlay_splitline), TRUE); } if(which == OVERLAY_ID) gtk_widget_set_visible(GTK_WIDGET(lib->overlay_id_box), TRUE); else gtk_widget_set_visible(GTK_WIDGET(lib->overlay_id_box), FALSE); } const char *name(dt_lib_module_t *self) { return _("live view"); } const char **views(dt_lib_module_t *self) { static const char *v[] = {"tethering", NULL}; return v; } uint32_t container(dt_lib_module_t *self) { return DT_UI_CONTAINER_PANEL_RIGHT_CENTER; } void gui_reset(dt_lib_module_t *self) { } int position() { return 998; } void init_key_accels(dt_lib_module_t *self) { dt_accel_register_lib(self, NC_("accel", "toggle live view"), GDK_KEY_v, 0); dt_accel_register_lib(self, NC_("accel", "zoom live view"), GDK_KEY_z, 0); dt_accel_register_lib(self, NC_("accel", "rotate 90 degrees CCW"), 0, 0); dt_accel_register_lib(self, NC_("accel", "rotate 90 degrees CW"), 0, 0); dt_accel_register_lib(self, NC_("accel", "flip horizontally"), 0, 0); dt_accel_register_lib(self, NC_("accel", "move focus point in (big steps)"), 0, 0); dt_accel_register_lib(self, NC_("accel", "move focus point in (small steps)"), 0, 0); dt_accel_register_lib(self, NC_("accel", "move focus point out (small steps)"), 0, 0); dt_accel_register_lib(self, NC_("accel", "move focus point out (big steps)"), 0, 0); } void connect_key_accels(dt_lib_module_t *self) { dt_lib_live_view_t *lib = (dt_lib_live_view_t *)self->data; dt_accel_connect_button_lib(self, "toggle live view", GTK_WIDGET(lib->live_view)); dt_accel_connect_button_lib(self, "zoom live view", GTK_WIDGET(lib->live_view_zoom)); dt_accel_connect_button_lib(self, "rotate 90 degrees CCW", GTK_WIDGET(lib->rotate_ccw)); dt_accel_connect_button_lib(self, "rotate 90 degrees CW", GTK_WIDGET(lib->rotate_cw)); dt_accel_connect_button_lib(self, "flip horizontally", GTK_WIDGET(lib->flip)); dt_accel_connect_button_lib(self, "move focus point in (big steps)", GTK_WIDGET(lib->focus_in_big)); dt_accel_connect_button_lib(self, "move focus point in (small steps)", GTK_WIDGET(lib->focus_in_small)); dt_accel_connect_button_lib(self, "move focus point out (small steps)", GTK_WIDGET(lib->focus_out_small)); dt_accel_connect_button_lib(self, "move focus point out (big steps)", GTK_WIDGET(lib->focus_out_big)); } static void _rotate_ccw(GtkWidget *widget, gpointer user_data) { dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera; cam->live_view_rotation = (cam->live_view_rotation + 1) % 4; // 0 -> 1 -> 2 -> 3 -> 0 -> ... } static void _rotate_cw(GtkWidget *widget, gpointer user_data) { dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera; cam->live_view_rotation = (cam->live_view_rotation + 3) % 4; // 0 -> 3 -> 2 -> 1 -> 0 -> ... } // Congratulations to Simon for being the first one recognizing live view in a screen shot ^^ static void _toggle_live_view_clicked(GtkWidget *widget, gpointer user_data) { if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) == TRUE) { if(dt_camctl_camera_start_live_view(darktable.camctl) == FALSE) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), FALSE); } else { dt_camctl_camera_stop_live_view(darktable.camctl); } } // TODO: using a toggle button would be better, but this setting can also be changed by right clicking on the // canvas (src/views/capture.c). // maybe using a signal would work? i have no idea. static void _zoom_live_view_clicked(GtkWidget *widget, gpointer user_data) { dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera; if(cam->is_live_viewing) { cam->live_view_zoom = !cam->live_view_zoom; if(cam->live_view_zoom == TRUE) dt_camctl_camera_set_property_string(darktable.camctl, NULL, "eoszoom", "5"); else dt_camctl_camera_set_property_string(darktable.camctl, NULL, "eoszoom", "1"); } } static void _focus_button_clicked(GtkWidget *widget, gpointer user_data) { int focus = GPOINTER_TO_INT(user_data); dt_camctl_camera_set_property_choice(darktable.camctl, NULL, "manualfocusdrive", focus); } static void _toggle_flip_clicked(GtkWidget *widget, gpointer user_data) { dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera; cam->live_view_flip = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); } static void _overlay_id_changed(GtkWidget *widget, gpointer user_data) { dt_lib_live_view_t *lib = (dt_lib_live_view_t *)user_data; lib->imgid = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)); dt_conf_set_int("plugins/lighttable/live_view/overlay_imgid", lib->imgid); } static void _overlay_mode_changed(GtkWidget *combo, gpointer user_data) { dt_conf_set_int("plugins/lighttable/live_view/overlay_mode", dt_bauhaus_combobox_get(combo)); } static void _overlay_splitline_changed(GtkWidget *combo, gpointer user_data) { dt_conf_set_int("plugins/lighttable/live_view/splitline", dt_bauhaus_combobox_get(combo)); } void gui_init(dt_lib_module_t *self) { self->data = calloc(1, sizeof(dt_lib_live_view_t)); // Setup lib data dt_lib_live_view_t *lib = self->data; lib->splitline_x = lib->splitline_y = 0.5; // Setup gui self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); dt_gui_add_help_link(self->widget, "live_view.html#live_view"); GtkWidget *box; box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0); lib->live_view = dtgtk_togglebutton_new(dtgtk_cairo_paint_eye, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER, NULL); lib->live_view_zoom = dtgtk_button_new( dtgtk_cairo_paint_zoom, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER, NULL); // TODO: see _zoom_live_view_clicked lib->rotate_ccw = dtgtk_button_new(dtgtk_cairo_paint_refresh, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER, NULL); lib->rotate_cw = dtgtk_button_new(dtgtk_cairo_paint_refresh, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_UP, NULL); lib->flip = dtgtk_togglebutton_new(dtgtk_cairo_paint_flip, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_UP, NULL); gtk_box_pack_start(GTK_BOX(box), lib->live_view, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), lib->live_view_zoom, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), lib->rotate_ccw, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), lib->rotate_cw, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), lib->flip, TRUE, TRUE, 0); gtk_widget_set_tooltip_text(lib->live_view, _("toggle live view")); gtk_widget_set_tooltip_text(lib->live_view_zoom, _("zoom live view")); gtk_widget_set_tooltip_text(lib->rotate_ccw, _("rotate 90 degrees ccw")); gtk_widget_set_tooltip_text(lib->rotate_cw, _("rotate 90 degrees cw")); gtk_widget_set_tooltip_text(lib->flip, _("flip live view horizontally")); g_signal_connect(G_OBJECT(lib->live_view), "clicked", G_CALLBACK(_toggle_live_view_clicked), lib); g_signal_connect(G_OBJECT(lib->live_view_zoom), "clicked", G_CALLBACK(_zoom_live_view_clicked), lib); g_signal_connect(G_OBJECT(lib->rotate_ccw), "clicked", G_CALLBACK(_rotate_ccw), lib); g_signal_connect(G_OBJECT(lib->rotate_cw), "clicked", G_CALLBACK(_rotate_cw), lib); g_signal_connect(G_OBJECT(lib->flip), "clicked", G_CALLBACK(_toggle_flip_clicked), lib); // focus buttons box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_pack_start(GTK_BOX(self->widget), box, TRUE, TRUE, 0); lib->focus_in_big = dtgtk_button_new(dtgtk_cairo_paint_solid_triangle, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_LEFT, NULL); lib->focus_in_small = dtgtk_button_new(dtgtk_cairo_paint_arrow, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_LEFT, NULL); // TODO icon not centered lib->focus_out_small = dtgtk_button_new(dtgtk_cairo_paint_arrow, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_RIGHT, NULL); // TODO same here lib->focus_out_big = dtgtk_button_new(dtgtk_cairo_paint_solid_triangle, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_RIGHT, NULL); gtk_box_pack_start(GTK_BOX(box), lib->focus_in_big, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), lib->focus_in_small, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), lib->focus_out_small, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), lib->focus_out_big, TRUE, TRUE, 0); gtk_widget_set_tooltip_text(lib->focus_in_big, _("move focus point in (big steps)")); gtk_widget_set_tooltip_text(lib->focus_in_small, _("move focus point in (small steps)")); gtk_widget_set_tooltip_text(lib->focus_out_small, _("move focus point out (small steps)")); gtk_widget_set_tooltip_text(lib->focus_out_big, _("move focus point out (big steps)")); // Near 3 g_signal_connect(G_OBJECT(lib->focus_in_big), "clicked", G_CALLBACK(_focus_button_clicked), GINT_TO_POINTER(2)); // Near 1 g_signal_connect(G_OBJECT(lib->focus_in_small), "clicked", G_CALLBACK(_focus_button_clicked), GINT_TO_POINTER(0)); // Far 1 g_signal_connect(G_OBJECT(lib->focus_out_small), "clicked", G_CALLBACK(_focus_button_clicked), GINT_TO_POINTER(4)); // Far 3 g_signal_connect(G_OBJECT(lib->focus_out_big), "clicked", G_CALLBACK(_focus_button_clicked), GINT_TO_POINTER(6)); // Guides lib->guide_selector = dt_bauhaus_combobox_new(NULL); dt_bauhaus_widget_set_label(lib->guide_selector, NULL, _("guides")); gtk_box_pack_start(GTK_BOX(self->widget), lib->guide_selector, TRUE, TRUE, 0); lib->guides_widgets = gtk_stack_new(); gtk_stack_set_homogeneous(GTK_STACK(lib->guides_widgets), FALSE); gtk_box_pack_start(GTK_BOX(self->widget), lib->guides_widgets, TRUE, TRUE, 0); dt_bauhaus_combobox_add(lib->guide_selector, _("none")); int i = 0; for(GList *iter = darktable.guides; iter; iter = g_list_next(iter), i++) { GtkWidget *widget = NULL; dt_guides_t *guide = (dt_guides_t *)iter->data; dt_bauhaus_combobox_add(lib->guide_selector, _(guide->name)); if(guide->widget) { // generate some unique name so that we can have the same name several times char name[5]; snprintf(name, sizeof(name), "%d", i); widget = guide->widget(NULL, guide->user_data); gtk_widget_show_all(widget); gtk_stack_add_named(GTK_STACK(lib->guides_widgets), widget, name); } lib->guides_widgets_list = g_list_append(lib->guides_widgets_list, widget); } gtk_widget_set_no_show_all(lib->guides_widgets, TRUE); gtk_widget_set_tooltip_text(lib->guide_selector, _("display guide lines to help compose your photograph")); g_signal_connect(G_OBJECT(lib->guide_selector), "value-changed", G_CALLBACK(guides_presets_changed), lib); lib->flip_guides = dt_bauhaus_combobox_new(NULL); dt_bauhaus_widget_set_label(lib->flip_guides, NULL, _("flip")); dt_bauhaus_combobox_add(lib->flip_guides, _("none")); dt_bauhaus_combobox_add(lib->flip_guides, _("horizontally")); dt_bauhaus_combobox_add(lib->flip_guides, _("vertically")); dt_bauhaus_combobox_add(lib->flip_guides, _("both")); gtk_widget_set_tooltip_text(lib->flip_guides, _("flip guides")); gtk_box_pack_start(GTK_BOX(self->widget), lib->flip_guides, TRUE, TRUE, 0); lib->overlay = dt_bauhaus_combobox_new(NULL); dt_bauhaus_widget_set_label(lib->overlay, NULL, _("overlay")); dt_bauhaus_combobox_add(lib->overlay, _("none")); dt_bauhaus_combobox_add(lib->overlay, _("selected image")); dt_bauhaus_combobox_add(lib->overlay, _("id")); gtk_widget_set_tooltip_text(lib->overlay, _("overlay another image over the live view")); g_signal_connect(G_OBJECT(lib->overlay), "value-changed", G_CALLBACK(overlay_changed), lib); gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay, TRUE, TRUE, 0); lib->overlay_id_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); GtkWidget *label = gtk_label_new(_("image id")); gtk_widget_set_halign(label, GTK_ALIGN_START); lib->overlay_id = gtk_spin_button_new_with_range(0, 1000000000, 1); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(lib->overlay_id), 0); gtk_widget_set_tooltip_text(lib->overlay_id, _("enter image id of the overlay manually")); g_signal_connect(G_OBJECT(lib->overlay_id), "value-changed", G_CALLBACK(_overlay_id_changed), lib); gtk_spin_button_set_value(GTK_SPIN_BUTTON(lib->overlay_id), dt_conf_get_int("plugins/lighttable/live_view/overlay_imgid")); gtk_box_pack_start(GTK_BOX(lib->overlay_id_box), label, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(lib->overlay_id_box), lib->overlay_id, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay_id_box, TRUE, TRUE, 0); gtk_widget_show(lib->overlay_id); gtk_widget_show(label); lib->overlay_mode = dt_bauhaus_combobox_new(NULL); dt_bauhaus_widget_set_label(lib->overlay_mode, NULL, _("overlay mode")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "normal")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "xor")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "add")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "saturate")); #if(CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0)) dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "multiply")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "screen")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "overlay")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "darken")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "lighten")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "color dodge")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "color burn")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "hard light")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "soft light")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "difference")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "exclusion")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL hue")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL saturation")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL color")); dt_bauhaus_combobox_add(lib->overlay_mode, C_("blendmode", "HSL luminosity")); #endif gtk_widget_set_tooltip_text(lib->overlay_mode, _("mode of the overlay")); dt_bauhaus_combobox_set(lib->overlay_mode, dt_conf_get_int("plugins/lighttable/live_view/overlay_mode")); g_signal_connect(G_OBJECT(lib->overlay_mode), "value-changed", G_CALLBACK(_overlay_mode_changed), lib); gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay_mode, TRUE, TRUE, 0); lib->overlay_splitline = dt_bauhaus_combobox_new(NULL); dt_bauhaus_widget_set_label(lib->overlay_splitline, NULL, _("split line")); dt_bauhaus_combobox_add(lib->overlay_splitline, _("off")); dt_bauhaus_combobox_add(lib->overlay_splitline, _("on")); gtk_widget_set_tooltip_text(lib->overlay_splitline, _("only draw part of the overlay")); dt_bauhaus_combobox_set(lib->overlay_splitline, dt_conf_get_int("plugins/lighttable/live_view/splitline")); g_signal_connect(G_OBJECT(lib->overlay_splitline), "value-changed", G_CALLBACK(_overlay_splitline_changed), lib); gtk_box_pack_start(GTK_BOX(self->widget), lib->overlay_splitline, TRUE, TRUE, 0); gtk_widget_set_visible(GTK_WIDGET(lib->overlay_mode), FALSE); gtk_widget_set_visible(GTK_WIDGET(lib->overlay_id_box), FALSE); gtk_widget_set_visible(GTK_WIDGET(lib->overlay_splitline), FALSE); gtk_widget_set_no_show_all(GTK_WIDGET(lib->overlay_mode), TRUE); gtk_widget_set_no_show_all(GTK_WIDGET(lib->overlay_id_box), TRUE); gtk_widget_set_no_show_all(GTK_WIDGET(lib->overlay_splitline), TRUE); guides_presets_set_visibility(lib, 0); } void gui_cleanup(dt_lib_module_t *self) { // dt_lib_live_view_t *lib = self->data; // g_list_free(lib->guides_widgets_list); // INTENTIONAL. it's supposed to be leaky until lua is fixed. free(self->data); self->data = NULL; } void view_enter(struct dt_lib_module_t *self,struct dt_view_t *old_view,struct dt_view_t *new_view) { // disable buttons that won't work with this camera // TODO: initialize tethering mode outside of libs/camera.s so we can use darktable.camctl->active_camera // here dt_lib_live_view_t *lib = self->data; const dt_camera_t *cam = darktable.camctl->active_camera; if(cam == NULL) cam = darktable.camctl->wanted_camera; gboolean sensitive = cam && cam->can_live_view_advanced; gtk_widget_set_sensitive(lib->live_view_zoom, sensitive); gtk_widget_set_sensitive(lib->focus_in_big, sensitive); gtk_widget_set_sensitive(lib->focus_in_small, sensitive); gtk_widget_set_sensitive(lib->focus_out_big, sensitive); gtk_widget_set_sensitive(lib->focus_out_small, sensitive); } // TODO: find out where the zoom window is and draw overlay + grid accordingly #define MARGIN 20 #define BAR_HEIGHT 18 /* see libs/camera.c */ void gui_post_expose(dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery) { dt_camera_t *cam = (dt_camera_t *)darktable.camctl->active_camera; dt_lib_live_view_t *lib = self->data; if(cam->is_live_viewing == FALSE || cam->live_view_zoom == TRUE) return; dt_pthread_mutex_lock(&cam->live_view_pixbuf_mutex); if(GDK_IS_PIXBUF(cam->live_view_pixbuf) == FALSE) { dt_pthread_mutex_unlock(&cam->live_view_pixbuf_mutex); return; } double w = width - (MARGIN * 2.0f); double h = height - (MARGIN * 2.0f) - BAR_HEIGHT; gint pw = gdk_pixbuf_get_width(cam->live_view_pixbuf); gint ph = gdk_pixbuf_get_height(cam->live_view_pixbuf); lib->overlay_x0 = lib->overlay_x1 = lib->overlay_y0 = lib->overlay_y1 = 0.0; gboolean use_splitline = (dt_bauhaus_combobox_get(lib->overlay_splitline) == 1); // OVERLAY int imgid = 0; switch(dt_bauhaus_combobox_get(lib->overlay)) { case OVERLAY_SELECTED: imgid = dt_view_tethering_get_selected_imgid(darktable.view_manager); break; case OVERLAY_ID: imgid = lib->imgid; break; } if(imgid > 0) { cairo_save(cr); const dt_image_t *img = dt_image_cache_testget(darktable.image_cache, imgid, 'r'); // if the user points at this image, we really want it: if(!img) img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); const float imgwd = 0.97f; dt_mipmap_buffer_t buf; dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, imgwd * w, imgwd * h); dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, mip, 0, 'r'); float scale = 1.0; cairo_surface_t *surface = NULL; if(buf.buf) { const int32_t stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, buf.width); surface = cairo_image_surface_create_for_data(buf.buf, CAIRO_FORMAT_RGB24, buf.width, buf.height, stride); scale = fminf(fminf(w, pw) / (float)buf.width, fminf(h, ph) / (float)buf.height); } // draw centered and fitted: cairo_translate(cr, width / 2.0, (height + BAR_HEIGHT) / 2.0f); cairo_scale(cr, scale, scale); if(buf.buf) { cairo_translate(cr, -.5f * buf.width, -.5f * buf.height); if(use_splitline) { double x0, y0, x1, y1; switch(lib->splitline_rotation) { case 0: x0 = 0.0; y0 = 0.0; x1 = buf.width * lib->splitline_x; y1 = buf.height; break; case 1: x0 = 0.0; y0 = 0.0; x1 = buf.width; y1 = buf.height * lib->splitline_y; break; case 2: x0 = buf.width * lib->splitline_x; y0 = 0.0; x1 = buf.width; y1 = buf.height; break; case 3: x0 = 0.0; y0 = buf.height * lib->splitline_y; x1 = buf.width; y1 = buf.height; break; default: fprintf(stderr, "OMFG, the world will collapse, this shouldn't be reachable!\n"); dt_pthread_mutex_unlock(&cam->live_view_pixbuf_mutex); return; } cairo_rectangle(cr, x0, y0, x1, y1); cairo_clip(cr); } cairo_set_source_surface(cr, surface, 0, 0); // set filter no nearest: // in skull mode, we want to see big pixels. // in 1 iir mode for the right mip, we want to see exactly what the pipe gave us, 1:1 pixel for pixel. // in between, filtering just makes stuff go unsharp. if((buf.width <= 8 && buf.height <= 8) || fabsf(scale - 1.0f) < 0.01f) cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); cairo_rectangle(cr, 0, 0, buf.width, buf.height); int overlay_modes_index = dt_bauhaus_combobox_get(lib->overlay_mode); if(overlay_modes_index >= 0) { cairo_operator_t mode = _overlay_modes[overlay_modes_index]; cairo_set_operator(cr, mode); } cairo_fill(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_surface_destroy(surface); } cairo_restore(cr); if(buf.buf) dt_mipmap_cache_release(darktable.mipmap_cache, &buf); if(img) dt_image_cache_read_release(darktable.image_cache, img); // ON CANVAS CONTROLS if(use_splitline) { scale = fminf(1.0, fminf(w / pw, h / ph)); // image coordinates lib->overlay_x0 = 0.5 * (width - pw * scale); lib->overlay_y0 = 0.5 * (height - ph * scale + BAR_HEIGHT); lib->overlay_x1 = lib->overlay_x0 + pw * scale; lib->overlay_y1 = lib->overlay_y0 + ph * scale; // splitline position to absolute coords: double sl_x = lib->overlay_x0 + lib->splitline_x * pw * scale; double sl_y = lib->overlay_y0 + lib->splitline_y * ph * scale; int x0 = sl_x, y0 = 0.0, x1 = x0, y1 = height; if(lib->splitline_rotation % 2 != 0) { x0 = 0.0; y0 = sl_y; x1 = width; y1 = y0; } gboolean mouse_over_control = (lib->splitline_rotation % 2 == 0) ? (fabs(sl_x - pointerx) < 5) : (fabs(sl_y - pointery) < 5); cairo_save(cr); cairo_set_source_rgb(cr, .7, .7, .7); cairo_set_line_width(cr, (mouse_over_control ? 2.0 : 0.5)); cairo_move_to(cr, x0, y0); cairo_line_to(cr, x1, y1); cairo_stroke(cr); /* if mouse over control lets draw center rotate control, hide if split is dragged */ if(!lib->splitline_dragging && mouse_over_control) { cairo_set_line_width(cr, 0.5); double s = width * HANDLE_SIZE; dtgtk_cairo_paint_refresh(cr, sl_x - (s * 0.5), sl_y - (s * 0.5), s, s, 1, NULL); } cairo_restore(cr); } } // GUIDES if(cam->live_view_rotation % 2 == 1) { gint tmp = pw; pw = ph; ph = tmp; } float scale = 1.0; // if(cam->live_view_zoom == FALSE) // { if(pw > w) scale = w / pw; if(ph > h) scale = fminf(scale, h / ph); // } double sw = scale * pw; double sh = scale * ph; // draw guides int guide_flip = dt_bauhaus_combobox_get(lib->flip_guides); double left = (width - sw) * 0.5; double top = (height + BAR_HEIGHT - sh) * 0.5; double dashes = 5.0; cairo_save(cr); cairo_rectangle(cr, left, top, sw, sh); cairo_clip(cr); cairo_set_dash(cr, &dashes, 1, 0); // Move coordinates to local center selection. cairo_translate(cr, (sw / 2 + left), (sh / 2 + top)); // Flip horizontal. if(guide_flip & FLAG_FLIP_HORIZONTAL) cairo_scale(cr, -1, 1); // Flip vertical. if(guide_flip & FLAG_FLIP_VERTICAL) cairo_scale(cr, 1, -1); int which = dt_bauhaus_combobox_get(lib->guide_selector); dt_guides_t *guide = (dt_guides_t *)g_list_nth_data(darktable.guides, which - 1); if(guide) { guide->draw(cr, -sw / 2, -sh / 2, sw, sh, 1.0, guide->user_data); cairo_stroke_preserve(cr); cairo_set_dash(cr, &dashes, 0, 0); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_stroke(cr); } cairo_restore(cr); dt_pthread_mutex_unlock(&cam->live_view_pixbuf_mutex); }
/* * BackgroundLayer::render * * Render the background to the tab bar, also render the tab bar animation * */ void BackgroundLayer::render () { cairo_t *cr; int twidth, theight, radius; int borderWidth; float r, g, b, a; double x0, y0, x1, y1; GROUP_SCREEN (screen); if (!HAS_TOP_WIN (mGroup) || !mCairo) return; /* Dimentions are the tab bar's region */ twidth = mGroup->mTabBar->mRegion.boundingRect ().width (); theight = mGroup->mTabBar->mRegion.boundingRect ().height (); radius = gs->optionGetBorderRadius (); /* Do not draw more than the tab bar width */ if (twidth > width ()) twidth = width (); /* Border radius should not exceed * half of the tab bar height */ if (radius > twidth / 2) radius = twidth / 2; cr = mCairo; /* Clear the layer */ clear (); /* Draw the border around the tab bar */ borderWidth = gs->optionGetBorderWidth (); cairo_set_line_width (cr, borderWidth); cairo_save (cr); /* Move to the center of where we want to draw the line */ x0 = borderWidth / 2.0f; y0 = borderWidth / 2.0f; /* The center of where we want to draw the opposite line */ x1 = twidth - borderWidth / 2.0f; y1 = theight - borderWidth / 2.0f; cairo_move_to (cr, x0 + radius, y0); /* Arc the top right corner */ cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); /* Arc the bottom right corner */ cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); /* Arc the bottom left corner */ cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); /* Arc the top left corner */ cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); cairo_close_path (cr); /* There are 5 different tab styles here: * Simple: draws a simple filled rect * Gradient: left to right gradient between base and highlight * Glass: left to right gradient, stopping at 60% and drawing a shadow * Metal: base -> highlight -> base gradient * Murrina: draws an arc between the two corners blending base and highlight */ switch (gs->optionGetTabStyle ()) { case GroupOptions::TabStyleSimple: { /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_set_source_rgba (cr, r, g, b, a); cairo_fill_preserve (cr); break; } case GroupOptions::TabStyleGradient: { /* fill */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_linear (0, 0, twidth, theight); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); break; } case GroupOptions::TabStyleGlass: { cairo_pattern_t *pattern; cairo_save (cr); /* clip width rounded rectangle */ cairo_clip (cr); /* ===== HIGHLIGHT ===== */ /* make draw the shape for the highlight and create a pattern for it */ cairo_rectangle (cr, 0, 0, twidth, theight / 2); pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.6f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); /* ==== SHADOW ===== */ /* make draw the shape for the show and create a pattern for it */ cairo_rectangle (cr, 0, theight / 2, twidth, theight); pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* we don't want to use a full highlight here so we mix the colors */ r = (gs->optionGetTabHighlightColorRed () + gs->optionGetTabBaseColorRed ()) / (2 * 65535.0f); g = (gs->optionGetTabHighlightColorGreen () + gs->optionGetTabBaseColorGreen ()) / (2 * 65535.0f); b = (gs->optionGetTabHighlightColorBlue () + gs->optionGetTabBaseColorBlue ()) / (2 * 65535.0f); a = (gs->optionGetTabHighlightColorAlpha () + gs->optionGetTabBaseColorAlpha ()) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.5f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); cairo_restore (cr); /* draw shape again for the outline */ cairo_move_to (cr, x0 + radius, y0); cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); break; } case GroupOptions::TabStyleMetal: { /* fill */ cairo_pattern_t *pattern; pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* base color #1 */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.55f, r, g, b, a); /* base color #2 */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill_preserve (cr); cairo_pattern_destroy (pattern); break; } case GroupOptions::TabStyleMurrina: { double ratio, transX; cairo_pattern_t *pattern; cairo_save (cr); /* clip width rounded rectangle */ cairo_clip_preserve (cr); /* ==== TOP ==== */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = twidth - borderWidth / 2.0; y1 = theight - borderWidth / 2.0; radius = (y1 - y0) / 2; /* setup pattern */ pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* we don't want to use a full highlight here so we mix the colors */ r = (gs->optionGetTabHighlightColorRed () + gs->optionGetTabBaseColorRed ()) / (2 * 65535.0f); g = (gs->optionGetTabHighlightColorGreen () + gs->optionGetTabBaseColorGreen ()) / (2 * 65535.0f); b = (gs->optionGetTabHighlightColorBlue () + gs->optionGetTabBaseColorBlue ()) / (2 * 65535.0f); a = (gs->optionGetTabHighlightColorAlpha () + gs->optionGetTabBaseColorAlpha ()) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* highlight color */ r = gs->optionGetTabHighlightColorRed () / 65535.0f; g = gs->optionGetTabHighlightColorGreen () / 65535.0f; b = gs->optionGetTabHighlightColorBlue () / 65535.0f; a = gs->optionGetTabHighlightColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); /* ==== BOTTOM ===== */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = twidth - borderWidth / 2.0; y1 = theight - borderWidth / 2.0; radius = (y1 - y0) / 2; ratio = (double)twidth / (double)theight; transX = twidth - (twidth * ratio); cairo_move_to (cr, x1, y1); cairo_line_to (cr, x1, y0); if (twidth < theight) { cairo_translate (cr, transX, 0); cairo_scale (cr, ratio, 1.0); } cairo_arc (cr, x1 - radius, y0, radius, 0.0, M_PI * 0.5); if (twidth < theight) { cairo_scale (cr, 1.0 / ratio, 1.0); cairo_translate (cr, -transX, 0); cairo_scale (cr, ratio, 1.0); } cairo_arc_negative (cr, x0 + radius, y1, radius, M_PI * 1.5, M_PI); cairo_close_path (cr); /* setup pattern */ pattern = cairo_pattern_create_linear (0, 0, 0, theight); /* base color */ r = gs->optionGetTabBaseColorRed () / 65535.0f; g = gs->optionGetTabBaseColorGreen () / 65535.0f; b = gs->optionGetTabBaseColorBlue () / 65535.0f; a = gs->optionGetTabBaseColorAlpha () / 65535.0f; cairo_pattern_add_color_stop_rgba (pattern, 0.0f, r, g, b, a); /* we don't want to use a full highlight here so we mix the colors */ r = (gs->optionGetTabHighlightColorRed () + gs->optionGetTabBaseColorRed ()) / (2 * 65535.0f); g = (gs->optionGetTabHighlightColorGreen () + gs->optionGetTabBaseColorGreen ()) / (2 * 65535.0f); b = (gs->optionGetTabHighlightColorBlue () + gs->optionGetTabBaseColorBlue ()) / (2 * 65535.0f); a = (gs->optionGetTabHighlightColorAlpha () + gs->optionGetTabBaseColorAlpha ()) / (2 * 65535.0f); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, r, g, b, a); cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_pattern_destroy (pattern); cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_restore (cr); /* draw shape again for the outline */ x0 = borderWidth / 2.0; y0 = borderWidth / 2.0; x1 = twidth - borderWidth / 2.0; y1 = theight - borderWidth / 2.0; radius = gs->optionGetBorderRadius (); cairo_move_to (cr, x0 + radius, y0); cairo_arc (cr, x1 - radius, y0 + radius, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius, y1 - radius, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius, y1 - radius, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius, y0 + radius, radius, M_PI, M_PI * 1.5); break; } default: break; } /* outline */ r = gs->optionGetTabBorderColorRed () / 65535.0f; g = gs->optionGetTabBorderColorGreen () / 65535.0f; b = gs->optionGetTabBorderColorBlue () / 65535.0f; a = gs->optionGetTabBorderColorAlpha () / 65535.0f; cairo_set_source_rgba (cr, r, g, b, a); /* If there is an animation running, stroke preserved * so that we can paint directly on top (and blend!) * the new animation with the existing tab bar. * Otherwise just stroke normally, this is less expensive */ if (mBgAnimation != AnimationNone) cairo_stroke_preserve (cr); else cairo_stroke (cr); /* There are two animations here: * Pulse: Highlight tab bar in and out (used for tab hover) * Reflex: Paint a diagonal gradient moving from right to left * on the tab bar when it appears */ switch (mBgAnimation) { case AnimationPulse: { double animationProgress; double alpha; /* Progress here is measured in the current time */ animationProgress = mBgAnimationTime / (gs->optionGetPulseTime () * 1000.0); /* The highlight pulsates in and out, so the alpha here should run * on a sine wave */ alpha = sin ((2 * PI * animationProgress) - 1.55)*0.5 + 0.5; /* If the alpha of the animation is < 0, don't bother painting */ if (alpha <= 0) break; cairo_save (cr); cairo_clip (cr); /* Paint highlight over the tab bar */ cairo_set_operator (cr, CAIRO_OPERATOR_XOR); cairo_rectangle (cr, 0.0, 0.0, twidth, theight); cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha); cairo_fill (cr); cairo_restore (cr); break; } case AnimationReflex: { double animationProgress; double reflexWidth; double posX, alpha; cairo_pattern_t *pattern; /* Progress is measured in current time */ animationProgress = mBgAnimationTime / (gs->optionGetReflexTime () * 1000.0); /* Position here is the tab bar width plus the reflection width * 2 */ reflexWidth = (mGroup->mTabBar->mSlots.size () / 2.0) * 30; posX = (twidth + reflexWidth * 2.0) * animationProgress; alpha = sin (PI * animationProgress) * 0.55; if (alpha <= 0) break; cairo_save (cr); cairo_clip (cr); pattern = cairo_pattern_create_linear (posX - reflexWidth, 0.0, posX, theight); cairo_pattern_add_color_stop_rgba (pattern, 0.0f, 1.0, 1.0, 1.0, 0.0); cairo_pattern_add_color_stop_rgba (pattern, 0.5f, 1.0, 1.0, 1.0, alpha); cairo_pattern_add_color_stop_rgba (pattern, 1.0f, 1.0, 1.0, 1.0, 0.0); cairo_rectangle (cr, 0.0, 0.0, twidth, theight); cairo_set_source (cr, pattern); cairo_fill (cr); cairo_restore (cr); cairo_pattern_destroy (pattern); break; } case AnimationNone: default: break; } /* draw inner outline */ cairo_move_to (cr, x0 + radius + 1.0, y0 + 1.0); cairo_arc (cr, x1 - radius - 1.0, y0 + radius + 1.0, radius, M_PI * 1.5, M_PI * 2.0); cairo_arc (cr, x1 - radius - 1.0, y1 - radius - 1.0, radius, 0.0, M_PI * 0.5); cairo_arc (cr, x0 + radius + 1.0, y1 - radius - 1.0, radius, M_PI * 0.5, M_PI); cairo_arc (cr, x0 + radius + 1.0, y0 + radius + 1.0, radius, M_PI, M_PI * 1.5); cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.3); cairo_stroke(cr); cairo_restore (cr); mTexture = GLTexture::imageBufferToTexture ((char*) mBuffer, (CompSize &) *this); }
void drawPie(cairo_t* c, int w, int h) { double w2 = w / 2.0f; double h2 = h / 2.0f; double r = h2 * 0.8f; double seg = (2.0f * osg::PI) / 8.0f; double top = osg::PI + (osg::PI / 2.0f); // each "tier" or level or an arc double lvl[] = { 0.0f, 0.25f, 0.50f, 0.75f, 1.0f }; const char* atts[] = { "Milk", "Horns", "Beefiness", "Moo/HR", "Grazing", "Sleeping", "Cowpower!", "s p o t s" }; double attl[] = { 0.25f, 0.0f, 0.50f, 1.0f, 0.0f, 0.25f, 0.75f, 1.0f }; cairo_set_line_width(c, ((w + h) / 2.0f) * 0.003f); cairo_select_font_face(c, "SegoeUI", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(c, ((w + h) / 2.0f) * 0.05f); cairo_translate(c, w2, h2); cairo_rotate(c, -seg / 2.0f); cairo_set_source_rgba(c, 1.0f, 1.0f, 1.0f, 1.0f); for(unsigned int i = 0; i < 8; i++) { // Pick a random level... cairo_move_to(c, 0.0f, 0.0f); cairo_line_to(c, 0.0f, -r); cairo_arc(c, 0.0f, 0.0f, attl[i] * r, top, top + seg); cairo_line_to(c, 0.0f, 0.0f); cairo_set_source_rgba(c, 0.2f, 0.8f, 0.2f, 0.5f); cairo_fill(c); cairo_set_source_rgba(c, 1.0f, 1.0f, 1.0f, 1.0f); // Do the various levels... cairo_move_to(c, 0.0f, 0.0f); cairo_line_to(c, 0.0f, -r); cairo_stroke(c); for(unsigned int l = 0; l < 5; l++) { cairo_arc(c, 0.0f, 0.0f, lvl[l] * r, top, top + seg); cairo_stroke(c); } cairo_text_extents_t extents; cairo_text_extents(c, atts[i], &extents); double arcsize = r * seg; // ------------------------------------ cairo_save(c); double tr = extents.width / r; double aa = ((arcsize - extents.width) / 2.0f) / r; cairo_arc(c, 0.0f, 0.0f, h2 * 0.85f, top + aa, top + aa + tr); cairo_set_tolerance(c, 0.01f); cairo_path_t* path = cairo_copy_path_flat(c); cairo_new_path(c); cairo_text_path(c, atts[i]); osgCairo::mapPathOnto(c, path); cairo_path_destroy(path); cairo_set_source_rgba(c, 1.0f, 1.0f, 1.0f, 1.0f); cairo_set_line_width(c, 1.0f); cairo_stroke_preserve(c); cairo_set_source_rgba(c, 0.8f, 0.5f, 0.1f, 0.7f); cairo_fill(c); cairo_restore(c); // ------------------------------------ // Pick a random level... cairo_move_to(c, 0.0f, 0.0f); cairo_line_to(c, 0.0f, -r); cairo_arc(c, 0.0f, 0.0f, r, top, top + seg); cairo_line_to(c, 0.0f, 0.0f); cairo_set_source_rgba(c, 1.0f, 1.0f, 1.0f, 1.0f); cairo_stroke(c); cairo_rotate(c, seg); } }
void dt_view_image_expose( dt_view_image_over_t *image_over, uint32_t imgid, cairo_t *cr, int32_t width, int32_t height, int32_t zoom, int32_t px, int32_t py) { cairo_save (cr); float bgcol = 0.4, fontcol = 0.425, bordercol = 0.1, outlinecol = 0.2; int selected = 0, altered = 0, imgsel; DT_CTL_GET_GLOBAL(imgsel, lib_image_mouse_over_id); // if(img->flags & DT_IMAGE_SELECTED) selected = 1; /* clear and reset statements */ DT_DEBUG_SQLITE3_CLEAR_BINDINGS(darktable.view_manager->statements.is_selected); DT_DEBUG_SQLITE3_CLEAR_BINDINGS(darktable.view_manager->statements.have_history); DT_DEBUG_SQLITE3_RESET(darktable.view_manager->statements.is_selected); DT_DEBUG_SQLITE3_RESET(darktable.view_manager->statements.have_history); /* bind imgid to prepared statments */ DT_DEBUG_SQLITE3_BIND_INT(darktable.view_manager->statements.is_selected, 1, imgid); DT_DEBUG_SQLITE3_BIND_INT(darktable.view_manager->statements.have_history, 1, imgid); /* lets check if imgid is selected */ if(sqlite3_step(darktable.view_manager->statements.is_selected) == SQLITE_ROW) selected = 1; /* lets check if imgid has history */ if(sqlite3_step(darktable.view_manager->statements.have_history) == SQLITE_ROW) altered = 1; const dt_image_t *img = dt_image_cache_read_testget(darktable.image_cache, imgid); if(selected == 1) { outlinecol = 0.4; bgcol = 0.6; fontcol = 0.5; } if(imgsel == imgid) { bgcol = 0.8; // mouse over fontcol = 0.7; outlinecol = 0.6; // if the user points at this image, we really want it: if(!img) img = dt_image_cache_read_get(darktable.image_cache, imgid); } float imgwd = 0.90f; if(zoom == 1) { imgwd = .97f; // cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); } else { double x0 = 1, y0 = 1, rect_width = width-2, rect_height = height-2, radius = 5; double x1, y1, off, off1; x1=x0+rect_width; y1=y0+rect_height; off=radius*0.666; off1 = radius-off; cairo_move_to (cr, x0, y0 + radius); cairo_curve_to (cr, x0, y0+off1, x0+off1 , y0, x0 + radius, y0); cairo_line_to (cr, x1 - radius, y0); cairo_curve_to (cr, x1-off1, y0, x1, y0+off1, x1, y0 + radius); cairo_line_to (cr, x1 , y1 - radius); cairo_curve_to (cr, x1, y1-off1, x1-off1, y1, x1 - radius, y1); cairo_line_to (cr, x0 + radius, y1); cairo_curve_to (cr, x0+off1, y1, x0, y1-off1, x0, y1- radius); cairo_close_path (cr); cairo_set_source_rgb(cr, bgcol, bgcol, bgcol); cairo_fill_preserve(cr); cairo_set_line_width(cr, 0.005*width); cairo_set_source_rgb(cr, outlinecol, outlinecol, outlinecol); cairo_stroke(cr); if(img) { const char *ext = img->filename + strlen(img->filename); while(ext > img->filename && *ext != '.') ext--; ext++; cairo_set_source_rgb(cr, fontcol, fontcol, fontcol); cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, .25*width); cairo_move_to (cr, .01*width, .24*height); cairo_show_text (cr, ext); } } float scale = 1.0; dt_mipmap_buffer_t buf; dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size( darktable.mipmap_cache, imgwd*width, imgwd*height); dt_mipmap_cache_read_get( darktable.mipmap_cache, &buf, imgid, mip, 0); cairo_surface_t *surface = NULL; if(buf.buf) { const int32_t stride = cairo_format_stride_for_width (CAIRO_FORMAT_RGB24, buf.width); surface = cairo_image_surface_create_for_data (buf.buf, CAIRO_FORMAT_RGB24, buf.width, buf.height, stride); if(zoom == 1) { scale = fminf( fminf(darktable.thumbnail_width, width) / (float)buf.width, fminf(darktable.thumbnail_height, height) / (float)buf.height ); } else scale = fminf(width*imgwd/(float)buf.width, height*imgwd/(float)buf.height); } // draw centered and fitted: cairo_save(cr); cairo_translate(cr, width/2.0, height/2.0f); cairo_scale(cr, scale, scale); if(buf.buf) { cairo_translate(cr, -.5f*buf.width, -.5f*buf.height); cairo_set_source_surface (cr, surface, 0, 0); if(buf.width <= 8 && buf.height <= 8) cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); cairo_rectangle(cr, 0, 0, buf.width, buf.height); cairo_fill(cr); cairo_surface_destroy (surface); if(zoom == 1) cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BEST); cairo_rectangle(cr, 0, 0, buf.width, buf.height); } // border around image const float border = zoom == 1 ? 16/scale : 2/scale; cairo_set_source_rgb(cr, bordercol, bordercol, bordercol); if(buf.buf && selected) { cairo_set_line_width(cr, 1./scale); if(zoom == 1) { // draw shadow around border cairo_set_source_rgb(cr, 0.2, 0.2, 0.2); cairo_stroke(cr); // cairo_new_path(cr); cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); float alpha = 1.0f; for(int k=0; k<16; k++) { cairo_rectangle(cr, 0, 0, buf.width, buf.height); cairo_new_sub_path(cr); cairo_rectangle(cr, -k/scale, -k/scale, buf.width+2.*k/scale, buf.height+2.*k/scale); cairo_set_source_rgba(cr, 0, 0, 0, alpha); alpha *= 0.6f; cairo_fill(cr); } } else { cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD); cairo_new_sub_path(cr); cairo_rectangle(cr, -border, -border, buf.width+2.*border, buf.height+2.*border); cairo_stroke_preserve(cr); cairo_set_source_rgb(cr, 1.0-bordercol, 1.0-bordercol, 1.0-bordercol); cairo_fill(cr); } } else if(buf.buf) { cairo_set_line_width(cr, 1); cairo_stroke(cr); } cairo_restore(cr); if(buf.buf) dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf); const float fscale = fminf(width, height); if(imgsel == imgid) { // draw mouseover hover effects, set event hook for mouse button down! *image_over = DT_VIEW_DESERT; cairo_set_line_width(cr, 1.5); cairo_set_source_rgb(cr, outlinecol, outlinecol, outlinecol); cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND); float r1, r2; if(zoom != 1) { r1 = 0.05*width; r2 = 0.022*width; } else { r1 = 0.015*fscale; r2 = 0.007*fscale; } float x, y; if(zoom != 1) y = 0.90*height; else y = .12*fscale; if(img) for(int k=0; k<5; k++) { if(zoom != 1) x = (0.41+k*0.12)*width; else x = (.08+k*0.04)*fscale; if((img->flags & 0x7) != 6) //if rejected: draw no stars { dt_view_star(cr, x, y, r1, r2); if((px - x)*(px - x) + (py - y)*(py - y) < r1*r1) { *image_over = DT_VIEW_STAR_1 + k; cairo_fill(cr); } else if((img->flags & 0x7) > k) { cairo_fill_preserve(cr); cairo_set_source_rgb(cr, 1.0-bordercol, 1.0-bordercol, 1.0-bordercol); cairo_stroke(cr); cairo_set_source_rgb(cr, outlinecol, outlinecol, outlinecol); } else cairo_stroke(cr); } } //Image rejected? if(zoom !=1) x = 0.11*width; else x = .04*fscale; if((px - x)*(px - x) + (py - y)*(py - y) < r1*r1) { *image_over = DT_VIEW_REJECT; //mouse sensitive cairo_new_sub_path(cr); cairo_arc(cr, x, y, (r1+r2)*.5, 0, 2.0f*M_PI); cairo_stroke(cr); } else if (img && ((img->flags & 0x7) == 6)) { cairo_set_source_rgb(cr, 1., 0., 0.); cairo_new_sub_path(cr); cairo_arc(cr, x, y, (r1+r2)*.5, 0, 2.0f*M_PI); cairo_stroke(cr); cairo_set_line_width(cr, 2.5); } //reject cross: cairo_move_to(cr, x-r2, y-r2); cairo_line_to(cr, x+r2, y+r2); cairo_move_to(cr, x+r2, y-r2); cairo_line_to(cr, x-r2, y+r2); cairo_close_path(cr); cairo_stroke(cr); cairo_set_source_rgb(cr, outlinecol, outlinecol, outlinecol); cairo_set_line_width(cr, 1.5); // image altered? if(altered) { // align to right float s = (r1+r2)*.5; if(zoom != 1) { x = width*0.9; y = height*0.1; } else x = (.04+7*0.04)*fscale; dt_view_draw_altered(cr, x, y, s); //g_print("px = %d, x = %.4f, py = %d, y = %.4f\n", px, x, py, y); if(img && abs(px-x) <= 1.2*s && abs(py-y) <= 1.2*s) // mouse hovers over the altered-icon -> history tooltip! { darktable.gui->center_tooltip = 1; } } } // kill all paths, in case img was not loaded yet, or is blocked: cairo_new_path(cr); // TODO: make mouse sensitive, just as stars! // TODO: cache in image struct! { // color labels: const float x = zoom == 1 ? (0.07)*fscale : .21*width; const float y = zoom == 1 ? 0.17*fscale: 0.1*height; const float r = zoom == 1 ? 0.01*fscale : 0.03*width; /* clear and reset prepared statement */ DT_DEBUG_SQLITE3_CLEAR_BINDINGS(darktable.view_manager->statements.get_color); DT_DEBUG_SQLITE3_RESET(darktable.view_manager->statements.get_color); /* setup statement and iterate rows */ DT_DEBUG_SQLITE3_BIND_INT(darktable.view_manager->statements.get_color, 1, imgid); while(sqlite3_step(darktable.view_manager->statements.get_color) == SQLITE_ROW) { cairo_save(cr); int col = sqlite3_column_int(darktable.view_manager->statements.get_color, 0); // see src/dtgtk/paint.c dtgtk_cairo_paint_label(cr, x+(3*r*col)-5*r, y-r, r*2, r*2, col); cairo_restore(cr); } } if(img && (zoom == 1)) { // some exif data cairo_set_source_rgb(cr, .7, .7, .7); cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, .025*fscale); cairo_move_to (cr, .02*fscale, .04*fscale); // cairo_show_text(cr, img->filename); cairo_text_path(cr, img->filename); char exifline[50]; cairo_move_to (cr, .02*fscale, .08*fscale); dt_image_print_exif(img, exifline, 50); cairo_text_path(cr, exifline); cairo_fill_preserve(cr); cairo_set_line_width(cr, 1.0); cairo_set_source_rgb(cr, 0.3, 0.3, 0.3); cairo_stroke(cr); } if(img) dt_image_cache_read_release(darktable.image_cache, img); cairo_restore(cr); // if(zoom == 1) cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT); }
static void dt_ellipse_events_post_expose(cairo_t *cr, float zoom_scale, dt_masks_form_gui_t *gui, int index) { double dashed[] = { 4.0, 4.0 }; dashed[0] /= zoom_scale; dashed[1] /= zoom_scale; int len = sizeof(dashed) / sizeof(dashed[0]); dt_masks_form_gui_points_t *gpt = (dt_masks_form_gui_points_t *)g_list_nth_data(gui->points, index); if(!gpt) return; const float r = atan2(gpt->points[3] - gpt->points[1], gpt->points[2] - gpt->points[0]); const float sinr = sin(r); const float cosr = cos(r); float dx = 0.0f, dy = 0.0f, xref = gpt->points[0], yref = gpt->points[1]; float dxs = 0.0f, dys = 0.0f, xrefs = 0.0f, yrefs = 0.0f; float sinv = 0.0f, cosv = 1.0f; float scalea = 1.0f, scaleb = 1.0f, scaleab = 1.0f, scalebb = 1.0f; if(gpt->source_count > 10) { xrefs = gpt->source[0]; yrefs = gpt->source[1]; } if((gui->group_selected == index) && gui->form_dragging) { dx = gui->posx + gui->dx - xref; dy = gui->posy + gui->dy - yref; } else if((gui->group_selected == index) && gui->source_dragging) { xrefs = gpt->source[0], yrefs = gpt->source[1]; dxs = gui->posx + gui->dx - xrefs; dys = gui->posy + gui->dy - yrefs; } else if((gui->group_selected == index) && gui->form_rotating) { const float v = atan2(gui->posy - yref, gui->posx - xref) - atan2(-gui->dy, -gui->dx); sinv = sin(v); cosv = cos(v); } else if((gui->group_selected == index) && (gui->point_dragging >= 1)) { const int k = gui->point_dragging; const float rx = gpt->points[k * 2] - xref; const float ry = gpt->points[k * 2 + 1] - yref; const float bx = gpt->border[k * 2] - xref; const float by = gpt->border[k * 2 + 1] - yref; const float deltax = gui->posx + gui->dx - xref; const float deltay = gui->posy + gui->dy - yref; const float r = sqrtf(rx * rx + ry * ry); const float b = sqrtf(bx * bx + by * by); float d = (rx * deltax + ry * deltay) / r; if(r + d < 0) d = -r; if(k == 1 || k == 2) { scalea = r > 0 ? (r + d) / r : 0; scaleab = b > 0 ? (b + d) / b : 0; } else { scaleb = r > 0 ? (r + d) / r : 0; scalebb = b > 0 ? (b + d) / b : 0; } } float x, y; // draw shape if(gpt->points_count > 10) { cairo_set_dash(cr, dashed, 0, 0); if((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 5.0 / zoom_scale); else cairo_set_line_width(cr, 3.0 / zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); _ellipse_point_transform(xref, yref, gpt->points[10] + dx, gpt->points[11] + dy, sinr, cosr, scalea, scaleb, sinv, cosv, &x, &y); cairo_move_to(cr, x, y); for(int i = 6; i < gpt->points_count; i++) { _ellipse_point_transform(xref, yref, gpt->points[i * 2] + dx, gpt->points[i * 2 + 1] + dy, sinr, cosr, scalea, scaleb, sinv, cosv, &x, &y); cairo_line_to(cr, x, y); } _ellipse_point_transform(xref, yref, gpt->points[10] + dx, gpt->points[11] + dy, sinr, cosr, scalea, scaleb, sinv, cosv, &x, &y); cairo_line_to(cr, x, y); cairo_stroke_preserve(cr); if((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 2.0 / zoom_scale); else cairo_set_line_width(cr, 1.0 / zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_stroke(cr); } // draw anchor points if(TRUE) { cairo_set_dash(cr, dashed, 0, 0); float anchor_size; // = (gui->form_dragging || gui->form_selected) ? 7.0f / zoom_scale : 5.0f / // zoom_scale; for(int i = 1; i < 5; i++) { cairo_set_source_rgba(cr, .8, .8, .8, .8); if(i == gui->point_dragging || i == gui->point_selected) anchor_size = 7.0f / zoom_scale; else anchor_size = 5.0f / zoom_scale; _ellipse_point_transform(xref, yref, gpt->points[i * 2] + dx, gpt->points[i * 2 + 1] + dy, sinr, cosr, scalea, scaleb, sinv, cosv, &x, &y); cairo_rectangle(cr, x - (anchor_size * 0.5), y - (anchor_size * 0.5), anchor_size, anchor_size); cairo_fill_preserve(cr); if((gui->group_selected == index) && (i == gui->point_dragging || i == gui->point_selected)) cairo_set_line_width(cr, 2.0 / zoom_scale); if((gui->group_selected == index) && (gui->form_dragging || gui->form_selected)) cairo_set_line_width(cr, 2.0 / zoom_scale); else cairo_set_line_width(cr, 1.0 / zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_stroke(cr); } } // draw border if((gui->group_selected == index) && gpt->border_count > 10) { cairo_set_dash(cr, dashed, len, 0); if((gui->group_selected == index) && (gui->border_selected)) cairo_set_line_width(cr, 2.0 / zoom_scale); else cairo_set_line_width(cr, 1.0 / zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); _ellipse_point_transform(xref, yref, gpt->border[10] + dx, gpt->border[11] + dy, sinr, cosr, scaleab, scalebb, sinv, cosv, &x, &y); cairo_move_to(cr, x, y); for(int i = 6; i < gpt->border_count; i++) { _ellipse_point_transform(xref, yref, gpt->border[i * 2] + dx, gpt->border[i * 2 + 1] + dy, sinr, cosr, scaleab, scalebb, sinv, cosv, &x, &y); cairo_line_to(cr, x, y); } _ellipse_point_transform(xref, yref, gpt->border[10] + dx, gpt->border[11] + dy, sinr, cosr, scaleab, scalebb, sinv, cosv, &x, &y); cairo_line_to(cr, x, y); cairo_stroke_preserve(cr); if((gui->group_selected == index) && (gui->border_selected)) cairo_set_line_width(cr, 2.0 / zoom_scale); else cairo_set_line_width(cr, 1.0 / zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_set_dash(cr, dashed, len, 4); cairo_stroke(cr); } // draw the source if any if(gpt->source_count > 10) { // compute the dest inner ellipse intersection with the line from source center to dest center. float cdx = gpt->source[0] + dxs - gpt->points[0] - dx; float cdy = gpt->source[1] + dys - gpt->points[1] - dy; // we don't draw the line if source==point if(cdx != 0.0 && cdy != 0.0) { cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); float cangle = atan(cdx / cdy); if(cdy > 0) cangle = (M_PI / 2) - cangle; else cangle = -(M_PI / 2) - cangle; float arrowx = gpt->points[0] + dx; float arrowy = gpt->points[1] + dy; cairo_move_to(cr, gpt->source[0] + dxs, gpt->source[1] + dys); // source center cairo_line_to(cr, arrowx, arrowy); // dest border // then draw to line for the arrow itself const float arrow_scale = 8.0; cairo_move_to(cr, arrowx + arrow_scale * cos(cangle + (0.4)), arrowy + arrow_scale * sin(cangle + (0.4))); cairo_line_to(cr, arrowx, arrowy); cairo_line_to(cr, arrowx + arrow_scale * cos(cangle - (0.4)), arrowy + arrow_scale * sin(cangle - (0.4))); cairo_set_dash(cr, dashed, 0, 0); if((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 2.5 / zoom_scale); else cairo_set_line_width(cr, 1.5 / zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_stroke_preserve(cr); if((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 1.0 / zoom_scale); else cairo_set_line_width(cr, 0.5 / zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_stroke(cr); } // we draw the source cairo_set_dash(cr, dashed, 0, 0); if((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 2.5 / zoom_scale); else cairo_set_line_width(cr, 1.5 / zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); _ellipse_point_transform(xrefs, yrefs, gpt->source[10] + dxs, gpt->source[11] + dys, sinr, cosr, scalea, scaleb, sinv, cosv, &x, &y); cairo_move_to(cr, x, y); for(int i = 6; i < gpt->source_count; i++) { _ellipse_point_transform(xrefs, yrefs, gpt->source[i * 2] + dxs, gpt->source[i * 2 + 1] + dys, sinr, cosr, scalea, scaleb, sinv, cosv, &x, &y); cairo_line_to(cr, x, y); } _ellipse_point_transform(xrefs, yrefs, gpt->source[10] + dxs, gpt->source[11] + dys, sinr, cosr, scalea, scaleb, sinv, cosv, &x, &y); cairo_line_to(cr, x, y); cairo_stroke_preserve(cr); if((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 1.0 / zoom_scale); else cairo_set_line_width(cr, 0.5 / zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_stroke(cr); } }
static int cr_stroke_preserve (lua_State *L) { cairo_t **obj = luaL_checkudata(L, 1, OOCAIRO_MT_NAME_CONTEXT); cairo_stroke_preserve(*obj); return 0; }
static void gimp_cell_renderer_color_render (GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags) { GimpCellRendererColor *color = GIMP_CELL_RENDERER_COLOR (cell); GdkRectangle rect; gimp_cell_renderer_color_get_size (cell, widget, cell_area, &rect.x, &rect.y, &rect.width, &rect.height); rect.x += cell_area->x + cell->xpad; rect.y += cell_area->y + cell->ypad; rect.width -= 2 * cell->xpad; rect.height -= 2 * cell->ypad; if (rect.width > 2 && rect.height > 2) { cairo_t *cr = gdk_cairo_create (window); GtkStyle *style = gtk_widget_get_style (widget); GtkStateType state; cairo_rectangle (cr, rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 2); gimp_cairo_set_source_rgb (cr, &color->color); cairo_fill (cr); if (! color->opaque && color->color.a < 1.0) { cairo_pattern_t *pattern; cairo_move_to (cr, rect.x + 1, rect.y + rect.height - 1); cairo_line_to (cr, rect.x + rect.width - 1, rect.y + rect.height - 1); cairo_line_to (cr, rect.x + rect.width - 1, rect.y + 1); cairo_close_path (cr); pattern = gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM, NULL, NULL); cairo_set_source (cr, pattern); cairo_pattern_destroy (pattern); cairo_fill_preserve (cr); gimp_cairo_set_source_rgba (cr, &color->color); cairo_fill (cr); } /* draw border */ cairo_rectangle (cr, rect.x + 0.5, rect.y + 0.5, rect.width - 1, rect.height - 1); if (! cell->sensitive || GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE) { state = GTK_STATE_INSENSITIVE; } else { state = (flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED : GTK_STATE_NORMAL); } cairo_set_line_width (cr, 1); gdk_cairo_set_source_color (cr, &style->fg[state]); cairo_stroke_preserve (cr); if (state == GTK_STATE_SELECTED && gimp_cairo_set_focus_line_pattern (cr, widget)) { gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_NORMAL]); cairo_stroke (cr); } cairo_destroy (cr); } }
void gimp_display_shell_render (GimpDisplayShell *shell, cairo_t *cr, gint x, gint y, gint w, gint h) { GimpImage *image; GimpProjection *projection; GeglBuffer *buffer; gdouble scale_x = 1.0; gdouble scale_y = 1.0; gdouble buffer_scale = 1.0; gint viewport_offset_x; gint viewport_offset_y; gint viewport_width; gint viewport_height; gint scaled_x; gint scaled_y; gint scaled_width; gint scaled_height; cairo_surface_t *xfer; gint xfer_src_x; gint xfer_src_y; gint mask_src_x = 0; gint mask_src_y = 0; gint stride; guchar *data; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (cr != NULL); g_return_if_fail (w > 0 && h > 0); image = gimp_display_get_image (shell->display); projection = gimp_image_get_projection (image); buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (projection)); #ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING /* if we had this future API, things would look pretty on hires (retina) */ scale_x = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell)))); #endif scale_x = MIN (scale_x, GIMP_DISPLAY_RENDER_MAX_SCALE); scale_y = scale_x; if (shell->scale_x > shell->scale_y) { scale_y *= (shell->scale_x / shell->scale_y); buffer_scale = shell->scale_y * scale_y; } else if (shell->scale_y > shell->scale_x) { scale_x *= (shell->scale_y / shell->scale_x); buffer_scale = shell->scale_x * scale_x; } else { buffer_scale = shell->scale_x * scale_x; } gimp_display_shell_scroll_get_scaled_viewport (shell, &viewport_offset_x, &viewport_offset_y, &viewport_width, &viewport_height); scaled_x = floor ((x + viewport_offset_x) * scale_x); scaled_y = floor ((y + viewport_offset_y) * scale_y); scaled_width = ceil (w * scale_x); scaled_height = ceil (h * scale_y); if (shell->rotate_transform) { xfer = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_ARGB32, scaled_width, scaled_height); cairo_surface_mark_dirty (xfer); xfer_src_x = 0; xfer_src_y = 0; } else { xfer = gimp_display_xfer_get_surface (shell->xfer, scaled_width, scaled_height, &xfer_src_x, &xfer_src_y); } stride = cairo_image_surface_get_stride (xfer); data = cairo_image_surface_get_data (xfer); data += xfer_src_y * stride + xfer_src_x * 4; /* apply filters to the rendered projection */ if (shell->filter_stack) { const Babl *filter_format = babl_format ("R'G'B'A float"); if (! shell->filter_buffer) { gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE; gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE; shell->filter_data = gegl_malloc (w * h * babl_format_get_bytes_per_pixel (filter_format)); shell->filter_stride = w * babl_format_get_bytes_per_pixel (filter_format); shell->filter_buffer = gegl_buffer_linear_new_from_data (shell->filter_data, filter_format, GEGL_RECTANGLE (0, 0, w, h), GEGL_AUTO_ROWSTRIDE, (GDestroyNotify) gegl_free, shell->filter_data); } gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, filter_format, shell->filter_data, shell->filter_stride, GEGL_ABYSS_CLAMP); gimp_color_display_stack_convert_buffer (shell->filter_stack, shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); gegl_buffer_get (shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), 1.0, babl_format ("cairo-ARGB32"), data, stride, GEGL_ABYSS_CLAMP); } else { gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, babl_format ("cairo-ARGB32"), data, stride, GEGL_ABYSS_CLAMP); } if (shell->mask) { gint mask_height; if (! shell->mask_surface) { shell->mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE, GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE); } cairo_surface_mark_dirty (shell->mask_surface); stride = cairo_image_surface_get_stride (shell->mask_surface); data = cairo_image_surface_get_data (shell->mask_surface); data += mask_src_y * stride + mask_src_x * 4; gegl_buffer_get (shell->mask, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, babl_format ("Y u8"), data, stride, GEGL_ABYSS_CLAMP); /* invert the mask so what is *not* the foreground object is masked */ mask_height = scaled_height; while (mask_height--) { gint mask_width = scaled_width; guchar *d = data; while (mask_width--) { guchar inv = 255 - *d; *d++ = inv; } data += stride; } } /* put it to the screen */ cairo_save (cr); cairo_rectangle (cr, x, y, w, h); cairo_scale (cr, 1.0 / scale_x, 1.0 / scale_y); cairo_set_source_surface (cr, xfer, x * scale_x - xfer_src_x, y * scale_y - xfer_src_y); if (shell->rotate_transform) { cairo_pattern_t *pattern; pattern = cairo_get_source (cr); cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_set_line_width (cr, 1.0); cairo_stroke_preserve (cr); cairo_surface_destroy (xfer); } cairo_clip (cr); cairo_paint (cr); if (shell->mask) { gimp_cairo_set_source_rgba (cr, &shell->mask_color); cairo_mask_surface (cr, shell->mask_surface, (x - mask_src_x) * scale_x, (y - mask_src_y) * scale_y); } cairo_restore (cr); }
static void dt_circle_events_post_expose(cairo_t *cr,float zoom_scale,dt_masks_form_gui_t *gui,int index) { double dashed[] = {4.0, 4.0}; dashed[0] /= zoom_scale; dashed[1] /= zoom_scale; int len = sizeof(dashed) / sizeof(dashed[0]); dt_masks_form_gui_points_t *gpt = (dt_masks_form_gui_points_t *) g_list_nth_data(gui->points,index); if (!gpt) return; float dx=0, dy=0, dxs=0, dys=0; if ((gui->group_selected == index) && gui->form_dragging) { dx = gui->posx + gui->dx - gpt->points[0]; dy = gui->posy + gui->dy - gpt->points[1]; } if ((gui->group_selected == index) && gui->source_dragging) { dxs = gui->posx + gui->dx - gpt->source[0]; dys = gui->posy + gui->dy - gpt->source[1]; } if (gpt->points_count > 6) { cairo_set_dash(cr, dashed, 0, 0); if ((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 5.0/zoom_scale); else cairo_set_line_width(cr, 3.0/zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_move_to(cr,gpt->points[2]+dx,gpt->points[3]+dy); for (int i=2; i<gpt->points_count; i++) { cairo_line_to(cr,gpt->points[i*2]+dx,gpt->points[i*2+1]+dy); } cairo_line_to(cr,gpt->points[2]+dx,gpt->points[3]+dy); cairo_stroke_preserve(cr); if ((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 2.0/zoom_scale); else cairo_set_line_width(cr, 1.0/zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_stroke(cr); } //draw border if ((gui->group_selected == index) && gpt->border_count > 6) { cairo_set_dash(cr, dashed, len, 0); if ((gui->group_selected == index) && (gui->border_selected)) cairo_set_line_width(cr, 2.0/zoom_scale); else cairo_set_line_width(cr, 1.0/zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_move_to(cr,gpt->border[2]+dx,gpt->border[3]+dy); for (int i=2; i<gpt->border_count; i++) { cairo_line_to(cr,gpt->border[i*2]+dx,gpt->border[i*2+1]+dy); } cairo_line_to(cr,gpt->border[2]+dx,gpt->border[3]+dy); cairo_stroke_preserve(cr); if ((gui->group_selected == index) && (gui->border_selected)) cairo_set_line_width(cr, 2.0/zoom_scale); else cairo_set_line_width(cr, 1.0/zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_set_dash(cr, dashed, len, 4); cairo_stroke(cr); } //draw the source if any if (gpt->source_count>6) { const float radius = fabs(gpt->points[3] - gpt->points[1]); // compute the dest inner circle intersection with the line from source center to dest center. float cdx = gpt->source[0] + dxs - gpt->points[0] - dx; float cdy = gpt->source[1] + dys - gpt->points[1] - dy; //we don't draw the line if source==point if (cdx != 0.0 && cdy != 0.0) { cairo_set_line_cap(cr,CAIRO_LINE_CAP_ROUND); float cangle = atan(cdx / cdy); if (cdy>0) cangle = (M_PI/2) - cangle; else cangle = -(M_PI/2) - cangle; // (arrowx,arrowy) is the point of intersection, we move it (factor 1.11) a bit farther than the // inner circle to avoid superposition. float arrowx = gpt->points[0] + 1.11 * radius * cos (cangle) + dx; float arrowy = gpt->points[1] + 1.11 * radius * sin (cangle) + dy; cairo_move_to(cr,gpt->source[0]+dxs,gpt->source[1]+dys); // source center cairo_line_to(cr,arrowx,arrowy); // dest border // then draw to line for the arrow itself const float arrow_scale = 8.0; cairo_move_to(cr,arrowx + arrow_scale * cos (cangle+(0.4)), arrowy + arrow_scale * sin (cangle+(0.4))); cairo_line_to(cr,arrowx,arrowy); cairo_line_to(cr,arrowx + arrow_scale * cos (cangle-(0.4)), arrowy + arrow_scale * sin (cangle-(0.4))); cairo_set_dash(cr, dashed, 0, 0); if ((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 2.5/zoom_scale); else cairo_set_line_width(cr, 1.5/zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_stroke_preserve(cr); if ((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 1.0/zoom_scale); else cairo_set_line_width(cr, 0.5/zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_stroke(cr); } //we draw the source cairo_set_dash(cr, dashed, 0, 0); if ((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 2.5/zoom_scale); else cairo_set_line_width(cr, 1.5/zoom_scale); cairo_set_source_rgba(cr, .3, .3, .3, .8); cairo_move_to(cr,gpt->source[2]+dxs,gpt->source[3]+dys); for (int i=2; i<gpt->source_count; i++) { cairo_line_to(cr,gpt->source[i*2]+dxs,gpt->source[i*2+1]+dys); } cairo_line_to(cr,gpt->source[2]+dxs,gpt->source[3]+dys); cairo_stroke_preserve(cr); if ((gui->group_selected == index) && (gui->form_selected || gui->form_dragging)) cairo_set_line_width(cr, 1.0/zoom_scale); else cairo_set_line_width(cr, 0.5/zoom_scale); cairo_set_source_rgba(cr, .8, .8, .8, .8); cairo_stroke(cr); } }
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int /* offset */, const Color& color) { if (paintingDisabled()) return; unsigned rectCount = rects.size(); cairo_t* cr = platformContext()->cr(); cairo_save(cr); cairo_push_group(cr); cairo_new_path(cr); #if PLATFORM(GTK) #ifdef GTK_API_VERSION_2 GdkRegion* reg = gdk_region_new(); #else cairo_region_t* reg = cairo_region_create(); #endif for (unsigned i = 0; i < rectCount; i++) { #ifdef GTK_API_VERSION_2 GdkRectangle rect = rects[i]; gdk_region_union_with_rect(reg, &rect); #else cairo_rectangle_int_t rect = rects[i]; cairo_region_union_rectangle(reg, &rect); #endif } gdk_cairo_region(cr, reg); #ifdef GTK_API_VERSION_2 gdk_region_destroy(reg); #else cairo_region_destroy(reg); #endif #else int radius = (width - 1) / 2; Path path; for (unsigned i = 0; i < rectCount; ++i) { if (i > 0) path.clear(); path.addRoundedRect(rects[i], FloatSize(radius, radius)); appendWebCorePathToCairoContext(cr, path); } #endif Color ringColor = color; adjustFocusRingColor(ringColor); adjustFocusRingLineWidth(width); setSourceRGBAFromColor(cr, ringColor); cairo_set_line_width(cr, width); setPlatformStrokeStyle(focusRingStrokeStyle()); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_stroke_preserve(cr); cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); cairo_fill(cr); cairo_pop_group_to_source(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); cairo_paint(cr); cairo_restore(cr); }
static gboolean on_expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { //ifff a====0 cairo_t *cr; cr = gdk_cairo_create(widget->window); if(a==0) { cairo_set_source_rgb(cr, 0, 0, 0); cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, 40.0); cairo_move_to(cr, 70, 100); cairo_show_text(cr, buf); } //iffff a===1 if(a==1) { int i; cairo_set_source_rgb(cr, 0 , 0 , 0 ); cairo_set_line_width(cr, 6 ); cairo_arc(cr, 150, 100, 75, 0, 2 * M_PI); cairo_stroke_preserve(cr); /*cairo_set_source_rgb(cr, 0.3, 0.4, 0.6); cairo_fill(cr); */ for(i=0;i<12;i++) { cairo_set_source_rgb(cr, 0, 0, 0); cairo_set_line_width(cr, 4 ); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_move_to(cr,150 + 66.5 * cos(i * M_PI / 6),100 + 66.5 * sin(i * M_PI / 6 )); cairo_line_to(cr,150 + 75 * cos(i * M_PI / 6),100 + 75 * sin(i * M_PI / 6 )); cairo_stroke(cr); } for(i=0;i<12;i+=3) { cairo_set_source_rgb(cr, 0, 0, 0); cairo_set_line_width(cr, 7 ); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_move_to(cr,150 + 65.5 * cos(i * M_PI / 6),100 + 65.5 * sin(i * M_PI / 6 )); cairo_line_to(cr,150 + 75 * cos(i * M_PI / 6),100 + 75 * sin(i * M_PI / 6 )); cairo_stroke(cr); } minutes = minutes * M_PI / 30; hours = hours * M_PI / 6; seconds=seconds * M_PI / 30; cairo_set_source_rgb(cr,0.3,0.6,0.2); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_width(cr, 8 ); cairo_move_to(cr,150 ,100); cairo_line_to(cr,150 + 30 * sin(hours + minutes / 12.0),100 + 40 * -1*cos(hours + minutes / 12.0)); cairo_stroke(cr); cairo_set_source_rgb(cr, 0.3, 0.4, 0.6); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_width(cr, 6 ); cairo_move_to(cr,150 ,100); cairo_line_to(cr,150 + 60 * sin(minutes + seconds / 60),100 + 60 * -1*cos(minutes + seconds / 60)); cairo_stroke(cr); cairo_set_source_rgb(cr, 0.6, 0.6, 0.6); cairo_set_line_width(cr, 2.5 ); cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); cairo_move_to(cr,150 ,100); cairo_line_to(cr,150 + 70 * sin(seconds),100 + 60*-1 * cos(seconds)); cairo_stroke(cr); cairo_set_source_rgb(cr, 0 , 0 , 0 ); cairo_set_line_width(cr, 2 ); cairo_arc(cr, 150, 100, 1.5, 0, 2 * M_PI); cairo_stroke_preserve(cr); } if (a==2) { cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 50, 120); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(hour_arr[2]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(hour_arr[2]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, 35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(hour_arr[3]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(hour_arr[3]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 35, 0); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(hour_brr[3]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(hour_brr[3]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(hour_brr[2]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(hour_brr[2]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(hour_brr[1]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(hour_brr[1]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(hour_brr[0]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(hour_brr[0]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 50, 35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(min_arr[1]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(min_arr[1]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, 35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(min_arr[2]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(min_arr[2]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, 35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(min_arr[3]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(min_arr[3]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 35,0 ); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(min_brr[3]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(min_brr[3]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(min_brr[2]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(min_brr[2]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(min_brr[1]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(min_brr[1]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(min_brr[0]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(min_brr[0]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 50, 35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(sec_arr[1]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(sec_arr[1]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, 35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(sec_arr[2]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(sec_arr[2]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, 35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(sec_arr[3]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(sec_arr[3]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 35,0 ); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(sec_brr[3]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(sec_brr[3]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(sec_brr[2]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(sec_brr[2]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(sec_brr[1]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(sec_brr[1]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); cairo_set_line_width(cr, 4); cairo_set_source_rgb(cr, 0.69, 0.19, 0); cairo_translate(cr, 0, -35); cairo_arc(cr, 0, 0, 10, 0, 2 * M_PI); cairo_stroke_preserve(cr); if(sec_brr[0]==0) cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); else if(sec_brr[0]==1) cairo_set_source_rgb(cr, 0, 0, 0); cairo_fill(cr); } }
static gboolean _lib_histogram_expose_callback(GtkWidget *widget, GdkEventExpose *event, 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; float *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; int width = widget->allocation.width, height = widget->allocation.height; cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); GtkStyle *style=gtk_rc_get_style_by_paths(gtk_settings_get_default(), NULL,"GtkWidget", GTK_TYPE_WIDGET); if(!style) style = gtk_rc_get_style(widget); cairo_set_source_rgb(cr, style->bg[0].red/65535.0, style->bg[0].green/65535.0, style->bg[0].blue/65535.0); cairo_paint(cr); 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) { 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); } if(d->green) { cairo_set_source_rgba(cr, 0., 1., 0., 0.2); dt_draw_histogram_8(cr, hist, 1, dev->histogram_type); } if(d->blue) { cairo_set_source_rgba(cr, 0., 0., 1., 0.2); dt_draw_histogram_8(cr, hist, 2, dev->histogram_type); } 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_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, .1*height); char exifline[50]; cairo_move_to (cr, .02*width, .98*height); dt_image_print_exif(&dev->image_storage, exifline, 50); cairo_save(cr); // cairo_show_text(cr, exifline); cairo_set_line_width(cr, 2.0); cairo_set_source_rgba(cr, 1, 1, 1, 0.3); cairo_text_path(cr, exifline); 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_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_surface (cr_pixmap, cst, 0, 0); cairo_paint(cr_pixmap); cairo_destroy(cr_pixmap); cairo_surface_destroy(cst); return TRUE; }
static GdkPixbuf * create_gallery (ThumbApp *app) { GdkPixbuf *screenshot, *pixbuf = NULL; cairo_t *cr; cairo_surface_t *surface; PangoLayout *layout; PangoFontDescription *font_desc; gint64 stream_length, screenshot_interval, pos; guint columns = 3, rows, current_column, current_row, x, y; gint screenshot_width = 0, screenshot_height = 0, x_padding = 0, y_padding = 0; gfloat scale = 1.0; gchar *header_text, *duration_text, *filename; /* Calculate how many screenshots we're going to take */ stream_length = app->duration; /* As a default, we have one screenshot per minute of stream, * but adjusted so we don't have any gaps in the resulting gallery. */ if (gallery == 0) { gallery = stream_length / 60000; while (gallery % 3 != 0 && gallery % 4 != 0 && gallery % 5 != 0) { gallery++; } } if (gallery < GALLERY_MIN) gallery = GALLERY_MIN; if (gallery > GALLERY_MAX) gallery = GALLERY_MAX; screenshot_interval = stream_length / gallery; /* Put a lower bound on the screenshot interval so we can't enter an infinite loop below */ if (screenshot_interval == 0) screenshot_interval = 1; PROGRESS_DEBUG ("Producing gallery of %u screenshots, taken at %" G_GINT64_FORMAT " millisecond intervals throughout a %" G_GINT64_FORMAT " millisecond-long stream.", gallery, screenshot_interval, stream_length); /* Calculate how to arrange the screenshots so we don't get ones orphaned on the last row. * At this point, only deal with arrangements of 3, 4 or 5 columns. */ y = G_MAXUINT; for (x = 3; x <= 5; x++) { if (gallery % x == 0 || x - gallery % x < y) { y = x - gallery % x; columns = x; /* Have we found an optimal solution already? */ if (y == x) break; } } rows = ceil ((gfloat) gallery / (gfloat) columns); PROGRESS_DEBUG ("Outputting as %u rows and %u columns.", rows, columns); /* Take the screenshots and composite them into a pixbuf */ current_column = current_row = x = y = 0; for (pos = screenshot_interval; pos <= stream_length; pos += screenshot_interval) { if (pos == stream_length) screenshot = capture_frame_at_time (app, pos - 1); else screenshot = capture_frame_at_time (app, pos); if (pixbuf == NULL) { screenshot_width = gdk_pixbuf_get_width (screenshot); screenshot_height = gdk_pixbuf_get_height (screenshot); /* Calculate a scaling factor so that screenshot_width -> output_size */ scale = (float) output_size / (float) screenshot_width; x_padding = x = MAX (output_size * 0.05, 1); y_padding = y = MAX (scale * screenshot_height * 0.05, 1); PROGRESS_DEBUG ("Scaling each screenshot by %f.", scale); /* Create our massive pixbuf */ pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, columns * output_size + (columns + 1) * x_padding, (guint) (rows * scale * screenshot_height + (rows + 1) * y_padding)); gdk_pixbuf_fill (pixbuf, 0x000000ff); PROGRESS_DEBUG ("Created output pixbuf (%ux%u).", gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); } /* Composite the screenshot into our gallery */ gdk_pixbuf_composite (screenshot, pixbuf, x, y, output_size, scale * screenshot_height, (gdouble) x, (gdouble) y, scale, scale, GDK_INTERP_BILINEAR, 255); g_object_unref (screenshot); PROGRESS_DEBUG ("Composited screenshot from %" G_GINT64_FORMAT " milliseconds (address %u) at (%u,%u).", pos, GPOINTER_TO_UINT (screenshot), x, y); /* We print progress in the range 10% (MIN_PROGRESS) to 50% (MAX_PROGRESS - MIN_PROGRESS) / 2.0 */ PRINT_PROGRESS (MIN_PROGRESS + (current_row * columns + current_column) * (((MAX_PROGRESS - MIN_PROGRESS) / gallery) / 2.0)); current_column = (current_column + 1) % columns; x += output_size + x_padding; if (current_column == 0) { x = x_padding; y += scale * screenshot_height + y_padding; current_row++; } } PROGRESS_DEBUG ("Converting pixbuf to a Cairo surface."); /* Load the pixbuf into a Cairo surface and overlay the text. The height is the height of * the gallery plus the necessary height for 3 lines of header (at ~18px each), plus some * extra padding. */ surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf) + GALLERY_HEADER_HEIGHT + y_padding); cr = cairo_create (surface); cairo_surface_destroy (surface); /* First, copy across the gallery pixbuf */ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0.0, GALLERY_HEADER_HEIGHT + y_padding); cairo_rectangle (cr, 0.0, GALLERY_HEADER_HEIGHT + y_padding, gdk_pixbuf_get_width (pixbuf), gdk_pixbuf_get_height (pixbuf)); cairo_fill (cr); g_object_unref (pixbuf); /* Build the header information */ duration_text = xplayer_time_to_string (stream_length); filename = NULL; if (strstr (app->input, "://")) { char *local; local = g_filename_from_uri (app->input, NULL, NULL); filename = g_path_get_basename (local); g_free (local); } if (filename == NULL) filename = g_path_get_basename (app->input); /* Translators: The first string is "Filename" (as translated); the second is an actual filename. The third string is "Resolution" (as translated); the fourth and fifth are screenshot height and width, respectively. The sixth string is "Duration" (as translated); the seventh is the movie duration in words. */ header_text = g_markup_printf_escaped (_("<b>%s</b>: %s\n<b>%s</b>: %d\303\227%d\n<b>%s</b>: %s"), _("Filename"), filename, _("Resolution"), screenshot_width, screenshot_height, _("Duration"), duration_text); g_free (duration_text); g_free (filename); PROGRESS_DEBUG ("Writing header text with Pango."); /* Write out some header information */ layout = pango_cairo_create_layout (cr); font_desc = pango_font_description_from_string ("Sans 18px"); pango_layout_set_font_description (layout, font_desc); pango_font_description_free (font_desc); pango_layout_set_markup (layout, header_text, -1); g_free (header_text); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ cairo_move_to (cr, (gdouble) x_padding, (gdouble) y_padding); pango_cairo_show_layout (cr, layout); /* Go through each screenshot and write its timestamp */ current_column = current_row = 0; x = x_padding + output_size; y = y_padding * 2 + GALLERY_HEADER_HEIGHT + scale * screenshot_height; font_desc = pango_font_description_from_string ("Sans 10px"); pango_layout_set_font_description (layout, font_desc); pango_font_description_free (font_desc); PROGRESS_DEBUG ("Writing screenshot timestamps with Pango."); for (pos = screenshot_interval; pos <= stream_length; pos += screenshot_interval) { gchar *timestamp_text; gint layout_width, layout_height; timestamp_text = xplayer_time_to_string (pos); pango_layout_set_text (layout, timestamp_text, -1); pango_layout_get_pixel_size (layout, &layout_width, &layout_height); /* Display the timestamp in the bottom-right corner of the current screenshot */ cairo_move_to (cr, x - layout_width - 0.02 * output_size, y - layout_height - 0.02 * scale * screenshot_height); /* We have to stroke the text so it's visible against screenshots of the same * foreground color. */ pango_cairo_layout_path (cr, layout); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */ cairo_stroke_preserve (cr); cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */ cairo_fill (cr); PROGRESS_DEBUG ("Writing timestamp \"%s\" at (%f,%f).", timestamp_text, x - layout_width - 0.02 * output_size, y - layout_height - 0.02 * scale * screenshot_height); /* We print progress in the range 50% (MAX_PROGRESS - MIN_PROGRESS) / 2.0) to 90% (MAX_PROGRESS) */ PRINT_PROGRESS (MIN_PROGRESS + (MAX_PROGRESS - MIN_PROGRESS) / 2.0 + (current_row * columns + current_column) * (((MAX_PROGRESS - MIN_PROGRESS) / gallery) / 2.0)); g_free (timestamp_text); current_column = (current_column + 1) % columns; x += output_size + x_padding; if (current_column == 0) { x = x_padding + output_size; y += scale * screenshot_height + y_padding; current_row++; } } g_object_unref (layout); PROGRESS_DEBUG ("Converting Cairo surface back to pixbuf."); /* Create a new pixbuf from the Cairo context */ pixbuf = cairo_surface_to_pixbuf (cairo_get_target (cr)); cairo_destroy (cr); return pixbuf; }
void Context::strokePreserve() { cairo_stroke_preserve( mCairo ); }
void draw_single_road(struct ScreenContext *screenContext, cairo_t *cr, struct Road *aRoad, struct RGBO *fillColor) { struct Item *p; struct Point point, mp; double width, wRoad; struct Color lineColor; double dist, d, angle; width = aRoad->width/screenContext->meterperpixel; if(width < 1) wRoad =1; else wRoad = width; /* draw a road */ lineColor.red = 179.0/255; lineColor.green = 166.0/255; lineColor.blue = 147.0/255; // for test, draw origpoints if (screenContext->debug) { p = aRoad->origPoints.head; gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_move_to(cr, point.x-screenContext->scr_x, point.y-screenContext->scr_y); p = p->next; while(p!=NULL) { gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_line_to(cr, point.x-screenContext->scr_x, point.y-screenContext->scr_y); p = p->next; } cairo_set_line_width(cr, wRoad+1); cairo_set_source_rgb(cr, lineColor.red, lineColor.green, lineColor.blue); cairo_stroke_preserve(cr); cairo_set_line_width(cr, wRoad); cairo_set_source_rgba(cr, fillColor->red/255.0, fillColor->green/255.0, fillColor->blue/255.0, fillColor->opacity/255.0); cairo_stroke(cr); p = aRoad->origPoints.head; gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_arc(cr, (int)point.x-screenContext->scr_x, (int)point.y-screenContext->scr_y, 2, 0, 2*M_PI) ; cairo_set_source_rgb(cr, 0.2, 0.2, 0.8); cairo_fill(cr); p = p->next; while(p!=NULL) { gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_arc(cr, (int)point.x-screenContext->scr_x, (int)point.y-screenContext->scr_y, 2, 0, 2*M_PI) ; cairo_set_source_rgb(cr, 0.2, 0.2, 0.8); cairo_fill(cr); p = p->next; } } // draw points on the road p = aRoad->points.head; gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_move_to(cr, point.x-screenContext->scr_x, point.y-screenContext->scr_y); dist = 0; p = p->next; while(p!=NULL) { gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_line_to(cr, point.x-screenContext->scr_x, point.y-screenContext->scr_y); d = distance_in_meter(((struct Point*)p->prev->datap)->x, ((struct Point*)p->prev->datap)->y, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y); if (dist < aRoad->length/2 && dist + d > aRoad->length/2) { gps_to_canvas(&screenContext->awin, (((struct Point*)p->prev->datap)->x+((struct Point*)p->datap)->x)/2, (((struct Point*)p->prev->datap)->y+((struct Point*)p->datap)->y)/2, &mp.x, &mp.y); angle = angle_between(((struct Point*)p->prev->datap)->x, ((struct Point*)p->prev->datap)->y, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y); } dist += d; p = p->next; } cairo_set_line_width(cr, wRoad+1); cairo_set_source_rgb(cr, lineColor.red, lineColor.green, lineColor.blue); cairo_stroke_preserve(cr); cairo_set_line_width(cr, wRoad); cairo_set_source_rgba(cr, fillColor->red/255.0, fillColor->green/255.0, fillColor->blue/255.0, fillColor->opacity/255.0); cairo_stroke(cr); if (screenContext->debug) { p = aRoad->points.head; gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_arc(cr, (int)point.x-screenContext->scr_x, (int)point.y-screenContext->scr_y, 2, 0, 2*M_PI) ; cairo_set_source_rgb(cr, 0.2, 0.2, 0.8); cairo_fill(cr); p = p->next; while(p!=NULL) { gps_to_canvas(&screenContext->awin, ((struct Point*)p->datap)->x, ((struct Point*)p->datap)->y, &point.x, &point.y); cairo_arc(cr, (int)point.x-screenContext->scr_x, (int)point.y-screenContext->scr_y, 2, 0, 2*M_PI) ; cairo_set_source_rgb(cr, 0.2, 0.2, 0.8); cairo_fill(cr); p = p->next; } } // draw arrow if(screenContext->meterperpixel < 2.5) { cairo_set_line_width(cr, 1); cairo_set_source_rgb(cr, lineColor.red, lineColor.green, lineColor.blue); cairo_move_to(cr, mp.x+cos(M_PI*(90+angle)/180)*MARK_LENGTH/4-screenContext->scr_x, mp.y-sin(M_PI*(90+angle)/180)*MARK_LENGTH/4-screenContext->scr_y); cairo_line_to(cr, mp.x+cos(M_PI*angle/180)*MARK_LENGTH/2-screenContext->scr_x, mp.y-sin(M_PI*angle/180)*MARK_LENGTH/2-screenContext->scr_y); cairo_line_to(cr, mp.x+cos(M_PI*(270+angle)/180)*MARK_LENGTH/4-screenContext->scr_x, mp.y-sin(M_PI*(270+angle)/180)*MARK_LENGTH/4-screenContext->scr_y); cairo_stroke(cr); cairo_move_to(cr, mp.x+cos(M_PI*angle/180)*MARK_LENGTH/2-screenContext->scr_x, mp.y-sin(M_PI*angle/180)*MARK_LENGTH/2-screenContext->scr_y); cairo_line_to(cr, mp.x-cos(M_PI*angle/180)*MARK_LENGTH/2-screenContext->scr_x, mp.y+sin(M_PI*angle/180)*MARK_LENGTH/2-screenContext->scr_y); cairo_stroke(cr); } }
void Circle::draw() const { cairo_scale(cairoHandle_, 1, 0.7); cairo_arc(cairoHandle_, center_.getX(), center_.getY(), radius_, 0, 2*M_PI); cairo_stroke_preserve(cairoHandle_); }
void lime_cairo_stroke_preserve (value handle) { cairo_stroke_preserve ((cairo_t*)val_data (handle)); }
void draw_cells(struct ScreenContext *screenContext, cairo_t *cr) { char buf[128]; double transparent; struct Item *aItem; struct Point p1, p2; double cellsize, fontSize, fsize, fontX, fontY; cairo_text_extents_t extents; struct Color fillColor, lineColor, fontColor; fillColor.red = 175.0/255; fillColor.green = 210.0/255; fillColor.blue = 235.0/255; lineColor.red = 140.0/255; lineColor.green = 145.0/255; lineColor.blue = 135.0/255; fontColor.red = 0/255; fontColor.green = 0/255; fontColor.blue = 0/255; transparent = 0.3; aItem = screenContext->surroundings.head; gps_to_canvas(&screenContext->awin, ((struct Cell*)aItem->datap)->box.xmin, ((struct Cell*)aItem->datap)->box.ymin, &p1.x, &p1.y); gps_to_canvas(&screenContext->awin, ((struct Cell*)aItem->datap)->box.xmax, ((struct Cell*)aItem->datap)->box.ymax, &p2.x, &p2.y); cellsize = p2.x - p1.x; while(aItem!=NULL) { gps_to_canvas(&screenContext->awin, ((struct Cell*)aItem->datap)->box.xmin, ((struct Cell*)aItem->datap)->box.ymin, &p1.x, &p1.y); fontX = p1.x-screenContext->scr_x, fontY = p1.y-screenContext->scr_y; cairo_move_to(cr, p1.x-screenContext->scr_x, p1.y-screenContext->scr_y); gps_to_canvas(&screenContext->awin, ((struct Cell*)aItem->datap)->box.xmin, ((struct Cell*)aItem->datap)->box.ymax, &p1.x, &p1.y); cairo_line_to(cr, p1.x-screenContext->scr_x, p1.y-screenContext->scr_y); gps_to_canvas(&screenContext->awin, ((struct Cell*)aItem->datap)->box.xmax, ((struct Cell*)aItem->datap)->box.ymax, &p1.x, &p1.y); cairo_line_to(cr, p1.x-screenContext->scr_x, p1.y-screenContext->scr_y); gps_to_canvas(&screenContext->awin, ((struct Cell*)aItem->datap)->box.xmax, ((struct Cell*)aItem->datap)->box.ymin, &p1.x, &p1.y); cairo_line_to(cr, p1.x-screenContext->scr_x, p1.y-screenContext->scr_y); cairo_close_path(cr); cairo_set_line_width(cr, 1); cairo_set_source_rgba(cr, lineColor.red, lineColor.green, lineColor.blue, transparent); cairo_stroke_preserve(cr); cairo_set_source_rgba(cr, fillColor.red, fillColor.green, fillColor.blue, transparent); cairo_fill(cr); sprintf(buf, "(%d, %d)", ((struct Cell*)aItem->datap)->xNumber, ((struct Cell*)aItem->datap)->yNumber); if (aItem == screenContext->surroundings.head) { fsize = 2*cellsize/(strlen(buf)+2); if (fsize > 25) fsize = 15; fontSize = fsize; } else fontSize = 0.75*fsize; if(fsize > 5) { fontX = fontX + fontSize*0.5; fontY = fontY + fontSize*0.5; cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, (int)fontSize); cairo_text_extents(cr, buf, &extents); cairo_set_source_rgba(cr, fontColor.red, fontColor.green, fontColor.blue, transparent); cairo_move_to(cr, fontX, fontY-extents.height); cairo_show_text(cr, buf); } aItem=aItem->next; } }
static void render (cairo_t *pCairoContext, CairoDesklet *pDesklet) { CDPanelParameters *pPanel = (CDPanelParameters *) pDesklet->pRendererData; //g_print ("%s(%x)\n", __func__, pPanel); if (pPanel == NULL) return ; double fRadius = pPanel->iRadius; double fLineWidth = pPanel->iLineWidth; double fOffsetX = fRadius + fLineWidth/2; double fOffsetY = fLineWidth/2; double fFrameWidth = pDesklet->container.iWidth - 2 * fRadius - fLineWidth; double fFrameHeight = pDesklet->container.iHeight - fLineWidth; // le cadre. cairo_set_line_width (pCairoContext, pPanel->iLineWidth); cairo_move_to (pCairoContext, fOffsetX, fOffsetY); cairo_rel_curve_to (pCairoContext, fFrameWidth/2, 0, fFrameWidth/2, pPanel->iMainIconSize, fFrameWidth, pPanel->iMainIconSize); //\_________________ Coin haut droit. cairo_rel_curve_to (pCairoContext, 0, 0, fRadius, 0, fRadius, fRadius); cairo_rel_line_to (pCairoContext, 0, fFrameHeight - fRadius * 2 - pPanel->iMainIconSize); //\_________________ Coin bas droit. cairo_rel_curve_to (pCairoContext, 0, 0, 0, fRadius, -fRadius, fRadius); cairo_rel_line_to (pCairoContext, - fFrameWidth, 0); //\_________________ Coin bas gauche. cairo_rel_curve_to (pCairoContext, 0, 0, -fRadius, 0, -fRadius, - fRadius); cairo_rel_line_to (pCairoContext, 0, - (fFrameHeight - fRadius * 2)); //\_________________ Coin haut gauche. cairo_rel_curve_to (pCairoContext, 0, 0, 0, -fRadius, fRadius, -fRadius); cairo_set_source_rgba (pCairoContext, pPanel->fBgColor[0], pPanel->fBgColor[1], pPanel->fBgColor[2], 1.); cairo_stroke_preserve (pCairoContext); cairo_set_source_rgba (pCairoContext, pPanel->fBgColor[0], pPanel->fBgColor[1], pPanel->fBgColor[2], pPanel->fBgColor[3]); cairo_fill (pCairoContext); // les icones. Icon *pIcon; GList *ic; pIcon = pDesklet->pIcon; if (pIcon && pIcon->image.pSurface != NULL) { cairo_save (pCairoContext); cairo_translate (pCairoContext, pIcon->fDrawX, pIcon->fDrawY); cairo_dock_apply_image_buffer_surface_with_offset (&pIcon->image, pCairoContext, 0, 0, pIcon->fAlpha); cairo_dock_draw_icon_overlays_cairo (pIcon, pDesklet->container.fRatio, pCairoContext); cairo_restore (pCairoContext); } GList *pFirstDrawnElement = cairo_dock_get_first_drawn_element_linear (pDesklet->icons); if (pFirstDrawnElement == NULL) return; ic = pFirstDrawnElement; do { pIcon = ic->data; if (pIcon->image.pSurface != NULL && ! CAIRO_DOCK_ICON_TYPE_IS_SEPARATOR (pIcon)) { cairo_save (pCairoContext); cairo_translate (pCairoContext, pIcon->fDrawX, pIcon->fDrawY); cairo_dock_apply_image_buffer_surface_with_offset (&pIcon->image, pCairoContext, 0, 0, pIcon->fAlpha); if (pIcon->label.pSurface != NULL) { cairo_save (pCairoContext); double fOffsetX = 0., fAlpha; if (pIcon->bPointed) { fAlpha = 1.; /**if (pIcon->fDrawX + pIcon->fWidth/2 + pIcon->label.iWidth/2 > pDesklet->container.iWidth) fOffsetX = pDesklet->container.iWidth - (pIcon->fDrawX + pIcon->fWidth/2 + pIcon->label.iWidth/2); if (pIcon->fDrawX + pIcon->fWidth/2 - pIcon->label.iWidth/2 < 0) fOffsetX = pIcon->label.iWidth/2 - (pIcon->fDrawX + pIcon->fWidth/2); cairo_set_source_surface (pCairoContext, pIcon->label.pSurface, fOffsetX + pIcon->fWidth/2 - pIcon->label.iWidth/2, -myIconsParam.iLabelSize);*/ cairo_set_source_surface (pCairoContext, pIcon->label.pSurface, 0., -myIconsParam.iLabelSize); cairo_paint_with_alpha (pCairoContext, fAlpha); } else { fAlpha = .6; if (pIcon->label.iWidth > 2*pIcon->fWidth + 0 * myIconsParam.iLabelSize) { ///fOffsetX = - myIconsParam.iLabelSize; cairo_pattern_t *pGradationPattern = cairo_pattern_create_linear (fOffsetX, 0., fOffsetX + 2*pIcon->fWidth + 0*myIconsParam.iLabelSize, 0.); cairo_pattern_set_extend (pGradationPattern, CAIRO_EXTEND_NONE); cairo_pattern_add_color_stop_rgba (pGradationPattern, 0., 0., 0., 0., fAlpha); cairo_pattern_add_color_stop_rgba (pGradationPattern, 0.75, 0., 0., 0., fAlpha); cairo_pattern_add_color_stop_rgba (pGradationPattern, 1., 0., 0., 0., 0.); cairo_set_source_surface (pCairoContext, pIcon->label.pSurface, fOffsetX, -myIconsParam.iLabelSize); cairo_mask (pCairoContext, pGradationPattern); cairo_pattern_destroy (pGradationPattern); } else { ///fOffsetX = pIcon->fWidth/2 - pIcon->label.iWidth/2; cairo_set_source_surface (pCairoContext, pIcon->label.pSurface, fOffsetX, -myIconsParam.iLabelSize); cairo_paint_with_alpha (pCairoContext, fAlpha); } } cairo_restore (pCairoContext); } cairo_translate (pCairoContext, pIcon->fWidth, - pIcon->fHeight/2); // not ideal, it should be vertically centered. cairo_dock_draw_icon_overlays_cairo (pIcon, pDesklet->container.fRatio, pCairoContext); cairo_restore (pCairoContext); } ic = cairo_dock_get_next_element (ic, pDesklet->icons); } while (ic != pFirstDrawnElement); }
int renderGlyphsCairo(imageObj *img,double x, double y, labelStyleObj *style, char *text) { cairo_renderer *r = CAIRO_RENDERER(img); cairoCacheData *cache = MS_IMAGE_RENDERER_CACHE(img); faceCacheObj *face = getFontFace(cache,style->font); char *utfptr=text; int i,has_kerning,unicode; unsigned long previdx=0; int numglyphs = msGetNumGlyphs(text); cairo_glyph_t glyph; cairo_text_extents_t extents; double px=0,py=0; if(face == NULL) { return MS_FAILURE; } cairo_set_font_face(r->cr,face->face); cairo_set_font_size(r->cr,style->size*96/72.0); cairo_save(r->cr); cairo_translate(r->cr,MS_NINT(x),MS_NINT(y)); if(style->rotation != 0.0) cairo_rotate(r->cr, -style->rotation); has_kerning = FT_HAS_KERNING((face->ftface)); for(i=0;i<numglyphs;i++) { utfptr+=msUTF8ToUniChar(utfptr, &unicode); glyph.x=px; glyph.y=py; if(unicode=='\n') { py += ceil(style->size*CAIROLINESPACE); px = 0; previdx=0; continue; } glyph.index = FT_Get_Char_Index(face->ftface, unicode); if( has_kerning && previdx ) { FT_Vector delta; FT_Get_Kerning( face->ftface, previdx, glyph.index, FT_KERNING_DEFAULT, &delta ); px += delta.x / 64.; } cairo_glyph_extents(r->cr,&glyph,1,&extents); cairo_glyph_path(r->cr,&glyph,1); px += extents.x_advance; previdx=glyph.index; } if (style->outlinewidth > 0) { cairo_save(r->cr); msCairoSetSourceColor(r->cr, style->outlinecolor); cairo_set_line_width(r->cr, style->outlinewidth + 1); cairo_stroke_preserve(r->cr); cairo_restore(r->cr); } if(style->color) { msCairoSetSourceColor(r->cr, style->color); cairo_fill(r->cr); } cairo_new_path(r->cr); cairo_restore(r->cr); return MS_SUCCESS; }
void gimp_display_shell_render (GimpDisplayShell *shell, cairo_t *cr, gint x, gint y, gint w, gint h) { GimpImage *image; GeglBuffer *buffer; #ifdef USE_NODE_BLIT GeglNode *node; #endif gdouble scale_x = 1.0; gdouble scale_y = 1.0; gdouble buffer_scale = 1.0; gint viewport_offset_x; gint viewport_offset_y; gint viewport_width; gint viewport_height; gint scaled_x; gint scaled_y; gint scaled_width; gint scaled_height; cairo_surface_t *xfer; gint xfer_src_x; gint xfer_src_y; gint mask_src_x = 0; gint mask_src_y = 0; gint cairo_stride; guchar *cairo_data; GeglBuffer *cairo_buffer; g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell)); g_return_if_fail (cr != NULL); g_return_if_fail (w > 0 && h > 0); image = gimp_display_get_image (shell->display); buffer = gimp_pickable_get_buffer (GIMP_PICKABLE (image)); #ifdef USE_NODE_BLIT node = gimp_projectable_get_graph (GIMP_PROJECTABLE (image)); #endif #ifdef GIMP_DISPLAY_RENDER_ENABLE_SCALING /* if we had this future API, things would look pretty on hires (retina) */ scale_x = gdk_window_get_scale_factor (gtk_widget_get_window (gtk_widget_get_toplevel (GTK_WIDGET (shell)))); #endif scale_x = MIN (scale_x, GIMP_DISPLAY_RENDER_MAX_SCALE); scale_y = scale_x; if (shell->scale_x > shell->scale_y) { scale_y *= (shell->scale_x / shell->scale_y); buffer_scale = shell->scale_y * scale_y; } else if (shell->scale_y > shell->scale_x) { scale_x *= (shell->scale_y / shell->scale_x); buffer_scale = shell->scale_x * scale_x; } else { buffer_scale = shell->scale_x * scale_x; } gimp_display_shell_scroll_get_scaled_viewport (shell, &viewport_offset_x, &viewport_offset_y, &viewport_width, &viewport_height); scaled_x = floor ((x + viewport_offset_x) * scale_x); scaled_y = floor ((y + viewport_offset_y) * scale_y); scaled_width = ceil (w * scale_x); scaled_height = ceil (h * scale_y); if (shell->rotate_transform) { xfer = cairo_surface_create_similar_image (cairo_get_target (cr), CAIRO_FORMAT_ARGB32, scaled_width, scaled_height); cairo_surface_mark_dirty (xfer); xfer_src_x = 0; xfer_src_y = 0; } else { xfer = gimp_display_xfer_get_surface (shell->xfer, scaled_width, scaled_height, &xfer_src_x, &xfer_src_y); } cairo_stride = cairo_image_surface_get_stride (xfer); cairo_data = cairo_image_surface_get_data (xfer) + xfer_src_y * cairo_stride + xfer_src_x * 4; cairo_buffer = gegl_buffer_linear_new_from_data (cairo_data, babl_format ("cairo-ARGB32"), GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), cairo_stride, NULL, NULL); if (shell->profile_transform || gimp_display_shell_has_filter (shell)) { gboolean can_convert_to_u8; /* if there is a profile transform or a display filter, we need * to use temp buffers */ can_convert_to_u8 = gimp_display_shell_profile_can_convert_to_u8 (shell); /* create the filter buffer if we have filters */ if ((gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) && ! shell->filter_buffer) { gint w = GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE; gint h = GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE; shell->filter_data = gegl_malloc (w * h * babl_format_get_bytes_per_pixel (shell->filter_format)); shell->filter_stride = w * babl_format_get_bytes_per_pixel (shell->filter_format); shell->filter_buffer = gegl_buffer_linear_new_from_data (shell->filter_data, shell->filter_format, GEGL_RECTANGLE (0, 0, w, h), GEGL_AUTO_ROWSTRIDE, (GDestroyNotify) gegl_free, shell->filter_data); } if (shell->profile_transform) { /* if there is a profile transform, load the projection * pixels into the profile_buffer */ #ifndef USE_NODE_BLIT gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, gimp_projectable_get_format (GIMP_PROJECTABLE (image)), shell->profile_data, shell->profile_stride, GEGL_ABYSS_CLAMP); #else gegl_node_blit (node, buffer_scale, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), gimp_projectable_get_format (GIMP_PROJECTABLE (image)), shell->profile_data, shell->profile_stride, GEGL_BLIT_CACHE); #endif if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) { /* if there are filters, convert the pixels from the * profile_buffer to the filter_buffer */ gimp_display_shell_profile_convert_buffer (shell, shell->profile_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); } else { /* otherwise, convert the profile_buffer directly into * the cairo_buffer */ gimp_display_shell_profile_convert_buffer (shell, shell->profile_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), cairo_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); } } else { /* otherwise, load the projection pixels directly into the * filter_buffer */ #ifndef USE_NODE_BLIT gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, shell->filter_format, shell->filter_data, shell->filter_stride, GEGL_ABYSS_CLAMP); #else gegl_node_blit (node, buffer_scale, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), shell->filter_format, shell->filter_data, shell->filter_stride, GEGL_BLIT_CACHE); #endif } if (gimp_display_shell_has_filter (shell)) { /* convert the filter_buffer in place */ gimp_color_display_stack_convert_buffer (shell->filter_stack, shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height)); } if (gimp_display_shell_has_filter (shell) || ! can_convert_to_u8) { /* finally, copy the filter buffer to the cairo-ARGB32 buffer */ gegl_buffer_get (shell->filter_buffer, GEGL_RECTANGLE (0, 0, scaled_width, scaled_height), 1.0, babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, GEGL_ABYSS_CLAMP); } } else { /* otherwise we can copy the projection pixels straight to the * cairo-ARGB32 buffer */ #ifndef USE_NODE_BLIT gegl_buffer_get (buffer, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), buffer_scale, babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, GEGL_ABYSS_CLAMP); #else gegl_node_blit (node, buffer_scale, GEGL_RECTANGLE (scaled_x, scaled_y, scaled_width, scaled_height), babl_format ("cairo-ARGB32"), cairo_data, cairo_stride, GEGL_BLIT_CACHE); #endif } g_object_unref (cairo_buffer); if (shell->mask) { if (! shell->mask_surface) { shell->mask_surface = cairo_image_surface_create (CAIRO_FORMAT_A8, GIMP_DISPLAY_RENDER_BUF_WIDTH * GIMP_DISPLAY_RENDER_MAX_SCALE, GIMP_DISPLAY_RENDER_BUF_HEIGHT * GIMP_DISPLAY_RENDER_MAX_SCALE); } cairo_surface_mark_dirty (shell->mask_surface); cairo_stride = cairo_image_surface_get_stride (shell->mask_surface); cairo_data = cairo_image_surface_get_data (shell->mask_surface) + mask_src_y * cairo_stride + mask_src_x * 4; gegl_buffer_get (shell->mask, GEGL_RECTANGLE (scaled_x - shell->mask_offset_x, scaled_y - shell->mask_offset_y, scaled_width, scaled_height), buffer_scale, babl_format ("Y u8"), cairo_data, cairo_stride, GEGL_ABYSS_NONE); if (shell->mask_inverted) { gint mask_height = scaled_height; while (mask_height--) { gint mask_width = scaled_width; guchar *d = cairo_data; while (mask_width--) { guchar inv = 255 - *d; *d++ = inv; } cairo_data += cairo_stride; } } } /* put it to the screen */ cairo_save (cr); cairo_rectangle (cr, x, y, w, h); cairo_scale (cr, 1.0 / scale_x, 1.0 / scale_y); cairo_set_source_surface (cr, xfer, x * scale_x - xfer_src_x, y * scale_y - xfer_src_y); if (shell->rotate_transform) { cairo_pattern_t *pattern; pattern = cairo_get_source (cr); cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD); cairo_set_line_width (cr, 1.0); cairo_stroke_preserve (cr); cairo_surface_destroy (xfer); } cairo_clip (cr); cairo_paint (cr); if (shell->mask) { gimp_cairo_set_source_rgba (cr, &shell->mask_color); cairo_mask_surface (cr, shell->mask_surface, (x - mask_src_x) * scale_x, (y - mask_src_y) * scale_y); } cairo_restore (cr); }
EXPORT void stroke_preserve(cairo_t *context) { cairo_stroke_preserve(context); }
/*Function executes only if there is button press event*/ static gboolean button_press_event( GtkWidget *widget, GdkEventButton *event ) { int i; if (( event->button == 1) && SPLINE==0 && FILL==0 && line==0 && complete==0 && CENTER!=1 && RADIUS!=1&&CIRCLE==0) { draw_brush (widget, event->x, event->y); return TRUE; } if(SPLINE==1) { get_points_spline(widget, event); return TRUE; } if(CENTER==1) { get_center(widget,event); return TRUE; } if(RADIUS==1) { get_radius(widget,event); return TRUE; } if(FILL==1) { floodfill_select(widget,event); return TRUE; } if( complete == 1 ) { if (event->button == 1 ) { glob.coordx[glob.count] = event->x; //stores the coordinates of present point glob.coordy[glob.count] = event->y; draw_brush (widget, event->x, event->y); if(glob.count>0) { cr = gdk_cairo_create(widget->window); cairo_set_source_rgb(cr,red,green,blue); cairo_set_line_width(cr, rec1); //moves to present point for( i = 0; i<=glob.count-1; i++ ) { cairo_move_to(cr, glob.coordx[glob.count], glob.coordy[glob.count]); //line is made to previous point. cairo_line_to(cr, glob.coordx[i], glob.coordy[i]); int end_x = glob.coordx[glob.count]; //present point coordinates stored in end_x. int end_y = glob.coordy[glob.count]; int start_x = glob.coordx[i]; //coordinates of previously selected points. int start_y = glob.coordy[i]; pixels[start_x][start_y]=1; R[start_x][start_y]=red; G[start_x][start_y]=green; B[start_x][start_y]=blue; int distance = sqrt(pow((end_x - start_x),2) + pow((end_y - start_y),2)); double slope = ((double)(end_y-start_y)/(double)(end_x-start_x)); int i,j; for(i=start_x;i<=end_x;i++) { j=(slope*i)-(slope*start_x)+(start_y); pixels[i][j]=1; pixels[i+1][j]=1; pixels[i-1][j]=1; pixels[i][j+1]=1; pixels[i][j-1]=1; pixels[i+2][j]=1; pixels[i-2][j]=1; pixels[i][j+2]=1; pixels[i][j-2]=1; R[i][j]=red; G[i][j]=green; B[i][j]=blue; } cairo_stroke(cr); } } glob.count++; } } if( line == 1 ) { if (event->button == 1 ) { glob.coordx[glob.count] = event->x; glob.coordy[glob.count] = event->y; int end_x = event->x; // coordinates of present points int end_y = event->y; pixels[end_x][end_y]=1; R[end_x][end_y]=1; G[end_x][end_y]=1; B[end_x][end_y]=1; // this function shows the presently selected point. draw_brush (widget, event->x, event->y); if(glob.count>0) { cr = gdk_cairo_create(widget->window); cairo_set_source_rgb(cr,red,green,blue); //line colour is set cairo_set_line_width(cr, rec1); // line width is set rec1 is global variable // moved to present point cairo_move_to(cr, glob.coordx[glob.count], glob.coordy[glob.count]); // line is made to previous point cairo_line_to(cr, glob.coordx[glob.count-1], glob.coordy[glob.count-1]); line=0; gtk_label_set_text (GTK_LABEL(butlabel),"Pencil"); int start_x = glob.coordx[glob.count-1]; int start_y = glob.coordy[glob.count-1]; pixels[start_x][start_y]=1; R[start_x][start_y]=red; G[start_x][start_y]=green; B[start_x][start_y]=blue; int distance = sqrt(pow((end_x - start_x),2) + pow((end_y - start_y),2)); double slope = ((double)(end_y-start_y)/(double)(end_x-start_x)); int i,j; for(i=start_x;i<=end_x;i++) { j=(slope*i)-(slope*start_x)+(start_y); pixels[i][j]=1; pixels[i+1][j]=1; pixels[i-1][j]=1; pixels[i][j+1]=1; pixels[i][j-1]=1; pixels[i+2][j]=1; pixels[i-2][j]=1; pixels[i][j+2]=1; pixels[i][j-2]=1; R[i][j]=red; G[i][j]=green; B[i][j]=blue; } cairo_stroke_preserve(cr); cairo_stroke(cr); } glob.count++; } } if(CIRCLE==1) { cr=gdk_cairo_create(widget->window); cairo_set_source_rgb(cr, red, green, blue); cairo_set_line_width(cr,1); cairo_rectangle(cr, event->x,event->y, rec1, rec2); int X=event->x; int Y=event->y; R[X][Y]=red; B[X][Y]=blue; G[X][Y]=green; cairo_stroke_preserve(cr); cairo_fill(cr); return TRUE; } }
void eda_cairo_stroke (cairo_t *cr, int flags, int line_type, int line_end, double wwidth, double wlength, double wspace) { double offset = 0; double dashes[4]; double dummy = 0; cairo_line_cap_t cap; cairo_line_cap_t round_cap_if_legible = CAIRO_LINE_CAP_ROUND; int num_dashes; int iwidth; double width = wwidth, length = wlength, space = wspace; if (flags & EDA_CAIRO_ENABLE_HINTS) { width = iwidth = screen_width (cr, wwidth); length = screen_width (cr, wlength); space = screen_width (cr, wspace); cairo_device_to_user_distance (cr, &width, &dummy); cairo_device_to_user_distance (cr, &length, &dummy); cairo_device_to_user_distance (cr, &space, &dummy); offset = ((iwidth % 2) == 0) ? 0 : 0.5; round_cap_if_legible = (iwidth <= 1) ? CAIRO_LINE_CAP_SQUARE : CAIRO_LINE_CAP_ROUND; } cairo_set_line_width (cr, width); cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER); switch (line_end) { case END_NONE: cap = CAIRO_LINE_CAP_BUTT; break; case END_SQUARE: cap = CAIRO_LINE_CAP_SQUARE; break; case END_ROUND: cap = round_cap_if_legible; break; default: g_warn_if_reached (); cap = CAIRO_LINE_CAP_BUTT; break; } switch (line_type) { default: g_warn_if_reached (); /* Fall through */ case TYPE_SOLID: num_dashes = 0; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, cap); cairo_stroke (cr); break; case TYPE_DOTTED: dashes[0] = 0; /* DOT */ dashes[1] = space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, offset); cairo_set_line_cap (cr, round_cap_if_legible); cairo_stroke (cr); break; case TYPE_DASHED: dashes[0] = length; /* DASH */ dashes[1] = space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); cairo_stroke (cr); break; case TYPE_CENTER: dashes[0] = length; /* DASH */ dashes[1] = 2 * space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); cairo_stroke_preserve (cr); dashes[0] = 0; /* DOT */ dashes[1] = 2 * space + length; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, -length - space + offset); cairo_set_line_cap (cr, round_cap_if_legible); cairo_stroke (cr); break; case TYPE_PHANTOM: dashes[0] = length; /* DASH */ dashes[1] = 3 * space; num_dashes = 2; cairo_set_dash (cr, dashes, num_dashes, 0.); cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT); cairo_stroke_preserve (cr); dashes[0] = 0; /* DOT */ dashes[1] = space; dashes[2] = 0; /* DOT */ dashes[3] = 2 * space + length; num_dashes = 4; cairo_set_dash (cr, dashes, num_dashes, -length - space + offset); cairo_set_line_cap (cr, round_cap_if_legible); cairo_stroke (cr); break; } cairo_set_dash (cr, NULL, 0, 0.); }
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; }