diff --git a/featurelist.txt b/featurelist.txt index ae99076..c7592f7 100644 --- a/featurelist.txt +++ b/featurelist.txt @@ -1,13 +1,13 @@ - Draggable windows ✔ - Resizable windows ✔ +- Text windows ✔ +- Background images ✔ - Windows can calculate minimum size to fit children - Anchors - Anchor to left, center, right or top, middle, bottom -- Background images - Drop shadows - Gradients - Independent border colors/sizes with joining corners - Animations and Time delta -- Text windows - XML export and import diff --git a/jgui/settings.py b/jgui/settings.py index 147ae0a..7cf7729 100644 --- a/jgui/settings.py +++ b/jgui/settings.py @@ -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') diff --git a/jgui/surface/surface.py b/jgui/surface/surface.py index 6cc5b14..b7209a4 100644 --- a/jgui/surface/surface.py +++ b/jgui/surface/surface.py @@ -1,6 +1,7 @@ import cairo import pango import pangocairo as pc +import gtk import math from .structures import Size, Position, Rectangle, Color, BorderRadius, Padding from ..events.events import WindowEventSource @@ -97,9 +98,23 @@ class WindowSurface(object): font_map = pc.cairo_font_map_get_default() 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): 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): color = Color.from_value(color) line_color = Color.from_value(line_color) @@ -125,6 +140,69 @@ class WindowSurface(object): context.set_source_rgba(*line_color) 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, font_weight='normal', 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_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_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.padding = Padding.from_value(kwargs.pop('padding', 0)) self.dashed_border = kwargs.pop('dashed_border', False) @@ -337,6 +423,15 @@ class Window(WindowEventSource, WindowSurface): line_dashed=self.dashed_border, 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 def resizable(self): return self._resizable @@ -901,3 +996,14 @@ class TextWindow(Window): self.font_size, font_weight=self.font_weight, font_style=self.font_style, font_family=self.font_family, 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() + diff --git a/testclasses.py b/testclasses.py index 1504534..164880c 100644 --- a/testclasses.py +++ b/testclasses.py @@ -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 class TestSurface(Surface): @@ -16,12 +16,30 @@ class TestSurface(Surface): border_color=(0,0,0), background_color=(1,1,1), clip_children=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)) + ignore_debug=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(TestWindow('child2', position=[200,200], size=[200,200], draggable=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(TestWindow('child2', position=[200,200], + size=[200,200], draggable=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)