Ejemplo n.º 1
0
static gboolean dt_iop_basecurve_motion_notify(GtkWidget *widget, GdkEventMotion *event, 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 ch = 0;
  int nodes = p->basecurve_nodes[ch];
  dt_iop_basecurve_node_t *basecurve = p->basecurve[ch];

  GtkAllocation allocation;
  gtk_widget_get_allocation(widget, &allocation);
  const int inset = DT_GUI_CURVE_EDITOR_INSET;
  int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset;
  c->mouse_x = CLAMP(event->x - inset, 0, width);
  c->mouse_y = CLAMP(event->y - inset, 0, height);

  const float mx = c->mouse_x / (float)width;
  const float my = 1.0f - c->mouse_y / (float)height;
  const float linx = to_lin(mx, c->loglogscale), liny = to_lin(my, c->loglogscale);

  if(event->state & GDK_BUTTON1_MASK)
  {
    // got a vertex selected:
    if(c->selected >= 0)
    {
      basecurve[c->selected].x = linx;
      basecurve[c->selected].y = liny;

      // delete vertex if order has changed:
      if(nodes > 2)
        if((c->selected > 0 && basecurve[c->selected - 1].x >= linx)
           || (c->selected < nodes - 1 && basecurve[c->selected + 1].x <= linx))
        {
          for(int k = c->selected; k < nodes - 1; k++)
          {
            basecurve[k].x = basecurve[k + 1].x;
            basecurve[k].y = basecurve[k + 1].y;
          }
          c->selected = -2; // avoid re-insertion of that point immediately after this
          p->basecurve_nodes[ch]--;
        }
      dt_dev_add_history_item(darktable.develop, self, TRUE);
    }
    else if(nodes < 20 && c->selected >= -1)
    {
      // no vertex was close, create a new one!
      if(basecurve[0].x > linx)
        c->selected = 0;
      else
        for(int k = 1; k < nodes; k++)
        {
          if(basecurve[k].x > linx)
          {
            c->selected = k;
            break;
          }
        }
      if(c->selected == -1) c->selected = nodes;
      for(int i = nodes; i > c->selected; i--)
      {
        basecurve[i].x = basecurve[i - 1].x;
        basecurve[i].y = basecurve[i - 1].y;
      }
      // found a new point
      basecurve[c->selected].x = linx;
      basecurve[c->selected].y = liny;
      p->basecurve_nodes[ch]++;
      dt_dev_add_history_item(darktable.develop, self, TRUE);
    }
  }
  else
  {
    // minimum area around the node to select it:
    float min = .04f;
    min *= min; // comparing against square
    int nearest = -1;
    for(int k = 0; k < nodes; k++)
    {
      float dist
          = (my - to_log(basecurve[k].y, c->loglogscale)) * (my - to_log(basecurve[k].y, c->loglogscale))
            + (mx - to_log(basecurve[k].x, c->loglogscale)) * (mx - to_log(basecurve[k].x, c->loglogscale));
      if(dist < min)
      {
        min = dist;
        nearest = k;
      }
    }
    c->selected = nearest;
  }
  gtk_widget_queue_draw(widget);
  return TRUE;
}
Ejemplo n.º 2
0
static gboolean dt_iop_basecurve_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
  dt_iop_module_t *self = (dt_iop_module_t *)user_data;
  dt_iop_basecurve_params_t *p = (dt_iop_basecurve_params_t *)self->params;
  dt_iop_basecurve_params_t *d = (dt_iop_basecurve_params_t *)self->default_params;
  dt_iop_basecurve_gui_data_t *c = (dt_iop_basecurve_gui_data_t *)self->gui_data;

  int ch = 0;
  int nodes = p->basecurve_nodes[ch];
  dt_iop_basecurve_node_t *basecurve = p->basecurve[ch];

  if(event->button == 1)
  {
    if(event->type == GDK_BUTTON_PRESS && (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK
      && nodes < MAXNODES && c->selected == -1)
    {
      // if we are not on a node -> add a new node at the current x of the pointer and y of the curve at that x
      const int inset = DT_GUI_CURVE_EDITOR_INSET;
      GtkAllocation allocation;
      gtk_widget_get_allocation(widget, &allocation);
      int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset;
      c->mouse_x = CLAMP(event->x - inset, 0, width);
      c->mouse_y = CLAMP(event->y - inset, 0, height);

      const float mx = c->mouse_x / (float)width;
      const float linx = to_lin(mx, c->loglogscale);

      // don't add a node too close to others in x direction, it can crash dt
      int selected = -1;
      if(basecurve[0].x > linx)
        selected = 0;
      else
      {
        for(int k = 1; k < nodes; k++)
        {
          if(basecurve[k].x > linx)
          {
            selected = k;
            break;
          }
        }
      }
      if(selected == -1) selected = nodes;
      // > 0 -> check distance to left neighbour
      // < nodes -> check distance to right neighbour
      if(!((selected > 0 && linx - basecurve[selected - 1].x <= 0.025) ||
           (selected < nodes && basecurve[selected].x - linx <= 0.025)))
      {
        // evaluate the curve at the current x position
        const float y = dt_draw_curve_calc_value(c->minmax_curve, linx);

        if(y >= 0.0 && y <= 1.0) // never add something outside the viewport, you couldn't change it afterwards
        {
          // create a new node
          int selected = _add_node(basecurve, &p->basecurve_nodes[ch], linx, y);

          // maybe set the new one as being selected
          float min = .04f;
          min *= min; // comparing against square
          for(int k = 0; k < nodes; k++)
          {
            float other_y = to_log(basecurve[k].y, c->loglogscale);
            float dist = (y - other_y) * (y - other_y);
            if(dist < min) c->selected = selected;
          }

          dt_dev_add_history_item(darktable.develop, self, TRUE);
          gtk_widget_queue_draw(self->widget);
        }
      }
      return TRUE;
    }
    else if(event->type == GDK_2BUTTON_PRESS)
    {
      // reset current curve
      p->basecurve_nodes[ch] = d->basecurve_nodes[ch];
      p->basecurve_type[ch] = d->basecurve_type[ch];
      for(int k = 0; k < d->basecurve_nodes[ch]; k++)
      {
        p->basecurve[ch][k].x = d->basecurve[ch][k].x;
        p->basecurve[ch][k].y = d->basecurve[ch][k].y;
      }
      c->selected = -2; // avoid motion notify re-inserting immediately.
      dt_dev_add_history_item(darktable.develop, self, TRUE);
      gtk_widget_queue_draw(self->widget);
      return TRUE;
    }
  }
  return FALSE;
}