From 14738704ede6dfa6ac79f362a9c1f7f40f470cdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Eduardo?= Date: Mon, 11 Sep 2017 17:47:17 -0500 Subject: rename mvc at lvc --- lvc/widgets/gtk/simple.py | 313 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 lvc/widgets/gtk/simple.py (limited to 'lvc/widgets/gtk/simple.py') diff --git a/lvc/widgets/gtk/simple.py b/lvc/widgets/gtk/simple.py new file mode 100644 index 0000000..102fcd4 --- /dev/null +++ b/lvc/widgets/gtk/simple.py @@ -0,0 +1,313 @@ +# @Base: Miro - an RSS based video player application +# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011 +# Participatory Culture Foundation +# +# 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 2 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, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +# In addition, as a special exception, the copyright holders give +# permission to link the code of portions of this program with the OpenSSL +# library. +# +# You must obey the GNU General Public License in all respects for all of +# the code used other than OpenSSL. If you modify file(s) with this +# exception, you may extend this exception to your version of the file(s), +# but you are not obligated to do so. If you do not wish to do so, delete +# this exception statement from your version. If you delete this exception +# statement from all source files in the program, then also delete it here. + +"""simple.py -- Collection of simple widgets.""" + +import gtk +import gobject +import pango + +from lvc.widgets import widgetconst +from .base import Widget, Bin + +class Image(object): + def __init__(self, path): + try: + self._set_pixbuf(gtk.gdk.pixbuf_new_from_file(path)) + except gobject.GError, ge: + raise ValueError("%s" % ge) + self.width = self.pixbuf.get_width() + self.height = self.pixbuf.get_height() + + def _set_pixbuf(self, pixbuf): + self.pixbuf = pixbuf + self.width = self.pixbuf.get_width() + self.height = self.pixbuf.get_height() + + def resize(self, width, height): + width = int(round(width)) + height = int(round(height)) + resized_pixbuf = self.pixbuf.scale_simple(width, height, + gtk.gdk.INTERP_BILINEAR) + return TransformedImage(resized_pixbuf) + + def resize_for_space(self, width, height): + """Returns an image scaled to fit into the specified space at the + correct height/width ratio. + """ + ratio = min(1.0 * width / self.width, 1.0 * height / self.height) + return self.resize(ratio * self.width, ratio * self.height) + + def crop_and_scale(self, src_x, src_y, src_width, src_height, dest_width, + dest_height): + """Crop an image then scale it. + + The image will be cropped to the rectangle (src_x, src_y, src_width, + src_height), that rectangle will be scaled to a new Image with tisez + (dest_width, dest_height) + """ + dest = gtk.gdk.Pixbuf(self.pixbuf.get_colorspace(), + self.pixbuf.get_has_alpha(), + self.pixbuf.get_bits_per_sample(), dest_width, dest_height) + + scale_x = dest_width / float(src_width) + scale_y = dest_height / float(src_height) + + self.pixbuf.scale(dest, 0, 0, dest_width, dest_height, + -src_x * scale_x, -src_y * scale_y, scale_x, scale_y, + gtk.gdk.INTERP_BILINEAR) + return TransformedImage(dest) + +class TransformedImage(Image): + def __init__(self, pixbuf): + # XXX intentionally not calling direct super's __init__; we should do + # this differently + self._set_pixbuf(pixbuf) + +class ImageDisplay(Widget): + def __init__(self, image=None): + Widget.__init__(self) + self.set_widget(gtk.Image()) + self.set_image(image) + + def set_image(self, image): + self.image = image + if image is not None: + self._widget.set_from_pixbuf(image.pixbuf) + else: + self._widget.clear() + +class AnimatedImageDisplay(Widget): + def __init__(self, path): + Widget.__init__(self) + self.set_widget(gtk.Image()) + self._animation = gtk.gdk.PixbufAnimation(path) + # Set to animate before we are shown and stop animating after + # we disappear. + self._widget.connect('map', lambda w: self._set_animate(True)) + self._widget.connect('unmap-event', + lambda w, a: self._set_animate(False)) + + def _set_animate(self, enabled): + if enabled: + self._widget.set_from_animation(self._animation) + else: + self._widget.clear() + +class Label(Widget): + """Widget that displays simple text.""" + def __init__(self, text="", color=None): + Widget.__init__(self) + self.set_widget(gtk.Label()) + if text: + self.set_text(text) + self.attr_list = pango.AttrList() + self.font_description = self._widget.style.font_desc.copy() + self.scale_factor = 1.0 + if color is not None: + self.set_color(color) + self.wrapped_widget_connect('style-set', self.on_style_set) + + def set_bold(self, bold): + if bold: + weight = pango.WEIGHT_BOLD + else: + weight = pango.WEIGHT_NORMAL + self.font_description.set_weight(weight) + self.set_attr(pango.AttrFontDesc(self.font_description)) + + def set_size(self, size): + if size == widgetconst.SIZE_NORMAL: + self.scale_factor = 1 + elif size == widgetconst.SIZE_SMALL: + self.scale_factor = 0.75 + else: + self.scale_factor = size + baseline = self._widget.style.font_desc.get_size() + self.font_description.set_size(int(baseline * self.scale_factor)) + self.set_attr(pango.AttrFontDesc(self.font_description)) + + def get_preferred_width(self): + return self._widget.size_request()[0] + + def on_style_set(self, widget, old_style): + self.set_size(self.scale_factor) + + def set_wrap(self, wrap): + self._widget.set_line_wrap(wrap) + + def set_alignment(self, alignment): + # default to left. + gtkalignment = gtk.JUSTIFY_LEFT + if alignment == widgetconst.TEXT_JUSTIFY_LEFT: + gtkalignment = gtk.JUSTIFY_LEFT + elif alignment == widgetconst.TEXT_JUSTIFY_RIGHT: + gtkalignment = gtk.JUSTIFY_RIGHT + elif alignment == widgetconst.TEXT_JUSTIFY_CENTER: + gtkalignment = gtk.JUSTIFY_CENTER + self._widget.set_justify(gtkalignment) + + def get_alignment(self): + return self._widget.get_justify() + + def get_width(self): + return self._widget.get_layout().get_pixel_size()[0] + + def set_text(self, text): + self._widget.set_text(text) + + def get_text(self): + return self._widget.get_text().decode('utf-8') + + def set_selectable(self, val): + self._widget.set_selectable(val) + + def set_attr(self, attr): + attr.end_index = 65535 + self.attr_list.change(attr) + self._widget.set_attributes(self.attr_list) + + def set_color(self, color): + color_as_int = (int(65535 * c) for c in color) + self.set_attr(pango.AttrForeground(*color_as_int)) + + def baseline(self): + pango_context = self._widget.get_pango_context() + metrics = pango_context.get_metrics(self.font_description) + return pango.PIXELS(metrics.get_descent()) + + def hide(self): + self._widget.hide() + + def show(self): + self._widget.show() + +class Scroller(Bin): + def __init__(self, horizontal, vertical): + Bin.__init__(self) + self.set_widget(gtk.ScrolledWindow()) + if horizontal: + h_policy = gtk.POLICY_AUTOMATIC + else: + h_policy = gtk.POLICY_NEVER + if vertical: + v_policy = gtk.POLICY_AUTOMATIC + else: + v_policy = gtk.POLICY_NEVER + self._widget.set_policy(h_policy, v_policy) + + def set_has_borders(self, has_border): + pass + + def set_background_color(self, color): + pass + + def add_child_to_widget(self): + if (isinstance(self.child._widget, gtk.TreeView) or + isinstance(self.child._widget, gtk.TextView)): + # child has native scroller + self._widget.add(self.child._widget) + else: + self._widget.add_with_viewport(self.child._widget) + self._widget.get_child().set_shadow_type(gtk.SHADOW_NONE) + if isinstance(self.child._widget, gtk.TextView): + self._widget.set_shadow_type(gtk.SHADOW_IN) + else: + self._widget.set_shadow_type(gtk.SHADOW_NONE) + + def prepare_for_dark_content(self): + # this is just a hack for cocoa + pass + + +class SolidBackground(Bin): + def __init__(self, color=None): + Bin.__init__(self) + self.set_widget(gtk.EventBox()) + if color is not None: + self.set_background_color(color) + + def set_background_color(self, color): + self.modify_style('base', gtk.STATE_NORMAL, self.make_color(color)) + self.modify_style('bg', gtk.STATE_NORMAL, self.make_color(color)) + +class Expander(Bin): + def __init__(self, child=None): + Bin.__init__(self) + self.set_widget(gtk.Expander()) + if child is not None: + self.add(child) + self.label = None + # This is a complete hack. GTK expanders have a transparent + # background most of the time, except when they are prelighted. So we + # just set the background to white there because that's what should + # happen in the item list. + self.modify_style('bg', gtk.STATE_PRELIGHT, + gtk.gdk.color_parse('white')) + + def set_spacing(self, spacing): + self._widget.set_spacing(spacing) + + def set_label(self, widget): + self.label = widget + self._widget.set_label_widget(widget._widget) + widget._widget.show() + + def set_expanded(self, expanded): + self._widget.set_expanded(expanded) + +class ProgressBar(Widget): + def __init__(self): + Widget.__init__(self) + self.set_widget(gtk.ProgressBar()) + self._timer = None + + def set_progress(self, fraction): + self._widget.set_fraction(fraction) + + def start_pulsing(self): + if self._timer is None: + self._timer = gobject.timeout_add(100, self._do_pulse) + + def stop_pulsing(self): + if self._timer: + gobject.source_remove(self._timer) + self._timer = None + + def _do_pulse(self): + self._widget.pulse() + return True + +class HLine(Widget): + """A horizontal separator. Not to be confused with HSeparator, which is is + a DrawingArea, not a Widget. + """ + def __init__(self): + Widget.__init__(self) + self.set_widget(gtk.HSeparator()) -- cgit v1.2.3