Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions data/themes/darktable.css
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,16 @@ menuitem > arrow
margin: 0.2em 0;
}

/* the "show guides" checkbox, which is the one that carries an icon of its
own and is appended to modules that know nothing about it. Left moves its
tick box and label in from the start of the row, right pulls its icon in
from the end, and neither touches any other checkbox */
.dt_guides_toggle
{
padding-left: 0.65em;
padding-right: 0.65em;
}

/* and set menuitem related to sort of combobox like metadata presets in import module */
menuitem label,
#view-dropdown button,
Expand Down
41 changes: 33 additions & 8 deletions src/bauhaus/bauhaus.c
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,7 @@ void dt_bauhaus_load_theme()
// around it
gint min_width = 0, min_height = 0;
GtkBorder check_padding = { 0 }, check_border = { 0 };
bh->check_margin = (GtkBorder){ 0 };
if(bh->check_context)
{
const GtkStateFlags check_state = gtk_style_context_get_state(bh->check_context);
Expand All @@ -928,7 +929,14 @@ void dt_bauhaus_load_theme()
NULL);
gtk_style_context_get_padding(bh->check_context, check_state, &check_padding);
gtk_style_context_get_border(bh->check_context, check_state, &check_border);
// gtk lays a check button out with these around the indicator, and
// gtk_render_check() does not apply them, so the space in front of the
// box and between the box and the label are ours to add
gtk_style_context_get_margin(bh->check_context, check_state, &bh->check_margin);
}
// only the gap between the box and the label is used, and never less than
// the spacing the other widget types keep between their own parts
bh->check_margin.right = MAX(bh->check_margin.right, INNER_PADDING);
const gint css_width = min_width + check_padding.left + check_padding.right
+ check_border.left + check_border.right;
const gint css_height = min_height + check_padding.top + check_padding.bottom
Expand Down Expand Up @@ -1168,6 +1176,25 @@ void dt_bauhaus_widget_set_label_ellipsize(GtkWidget *widget,
gtk_widget_queue_draw(GTK_WIDGET(w));
}

void dt_bauhaus_widget_get_quad_rect(GtkWidget *widget,
GdkRectangle *rect)
{
dt_bauhaus_widget_t *w = DT_BAUHAUS_WIDGET(widget);

GtkAllocation allocation;
gtk_widget_get_allocation(widget, &allocation);

// the quad is the last thing on the row, drawn INNER_PADDING * 4 into the
// width _widget_get_quad_width() reserves for it at the end
const int right = allocation.width - w->margin.right - w->padding.right;
const int top = w->margin.top + w->padding.top;

rect->width = darktable.bauhaus->quad_width;
rect->height = allocation.height - top - w->margin.bottom - w->padding.bottom;
rect->x = right - _widget_get_quad_width(w) + INNER_PADDING * 4;
rect->y = top;
}

