Added support for background images on any window.

This commit is contained in:
Joey Payne 2014-02-07 11:58:22 -07:00
commit 955a3db31f
4 changed files with 137 additions and 9 deletions

View file

@ -1,13 +1,13 @@
- Draggable windows ✔ - Draggable windows ✔
- Resizable windows ✔ - Resizable windows ✔
- Text windows ✔
- Background images ✔
- Windows can calculate minimum size to fit children - Windows can calculate minimum size to fit children
- Anchors - Anchors
- Anchor to left, center, right or top, middle, bottom - Anchor to left, center, right or top, middle, bottom
- Background images
- Drop shadows - Drop shadows
- Gradients - Gradients
- Independent border colors/sizes with joining corners - Independent border colors/sizes with joining corners
- Animations and Time delta - Animations and Time delta
- Text windows
- XML export and import - XML export and import

View file

@ -1 +1,5 @@
DEBUG=True import os
DEBUG = True
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SCREENSHOT_DIR = os.path.join(PROJECT_ROOT, 'screenshots')

View file

@ -1,6 +1,7 @@
import cairo import cairo
import pango import pango
import pangocairo as pc import pangocairo as pc
import gtk
import math import math
from .structures import Size, Position, Rectangle, Color, BorderRadius, Padding from .structures import Size, Position, Rectangle, Color, BorderRadius, Padding
from ..events.events import WindowEventSource from ..events.events import WindowEventSource
@ -97,9 +98,23 @@ class WindowSurface(object):
font_map = pc.cairo_font_map_get_default() font_map = pc.cairo_font_map_get_default()
font_list = [f.get_name() for f in font_map.list_families()] font_list = [f.get_name() for f in font_map.list_families()]
filters = {'none': cairo.FILTER_FAST,
'good': cairo.FILTER_GOOD,
'best': cairo.FILTER_BEST,
'bilinear': cairo.FILTER_BILINEAR,
'gaussian': cairo.FILTER_GAUSSIAN,
'nearest' : cairo.FILTER_NEAREST}
def __init__(self): def __init__(self):
super(WindowSurface, self).__init__() super(WindowSurface, self).__init__()
def load_image(self, image_path):
if image_path is not None:
if isinstance(image_path, basestring):
return gtk.gdk.pixbuf_new_from_file(image_path)
else:
return image_path
def draw_circle(self, position, size, color=(1,1,1,1), line_width=1.0, line_color=(0,0,0,1), start_angle=0.0, end_angle=360.0): def draw_circle(self, position, size, color=(1,1,1,1), line_width=1.0, line_color=(0,0,0,1), start_angle=0.0, end_angle=360.0):
color = Color.from_value(color) color = Color.from_value(color)
line_color = Color.from_value(line_color) line_color = Color.from_value(line_color)
@ -125,6 +140,69 @@ class WindowSurface(object):
context.set_source_rgba(*line_color) context.set_source_rgba(*line_color)
context.stroke() context.stroke()
def draw_image(self, image, position, size,
filter='none', stretch=True,
keep_aspect=True, center_horizontal=True,
center_vertical=True, image_offset=(0, 0)):
context = self.context
position = Position.from_value(position)
offset = Position.from_value(image_offset)
size = Size.from_value(size)
width = size.width
height = size.height
x,y = (self.position.x+position.x,
self.position.y+position.y)
context.rectangle(x, y, width, height)
context.clip()
if isinstance(image, basestring):
image = self.load_image(image)
im_width = image.get_width()
im_height = image.get_height()
new_height = height
new_width = width
if keep_aspect:
aspect_ratio = min(im_width, im_height)/float(max(im_width, im_height))
if width >= height:
new_width = aspect_ratio * new_height
else:
new_height = aspect_ratio * new_width
if center_horizontal:
x += width/2.0 - new_width/2.0
if x < 0:
x = 0
if center_vertical:
y += height/2.0 - new_height/2.0
if y < 0:
y = 0
im_surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(new_width), int(new_height))
sp = cairo.SurfacePattern(im_surf)
ct2 = cairo.Context(im_surf)
ct2.set_source(sp)
ct3 = gtk.gdk.CairoContext(ct2)
if stretch:
ct3.scale(new_width/float(im_width), new_height/float(im_height))
ct3.set_source_pixbuf(image, -offset.x, -offset.y)
ct3.get_source().set_filter(self.filters[filter])
ct3.paint()
context.set_source_surface(im_surf,x,y)
context.paint()
def draw_text(self, text, position, font_size=12, def draw_text(self, text, position, font_size=12,
font_weight='normal', font_weight='normal',
font_style='normal', font_color=(0,0,0,1), font_style='normal', font_color=(0,0,0,1),
@ -300,6 +378,14 @@ class Window(WindowEventSource, WindowSurface):
self.border_width = kwargs.pop('border_width', 1) self.border_width = kwargs.pop('border_width', 1)
self.border_color = Color.from_value(kwargs.pop('border_color', (0,0,0,0))) self.border_color = Color.from_value(kwargs.pop('border_color', (0,0,0,0)))
self.background_color = Color.from_value(kwargs.pop('background_color', (0,0,0,0))) self.background_color = Color.from_value(kwargs.pop('background_color', (0,0,0,0)))
self.background_image = self.load_image(kwargs.pop('background_image', None))
self.background_image_filter = kwargs.pop('background_image_filter','none')
self.background_image_stretch = kwargs.pop('background_image_stretch', True)
self.background_image_keep_ratio = kwargs.pop('background_image_keep_ratio', True)
self.background_image_center_horizontal = kwargs.pop('background_image_center_horizontal', True)
self.background_image_center_vertical = kwargs.pop('background_image_center_vertical', True)
self.background_image_offset = Position.from_value(kwargs.pop('background_image_offset', (0, 0)))
self.border_radius = BorderRadius.from_value(kwargs.pop('border_radius', 1)) self.border_radius = BorderRadius.from_value(kwargs.pop('border_radius', 1))
self.padding = Padding.from_value(kwargs.pop('padding', 0)) self.padding = Padding.from_value(kwargs.pop('padding', 0))
self.dashed_border = kwargs.pop('dashed_border', False) self.dashed_border = kwargs.pop('dashed_border', False)
@ -337,6 +423,15 @@ class Window(WindowEventSource, WindowSurface):
line_dashed=self.dashed_border, line_dashed=self.dashed_border,
clip=self.clip_children) clip=self.clip_children)
if self.background_image is not None:
self.draw_image(self.background_image, [0, 0], self.size,
filter=self.background_image_filter,
stretch=self.background_image_stretch,
keep_aspect=self.background_image_keep_ratio,
center_horizontal=self.background_image_center_horizontal,
center_vertical=self.background_image_center_vertical,
image_offset=self.background_image_offset)
@property @property
def resizable(self): def resizable(self):
return self._resizable return self._resizable
@ -901,3 +996,14 @@ class TextWindow(Window):
self.font_size, font_weight=self.font_weight, self.font_size, font_weight=self.font_weight,
font_style=self.font_style, font_family=self.font_family, font_style=self.font_style, font_family=self.font_family,
font_color=self.font_color, word_wrap=self.word_wrap) font_color=self.font_color, word_wrap=self.word_wrap)
class ImageWindow(Window):
def __init__(self, name, image_path, *args, **kwargs):
super(ImageWindow, self).__init__(name, *args, **kwargs)
self.image_path = image_path
self.image = self.load_image(self.image_path)
def render(self):
self.draw_image(self.image, [0,0], self.size)
super(ImageWindow, self).render()

