Exemplo n.º 1
0
void
dt_guides_draw_simple_grid(cairo_t *cr, const float left, const float top,  const float right, const float bottom, float zoom_scale)
{
  // cairo_set_operator(cr, CAIRO_OPERATOR_XOR);
  cairo_set_line_width(cr, 1.0/zoom_scale);
  cairo_set_source_rgb(cr, .2, .2, .2);
  dt_draw_grid(cr, 3, left, top, right, bottom);
  cairo_translate(cr, 1.0/zoom_scale, 1.0/zoom_scale);
  cairo_set_source_rgb(cr, .8, .8, .8);
  dt_draw_grid(cr, 3, left, top, right, bottom);
  cairo_set_source_rgba(cr, .8, .8, .8, 0.5);
  double dashes = 5.0/zoom_scale;
  cairo_set_dash(cr, &dashes, 1, 0);
  dt_draw_grid(cr, 9, left, top, right, bottom);
}
Exemplo n.º 2
0
static void dt_guides_draw_simple_grid(cairo_t *cr, const float x, const float y, const float w,
                                       const float h, float zoom_scale)
{
  float right = x + w;
  float bottom = y + h;
  // cairo_set_operator(cr, CAIRO_OPERATOR_XOR);
  cairo_set_line_width(cr, 1.0 / zoom_scale);
  cairo_set_source_rgb(cr, .2, .2, .2);
  dt_draw_grid(cr, 3, x, y, right, bottom);
  cairo_translate(cr, 1.0 / zoom_scale, 1.0 / zoom_scale);
  cairo_set_source_rgb(cr, .8, .8, .8);
  dt_draw_grid(cr, 3, x, y, right, bottom);
  cairo_set_source_rgba(cr, .8, .8, .8, 0.5);
  double dashes = 5.0 / zoom_scale;
  cairo_set_dash(cr, &dashes, 1, 0);
  dt_draw_grid(cr, 9, x, y, right, bottom);
}
Exemplo n.º 3
0
static gboolean _lib_histogram_draw_callback(GtkWidget *widget, cairo_t *crf, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_histogram_t *d = (dt_lib_histogram_t *)self->data;

  dt_develop_t *dev = darktable.develop;
  uint32_t *hist = dev->histogram;
  float hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR ? dev->histogram_max
                                                                  : logf(1.0 + dev->histogram_max);
  const int inset = DT_HIST_INSET;
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int width = allocation.width, height = allocation.height;
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, allocation.width, allocation.height);

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

  if(d->mode_x == 0)
  {
    d->color_w = 0.06 * width;
    d->button_spacing = 0.01 * width;
    d->button_h = 0.06 * width;
    d->button_y = d->button_spacing;
    d->mode_w = d->color_w;
    d->mode_x = width - 3 * (d->color_w + d->button_spacing) - (d->mode_w + d->button_spacing);
    d->red_x = width - 3 * (d->color_w + d->button_spacing);
    d->green_x = width - 2 * (d->color_w + d->button_spacing);
    d->blue_x = width - (d->color_w + d->button_spacing);
  }

  // TODO: probably this should move to the configure-event callback! That would be future proof if we ever
  // (again) allow to resize the side panels.
  const gint stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);

  // this code assumes that the first expose comes before the first (preview) pipe is processed and that the
  // size of the widget doesn't change!
  if(dev->histogram_waveform_width == 0)
  {
    dev->histogram_waveform = (uint32_t *)calloc(height * stride / 4, sizeof(uint32_t));
    dev->histogram_waveform_stride = stride;
    dev->histogram_waveform_height = height;
    dev->histogram_waveform_width = width;
    //     return TRUE; // there are enough expose events following ...
  }

#if 1
  // draw shadow around
  float alpha = 1.0f;
  cairo_set_line_width(cr, 0.2);
  for(int k = 0; k < inset; k++)
  {
    cairo_rectangle(cr, -k, -k, width + 2 * k, height + 2 * k);
    cairo_set_source_rgba(cr, 0, 0, 0, alpha);
    alpha *= 0.5f;
    cairo_fill(cr);
  }
  cairo_set_line_width(cr, 1.0);
#else
  cairo_set_line_width(cr, 1.0);
  cairo_set_source_rgb(cr, .1, .1, .1);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_stroke(cr);