const char* dt_bauhaus_widget_get_label(GtkWidget *widget)
{
const dt_bauhaus_widget_t *w = DT_BAUHAUS_WIDGET(widget);
Expand Down Expand Up @@ -1685,10 +1712,6 @@ GtkWidget *dt_bauhaus_toggle_from_widget(dt_bauhaus_widget_t *w,
d->active = FALSE;
d->defpos = FALSE;

// the tick box is drawn in front of the label, so the column that the
// other types keep free on the right would only be wasted width here
w->show_quad = FALSE;

gtk_widget_set_name(GTK_WIDGET(w), "bauhaus-toggle");

return GTK_WIDGET(w);
Expand Down Expand Up @@ -2972,10 +2995,12 @@ static gboolean _widget_draw(GtkWidget *widget,
break;
case DT_BAUHAUS_TOGGLE:
{
// box first, then the label beside it, so the pair reads as one
// control the way a check button does
// the box starts where the other types start their label, so that a
// checkbox lines up with them down the left of a module, and the
// label follows it after the gap the css keeps between a check
// button's indicator and its own label
const float size = _toggle_box_size();
const float indent = size + INNER_PADDING * 2;
const float indent = size + darktable.bauhaus->check_margin.right;
_draw_toggle_box(w, cr, 0, h3, size);

gchar *label_text = _build_label(w);
Expand Down Expand Up @@ -3058,7 +3083,7 @@ static gint _natural_width(GtkWidget *widget,
else if(w->type == DT_BAUHAUS_TOGGLE)
{
// the box sits in front of the label rather than in the quad column
natural_size += _toggle_box_size() + INNER_PADDING * 2;
natural_size += _toggle_box_size() + darktable.bauhaus->check_margin.right;
}
else
{
Expand Down
5 changes: 5 additions & 0 deletions src/bauhaus/bauhaus.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ typedef struct dt_bauhaus_t
// that toggles are drawn by the theme rather than from hardcoded colours
GtkStyleContext *check_context;
float check_size; // side of a toggle's tick box
GtkBorder check_margin; // space the css keeps around it

// initialise or connect accelerators in set_label
int skip_accel;
Expand Down Expand Up @@ -186,6 +187,10 @@ void dt_bauhaus_widget_set_label_text(GtkWidget *widget,
// instead, so that the value survives
void dt_bauhaus_widget_set_label_ellipsize(GtkWidget *widget,
const PangoEllipsizeMode ellipsize);
// where the quad is drawn, in widget coordinates, for anchoring a popup to
// the icon rather than to the whole widget
void dt_bauhaus_widget_get_quad_rect(GtkWidget *widget,
GdkRectangle *rect);
const char* dt_bauhaus_widget_get_label(GtkWidget *widget);
void dt_bauhaus_widget_hide_label(GtkWidget *widget);
void dt_bauhaus_widget_set_show_extended_label(GtkWidget *widget,
Expand Down
51 changes: 34 additions & 17 deletions src/gui/guides.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "common/darktable.h"
#include "common/math.h"
#include "dtgtk/button.h"
#include "gui/gtk.h"
#include "gui/guides.h"

#define DEFAULT_GUIDE_NAME "rules of thirds"
Expand Down Expand Up @@ -1006,7 +1007,7 @@ static void _settings_autoshow_change2(GtkWidget *combo,
{
DT_GUARD_GUI_UPDATE();
gchar *key = _conf_get_path(module->op, "autoshow", NULL);
dt_conf_set_bool(key, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(combo)));
dt_conf_set_bool(key, dt_bauhaus_toggle_get(combo));
g_free(key);
dt_control_queue_redraw_center();
}
Expand All @@ -1017,6 +1018,12 @@ static void _settings_autoshow_menu(GtkWidget *button,
GtkWidget *popover = darktable.view_manager->guides_popover;
gtk_popover_set_relative_to(GTK_POPOVER(popover), button);

// the icon is this widget's quad, so point at that rather than letting the
// popup aim at the middle of the whole checkbox
GdkRectangle quad;
dt_bauhaus_widget_get_quad_rect(button, &quad);
gtk_popover_set_pointing_to(GTK_POPOVER(popover), &quad);

g_object_set(G_OBJECT(popover), "transitions-enabled", FALSE, NULL);

dt_guides_update_popover_values();
Expand All @@ -1029,38 +1036,48 @@ void dt_guides_init_module_widget(GtkWidget *iopw,
{
if(!(module->flags() & IOP_FLAGS_GUIDES_WIDGET)) return;

GtkWidget *cb = module->guides_combo = gtk_check_button_new_with_label(_("show guides"));
gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(cb))), PANGO_ELLIPSIZE_START);
// no field: whether the overlay is shown is a per module preference kept
// in conf, not one of the module's parameters
GtkWidget *cb = module->guides_combo = dt_bauhaus_toggle_new(module);
dt_bauhaus_widget_set_label(cb, NULL, N_("show guides"));
// this row is the only checkbox that carries an icon of its own, and it is
// added to the bottom of modules whose other widgets it knows nothing
// about, so give it a class of its own to be spaced by rather than
// borrowing the one every checkbox in every module is drawn with
dt_gui_add_class(cb, "dt_guides_toggle");
dt_bauhaus_widget_set_label_ellipsize(cb, PANGO_ELLIPSIZE_START);

gchar *key = _conf_get_path(module->op, "autoshow", NULL);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb), dt_conf_get_bool(key));
dt_bauhaus_toggle_set(cb, dt_conf_get_bool(key));
g_free(key);

g_signal_connect(G_OBJECT(cb), "toggled",
g_signal_connect(G_OBJECT(cb), "value-changed",
G_CALLBACK(_settings_autoshow_change2), module);
gtk_widget_set_tooltip_text(cb, _("show guide overlay when this module has focus"));
GtkWidget *ic = dtgtk_button_new(dtgtk_cairo_paint_grid, 0, NULL);
gtk_widget_set_tooltip_text
(ic, _("change global guide settings\nnote that these settings are applied globally "
"and will impact any module that shows guide overlays"));
g_signal_connect(G_OBJECT(ic), "clicked",
G_CALLBACK(_settings_autoshow_menu), module);

GtkWidget *box = dt_gui_hbox(dt_gui_expand(cb), ic);
// the settings icon goes in the widget's own quad, which is the column the
// sliders and comboboxes above draw theirs in, rather than in a box beside
// the widget where it would sit further out than all of them
dt_bauhaus_widget_set_quad
(cb, module, dtgtk_cairo_paint_grid, FALSE, _settings_autoshow_menu,
_("change global guide settings\nnote that these settings are applied globally "
"and will impact any module that shows guide overlays"));

// we hide it if the preference is set to "off"
gtk_widget_set_no_show_all(box, TRUE);
gtk_widget_set_no_show_all(cb, TRUE);
gtk_widget_show(cb);
gtk_widget_show(ic);

dt_gui_box_add(iopw, box);
dt_gui_box_add(iopw, cb);
}

void dt_guides_update_module_widget(const dt_iop_module_t *module)
{
if(!module->guides_combo) return;

GtkWidget *box = gtk_widget_get_parent(module->guides_combo);
gtk_widget_set_visible(box, dt_conf_get_bool("plugins/darkroom/show_guides_in_ui"));
// the checkbox is added to the module box directly, there is no wrapper
// to hide any more
gtk_widget_set_visible(module->guides_combo,
dt_conf_get_bool("plugins/darkroom/show_guides_in_ui"));
}

void dt_guides_update_popover_values()
Expand Down
18 changes: 8 additions & 10 deletions src/iop/channelmixerrgb.c
Original file line number Diff line number Diff line change
Expand Up @@ -3784,7 +3784,7 @@ void gui_update(dt_iop_module_t *self)
gboolean use_mixing = TRUE;
if(dt_conf_key_exists("darkroom/modules/channelmixerrgb/use_mixing"))
use_mixing = dt_conf_get_bool("darkroom/modules/channelmixerrgb/use_mixing");
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->use_mixing), use_mixing);
dt_bauhaus_toggle_set(g->use_mixing, use_mixing);

float lightness = 50.f;
if(dt_conf_key_exists("darkroom/modules/channelmixerrgb/lightness"))
Expand Down Expand Up @@ -3955,8 +3955,7 @@ static void _spot_settings_changed_callback(GtkWidget *slider,
Lch_target[0] = dt_bauhaus_slider_get(g->lightness_spot);
Lch_target[1] = dt_bauhaus_slider_get(g->chroma_spot);
Lch_target[2] = dt_bauhaus_slider_get(g->hue_spot) / 360.f;
const gboolean use_mixing =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->use_mixing));
const gboolean use_mixing = dt_bauhaus_toggle_get(g->use_mixing);
dt_iop_gui_leave_critical_section(self);

// Save the color on change
Expand Down Expand Up @@ -4191,8 +4190,7 @@ static void _auto_set_illuminant(dt_iop_module_t *self,
g_free(str);

const dt_spot_mode_t mode = dt_bauhaus_combobox_get(g->spot_mode);
const gboolean use_mixing =
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->use_mixing));
const gboolean use_mixing = dt_bauhaus_toggle_get(g->use_mixing);

// build the channel mixing matrix - keep in synch with commit_params()
dt_colormatrix_t MIX = { { 0.f } };
Expand Down Expand Up @@ -4553,15 +4551,15 @@ void gui_init(dt_iop_module_t *self)
G_CALLBACK(_spot_settings_changed_callback), self);

const gchar *label = N_("take channel mixing into account");
g->use_mixing = gtk_check_button_new_with_label(_(label));
dt_action_define_iop(self, N_("mapping"), label, g->use_mixing, &dt_action_def_toggle);
gtk_label_set_ellipsize
(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->use_mixing))), PANGO_ELLIPSIZE_END);
// no field: this setting belongs to the spot mapping workflow and is kept
// in conf across images, rather than being part of the module's params
g->use_mixing = dt_bauhaus_toggle_new(self);
dt_bauhaus_widget_set_label(g->use_mixing, N_("mapping"), label);
gtk_widget_set_tooltip_text
(g->use_mixing,
_("compute the target by taking the channel mixing into account.\n"
"if disabled, only the CAT is considered."));
g_signal_connect(G_OBJECT(g->use_mixing), "toggled",
g_signal_connect(G_OBJECT(g->use_mixing), "value-changed",
G_CALLBACK(_spot_settings_changed_callback), self);

g->origin_spot = gtk_drawing_area_new();
Expand Down
26 changes: 14 additions & 12 deletions src/iop/colorharmonizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -909,10 +909,10 @@ static void _on_vectorscope_harmony_changed(const dt_color_harmony_guide_t *guid
_apply_harmony_guide(self, self->params, self->gui_data, guide);
}

static void _sync_to_vectorscope_toggled(GtkToggleButton *button, dt_iop_module_t *self)
static void _sync_to_vectorscope_toggled(GtkWidget *button, dt_iop_module_t *self)
{
dt_iop_colorharmonizer_gui_data_t *g = self->gui_data;
const gboolean active = gtk_toggle_button_get_active(button);
const gboolean active = dt_bauhaus_toggle_get(button);
dt_conf_set_bool("plugins/darkroom/colorharmonizer/sync_to_vectorscope", active);

if(active)
Expand Down Expand Up @@ -999,7 +999,7 @@ static void _custom_hue_changed(GtkWidget *widget, dt_iop_module_t *self)
dt_dev_add_history_item(self->dev, self, TRUE);

if(g->sync_to_vectorscope
&& gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->sync_to_vectorscope)))
&& dt_bauhaus_toggle_get(g->sync_to_vectorscope))
_push_to_vectorscope(self);
}

