diff options
author | Jesús Eduardo <heckyel@hyperbola.info> | 2017-09-11 17:47:17 -0500 |
---|---|---|
committer | Jesús Eduardo <heckyel@hyperbola.info> | 2017-09-11 17:47:17 -0500 |
commit | 14738704ede6dfa6ac79f362a9c1f7f40f470cdc (patch) | |
tree | 31c83bdd188ae7b64d7169974d6f066ccfe95367 /lvc/widgets/gtk/drawing.py | |
parent | eb1896583afbbb622cadcde1a24e17173f61904f (diff) | |
download | librevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.tar.lz librevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.tar.xz librevideoconverter-14738704ede6dfa6ac79f362a9c1f7f40f470cdc.zip |
rename mvc at lvc
Diffstat (limited to 'lvc/widgets/gtk/drawing.py')
-rw-r--r-- | lvc/widgets/gtk/drawing.py | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/lvc/widgets/gtk/drawing.py b/lvc/widgets/gtk/drawing.py new file mode 100644 index 0000000..5888851 --- /dev/null +++ b/lvc/widgets/gtk/drawing.py @@ -0,0 +1,268 @@ +# @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. + +""".drawing -- Contains classes used to draw on +widgets. +""" + +import cairo +import gobject +import gtk + +import wrappermap +from .base import Widget, Bin +from .layoutmanager import LayoutManager + +def css_to_color(css_string): + parts = (css_string[1:3], css_string[3:5], css_string[5:7]) + return tuple((int(value, 16) / 255.0) for value in parts) + +class ImageSurface: + def __init__(self, image): + format = cairo.FORMAT_RGB24 + if image.pixbuf.get_has_alpha(): + format = cairo.FORMAT_ARGB32 + self.image = cairo.ImageSurface( + format, int(image.width), int(image.height)) + context = cairo.Context(self.image) + gdkcontext = gtk.gdk.CairoContext(context) + gdkcontext.set_source_pixbuf(image.pixbuf, 0, 0) + gdkcontext.paint() + self.pattern = cairo.SurfacePattern(self.image) + self.pattern.set_extend(cairo.EXTEND_REPEAT) + self.width = image.width + self.height = image.height + + def get_size(self): + return self.width, self.height + + def _align_pattern(self, x, y): + """Line up our image pattern so that it's top-left corner is x, y.""" + m = cairo.Matrix() + m.translate(-x, -y) + self.pattern.set_matrix(m) + + def draw(self, context, x, y, width, height, fraction=1.0): + self._align_pattern(x, y) + cairo_context = context.context + cairo_context.save() + cairo_context.set_source(self.pattern) + cairo_context.new_path() + cairo_context.rectangle(x, y, width, height) + if fraction >= 1.0: + cairo_context.fill() + else: + cairo_context.clip() + cairo_context.paint_with_alpha(fraction) + cairo_context.restore() + + def draw_rect(self, context, dest_x, dest_y, source_x, source_y, + width, height, fraction=1.0): + + self._align_pattern(dest_x-source_x, dest_y-source_y) + cairo_context = context.context + cairo_context.save() + cairo_context.set_source(self.pattern) + cairo_context.new_path() + cairo_context.rectangle(dest_x, dest_y, width, height) + if fraction >= 1.0: + cairo_context.fill() + else: + cairo_context.clip() + cairo_context.paint_with_alpha(fraction) + cairo_context.restore() + +class DrawingStyle(object): + def __init__(self, widget, use_base_color=False, state=None): + if state is None: + state = widget._widget.state + self.use_custom_style = widget.use_custom_style + self.style = widget._widget.style + self.text_color = widget.convert_gtk_color(self.style.text[state]) + if use_base_color: + self.bg_color = widget.convert_gtk_color(self.style.base[state]) + else: + self.bg_color = widget.convert_gtk_color(self.style.bg[state]) + +class DrawingContext(object): + """DrawingContext. This basically just wraps a Cairo context and adds a + couple convenience methods. + """ + + def __init__(self, window, drawing_area, expose_area): + self.window = window + self.context = window.cairo_create() + self.context.rectangle(expose_area.x, expose_area.y, + expose_area.width, expose_area.height) + self.context.clip() + self.width = drawing_area.width + self.height = drawing_area.height + self.context.translate(drawing_area.x, drawing_area.y) + + def __getattr__(self, name): + return getattr(self.context, name) + + def set_color(self, (red, green, blue), alpha=1.0): + self.context.set_source_rgba(red, green, blue, alpha) + + def set_shadow(self, color, opacity, offset, blur_radius): + pass + + def gradient_fill(self, gradient): + old_source = self.context.get_source() + self.context.set_source(gradient.pattern) + self.context.fill() + self.context.set_source(old_source) + + def gradient_fill_preserve(self, gradient): + old_source = self.context.get_source() + self.context.set_source(gradient.pattern) + self.context.fill_preserve() + self.context.set_source(old_source) + +class Gradient(object): + def __init__(self, x1, y1, x2, y2): + self.pattern = cairo.LinearGradient(x1, y1, x2, y2) + + def set_start_color(self, (red, green, blue)): + self.pattern.add_color_stop_rgb(0, red, green, blue) + + def set_end_color(self, (red, green, blue)): + self.pattern.add_color_stop_rgb(1, red, green, blue) + +class CustomDrawingMixin(object): + def do_expose_event(self, event): + wrapper = wrappermap.wrapper(self) + if self.flags() & gtk.NO_WINDOW: + drawing_area = self.allocation + else: + drawing_area = gtk.gdk.Rectangle(0, 0, + self.allocation.width, self.allocation.height) + context = DrawingContext(event.window, drawing_area, event.area) + context.style = DrawingStyle(wrapper) + if self.flags() & gtk.CAN_FOCUS: + focus_space = (self.style_get_property('focus-padding') + + self.style_get_property('focus-line-width')) + if not wrapper.squish_width: + context.width -= focus_space * 2 + translate_x = focus_space + else: + translate_x = 0 + if not wrapper.squish_height: + context.height -= focus_space * 2 + translate_y = focus_space + else: + translate_y = 0 + context.translate(translate_x, translate_y) + wrapper.layout_manager.update_cairo_context(context.context) + self.draw(wrapper, context) + + def draw(self, wrapper, context): + wrapper.layout_manager.reset() + wrapper.draw(context, wrapper.layout_manager) + + def do_size_request(self, requesition): + wrapper = wrappermap.wrapper(self) + width, height = wrapper.size_request(wrapper.layout_manager) + requesition.width = width + requesition.height = height + if self.flags() & gtk.CAN_FOCUS: + focus_space = (self.style_get_property('focus-padding') + + self.style_get_property('focus-line-width')) + if not wrapper.squish_width: + requesition.width += focus_space * 2 + if not wrapper.squish_height: + requesition.height += focus_space * 2 + +class MiroDrawingArea(CustomDrawingMixin, gtk.Widget): + def __init__(self): + gtk.Widget.__init__(self) + CustomDrawingMixin.__init__(self) + self.set_flags(gtk.NO_WINDOW) + +class BackgroundWidget(CustomDrawingMixin, gtk.Bin): + def do_size_request(self, requesition): + CustomDrawingMixin.do_size_request(self, requesition) + if self.get_child(): + child_width, child_height = self.get_child().size_request() + requesition.width = max(child_width, requesition.width) + requesition.height = max(child_height, requesition.height) + + def do_expose_event(self, event): + CustomDrawingMixin.do_expose_event(self, event) + if self.get_child(): + self.propagate_expose(self.get_child(), event) + + def do_size_allocate(self, allocation): + gtk.Bin.do_size_allocate(self, allocation) + if self.get_child(): + self.get_child().size_allocate(allocation) + +gobject.type_register(MiroDrawingArea) +gobject.type_register(BackgroundWidget) + +class Drawable: + def __init__(self): + self.squish_width = self.squish_height = False + + def set_squish_width(self, setting): + self.squish_width = setting + + def set_squish_height(self, setting): + self.squish_height = setting + + def set_widget(self, drawing_widget): + if self.is_opaque() and 0: + box = gtk.EventBox() + box.add(drawing_widget) + Widget.set_widget(self, box) + else: + Widget.set_widget(self, drawing_widget) + self.layout_manager = LayoutManager(self._widget) + + def size_request(self, layout_manager): + return 0, 0 + + def draw(self, context, layout_manager): + pass + + def is_opaque(self): + return False + +class DrawingArea(Drawable, Widget): + def __init__(self): + Widget.__init__(self) + Drawable.__init__(self) + self.set_widget(MiroDrawingArea()) + +class Background(Drawable, Bin): + def __init__(self): + Bin.__init__(self) + Drawable.__init__(self) + self.set_widget(BackgroundWidget()) |