#endif

  cairo_rectangle(cr, 0, 0, width, height);
  cairo_clip(cr);

  cairo_set_source_rgb(cr, .3, .3, .3);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_fill(cr);
  if(d->highlight == 1)
  {
    cairo_set_source_rgb(cr, .5, .5, .5);
    cairo_rectangle(cr, 0, 0, .2 * width, height);
    cairo_fill(cr);
  }
  else if(d->highlight == 2)
  {
    cairo_set_source_rgb(cr, .5, .5, .5);
    cairo_rectangle(cr, 0.2 * width, 0, width, height);
    cairo_fill(cr);
  }

  // draw grid
  cairo_set_line_width(cr, .4);
  cairo_set_source_rgb(cr, .1, .1, .1);
  if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM)
    dt_draw_waveform_lines(cr, 0, 0, width, height);
  else
    dt_draw_grid(cr, 4, 0, 0, width, height);

  if(hist_max > 0.0f)
  {
    cairo_save(cr);
    if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM)
    {
      // make the color channel selector work:
      uint8_t *buf = (uint8_t *)malloc(sizeof(uint8_t) * height * stride);
      uint8_t mask[3] = { d->blue, d->green, d->red };
      memcpy(buf, dev->histogram_waveform, sizeof(uint8_t) * height * stride);
      for(int y = 0; y < height; y++)
        for(int x = 0; x < width; x++)
          for(int k = 0; k < 3; k++)
          {
            buf[y * stride + x * 4 + k] *= mask[k];
          }

      cairo_surface_t *source
          = cairo_image_surface_create_for_data(buf, CAIRO_FORMAT_ARGB32, width, height, stride);

      cairo_set_source_surface(cr, source, 0.0, 0.0);
      cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
      cairo_paint(cr);
      cairo_surface_destroy(source);
      free(buf);
    }
    else
    {
      // cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
      cairo_translate(cr, 0, height);
      cairo_scale(cr, width / 63.0, -(height - 10) / hist_max);
      cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
      // cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
      cairo_set_line_width(cr, 1.);
      if(d->red)
      {
        cairo_set_source_rgba(cr, 1., 0., 0., 0.2);
        dt_draw_histogram_8(cr, hist, 0, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR);
      }
      if(d->green)
      {
        cairo_set_source_rgba(cr, 0., 1., 0., 0.2);
        dt_draw_histogram_8(cr, hist, 1, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR);
      }
      if(d->blue)
      {
        cairo_set_source_rgba(cr, 0., 0., 1., 0.2);
        dt_draw_histogram_8(cr, hist, 2, dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR);
      }
      cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
      // cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
    }
    cairo_restore(cr);
  }

  cairo_set_source_rgb(cr, .25, .25, .25);
  cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
  PangoLayout *layout;
  PangoRectangle ink;
  PangoFontDescription *desc = pango_font_description_copy_static(darktable.bauhaus->pango_font_desc);
  pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
  layout = pango_cairo_create_layout(cr);
  pango_font_description_set_absolute_size(desc, .1 * height * PANGO_SCALE);
  pango_layout_set_font_description(layout, desc);

  char exifline[50];
  dt_image_print_exif(&dev->image_storage, exifline, 50);
  pango_layout_set_text(layout, exifline, -1);
  pango_layout_get_pixel_extents(layout, &ink, NULL);
  cairo_move_to(cr, .02 * width, .98 * height - ink.height - ink.y);
  cairo_save(cr);
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.0));
  cairo_set_source_rgba(cr, 1, 1, 1, 0.3);
  pango_cairo_layout_path(cr, layout);
  cairo_stroke_preserve(cr);
  cairo_set_source_rgb(cr, .25, .25, .25);
  cairo_fill(cr);
  cairo_restore(cr);

  // buttons to control the display of the histogram: linear/log, r, g, b
  if(d->highlight != 0)
  {
    _draw_mode_toggle(cr, d->mode_x, d->button_y, d->mode_w, d->button_h, dev->histogram_type);
    cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
    _draw_color_toggle(cr, d->red_x, d->button_y, d->color_w, d->button_h, d->red);
    cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.4);
    _draw_color_toggle(cr, d->green_x, d->button_y, d->color_w, d->button_h, d->green);
    cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
    _draw_color_toggle(cr, d->blue_x, d->button_y, d->color_w, d->button_h, d->blue);
  }

  cairo_destroy(cr);
  cairo_set_source_surface(crf, cst, 0, 0);
  cairo_paint(crf);
  cairo_surface_destroy(cst);
  pango_font_description_free(desc);
  g_object_unref(layout);
  return TRUE;
}
Exemplo n.º 4
0
static gboolean dt_iop_tonecurve_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_tonecurve_gui_data_t *c = (dt_iop_tonecurve_gui_data_t *)self->gui_data;
  dt_iop_tonecurve_params_t *p = (dt_iop_tonecurve_params_t *)self->params;
  dt_develop_t *dev = darktable.develop;

  const float color_labels_left[3][3] = { { 0.3f, 0.3f,  0.3f  },
    { 0.0f, 0.34f, 0.27f },
    { 0.0f, 0.27f, 0.58f }
  };

  const float color_labels_right[3][3] = {{ 0.3f, 0.3f, 0.3f   },
    { 0.53f, 0.08f, 0.28f},
    { 0.81f, 0.66f, 0.0f }
  };

  int ch = c->channel;
  int nodes = p->tonecurve_nodes[ch];
  dt_iop_tonecurve_node_t *tonecurve = p->tonecurve[ch];
  int autoscale_ab = p->tonecurve_autoscale_ab;
  if(c->minmax_curve_type[ch] != p->tonecurve_type[ch] || c->minmax_curve_nodes[ch] != p->tonecurve_nodes[ch])
  {
    dt_draw_curve_destroy(c->minmax_curve[ch]);
    c->minmax_curve[ch] = dt_draw_curve_new(0.0, 1.0, p->tonecurve_type[ch]);
    c->minmax_curve_nodes[ch] = p->tonecurve_nodes[ch];
    c->minmax_curve_type[ch] = p->tonecurve_type[ch];
    for(int k=0; k<p->tonecurve_nodes[ch]; k++)
      (void)dt_draw_curve_add_point(c->minmax_curve[ch], p->tonecurve[ch][k].x, p->tonecurve[ch][k].y);
  }
  else
  {
    for(int k=0; k<p->tonecurve_nodes[ch]; k++)
      dt_draw_curve_set_point(c->minmax_curve[ch], k, p->tonecurve[ch][k].x, p->tonecurve[ch][k].y);
  }
  dt_draw_curve_t *minmax_curve = c->minmax_curve[ch];
  dt_draw_curve_calc_values(minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_xs, c->draw_ys);

  const float xm = tonecurve[nodes-1].x;
  const float x[4] = {0.7f*xm, 0.8f*xm, 0.9f*xm, 1.0f*xm};
  const float y[4] = {c->draw_ys[CLAMP((int)(x[0]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)],
                      c->draw_ys[CLAMP((int)(x[1]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)],
                      c->draw_ys[CLAMP((int)(x[2]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)],
                      c->draw_ys[CLAMP((int)(x[3]*DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES-1)]
                     };
  float unbounded_coeffs[3];
  dt_iop_estimate_exp(x, y, 4, unbounded_coeffs);

  const int inset = DT_GUI_CURVE_EDITOR_INSET;
  int width = widget->allocation.width, height = widget->allocation.height;
  cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);
  // clear bg
  cairo_set_source_rgb (cr, .2, .2, .2);
  cairo_paint(cr);

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

#if 0
  // draw shadow around
  float alpha = 1.0f;
  for(int k=0; k<inset; k++)
  {
    cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k);
    cairo_set_source_rgba(cr, 0, 0, 0, alpha);
    alpha *= 0.6f;
    cairo_fill(cr);
  }
#else
  cairo_set_line_width(cr, 1.0);
  cairo_set_source_rgb (cr, .1, .1, .1);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_stroke(cr);
#endif

  cairo_set_source_rgb (cr, .3, .3, .3);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_fill(cr);

  // draw color labels
  const int cells = 8;
  for(int j=0; j<cells; j++)
  {
    for(int i=0; i<cells; i++)
    {
      const float f = (cells-1-j+i)/(2.0f*cells-2.0f);
      cairo_set_source_rgba (cr,
                             (1.0f-f)*color_labels_left[ch][0] + f*color_labels_right[ch][0],
                             (1.0f-f)*color_labels_left[ch][1] + f*color_labels_right[ch][1],
                             (1.0f-f)*color_labels_left[ch][2] + f*color_labels_right[ch][2],
                             .5f); // blend over to make colors darker, so the overlay is more visible
      cairo_rectangle(cr, width*i/(float)cells, height*j/(float)cells, width/(float)cells, height/(float)cells);
      cairo_fill(cr);
    }
  }

  // draw grid
  cairo_set_line_width(cr, .4);
  cairo_set_source_rgb (cr, .1, .1, .1);
  if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM)
    dt_draw_waveform_lines(cr, 0, 0, width, height);
  else
  dt_draw_grid(cr, 4, 0, 0, width, height);

  // if autoscale_ab is on: do not display a and b curves
  if (autoscale_ab && ch != ch_L) goto finally;

  // draw nodes positions
  cairo_set_line_width(cr, 1.);
  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  cairo_translate(cr, 0, height);

  for(int k=0; k<nodes; k++)
  {
    cairo_arc(cr, tonecurve[k].x*width, -tonecurve[k].y*height, 3, 0, 2.*M_PI);
    cairo_stroke(cr);
  }

  // draw selected cursor
  cairo_set_line_width(cr, 1.);

  // draw histogram in background
  // only if module is enabled
  if (self->enabled)
  {
    float *hist, hist_max;
    float *raw_mean, *raw_min, *raw_max;
    float *raw_mean_output;
    float picker_mean[3], picker_min[3], picker_max[3];
    char text[256];

    raw_mean = self->picked_color;
    raw_min = self->picked_color_min;
    raw_max = self->picked_color_max;
    raw_mean_output = self->picked_output_color;

    hist = self->histogram;
    hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR?self->histogram_max[ch]:logf(1.0 + self->histogram_max[ch]);
    if(hist && hist_max > 0)
    {
      cairo_save(cr);
      cairo_scale(cr, width/63.0, -(height-5)/(float)hist_max);
      cairo_set_source_rgba(cr, .2, .2, .2, 0.5);
      dt_draw_histogram_8(cr, hist, ch, dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM?DT_DEV_HISTOGRAM_LOGARITHMIC:dev->histogram_type); // TODO: make draw handle waveform histograms
      cairo_restore(cr);
    }

    if(self->request_color_pick)
    {
      // the global live samples ...
      GSList *samples = darktable.lib->proxy.colorpicker.live_samples;
      dt_colorpicker_sample_t *sample = NULL;
      while(samples)
      {
        sample = samples->data;

        picker_scale(sample->picked_color_lab_mean, picker_mean);
        picker_scale(sample->picked_color_lab_min, picker_min);
        picker_scale(sample->picked_color_lab_max, picker_max);

        cairo_set_source_rgba(cr, 0.5, 0.7, 0.5, 0.15);
        cairo_rectangle(cr, width*picker_min[ch], 0, width*fmax(picker_max[ch]-picker_min[ch], 0.0f), -height);
        cairo_fill(cr);
        cairo_set_source_rgba(cr, 0.5, 0.7, 0.5, 0.5);
        cairo_move_to(cr, width*picker_mean[ch], 0);
        cairo_line_to(cr, width*picker_mean[ch], -height);
        cairo_stroke(cr);

        samples = g_slist_next(samples);
      }

      // ... and the local sample
      picker_scale(raw_mean, picker_mean);
      picker_scale(raw_min, picker_min);
      picker_scale(raw_max, picker_max);

      cairo_set_source_rgba(cr, 0.7, 0.5, 0.5, 0.33);
      cairo_rectangle(cr, width*picker_min[ch], 0, width*fmax(picker_max[ch]-picker_min[ch], 0.0f), -height);
      cairo_fill(cr);
      cairo_set_source_rgba(cr, 0.9, 0.7, 0.7, 0.5);
      cairo_move_to(cr, width*picker_mean[ch], 0);
      cairo_line_to(cr, width*picker_mean[ch], -height);
      cairo_stroke(cr);

      snprintf(text, 256, "%.1f → %.1f", raw_mean[ch], raw_mean_output[ch]);

      cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
      cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
      cairo_set_font_size (cr, 0.06*height);
      cairo_move_to (cr, 0.02f*width, -0.94*height);
      cairo_show_text(cr, text);
      cairo_stroke(cr);
    }
  }

  if(c->selected >= 0)
  {
    cairo_set_source_rgb(cr, .9, .9, .9);
    cairo_arc(cr, tonecurve[c->selected].x*width, -tonecurve[c->selected].y*height, 4, 0, 2.*M_PI);
    cairo_stroke(cr);
  }

  // draw curve
  cairo_set_line_width(cr, 2.);
  cairo_set_source_rgb(cr, .9, .9, .9);
  // cairo_set_line_cap  (cr, CAIRO_LINE_CAP_SQUARE);
  cairo_move_to(cr, 0, -height*c->draw_ys[0]);
  for(int k=1; k<DT_IOP_TONECURVE_RES; k++)
  {
    const float xx = k/(DT_IOP_TONECURVE_RES-1.0);
    if(xx > xm)
    {
      const float yy = dt_iop_eval_exp(unbounded_coeffs, xx);
      cairo_line_to(cr, xx*width, - height*yy);
    }
    else
    {
      cairo_line_to(cr, xx*width, - height*c->draw_ys[k]);
    }
  }
  cairo_stroke(cr);

finally:
  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;
}
Exemplo n.º 5
0
static gboolean lowlight_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
  dt_iop_lowlight_params_t p = *(dt_iop_lowlight_params_t *)self->params;

  dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS - 2] - 1.0,
                          p.transition_y[0]);
  for(int k = 0; k < DT_IOP_LOWLIGHT_BANDS; k++)
    dt_draw_curve_set_point(c->transition_curve, k + 1, p.transition_x[k], p.transition_y[k]);
  dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS + 1, p.transition_x[1] + 1.0,
                          p.transition_y[DT_IOP_LOWLIGHT_BANDS - 1]);

  const int inset = DT_IOP_LOWLIGHT_INSET;
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int width = allocation.width, height = allocation.height;
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  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);
  dt_draw_grid(cr, 8, 0, 0, width, height);


  if(c->mouse_y > 0 || c->dragging)
  {
    // draw min/max curves:
    dt_iop_lowlight_get_params(&p, c->mouse_x, 1., c->mouse_radius);
    dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS - 2] - 1.0,
                            p.transition_y[0]);
    for(int k = 0; k < DT_IOP_LOWLIGHT_BANDS; k++)
      dt_draw_curve_set_point(c->transition_curve, k + 1, p.transition_x[k], p.transition_y[k]);
    dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS + 1, p.transition_x[1] + 1.0,
                            p.transition_y[DT_IOP_LOWLIGHT_BANDS - 1]);
    dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_min_xs,
                              c->draw_min_ys);

    p = *(dt_iop_lowlight_params_t *)self->params;
    dt_iop_lowlight_get_params(&p, c->mouse_x, .0, c->mouse_radius);
    dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS - 2] - 1.0,
                            p.transition_y[0]);
    for(int k = 0; k < DT_IOP_LOWLIGHT_BANDS; k++)
      dt_draw_curve_set_point(c->transition_curve, k + 1, p.transition_x[k], p.transition_y[k]);
    dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS + 1, p.transition_x[1] + 1.0,
                            p.transition_y[DT_IOP_LOWLIGHT_BANDS - 1]);
    dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_max_xs,
                              c->draw_max_ys);
  }

  cairo_save(cr);

  // draw x positions
  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
  const float arrw = DT_PIXEL_APPLY_DPI(7.0f);
  for(int k = 0; k < DT_IOP_LOWLIGHT_BANDS; k++)
  {
    cairo_move_to(cr, width * p.transition_x[k], height + inset - DT_PIXEL_APPLY_DPI(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->x_move == k)
      cairo_fill(cr);
    else
      cairo_stroke(cr);
  }

  // draw selected cursor
  cairo_translate(cr, 0, height);

  // cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
  // cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.));
  cairo_set_source_rgba(cr, .7, .7, .7, 1.0);

  p = *(dt_iop_lowlight_params_t *)self->params;
  dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS - 2] - 1.0,
                          p.transition_y[0]);
  for(int k = 0; k < DT_IOP_LOWLIGHT_BANDS; k++)
    dt_draw_curve_set_point(c->transition_curve, k + 1, p.transition_x[k], p.transition_y[k]);
  dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS + 1, p.transition_x[1] + 1.0,
                          p.transition_y[DT_IOP_LOWLIGHT_BANDS - 1]);
  dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_xs, c->draw_ys);
  cairo_move_to(cr, 0 * width / (float)(DT_IOP_LOWLIGHT_RES - 1), -height * c->draw_ys[0]);
  for(int k = 1; k < DT_IOP_LOWLIGHT_RES; k++)
    cairo_line_to(cr, k * width / (float)(DT_IOP_LOWLIGHT_RES - 1), -height * c->draw_ys[k]);
  cairo_stroke(cr);

  // draw dots on knots
  cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
  for(int k = 0; k < DT_IOP_LOWLIGHT_BANDS; k++)
  {
    cairo_arc(cr, width * p.transition_x[k], -height * p.transition_y[k], DT_PIXEL_APPLY_DPI(3.0), 0.0,
              2.0 * M_PI);
    if(c->x_move == k)
      cairo_fill(cr);
    else
      cairo_stroke(cr);
  }

  if(c->mouse_y > 0 || c->dragging)
  {
    // draw min/max, if selected
    cairo_set_source_rgba(cr, .7, .7, .7, .6);
    cairo_move_to(cr, 0, -height * c->draw_min_ys[0]);
    for(int k = 1; k < DT_IOP_LOWLIGHT_RES; k++)
      cairo_line_to(cr, k * width / (float)(DT_IOP_LOWLIGHT_RES - 1), -height * c->draw_min_ys[k]);
    for(int k = DT_IOP_LOWLIGHT_RES - 1; k >= 0; k--)
      cairo_line_to(cr, k * width / (float)(DT_IOP_LOWLIGHT_RES - 1), -height * c->draw_max_ys[k]);
    cairo_close_path(cr);
    cairo_fill(cr);
    // draw mouse focus circle
    cairo_set_source_rgba(cr, .9, .9, .9, .5);
    const float pos = DT_IOP_LOWLIGHT_RES * c->mouse_x;
    int k = (int)pos;
    const float f = k - pos;
    if(k >= DT_IOP_LOWLIGHT_RES - 1) k = DT_IOP_LOWLIGHT_RES - 2;
    float ht = -height * (f * c->draw_ys[k] + (1 - f) * c->draw_ys[k + 1]);
    cairo_arc(cr, c->mouse_x * width, ht, c->mouse_radius * width, 0, 2. * M_PI);
    cairo_stroke(cr);
  }

  cairo_restore(cr);

  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);

  // draw labels:
  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);
  pango_font_description_set_absolute_size(desc,(.06 * height) * PANGO_SCALE);
  layout = pango_cairo_create_layout(cr);
  pango_layout_set_font_description(layout, desc);
  cairo_set_source_rgb(cr, .1, .1, .1);

  pango_layout_set_text(layout, _("dark"), -1);
  pango_layout_get_pixel_extents(layout, &ink, NULL);
  cairo_move_to(cr, .02 * width - ink.y, .5 * (height + ink.width));
  cairo_save(cr);
  cairo_rotate(cr, -M_PI * .5f);
  pango_cairo_show_layout(cr, layout);
  cairo_restore(cr);

  pango_layout_set_text(layout, _("bright"), -1);
  pango_layout_get_pixel_extents(layout, &ink, NULL);
  cairo_move_to(cr, .98 * width - ink.height, .5 * (height + ink.width));
  cairo_save(cr);
  cairo_rotate(cr, -M_PI * .5f);
  pango_cairo_show_layout(cr, layout);
  cairo_restore(cr);


  pango_layout_set_text(layout, _("day vision"), -1);
  pango_layout_get_pixel_extents(layout, &ink, NULL);
  cairo_move_to(cr, .5 * (width - ink.width), .08 * height - ink.height);
  pango_cairo_show_layout(cr, layout);

  pango_layout_set_text(layout, _("night vision"), -1);
  pango_layout_get_pixel_extents(layout, &ink, NULL);
  cairo_move_to(cr, .5 * (width - ink.width), .97 * height - ink.height);
  pango_cairo_show_layout(cr, layout);

  pango_font_description_free(desc);
  g_object_unref(layout);
  cairo_destroy(cr);
  cairo_set_source_surface(crf, cst, 0, 0);
  cairo_paint(crf);
  cairo_surface_destroy(cst);
  return TRUE;
}
Exemplo n.º 6
0
static gboolean dt_iop_basecurve_draw(GtkWidget *widget, cairo_t *crf, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_basecurve_gui_data_t *c = (dt_iop_basecurve_gui_data_t *)self->gui_data;
  dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)self->params;

  int nodes = p->basecurve_nodes[0];
  dt_iop_basecurve_node_t *basecurve = p->basecurve[0];
  if(c->minmax_curve_type != p->basecurve_type[0] || c->minmax_curve_nodes != p->basecurve_nodes[0])
  {
    dt_draw_curve_destroy(c->minmax_curve);
    c->minmax_curve = dt_draw_curve_new(0.0, 1.0, p->basecurve_type[0]);
    c->minmax_curve_nodes = p->basecurve_nodes[0];
    c->minmax_curve_type = p->basecurve_type[0];
    for(int k = 0; k < p->basecurve_nodes[0]; k++)
      (void)dt_draw_curve_add_point(c->minmax_curve, p->basecurve[0][k].x, p->basecurve[0][k].y);
  }
  else
  {
    for(int k = 0; k < p->basecurve_nodes[0]; k++)
      dt_draw_curve_set_point(c->minmax_curve, k, p->basecurve[0][k].x, p->basecurve[0][k].y);
  }
  dt_draw_curve_t *minmax_curve = c->minmax_curve;
  dt_draw_curve_calc_values(minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_xs, c->draw_ys);

  const float xm = basecurve[nodes - 1].x;
  const float x[4] = { 0.7f * xm, 0.8f * xm, 0.9f * xm, 1.0f * xm };
  const float y[4] = { c->draw_ys[CLAMP((int)(x[0] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)],
                       c->draw_ys[CLAMP((int)(x[1] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)],
                       c->draw_ys[CLAMP((int)(x[2] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)],
                       c->draw_ys[CLAMP((int)(x[3] * DT_IOP_TONECURVE_RES), 0, DT_IOP_TONECURVE_RES - 1)] };
  float unbounded_coeffs[3];
  dt_iop_estimate_exp(x, y, 4, unbounded_coeffs);

  const int inset = DT_GUI_CURVE_EDITOR_INSET;
  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  int width = allocation.width, height = allocation.height;
  cairo_surface_t *cst = dt_cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);
  // clear bg
  cairo_set_source_rgb(cr, .2, .2, .2);
  cairo_paint(cr);

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

#if 0
  // draw shadow around
  float alpha = 1.0f;
  for(int k=0; k<inset; k++)
  {
    cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k);
    cairo_set_source_rgba(cr, 0, 0, 0, alpha);
    alpha *= 0.6f;
    cairo_fill(cr);
  }
#else
  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);