View file

@ -1,4 +1,4 @@
from jgui.surface import Surface, Window, Position, Size, Color, TextWindow from jgui.surface import Surface, Window, Position, Size, Color, TextWindow, ImageWindow
import math import math
class TestSurface(Surface): class TestSurface(Surface):
@ -16,12 +16,30 @@ class TestSurface(Surface):
border_color=(0,0,0), border_color=(0,0,0),
background_color=(1,1,1), background_color=(1,1,1),
clip_children=True, clip_children=True,
ignore_debug=True) ignore_debug=True,
my_win.add_child(TextWindow('text','Micro Bean is the best bean ever.', position=[20,20], size=[100, 50], resizable=True, clip_children=True, font_color=(1,0,1), padding=20, draggable=True)) background_image='/home/joey/Pictures/wrench.png',
background_image_filter='bilinear')
my_win.add_child(TextWindow('text','Micro Bean is the best bean ever.',
position=[20,20], size=[100, 50],
resizable=True, clip_children=True,
font_color=(1,0,1), padding=20,
draggable=True))
self.root_window.add_child(my_win) self.root_window.add_child(my_win)
self.root_window.add_child(TestWindow('child2', position=[200,200], size=[200,200], draggable=True)) self.root_window.add_child(TestWindow('child2', position=[200,200],
child3 = TestWindow('child3', position=[300,300], size=[200,200], draggable=True) size=[200,200], draggable=True))
child3.add_child(TestWindow('child3-1', position=[10,10], size=[50,50], draggable=True, resizable=True))
self.root_window.add_child(ImageWindow('image', image_path='/home/joey/Pictures/wrench.png',
position=[0,200], size=[200,200],
draggable=True, resizable=True))
child3 = TestWindow('child3', position=[300,300],
size=[200,200], draggable=True)
child3.add_child(TestWindow('child3-1', position=[10,10],
size=[50,50], draggable=True,
resizable=True))
self.root_window.add_child(child3) self.root_window.add_child(child3)