1 /*
2  * e-html-editor-image-dialog.h
3  *
4  * Copyright (C) 2012 Dan Vrátil <dvratil@redhat.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) version 3.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with the program; if not, see <http://www.gnu.org/licenses/>
18  *
19  */
20 
21 #include "evolution-config.h"
22 
23 #include <stdlib.h>
24 #include <glib/gi18n-lib.h>
25 
26 #include "e-image-chooser-dialog.h"
27 #include "e-misc-utils.h"
28 
29 #include "e-html-editor-image-dialog.h"
30 
31 #define E_HTML_EDITOR_IMAGE_DIALOG_GET_PRIVATE(obj) \
32 	(G_TYPE_INSTANCE_GET_PRIVATE \
33 	((obj), E_TYPE_HTML_EDITOR_IMAGE_DIALOG, EHTMLEditorImageDialogPrivate))
34 
35 typedef enum {
36 	E_SYNC_ASPECT_RATIO_BY_WIDTH,
37 	E_SYNC_ASPECT_RATIO_BY_HEIGHT
38 } ESyncAspectRatio;
39 
40 struct _EHTMLEditorImageDialogPrivate {
41 	GtkWidget *file_chooser;
42 	GtkWidget *description_edit;
43 
44 	GtkWidget *width_edit;
45 	GtkWidget *height_edit;
46 	GtkWidget *size_units;
47 	GtkWidget *alignment;
48 
49 	GtkWidget *x_padding_edit;
50 	GtkWidget *y_padding_edit;
51 	GtkWidget *border_edit;
52 
53 	GtkWidget *url_edit;
54 	GtkWidget *test_url_button;
55 
56 	gboolean preserve_aspect_ratio;
57 };
58 
59 G_DEFINE_TYPE (
60 	EHTMLEditorImageDialog,
61 	e_html_editor_image_dialog,
62 	E_TYPE_HTML_EDITOR_DIALOG);
63 
64 static void
html_editor_image_dialog_set_src(EHTMLEditorImageDialog * dialog)65 html_editor_image_dialog_set_src (EHTMLEditorImageDialog *dialog)
66 {
67 	EHTMLEditor *editor;
68 	EContentEditor *cnt_editor;
69 	gchar *uri;
70 
71 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
72 		return;
73 
74 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
75 	cnt_editor = e_html_editor_get_content_editor (editor);
76 
77 	uri = gtk_file_chooser_get_uri (
78 		GTK_FILE_CHOOSER (dialog->priv->file_chooser));
79 
80 	e_content_editor_image_set_src (cnt_editor, uri);
81 
82 	g_free (uri);
83 }
84 
85 static void
html_editor_image_dialog_set_alt(EHTMLEditorImageDialog * dialog)86 html_editor_image_dialog_set_alt (EHTMLEditorImageDialog *dialog)
87 {
88 	EHTMLEditor *editor;
89 	EContentEditor *cnt_editor;
90 	const gchar *value;
91 
92 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
93 		return;
94 
95 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
96 	cnt_editor = e_html_editor_get_content_editor (editor);
97 
98 	value = gtk_entry_get_text (GTK_ENTRY (dialog->priv->description_edit));
99 
100 	e_content_editor_image_set_alt (cnt_editor, value);
101 }
102 
103 static void
maybe_sync_aspect_ration(EHTMLEditorImageDialog * dialog,ESyncAspectRatio kind)104 maybe_sync_aspect_ration (EHTMLEditorImageDialog *dialog,
105 			  ESyncAspectRatio kind)
106 {
107 	EHTMLEditor *editor;
108 	EContentEditor *cnt_editor;
109 	gint32 natural_width, natural_height;
110 	gint width = -1, height = -1, requested;
111 
112 	if (!dialog->priv->preserve_aspect_ratio)
113 		return;
114 
115 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
116 	cnt_editor = e_html_editor_get_content_editor (editor);
117 
118 	natural_width = e_content_editor_image_get_natural_width (cnt_editor);
119 	natural_height = e_content_editor_image_get_natural_height (cnt_editor);
120 
121 	requested = kind == E_SYNC_ASPECT_RATIO_BY_WIDTH ?
122 		gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->width_edit)) :
123 		gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->height_edit));
124 
125 	switch (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->size_units))) {
126 		case 0:	/* px */
127 			if (kind == E_SYNC_ASPECT_RATIO_BY_WIDTH) {
128 				if (!natural_width)
129 					height = 0;
130 				else
131 					height = ((gdouble) natural_height) * requested / natural_width;
132 			} else { /* E_SYNC_ASPECT_RATIO_BY_HEIGHT */
133 				if (!natural_height)
134 					width = 0;
135 				else
136 					width = ((gdouble) natural_width) * requested / natural_height;
137 			}
138 			break;
139 
140 		case 1: /* percent */
141 			if (kind == E_SYNC_ASPECT_RATIO_BY_WIDTH)
142 				height = requested;
143 			else /* E_SYNC_ASPECT_RATIO_BY_HEIGHT */
144 				width = requested;
145 			break;
146 
147 		case 2: /* follow */
148 			/* ignore */
149 			break;
150 	}
151 
152 	/* To avoid recursion on set */
153 	dialog->priv->preserve_aspect_ratio = FALSE;
154 
155 	if (width != -1) {
156 		if (gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->width_edit)) == width)
157 			g_signal_emit_by_name (dialog->priv->width_edit, "value-changed", NULL);
158 		else
159 			gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->width_edit), width);
160 	}
161 
162 	if (height != -1) {
163 		if (gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->height_edit)) == height)
164 			g_signal_emit_by_name (dialog->priv->height_edit, "value-changed", NULL);
165 		else
166 			gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->height_edit), height);
167 	}
168 
169 	dialog->priv->preserve_aspect_ratio = TRUE;
170 }
171 
172 static void
html_editor_image_dialog_set_width(EHTMLEditorImageDialog * dialog)173 html_editor_image_dialog_set_width (EHTMLEditorImageDialog *dialog)
174 {
175 	EHTMLEditor *editor;
176 	EContentEditor *cnt_editor;
177 	gint requested;
178 	gint32 natural = 0;
179 	gint width;
180 
181 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
182 		return;
183 
184 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
185 	cnt_editor = e_html_editor_get_content_editor (editor);
186 
187 	natural = e_content_editor_image_get_natural_width (cnt_editor);
188 
189 	requested = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->width_edit));
190 
191 	switch (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->size_units))) {
192 		case 0:	/* px */
193 			width = requested;
194 			break;
195 
196 		case 1: /* percent */
197 			if (requested)
198 				width = natural * requested / 100.0;
199 			else
200 				width = natural;
201 			break;
202 
203 		case 2: /* follow */
204 			width = natural;
205 			break;
206 
207 		default:
208 			return;
209 	}
210 
211 	e_content_editor_image_set_width (cnt_editor, width);
212 
213 	maybe_sync_aspect_ration (dialog, E_SYNC_ASPECT_RATIO_BY_WIDTH);
214 }
215 
216 static void
html_editor_image_dialog_set_height(EHTMLEditorImageDialog * dialog)217 html_editor_image_dialog_set_height (EHTMLEditorImageDialog *dialog)
218 {
219 	EHTMLEditor *editor;
220 	EContentEditor *cnt_editor;
221 	gint requested;
222 	gint32 natural = 0;
223 	gint height;
224 
225 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
226 		return;
227 
228 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
229 	cnt_editor = e_html_editor_get_content_editor (editor);
230 
231 	natural = e_content_editor_image_get_natural_height (cnt_editor);
232 
233 	requested = gtk_spin_button_get_value_as_int (
234 		GTK_SPIN_BUTTON (dialog->priv->height_edit));
235 
236 	switch (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->size_units))) {
237 		case 0:	/* px */
238 			height = requested;
239 			break;
240 
241 		case 1: /* percent */
242 			if (requested)
243 				height = natural * requested / 100.0;
244 			else
245 				height = natural;
246 			break;
247 
248 		case 2: /* follow */
249 			height = natural;
250 			break;
251 
252 		default:
253 			return;
254 	}
255 
256 	e_content_editor_image_set_height (cnt_editor, height);
257 
258 	maybe_sync_aspect_ration (dialog, E_SYNC_ASPECT_RATIO_BY_HEIGHT);
259 }
260 
261 static void
html_editor_image_dialog_set_size_units(EHTMLEditorImageDialog * dialog)262 html_editor_image_dialog_set_size_units (EHTMLEditorImageDialog *dialog)
263 {
264 	EHTMLEditor *editor;
265 	EContentEditor *cnt_editor;
266 	gint requested_width, requested_height;
267 	gint32 natural_width, natural_height;
268 	gint width = -1, height = -1;
269 
270 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
271 		return;
272 
273 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
274 	cnt_editor = e_html_editor_get_content_editor (editor);
275 
276 	natural_width = e_content_editor_image_get_natural_width (cnt_editor);
277 	natural_height = e_content_editor_image_get_natural_height (cnt_editor);
278 
279 	requested_width = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->width_edit));
280 	requested_height = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (dialog->priv->height_edit));
281 
282 	switch (gtk_combo_box_get_active (GTK_COMBO_BOX (dialog->priv->size_units))) {
283 		case 0:	/* px */
284 			if (gtk_widget_is_sensitive (dialog->priv->width_edit)) {
285 				width = requested_width * natural_width * 0.01;
286 				height = requested_height * natural_height * 0.01;
287 			} else {
288 				width = natural_width;
289 				height = natural_height;
290 			}
291 			gtk_widget_set_sensitive (dialog->priv->width_edit, TRUE);
292 			gtk_widget_set_sensitive (dialog->priv->height_edit, TRUE);
293 			break;
294 
295 		case 1: /* percent */
296 			if (natural_width && gtk_widget_is_sensitive (dialog->priv->width_edit)) {
297 				width = (((gdouble) requested_width) / natural_width) * 100;
298 			} else {
299 				width = 100;
300 			}
301 			if (natural_height && gtk_widget_is_sensitive (dialog->priv->height_edit)) {
302 				height = (((gdouble) requested_height) / natural_height) * 100;
303 			} else {
304 				height = 100;
305 			}
306 			gtk_widget_set_sensitive (dialog->priv->width_edit, TRUE);
307 			gtk_widget_set_sensitive (dialog->priv->height_edit, TRUE);
308 			break;
309 
310 		case 2: /* follow */
311 			gtk_widget_set_sensitive (dialog->priv->width_edit, FALSE);
312 			gtk_widget_set_sensitive (dialog->priv->height_edit, FALSE);
313 			break;
314 	}
315 
316 	e_content_editor_image_set_width_follow (cnt_editor, !gtk_widget_get_sensitive (dialog->priv->width_edit));
317 	e_content_editor_image_set_height_follow (cnt_editor, !gtk_widget_get_sensitive (dialog->priv->height_edit));
318 
319 	if (width != -1)
320 		gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->width_edit), width);
321 	if (height != -1)
322 		gtk_spin_button_set_value (GTK_SPIN_BUTTON (dialog->priv->height_edit), height);
323 }
324 
325 static void
html_editor_image_dialog_set_alignment(EHTMLEditorImageDialog * dialog)326 html_editor_image_dialog_set_alignment (EHTMLEditorImageDialog *dialog)
327 {
328 	EHTMLEditor *editor;
329 	EContentEditor *cnt_editor;
330 	const gchar *value;
331 
332 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
333 		return;
334 
335 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
336 	cnt_editor = e_html_editor_get_content_editor (editor);
337 
338 	value = gtk_combo_box_get_active_id (GTK_COMBO_BOX (dialog->priv->alignment));
339 	e_content_editor_image_set_align (cnt_editor, value);
340 }
341 
342 static void
html_editor_image_dialog_set_x_padding(EHTMLEditorImageDialog * dialog)343 html_editor_image_dialog_set_x_padding (EHTMLEditorImageDialog *dialog)
344 {
345 	EHTMLEditor *editor;
346 	EContentEditor *cnt_editor;
347 	gint value;
348 
349 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
350 		return;
351 
352 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
353 	cnt_editor = e_html_editor_get_content_editor (editor);
354 
355 	value = gtk_spin_button_get_value_as_int (
356 		GTK_SPIN_BUTTON (dialog->priv->x_padding_edit));
357 	e_content_editor_image_set_hspace (cnt_editor, value);
358 }
359 
360 static void
html_editor_image_dialog_set_y_padding(EHTMLEditorImageDialog * dialog)361 html_editor_image_dialog_set_y_padding (EHTMLEditorImageDialog *dialog)
362 {
363 	EHTMLEditor *editor;
364 	EContentEditor *cnt_editor;
365 	gint value;
366 
367 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
368 		return;
369 
370 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
371 	cnt_editor = e_html_editor_get_content_editor (editor);
372 
373 	value = gtk_spin_button_get_value_as_int (
374 		GTK_SPIN_BUTTON (dialog->priv->y_padding_edit));
375 	e_content_editor_image_set_vspace (cnt_editor, value);
376 }
377 
378 static void
html_editor_image_dialog_set_border(EHTMLEditorImageDialog * dialog)379 html_editor_image_dialog_set_border (EHTMLEditorImageDialog *dialog)
380 {
381 	EHTMLEditor *editor;
382 	EContentEditor *cnt_editor;
383 	gint value;
384 
385 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
386 		return;
387 
388 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
389 	cnt_editor = e_html_editor_get_content_editor (editor);
390 
391 	value = gtk_spin_button_get_value_as_int (
392 		GTK_SPIN_BUTTON (dialog->priv->border_edit));
393 
394 	e_content_editor_image_set_border (cnt_editor, value);
395 }
396 
397 static void
html_editor_image_dialog_set_url(EHTMLEditorImageDialog * dialog)398 html_editor_image_dialog_set_url (EHTMLEditorImageDialog *dialog)
399 {
400 	EHTMLEditor *editor;
401 	EContentEditor *cnt_editor;
402 	const gchar *value;
403 
404 	if (!gtk_widget_get_visible (GTK_WIDGET (dialog)))
405 		return;
406 
407 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
408 	cnt_editor = e_html_editor_get_content_editor (editor);
409 
410 	value = gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit));
411 
412 	e_content_editor_image_set_url (cnt_editor, value);
413 }
414 
415 static void
html_editor_image_dialog_test_url(EHTMLEditorImageDialog * dialog)416 html_editor_image_dialog_test_url (EHTMLEditorImageDialog *dialog)
417 {
418 	e_show_uri (
419 		GTK_WINDOW (dialog),
420 		gtk_entry_get_text (GTK_ENTRY (dialog->priv->url_edit)));
421 }
422 
423 static void
html_editor_image_dialog_show(GtkWidget * widget)424 html_editor_image_dialog_show (GtkWidget *widget)
425 {
426 	EHTMLEditor *editor;
427 	EHTMLEditorImageDialog *dialog;
428 	EContentEditor *cnt_editor;
429 	gchar *value;
430 
431 	dialog = E_HTML_EDITOR_IMAGE_DIALOG (widget);
432 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
433 	cnt_editor = e_html_editor_get_content_editor (editor);
434 
435 	e_content_editor_on_dialog_open (cnt_editor, E_CONTENT_EDITOR_DIALOG_IMAGE);
436 
437 	value = e_content_editor_image_get_src (cnt_editor);
438 	if (value && *value) {
439 		gtk_file_chooser_set_uri (
440 			GTK_FILE_CHOOSER (dialog->priv->file_chooser), value);
441 		gtk_widget_set_sensitive (
442 			GTK_WIDGET (dialog->priv->file_chooser), TRUE);
443 	} else {
444 		gtk_file_chooser_set_uri (
445 			GTK_FILE_CHOOSER (dialog->priv->file_chooser), "");
446 		gtk_widget_set_sensitive (
447 			GTK_WIDGET (dialog->priv->file_chooser), FALSE);
448 	}
449 	g_free (value);
450 
451 	value = e_content_editor_image_get_alt (cnt_editor);
452 	gtk_entry_set_text (
453 		GTK_ENTRY (dialog->priv->description_edit), value ? value : "");
454 	g_free (value);
455 
456 	gtk_spin_button_set_value (
457 		GTK_SPIN_BUTTON (dialog->priv->width_edit),
458 		e_content_editor_image_get_width (cnt_editor));
459 
460 	gtk_spin_button_set_value (
461 		GTK_SPIN_BUTTON (dialog->priv->height_edit),
462 		e_content_editor_image_get_height (cnt_editor));
463 
464 	gtk_combo_box_set_active_id (
465 		GTK_COMBO_BOX (dialog->priv->size_units), "units-px");
466 
467 	gtk_spin_button_set_value (
468 		GTK_SPIN_BUTTON (dialog->priv->border_edit),
469 		e_content_editor_image_get_border (cnt_editor));
470 
471 	value = e_content_editor_image_get_align (cnt_editor);
472 	gtk_combo_box_set_active_id (
473 		GTK_COMBO_BOX (dialog->priv->alignment),
474 		(value && *value) ? value : "bottom");
475 	g_free (value);
476 
477 	gtk_spin_button_set_value (
478 		GTK_SPIN_BUTTON (dialog->priv->y_padding_edit),
479 		e_content_editor_image_get_hspace (cnt_editor));
480 
481 	gtk_spin_button_set_value (
482 		GTK_SPIN_BUTTON (dialog->priv->y_padding_edit),
483 		e_content_editor_image_get_vspace (cnt_editor));
484 
485 	value = e_content_editor_image_get_url (cnt_editor);
486 	if (value && *value)
487 		gtk_entry_set_text (GTK_ENTRY (dialog->priv->url_edit), value);
488 	g_free (value);
489 
490 	/* Chain up to parent implementation */
491 	GTK_WIDGET_CLASS (e_html_editor_image_dialog_parent_class)->show (widget);
492 }
493 
494 static void
aspect_ration_clicked_cb(GtkButton * button,gpointer user_data)495 aspect_ration_clicked_cb (GtkButton *button,
496 			  gpointer user_data)
497 {
498 	EHTMLEditorImageDialog *dialog = user_data;
499 	const gchar *icon_name;
500 
501 	dialog->priv->preserve_aspect_ratio = !dialog->priv->preserve_aspect_ratio;
502 
503 	if (dialog->priv->preserve_aspect_ratio)
504 		icon_name = "aspect-ratio-lock";
505 	else
506 		icon_name = "aspect-ratio-unlock";
507 
508 	gtk_button_set_image (button, gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_BUTTON));
509 
510 	maybe_sync_aspect_ration (dialog, E_SYNC_ASPECT_RATIO_BY_WIDTH);
511 }
512 
513 static void
html_editor_image_dialog_hide(GtkWidget * widget)514 html_editor_image_dialog_hide (GtkWidget *widget)
515 {
516 	EHTMLEditor *editor;
517 	EHTMLEditorImageDialog *dialog;
518 	EContentEditor *cnt_editor;
519 
520 	dialog = E_HTML_EDITOR_IMAGE_DIALOG (widget);
521 	editor = e_html_editor_dialog_get_editor (E_HTML_EDITOR_DIALOG (dialog));
522 	cnt_editor = e_html_editor_get_content_editor (editor);
523 
524 	e_content_editor_on_dialog_close (cnt_editor, E_CONTENT_EDITOR_DIALOG_IMAGE);
525 
526 	GTK_WIDGET_CLASS (e_html_editor_image_dialog_parent_class)->hide (widget);
527 }
528 
529 static void
e_html_editor_image_dialog_class_init(EHTMLEditorImageDialogClass * class)530 e_html_editor_image_dialog_class_init (EHTMLEditorImageDialogClass *class)
531 {
532 	GtkWidgetClass *widget_class;
533 
534 	g_type_class_add_private (class, sizeof (EHTMLEditorImageDialogPrivate));
535 
536 	widget_class = GTK_WIDGET_CLASS (class);
537 	widget_class->show = html_editor_image_dialog_show;
538 	widget_class->hide = html_editor_image_dialog_hide;
539 }
540 
541 static void
e_html_editor_image_dialog_init(EHTMLEditorImageDialog * dialog)542 e_html_editor_image_dialog_init (EHTMLEditorImageDialog *dialog)
543 {
544 	GtkGrid *main_layout, *grid;
545 	GtkWidget *widget;
546 	GtkFileFilter *file_filter;
547 
548 	dialog->priv = E_HTML_EDITOR_IMAGE_DIALOG_GET_PRIVATE (dialog);
549 
550 	main_layout = e_html_editor_dialog_get_container (E_HTML_EDITOR_DIALOG (dialog));
551 
552 	/* == General == */
553 	widget = gtk_label_new ("");
554 	gtk_label_set_markup (GTK_LABEL (widget), _("<b>General</b>"));
555 	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
556 	gtk_grid_attach (main_layout, widget, 0, 0, 1, 1);
557 
558 	grid = GTK_GRID (gtk_grid_new ());
559 	gtk_grid_set_row_spacing (grid, 5);
560 	gtk_grid_set_column_spacing (grid, 5);
561 	gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 1, 1, 1);
562 	gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
563 
564 	file_filter = gtk_file_filter_new ();
565 	gtk_file_filter_set_name (file_filter, _("Images"));
566 	gtk_file_filter_add_mime_type (file_filter, "image/*");
567 
568 	/* Source */
569 	if (e_util_is_running_flatpak ()) {
570 		widget = gtk_file_chooser_button_new (_("Choose Background Image"), GTK_FILE_CHOOSER_ACTION_OPEN);
571 	} else {
572 		widget = e_image_chooser_dialog_new (
573 				_("Choose Background Image"),
574 				GTK_WINDOW (dialog));
575 		gtk_file_chooser_set_action (
576 			GTK_FILE_CHOOSER (widget), GTK_FILE_CHOOSER_ACTION_OPEN);
577 
578 		widget = gtk_file_chooser_button_new_with_dialog (widget);
579 	}
580 
581 	gtk_widget_set_hexpand (widget, TRUE);
582 	gtk_grid_attach (grid, widget, 1, 0, 1, 1);
583 	g_signal_connect_swapped (
584 		widget, "file-set",
585 		G_CALLBACK (html_editor_image_dialog_set_src), dialog);
586 	dialog->priv->file_chooser = widget;
587 
588 	widget = gtk_label_new_with_mnemonic (_("_Source:"));
589 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
590 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->file_chooser);
591 	gtk_grid_attach (grid, widget, 0, 0, 1, 1);
592 
593 	/* Description */
594 	widget = gtk_entry_new ();
595 	gtk_widget_set_hexpand (widget, TRUE);
596 	gtk_grid_attach (grid, widget, 1, 1, 1, 1);
597 	g_signal_connect_swapped (
598 		widget, "notify::text",
599 		G_CALLBACK (html_editor_image_dialog_set_alt), dialog);
600 	dialog->priv->description_edit = widget;
601 
602 	widget = gtk_label_new_with_mnemonic (_("_Description:"));
603 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
604 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->description_edit);
605 	gtk_grid_attach (grid, widget, 0, 1, 1, 1);
606 
607 	/* == Layout == */
608 	widget = gtk_label_new ("");
609 	gtk_label_set_markup (GTK_LABEL (widget), _("<b>Layout</b>"));
610 	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
611 	gtk_grid_attach (main_layout, widget, 0, 2, 1, 1);
612 
613 	grid = GTK_GRID (gtk_grid_new ());
614 	gtk_grid_set_row_spacing (grid, 5);
615 	gtk_grid_set_column_spacing (grid, 5);
616 	gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 3, 1, 1);
617 	gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
618 
619 	/* Width */
620 	widget = gtk_spin_button_new_with_range (1, G_MAXUINT, 1);
621 	gtk_grid_attach (grid, widget, 1, 0, 1, 1);
622 	g_signal_connect_swapped (
623 		widget, "value-changed",
624 		G_CALLBACK (html_editor_image_dialog_set_width), dialog);
625 	dialog->priv->width_edit = widget;
626 
627 	widget = gtk_label_new_with_mnemonic (_("_Width:"));
628 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
629 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->width_edit);
630 	gtk_grid_attach (grid, widget, 0, 0, 1, 1);
631 
632 	/* Height */
633 	widget = gtk_spin_button_new_with_range (1, G_MAXUINT, 1);
634 	gtk_grid_attach (grid, widget, 1, 1, 1, 1);
635 	g_signal_connect_swapped (
636 		widget, "value-changed",
637 		G_CALLBACK (html_editor_image_dialog_set_height), dialog);
638 	dialog->priv->height_edit = widget;
639 
640 	widget = gtk_label_new_with_mnemonic (_("_Height:"));
641 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
642 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->height_edit);
643 	gtk_grid_attach (grid, widget, 0, 1, 1, 1);
644 
645 	widget = gtk_combo_box_text_new ();
646 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-px", "px");
647 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-percent", "%");
648 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "units-follow", "follow");
649 	gtk_combo_box_set_active_id (GTK_COMBO_BOX (widget), "units-px");
650 	gtk_grid_attach (grid, widget, 2, 1, 1, 1);
651 	g_signal_connect_swapped (
652 		widget, "changed",
653 		G_CALLBACK (html_editor_image_dialog_set_size_units), dialog);
654 	dialog->priv->size_units = widget;
655 
656 	widget = gtk_button_new ();
657 	gtk_button_set_always_show_image (GTK_BUTTON (widget), TRUE);
658 	gtk_button_set_image (GTK_BUTTON (widget), gtk_image_new_from_icon_name ("aspect-ratio-lock", GTK_ICON_SIZE_BUTTON));
659 	gtk_widget_set_tooltip_text (widget, _("Preserve aspect ratio"));
660 	gtk_grid_attach (grid, widget, 3, 0, 1, 2);
661 	dialog->priv->preserve_aspect_ratio = TRUE;
662 
663 	g_signal_connect_object (widget, "clicked",
664 		G_CALLBACK (aspect_ration_clicked_cb), dialog, 0);
665 
666 	/* Alignment */
667 	widget = gtk_combo_box_text_new ();
668 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "top", _("Top"));
669 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "middle", _("Middle"));
670 	gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (widget), "bottom", _("Bottom"));
671 	gtk_combo_box_set_active_id (GTK_COMBO_BOX (widget), "bottom");
672 	gtk_grid_attach (grid, widget, 1, 2, 1, 1);
673 	g_signal_connect_swapped (
674 		widget, "changed",
675 		G_CALLBACK (html_editor_image_dialog_set_alignment), dialog);
676 	dialog->priv->alignment = widget;
677 
678 	widget = gtk_label_new_with_mnemonic (_("_Alignment"));
679 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
680 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->alignment);
681 	gtk_grid_attach (grid, widget, 0, 2, 1, 1);
682 
683 	/* X Padding */
684 	widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
685 	gtk_grid_attach (grid, widget, 6, 0, 1, 1);
686 	g_signal_connect_swapped (
687 		widget, "value-changed",
688 		G_CALLBACK (html_editor_image_dialog_set_x_padding), dialog);
689 	dialog->priv->x_padding_edit = widget;
690 
691 	widget = gtk_label_new_with_mnemonic (_("_X-Padding:"));
692 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
693 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->x_padding_edit);
694 	gtk_grid_attach (grid, widget, 5, 0, 1, 1);
695 
696 	widget = gtk_label_new ("px");
697 	gtk_grid_attach (grid, widget, 7, 0, 1, 1);
698 
699 	/* Y Padding */
700 	widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
701 	gtk_grid_attach (grid, widget, 6, 1, 1, 1);
702 	g_signal_connect_swapped (
703 		widget, "value-changed",
704 		G_CALLBACK (html_editor_image_dialog_set_y_padding), dialog);
705 	dialog->priv->y_padding_edit = widget;
706 
707 	widget = gtk_label_new_with_mnemonic (_("_Y-Padding:"));
708 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
709 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->y_padding_edit);
710 	gtk_grid_attach (grid, widget, 5, 1, 1, 1);
711 
712 	widget = gtk_label_new ("px");
713 	gtk_grid_attach (grid, widget, 7, 1, 1, 1);
714 
715 	/* Border */
716 	widget = gtk_spin_button_new_with_range (0, G_MAXUINT, 1);
717 	gtk_grid_attach (grid, widget, 6, 2, 1, 1);
718 	g_signal_connect_swapped (
719 		widget, "value-changed",
720 		G_CALLBACK (html_editor_image_dialog_set_border), dialog);
721 	dialog->priv->border_edit = widget;
722 
723 	widget = gtk_label_new_with_mnemonic (_("_Border:"));
724 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
725 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->border_edit);
726 	gtk_grid_attach (grid, widget, 5, 2, 1, 1);
727 
728 	widget = gtk_label_new ("px");
729 	gtk_grid_attach (grid, widget, 7, 2, 1, 1);
730 
731 	/* == Layout == */
732 	widget = gtk_label_new ("");
733 	gtk_label_set_markup (GTK_LABEL (widget), _("<b>Link</b>"));
734 	gtk_misc_set_alignment (GTK_MISC (widget), 0, 0.5);
735 	gtk_grid_attach (main_layout, widget, 0, 4, 1, 1);
736 
737 	grid = GTK_GRID (gtk_grid_new ());
738 	gtk_grid_set_row_spacing (grid, 5);
739 	gtk_grid_set_column_spacing (grid, 5);
740 	gtk_grid_attach (main_layout, GTK_WIDGET (grid), 0, 6, 1, 1);
741 	gtk_widget_set_margin_left (GTK_WIDGET (grid), 10);
742 
743 	widget = gtk_entry_new ();
744 	gtk_grid_attach (grid, widget, 1 ,0, 1, 1);
745 	gtk_widget_set_hexpand (widget, TRUE);
746 	g_signal_connect_swapped (
747 		widget, "notify::text",
748 		G_CALLBACK (html_editor_image_dialog_set_url), dialog);
749 	dialog->priv->url_edit = widget;
750 
751 	widget = gtk_label_new_with_mnemonic (_("_URL:"));
752 	gtk_label_set_justify (GTK_LABEL (widget), GTK_JUSTIFY_RIGHT);
753 	gtk_label_set_mnemonic_widget (GTK_LABEL (widget), dialog->priv->url_edit);
754 	gtk_grid_attach (grid, widget, 0, 0, 1, 1);
755 
756 	widget = gtk_button_new_with_mnemonic (_("_Test URL…"));
757 	gtk_grid_attach (grid, widget, 2, 0, 1, 1);
758 	g_signal_connect_swapped (
759 		widget, "clicked",
760 		G_CALLBACK (html_editor_image_dialog_test_url), dialog);
761 	dialog->priv->test_url_button = widget;
762 
763 	gtk_widget_show_all (GTK_WIDGET (main_layout));
764 }
765 
766 GtkWidget *
e_html_editor_image_dialog_new(EHTMLEditor * editor)767 e_html_editor_image_dialog_new (EHTMLEditor *editor)
768 {
769 	return GTK_WIDGET (
770 		g_object_new (
771 			E_TYPE_HTML_EDITOR_IMAGE_DIALOG,
772 			"editor", editor,
773 			"title", _("Image Properties"),
774 			NULL));
775 }
776 
777 void
e_html_editor_image_dialog_show(EHTMLEditorImageDialog * dialog)778 e_html_editor_image_dialog_show (EHTMLEditorImageDialog *dialog)
779 {
780 	EHTMLEditorImageDialogClass *class;
781 
782 	g_return_if_fail (E_IS_HTML_EDITOR_IMAGE_DIALOG (dialog));
783 
784 	class = E_HTML_EDITOR_IMAGE_DIALOG_GET_CLASS (dialog);
785 	GTK_WIDGET_CLASS (class)->show (GTK_WIDGET (dialog));
786 }
787