#endif

  cairo_set_source_rgb(cr, .3, .3, .3);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_fill(cr);

  cairo_translate(cr, 0, height);
  cairo_scale(cr, 1.0f, -1.0f);

  // draw grid
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(.4));
  cairo_set_source_rgb(cr, .1, .1, .1);
  if(c->loglogscale)
    dt_draw_loglog_grid(cr, 4, 0, 0, width, height, c->loglogscale);
  else
    dt_draw_grid(cr, 4, 0, 0, width, height);

  // draw nodes positions
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  for(int k = 0; k < nodes; k++)
  {
    const float x = to_log(basecurve[k].x, c->loglogscale), y = to_log(basecurve[k].y, c->loglogscale);
    cairo_arc(cr, x * width, y * height, DT_PIXEL_APPLY_DPI(3), 0, 2. * M_PI);
    cairo_stroke(cr);
  }

  // draw selected cursor
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));

  if(c->selected >= 0)
  {
    cairo_set_source_rgb(cr, .9, .9, .9);
    const float x = to_log(basecurve[c->selected].x, c->loglogscale),
                y = to_log(basecurve[c->selected].y, c->loglogscale);
    cairo_arc(cr, x * width, y * height, DT_PIXEL_APPLY_DPI(4), 0, 2. * M_PI);
    cairo_stroke(cr);
  }

  // draw curve
  cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(2.));
  cairo_set_source_rgb(cr, .9, .9, .9);
  // cairo_set_line_cap  (cr, CAIRO_LINE_CAP_SQUARE);
  cairo_move_to(cr, 0, height * to_log(c->draw_ys[0], c->loglogscale));
  for(int k = 1; k < DT_IOP_TONECURVE_RES; k++)
  {
    const float xx = k / (DT_IOP_TONECURVE_RES - 1.0);
    if(xx > xm)
    {
      const float yy = dt_iop_eval_exp(unbounded_coeffs, xx);
      const float x = to_log(xx, c->loglogscale), y = to_log(yy, c->loglogscale);
      cairo_line_to(cr, x * width, height * y);
    }
    else
    {
      const float yy = c->draw_ys[k];
      const float x = to_log(xx, c->loglogscale), y = to_log(yy, c->loglogscale);
      cairo_line_to(cr, x * width, height * y);
    }
  }
  cairo_stroke(cr);

  cairo_destroy(cr);
  cairo_set_source_surface(crf, cst, 0, 0);
  cairo_paint(crf);
  cairo_surface_destroy(cst);
  return TRUE;
}
Exemplo n.º 7
0
static gboolean dt_iop_tonecurve_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
    dt_iop_module_t *self = (dt_iop_module_t *)user_data;
    dt_iop_tonecurve_gui_data_t *c = (dt_iop_tonecurve_gui_data_t *)self->gui_data;
    dt_iop_tonecurve_params_t *p = (dt_iop_tonecurve_params_t *)self->params;
    for(int k=0; k<6; k++) dt_draw_curve_set_point(c->minmax_curve, k, p->tonecurve_x[k], p->tonecurve_y[k]);
    const int inset = DT_GUI_CURVE_EDITOR_INSET;
    int width = widget->allocation.width, height = widget->allocation.height;
    cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
    cairo_t *cr = cairo_create(cst);
    // clear bg
    cairo_set_source_rgb (cr, .2, .2, .2);
    cairo_paint(cr);

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