Expand Down Expand Up @@ -1094,7 +1094,7 @@ static void _sync_vectorscope_if_enabled(dt_iop_module_t *self,
GtkWidget *widget)
{
if(!g->sync_to_vectorscope
|| !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->sync_to_vectorscope)))
|| !dt_bauhaus_toggle_get(g->sync_to_vectorscope))
return;

if(self->enabled)
Expand Down Expand Up @@ -1373,7 +1373,7 @@ static void _auto_detect_callback(GtkButton *button, dt_iop_module_t *self)
dt_dev_add_history_item(self->dev, self, TRUE);

if(g->sync_to_vectorscope
&& gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->sync_to_vectorscope)))
&& dt_bauhaus_toggle_get(g->sync_to_vectorscope))
_push_to_vectorscope(self);
}

Expand Down Expand Up @@ -1510,9 +1510,11 @@ void gui_init(dt_iop_module_t *self)

GtkWidget *sync_row = dt_gui_hbox();

g->sync_to_vectorscope = gtk_check_button_new_with_label(_("vectorscope two-way sync"));
gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->sync_to_vectorscope))),
PANGO_ELLIPSIZE_END);
// no field: this only says whether the vectorscope overlay follows the
// module, it is not one of the module's parameters
g->sync_to_vectorscope = dt_bauhaus_toggle_new(self);
dt_bauhaus_widget_set_label(g->sync_to_vectorscope, NULL,
N_("vectorscope two-way sync"));
gtk_widget_set_tooltip_text(g->sync_to_vectorscope,
_("when enabled, the vectorscope harmony overlay is kept in sync with\n"
"the harmony rule and anchor hue controls in the module.\n"
Expand All @@ -1521,9 +1523,9 @@ void gui_init(dt_iop_module_t *self)
const char *conf_key = "plugins/darkroom/colorharmonizer/sync_to_vectorscope";
if(!dt_conf_key_exists(conf_key))
dt_conf_set_bool(conf_key, TRUE);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->sync_to_vectorscope), dt_conf_get_bool(conf_key));
dt_bauhaus_toggle_set(g->sync_to_vectorscope, dt_conf_get_bool(conf_key));

