diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index 22db1bad21..238503c0d2 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -112,6 +112,9 @@ dnd.css + + errorstates.ui + fishbowl.ui gtkfishbowl.c @@ -222,6 +225,7 @@ editable_cells.c entry_completion.c entry_undo.c + errorstates.c expander.c filtermodel.c fishbowl.c diff --git a/demos/gtk-demo/errorstates.c b/demos/gtk-demo/errorstates.c new file mode 100644 index 0000000000..3dc3b50f3b --- /dev/null +++ b/demos/gtk-demo/errorstates.c @@ -0,0 +1,124 @@ +/* Error states + * + * GtkLabel and GtkEntry can indicate errors if you set the .error + * style class on them. + * + * This examples shows how this can be used in a dialog for input validation. + * + * It also shows how pass callbacks and objects to GtkBuilder with + * GtkBuilderScope and gtk_builder_expose_object(). + */ + +#include +#include + +static void +validate_more_details (GtkEntry *entry, + GParamSpec *pspec, + GtkEntry *details) +{ + if (strlen (gtk_editable_get_text (GTK_EDITABLE (entry))) > 0 && + strlen (gtk_editable_get_text (GTK_EDITABLE (details))) == 0) + { + gtk_widget_set_tooltip_text (GTK_WIDGET (entry), "Must have details first"); + gtk_widget_add_css_class (GTK_WIDGET (entry), "error"); + } + else + { + gtk_widget_set_tooltip_text (GTK_WIDGET (entry), ""); + gtk_widget_remove_css_class (GTK_WIDGET (entry), "error"); + } +} + +static gboolean +mode_switch_state_set (GtkSwitch *sw, + gboolean state, + GtkWidget *scale) +{ + GtkWidget *label; + + label = GTK_WIDGET (g_object_get_data (G_OBJECT (sw), "error_label")); + + if (!state || + (gtk_range_get_value (GTK_RANGE (scale)) > 50)) + { + gtk_widget_hide (label); + gtk_switch_set_state (sw, state); + } + else + { + gtk_widget_show (label); + } + + return TRUE; +} + +static void +level_scale_value_changed (GtkRange *range, + GtkWidget *sw) +{ + GtkWidget *label; + + label = GTK_WIDGET (g_object_get_data (G_OBJECT (sw), "error_label")); + + if (gtk_switch_get_active (GTK_SWITCH (sw)) && + !gtk_switch_get_state (GTK_SWITCH (sw)) && + (gtk_range_get_value (range) > 50)) + { + gtk_widget_hide (label); + gtk_switch_set_state (GTK_SWITCH (sw), TRUE); + } + else if (gtk_switch_get_state (GTK_SWITCH (sw)) && + (gtk_range_get_value (range) <= 50)) + { + gtk_switch_set_state (GTK_SWITCH (sw), FALSE); + } +} + +GtkWidget * +do_errorstates (GtkWidget *do_widget) +{ + static GtkWidget *window = NULL; + + if (!window) + { + GtkWidget *toplevel; + GtkBuilder *builder; + GtkBuilderScope *scope; + GtkWidget *sw, *label; + + toplevel = GTK_WIDGET (gtk_widget_get_root (do_widget)); + + scope = gtk_builder_cscope_new (); + gtk_builder_cscope_add_callback_symbols (GTK_BUILDER_CSCOPE (scope), + "validate_more_details", G_CALLBACK (validate_more_details), + "mode_switch_state_set", G_CALLBACK (mode_switch_state_set), + "level_scale_value_changed", G_CALLBACK (level_scale_value_changed), + NULL); + + builder = gtk_builder_new (); + gtk_builder_set_scope (builder, scope); + gtk_builder_expose_object (builder, "toplevel", G_OBJECT (toplevel)); + gtk_builder_add_from_resource (builder, "/errorstates/errorstates.ui", NULL); + + window = GTK_WIDGET (gtk_builder_get_object (builder, "dialog")); + + gtk_window_set_display (GTK_WINDOW (window), + gtk_widget_get_display (do_widget)); + g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window); + + sw = GTK_WIDGET (gtk_builder_get_object (builder, "mode_switch")); + label = GTK_WIDGET (gtk_builder_get_object (builder, "error_label")); + g_object_set_data (G_OBJECT (sw), "error_label", label); + + g_object_unref (builder); + g_object_unref (scope); + } + + if (!gtk_widget_get_visible (window)) + gtk_widget_show (window); + else + gtk_window_destroy (GTK_WINDOW (window)); + + return window; +} diff --git a/demos/gtk-demo/errorstates.ui b/demos/gtk-demo/errorstates.ui new file mode 100644 index 0000000000..dd4a95b8fc --- /dev/null +++ b/demos/gtk-demo/errorstates.ui @@ -0,0 +1,158 @@ + + + + toplevel + 1 + 0 + 1 + Settings + 1 + + + + + 10 + 10 + 20 + 20 + 20 + 20 + + + end + baseline + _Details + 1 + details_entry + + + 0 + 0 + + + + + + baseline + + + 1 + 0 + 2 + + + + + + end + baseline + More D_etails + 1 + more_details_entry + + + 0 + 1 + + + + + + baseline + + + 1 + 1 + 2 + + + + + + end + baseline + _Level + 1 + level_scale + + + 0 + 2 + + + + + + baseline + 0 + + + 100 + 0 + 50 + 1 + 10 + + + + + 1 + 2 + 2 + + + + + + end + baseline + _Mode + 1 + mode_switch + + + 0 + 3 + + + + + + start + baseline + + + 1 + 3 + + + + + + 0 + start + baseline + Level too low + + + 2 + 3 + + + + + + + + + diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build index 07fd1b2330..a60f121896 100644 --- a/demos/gtk-demo/meson.build +++ b/demos/gtk-demo/meson.build @@ -23,6 +23,7 @@ demos = files([ 'editable_cells.c', 'entry_completion.c', 'entry_undo.c', + 'errorstates.c', 'expander.c', 'filtermodel.c', 'fishbowl.c',