2
Copyright (c) 2016 elementary LLC (http://launchpad.net/elementary)
4
Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
5
Copyright (c) 2011 ammonkey <am.monkeyd@gmail.com>
7
Transcribed from marlin-icon-renderer
8
Originaly Written in gtk+: gtkcellrendererpixbuf
10
Pantheon Files is free software; you can redistribute it and/or
11
modify it under the terms of the GNU General Public License as
12
published by the Free Software Foundation; either version 2 of the
13
License, or (at your option) any later version.
15
Pantheon Files is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
General Public License for more details.
20
You should have received a copy of the GNU General Public
21
License along with this program; see the file COPYING. If not,
22
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23
Boston, MA 02111-1307, USA.
25
Author(s): Jeremy Wootten <jeremy@elementaryos.org>
32
public class IconRenderer : Gtk.CellRenderer {
33
public Marlin.IconSize helper_size {get; private set; default = Marlin.IconSize.EMBLEM;}
34
public bool follow_state {get; set;}
35
public GOF.File drop_file {get; set;}
36
public bool selection_helpers {get; set; default = true;}
38
public Marlin.ZoomLevel zoom_level {
44
helper_size = _zoom_level > Marlin.ZoomLevel.LARGER ? Marlin.IconSize.LARGE_EMBLEM : Marlin.IconSize.EMBLEM;
45
emblem_overlap = helper_size / 4;
46
icon_size = Marlin.zoom_level_to_icon_size (_zoom_level);
47
show_emblems = _zoom_level > Marlin.ZoomLevel.SMALLEST;
51
public GOF.File? file {
58
_file.update_icon (icon_size);
62
private bool show_emblems = true;
63
private Marlin.ZoomLevel _zoom_level = Marlin.ZoomLevel.NORMAL;
64
private GOF.File? _file;
65
private Marlin.IconSize icon_size;
66
private int emblem_overlap = 0;
67
private unowned Gdk.Pixbuf? pixbuf {
69
return _file != null ? _file.pix : null;
73
private ClipboardManager clipboard;
75
public IconRenderer () {
76
clipboard = Marlin.ClipboardManager.get_for_display ();
79
public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle background_area,
80
Gdk.Rectangle cell_area, Gtk.CellRendererState flags) {
82
if (file == null || pixbuf == null) {
86
Gdk.Pixbuf? pb = pixbuf;
88
var pix_rect = Gdk.Rectangle ();
90
pix_rect.width = pixbuf.get_width ();
91
pix_rect.height = pixbuf.get_height ();
92
pix_rect.x = cell_area.x + (cell_area.width - pix_rect.width) / 2;
93
pix_rect.y = cell_area.y + (cell_area.height - pix_rect.height) / 2;
95
var draw_rect = Gdk.Rectangle ();
96
if (!cell_area.intersect (pix_rect, out draw_rect)) {
100
string? special_icon_name = null;
101
if (file == drop_file) {
102
flags |= Gtk.CellRendererState.PRELIT;
103
special_icon_name = "folder-drag-accept";
105
} else if (file.is_directory && file.is_expanded) {
106
special_icon_name = "folder-open";
109
if (special_icon_name != null) {
110
var nicon = Marlin.IconInfo.lookup_from_name (special_icon_name, icon_size);
112
pb = nicon.get_pixbuf_nodefault ();
116
if (clipboard.has_cutted_file (file)) {
117
/* 50% translucent for cutted files */
118
pb = Eel.gdk_pixbuf_lucent (pixbuf, 50);
120
if (file.is_hidden) {
121
/* 75% translucent for hidden files */
122
pb = Eel.gdk_pixbuf_lucent (pixbuf, 75);
123
pb = Eel.create_darkened_pixbuf (pb, 150, 200);
126
var style_context = widget.get_parent ().get_style_context ();
127
style_context.save ();
129
bool prelit = (flags & Gtk.CellRendererState.PRELIT) > 0;
130
bool selected = (flags & Gtk.CellRendererState.SELECTED) > 0;
131
var state = Gtk.StateFlags.NORMAL;
133
if (!widget.sensitive || !this.sensitive) {
134
state |= Gtk.StateFlags.INSENSITIVE;
135
} else if (follow_state) {
137
state = Gtk.StateFlags.SELECTED;
138
state |= widget.get_state_flags ();
139
var color = style_context.get_background_color (state);
140
pb = Eel.create_colorized_pixbuf (pb, color);
143
pb = Eel.create_spotlight_pixbuf (pb);
151
style_context.render_icon (cr, pb, draw_rect.x, draw_rect.y);
152
style_context.restore ();
154
/* Do not show selection helpers or emblems for very small icons */
155
if (selection_helpers && show_emblems &&
156
(selected || prelit) &&
159
special_icon_name = null;
160
if (selected && prelit) {
161
special_icon_name = "selection-remove";
162
} else if (selected) {
163
special_icon_name = "selection-checked";
165
special_icon_name = "selection-add";
168
if (special_icon_name != null) {
169
var nicon = Marlin.IconInfo.lookup_from_name (special_icon_name, helper_size);
170
Gdk.Pixbuf? pix = null;
172
pix = nicon.get_pixbuf_nodefault ();
176
var helper_area = Gdk.Rectangle ();
177
helper_area.x = draw_rect.x - helper_size / 2;
178
helper_area.y = draw_rect.y - helper_size / 2;
180
if (helper_area.y < background_area.y) {
181
helper_area.y = background_area.y;
184
if (helper_area.x < background_area.x) {
185
helper_area.x = background_area.x;
188
Gdk.cairo_set_source_pixbuf (cr, pix, helper_area.x, helper_area.y);
194
/* check if we should render emblems as well */
195
/* Still show emblems when selection helpers hidden in double click mode */
196
/* How many emblems can be shown depends on icon icon_size (zoom lebel) */
199
var emblem_area = Gdk.Rectangle ();
201
foreach (string emblem in file.emblems_list) {
202
if (pos > zoom_level) {
206
Gdk.Pixbuf? pix = null;
207
var nicon = Marlin.IconInfo.lookup_from_name (emblem, helper_size);
213
pix = nicon.get_pixbuf_nodefault ();
219
emblem_area.x = draw_rect.x + draw_rect.width - emblem_overlap;
220
emblem_area.y = draw_rect.y + draw_rect.height - helper_size;
221
emblem_area.y -= helper_size * pos;
223
if (emblem_area.y < background_area.y) {
227
if (emblem_area.x + helper_size > (background_area.x + background_area.width)) {
228
emblem_area.x = (background_area.x + background_area.width) - helper_size;
231
Gdk.cairo_set_source_pixbuf (cr, pix, emblem_area.x, emblem_area.y);
238
/* We still have to implement this even though it is deprecated */
239
public override void get_size (Gtk.Widget widget, Gdk.Rectangle? cell_area,
240
out int x_offset, out int y_offset,
241
out int width, out int height) {
248
if (pixbuf == null || !(pixbuf is Gdk.Pixbuf)) {
253
int pixbuf_width = pixbuf.get_width ();
254
int pixbuf_height = pixbuf.get_height ();
256
int calc_width = pixbuf_width;
257
int calc_height = pixbuf_height;
259
if (cell_area != null && pixbuf_width > 0 && pixbuf_height > 0) {
260
float xalign, yalign;
261
bool rtl = widget.get_direction () == Gtk.TextDirection.RTL;
262
get_alignment (out xalign, out yalign);
263
x_offset = (int)(rtl ? (1.0 -xalign) : xalign) * (cell_area.width - calc_width);
264
x_offset = int.max (x_offset, 0);
265
y_offset = (int)(yalign * (cell_area.height - calc_height));
266
y_offset = int.max (y_offset, 0);
272
/* Even if the last new pixbuf corresponding to the last requested icon_size isn't generated
273
yet, we can still determine its dimensions. This allow to asyncronously load the thumbnails
276
int s = int.max (pixbuf_width, pixbuf_height);
277
scale = double.min (1.0, (double)icon_size / s); /* scaling to make pix required icon_size (not taking into account screen scaling) */
279
width = (int)(calc_width * scale);
280
height = (int)(calc_height * scale);