Пример #1
0
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);
}
Пример #2
0
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;
}
Пример #3
0
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;
    }
}
Пример #4
0
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;
}
Пример #5
0
/* 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);
    }
  }
}
Пример #6
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);
}
Пример #7
0
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);
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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
}
Пример #12
0
Файл: main.c Проект: actics/sway
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);
}
Пример #13
0
/*
    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);
}
Пример #14
0
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);
}
Пример #15
0
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;
}
Пример #16
0
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;
}
Пример #17
0
/* 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;
}
Пример #18
0
/**
 * 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);
}
Пример #19
0
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;
}
Пример #20
0
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;
}
Пример #21
0
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;
}
Пример #22
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);
}
Пример #23
0
/**
 * 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 ();
}
Пример #24
0
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);
}
Пример #25
0
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;
}
Пример #26
0
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;
}
Пример #27
0
static gboolean _lib_navigation_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_navigation_t *d = (dt_lib_navigation_t *)self->data;

  const int inset = DT_NAVIGATION_INSET;
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int width = allocation.width, height = allocation.height;

  dt_develop_t *dev = darktable.develop;

  /* double buffering of image data: only take new data if valid */
  if(dev->preview_pipe->backbuf && dev->preview_status == DT_DEV_PIXELPIPE_VALID)
  {
    /* re-allocate in case of changed image dimensions */
    if(d->buffer == NULL || dev->preview_pipe->backbuf_width != d->wd || dev->preview_pipe->backbuf_height != d->ht)
    {
      g_free(d->buffer);
      d->wd = dev->preview_pipe->backbuf_width;
      d->ht = dev->preview_pipe->backbuf_height;
      d->buffer = g_malloc0((size_t)d->wd * d->ht * 4 * sizeof(unsigned char));
    }

    /* update buffer if new data is available */
    if(d->buffer && dev->preview_pipe->input_timestamp > d->timestamp)
    {
      dt_pthread_mutex_t *mutex = &dev->preview_pipe->backbuf_mutex;
      dt_pthread_mutex_lock(mutex);
      memcpy(d->buffer, dev->preview_pipe->backbuf, (size_t)d->wd * d->ht * 4 * sizeof(unsigned char));
      d->timestamp = dev->preview_pipe->input_timestamp;
      dt_pthread_mutex_unlock(mutex);
    }
  }

  /* get the current style */
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  GtkStyleContext *context = gtk_widget_get_style_context(widget);
  gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);

  width -= 2 * inset;
  height -= 2 * inset;
  cairo_translate(cr, inset, inset);

  /* draw navigation image if available */
  if(d->buffer)
  {
    cairo_save(cr);
    const int wd = d->wd;
    const int ht = d->ht;
    const float scale = fminf(width / (float)wd, height / (float)ht);

    const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wd);
    cairo_surface_t *surface
        = cairo_image_surface_create_for_data(d->buffer, CAIRO_FORMAT_RGB24, wd, ht, stride);
    cairo_translate(cr, width / 2.0, height / 2.0f);
    cairo_scale(cr, scale, scale);
    cairo_translate(cr, -.5f * wd, -.5f * ht);

    // draw shadow around
    float alpha = 1.0f;
    for(int k = 0; k < 4; k++)
    {
      cairo_rectangle(cr, -k / scale, -k / scale, wd + 2 * k / scale, ht + 2 * k / scale);
      cairo_set_source_rgba(cr, 0, 0, 0, alpha);
      alpha *= 0.6f;
      cairo_fill(cr);
    }

    cairo_rectangle(cr, 0, 0, wd - 2, ht - 1);
    cairo_set_source_surface(cr, surface, 0, 0);
    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_FAST);
    cairo_fill(cr);
    cairo_surface_destroy(surface);

    // draw box where we are
    dt_dev_zoom_t zoom = dt_control_get_dev_zoom();
    int closeup = dt_control_get_dev_closeup();
    float zoom_x = dt_control_get_dev_zoom_x();
    float zoom_y = dt_control_get_dev_zoom_y();
    const float min_scale = dt_dev_get_zoom_scale(dev, DT_ZOOM_FIT, closeup ? 2.0 : 1.0, 0);
    const float cur_scale = dt_dev_get_zoom_scale(dev, zoom, closeup ? 2.0 : 1.0, 0);
    // avoid numerical instability for small resolutions:
    double h, w;
    if(cur_scale > min_scale)
    {
      float boxw = 1, boxh = 1;
      dt_dev_check_zoom_bounds(darktable.develop, &zoom_x, &zoom_y, zoom, closeup, &boxw, &boxh);
      cairo_translate(cr, wd * (.5f + zoom_x), ht * (.5f + zoom_y));
      cairo_set_source_rgb(cr, 0., 0., 0.);
      cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.f / scale));
      boxw *= wd;
      boxh *= ht;
      cairo_rectangle(cr, -boxw / 2 - 1, -boxh / 2 - 1, boxw + 2, boxh + 2);
      cairo_stroke(cr);
      cairo_set_source_rgb(cr, 1., 1., 1.);
      cairo_rectangle(cr, -boxw / 2, -boxh / 2, boxw, boxh);
      cairo_stroke(cr);
    }
    cairo_restore(cr);
    if(fabsf(cur_scale - min_scale) > 0.001f)
    {
      /* Zoom % */
      PangoLayout *layout;
      PangoRectangle ink;
      PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
      pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
      layout = pango_cairo_create_layout(cr);
      const float fontsize = DT_PIXEL_APPLY_DPI(11);
      pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE);
      pango_layout_set_font_description(layout, desc);
      cairo_translate(cr, 0, height);
      cairo_set_source_rgba(cr, 1., 1., 1., 0.5);
      cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);

      char zoomline[5];
      snprintf(zoomline, sizeof(zoomline), "%.0f%%", cur_scale * 100);

      pango_layout_set_text(layout, zoomline, -1);
      pango_layout_get_pixel_extents(layout, &ink, NULL);
      h = d->zoom_h = ink.height;
      w = d->zoom_w = ink.width;

      cairo_move_to(cr, width - w - h * 1.1 - ink.x, - fontsize);

      cairo_save(cr);
      cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0));

      GdkRGBA *color;
      gtk_style_context_get(context, gtk_widget_get_state_flags(widget), "background-color", &color, NULL);

      gdk_cairo_set_source_rgba(cr, color);
      pango_cairo_layout_path(cr, layout);
      cairo_stroke_preserve(cr);
      cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
      cairo_fill(cr);
      cairo_restore(cr);

      gdk_rgba_free(color);
      pango_font_description_free(desc);
      g_object_unref(layout);

    }
    else
    {
      // draw the zoom-to-fit icon
      cairo_translate(cr, 0, height);
      cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);

      static int height = -1;
      if(height == -1)
      {
        PangoLayout *layout;
        PangoRectangle ink;
        PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
        pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
        layout = pango_cairo_create_layout(cr);
        pango_font_description_set_absolute_size(desc, DT_PIXEL_APPLY_DPI(11) * PANGO_SCALE);
        pango_layout_set_font_description(layout, desc);
        pango_layout_set_text(layout, "100%", -1); // dummy text, just to get the height
        pango_layout_get_pixel_extents(layout, &ink, NULL);
        height = ink.height;
        pango_font_description_free(desc);
        g_object_unref(layout);
      }

      h = d->zoom_h = height;
      w = h * 1.5;
      float sp = h * 0.6;
      d->zoom_w = w + sp;

      cairo_move_to(cr, width - w - h - sp, -1.0 * h);
      cairo_rectangle(cr, width - w - h - sp, -1.0 * h, w, h);
      cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
      cairo_fill(cr);

      cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0));

      cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
      cairo_move_to(cr, width - w * 0.8 - h - sp, -1.0 * h);
      cairo_line_to(cr, width - w - h - sp, -1.0 * h);
      cairo_line_to(cr, width - w - h - sp, -0.7 * h);
      cairo_stroke(cr);
      cairo_move_to(cr, width - w - h - sp, -0.3 * h);
      cairo_line_to(cr, width - w - h - sp, 0);
      cairo_line_to(cr, width - w * 0.8 - h - sp, 0);
      cairo_stroke(cr);
      cairo_move_to(cr, width - w * 0.2 - h - sp, 0);
      cairo_line_to(cr, width - h - sp, 0);
      cairo_line_to(cr, width - h - sp, -0.3 * h);
      cairo_stroke(cr);
      cairo_move_to(cr, width - h - sp, -0.7 * h);
      cairo_line_to(cr, width - h - sp, -1.0 * h);
      cairo_line_to(cr, width - w * 0.2 - h - sp, -1.0 * h);
      cairo_stroke(cr);
    }

    cairo_move_to(cr, width - 0.95 * h, -0.9 * h);
    cairo_line_to(cr, width - 0.05 * h, -0.9 * h);
    cairo_line_to(cr, width - 0.5 * h, -0.1 * h);
    cairo_fill(cr);
  }

  /* blit memsurface into widget */
  cairo_destroy(cr);
  cairo_set_source_surface(crf, cst, 0, 0);
  cairo_paint(crf);
  cairo_surface_destroy(cst);

  return TRUE;
}
Пример #28
0
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);
}
Пример #30
0
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);
}