mirror of
https://gitlab.gnome.org/GNOME/gitg
synced 2024-11-04 21:16:52 +00:00
Add diff renderer for images
This commit is contained in:
parent
93476469aa
commit
b2ed43d22d
13 changed files with 990 additions and 6 deletions
|
@ -67,6 +67,12 @@ libgitg_libgitg_1_0_la_VALASOURCES = \
|
|||
libgitg/gitg-credentials-manager.vala \
|
||||
libgitg/gitg-date.vala \
|
||||
libgitg/gitg-diff-stat.vala \
|
||||
libgitg/gitg-diff-image-composite.vala \
|
||||
libgitg/gitg-diff-image-difference.vala \
|
||||
libgitg/gitg-diff-image-overlay.vala \
|
||||
libgitg/gitg-diff-image-side-by-side.vala \
|
||||
libgitg/gitg-diff-image-slider.vala \
|
||||
libgitg/gitg-diff-image-surface-cache.vala \
|
||||
libgitg/gitg-diff-view.vala \
|
||||
libgitg/gitg-diff-view-file.vala \
|
||||
libgitg/gitg-diff-view-file-info.vala \
|
||||
|
@ -74,6 +80,7 @@ libgitg_libgitg_1_0_la_VALASOURCES = \
|
|||
libgitg/gitg-diff-view-file-renderer.vala \
|
||||
libgitg/gitg-diff-view-file-renderer-binary.vala \
|
||||
libgitg/gitg-diff-view-file-renderer-text.vala \
|
||||
libgitg/gitg-diff-view-file-renderer-image.vala \
|
||||
libgitg/gitg-diff-view-lines-renderer.vala \
|
||||
libgitg/gitg-diff-selectable.vala \
|
||||
libgitg/gitg-diff-view-commit-details.vala \
|
||||
|
|
91
libgitg/gitg-diff-image-composite.vala
Normal file
91
libgitg/gitg-diff-image-composite.vala
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2016 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Gitg.DiffImageComposite : Gtk.DrawingArea
|
||||
{
|
||||
public Gitg.DiffImageSurfaceCache cache { get; set; }
|
||||
|
||||
private void get_natural_size(out int image_width, out int image_height)
|
||||
{
|
||||
var pixbuf = cache.old_pixbuf;
|
||||
var window = get_window();
|
||||
|
||||
double xscale = 1, yscale = 1;
|
||||
|
||||
if (window != null)
|
||||
{
|
||||
cache.get_old_surface(get_window()).get_device_scale(out xscale, out yscale);
|
||||
}
|
||||
|
||||
image_width = (int)(pixbuf.get_width() / xscale);
|
||||
image_height = (int)(pixbuf.get_height() / yscale);
|
||||
}
|
||||
|
||||
protected void get_sizing(int width, out int image_width, out int image_height)
|
||||
{
|
||||
get_natural_size(out image_width, out image_height);
|
||||
|
||||
// Scale down to fit in width
|
||||
if (image_width > width)
|
||||
{
|
||||
image_height *= width / image_width;
|
||||
image_width = width;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void get_preferred_width(out int minimum_width, out int natural_width)
|
||||
{
|
||||
int natural_height;
|
||||
|
||||
get_natural_size(out natural_width, out natural_height);
|
||||
minimum_width = 1;
|
||||
}
|
||||
|
||||
protected override void get_preferred_height_for_width(int width, out int minimum_height, out int natural_height)
|
||||
{
|
||||
int image_width, image_height;
|
||||
|
||||
get_sizing(width, out image_width, out image_height);
|
||||
|
||||
minimum_height = image_height;
|
||||
natural_height = image_height;
|
||||
}
|
||||
|
||||
protected override Gtk.SizeRequestMode get_request_mode()
|
||||
{
|
||||
return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH;
|
||||
}
|
||||
|
||||
protected override bool draw(Cairo.Context cr)
|
||||
{
|
||||
Gtk.Allocation alloc;
|
||||
get_allocation(out alloc);
|
||||
|
||||
var ctx = get_style_context();
|
||||
|
||||
ctx.render_background(cr, alloc.x, alloc.y, alloc.width, alloc.height);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void realize()
|
||||
{
|
||||
base.realize();
|
||||
queue_resize();
|
||||
}
|
||||
}
|
65
libgitg/gitg-diff-image-difference.vala
Normal file
65
libgitg/gitg-diff-image-difference.vala
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2016 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Gitg.DiffImageDifference : DiffImageComposite
|
||||
{
|
||||
protected override bool draw(Cairo.Context cr)
|
||||
{
|
||||
base.draw(cr);
|
||||
|
||||
var window = get_window();
|
||||
|
||||
Gtk.Allocation alloc;
|
||||
get_allocation(out alloc);
|
||||
|
||||
int image_width, image_height;
|
||||
get_sizing(alloc.width, out image_width, out image_height);
|
||||
|
||||
var old_surface = cache.get_old_surface(window);
|
||||
var new_surface = cache.get_new_surface(window);
|
||||
|
||||
int x = (alloc.width - image_width) / 2;
|
||||
int y = 0;
|
||||
|
||||
if (old_surface != null)
|
||||
{
|
||||
cr.set_source_surface(old_surface, x, y);
|
||||
cr.paint();
|
||||
}
|
||||
|
||||
if (new_surface != null)
|
||||
{
|
||||
cr.save();
|
||||
{
|
||||
cr.set_operator(Cairo.Operator.DIFFERENCE);
|
||||
cr.set_source_surface(new_surface, x, y);
|
||||
cr.paint();
|
||||
}
|
||||
cr.restore();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void realize()
|
||||
{
|
||||
base.realize();
|
||||
queue_resize();
|
||||
}
|
||||
}
|
80
libgitg/gitg-diff-image-overlay.vala
Normal file
80
libgitg/gitg-diff-image-overlay.vala
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2016 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Gitg.DiffImageOverlay : DiffImageComposite
|
||||
{
|
||||
private double d_alpha;
|
||||
|
||||
public double alpha
|
||||
{
|
||||
get { return d_alpha; }
|
||||
|
||||
set
|
||||
{
|
||||
var newalpha = double.max(0, double.min(value, 1));
|
||||
|
||||
if (newalpha != d_alpha)
|
||||
{
|
||||
d_alpha = newalpha;
|
||||
queue_draw();
|
||||
}
|
||||
}
|
||||
|
||||
default = 0.5;
|
||||
}
|
||||
|
||||
protected override bool draw(Cairo.Context cr)
|
||||
{
|
||||
base.draw(cr);
|
||||
|
||||
var window = get_window();
|
||||
|
||||
Gtk.Allocation alloc;
|
||||
get_allocation(out alloc);
|
||||
|
||||
int image_width, image_height;
|
||||
get_sizing(alloc.width, out image_width, out image_height);
|
||||
|
||||
var old_surface = cache.get_old_surface(window);
|
||||
var new_surface = cache.get_new_surface(window);
|
||||
|
||||
int x = (alloc.width - image_width) / 2;
|
||||
int y = 0;
|
||||
|
||||
if (old_surface != null && d_alpha != 1)
|
||||
{
|
||||
cr.set_source_surface(old_surface, x, y);
|
||||
cr.paint_with_alpha(1 - d_alpha);
|
||||
}
|
||||
|
||||
if (new_surface != null && d_alpha != 0)
|
||||
{
|
||||
cr.set_source_surface(new_surface, x, y);
|
||||
cr.paint_with_alpha(d_alpha);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void realize()
|
||||
{
|
||||
base.realize();
|
||||
queue_resize();
|
||||
}
|
||||
}
|
290
libgitg/gitg-diff-image-side-by-side.vala
Normal file
290
libgitg/gitg-diff-image-side-by-side.vala
Normal file
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2016 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Gitg.DiffImageSideBySide : Gtk.DrawingArea
|
||||
{
|
||||
private Pango.Layout d_old_size_layout;
|
||||
private Pango.Layout d_new_size_layout;
|
||||
|
||||
private static const int TEXT_SPACING = 6;
|
||||
|
||||
private Pango.Layout? old_size_layout
|
||||
{
|
||||
get
|
||||
{
|
||||
if (d_old_size_layout == null && cache.old_pixbuf != null)
|
||||
{
|
||||
string message;
|
||||
|
||||
if (cache.new_pixbuf != null)
|
||||
{
|
||||
// Translators: this label is displayed below the image diff, %s
|
||||
// is substituted with the size of the image
|
||||
message = _("before (%s)");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Translators: this label is displayed below the image diff, %s
|
||||
// is substituted with the size of the image
|
||||
message = _("removed (%s)");
|
||||
}
|
||||
|
||||
d_old_size_layout = create_pango_layout(message.printf(@"$(cache.old_pixbuf.get_width()) × $(cache.old_pixbuf.get_height())"));
|
||||
}
|
||||
|
||||
return d_old_size_layout;
|
||||
}
|
||||
}
|
||||
|
||||
private Pango.Layout? new_size_layout
|
||||
{
|
||||
get
|
||||
{
|
||||
if (d_new_size_layout == null && cache.new_pixbuf != null)
|
||||
{
|
||||
string message;
|
||||
|
||||
if (cache.old_pixbuf != null)
|
||||
{
|
||||
// Translators: this label is displayed below the image diff, %s
|
||||
// is substituted with the size of the image
|
||||
message = _("after (%s)");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Translators: this label is displayed below the image diff, %s
|
||||
// is substituted with the size of the image
|
||||
message = _("added (%s)");
|
||||
}
|
||||
|
||||
d_new_size_layout = create_pango_layout(message.printf(@"$(cache.new_pixbuf.get_width()) × $(cache.new_pixbuf.get_height())"));
|
||||
}
|
||||
|
||||
return d_new_size_layout;
|
||||
}
|
||||
}
|
||||
|
||||
public Gitg.DiffImageSurfaceCache cache { get; set; }
|
||||
public int spacing { get; set; }
|
||||
|
||||
private struct Size
|
||||
{
|
||||
public int width;
|
||||
|
||||
public int image_width;
|
||||
public int image_height;
|
||||
}
|
||||
|
||||
private struct Sizing
|
||||
{
|
||||
public Size old_size;
|
||||
public Size new_size;
|
||||
}
|
||||
|
||||
private Sizing get_sizing(int width)
|
||||
{
|
||||
double ow = 0, oh = 0, nw = 0, nh = 0;
|
||||
|
||||
var old_pixbuf = cache.old_pixbuf;
|
||||
var new_pixbuf = cache.new_pixbuf;
|
||||
|
||||
var window = get_window();
|
||||
|
||||
if (old_pixbuf != null)
|
||||
{
|
||||
double xscale = 1, yscale = 1;
|
||||
|
||||
if (window != null)
|
||||
{
|
||||
cache.get_old_surface(get_window()).get_device_scale(out xscale, out yscale);
|
||||
}
|
||||
|
||||
ow = (double)old_pixbuf.get_width() / xscale;
|
||||
oh = (double)old_pixbuf.get_height() / yscale;
|
||||
}
|
||||
|
||||
if (new_pixbuf != null)
|
||||
{
|
||||
double xscale = 1, yscale = 1;
|
||||
|
||||
if (window != null)
|
||||
{
|
||||
cache.get_new_surface(get_window()).get_device_scale(out xscale, out yscale);
|
||||
}
|
||||
|
||||
nw = (double)new_pixbuf.get_width() / xscale;
|
||||
nh = (double)new_pixbuf.get_height() / yscale;
|
||||
}
|
||||
|
||||
var tw = ow + nw;
|
||||
|
||||
width -= spacing;
|
||||
|
||||
double osw = 0, nsw = 0;
|
||||
|
||||
if (tw != 0)
|
||||
{
|
||||
if (ow != 0)
|
||||
{
|
||||
osw = width * (ow / tw);
|
||||
}
|
||||
|
||||
if (nw != 0)
|
||||
{
|
||||
nsw = width * (nw / tw);
|
||||
}
|
||||
}
|
||||
|
||||
var oswi = double.min(osw, ow);
|
||||
var nswi = double.min(nsw, nw);
|
||||
|
||||
double oshi = 0, nshi = 0;
|
||||
|
||||
if (ow != 0)
|
||||
{
|
||||
oshi = oswi / ow * oh;
|
||||
}
|
||||
|
||||
if (nw != 0)
|
||||
{
|
||||
nshi = nswi / nw * nh;
|
||||
}
|
||||
|
||||
return Sizing() {
|
||||
old_size = Size() {
|
||||
width = (int)osw,
|
||||
|
||||
image_width = (int)oswi,
|
||||
image_height = (int)oshi
|
||||
},
|
||||
|
||||
new_size = Size() {
|
||||
width = (int)nsw,
|
||||
|
||||
image_width = (int)nswi,
|
||||
image_height = (int)nshi
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void style_updated()
|
||||
{
|
||||
d_old_size_layout = null;
|
||||
d_new_size_layout = null;
|
||||
}
|
||||
|
||||
protected override void get_preferred_height_for_width(int width, out int minimum_height, out int natural_height)
|
||||
{
|
||||
var sizing = get_sizing(width);
|
||||
var h = double.max(sizing.old_size.image_height, sizing.new_size.image_height);
|
||||
|
||||
var ol = old_size_layout;
|
||||
var nl = new_size_layout;
|
||||
|
||||
int osw = 0, osh = 0, nsw = 0, nsh = 0;
|
||||
|
||||
if (ol != null)
|
||||
{
|
||||
ol.get_pixel_size(out osw, out osh);
|
||||
}
|
||||
|
||||
if (nl != null)
|
||||
{
|
||||
nl.get_pixel_size(out nsw, out nsh);
|
||||
}
|
||||
|
||||
h += TEXT_SPACING + int.max(osh, nsh);
|
||||
|
||||
minimum_height = (int)h;
|
||||
natural_height = (int)h;
|
||||
}
|
||||
|
||||
protected override Gtk.SizeRequestMode get_request_mode()
|
||||
{
|
||||
return Gtk.SizeRequestMode.HEIGHT_FOR_WIDTH;
|
||||
}
|
||||
|
||||
protected override bool draw(Cairo.Context cr)
|
||||
{
|
||||
var window = get_window();
|
||||
|
||||
Gtk.Allocation alloc;
|
||||
get_allocation(out alloc);
|
||||
|
||||
var sizing = get_sizing(alloc.width);
|
||||
|
||||
var old_surface = cache.get_old_surface(window);
|
||||
var new_surface = cache.get_new_surface(window);
|
||||
|
||||
var ctx = get_style_context();
|
||||
|
||||
ctx.render_background(cr, alloc.x, alloc.y, alloc.width, alloc.height);
|
||||
|
||||
double max_height = double.max(sizing.old_size.image_height, sizing.new_size.image_height);
|
||||
|
||||
if (old_surface != null)
|
||||
{
|
||||
var x = (sizing.old_size.width - sizing.old_size.image_width) * 2 / 3;
|
||||
var y = (max_height - sizing.old_size.image_height) / 2;
|
||||
|
||||
cr.set_source_surface(old_surface, x, y);
|
||||
cr.paint();
|
||||
|
||||
Pango.Rectangle rect;
|
||||
|
||||
old_size_layout.get_pixel_extents(null, out rect);
|
||||
|
||||
ctx.render_layout(cr,
|
||||
x + rect.x + (sizing.old_size.image_width - rect.width) / 2,
|
||||
rect.y + max_height + TEXT_SPACING,
|
||||
old_size_layout);
|
||||
}
|
||||
|
||||
if (new_surface != null)
|
||||
{
|
||||
var x = (sizing.new_size.width - sizing.new_size.image_width) * 1 / 3;
|
||||
var y = (max_height - sizing.new_size.image_height) / 2;
|
||||
|
||||
if (cache.old_pixbuf != null)
|
||||
{
|
||||
x += sizing.old_size.width + spacing;
|
||||
}
|
||||
|
||||
cr.set_source_surface(new_surface, x, y);
|
||||
cr.paint();
|
||||
|
||||
Pango.Rectangle rect;
|
||||
|
||||
new_size_layout.get_pixel_extents(null, out rect);
|
||||
|
||||
ctx.render_layout(cr,
|
||||
x + rect.x + (sizing.new_size.image_width - rect.width) / 2,
|
||||
rect.y + max_height + TEXT_SPACING,
|
||||
new_size_layout);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void realize()
|
||||
{
|
||||
base.realize();
|
||||
queue_resize();
|
||||
}
|
||||
}
|
94
libgitg/gitg-diff-image-slider.vala
Normal file
94
libgitg/gitg-diff-image-slider.vala
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2016 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
class Gitg.DiffImageSlider : DiffImageComposite
|
||||
{
|
||||
private double d_position;
|
||||
|
||||
public double position
|
||||
{
|
||||
get { return d_position; }
|
||||
|
||||
set
|
||||
{
|
||||
var newpos = double.max(0, double.min(value, 1));
|
||||
|
||||
if (newpos != d_position)
|
||||
{
|
||||
d_position = newpos;
|
||||
queue_draw();
|
||||
}
|
||||
}
|
||||
|
||||
default = 0.5;
|
||||
}
|
||||
|
||||
protected override bool draw(Cairo.Context cr)
|
||||
{
|
||||
base.draw(cr);
|
||||
|
||||
var window = get_window();
|
||||
|
||||
Gtk.Allocation alloc;
|
||||
get_allocation(out alloc);
|
||||
|
||||
int image_width, image_height;
|
||||
get_sizing(alloc.width, out image_width, out image_height);
|
||||
|
||||
var old_surface = cache.get_old_surface(window);
|
||||
var new_surface = cache.get_new_surface(window);
|
||||
|
||||
int x = (alloc.width - image_width) / 2;
|
||||
int y = 0;
|
||||
|
||||
int pos = (int)(image_width * position);
|
||||
|
||||
if (old_surface != null)
|
||||
{
|
||||
cr.save();
|
||||
{
|
||||
cr.rectangle(x, y, pos, image_height);
|
||||
cr.clip();
|
||||
cr.set_source_surface(old_surface, x, y);
|
||||
cr.paint();
|
||||
}
|
||||
cr.restore();
|
||||
}
|
||||
|
||||
if (new_surface != null)
|
||||
{
|
||||
cr.save();
|
||||
{
|
||||
cr.rectangle(x + pos, y, image_width - pos, image_height);
|
||||
cr.clip();
|
||||
cr.set_source_surface(new_surface, x, y);
|
||||
cr.paint();
|
||||
}
|
||||
cr.restore();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void realize()
|
||||
{
|
||||
base.realize();
|
||||
queue_resize();
|
||||
}
|
||||
}
|
29
libgitg/gitg-diff-image-surface-cache.vala
Normal file
29
libgitg/gitg-diff-image-surface-cache.vala
Normal file
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2016 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
interface Gitg.DiffImageSurfaceCache : Object
|
||||
{
|
||||
public abstract Gdk.Pixbuf? old_pixbuf { get; construct set; }
|
||||
public abstract Gdk.Pixbuf? new_pixbuf { get; construct set; }
|
||||
|
||||
public abstract Gdk.Window window { get; construct set; }
|
||||
|
||||
public abstract Cairo.Surface? get_old_surface(Gdk.Window window);
|
||||
public abstract Cairo.Surface? get_new_surface(Gdk.Window window);
|
||||
}
|
152
libgitg/gitg-diff-view-file-renderer-image.vala
Normal file
152
libgitg/gitg-diff-view-file-renderer-image.vala
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* This file is part of gitg
|
||||
*
|
||||
* Copyright (C) 2016 - Jesse van den Kieboom
|
||||
*
|
||||
* gitg is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* gitg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-diff-view-file-renderer-image.ui")]
|
||||
class Gitg.DiffViewFileRendererImage : Gtk.Grid, DiffViewFileRenderer
|
||||
{
|
||||
public Ggit.DiffDelta? delta { get; construct set; }
|
||||
public Repository repository { get; construct set; }
|
||||
|
||||
[GtkChild( name = "diff_image_side_by_side" )]
|
||||
private Gitg.DiffImageSideBySide d_diff_image_side_by_side;
|
||||
|
||||
[GtkChild( name = "diff_image_slider" )]
|
||||
private Gitg.DiffImageSlider d_diff_image_slider;
|
||||
|
||||
[GtkChild( name = "scale_slider_adjustment" )]
|
||||
private Gtk.Adjustment d_scale_slider_adjustment;
|
||||
|
||||
[GtkChild( name = "diff_image_overlay" )]
|
||||
private Gitg.DiffImageOverlay d_diff_image_overlay;
|
||||
|
||||
[GtkChild( name = "scale_overlay_adjustment" )]
|
||||
private Gtk.Adjustment d_scale_overlay_adjustment;
|
||||
|
||||
[GtkChild( name = "diff_image_difference" )]
|
||||
private Gitg.DiffImageDifference d_diff_image_difference;
|
||||
|
||||
[GtkChild( name = "stack_switcher" )]
|
||||
private Gtk.StackSwitcher d_stack_switcher;
|
||||
|
||||
private SurfaceCache d_cache;
|
||||
|
||||
public DiffViewFileRendererImage(Repository repository, Ggit.DiffDelta delta)
|
||||
{
|
||||
Object(repository: repository, delta: delta);
|
||||
}
|
||||
|
||||
construct
|
||||
{
|
||||
d_cache = new SurfaceCache(pixbuf_for_file(delta.get_old_file()),
|
||||
pixbuf_for_file(delta.get_new_file()));
|
||||
|
||||
d_diff_image_side_by_side.cache = d_cache;
|
||||
d_diff_image_slider.cache = d_cache;
|
||||
d_diff_image_overlay.cache = d_cache;
|
||||
d_diff_image_difference.cache = d_cache;
|
||||
|
||||
if (d_cache.old_pixbuf == null || d_cache.new_pixbuf == null ||
|
||||
d_cache.old_pixbuf.get_width() != d_cache.new_pixbuf.get_width() ||
|
||||
d_cache.old_pixbuf.get_height() != d_cache.new_pixbuf.get_height())
|
||||
{
|
||||
d_stack_switcher.sensitive = false;
|
||||
}
|
||||
|
||||
d_scale_slider_adjustment.bind_property("value", d_diff_image_slider, "position", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
|
||||
d_scale_overlay_adjustment.bind_property("value", d_diff_image_overlay, "alpha", BindingFlags.DEFAULT | BindingFlags.SYNC_CREATE);
|
||||
}
|
||||
|
||||
private Gdk.Pixbuf? pixbuf_for_file(Ggit.DiffFile file)
|
||||
{
|
||||
if ((file.get_flags() & Ggit.DiffFlag.VALID_ID) == 0 || file.get_oid().is_zero())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Ggit.Blob blob;
|
||||
|
||||
try
|
||||
{
|
||||
blob = repository.lookup<Ggit.Blob>(file.get_oid());
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
stderr.printf(@"ERROR: failed to load image blob: $(e.message)\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
var stream = new MemoryInputStream.from_data(blob.get_raw_content(), null);
|
||||
|
||||
try
|
||||
{
|
||||
return new Gdk.Pixbuf.from_stream(stream);
|
||||
}
|
||||
catch (Error e)
|
||||
{
|
||||
stderr.printf(@"ERROR: failed to create pixbuf: $(e.message)\n");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void add_hunk(Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines)
|
||||
{
|
||||
}
|
||||
|
||||
private class SurfaceCache : Object, Gitg.DiffImageSurfaceCache {
|
||||
private Cairo.Surface? d_old_surface;
|
||||
private Cairo.Surface? d_new_surface;
|
||||
|
||||
public Gdk.Pixbuf? old_pixbuf { get; construct set; }
|
||||
public Gdk.Pixbuf? new_pixbuf { get; construct set; }
|
||||
|
||||
public Gdk.Window window { get; construct set; }
|
||||
|
||||
public SurfaceCache(Gdk.Pixbuf? old_pixbuf, Gdk.Pixbuf? new_pixbuf)
|
||||
{
|
||||
Object(old_pixbuf: old_pixbuf, new_pixbuf: new_pixbuf);
|
||||
}
|
||||
|
||||
public Cairo.Surface? get_old_surface(Gdk.Window window)
|
||||
{
|
||||
return get_cached_surface(window, old_pixbuf, ref d_old_surface);
|
||||
}
|
||||
|
||||
public Cairo.Surface? get_new_surface(Gdk.Window window)
|
||||
{
|
||||
return get_cached_surface(window, new_pixbuf, ref d_new_surface);
|
||||
}
|
||||
|
||||
private Cairo.Surface? get_cached_surface(Gdk.Window window, Gdk.Pixbuf? pixbuf, ref Cairo.Surface? cached)
|
||||
{
|
||||
if (pixbuf == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cached == null)
|
||||
{
|
||||
cached = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, window);
|
||||
}
|
||||
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ex:ts=4 noet
|
|
@ -128,6 +128,11 @@ class Gitg.DiffViewFile : Gtk.Grid
|
|||
public DiffViewFile.image(Repository? repository, Ggit.DiffDelta delta)
|
||||
{
|
||||
this(repository, delta);
|
||||
|
||||
this.renderer = new DiffViewFileRendererImage(repository, delta);
|
||||
this.renderer.show();
|
||||
|
||||
d_diff_stat_file.hide();
|
||||
}
|
||||
|
||||
protected override void constructed()
|
||||
|
|
|
@ -52,6 +52,8 @@ public class Gitg.DiffView : Gtk.Grid
|
|||
private uint d_reveal_options_timeout;
|
||||
private uint d_unreveal_options_timeout;
|
||||
|
||||
private static Gee.HashSet<string> s_image_mime_types;
|
||||
|
||||
public Ggit.DiffOptions options
|
||||
{
|
||||
get
|
||||
|
@ -224,6 +226,16 @@ public class Gitg.DiffView : Gtk.Grid
|
|||
|
||||
static construct
|
||||
{
|
||||
s_image_mime_types = new Gee.HashSet<string>();
|
||||
|
||||
foreach (var format in Gdk.Pixbuf.get_formats())
|
||||
{
|
||||
foreach (var mime_type in format.get_mime_types())
|
||||
{
|
||||
s_image_mime_types.add(mime_type);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
s_message_regexp = new Regex(".*[\\R\\s]*(?P<message>(?:.|\\R)*?)\\s*$");
|
||||
|
@ -336,13 +348,13 @@ public class Gitg.DiffView : Gtk.Grid
|
|||
}
|
||||
}
|
||||
|
||||
private string? primary_path(Gitg.DiffViewFile f)
|
||||
private string? primary_path(Ggit.DiffDelta delta)
|
||||
{
|
||||
var path = f.delta.get_old_file().get_path();
|
||||
var path = delta.get_old_file().get_path();
|
||||
|
||||
if (path == null)
|
||||
{
|
||||
path = f.delta.get_new_file().get_path();
|
||||
path = delta.get_new_file().get_path();
|
||||
}
|
||||
|
||||
return path;
|
||||
|
@ -479,7 +491,34 @@ public class Gitg.DiffView : Gtk.Grid
|
|||
current_is_binary = true;
|
||||
}
|
||||
|
||||
if (current_is_binary)
|
||||
string? mime_type_for_image = null;
|
||||
|
||||
if (info == null || info.new_file_content_type == null)
|
||||
{
|
||||
// Guess mime type from old file name in the case of a deleted file
|
||||
var oldpath = delta.get_old_file().get_path();
|
||||
|
||||
if (oldpath != null)
|
||||
{
|
||||
bool uncertain;
|
||||
var ctype = ContentType.guess(Path.get_basename(oldpath), null, out uncertain);
|
||||
|
||||
if (ctype != null)
|
||||
{
|
||||
mime_type_for_image = ContentType.get_mime_type(ctype);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mime_type_for_image = ContentType.get_mime_type(info.new_file_content_type);
|
||||
}
|
||||
|
||||
if (mime_type_for_image != null && s_image_mime_types.contains(mime_type_for_image))
|
||||
{
|
||||
current_file = new Gitg.DiffViewFile.image(repository, delta);
|
||||
}
|
||||
else if (current_is_binary)
|
||||
{
|
||||
current_file = new Gitg.DiffViewFile.binary(repository, delta);
|
||||
}
|
||||
|
@ -550,7 +589,7 @@ public class Gitg.DiffView : Gtk.Grid
|
|||
|
||||
if (preserve_expanded && f.expanded)
|
||||
{
|
||||
var path = primary_path(f);
|
||||
var path = primary_path(f.delta);
|
||||
|
||||
if (path != null)
|
||||
{
|
||||
|
@ -567,7 +606,7 @@ public class Gitg.DiffView : Gtk.Grid
|
|||
for (var i = 0; i < files.size; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
var path = primary_path(file);
|
||||
var path = primary_path(file.delta);
|
||||
|
||||
file.expanded = d_commit_details.expanded || (path != null && was_expanded.contains(path));
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-authentication-dialog.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-image.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-text.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-file-renderer-binary.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks">ui/gitg-diff-view-options.ui</file>
|
||||
|
|
123
libgitg/resources/ui/gitg-diff-view-file-renderer-image.ui
Normal file
123
libgitg/resources/ui/gitg-diff-view-file-renderer-image.ui
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<template class="GitgDiffViewFileRendererImage" parent="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkStackSwitcher" id="stack_switcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="stack">stack</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">center</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid_side_by_side">
|
||||
<property name="visible">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="margin">12</property>
|
||||
<child>
|
||||
<object class="GitgDiffImageSideBySide" id="diff_image_side_by_side">
|
||||
<property name="visible">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">side-by-side</property>
|
||||
<property name="title" translatable="yes">Side by side</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid_slider">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="scale_slider">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="draw_value">False</property>
|
||||
<property name="adjustment">scale_slider_adjustment</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GitgDiffImageSlider" id="diff_image_slider">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">slider</property>
|
||||
<property name="title" translatable="yes">Slider</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid_overlay">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkScale" id="scale_overlay">
|
||||
<property name="visible">True</property>
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="draw_value">False</property>
|
||||
<property name="adjustment">scale_overlay_adjustment</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GitgDiffImageOverlay" id="diff_image_overlay">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">overlay</property>
|
||||
<property name="title" translatable="yes">Overlay</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid" id="grid_difference">
|
||||
<property name="visible">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GitgDiffImageDifference" id="diff_image_difference">
|
||||
<property name="visible">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">difference</property>
|
||||
<property name="title" translatable="yes">Difference</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<object class="GtkAdjustment" id="scale_slider_adjustment">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="value">0.5</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="scale_overlay_adjustment">
|
||||
<property name="lower">0</property>
|
||||
<property name="upper">1</property>
|
||||
<property name="value">0.5</property>
|
||||
</object>
|
||||
</interface>
|
|
@ -117,3 +117,11 @@ GitgDiffViewOptions {
|
|||
.dark .language-frame {
|
||||
background-color: #535353;
|
||||
}
|
||||
|
||||
GitgDiffImageSideBySide.old {
|
||||
border: 10px solid #ddddff;
|
||||
}
|
||||
|
||||
GitgDiffImageSideBySide.new {
|
||||
border: 10px solid #ddffdd;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue