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/osx/simple.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/osx/simple.py')
-rw-r--r-- | lvc/widgets/osx/simple.py | 376 |
1 files changed, 376 insertions, 0 deletions
diff --git a/lvc/widgets/osx/simple.py b/lvc/widgets/osx/simple.py new file mode 100644 index 0000000..37407a1 --- /dev/null +++ b/lvc/widgets/osx/simple.py @@ -0,0 +1,376 @@ +# @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. + +from __future__ import division +import logging +import math + +from AppKit import * +from Foundation import * +from objc import YES, NO, nil + +from lvc.widgets import widgetconst +from .base import Widget, SimpleBin, FlippedView +from .utils import filename_to_unicode +import drawing +import wrappermap + +"""A collection of various simple widgets.""" + +class Image(object): + """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" + def __init__(self, path): + self._set_image(NSImage.alloc().initByReferencingFile_( + filename_to_unicode(path))) + + def _set_image(self, nsimage): + self.nsimage = nsimage + self.width = self.nsimage.size().width + self.height = self.nsimage.size().height + if self.width * self.height == 0: + raise ValueError('Image has invalid size: (%d, %d)' % ( + self.width, self.height)) + + def resize(self, width, height): + return ResizedImage(self, width, height) + + def crop_and_scale(self, src_x, src_y, src_width, src_height, dest_width, + dest_height): + if dest_width <= 0 or dest_height <= 0: + logging.stacktrace("invalid dest sizes: %s %s" % (dest_width, + dest_height)) + return TransformedImage(self.nsimage) + + source_rect = NSMakeRect(src_x, src_y, src_width, src_height) + dest_rect = NSMakeRect(0, 0, dest_width, dest_height) + + dest = NSImage.alloc().initWithSize_(NSSize(dest_width, dest_height)) + dest.lockFocus() + try: + NSGraphicsContext.currentContext().setImageInterpolation_( + NSImageInterpolationHigh) + self.nsimage.drawInRect_fromRect_operation_fraction_(dest_rect, + source_rect, NSCompositeCopy, 1.0) + finally: + dest.unlockFocus() + return TransformedImage(dest) + + def resize_for_space(self, width, height): + """Returns an image scaled to fit into the specified space at the + correct height/width ratio. + """ + # this prevents division by 0. + if self.width == 0 and self.height == 0: + return self + elif self.width == 0: + ratio = height / self.height + return self.resize(self.width, ratio * self.height) + elif self.height == 0: + ratio = width / self.width + return self.resize(ratio * self.width, self.height) + + ratio = min(width / self.width, height / self.height) + return self.resize(ratio * self.width, ratio * self.height) + +class ResizedImage(Image): + def __init__(self, image, width, height): + nsimage = image.nsimage.copy() + nsimage.setCacheMode_(NSImageCacheNever) + nsimage.setScalesWhenResized_(YES) + nsimage.setSize_(NSSize(width, height)) + self._set_image(nsimage) + +class TransformedImage(Image): + def __init__(self, nsimage): + self._set_image(nsimage) + +class NSImageDisplay(NSView): + def init(self): + self = super(NSImageDisplay, self).init() + self.border = False + self.image = None + return self + + def isFlipped(self): + return YES + + def set_border(self, border): + self.border = border + + def set_image(self, image): + self.image = image + + def drawRect_(self, dest_rect): + if self.image is not None: + source_rect = self.calculateSourceRectFromDestRect_(dest_rect) + context = NSGraphicsContext.currentContext() + context.setShouldAntialias_(YES) + context.setImageInterpolation_(NSImageInterpolationHigh) + context.saveGraphicsState() + drawing.flip_context(self.bounds().size.height) + self.image.nsimage.drawInRect_fromRect_operation_fraction_( + dest_rect, source_rect, NSCompositeSourceOver, 1.0) + context.restoreGraphicsState() + if self.border: + context = drawing.DrawingContext(self, self.bounds(), dest_rect) + context.style = drawing.DrawingStyle() + context.set_line_width(1) + context.set_color((0, 0, 0)) # black + context.rectangle(0, 0, context.width, context.height) + context.stroke() + + def calculateSourceRectFromDestRect_(self, dest_rect): + """Calulate where dest_rect maps to on our image. + + This is tricky because our image might be scaled up, in which case + the rect from our image will be smaller than dest_rect. + """ + view_size = self.frame().size + x_scale = float(self.image.width) / view_size.width + y_scale = float(self.image.height) / view_size.height + + return NSMakeRect(dest_rect.origin.x * x_scale, + dest_rect.origin.y * y_scale, + dest_rect.size.width * x_scale, + dest_rect.size.height * y_scale) + + # XXX FIXME: should track mouse movement - mouseDown is not the correct + # event. + def mouseDown_(self, event): + wrappermap.wrapper(self).emit('clicked') + +class ImageDisplay(Widget): + """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" + def __init__(self, image=None): + Widget.__init__(self) + self.create_signal('clicked') + self.view = NSImageDisplay.alloc().init() + self.set_image(image) + + def set_image(self, image): + self.image = image + if image: + image.nsimage.setCacheMode_(NSImageCacheNever) + self.view.set_image(image) + self.invalidate_size_request() + + def set_border(self, border): + self.view.set_border(border) + + def calc_size_request(self): + if self.image is not None: + return self.image.width, self.image.height + else: + return 0, 0 + +class ClickableImageButton(ImageDisplay): + def __init__(self, image_path, max_width=None, max_height=None): + ImageDisplay.__init__(self) + self.set_border(True) + self.max_width = max_width + self.max_height = max_height + self.image = None + self._width, self._height = None, None + if image_path: + self.set_path(image_path) + + def set_path(self, path): + image = Image(path) + if self.max_width: + image = image.resize_for_space(self.max_width, self.max_height) + super(ClickableImageButton, self).set_image(image) + + def calc_size_request(self): + if self.max_width: + return self.max_width, self.max_height + else: + return ImageDisplay.calc_size_request(self) + +class MiroImageView(NSImageView): + def viewWillMoveToWindow_(self, aWindow): + self.setAnimates_(not aWindow == nil) + +class AnimatedImageDisplay(Widget): + def __init__(self, path): + Widget.__init__(self) + self.nsimage = NSImage.alloc().initByReferencingFile_( + filename_to_unicode(path)) + self.view = MiroImageView.alloc().init() + self.view.setImage_(self.nsimage) + # enabled when viewWillMoveToWindow:aWindow invoked + self.view.setAnimates_(NO) + + def calc_size_request(self): + return self.nsimage.size().width, self.nsimage.size().height + +class Label(Widget): + """See https://develop.participatoryculture.org/index.php/WidgetAPI for a description of the API for this class.""" + def __init__(self, text="", wrap=False, color=None): + Widget.__init__(self) + self.view = NSTextField.alloc().init() + self.view.setEditable_(NO) + self.view.setBezeled_(NO) + self.view.setBordered_(NO) + self.view.setDrawsBackground_(NO) + self.wrap = wrap + self.bold = False + self.size = NSFont.systemFontSize() + self.sizer_cell = self.view.cell().copy() + self.set_font() + self.set_text(text) + self.__color = self.view.textColor() + if color is not None: + self.set_color(color) + + def get_width(self): + return self.calc_size_request()[0] + + def set_bold(self, bold): + self.bold = bold + self.set_font() + + def set_size(self, size): + if size > 0: + self.size = NSFont.systemFontSize() * size + elif size == widgetconst.SIZE_SMALL: + self.size = NSFont.smallSystemFontSize() + elif size == widgetconst.SIZE_NORMAL: + self.size = NSFont.systemFontSize() + else: + raise ValueError("Unknown size constant: %s" % size) + + self.set_font() + + def set_color(self, color): + self.__color = self.make_color(color) + + if self.view.isEnabled(): + self.view.setTextColor_(self.__color) + else: + self.view.setTextColor_(self.__color.colorWithAlphaComponent_(0.5)) + + def set_background_color(self, color): + self.view.setBackgroundColor_(self.make_color(color)) + self.view.setDrawsBackground_(YES) + + def set_font(self): + if self.bold: + font = NSFont.boldSystemFontOfSize_(self.size) + else: + font= NSFont.systemFontOfSize_(self.size) + self.view.setFont_(font) + self.sizer_cell.setFont_(font) + self.invalidate_size_request() + + def calc_size_request(self): + if (self.wrap and self.manual_size_request is not None and + self.manual_size_request[0] > 0): + wrap_width = self.manual_size_request[0] + size = self.sizer_cell.cellSizeForBounds_(NSMakeRect(0, 0, + wrap_width, 10000)) + else: + size = self.sizer_cell.cellSize() + return math.ceil(size.width), math.ceil(size.height) + + def baseline(self): + return -self.view.font().descender() + + def set_text(self, text): + self.view.setStringValue_(text) + self.sizer_cell.setStringValue_(text) + self.invalidate_size_request() + + def get_text(self): + val = self.view.stringValue() + if not val: + val = u'' + return val + + def set_selectable(self, val): + self.view.setSelectable_(val) + + def set_alignment(self, alignment): + self.view.setAlignment_(alignment) + + def get_alignment(self, alignment): + return self.view.alignment() + + def set_wrap(self, wrap): + self.wrap = True + self.invalidate_size_request() + + def enable(self): + Widget.enable(self) + self.view.setTextColor_(self.__color) + self.view.setEnabled_(True) + + def disable(self): + Widget.disable(self) + self.view.setTextColor_(self.__color.colorWithAlphaComponent_(0.5)) + self.view.setEnabled_(False) + +class SolidBackground(SimpleBin): + def __init__(self, color=None): + SimpleBin.__init__(self) + self.view = FlippedView.alloc().init() + if color is not None: + self.set_background_color(color) + + def set_background_color(self, color): + self.view.setBackgroundColor_(self.make_color(color)) + +class ProgressBar(Widget): + def __init__(self): + Widget.__init__(self) + self.view = NSProgressIndicator.alloc().init() + self.view.setMaxValue_(1.0) + self.view.setIndeterminate_(False) + + def calc_size_request(self): + return 20, 20 + + def set_progress(self, fraction): + self.view.setIndeterminate_(False) + self.view.setDoubleValue_(fraction) + + def start_pulsing(self): + self.view.setIndeterminate_(True) + self.view.startAnimation_(nil) + + def stop_pulsing(self): + self.view.stopAnimation_(nil) + +class HLine(Widget): + def __init__(self): + Widget.__init__(self) + self.view = NSBox.alloc().init() + self.view.setBoxType_(NSBoxSeparator) + + def calc_size_request(self): + return self.view.frame().size.width, self.view.frame().size.height |