1/*
2 * This file is part of gitg
3 *
4 * Copyright (C) 2016 - Jesse van den Kieboom
5 *
6 * gitg is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * gitg 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with gitg. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-diff-view-file-renderer-image.ui")]
21class Gitg.DiffViewFileRendererImage : Gtk.Grid, DiffViewFileRenderer
22{
23	public Ggit.DiffDelta? delta { get; construct set; }
24	public Repository repository { get; construct set; }
25
26	[GtkChild( name = "diff_image_side_by_side" )]
27	private Gitg.DiffImageSideBySide d_diff_image_side_by_side;
28
29	[GtkChild( name = "diff_image_slider" )]
30	private Gitg.DiffImageSlider d_diff_image_slider;
31
32	[GtkChild( name = "scale_slider_adjustment" )]
33	private Gtk.Adjustment d_scale_slider_adjustment;
34
35	[GtkChild( name = "diff_image_overlay" )]
36	private Gitg.DiffImageOverlay d_diff_image_overlay;
37
38	[GtkChild( name = "scale_overlay_adjustment" )]
39	private Gtk.Adjustment d_scale_overlay_adjustment;
40
41	[GtkChild( name = "diff_image_difference" )]
42	private Gitg.DiffImageDifference d_diff_image_difference;
43
44	[GtkChild( name = "stack_switcher" )]
45	private Gtk.StackSwitcher d_stack_switcher;
46
47	private SurfaceCache d_cache;
48
49	public DiffViewFileRendererImage(Repository repository, Ggit.DiffDelta delta)
50	{
51		Object(repository: repository, delta: delta);
52	}
53
54	construct
55	{
56		d_cache = new SurfaceCache(pixbuf_for_file(delta.get_old_file()),
57		                           pixbuf_for_file(delta.get_new_file()));
58
59		d_diff_image_side_by_side.cache = d_cache;
60		d_diff_image_slider.cache = d_cache;
61		d_diff_image_overlay.cache = d_cache;
62		d_diff_image_difference.cache = d_cache;
63
64		if (d_cache.old_pixbuf == null || d_cache.new_pixbuf == null ||
65		    d_cache.old_pixbuf.get_width() != d_cache.new_pixbuf.get_width() ||
66		    d_cache.old_pixbuf.get_height() != d_cache.new_pixbuf.get_height())
67		{
68			d_stack_switcher.sensitive = false;
69		}
70
71		d_scale_slider_adjustment.bind_property("value", d_diff_image_slider, "position", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
72		d_scale_overlay_adjustment.bind_property("value", d_diff_image_overlay, "alpha", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
73	}
74
75	private Gdk.Pixbuf? pixbuf_for_file(Ggit.DiffFile file)
76	{
77		if ((file.get_flags() & Ggit.DiffFlag.VALID_ID) == 0 || file.get_oid().is_zero())
78		{
79			return null;
80		}
81
82		Ggit.Blob blob;
83
84		try
85		{
86			blob = repository.lookup<Ggit.Blob>(file.get_oid());
87		}
88		catch (Error e)
89		{
90			stderr.printf(@"ERROR: failed to load image blob: $(e.message)\n");
91			return null;
92		}
93
94		var stream = new MemoryInputStream.from_data(blob.get_raw_content(), null);
95
96		try
97		{
98			return new Gdk.Pixbuf.from_stream(stream);
99		}
100		catch (Error e)
101		{
102			stderr.printf(@"ERROR: failed to create pixbuf: $(e.message)\n");
103			return null;
104		}
105	}
106
107	public void add_hunk(Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines)
108	{
109	}
110
111	private class SurfaceCache : Object, Gitg.DiffImageSurfaceCache {
112		private Cairo.Surface? d_old_surface;
113		private Cairo.Surface? d_new_surface;
114
115		public Gdk.Pixbuf? old_pixbuf { get; construct set; }
116		public Gdk.Pixbuf? new_pixbuf { get; construct set; }
117
118		public Gdk.Window window { get; construct set; }
119
120		public SurfaceCache(Gdk.Pixbuf? old_pixbuf, Gdk.Pixbuf? new_pixbuf)
121		{
122			Object(old_pixbuf: old_pixbuf, new_pixbuf: new_pixbuf);
123		}
124
125		public Cairo.Surface? get_old_surface(Gdk.Window window)
126		{
127			return get_cached_surface(window, old_pixbuf, ref d_old_surface);
128		}
129
130		public Cairo.Surface? get_new_surface(Gdk.Window window)
131		{
132			return get_cached_surface(window, new_pixbuf, ref d_new_surface);
133		}
134
135		private Cairo.Surface? get_cached_surface(Gdk.Window window, Gdk.Pixbuf? pixbuf, ref Cairo.Surface? cached)
136		{
137			if (pixbuf == null)
138			{
139				return null;
140			}
141
142			if (cached == null)
143			{
144				cached = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, window);
145			}
146
147			return cached;
148		}
149	}
150}
151
152// ex:ts=4 noet
153