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++)
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;
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);
838 y = (y - line_height) / (1.0 - line_height);
839 offset = (
x - sqf(y) * .5 - (1.0 - sqf(y)) * pos)
840 / (.5 * sqf(y) / scale + (1.0 - sqf(y)));
843 if(pos + offset > 1.0) offset = 1.0 - pos;
844 if(pos + offset < 0.0) offset = -pos;
850 const double line_height,
double line_width)
854 const int steps = 128;
855 const double corrected_height = (
height - line_height);
857 cairo_set_line_width(cr, line_width);
858 cairo_move_to(cr,
width * (pos + off), line_height);
859 const double half_line_width = line_width / 2.;
860 for(
int j = 1; j < steps; j++)
862 const double y = (
double)j / (
double)(steps - 1);
863 const double x = sqf(y) * .5f * (1.f + off / scale) + (1.0f - sqf(y)) * (pos + off);
864 cairo_line_to(cr,
x *
width - half_line_width, line_height + y * corrected_height);
875 if(roundf(zoom) == 0.f)
877 d->min =
d->soft_min;
878 d->max =
d->soft_max;
885 const float multiplier = exp2f(zoom / 2.f);
886 const float new_min =
value - multiplier * (
value -
d->min);
887 const float new_max =
value + multiplier * (
d->max -
value);
888 if(new_min >=
d->hard_min
889 && new_max <= d->hard_max
890 && new_max - new_min >= min_visible * 10)
896 gtk_widget_queue_draw(GTK_WIDGET(w));
901 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
909 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
917 fprintf(stdout,
"x: %i, y: %i, active: %i\n", (
int)event_x, (
int)event_y, active);
948 d->pos =
d->oldpos + mouse_off;
958 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL,
TRUE);
965 g_object_get(gtk_settings_get_default(),
"gtk-double-click-time", &delay, NULL);
966 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
972 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_ACTIVE,
TRUE);
986 g_object_get(gtk_settings_get_default(),
"gtk-double-click-time", &delay, NULL);
988 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
991 if(event->button == 1)
994 && event->time < bh->
opentime + delay)
1028 const float value =
d->pos;
1043 gtk_widget_queue_draw(widget);
1055 gtk_grab_add(GTK_WIDGET(user_data));
1066 if(event->type == GDK_ENTER_NOTIFY)
1068 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
FALSE);
1072 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
1077 const gboolean real_leave =
event->mode == GDK_CROSSING_NORMAL
1078 &&
event->detail != GDK_NOTIFY_INFERIOR
1084 gtk_widget_queue_draw(widget);
1105 if(event->type == GDK_ENTER_NOTIFY)
1107 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
FALSE);
1109 ? GDK_SB_V_DOUBLE_ARROW
1110 : GDK_SB_H_DOUBLE_ARROW);
1114 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
1118 gtk_widget_queue_draw(widget);
1125 if(event->button != 1)
return TRUE;
1127 if(event->type == GDK_BUTTON_PRESS)
1130 handle->
start_root = (handle->
orientation == GTK_ORIENTATION_VERTICAL) ? event->y_root :
event->x_root;
1133 gtk_grab_add(widget);
1135 ? GDK_SB_V_DOUBLE_ARROW
1136 : GDK_SB_H_DOUBLE_ARROW);
1138 else if(event->type == GDK_BUTTON_RELEASE)
1141 gtk_grab_remove(widget);
1144 GtkAllocation allocation;
1145 gtk_widget_get_allocation(widget, &allocation);
1146 const gboolean pointer_on_handle =
event->x >= 0. &&
event->x <= allocation.width
1147 &&
event->y >= 0. &&
event->y <= allocation.height;
1148 if(pointer_on_handle)
1149 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
FALSE);
1151 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
1154 ? (handle->
orientation == GTK_ORIENTATION_VERTICAL
1155 ? GDK_SB_V_DOUBLE_ARROW
1156 : GDK_SB_H_DOUBLE_ARROW)
1158 gtk_widget_queue_draw(widget);
1172 const double root = (handle->
orientation == GTK_ORIENTATION_VERTICAL) ? event->y_root :
event->x_root;
1187 GtkWidget *handle_widget = gtk_event_box_new();
1199 GtkStyleContext *ctx = gtk_widget_get_style_context(handle_widget);
1200 gtk_style_context_add_class(ctx,
"resize-handle");
1201 if(orientation == GTK_ORIENTATION_VERTICAL)
1204 gtk_widget_set_halign(handle_widget, GTK_ALIGN_FILL);
1205 gtk_widget_set_valign(handle_widget, invert ? GTK_ALIGN_START : GTK_ALIGN_END);
1206 gtk_style_context_add_class(ctx, invert ?
"resize-handle-top" :
"resize-handle-bottom");
1211 gtk_widget_set_valign(handle_widget, GTK_ALIGN_FILL);
1212 gtk_widget_set_halign(handle_widget, invert ? GTK_ALIGN_START : GTK_ALIGN_END);
1213 gtk_style_context_add_class(ctx, invert ?
"resize-handle-left" :
"resize-handle-right");
1216 gtk_widget_set_events(handle_widget, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1217 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
1218 | GDK_POINTER_MOTION_MASK);
1220 gtk_widget_set_tooltip_text(handle_widget,
tooltip);
1222 g_object_set_data_full(G_OBJECT(handle_widget),
"dt-bauhaus-resize-handle", handle, g_free);
1223 g_signal_connect(G_OBJECT(handle_widget),
"button-press-event", G_CALLBACK(
_resize_handle_button), handle);
1224 g_signal_connect(G_OBJECT(handle_widget),
"button-release-event", G_CALLBACK(
_resize_handle_button), handle);
1225 g_signal_connect(G_OBJECT(handle_widget),
"motion-notify-event", G_CALLBACK(
_resize_handle_motion), handle);
1226 g_signal_connect(G_OBJECT(handle_widget),
"enter-notify-event", G_CALLBACK(
_resize_handle_cursor), handle);
1227 g_signal_connect(G_OBJECT(handle_widget),
"leave-notify-event", G_CALLBACK(
_resize_handle_cursor), handle);
1229 return handle_widget;
1237 if(focus_source > 0)
1239 g_source_remove(focus_source);
1244 const char *accel_path = g_object_get_data(G_OBJECT(widget),
"accel-path");
1260 g_ptr_array_free(
d->entries,
TRUE);
1263 gtk_border_free(w->
margin);
1266 G_OBJECT_CLASS(dt_bh_parent_class)->finalize(widget);
1272 = g_signal_new(
"value-changed", G_TYPE_FROM_CLASS(
class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1273 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1275 = g_signal_new(
"quad-pressed", G_TYPE_FROM_CLASS(
class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1276 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1278 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(
class);
1296 GtkStyleContext *ctx = gtk_widget_get_style_context(root_window);
1297 gtk_style_context_set_screen(ctx, gtk_widget_get_screen(root_window));
1299 gtk_style_context_lookup_color(ctx,
"bauhaus_fg", &
bauhaus->
color_fg);
1301 gtk_style_context_lookup_color(ctx,
"bauhaus_bg", &
bauhaus->
color_bg);
1327 gtk_style_context_lookup_color(ctx,
"colorlabel_red",
1329 gtk_style_context_lookup_color(ctx,
"colorlabel_yellow",
1331 gtk_style_context_lookup_color(ctx,
"colorlabel_green",
1333 gtk_style_context_lookup_color(ctx,
"colorlabel_blue",
1335 gtk_style_context_lookup_color(ctx,
"colorlabel_purple",
1344 cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 128, 128);
1345 cairo_t *cr = cairo_create(cst);
1349 ctx = gtk_widget_get_style_context(ref);
1352 PangoContext *context = gtk_widget_get_pango_context(ref);
1353 PangoLayout *layout = pango_layout_new(context);
1354 pango_layout_set_text(layout,
"em", -1);
1364 pango_cairo_update_layout(cr, layout);
1365 pango_cairo_show_layout(cr, layout);
1370 pango_layout_get_size(layout, &pango_width, &pango_height);
1371 g_object_unref(layout);
1373 cairo_surface_destroy(cst);
1397#ifdef GDK_WINDOWING_QUARTZ
1416 gtk_window_set_type_hint(GTK_WINDOW(
bauhaus->
popup_window), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
1426 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1427 | GDK_KEY_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK
1432 g_object_set_data(area,
"bauhaus",
bauhaus);
1444 gchar *path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Increase value (normal step)"));
1446 path, NULL, GDK_KEY_Right, 0);
1448 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Decrease value (normal step)"));
1450 path, NULL, GDK_KEY_Left, 0);
1454 path, NULL, GDK_KEY_Right, GDK_CONTROL_MASK);
1458 path, NULL, GDK_KEY_Left, GDK_CONTROL_MASK);
1460 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Increase value (coarse step)"));
1462 path, NULL, GDK_KEY_Right, GDK_SHIFT_MASK);
1464 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Decrease value (coarse step)"));
1466 path, NULL, GDK_KEY_Left, GDK_SHIFT_MASK);
1470 path, NULL, GDK_KEY_Insert, 0);
1475 path, NULL, GDK_KEY_Return, 0);
1479 path, NULL, GDK_KEY_Escape, 0);
1481 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Select previous (in editing mode)"));
1483 path, NULL, GDK_KEY_Up, 0);
1485 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Select next (in editing mode)"));
1487 path, NULL, GDK_KEY_Down, 0);
1489 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Validate result (in editing mode)"));
1491 path, NULL, GDK_KEY_Return, 0);
1495 path, NULL, GDK_KEY_Insert, 0);
1536 gtk_widget_add_events(GTK_WIDGET(w), GDK_POINTER_MOTION_MASK
1537 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1538 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
1539 | GDK_FOCUS_CHANGE_MASK
1542 gtk_widget_set_can_focus(GTK_WIDGET(w),
TRUE);
1543 gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_FILL);
1544 gtk_widget_set_hexpand(GTK_WIDGET(w),
TRUE);
1566 d->min =
MAX(
d->min,
d->hard_min);
1567 d->soft_min =
MAX(
d->soft_min,
d->hard_min);
1569 if(desired_position >
d->hard_max)
1572 if(current_position < desired_position)
1590 d->hard_max = desired_position;
1591 d->max =
MIN(
d->max,
d->hard_max);
1592 d->soft_max =
MIN(
d->soft_max,
d->hard_max);
1594 if(desired_position < d->hard_min)
1597 if(current_position > desired_position)
1614 d->min =
d->soft_min = CLAMP(val,
d->hard_min,
d->hard_max);
1631 d->max =
d->soft_max = CLAMP(val,
d->hard_min,
d->hard_max);
1670 m->widget_list = g_list_append(
m->widget_list, w);
1673 m->widget_list_bh = g_list_append(
m->widget_list_bh, w);
1681 assert(g_strrstr(
label,
"/") == NULL);
1683 gchar *plugin_name = g_strdup_printf(
"%s/%s",
m->name, w->
label);
1686 gchar *scope = g_strdup_printf(
"%s/Modules",
m->view);
1688 g_object_set_data_full(G_OBJECT(widget),
"accel-path",
1690 gtk_widget_set_has_tooltip(widget,
TRUE);
1695 gtk_widget_queue_draw(GTK_WIDGET(w));
1717 fprintf(stderr,
"[dt_bauhaus_widget_set_field] bauhaus label '%s' set before field (needs to be after)\n", w->
label);
1736 gtk_widget_queue_draw(GTK_WIDGET(w));
1743 gtk_widget_queue_draw(GTK_WIDGET(w));
1762 g_signal_emit_by_name(G_OBJECT(w),
"quad-pressed");
1768 gtk_widget_grab_focus(widget);
1774 gtk_widget_queue_draw(GTK_WIDGET(w));
1784 float defval,
int digits)
1790 float step,
float defval,
int digits,
int feedback)
1811 float step,
float defval,
int digits,
int feedback)
1816 d->
min =
d->soft_min =
d->hard_min =
min;
1817 d->max =
d->soft_max =
d->hard_max =
max;
1832 d->fill_feedback = feedback;
1842 return GTK_WIDGET(w);
1849 return GTK_WIDGET(w);
1853 int pos, GtkCallback callback, gpointer
data,
const char **texts)
1859 gtk_widget_set_tooltip_text(combo, tip ? tip : _(
label));
1860 if(callback) g_signal_connect(G_OBJECT(combo),
"value-changed", G_CALLBACK(callback),
data);
1875 fprintf(stderr,
"[dt_bauhaus_combobox_from_conf] `%s` is not declared as an <enum> config entry\n", confkey);
1889 int pos = 0, active = 0;
1890 for(GList *opt =
options; opt; opt = g_list_next(opt))
1892 char *item = (
char *)opt->data;
1894 if(item[0] ==
'[') item++;
1895 else if(item[strlen(item) - 1] ==
']') item[strlen(item) - 1] =
'\0';
1900 if(!g_strcmp0(current, item)) active = pos;
1925 d->entries_ellipsis = PANGO_ELLIPSIZE_END;
1941 if(
d->active >=
d->entries->len)
d->
active = -1;
1970 const gboolean allow_end)
1974 int selectable_pos = 0;
1975 for(
int i = 0;
i <
d->entries->len;
i++)
1979 if(selectable_pos == pos)
return i;
1983 return (allow_end && selectable_pos == pos) ? (int)
d->entries->len : -1;
1991 if(
IS_NULL_PTR(
d) || entry_pos < 0 || entry_pos >=
d->entries->len)
return -1;
1993 int selectable_pos = 0;
1994 for(
int i = 0;
i <= entry_pos;
i++)
1998 if(
i == entry_pos)
return selectable_pos;
2010 w->data.combobox.populate = fct;
2015 while(texts && *texts)
2032 g_ptr_array_add(
d->entries, entry);
2033 if(
d->active < 0)
d->active = (int)
d->entries->len - 1;
2042 gpointer
data,
void (free_func)(
void *
data), gboolean sensitive)
2049 g_ptr_array_add(
d->entries, entry);
2050 if(
d->active < 0)
d->active = (int)
d->entries->len - 1;
2092 return d ?
d->editable : 0;
2110 if(entry_pos < 0)
return;
2115 if(
d->active > entry_pos ||
d->active ==
d->entries->len-1)
2118 g_ptr_array_remove_index(
d->entries, entry_pos);
2127 gpointer
data,
void (*free_func)(
void *),
int pos)
2133 if(entry_pos < 0)
return;
2136 d->active = entry_pos;
2137 else if(entry_pos <= d->active)
2153 if(entry_pos < 0)
return;
2155 if(entry_pos <= d->active)
d->active++;
2172 return d->editable ?
d->text : NULL;
2178 return entry->
label;
2199 g_ptr_array_set_size(
d->entries, 0);
2206 if(entry_pos < 0)
return NULL;
2209 return entry->
label;
2236 fprintf(stderr,
"ERROR: %s - %s is set to use default callback but none is provided\n", w->module->name,
2242 fprintf(stderr,
"WARNING: %s - %s has an IOP module but doesn't use default callback\n", w->module->name,
2247 g_signal_emit_by_name(G_OBJECT(w),
"value-changed");
2264 const int old_pos =
d->
active;
2265 const int new_pos = (
d->entries) ? CLAMP(pos, -1, (
int)
d->entries->len - 1)
2278 if(old_pos != new_pos)
2280 d->active = new_pos;
2285 gtk_widget_queue_draw(GTK_WIDGET(w));
2308 const int public_pos = (selectable_count > 0) ? CLAMP(pos, -1, selectable_count - 1) : -1;
2320 for(
int i = 0;
d &&
i <
d->entries->len;
i++)
2324 if(!g_strcmp0(entry->
label, text))
2337 for(
int i = 0;
d &&
i <
d->entries->len;
i++)
2341 if(GPOINTER_TO_INT(entry->
data) ==
value)
2361 if(entry_pos < 0)
return;
2387 for(
int k = 0;
k <
d->grad_cnt;
k++)
2389 if(
d->grad_pos[
k] == stop)
2391 d->grad_col[
k][0] =
r;
2392 d->grad_col[
k][1] =
g;
2393 d->grad_col[
k][2] = b;
2400 int k =
d->grad_cnt++;
2401 d->grad_pos[
k] = stop;
2402 d->grad_col[
k][0] =
r;
2403 d->grad_col[
k][1] =
g;
2404 d->grad_col[
k][2] = b;
2417 const float horizontal_position = pos * wd;
2420 cairo_translate(cr, horizontal_position, vertical_position);
2423 const gboolean has_colored_background =
d->
grad_cnt > 0;
2425 if(!has_colored_background &&
d->fill_feedback)
2428 cairo_arc(cr, 0, 0,
size / 2., 0,
M_PI * 2);
2430 cairo_set_line_width(cr, 0);
2438 cairo_set_line_width(cr, border);
2439 const float radius =
size / 2. - border / 2.;
2440 cairo_arc(cr, 0, 0, radius, 0,
M_PI * 2);
2469 cairo_move_to(cr, -
r, -
r * .5f);
2470 cairo_line_to(cr, 0,
r * .5f);
2471 cairo_line_to(cr,
r, -
r * .5f);
2489 const gboolean has_colored_background =
d->
grad_cnt > 0;
2492 const gboolean is_sensitive = gtk_widget_is_sensitive(GTK_WIDGET(w));
2504 const double baseline_width =
width - x_origin;
2506 cairo_rectangle(cr, round(x_origin), round(baseline_top),
2507 round(baseline_width), round(baseline_height));
2509 cairo_pattern_t *gradient = NULL;
2510 if(has_colored_background && is_sensitive)
2513 const double zoom = (
d->max -
d->min) / (
d->hard_max -
d->hard_min);
2514 const double offset = (
d->min -
d->hard_min) / (
d->hard_max -
d->hard_min);
2515 gradient = cairo_pattern_create_linear(x_origin, 0,
width, baseline_height);
2516 for(
int k = 0;
k <
d->grad_cnt;
k++)
2517 cairo_pattern_add_color_stop_rgba(gradient, (
d->grad_pos[
k] - offset) / zoom,
2518 d->grad_col[
k][0],
d->grad_col[
k][1],
d->grad_col[
k][2], 0.4f);
2519 cairo_set_source(cr, gradient);
2534 const double line_width = 1.;
2535 cairo_rectangle(cr, round(x_origin) + line_width / 2., round(baseline_top) + line_width / 2.,
2536 round(baseline_width) - line_width, round(baseline_height) - line_width);
2537 cairo_set_line_width(cr, line_width);
2542 if(gradient) cairo_pattern_destroy(gradient);
2545 float origin = fmaxf(fminf((
d->factor > 0 ? -
d->min -
d->offset/
d->factor
2546 :
d->max +
d->offset/
d->factor)
2547 / (
d->max -
d->min),
2552 if(!has_colored_background &&
d->fill_feedback && is_sensitive)
2562 cairo_rectangle(cr, x_origin, baseline_top,
delta - x_origin, baseline_height);
2564 cairo_rectangle(cr, origin, baseline_top,
delta, baseline_height);
2572 if(
d->hard_max != 360.0f && is_sensitive)
2620 fprintf(stdout,
"combobox went the custom path\n");
2630 gchar *keys = g_utf8_casefold(w->
bauhaus->
keys, -1);
2634 for(
int j = 0; j <
d->entries->len; j++)
2637 gchar *text_cmp = g_utf8_casefold(entry->
label, -1);
2682 return g_strdup(w->
label);
2690 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
2694 GtkAllocation allocation;
2695 gtk_widget_get_allocation(widget, &allocation);
2697 cairo_t *cr = cairo_create(cst);
2698 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2701 GdkRGBA text_color, text_color_selected, text_color_hover, text_color_insensitive, text_color_focused;
2702 gtk_style_context_get_color(context, GTK_STATE_FLAG_NORMAL, &text_color);
2703 gtk_style_context_get_color(context, GTK_STATE_FLAG_SELECTED, &text_color_selected);
2704 gtk_style_context_get_color(context, GTK_STATE_FLAG_PRELIGHT, &text_color_hover);
2705 gtk_style_context_get_color(context, GTK_STATE_FLAG_INSENSITIVE, &text_color_insensitive);
2706 gtk_style_context_get_color(context, GTK_STATE_FLAG_FOCUSED, &text_color_focused);
2710 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2712 gtk_style_context_get(context,
state,
"background-color", &bg_color, NULL);
2713 gtk_style_context_get_color(context,
state, fg_color);
2716 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
2717 gtk_render_frame(context, cr, 0, 0, allocation.width, allocation.height);
2720 double total_width = 0.f;
2733 const double text_width = main_width + slider_cursor_radius;
2735 cairo_translate(cr, slider_cursor_radius, 0.0);
2739 const int num_scales = 1.f / scale;
2742 for(
int k = 0;
k < num_scales;
k++)
2744 const float off =
k * scale -
d->oldpos;
2745 GdkRGBA fg_copy = *fg_color;
2746 fg_copy.alpha = scale / fabsf(off);
2748 draw_slider_line(cr,
d->oldpos, off, scale, main_width, main_height, bottom_baseline, 1);
2754 const double mouse_off =
d->pos -
d->oldpos;
2757 cairo_translate(cr, slider_cursor_radius, 0.0);
2764 draw_slider_line(cr,
d->oldpos, mouse_off, scale, main_width, main_height, bottom_baseline, 2);
2776 float value_width = 0.f;
2778 GdkRectangle bounding_value = { .x = 0.,
2780 .width = text_width,
2785 BH_ALIGN_MIDDLE, PANGO_ELLIPSIZE_NONE, NULL, &value_width, NULL, GTK_STATE_FLAG_NORMAL);
2790 const float label_width = text_width - value_width -
INNER_PADDING;
2791 GdkRectangle bounding_label = { .x = 0.,
2793 .width = label_width,
2797 PANGO_ELLIPSIZE_END, NULL, NULL, NULL, GTK_STATE_FLAG_NORMAL);
2808 double popup_y = 0.;
2814 GdkRectangle query_label = { .x = 0.,
2816 .width = main_width,
2817 .height = query_height };
2819 PANGO_ELLIPSIZE_NONE, NULL, NULL, NULL, GTK_STATE_FLAG_NORMAL);
2820 popup_y += query_height;
2825 gchar *keys = g_utf8_casefold(w->
bauhaus->
keys, -1);
2826 for(
int j = 0; j <
d->entries->len; j++)
2834 cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.);
2835 cairo_move_to(cr, 0., popup_y + 0.5 * entry_height);
2836 cairo_line_to(cr, main_width, popup_y + 0.5 * entry_height);
2837 cairo_set_line_width(cr, 1.);
2840 popup_y += entry_height;
2844 gchar *text_cmp = g_utf8_casefold(entry->
label, -1);
2854 state = GTK_STATE_FLAG_INSENSITIVE;
2856 else if(j ==
d->active)
2859 state = GTK_STATE_FLAG_SELECTED;
2861 else if(j ==
d->hovered)
2864 state = GTK_STATE_FLAG_PRELIGHT;
2869 state = GTK_STATE_FLAG_NORMAL;
2872 GdkRectangle bounding_label = { .x = 0.,
2874 .width = main_width,
2875 .height = entry_height };
2877 cairo_rectangle(cr, bounding_label.x, bounding_label.y, bounding_label.width, bounding_label.height);
2878 cairo_set_line_width(cr, 2);
2882 d->entries_ellipsis, bg_color, NULL, NULL,
state);
2886 popup_y += entry_height;
2898 cairo_set_source_surface(crf, cst, 0, 0);
2900 cairo_surface_destroy(cst);
2902 gdk_rgba_free(bg_color);
2903 gdk_rgba_free(fg_color);
2914 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2915 const GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2918 cairo_t *cr = cairo_create(cst);
2926 float label_width = 0.f;
2927 GdkRectangle bounding_label = { .x = 0.,
2933 PANGO_ELLIPSIZE_NONE, NULL, &label_width, NULL,
state);
2938 float max_entry = 0.f;
2939 for(
int i = 0;
i <
d->entries->len;
i++)
2944 GdkRectangle bounding_value = { .x = 0,
2948 float entry_label_width = 0.f;
2951 &entry_label_width, NULL,
state);
2960 cairo_surface_destroy(cst);
2968 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2971 GtkAllocation allocation;
2972 gtk_widget_get_allocation(widget, &allocation);
2984 if(max_width < allocation.width)
2985 allocation.width = ceilf(max_width);
2989 gtk_widget_size_allocate(widget, &allocation);
2992 cairo_t *cr = cairo_create(cst);
2997 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2998 if(gtk_widget_has_focus(widget))
2999 state |= GTK_STATE_FLAG_FOCUSED;
3001 gtk_style_context_save(context);
3002 gtk_style_context_set_state(context,
state);
3003 gtk_style_context_get_color(context,
state, text_color);
3011 const float box_width = allocation.width - w->
margin->left - w->
margin->right;
3012 const float box_height = allocation.height - w->
margin->top - w->
margin->bottom;
3015 gtk_render_background(context, crf, w->
margin->left, w->
margin->top, box_width, box_height);
3016 gtk_render_frame(context, crf, w->
margin->left, w->
margin->top, box_width, box_height);
3029 cairo_set_line_width(cr, 1.0);
3044 float label_width = 0.f;
3045 float label_height = 0.f;
3047 GdkRectangle bounding_label = { .x = 0.,
3049 .width = available_width,
3050 .height = inner_height };
3053 combo_ellipsis, NULL, &label_width, &label_height,
state);
3056 gchar *text =
d->text;
3057 if(
d->active >= 0 &&
d->active <
d->entries->len)
3060 text = entry->
label;
3062 GdkRectangle bounding_value = { .x = label_width +
INNER_PADDING,
3065 .height = inner_height };
3075 const double text_width = available_width + slider_cursor_radius;
3079 cairo_translate(cr, slider_cursor_radius, 0.0);
3087 cairo_set_source_rgba(cr, text_color->red, text_color->green, text_color->blue, text_color->alpha * 0.7);
3092 float value_width = 0;
3093 if(gtk_widget_is_sensitive(widget))
3096 cairo_translate(cr, slider_cursor_radius, 0.0);
3101 GdkRectangle bounding_value = { .x = 0.,
3103 .width = text_width,
3107 PANGO_ELLIPSIZE_NONE, NULL, &value_width, NULL,
state);
3113 const float label_width = text_width - value_width -
INNER_PADDING;
3114 GdkRectangle bounding_label = { .x = 0.,
3116 .width = label_width,
3120 PANGO_ELLIPSIZE_END, NULL, NULL, NULL,
state);
3129 cairo_set_source_surface(crf, cst, 0, 0);
3131 cairo_surface_destroy(cst);
3132 gtk_style_context_restore(context);
3134 gdk_rgba_free(text_color);
3135 gdk_rgba_free(value_color);
3136 gdk_rgba_free(value_text_color);
3181 gtk_window_set_attached_to(GTK_WINDOW(bh->
popup_window), NULL);
3184 gtk_widget_grab_focus(GTK_WIDGET(bh->
current));
3204 gtk_widget_realize(widget);
3208 gtk_widget_get_allocation(widget, &tmp);
3230 fprintf(stderr,
"[dt_bauhaus_show_popup] The bauhaus widget has an unknown type\n");
3236 GtkStyleContext *context = gtk_widget_get_style_context(w->
bauhaus->
popup_area);
3237 gtk_style_context_add_class(context,
"dt_bauhaus_popup");
3239 #ifdef GDK_WINDOWING_WAYLAND
3240 if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
3241 GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
3249 gint wx = 0, wy = 0;
3250 GdkWindow *widget_window = gtk_widget_get_window(widget);
3251 if(widget_window) gdk_window_get_origin(widget_window, &wx, &wy);
3255 gint wwx = 0, wwy = 0;
3257 if(main_window) gdk_window_get_origin(main_window, &wwx, &wwy);
3259 GdkRectangle anchor = {
3262 .width =
MAX(tmp.width, 1),
3263 .height =
MAX(tmp.height, 1)
3282 gdk_window_move_to_rect(GDK_WINDOW(
window), &anchor, GDK_GRAVITY_STATIC, GDK_GRAVITY_STATIC,
3283 GDK_ANCHOR_SLIDE, 0, 0);
3291 if(
delta == 0.f)
return;
3300 const float min_visible = 1.f / (fabsf(
d->factor) *
ipow(10,
d->digits));
3301 if(fabsf(
delta) < min_visible)
3313 const gboolean key_captured = gtk_widget_has_focus(widget);
3314 const gboolean smooth = (
event->direction == GDK_SCROLL_SMOOTH);
3324 if(!key_captured && !popup_captured && !scroll_captured)
3341 const gboolean vscroll = delta_y != 0 && abs(delta_y) > abs(delta_x);
3342 const gboolean hscroll = delta_x != 0 && abs(delta_x) > abs(delta_y);
3391 case GDK_KEY_Insert:
3407 case GDK_KEY_Return:
3411 case GDK_KEY_Insert:
3430 double event_x =
event->x;
3431 double event_y =
event->y;
3444 gtk_widget_grab_focus(widget);
3455 if(event->button == 3)
3462 else if(event->button == 1)
3465 if(event->type == GDK_2BUTTON_PRESS)
3491 return d->
min +
d->pos * (
d->max -
d->min);
3503 if((
d->hard_max *
d->factor +
d->offset)*(
d->hard_min *
d->factor +
d->offset) < 0)
3504 return g_strdup_printf(
"%+.*f%s",
d->digits, val *
d->factor +
d->offset,
d->format);
3506 return g_strdup_printf(
"%.*f%s",
d->digits, val *
d->factor +
d->offset,
d->format);
3520 const float rpos = CLAMP(pos,
d->hard_min,
d->hard_max);
3523 float rrpos = (rpos -
d->soft_min) / (
d->soft_max -
d->soft_min);
3525 d->min =
d->soft_min;
3530 d->max =
d->soft_max;
3574 float step =
d->
step;
3578 const float min =
d->soft_min;
3579 const float max =
d->soft_max;
3592 return copysignf(step,
d->factor);
3600 gtk_widget_queue_draw(widget);
3607 d->
min =
d->soft_min;
3608 d->max =
d->soft_max;
3617 d->
format = g_intern_string(format);
3619 if(strstr(format,
"%") && fabsf(
d->hard_max) <= 10)
3621 if(
d->factor == 1.0f)
d->factor = 100;
3655 fprintf(stderr,
"ERROR: %s - %s is set to use default callback but none is provided\n", w->module->name,
3661 fprintf(stderr,
"WARNING: %s - %s has an IOP module but doesn't use default callback\n", w->module->name,
3666 g_signal_emit_by_name(G_OBJECT(w),
"value-changed");
3684 const float old_pos =
d->
pos;
3685 const float new_pos = CLAMP(pos, 0.0f, 1.0f);
3687 if(old_pos != new_pos || raise)
3689 const float new_value = new_pos * (
d->max -
d->min) +
d->min;
3692 d->pos = (rounded_value -
d->min) / (
d->max -
d->min);
3697 gtk_widget_queue_draw(GTK_WIDGET(w));
3721 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
3731 && (
key == GDK_KEY_space ||
3732 key == GDK_KEY_percent ||
3733 (event->string[0] >= 40 && event->string[0] <= 57) ||
3734 key == GDK_KEY_asciicircum ||
key == GDK_KEY_dead_circumflex ||
3735 key == GDK_KEY_X ||
key == GDK_KEY_x))
3737 if(
key == GDK_KEY_dead_circumflex)
3744 && (
key == GDK_KEY_BackSpace ||
key == GDK_KEY_Delete))
3750 && (
key == GDK_KEY_Return))
3759 memset(bh->
keys, 0,
sizeof(bh->
keys));
3762 else if(
key == GDK_KEY_Escape)
3766 memset(bh->
keys, 0,
sizeof(bh->
keys));
3776 if(!g_utf8_validate(event->string, -1, NULL))
return FALSE;
3777 const gunichar c = g_utf8_get_char(event->string);
3778 const long int char_width = g_utf8_next_char(event->string) -
event->string;
3779 if(bh->
keys_cnt + 1 + char_width < 64 && g_unichar_isprint(c))
3782 g_utf8_strncpy(bh->
keys + bh->
keys_cnt, event->string, 1);
3787 && (
key == GDK_KEY_BackSpace ||
key == GDK_KEY_Delete))
3796 && (
key == GDK_KEY_Return))
3806 memset(bh->
keys, 0,
sizeof(bh->
keys));
3809 else if(
key == GDK_KEY_Escape)
3813 memset(bh->
keys, 0,
sizeof(bh->
keys));
3816 else if(
key == GDK_KEY_Up)
3820 else if(
key == GDK_KEY_Down)
3824 else if(
key == GDK_KEY_Return)
3830 memset(bh->
keys, 0,
sizeof(bh->
keys));
3848 double event_x =
event->x;
3849 double event_y =
event->y;
3850 double main_width = 0.;
3861 gtk_widget_grab_focus(widget);
3871 if(event->button == 1)
3873 if(event->type == GDK_2BUTTON_PRESS)
3896 else if(event->button == 3)
3902 else if(event->button == 2)
3927 if(event->button == 1)
3942 if(
d->is_dragging && event->state & GDK_BUTTON1_MASK)
3944 double event_x =
event->x;
3945 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)
static void _dt_bauhaus_slider_set_with_raise(GtkWidget *widget, float pos, gboolean raise)
#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)
void void void gboolean dt_gui_widgets_suppressed(void)
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)