static void draw (cairo_t *cr, int width, int height) { cairo_surface_t *overlay, *punch, *circles; cairo_t *overlay_cr, *punch_cr, *circles_cr; /* Fill the background */ double radius = 0.5 * (width < height ? width : height) - 10; double xc = width / 2.; double yc = height / 2.; overlay = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR_ALPHA, width, height); if (overlay == NULL) return; punch = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_ALPHA, width, height); if (punch == NULL) return; circles = cairo_surface_create_similar (cairo_get_target (cr), CAIRO_CONTENT_COLOR_ALPHA, width, height); if (circles == NULL) return; fill_checks (cr, 0, 0, width, height); /* Draw a black circle on the overlay */ overlay_cr = cairo_create (overlay); cairo_set_source_rgb (overlay_cr, 0., 0., 0.); oval_path (overlay_cr, xc, yc, radius, radius); cairo_fill (overlay_cr); /* Draw 3 circles to the punch surface, then cut * that out of the main circle in the overlay */ punch_cr = cairo_create (punch); draw_3circles (punch_cr, xc, yc, radius, 1.0); cairo_destroy (punch_cr); cairo_set_operator (overlay_cr, CAIRO_OPERATOR_DEST_OUT); cairo_set_source_surface (overlay_cr, punch, 0, 0); cairo_paint (overlay_cr); /* Now draw the 3 circles in a subgroup again * at half intensity, and use OperatorAdd to join up * without seams. */ circles_cr = cairo_create (circles); cairo_set_operator (circles_cr, CAIRO_OPERATOR_OVER); draw_3circles (circles_cr, xc, yc, radius, 0.5); cairo_destroy (circles_cr); cairo_set_operator (overlay_cr, CAIRO_OPERATOR_ADD); cairo_set_source_surface (overlay_cr, circles, 0, 0); cairo_paint (overlay_cr); cairo_destroy (overlay_cr); cairo_set_source_surface (cr, overlay, 0, 0); cairo_paint (cr); cairo_surface_destroy (overlay); cairo_surface_destroy (punch); cairo_surface_destroy (circles); }
bool wxGTKCairoDCImpl::DoStretchBlit(int xdest, int ydest, int dstWidth, int dstHeight, wxDC* source, int xsrc, int ysrc, int srcWidth, int srcHeight, wxRasterOperationMode rop, bool useMask, int xsrcMask, int ysrcMask) { wxCHECK_MSG(IsOk(), false, "invalid DC"); wxCHECK_MSG(source && source->IsOk(), false, "invalid source DC"); cairo_t* cr = NULL; if (m_graphicContext) cr = static_cast<cairo_t*>(m_graphicContext->GetNativeContext()); cairo_t* cr_src = NULL; wxGraphicsContext* gc_src = source->GetGraphicsContext(); if (gc_src) cr_src = static_cast<cairo_t*>(gc_src->GetNativeContext()); if (cr == NULL || cr_src == NULL) return false; const int xsrc_dev = source->LogicalToDeviceX(xsrc); const int ysrc_dev = source->LogicalToDeviceY(ysrc); cairo_surface_t* surfaceSrc = cairo_get_target(cr_src); cairo_surface_flush(surfaceSrc); cairo_surface_t* surfaceTmp = NULL; // If destination (this) and source wxDC refer to the same Cairo context // it means that we operate on one surface and results of drawing // can be invalid if destination and source regions overlap. // In such situation we have to copy source surface to the temporary // surface and use this copy in the drawing operations. if ( cr == cr_src ) { // Check if destination and source regions overlap. // If necessary, copy source surface to the temporary one. if (wxRect(xdest, ydest, dstWidth, dstHeight) .Intersects(wxRect(xsrc, ysrc, srcWidth, srcHeight))) { const int w = cairo_image_surface_get_width(surfaceSrc); const int h = cairo_image_surface_get_height(surfaceSrc); #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) if ( cairo_version() >= CAIRO_VERSION_ENCODE(1, 12, 0) ) { surfaceTmp = cairo_surface_create_similar_image(surfaceSrc, cairo_image_surface_get_format(surfaceSrc), w, h); } else #endif // Cairo 1.12 { surfaceTmp = cairo_surface_create_similar(surfaceSrc, CAIRO_CONTENT_COLOR_ALPHA, w, h); } cairo_t* crTmp = cairo_create(surfaceTmp); cairo_set_source_surface(crTmp, surfaceSrc, 0, 0); cairo_rectangle(crTmp, 0.0, 0.0, w, h); cairo_set_operator(crTmp, CAIRO_OPERATOR_SOURCE); cairo_fill(crTmp); cairo_destroy(crTmp); cairo_surface_flush(surfaceTmp); surfaceSrc = surfaceTmp; } } cairo_save(cr); cairo_translate(cr, xdest, ydest); cairo_rectangle(cr, 0, 0, dstWidth, dstHeight); double sx, sy; source->GetUserScale(&sx, &sy); cairo_scale(cr, dstWidth / (sx * srcWidth), dstHeight / (sy * srcHeight)); cairo_set_source_surface(cr, surfaceSrc, -xsrc_dev, -ysrc_dev); const wxRasterOperationMode rop_save = m_logicalFunction; SetLogicalFunction(rop); cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST); cairo_surface_t* maskSurf = NULL; if (useMask) { const wxBitmap& bitmap = source->GetImpl()->GetSelectedBitmap(); if (bitmap.IsOk()) { wxMask* mask = bitmap.GetMask(); if (mask) maskSurf = *mask; } } if (maskSurf) { int xsrcMask_dev = xsrc_dev; int ysrcMask_dev = ysrc_dev; if (xsrcMask != -1) xsrcMask_dev = source->LogicalToDeviceX(xsrcMask); if (ysrcMask != -1) ysrcMask_dev = source->LogicalToDeviceY(ysrcMask); cairo_clip(cr); cairo_mask_surface(cr, maskSurf, -xsrcMask_dev, -ysrcMask_dev); } else { cairo_fill(cr); } cairo_restore(cr); if ( surfaceTmp ) { cairo_surface_destroy(surfaceTmp); } m_logicalFunction = rop_save; return true; }
void _gtk_pixel_cache_set_position (GtkPixelCache *cache, cairo_rectangle_int_t *view_rect, cairo_rectangle_int_t *canvas_rect) { cairo_rectangle_int_t r, view_pos; cairo_region_t *copy_region; int new_surf_x, new_surf_y; cairo_t *backing_cr; if (cache->surface == NULL) return; /* Position of view inside canvas */ view_pos.x = -canvas_rect->x; view_pos.y = -canvas_rect->y; view_pos.width = view_rect->width; view_pos.height = view_rect->height; /* Reposition so all is visible */ if (view_pos.x < cache->surface_x || view_pos.x + view_pos.width > cache->surface_x + cache->surface_w || view_pos.y < cache->surface_y || view_pos.y + view_pos.height > cache->surface_y + cache->surface_h) { new_surf_x = cache->surface_x; if (view_pos.x < cache->surface_x) new_surf_x = MAX (view_pos.x + view_pos.width - cache->surface_w, 0); else if (view_pos.x + view_pos.width > cache->surface_x + cache->surface_w) new_surf_x = MIN (view_pos.x, canvas_rect->width - cache->surface_w); new_surf_y = cache->surface_y; if (view_pos.y < cache->surface_y) new_surf_y = MAX (view_pos.y + view_pos.height - cache->surface_h, 0); else if (view_pos.y + view_pos.height > cache->surface_y + cache->surface_h) new_surf_y = MIN (view_pos.y, canvas_rect->height - cache->surface_h); r.x = 0; r.y = 0; r.width = cache->surface_w; r.height = cache->surface_h; copy_region = cairo_region_create_rectangle (&r); if (cache->surface_dirty) { cairo_region_subtract (copy_region, cache->surface_dirty); cairo_region_destroy (cache->surface_dirty); cache->surface_dirty = NULL; } cairo_region_translate (copy_region, cache->surface_x - new_surf_x, cache->surface_y - new_surf_y); cairo_region_intersect_rectangle (copy_region, &r); backing_cr = cairo_create (cache->surface); gdk_cairo_region (backing_cr, copy_region); cairo_set_operator (backing_cr, CAIRO_OPERATOR_SOURCE); cairo_clip (backing_cr); cairo_push_group (backing_cr); cairo_set_source_surface (backing_cr, cache->surface, cache->surface_x - new_surf_x, cache->surface_y - new_surf_y); cairo_paint (backing_cr); cairo_pop_group_to_source (backing_cr); cairo_paint (backing_cr); cairo_destroy (backing_cr); cache->surface_x = new_surf_x; cache->surface_y = new_surf_y; cairo_region_xor_rectangle (copy_region, &r); cache->surface_dirty = copy_region; } }
static gboolean dt_iop_levels_area_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_levels_gui_data_t *c = (dt_iop_levels_gui_data_t *)self->gui_data; dt_iop_levels_params_t *p = (dt_iop_levels_params_t *)self->params; dt_develop_t *dev = darktable.develop; const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(GTK_WIDGET(c->area), &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); // clear bg cairo_set_source_rgb(cr, .2, .2, .2); cairo_paint(cr); cairo_translate(cr, inset, inset); width -= 2 * inset; height -= 2 * inset; cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0)); cairo_set_source_rgb(cr, .1, .1, .1); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); cairo_set_source_rgb(cr, .3, .3, .3); cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); // draw grid cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(.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_vertical_lines(cr, 4, 0, 0, width, height); // Drawing the vertical line indicators cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.)); for(int k = 0; k < 3; k++) { if(k == c->handle_move && c->mouse_x > 0) cairo_set_source_rgb(cr, 1, 1, 1); else cairo_set_source_rgb(cr, .7, .7, .7); cairo_move_to(cr, width * p->levels[k], height); cairo_rel_line_to(cr, 0, -height); cairo_stroke(cr); } // draw x positions cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.)); const float arrw = DT_PIXEL_APPLY_DPI(7.0f); for(int k = 0; k < 3; k++) { switch(k) { case 0: cairo_set_source_rgb(cr, 0, 0, 0); break; case 1: cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); break; default: cairo_set_source_rgb(cr, 1, 1, 1); break; } cairo_move_to(cr, width * p->levels[k], height + inset - 1); cairo_rel_line_to(cr, -arrw * .5f, 0); cairo_rel_line_to(cr, arrw * .5f, -arrw); cairo_rel_line_to(cr, arrw * .5f, arrw); cairo_close_path(cr); if(c->handle_move == k && c->mouse_x > 0) cairo_fill(cr); else cairo_stroke(cr); } cairo_translate(cr, 0, height); // draw lum histogram in background // only if the module is enabled if(self->enabled) { uint32_t *hist = self->histogram; float hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR ? self->histogram_max[0] : logf(1.0 + self->histogram_max[0]); if(hist && hist_max > 0.0f) { cairo_save(cr); cairo_scale(cr, width / 255.0, -(height - DT_PIXEL_APPLY_DPI(5)) / hist_max); cairo_set_source_rgba(cr, .2, .2, .2, 0.5); dt_draw_histogram_8(cr, hist, 4, 0, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR); // TODO: make draw // handle waveform // histograms cairo_restore(cr); } } // Cleaning up cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }
/* expose snapshot over center viewport */ void gui_post_expose(dt_lib_module_t *self, cairo_t *cri, int32_t width, int32_t height, int32_t pointerx, int32_t pointery) { dt_lib_snapshots_t *d = (dt_lib_snapshots_t *)self->data; // convert to image coordinates: const int32_t capwd = darktable.thumbnail_width; const int32_t capht = darktable.thumbnail_height; const int32_t width_i = d->vp_width; const int32_t height_i = d->vp_height; if(width_i > capwd) pointerx += (capwd-width_i) *.5f; if(height_i > capht) pointery += (capht-height_i)*.5f; if(d->snapshot_image) { d->vp_width = width; d->vp_height = height; /* check if mouse pointer is on draggable area */ double xp = pointerx/d->vp_width; double yp = pointery/d->vp_height; double xpt = xp*0.01; double ypt = yp*0.01; gboolean mouse_over_control = d->vertical ? ((xp > d->vp_xpointer-xpt && xp < d->vp_xpointer+xpt)?TRUE:FALSE) : ((yp > d->vp_ypointer-ypt && yp < d->vp_ypointer+ypt)?TRUE:FALSE); /* set x,y,w,h of surface depending on split align and invert */ double x = d->vertical ? (d->inverted?width*d->vp_xpointer:0) : 0; double y = d->vertical ? 0 : (d->inverted?height*d->vp_ypointer:0); double w = d->vertical ? (d->inverted?(width * (1.0 - d->vp_xpointer)):width * d->vp_xpointer) : width; double h = d->vertical ? height : (d->inverted?(height * (1.0 - d->vp_ypointer)):height * d->vp_ypointer); cairo_set_source_surface(cri, d->snapshot_image, 0, 0); //cairo_rectangle(cri, 0, 0, width*d->vp_xpointer, height); cairo_rectangle(cri,x,y,w,h); cairo_fill(cri); /* draw the split line */ cairo_set_source_rgb(cri, .7, .7, .7); cairo_set_line_width(cri, (mouse_over_control ? 2.0 : 0.5) ); if(d->vertical) { cairo_move_to(cri, width*d->vp_xpointer, 0.0f); cairo_line_to(cri, width*d->vp_xpointer, height); } else { cairo_move_to(cri, 0.0f, height*d->vp_ypointer); cairo_line_to(cri, width, height*d->vp_ypointer); } cairo_stroke(cri); /* if mouse over control lets draw center rotate control, hide if split is dragged */ if(!d->dragging && mouse_over_control) { cairo_set_line_width(cri,0.5); double s = width*HANDLE_SIZE; dtgtk_cairo_paint_refresh(cri, (d->vertical ? width*d->vp_xpointer : width*0.5)-(s*0.5), (d->vertical ? height*0.5 : height*d->vp_ypointer)-(s*0.5), s,s,d->vertical?1:0); } } }
static void update_icon(ShowDesktopData* sdd) { GtkStyleContext *context; GtkStateFlags state; GtkBorder padding; int width, height; cairo_surface_t* icon; cairo_surface_t* scaled; int icon_size, icon_scale; GError* error; int thickness = 0; if (!sdd->icon_theme) return; state = gtk_widget_get_state_flags (sdd->button); context = gtk_widget_get_style_context (sdd->button); gtk_style_context_get_padding (context, state, &padding); switch (sdd->orient) { case GTK_ORIENTATION_HORIZONTAL: thickness = padding.top + padding.bottom; break; case GTK_ORIENTATION_VERTICAL: thickness = padding.left + padding.right; break; } icon_scale = gtk_widget_get_scale_factor (sdd->button); icon_size = sdd->size * icon_scale - thickness; if (icon_size < 22) icon_size = 16; else if (icon_size < 24) icon_size = 22; else if (icon_size < 32) icon_size = 24; else if (icon_size < 48) icon_size = 32; else if (icon_size < 64) icon_size = 48; else if (icon_size < 128) icon_size = 64; error = NULL; icon = gtk_icon_theme_load_surface (sdd->icon_theme, SHOW_DESKTOP_ICON, icon_size, icon_scale, NULL, 0, &error); if (icon == NULL) { g_printerr(_("Failed to load %s: %s\n"), SHOW_DESKTOP_ICON, error ? error->message : _("Icon not found")); if (error) { g_error_free(error); error = NULL; } gtk_image_set_from_icon_name (GTK_IMAGE (sdd->image), "image-missing", GTK_ICON_SIZE_SMALL_TOOLBAR); return; } width = cairo_image_surface_get_width (icon); height = cairo_image_surface_get_height (icon); scaled = NULL; /* Make it fit on the given panel */ switch (sdd->orient) { case GTK_ORIENTATION_HORIZONTAL: width = (icon_size / icon_scale * width) / height; height = icon_size / icon_scale; break; case GTK_ORIENTATION_VERTICAL: height = (icon_size / icon_scale * height) / width; width = icon_size / icon_scale; break; } scaled = cairo_surface_create_similar (icon, cairo_surface_get_content (icon), width, height); if (scaled != NULL) { cairo_t *cr; cr = cairo_create (scaled); cairo_scale (cr, (double) width / icon_size, (double) height / icon_size); cairo_set_source_surface (cr, icon, 0, 0); cairo_paint (cr); gtk_image_set_from_surface (GTK_IMAGE(sdd->image), scaled); cairo_surface_destroy (scaled); } else { gtk_image_set_from_surface (GTK_IMAGE (sdd->image), icon); } cairo_surface_destroy (icon); }
void wxSVGCanvasCairo::DrawCanvasImage(wxSVGCanvasImage& canvasImage, cairo_surface_t* cairoSurface, wxSVGMatrix& matrix, const wxCSSStyleDeclaration& style, wxSVGSVGElement& svgElem) { if (cairoSurface == NULL) return; cairo_save(m_cr); // ClipPath if (style.GetClipPath().GetCSSPrimitiveType() == wxCSS_URI && style.GetClipPath().GetStringValue().length() > 1) { wxString clipPathId = style.GetClipPath().GetStringValue().substr(1); wxSVGClipPathElement* clipPathElem = (wxSVGClipPathElement*) svgElem.GetElementById(clipPathId); if (clipPathElem && clipPathElem->GetDtd() == wxSVG_CLIPPATH_ELEMENT) { clipPathElem->SetOwnerSVGElement(&svgElem); clipPathElem->SetViewportElement(&svgElem); wxSVGMatrix clipMatrix(matrix); clipPathElem->UpdateMatrix(clipMatrix); SetClipPath(clipPathElem, clipMatrix); } } SetMatrix(m_cr, matrix); // scale context double x = canvasImage.m_x; double y = canvasImage.m_y; double scaleX = canvasImage.m_width / canvasImage.m_image.GetWidth(); double scaleY = canvasImage.m_height / canvasImage.m_image.GetHeight(); wxSVG_PRESERVEASPECTRATIO align = canvasImage.GetPreserveAspectRatio().GetAlign(); bool alignX = false; if (align > wxSVG_PRESERVEASPECTRATIO_NONE) { scaleY = canvasImage.m_height / canvasImage.GetDefaultHeight(); if (canvasImage.GetPreserveAspectRatio().GetMeetOrSlice() != wxSVG_MEETORSLICE_SLICE) { alignX = scaleX > scaleY; } else { cairo_rectangle(m_cr, x, y, canvasImage.m_width, canvasImage.m_height); cairo_clip(m_cr); alignX = scaleX < scaleY; } if (alignX) { scaleX = scaleY; if (align == wxSVG_PRESERVEASPECTRATIO_XMIDYMIN || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMID || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMAX) x += (canvasImage.m_width - canvasImage.GetDefaultWidth() * scaleX) / 2; else if (align == wxSVG_PRESERVEASPECTRATIO_XMAXYMIN || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMID || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMAX) x += canvasImage.m_width - canvasImage.GetDefaultWidth() * scaleX; } else { scaleY = scaleX; if (align == wxSVG_PRESERVEASPECTRATIO_XMINYMID || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMID || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMID) y += (canvasImage.m_height - canvasImage.GetDefaultHeight() * scaleY) / 2; else if (align == wxSVG_PRESERVEASPECTRATIO_XMINYMAX || align == wxSVG_PRESERVEASPECTRATIO_XMIDYMAX || align == wxSVG_PRESERVEASPECTRATIO_XMAXYMAX) y += canvasImage.m_height - canvasImage.GetDefaultHeight() * scaleY; } scaleY = scaleY * canvasImage.GetDefaultHeight() / canvasImage.m_image.GetHeight(); } cairo_translate(m_cr, x, y); cairo_scale(m_cr, scaleX, scaleY); // prepare to draw the image cairo_set_source_surface(m_cr, cairoSurface, 0, 0); // use the original size here since the context is scaled already... cairo_rectangle(m_cr, 0, 0, canvasImage.m_image.GetWidth(), canvasImage.m_image.GetHeight()); // paint if (style.GetMask().GetCSSPrimitiveType() == wxCSS_URI && style.GetMask().GetStringValue().length() > 1) { wxString maskId = style.GetMask().GetStringValue().substr(1); wxSVGMaskElement* maskElem = (wxSVGMaskElement*) svgElem.GetElementById(maskId); if (maskElem && maskElem->GetDtd() == wxSVG_MASK_ELEMENT) { maskElem->SetOwnerSVGElement(&svgElem); maskElem->SetViewportElement(&svgElem); cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, svgElem.GetWidth().GetAnimVal()/scaleX, svgElem.GetHeight().GetAnimVal()/scaleY); cairo_t* cr = cairo_create(surface); wxSVGMatrix maskMatrix; maskMatrix = maskMatrix.Translate(x, y).ScaleNonUniform(scaleX, scaleY).Inverse(); DrawMask(cr, maskElem, maskMatrix, style, svgElem); cairo_mask_surface(m_cr, surface, 0, 0); cairo_destroy(cr); cairo_surface_destroy(surface); } } else { cairo_paint_with_alpha(m_cr, style.GetOpacity()); } cairo_new_path(m_cr); // clean up cairo_restore(m_cr); }
void draw_rectangles(cairo_t *fbcr, struct tsdev *ts, cairo_linuxfb_device_t *device) { int bufid = 1; /* start drawing into second buffer */ float r, g, b; int fbsizex = device->fb_vinfo.xres; int fbsizey = device->fb_vinfo.yres; int startx, starty, sizex, sizey; struct ts_sample sample; cairo_surface_t *surface; cairo_t *cr; float scale = 1.0f; surface = cairo_image_surface_create(CAIRO_FORMAT_RGB16_565, fbsizex, fbsizey); cr = cairo_create(surface); /* * We clear the cairo surface here before drawing * This is required in case something was drawn on this surface * previously, the previous contents would not be cleared without this. */ cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); cairo_paint(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); srand(time(NULL)); while (!cancel) { r = (rand() % 100) / 100.0; g = (rand() % 100) / 100.0; b = (rand() % 100) / 100.0; startx = rand() % fbsizex; starty = rand() % fbsizey; sizex = rand() % (fbsizex - startx); sizey = rand() % (fbsizey - starty); cairo_identity_matrix(cr); if (ts) { int pressed = 0; /* Pressure is our identication whether we act on axis... */ while (ts_read(ts, &sample, 1)) { if (sample.pressure > 0) pressed = 1; } if (pressed) { scale *= 1.05f; cairo_translate(cr, sample.x, sample.y); cairo_scale(cr, scale, scale); //r = g = b = 0; startx = -5; starty = -5; sizex = 10; sizey = 10; } else { scale = 1.0f; } } cairo_set_source_rgb(cr, r, g, b); cairo_rectangle(cr, startx, starty, sizex, sizey); cairo_stroke_preserve(cr); cairo_fill(cr); /* Draw to framebuffer at y offset according to current buffer.. */ cairo_set_source_surface(fbcr, surface, 0, bufid * fbsizey); cairo_paint(fbcr); flip_buffer(device, 1, bufid); /* Switch buffer ID for next draw */ bufid = !bufid; usleep(20000); } /* Make sure we leave with buffer 0 enabled */ flip_buffer(device, 1, 0); /* Destroy and release all cairo related contexts */ cairo_destroy(cr); cairo_surface_destroy(surface); }
static gboolean gtk_offscreen_box_draw (GtkWidget *widget, cairo_t *cr) { GtkOffscreenBox *offscreen_box = GTK_OFFSCREEN_BOX (widget); GdkWindow *window; window = gtk_widget_get_window (widget); if (gtk_cairo_should_draw_window (cr, window)) { cairo_surface_t *surface; GtkAllocation child_area; if (offscreen_box->child1 && gtk_widget_get_visible (offscreen_box->child1)) { surface = gdk_offscreen_window_get_surface (offscreen_box->offscreen_window1); cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); gtk_widget_get_allocation (offscreen_box->child1, &child_area); cairo_translate (cr, 0, child_area.height); } if (offscreen_box->child2 && gtk_widget_get_visible (offscreen_box->child2)) { surface = gdk_offscreen_window_get_surface (offscreen_box->offscreen_window2); gtk_widget_get_allocation (offscreen_box->child2, &child_area); /* transform */ cairo_translate (cr, child_area.width / 2, child_area.height / 2); cairo_rotate (cr, offscreen_box->angle); cairo_translate (cr, -child_area.width / 2, -child_area.height / 2); /* paint */ cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); } } else if (gtk_cairo_should_draw_window (cr, offscreen_box->offscreen_window1)) { gtk_render_background (gtk_widget_get_style_context (widget), cr, 0, 0, gdk_window_get_width (offscreen_box->offscreen_window1), gdk_window_get_height (offscreen_box->offscreen_window1)); if (offscreen_box->child1) gtk_container_propagate_draw (GTK_CONTAINER (widget), offscreen_box->child1, cr); } else if (gtk_cairo_should_draw_window (cr, offscreen_box->offscreen_window2)) { gtk_render_background (gtk_widget_get_style_context (widget), cr, 0, 0, gdk_window_get_width (offscreen_box->offscreen_window2), gdk_window_get_height (offscreen_box->offscreen_window2)); if (offscreen_box->child2) gtk_container_propagate_draw (GTK_CONTAINER (widget), offscreen_box->child2, cr); } return FALSE; }
void *dt_control_expose(void *voidptr) { int width, height, pointerx, pointery; if(!darktable.gui->surface) return NULL; width = dt_cairo_image_surface_get_width(darktable.gui->surface); height = dt_cairo_image_surface_get_height(darktable.gui->surface); GtkWidget *widget = dt_ui_center(darktable.gui->ui); #if GTK_CHECK_VERSION(3, 20, 0) gdk_window_get_device_position(gtk_widget_get_window(widget), gdk_seat_get_pointer(gdk_display_get_default_seat(gtk_widget_get_display(widget))), &pointerx, &pointery, NULL); #else GdkDevice *device = gdk_device_manager_get_client_pointer(gdk_display_get_device_manager(gtk_widget_get_display(widget))); gdk_window_get_device_position(gtk_widget_get_window(widget), device, &pointerx, &pointery, NULL); #endif // create a gtk-independent surface to draw on cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(cst); // TODO: control_expose: only redraw the part not overlapped by temporary control panel show! // float tb = 8; // fmaxf(10, width/100.0); darktable.control->tabborder = tb; darktable.control->width = width; darktable.control->height = height; GdkRGBA color; GtkStyleContext *context = gtk_widget_get_style_context(widget); gboolean color_found = gtk_style_context_lookup_color (context, "bg_color", &color); if(!color_found) { color.red = 1.0; color.green = 0.0; color.blue = 0.0; color.alpha = 1.0; } gdk_cairo_set_source_rgba(cr, &color); cairo_set_line_width(cr, tb); cairo_rectangle(cr, tb / 2., tb / 2., width - tb, height - tb); cairo_stroke(cr); cairo_set_line_width(cr, 1.5); color_found = gtk_style_context_lookup_color (context, "really_dark_bg_color", &color); if(!color_found) { color.red = 1.0; color.green = 0.0; color.blue = 0.0; color.alpha = 1.0; } gdk_cairo_set_source_rgba(cr, &color); cairo_rectangle(cr, tb, tb, width - 2 * tb, height - 2 * tb); cairo_stroke(cr); cairo_save(cr); cairo_translate(cr, tb, tb); cairo_rectangle(cr, 0, 0, width - 2 * tb, height - 2 * tb); cairo_clip(cr); cairo_new_path(cr); // draw view dt_view_manager_expose(darktable.view_manager, cr, width - 2 * tb, height - 2 * tb, pointerx - tb, pointery - tb); cairo_restore(cr); // draw log message, if any dt_pthread_mutex_lock(&darktable.control->log_mutex); if(darktable.control->log_ack != darktable.control->log_pos) { PangoRectangle ink; PangoLayout *layout; PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc); const float fontsize = DT_PIXEL_APPLY_DPI(14); pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE); pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); layout = pango_cairo_create_layout(cr); pango_layout_set_font_description(layout, desc); pango_layout_set_text(layout, darktable.control->log_message[darktable.control->log_ack], -1); pango_layout_get_pixel_extents(layout, &ink, NULL); const float pad = DT_PIXEL_APPLY_DPI(20.0f), xc = width / 2.0; const float yc = height * 0.85 + DT_PIXEL_APPLY_DPI(10), wd = pad + ink.width * .5f; float rad = DT_PIXEL_APPLY_DPI(14); cairo_set_line_width(cr, 1.); cairo_move_to(cr, xc - wd, yc + rad); for(int k = 0; k < 5; k++) { cairo_arc(cr, xc - wd, yc, rad, M_PI / 2.0, 3.0 / 2.0 * M_PI); cairo_line_to(cr, xc + wd, yc - rad); cairo_arc(cr, xc + wd, yc, rad, 3.0 * M_PI / 2.0, M_PI / 2.0); cairo_line_to(cr, xc - wd, yc + rad); if(k == 0) { color_found = gtk_style_context_lookup_color (context, "selected_bg_color", &color); if(!color_found) { color.red = 1.0; color.green = 0.0; color.blue = 0.0; color.alpha = 1.0; } gdk_cairo_set_source_rgba(cr, &color); cairo_fill_preserve(cr); } cairo_set_source_rgba(cr, 0., 0., 0., 1.0 / (1 + k)); cairo_stroke(cr); rad += .5f; } color_found = gtk_style_context_lookup_color (context, "fg_color", &color); if(!color_found) { color.red = 1.0; color.green = 0.0; color.blue = 0.0; color.alpha = 1.0; } gdk_cairo_set_source_rgba(cr, &color); cairo_move_to(cr, xc - wd + .5f * pad, (yc + 1. / 3. * fontsize) - fontsize); pango_cairo_show_layout(cr, layout); pango_font_description_free(desc); g_object_unref(layout); } // draw busy indicator if(darktable.control->log_busy > 0) { PangoRectangle ink; PangoLayout *layout; PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc); const float fontsize = DT_PIXEL_APPLY_DPI(14); pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE); pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); layout = pango_cairo_create_layout(cr); pango_layout_set_font_description(layout, desc); pango_layout_set_text(layout, _("working.."), -1); pango_layout_get_pixel_extents(layout, &ink, NULL); const float xc = width / 2.0, yc = height * 0.85 - DT_PIXEL_APPLY_DPI(30), wd = ink.width * .5f; cairo_move_to(cr, xc - wd, yc + 1. / 3. * fontsize - fontsize); pango_cairo_layout_path(cr, layout); cairo_set_source_rgb(cr, 0.7, 0.7, 0.7); cairo_fill_preserve(cr); cairo_set_line_width(cr, 0.7); cairo_set_source_rgb(cr, 0.3, 0.3, 0.3); cairo_stroke(cr); pango_font_description_free(desc); g_object_unref(layout); } dt_pthread_mutex_unlock(&darktable.control->log_mutex); cairo_destroy(cr); cairo_t *cr_pixmap = cairo_create(darktable.gui->surface); cairo_set_source_surface(cr_pixmap, cst, 0, 0); cairo_paint(cr_pixmap); cairo_destroy(cr_pixmap); cairo_surface_destroy(cst); return NULL; }
void SaveSummary(const std::string &fname, Result &result, Config &config) { #if 0 const float fnorm = 2.f / sqrtf(result.npoints); const float rnorm = 1.f / sqrtf(2.f / (SQRT3 * result.npoints)); const int csize = 512; // Composition cell size const double dashes[] = { 6.0, 3.0 }; cairo_surface_t *surface = cairo_pdf_surface_create(fname.c_str(), 2*csize, 1.5*csize); cairo_pdf_surface_restrict_to_version(surface, CAIRO_PDF_VERSION_1_4); cairo_t *cr = cairo_create(surface); unsigned char *imgdata = NULL; cairo_surface_t *image = NULL; // Draw points const float radius = 2.0; cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); for (int i = 0; i < result.points.size(); ++i) { float x = result.points[i].x * csize; float y = (1.f - result.points[i].y) * csize; cairo_arc(cr, x, y, radius, 0, TWOPI); cairo_fill(cr); } // Draw radial power reference level cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, dashes, 2, 0); const float rpref = 1.f - (1.f - config.fymin) / (config.fymax - config.fymin); cairo_move_to(cr, csize, csize + rpref*csize/2); cairo_line_to(cr, 2*csize, csize + rpref*csize/2); cairo_stroke(cr); // Draw radial power cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, NULL, 0, 0); for (int i = 0; i < result.rp.size(); ++i) { float x = i / (float) result.rp.size(); float y = 1.f - (result.rp[i] - config.fymin) / (config.fymax - config.fymin); Clamp01(y); if (i == 0) cairo_move_to(cr, csize + x*csize, csize + y*csize/2); else cairo_line_to(cr, csize + x*csize, csize + y*csize/2); } cairo_stroke(cr); // Draw spectrum int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, result.spectrum.width); result.spectrum.GetRGBA(imgdata); image = cairo_image_surface_create_for_data(imgdata, CAIRO_FORMAT_RGB24, result.spectrum.width, result.spectrum.height, stride); cairo_identity_matrix(cr); cairo_translate(cr, csize, 0); cairo_scale(cr, csize / (float) result.spectrum.width, csize / (float) result.spectrum.height); cairo_set_source_surface(cr, image, 0, 0); cairo_paint(cr); // Draw RDF reference level cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0.6, 0.6, 0.6, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, dashes, 2, 0); const float rdfref = 1.f - (1.f - config.rymin) / (config.rymax - config.rymin); cairo_move_to(cr, 0, csize + rdfref*csize/2); cairo_line_to(cr, csize, csize + rdfref*csize/2); cairo_stroke(cr); // Draw RDF cairo_identity_matrix(cr); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_set_line_width(cr, 1.0); cairo_set_dash(cr, NULL, 0, 0); for (int i = 0; i < result.rdf.size(); ++i) { float x = i / (float) result.rdf.size(); float y = 1.f - (result.rdf[i] - config.rymin) / (config.rymax - config.rymin); Clamp01(y); if (i == 0) cairo_move_to(cr, x*csize, csize + y*csize/2); else cairo_line_to(cr, x*csize, csize + y*csize/2); } cairo_stroke(cr); // Draw separators cairo_identity_matrix(cr); cairo_set_line_width(cr, 1.0); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_move_to(cr, 0, csize); cairo_line_to(cr, 2*csize, csize); cairo_stroke(cr); cairo_move_to(cr, csize, 0); cairo_line_to(cr, csize, 1.5*csize); cairo_stroke(cr); // Draw labels cairo_identity_matrix(cr); cairo_set_font_size(cr, 12.0); cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_source_rgba(cr, 0, 0, 0, 1); cairo_move_to(cr, 0.0125 * csize, 1.025 * csize); cairo_show_text(cr, "RDF"); cairo_stroke(cr); cairo_move_to(cr, 1.0125 * csize, 1.025 * csize); cairo_show_text(cr, "Power Spectrum"); cairo_stroke(cr); // Draw stats box #ifdef PSA_HAS_CGAL int nlines = 5; #else int nlines = 4; #endif nlines += (result.nsets > 1); double offset = 0.03; double bsize[] = { 0.33 * csize, (nlines * offset + 0.01) * csize }; double banchor = 0.0125 * csize; cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.7); cairo_rectangle(cr, banchor, banchor, bsize[0], bsize[1]); cairo_fill(cr); // Draw stats and corresponding labels cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); cairo_set_font_size(cr, 12.0); cairo_select_font_face(cr, "monospace", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); const int len = 128; char label[len]; double tanchor[2] = { 1.75 * banchor, 0.9 * banchor }; int i = 1; if (result.nsets > 1) { snprintf(label, len, "Averaged over %d sets", result.nsets); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); cairo_show_text(cr, label); ++i; } snprintf(label, len, "Gbl. Mindist %.5f", result.stats.mindist * rnorm); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); snprintf(label, len, "Avg. Mindist %.5f", result.stats.avgmindist * rnorm); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); #ifdef PSA_HAS_CGAL snprintf(label, len, "Orient. order %.5f", result.stats.orientorder); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); #endif snprintf(label, len, "Eff. Nyquist %.5f", result.stats.effnyquist * fnorm); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); snprintf(label, len, "Oscillations %.5f", result.stats.oscillations); cairo_move_to(cr, tanchor[0], tanchor[1] + i * offset * csize); ++i; cairo_show_text(cr, label); cairo_stroke(cr); // Save and clean up cairo_show_page(cr); cairo_surface_destroy(image); if (imgdata) delete[] imgdata; cairo_destroy(cr); cairo_surface_destroy(surface); #endif }
void render_image(struct window *window, cairo_surface_t *image, enum scaling_mode scaling_mode) { double width = cairo_image_surface_get_width(image); double height = cairo_image_surface_get_height(image); switch (scaling_mode) { case SCALING_MODE_STRETCH: cairo_scale(window->cairo, (double) window->width / width, (double) window->height / height); cairo_set_source_surface(window->cairo, image, 0, 0); break; case SCALING_MODE_FILL: { double window_ratio = (double) window->width / window->height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double) window->width / width; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, 0, (double) window->height/2 / scale - height/2); } else { double scale = (double) window->height / height; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, (double) window->width/2 / scale - width/2, 0); } break; } case SCALING_MODE_FIT: { double window_ratio = (double) window->width / window->height; double bg_ratio = width / height; if (window_ratio > bg_ratio) { double scale = (double) window->height / height; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, (double) window->width/2 / scale - width/2, 0); } else { double scale = (double) window->width / width; cairo_scale(window->cairo, scale, scale); cairo_set_source_surface(window->cairo, image, 0, (double) window->height/2 / scale - height/2); } break; } case SCALING_MODE_CENTER: cairo_set_source_surface(window->cairo, image, (double) window->width/2 - width/2, (double) window->height/2 - height/2); break; case SCALING_MODE_TILE: { cairo_pattern_t *pattern = cairo_pattern_create_for_surface(image); cairo_pattern_set_extend(pattern, CAIRO_EXTEND_REPEAT); cairo_set_source(window->cairo, pattern); break; } } cairo_paint(window->cairo); window_render(window); }
/* 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"); } uint32_t views(dt_lib_module_t *self) { return DT_VIEW_TETHERING; } 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, 5); GtkWidget *box; box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); 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); lib->live_view_zoom = dtgtk_button_new( dtgtk_cairo_paint_zoom, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER); // TODO: see _zoom_live_view_clicked lib->rotate_ccw = dtgtk_button_new(dtgtk_cairo_paint_refresh, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER); lib->rotate_cw = dtgtk_button_new(dtgtk_cairo_paint_refresh, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_UP); lib->flip = dtgtk_togglebutton_new(dtgtk_cairo_paint_flip, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_UP); 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, 5); 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); lib->focus_in_small = dtgtk_button_new(dtgtk_cairo_paint_arrow, CPF_STYLE_FLAT | CPF_DO_NOT_USE_BORDER | CPF_DIRECTION_LEFT); // 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); // 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); 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, 5); 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'); int zoom = 1; float imgwd = 0.90f; if(zoom == 1) { imgwd = .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); if(zoom == 1) { scale = fminf(fminf(w, pw) / (float)buf.width, fminf(h, ph) / (float)buf.height); } else scale = fminf(w * imgwd / (float)buf.width, h * imgwd / (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"); 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) { float 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); } 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); }
void gfxContext::SetSource(gfxASurface *surface, const gfxPoint& offset) { NS_ASSERTION(surface->GetAllowUseAsSource(), "Surface not allowed to be used as source!"); cairo_set_source_surface(mCairo, surface->CairoSurface(), offset.x, offset.y); }
gboolean ly_3lrc_desktop_on_expose_cb (GtkWidget * widget, cairo_t *cr, gpointer data) { gchar desktop_font[1024]="Sans Regular 25"; ly_reg_get("3lrc_desktop_font", "%1024[^\n]", desktop_font); gchar path[1024]; g_snprintf(path,sizeof(path),"%sicon/null.png",LY_GLB_PROG_UIXDIR); if(!desktop_bg) desktop_bg=cairo_image_surface_create_from_png(path); cairo_set_source_surface(cr, desktop_bg, 0, 0); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); int width; int height; width = gtk_widget_get_allocated_width (widget); height = gtk_widget_get_allocated_height (widget); int x=0; int y=height; //鼠标进入 if(flag_notify) { //填充圆角矩形拖动区域 cairo_set_source_rgba(cr,0,0,0,0.3); cairo_move_to (cr, 0 + 5, 0); cairo_line_to (cr, 0 + width - 5, 0); cairo_move_to (cr, 0 + width, 0 + 5); cairo_line_to (cr, 0 + width, 0 + height - 5); cairo_move_to (cr, 0 + width - 5, 0 + height); cairo_line_to (cr, 0 + 5, 0 + height); cairo_move_to (cr, 0, 0 + height - 5); cairo_line_to (cr, 0, 0 + 5); cairo_arc (cr, 0 + 5, 0 + 5, 5, M_PI, 3 * M_PI / 2.0); cairo_arc (cr, 0 + width - 5, 0 + 5, 5, 3 * M_PI / 2, 2 * M_PI); cairo_arc (cr, 0 + width - 5, 0 + height - 5, 5, 0, M_PI / 2); cairo_arc (cr, 0 + 5, 0 + height - 5, 5, M_PI / 2, M_PI); cairo_fill(cr); } if(ly_lrc_get_length()>0) { //计算占空比 gint64 t1=0; gint64 t2=0; LyMdhMetadata *md=NULL; md=ly_pqm_get_current_md(); if(!md) return FALSE; if(ly_lrc_get_index()+1<ly_lrc_get_length()) t1=(ly_lrc_get_array()[ly_lrc_get_index()+1])->time-(ly_lrc_get_array()[ly_lrc_get_index()])->time; else t1=ly_mdh_time_str2int(md->duration)-ly_mdh_time_str2int(md->start)-(ly_lrc_get_array()[ly_lrc_get_index()])->time; t2=ly_aud_get_position_abs()-ly_mdh_time_str2int(md->start)-(ly_lrc_get_array()[ly_lrc_get_index()])->time; if(t1!=0) { x=(int)((t2/(gdouble)t1)*pos_layout[X]); } //画歌词 cairo_set_source_rgb(cr,0,0,0); //确定起始点 if((x>=width/2)&&(pos_layout[X]>width)&&(width<(pos_layout[X]-x)*2)) { cairo_move_to(cr, 0-(x-width/2), 5); x=width/2; } else if((x>=width/2)&&(pos_layout[X]>width)&&(width>=(pos_layout[X]-x)*2)) cairo_move_to(cr, 0-(pos_layout[X]-width), 5); else cairo_move_to(cr, 0, 5); PangoLayout *layout; PangoFontDescription *desc; layout = pango_cairo_create_layout (cr); pango_layout_set_text(layout, ly_lrc_get_array()[ly_lrc_get_index()]->text, -1); desc = pango_font_description_from_string (desktop_font); pango_layout_set_font_description (layout, desc); pango_font_description_free (desc); pango_layout_get_size(layout,&pos_layout[X],&pos_layout[Y]); pos_layout[X]=pos_layout[X]/1000; pango_cairo_update_layout (cr, layout); pango_cairo_layout_path (cr, layout); cairo_clip(cr); g_object_unref (layout); //画背景条 cairo_pattern_t *pat; pat = cairo_pattern_create_linear (0, 0,10.0, 150); cairo_pattern_add_color_stop_rgb (pat, 0.1, 65535/65535.0, 10449/65535.0, 0/65535.0); cairo_pattern_add_color_stop_rgb (pat, 0.5, 65535/65535.0, 61062/65535.0, 0/65535.0); cairo_pattern_add_color_stop_rgb (pat, 0.9, 65535/65535.0, 10449/65535.0, 0/65535.0); //画矩形 if((x>=width/2)&&(pos_layout[X]>width)&&(width<(pos_layout[X]-x)*2)) cairo_rectangle (cr, 0, 0, width/2, y); else if((x>=width/2)&&(pos_layout[X]>width)&&(width>=(pos_layout[X]-x)*2)) cairo_rectangle (cr, 0, 0, width-(pos_layout[X]-x), y); else cairo_rectangle (cr, 0, 0, x, y); cairo_set_source (cr, pat); cairo_fill(cr); cairo_pattern_destroy (pat); pat = cairo_pattern_create_linear (0, 0,10.0, 150); cairo_pattern_add_color_stop_rgb (pat, 0.1, 19532/65535.0, 65535/65535.0, 65535/65535.0); cairo_pattern_add_color_stop_rgb (pat, 0.5, 5539/65535.0, 0/65535.0, 65535/65535.0); cairo_pattern_add_color_stop_rgb (pat, 0.9, 19532/65535.0, 65535/65535.0, 65535/65535.0); //画矩形 if((x>=width/2)&&(pos_layout[X]>width)&&(width<(pos_layout[X]-x)*2)) cairo_rectangle (cr, width/2, 0, width-(width/2), y); else if((x>=width/2)&&(pos_layout[X]>width)&&(width>=(pos_layout[X]-x)*2)) cairo_rectangle (cr, width-(pos_layout[X]-x), 0, pos_layout[X]-x, y); else cairo_rectangle (cr, x, 0, width-x, y); cairo_set_source (cr, pat); cairo_fill(cr); cairo_pattern_destroy (pat); } int lrc_desktop=1; int lrc_desktop_fix=0; if(!ly_reg_get("3lrc_desktop_state", "%d:%d", &lrc_desktop, &lrc_desktop_fix)) { ly_reg_set("3lrc_desktop_state", "%d:%d", lrc_desktop, lrc_desktop_fix); } if(lrc_desktop_fix>0) gtk_widget_set_sensitive(widget,FALSE); else gtk_widget_set_sensitive(widget,TRUE); cairo_region_t *region; if(!(lrc_desktop_fix)) { cairo_rectangle_int_t rect; rect.x=rect.y=0; rect.width=width; rect.height=height; region=cairo_region_create_rectangle(&rect); } else { region=cairo_region_create(); } gdk_window_input_shape_combine_region (gtk_widget_get_window(widget), region, 0, 0); cairo_region_destroy (region); return FALSE; }
static gboolean area_draw_cb(GtkWidget *widget, cairo_t *cr, Window *window) { cairo_set_source_surface(cr, window->surface, 0, 0); cairo_paint(cr); return TRUE; }
/* stereo-phase correlation display */ static bool pc_expose_event(RobWidget* handle, cairo_t* cr, cairo_rectangle_t *ev) { MF2UI* ui = (MF2UI*)GET_HANDLE(handle); if (!ui->sf_nfo && ui->nfo) { PangoFontDescription *fd = pango_font_description_from_string("Sans 10px"); create_text_surface2(&ui->sf_nfo, 12, PC_BOUNDH, 0, PC_TOP, ui->nfo, fd, M_PI * -.5, 7, c_g60); pango_font_description_free(fd); } cairo_save(cr); cairo_translate(cr, 0, rint((ui->m0_height - ui->height) * .5)); cairo_rectangle (cr, ev->x, ev->y, ev->width, ev->height); cairo_clip (cr); /* display phase-correlation */ cairo_set_operator (cr, CAIRO_OPERATOR_OVER); /* PC meter backgroud */ CairoSetSouerceRGBA(ui->c_bg); cairo_rectangle (cr, 0, 0, PC_BOUNDW, PC_BOUNDH); cairo_fill(cr); CairoSetSouerceRGBA(c_blk); cairo_set_line_width(cr, 1.0); rounded_rectangle (cr, PC_LEFT-1, PC_TOP + 1.0, PC_WIDTH+2, PC_HEIGHT - 2.0, 3); cairo_fill_preserve(cr); cairo_save(cr); cairo_clip(cr); /* value */ CairoSetSouerceRGBA(c_glb); const float c = rintf(PC_TOP + PC_BLOCKSIZE * ui->cor); rounded_rectangle (cr, PC_LEFT, c, PC_WIDTH, PC_BLOCK, 4); cairo_fill(cr); /* labels w/ background */ cairo_set_source_surface(cr, ui->sf_pc[0], PC_LEFT, PC_TOP + 5); cairo_paint (cr); cairo_set_source_surface(cr, ui->sf_pc[1], PC_LEFT, PC_TOP + PC_HEIGHT - 25); cairo_paint (cr); cairo_restore(cr); rounded_rectangle (cr, PC_LEFT - .5, PC_TOP + .5, PC_WIDTH + 1, PC_HEIGHT - 1, 3); CairoSetSouerceRGBA(c_g90); cairo_stroke(cr); /* annotations */ cairo_set_operator (cr, CAIRO_OPERATOR_SCREEN); CairoSetSouerceRGBA(c_grd); cairo_set_line_width(cr, 1.0); #define PC_ANNOTATION(YPOS, OFF) \ cairo_move_to(cr, PC_LEFT + OFF, rintf(PC_TOP + YPOS) + 0.5); \ cairo_line_to(cr, PC_LEFT + PC_WIDTH - OFF, rintf(PC_TOP + YPOS) + 0.5);\ cairo_stroke(cr); PC_ANNOTATION(PC_HEIGHT * 0.1, 4.0); PC_ANNOTATION(PC_HEIGHT * 0.2, 4.0); PC_ANNOTATION(PC_HEIGHT * 0.3, 4.0); PC_ANNOTATION(PC_HEIGHT * 0.4, 4.0); PC_ANNOTATION(PC_HEIGHT * 0.6, 4.0); PC_ANNOTATION(PC_HEIGHT * 0.7, 4.0); PC_ANNOTATION(PC_HEIGHT * 0.8, 4.0); PC_ANNOTATION(PC_HEIGHT * 0.9, 4.0); CairoSetSouerceRGBA(c_glr); cairo_set_line_width(cr, 1.5); PC_ANNOTATION(PC_HEIGHT * 0.5, 1.5); cairo_restore(cr); if (ui->sf_nfo) { cairo_rectangle (cr, ev->x, ev->y, ev->width, ev->height); cairo_clip (cr); cairo_set_source_surface(cr, ui->sf_nfo, PC_BOUNDW - 14, 0); cairo_paint (cr); } return TRUE; }
/** * fo_doc_cairo_place_image: * @fo_doc: * @fo_image: * @x: * @y: * @xscale: * @yscale: * * **/ static void fo_doc_cairo_place_image (FoDoc *fo_doc, FoImage *fo_image, gdouble x G_GNUC_UNUSED, gdouble y G_GNUC_UNUSED, gdouble xscale G_GNUC_UNUSED, gdouble yscale G_GNUC_UNUSED) { GdkPixbuf *pixbuf = g_object_ref (fo_pixbuf_get_pixbuf (fo_image)); gint width = gdk_pixbuf_get_width (pixbuf); gint height = gdk_pixbuf_get_height (pixbuf); guchar *gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); int gdk_rowstride = gdk_pixbuf_get_rowstride (pixbuf); int n_channels = gdk_pixbuf_get_n_channels (pixbuf); guchar *cairo_pixels; cairo_format_t format; cairo_surface_t *surface; static const cairo_user_data_key_t key; int j; cairo_translate (FO_DOC_CAIRO (fo_doc)->cr, 0, FO_DOC_CAIRO(fo_doc)->page_height); cairo_save (FO_DOC_CAIRO(fo_doc)->cr); cairo_scale (FO_DOC_CAIRO (fo_doc)->cr, xscale * 72.0 / PIXELS_PER_INCH, yscale * 72.0 / PIXELS_PER_INCH); #if HAVE_LIBRSVG if (g_str_has_suffix( fo_image_get_uri(fo_image), ".svg")) { RsvgHandle *rsvg; GError *error = NULL; g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "rendering %s as SVG\n", fo_image_get_uri(fo_image)); rsvg_init(); rsvg_set_default_dpi_x_y (PIXELS_PER_INCH, PIXELS_PER_INCH); rsvg = rsvg_handle_new_from_file (fo_image_get_uri(fo_image), &error); rsvg_handle_render_cairo (rsvg, FO_DOC_CAIRO(fo_doc)->cr); rsvg_term(); cairo_restore (FO_DOC_CAIRO(fo_doc)->cr); if (error) { g_log (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, error->message); g_error_free (error); } return; } #endif if (n_channels == 3) { format = CAIRO_FORMAT_RGB24; } else { format = CAIRO_FORMAT_ARGB32; } cairo_pixels = g_malloc (4 * width * height); surface = cairo_image_surface_create_for_data ((unsigned char *)cairo_pixels, format, width, height, 4 * width); cairo_surface_set_user_data (surface, &key, cairo_pixels, (cairo_destroy_func_t)g_free); for (j = height; j; j--) { guchar *p = gdk_pixels; guchar *q = cairo_pixels; if (n_channels == 3) { guchar *end = p + 3 * width; while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN q[0] = p[2]; q[1] = p[1]; q[2] = p[0]; #else q[1] = p[0]; q[2] = p[1]; q[3] = p[2]; #endif p += 3; q += 4; } } else { guchar *end = p + 4 * width; guint t1,t2,t3; #define MULT(d,c,a,t) G_STMT_START { t = c * a + 0x7f; d = ((t >> 8) + t) >> 8; } G_STMT_END while (p < end) { #if G_BYTE_ORDER == G_LITTLE_ENDIAN MULT(q[0], p[2], p[3], t1); MULT(q[1], p[1], p[3], t2); MULT(q[2], p[0], p[3], t3); q[3] = p[3]; #else q[0] = p[3]; MULT(q[1], p[0], p[3], t1); MULT(q[2], p[1], p[3], t2); MULT(q[3], p[2], p[3], t3); #endif p += 4; q += 4; } #undef MULT } gdk_pixels += gdk_rowstride; cairo_pixels += 4 * width; } cairo_surface_set_fallback_resolution (surface, PIXELS_PER_INCH, PIXELS_PER_INCH); cairo_set_source_surface (FO_DOC_CAIRO (fo_doc)->cr, surface, 0, 0); cairo_pattern_t *pattern = cairo_get_source (FO_DOC_CAIRO (fo_doc)->cr); cairo_pattern_set_extend (pattern, CAIRO_EXTEND_NONE); cairo_paint (FO_DOC_CAIRO (fo_doc)->cr); cairo_surface_destroy (surface); g_object_unref (pixbuf); cairo_restore (FO_DOC_CAIRO(fo_doc)->cr); }
static gboolean dt_iop_levels_area_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_levels_gui_data_t *c = (dt_iop_levels_gui_data_t *)self->gui_data; dt_iop_levels_params_t *p = (dt_iop_levels_params_t *)self->params; dt_develop_t *dev = darktable.develop; const int inset = DT_GUI_CURVE_EDITOR_INSET; GtkAllocation allocation; gtk_widget_get_allocation(GTK_WIDGET(c->area), &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); float mean_picked_color = *self->picked_color / 100.0; /* we need to save the last picked color to prevent flickering when * changing from one picker to another, as the picked_color value does not * update as rapidly */ if(self->request_color_pick != DT_REQUEST_COLORPICK_OFF && self->color_picker_point[0] >= 0.0f && self->color_picker_point[1] >= 0.0f && self->picked_color_max[0] >= 0.0f && mean_picked_color != c->last_picked_color) { float previous_color[3]; previous_color[0] = p->levels[0]; previous_color[1] = p->levels[1]; previous_color[2] = p->levels[2]; c->last_picked_color = mean_picked_color; if(BLACK == c->current_pick) { if(mean_picked_color > p->levels[1]) { p->levels[0] = p->levels[1] - FLT_EPSILON; } else { p->levels[0] = mean_picked_color; } c->pick_xy_positions[0][0] = self->color_picker_point[0]; c->pick_xy_positions[0][1] = self->color_picker_point[1]; } else if(GREY == c->current_pick) { if(mean_picked_color < p->levels[0] || mean_picked_color > p->levels[2]) { p->levels[1] = p->levels[1]; } else { p->levels[1] = mean_picked_color; } c->pick_xy_positions[1][0] = self->color_picker_point[0]; c->pick_xy_positions[1][1] = self->color_picker_point[1]; } else if(WHITE == c->current_pick) { if(mean_picked_color < p->levels[1]) { p->levels[2] = p->levels[1] + FLT_EPSILON; } else { p->levels[2] = mean_picked_color; } c->pick_xy_positions[2][0] = self->color_picker_point[0]; c->pick_xy_positions[2][1] = self->color_picker_point[1]; } if(previous_color[0] != p->levels[0] || previous_color[1] != p->levels[1] || previous_color[2] != p->levels[2]) { dt_dev_add_history_item(darktable.develop, self, TRUE); } } // clear bg cairo_set_source_rgb(cr, .2, .2, .2); cairo_paint(cr); cairo_translate(cr, inset, inset); width -= 2 * inset; height -= 2 * inset; cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.0)); cairo_set_source_rgb(cr, .1, .1, .1); cairo_rectangle(cr, 0, 0, width, height); cairo_stroke(cr); cairo_set_source_rgb(cr, .3, .3, .3); cairo_rectangle(cr, 0, 0, width, height); cairo_fill(cr); // draw grid cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(.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_vertical_lines(cr, 4, 0, 0, width, height); // Drawing the vertical line indicators cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.)); for(int k = 0; k < 3; k++) { if(k == c->handle_move && c->mouse_x > 0) cairo_set_source_rgb(cr, 1, 1, 1); else cairo_set_source_rgb(cr, .7, .7, .7); cairo_move_to(cr, width * p->levels[k], height); cairo_rel_line_to(cr, 0, -height); cairo_stroke(cr); } // draw x positions cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.)); const float arrw = DT_PIXEL_APPLY_DPI(7.0f); for(int k = 0; k < 3; k++) { switch(k) { case 0: cairo_set_source_rgb(cr, 0, 0, 0); break; case 1: cairo_set_source_rgb(cr, 0.5, 0.5, 0.5); break; default: cairo_set_source_rgb(cr, 1, 1, 1); break; } cairo_move_to(cr, width * p->levels[k], height + inset - 1); cairo_rel_line_to(cr, -arrw * .5f, 0); cairo_rel_line_to(cr, arrw * .5f, -arrw); cairo_rel_line_to(cr, arrw * .5f, arrw); cairo_close_path(cr); if(c->handle_move == k && c->mouse_x > 0) cairo_fill(cr); else cairo_stroke(cr); } cairo_translate(cr, 0, height); // draw lum histogram in background // only if the module is enabled if(self->enabled) { uint32_t *hist = self->histogram; float hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR ? self->histogram_max[0] : logf(1.0 + self->histogram_max[0]); if(hist && hist_max > 0.0f) { cairo_save(cr); cairo_scale(cr, width / 63.0, -(height - DT_PIXEL_APPLY_DPI(5)) / hist_max); cairo_set_source_rgba(cr, .2, .2, .2, 0.5); dt_draw_histogram_8(cr, hist, 0, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR); // TODO: make draw // handle waveform // histograms cairo_restore(cr); } } // Cleaning up cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }
static cairo_test_status_t draw (cairo_t *cr, int width, int height) { cairo_surface_t *surface; uint32_t data[STAMP_WIDTH * STAMP_HEIGHT] = { 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, 0xffffffff, 0xffffffff, 0xffff0000, 0xffff0000, 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff, 0xff00ff00, 0xff00ff00, 0xff0000ff, 0xff0000ff }; int i, j; /* fill with off-white to avoid a separate rgb24 ref image */ cairo_save (cr); cairo_set_source_rgb (cr, .7, .7, .7); cairo_paint (cr); cairo_restore (cr); /* Draw reference lines where the jump should be. */ cairo_move_to (cr, PAD + STEPS / 2 * (STAMP_WIDTH + PAD), 0); cairo_rel_line_to (cr, 0, IMAGE_HEIGHT); cairo_move_to (cr, 0, PAD + STEPS / 2 * (STAMP_HEIGHT + PAD)); cairo_rel_line_to (cr, IMAGE_WIDTH, 0); cairo_set_line_width (cr, 2.0); cairo_stroke (cr); surface = cairo_image_surface_create_for_data ((unsigned char *) data, CAIRO_FORMAT_RGB24, STAMP_WIDTH, STAMP_HEIGHT, STAMP_WIDTH * 4); for (j=0; j < STEPS; j++) { double j_step; for (i=0; i < STEPS; i++) { double i_step; #define GENERATE_REFERENCE_IMAGE 0 #if GENERATE_REFERENCE_IMAGE i_step = i >= STEPS / 2 ? 1 : 0; j_step = j >= STEPS / 2 ? 1 : 0; #else i_step = i * 1.0 / STEPS; j_step = j * 1.0 / STEPS; #endif cairo_save (cr); cairo_set_source_surface (cr, surface, PAD + i * (STAMP_WIDTH + PAD) + i_step, PAD + j * (STAMP_HEIGHT + PAD) + j_step); cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); cairo_paint (cr); cairo_restore (cr); } } cairo_surface_destroy (surface); return CAIRO_TEST_SUCCESS; }
int mikaGlWindow::eventExpose( ) { static XImage *image = NULL; static cairo_t *cairo = NULL; static cairo_surface_t *csurface = NULL; static cairo_surface_t *source = NULL; #ifdef _GLDEBUG printf("mikaGlWindow::eventExpose\n"); #endif XGrabServer(window->dpy); /** csurface = cairo_xlib_surface_create( window->dpy, window->id, DefaultVisual(window->dpy,window->screen), mw, mh ); */ csurface = cairo_image_surface_create_for_data( window->surface, CAIRO_FORMAT_ARGB32, mw, mh, 4*mw ); source = cairo_image_surface_create_for_data( surface->pixels, CAIRO_FORMAT_ARGB32, mw, mh, 4*mw ); printf("\tcheck 01\n"); cairo = cairo_create(csurface); cairo_set_source_surface(cairo, source, 0, 0); cairo_paint(cairo); cairo_destroy(cairo); cairo_surface_destroy(csurface); cairo_surface_destroy(source); printf("\tcheck 02\n"); XPutImage( window->dpy, window->id, XDefaultGC( window->dpy, window->screen ), window->ximage, 0,0,0,0, mw,mh ); XUngrabServer(window->dpy); XFlush(window->dpy); XSync(window->dpy,0); return 0; }
static void demo2 (BroadwayOutput *output) { cairo_t *cr; cairo_surface_t *surface, *old_surface; BroadwayRect rects[2]; double da = 0; int i; broadway_output_new_surface(output, 0, 100, 100, 800, 600); surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 800, 600); old_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 800, 600); cr = cairo_create (old_surface); cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); cairo_rectangle (cr, 0, 0, 800, 600); cairo_fill (cr); cairo_destroy (cr); for (i = 0; i < 100; i++) { cr = cairo_create (surface); cairo_set_source_rgb (cr, 0.8, 0.8, 0.8); cairo_rectangle (cr, 0, 0, 800, 600); cairo_fill (cr); snippet(cr, i); cairo_destroy (cr); if (i == 0) { broadway_output_put_rgb (output, 0, 0, 0, 800, 600, 800*4, cairo_image_surface_get_data(surface) ); broadway_output_show_surface (output, 0); } else { diff_surfaces (surface, old_surface); broadway_output_put_rgba (output, 0, 0, 0, 800, 600, 800*4, cairo_image_surface_get_data(old_surface)); } broadway_output_move_surface (output, 0, 100 + i, 100 + i); rects[0].x = 500; rects[0].y = 0; rects[0].width = 100; rects[0].height = 100; rects[1].x = 600; rects[1].y = 100; rects[1].width = 100; rects[1].height = 100; broadway_output_copy_rectangles (output, 0, rects, 2, 400, 0); broadway_output_flush (output); cr = cairo_create (old_surface); cairo_set_source_surface (cr, surface, 0, 0); cairo_paint (cr); cairo_destroy (cr); da += 10; usleep (50 * 1000); } cairo_surface_destroy (surface); broadway_output_destroy_surface(output, 0); broadway_output_flush (output); }
/** * mate_bg_crossfade_start: * @fade: a #MateBGCrossfade * @window: The #GdkWindow to draw crossfade on * * This function initiates a quick crossfade between two surfaces on * the background of @window. Before initiating the crossfade both * mate_bg_crossfade_set_start_surface() and * mate_bg_crossfade_set_end_surface() need to be called. If animations * are disabled, the crossfade is skipped, and the window background is * set immediately to the end surface. **/ void mate_bg_crossfade_start (MateBGCrossfade *fade, GdkWindow *window) { GSource *source; GMainContext *context; g_return_if_fail (MATE_IS_BG_CROSSFADE (fade)); g_return_if_fail (window != NULL); g_return_if_fail (fade->priv->start_surface != NULL); g_return_if_fail (fade->priv->end_surface != NULL); g_return_if_fail (!mate_bg_crossfade_is_started (fade)); g_return_if_fail (gdk_window_get_window_type (window) != GDK_WINDOW_FOREIGN); /* If drawing is done on the root window, * it is essential to have the root pixmap. */ if (gdk_window_get_window_type (window) == GDK_WINDOW_ROOT) { GdkDisplay *display = gdk_window_get_display (window); cairo_surface_t *surface = get_root_pixmap_id_surface (display); g_return_if_fail (surface != NULL); cairo_surface_destroy (surface); } if (fade->priv->fading_surface != NULL) { cairo_surface_destroy (fade->priv->fading_surface); fade->priv->fading_surface = NULL; } fade->priv->window = window; if (gdk_window_get_window_type (fade->priv->window) != GDK_WINDOW_ROOT) { fade->priv->fading_surface = tile_surface (fade->priv->start_surface, fade->priv->width, fade->priv->height); if (fade->priv->widget != NULL) { g_signal_connect (fade->priv->widget, "draw", (GCallback) on_widget_draw, fade); } } else { cairo_t *cr; GdkDisplay *display = gdk_window_get_display (fade->priv->window); fade->priv->fading_surface = get_root_pixmap_id_surface (display); cr = cairo_create (fade->priv->fading_surface); cairo_set_source_surface (cr, fade->priv->start_surface, 0, 0); cairo_paint (cr); cairo_destroy (cr); } draw_background (fade); source = g_timeout_source_new (1000 / 60.0); g_source_set_callback (source, (GSourceFunc) on_tick, fade, (GDestroyNotify) on_finished); context = g_main_context_default (); fade->priv->timeout_id = g_source_attach (source, context); g_source_unref (source); fade->priv->is_first_frame = TRUE; fade->priv->total_duration = .75; fade->priv->start_time = get_current_time (); }
void ChromeClient::widgetSizeChanged(const IntSize& oldWidgetSize, IntSize newSize) { #if USE(ACCELERATED_COMPOSITING) AcceleratedCompositingContext* compositingContext = m_webView->priv->acceleratedCompositingContext.get(); if (compositingContext->enabled()) { m_webView->priv->acceleratedCompositingContext->resizeRootLayer(newSize); return; } #endif // Grow the backing store by at least 1.5 times the current size. This prevents // lots of unnecessary allocations during an opaque resize. WidgetBackingStore* backingStore = m_webView->priv->backingStore.get(); if (backingStore && oldWidgetSize == newSize) return; if (backingStore) { const IntSize& oldSize = backingStore->size(); if (newSize.width() > oldSize.width()) newSize.setWidth(std::max(newSize.width(), static_cast<int>(oldSize.width() * 1.5))); if (newSize.height() > oldSize.height()) newSize.setHeight(std::max(newSize.height(), static_cast<int>(oldSize.height() * 1.5))); } // If we did not have a backing store before or if the backing store is growing, we need // to reallocate a new one and set it up so that we don't see artifacts while resizing. if (!backingStore || newSize.width() > backingStore->size().width() || newSize.height() > backingStore->size().height()) { OwnPtr<WidgetBackingStore> newBackingStore = createBackingStore(GTK_WIDGET(m_webView), newSize); RefPtr<cairo_t> cr = adoptRef(cairo_create(newBackingStore->cairoSurface())); clearEverywhereInBackingStore(m_webView, cr.get()); // Now we copy the old backing store image over the new cleared surface to prevent // annoying flashing as the widget grows. We do the "real" paint in a timeout // since we don't want to block resizing too long. if (backingStore) { cairo_set_source_surface(cr.get(), backingStore->cairoSurface(), 0, 0); cairo_rectangle(cr.get(), 0, 0, backingStore->size().width(), backingStore->size().height()); cairo_fill(cr.get()); } m_webView->priv->backingStore = newBackingStore.release(); backingStore = m_webView->priv->backingStore.get(); } else if (oldWidgetSize.width() < newSize.width() || oldWidgetSize.height() < newSize.height()) { // The widget is growing, but we did not need to create a new backing store. // We should clear any old data outside of the old widget region. RefPtr<cairo_t> cr = adoptRef(cairo_create(backingStore->cairoSurface())); clipOutOldWidgetArea(cr.get(), oldWidgetSize, newSize); clearEverywhereInBackingStore(m_webView, cr.get()); } // We need to force a redraw and ignore the framerate cap. m_lastDisplayTime = 0; m_dirtyRegion.unite(IntRect(IntPoint(), backingStore->size())); // WebCore timers by default have a lower priority which leads to more artifacts when opaque // resize is on, thus we use g_timeout_add here to force a higher timeout priority. if (!m_repaintSoonSourceId) m_repaintSoonSourceId = g_timeout_add(0, reinterpret_cast<GSourceFunc>(repaintEverythingSoonTimeout), this); }
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_dirty) 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_dirty) { 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; int closeup; float zoom_x, zoom_y; DT_CTL_GET_GLOBAL(zoom, dev_zoom); DT_CTL_GET_GLOBAL(closeup, dev_closeup); DT_CTL_GET_GLOBAL(zoom_x, dev_zoom_x); DT_CTL_GET_GLOBAL(zoom_y, 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, 11); char zoomline[5]; snprintf(zoomline, 5, "%.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, 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 gboolean checker_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_colorchecker_gui_data_t *g = (dt_iop_colorchecker_gui_data_t *)self->gui_data; dt_iop_colorchecker_params_t *p = (dt_iop_colorchecker_params_t *)self->params; 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); // clear bg cairo_set_source_rgb(cr, .2, .2, .2); cairo_paint(cr); const float *picked_mean = self->picked_color; int besti = 0, bestj = 0; cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); int cells_x = 6, cells_y = 4; if(p->num_patches > 24) { cells_x = 7; cells_y = 7; } for(int j = 0; j < cells_y; j++) { for(int i = 0; i < cells_x; i++) { double rgb[3] = { 0.5, 0.5, 0.5 }; // Lab: rgb grey converted to Lab cmsCIELab Lab; const int patch = i + j*cells_x; if(patch >= p->num_patches) continue; Lab.L = p->source_L[patch]; Lab.a = p->source_a[patch]; Lab.b = p->source_b[patch]; if((picked_mean[0] - Lab.L)*(picked_mean[0] - Lab.L) + (picked_mean[1] - Lab.a)*(picked_mean[1] - Lab.a) + (picked_mean[2] - Lab.b)*(picked_mean[2] - Lab.b) < (picked_mean[0] - p->source_L[cells_x*bestj+besti])* (picked_mean[0] - p->source_L[cells_x*bestj+besti])+ (picked_mean[1] - p->source_a[cells_x*bestj+besti])* (picked_mean[1] - p->source_a[cells_x*bestj+besti])+ (picked_mean[2] - p->source_b[cells_x*bestj+besti])* (picked_mean[2] - p->source_b[cells_x*bestj+besti])) { besti = i; bestj = j; } cmsDoTransform(g->xform, &Lab, rgb, 1); cairo_set_source_rgb(cr, rgb[0], rgb[1], rgb[2]); cairo_rectangle(cr, width * i / (float)cells_x, height * j / (float)cells_y, width / (float)cells_x - DT_PIXEL_APPLY_DPI(1), height / (float)cells_y - DT_PIXEL_APPLY_DPI(1)); cairo_fill(cr); if(fabsf(p->target_L[patch] - p->source_L[patch]) > 1e-5f || fabsf(p->target_a[patch] - p->source_a[patch]) > 1e-5f || fabsf(p->target_b[patch] - p->source_b[patch]) > 1e-5f) { cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.)); cairo_set_source_rgb(cr, 0.8, 0.8, 0.8); cairo_rectangle(cr, width * i / (float)cells_x + DT_PIXEL_APPLY_DPI(1), height * j / (float)cells_y + DT_PIXEL_APPLY_DPI(1), width / (float)cells_x - DT_PIXEL_APPLY_DPI(3), height / (float)cells_y - DT_PIXEL_APPLY_DPI(3)); cairo_stroke(cr); cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.)); cairo_set_source_rgb(cr, 0.2, 0.2, 0.2); cairo_rectangle(cr, width * i / (float)cells_x + DT_PIXEL_APPLY_DPI(2), height * j / (float)cells_y + DT_PIXEL_APPLY_DPI(2), width / (float)cells_x - DT_PIXEL_APPLY_DPI(5), height / (float)cells_y - DT_PIXEL_APPLY_DPI(5)); cairo_stroke(cr); } } } // highlight patch that is closest to picked colour, // or the one selected in the combobox. if(self->request_color_pick == DT_REQUEST_COLORPICK_OFF) { int i = dt_bauhaus_combobox_get(g->combobox_patch); besti = i % cells_x; bestj = i / cells_x; g->drawn_patch = cells_x * bestj + besti; } else { // freshly picked, also select it in gui: int pick = self->request_color_pick; g->drawn_patch = cells_x * bestj + besti; darktable.gui->reset = 1; dt_bauhaus_combobox_set(g->combobox_patch, g->drawn_patch); g->patch = g->drawn_patch; self->gui_update(self); darktable.gui->reset = 0; self->request_color_pick = pick; // restore, the combobox will kill it } cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.)); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_rectangle(cr, width * besti / (float)cells_x + DT_PIXEL_APPLY_DPI(5), height * bestj / (float)cells_y + DT_PIXEL_APPLY_DPI(5), width / (float)cells_x - DT_PIXEL_APPLY_DPI(11), height / (float)cells_y - DT_PIXEL_APPLY_DPI(11)); cairo_stroke(cr); cairo_destroy(cr); cairo_set_source_surface(crf, cst, 0, 0); cairo_paint(crf); cairo_surface_destroy(cst); return TRUE; }
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; }
static gboolean calf_tube_expose (GtkWidget *widget, GdkEventExpose *event) { g_assert(CALF_IS_TUBE(widget)); CalfTube *self = CALF_TUBE(widget); GdkWindow *window = widget->window; GtkStyle *style = gtk_widget_get_style(widget); cairo_t *c = gdk_cairo_create(GDK_DRAWABLE(window)); int ox = 4, oy = 4, inner = 1, pad; int sx = widget->allocation.width - (ox * 2), sy = widget->allocation.height - (oy * 2); if( self->cache_surface == NULL ) { // looks like its either first call or the widget has been resized. // create the cache_surface. cairo_surface_t *window_surface = cairo_get_target( c ); self->cache_surface = cairo_surface_create_similar( window_surface, CAIRO_CONTENT_COLOR, widget->allocation.width, widget->allocation.height ); // And render the meterstuff again. cairo_t *cache_cr = cairo_create( self->cache_surface ); // theme background for reduced width and round borders // if(widget->style->bg_pixmap[0] == NULL) { gdk_cairo_set_source_color(cache_cr,&style->bg[GTK_STATE_NORMAL]); // } else { // gdk_cairo_set_source_pixbuf(cache_cr, GDK_PIXBUF(widget->style->bg_pixmap[0]), widget->allocation.x, widget->allocation.y + 20); // } cairo_paint(cache_cr); // outer (black) pad = 0; cairo_rectangle(cache_cr, pad, pad, sx + ox * 2 - pad * 2, sy + oy * 2 - pad * 2); cairo_set_source_rgb(cache_cr, 0, 0, 0); cairo_fill(cache_cr); // inner (bevel) pad = 1; cairo_rectangle(cache_cr, pad, pad, sx + ox * 2 - pad * 2, sy + oy * 2 - pad * 2); cairo_pattern_t *pat2 = cairo_pattern_create_linear (0, 0, 0, sy + oy * 2 - pad * 2); cairo_pattern_add_color_stop_rgba (pat2, 0, 0.23, 0.23, 0.23, 1); cairo_pattern_add_color_stop_rgba (pat2, 0.5, 0, 0, 0, 1); cairo_set_source (cache_cr, pat2); cairo_fill(cache_cr); cairo_pattern_destroy(pat2); cairo_rectangle(cache_cr, ox, oy, sx, sy); cairo_set_source_rgb (cache_cr, 0, 0, 0); cairo_fill(cache_cr); cairo_surface_t *image; switch(self->direction) { case 1: // vertical switch(self->size) { default: case 1: image = cairo_image_surface_create_from_png (PKGLIBDIR "tubeV1.png"); break; case 2: image = cairo_image_surface_create_from_png (PKGLIBDIR "tubeV2.png"); break; } break; default: case 2: // horizontal switch(self->size) { default: case 1: image = cairo_image_surface_create_from_png (PKGLIBDIR "tubeH1.png"); break; case 2: image = cairo_image_surface_create_from_png (PKGLIBDIR "tubeH2.png"); break; } break; } cairo_set_source_surface (cache_cr, image, widget->allocation.width / 2 - sx / 2 + inner, widget->allocation.height / 2 - sy / 2 + inner); cairo_paint (cache_cr); cairo_surface_destroy (image); cairo_destroy( cache_cr ); } cairo_set_source_surface( c, self->cache_surface, 0,0 ); cairo_paint( c ); // get microseconds timeval tv; gettimeofday(&tv, 0); long time = tv.tv_sec * 1000 * 1000 + tv.tv_usec; // limit to 1.f float value_orig = self->value > 1.f ? 1.f : self->value; value_orig = value_orig < 0.f ? 0.f : value_orig; float value = 0.f; float s = ((float)(time - self->last_falltime) / 1000000.0); float m = self->last_falloff * s * 2.5; self->last_falloff -= m; // new max value? if(value_orig > self->last_falloff) { self->last_falloff = value_orig; } value = self->last_falloff; self->last_falltime = time; self->falling = self->last_falloff > 0.000001; cairo_pattern_t *pat; // draw upper light switch(self->direction) { case 1: // vertical cairo_arc(c, ox + sx * 0.5, oy + sy * 0.2, sx, 0, 2 * M_PI); pat = cairo_pattern_create_radial (ox + sx * 0.5, oy + sy * 0.2, 3, ox + sx * 0.5, oy + sy * 0.2, sx); break; default: case 2: // horizontal cairo_arc(c, ox + sx * 0.8, oy + sy * 0.5, sy, 0, 2 * M_PI); pat = cairo_pattern_create_radial (ox + sx * 0.8, oy + sy * 0.5, 3, ox + sx * 0.8, oy + sy * 0.5, sy); break; } cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, value); cairo_pattern_add_color_stop_rgba (pat, 0.3, 1, 0.8, 0.3, value * 0.4); cairo_pattern_add_color_stop_rgba (pat, 0.31, 0.9, 0.5, 0.1, value * 0.5); cairo_pattern_add_color_stop_rgba (pat, 1, 0.0, 0.2, 0.7, 0); cairo_set_source (c, pat); cairo_fill(c); // draw lower light switch(self->direction) { case 1: // vertical cairo_arc(c, ox + sx * 0.5, oy + sy * 0.75, sx / 2, 0, 2 * M_PI); pat = cairo_pattern_create_radial (ox + sx * 0.5, oy + sy * 0.75, 2, ox + sx * 0.5, oy + sy * 0.75, sx / 2); break; default: case 2: // horizontal cairo_arc(c, ox + sx * 0.25, oy + sy * 0.5, sy / 2, 0, 2 * M_PI); pat = cairo_pattern_create_radial (ox + sx * 0.25, oy + sy * 0.5, 2, ox + sx * 0.25, oy + sy * 0.5, sy / 2); break; } cairo_pattern_add_color_stop_rgba (pat, 0, 1, 1, 1, value); cairo_pattern_add_color_stop_rgba (pat, 0.3, 1, 0.8, 0.3, value * 0.4); cairo_pattern_add_color_stop_rgba (pat, 0.31, 0.9, 0.5, 0.1, value * 0.5); cairo_pattern_add_color_stop_rgba (pat, 1, 0.0, 0.2, 0.7, 0); cairo_set_source (c, pat); cairo_fill(c); cairo_destroy(c); return TRUE; }
gboolean cd_slider_fade_in_out (GldiModuleInstance *myApplet) { myData.iAnimCNT ++; if (myData.iAnimCNT <= myConfig.iNbAnimationStep) // courbe de alpha : \__/ myData.fAnimAlpha = 1. * (myConfig.iNbAnimationStep - myData.iAnimCNT) / myConfig.iNbAnimationStep; else if (myData.iAnimCNT <= 1.5 * myConfig.iNbAnimationStep) { return TRUE; // on ne fait rien, texture inchangee. } else myData.fAnimAlpha = 1. * (myData.iAnimCNT - 1.5 * myConfig.iNbAnimationStep) / myConfig.iNbAnimationStep; if (CD_APPLET_MY_CONTAINER_IS_OPENGL) { CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN (FALSE); if (myData.iAnimCNT < myConfig.iNbAnimationStep && myData.iPrevTexture != 0) // image precedente en train de disparaitre { //On empeche la transparence _cd_slider_add_background_to_prev_slide_opengl (myApplet, 0., 0., myData.fAnimAlpha); //Image glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f (1., 1., 1., myData.fAnimAlpha); cairo_dock_apply_texture_at_size (myData.iPrevTexture, myData.prevSlideArea.fImgW, myData.prevSlideArea.fImgH); } else if (myData.iAnimCNT > myConfig.iNbAnimationStep) // image courante en train d'apparaitre. { //On empeche la transparence _cd_slider_add_background_to_current_slide_opengl (myApplet, 0., 0., myData.fAnimAlpha); //Image glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColor4f (1., 1., 1., myData.fAnimAlpha); cairo_dock_apply_texture_at_size (myData.iTexture, myData.slideArea.fImgW, myData.slideArea.fImgH); } glDisable (GL_TEXTURE_2D); glDisable (GL_BLEND); CD_APPLET_FINISH_DRAWING_MY_ICON; } else { CD_APPLET_START_DRAWING_MY_ICON_OR_RETURN_CAIRO (FALSE); //On efface le fond ///_cd_slider_erase_surface (myApplet); if (myData.iAnimCNT < myConfig.iNbAnimationStep) // image precedente en train de disparaitre { //On empeche la transparence _cd_slider_add_background_to_prev_slide (myApplet, myData.prevSlideArea.fImgX, myData.prevSlideArea.fImgY, myData.fAnimAlpha); //Image cairo_set_source_surface (myDrawContext, myData.pPrevCairoSurface, myData.prevSlideArea.fImgX, myData.prevSlideArea.fImgY); } else if (myData.iAnimCNT > myConfig.iNbAnimationStep) // image courante en train d'apparaitre. { //On empeche la transparence _cd_slider_add_background_to_current_slide (myApplet, myData.slideArea.fImgX, myData.slideArea.fImgY, myData.fAnimAlpha); //Image cairo_set_source_surface (myDrawContext, myData.pCairoSurface, myData.slideArea.fImgX, myData.slideArea.fImgY); } cairo_paint_with_alpha (myDrawContext, myData.fAnimAlpha); CD_APPLET_FINISH_DRAWING_MY_ICON_CAIRO; } return (myData.fAnimAlpha < .99); }
static void gimp_view_render_temp_buf_to_surface (GimpViewRenderer *renderer, GtkWidget *widget, GimpTempBuf *temp_buf, gint temp_buf_x, gint temp_buf_y, gint channel, GimpViewBG inside_bg, GimpViewBG outside_bg, cairo_surface_t *surface, gint surface_width, gint surface_height) { cairo_t *cr; gint x, y; gint width, height; const Babl *temp_buf_format; gint temp_buf_width; gint temp_buf_height; g_return_if_fail (temp_buf != NULL); g_return_if_fail (surface != NULL); temp_buf_format = gimp_temp_buf_get_format (temp_buf); temp_buf_width = gimp_temp_buf_get_width (temp_buf); temp_buf_height = gimp_temp_buf_get_height (temp_buf); /* Here are the different cases this functions handles correctly: * 1) Offset temp_buf which does not necessarily cover full image area * 2) Color conversion of temp_buf if it is gray and image is color * 3) Background check buffer for transparent temp_bufs * 4) Using the optional "channel" argument, one channel can be extracted * from a multi-channel temp_buf and composited as a grayscale * Prereqs: * 1) Grayscale temp_bufs have bytes == {1, 2} * 2) Color temp_bufs have bytes == {3, 4} * 3) If image is gray, then temp_buf should have bytes == {1, 2} */ cr = cairo_create (surface); if (outside_bg == GIMP_VIEW_BG_CHECKS || inside_bg == GIMP_VIEW_BG_CHECKS) { if (! renderer->pattern) renderer->pattern = gimp_cairo_checkerboard_create (cr, GIMP_CHECK_SIZE_SM, gimp_render_light_check_color (), gimp_render_dark_check_color ()); } switch (outside_bg) { case GIMP_VIEW_BG_CHECKS: cairo_set_source (cr, renderer->pattern); break; case GIMP_VIEW_BG_WHITE: cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); break; } cairo_paint (cr); if (! gimp_rectangle_intersect (0, 0, surface_width, surface_height, temp_buf_x, temp_buf_y, temp_buf_width, temp_buf_height, &x, &y, &width, &height)) { cairo_destroy (cr); return; } if (inside_bg != outside_bg && babl_format_has_alpha (temp_buf_format) && channel == -1) { cairo_rectangle (cr, x, y, width, height); switch (inside_bg) { case GIMP_VIEW_BG_CHECKS: cairo_set_source (cr, renderer->pattern); break; case GIMP_VIEW_BG_WHITE: cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); break; } cairo_fill (cr); } if (babl_format_has_alpha (temp_buf_format) && channel == -1) { GeglBuffer *src_buffer; GeglBuffer *dest_buffer; cairo_surface_t *alpha_surface; alpha_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); src_buffer = gimp_temp_buf_create_buffer (temp_buf); dest_buffer = gimp_cairo_surface_create_buffer (alpha_surface); if (! renderer->profile_transform) gimp_view_renderer_transform_create (renderer, widget, src_buffer, dest_buffer); if (renderer->profile_transform) { gimp_gegl_convert_color_transform (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), renderer->profile_src_format, dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0), renderer->profile_dest_format, renderer->profile_transform); } else { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), GEGL_ABYSS_NONE, dest_buffer, GEGL_RECTANGLE (0, 0, 0, 0)); } g_object_unref (src_buffer); g_object_unref (dest_buffer); cairo_surface_mark_dirty (alpha_surface); cairo_translate (cr, x, y); cairo_rectangle (cr, 0, 0, width, height); cairo_set_source_surface (cr, alpha_surface, 0, 0); cairo_fill (cr); cairo_surface_destroy (alpha_surface); } else if (channel == -1) { GeglBuffer *src_buffer; GeglBuffer *dest_buffer; cairo_surface_flush (surface); src_buffer = gimp_temp_buf_create_buffer (temp_buf); dest_buffer = gimp_cairo_surface_create_buffer (surface); if (! renderer->profile_transform) gimp_view_renderer_transform_create (renderer, widget, src_buffer, dest_buffer); if (renderer->profile_transform) { gimp_gegl_convert_color_transform (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), renderer->profile_src_format, dest_buffer, GEGL_RECTANGLE (x, y, 0, 0), renderer->profile_dest_format, renderer->profile_transform); } else { gegl_buffer_copy (src_buffer, GEGL_RECTANGLE (x - temp_buf_x, y - temp_buf_y, width, height), GEGL_ABYSS_NONE, dest_buffer, GEGL_RECTANGLE (x, y, 0, 0)); } g_object_unref (src_buffer); g_object_unref (dest_buffer); cairo_surface_mark_dirty (surface); } else { const Babl *fish; const guchar *src; guchar *dest; gint dest_stride; gint bytes; gint rowstride; gint i; cairo_surface_flush (surface); bytes = babl_format_get_bytes_per_pixel (temp_buf_format); rowstride = temp_buf_width * bytes; src = gimp_temp_buf_get_data (temp_buf) + ((y - temp_buf_y) * rowstride + (x - temp_buf_x) * bytes); dest = cairo_image_surface_get_data (surface); dest_stride = cairo_image_surface_get_stride (surface); dest += y * dest_stride + x * 4; fish = babl_fish (temp_buf_format, babl_format ("cairo-RGB24")); for (i = y; i < (y + height); i++) { const guchar *s = src; guchar *d = dest; gint j; for (j = x; j < (x + width); j++, d += 4, s += bytes) { if (bytes > 2) { guchar pixel[4] = { s[channel], s[channel], s[channel], 255 }; babl_process (fish, pixel, d, 1); } else { guchar pixel[2] = { s[channel], 255 }; babl_process (fish, pixel, d, 1); } } src += rowstride; dest += dest_stride; } cairo_surface_mark_dirty (surface); } cairo_destroy (cr); }