g_signal_connect(G_OBJECT(g->sync_to_vectorscope), "toggled",
g_signal_connect(G_OBJECT(g->sync_to_vectorscope), "value-changed",
G_CALLBACK(_sync_to_vectorscope_toggled), self);

g->set_from_vectorscope = dtgtk_button_new(dtgtk_cairo_paint_refresh, CPF_NONE, NULL);
Expand All @@ -1542,7 +1544,7 @@ void gui_init(dt_iop_module_t *self)
// "set from vectorscope" is redundant when sync is active; disable it initially
// (sync checkbox starts checked, so the button starts insensitive)
gtk_widget_set_sensitive(g->set_from_vectorscope,
!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->sync_to_vectorscope)));
!dt_bauhaus_toggle_get(g->sync_to_vectorscope));

g->histogram_valid = FALSE;
g_mutex_init(&g->histogram_lock);
Expand Down Expand Up @@ -1636,7 +1638,7 @@ void gui_focus(dt_iop_module_t *self, gboolean in)
dt_iop_colorharmonizer_gui_data_t *g = self->gui_data;
if(!g) return;
const gboolean sync = g->sync_to_vectorscope
&& gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(g->sync_to_vectorscope));
&& dt_bauhaus_toggle_get(g->sync_to_vectorscope);
if(in)
{
if(sync && self->enabled)
Expand Down
15 changes: 8 additions & 7 deletions src/iop/colorzones.c
Original file line number Diff line number Diff line change
Expand Up @@ -2364,7 +2364,7 @@ static void _edit_by_area_callback(GtkWidget *widget,
DT_GUARD_GUI_UPDATE();
dt_iop_colorzones_gui_data_t *g = self->gui_data;

g->edit_by_area = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
g->edit_by_area = dt_bauhaus_toggle_get(widget);

gtk_widget_queue_draw(GTK_WIDGET(g->area));
}
Expand Down Expand Up @@ -2669,13 +2669,14 @@ void gui_init(dt_iop_module_t *self)

// edit by area
gchar *label = N_("edit by area");
g->chk_edit_by_area = gtk_check_button_new_with_label(_(label));
dt_action_define_iop(self, NULL, label, g->chk_edit_by_area, &dt_action_def_toggle);
gtk_label_set_ellipsize(GTK_LABEL(gtk_bin_get_child(GTK_BIN(g->chk_edit_by_area))),
PANGO_ELLIPSIZE_START);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->chk_edit_by_area), g->edit_by_area);
// no field: this selects an editing mode for the curve widget below, it
// is not one of the module's parameters
g->chk_edit_by_area = dt_bauhaus_toggle_new(self);
dt_bauhaus_widget_set_label(g->chk_edit_by_area, NULL, label);
dt_bauhaus_widget_set_label_ellipsize(g->chk_edit_by_area, PANGO_ELLIPSIZE_START);
dt_bauhaus_toggle_set(g->chk_edit_by_area, g->edit_by_area);
gtk_widget_set_tooltip_text(g->chk_edit_by_area, _("edit the curve nodes by area"));
g_signal_connect(G_OBJECT(g->chk_edit_by_area), "toggled",
g_signal_connect(G_OBJECT(g->chk_edit_by_area), "value-changed",
G_CALLBACK(_edit_by_area_callback), self);

// display selection
Expand Down
Loading
Loading