73#include <glib/gi18n.h>
74#ifdef GDK_WINDOWING_QUARTZ
80#include <pango/pangocairo.h>
82#ifdef GDK_WINDOWING_WAYLAND
83#include <gdk/gdkwayland.h>
127 GtkStyleContext *context = gtk_widget_get_style_context(GTK_WIDGET(w));
128 const GtkStateFlags
state = gtk_widget_get_state_flags(GTK_WIDGET(w));
129 gtk_style_context_get_margin(context,
state, w->
margin);
130 gtk_style_context_get_padding(context,
state, w->
padding);
133 GtkBorder *borders = gtk_border_new();
134 gtk_style_context_get_border(context,
state, borders);
135 w->
margin->left += borders->left;
136 w->
margin->right += borders->right;
137 w->
margin->top += borders->top;
138 w->
margin->bottom += borders->bottom;
139 gtk_border_free(borders);
190 GtkWidget *box_reference = (widget) ? widget : GTK_WIDGET(w);
191 GtkAllocation allocation;
192 gtk_widget_get_allocation(box_reference, &allocation);
211 if(total_width) *total_width = tot_width;
224 GtkWidget *box_reference = (widget) ? widget : GTK_WIDGET(w);
225 GtkAllocation allocation;
226 gtk_widget_get_allocation(box_reference, &allocation);
280 if(
d->populate)
d->
populate(GTK_WIDGET(w), module);
281 if(!
d->entries->len)
return 0.;
288 for(
int i = 0;
i <
d->entries->len;
i++)
309 const double left_offset = w->
margin->left + w->
padding->left + slider_cursor_radius;
339 GtkWidget *box_reference = (popup) ? popup : widget;
348 if(*y < 0. || *y > main_height || *x < 0. || *x > total_width)
412 for(
int i = 0;
i <
d->entries->len;
i++)
435 gdk_window_get_origin(
window, &wx, &wy);
436 *event_x = x_root - (
double)wx;
437 *event_y = y_root - (
double)wy;
443#define DT_BAUHAUS_FOCUS_IDLE_SOURCE_KEY "dt-bauhaus-focus-idle-source"
444#define DT_BAUHAUS_FOCUS_IDLE_TRIES_KEY "dt-bauhaus-focus-idle-tries"
445#define DT_BAUHAUS_FOCUS_IDLE_MAX_TRIES 20
449 if(!GTK_IS_WIDGET(target))
return G_SOURCE_REMOVE;
453 for(
GtkWidget *w = child; w; w = gtk_widget_get_parent(w))
455 if(GTK_IS_NOTEBOOK(w))
458 while(!
IS_NULL_PTR(page) && gtk_widget_get_parent(page) != w)
459 page = gtk_widget_get_parent(page);
461 GtkNotebook *nb = GTK_NOTEBOOK(w);
462 const gint page_num = !
IS_NULL_PTR(page) ? gtk_notebook_page_num(nb, page) : -1;
463 if(page_num >= 0) gtk_notebook_set_current_page(nb, page_num);
465 else if(GTK_IS_STACK(w))
468 while(!
IS_NULL_PTR(page) && gtk_widget_get_parent(page) != w)
469 page = gtk_widget_get_parent(page);
471 GtkWidget *visible_child = gtk_stack_get_visible_child(GTK_STACK(w));
472 if(!
IS_NULL_PTR(page) && visible_child != page) gtk_stack_set_visible_child(GTK_STACK(w), page);
477 if(gtk_widget_is_drawable(target))
479 gtk_widget_grab_focus(target);
483 GtkWidget *toplevel = gtk_widget_get_toplevel(target);
484 GtkWidget *gtk_focus = (toplevel && gtk_widget_is_toplevel(toplevel))
485 ? gtk_window_get_focus(GTK_WINDOW(toplevel)) : NULL;
486 dt_widget_log(
"[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;
499 dt_widget_log(
"[bauhaus] ensure_focus_idle abort target=%s(%p) tries=%d drawable=%d\n",
500 gtk_widget_get_name(target), (
void *)target, tries, gtk_widget_is_drawable(target));
503 return G_SOURCE_REMOVE;
507 return G_SOURCE_CONTINUE;
516 gtk_widget_queue_draw(widget);
524 gtk_widget_queue_draw(widget);
532 if(direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
return FALSE;
539 GdkModifierType modifier, gpointer
data)
544 fprintf(stderr,
"The target widget of the action does not exist anymore");
555 if(w->module->ensure_visible) w->module->ensure_visible(w->module);
556 w->module->focus(w->module,
FALSE);
561 if(previous_source > 0)
562 g_source_remove(previous_source);
565 const guint source = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
ensure_focus_idle, g_object_ref(target),
566 (GDestroyNotify)g_object_unref);
577 int cur = new_pos +
inc;
588 d->hovered = new_pos;
594 void *
data,
void (*free_func)(
void *))
616 entry->
label = g_strdup(
"");
637 GdkRGBA
color = {.red = 1.0f, .green = 0.0f, .blue = 0.0f, .alpha = 1.0f};
638 return gdk_rgba_copy(&
color);
674 GtkStyleContext *context,
676 GdkRectangle *bounding_box,
680 PangoEllipsizeMode ellipsize,
689 PangoFontDescription *css_font = NULL;
690 gtk_style_context_get(context,
state, GTK_STYLE_PROPERTY_FONT, &css_font, NULL);
696 pango_font_description_set_weight(resolved, pango_font_description_get_weight(css_font));
697 pango_font_description_set_style(resolved, pango_font_description_get_style(css_font));
698 pango_font_description_set_variant(resolved, pango_font_description_get_variant(css_font));
699 pango_font_description_set_stretch(resolved, pango_font_description_get_stretch(css_font));
700 pango_font_description_set_family(resolved, pango_font_description_get_family(css_font));
701 pango_font_description_free(css_font);
725 PangoContext *pc = gtk_widget_get_pango_context(GTK_WIDGET(w));
729 PangoLayout *layout = pango_layout_new(pc);
730 pango_layout_set_font_description(layout, resolved);
731 pango_font_description_free(resolved);
734 pango_layout_set_text(layout, text, -1);
738 pango_cairo_update_layout(cr, layout);
741 int pango_width, pango_height;
742 pango_layout_get_size(layout, &pango_width, &pango_height);
743 double text_width = (
double)pango_width / PANGO_SCALE;
744 double text_height = fmax((
double)pango_height / PANGO_SCALE, w->
bauhaus->
line_height);
749 if(text_width > bounding_box->width)
751 pango_layout_set_ellipsize(layout, ellipsize);
752 pango_layout_set_width(layout, (
int)(PANGO_SCALE * bounding_box->width));
753 text_width = bounding_box->width;
755 pango_cairo_update_layout(cr, layout);
762 cairo_rectangle(cr, bounding_box->x, bounding_box->y,
763 bounding_box->width, bounding_box->height);
764 cairo_set_source_rgba(cr, bg_color->red, bg_color->green,
765 bg_color->blue, bg_color->alpha);
776 x = bounding_box->x + bounding_box->width / 2. - text_width / 2.;
779 x = bounding_box->x + bounding_box->width - text_width;
791 y = bounding_box->y + bounding_box->height / 2. - text_height / 2.;
794 y = bounding_box->y + bounding_box->height - text_height;
803 cairo_move_to(cr,
x, y);
804 pango_cairo_show_layout(cr, layout);
807 g_object_unref(layout);
825 y = (y - line_height) / (1.0 - line_height);
826 offset = (
x - sqf(y) * .5 - (1.0 - sqf(y)) * pos)
827 / (.5 * sqf(y) / scale + (1.0 - sqf(y)));
830 if(pos + offset > 1.0) offset = 1.0 - pos;
831 if(pos + offset < 0.0) offset = -pos;
837 const double line_height,
double line_width)
841 const int steps = 128;
842 const double corrected_height = (
height - line_height);
844 cairo_set_line_width(cr, line_width);
845 cairo_move_to(cr,
width * (pos + off), line_height);
846 const double half_line_width = line_width / 2.;
847 for(
int j = 1; j < steps; j++)
849 const double y = (
double)j / (
double)(steps - 1);
850 const double x = sqf(y) * .5f * (1.f + off / scale) + (1.0f - sqf(y)) * (pos + off);
851 cairo_line_to(cr,
x *
width - half_line_width, line_height + y * corrected_height);
862 if(roundf(zoom) == 0.f)
864 d->min =
d->soft_min;
865 d->max =
d->soft_max;
872 const float multiplier = exp2f(zoom / 2.f);
873 const float new_min =
value - multiplier * (
value -
d->min);
874 const float new_max =
value + multiplier * (
d->max -
value);
875 if(new_min >=
d->hard_min
876 && new_max <= d->hard_max
877 && new_max - new_min >= min_visible * 10)
883 gtk_widget_queue_draw(GTK_WIDGET(w));
888 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
896 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
904 fprintf(stdout,
"x: %i, y: %i, active: %i\n", (
int)event_x, (
int)event_y, active);
935 d->pos =
d->oldpos + mouse_off;
945 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_NORMAL,
TRUE);
952 g_object_get(gtk_settings_get_default(),
"gtk-double-click-time", &delay, NULL);
953 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
959 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_ACTIVE,
TRUE);
973 g_object_get(gtk_settings_get_default(),
"gtk-double-click-time", &delay, NULL);
975 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
978 if(event->button == 1)
981 && event->time < bh->
opentime + delay)
1015 const float value =
d->pos;
1030 gtk_widget_queue_draw(widget);
1042 gtk_grab_add(GTK_WIDGET(user_data));
1053 if(event->type == GDK_ENTER_NOTIFY)
1055 gtk_widget_set_state_flags(widget, GTK_STATE_FLAG_PRELIGHT,
FALSE);
1059 gtk_widget_unset_state_flags(widget, GTK_STATE_FLAG_PRELIGHT);
1064 const gboolean real_leave =
event->mode == GDK_CROSSING_NORMAL
1065 &&
event->detail != GDK_NOTIFY_INFERIOR
1071 gtk_widget_queue_draw(widget);
1081 if(focus_source > 0)
1083 g_source_remove(focus_source);
1088 const char *accel_path = g_object_get_data(G_OBJECT(widget),
"accel-path");
1103 g_ptr_array_free(
d->entries,
TRUE);
1106 gtk_border_free(w->
margin);
1109 G_OBJECT_CLASS(dt_bh_parent_class)->finalize(widget);
1115 = g_signal_new(
"value-changed", G_TYPE_FROM_CLASS(
class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1116 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1118 = g_signal_new(
"quad-pressed", G_TYPE_FROM_CLASS(
class), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
1119 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1121 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(
class);
1140 GtkStyleContext *ctx = gtk_widget_get_style_context(root_window);
1141 gtk_style_context_set_screen(ctx, gtk_widget_get_screen(root_window));
1143 gtk_style_context_lookup_color(ctx,
"bauhaus_fg", &
bauhaus->
color_fg);
1145 gtk_style_context_lookup_color(ctx,
"bauhaus_bg", &
bauhaus->
color_bg);
1171 gtk_style_context_lookup_color(ctx,
"colorlabel_red",
1173 gtk_style_context_lookup_color(ctx,
"colorlabel_yellow",
1175 gtk_style_context_lookup_color(ctx,
"colorlabel_green",
1177 gtk_style_context_lookup_color(ctx,
"colorlabel_blue",
1179 gtk_style_context_lookup_color(ctx,
"colorlabel_purple",
1192 cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 128, 128);
1193 cairo_t *cr = cairo_create(cst);
1197 ctx = gtk_widget_get_style_context(ref);
1200 PangoContext *context = gtk_widget_get_pango_context(ref);
1201 PangoLayout *layout = pango_layout_new(context);
1202 pango_layout_set_text(layout,
"em", -1);
1212 pango_cairo_update_layout(cr, layout);
1213 pango_cairo_show_layout(cr, layout);
1218 pango_layout_get_size(layout, &pango_width, &pango_height);
1219 g_object_unref(layout);
1221 cairo_surface_destroy(cst);
1245#ifdef GDK_WINDOWING_QUARTZ
1258 if(root) gtk_window_set_transient_for(GTK_WINDOW(
bauhaus->
popup_window), GTK_WINDOW(root));
1264 gtk_window_set_type_hint(GTK_WINDOW(
bauhaus->
popup_window), GDK_WINDOW_TYPE_HINT_POPUP_MENU);
1274 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1275 | GDK_KEY_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK
1280 g_object_set_data(area,
"bauhaus",
bauhaus);
1292 gchar *path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Increase value (normal step)"));
1294 path, NULL, GDK_KEY_Right, 0);
1296 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Decrease value (normal step)"));
1298 path, NULL, GDK_KEY_Left, 0);
1308 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Increase value (coarse step)"));
1310 path, NULL, GDK_KEY_Right, GDK_SHIFT_MASK);
1312 path =
dt_accels_build_path(_(
"Darkroom/Controls/Sliders"), _(
"Decrease value (coarse step)"));
1314 path, NULL, GDK_KEY_Left, GDK_SHIFT_MASK);
1318 path, NULL, GDK_KEY_Insert, 0);
1323 path, NULL, GDK_KEY_Return, 0);
1327 path, NULL, GDK_KEY_Escape, 0);
1329 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Select previous (in editing mode)"));
1331 path, NULL, GDK_KEY_Up, 0);
1333 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Select next (in editing mode)"));
1335 path, NULL, GDK_KEY_Down, 0);
1337 path =
dt_accels_build_path(_(
"Darkroom/Controls/Comboboxes"), _(
"Validate result (in editing mode)"));
1339 path, NULL, GDK_KEY_Return, 0);
1343 path, NULL, GDK_KEY_Insert, 0);
1384 gtk_widget_add_events(GTK_WIDGET(w), GDK_POINTER_MOTION_MASK
1385 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
1386 | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
1387 | GDK_FOCUS_CHANGE_MASK
1390 gtk_widget_set_can_focus(GTK_WIDGET(w),
TRUE);
1391 gtk_widget_set_halign(GTK_WIDGET(w), GTK_ALIGN_FILL);
1392 gtk_widget_set_hexpand(GTK_WIDGET(w),
TRUE);
1414 d->min =
MAX(
d->min,
d->hard_min);
1415 d->soft_min =
MAX(
d->soft_min,
d->hard_min);
1417 if(desired_position >
d->hard_max)
1420 if(current_position < desired_position)
1438 d->hard_max = desired_position;
1439 d->max =
MIN(
d->max,
d->hard_max);
1440 d->soft_max =
MIN(
d->soft_max,
d->hard_max);
1442 if(desired_position < d->hard_min)
1445 if(current_position > desired_position)
1462 d->min =
d->soft_min = CLAMP(val,
d->hard_min,
d->hard_max);
1479 d->max =
d->soft_max = CLAMP(val,
d->hard_min,
d->hard_max);
1518 m->widget_list = g_list_append(
m->widget_list, w);
1521 m->widget_list_bh = g_list_append(
m->widget_list_bh, w);
1529 assert(g_strrstr(
label,
"/") == NULL);
1531 gchar *plugin_name = g_strdup_printf(
"%s/%s",
m->name, w->
label);
1534 gchar *scope = g_strdup_printf(
"%s/Modules",
m->view);
1536 _(
"Focuses the control"));
1537 g_object_set_data_full(G_OBJECT(widget),
"accel-path",
1539 gtk_widget_set_has_tooltip(widget,
TRUE);
1544 gtk_widget_queue_draw(GTK_WIDGET(w));
1566 fprintf(stderr,
"[dt_bauhaus_widget_set_field] bauhaus label '%s' set before field (needs to be after)\n", w->
label);
1585 gtk_widget_queue_draw(GTK_WIDGET(w));
1592 gtk_widget_queue_draw(GTK_WIDGET(w));
1611 g_signal_emit_by_name(G_OBJECT(w),
"quad-pressed");
1617 gtk_widget_grab_focus(widget);
1623 gtk_widget_queue_draw(GTK_WIDGET(w));
1633 float defval,
int digits)
1639 float step,
float defval,
int digits,
int feedback)
1649 GTK_WIDGET_CLASS(dt_bh_parent_class)->style_updated(widget);
1664 float step,
float defval,
int digits,
int feedback)
1669 d->
min =
d->soft_min =
d->hard_min =
min;
1670 d->max =
d->soft_max =
d->hard_max =
max;
1685 d->fill_feedback = feedback;
1695 return GTK_WIDGET(w);
1702 return GTK_WIDGET(w);
1706 int pos, GtkCallback callback, gpointer
data,
const char **texts)
1712 gtk_widget_set_tooltip_text(combo, tip ? tip : _(
label));
1713 if(callback) g_signal_connect(G_OBJECT(combo),
"value-changed", G_CALLBACK(callback),
data);
1730 d->entries_ellipsis = PANGO_ELLIPSIZE_END;
1746 if(
d->active >=
d->entries->len)
d->
active = -1;
1775 const gboolean allow_end)
1779 int selectable_pos = 0;
1780 for(
int i = 0;
i <
d->entries->len;
i++)
1784 if(selectable_pos == pos)
return i;
1788 return (allow_end && selectable_pos == pos) ? (int)
d->entries->len : -1;
1796 if(
IS_NULL_PTR(
d) || entry_pos < 0 || entry_pos >=
d->entries->len)
return -1;
1798 int selectable_pos = 0;
1799 for(
int i = 0;
i <= entry_pos;
i++)
1803 if(
i == entry_pos)
return selectable_pos;
1815 w->data.combobox.populate = fct;
1820 while(texts && *texts)
1837 g_ptr_array_add(
d->entries, entry);
1838 if(
d->active < 0)
d->active = (int)
d->entries->len - 1;
1847 gpointer
data,
void (free_func)(
void *
data), gboolean sensitive)
1854 g_ptr_array_add(
d->entries, entry);
1855 if(
d->active < 0)
d->active = (int)
d->entries->len - 1;
1897 return d ?
d->editable : 0;
1915 if(entry_pos < 0)
return;
1920 if(
d->active > entry_pos ||
d->active ==
d->entries->len-1)
1923 g_ptr_array_remove_index(
d->entries, entry_pos);
1932 gpointer
data,
void (*free_func)(
void *),
int pos)
1938 if(entry_pos < 0)
return;
1941 d->active = entry_pos;
1942 else if(entry_pos <= d->active)
1958 if(entry_pos < 0)
return;
1960 if(entry_pos <= d->active)
d->active++;
1977 return d->editable ?
d->text : NULL;
1983 return entry->
label;
2004 g_ptr_array_set_size(
d->entries, 0);
2011 if(entry_pos < 0)
return NULL;
2014 return entry->
label;
2041 fprintf(stderr,
"ERROR: %s - %s is set to use default callback but none is provided\n", w->module->name,
2047 fprintf(stderr,
"WARNING: %s - %s has an IOP module but doesn't use default callback\n", w->module->name,
2052 g_signal_emit_by_name(G_OBJECT(w),
"value-changed");
2066 const int old_pos =
d->
active;
2067 const int new_pos = (
d->entries) ? CLAMP(pos, -1, (
int)
d->entries->len - 1)
2076 if(old_pos != new_pos)
2078 d->active = new_pos;
2083 gtk_widget_queue_draw(GTK_WIDGET(w));
2094 const int public_pos = (selectable_count > 0) ? CLAMP(pos, -1, selectable_count - 1) : -1;
2106 for(
int i = 0;
d &&
i <
d->entries->len;
i++)
2110 if(!g_strcmp0(entry->
label, text))
2123 for(
int i = 0;
d &&
i <
d->entries->len;
i++)
2127 if(GPOINTER_TO_INT(entry->
data) ==
value)
2147 if(entry_pos < 0)
return;
2173 for(
int k = 0;
k <
d->grad_cnt;
k++)
2175 if(
d->grad_pos[
k] == stop)
2177 d->grad_col[
k][0] =
r;
2178 d->grad_col[
k][1] =
g;
2179 d->grad_col[
k][2] = b;
2186 int k =
d->grad_cnt++;
2187 d->grad_pos[
k] = stop;
2188 d->grad_col[
k][0] =
r;
2189 d->grad_col[
k][1] =
g;
2190 d->grad_col[
k][2] = b;
2203 const float horizontal_position = pos * wd;
2206 cairo_translate(cr, horizontal_position, vertical_position);
2209 const gboolean has_colored_background =
d->
grad_cnt > 0;
2211 if(!has_colored_background &&
d->fill_feedback)
2214 cairo_arc(cr, 0, 0,
size / 2., 0,
M_PI * 2);
2216 cairo_set_line_width(cr, 0);
2224 cairo_set_line_width(cr, border);
2225 const float radius =
size / 2. - border / 2.;
2226 cairo_arc(cr, 0, 0, radius, 0,
M_PI * 2);
2255 cairo_move_to(cr, -
r, -
r * .5f);
2256 cairo_line_to(cr, 0,
r * .5f);
2257 cairo_line_to(cr,
r, -
r * .5f);
2275 const gboolean has_colored_background =
d->
grad_cnt > 0;
2278 const gboolean is_sensitive = gtk_widget_is_sensitive(GTK_WIDGET(w));
2290 const double baseline_width =
width - x_origin;
2292 cairo_rectangle(cr, round(x_origin), round(baseline_top),
2293 round(baseline_width), round(baseline_height));
2295 cairo_pattern_t *gradient = NULL;
2296 if(has_colored_background && is_sensitive)
2299 const double zoom = (
d->max -
d->min) / (
d->hard_max -
d->hard_min);
2300 const double offset = (
d->min -
d->hard_min) / (
d->hard_max -
d->hard_min);
2301 gradient = cairo_pattern_create_linear(x_origin, 0,
width, baseline_height);
2302 for(
int k = 0;
k <
d->grad_cnt;
k++)
2303 cairo_pattern_add_color_stop_rgba(gradient, (
d->grad_pos[
k] - offset) / zoom,
2304 d->grad_col[
k][0],
d->grad_col[
k][1],
d->grad_col[
k][2], 0.4f);
2305 cairo_set_source(cr, gradient);
2320 const double line_width = 1.;
2321 cairo_rectangle(cr, round(x_origin) + line_width / 2., round(baseline_top) + line_width / 2.,
2322 round(baseline_width) - line_width, round(baseline_height) - line_width);
2323 cairo_set_line_width(cr, line_width);
2328 if(gradient) cairo_pattern_destroy(gradient);
2331 float origin = fmaxf(fminf((
d->factor > 0 ? -
d->min -
d->offset/
d->factor
2332 :
d->max +
d->offset/
d->factor)
2333 / (
d->max -
d->min),
2338 if(!has_colored_background &&
d->fill_feedback && is_sensitive)
2348 cairo_rectangle(cr, x_origin, baseline_top,
delta - x_origin, baseline_height);
2350 cairo_rectangle(cr, origin, baseline_top,
delta, baseline_height);
2358 if(
d->hard_max != 360.0f && is_sensitive)
2406 fprintf(stdout,
"combobox went the custom path\n");
2416 gchar *keys = g_utf8_casefold(w->
bauhaus->
keys, -1);
2420 for(
int j = 0; j <
d->entries->len; j++)
2423 gchar *text_cmp = g_utf8_casefold(entry->
label, -1);
2468 return g_strdup(w->
label);
2476 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
2480 GtkAllocation allocation;
2481 gtk_widget_get_allocation(widget, &allocation);
2483 cairo_t *cr = cairo_create(cst);
2484 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2487 GdkRGBA text_color, text_color_selected, text_color_hover, text_color_insensitive, text_color_focused;
2488 gtk_style_context_get_color(context, GTK_STATE_FLAG_NORMAL, &text_color);
2489 gtk_style_context_get_color(context, GTK_STATE_FLAG_SELECTED, &text_color_selected);
2490 gtk_style_context_get_color(context, GTK_STATE_FLAG_PRELIGHT, &text_color_hover);
2491 gtk_style_context_get_color(context, GTK_STATE_FLAG_INSENSITIVE, &text_color_insensitive);
2492 gtk_style_context_get_color(context, GTK_STATE_FLAG_FOCUSED, &text_color_focused);
2496 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2498 gtk_style_context_get(context,
state,
"background-color", &bg_color, NULL);
2499 gtk_style_context_get_color(context,
state, fg_color);
2502 gtk_render_background(context, cr, 0, 0, allocation.width, allocation.height);
2503 gtk_render_frame(context, cr, 0, 0, allocation.width, allocation.height);
2506 double total_width = 0.f;
2519 const double text_width = main_width + slider_cursor_radius;
2521 cairo_translate(cr, slider_cursor_radius, 0.0);
2525 const int num_scales = 1.f / scale;
2528 for(
int k = 0;
k < num_scales;
k++)
2530 const float off =
k * scale -
d->oldpos;
2531 GdkRGBA fg_copy = *fg_color;
2532 fg_copy.alpha = scale / fabsf(off);
2534 draw_slider_line(cr,
d->oldpos, off, scale, main_width, main_height, bottom_baseline, 1);
2540 const double mouse_off =
d->pos -
d->oldpos;
2543 cairo_translate(cr, slider_cursor_radius, 0.0);
2550 draw_slider_line(cr,
d->oldpos, mouse_off, scale, main_width, main_height, bottom_baseline, 2);
2562 float value_width = 0.f;
2564 GdkRectangle bounding_value = { .x = 0.,
2566 .width = text_width,
2571 BH_ALIGN_MIDDLE, PANGO_ELLIPSIZE_NONE, NULL, &value_width, NULL, GTK_STATE_FLAG_NORMAL);
2576 const float label_width = text_width - value_width -
INNER_PADDING;
2577 GdkRectangle bounding_label = { .x = 0.,
2579 .width = label_width,
2583 PANGO_ELLIPSIZE_END, NULL, NULL, NULL, GTK_STATE_FLAG_NORMAL);
2594 double popup_y = 0.;
2600 GdkRectangle query_label = { .x = 0.,
2602 .width = main_width,
2603 .height = query_height };
2605 PANGO_ELLIPSIZE_NONE, NULL, NULL, NULL, GTK_STATE_FLAG_NORMAL);
2606 popup_y += query_height;
2611 gchar *keys = g_utf8_casefold(w->
bauhaus->
keys, -1);
2612 for(
int j = 0; j <
d->entries->len; j++)
2620 cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.);
2621 cairo_move_to(cr, 0., popup_y + 0.5 * entry_height);
2622 cairo_line_to(cr, main_width, popup_y + 0.5 * entry_height);
2623 cairo_set_line_width(cr, 1.);
2626 popup_y += entry_height;
2630 gchar *text_cmp = g_utf8_casefold(entry->
label, -1);
2640 state = GTK_STATE_FLAG_INSENSITIVE;
2642 else if(j ==
d->active)
2645 state = GTK_STATE_FLAG_SELECTED;
2647 else if(j ==
d->hovered)
2650 state = GTK_STATE_FLAG_PRELIGHT;
2655 state = GTK_STATE_FLAG_NORMAL;
2658 GdkRectangle bounding_label = { .x = 0.,
2660 .width = main_width,
2661 .height = entry_height };
2663 cairo_rectangle(cr, bounding_label.x, bounding_label.y, bounding_label.width, bounding_label.height);
2664 cairo_set_line_width(cr, 2);
2668 d->entries_ellipsis, bg_color, NULL, NULL,
state);
2672 popup_y += entry_height;
2684 cairo_set_source_surface(crf, cst, 0, 0);
2686 cairo_surface_destroy(cst);
2688 gdk_rgba_free(bg_color);
2689 gdk_rgba_free(fg_color);
2700 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2701 const GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2704 cairo_t *cr = cairo_create(cst);
2712 float label_width = 0.f;
2713 GdkRectangle bounding_label = { .x = 0.,
2719 PANGO_ELLIPSIZE_NONE, NULL, &label_width, NULL,
state);
2724 float max_entry = 0.f;
2725 for(
int i = 0;
i <
d->entries->len;
i++)
2730 GdkRectangle bounding_value = { .x = 0,
2734 float entry_label_width = 0.f;
2737 &entry_label_width, NULL,
state);
2746 cairo_surface_destroy(cst);
2754 GtkStyleContext *context = gtk_widget_get_style_context(widget);
2757 GtkAllocation allocation;
2758 gtk_widget_get_allocation(widget, &allocation);
2770 if(max_width < allocation.width)
2771 allocation.width = ceilf(max_width);
2775 gtk_widget_size_allocate(widget, &allocation);
2778 cairo_t *cr = cairo_create(cst);
2783 GtkStateFlags
state = gtk_widget_get_state_flags(widget);
2784 if(gtk_widget_has_focus(widget))
2785 state |= GTK_STATE_FLAG_FOCUSED;
2787 gtk_style_context_save(context);
2788 gtk_style_context_set_state(context,
state);
2789 gtk_style_context_get_color(context,
state, text_color);
2797 const float box_width = allocation.width - w->
margin->left - w->
margin->right;
2798 const float box_height = allocation.height - w->
margin->top - w->
margin->bottom;
2801 gtk_render_background(context, crf, w->
margin->left, w->
margin->top, box_width, box_height);
2802 gtk_render_frame(context, crf, w->
margin->left, w->
margin->top, box_width, box_height);
2815 cairo_set_line_width(cr, 1.0);
2830 float label_width = 0.f;
2831 float label_height = 0.f;
2833 GdkRectangle bounding_label = { .x = 0.,
2835 .width = available_width,
2836 .height = inner_height };
2839 combo_ellipsis, NULL, &label_width, &label_height,
state);
2842 gchar *text =
d->text;
2843 if(
d->active >= 0 &&
d->active <
d->entries->len)
2846 text = entry->
label;
2848 GdkRectangle bounding_value = { .x = label_width +
INNER_PADDING,
2851 .height = inner_height };
2861 const double text_width = available_width + slider_cursor_radius;
2865 cairo_translate(cr, slider_cursor_radius, 0.0);
2873 cairo_set_source_rgba(cr, text_color->red, text_color->green, text_color->blue, text_color->alpha * 0.7);
2878 float value_width = 0;
2879 if(gtk_widget_is_sensitive(widget))
2882 cairo_translate(cr, slider_cursor_radius, 0.0);
2887 GdkRectangle bounding_value = { .x = 0.,
2889 .width = text_width,
2893 PANGO_ELLIPSIZE_NONE, NULL, &value_width, NULL,
state);
2899 const float label_width = text_width - value_width -
INNER_PADDING;
2900 GdkRectangle bounding_label = { .x = 0.,
2902 .width = label_width,
2906 PANGO_ELLIPSIZE_END, NULL, NULL, NULL,
state);
2915 cairo_set_source_surface(crf, cst, 0, 0);
2917 cairo_surface_destroy(cst);
2918 gtk_style_context_restore(context);
2920 gdk_rgba_free(text_color);
2921 gdk_rgba_free(value_color);
2922 gdk_rgba_free(value_text_color);
2964 gtk_window_set_attached_to(GTK_WINDOW(bh->
popup_window), NULL);
2967 gtk_widget_grab_focus(GTK_WIDGET(bh->
current));
2983 GtkWidget *parent_toplevel = gtk_widget_get_toplevel(widget);
2984 if(parent_toplevel && gtk_widget_is_toplevel(parent_toplevel))
2985 gtk_window_set_transient_for(GTK_WINDOW(w->
bauhaus->
popup_window), GTK_WINDOW(parent_toplevel));
2995 gtk_widget_realize(widget);
2999 gtk_widget_get_allocation(widget, &tmp);
3021 fprintf(stderr,
"[dt_bauhaus_show_popup] The bauhaus widget has an unknown type\n");
3027 GtkStyleContext *context = gtk_widget_get_style_context(w->
bauhaus->
popup_area);
3028 gtk_style_context_add_class(context,
"dt_bauhaus_popup");
3030 #ifdef GDK_WINDOWING_WAYLAND
3031 if (GDK_IS_WAYLAND_DISPLAY(gdk_display_get_default())) {
3032 GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
3040 gint wx = 0, wy = 0;
3041 GdkWindow *widget_window = gtk_widget_get_window(widget);
3042 if(widget_window) gdk_window_get_origin(widget_window, &wx, &wy);
3046 gint wwx = 0, wwy = 0;
3049 GtkWidget *toplevel = gtk_widget_get_toplevel(GTK_WIDGET(w));
3050 GdkWindow *main_window = (toplevel && gtk_widget_is_toplevel(toplevel))
3051 ? gtk_widget_get_window(toplevel) : NULL;
3052 if(main_window) gdk_window_get_origin(main_window, &wwx, &wwy);
3054 GdkRectangle anchor = {
3057 .width =
MAX(tmp.width, 1),
3058 .height =
MAX(tmp.height, 1)
3077 gdk_window_move_to_rect(GDK_WINDOW(
window), &anchor, GDK_GRAVITY_STATIC, GDK_GRAVITY_STATIC,
3078 GDK_ANCHOR_SLIDE, 0, 0);
3086 if(
delta == 0.f)
return;
3095 const float min_visible = 1.f / (fabsf(
d->factor) *
ipow(10,
d->digits));
3096 if(fabsf(
delta) < min_visible)
3108 const gboolean key_captured = gtk_widget_has_focus(widget);
3109 const gboolean smooth = (
event->direction == GDK_SCROLL_SMOOTH);
3119 if(!key_captured && !popup_captured && !scroll_captured)
3136 const gboolean vscroll = delta_y != 0 && abs(delta_y) > abs(delta_x);
3137 const gboolean hscroll = delta_x != 0 && abs(delta_x) > abs(delta_y);
3186 case GDK_KEY_Insert:
3202 case GDK_KEY_Return:
3206 case GDK_KEY_Insert:
3225 double event_x =
event->x;
3226 double event_y =
event->y;
3238 gtk_widget_grab_focus(widget);
3249 if(event->button == 3)
3256 else if(event->button == 1)
3259 if(event->type == GDK_2BUTTON_PRESS)
3285 return d->
min +
d->pos * (
d->max -
d->min);
3297 if((
d->hard_max *
d->factor +
d->offset)*(
d->hard_min *
d->factor +
d->offset) < 0)
3298 return g_strdup_printf(
"%+.*f%s",
d->digits, val *
d->factor +
d->offset,
d->format);
3300 return g_strdup_printf(
"%.*f%s",
d->digits, val *
d->factor +
d->offset,
d->format);
3314 const float rpos = CLAMP(pos,
d->hard_min,
d->hard_max);
3317 float rrpos = (rpos -
d->soft_min) / (
d->soft_max -
d->soft_min);
3319 d->min =
d->soft_min;
3324 d->max =
d->soft_max;
3368 float step =
d->
step;
3372 const float min =
d->soft_min;
3373 const float max =
d->soft_max;
3386 return copysignf(step,
d->factor);
3394 gtk_widget_queue_draw(widget);
3401 d->
min =
d->soft_min;
3402 d->max =
d->soft_max;
3411 d->
format = g_intern_string(format);
3413 if(strstr(format,
"%") && fabsf(
d->hard_max) <= 10)
3415 if(
d->factor == 1.0f)
d->factor = 100;
3419 d->digits =
MAX(
d->digits - 2, 0);
3452 fprintf(stderr,
"ERROR: %s - %s is set to use default callback but none is provided\n", w->module->name,
3458 fprintf(stderr,
"WARNING: %s - %s has an IOP module but doesn't use default callback\n", w->module->name,
3463 g_signal_emit_by_name(G_OBJECT(w),
"value-changed");
3478 const float old_pos =
d->
pos;
3479 const float new_pos = CLAMP(pos, 0.0f, 1.0f);
3481 if(old_pos != new_pos || raise)
3483 const float new_value = new_pos * (
d->max -
d->min) +
d->min;
3486 d->pos = (rounded_value -
d->min) / (
d->max -
d->min);
3491 gtk_widget_queue_draw(GTK_WIDGET(w));
3499 dt_bauhaus_t *bh = g_object_get_data(G_OBJECT(widget),
"bauhaus");
3509 && (
key == GDK_KEY_space ||
3510 key == GDK_KEY_percent ||
3511 (event->string[0] >= 40 && event->string[0] <= 57) ||
3512 key == GDK_KEY_asciicircum ||
key == GDK_KEY_dead_circumflex ||
3513 key == GDK_KEY_X ||
key == GDK_KEY_x))
3515 if(
key == GDK_KEY_dead_circumflex)
3522 && (
key == GDK_KEY_BackSpace ||
key == GDK_KEY_Delete))
3528 && (
key == GDK_KEY_Return))
3537 memset(bh->
keys, 0,
sizeof(bh->
keys));
3540 else if(
key == GDK_KEY_Escape)
3544 memset(bh->
keys, 0,
sizeof(bh->
keys));
3554 if(!g_utf8_validate(event->string, -1, NULL))
return FALSE;
3555 const gunichar c = g_utf8_get_char(event->string);
3556 const long int char_width = g_utf8_next_char(event->string) -
event->string;
3557 if(bh->
keys_cnt + 1 + char_width < 64 && g_unichar_isprint(c))
3560 g_utf8_strncpy(bh->
keys + bh->
keys_cnt, event->string, 1);
3565 && (
key == GDK_KEY_BackSpace ||
key == GDK_KEY_Delete))
3574 && (
key == GDK_KEY_Return))
3584 memset(bh->
keys, 0,
sizeof(bh->
keys));
3587 else if(
key == GDK_KEY_Escape)
3591 memset(bh->
keys, 0,
sizeof(bh->
keys));
3594 else if(
key == GDK_KEY_Up)
3598 else if(
key == GDK_KEY_Down)
3602 else if(
key == GDK_KEY_Return)
3608 memset(bh->
keys, 0,
sizeof(bh->
keys));
3626 double event_x =
event->x;
3627 double event_y =
event->y;
3628 double main_width = 0.;
3639 gtk_widget_grab_focus(widget);
3649 if(event->button == 1)
3651 if(event->type == GDK_2BUTTON_PRESS)
3674 else if(event->button == 3)
3680 else if(event->button == 2)
3704 if(event->button == 1)
3719 if(
d->is_dragging && event->state & GDK_BUTTON1_MASK)
3721 double event_x =
event->x;
3722 double event_y =
event->y;
dt_accels_t * dt_accels_get_global(void)
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)
#define dt_accels_new_darkroom_action(a, b, w, c, d, e, f, g)
GtkWidget * dt_bauhaus_slider_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
static void dt_bauhaus_widget_accept(struct dt_bauhaus_widget_t *w)
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 void dt_bauhaus_slider_set_normalized(struct dt_bauhaus_widget_t *w, float pos, gboolean raise)
Set the value of a slider as a ratio of the GUI slider width.
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 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.
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 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 _bh_combobox_get_hovered_entry(struct dt_bauhaus_widget_t *w)
float dt_bauhaus_slider_get_soft_min(GtkWidget *widget)
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)
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.
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)
static void _commit_combobox_value(struct dt_bauhaus_widget_t *w)
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)
static void _combobox_set(GtkWidget *widget, const int pos)
Set a combobox to a given integer position. Private API function, called from user events.
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)
static void _commit_slider_value(struct dt_bauhaus_widget_t *w)
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)
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 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)
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
#define DT_BAUHAUS_COMBO_MAX_TEXT
#define DT_BAUHAUS_WIDGET(obj)
#define DT_BAUHAUS_WIDGET_TYPE
@ DT_BAUHAUS_QUAD_PRESSED_SIGNAL
@ DT_BAUHAUS_VALUE_CHANGED_SIGNAL
#define DT_BAUHAUS_COMBO_SEPARATOR_DEFAULT_HEIGHT_FACTOR
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
float dt_calculator_solve(const float x, const char *formula)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
static const float const float const float min
static void set_color(cairo_t *cr, GdkRGBA color)
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.
static int precision(double x, double adj)
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static int ipow(int base, int exp)
Fast integer power, computing base^exp.
#define CLAMPF(a, mn, mx)
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
void dt_osx_disallow_fullscreen(GtkWidget *widget)
static const dt_aligned_pixel_simd_t value
const float uint32_t state[4]
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
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
The dt_gui_module_t type is the intersection between a dt_lib_module_t and a dt_iop_module_t structur...
static G_BEGIN_DECLS cairo_surface_t * dt_cairo_surface_create_at_scale(cairo_format_t format, int width, int height, double scale)
typedef double((*spd)(unsigned long int wavelength, double TempK))
dt_bauhaus_combobox_data_t combobox
dt_bauhaus_slider_data_t slider