Fix the label int he sidebar
[gmpc.git] / src / Widgets / gmpc-image-async.vala
blobd0ac3aa1310d3179aac3bfec8fb939e7f4818e28
1 /* Gnome Music Player Client (GMPC)
2 * Copyright (C) 2004-2012 Qball Cow <qball@gmpclient.org>
3 * Project homepage: http://gmpclient.org/
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 using GLib;
21 using Gtk;
22 using Gdk;
24 const string LOG_DOMAIN = "ImageAsync";
25 namespace Gmpc
27 /**
28 * Operations you can do on the image.
29 * The modified pixbuf will be stored in cache.
31 public enum ModificationType
33 NONE = 0, // Add nothing
34 CASING = 1, // Add border and or casing
35 DARKEN = 2, // Darken the image (for backdrop)
36 DECOLOR = 4, // Remove color from image.
37 BORDER = 8
39 public class PixbufLoaderAsync : GLib.Object
41 public string uri = null;
42 public Gdk.Pixbuf pixbuf {set; get; default=null;}
43 private Gtk.TreeRowReference rref = null;
44 private int width=0;
45 private int height=0;
47 public signal void pixbuf_update(Gdk.Pixbuf? pixbuf);
49 public void set_rref(Gtk.TreeRowReference rreference)
51 this.rref = rreference;
54 private void call_row_changed()
56 if(rref != null)
58 var model = rref.get_model();
59 var path = rref.get_path();
60 Gtk.TreeIter iter;
61 if(model.get_iter(out iter, path))
63 model.row_changed(path, iter);
68 construct
70 GLib.log(LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG,"Create the image loading\n" );
74 private Gdk.Pixbuf? modify_pixbuf(owned Gdk.Pixbuf? pix, int size,ModificationType casing)
76 if(pix == null) return null;
77 if((casing&ModificationType.CASING) == ModificationType.CASING)
79 if(config.get_int_with_default("metaimage", "addcase", 1) == 1)
81 int width = pix.width;
82 int height = pix.height;
83 double spineRatio = 5.0/65.0;
85 var ii = Gtk.IconTheme.get_default().lookup_icon("stylized-cover", size, 0);
86 if(ii != null)
88 var path = ii.get_filename();
89 try
91 var case_image = new Gdk.Pixbuf.from_file_at_scale(path, size, size, true);
93 var tempw = (int)(case_image.width*(1.0-spineRatio));
94 Gdk.Pixbuf pix2;
95 if((case_image.height/(double)height)*width < tempw)
97 pix2 = pix.scale_simple(tempw, (int)((height*tempw)/width), Gdk.InterpType.BILINEAR);
99 else
101 pix2 = pix.scale_simple((int)(width*(case_image.height/(double)height)), case_image.height, Gdk.InterpType.BILINEAR);
103 var blank = new Gdk.Pixbuf(Gdk.Colorspace.RGB, true, 8, case_image.width, case_image.height);
104 blank.fill(0x000000FF);
105 tempw = (tempw >= pix2.width)? pix2.width:tempw;
106 var temph = (case_image.height > pix2.height)?pix2.height:case_image.height;
107 pix2.copy_area(0,0, tempw-1, temph-2, blank, case_image.width-tempw, 1);
108 case_image.composite(blank, 0,0,case_image.width, case_image.height, 0,0,1,1,Gdk.InterpType.BILINEAR, 250);
109 pix = (owned)blank;
111 catch (Error e)
113 GLib.log(LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_WARNING,
114 "Failed to get the stylized-cover image");
119 else
121 Gmpc.Fix.add_border(pix);
124 if ((casing&ModificationType.DARKEN) == ModificationType.DARKEN)
126 Gmpc.Misc.darken_pixbuf(pix, 2);
128 if ((casing&ModificationType.DECOLOR) == ModificationType.DECOLOR)
130 Gmpc.Misc.decolor_pixbuf(pix, pix);
132 if ((casing&ModificationType.BORDER) == ModificationType.BORDER)
134 Gmpc.Misc.border_pixbuf(pix);
137 return pix;
141 private uint loader_timeout = 0;
142 private Gdk.PixbufLoader? loader = null;
143 private uchar[] loader_data = null;
144 private uint loader_data_offset = 0;
145 private uchar[] loader_md5sum = null;
146 private ModificationType loader_border = ModificationType.NONE;
148 ~PixbufLoaderAsync()
150 GLib.log(LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG,"Free the image loading");
151 // Cancel previous load.
152 if ( loader_timeout > 0)
154 GLib.Source.remove(loader_timeout);
156 loader_data = null;
157 loader_md5sum = null;
158 loader_timeout = 0;
161 loader.close();
163 catch (Error e)
165 // Ignore this.
167 loader = null;
173 public void set_from_raw(uchar[] data, int req_width, int req_height, ModificationType border, [CCode (array_length = false)]uchar[] md5sum)
175 width = req_width;
176 height = req_height;
178 // Cancel previous load.
179 if ( loader_timeout > 0)
181 GLib.Source.remove(loader_timeout);
183 loader_data = null;
184 loader_md5sum = null;
185 loader_timeout = 0;
188 loader.close();
190 catch (Error e)
192 // Ignore this.
194 loader = null;
198 var pb = Gmpc.PixbufCache.lookup_icon(int.max(width,height), md5sum);
199 if(pb != null)
201 this.pixbuf = pb;
202 pixbuf_update(pixbuf);
203 call_row_changed();
204 return;
207 loader = new Gdk.PixbufLoader();
208 loader.size_prepared.connect(size_prepare);
210 loader_data = data;
211 loader_data_offset = 0;
212 loader_md5sum = md5sum[0:16];
213 loader_border = border;
216 loader_timeout = GLib.Idle.add(loader_idle_callback);
217 // loader_timeout = GLib.Timeout.add(200, loader_idle_callback);
218 return;
221 private bool loader_idle_callback()
226 uint end = uint.min(loader_data_offset+2048, loader_data.length);
227 Gmpc.Fix.write_loader(loader, (string)loader_data[loader_data_offset:end], end-loader_data_offset);
228 loader_data_offset = end;;
230 catch ( Error e)
232 warning("Error trying to load image: %s::%s", e.message,uri);
234 if(loader_data_offset < loader_data.length) return true;
238 loader.close();
240 catch (Error err)
242 debug("Error trying to parse image: %s::%s? query cancelled?", err.message,uri);
243 pixbuf_update(null);
244 call_row_changed();
246 loader_data = null;
247 loader_md5sum = null;
248 loader = null;
249 loader_timeout = 0;
250 return false;
253 Gdk.Pixbuf pix = loader.get_pixbuf();
254 /* Maybe another thread allready fetched it in the mean time, we want to use that... */
255 var final = Gmpc.PixbufCache.lookup_icon(int.max(height, width), loader_md5sum);
256 if(final == null)
258 final = this.modify_pixbuf((owned)pix, int.max(height, width),loader_border);
259 Gmpc.PixbufCache.add_icon(int.max(height, width),loader_md5sum, final);
262 this.pixbuf = final;
263 pixbuf_update(pixbuf);
264 call_row_changed();
266 // Cleanup
267 loader = null;
268 loader_data = null;
269 loader_md5sum = null;
270 loader_timeout = 0;
271 return false;
274 private void size_prepare(Gdk.PixbufLoader loader,int gwidth, int gheight)
276 double dsize = (double)(int.max(width,height));
277 int nwidth = 0, nheight = 0;
278 if(height < 0)
280 double scale = width/(double)gwidth;
281 nwidth = width;
282 nheight = (int)(gheight*scale);
284 else if (width < 0)
286 double scale = height/(double)gheight;
287 nheight = height;
288 nwidth = (int)(gwidth*scale);
290 else
292 nwidth = (gheight >gwidth)? (int)((dsize/gheight)*gwidth): (int)dsize;
293 nheight= (gwidth > gheight )? (int)((dsize/gwidth)*gheight): (int)dsize;
295 loader.set_size(nwidth, nheight);
298 public class MetaImageAsync : Gtk.Image
300 private Gmpc.PixbufLoaderAsync? loader = null;
301 public string uri = null;
303 construct
307 ~MetaImageAsync()
309 GLib.log(LOG_DOMAIN,GLib.LogLevelFlags.LEVEL_DEBUG,"Freeing metaimageasync\n");
311 public new void set_from_raw(uchar[] data, int size, ModificationType border, [CCode (array_length = false)] uchar[] md5sum)
313 if(loader == null)
315 loader = new PixbufLoaderAsync();
316 loader.pixbuf_update.connect((source, pixbuf)=>
318 this.set_from_pixbuf(pixbuf);
321 loader.set_from_raw(data, size,size, border,md5sum);
324 public void clear_now()
326 this.loader = null;
327 this.uri = null;
328 this.clear();
331 public void set_pixbuf(Gdk.Pixbuf? pb)
333 this.loader = null;
334 this.uri = null;
335 if(pb != null)
337 this.set_from_pixbuf(pb);
339 else
341 this.clear();