75#ifdef GDK_WINDOWING_QUARTZ
82#include <pango/pangocairo.h>
83#ifdef GDK_WINDOWING_WAYLAND
84#include <gdk/gdkwayland.h>
128 GtkStyleContext *context = gtk_widget_get_style_context(GTK_WIDGET(w));
129 const GtkStateFlags
state = gtk_widget_get_state_flags(GTK_WIDGET(w));
130 gtk_style_context_get_margin(context,
state, w->
margin);
131 gtk_style_context_get_padding(context,
state, w->
padding);
134 GtkBorder *borders = gtk_border_new();
135 gtk_style_context_get_border(context,
state, borders);
136 w->
margin->left += borders->left;
137 w->
margin->right += borders->right;
138 w->
margin->top += borders->top;
139 w->
margin->bottom += borders->bottom;
140 gtk_border_free(borders);
191 GtkWidget *box_reference = (widget) ? widget : GTK_WIDGET(w);
192 GtkAllocation allocation;
193 gtk_widget_get_allocation(box_reference, &allocation);
212 if(total_width) *total_width = tot_width;
225 GtkWidget *box_reference = (widget) ? widget : GTK_WIDGET(w);
226 GtkAllocation allocation;
227 gtk_widget_get_allocation(box_reference, &allocation);
281 if(
d->populate)
d->
populate(GTK_WIDGET(w), module);
282 if(!
d->entries->len)
return 0.;
289 for(
int i = 0;
i <
d->entries->len;
i++)
310 const double left_offset = w->
margin->left + w->
padding->left + slider_cursor_radius;
340 GtkWidget *box_reference = (popup) ? popup : widget;
349 if(*y < 0. || *y > main_height || *x < 0. || *x > total_width)
413 for(
int i = 0;
i <
d->entries->len;
i++)
435 GdkWindow *window = gtk_widget_get_window(bh->
popup_window);
436 gdk_window_get_origin(window, &wx, &wy);
437 *event_x = x_root - (
double)wx;
438 *event_y = y_root - (
double)wy;
444#define DT_BAUHAUS_FOCUS_IDLE_SOURCE_KEY "dt-bauhaus-focus-idle-source"
445#define DT_BAUHAUS_FOCUS_IDLE_TRIES_KEY "dt-bauhaus-focus-idle-tries"
446#define DT_BAUHAUS_FOCUS_IDLE_MAX_TRIES 20
450 if(!GTK_IS_WIDGET(target))
return G_SOURCE_REMOVE;
454 for(
GtkWidget *w = child; w; w = gtk_widget_get_parent(w))
456 if(GTK_IS_NOTEBOOK(w))
459 while(!
IS_NULL_PTR(page) && gtk_widget_get_parent(page) != w)
460 page = gtk_widget_get_parent(page);
462 GtkNotebook *nb = GTK_NOTEBOOK(w);
463 const gint page_num = !
IS_NULL_PTR(page) ? gtk_notebook_page_num(nb, page) : -1;
464 if(page_num >= 0) gtk_notebook_set_current_page(nb, page_num);
466 else if(GTK_IS_STACK(w))
469 while(!
IS_NULL_PTR(page) && gtk_widget_get_parent(page) != w)
470 page = gtk_widget_get_parent(page);
472 GtkWidget *visible_child = gtk_stack_get_visible_child(GTK_STACK(w));
473 if(!
IS_NULL_PTR(page) && visible_child != page) gtk_stack_set_visible_child(GTK_STACK(w), page);
478 if(gtk_widget_is_drawable(target))
480 gtk_widget_grab_focus(target);
486 "[bauhaus] ensure_focus_idle success target=%s(%p) gtk_focus=%s(%p) scroll_focus=%s(%p)\n",
487 gtk_widget_get_name(target), (
void *)target,
488 !
IS_NULL_PTR(gtk_focus) ? gtk_widget_get_name(gtk_focus) :
"<null>", (
void *)gtk_focus,
493 return G_SOURCE_REMOVE;
500 "[bauhaus] ensure_focus_idle abort target=%s(%p) tries=%d drawable=%d\n",
501 gtk_widget_get_name(target), (
void *)target, tries, gtk_widget_is_drawable(target));
504 return G_SOURCE_REMOVE;
508 return G_SOURCE_CONTINUE;
517 gtk_widget_queue_draw(widget);
525 gtk_widget_queue_draw(widget);
533 if(direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
return FALSE;
540 GdkModifierType modifier, gpointer
data)
544 dt_toast_log(_(
"The target widget of the action does not exist anymore"));
545 fprintf(stderr,
"The target widget of the action does not exist anymore");
558 g_object_set_data(G_OBJECT(module->expander),
"dt-modulegroups-switch-from-active-once",
559 GINT_TO_POINTER(
TRUE));
569 w->module->focus(w->module,
FALSE);
574 if(previous_source > 0)
575 g_source_remove(previous_source);
578 const guint source = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ensure_focus_idle, g_object_ref(target),
579 (GDestroyNotify)g_object_unref);
590 int cur = new_pos +
inc;
591 while(
delta && cur >= 0 && cur < d->entries->len)
601 d->hovered = new_pos;
607 void *
data,
void (*free_func)(
void *))
629 entry->
label = g_strdup(
"");
650 GdkRGBA color = {.red = 1.0f, .green = 0.0f, .blue = 0.0f, .alpha = 1.0f};
651 return gdk_rgba_copy(&color);
687 GtkStyleContext *context,
689 GdkRectangle *bounding_box,
693 PangoEllipsizeMode ellipsize,
702 PangoFontDescription *css_font = NULL;
703 gtk_style_context_get(context,
state, GTK_STYLE_PROPERTY_FONT, &css_font, NULL);
709 pango_font_description_set_weight(resolved, pango_font_description_get_weight(css_font));
710 pango_font_description_set_style(resolved, pango_font_description_get_style(css_font));
711 pango_font_description_set_variant(resolved, pango_font_description_get_variant(css_font));
712 pango_font_description_set_stretch(resolved, pango_font_description_get_stretch(css_font));
713 pango_font_description_set_family(resolved, pango_font_description_get_family(css_font));
714 pango_font_description_free(css_font);
738 PangoContext *pc = gtk_widget_get_pango_context(GTK_WIDGET(w));
742 PangoLayout *layout = pango_layout_new(pc);
743 pango_layout_set_font_description(layout, resolved);
744 pango_font_description_free(resolved);
747 pango_layout_set_text(layout, text, -1);
751 pango_cairo_update_layout(cr, layout);
754 int pango_width, pango_height;
755 pango_layout_get_size(layout, &pango_width, &pango_height);
756 double text_width = (
double)pango_width / PANGO_SCALE;
757 double text_height = fmax((
double)pango_height / PANGO_SCALE, w->
bauhaus->
line_height);
762 if(text_width > bounding_box->width)
764 pango_layout_set_ellipsize(layout, ellipsize);
765 pango_layout_set_width(layout, (
int)(PANGO_SCALE * bounding_box->width));
766 text_width = bounding_box->width;
768 pango_cairo_update_layout(cr, layout);
775 cairo_rectangle(cr, bounding_box->x, bounding_box->y,
776 bounding_box->width, bounding_box->height);
777 cairo_set_source_rgba(cr, bg_color->red, bg_color->green,
778 bg_color->blue, bg_color->alpha);
789 x = bounding_box->x + bounding_box->width / 2. - text_width / 2.;
792 x = bounding_box->x + bounding_box->width - text_width;
804 y = bounding_box->y + bounding_box->height / 2. - text_height / 2.;
807 y = bounding_box->y + bounding_box->height - text_height;
816 cairo_move_to(cr,
x, y);
817 pango_cairo_show_layout(cr, layout);
820 g_object_unref(layout);
837 y = (y - line_height) / (1.0 - line_height);
838 offset = (
x - sqf(y) * .5 - (1.0 - sqf(y)) * pos)
839 / (.5 * sqf(y) / scale + (1.0 - sqf(y)));
842 if(pos + offset > 1.0) offset = 1.0 - pos;
843 if(pos + offset < 0.0) offset = -pos;
849 const double line_height,
double line_width)
853 const int steps = 128;
854 const double corrected_height = (
height - line_height);
856 cairo_set_line_width(cr, line_width);
857 cairo_move_to(cr,
width * (pos + off), line_height);
858 const double half_line_width = line_width / 2.;
859 for(
int j = 1; j < steps; j++)
861 const double y = (
double)j / (
double)(steps - 1);
862 const double x = sqf(y) * .5f * (1.f + off / scale) + (1.0f - sqf(y)) * (pos + off);
863 cairo_line_to(cr,
x *
width - half_line_width, line_height + y * corrected_height);
874 if(roundf(zoom) == 0.f)
876 d->min =
d->soft_min;
877 d->max =
d->soft_max;
884 const float multiplier = exp2f(zoom / 2.f);
885 const float new_min =
value - multiplier * (
value -
d->min);
886 const float new_max =
value + multiplier * (
d->max -
value);
887 if(new_min >=
d->hard_min
888 && new_max <= d->hard_max
889 && new_max - new_min >= min_visible * 10)
895 gtk_widget_queue_draw(GTK_WIDGET(w));
900 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
908 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
916 fprintf(stdout,
"x: %i, y: %i, active: %i\n", (
int)event_x, (
int)event_y, active);
947 d->pos =
d->oldpos + mouse_off;
957 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL,
TRUE);
964 g_object_get(gtk_settings_get_default(),
"gtk-double-click-time", &delay, NULL);
965 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
971 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_ACTIVE,
TRUE);
985 g_object_get(gtk_settings_get_default(),
"gtk-double-click-time", &delay, NULL);
987 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
990 if(event->button == 1)
993 && event->time < bh->
opentime + delay)
1027 const float value =
d->pos;
1042 gtk_widget_queue_draw(widget);
1054 gtk_grab_add(GTK_WIDGET(user_data));
1065 if(event->type == GDK_ENTER_NOTIFY)
1067 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
FALSE);
1071 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
1076 const gboolean real_leave =
event->mode == GDK_CROSSING_NORMAL
1077 &&
event->detail != GDK_NOTIFY_INFERIOR
1083 gtk_widget_queue_draw(widget);
1104 if(event->type == GDK_ENTER_NOTIFY)
1106 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
FALSE);
1108 ? GDK_SB_V_DOUBLE_ARROW
1109 : GDK_SB_H_DOUBLE_ARROW);
1113 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
1117 gtk_widget_queue_draw(widget);
1124 if(event->button != 1)
return TRUE;
1126 if(event->type == GDK_BUTTON_PRESS)
1129 handle->
start_root = (handle->
orientation == GTK_ORIENTATION_VERTICAL) ? event->y_root :
event->x_root;
1132 gtk_grab_add(widget);
1134 ? GDK_SB_V_DOUBLE_ARROW
1135 : GDK_SB_H_DOUBLE_ARROW);
1137 else if(event->type == GDK_BUTTON_RELEASE)
1140 gtk_grab_remove(widget);
1143 GtkAllocation allocation;
1144 gtk_widget_get_allocation(widget, &allocation);
1145 const gboolean pointer_on_handle =
event->x >= 0. &&
event->x <= allocation.width
1146 &&
event->y >= 0. &&
event->y <= allocation.height;
1147 if(pointer_on_handle)
1148 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
FALSE);
1150 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
1153 ? (handle->
orientation == GTK_ORIENTATION_VERTICAL
1154 ? GDK_SB_V_DOUBLE_ARROW
1155 : GDK_SB_H_DOUBLE_ARROW)
1157 gtk_widget_queue_draw(widget);
1171 const double root = (handle->
orientation == GTK_ORIENTATION_VERTICAL) ? event->y_root :
event->x_root;
1186 GtkWidget *handle_widget = gtk_event_box_new();
1198 GtkStyleContext *ctx = gtk_widget_get_style_context(handle_widget);
1199 gtk_style_context_add_class(ctx,
"resize-handle");
1200 if(orientation == GTK_ORIENTATION_VERTICAL)
1203 gtk_widget_set_halign(handle_widget, GTK_ALIGN_FILL);
1204 gtk_widget_set_valign(handle_widget, invert ? GTK_ALIGN_START : GTK_ALIGN_END);
1205 gtk_style_context_add_class(ctx, invert ?
"resize-handle-top" :
"resize-handle-bottom");
1210 gtk_widget_set_valign(handle_widget, GTK_ALIGN_FILL);
1211 gtk_widget_set_halign(handle_widget, invert ? GTK_ALIGN_START : GTK_ALIGN_END);
1212 gtk_style_context_add_class(ctx, invert ?
"resize-handle-left" :
"resize-handle-right");
1215 gtk_widget_set_events(handle_widget, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1216 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
1217 | GDK_POINTER_MOTION_MASK);
1219 gtk_widget_set_tooltip_text(handle_widget,
tooltip);
1221 g_object_set_data_full(G_OBJECT(handle_widget),
"dt-bauhaus-resize-handle", handle, g_free);
1222 g_signal_connect(G_OBJECT(handle_widget),
"button-press-event", G_CALLBACK(
_resize_handle_button), handle);
1223 g_signal_connect(G_OBJECT(handle_widget),
"button-release-event", G_CALLBACK(
_resize_handle_button), handle);
1224 g_signal_connect(G_OBJECT(handle_widget),
"motion-notify-event", G_CALLBACK(
_resize_handle_motion), handle);
1225 g_signal_connect(G_OBJECT(handle_widget),
"enter-notify-event", G_CALLBACK(
_resize_handle_cursor), handle);
1226 g_signal_connect(G_OBJECT(handle_widget),
"leave-notify-event", G_CALLBACK(
_resize_handle_cursor), handle);
1228 return handle_widget;
1236 if(focus_source > 0)
1238 g_source_remove(focus_source);
1243 const char *accel_path = g_object_get_data(G_OBJECT(widget),
"accel-path");
1259 g_ptr_array_free(
d->entries,
TRUE);
1262 gtk_border_free(w->
margin);
1265 G_OBJECT_CLASS(dt_bh_parent_class)->finalize(widget);
1271 = g_signal_new(
"value-changed", G_TYPE_FROM_CLASS(
class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1272 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1274 = g_signal_new(
"quad-pressed", G_TYPE_FROM_CLASS(
class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1275 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1277 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(
class);
1295 GtkStyleContext *ctx = gtk_widget_get_style_context(root_window);
1296 gtk_style_context_set_screen(ctx, gtk_widget_get_screen(root_window));
1298 gtk_style_context_lookup_color(ctx,
"bauhaus_fg", &
bauhaus->
color_fg);
1300 gtk_style_context_lookup_color(ctx,
"bauhaus_bg", &
bauhaus->
color_bg);
1326 gtk_style_context_lookup_color(ctx,
"colorlabel_red",
1328 gtk_style_context_lookup_color(ctx,
"colorlabel_yellow",
1330 gtk_style_context_lookup_color(ctx,
"colorlabel_green",
1332 gtk_style_context_lookup_color(ctx,
"colorlabel_blue",
1334 gtk_style_context_lookup_color(ctx,
"colorlabel_purple",
1343 cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 128, 128);
1344 cairo_t *cr = cairo_create(cst);
1348 ctx = gtk_widget_get_style_context(ref);
1351 PangoContext *context = gtk_widget_get_pango_context(ref);
1352 PangoLayout *layout = pango_layout_new(context);
1353 pango_layout_set_text(layout,
"em", -1);
1363 pango_cairo_update_layout(cr, layout);
1364 pango_cairo_show_layout(cr, layout);
1369 pango_layout_get_size(layout, &pango_width, &pango_height);
1370 g_object_unref(layout);
1372 cairo_surface_destroy(cst);
1396#ifdef GDK_WINDOWING_QUARTZ
1415 gtk_window_set_type_hint(GTK_WINDOW(
bauhaus->
popup_window), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
1425 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1426 | GDK_KEY_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK
1431 g_object_set_data(area,
"bauhaus",
bauhaus);
1443 gchar *path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Increase value (normal step)"));
1445 path, NULL, GDK_KEY_Right, 0);
1447 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Decrease value (normal step)"));
1449 path, NULL, GDK_KEY_Left, 0);
1453 path, NULL, GDK_KEY_Right, GDK_CONTROL_MASK);
1457 path, NULL, GDK_KEY_Left, GDK_CONTROL_MASK);
1459 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Increase value (coarse step)"));
1461 path, NULL, GDK_KEY_Right, GDK_SHIFT_MASK);
1463 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Decrease value (coarse step)"));
1465 path, NULL, GDK_KEY_Left, GDK_SHIFT_MASK);
1469 path, NULL, GDK_KEY_Insert, 0);
1474 path, NULL, GDK_KEY_Return, 0);
1478 path, NULL, GDK_KEY_Escape, 0);
1480 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Select previous (in editing mode)"));
1482 path, NULL, GDK_KEY_Up, 0);
1484 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Select next (in editing mode)"));
1486 path, NULL, GDK_KEY_Down, 0);
1488 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Validate result (in editing mode)"));
1490 path, NULL, GDK_KEY_Return, 0);
1494 path, NULL, GDK_KEY_Insert, 0);
1535 gtk_widget_add_events(GTK_WIDGET(w), GDK_POINTER_MOTION_MASK
1536 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1537 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
1538 | GDK_FOCUS_CHANGE_MASK
1541 gtk_widget_set_can_focus(GTK_WIDGET(w),
TRUE);
1542 gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_FILL);
1543 gtk_widget_set_hexpand(GTK_WIDGET(w),
TRUE);
1565 d->min =
MAX(
d->min,
d->hard_min);
1566 d->soft_min =
MAX(
d->soft_min,
d->hard_min);
1568 if(desired_position >
d->hard_max)
1571 if(current_position < desired_position)
1589 d->hard_max = desired_position;
1590 d->max =
MIN(
d->max,
d->hard_max);
1591 d->soft_max =
MIN(
d->soft_max,
d->hard_max);
1593 if(desired_position < d->hard_min)
1596 if(current_position > desired_position)
1613 d->min =
d->soft_min = CLAMP(val,
d->hard_min,
d->hard_max);
1629 d->max =
d->soft_max = CLAMP(val,
d->hard_min,
d->hard_max);
1667 m->widget_list = g_list_append(
m->widget_list, w);
1670 m->widget_list_bh = g_list_append(
m->widget_list_bh, w);
1678 assert(g_strrstr(
label,
"/") == NULL);
1680 gchar *plugin_name = g_strdup_printf(
"%s/%s",
m->name, w->
label);
1683 gchar *scope = g_strdup_printf(
"%s/Modules",
m->view);
1685 g_object_set_data_full(G_OBJECT(widget),
"accel-path",
1687 gtk_widget_set_has_tooltip(widget,
TRUE);
1692 gtk_widget_queue_draw(GTK_WIDGET(w));
1714 fprintf(stderr,
"[dt_bauhaus_widget_set_field] bauhaus label '%s' set before field (needs to be after)\n", w->
label);
1733 gtk_widget_queue_draw(GTK_WIDGET(w));
1740 gtk_widget_queue_draw(GTK_WIDGET(w));
1759 g_signal_emit_by_name(G_OBJECT(w),
"quad-pressed");
1765 gtk_widget_grab_focus(widget);
1771 gtk_widget_queue_draw(GTK_WIDGET(w));
1781 float defval,
int digits)
1787 float step,
float defval,
int digits,
int feedback)
1808 float step,
float defval,
int digits,
int feedback)
1813 d->
min =
d->soft_min =
d->hard_min =
min;
1814 d->max =
d->soft_max =
d->hard_max =
max;
1829 d->fill_feedback = feedback;
1839 return GTK_WIDGET(w);
1846 return GTK_WIDGET(w);
1850 int pos, GtkCallback callback, gpointer
data,
const char **texts)
1856 gtk_widget_set_tooltip_text(combo, tip ? tip : _(
label));
1857 if(callback) g_signal_connect(G_OBJECT(combo),
"value-changed", G_CALLBACK(callback),
data);
1872 fprintf(stderr,
"[dt_bauhaus_combobox_from_conf] `%s` is not declared as an <enum> config entry\n", confkey);
1886 int pos = 0, active = 0;
1887 for(GList *opt =
options; opt; opt = g_list_next(opt))
1889 char *item = (
char *)opt->data;
1891 if(item[0] ==
'[') item++;
1892 else if(item[strlen(item) - 1] ==
']') item[strlen(item) - 1] =
'\0';
1897 if(!g_strcmp0(current, item)) active = pos;
1922 d->entries_ellipsis = PANGO_ELLIPSIZE_END;
1938 if(
d->active >=
d->entries->len)
d->
active = -1;
1967 const gboolean allow_end)
1971 int selectable_pos = 0;
1972 for(
int i = 0;
i <
d->entries->len;
i++)
1976 if(selectable_pos == pos)
return i;
1980 return (allow_end && selectable_pos == pos) ? (int)
d->entries->len : -1;
1988 if(
IS_NULL_PTR(
d) || entry_pos < 0 || entry_pos >=
d->entries->len)
return -1;
1990 int selectable_pos = 0;
1991 for(
int i = 0;
i <= entry_pos;
i++)
1995 if(
i == entry_pos)
return selectable_pos;
2007 w->data.combobox.populate = fct;
2012 while(texts && *texts)
2029 g_ptr_array_add(
d->entries, entry);
2030 if(
d->active < 0)
d->active = (int)
d->entries->len - 1;
2039 gpointer
data,
void (free_func)(
void *
data), gboolean sensitive)
2046 g_ptr_array_add(
d->entries, entry);
2047 if(
d->active < 0)
d->active = (int)
d->entries->len - 1;
2089 return d ?
d->editable : 0;
2107 if(entry_pos < 0)
return;
2112 if(
d->active > entry_pos ||
d->active ==
d->entries->len-1)
2115 g_ptr_array_remove_index(
d->entries, entry_pos);
2124 gpointer
data,
void (*free_func)(
void *),
int pos)
2130 if(entry_pos < 0)
return;
2133 d->active = entry_pos;
2134 else if(entry_pos <= d->active)
2150 if(entry_pos < 0)
return;
2152 if(entry_pos <= d->active)
d->active++;
2169 return d->editable ?
d->text : NULL;
2175 return entry->
label;
2196 g_ptr_array_set_size(
d->entries, 0);
2203 if(entry_pos < 0)
return NULL;
2206 return entry->
label;
2233 fprintf(stderr,
"ERROR: %s - %s is set to use default callback but none is provided\n", w->module->name,
2239 fprintf(stderr,
"WARNING: %s - %s has an IOP module but doesn't use default callback\n", w->module->name,
2244 g_signal_emit_by_name(G_OBJECT(w),
"value-changed");
2261 const int old_pos =
d->
active;
2262 const int new_pos = (
d->entries) ? CLAMP(pos, -1, (
int)
d->entries->len - 1)
2275 if(old_pos != new_pos)
2277 d->active = new_pos;
2282 gtk_widget_queue_draw(GTK_WIDGET(w));
2305 const int public_pos = (selectable_count > 0) ? CLAMP(pos, -1, selectable_count - 1) : -1;
2317 for(
int i = 0;
d &&
i <
d->entries->len;
i++)
2321 if(!g_strcmp0(entry->
label, text))
2334 for(
int i = 0;
d &&
i <
d->entries->len;
i++)
2338 if(GPOINTER_TO_INT(entry->
data) ==
value)
2358 if(entry_pos < 0)
return;
2384 for(
int k = 0;
k <
d->grad_cnt;
k++)
2386 if(
d->grad_pos[
k] == stop)
2388 d->grad_col[
k][0] =
r;
2389 d->grad_col[
k][1] =
g;
2390 d->grad_col[
k][2] = b;
2397 int k =
d->grad_cnt++;
2398 d->grad_pos[
k] = stop;
2399 d->grad_col[
k][0] =
r;
2400 d->grad_col[
k][1] =
g;
2401 d->grad_col[
k][2] = b;
2414 const float horizontal_position = pos * wd;
2417 cairo_translate(cr, horizontal_position, vertical_position);
2420 const gboolean has_colored_background =
d->
grad_cnt > 0;
2422 if(!has_colored_background &&
d->fill_feedback)
2425 cairo_arc(cr, 0, 0,
size / 2., 0,
M_PI * 2);
2427 cairo_set_line_width(cr, 0);
2435 cairo_set_line_width(cr, border);
2436 const float radius =
size / 2. - border / 2.;
2437 cairo_arc(cr, 0, 0, radius, 0,
M_PI * 2);
2466 cairo_move_to(cr, -
r, -
r * .5f);
2467 cairo_line_to(cr, 0,
r * .5f);
2468 cairo_line_to(cr,
r, -
r * .5f);
2486 const gboolean has_colored_background =
d->
grad_cnt > 0;
2489 const gboolean is_sensitive = gtk_widget_is_sensitive(GTK_WIDGET(w));
2501 const double baseline_width =
width - x_origin;
2503 cairo_rectangle(cr, round(x_origin), round(baseline_top),
2504 round(baseline_width), round(baseline_height));
2506 cairo_pattern_t *gradient = NULL;
2507 if(has_colored_background && is_sensitive)
2510 const double zoom = (
d->max -
d->min) / (
d->hard_max -
d->hard_min);
2511 const double offset = (
d->min -
d->hard_min) / (
d->hard_max -
d->hard_min);
2512 gradient = cairo_pattern_create_linear(x_origin, 0,
width, baseline_height);
2513 for(
int k = 0;
k <
d->grad_cnt;
k++)
2514 cairo_pattern_add_color_stop_rgba(gradient, (
d->grad_pos[
k] - offset) / zoom,
2515 d->grad_col[
k][0],
d->grad_col[
k][1],
d->grad_col[
k][2], 0.4f);
2516 cairo_set_source(cr, gradient);
2531 const double line_width = 1.;
2532 cairo_rectangle(cr, round(x_origin) + line_width / 2., round(baseline_top) + line_width / 2.,
2533 round(baseline_width) - line_width, round(baseline_height) - line_width);
2534 cairo_set_line_width(cr, line_width);
2539 if(gradient) cairo_pattern_destroy(gradient);
2542 float origin = fmaxf(fminf((
d->factor > 0 ? -
d->min -
d->offset/
d->factor
2543 :
d->max +
d->offset/
d->factor)
2544 / (
d->max -
d->min),
2549 if(!has_colored_background &&
d->fill_feedback && is_sensitive)
2559 cairo_rectangle(cr, x_origin, baseline_top,
delta - x_origin, baseline_height);
2561 cairo_rectangle(cr, origin, baseline_top,
delta, baseline_height);
2569 if(
d->hard_max != 360.0f && is_sensitive)
2617 fprintf(stdout,
"combobox went the custom path\n");
2627 gchar *keys = g_utf8_casefold(w->
bauhaus->
keys, -1);
2631 for(
int j = 0; j <
d->entries->len; j++)
2634 gchar *text_cmp = g_utf8_casefold(entry->
label, -1);
2679 return g_strdup(w->
label);
2687 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
2691 GtkAllocation allocation;
2692 gtk_widget_get_allocation(widget, &allocation);
2694 cairo_t *cr = cairo_create(cst);
2695 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2698 GdkRGBA text_color, text_color_selected, text_color_hover, text_color_insensitive, text_color_focused;
2699 gtk_style_context_get_color(context, GTK_STATE_FLAG_NORMAL, &text_color);
2700 gtk_style_context_get_color(context, GTK_STATE_FLAG_SELECTED, &text_color_selected);
2701 gtk_style_context_get_color(context, GTK_STATE_FLAG_PRELIGHT, &text_color_hover);
2702 gtk_style_context_get_color(context, GTK_STATE_FLAG_INSENSITIVE, &text_color_insensitive);
2703 gtk_style_context_get_color(context, GTK_STATE_FLAG_FOCUSED, &text_color_focused);
2707 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2709 gtk_style_context_get(context,
state,
"background-color", &bg_color, NULL);
2710 gtk_style_context_get_color(context,
state, fg_color);
2713 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
2714 gtk_render_frame(context, cr, 0, 0, allocation.width, allocation.height);
2717 double total_width = 0.f;
2730 const double text_width = main_width + slider_cursor_radius;
2732 cairo_translate(cr, slider_cursor_radius, 0.0);
2736 const int num_scales = 1.f / scale;
2739 for(
int k = 0;
k < num_scales;
k++)
2741 const float off =
k * scale -
d->oldpos;
2742 GdkRGBA fg_copy = *fg_color;
2743 fg_copy.alpha = scale / fabsf(off);
2745 draw_slider_line(cr,
d->oldpos, off, scale, main_width, main_height, bottom_baseline, 1);
2751 const double mouse_off =
d->pos -
d->oldpos;
2754 cairo_translate(cr, slider_cursor_radius, 0.0);
2761 draw_slider_line(cr,
d->oldpos, mouse_off, scale, main_width, main_height, bottom_baseline, 2);
2773 float value_width = 0.f;
2775 GdkRectangle bounding_value = { .x = 0.,
2777 .width = text_width,
2782 BH_ALIGN_MIDDLE, PANGO_ELLIPSIZE_NONE, NULL, &value_width, NULL, GTK_STATE_FLAG_NORMAL);
2787 const float label_width = text_width - value_width -
INNER_PADDING;
2788 GdkRectangle bounding_label = { .x = 0.,
2790 .width = label_width,
2794 PANGO_ELLIPSIZE_END, NULL, NULL, NULL, GTK_STATE_FLAG_NORMAL);
2805 double popup_y = 0.;
2811 GdkRectangle query_label = { .x = 0.,
2813 .width = main_width,
2814 .height = query_height };
2816 PANGO_ELLIPSIZE_NONE, NULL, NULL, NULL, GTK_STATE_FLAG_NORMAL);
2817 popup_y += query_height;
2822 gchar *keys = g_utf8_casefold(w->
bauhaus->
keys, -1);
2823 for(
int j = 0; j <
d->entries->len; j++)
2831 cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.);
2832 cairo_move_to(cr, 0., popup_y + 0.5 * entry_height);
2833 cairo_line_to(cr, main_width, popup_y + 0.5 * entry_height);
2834 cairo_set_line_width(cr, 1.);
2837 popup_y += entry_height;
2841 gchar *text_cmp = g_utf8_casefold(entry->
label, -1);
2851 state = GTK_STATE_FLAG_INSENSITIVE;
2853 else if(j ==
d->active)
2856 state = GTK_STATE_FLAG_SELECTED;
2858 else if(j ==
d->hovered)
2861 state = GTK_STATE_FLAG_PRELIGHT;
2866 state = GTK_STATE_FLAG_NORMAL;
2869 GdkRectangle bounding_label = { .x = 0.,
2871 .width = main_width,
2872 .height = entry_height };
2874 cairo_rectangle(cr, bounding_label.x, bounding_label.y, bounding_label.width, bounding_label.height);
2875 cairo_set_line_width(cr, 2);
2879 d->entries_ellipsis, bg_color, NULL, NULL,
state);
2883 popup_y += entry_height;
2895 cairo_set_source_surface(crf, cst, 0, 0);
2897 cairo_surface_destroy(cst);
2899 gdk_rgba_free(bg_color);
2900 gdk_rgba_free(fg_color);
2911 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2912 const GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2915 cairo_t *cr = cairo_create(cst);
2923 float label_width = 0.f;
2924 GdkRectangle bounding_label = { .x = 0.,
2930 PANGO_ELLIPSIZE_NONE, NULL, &label_width, NULL,
state);
2935 float max_entry = 0.f;
2936 for(
int i = 0;
i <
d->entries->len;
i++)
2941 GdkRectangle bounding_value = { .x = 0,
2945 float entry_label_width = 0.f;
2948 &entry_label_width, NULL,
state);
2957 cairo_surface_destroy(cst);
2965 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2968 GtkAllocation allocation;
2969 gtk_widget_get_allocation(widget, &allocation);
2981 if(max_width < allocation.width)
2982 allocation.width = ceilf(max_width);
2986 gtk_widget_size_allocate(widget, &allocation);
2989 cairo_t *cr = cairo_create(cst);
2994 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2995 if(gtk_widget_has_focus(widget))
2996 state |= GTK_STATE_FLAG_FOCUSED;
2998 gtk_style_context_save(context);
2999 gtk_style_context_set_state(context,
state);
3000 gtk_style_context_get_color(context,
state, text_color);
3008 const float box_width = allocation.width - w->
margin->left - w->
margin->right;
3009 const float box_height = allocation.height - w->
margin->top - w->
margin->bottom;
3012 gtk_render_background(context, crf, w->
margin->left, w->
margin->top, box_width, box_height);
3013 gtk_render_frame(context, crf, w->
margin->left, w->
margin->top, box_width, box_height);
3026 cairo_set_line_width(cr, 1.0);
3041 float label_width = 0.f;
3042 float label_height = 0.f;
3044 GdkRectangle bounding_label = { .x = 0.,
3046 .width = available_width,
3047 .height = inner_height };
3050 combo_ellipsis, NULL, &label_width, &label_height,
state);
3053 gchar *text =
d->text;
3054 if(
d->active >= 0 &&
d->active <
d->entries->len)
3057 text = entry->
label;
3059 GdkRectangle bounding_value = { .x = label_width +
INNER_PADDING,
3062 .height = inner_height };
3072 const double text_width = available_width + slider_cursor_radius;
3076 cairo_translate(cr, slider_cursor_radius, 0.0);
3084 cairo_set_source_rgba(cr, text_color->red, text_color->green, text_color->blue, text_color->alpha * 0.7);
3089 float value_width = 0;
3090 if(gtk_widget_is_sensitive(widget))
3093 cairo_translate(cr, slider_cursor_radius, 0.0);
3098 GdkRectangle bounding_value = { .x = 0.,
3100 .width = text_width,
3104 PANGO_ELLIPSIZE_NONE, NULL, &value_width, NULL,
state);
3110 const float label_width = text_width - value_width -
INNER_PADDING;
3111 GdkRectangle bounding_label = { .x = 0.,
3113 .width = label_width,
3117 PANGO_ELLIPSIZE_END, NULL, NULL, NULL,
state);
3126 cairo_set_source_surface(crf, cst, 0, 0);
3128 cairo_surface_destroy(cst);
3129 gtk_style_context_restore(context);
3131 gdk_rgba_free(text_color);
3132 gdk_rgba_free(value_color);
3133 gdk_rgba_free(value_text_color);
3178 gtk_window_set_attached_to(GTK_WINDOW(bh->
popup_window), NULL);
3181 gtk_widget_grab_focus(GTK_WIDGET(bh->
current));
3201 gtk_widget_realize(widget);
3205 gtk_widget_get_allocation(widget, &tmp);
3227 fprintf(stderr,
"[dt_bauhaus_show_popup] The bauhaus widget has an unknown type\n");
3233 GtkStyleContext *context = gtk_widget_get_style_context(w->
bauhaus->
popup_area);
3234 gtk_style_context_add_class(context,
"dt_bauhaus_popup");
3236 #ifdef GDK_WINDOWING_WAYLAND
3237 if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
3238 GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
3246 gint wx = 0, wy = 0;
3247 GdkWindow *widget_window = gtk_widget_get_window(widget);
3248 if(widget_window) gdk_window_get_origin(widget_window, &wx, &wy);
3252 gint wwx = 0, wwy = 0;
3254 if(main_window) gdk_window_get_origin(main_window, &wwx, &wwy);
3256 GdkRectangle anchor = {
3259 .width =
MAX(tmp.width, 1),
3260 .height =
MAX(tmp.height, 1)
3279 gdk_window_move_to_rect(GDK_WINDOW(window), &anchor, GDK_GRAVITY_STATIC, GDK_GRAVITY_STATIC,
3280 GDK_ANCHOR_SLIDE, 0, 0);
3288 if(
delta == 0.f)
return;
3297 const float min_visible = 1.f / (fabsf(
d->factor) *
ipow(10,
d->digits));
3298 if(fabsf(
delta) < min_visible)
3310 const gboolean key_captured = gtk_widget_has_focus(widget);
3311 const gboolean smooth = (
event->direction == GDK_SCROLL_SMOOTH);
3321 if(!key_captured && !popup_captured && !scroll_captured)
3338 const gboolean vscroll = delta_y != 0 && abs(delta_y) > abs(delta_x);
3339 const gboolean hscroll = delta_x != 0 && abs(delta_x) > abs(delta_y);
3388 case GDK_KEY_Insert:
3404 case GDK_KEY_Return:
3408 case GDK_KEY_Insert:
3427 double event_x =
event->x;
3428 double event_y =
event->y;
3441 gtk_widget_grab_focus(widget);
3452 if(event->button == 3)
3459 else if(event->button == 1)
3462 if(event->type == GDK_2BUTTON_PRESS)
3488 return d->
min +
d->pos * (
d->max -
d->min);
3500 if((
d->hard_max *
d->factor +
d->offset)*(
d->hard_min *
d->factor +
d->offset) < 0)
3501 return g_strdup_printf(
"%+.*f%s",
d->digits, val *
d->factor +
d->offset,
d->format);
3503 return g_strdup_printf(
"%.*f%s",
d->digits, val *
d->factor +
d->offset,
d->format);
3511 const float rpos = CLAMP(pos,
d->hard_min,
d->hard_max);
3514 float rrpos = (rpos -
d->soft_min) / (
d->soft_max -
d->soft_min);
3516 d->min =
d->soft_min;
3521 d->max =
d->soft_max;
3559 float step =
d->
step;
3563 const float min =
d->soft_min;
3564 const float max =
d->soft_max;
3577 return copysignf(step,
d->factor);
3585 gtk_widget_queue_draw(widget);
3592 d->
min =
d->soft_min;
3593 d->max =
d->soft_max;
3602 d->
format = g_intern_string(format);
3604 if(strstr(format,
"%") && fabsf(
d->hard_max) <= 10)
3606 if(
d->factor == 1.0f)
d->factor = 100;
3640 fprintf(stderr,
"ERROR: %s - %s is set to use default callback but none is provided\n", w->module->name,
3646 fprintf(stderr,
"WARNING: %s - %s has an IOP module but doesn't use default callback\n", w->module->name,
3651 g_signal_emit_by_name(G_OBJECT(w),
"value-changed");
3669 const float old_pos =
d->
pos;
3670 const float new_pos = CLAMP(pos, 0.0f, 1.0f);
3672 if(old_pos != new_pos || raise)
3674 const float new_value = new_pos * (
d->max -
d->min) +
d->min;
3677 d->pos = (rounded_value -
d->min) / (
d->max -
d->min);
3682 gtk_widget_queue_draw(GTK_WIDGET(w));
3706 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
3716 && (
key == GDK_KEY_space ||
3717 key == GDK_KEY_percent ||
3718 (event->string[0] >= 40 && event->string[0] <= 57) ||
3719 key == GDK_KEY_asciicircum ||
key == GDK_KEY_dead_circumflex ||
3720 key == GDK_KEY_X ||
key == GDK_KEY_x))
3722 if(
key == GDK_KEY_dead_circumflex)
3729 && (
key == GDK_KEY_BackSpace ||
key == GDK_KEY_Delete))
3735 && (
key == GDK_KEY_Return))
3744 memset(bh->
keys, 0,
sizeof(bh->
keys));
3747 else if(
key == GDK_KEY_Escape)
3751 memset(bh->
keys, 0,
sizeof(bh->
keys));
3761 if(!g_utf8_validate(event->string, -1, NULL))
return FALSE;
3762 const gunichar c = g_utf8_get_char(event->string);
3763 const long int char_width = g_utf8_next_char(event->string) -
event->string;
3764 if(bh->
keys_cnt + 1 + char_width < 64 && g_unichar_isprint(c))
3767 g_utf8_strncpy(bh->
keys + bh->
keys_cnt, event->string, 1);
3772 && (
key == GDK_KEY_BackSpace ||
key == GDK_KEY_Delete))
3781 && (
key == GDK_KEY_Return))
3791 memset(bh->
keys, 0,
sizeof(bh->
keys));
3794 else if(
key == GDK_KEY_Escape)
3798 memset(bh->
keys, 0,
sizeof(bh->
keys));
3801 else if(
key == GDK_KEY_Up)
3805 else if(
key == GDK_KEY_Down)
3809 else if(
key == GDK_KEY_Return)
3815 memset(bh->
keys, 0,
sizeof(bh->
keys));
3833 double event_x =
event->x;
3834 double event_y =
event->y;
3835 double main_width = 0.;
3846 gtk_widget_grab_focus(widget);
3856 if(event->button == 1)
3858 if(event->type == GDK_2BUTTON_PRESS)
3881 else if(event->button == 3)
3887 else if(event->button == 2)
3912 if(event->button == 1)
3927 if(
d->is_dragging && event->state & GDK_BUTTON1_MASK)
3929 double event_x =
event->x;
3930 double event_y =
event->y;
void dt_accels_new_virtual_shortcut(dt_accels_t *accels, GtkAccelGroup *accel_group, const gchar *accel_path, GtkWidget *widget, guint key_val, GdkModifierType accel_mods)
Add a new virtual shortcut. Virtual shortcuts are immutable, read-only and don't trigger any action....
gchar * dt_accels_build_path(const gchar *scope, const gchar *feature)
void dt_accels_remove_accel(dt_accels_t *accels, const char *path, gpointer data)
Recursively remove all accels for all shortcuts containing path. This is unneeded for accels attached...
Handle default and user-set shortcuts (accelerators)
GtkWidget * dt_bauhaus_slider_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
static gboolean dt_bauhaus_popup_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
int dt_bauhaus_slider_get_digits(GtkWidget *widget)
GtkWidget * dt_bauhaus_combobox_new_full(dt_bauhaus_t *bh, dt_gui_module_t *self, const char *label, const char *tip, int pos, GtkCallback callback, gpointer data, const char **texts)
static float _bh_get_row_height(struct dt_bauhaus_widget_t *w)
Get the total height of a GUI row containing a line of text + top and bottom padding.
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
static gboolean ensure_focus_idle(gpointer data)
static gboolean dt_bauhaus_popup_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
GtkWidget * dt_bauhaus_slider_from_widget(dt_bauhaus_t *bh, dt_bauhaus_widget_t *w, dt_gui_module_t *self, float min, float max, float step, float defval, int digits, int feedback)
void dt_bauhaus_combobox_insert(GtkWidget *widget, const char *text, int pos)
static gboolean _widget_key_press(GtkWidget *widget, GdkEventKey *event)
void dt_bauhaus_slider_set_hard_max(GtkWidget *widget, float val)
static _bh_active_region_t _bh_get_active_region(GtkWidget *widget, double *x, double *y, double *width, GtkWidget *popup)
Check if we have user cursor over quad area or over the slider/main area, then correct cursor coordin...
void dt_bauhaus_combobox_clear(GtkWidget *widget)
static gboolean dt_bauhaus_popup_scroll(GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
static gboolean _widget_scroll(GtkWidget *widget, GdkEventScroll *event)
void dt_bauhaus_slider_clear_stops(GtkWidget *widget)
static gboolean dt_bauhaus_slider_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
static void _delayed_slider_commit(gpointer data)
static gboolean dt_bauhaus_popup_leave_notify(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
static void dt_bauhaus_widget_reject(struct dt_bauhaus_widget_t *w)
char * dt_bauhaus_slider_get_text(GtkWidget *w, float val)
void dt_bauhaus_combobox_set_selected_text_align(GtkWidget *widget, const dt_bauhaus_combobox_alignment_t text_align)
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
static double _widget_get_main_width(struct dt_bauhaus_widget_t *w, GtkWidget *widget, double *total_width)
Get the width of the main Bauhaus widget area (slider scale or combobox), accounting for quad space,...
gboolean dt_bauhaus_focus_in_callback(GtkWidget *widget, GdkEventFocus event, gpointer user_data)
void dt_bauhaus_hide_popup(dt_bauhaus_t *bh)
gboolean dt_bauhaus_focus_callback(GtkWidget *widget, GtkDirectionType direction, gpointer data)
static double _get_slider_height(GtkWidget *widget)
void dt_bauhaus_slider_reset(GtkWidget *widget)
static void dt_bauhaus_window_show(GtkWidget *w, gpointer user_data)
static void _style_updated(GtkWidget *widget)
void dt_bauhaus_cleanup(dt_bauhaus_t *bauhaus)
static float _bh_slider_get_min_step(const struct dt_bauhaus_widget_t *const w)
Return the minimum representable value step, for current UI scaling factor and number of digits.
static gboolean _resize_handle_button(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
const char * dt_bauhaus_combobox_get_entry(GtkWidget *widget, int pos)
gboolean dt_bauhaus_focus_out_callback(GtkWidget *widget, GdkEventFocus event, gpointer user_data)
static void dt_bauhaus_draw_baseline(struct dt_bauhaus_widget_t *w, cairo_t *cr, float width)
Draw the slider baseline, aka the backgronud bar.
void dt_bauhaus_slider_set_stop(GtkWidget *widget, float stop, float r, float g, float b)
#define DT_BAUHAUS_FOCUS_IDLE_MAX_TRIES
void dt_bauhaus_load_theme(dt_bauhaus_t *bauhaus)
float dt_bauhaus_slider_get(GtkWidget *widget)
void dt_bauhaus_combobox_set_text(GtkWidget *widget, const char *text)
static void dt_bauhaus_draw_indicator(struct dt_bauhaus_widget_t *w, float pos, cairo_t *cr, float wd)
void dt_bauhaus_combobox_entry_set_sensitive(GtkWidget *widget, int pos, gboolean sensitive)
gboolean dt_bauhaus_combobox_set_from_value(GtkWidget *widget, int value)
void dt_bauhaus_widget_release_quad(GtkWidget *widget)
GtkWidget * dt_bauhaus_slider_new_with_range_and_feedback(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits, int feedback)
void dt_bauhaus_combobox_from_widget(dt_bauhaus_t *bh, dt_bauhaus_widget_t *w, dt_gui_module_t *self)
static void _get_preferred_width(GtkWidget *widget, gint *minimum_size, gint *natural_size)
void dt_bauhaus_combobox_insert_separator_with_height(GtkWidget *widget, int pos, const float row_height_factor)
static void _delayed_combobox_commit(gpointer data)
static gboolean dt_bauhaus_popup_key_press(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
float dt_bauhaus_slider_get_soft_max(GtkWidget *widget)
static void free_combobox_entry(gpointer data)
static double _get_combobox_popup_height(struct dt_bauhaus_widget_t *w)
void dt_bauhaus_widget_set_field(GtkWidget *widget, gpointer field, dt_introspection_type_t field_type)
static void dt_bauhaus_slider_set_normalized(struct dt_bauhaus_widget_t *w, float pos, gboolean raise, gboolean timeout)
Set the value of a slider as a ratio of the GUI slider width.
static void _bh_combobox_get_hovered_entry(struct dt_bauhaus_widget_t *w)
float dt_bauhaus_slider_get_soft_min(GtkWidget *widget)
GtkWidget * dt_bauhaus_combobox_from_conf(dt_bauhaus_t *bh, dt_gui_module_t *self, const char *confkey)
static void _combobox_set(GtkWidget *widget, const int pos, gboolean timeout)
Set a combobox to a given integer position. Private API function, called from user events.
void dt_bauhaus_slider_set_feedback(GtkWidget *widget, int feedback)
static double get_slider_line_offset(const double pos, const double scale, const double x, double y, const double line_height)
static gboolean _resize_handle_cursor(GtkWidget *widget, GdkEventCrossing *event, gpointer user_data)
void dt_bauhaus_disable_module_list(GtkWidget *widget)
static void _widget_finalize(GObject *widget)
static float _bh_get_combobox_entry_height(struct dt_bauhaus_widget_t *w, const dt_bauhaus_combobox_entry_t *entry)
Get the vertical space used by a combobox popup entry.
static void _combobox_conf_value_changed(GtkWidget *widget, gpointer user_data)
float dt_bauhaus_slider_get_val(GtkWidget *widget)
static dt_bauhaus_combobox_data_t * _combobox_data(GtkWidget *widget)
void dt_bauhaus_combobox_insert_full(GtkWidget *widget, const char *text, dt_bauhaus_combobox_alignment_t align, gpointer data, void(*free_func)(void *), int pos)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_widget_set_quad_toggle(GtkWidget *widget, int toggle)
static int _combobox_selectable_count(const dt_bauhaus_combobox_data_t *d)
Count selectable combobox entries.
static gboolean dt_bauhaus_popup_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static void show_pango_text(struct dt_bauhaus_widget_t *w, GtkStyleContext *context, cairo_t *cr, GdkRectangle *bounding_box, const char *text, _bh_halign_t halign, _bh_valign_t valign, PangoEllipsizeMode ellipsize, GdkRGBA *bg_color, float *width, float *height, GtkStateFlags state)
Display text aligned in a bounding box, with pseudo-classes properties handled, and optional backgrou...
void dt_bauhaus_slider_set_offset(GtkWidget *widget, float offset)
#define DT_BAUHAUS_FOCUS_IDLE_SOURCE_KEY
static void _combobox_next_sensitive(struct dt_bauhaus_widget_t *w, int delta)
static gboolean dt_bauhaus_slider_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void dt_bauhaus_combobox_set_entries_ellipsis(GtkWidget *widget, PangoEllipsizeMode ellipis)
void dt_bauhaus_slider_set_step(GtkWidget *widget, float val)
static dt_bauhaus_combobox_entry_t * new_combobox_entry(const char *label, const char *tooltip, dt_bauhaus_combobox_alignment_t alignment, gboolean sensitive, void *data, void(*free_func)(void *))
static void _slider_zoom_range(struct dt_bauhaus_widget_t *w, float zoom)
static GdkRGBA * default_color_assign()
void dt_bauhaus_slider_set_soft_max(GtkWidget *widget, float val)
void dt_bauhaus_combobox_insert_separator(GtkWidget *widget, int pos)
void dt_bauhaus_show_popup(GtkWidget *widget)
void dt_bauhaus_set_use_default_callback(GtkWidget *widget)
Tell the widget to use the globally-defined default callback in the bauhaus structure This callback n...
int dt_bauhaus_combobox_length(GtkWidget *widget)
void dt_bauhaus_widget_set_quad_active(GtkWidget *widget, int active)
static _bh_active_region_t _popup_coordinates(dt_bauhaus_t *bh, const double x_root, const double y_root, double *event_x, double *event_y)
void dt_bauhaus_combobox_set_default(GtkWidget *widget, int def)
static double _widget_get_quad_width(struct dt_bauhaus_widget_t *w)
Get the width of the quad without padding.
float dt_bauhaus_slider_get_hard_min(GtkWidget *widget)
static double _widget_get_total_width(struct dt_bauhaus_widget_t *w, GtkWidget *widget)
Get the total width of the main Bauhaus widget area, accounting for padding and margins.
static float _bh_round_to_n_digits(const struct dt_bauhaus_widget_t *const w, float x)
Round a slider numeric value to the number of digits specified in the widget w.
void dt_bauhaus_combobox_add_full(GtkWidget *widget, const char *text, dt_bauhaus_combobox_alignment_t align, gpointer data, void(free_func)(void *data), gboolean sensitive)
gpointer dt_bauhaus_combobox_get_data(GtkWidget *widget)
void dt_bauhaus_combobox_add_populate_fct(GtkWidget *widget, void(*fct)(GtkWidget *w, void *module))
static void _bauhaus_widget_init(dt_bauhaus_t *bauhaus, dt_bauhaus_widget_t *w, dt_gui_module_t *self)
void dt_bauhaus_combobox_add_separator(GtkWidget *widget)
static float _get_combobox_max_width(GtkWidget *widget)
static dt_bauhaus_combobox_entry_t * new_combobox_separator(const float row_height_factor)
Create a new combobox separator entry.
void dt_bauhaus_combobox_add_list(GtkWidget *widget, const char **texts)
gboolean _action_request_focus(GtkAccelGroup *accel_group, GObject *accelerable, guint keyval, GdkModifierType modifier, gpointer data)
static double _get_indicator_y_position(struct dt_bauhaus_widget_t *w)
int dt_bauhaus_combobox_get_editable(GtkWidget *widget)
static void draw_slider_line(cairo_t *cr, const double pos, const double off, const double scale, const double width, const double height, const double line_height, double line_width)
const char * dt_bauhaus_widget_get_label(GtkWidget *widget)
int dt_bauhaus_widget_get_quad_active(GtkWidget *widget)
void dt_bauhaus_slider_set_soft_min(GtkWidget *widget, float val)
void dt_bauhaus_disable_accels(GtkWidget *widget)
GtkWidget * dt_bauhaus_resize_handle_new(GtkOrientation orientation, gboolean invert, const char *tooltip, dt_bauhaus_resize_handle_get_size_f get_size, dt_bauhaus_resize_handle_resize_f resize, gpointer user_data)
Create a themed handle widget driving one-dimensional resize gestures.
static void _margins_retrieve(struct dt_bauhaus_widget_t *w)
Update the box margin and padding properties of the widget w by reading CSS context.
static gboolean dt_bauhaus_slider_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static gchar * _build_label(const struct dt_bauhaus_widget_t *w)
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
void dt_bauhaus_slider_set_val(GtkWidget *widget, float val)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
static double _widget_get_main_height(struct dt_bauhaus_widget_t *w, GtkWidget *widget)
Get the height of the main Bauhaus widget area (slider scale or combobox), that is the box allocation...
float dt_bauhaus_slider_get_step(GtkWidget *widget)
static void dt_bauhaus_widget_accept(struct dt_bauhaus_widget_t *w, gboolean timeout)
static gboolean _widget_draw(GtkWidget *widget, cairo_t *crf)
static gboolean _enter_leave(GtkWidget *widget, GdkEventCrossing *event)
static void _slider_add_step(GtkWidget *widget, float delta, guint state)
void dt_bauhaus_widget_press_quad(GtkWidget *widget)
static int _combobox_entry_pos_to_public(const dt_bauhaus_combobox_data_t *d, const int entry_pos)
Convert an internal entry row to the public value index.
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
#define DT_BAUHAUS_FOCUS_IDLE_TRIES_KEY
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
void dt_bauhaus_slider_set_hard_min(GtkWidget *widget, float val)
GtkWidget * dt_bauhaus_slider_new_with_range(dt_bauhaus_t *bh, dt_gui_module_t *self, float min, float max, float step, float defval, int digits)
void dt_bauhaus_combobox_remove_at(GtkWidget *widget, int pos)
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
void dt_bauhaus_widget_set_quad_visibility(GtkWidget *widget, const gboolean visible)
static double _get_slider_bar_height(struct dt_bauhaus_widget_t *w)
static void _get_preferred_height(GtkWidget *widget, gint *minimum_size, gint *natural_size)
gboolean dt_bauhaus_combobox_set_from_text(GtkWidget *widget, const char *text)
static gboolean _resize_handle_motion(GtkWidget *widget, GdkEventMotion *event, gpointer user_data)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
float dt_bauhaus_slider_get_hard_max(GtkWidget *widget)
static void dt_bauhaus_draw_quad(struct dt_bauhaus_widget_t *w, cairo_t *cr, const double x, const double y)
static int _combobox_public_to_entry_pos(const dt_bauhaus_combobox_data_t *d, const int pos, const gboolean allow_end)
Convert a public value index to the internal entry row.
static void _translate_cursor(double *x, double *y, struct dt_bauhaus_widget_t *const w)
Translate in-place the cursor coordinates within the widget or popup according to padding and margin,...
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
void dt_bauhaus_widget_set_quad_paint(GtkWidget *widget, dt_bauhaus_quad_paint_f f, int paint_flags, void *paint_data)
static gboolean dt_bauhaus_popup_button_release(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void dt_bauhaus_combobox_add_with_tooltip(GtkWidget *widget, const char *text, const char *tooltip)
void dt_bauhaus_combobox_add_separator_with_height(GtkWidget *widget, const float row_height_factor)
dt_bauhaus_t * dt_bauhaus_init()
static void dt_bh_init(DtBauhausWidget *class)
void dt_bauhaus_slider_set_factor(GtkWidget *widget, float factor)
static gboolean dt_bauhaus_combobox_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
void dt_bauhaus_combobox_add_aligned(GtkWidget *widget, const char *text, dt_bauhaus_combobox_alignment_t align)
static double _bh_slider_get_scale(struct dt_bauhaus_widget_t *w)
static void dt_bh_class_init(DtBauhausWidgetClass *class)
static double _get_combobox_height(GtkWidget *widget)
dt_bauhaus_combobox_alignment_t
@ DT_BAUHAUS_COMBOBOX_ALIGN_RIGHT
@ DT_BAUHAUS_QUAD_PRESSED_SIGNAL
@ DT_BAUHAUS_VALUE_CHANGED_SIGNAL
#define DT_BAUHAUS_COMBO_MAX_TEXT
#define DT_BAUHAUS_WIDGET(obj)
#define DT_BAUHAUS_WIDGET_TYPE
static void set_color(cairo_t *cr, GdkRGBA color)
#define DT_BAUHAUS_COMBO_SEPARATOR_DEFAULT_HEIGHT_FACTOR
int(* dt_bauhaus_resize_handle_get_size_f)(gpointer user_data)
void(* dt_bauhaus_quad_paint_f)(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
#define DT_BAUHAUS_SLIDER_MAX_STOPS
int(* dt_bauhaus_resize_handle_resize_f)(int requested_size, gboolean finished, gpointer user_data)
float dt_calculator_solve(const float x, const char *formula)
const dt_aligned_pixel_t f
static const float const float const float min
const char * dt_confgen_get_tooltip(const char *name)
gchar * dt_conf_get_string(const char *name)
gboolean dt_confgen_value_exists(const char *name, dt_confgen_value_kind_t kind)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_confgen_get(const char *name, dt_confgen_value_kind_t kind)
dt_confgen_type_t dt_confgen_type(const char *name)
const char * dt_confgen_get_label(const char *name)
void dt_toast_log(const char *msg,...)
#define dt_control_change_cursor(cursor)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
static void dt_free_gpointer(gpointer ptr)
static const dt_aligned_pixel_simd_t value
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
G_DEFINE_TYPE(GtkDarktableDrawingArea, dtgtk_drawing_area, GTK_TYPE_DRAWING_AREA)
static guint dt_keys_mainpad_alternatives(const guint key_val)
Remap keypad keys to usual mainpad ones.
void dt_gui_cairo_set_font_options(cairo_t *cr, GtkWidget *widget)
gboolean dt_gui_get_scroll_unit_deltas(const GdkEventScroll *event, int *delta_x, int *delta_y)
void dt_capitalize_label(gchar *text)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
static cairo_surface_t * dt_cairo_image_surface_create(cairo_format_t format, int width, int height)
#define dt_accels_new_darkroom_action(a, b, c, d, e, f, g)
int dt_ui_panel_get_size(dt_ui_t *ui, const dt_ui_panel_t p)
get width of right, left, or bottom panel
gboolean dt_ui_panel_ancestor(dt_ui_t *ui, const dt_ui_panel_t p, GtkWidget *w)
is the panel ancestor of widget
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_PIXEL_APPLY_DPI(value)
void dt_gui_throttle_cancel(gpointer source)
void dt_gui_throttle_queue(gpointer source, dt_gui_throttle_callback_t callback, gpointer user_data)
void dt_iop_request_focus(dt_iop_module_t *module)
void dt_iop_gui_set_expanded(dt_iop_module_t *module, gboolean expanded, gboolean collapse_others)
static int precision(double x, double adj)
float *const restrict const size_t k
static int ipow(int base, int exp)
Fast integer power, computing base^exp.
#define CLAMPF(a, mn, mx)
static dt_mipmap_size_t get_size(const uint32_t key)
void dt_osx_disallow_fullscreen(GtkWidget *widget)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
struct dt_gui_gtk_t * gui
struct dt_develop_t * develop
GtkAccelGroup * darkroom_accels
PangoEllipsizeMode entries_ellipsis
void(* populate)(GtkWidget *w, void *module)
dt_bauhaus_combobox_alignment_t text_align
void(* free_func)(gpointer)
dt_bauhaus_combobox_alignment_t alignment
dt_bauhaus_resize_handle_get_size_f get_size
dt_bauhaus_resize_handle_resize_f resize
GtkOrientation orientation
GdkRGBA color_value_text_insensitive
GdkRGBA graph_scope_restricted
GdkRGBA colorlabels[DT_COLORLABELS_LAST]
void(* default_value_changed_callback)(GtkWidget *widget)
float mouse_line_distance
GdkRGBA color_value_insensitive
PangoFontDescription * pango_font_desc
struct dt_bauhaus_widget_t * current
GdkRGBA color_fg_insensitive
struct dt_iop_module_t * gui_module
GtkWidget * has_scroll_focus
The dt_gui_module_t type is the intersection between a dt_lib_module_t and a dt_iop_module_t structur...
typedef double((*spd)(unsigned long int wavelength, double TempK))
dt_bauhaus_combobox_data_t combobox
dt_bauhaus_slider_data_t slider
GList * dt_util_str_to_glist(const gchar *separator, const gchar *text)