static gboolean lowlight_motion_notify(GtkWidget *widget, GdkEventMotion *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; const int inset = DT_IOP_LOWLIGHT_INSET; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int height = allocation.height - 2 * inset, width = allocation.width - 2 * inset; if(!c->dragging) c->mouse_x = CLAMP(event->x - inset, 0, width) / (float)width; c->mouse_y = 1.0 - CLAMP(event->y - inset, 0, height) / (float)height; if(c->dragging) { *p = c->drag_params; if(c->x_move >= 0) { const float mx = CLAMP(event->x - inset, 0, width) / (float)width; if(c->x_move > 0 && c->x_move < DT_IOP_LOWLIGHT_BANDS - 1) { const float minx = p->transition_x[c->x_move - 1] + 0.001f; const float maxx = p->transition_x[c->x_move + 1] - 0.001f; p->transition_x[c->x_move] = fminf(maxx, fmaxf(minx, mx)); } } else { dt_iop_lowlight_get_params(p, c->mouse_x, c->mouse_y + c->mouse_pick, c->mouse_radius); } dt_dev_add_history_item(darktable.develop, self, TRUE); } else if(event->y > height) { c->x_move = 0; float dist = fabs(p->transition_x[0] - c->mouse_x); for(int k = 1; k < DT_IOP_LOWLIGHT_BANDS; k++) { float d2 = fabs(p->transition_x[k] - c->mouse_x); if(d2 < dist) { c->x_move = k; dist = d2; } } } else { c->x_move = -1; } gtk_widget_queue_draw(widget); gint x, y; gdk_window_get_device_position(event->window, gdk_device_manager_get_client_pointer( gdk_display_get_device_manager(gdk_window_get_display(event->window))), &x, &y, NULL); return TRUE; }
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; }
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; }