#if 0
    // draw shadow around
    float alpha = 1.0f;
    for(int k=0; k<inset; k++)
    {
        cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k);
        cairo_set_source_rgba(cr, 0, 0, 0, alpha);
        alpha *= 0.6f;
        cairo_fill(cr);
    }
#else
    cairo_set_line_width(cr, 1.0);
    cairo_set_source_rgb (cr, .1, .1, .1);
    cairo_rectangle(cr, 0, 0, width, height);
    cairo_stroke(cr);
#endif

    cairo_set_source_rgb (cr, .3, .3, .3);
    cairo_rectangle(cr, 0, 0, width, height);
    cairo_fill(cr);

    if(c->mouse_y > 0 || c->dragging)
    {
        float oldx1, oldy1;
        oldx1 = p->tonecurve_x[c->selected];
        oldy1 = p->tonecurve_y[c->selected];

        if(c->selected == 0) dt_draw_curve_set_point(c->minmax_curve, 1, p->tonecurve_x[1], fmaxf(c->selected_min, p->tonecurve_y[1]));
        if(c->selected == 2) dt_draw_curve_set_point(c->minmax_curve, 1, p->tonecurve_x[1], fminf(c->selected_min, fmaxf(0.0, p->tonecurve_y[1] + DT_GUI_CURVE_INFL*(c->selected_min - oldy1))));
        if(c->selected == 3) dt_draw_curve_set_point(c->minmax_curve, 4, p->tonecurve_x[4], fmaxf(c->selected_min, fminf(1.0, p->tonecurve_y[4] + DT_GUI_CURVE_INFL*(c->selected_min - oldy1))));
        if(c->selected == 5) dt_draw_curve_set_point(c->minmax_curve, 4, p->tonecurve_x[4], fminf(c->selected_min, p->tonecurve_y[4]));
        dt_draw_curve_set_point(c->minmax_curve, c->selected, oldx1, c->selected_min);
        dt_draw_curve_calc_values(c->minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_min_xs, c->draw_min_ys);

        if(c->selected == 0) dt_draw_curve_set_point(c->minmax_curve, 1, p->tonecurve_x[1], fmaxf(c->selected_max, p->tonecurve_y[1]));
        if(c->selected == 2) dt_draw_curve_set_point(c->minmax_curve, 1, p->tonecurve_x[1], fminf(c->selected_max, fmaxf(0.0, p->tonecurve_y[1] + DT_GUI_CURVE_INFL*(c->selected_max - oldy1))));
        if(c->selected == 3) dt_draw_curve_set_point(c->minmax_curve, 4, p->tonecurve_x[4], fmaxf(c->selected_max, fminf(1.0, p->tonecurve_y[4] + DT_GUI_CURVE_INFL*(c->selected_max - oldy1))));
        if(c->selected == 5) dt_draw_curve_set_point(c->minmax_curve, 4, p->tonecurve_x[4], fminf(c->selected_max, p->tonecurve_y[4]));
        dt_draw_curve_set_point  (c->minmax_curve, c->selected, oldx1, c->selected_max);
        dt_draw_curve_calc_values(c->minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_max_xs, c->draw_max_ys);

    }
    for(int k=0; k<6; k++) dt_draw_curve_set_point(c->minmax_curve, k, p->tonecurve_x[k], p->tonecurve_y[k]);
    dt_draw_curve_calc_values(c->minmax_curve, 0.0, 1.0, DT_IOP_TONECURVE_RES, c->draw_xs, c->draw_ys);

    // draw grid
    cairo_set_line_width(cr, .4);
    cairo_set_source_rgb (cr, .1, .1, .1);
    dt_draw_grid(cr, 4, 0, 0, width, height);

    // draw x positions
    cairo_set_line_width(cr, 1.);
    cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
    const float arrw = 7.0f;
    for(int k=1; k<5; k++)
    {
        cairo_move_to(cr, width*p->tonecurve_x[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->x_move == k) cairo_fill(cr);
        else               cairo_stroke(cr);
    }

    // draw selected cursor
    cairo_set_line_width(cr, 1.);
    cairo_translate(cr, 0, height);

    // draw lum h istogram in background
    dt_develop_t *dev = darktable.develop;
    float *hist, hist_max;
    hist = dev->histogram_pre_tonecurve;
    hist_max = dev->histogram_pre_tonecurve_max;
    if(hist_max > 0)
    {
        cairo_save(cr);
        cairo_scale(cr, width/63.0, -(height-5)/(float)hist_max);
        cairo_set_source_rgba(cr, .2, .2, .2, 0.5);
        dt_draw_histogram_8(cr, hist, 3);
        cairo_restore(cr);
    }

    if(c->mouse_y > 0 || c->dragging)
    {
        // draw min/max, if selected
        cairo_set_source_rgba(cr, .6, .6, .6, .5);
        cairo_move_to(cr, 0, - height*c->draw_min_ys[0]);
        for(int k=1; k<DT_IOP_TONECURVE_RES; k++)   cairo_line_to(cr, k*width/(DT_IOP_TONECURVE_RES-1.0), - height*c->draw_min_ys[k]);
        cairo_line_to(cr, width, - height*c->draw_min_ys[DT_IOP_TONECURVE_RES-1]);
        cairo_line_to(cr, width, - height*c->draw_max_ys[DT_IOP_TONECURVE_RES-1]);
        for(int k=DT_IOP_TONECURVE_RES-2; k>=0; k--) cairo_line_to(cr, k*width/(DT_IOP_TONECURVE_RES-1.0), - height*c->draw_max_ys[k]);
        cairo_close_path(cr);
        cairo_fill(cr);
        // draw mouse focus circle
        cairo_set_source_rgb(cr, .9, .9, .9);
        const float pos = MAX(0, (DT_IOP_TONECURVE_RES-1) * c->mouse_x/(float)width - 1);
        int k = (int)pos;
        const float f = k - pos;
        if(k >= DT_IOP_TONECURVE_RES-1) k = DT_IOP_TONECURVE_RES - 2;
        float ht = -height*(f*c->draw_ys[k] + (1-f)*c->draw_ys[k+1]);
        cairo_arc(cr, c->mouse_x, ht, 4, 0, 2.*M_PI);
        cairo_stroke(cr);
    }

    // draw curve
    cairo_set_line_width(cr, 2.);
    cairo_set_source_rgb(cr, .9, .9, .9);
    // cairo_set_line_cap  (cr, CAIRO_LINE_CAP_SQUARE);
    cairo_move_to(cr, 0, -height*c->draw_ys[0]);
    for(int k=1; k<DT_IOP_TONECURVE_RES; k++) cairo_line_to(cr, k*width/(DT_IOP_TONECURVE_RES-1.0), - height*c->draw_ys[k]);
    cairo_stroke(cr);

    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;
}
Exemplo n.º 8
0
static gboolean _lib_histogram_expose_callback(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_histogram_t *d = (dt_lib_histogram_t *)self->data;

  dt_develop_t *dev = darktable.develop;
  float *hist = dev->histogram;
  float hist_max = dev->histogram_type == DT_DEV_HISTOGRAM_LINEAR?dev->histogram_max:logf(1.0 + dev->histogram_max);
  const int inset = DT_HIST_INSET;
  int width = widget->allocation.width, height = widget->allocation.height;
  cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);
  GtkStyle *style=gtk_rc_get_style_by_paths(gtk_settings_get_default(), NULL,"GtkWidget", GTK_TYPE_WIDGET);
  if(!style) style = gtk_rc_get_style(widget);
  cairo_set_source_rgb(cr, style->bg[0].red/65535.0, style->bg[0].green/65535.0, style->bg[0].blue/65535.0);
  cairo_paint(cr);

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

  if(d->mode_x == 0)
  {
    d->color_w = 0.06*width;
    d->button_spacing = 0.01*width;
    d->button_h = 0.06*width;
    d->button_y = d->button_spacing;
    d->mode_w = d->color_w;
    d->mode_x = width - 3*(d->color_w+d->button_spacing) - (d->mode_w+d->button_spacing);
    d->red_x = width - 3*(d->color_w+d->button_spacing);
    d->green_x = width - 2*(d->color_w+d->button_spacing);
    d->blue_x = width - (d->color_w+d->button_spacing);
  }

  // TODO: probably this should move to the configure-event callback! That would be future proof if we ever (again) allow to resize the side panels.
  const gint stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);

  // this code assumes that the first expose comes before the first (preview) pipe is processed and that the size of the widget doesn't change!
  if(dev->histogram_waveform_width == 0)
  {
    dev->histogram_waveform = (uint32_t*)calloc(height * stride / 4, sizeof(uint32_t));
    dev->histogram_waveform_stride = stride;
    dev->histogram_waveform_height = height;
    dev->histogram_waveform_width = width;
//     return TRUE; // there are enough expose events following ...
  }

