diff options
Diffstat (limited to 'src/images')
-rw-r--r-- | src/images/icon.vala | 102 | ||||
-rw-r--r-- | src/images/image.vala | 163 | ||||
-rw-r--r-- | src/images/renderedText.vala | 110 | ||||
-rw-r--r-- | src/images/themedIcon.vala | 161 |
4 files changed, 536 insertions, 0 deletions
diff --git a/src/images/icon.vala b/src/images/icon.vala new file mode 100644 index 0000000..1c8a9f4 --- /dev/null +++ b/src/images/icon.vala @@ -0,0 +1,102 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +This program 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 3 of the License, or (at your option) +any later version. + +This program 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 +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class representing a square-shaped icon, loaded from the users +/// icon theme. +///////////////////////////////////////////////////////////////////////// + +public class Icon : Image { + + ///////////////////////////////////////////////////////////////////// + /// A cache which stores loaded icon. It is cleared when the icon + /// theme of the user changes. The key is in form <filename>@<size>. + ///////////////////////////////////////////////////////////////////// + + private static Gee.HashMap<string, Cairo.ImageSurface?> cache { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Initializes the cache. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + clear_cache(); + + Gtk.IconTheme.get_default().changed.connect(() => { + clear_cache(); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears the cache. + ///////////////////////////////////////////////////////////////////// + + public static void clear_cache() { + cache = new Gee.HashMap<string, Cairo.ImageSurface?>(); + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an icon from the current icon theme of the user. + ///////////////////////////////////////////////////////////////////// + + public Icon(string icon_name, int size) { + var cached = this.cache.get("%s@%u".printf(icon_name, size)); + + if (cached == null) { + this.load_file_at_size(this.get_icon_file(icon_name, size), size, size); + this.cache.set("%s@%u".printf(icon_name, size), this.surface); + } else { + this.surface = cached; + } + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the size of the icon in pixels. Greetings to Liskov. + ///////////////////////////////////////////////////////////////////// + + public int size() { + return base.width(); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the filename for a given system icon. + ///////////////////////////////////////////////////////////////////// + + public static string get_icon_file(string icon_name, int size) { + string result = ""; + + var icon_theme = Gtk.IconTheme.get_default(); + var file = icon_theme.lookup_icon(icon_name, size, 0); + if (file != null) result = file.get_filename(); + + if (result == "") { + warning("Icon \"" + icon_name + "\" not found! Using default icon..."); + icon_name = "application-default-icon"; + file = icon_theme.lookup_icon(icon_name, size, 0); + if (file != null) result = file.get_filename(); + } + + if (result == "") + warning("Icon \"" + icon_name + "\" not found! Will be ugly..."); + + return result; + } +} + +} diff --git a/src/images/image.vala b/src/images/image.vala new file mode 100644 index 0000000..836e4e2 --- /dev/null +++ b/src/images/image.vala @@ -0,0 +1,163 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +This program 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 3 of the License, or (at your option) +any later version. + +This program 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 +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class which loads image files. It can load image files in various +/// formats, including jpeg, png and svg. +///////////////////////////////////////////////////////////////////////// + +public class Image : GLib.Object { + + ///////////////////////////////////////////////////////////////////// + /// The internally used surface. + ///////////////////////////////////////////////////////////////////// + + public Cairo.ImageSurface surface { public get; protected set; default=null; } + + ///////////////////////////////////////////////////////////////////// + /// Creates an empty Image. + ///////////////////////////////////////////////////////////////////// + + public Image.empty(int width, int height, Color? color = null) { + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + + if (color != null) { + var ctx = this.context(); + ctx.set_source_rgb(color.r, color.g, color.b); + ctx.paint(); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Creates an image from the the given filename. + ///////////////////////////////////////////////////////////////////// + + public Image.from_file(string filename) { + this.load_file(filename); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates an image from the the given filename at a given size. + ///////////////////////////////////////////////////////////////////// + + public Image.from_file_at_size(string filename, int width, int height) { + this.load_file_at_size(filename, width, height); + } + + ///////////////////////////////////////////////////////////////////// + /// Creates an image from the the given Gdk.Pixbuf. + ///////////////////////////////////////////////////////////////////// + + public Image.from_pixbuf(Gdk.Pixbuf pixbuf) { + this.load_pixbuf(pixbuf); + } + + public Image.capture_screen(int posx, int posy, int width, int height) { + Gdk.Window root = Gdk.get_default_root_window(); + Gdk.Pixbuf pixbuf = Gdk.pixbuf_get_from_drawable(null, root, null, posx, posy, 0, 0, width, height); + + this.load_pixbuf(pixbuf); + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an image from the the given filename. + ///////////////////////////////////////////////////////////////////// + + public void load_file(string filename) { + try { + var pixbuf = new Gdk.Pixbuf.from_file(filename); + + if (pixbuf != null) { + this.load_pixbuf(pixbuf); + } else { + warning("Failed to load " + filename + "!"); + } + } catch (GLib.Error e) { + message("Error loading image file: %s", e.message); + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, 1, 1); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an image from the the given filename at a given size. + ///////////////////////////////////////////////////////////////////// + + public void load_file_at_size(string filename, int width, int height) { + try { + var pixbuf = new Gdk.Pixbuf.from_file_at_size(filename, width, height); + + if (pixbuf != null) { + this.load_pixbuf(pixbuf); + } else { + warning("Failed to load " + filename + "!"); + } + } catch (GLib.Error e) { + message("Error loading image file: %s", e.message); + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + } + } + + ///////////////////////////////////////////////////////////////////// + /// Loads an image from the the given Gdk.Pixbuf. + ///////////////////////////////////////////////////////////////////// + + public void load_pixbuf(Gdk.Pixbuf pixbuf) { + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, pixbuf.width, pixbuf.height); + + var ctx = this.context(); + Gdk.cairo_set_source_pixbuf(ctx, pixbuf, 1.0, 1.0); + ctx.paint(); + } + + ///////////////////////////////////////////////////////////////////// + /// Paints the image onto the given Cairo.Context + ///////////////////////////////////////////////////////////////////// + + public void paint_on(Cairo.Context ctx, double alpha = 1.0) { + ctx.set_source_surface(this.surface, -0.5*this.width()-1, -0.5*this.height()-1); + if (alpha >= 1.0) ctx.paint(); + else ctx.paint_with_alpha(alpha); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns a Cairo.Context for the Image. + ///////////////////////////////////////////////////////////////////// + + public Cairo.Context context() { + return new Cairo.Context(this.surface);; + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the width of the image in pixels. + ///////////////////////////////////////////////////////////////////// + + public int width() { + return this.surface.get_width(); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the height of the image in pixels. + ///////////////////////////////////////////////////////////////////// + + public int height() { + return this.surface.get_height(); + } +} + +} diff --git a/src/images/renderedText.vala b/src/images/renderedText.vala new file mode 100644 index 0000000..924742a --- /dev/null +++ b/src/images/renderedText.vala @@ -0,0 +1,110 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +This program 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 3 of the License, or (at your option) +any later version. + +This program 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 +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class representing string, rendered on an Image. +///////////////////////////////////////////////////////////////////////// + +public class RenderedText : Image { + + ///////////////////////////////////////////////////////////////////// + /// A cache which stores images. It is cleared when the theme of + /// Gnome-Pie changes. + /// The key is in form <string>@<width>x<height>:<font>. + ///////////////////////////////////////////////////////////////////// + + private static Gee.HashMap<string, Cairo.ImageSurface?> cache { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Initializes the cache. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + clear_cache(); + + Config.global.notify["theme"].connect(() => { + clear_cache(); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears the cache. + ///////////////////////////////////////////////////////////////////// + + static void clear_cache() { + cache = new Gee.HashMap<string, Cairo.ImageSurface?>(); + } + + ///////////////////////////////////////////////////////////////////// + /// C'tor, creates a new image representation of a string. + ///////////////////////////////////////////////////////////////////// + + public RenderedText(string text, int width, int height, string font) { + var cached = this.cache.get("%s@%ux%u:%s".printf(text, width, height, font)); + + if (cached == null) { + this.render_text(text, width, height, font); + this.cache.set("%s@%ux%u:%s".printf(text, width, height, font), this.surface); + } else { + this.surface = cached; + } + } + + ///////////////////////////////////////////////////////////////////// + /// Creates a new transparent image, with text written onto. + ///////////////////////////////////////////////////////////////////// + + public void render_text(string text, int width, int height, string font) { + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, width, height); + + var ctx = this.context(); + + // set the color as specified in the current theme + Color color = Config.global.theme.caption_color; + ctx.set_source_rgb(color.r, color.g, color.g); + + var layout = Pango.cairo_create_layout(ctx); + layout.set_width(Pango.units_from_double(width)); + + var font_description = Pango.FontDescription.from_string(font); + font_description.set_size((int)(font_description.get_size() * Config.global.global_scale)); + + layout.set_font_description(font_description); + layout.set_text(text, -1); + + // add newlines at the end of each line, in order to allow ellipsizing + string broken_string = ""; + foreach (var line in layout.get_lines()) { + broken_string = broken_string.concat(text.substring(line.start_index, line.length), "\n"); + } + layout.set_text(broken_string, broken_string.length-1); + + layout.set_ellipsize(Pango.EllipsizeMode.END); + layout.set_alignment(Pango.Alignment.CENTER); + + Pango.Rectangle extents; + layout.get_pixel_extents(null, out extents); + ctx.move_to(0, (int)(0.5*(height - extents.height))); + + Pango.cairo_update_layout(ctx, layout); + Pango.cairo_show_layout(ctx, layout); + } +} + +} diff --git a/src/images/themedIcon.vala b/src/images/themedIcon.vala new file mode 100644 index 0000000..29ae380 --- /dev/null +++ b/src/images/themedIcon.vala @@ -0,0 +1,161 @@ +/* +Copyright (c) 2011 by Simon Schneegans + +This program 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 3 of the License, or (at your option) +any later version. + +This program 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 +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +namespace GnomePie { + +///////////////////////////////////////////////////////////////////////// +/// A class representing a square-shaped icon, themed according to the +/// current theme of Gnome-Pie. +///////////////////////////////////////////////////////////////////////// + +public class ThemedIcon : Image { + + ///////////////////////////////////////////////////////////////////// + /// A cache which stores loaded icon. The key is the icon name. When + /// the users icon theme or the theme of Gnome-Pie changes, these + /// cahces are cleared. + ///////////////////////////////////////////////////////////////////// + + private static Gee.HashMap<string, Cairo.ImageSurface?> active_cache { private get; private set; } + private static Gee.HashMap<string, Cairo.ImageSurface?> inactive_cache { private get; private set; } + + ///////////////////////////////////////////////////////////////////// + /// Initializes the caches. + ///////////////////////////////////////////////////////////////////// + + public static void init() { + clear_cache(); + + Config.global.notify["theme"].connect(() => { + clear_cache(); + }); + + Gtk.IconTheme.get_default().changed.connect(() => { + clear_cache(); + }); + } + + ///////////////////////////////////////////////////////////////////// + /// Clears the cache. + ///////////////////////////////////////////////////////////////////// + + public static void clear_cache() { + active_cache = new Gee.HashMap<string, Cairo.ImageSurface?>(); + inactive_cache = new Gee.HashMap<string, Cairo.ImageSurface?>(); + } + + ///////////////////////////////////////////////////////////////////// + /// Paint a slice icon according to the current theme. + ///////////////////////////////////////////////////////////////////// + + public ThemedIcon(string icon_name, bool active) { + // check cache + var current_cache = active ? active_cache : inactive_cache; + var cached = current_cache.get(icon_name); + + if (cached != null) { + this.surface = cached; + return; + } + + // get layers for the desired slice type + var layers = active ? Config.global.theme.active_slice_layers : Config.global.theme.inactive_slice_layers; + + // get max size + int size = 0; + foreach (var layer in layers) { + if (layer.image.width() > size) size = layer.image.width(); + } + + this.surface = new Cairo.ImageSurface(Cairo.Format.ARGB32, size, size); + + // get size of icon layer + int icon_size = size; + foreach (var layer in layers) { + if (layer.is_icon) icon_size = layer.image.width(); + } + + Image icon; + if (icon_name.contains("/")) + icon = new Image.from_file_at_size(icon_name, icon_size, icon_size); + else + icon = new Icon(icon_name, icon_size); + + var color = new Color.from_icon(icon); + var ctx = this.context(); + + ctx.translate(size/2, size/2); + ctx.set_operator(Cairo.Operator.OVER); + + // now render all layers on top of each other + foreach (var layer in layers) { + + if (layer.colorize) { + ctx.push_group(); + } + + if (layer.is_icon) { + + ctx.push_group(); + + layer.image.paint_on(ctx); + + ctx.set_operator(Cairo.Operator.IN); + + if (layer.image.width() != icon_size) { + if (icon_name.contains("/")) + icon = new Image.from_file_at_size(icon_name, layer.image.width(), layer.image.width()); + else + icon = new Icon(icon_name,layer.image.width()); + } + + icon.paint_on(ctx); + + ctx.pop_group_to_source(); + ctx.paint(); + ctx.set_operator(Cairo.Operator.OVER); + + } else { + layer.image.paint_on(ctx); + } + + // colorize the whole layer if neccasary + if (layer.colorize) { + ctx.set_operator(Cairo.Operator.ATOP); + ctx.set_source_rgb(color.r, color.g, color.b); + ctx.paint(); + + ctx.set_operator(Cairo.Operator.OVER); + ctx.pop_group_to_source(); + ctx.paint(); + } + } + + // store the surface in cache + current_cache.set(icon_name, this.surface); + } + + ///////////////////////////////////////////////////////////////////// + /// Returns the size of the icon in pixels. Greetings to Liskov. + ///////////////////////////////////////////////////////////////////// + + public int size() { + return base.width(); + } +} + +} |