51#define DTGTK_GRADIENT_SLIDER_VALUE_CHANGED_DELAY_MAX 50
52#define DTGTK_GRADIENT_SLIDER_VALUE_CHANGED_DELAY_MIN 10
53#define DTGTK_GRADIENT_SLIDER_DEFAULT_INCREMENT 0.01
57#define parent_class _gradient_slider_parent_class
84 if(!GTK_IS_WIDGET(data))
return 0;
88 g_signal_emit_by_name(G_OBJECT(data),
"value-changed");
93 return G_SOURCE_REMOVE;
116 GtkAllocation allocation;
117 gtk_widget_get_allocation(widget, &allocation);
125 GtkAllocation allocation;
126 gtk_widget_get_allocation(widget, &allocation);
146 const gdouble
min = (selected == 0) ? 0.0f : gslider->
position[selected - 1];
147 const gdouble
max = (selected == gslider->
positions - 1) ? 1.0f : gslider->
position[selected + 1];
162 if(lselected < 0) lselected =
k;
163 if(fabs(newposition - gslider->
position[
k]) < fabs(newposition - gslider->
position[lselected]))
172 GtkAllocation allocation;
173 gtk_widget_get_allocation(widget, &allocation);
175 gboolean up = (y <= allocation.height / 2.f);
179 assert(lselected >= 0);
190 gdouble newvalue =
value;
191 gdouble leftnext, rightnext, ms;
197 leftnext = (
k == 0) ? 0.0f : gslider->
position[
k - 1];
203 if(
value < leftnext + ms)
207 if(
value > rightnext - ms)
216 const double vmin = ((
k == 0) ? 0.0f : gslider->
position[0]);
219 newvalue = CLAMP(
value, vmin + ms *
k, vmax - ms * (gslider->
positions - 1 -
k));
224 for(
int i = 1;
i <
k;
i++)
243 if(selected == -1)
return TRUE;
249 gtk_widget_queue_draw(widget);
272 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
TRUE);
274 gtk_widget_queue_draw(widget);
285 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL,
TRUE);
288 gtk_widget_queue_draw(widget);
301 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS && gslider->
is_resettable)
307 gtk_widget_queue_draw(widget);
308 g_signal_emit_by_name(G_OBJECT(widget),
"value-changed");
309 g_signal_emit_by_name(G_OBJECT(widget),
"value-reset");
311 else if((event->button == 1 || event->button == 3) && event->type == GDK_BUTTON_PRESS)
315 assert(lselected >= 0);
316 assert(lselected <= gslider->positions - 1);
318 if(event->button == 1)
341 gtk_widget_queue_draw(widget);
363 gtk_widget_queue_draw(widget);
378 if(gslider->
selected != -1) gtk_widget_grab_focus(widget);
390 if(event->button == 1 && selected != -1 && gslider->
do_reset ==
FALSE)
399 gtk_widget_queue_draw(widget);
403 g_signal_emit_by_name(G_OBJECT(widget),
"value-changed");
416 if(selected == -1)
return TRUE;
418 gtk_widget_grab_focus(widget);
450 if(!handled)
return FALSE;
453 if(selected == -1)
return TRUE;
460 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
475 _signals[
VALUE_CHANGED] = g_signal_new(
"value-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0,
476 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
477 _signals[
VALUE_RESET] = g_signal_new(
"value-reset", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0,
478 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
486 gtk_widget_add_events(widget,
488 GDK_BUTTON_PRESS_MASK |
489 GDK_BUTTON_RELEASE_MASK |
490 GDK_ENTER_NOTIFY_MASK |
491 GDK_LEAVE_NOTIFY_MASK |
493 GDK_KEY_RELEASE_MASK |
494 GDK_POINTER_MOTION_MASK |
497 gtk_widget_set_has_window(widget,
TRUE);
498 gtk_widget_set_can_focus(widget,
TRUE);
505 GtkStyleContext *context = gtk_widget_get_style_context(widget);
506 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
508 GtkBorder margin, border, padding;
510 gtk_style_context_get (context,
state,
"min-height", &css_min_height, NULL);
511 gtk_style_context_get_margin(context,
state, &margin);
512 gtk_style_context_get_border(context,
state, &border);
513 gtk_style_context_get_padding(context,
state, &padding);
514 *min_height = *nat_height = css_min_height + padding.top + padding.bottom + border.top + border.bottom + margin.top + margin.bottom;
521 GtkStyleContext *context = gtk_widget_get_style_context(widget);
522 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
524 GtkBorder margin, border, padding;
526 gtk_style_context_get (context,
state,
"min-width", &css_min_width, NULL);
527 gtk_style_context_get_margin(context,
state, &margin);
528 gtk_style_context_get_border(context,
state, &border);
529 gtk_style_context_get_padding(context,
state, &padding);
530 *min_width = *nat_width = css_min_width + padding.left + padding.right + border.left + border.right + margin.left + margin.right;
563 GtkStyleContext *context = gtk_widget_get_style_context(widget);
564 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
567 gtk_style_context_get_color(context,
state, &color);
569 GtkAllocation allocation;
570 GtkBorder margin, border, padding;
571 gtk_widget_get_allocation(widget, &allocation);
572 gtk_style_context_get_margin(context,
state, &margin);
573 gtk_style_context_get_border(context,
state, &border);
574 gtk_style_context_get_padding(context,
state, &padding);
578 int startx = margin.left;
579 int starty = margin.top;
580 int cwidth = allocation.width - margin.left - margin.right;
581 int cheight = allocation.height - margin.top - margin.bottom;
582 gtk_render_background(context, cr, startx, starty, cwidth, cheight);
583 gtk_render_frame(context, cr, startx, starty, cwidth, cheight);
586 startx += padding.left + border.left;
587 starty += padding.top + border.top;
588 cwidth -= padding.left + padding.right + border.left + border.right;
589 cheight -= padding.top + padding.bottom + border.top + border.bottom;
590 const int y1 = round(0.3f * cheight);
591 const int gheight = cheight - 2 * y1;
596 cairo_pattern_t *gradient = cairo_pattern_create_linear(0, 0, cwidth, 0);
597 for(GList *current = gslider->
colors; current; current = g_list_next(current))
600 cairo_pattern_add_color_stop_rgba(gradient, stop->
position, stop->
color.red, stop->
color.green,
605 cairo_set_line_width(cr, 0.1);
606 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
607 cairo_translate(cr, 0, starty);
608 cairo_set_source(cr, gradient);
609 cairo_rectangle(cr, startx, y1, cwidth, gheight);
612 cairo_pattern_destroy(gradient);
617 cairo_set_source_rgba(cr, color.red, color.green, color.blue, 1.0);
620 if(!isnan(gslider->
picker[0]))
626 cairo_set_source_rgba(cr, color.red, color.green, color.blue, 0.33);
628 cairo_rectangle(cr, vx_min, y1, fmax((
float)vx_max - vx_min, 0.0f), gheight);
631 cairo_set_source_rgba(cr, color.red, color.green, color.blue, 1.0);
633 cairo_move_to(cr, vx_avg, y1);
634 cairo_rel_line_to(cr, 0, gheight);
635 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
636 cairo_set_line_width(cr, 1.0);
643 const int mk = gslider->
marker[
k];
644 const int sz = round((mk & (1 << 3)) ? 1.9f * y1 : 1.4f * y1);
647 cairo_set_source_rgba(cr, color.red, color.green, color.blue, 1.0);
649 cairo_set_source_rgba(cr, color.red * 0.8, color.green * 0.8, color.blue * 0.8, 1.0);
651 cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
712 gslider = g_object_new(_gradient_slider_get_type(), NULL);
722 if (
name) gtk_widget_set_name(widget,
name);
732 gslider = g_object_new(_gradient_slider_get_type(), NULL);
739 memcpy(&gc->
color, &start,
sizeof(GdkRGBA));
745 memcpy(&gc->
color, &end,
sizeof(GdkRGBA));
754 if (
name) gtk_widget_set_name(widget,
name);
775 memcpy(&gc->
color, &color,
sizeof(GdkRGBA));
789 return _gradient_slider_get_type();
794 assert(pos <= gslider->positions);
809 assert(pos <= gslider->positions);
813 if(!
darktable.
gui->
reset) g_signal_emit_by_name(G_OBJECT(gslider),
"value-changed");
814 gtk_widget_queue_draw(GTK_WIDGET(gslider));
824 if(!
darktable.
gui->
reset) g_signal_emit_by_name(G_OBJECT(gslider),
"value-changed");
825 gtk_widget_queue_draw(GTK_WIDGET(gslider));
831 assert(pos <= gslider->positions);
833 gslider->
marker[pos] = mark;
834 gtk_widget_queue_draw(GTK_WIDGET(gslider));
841 gtk_widget_queue_draw(GTK_WIDGET(gslider));
848 assert(pos <= gslider->positions);
856 assert(pos <= gslider->positions);
874 gtk_widget_queue_draw(GTK_WIDGET(gslider));
884 gtk_widget_queue_draw(GTK_WIDGET(gslider));
905 if(old_callback == new_callback)
return;
913 for(
int k = 0;
k < 3;
k++)
918 for(GList *current = gslider->
colors; current; current = g_list_next(current))
925 gtk_widget_queue_draw(GTK_WIDGET(gslider));
940 if (
name) gtk_widget_set_name(widget,
name);
955 if (
name) gtk_widget_set_name(widget,
name);
967 return _gradient_slider_get_type();
1000 gtk_widget_queue_draw(GTK_WIDGET(gslider));
1004 gdouble
min, gdouble
max)
1010 gtk_widget_queue_draw(GTK_WIDGET(gslider));
static const float const float const float min
static void dt_free_gpointer(gpointer ptr)
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
void dtgtk_cairo_paint_triangle(cairo_t *cr, gint x, int y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_solid_triangle(cairo_t *cr, gint x, int y, gint w, gint h, gint flags, void *data)
static guint dt_keys_mainpad_alternatives(const guint key_val)
Remap keypad keys to usual mainpad ones.
void dtgtk_gradient_slider_set_marker(GtkDarktableGradientSlider *gslider, gint mark)
void dtgtk_gradient_slider_multivalue_set_resetvalue(GtkDarktableGradientSlider *gslider, gdouble value, gint pos)
GType dtgtk_gradient_slider_multivalue_get_type()
static gdouble _screen_to_scale(GtkWidget *widget, gint screen)
void dtgtk_gradient_slider_multivalue_set_value(GtkDarktableGradientSlider *gslider, gdouble value, gint pos)
static gint _get_active_marker(GtkDarktableGradientSlider *gslider)
GtkWidget * dtgtk_gradient_slider_new_with_name(gchar *name)
static void _gradient_slider_get_preferred_width(GtkWidget *widget, gint *min_width, gint *nat_width)
void dtgtk_gradient_slider_set_resetvalue(GtkDarktableGradientSlider *gslider, gdouble value)
void dtgtk_gradient_slider_multivalue_set_values(GtkDarktableGradientSlider *gslider, gdouble *values)
static void _gradient_slider_set_defaults(GtkDarktableGradientSlider *gslider)
GtkWidget * dtgtk_gradient_slider_multivalue_new_with_color(GdkRGBA start, GdkRGBA end, gint positions)
static gboolean _gradient_slider_leave_notify_event(GtkWidget *widget, GdkEventCrossing *event)
static gboolean _gradient_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event)
static void _gradient_slider_init(GtkDarktableGradientSlider *gslider)
GtkWidget * dtgtk_gradient_slider_new_with_color_and_name(GdkRGBA start, GdkRGBA end, gchar *name)
GtkWidget * dtgtk_gradient_slider_new_with_color(GdkRGBA start, GdkRGBA end)
static void _clamp_marker(GtkDarktableGradientSlider *gslider, const gint selected)
void dtgtk_gradient_slider_set_value(GtkDarktableGradientSlider *gslider, gdouble value)
void dtgtk_gradient_slider_multivalue_set_increment(GtkDarktableGradientSlider *gslider, gdouble value)
static gdouble _slider_move(GtkWidget *widget, gint k, gdouble value, gint direction)
gint _list_find_by_position(gconstpointer a, gconstpointer b)
static gboolean _gradient_slider_postponed_value_change(gpointer data)
static gint _get_active_marker_from_screen(GtkWidget *widget, const gdouble x, const gdouble y)
void dtgtk_gradient_slider_multivalue_set_picker(GtkDarktableGradientSlider *gslider, gdouble value)
GtkWidget * dtgtk_gradient_slider_new()
gdouble dtgtk_gradient_slider_multivalue_get_value(GtkDarktableGradientSlider *gslider, gint pos)
G_DEFINE_TYPE(GtkDarktableGradientSlider, _gradient_slider, GTK_TYPE_DRAWING_AREA)
void dtgtk_gradient_slider_multivalue_set_markers(GtkDarktableGradientSlider *gslider, gint *markers)
static gint _scale_to_screen(GtkWidget *widget, gdouble scale)
static void _gradient_slider_class_init(GtkDarktableGradientSliderClass *klass)
void dtgtk_gradient_slider_set_picker(GtkDarktableGradientSlider *gslider, gdouble value)
void dtgtk_gradient_slider_multivalue_set_picker_meanminmax(GtkDarktableGradientSlider *gslider, gdouble mean, gdouble min, gdouble max)
void dtgtk_gradient_slider_multivalue_get_values(GtkDarktableGradientSlider *gslider, gdouble *values)
static gboolean _gradient_slider_add_delta_internal(GtkWidget *widget, gdouble delta, guint state, const gint selected)
void dtgtk_gradient_slider_multivalue_clear_stops(GtkDarktableGradientSlider *gslider)
static guint _signals[LAST_SIGNAL]
static gboolean _gradient_slider_button_press(GtkWidget *widget, GdkEventButton *event)
gboolean dtgtk_gradient_slider_multivalue_is_dragging(GtkDarktableGradientSlider *gslider)
static gboolean _gradient_slider_draw(GtkWidget *widget, cairo_t *cr)
static gboolean _gradient_slider_scroll_event(GtkWidget *widget, GdkEventScroll *event)
static gboolean _gradient_slider_button_release(GtkWidget *widget, GdkEventButton *event)
GtkWidget * dtgtk_gradient_slider_multivalue_new(gint positions)
gboolean dtgtk_gradient_slider_is_dragging(GtkDarktableGradientSlider *gslider)
gdouble dtgtk_gradient_slider_get_value(GtkDarktableGradientSlider *gslider)
gdouble dtgtk_gradient_slider_get_resetvalue(GtkDarktableGradientSlider *gslider)
void dtgtk_gradient_slider_set_picker_meanminmax(GtkDarktableGradientSlider *gslider, gdouble mean, gdouble min, gdouble max)
static gboolean _gradient_slider_enter_notify_event(GtkWidget *widget, GdkEventCrossing *event)
void dtgtk_gradient_slider_set_stop(GtkDarktableGradientSlider *gslider, gfloat position, GdkRGBA color)
static gboolean _gradient_slider_key_press_event(GtkWidget *widget, GdkEventKey *event)
GtkWidget * dtgtk_gradient_slider_multivalue_new_with_color_and_name(GdkRGBA start, GdkRGBA end, gint positions, gchar *name)
#define DTGTK_GRADIENT_SLIDER_DEFAULT_INCREMENT
void dtgtk_gradient_slider_multivalue_set_scale_callback(GtkDarktableGradientSlider *gslider, float(*callback)(GtkWidget *self, float value, int dir))
GType dtgtk_gradient_slider_get_type()
void dtgtk_gradient_slider_set_increment(GtkDarktableGradientSlider *gslider, gdouble value)
void dtgtk_gradient_slider_multivalue_set_stop(GtkDarktableGradientSlider *gslider, gfloat position, GdkRGBA color)
static void _gradient_slider_destroy(GtkWidget *widget)
gdouble dtgtk_gradient_slider_multivalue_get_resetvalue(GtkDarktableGradientSlider *gslider, gint pos)
static gboolean _test_if_marker_is_upper_or_down(const gint marker, const gboolean up)
void dtgtk_gradient_slider_multivalue_set_marker(GtkDarktableGradientSlider *gslider, gint mark, gint pos)
void dtgtk_gradient_slider_multivalue_set_resetvalues(GtkDarktableGradientSlider *gslider, gdouble *values)
static gint _get_active_marker_internal(GtkWidget *widget, const gdouble x, const gboolean up)
static gdouble _get_position_from_screen(GtkWidget *widget, const gdouble x)
static void _gradient_slider_get_preferred_height(GtkWidget *widget, gint *min_height, gint *nat_height)
static float _default_linear_scale_callback(GtkWidget *self, float value, int dir)
GtkWidget * dtgtk_gradient_slider_multivalue_new_with_name(gint positions, gchar *name)
#define DTGTK_GRADIENT_SLIDER(obj)
@ GRADIENT_SLIDER_MARKER_UPPER_OPEN
@ GRADIENT_SLIDER_MARKER_UPPER_FILLED
@ GRADIENT_SLIDER_MARKER_LOWER_OPEN
@ GRADIENT_SLIDER_MARKER_UPPER_FILLED_BIG
@ GRADIENT_SLIDER_MARKER_LOWER_OPEN_BIG
@ GRADIENT_SLIDER_MARKER_LOWER_FILLED
@ GRADIENT_SLIDER_MARKER_UPPER_OPEN_BIG
@ GRADIENT_SLIDER_MARKER_LOWER_FILLED_BIG
#define GRADIENT_SLIDER_MAX_POSITIONS
@ GRADIENT_SLIDER_MARGINS_DEFAULT
#define DTGTK_IS_GRADIENT_SLIDER(obj)
gboolean dt_gui_get_scroll_unit_delta(const GdkEventScroll *event, int *delta)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
float *const restrict const size_t k
struct _GtkWidget GtkWidget
const float uint32_t state[4]
float(* scale_callback)(GtkWidget *, float, int)
struct dt_gui_gtk_t * gui
GtkWidget * has_scroll_focus