#if 1
  // draw shadow around
  float alpha = 1.0f;
  cairo_set_line_width(cr, 0.2);
  for(int k=0; k<inset; k++)
  {
    cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k);
    cairo_set_source_rgba(cr, 0, 0, 0, alpha);
    alpha *= 0.5f;
    cairo_fill(cr);
  }
  cairo_set_line_width(cr, 1.0);
#else
  cairo_set_line_width(cr, 1.0);
  cairo_set_source_rgb (cr, .1, .1, .1);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_stroke(cr);
#endif

  cairo_rectangle(cr, 0, 0, width, height);
  cairo_clip(cr);

  cairo_set_source_rgb (cr, .3, .3, .3);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_fill(cr);
  if(d->highlight == 1)
  {
    cairo_set_source_rgb (cr, .5, .5, .5);
    cairo_rectangle(cr, 0, 0, .2*width, height);
    cairo_fill(cr);
  }
  else if(d->highlight == 2)
  {
    cairo_set_source_rgb (cr, .5, .5, .5);
    cairo_rectangle(cr, 0.2*width, 0, width, height);
    cairo_fill(cr);
  }

  // draw grid
  cairo_set_line_width(cr, .4);
  cairo_set_source_rgb (cr, .1, .1, .1);
  if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM)
    dt_draw_waveform_lines(cr, 0, 0, width, height);
  else
    dt_draw_grid(cr, 4, 0, 0, width, height);

  if(hist_max > 0)
  {
    cairo_save(cr);
    if(dev->histogram_type == DT_DEV_HISTOGRAM_WAVEFORM)
    {
      // make the color channel selector work:
      uint8_t *buf = (uint8_t*)malloc(sizeof(uint8_t) * height * stride);
      uint8_t mask[3] = {d->blue, d->green, d->red};
      memcpy(buf, dev->histogram_waveform, sizeof(uint8_t) * height * stride);
      for(int y = 0; y < height; y++)
        for(int x = 0; x < width; x++)
          for(int k = 0; k < 3; k++)
          {
            buf[y * stride + x * 4 + k] *= mask[k];
          }

      cairo_surface_t *source = cairo_image_surface_create_for_data(buf,
                                                CAIRO_FORMAT_ARGB32,
                                                width, height, stride);

      cairo_set_source_surface(cr, source, 0.0, 0.0);
      cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
      cairo_paint(cr);
      cairo_surface_destroy(source);
      free(buf);
    }
    else
    {
      // cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
      cairo_translate(cr, 0, height);
      cairo_scale(cr, width/63.0, -(height-10)/hist_max);
      cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
      // cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
      cairo_set_line_width(cr, 1.);
      if(d->red)
      {
        cairo_set_source_rgba(cr, 1., 0., 0., 0.2);
        dt_draw_histogram_8(cr, hist, 0, dev->histogram_type);
      }
      if(d->green)
      {
        cairo_set_source_rgba(cr, 0., 1., 0., 0.2);
        dt_draw_histogram_8(cr, hist, 1, dev->histogram_type);
      }
      if(d->blue)
      {
        cairo_set_source_rgba(cr, 0., 0., 1., 0.2);
        dt_draw_histogram_8(cr, hist, 2, dev->histogram_type);
      }
      cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
      // cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
    }
    cairo_restore(cr);
  }

  cairo_set_source_rgb(cr, .25, .25, .25);
  cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_font_size (cr, .1*height);

  char exifline[50];
  cairo_move_to (cr, .02*width, .98*height);
  dt_image_print_exif(&dev->image_storage, exifline, 50);
  cairo_save(cr);
  //   cairo_show_text(cr, exifline);
  cairo_set_line_width(cr, 2.0);
  cairo_set_source_rgba(cr, 1, 1, 1, 0.3);
  cairo_text_path(cr, exifline);
  cairo_stroke_preserve(cr);
  cairo_set_source_rgb(cr, .25, .25, .25);
  cairo_fill(cr);
  cairo_restore(cr);

  // buttons to control the display of the histogram: linear/log, r, g, b
  if(d->highlight != 0)
  {
    _draw_mode_toggle(cr, d->mode_x, d->button_y, d->mode_w, d->button_h, dev->histogram_type);
    cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.4);
    _draw_color_toggle(cr, d->red_x, d->button_y, d->color_w, d->button_h, d->red);
    cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.4);
    _draw_color_toggle(cr, d->green_x, d->button_y, d->color_w, d->button_h, d->green);
    cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 0.4);
    _draw_color_toggle(cr, d->blue_x, d->button_y, d->color_w, d->button_h, d->blue);
  }

  cairo_destroy(cr);
  cairo_t *cr_pixmap = gdk_cairo_create(gtk_widget_get_window(widget));
  cairo_set_source_surface (cr_pixmap, cst, 0, 0);
  cairo_paint(cr_pixmap);
  cairo_destroy(cr_pixmap);
  cairo_surface_destroy(cst);
  return TRUE;
}
Exemplo n.º 9
0
static gboolean _lib_histogram_expose_callback(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
  dt_lib_module_t *self = (dt_lib_module_t *)user_data;
  dt_lib_histogram_t *d = (dt_lib_histogram_t *)self->data;

  dt_develop_t *dev = darktable.develop;
  float *hist = dev->histogram;
  float hist_max = dev->histogram_max;
  const int inset = DT_HIST_INSET;
  int width = widget->allocation.width, height = widget->allocation.height;
  cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);
  GtkStyle *style=gtk_rc_get_style_by_paths(gtk_settings_get_default(), NULL,"GtkWidget", GTK_TYPE_WIDGET);
  if(!style) style = gtk_rc_get_style(widget);
  cairo_set_source_rgb(cr, style->bg[0].red/65535.0, style->bg[0].green/65535.0, style->bg[0].blue/65535.0);
  cairo_paint(cr);

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

