52#define DTGTK_GRADIENT_SLIDER_VALUE_CHANGED_DELAY_MAX 50
53#define DTGTK_GRADIENT_SLIDER_VALUE_CHANGED_DELAY_MIN 10
54#define DTGTK_GRADIENT_SLIDER_DEFAULT_INCREMENT 0.01
58#define parent_class _gradient_slider_parent_class
85 if(!GTK_IS_WIDGET(data))
return 0;
89 g_signal_emit_by_name(G_OBJECT(data),
"value-changed");
94 return G_SOURCE_REMOVE;
117 GtkAllocation allocation;
118 gtk_widget_get_allocation(widget, &allocation);
126 GtkAllocation allocation;
127 gtk_widget_get_allocation(widget, &allocation);
163 if(lselected < 0) lselected =
k;
164 if(fabs(newposition - gslider->
position[
k]) < fabs(newposition - gslider->
position[lselected]))
173 GtkAllocation allocation;
174 gtk_widget_get_allocation(widget, &allocation);
176 gboolean up = (y <= allocation.height / 2.f);
180 assert(lselected >= 0);
191 gdouble newvalue =
value;
192 gdouble leftnext, rightnext, ms;
198 leftnext = (
k == 0) ? 0.0f : gslider->
position[
k - 1];
204 if(
value < leftnext + ms)
208 if(
value > rightnext - ms)
217 const double vmin = ((
k == 0) ? 0.0f : gslider->
position[0]);
220 newvalue = CLAMP(
value, vmin + ms *
k, vmax - ms * (gslider->
positions - 1 -
k));
225 for(
int i = 1;
i <
k;
i++)
250 gtk_widget_queue_draw(widget);
273 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
TRUE);
275 gtk_widget_queue_draw(widget);
286 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL,
TRUE);
289 gtk_widget_queue_draw(widget);
302 if(event->button == 1 && event->type == GDK_2BUTTON_PRESS && gslider->
is_resettable)
308 gtk_widget_queue_draw(widget);
309 g_signal_emit_by_name(G_OBJECT(widget),
"value-changed");
310 g_signal_emit_by_name(G_OBJECT(widget),
"value-reset");
312 else if((event->button == 1 || event->button == 3) && event->type == GDK_BUTTON_PRESS)
316 assert(lselected >= 0);
317 assert(lselected <= gslider->positions - 1);
319 if(event->button == 1)
342 gtk_widget_queue_draw(widget);
364 gtk_widget_queue_draw(widget);
379 if(gslider->
selected != -1) gtk_widget_grab_focus(widget);
400 gtk_widget_queue_draw(widget);
404 g_signal_emit_by_name(G_OBJECT(widget),
"value-changed");
419 gtk_widget_grab_focus(widget);
451 if(!handled)
return FALSE;
461 GtkWidgetClass *widget_class = (GtkWidgetClass *)klass;
476 _signals[
VALUE_CHANGED] = g_signal_new(
"value-changed", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0,
477 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
478 _signals[
VALUE_RESET] = g_signal_new(
"value-reset", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST, 0,
479 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
487 gtk_widget_add_events(widget,
489 GDK_BUTTON_PRESS_MASK |
490 GDK_BUTTON_RELEASE_MASK |
491 GDK_ENTER_NOTIFY_MASK |
492 GDK_LEAVE_NOTIFY_MASK |
494 GDK_KEY_RELEASE_MASK |
495 GDK_POINTER_MOTION_MASK |
498 gtk_widget_set_has_window(widget,
TRUE);
499 gtk_widget_set_can_focus(widget,
TRUE);
506 GtkStyleContext *context = gtk_widget_get_style_context(widget);
507 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
509 GtkBorder margin, border, padding;
511 gtk_style_context_get (context,
state,
"min-height", &css_min_height, NULL);
512 gtk_style_context_get_margin(context,
state, &margin);
513 gtk_style_context_get_border(context,
state, &border);
514 gtk_style_context_get_padding(context,
state, &padding);
515 *min_height = *nat_height = css_min_height + padding.top + padding.bottom + border.top + border.bottom + margin.top + margin.bottom;
522 GtkStyleContext *context = gtk_widget_get_style_context(widget);
523 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
525 GtkBorder margin, border, padding;
527 gtk_style_context_get (context,
state,
"min-width", &css_min_width, NULL);
528 gtk_style_context_get_margin(context,
state, &margin);
529 gtk_style_context_get_border(context,
state, &border);
530 gtk_style_context_get_padding(context,
state, &padding);
531 *min_width = *nat_width = css_min_width + padding.left + padding.right + border.left + border.right + margin.left + margin.right;
564 GtkStyleContext *context = gtk_widget_get_style_context(widget);
565 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
568 gtk_style_context_get_color(context,
state, &
color);
570 GtkAllocation allocation;
571 GtkBorder margin, border, padding;
572 gtk_widget_get_allocation(widget, &allocation);
573 gtk_style_context_get_margin(context,
state, &margin);
574 gtk_style_context_get_border(context,
state, &border);
575 gtk_style_context_get_padding(context,
state, &padding);
579 int startx = margin.left;
580 int starty = margin.top;
581 int cwidth = allocation.width - margin.left - margin.right;
582 int cheight = allocation.height - margin.top - margin.bottom;
583 gtk_render_background(context, cr, startx, starty, cwidth, cheight);
584 gtk_render_frame(context, cr, startx, starty, cwidth, cheight);
587 startx += padding.left + border.left;
588 starty += padding.top + border.top;
589 cwidth -= padding.left + padding.right + border.left + border.right;
590 cheight -= padding.top + padding.bottom + border.top + border.bottom;
591 const int y1 = round(0.3f * cheight);
592 const int gheight = cheight - 2 * y1;
597 cairo_pattern_t *gradient = cairo_pattern_create_linear(0, 0, cwidth, 0);
598 for(GList *current = gslider->
colors; current; current = g_list_next(current))
601 cairo_pattern_add_color_stop_rgba(gradient, stop->
position, stop->
color.red, stop->
color.green,
606 cairo_set_line_width(cr, 0.1);
607 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
608 cairo_translate(cr, 0, starty);
609 cairo_set_source(cr, gradient);
610 cairo_rectangle(cr, startx, y1, cwidth, gheight);
613 cairo_pattern_destroy(gradient);
621 if(!isnan(gslider->
picker[0]))
629 cairo_rectangle(cr, vx_min, y1, fmax((
float)vx_max - vx_min, 0.0f), gheight);
634 cairo_move_to(cr, vx_avg, y1);
635 cairo_rel_line_to(cr, 0, gheight);
636 cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
637 cairo_set_line_width(cr, 1.0);
644 const int mk = gslider->
marker[
k];
645 const int sz = round((mk & (1 << 3)) ? 1.9f * y1 : 1.4f * y1);
650 cairo_set_source_rgba(cr,
color.red * 0.8,
color.green * 0.8,
color.blue * 0.8, 1.0);
652 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);
789 return _gradient_slider_get_type();
794 assert(pos <= gslider->positions);
809 assert(pos <= gslider->positions);
814 gtk_widget_queue_draw(GTK_WIDGET(gslider));
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));
939 if (
name) gtk_widget_set_name(widget,
name);
954 if (
name) gtk_widget_set_name(widget,
name);
966 return _gradient_slider_get_type();
999 gtk_widget_queue_draw(GTK_WIDGET(gslider));
1003 gdouble
min, gdouble
max)
1009 gtk_widget_queue_draw(GTK_WIDGET(gslider));
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
static const float const float const float min
GHashTable * selected
set of checked row labels, mirrored to conf on every change
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)
#define GRADIENT_SLIDER_MAX_POSITIONS
@ GRADIENT_SLIDER_MARGINS_DEFAULT
@ 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 DTGTK_IS_GRADIENT_SLIDER(obj)
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
static const dt_aligned_pixel_simd_t value
const float uint32_t state[4]
float(* scale_callback)(GtkWidget *, float, int)