#if 1
  // draw shadow around
  float alpha = 1.0f;
  cairo_set_line_width(cr, 0.2);
  for(int k=0; k<inset; k++)
  {
    cairo_rectangle(cr, -k, -k, width + 2*k, height + 2*k);
    cairo_set_source_rgba(cr, 0, 0, 0, alpha);
    alpha *= 0.5f;
    cairo_fill(cr);
  }
  cairo_set_line_width(cr, 1.0);
#else
  cairo_set_line_width(cr, 1.0);
  cairo_set_source_rgb (cr, .1, .1, .1);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_stroke(cr);
#endif

  cairo_rectangle(cr, 0, 0, width, height);
  cairo_clip(cr);

  cairo_set_source_rgb (cr, .3, .3, .3);
  cairo_rectangle(cr, 0, 0, width, height);
  cairo_fill(cr);
  if(d->highlight == 1)
  {
    cairo_set_source_rgb (cr, .5, .5, .5);
    cairo_rectangle(cr, 0, 0, .2*width, height);
    cairo_fill(cr);
  }
  else if(d->highlight == 2)
  {
    cairo_set_source_rgb (cr, .5, .5, .5);
    cairo_rectangle(cr, 0.2*width, 0, width, height);
    cairo_fill(cr);
  }

  // draw grid
  cairo_set_line_width(cr, .4);
  cairo_set_source_rgb (cr, .1, .1, .1);
  dt_draw_grid(cr, 4, 0, 0, width, height);

  if(hist_max > 0)
  {
    cairo_save(cr);
    // cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
    cairo_translate(cr, 0, height);
    cairo_scale(cr, width/63.0, -(height-10)/hist_max);
    cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
    // cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
    cairo_set_line_width(cr, 1.);
    cairo_set_source_rgba(cr, 1., 0., 0., 0.2);
    dt_draw_histogram_8(cr, hist, 0);
    cairo_set_source_rgba(cr, 0., 1., 0., 0.2);
    dt_draw_histogram_8(cr, hist, 1);
    cairo_set_source_rgba(cr, 0., 0., 1., 0.2);
    dt_draw_histogram_8(cr, hist, 2);
    cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
    // cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
    cairo_restore(cr);
  }

  cairo_set_source_rgb(cr, .25, .25, .25);
  cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_font_size (cr, .1*height);

  char exifline[50];
  cairo_move_to (cr, .02*width, .98*height);
  dt_image_print_exif(&dev->image_storage, exifline, 50);
  cairo_show_text(cr, exifline);
  /*cairo_text_path(cr, exifline);
  cairo_fill_preserve(cr);
  cairo_set_line_width(cr, 1.0);
  cairo_set_source_rgb(cr, 0.3, 0.3, 0.3);
  cairo_stroke(cr);*/

  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;
}
Exemplo n.º 10
0
static gboolean
lowlight_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_lowlight_gui_data_t *c = (dt_iop_lowlight_gui_data_t *)self->gui_data;
  dt_iop_lowlight_params_t p = *(dt_iop_lowlight_params_t *)self->params;

  dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
  for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++) dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
  dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);

  const int inset = DT_IOP_LOWLIGHT_INSET;
  int width = widget->allocation.width, height = widget->allocation.height;
  cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
  cairo_t *cr = cairo_create(cst);

  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, 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, .4);
  cairo_set_source_rgb (cr, .1, .1, .1);
  dt_draw_grid(cr, 8, 0, 0, width, height);


  if(c->mouse_y > 0 || c->dragging)
  {
    // draw min/max curves:
    dt_iop_lowlight_get_params(&p, c->mouse_x, 1., c->mouse_radius);
    dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
    for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
      dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
    dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
    dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_min_xs, c->draw_min_ys);

    p = *(dt_iop_lowlight_params_t *)self->params;
    dt_iop_lowlight_get_params(&p, c->mouse_x, .0, c->mouse_radius);
    dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
    for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
      dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
    dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
    dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_max_xs, c->draw_max_ys);
  }

  cairo_save(cr);

  // draw x positions
  cairo_set_source_rgb(cr, 0.6, 0.6, 0.6);
  cairo_set_line_width(cr, 1.);
  const float arrw = 7.0f;
  for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
  {
    cairo_move_to(cr, width*p.transition_x[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->x_move == k) cairo_fill(cr);
    else               cairo_stroke(cr);
  }

  // draw selected cursor
  cairo_translate(cr, 0, height);

  // cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
  //cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
  cairo_set_line_width(cr, 2.);
  cairo_set_source_rgba(cr, .7, .7, .7, 1.0);

  p = *(dt_iop_lowlight_params_t *)self->params;
  dt_draw_curve_set_point(c->transition_curve, 0, p.transition_x[DT_IOP_LOWLIGHT_BANDS-2]-1.0, p.transition_y[0]);
  for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
    dt_draw_curve_set_point(c->transition_curve, k+1, p.transition_x[k], p.transition_y[k]);
  dt_draw_curve_set_point(c->transition_curve, DT_IOP_LOWLIGHT_BANDS+1, p.transition_x[1]+1.0, p.transition_y[DT_IOP_LOWLIGHT_BANDS-1]);
  dt_draw_curve_calc_values(c->transition_curve, 0.0, 1.0, DT_IOP_LOWLIGHT_RES, c->draw_xs, c->draw_ys);
  cairo_move_to(cr, 0*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_ys[0]);
  for(int k=1; k<DT_IOP_LOWLIGHT_RES; k++) cairo_line_to(cr, k*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_ys[k]);
  cairo_stroke(cr);

  // draw dots on knots
  cairo_set_source_rgb(cr, 0.7, 0.7, 0.7);
  cairo_set_line_width(cr, 1.);
  for(int k=0; k<DT_IOP_LOWLIGHT_BANDS; k++)
  {
    cairo_arc(cr, width*p.transition_x[k], - height*p.transition_y[k], 3.0, 0.0, 2.0*M_PI);
    if(c->x_move == k) cairo_fill(cr);
    else               cairo_stroke(cr);
  }

  if(c->mouse_y > 0 || c->dragging)
  {
    // draw min/max, if selected
    cairo_set_source_rgba(cr, .7, .7, .7, .6);
    cairo_move_to(cr, 0, - height*c->draw_min_ys[0]);
    for(int k=1; k<DT_IOP_LOWLIGHT_RES; k++)    cairo_line_to(cr, k*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_min_ys[k]);
    for(int k=DT_IOP_LOWLIGHT_RES-1; k>=0; k--) cairo_line_to(cr, k*width/(float)(DT_IOP_LOWLIGHT_RES-1), - height*c->draw_max_ys[k]);
    cairo_close_path(cr);
    cairo_fill(cr);
    // draw mouse focus circle
    cairo_set_source_rgba(cr, .9, .9, .9, .5);
    const float pos = DT_IOP_LOWLIGHT_RES * c->mouse_x;
    int k = (int)pos;
    const float f = k - pos;
    if(k >= DT_IOP_LOWLIGHT_RES-1) k = DT_IOP_LOWLIGHT_RES - 2;
    float ht = -height*(f*c->draw_ys[k] + (1-f)*c->draw_ys[k+1]);
    cairo_arc(cr, c->mouse_x*width, ht, c->mouse_radius*width, 0, 2.*M_PI);
    cairo_stroke(cr);
  }

  cairo_restore (cr);

  cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);

  // draw labels:
  cairo_text_extents_t ext;
  cairo_set_source_rgb(cr, .1, .1, .1);
  cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
  cairo_set_font_size (cr, .06*height);

  cairo_text_extents (cr, _("dark"), &ext);
  cairo_move_to (cr, .02*width+ext.height, .5*(height+ext.width));
  cairo_save (cr);
  cairo_rotate (cr, -M_PI*.5f);
  cairo_show_text(cr, _("dark"));
  cairo_restore (cr);

  cairo_text_extents (cr, _("bright"), &ext);
  cairo_move_to (cr, .98*width, .5*(height+ext.width));
  cairo_save (cr);
  cairo_rotate (cr, -M_PI*.5f);
  cairo_show_text(cr, _("bright"));
  cairo_restore (cr);

  cairo_text_extents (cr, _("day vision"), &ext);
  cairo_move_to (cr, .5*(width-ext.width), .08*height);
  cairo_show_text(cr, _("day vision"));

  cairo_text_extents (cr, _("night vision"), &ext);
  cairo_move_to (cr, .5*(width-ext.width), .97*height);
  cairo_show_text(cr, _("night vision"));


  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;
}