diff -Nru photofilmstrip-3.2.0/debian/changelog photofilmstrip-3.3.1/debian/changelog --- photofilmstrip-3.2.0/debian/changelog 2017-11-23 07:20:43.000000000 +0000 +++ photofilmstrip-3.3.1/debian/changelog 2017-12-27 20:43:42.000000000 +0000 @@ -1,44 +1,10 @@ -photofilmstrip (3.2.0-1) unstable; urgency=medium +photofilmstrip (3.3.1-1dhor~xenial) xenial; urgency=low - * New upstream version 3.2.0 - * Remove deprecated patches - * Remove custom manapges, now provided upstream - * Remove debian/menu - * Remove debian/dirs - * Update debian/copyright - * Update debian/watch - * Update debian/control, switch to debhelper 10 and pybuild - * Update debian/photofilmstrip.doc-base - * Update dependencies + * a lot more output formats + * complete new user interface design + * bug fixes - -- Philipp Huebner Thu, 23 Nov 2017 08:20:43 +0100 -photofilmstrip (1.9.92+dfsg-1) unstable; urgency=low - * New upstream release (Closes: #695062) - * Updated standards version: 3.9.4 (no changes needed) - * Updated debian/copyright - * Corrected debian/watch + -- Dariusz Duma Wed, 27 Dec 2017 10:26:08 +0100 - -- Philipp Huebner Thu, 18 Jul 2013 13:30:51 +0200 - -photofilmstrip (1.9.91+dfsg-1) unstable; urgency=low - - [ Gürkan Sengün ] - * Repackaged (remove windows/) - * New upstream version (Closes: #668857) - * Bumped up standards version to 3.9.3. - - [ Philipp Huebner ] - * Fixed double installation of html documentation - * Added doc-base registration - * Added myself as uploader - * Updated debian/copyright - - -- Philipp Huebner Tue, 22 May 2012 14:45:58 +0200 - -photofilmstrip (1.4.0-1) unstable; urgency=low - - * Initial release. (Closes: #586268) - - -- Gürkan Sengün Thu, 27 Jan 2011 10:26:08 +0100 diff -Nru photofilmstrip-3.2.0/debian/compat photofilmstrip-3.3.1/debian/compat --- photofilmstrip-3.2.0/debian/compat 2017-11-16 16:17:38.000000000 +0000 +++ photofilmstrip-3.3.1/debian/compat 2017-12-27 22:42:57.000000000 +0000 @@ -1 +1 @@ -10 +9 \ No newline at end of file diff -Nru photofilmstrip-3.2.0/debian/control photofilmstrip-3.3.1/debian/control --- photofilmstrip-3.2.0/debian/control 2017-11-16 18:01:02.000000000 +0000 +++ photofilmstrip-3.3.1/debian/control 2017-12-27 22:42:09.000000000 +0000 @@ -1,23 +1,21 @@ Source: photofilmstrip Section: video Priority: optional -Maintainer: Philipp Huebner -Build-Depends: debhelper (>= 10), dh-python, python-all, python-gst-1.0, python-setuptools -X-Python-Version: >= 2.6 -Standards-Version: 4.1.1 -Homepage: http://www.photofilmstrip.org/ -Vcs-Git: https://anonscm.debian.org/git/users/debalance/photofilmstrip.git -Vcs-Browser: https://anonscm.debian.org/git/users/debalance/photofilmstrip.git +Maintainer: Dariusz Duma +Build-Depends: debhelper (>= 9), python, python-distutils-extra +X-Python-Version: >=2.7 +Standards-Version: 3.9.7 +Homepage: http://www.photofilmstrip.org Package: photofilmstrip Architecture: all -Depends: ${misc:Depends}, ${python:Depends}, gstreamer1.0-libav, python-gst-1.0, python-pil, python-wxgtk3.0 +Depends: ${misc:Depends}, python-wxgtk3.0, python-pil, python-gst-1.0, gstreamer1.0-libav Description: Slideshow creator with Ken Burns effect This creates movies out of your pictures in just three steps. First select your photos, customize the motion path and render the video. There are several output possibilities for VCD, SVCD, DVD up to - FULL-HD and even 4k. + FULL-HD. . The effect of the slideshow is known as "Ken Burns". Comments of the - pictures are generated into a subtitle file. Furthermore audio files - can be specified to setup the background music for the slide show. + pictures are generated into a subtitle file. Furthermore an audio file + can be specified to setup the background musice for the slide show. diff -Nru photofilmstrip-3.2.0/debian/copyright photofilmstrip-3.3.1/debian/copyright --- photofilmstrip-3.2.0/debian/copyright 2017-11-16 15:51:34.000000000 +0000 +++ photofilmstrip-3.3.1/debian/copyright 2017-11-15 19:49:04.000000000 +0000 @@ -1,45 +1,24 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: PhotoFilmStrip -Upstream-Contact: Jens Göpfert +Upstream-Contact: Jens Göpfert Source: http://www.photofilmstrip.org/ Files: * -Copyright: 2008-2017 Jens Göpfert +Copyright: 2008-2017 Jens Göpfert License: GPL-2+ - 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 package; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - . - On Debian systems, the complete text of the GNU General - Public License can be found in `/usr/share/common-licenses/GPL-2'. - -Files: debian/* -Copyright: 2012-2017 Philipp Huebner - 2010-2012 Gürkan Sengün - 2008-2010 Jens Göpfert -License: GPL-3+ - 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 3 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, see . - . - On Debian systems, the complete text of the GNU General - Public License can be found in `/usr/share/common-licenses/GPL-3'. + This package 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 package 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 package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-2'. diff -Nru photofilmstrip-3.2.0/debian/dirs photofilmstrip-3.3.1/debian/dirs --- photofilmstrip-3.2.0/debian/dirs 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/debian/dirs 2017-11-15 19:49:04.000000000 +0000 @@ -0,0 +1,4 @@ +usr/bin +usr/share/photofilmstrip +usr/share/applications +usr/share/pixmaps \ No newline at end of file diff -Nru photofilmstrip-3.2.0/debian/docs photofilmstrip-3.3.1/debian/docs --- photofilmstrip-3.2.0/debian/docs 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/debian/docs 2017-11-15 19:49:04.000000000 +0000 @@ -0,0 +1,4 @@ +README +CHANGES +COPYING + diff -Nru photofilmstrip-3.2.0/debian/menu photofilmstrip-3.3.1/debian/menu --- photofilmstrip-3.2.0/debian/menu 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/debian/menu 2017-11-15 19:49:04.000000000 +0000 @@ -0,0 +1,2 @@ +?package(photofilmstrip):needs="X11" section="Applications/Video"\ + title="Photofilmstrip" command="/usr/bin/photofilmstrip" diff -Nru photofilmstrip-3.2.0/debian/photofilmstrip.doc-base photofilmstrip-3.3.1/debian/photofilmstrip.doc-base --- photofilmstrip-3.2.0/debian/photofilmstrip.doc-base 2017-11-16 15:54:10.000000000 +0000 +++ photofilmstrip-3.3.1/debian/photofilmstrip.doc-base 2017-11-15 19:49:04.000000000 +0000 @@ -1,7 +1,9 @@ Document: photofilmstrip -Title: Debian PhotoFilmStrip Manual -Author: Jens Göpfert -Abstract: How to create and render a PhotoFilmStrip and more +Title: PhotoFilmStrip Manual +Author: Jens Goepfert +Abstract: This manual describes what photofilmstrip is + and how it can be used to + manage online manuals on Debian systems. Section: Video Format: HTML diff -Nru photofilmstrip-3.2.0/debian/rules photofilmstrip-3.3.1/debian/rules --- photofilmstrip-3.2.0/debian/rules 2017-11-16 16:06:23.000000000 +0000 +++ photofilmstrip-3.3.1/debian/rules 2017-12-27 22:42:30.000000000 +0000 @@ -1,5 +1,6 @@ #!/usr/bin/make -f -export DH_VERBOSE=1 %: - dh $@ --with python2 --buildsystem=pybuild + dh $@ --with-python3 --buildsystem=python_distutils + + diff -Nru photofilmstrip-3.2.0/debian/source/format photofilmstrip-3.3.1/debian/source/format --- photofilmstrip-3.2.0/debian/source/format 2017-11-16 14:04:19.000000000 +0000 +++ photofilmstrip-3.3.1/debian/source/format 2017-11-15 19:49:04.000000000 +0000 @@ -1 +1 @@ -3.0 (quilt) +3.0 (native) diff -Nru photofilmstrip-3.2.0/debian/watch photofilmstrip-3.3.1/debian/watch --- photofilmstrip-3.2.0/debian/watch 2017-11-16 15:55:55.000000000 +0000 +++ photofilmstrip-3.3.1/debian/watch 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -version=3 -opts="filenamemangle=s/.*\/v?(\d\S*)\.tar\.gz/photofilmstrip_$1.tar.gz/" \ - https://github.com/PhotoFilmStrip/PFS/releases .*/v?(\d\S*)\.tar\.gz diff -Nru photofilmstrip-3.2.0/make.bat photofilmstrip-3.3.1/make.bat --- photofilmstrip-3.2.0/make.bat 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/make.bat 2017-12-03 22:12:24.000000000 +0000 @@ -2,7 +2,7 @@ if %1!==! goto usage -set PYTHON=C:\Python27\python.exe +set PYTHON=python.exe git rev-parse --short HEAD > scm_rev.txt set /p SCM_REV= ratio: @@ -49,8 +50,8 @@ scaledWidth = width scaledHeight = width / ratio - centerRect = (int(round((width - scaledWidth) /2.0)), - int(round((height - scaledHeight) / 2.0)), + centerRect = (int(round((width - scaledWidth) / 2.0)), + int(round((height - scaledHeight) / 2.0)), int(round(scaledWidth)), int(round(scaledHeight))) self.__picture.SetStartRect(centerRect) self.__picture.SetTargetRect(centerRect) diff -Nru photofilmstrip-3.2.0/photofilmstrip/action/ActionI18N.py photofilmstrip-3.3.1/photofilmstrip/action/ActionI18N.py --- photofilmstrip-3.2.0/photofilmstrip/action/ActionI18N.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/action/ActionI18N.py 2017-12-03 22:12:24.000000000 +0000 @@ -40,11 +40,13 @@ def Execute(self): curLang = Settings().GetLanguage() + localeDir = None for localeDir in (os.path.join(Constants.APP_DIR, "share", "locale"), os.path.join(Constants.APP_DIR, "locale"),): if os.path.isdir(localeDir): break - else: + + if localeDir is None: gettext.install(Constants.APP_NAME, unicode=True) return @@ -54,4 +56,4 @@ languages=[curLang, "en"]) lang.install(True) except IOError: - gettext.install(Constants.APP_NAME) + gettext.install(Constants.APP_NAME, unicode=True) diff -Nru photofilmstrip-3.2.0/photofilmstrip/action/ActionOpenFolder.py photofilmstrip-3.3.1/photofilmstrip/action/ActionOpenFolder.py --- photofilmstrip-3.2.0/photofilmstrip/action/ActionOpenFolder.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/action/ActionOpenFolder.py 2017-12-03 22:12:24.000000000 +0000 @@ -26,25 +26,22 @@ class ActionOpenFolder(IAction): - + def __init__(self, outpath): self.outpath = outpath - + def GetName(self): return _(u'Open folder') - + def GetBitmap(self): import wx - ms = wx.ArtProvider.GetSizeHint(wx.ART_MENU) - return wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, - wx.ART_TOOLBAR, - ms) + return wx.ArtProvider.GetBitmap('PFS_FOLDER_OPEN_16') def Execute(self): if not os.path.exists(self.outpath): return - + if os.name == "nt": - os.startfile(self.outpath) # IGNORE:E1101 + os.startfile(self.outpath) # pylint: disable=no-member else: subprocess.Popen(["xdg-open", self.outpath]) diff -Nru photofilmstrip-3.2.0/photofilmstrip/action/ActionPlayVideo.py photofilmstrip-3.3.1/photofilmstrip/action/ActionPlayVideo.py --- photofilmstrip-3.2.0/photofilmstrip/action/ActionPlayVideo.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/action/ActionPlayVideo.py 2017-12-03 22:12:24.000000000 +0000 @@ -43,7 +43,7 @@ if os.name == "nt": try: - os.startfile(videoFile) + os.startfile(videoFile) # pylint: disable=no-member except: pass else: diff -Nru photofilmstrip-3.2.0/photofilmstrip/action/ActionRender.py photofilmstrip-3.3.1/photofilmstrip/action/ActionRender.py --- photofilmstrip-3.2.0/photofilmstrip/action/ActionRender.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/action/ActionRender.py 2017-12-03 22:12:24.000000000 +0000 @@ -37,12 +37,11 @@ class ActionRender(IAction): def __init__(self, photoFilmStrip, - profile, videoNorm, + profile, rendererClass, draftMode, outpath=None): self.__photoFilmStrip = photoFilmStrip self.__profile = profile - self.__profile.SetVideoNorm(videoNorm) self.__rendererClass = rendererClass self.__draftMode = draftMode self.__outpath = outpath @@ -64,14 +63,7 @@ def _SaveSettings(self): settings = Settings() - outputProfiles = GetOutputProfiles(self.__photoFilmStrip.GetAspect()) - idxProfile = 0 - for idx, prof in enumerate(outputProfiles): - if prof.GetName() == self.__profile.GetName(): - idxProfile = idx - settings.SetLastProfile(idxProfile) - - settings.SetVideoType(self.__profile.GetVideoNorm()) + settings.SetLastProfile(self.__profile.GetName()) idxRenderer = RENDERERS.index(self.__rendererClass) settings.SetUsedRenderer(idxRenderer) diff -Nru photofilmstrip-3.2.0/photofilmstrip/action/IAction.py photofilmstrip-3.3.1/photofilmstrip/action/IAction.py --- photofilmstrip-3.2.0/photofilmstrip/action/IAction.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/action/IAction.py 2017-12-03 22:12:24.000000000 +0000 @@ -19,10 +19,11 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # + class IAction(object): - + def GetName(self): raise NotImplementedError() - + def Execute(self): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/action/WxAbstractAction.py photofilmstrip-3.3.1/photofilmstrip/action/WxAbstractAction.py --- photofilmstrip-3.2.0/photofilmstrip/action/WxAbstractAction.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/action/WxAbstractAction.py 2017-12-03 22:12:24.000000000 +0000 @@ -25,10 +25,10 @@ class WxAbstractAction(IAction): - + def __init__(self): pass - + def GetBitmap(self, art=None): raise NotImplementedError() @@ -36,22 +36,22 @@ if ident is None: ident = wx.NewId() mitm = wx.MenuItem(menu, ident, self.GetName()) - + try: bmp = self.GetBitmap(wx.ART_MENU) except NotImplementedError: bmp = None - + if bmp: mitm.SetBitmap(bmp) - + menu.AppendItem(mitm) evtHandler.Bind(wx.EVT_MENU, self.__OnExecute, id=ident) return mitm - + def Bind(self, evtHandler, evt): evtHandler.Bind(evt, self.__OnExecute) - + def __OnExecute(self, event): self.Execute() event.Skip() diff -Nru photofilmstrip-3.2.0/photofilmstrip/action/WxAction.py photofilmstrip-3.3.1/photofilmstrip/action/WxAction.py --- photofilmstrip-3.2.0/photofilmstrip/action/WxAction.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/action/WxAction.py 2017-12-03 22:12:24.000000000 +0000 @@ -23,7 +23,7 @@ class WxAction(WxAbstractAction): - + def __init__(self, name, target, args=None, bmp=None): WxAbstractAction.__init__(self) self.name = name @@ -35,7 +35,7 @@ def GetName(self): return self.name - + def Execute(self): return self.target(*self.args) diff -Nru photofilmstrip-3.2.0/photofilmstrip/cli/Main.py photofilmstrip-3.3.1/photofilmstrip/cli/Main.py --- photofilmstrip-3.2.0/photofilmstrip/cli/Main.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/cli/Main.py 2017-12-03 22:12:24.000000000 +0000 @@ -27,7 +27,8 @@ from photofilmstrip.lib.util import Decode, CheckFile -from photofilmstrip.core.OutputProfile import OutputProfile, GetOutputProfiles, GetMPEGProfiles +from photofilmstrip.core.OutputProfile import ( + GetOutputProfiles, GetMPEGProfiles) from photofilmstrip.core.ProjectFile import ProjectFile from photofilmstrip.core.Renderer import RENDERERS from photofilmstrip.core.renderer.StreamRenderer import StreamRenderer @@ -76,8 +77,11 @@ print print u"%-20s: %s" % (_(u"processing project"), project) print u"%-20s: %s" % (_(u"using renderer"), rendererClass.GetName()) - print u"%-20s: %s" % (_(u"output format"), profile.GetName(withRes=True)) - print u"%-20s: %1.f (%s):" % (_(u"framerate"), profile.GetFramerate(), "PAL" if profile.GetVideoNorm() == OutputProfile.PAL else "NTSC") + print u"%-20s: %s" % (_(u"output format"), profile.GetName( + withRes=True)) + print u"%-20s: %1.f" % ( + _(u"framerate"), + profile.GetFrameRate().AsFloat()) print def Write(self, text): @@ -88,8 +92,10 @@ def OnHandleJobBegin(self, jobContext): pass + def OnHandleJobDone(self, jobContext): pass + def OnHandleJobUpdate(self, jobContext, fields=None): pass @@ -98,15 +104,17 @@ parser = OptionParser(prog="%s-cli" % Constants.APP_NAME.lower(), version="%%prog %s" % Constants.APP_VERSION_EX) - profiles = GetOutputProfiles() - profStr = ", ".join(["%d=%s" % (idx, prof.GetName()) for idx, prof in enumerate(profiles)]) + profiles = GetOutputProfiles() + GetMPEGProfiles() + profStr = ", ".join(["%d=%s" % ( + idx, + prof.GetName()) for idx, prof in enumerate(profiles)]) formatStr = ", ".join(["%d=%s" % (idx, rdr.GetName()) for idx, rdr in enumerate(RENDERERS)]) parser.add_option("-p", "--project", help=_(u"specifies the project file")) parser.add_option("-o", "--outputpath", help=_(u"The path where to save the output files. Use - for stdout."), metavar="PATH") parser.add_option("-t", "--profile", help=profStr + " [default: %default]", default=0, type="int") - parser.add_option("-n", "--videonorm", help="n=NTSC, p=PAL [default: %default]", default="p") + parser.add_option("-n", "--videonorm", help=_(u"Option videonorm is deprecated, use an appropriate profile!")) parser.add_option("-f", "--format", help=formatStr + " [default: %default]", default=4, type="int") parser.add_option("-a", "--draft", action="store_true", default=False, help=u"%s - %s" % (_(u"enable draft mode"), _(u"Activate this option to generate a preview of your PhotoFilmStrip. The rendering process will speed up dramatically, but results in lower quality."))) parser.add_option("-d", "--debug", action="store_true", default=False, help=u"enable debug logging") @@ -128,39 +136,28 @@ logging.error(_(u"no project file specified!")) return 2 - - if options.videonorm == "p": - videoNorm = OutputProfile.PAL - elif options.videonorm == "n": - videoNorm = OutputProfile.NTSC - else: + if options.videonorm: parser.print_help() - logging.error(_(u"invalid videonorm specified: %s"), options.videonorm) + logging.error(_(u"Option videonorm is deprecated, use an appropriate profile!")) return 4 - if options.format not in range(len(RENDERERS)): parser.print_help() logging.error(_(u"invalid format specified: %s"), options.format) return 5 rendererClass = RENDERERS[options.format] - - profile = GetMPEGProfiles().get(rendererClass.GetName()) - if profile is None: - if options.profile >= len(profiles): - parser.print_help() - logging.error(_(u"invalid profile specified: %s"), options.profile) - return 3 - profile = profiles[options.profile] - + if options.profile >= len(profiles): + parser.print_help() + logging.error(_(u"invalid profile specified: %s"), options.profile) + return 3 + profile = profiles[options.profile] prjFile = ProjectFile(filename=options.project) if not prjFile.Load(): logging.error(_(u"cannot load photofilmstrip")) return 6 - if options.outputpath: if options.outputpath == "-": outpath = "-" @@ -176,9 +173,8 @@ else: outpath = None - project = prjFile.GetProject() - ar = ActionRender(project, profile, videoNorm, rendererClass, False, outpath) + ar = ActionRender(project, profile, rendererClass, False, outpath) audioFile = project.GetAudioFile() if not CheckFile(audioFile): diff -Nru photofilmstrip-3.2.0/photofilmstrip/CLI.py photofilmstrip-3.3.1/photofilmstrip/CLI.py --- photofilmstrip-3.2.0/photofilmstrip/CLI.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/CLI.py 2017-12-03 22:12:24.000000000 +0000 @@ -25,10 +25,10 @@ class CliApp(AppMixin): - + def _GetLogFormat(self): return '\n%(levelname)s: %(message)s' - + def _OnStart(self): showHelp = False for helpOption in ("-h", "--help"): @@ -40,15 +40,14 @@ return main(showHelp) - def main(): cliApp = CliApp() - -# import hotshot + +# import hotshot # prof = hotshot.Profile("pfs.prof") # exitCode = prof.runcall(cliApp.Start) # prof.close() - + # import hotshot.stats # stats = hotshot.stats.load("pfs.prof") # stats.strip_dirs() diff -Nru photofilmstrip-3.2.0/photofilmstrip/Constants.py photofilmstrip-3.3.1/photofilmstrip/Constants.py --- photofilmstrip-3.2.0/photofilmstrip/Constants.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/Constants.py 2017-12-03 22:12:24.000000000 +0000 @@ -30,13 +30,12 @@ APP_DIR = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "..") APP_NAME = "PhotoFilmStrip" -APP_VERSION = "3.2.0" +APP_VERSION = "3.3.1" APP_VERSION_EX = "%s-%s" % (APP_VERSION, SCM_REV) APP_SLOGAN = "PhotoFilmStrip - Creates movies out of your pictures." APP_DESCRIPTION = """\ PhotoFilmStrip creates movies out of your pictures in just 3 steps. First select your photos, customize the motion path and render the video. There are several output possibilities for VCD, SVCD, DVD up to FULL-HD. """ APP_URL = "http://www.photofilmstrip.org" -DEVELOPERS = [u"Jens Göpfert", - u"Markus Wintermann"] +DEVELOPERS = [u"Jens Göpfert"] TRANSLATORS = ["Teza Lprod - http://lprod.org", "geogeo - http://www.geogeo.gr"] diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/Aspect.py photofilmstrip-3.3.1/photofilmstrip/core/Aspect.py --- photofilmstrip-3.2.0/photofilmstrip/core/Aspect.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/Aspect.py 2017-12-03 22:12:24.000000000 +0000 @@ -19,6 +19,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # + class Aspect(object): ASPECT_4_3 = "4:3" diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/AudioPlayer.py photofilmstrip-3.3.1/photofilmstrip/core/AudioPlayer.py --- photofilmstrip-3.2.0/photofilmstrip/core/AudioPlayer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/AudioPlayer.py 2017-12-03 22:12:24.000000000 +0000 @@ -19,5 +19,5 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -from GPlayer import GPlayer +from photofilmstrip.core.GPlayer import GPlayer AudioPlayer = GPlayer diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/BaseRenderer.py photofilmstrip-3.3.1/photofilmstrip/core/BaseRenderer.py --- photofilmstrip-3.2.0/photofilmstrip/core/BaseRenderer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/BaseRenderer.py 2017-12-03 22:12:24.000000000 +0000 @@ -61,16 +61,16 @@ @classmethod def SetProperty(cls, prop, value): if prop in cls.GetProperties(): - cls.PROP_VALUES[prop] = value + cls.PROP_VALUES[prop] = value # pylint: disable=no-member else: logging.getLogger(cls.GetName()).warning(_(u"Unknown property: %s"), prop) @classmethod def GetProperty(cls, prop): - return cls.PROP_VALUES.get(prop, cls.GetDefaultProperty(prop)) + return cls.PROP_VALUES.get(prop, cls.GetDefaultProperty(prop)) # pylint: disable=no-member @staticmethod - def GetDefaultProperty(prop): + def GetDefaultProperty(prop): # pylint: disable=unused-argument return _(u"") @classmethod @@ -122,9 +122,6 @@ def GetProfile(self): return self._profile - def EnsureFramerate(self): - return False - def GetFinalizeHandler(self): ''' :rtype: ImageDataFinalizeHandler diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/GPlayer.py photofilmstrip-3.3.1/photofilmstrip/core/GPlayer.py --- photofilmstrip-3.2.0/photofilmstrip/core/GPlayer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/GPlayer.py 2017-12-03 22:12:24.000000000 +0000 @@ -28,13 +28,13 @@ class GPlayer(object): - + def __init__(self, filename): self.__filename = filename self.__pipeline = None self.__length = None self.__gtkMainloop = None - + self.__Identify() def __Identify(self): @@ -67,18 +67,18 @@ hasResult, duration = pipeline.query_duration(Gst.Format.TIME) pipeline.set_state(Gst.State.NULL) - + self.__length = duration / Gst.MSECOND - + def GetFilename(self): return self.__filename def IsOk(self): return self.__length is not None - + def IsPlaying(self): return self.__pipeline is not None - + def Play(self): if self.__pipeline is None: pipeline = Gst.Pipeline() @@ -110,17 +110,17 @@ gtkMainloopThread = threading.Thread(name="gtkMainLoop", target=self._GtkMainloop) gtkMainloopThread.start() - + def Stop(self): self.Close() - + def Close(self): self.__pipeline.send_event(Gst.Event.new_eos()) - + def GetLength(self): return self.__length - def _GstOnMessage(self, bus, msg): + def _GstOnMessage(self, bus, msg): # pylint: disable=unused-argument logging.debug('_GstOnMessage: %s', msg.type) if msg.type == Gst.MessageType.ERROR: @@ -135,7 +135,7 @@ self.__pipeline = None self.__gtkMainloop = None - def _GstPadAdded(self, decodebin, pad, audioConv): + def _GstPadAdded(self, decodebin, pad, audioConv): # pylint: disable=unused-argument caps = pad.get_current_caps() compatible_pad = audioConv.get_compatible_pad(pad, caps) pad.link(compatible_pad) diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/OutputProfile.py photofilmstrip-3.3.1/photofilmstrip/core/OutputProfile.py --- photofilmstrip-3.2.0/photofilmstrip/core/OutputProfile.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/OutputProfile.py 2017-12-03 22:12:24.000000000 +0000 @@ -22,81 +22,276 @@ from photofilmstrip.core.Aspect import Aspect +class FrameRate(object): + + def __init__(self, numValue, strValue): + self.num = numValue + self.str = strValue + + def __str__(self, *args, **kwargs): + return u"%.2f fps" % self.num + + def AsFloat(self): + return self.num + + def AsStr(self): + return self.str + + class OutputProfile(object): PAL = 1 NTSC = 2 - def __init__(self, name, bitrate, resPal, resNtsc=None): + def __init__(self, name, resolution, frameRate, bitrate, videoNorm=None): self.__name = name - self.__resPal = resPal - if resNtsc is None: - self.__resNtsc = resPal - else: - self.__resNtsc = resNtsc + self.__resolution = resolution + self.__frameRate = frameRate self.__bitrate = bitrate - - self.__videoNorm = OutputProfile.PAL + self.__videoNorm = videoNorm + self.__friendlyName = None def GetName(self, withRes=False): + if self.__videoNorm: + simple = self.__name + else: + simple = "{0}@{1}".format(self.__name, self.__frameRate) if withRes: - return "%s (%dx%d)" % (self.__name, self.GetResolution()[0], self.GetResolution()[1]) + return "%s (%dx%d)" % (simple, self.GetResolution()[0], self.GetResolution()[1]) else: - return self.__name + return simple def GetBitrate(self): return self.__bitrate def GetResolution(self): - if self.__videoNorm == OutputProfile.PAL: - return self.__resPal - else: - return self.__resNtsc + return self.__resolution - def GetFramerate(self): - if self.__videoNorm == OutputProfile.PAL: - return 25.0 - else: - return 30000.0 / 1001.0 + def GetFrameRate(self): + return self.__frameRate - def SetVideoNorm(self, norm): - if norm not in [OutputProfile.PAL, OutputProfile.NTSC]: - raise RuntimeError("videonorm must be one of PAL or NTSC") - self.__videoNorm = norm def GetVideoNorm(self): return self.__videoNorm def IsMPEGProfile(self): - return self.GetName() in ("VCD", "SVCD", "DVD") + for mpegProf in ("VCD", "SVCD", "DVD"): + if self.__name.startswith(mpegProf): + return True + return False + + def SetFriendlyName(self, value): + self.__friendlyName = value + + def GetFriendlyName(self): + return self.__friendlyName + + +FPS15 = FrameRate(15.0, "15/1") +FPS23996 = FrameRate(24000.0 / 1001.0, "24000/1001") +FPS24 = FrameRate(24.0, "24/1") +FPS25 = FrameRate(25.0, "25/1") +FPS29997 = FrameRate(30000.0 / 1001.0, "30000/1001") +FPS30 = FrameRate(30.0, "30/1") +FPS50 = FrameRate(50.0, "50/1") +FPS59994 = FrameRate(60000.0 / 1001.0, "60000/1001") +FPS60 = FrameRate(60.0, "60/1") def __CreateMPEGProfiles(): - vcd = OutputProfile("VCD", 1150, (352, 288), (352, 240)) - svcd = OutputProfile("SVCD", 2500, (480, 576), (480, 480)) - dvd = OutputProfile("DVD", 8000, (720, 576), (720, 480)) - return [vcd, svcd, dvd] + vcd_pal = OutputProfile("VCD-PAL", (352, 288), FPS25, 1150, + OutputProfile.PAL) + vcd_ntsc = OutputProfile("VCD-NTSC", (352, 240), FPS29997, 1150, + OutputProfile.NTSC) + + svcd_pal = OutputProfile("SVCD-PAL", (480, 576), FPS25, 2500, + OutputProfile.PAL) + svcd_ntsc = OutputProfile("SVCD-NTSC", (480, 576), FPS29997, 2500, + OutputProfile.NTSC) + + dvd_pal = OutputProfile("DVD-PAL", (720, 576), FPS25, 8000, + OutputProfile.PAL) + dvd_ntsc = OutputProfile("DVD-NTSC", (720, 480), FPS29997, 8000, + OutputProfile.NTSC) + result = [vcd_pal, vcd_ntsc, svcd_pal, svcd_ntsc, dvd_pal, dvd_ntsc] + for prof in result: + prof.SetFriendlyName(prof.GetName()) + return result + def __Create16_9Profiles(): - medium = OutputProfile("Medium", 4000, (640, 360)) - hd = OutputProfile("HD", 6000, (1280, 720)) - fullhd = OutputProfile("FULL-HD", 8000, (1920, 1080)) - uhd = OutputProfile("UHD", 24000, (3840, 2160)) + profs = [] + + # 360p + for fps in [FPS23996, FPS25]: + prof = OutputProfile("360p", (640, 360), fps, 1000) + if fps is FPS25: + prof.SetFriendlyName("Medium") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS59994, FPS60]: + prof = OutputProfile("360p", (640, 360), fps, 1500) + profs.append(prof) + + # 480p + for fps in [FPS24, FPS30]: + prof = OutputProfile("480p", (854, 480), fps, 2500) + profs.append(prof) + for fps in [FPS50, FPS60]: + prof = OutputProfile("480p", (854, 480), fps, 4000) + profs.append(prof) + + # 720p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("HD 720p", (1280, 720), fps, 5000) + if fps is FPS25: + prof.SetFriendlyName("HD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS59994, FPS60]: + prof = OutputProfile("HD 720p", (1280, 720), fps, 7500) + profs.append(prof) + + # 1080p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("HD 1080p", (1920, 1080), fps, 8000) + if fps is FPS25: + prof.SetFriendlyName("FULL-HD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS60]: + prof = OutputProfile("HD 1080p", (1920, 1080), fps, 12000) + profs.append(prof) + + # 2160p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("UHD-1 2160p", (3840, 2160), fps, 25000) + if fps is FPS25: + prof.SetFriendlyName("UHD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS60]: + prof = OutputProfile("UHD-1 2160p", (3840, 2160), fps, 50000) + profs.append(prof) + + # 4320p + for fps in [FPS25, FPS30, FPS50, FPS60]: + prof = OutputProfile("UHD-2 4320p", (7680, 4320), fps, 60000) + profs.append(prof) + + return profs - return [medium, hd, fullhd, uhd] def __Create4_3Profiles(): - medium = OutputProfile("Medium", 4000, (640, 480)) - hd = OutputProfile("HD", 6000, (960, 720)) - fullhd = OutputProfile("FULL-HD", 8000, (1440, 1080)) + profs = [] + + # 360p + for fps in [FPS23996, FPS25]: + prof = OutputProfile("360p", (480, 360), fps, 1000) + if fps is FPS25: + prof.SetFriendlyName("Medium") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS59994, FPS60]: + prof = OutputProfile("360p", (480, 360), fps, 1500) + profs.append(prof) + + # 480p + for fps in [FPS24, FPS30]: + prof = OutputProfile("480p", (640, 480), fps, 2500) + profs.append(prof) + for fps in [FPS50, FPS60]: + prof = OutputProfile("480p", (640, 480), fps, 4000) + profs.append(prof) + + # 720p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("HD 720p", (960, 720), fps, 5000) + if fps is FPS25: + prof.SetFriendlyName("HD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS59994, FPS60]: + prof = OutputProfile("HD 720p", (960, 720), fps, 7500) + profs.append(prof) + + # 1080p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("HD 1080p", (1440, 1080), fps, 8000) + if fps is FPS25: + prof.SetFriendlyName("FULL-HD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS60]: + prof = OutputProfile("HD 1080p", (1440, 1080), fps, 12000) + profs.append(prof) + + # 2160p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("UHD-1 2160p", (2880, 2160), fps, 25000) + if fps is FPS25: + prof.SetFriendlyName("UHD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS60]: + prof = OutputProfile("UHD-1 2160p", (2880, 2160), fps, 50000) + profs.append(prof) + + # 4320p + for fps in [FPS25, FPS30, FPS50, FPS60]: + prof = OutputProfile("UHD-2 4320p", (5760, 4320), fps, 60000) + profs.append(prof) + return profs - return [medium, hd, fullhd] def __Create3_2Profiles(): - medium = OutputProfile("Medium", 4000, (720, 480)) - hd = OutputProfile("HD", 6000, (1080, 720)) - fullhd = OutputProfile("FULL-HD", 8000, (1620, 1080)) + profs = [] - return [medium, hd, fullhd] + # 360p + for fps in [FPS23996, FPS25]: + prof = OutputProfile("360p", (540, 360), fps, 1000) + if fps is FPS25: + prof.SetFriendlyName("Medium") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS59994, FPS60]: + prof = OutputProfile("360p", (540, 360), fps, 1500) + profs.append(prof) + + # 480p + for fps in [FPS24, FPS30]: + prof = OutputProfile("480p", (720, 480), fps, 2500) + profs.append(prof) + for fps in [FPS50, FPS60]: + prof = OutputProfile("480p", (720, 480), fps, 4000) + profs.append(prof) + + # 720p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("HD 720p", (1080, 720), fps, 5000) + if fps is FPS25: + prof.SetFriendlyName("HD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS59994, FPS60]: + prof = OutputProfile("HD 720p", (1080, 720), fps, 7500) + profs.append(prof) + + # 1080p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("HD 1080p", (1620, 1080), fps, 8000) + if fps is FPS25: + prof.SetFriendlyName("FULL-HD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS60]: + prof = OutputProfile("HD 1080p", (1620, 1080), fps, 12000) + profs.append(prof) + + # 2160p + for fps in [FPS23996, FPS24, FPS25]: + prof = OutputProfile("UHD-1 2160p", (3240, 2160), fps, 25000) + if fps is FPS25: + prof.SetFriendlyName("UHD") + profs.append(prof) + for fps in [FPS29997, FPS30, FPS50, FPS60]: + prof = OutputProfile("UHD-1 2160p", (3240, 2160), fps, 50000) + profs.append(prof) + + # 4320p + for fps in [FPS25, FPS30, FPS50, FPS60]: + prof = OutputProfile("UHD-2 4320p", (6480, 4320), fps, 60000) + profs.append(prof) + + return profs def GetOutputProfiles(aspect=Aspect.ASPECT_16_9): @@ -109,9 +304,4 @@ def GetMPEGProfiles(): - mpgProfiles = __CreateMPEGProfiles() - result = {} - for prof in mpgProfiles: - result[prof.GetName()] = prof - result[prof.GetName() + " (MPG)"] = prof - return result + return __CreateMPEGProfiles() diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/Picture.py photofilmstrip-3.3.1/photofilmstrip/core/Picture.py --- photofilmstrip-3.2.0/photofilmstrip/core/Picture.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/Picture.py 2017-12-03 22:12:24.000000000 +0000 @@ -25,37 +25,37 @@ class Picture(Observable): - - EFFECT_NONE = 0 + + EFFECT_NONE = 0 EFFECT_BLACK_WHITE = 1 - EFFECT_SEPIA = 2 - + EFFECT_SEPIA = 2 + TRANS_NONE = 0 TRANS_FADE = 1 TRANS_ROLL = 2 - - MOVE_LINEAR = 0 - MOVE_ACCEL = 1 + + MOVE_LINEAR = 0 + MOVE_ACCEL = 1 MOVE_DELAYED = 2 - + def __init__(self, filename): Observable.__init__(self) - self._filename = filename - self._startRect = (0, 0, 1280, 720) + self._filename = filename + self._startRect = (0, 0, 1280, 720) self._targetRect = (0, 0, 1280, 720) - self._isDummy = False - + self._isDummy = False + self._duration = 7.0 self._movement = Picture.MOVE_ACCEL self._rotation = 0 - self._comment = u"" - self._effect = Picture.EFFECT_NONE - self._width = -1 - self._height = -1 - - self._trans = Picture.TRANS_FADE + self._comment = u"" + self._effect = Picture.EFFECT_NONE + self._width = -1 + self._height = -1 + + self._trans = Picture.TRANS_FADE self._transDur = 1.0 - + def Copy(self): clone = Picture(self._filename) clone.SetStartRect(self._startRect[:]) @@ -70,104 +70,116 @@ clone.SetTransition(self._trans) clone.SetTransitionDuration(self._transDur) return clone - + def GetFilename(self): return self._filename - + def SetStartRect(self, rect): if rect == self._startRect or self._isDummy: return self._startRect = rect self.Notify("start") + def GetStartRect(self): return self._startRect - + def SetTargetRect(self, rect): if rect == self._targetRect or self._isDummy: return self._targetRect = rect self.Notify("target") + def GetTargetRect(self): return self._targetRect - + def SetDummy(self, isDummy): self._isDummy = isDummy + def IsDummy(self): return self._isDummy - + def SetDuration(self, duration): if duration == self._duration: return self._duration = duration self.Notify("duration") + def GetDuration(self): return self._duration - + def SetMovement(self, movement): if movement == self._movement: return self._movement = movement self.Notify("movement") + def GetMovement(self): return self._movement - + def SetComment(self, comment): if comment == self._comment: return self._comment = comment self.Notify('comment') + def GetComment(self): return self._comment - + def SetEffect(self, effect): if effect == self._effect: return self._effect = effect self.Notify('effect') self.Notify("bitmap") + def GetEffect(self): return self._effect def SetRotation(self, rotation): - for i in range(abs(rotation)): + for __ in range(abs(rotation)): self.__Rotate(rotation > 0) self.Notify("rotation") + def GetRotation(self): return self._rotation - + def SetWidth(self, width): self._width = width + def GetWidth(self): if self._width == -1: logging.debug("width not set yet!") return self._width - + def SetHeight(self, height): self._height = height + def GetHeight(self): if self._height == -1: logging.debug("height not set yet!") return self._height - + def SetTransition(self, transition): if transition == self._trans: return self._trans = transition self.Notify('transition') - self.Notify('duration') # if set to no transition + self.Notify('duration') # if set to no transition + def GetTransition(self): return self._trans - + def SetTransitionDuration(self, transDur): if transDur == self._transDur: return self._transDur = transDur self.Notify('duration') + def GetTransitionDuration(self, rawValue=False): if not rawValue and self._trans == Picture.TRANS_NONE: return 0.0 return self._transDur - + def __Rotate(self, clockwise=True): if clockwise: self._rotation += 1 @@ -179,13 +191,13 @@ self._rotation = 0 self._width, self._height = self._height, self._width - + def Rotate(self, clockwise=True): self.__Rotate(clockwise) self.Notify("bitmap") - + def GetKey(self): - key = "%s:%s:%s" % (self.GetFilename(), - self.GetRotation(), + key = "%s:%s:%s" % (self.GetFilename(), + self.GetRotation(), self.GetEffect()) return key diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/PILBackend.py photofilmstrip-3.3.1/photofilmstrip/core/PILBackend.py --- photofilmstrip-3.2.0/photofilmstrip/core/PILBackend.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/PILBackend.py 2017-12-03 22:12:24.000000000 +0000 @@ -33,22 +33,24 @@ fd.seek(0) return fd + def ImageFromBuffer(size, buffr): pilImg = Image.frombuffer("RGB", size, buffr, 'raw', "RGB", 0, 1) return pilImg + def RotateExif(pilImg): exifOrient = 274 - rotation = 0 + rotation = 0 try: - exif = pilImg._getexif() + exif = pilImg._getexif() # pylint: disable=protected-access if isinstance(exif, dict) and exif.has_key(exifOrient): rotation = exif[exifOrient] except AttributeError: pass except Exception, err: logging.debug("PILBackend.RotateExif(): %s", err, exc_info=1) - + if rotation == 2: # flip horizontal return pilImg.transpose(Image.FLIP_LEFT_RIGHT) @@ -72,9 +74,10 @@ elif rotation == 8: # rotate 270 return pilImg.rotate(-270, expand=1) - + return pilImg - + + def CropAndResize(pilImg, rect, size, draft=False): if draft: filtr = Image.NEAREST @@ -86,7 +89,8 @@ 0, rect[3] / float(size[1]), rect[1]], filtr) return img - + + def Transition(kind, pilImg1, pilImg2, percentage): if kind == Picture.TRANS_FADE: img = Image.blend(pilImg1, pilImg2, percentage) @@ -96,10 +100,10 @@ part1 = pilImg2.crop((0, 0, delta, ysize)) part2 = pilImg1.crop((delta, 0, xsize, ysize)) image = pilImg2.copy() - image.paste(part2, (0, 0, xsize-delta, ysize)) - image.paste(part1, (xsize-delta, 0, xsize, ysize)) + image.paste(part2, (0, 0, xsize - delta, ysize)) + image.paste(part1, (xsize - delta, 0, xsize, ysize)) img = image - + return img @@ -115,8 +119,8 @@ draw.text((x, y), message, fill=(0, 0, 0)) sz = width / 2 - draw.ellipse(((width - sz) / 2, (height - sz) / 2, - (width + sz) / 2, (height + sz) / 2), + draw.ellipse(((width - sz) / 2, (height - sz) / 2, + (width + sz) / 2, (height + sz) / 2), fill=(255, 0, 0)) sz = width / 7 @@ -124,9 +128,10 @@ draw.line((width / 2 + sz, height / 2 - sz, width / 2 - sz, height / 2 + sz), fill=(255, 255, 255), width=20) del draw - + return img + def __GetImage(picture): try: img = Image.open(picture.GetFilename()) @@ -141,7 +146,8 @@ img = __CreateDummyImage(str(err)) picture.SetDummy(True) return img - + + def __ProcessImage(img, picture): if not picture.IsDummy(): img = RotateExif(img) @@ -153,12 +159,13 @@ img = img.convert("L") elif picture.GetEffect() == picture.EFFECT_SEPIA: + def make_linear_ramp(white): # putpalette expects [r,g,b,r,g,b,...] ramp = [] r, g, b = white for i in range(255): - ramp.extend((r*i/255, g*i/255, b*i/255)) + ramp.extend((r * i / 255, g * i / 255, b * i / 255)) return ramp # make sepia ramp (tweak color as necessary) @@ -167,7 +174,8 @@ img.putpalette(sepia) return img.convert("RGB") - + + def GetImage(picture): pilImg = __GetImage(picture) pilImg = __ProcessImage(pilImg, picture) @@ -175,18 +183,19 @@ picture.SetHeight(pilImg.size[1]) return pilImg + def GetExifRotation(pilImg): exifOrient = 274 - rotation = 0 + rotation = 0 try: - exif = pilImg._getexif() + exif = pilImg._getexif() # pylint: disable=protected-access if isinstance(exif, dict) and exif.has_key(exifOrient): rotation = exif[exifOrient] except AttributeError: pass except Exception, err: logging.debug("PILBackend.RotateExif(): %s", err, exc_info=1) - + if rotation == 3: # rotate 180 return 2 @@ -205,6 +214,7 @@ else: return 0 + def GetImageSize(filename): pilImg = Image.open(filename) width, height = pilImg.size @@ -214,6 +224,7 @@ rotation -= 1 return width, height + def GetThumbnail(picture, width=None, height=None): img = __GetImage(picture) @@ -227,17 +238,17 @@ elif height is not None: thumbHeight = height thumbWidth = int(round(thumbHeight * aspect)) - + # prescale image to speed up processing img.thumbnail((max(thumbWidth, thumbHeight), max(thumbWidth, thumbHeight)), Image.NEAREST) img = __ProcessImage(img, picture) - + # make the real thumbnail img.thumbnail((thumbWidth, thumbHeight), Image.NEAREST) - + # newImg = Image.new("RGB", (thumbWidth, thumbHeight), 0) -# newImg.paste(img, (abs(thumbWidth - img.size[0]) / 2, +# newImg.paste(img, (abs(thumbWidth - img.size[0]) / 2, # abs(thumbHeight - img.size[1]) / 2)) # img = newImg - + return img diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/ProjectFile.py photofilmstrip-3.3.1/photofilmstrip/core/ProjectFile.py --- photofilmstrip-3.2.0/photofilmstrip/core/ProjectFile.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/ProjectFile.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,23 @@ # encoding: UTF-8 +# +# PhotoFilmStrip - Creates movies out of your pictures. +# +# Copyright (C) 2017 Jens Goepfert +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# import logging import os @@ -11,10 +30,9 @@ from photofilmstrip.core.Aspect import Aspect from photofilmstrip.core.Picture import Picture -from photofilmstrip.gui.util.ImageCache import ImageCache # FIXME: no gui import here +from photofilmstrip.gui.util.ImageCache import ImageCache # FIXME: no gui import here from photofilmstrip.core.Project import Project - SCHEMA_REV = 4 """ 4: @@ -27,7 +45,6 @@ - initial """ - SCHEMA = """ CREATE TABLE `picture` ( picture_id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -68,16 +85,18 @@ ); """ + class ProjectFile(object): + def __init__(self, project=None, filename=None): self._project = project self._filename = filename # project.GetFilename() - + self.__conn = None self.__altPaths = {} self.__fileRev = 1 - + def __del__(self): if self.__conn is not None: logging.debug("database not closed properly: %s", self._filename) @@ -85,7 +104,7 @@ def GetProject(self): return self._project - + def __Connect(self): if self.__conn is None: self.__conn = sqlite3.connect(Encode(self._filename), @@ -94,13 +113,13 @@ try: # at the beginning we had no property table - cur.execute("SELECT value FROM `property` WHERE name=?", ("rev", )) + cur.execute("SELECT value FROM `property` WHERE name=?", ("rev",)) result = cur.fetchone() if result: self.__fileRev = int(result[0]) except sqlite3.DatabaseError: pass - + def __Close(self, commit=False): if self.__conn is None: raise RuntimeError("not connected") @@ -108,14 +127,14 @@ self.__conn.commit() self.__conn.close() self.__conn = None - + def __GetCursor(self): if self.__conn is None: raise RuntimeError("not connected") cur = self.__conn.cursor() cur.row_factory = sqlite3.Row return cur - + def GetPicCount(self): self.IsOk() self.__Connect() @@ -129,11 +148,11 @@ finally: self.__Close() return -1 - + def GetPreviewThumb(self): if not self.Load(): return None - + img = None pics = self._project.GetPictures() imgCount = len(pics) @@ -141,11 +160,11 @@ picIdx = random.randint(0, imgCount - 1) pic = pics[picIdx] if os.path.exists(pic.GetFilename()): - img = PILBackend.GetThumbnail(pic, 64, 64) + img = PILBackend.GetThumbnail(pic, width=136, height=70) if pic.IsDummy(): img = None return img - + def IsOk(self): self.__Connect() try: @@ -153,15 +172,9 @@ cur = self.__GetCursor() cur.execute("SELECT * FROM `picture`") return True - except sqlite3.DatabaseError: - return False - except sqlite3.DatabaseError, err: - logging.debug("IsOk(%s): %s", self._filename, err) - return False except BaseException, err: logging.debug("IsOk(%s): %s", self._filename, err) return False - return False finally: self.__Close() @@ -173,7 +186,7 @@ fd.close() else: picData = None - + query = "INSERT INTO `picture` (" \ "filename, width, height, " \ "start_left, start_top, start_width, start_height, " \ @@ -184,28 +197,28 @@ "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?" \ ");" - values = (pic.GetFilename(), pic.GetWidth(), pic.GetHeight(), + values = (pic.GetFilename(), pic.GetWidth(), pic.GetHeight(), pic.GetStartRect()[0], pic.GetStartRect()[1], pic.GetStartRect()[2], pic.GetStartRect()[3], pic.GetTargetRect()[0], pic.GetTargetRect()[1], pic.GetTargetRect()[2], pic.GetTargetRect()[3], pic.GetRotation(), pic.GetDuration(), pic.GetMovement(), - pic.GetComment(), pic.GetEffect(), - pic.GetTransition(), pic.GetTransitionDuration(rawValue=True), + pic.GetComment(), pic.GetEffect(), + pic.GetTransition(), pic.GetTransitionDuration(rawValue=True), picData) return query, values - + def __ThumbToQuery(self, picId, pic): pilThumb = PILBackend.GetThumbnail(pic, height=120) thumbWidth, thumbHeight = pilThumb.size thumbData = buffer(pilThumb.tobytes()) - + query = "INSERT INTO `thumbnail` (" \ "picture_id, width, height, data" \ ") VALUES (" \ "?, ?, ?, ?" \ ");" values = (picId, thumbWidth, thumbHeight, thumbData) - return query, values - + return query, values + def _StepProgress(self, msg): pass @@ -215,20 +228,20 @@ os.makedirs(dirname) if os.path.exists(self._filename): os.remove(self._filename) - + self.__Connect() cur = self.__GetCursor() - cur.executescript(SCHEMA) + cur.executescript(SCHEMA) cur = self.__GetCursor() for pic in self._project.GetPictures(): self._StepProgress(_(u"Saving '%s' ...") % pic.GetFilename()) query, values = self.__PicToQuery(pic, includePics) cur.execute(query, values) - + query, values = self.__ThumbToQuery(cur.lastrowid, pic) cur.execute(query, values) - + query = "INSERT INTO `property` (name, value) VALUES (?, ?);" for name, value in [('rev', SCHEMA_REV), ('aspect', self._project.GetAspect()), @@ -236,12 +249,12 @@ ('timelapse', int(self._project.GetTimelapse()))]: if value is not None: cur.execute(query, (name, value)) - + for audioFile in self._project.GetAudioFiles(): cur.execute(query, ('audiofile', audioFile)) self.__Close(commit=True) - + self._project.SetFilename(self._filename) # load methods @@ -252,26 +265,26 @@ filename = self._filename if not os.path.isfile(filename): return False - + self.__Connect() cur = self.__GetCursor() fileRev = 1 try: # at the beginning we had no property table - cur.execute("SELECT value FROM `property` WHERE name=?", ("rev", )) + cur.execute("SELECT value FROM `property` WHERE name=?", ("rev",)) result = cur.fetchone() if result: fileRev = int(result[0]) except sqlite3.DatabaseError: pass - + try: cur.execute("SELECT * FROM `picture`") except sqlite3.DatabaseError: self.__Close() return False - + picList = [] for row in cur: imgFile = row["filename"] @@ -283,24 +296,28 @@ if not (os.path.exists(imgPath) and os.path.isfile(imgFile)): if not self.__altPaths.has_key(imgPath): self._SelectAlternatePath(imgPath) - - imgFile = os.path.join(self.__altPaths.get(imgPath, imgPath), + + imgFile = os.path.join(self.__altPaths.get(imgPath, imgPath), os.path.basename(imgFile)) - + pic = Picture(imgFile) else: if importPath is None: importPath = os.path.dirname(filename) - + tmpImg = os.path.join(importPath, os.path.basename(imgFile)) if os.path.isfile(tmpImg): - logging.debug('file exists: %s', tmpImg) + logging.debug('overwrite existing file: %s', tmpImg) + + if not os.path.isdir(importPath): + os.makedirs(importPath) + fd = open(tmpImg, 'wb') fd.write(picData) fd.close() pic = Picture(tmpImg) - + pic.SetWidth(self.__LoadSafe(row, 'width', -1)) pic.SetHeight(self.__LoadSafe(row, 'height', -1)) rect = (row["start_left"], row["start_top"], row["start_width"], row["start_height"]) @@ -315,9 +332,9 @@ pic.SetTransition(self.__LoadSafe(row, 'transition', Picture.TRANS_FADE)) pic.SetTransitionDuration(self.__LoadSafe(row, 'transition_duration', 1.0)) - + self.__LoadThumbnail(pic, row["picture_id"]) - + picList.append(pic) project = Project(self._filename) @@ -327,23 +344,23 @@ project.SetDuration(self.__LoadProperty(cur, "duration", float)) project.SetAspect(self.__LoadProperty(cur, "aspect", unicode, Aspect.ASPECT_16_9)) project.SetTimelapse(self.__LoadProperty(cur, "timelapse", int, False)) - + self.__Close() - + self._project = project return True - + def __LoadThumbnail(self, pic, picId): ImageCache().RegisterPicture(pic) return thumbNail = None if self.__fileRev >= 3: cur = self.__GetCursor() - cur.execute("SELECT * FROM `thumbnail` WHERE picture_id=?", (picId, )) + cur.execute("SELECT * FROM `thumbnail` WHERE picture_id=?", (picId,)) row = cur.fetchone() if row: thumbWidth = row["width"] - thumbHeight = row["height"] + thumbHeight = row["height"] thumbData = row["data"] thumbNail = PILBackend.ImageFromBuffer((thumbWidth, thumbHeight), thumbData) if thumbNail is None: @@ -355,20 +372,20 @@ return row[colName] except IndexError: return default - + def __LoadProperty(self, cur, propName, typ, default=None): - cur.execute("SELECT value FROM `property` WHERE name=?", (propName, )) + cur.execute("SELECT value FROM `property` WHERE name=?", (propName,)) result = cur.fetchone() if result: return typ(result[0]) else: return default - + def __LoadProperties(self, cur, propName, typ): cur.execute("SELECT value " "FROM `property` " "WHERE name=? " - "ORDER BY property_id ASC", (propName, )) + "ORDER BY property_id ASC", (propName,)) result = [] for row in cur: if row: diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/Project.py photofilmstrip-3.3.1/photofilmstrip/core/Project.py --- photofilmstrip-3.2.0/photofilmstrip/core/Project.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/Project.py 2017-12-03 22:12:24.000000000 +0000 @@ -26,41 +26,43 @@ class Project(Observable): - + def __init__(self, filename=None): Observable.__init__(self) self.__pictures = [] self.__filename = filename - + self.__audioFiles = [] self.__aspect = Aspect.ASPECT_16_9 self.__duration = None self.__timelapse = False - + def GetName(self): if self.__filename is None: return u"" fname = os.path.splitext(self.__filename)[0] return os.path.basename(fname) - + def GetFilename(self): return self.__filename + def SetFilename(self, filename): self.__filename = filename - + def GetPictures(self): return self.__pictures - + def SetPictures(self, picList): oldDuration = self.GetDuration() self.__pictures = picList self.Notify("pictures") if self.GetDuration() != oldDuration: self.Notify("duration") - + def SetAudioFiles(self, audioFiles): self.__audioFiles = audioFiles self.Notify("audiofile") + def GetAudioFile(self): ''' compatibility @@ -69,22 +71,25 @@ return self.__audioFiles[0] else: return None + def GetAudioFiles(self): return self.__audioFiles - + def SetAspect(self, aspect): if aspect == self.__aspect: return self.__aspect = aspect self.Notify("aspect") + def GetAspect(self): return self.__aspect - + def SetDuration(self, duration): if duration == self.__duration: return self.__duration = duration self.Notify("duration") + def GetDuration(self, calc=True): if calc: totalTime = 0 @@ -99,5 +104,6 @@ return self.__timelapse = value self.Notify("timelapse") + def GetTimelapse(self): return self.__timelapse diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/RenderEngine.py photofilmstrip-3.3.1/photofilmstrip/core/RenderEngine.py --- photofilmstrip-3.2.0/photofilmstrip/core/RenderEngine.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/RenderEngine.py 2017-12-03 22:12:24.000000000 +0000 @@ -71,7 +71,7 @@ """ returns the number of pictures """ - fr = self._profile.GetFramerate() + fr = self._profile.GetFrameRate().AsFloat() return int(round(pic.GetDuration() * \ fr * \ self.__picCountFactor)) @@ -80,7 +80,7 @@ """ returns the number of pictures needed for the transition """ - fr = self._profile.GetFramerate() + fr = self._profile.GetFrameRate().AsFloat() return int(round(pic.GetTransitionDuration() * \ fr * \ self.__picCountFactor)) @@ -111,7 +111,7 @@ pics) self._tasks.append(taskSub) - pathRectsBefore = None + pathRectsBefore = [] picBefore = None transCountBefore = 0 diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/renderer/CairoRenderer.py photofilmstrip-3.3.1/photofilmstrip/core/renderer/CairoRenderer.py --- photofilmstrip-3.2.0/photofilmstrip/core/renderer/CairoRenderer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/renderer/CairoRenderer.py 2017-12-03 22:12:24.000000000 +0000 @@ -22,11 +22,9 @@ import array import time - try: import wx import cairo - import wx.lib.wxcairo except (ImportError, RuntimeError): cairo = None @@ -35,22 +33,22 @@ class CairoRenderer(BaseRenderer): - + def __init__(self): BaseRenderer.__init__(self) self._ctx = None self._mainClock = Clock() self._framerate = None - - self._screen = wx.Frame(wx.GetApp().GetTopWindow(), + + self._screen = wx.Frame(wx.GetApp().GetTopWindow(), style=wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER) self._screen.Bind(wx.EVT_PAINT, self.OnPaint) self._screen.Show() - + @staticmethod def GetName(): return _(u"Preview") - + @staticmethod def CheckDependencies(msgList): BaseRenderer.CheckDependencies(msgList) @@ -63,28 +61,21 @@ ''' return PilToCairoFinalizeHandler() - def _GetFrameRate(self): - if self.GetProfile().GetVideoNorm() == OutputProfile.PAL: - framerate = 25.0 - else: - framerate = 30000.0 / 1001.0 - return framerate - def ToSink(self, data): self._ctx = data self._mainClock.tick(self._framerate) wx.CallAfter(self._screen.Refresh) - + def ProcessAbort(self): wx.CallAfter(self._screen.Destroy) def Prepare(self): self._screen.SetClientSizeWH(*self.GetProfile().GetResolution()) - - self._framerate = self._GetFrameRate() + + self._framerate = self.GetProfile().GetFrameRate().AsFloat() self._mainClock.reset() - + def OnPaint(self, event): dc = wx.BufferedPaintDC(self._screen) # dc.SetBackground(wx.Brush('black')) @@ -94,24 +85,14 @@ w = self._ctx.get_width() h = self._ctx.get_height() data = self._ctx.get_data() - wxbmp = wx.BitmapFromBufferRGBA(w, h, data) + wxbmp = wx.BitmapFromBufferRGBA(w, h, data) dc.DrawBitmap(wxbmp, 0, 0) -# if self._ctx: -# ctx = wx.lib.wxcairo.ContextFromDC(dc) -# ctx.set_source_surface(self._ctx, 0, 0) -# ctx.paint() event.Skip() - + def Finalize(self): wx.CallAfter(self._screen.Destroy) - - def EnsureFramerate(self): - if get_fps(self._mainClock, self._framerate): - return True - else: - return False - + class PilToCairoFinalizeHandler(FinalizeHandler): @@ -120,37 +101,39 @@ def ProcessFinalize(self, pilImg): pilImg = pilImg.copy() - w, h = pilImg.size + w, h = pilImg.size data = pilImg.convert('RGBA').tobytes() buff = array.array('B', data) - cairoImage = cairo.ImageSurface.create_for_data(buff, cairo.FORMAT_ARGB32, w, h) + cairoImage = cairo.ImageSurface.create_for_data(# pylint: disable=no-member + buff, cairo.FORMAT_ARGB32, w, h) # pylint: disable=no-member # cairoImage = cairo.ImageSurface.create_for_data(buff, cairo.FORMAT_RGB24, w, h) return cairoImage class Clock(object): + def __init__(self): self.fps = 0.0 self.fps_count = 0 self.start = 0 - + def reset(self): self.start = time.time() - + def tick(self, framerate): nowtime = time.time() self.fps_count += 1 - + timepassed = nowtime - self.start - + self.fps = 1.0 / (timepassed / self.fps_count) - + endtime = (1.0 / framerate) * self.fps_count delay = endtime - timepassed if delay < 0: delay = 0 time.sleep(delay) - + def get_fps(self): return self.fps diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/renderer/GStreamerRenderer.py photofilmstrip-3.3.1/photofilmstrip/core/renderer/GStreamerRenderer.py --- photofilmstrip-3.2.0/photofilmstrip/core/renderer/GStreamerRenderer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/renderer/GStreamerRenderer.py 2017-12-03 22:12:24.000000000 +0000 @@ -53,6 +53,7 @@ self.gtkMainloop = None self.textoverlay = None self.srtParse = None + self.concat = None self.ptsOffset = 0 self.ptsLast = None @@ -103,6 +104,7 @@ self.gtkMainloop = None self.textoverlay = None self.srtParse = None + self.concat = None self.ptsOffset = 0 self.ptsLast = None @@ -133,13 +135,9 @@ self.active = True self.finished = False - frameRate = self._GetFrameRate() - if frameRate == "25/1": - # 1000ms / 25fps == 40msec/frame - self.imgDuration = 1000 * Gst.MSECOND / 25 - elif frameRate == "30000/1001": - # 1000ms / 29.97fps == 33,367msec/frame - self.imgDuration = int(round(1000 * Gst.MSECOND / (30000.0 / 1001.0))) + frameRate = self.GetProfile().GetFrameRate() + # 1000ms / fps == x msec/frame + self.imgDuration = int(round(1000 * Gst.MSECOND / frameRate.AsFloat())) self._Log(logging.DEBUG, "set imgDuration=%s", self.imgDuration) outFile = os.path.join(self.GetOutputPath(), @@ -147,7 +145,8 @@ self.pipeline = Gst.Pipeline() - caps = Gst.caps_from_string("image/jpeg,framerate={0}".format(frameRate)) + caps = Gst.caps_from_string( + "image/jpeg,framerate={0}".format(frameRate.AsStr())) videoSrc = Gst.ElementFactory.make("appsrc") videoSrc.set_property("block", True) videoSrc.set_property("caps", caps) @@ -287,13 +286,6 @@ self.__CleanUp() - def _GetFrameRate(self): - if self.GetProfile().GetVideoNorm() == OutputProfile.PAL: - framerate = "25/1" - else: - framerate = "30000/1001" - return framerate - def _GetBitrate(self): bitrate = self.GetTypedProperty("Bitrate", int, self.GetProfile().GetBitrate()) @@ -301,7 +293,7 @@ raise RendererException(_(u"Bitrate must be a number!")) return bitrate - def _GstOnMessage(self, bus, msg): + def _GstOnMessage(self, bus, msg): # pylint: disable=unused-argument ''' Gstreamer message handler for messages in gstreamer event bus. :param bus: @@ -323,7 +315,7 @@ self.ready.set() # return Gst.BusSyncReply.PASS - def _GstNeedData(self, src, need_bytes): + def _GstNeedData(self, src, need_bytes): # pylint: disable=unused-argument ''' Gstreamer need-data probe callback to feed the appsrc with image data. The image data comes from a queue that is filled from other worker @@ -371,7 +363,8 @@ # self.textoverlay.set_property("text", "Frame: %s" % self.idxFrame) if self.srtParse is None: srtPath = os.path.join(self.GetOutputPath(), "output.srt") - self.srtParse = SrtParser(srtPath, self.GetProfile().GetFramerate()) + self.srtParse = SrtParser( + srtPath, self.GetProfile().GetFrameRate().AsFloat()) subtitle = self.srtParse.Get(self.idxFrame) self.textoverlay.set_property("text", subtitle) @@ -398,7 +391,7 @@ self._GstAddAudioFile(self.GetAudioFiles()[self.idxAudioFile]) # self.pipeline.set_state(Gst.State.PLAYING) - def _GstProbeBuffer(self, srcPad, probeInfo): + def _GstProbeBuffer(self, srcPad, probeInfo): # pylint: disable=unused-argument ''' Gstreamer pad probe callback to check if the current stream time has reached the final time (usually the length of the overall audio stream). diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/renderer/SingleFileRenderer.py photofilmstrip-3.3.1/photofilmstrip/core/renderer/SingleFileRenderer.py --- photofilmstrip-3.2.0/photofilmstrip/core/renderer/SingleFileRenderer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/renderer/SingleFileRenderer.py 2017-12-03 22:12:24.000000000 +0000 @@ -26,19 +26,19 @@ class SingleFileRenderer(BaseRenderer, FinalizeHandler): - + def __init__(self): BaseRenderer.__init__(self) self._counter = 0 - + @staticmethod def GetName(): return _(u"Single pictures") - + @staticmethod def GetProperties(): return ["ResampleFilter"] - + @staticmethod def GetDefaultProperty(prop): if prop == "ResampleFilter": @@ -48,7 +48,7 @@ def Prepare(self): pass - + def GetFinalizeHandler(self): return self @@ -65,13 +65,13 @@ :param pilImg: ''' self._counter += 1 - - newFilename = os.path.join(self.GetOutputPath(), - '%09d.%s' % (self._counter, + + newFilename = os.path.join(self.GetOutputPath(), + '%09d.%s' % (self._counter, "jpg")) pilImg.save(newFilename, "JPEG", quality=95) - + def Finalize(self): pass diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/renderer/StreamRenderer.py photofilmstrip-3.3.1/photofilmstrip/core/renderer/StreamRenderer.py --- photofilmstrip-3.2.0/photofilmstrip/core/renderer/StreamRenderer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/renderer/StreamRenderer.py 2017-12-03 22:12:24.000000000 +0000 @@ -26,14 +26,14 @@ class StreamRenderer(SingleFileRenderer, FinalizeHandler): - + def __init__(self): SingleFileRenderer.__init__(self) - + @staticmethod def GetName(): return u"Stream output" - + @staticmethod def GetProperties(): return SingleFileRenderer.GetProperties() + ["Format"] @@ -65,3 +65,6 @@ pilImg.save(sys.stdout, imgFormat) else: raise RuntimeError("unsupported format: %s", imgFormat) + + def ToSink(self, data): + pass diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/Renderer.py photofilmstrip-3.3.1/photofilmstrip/core/Renderer.py --- photofilmstrip-3.2.0/photofilmstrip/core/Renderer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/Renderer.py 2017-12-03 22:12:24.000000000 +0000 @@ -24,7 +24,6 @@ import photofilmstrip.core.renderer.GStreamerRenderer as GSR import photofilmstrip.core.renderer.CairoRenderer as CR - RENDERERS = [SFR.SingleFileRenderer] RENDERERS.extend([ diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/RenderJob.py photofilmstrip-3.3.1/photofilmstrip/core/RenderJob.py --- photofilmstrip-3.2.0/photofilmstrip/core/RenderJob.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/RenderJob.py 2017-12-03 22:12:24.000000000 +0000 @@ -78,7 +78,9 @@ finalizeHandler = None else: finalizeHandler = self.finalizeHandler - key = task.GetKey() + # make sure that a real sub task is not processed from FinalizeHandler + # so generate a special key for subtasks + key = "{0}{1}".format(task.GetKey(), isSubTask) if key in self.taskResultCache: trce = self.taskResultCache[key] isNew = False @@ -133,8 +135,8 @@ self.StepProgress() - def ProcessSubTask(self, task): - key = task.GetKey() + def ProcessSubTask(self, task, isSubTask=True): + key = "{0}{1}".format(task.GetKey(), isSubTask) trce = self.taskResultCache[key] result = trce.GetResult() if trce.refCount == 0: @@ -165,7 +167,9 @@ return self.idx def Run(self, jobContext): - return jobContext.ProcessSubTask(self.task) + # self.task is not really a sub task, but is processed as a sub task to + # use the result cache + return jobContext.ProcessSubTask(self.task, False) def GetInfo(self): return self.task.GetInfo() diff -Nru photofilmstrip-3.2.0/photofilmstrip/core/Subtitle.py photofilmstrip-3.3.1/photofilmstrip/core/Subtitle.py --- photofilmstrip-3.2.0/photofilmstrip/core/Subtitle.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/core/Subtitle.py 2017-12-03 22:12:24.000000000 +0000 @@ -24,27 +24,27 @@ class SubtitleSrt(object): - + def __init__(self, outputPath, factor=1.0): self.__outputPath = outputPath self.__index = 0 self.__curTime = 0.0 self.__factor = factor - + def __FormatTime(self, totalSecs): minutes = int(totalSecs / 60.0) hours = int(minutes / 60.0) seconds = int(totalSecs) % 60 frac = int((totalSecs - int(totalSecs)) * 1000.0) return "%02d:%02d:%02d,%03d" % (hours, minutes, seconds, frac) - + def __GetPicDuration(self, pic): return pic.GetDuration() * self.__factor - + def __ProcessPic(self, pic): start = self.__FormatTime(self.__curTime) - end = self.__FormatTime(self.__curTime + self.__GetPicDuration(pic)) - + end = self.__FormatTime(self.__curTime + self.__GetPicDuration(pic)) + result = u"%(idx)d\n" \ u"%(start)s --> %(end)s\n" \ u"%(text)s\n" \ @@ -52,10 +52,9 @@ 'start': start, 'end': end, 'text': pic.GetComment().strip()} - + return result - - + def Start(self, pics): if self.__outputPath is None: return @@ -63,31 +62,30 @@ fd.write(codecs.BOM_UTF8.decode("utf-8")) for pic in pics: self.__index += 1 - + data = self.__ProcessPic(pic) fd.write(data) - + self.__curTime += self.__GetPicDuration(pic) + \ (pic.GetTransitionDuration() * self.__factor) - + fd.close() class SrtParser(object): - + def __init__(self, path, framerate): self.__path = path self.__framerate = framerate - + self.__data = [] - + if os.path.exists(self.__path): self.Parse() - + def Parse(self): fd = codecs.open(self.__path, 'r', "utf-8") fd.read(len(codecs.BOM_UTF8.decode("utf-8"))) - idx = 0 try: while 1: lineIdx = fd.readline() @@ -95,7 +93,7 @@ _idx = int(lineIdx.strip()) except: break - + lineTime = fd.readline() start = self.__ParseTime(lineTime[:12]) end = self.__ParseTime(lineTime[17:]) @@ -106,28 +104,28 @@ lineTxt.append(_line) else: break - + self.__data.append((start, end, "\n".join(lineTxt))) finally: fd.close() - + def __ParseTime(self, text): hours = int(text[:2]) minutes = int(text[3:5]) seconds = float(text[6:].replace(",", ".")) - - millis = ((((hours * 60) + minutes) * 60) + seconds * 1000.0) - + + millis = ((((hours * 60) + minutes) * 60) + seconds * 1000.0) + return millis - + def Get(self, pic): msec = pic * (1.0 / self.__framerate) * 1000.0 for start, end, text in self.__data: if msec >= start and msec <= end: return text return "" - - + + def testWrite(): from photofilmstrip.core.Picture import Picture p1 = Picture(None) @@ -137,20 +135,21 @@ p2 = Picture(None) p2.SetComment("this is my second picture") p2.SetDuration(12) - + p3 = Picture(None) p3.SetComment("this is my third picture") p3.SetDuration(2) - + s = SubtitleSrt(".") s.Start([p1, p2, p3]) - + + def testRead(): - stp = SrtParser('/home/jens/My PhotoFilmStrips/test2a/Medium (640x480)/output.srt', 25.0) - + stp = SrtParser('output.srt', 25.0) + for f in xrange(800): print f, stp.Get(f) - - + + if __name__ == "__main__": testRead() diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/ActionManager.py photofilmstrip-3.3.1/photofilmstrip/gui/ActionManager.py --- photofilmstrip-3.2.0/photofilmstrip/gui/ActionManager.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/ActionManager.py 2017-12-03 22:12:24.000000000 +0000 @@ -2,7 +2,7 @@ # # PhotoFilmStrip - Creates movies out of your pictures. # -# Copyright (C) 2008 Jens Goepfert +# Copyright (C) 2017 Jens Goepfert # # 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 @@ -21,217 +21,148 @@ import wx +from photofilmstrip.lib.Settings import Settings +from photofilmstrip.gui.helper import CreateMenuItem + class ActionManager(object): - - ID_PIC_MOVE_LEFT = wx.NewId() - ID_PIC_MOVE_RIGHT = wx.NewId() - ID_PIC_REMOVE = wx.NewId() - ID_PIC_ROTATE_CW = wx.NewId() - ID_PIC_ROTATE_CCW = wx.NewId() - ID_PIC_MOTION_RANDOM = wx.NewId() - ID_PIC_MOTION_CENTER = wx.NewId() - ID_PIC_IMPORT = wx.NewId() - ID_RENDER_FILMSTRIP = wx.NewId() - ID_JOB_QUEUE = wx.NewId() - ID_PROJECT_IMPORT = wx.NewId() - ID_PROJECT_EXPORT = wx.NewId() - ID_PROJECT_PROPS = wx.NewId() - ID_PROJECT_CLOSE = wx.NewId() - ID_LANG_EN = wx.NewId() - ID_LANG_FR = wx.NewId() - ID_LANG_DE = wx.NewId() - ID_LANG_PT_BR = wx.NewId() - ID_LANG_CS = wx.NewId() - ID_LANG_IT = wx.NewId() - ID_LANG_KO = wx.NewId() - ID_LANG_NL = wx.NewId() - ID_LANG_RU = wx.NewId() - ID_LANG_TA = wx.NewId() - ID_LANG_UK = wx.NewId() - ID_LANG_EL = wx.NewId() - - LANG_MAP = {ID_LANG_EN: "en", - ID_LANG_FR: "fr", - ID_LANG_DE: "de", - ID_LANG_CS: "cs", - ID_LANG_IT: "it", - ID_LANG_KO: "ko", - ID_LANG_NL: "nl", - ID_LANG_RU: "ru", - ID_LANG_PT_BR: "pt_BR", - ID_LANG_TA: "ta", - ID_LANG_UK: "uk", - ID_LANG_EL: "el"} - - def __init__(self): - self.__menuBar = None - self.__toolBar = None - - self._menuSize = wx.ArtProvider.GetSizeHint(wx.ART_MENU) - self._toolSize = wx.ArtProvider.GetSizeHint(wx.ART_TOOLBAR) - - def GetMenuBar(self): - if self.__menuBar: - return self.__menuBar - - menuBar = wx.MenuBar() - menuFile = self.__MakeMenuFile() - menuEdit = self.__MakeMenuEdit() - menuTools = self.__MakeMenuTools() - menuHelp = self.__MakeMenuHelp() - - menuBar.Append(menuFile, _(u'&File')) - menuBar.Append(menuEdit, _(u'&Edit')) - menuBar.Append(menuTools, _(u'&Tools')) - menuBar.Append(menuHelp, _(u'&Help')) - - self.__menuBar = menuBar - return menuBar - - def GetToolBar(self, parent): - if self.__toolBar: - return self.__toolBar - if parent is None: - return - - toolBar = wx.ToolBar(parent) - toolBar.AddSimpleTool(wx.ID_NEW, - wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, self._toolSize), - _(u'New Project'), _(u'New Project')) - toolBar.AddSimpleTool(wx.ID_OPEN, - wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, self._toolSize), - _(u'Load Project'), _(u'Load Project')) - toolBar.AddSimpleTool(wx.ID_SAVE, - wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_TOOLBAR, self._toolSize), - _(u'Save Project'), _(u'Save Project')) -# toolBar.AddSimpleTool(wx.ID_SAVEAS, -# wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_TOOLBAR, self._toolSize), + + ID_JOB_QUEUE = wx.NewId() + ID_PROJECT_CLOSE = wx.NewId() + + ID_LANG_EN = wx.NewId() + ID_LANG_FR = wx.NewId() + ID_LANG_DE = wx.NewId() + ID_LANG_PT_BR = wx.NewId() + ID_LANG_CS = wx.NewId() + ID_LANG_IT = wx.NewId() + ID_LANG_KO = wx.NewId() + ID_LANG_NL = wx.NewId() + ID_LANG_RU = wx.NewId() + ID_LANG_TA = wx.NewId() + ID_LANG_UK = wx.NewId() + ID_LANG_EL = wx.NewId() + + LANG_MAP = { + ID_LANG_EN: "en", + ID_LANG_FR: "fr", + ID_LANG_DE: "de", + ID_LANG_CS: "cs", + ID_LANG_IT: "it", + ID_LANG_KO: "ko", + ID_LANG_NL: "nl", + ID_LANG_RU: "ru", + ID_LANG_PT_BR: "pt_BR", + ID_LANG_TA: "ta", + ID_LANG_UK: "uk", + ID_LANG_EL: "el" + } + + def __init__(self, frame, menuBar, toolBar): + self._frame = frame + self._menuBar = menuBar + self._toolBar = toolBar + + self._prevEditor = None + self._toolFix = 0 + + menuFile = self.__CreateMenuFile() + menuEdit = self.__CreateMenuEdit() + menuHelp = self.__CreateMenuHelp() + self._menuBar.Append(menuFile, _(u'&File')) + self._menuBar.Append(menuEdit, _(u'&Edit')) + self._menuBar.Append(menuHelp, _(u'&Help')) + + self.__MakeToolBar(toolBar) + self.__SelectLanguage(Settings().GetLanguage()) + + def __SelectLanguage(self, lang): + for ident, l in self.LANG_MAP.items(): + if l == lang: + self._menuBar.Check(ident, True) + + def __MakeToolBar(self, toolBar): + toolBar.DoAddTool(wx.ID_NEW, _(u'New Slideshow'), + wx.ArtProvider.GetBitmap('PFS_PROJECT_NEW_24'), + kind=wx.ITEM_DROPDOWN, + shortHelp=_(u'New Slideshow')) + toolBar.Bind(wx.EVT_TOOL_DROPDOWN, self.OnDropDownNew) + + toolBar.AddSimpleTool(wx.ID_OPEN, + wx.ArtProvider.GetBitmap('PFS_PROJECT_OPEN_24'), + _(u'Load'), _(u'Load')) + + toolBar.DoAddTool(wx.ID_SAVE, '', + wx.ArtProvider.GetBitmap('PFS_PROJECT_SAVE_24'), + wx.ArtProvider.GetBitmap('PFS_PROJECT_SAVE_D_24'), + wx.ITEM_NORMAL, + _(u'Save'), _(u'Save'), None) +# toolBar.AddSimpleTool(wx.ID_SAVEAS, +# wx.ArtProvider.GetBitmap('PFS_PROJECT_SAVEAS_16'), # _(u'Save Project as'), _(u'Save Project as')) toolBar.AddSeparator() - toolBar.AddSimpleTool(self.ID_PIC_IMPORT, - wx.ArtProvider.GetBitmap(wx.ART_ADD_BOOKMARK, wx.ART_TOOLBAR, self._toolSize), - _(u'Import Pictures'), _(u'Import Pictures')) - toolBar.AddSimpleTool(self.ID_RENDER_FILMSTRIP, - wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_TOOLBAR, self._toolSize), - _(u'Render filmstrip'), _(u'Render filmstrip')) + + toolBar.DoAddTool(self.ID_JOB_QUEUE, '', + wx.ArtProvider.GetBitmap('PFS_JOB_QUEUE_24'), + wx.ArtProvider.GetBitmap('PFS_JOB_QUEUE_D_24'), + wx.ITEM_NORMAL, + _(u'Show job queue'), + _(u'Show job queue'), + None) + toolBar.AddSeparator() - toolBar.AddSimpleTool(self.ID_JOB_QUEUE, - wx.ArtProvider.GetBitmap(wx.ART_EXECUTABLE_FILE, wx.ART_TOOLBAR, self._toolSize), - _(u'Show job queue'), _(u'Show job queue')) + self._toolFix = toolBar.GetToolsCount() toolBar.Realize() - - self.__toolBar = toolBar - return toolBar - - def __CreateMenuItem(self, menu, ident, text="", bmp=None): - if text: - item = wx.MenuItem(menu, ident, text) - item.SetHelp(text.replace('&', '').split('\t')[0]) - else: - item = wx.MenuItem(menu, ident) - if bmp is not None: - item.SetBitmap(bmp) - menu.AppendItem(item) - - def __MakeMenuFile(self): - menu = wx.Menu() - self.__CreateMenuItem(menu, - wx.ID_NEW, - _(u'&New Project') + '\tCtrl+N', - wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_MENU, self._menuSize)) - self.__CreateMenuItem(menu, - wx.ID_OPEN, - _(u'&Open Project') + '\tCtrl+O', - wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() - self.__CreateMenuItem(menu, - wx.ID_SAVE, - _(u'&Save Project') + '\tCtrl+S', - wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_MENU, self._menuSize)) - self.__CreateMenuItem(menu, - self.ID_PROJECT_CLOSE, - _(u'&Close Project') + '\tCtrl+W', - wx.ArtProvider.GetBitmap(wx.ART_REMOVABLE, wx.ART_MENU, self._menuSize)) -# self.__CreateMenuItem(menu, -# wx.ID_SAVEAS, -# _(u'Save Project &as'), -# wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() -# self.__CreateMenuItem(menu, self.ID_PROJECT_IMPORT, _(u"&Import Project")) -# self.__CreateMenuItem(menu, self.ID_PROJECT_EXPORT, _(u"&Export Project")) -# menu.AppendSeparator() - self.__CreateMenuItem(menu, - self.ID_PROJECT_PROPS, - _("&Properties"), - wx.ArtProvider_GetBitmap(wx.ART_EXECUTABLE_FILE, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() - self.__CreateMenuItem(menu, - wx.ID_EXIT, - _(u'E&xit') + '\tCtrl+Q', - wx.ArtProvider.GetBitmap(wx.ART_QUIT, wx.ART_MENU, self._menuSize)) + def __CreateMenuNew(self): + menu = wx.Menu() + CreateMenuItem(menu, wx.ID_NEW, _(u'Slideshow') + '\tCtrl+N', + wx.ArtProvider.GetBitmap('PFS_PROJECT_NEW_16')) return menu - def __MakeMenuEdit(self): + def __CreateMenuFile(self, editor=None): menu = wx.Menu() - self.__CreateMenuItem(menu, - self.ID_PIC_MOVE_LEFT, - _(u'Move picture &left'), - wx.ArtProvider.GetBitmap(wx.ART_GO_BACK, wx.ART_MENU, self._menuSize)) - self.__CreateMenuItem(menu, - self.ID_PIC_MOVE_RIGHT, - _(u'Move picture &right'), - wx.ArtProvider.GetBitmap(wx.ART_GO_FORWARD, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() - self.__CreateMenuItem(menu, - self.ID_PIC_REMOVE, - _(u'R&emove Picture') + '\tCtrl+Del', - wx.ArtProvider.GetBitmap(wx.ART_DELETE, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() - self.__CreateMenuItem(menu, - self.ID_PIC_ROTATE_CW, - _(u'Rotate &clockwise') + '\tCtrl+r', - wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_MENU, self._menuSize)) - self.__CreateMenuItem(menu, - self.ID_PIC_ROTATE_CCW, - _(u'Rotate counter clock&wise') + '\tCtrl+l', - wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() - self.__CreateMenuItem(menu, - self.ID_PIC_MOTION_RANDOM, - _(u'Random &motion' + '\tCtrl+d')) - self.__CreateMenuItem(menu, - self.ID_PIC_MOTION_CENTER, - _(u'Centralize m&otion') + '\tCtrl+f') - + menu.AppendMenu(wx.ID_ANY, _(u'New'), self.__CreateMenuNew()) + CreateMenuItem(menu, wx.ID_OPEN, + _(u'&Open') + '\tCtrl+O', + wx.ArtProvider.GetBitmap('PFS_PROJECT_OPEN_16')) + + menu.AppendSeparator() + CreateMenuItem(menu, wx.ID_SAVE, + _(u'&Save') + '\tCtrl+S', + wx.ArtProvider.GetBitmap('PFS_PROJECT_SAVE_16'), + wx.ArtProvider.GetBitmap('PFS_PROJECT_SAVE_D_16')) +# CreateMenuItem(menu, wx.ID_SAVEAS, +# _(u'Save Project &as'), +# wx.ArtProvider.GetBitmap('PFS_PROJECT_SAVEAS_16')) + menu.AppendSeparator() + + if editor: + editor.AddMenuFileActions(menu) + menu.AppendSeparator() + + CreateMenuItem(menu, ActionManager.ID_PROJECT_CLOSE, + _(u'&Close') + '\tCtrl+W', + wx.ArtProvider.GetBitmap('PFS_PROJECT_CLOSE_16'), + wx.ArtProvider.GetBitmap('PFS_PROJECT_CLOSE_D_16')) + menu.AppendSeparator() + CreateMenuItem(menu, wx.ID_EXIT, + _(u'E&xit') + '\tCtrl+Q', + wx.ArtProvider.GetBitmap('PFS_EXIT_16')) return menu - - def __MakeMenuTools(self): + + def __CreateMenuEdit(self, editor=None): menu = wx.Menu() - self.__CreateMenuItem(menu, - self.ID_PIC_IMPORT, - _(u'&Import Pictures') + '\tCtrl+I', - wx.ArtProvider.GetBitmap(wx.ART_ADD_BOOKMARK, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() - self.__CreateMenuItem(menu, - self.ID_RENDER_FILMSTRIP, - _(u'&Render filmstrip') + '\tF9', - wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_MENU, self._menuSize)) - menu.AppendSeparator() - self.__CreateMenuItem(menu, - self.ID_JOB_QUEUE, - _(u'&Show job queue') + '\tF12', - wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, wx.ART_MENU, self._menuSize)) + if editor: + editor.AddMenuEditActions(menu) return menu - - def __MakeMenuHelp(self): + + def __CreateMenuHelp(self): menu = wx.Menu() - self.__CreateMenuItem(menu, - wx.ID_HELP, - _(u'&Help') + '\tF1', - wx.ArtProvider.GetBitmap(wx.ART_HELP, wx.ART_MENU, self._menuSize)) + CreateMenuItem(menu, wx.ID_HELP, + _(u'&Help') + '\tF1', + wx.ArtProvider.GetBitmap('PFS_HELP_16')) menu.AppendSeparator() langMenu = wx.Menu() langMenu.AppendRadioItem(self.ID_LANG_EN, u"English") @@ -248,14 +179,30 @@ langMenu.AppendRadioItem(self.ID_LANG_EL, u"ελληνικά") menu.AppendMenu(wx.NewId(), _("Language"), langMenu) menu.AppendSeparator() - self.__CreateMenuItem(menu, - wx.ID_ABOUT, - _(u'&About'), - wx.ArtProvider.GetBitmap(wx.ART_INFORMATION, wx.ART_MENU, self._menuSize)) + CreateMenuItem(menu, wx.ID_ABOUT, + _(u'&About'), + wx.ArtProvider.GetBitmap('PFS_ABOUT_16')) return menu - def SelectLanguage(self, lang): - for ident, l in self.LANG_MAP.items(): - if l == lang: - self.GetMenuBar().Check(ident, True) - \ No newline at end of file + def OnDropDownNew(self, event): + menu = self.__CreateMenuNew() + self._frame.PopupMenu(menu) + + def UpdateActions(self, newEditor): + while self._toolFix < self._toolBar.GetToolsCount(): + self._toolBar.DeleteToolByPos(self._toolFix) + + if self._prevEditor: + self._prevEditor.DisconnEvents(self._frame) + + menuFile = self.__CreateMenuFile(newEditor) + menuEdit = self.__CreateMenuEdit(newEditor) + self._menuBar.Replace(0, menuFile, _(u'&File')).Destroy() + self._menuBar.Replace(1, menuEdit, _(u'&Edit')).Destroy() + + if newEditor: + newEditor.AddToolBarActions(self._toolBar) + newEditor.ConnectEvents(self._frame) + self._prevEditor = newEditor + + self._toolBar.Realize() diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/ArtProvider.py photofilmstrip-3.3.1/photofilmstrip/gui/ArtProvider.py --- photofilmstrip-3.2.0/photofilmstrip/gui/ArtProvider.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/ArtProvider.py 2017-12-03 22:12:24.000000000 +0000 @@ -20,7 +20,6 @@ # import wx - from wx.lib.art import img2pyartprov import photofilmstrip.res.images @@ -29,12 +28,12 @@ class ArtProvider(object): provider = None - + @classmethod def Init(cls): if cls.provider is None: cls.provider = img2pyartprov.Img2PyArtProvider( - photofilmstrip.res.images, + photofilmstrip.res.images, artIdPrefix='PFS_' ) wx.ArtProvider.Push(cls.provider) diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/IconLabelLink.py photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/IconLabelLink.py --- photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/IconLabelLink.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/IconLabelLink.py 2017-12-03 22:12:24.000000000 +0000 @@ -21,55 +21,71 @@ import wx +from photofilmstrip.gui.helper import ChopText + class IconLabelLink(wx.Panel): - - def __init__(self, - parent, - size=wx.DefaultSize, + + def __init__(self, + parent, + size=wx.DefaultSize, label="label", bmp=None, descr="descr"): - wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, (150, 100), 0, "IconLabelLink") - self.SetBackgroundColour(parent.GetBackgroundColour()) - stBmp = wx.StaticBitmap(self, -1, bmp) - self.lbl = wx.StaticText(self, -1, label) - - sz = wx.BoxSizer(wx.VERTICAL) - sz.AddStretchSpacer(1) - sz.Add(stBmp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 4) - sz.Add(self.lbl, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.BOTTOM, 4) - self.SetSizer(sz) - - self.SetToolTipString(descr) - stBmp.SetToolTipString(descr) - self.lbl.SetToolTipString(descr) - - self.Layout() - - stBmp.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) - self.lbl.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) - + wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, (150, 150), 0, "IconLabelLink") + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + + self.bmpDia = wx.ArtProvider.GetBitmap('PFS_DIA') + self.bmpDiaSelected = wx.ArtProvider.GetBitmap('PFS_DIA_S') + self.bmpThumb = bmp + self.label = label + self.mouseOver = False + + self.SetToolTipString(u'{0}\n{1}'.format(label, descr)) + + self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvents) - stBmp.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvents) - self.lbl.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvents) - - self.fontNormal = self.lbl.GetFont() - self.fontOver = self.lbl.GetFont() - self.fontOver.SetUnderlined(True) - + + self.SetCursor(wx.StockCursor(wx.CURSOR_HAND)) + def OnMouseEvents(self, event): if event.LeftDown(): self.OnClick() + + if event.Entering(): + self.mouseOver = True + self.Refresh() + if event.Leaving(): - self.lbl.SetFont(self.fontNormal) - self.lbl.SetForegroundColour(wx.BLACK) - self.lbl.Refresh() - if event.Moving(): - self.lbl.SetFont(self.fontOver) - self.lbl.SetForegroundColour(wx.BLUE) - self.lbl.Refresh() - event.Skip() + self.mouseOver = False + self.Refresh() + + # event.Skip() + + def OnPaint(self, event): # pylint: disable=unused-argument + dc = wx.AutoBufferedPaintDC(self) + dc.SetBackground(wx.Brush(self.GetParent().GetBackgroundColour())) + sz = self.GetSize() + dc.Clear() + + if self.mouseOver: + dc.DrawBitmap(self.bmpDiaSelected, 0, 0) + else: + dc.DrawBitmap(self.bmpDia, 0, 0) + + thumbSz = self.bmpThumb.GetSize() + thumbRect = wx.Rect(sz[0] / 2 - thumbSz[0] / 2, + sz[1] / 2 - thumbSz[1] / 2 - 15, + thumbSz[0], + thumbSz[1]) + + dc.DrawBitmapPoint(self.bmpThumb, thumbRect.GetTopLeft()) + thumbRect.Inflate(1, 1) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.DrawRectangleRect(thumbRect) + + label, width = ChopText(dc, self.label, 138) + dc.DrawText(label, sz[0] / 2 - width / 2, 97) def OnClick(self): raise NotImplementedError("OnClick") diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/PnlDlgHeader.py photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/PnlDlgHeader.py --- photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/PnlDlgHeader.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/PnlDlgHeader.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:FramePanel:PnlDlgHeader +# Boa:FramePanel:PnlDlgHeader # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -24,13 +24,13 @@ from wx.lib.wordwrap import wordwrap - -[wxID_PNLDLGHEADER, wxID_PNLDLGHEADERBMPLOGO, wxID_PNLDLGHEADERPNLHEADER, - wxID_PNLDLGHEADERSLHDR, wxID_PNLDLGHEADERSTERRMSG, wxID_PNLDLGHEADERSTHEADER, +[wxID_PNLDLGHEADER, wxID_PNLDLGHEADERBMPLOGO, wxID_PNLDLGHEADERPNLHEADER, + wxID_PNLDLGHEADERSLHDR, wxID_PNLDLGHEADERSTERRMSG, wxID_PNLDLGHEADERSTHEADER, ] = [wx.NewId() for _init_ctrls in range(6)] class PnlDlgHeader(wx.Panel): + def _init_coll_szHeaderText_Items(self, parent): # generated method, don't edit @@ -114,9 +114,9 @@ else: self.stErrMsg.Show(False) self.pnlHeader.Layout() - + def SetTitle(self, title): self.stHeader.SetLabel(title) - + def SetBitmap(self, bmp): self.bmpLogo.SetBitmap(bmp) diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/PnlFloatSpinCtrl.py photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/PnlFloatSpinCtrl.py --- photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/PnlFloatSpinCtrl.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/PnlFloatSpinCtrl.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:FramePanel:PnlFloatSpinCtrl +# Boa:FramePanel:PnlFloatSpinCtrl # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -24,13 +24,13 @@ from photofilmstrip.gui.util.FloatValidator import FloatValidator - -[wxID_PNLFLOATSPINCTRL, wxID_PNLFLOATSPINCTRLSPINBUTTONVALUE, - wxID_PNLFLOATSPINCTRLTCVALUE, +[wxID_PNLFLOATSPINCTRL, wxID_PNLFLOATSPINCTRLSPINBUTTONVALUE, + wxID_PNLFLOATSPINCTRLTCVALUE, ] = [wx.NewId() for _init_ctrls in range(3)] class PnlFloatSpinCtrl(wx.Panel): + def _init_coll_szMain_Items(self, parent): # generated method, don't edit @@ -71,22 +71,22 @@ def __init__(self, parent, id, pos, size, style, name): self._init_ctrls(parent) self.tcValue.SetValidator(FloatValidator()) - self.spinButtonValue.SetMinSize(wx.Size(-1, self.tcValue.GetSizeTuple()[1])) + self.spinButtonValue.SetMinSize(wx.Size(-1, self.tcValue.GetSize()[1])) def __SendValueChangedEvent(self, value): evt = ValueChangedEvent(self.GetId(), value) evt.SetEventObject(self) - self.GetEventHandler().ProcessEvent(evt) + self.GetEventHandler().ProcessEvent(evt) def SetRange(self, minVal, maxVal): self.spinButtonValue.SetRange(minVal, maxVal) - + def OnSpinButtonValueSpin(self, event): value = event.GetPosition() / 10.0 self.tcValue.ChangeValue("%.1f" % value) self.__SendValueChangedEvent(value) event.Skip() - + def __GetValue(self): val = self.tcValue.GetValue() try: @@ -94,29 +94,30 @@ except ValueError: floatVal = 1.0 return min(floatVal, 600.0) - + def SetValue(self, value): self.tcValue.ChangeValue("%.1f" % value) self.spinButtonValue.SetValue(int(value * 10)) - + def OnTextCtrlValueKillFocus(self, event): value = self.__GetValue() self.spinButtonValue.SetValue(int(value * 10)) self.tcValue.ChangeValue("%.1f" % value) self.__SendValueChangedEvent(value) event.Skip() - + def OnTextCtrlValueText(self, event): value = self.__GetValue() self.__SendValueChangedEvent(value) event.Skip() - -_EVT_VALUE_CHANGED_TYPE = wx.NewEventType() -EVT_VALUE_CHANGED = wx.PyEventBinder(_EVT_VALUE_CHANGED_TYPE, 1) + +_EVT_VALUE_CHANGED_TYPE = wx.NewEventType() +EVT_VALUE_CHANGED = wx.PyEventBinder(_EVT_VALUE_CHANGED_TYPE, 1) class ValueChangedEvent(wx.PyCommandEvent): + def __init__(self, wxId, value): wx.PyCommandEvent.__init__(self, _EVT_VALUE_CHANGED_TYPE, wxId) self.__value = value diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/PyListView.py photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/PyListView.py --- photofilmstrip-3.2.0/photofilmstrip/gui/ctrls/PyListView.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/ctrls/PyListView.py 2017-12-03 22:12:24.000000000 +0000 @@ -23,25 +23,25 @@ class PyListView(wx.ListView): - - def __init__(self, parent, id, - pos=wx.DefaultPosition, size=wx.DefaultSize, - style=wx.LC_ICON, validator=wx.DefaultValidator, + + def __init__(self, parent, id, + pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.LC_ICON, validator=wx.DefaultValidator, name=wx.ListCtrlNameStr): wx.ListView.__init__(self, parent, id, pos, size, style, validator, name) - + self.__data = {} self.__key = 0 - + def DeleteAllItems(self): self.__data.clear() wx.ListView.DeleteAllItems(self) - + def DeleteItem(self, item): key = self.GetItemData(item) del self.__data[key] wx.ListView.DeleteItem(self, item) - + def SetPyData(self, item, data): key = self.GetItemData(item) if key == 0: @@ -50,11 +50,11 @@ self.SetItemData(item, key) self.__data[key] = data - + def GetPyData(self, item): key = self.GetItemData(item) return self.__data.get(key) - + def GetPyDataList(self): result = [] for item in range(self.GetItemCount()): @@ -65,4 +65,3 @@ for key, pydata in self.__data.items(): if data is pydata: return self.FindItemData(-1, key) - \ No newline at end of file diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/DlgBugReport.py photofilmstrip-3.3.1/photofilmstrip/gui/DlgBugReport.py --- photofilmstrip-3.2.0/photofilmstrip/gui/DlgBugReport.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/DlgBugReport.py 2017-12-03 22:12:24.000000000 +0000 @@ -29,55 +29,56 @@ from photofilmstrip import Constants -from photofilmstrip.lib.Settings import Settings from photofilmstrip.lib.util import Encode class DlgBugReport(wx.Dialog): - + PARENT = None - + @classmethod def Initialize(cls, parent): cls.PARENT = parent + def excepthook(etype, value, tb): if not getattr(sys, 'frozen', False): traceback.print_exception(etype, value, tb) output = cStringIO.StringIO() traceback.print_exception(etype, value, tb, file=output) - dlg = DlgBugReport(cls.PARENT, output.getvalue()) + dlg = DlgBugReport(cls.PARENT, output.getvalue()) dlg.ShowModal() dlg.Destroy() + sys.excepthook = excepthook def __init__(self, parent, msg): - wx.Dialog.__init__(self, parent, -1, + wx.Dialog.__init__(self, parent, -1, _(u"An unexpected error occured"), name=u'DlgBugReport') - + text = _(u"An unexpected error occured. Do you want to send this bug report to the developers of %s?") % Constants.APP_NAME - - stBmp = wx.StaticBitmap(self, -1, wx.ArtProvider_GetBitmap(wx.ART_ERROR, wx.ART_OTHER, (32, 32))) + + stBmp = wx.StaticBitmap(self, -1, wx.ArtProvider.GetBitmap(wx.ART_ERROR, wx.ART_OTHER, (32, 32))) stMsg = wx.StaticText(self, -1, wordwrap(text, 300, wx.ClientDC(self))) - + szTop = wx.BoxSizer(wx.HORIZONTAL) szTop.Add(stBmp, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 8) szTop.Add(stMsg, 0, wx.ALL, 8) - + self.tcMsg = wx.TextCtrl(self, -1, msg, style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP) - + szCmd = self.CreateSeparatedButtonSizer(wx.YES | wx.NO) szMain = wx.BoxSizer(wx.VERTICAL) szMain.Add(szTop, 0) szMain.Add(self.tcMsg, 1, wx.EXPAND | wx.ALL, 4) szMain.Add(szCmd, 0, wx.EXPAND | wx.ALL, 4) - + self.SetSizer(szMain) - + self.Bind(wx.EVT_BUTTON, self.OnNo, id=wx.ID_NO) self.Bind(wx.EVT_BUTTON, self.OnYes, id=wx.ID_YES) - + self.SetAffirmativeId(wx.ID_YES) self.SetEscapeId(wx.ID_NO) self.SetInitialSize(self.GetEffectiveMinSize()) @@ -85,11 +86,11 @@ self.SetFocus() def OnYes(self, event): - info = "\n".join([sys.platform, - sys.getdefaultencoding(), + info = "\n".join([sys.platform, + sys.getdefaultencoding(), sys.getfilesystemencoding(), str(getattr(sys, 'frozen', False))]) - params = urllib.urlencode({'bugreport': "%s-%s\n\n%s\n%s\n" % (Constants.APP_NAME, + params = urllib.urlencode({'bugreport': "%s-%s\n\n%s\n%s\n" % (Constants.APP_NAME, Constants.APP_VERSION_EX, Encode(self.tcMsg.GetValue()), info)}) @@ -98,22 +99,22 @@ result = fd.read() except IOError: result = None - + if result and result.find("Result 1") != -1: dlg = wx.MessageDialog(self, - _(u"Bug-Report send. Thank you for your support."), + _(u"Bug-Report send. Thank you for your support."), _(u"Information"), wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy() else: dlg = wx.MessageDialog(self, - _(u"Sorry, this function is temporary not available.."), + _(u"Sorry, this function is temporary not available.."), _(u"Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() - + self.EndModal(wx.ID_YES) def OnNo(self, event): diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/DlgPositionInput.py photofilmstrip-3.3.1/photofilmstrip/gui/DlgPositionInput.py --- photofilmstrip-3.2.0/photofilmstrip/gui/DlgPositionInput.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/DlgPositionInput.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:Dialog:DlgPositionInput +# Boa:Dialog:DlgPositionInput # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -26,18 +26,17 @@ from photofilmstrip.gui.ctrls.PnlDlgHeader import PnlDlgHeader - -[wxID_DLGPOSITIONINPUT, wxID_DLGPOSITIONINPUTCMDCANCEL, - wxID_DLGPOSITIONINPUTCMDOK, wxID_DLGPOSITIONINPUTCMDRESET, - wxID_DLGPOSITIONINPUTPNLHDR, wxID_DLGPOSITIONINPUTSLENDPOS, - wxID_DLGPOSITIONINPUTSLSTARTPOS, wxID_DLGPOSITIONINPUTSPINENDHEIGHT, - wxID_DLGPOSITIONINPUTSPINENDWIDTH, wxID_DLGPOSITIONINPUTSPINENDX, - wxID_DLGPOSITIONINPUTSPINENDY, wxID_DLGPOSITIONINPUTSPINSTARTHEIGHT, - wxID_DLGPOSITIONINPUTSPINSTARTWIDTH, wxID_DLGPOSITIONINPUTSPINSTARTX, - wxID_DLGPOSITIONINPUTSPINSTARTY, wxID_DLGPOSITIONINPUTSTENDLOCATION, - wxID_DLGPOSITIONINPUTSTENDPOS, wxID_DLGPOSITIONINPUTSTENDSIZE, - wxID_DLGPOSITIONINPUTSTSTARTLOCATION, wxID_DLGPOSITIONINPUTSTSTARTPOS, - wxID_DLGPOSITIONINPUTSTSTARTSIZE, +[wxID_DLGPOSITIONINPUT, wxID_DLGPOSITIONINPUTCMDCANCEL, + wxID_DLGPOSITIONINPUTCMDOK, wxID_DLGPOSITIONINPUTCMDRESET, + wxID_DLGPOSITIONINPUTPNLHDR, wxID_DLGPOSITIONINPUTSLENDPOS, + wxID_DLGPOSITIONINPUTSLSTARTPOS, wxID_DLGPOSITIONINPUTSPINENDHEIGHT, + wxID_DLGPOSITIONINPUTSPINENDWIDTH, wxID_DLGPOSITIONINPUTSPINENDX, + wxID_DLGPOSITIONINPUTSPINENDY, wxID_DLGPOSITIONINPUTSPINSTARTHEIGHT, + wxID_DLGPOSITIONINPUTSPINSTARTWIDTH, wxID_DLGPOSITIONINPUTSPINSTARTX, + wxID_DLGPOSITIONINPUTSPINSTARTY, wxID_DLGPOSITIONINPUTSTENDLOCATION, + wxID_DLGPOSITIONINPUTSTENDPOS, wxID_DLGPOSITIONINPUTSTENDSIZE, + wxID_DLGPOSITIONINPUTSTSTARTLOCATION, wxID_DLGPOSITIONINPUTSTSTARTPOS, + wxID_DLGPOSITIONINPUTSTSTARTSIZE, ] = [wx.NewId() for _init_ctrls in range(21)] @@ -215,14 +214,14 @@ pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.spinEndX = wx.SpinCtrl(id=wxID_DLGPOSITIONINPUTSPINENDX, initial=0, - max=100, min=0, name=u'spinEndX', parent=self, pos=wx.Point(-1, - -1), size=wx.Size(-1, -1), style=wx.SP_ARROW_KEYS) + max=100, min=0, name=u'spinEndX', parent=self, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.SP_ARROW_KEYS) self.spinEndX.Bind(wx.EVT_TEXT, self.OnSpinChange, id=wxID_DLGPOSITIONINPUTSPINENDX) self.spinEndY = wx.SpinCtrl(id=wxID_DLGPOSITIONINPUTSPINENDY, initial=0, - max=100, min=0, name=u'spinEndY', parent=self, pos=wx.Point(-1, - -1), size=wx.Size(-1, -1), style=wx.SP_ARROW_KEYS) + max=100, min=0, name=u'spinEndY', parent=self, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.SP_ARROW_KEYS) self.spinEndY.Bind(wx.EVT_TEXT, self.OnSpinChange, id=wxID_DLGPOSITIONINPUTSPINENDY) @@ -245,8 +244,8 @@ id=wxID_DLGPOSITIONINPUTSPINENDHEIGHT) self.cmdReset = wx.Button(id=wxID_DLGPOSITIONINPUTCMDRESET, - label=_(u'Reset'), name=u'cmdReset', parent=self, pos=wx.Point(-1, - -1), size=wx.Size(-1, -1), style=0) + label=_(u'Reset'), name=u'cmdReset', parent=self, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.cmdReset.Bind(wx.EVT_BUTTON, self.OnCmdResetButton, id=wxID_DLGPOSITIONINPUTCMDRESET) @@ -265,44 +264,43 @@ self._init_ctrls(parent) self.pnlHdr.SetTitle(_(u'Adjust motion positions directly')) - self.pnlHdr.SetBitmap(wx.ArtProvider.GetBitmap('PFS_MOTION_INPUT', - wx.ART_TOOLBAR, (32, 32))) - + self.pnlHdr.SetBitmap(wx.ArtProvider.GetBitmap('PFS_MOTION_MANUAL_32')) + self.__pic = pic self.__ratio = Aspect.ToFloat(aspect) self.__doOnChange = True - + self.__backupStart = self.__pic.GetStartRect() self.__backupEnd = self.__pic.GetTargetRect() - + font = self.stStartPos.GetFont() font.SetWeight(wx.FONTWEIGHT_BOLD) self.stStartPos.SetFont(font) self.stEndPos.SetFont(font) - + self._InitValues() - + self.SetInitialSize(self.GetEffectiveMinSize()) - self.CenterOnParent() + self.CenterOnParent() self.SetFocus() - + def _InitValues(self): self.__doOnChange = False # Init ranges with max values self.spinStartX.SetRange(0, self.__pic.GetWidth()) self.spinStartY.SetRange(0, self.__pic.GetHeight()) - self.spinStartWidth.SetRange(0, min(int(round(self.__pic.GetHeight() * self.__ratio)), + self.spinStartWidth.SetRange(0, min(int(round(self.__pic.GetHeight() * self.__ratio)), self.__pic.GetWidth())) - self.spinStartHeight.SetRange(0, min(int(round(self.__pic.GetWidth() / self.__ratio)), + self.spinStartHeight.SetRange(0, min(int(round(self.__pic.GetWidth() / self.__ratio)), self.__pic.GetHeight())) - + self.spinEndX.SetRange(0, self.__pic.GetWidth()) self.spinEndY.SetRange(0, self.__pic.GetHeight()) - self.spinEndWidth.SetRange(0, min(int(round(self.__pic.GetHeight() * self.__ratio)), + self.spinEndWidth.SetRange(0, min(int(round(self.__pic.GetHeight() * self.__ratio)), self.__pic.GetWidth())) - self.spinEndHeight.SetRange(0, min(int(round(self.__pic.GetWidth() / self.__ratio)), + self.spinEndHeight.SetRange(0, min(int(round(self.__pic.GetWidth() / self.__ratio)), self.__pic.GetHeight())) - + # Init values self.spinStartX.SetValue(self.__pic.GetStartRect()[0]) self.spinStartY.SetValue(self.__pic.GetStartRect()[1]) @@ -315,19 +313,19 @@ self.spinEndHeight.SetValue(self.__pic.GetTargetRect()[3]) self.__doOnChange = True - + self._SetupRanges() - + def _SetupRanges(self): ''' Limit the location ranges to the current adjusted size ''' self.spinStartX.SetRange(0, self.__pic.GetWidth() - self.spinStartWidth.GetValue()) self.spinStartY.SetRange(0, self.__pic.GetHeight() - self.spinStartHeight.GetValue()) - + self.spinEndX.SetRange(0, self.__pic.GetWidth() - self.spinEndWidth.GetValue()) self.spinEndY.SetRange(0, self.__pic.GetHeight() - self.spinEndHeight.GetValue()) - + def _PreserveAspect(self, wxId): self.__doOnChange = False @@ -342,25 +340,25 @@ self.spinEndWidth.SetValue(int(round(self.spinEndHeight.GetValue() * self.__ratio))) self.__doOnChange = True - + def OnSpinChange(self, event): if not self.__doOnChange: return self._PreserveAspect(event.GetId()) - + startRect = (self.spinStartX.GetValue(), self.spinStartY.GetValue(), self.spinStartWidth.GetValue(), self.spinStartHeight.GetValue()) - + endRect = (self.spinEndX.GetValue(), self.spinEndY.GetValue(), self.spinEndWidth.GetValue(), self.spinEndHeight.GetValue()) - + if event.GetId() in (wxID_DLGPOSITIONINPUTSPINENDWIDTH, wxID_DLGPOSITIONINPUTSPINENDHEIGHT, wxID_DLGPOSITIONINPUTSPINSTARTWIDTH, wxID_DLGPOSITIONINPUTSPINSTARTHEIGHT): self._SetupRanges() - + self.__pic.SetStartRect(startRect) self.__pic.SetTargetRect(endRect) - + event.Skip() def OnCmdResetButton(self, event): diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/DlgProjectProps.py photofilmstrip-3.3.1/photofilmstrip/gui/DlgProjectProps.py --- photofilmstrip-3.2.0/photofilmstrip/gui/DlgProjectProps.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/DlgProjectProps.py 2017-12-03 22:12:24.000000000 +0000 @@ -19,11 +19,9 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -import logging import os import wx -import wx.lib.masked.textctrl import wx.lib.masked.timectrl from photofilmstrip import Constants @@ -120,8 +118,7 @@ name=u'tcFolder', style=wx.TE_READONLY, value=u'') self.cmdBrowseFolder = wx.BitmapButton(self, - bitmap=wx.ArtProvider.GetBitmap('wxART_FOLDER_OPEN', - wx.ART_TOOLBAR, (16, 16)), + bitmap=wx.ArtProvider.GetBitmap('PFS_FOLDER_OPEN_16'), name=u'cmdBrowseFolder', style=wx.BU_AUTODRAW) self.cmdBrowseFolder.Bind(wx.EVT_BUTTON, self.OnCmdBrowseFolderButton) @@ -138,33 +135,32 @@ self.lvAudio.Bind(wx.EVT_LISTBOX, self.OnControlStatusAudio) self.cmdBrowseAudio = wx.BitmapButton(self, - bitmap=wx.ArtProvider.GetBitmap('wxART_FILE_OPEN', - wx.ART_TOOLBAR, (16, 16)), + bitmap=wx.ArtProvider.GetBitmap('PFS_MUSIC_16'), name=u'cmdBrowseAudio', style=wx.BU_AUTODRAW) self.cmdBrowseAudio.Bind(wx.EVT_BUTTON, self.OnCmdBrowseAudioButton) self.cmdAudioPreview = wx.BitmapButton(self, - bitmap=wx.ArtProvider.GetBitmap('PFS_PLAY_PAUSE', - wx.ART_TOOLBAR, (16, 16)), + bitmap=wx.ArtProvider.GetBitmap('PFS_PLAY_PAUSE_16'), name=u'cmdAudioPreview', style=wx.BU_AUTODRAW) + self.cmdAudioPreview.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_PLAY_PAUSE_D_16')) self.cmdAudioPreview.Bind(wx.EVT_BUTTON, self.OnCmdAudioPreviewButton) self.cmdAudioMoveUp = wx.BitmapButton(self, - bitmap=wx.ArtProvider.GetBitmap(wx.ART_GO_UP, - wx.ART_TOOLBAR, (16, 16)), + bitmap=wx.ArtProvider.GetBitmap('PFS_ARROW_UP_16'), name=u'cmdAudioMoveUp', style=wx.BU_AUTODRAW) + self.cmdAudioMoveUp.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_ARROW_UP_D_16')) self.cmdAudioMoveUp.Bind(wx.EVT_BUTTON, self.OnCmdAudioMove) self.cmdAudioMoveDown = wx.BitmapButton(self, - bitmap=wx.ArtProvider.GetBitmap(wx.ART_GO_DOWN, - wx.ART_TOOLBAR, (16, 16)), + bitmap=wx.ArtProvider.GetBitmap('PFS_ARROW_DOWN_16'), name=u'cmdAudioMoveDown', style=wx.BU_AUTODRAW) + self.cmdAudioMoveDown.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_ARROW_DOWN_D_16')) self.cmdAudioMoveDown.Bind(wx.EVT_BUTTON, self.OnCmdAudioMove) self.cmdAudioDel = wx.BitmapButton(self, - bitmap=wx.ArtProvider.GetBitmap(wx.ART_DELETE, - wx.ART_TOOLBAR, (16, 16)), + bitmap=wx.ArtProvider.GetBitmap('PFS_REMOVE_16'), name=u'cmdAudioDel', style=wx.BU_AUTODRAW) + self.cmdAudioDel.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_REMOVE_D_16')) self.cmdAudioDel.Bind(wx.EVT_BUTTON, self.OnCmdAudioDel) self.cbTotalLength = wx.CheckBox(self, @@ -179,7 +175,7 @@ self.timeCtrlTotalLength = wx.lib.masked.timectrl.TimeCtrl(self, display_seconds=True, fmt24hr=True, - name=u'timeCtrlTotalLength', oob_color=wx.NamedColour('Yellow'), + name=u'timeCtrlTotalLength', oob_color=wx.YELLOW, style=0, useFixedWidthFont=True, value='12:00:00 AM') self.timeCtrlTotalLength.Enable(False) @@ -220,23 +216,23 @@ self.pnlHdr.SetTitle(_(u'PhotoFilmStrip project')) self.pnlHdr.SetBitmap(wx.ArtProvider.GetBitmap('PFS_ICON_48', wx.ART_TOOLBAR, (32, 32))) - + self.choiceAspect.Append(Aspect.ASPECT_16_9) self.choiceAspect.Append(Aspect.ASPECT_4_3) self.choiceAspect.Append(Aspect.ASPECT_3_2) self.choiceAspect.Select(0) - + self.tcProject.SetMinSize(wx.Size(300, -1)) self.tcFolder.SetMinSize(wx.Size(300, -1)) self.choiceAspect.SetMinSize(wx.Size(300, -1)) self.timeCtrlTotalLength.SetMinSize(wx.Size(300, -1)) self.lvAudio.SetMinSize(wx.Size(300, -1)) - - defTime = wx.DateTime_Now() + + defTime = wx.DateTime.Now() defTime.SetHMS(0, 0, 30) - minTime = wx.DateTime_Now() + minTime = wx.DateTime.Now() minTime.SetHMS(0, 0, 1) - maxTime = wx.DateTime_Now() + maxTime = wx.DateTime.Now() maxTime.SetHMS(1, 59, 59) self.timeCtrlTotalLength.SetValue(defTime) self.timeCtrlTotalLength.SetMin(minTime) @@ -246,7 +242,7 @@ self.mediaCtrl = None self.__project = project - + if project is None: projName = _(u"Unnamed PhotoFilmStrip") self.tcProject.SetValue(projName) @@ -258,21 +254,21 @@ projPath = os.path.join(wx.GetHomeDir(), _(u"My PhotoFilmStrips")) Settings().SetProjectPath(projPath) self.tcFolder.SetValue(projPath) - + self.cbTotalLength.SetValue(False) self.rbManual.SetValue(True) else: projName = os.path.splitext(os.path.basename(project.GetFilename()))[0] self.tcProject.SetValue(projName) self.tcProject.Enable(False) - + self.tcFolder.SetValue(os.path.dirname(project.GetFilename())) self.tcFolder.Enable(False) self.cmdBrowseFolder.Enable(False) - + self.choiceAspect.SetStringSelection(project.GetAspect()) self.choiceAspect.Enable(False) - + pfsDur = project.GetDuration(calc=True) duration = project.GetDuration(calc=False) if project.GetTimelapse(): @@ -288,7 +284,9 @@ self.rbManual.SetValue(True) pfsDur = duration - dur = wx.DateTime_Now() + pfsDur = int(round(pfsDur)) + + dur = wx.DateTime.Now() dur.SetHMS(0, pfsDur / 60, pfsDur % 60) try: self.timeCtrlTotalLength.SetWxDateTime(dur) @@ -306,10 +304,10 @@ self.Fit() self.CenterOnParent() self.SetFocus() - + def OnCmdBrowseFolderButton(self, event): - dlg = wx.DirDialog(self, - _(u"Browse for folder"), + dlg = wx.DirDialog(self, + _(u"Browse for folder"), defaultPath=self.tcFolder.GetValue()) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() @@ -321,22 +319,22 @@ def OnControlStatusTotalLength(self, event): self.__ControlStatusTotalLength() event.Skip() - + def OnControlStatusAudio(self, event): self.__ControlStatusAudio() def OnCmdBrowseAudioButton(self, event): - dlg = wx.FileDialog(self, _(u"Select music"), - Settings().GetAudioPath(), "", - _(u"Audio files") + " (*.*)|*.*", + dlg = wx.FileDialog(self, _(u"Select music"), + Settings().GetAudioPath(), "", + _(u"Audio files") + " (*.*)|*.*", wx.FD_OPEN | wx.FD_MULTIPLE) if dlg.ShowModal() == wx.ID_OK: path = dlg.GetPath() Settings().SetAudioPath(os.path.dirname(path)) - + for path in dlg.GetPaths(): self.lvAudio.Append(path) - + dlg.Destroy() def OnCmdAudioPreviewButton(self, event): @@ -385,7 +383,7 @@ self.lvAudio.Select(min(selIdx, self.lvAudio.GetCount() - 1)) self.__ControlStatusAudio() - + def OnDlgProjectPropsClose(self, event): self.__CloseMediaCtrl() event.Skip() @@ -400,17 +398,17 @@ # def __GetChoiceDataSelected(self, choice): # return choice.GetClientData(choice.GetSelection()) -# +# # def __SetChoiceSelectionByData(self, choice, data): # for idx in range(choice.GetCount()): # if choice.GetClientData(idx) == data: # choice.Select(idx) # return - + def __ControlStatusTotalLength(self): active = self.cbTotalLength.GetValue() manual = self.rbManual.GetValue() - + self.rbAudio.Enable(active) self.rbManual.Enable(active) self.rbTimelapse.Enable(active) @@ -422,8 +420,8 @@ self.cmdAudioPreview.Enable(selected != wx.NOT_FOUND) self.cmdAudioDel.Enable(selected != wx.NOT_FOUND) self.cmdAudioMoveUp.Enable(selected > 0) - self.cmdAudioMoveDown.Enable(selected < (self.lvAudio.GetCount()-1)) - + self.cmdAudioMoveDown.Enable(selected < (self.lvAudio.GetCount() - 1)) + def __LoadAudioFile(self, path): self.__CloseMediaCtrl() @@ -446,12 +444,12 @@ wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() - + def __ValidateAudioFile(self): for path in self.lvAudio.GetItems(): if not os.path.exists(path): dlg = wx.MessageDialog(self, - _(u"Audio file '%s' does not exist!") % path, + _(u"Audio file '%s' does not exist!") % path, _(u"Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() @@ -466,10 +464,10 @@ except: pass self.mediaCtrl = None - + def __GetTotalLength(self): totalLength = None - + if self.cbTotalLength.GetValue(): if self.rbManual.GetValue(): totalLength = 0 @@ -481,16 +479,16 @@ totalLength = -1 elif self.rbTimelapse.GetValue(): totalLength = None - + return totalLength - + def __ValidateOutDir(self, path=None): if path is None: path = self.tcFolder.GetValue().strip() - + if not os.path.isdir(path): dlg = wx.MessageDialog(self, - _(u"Folder does not exists! Do you want %s to create it?") % Constants.APP_NAME, + _(u"Folder does not exists! Do you want %s to create it?") % Constants.APP_NAME, _(u"Question"), wx.YES_NO | wx.ICON_QUESTION) resp = dlg.ShowModal() @@ -538,19 +536,19 @@ else: self.pnlHdr.SetErrorMessage(u"") return True - + def __GetProjectPath(self): projName = self.tcProject.GetValue().strip() projName = projName.strip(u".") - filepath = os.path.join(self.tcFolder.GetValue().strip(), + filepath = os.path.join(self.tcFolder.GetValue().strip(), projName, "%s.pfs" % projName) return filepath - + def Destroy(self): self.__CloseMediaCtrl() wx.Dialog.Destroy(self) - + def GetProject(self): if self.__project is None: self.__project = Project(self.__GetProjectPath()) diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/DlgRendererProps.py photofilmstrip-3.3.1/photofilmstrip/gui/DlgRendererProps.py --- photofilmstrip-3.2.0/photofilmstrip/gui/DlgRendererProps.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/DlgRendererProps.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:Dialog:DlgRendererProps +# Boa:Dialog:DlgRendererProps # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -27,19 +27,18 @@ from photofilmstrip.gui.HelpViewer import HelpViewer from photofilmstrip.gui.ctrls.PnlDlgHeader import PnlDlgHeader - -[wxID_DLGRENDERERPROPS, wxID_DLGRENDERERPROPSCMDCANCEL, - wxID_DLGRENDERERPROPSCMDHELP, wxID_DLGRENDERERPROPSCMDOK, - wxID_DLGRENDERERPROPSLCPROPS, wxID_DLGRENDERERPROPSPNLHDR, - wxID_DLGRENDERERPROPSSTATICLINE, +[wxID_DLGRENDERERPROPS, wxID_DLGRENDERERPROPSCMDCANCEL, + wxID_DLGRENDERERPROPSCMDHELP, wxID_DLGRENDERERPROPSCMDOK, + wxID_DLGRENDERERPROPSLCPROPS, wxID_DLGRENDERERPROPSPNLHDR, + wxID_DLGRENDERERPROPSSTATICLINE, ] = [wx.NewId() for _init_ctrls in range(7)] class DlgRendererProps(wx.Dialog): - + _custom_classes = {"wx.Choice": ["FormatComboBox"], "wx.Panel": ["PnlDlgHeader"]} - + def _init_coll_sizerCmd_Items(self, parent): # generated method, don't edit @@ -110,8 +109,8 @@ id=wxID_DLGRENDERERPROPSCMDCANCEL) self.cmdOk = wx.Button(id=wxID_DLGRENDERERPROPSCMDOK, label=_(u'&Ok'), - name=u'cmdOk', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, - -1), style=0) + name=u'cmdOk', parent=self, pos=wx.Point(-1, -1), + size=wx.Size(-1, -1), style=0) self.cmdOk.Bind(wx.EVT_BUTTON, self.OnCmdOkButton, id=wxID_DLGRENDERERPROPSCMDOK) @@ -124,11 +123,9 @@ def __init__(self, parent, rendererClass): self._init_ctrls(parent) self.Bind(wx.EVT_CLOSE, self.OnCmdCancelButton) - + self.pnlHdr.SetTitle(_(u'Edit extended output properties')) - self.pnlHdr.SetBitmap(wx.ArtProvider.GetBitmap('wxART_EXECUTABLE_FILE', - wx.ART_TOOLBAR, (32, 32))) - + self.pnlHdr.SetBitmap(wx.ArtProvider.GetBitmap('PFS_VIDEO_FORMAT_32')) self.rendererClass = rendererClass self.lcProps.DeleteAllItems() @@ -136,18 +133,18 @@ for prop in rendererClass.GetProperties(): value = savedProps.get(prop.lower(), rendererClass.GetProperty(prop)) self.lcProps.Append([prop, value]) - + rendererClass.SetProperty(prop, value) - + self.SetAffirmativeId(wxID_DLGRENDERERPROPSCMDOK) self.SetEscapeId(wxID_DLGRENDERERPROPSCMDCANCEL) self.SetInitialSize(self.GetEffectiveMinSize()) self.CentreOnParent() self.SetFocus() - + def OnCmdCancelButton(self, event): self.EndModal(wx.ID_CANCEL) - + def OnCmdOkButton(self, event): propDict = {} for prop in self.rendererClass.GetProperties(): @@ -160,9 +157,9 @@ def OnActivateProperty(self, event): idx = event.GetIndex() prop = self.lcProps.GetItemText(idx) - dlg = wx.TextEntryDialog(self, - _(u"Edit property"), - prop, + dlg = wx.TextEntryDialog(self, + _(u"Edit property"), + prop, unicode(self.rendererClass.GetProperty(prop))) if dlg.ShowModal() == wx.ID_OK: value = dlg.GetValue() @@ -171,8 +168,7 @@ self.rendererClass.SetProperty(prop, value) self.lcProps.SetStringItem(idx, 1, unicode(value)) dlg.Destroy() - + def OnCmdHelpButton(self, event): HelpViewer().DisplayID(HelpViewer.ID_RENDER) event.Skip() - diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/DlgRender.py photofilmstrip-3.3.1/photofilmstrip/gui/DlgRender.py --- photofilmstrip-3.2.0/photofilmstrip/gui/DlgRender.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/DlgRender.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:Dialog:DlgRender +# Boa:Dialog:DlgRender # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -20,40 +20,35 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # -import os - import wx import wx.combo - from photofilmstrip.core.OutputProfile import ( - OutputProfile, GetOutputProfiles, GetMPEGProfiles) + GetOutputProfiles, GetMPEGProfiles) from photofilmstrip.core.Renderer import RENDERERS from photofilmstrip.lib.Settings import Settings -from photofilmstrip.lib.util import CheckFile -from photofilmstrip.lib.jobimpl.JobManager import JobManager from photofilmstrip.gui.ctrls.PnlDlgHeader import PnlDlgHeader from photofilmstrip.gui.HelpViewer import HelpViewer from photofilmstrip.gui.DlgRendererProps import DlgRendererProps -from photofilmstrip.action.ActionRender import ActionRender -from photofilmstrip.core.exceptions import RenderException -[wxID_DLGRENDER, wxID_DLGRENDERCBDRAFT, wxID_DLGRENDERCHOICEFORMAT, - wxID_DLGRENDERCHOICEPROFILE, wxID_DLGRENDERCHOICETYPE, - wxID_DLGRENDERCMDCANCEL, wxID_DLGRENDERCMDHELP, - wxID_DLGRENDERCMDRENDERERPROPS, wxID_DLGRENDERCMDSTART, wxID_DLGRENDERPNLHDR, - wxID_DLGRENDERPNLSETTINGS, wxID_DLGRENDERSTFORMAT, wxID_DLGRENDERSTPROFILE, - wxID_DLGRENDERSTTYPE, -] = [wx.NewId() for _init_ctrls in range(14)] +[wxID_DLGRENDER, wxID_DLGRENDERCBDRAFT, wxID_DLGRENDERCHOICEFORMAT, + wxID_DLGRENDERCHOICEPROFILE, + wxID_DLGRENDERCMDCANCEL, wxID_DLGRENDERCMDHELP, + wxID_DLGRENDERCMDRENDERERPROPS, wxID_DLGRENDERCMDSTART, wxID_DLGRENDERPNLHDR, + wxID_DLGRENDERPNLSETTINGS, wxID_DLGRENDERSTFORMAT, wxID_DLGRENDERSTPROFILE, +] = [wx.NewId() for _init_ctrls in range(12)] class DlgRender(wx.Dialog): - + _custom_classes = {"wx.Choice": ["FormatComboBox"], "wx.Panel": ["PnlDlgHeader"]} - + + DEFAULT_FORMAT = u"x264/AC3 (MKV)" + DEFAULT_PROFILE = u"HD 720p@25.00 fps" + def _init_coll_sizerMain_Items(self, parent): # generated method, don't edit @@ -83,11 +78,7 @@ flag=wx.ALIGN_CENTER_VERTICAL) parent.AddWindow(self.choiceProfile, 0, border=0, flag=wx.EXPAND) parent.AddSpacer(wx.Size(8, 8), border=0, flag=0) - parent.AddWindow(self.stType, 0, border=0, - flag=wx.ALIGN_CENTER_VERTICAL) - parent.AddWindow(self.choiceType, 0, border=0, flag=wx.EXPAND) parent.AddSpacer(wx.Size(8, 8), border=0, flag=0) - parent.AddSpacer(wx.Size(8, 8), border=0, flag=wx.ALIGN_CENTER_VERTICAL) parent.AddWindow(self.cbDraft, 0, border=0, flag=0) def _init_coll_sizerSettings_Growables(self, parent): @@ -115,196 +106,178 @@ def _init_ctrls(self, prnt): # generated method, don't edit wx.Dialog.__init__(self, id=wxID_DLGRENDER, name=u'DlgRender', - parent=prnt, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), - style=wx.DEFAULT_DIALOG_STYLE, title=_(u'Render filmstrip')) + parent=prnt, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), + style=wx.DEFAULT_DIALOG_STYLE, title=_(u'Render filmstrip')) self.SetClientSize(wx.Size(400, 250)) self.pnlHdr = PnlDlgHeader(id=wxID_DLGRENDERPNLHDR, name=u'pnlHdr', - parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), - style=wx.TAB_TRAVERSAL) + parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), + style=wx.TAB_TRAVERSAL) self.pnlSettings = wx.Panel(id=wxID_DLGRENDERPNLSETTINGS, - name=u'pnlSettings', parent=self, pos=wx.Point(-1, -1), - size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL) + name=u'pnlSettings', parent=self, pos=wx.Point(-1, -1), + size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL) self.stFormat = wx.StaticText(id=wxID_DLGRENDERSTFORMAT, - label=_(u'Format:'), name=u'stFormat', parent=self.pnlSettings, - pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) + label=_(u'Format:'), name=u'stFormat', parent=self.pnlSettings, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.choiceFormat = FormatComboBox(choices=[], - id=wxID_DLGRENDERCHOICEFORMAT, name=u'choiceFormat', - parent=self.pnlSettings, pos=wx.Point(-1, -1), size=wx.Size(-1, - -1), style=wx.CB_READONLY) + id=wxID_DLGRENDERCHOICEFORMAT, name=u'choiceFormat', + parent=self.pnlSettings, pos=wx.Point(-1, -1), + size=wx.Size(-1, -1), style=wx.CB_READONLY) self.choiceFormat.SetMinSize(wx.Size(300, -1)) self.choiceFormat.Bind(wx.EVT_COMBOBOX, self.OnChoiceFormat, - id=wxID_DLGRENDERCHOICEFORMAT) + id=wxID_DLGRENDERCHOICEFORMAT) - self.cmdRendererProps = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('wxART_EXECUTABLE_FILE', - wx.ART_TOOLBAR, (16, 16)), + self.cmdRendererProps = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('PFS_VIDEO_FORMAT_16'), id=wxID_DLGRENDERCMDRENDERERPROPS, name=u'cmdRendererProps', - parent=self.pnlSettings, pos=wx.Point(-1, -1), size=wx.Size(-1, - -1), style=wx.BU_AUTODRAW) - self.cmdRendererProps.SetToolTipString(_("Properties")) + parent=self.pnlSettings, pos=wx.Point(-1, -1), + size=wx.Size(-1, -1), style=wx.BU_AUTODRAW) + self.cmdRendererProps.SetToolTipString(_(u"Properties")) self.cmdRendererProps.Bind(wx.EVT_BUTTON, self.OnCmdRendererPropsButton, - id=wxID_DLGRENDERCMDRENDERERPROPS) + id=wxID_DLGRENDERCMDRENDERERPROPS) self.stProfile = wx.StaticText(id=wxID_DLGRENDERSTPROFILE, - label=_(u'Resolution:'), name=u'stProfile', parent=self.pnlSettings, - pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) + label=_(u'Profile:'), name=u'stProfile', parent=self.pnlSettings, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.choiceProfile = wx.Choice(choices=[], - id=wxID_DLGRENDERCHOICEPROFILE, name=u'choiceProfile', - parent=self.pnlSettings, pos=wx.Point(-1, -1), size=wx.Size(-1, - -1), style=0) + id=wxID_DLGRENDERCHOICEPROFILE, name=u'choiceProfile', + parent=self.pnlSettings, pos=wx.Point(-1, -1), size=wx.Size(-1, + - 1), style=0) self.choiceProfile.SetMinSize(wx.Size(300, -1)) - self.stType = wx.StaticText(id=wxID_DLGRENDERSTTYPE, label=_(u'Type:'), - name=u'stType', parent=self.pnlSettings, pos=wx.Point(-1, -1), - size=wx.Size(-1, -1), style=0) - - self.choiceType = wx.Choice(choices=[], id=wxID_DLGRENDERCHOICETYPE, - name=u'choiceType', parent=self.pnlSettings, pos=wx.Point(-1, -1), - size=wx.Size(-1, -1), style=0) - self.choiceType.SetMinSize(wx.Size(300, -1)) - self.cbDraft = wx.CheckBox(id=wxID_DLGRENDERCBDRAFT, label=_(u'Draft'), - name=u'cbDraft', parent=self.pnlSettings, pos=wx.Point(-1, -1), - size=wx.Size(-1, -1), style=0) + name=u'cbDraft', parent=self.pnlSettings, pos=wx.Point(-1, -1), + size=wx.Size(-1, -1), style=0) self.cbDraft.SetValue(False) self.cmdHelp = wx.Button(id=wx.ID_HELP, label=_(u'&Help'), - name=u'cmdHelp', parent=self, pos=wx.Point(-1, -1), - size=wx.Size(-1, -1), style=0) + name=u'cmdHelp', parent=self, pos=wx.Point(-1, -1), + size=wx.Size(-1, -1), style=0) self.cmdHelp.Bind(wx.EVT_BUTTON, self.OnCmdHelpButton, id=wx.ID_HELP) self.cmdCancel = wx.Button(id=wxID_DLGRENDERCMDCANCEL, - label=_(u'&Cancel'), name=u'cmdCancel', parent=self, - pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) + label=_(u'&Cancel'), name=u'cmdCancel', parent=self, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.cmdCancel.Bind(wx.EVT_BUTTON, self.OnCmdCancelButton, - id=wxID_DLGRENDERCMDCANCEL) + id=wxID_DLGRENDERCMDCANCEL) self.cmdStart = wx.Button(id=wxID_DLGRENDERCMDSTART, label=_(u'&Start'), - name=u'cmdStart', parent=self, pos=wx.Point(-1, -1), - size=wx.Size(-1, -1), style=0) + name=u'cmdStart', parent=self, pos=wx.Point(-1, -1), + size=wx.Size(-1, -1), style=0) self.cmdStart.Bind(wx.EVT_BUTTON, self.OnCmdStartButton, - id=wxID_DLGRENDERCMDSTART) + id=wxID_DLGRENDERCMDSTART) self._init_sizers() - def __init__(self, parent, photoFilmStrip): + def __init__(self, parent, aspectRatio): self._init_ctrls(parent) self.Bind(wx.EVT_CLOSE, self.OnCmdCancelButton) - + self.pnlHdr.SetTitle(_('Configure output and start render process')) - self.pnlHdr.SetBitmap(wx.ArtProvider.GetBitmap(wx.ART_TICK_MARK, - wx.ART_TOOLBAR, (32, 32))) - - self.cbDraft.SetToolTipString(_(u"Activate this option to generate a preview of your PhotoFilmStrip. The rendering process will speed up dramatically, but results in lower quality.")) - - self.__photoFilmStrip = photoFilmStrip - self.__renderEngine = None - - for profile in GetOutputProfiles(photoFilmStrip.GetAspect()): - self.choiceProfile.Append(u"%s (%sx%s)" % (profile.GetName(), - profile.GetResolution()[0], - profile.GetResolution()[1]), - profile) - - self.choiceType.Append("PAL", OutputProfile.PAL) - self.choiceType.Append("NTSC", OutputProfile.NTSC) - self.choiceType.SetSelection(0) - - audioFile = self.__photoFilmStrip.GetAudioFile() - if audioFile and not os.path.exists(audioFile): - self.pnlHdr.SetErrorMessage(_(u"Audio file '%s' does not exist!") % audioFile) + self.pnlHdr.SetBitmap(wx.ArtProvider.GetBitmap('PFS_RENDER_32')) + + self.cbDraft.SetToolTipString(_(u"Activate this option to generate a preview. The rendering process will speed up dramatically, but results in lower quality.")) + + self.aspectRatio = aspectRatio + self.__InitProfiles() settings = Settings() - self.choiceProfile.SetSelection(settings.GetLastProfile()) - - self.__SetChoiceSelectionByData(self.choiceType, settings.GetVideoType()) - self.choiceFormat.SetSelection(settings.GetUsedRenderer()) + if settings.GetUsedRenderer() is None: + self.choiceFormat.SetStringSelection(self.DEFAULT_FORMAT) + else: + self.choiceFormat.SetSelection(settings.GetUsedRenderer()) self.OnChoiceFormat(None) - + + self.__SelectProfileByName(settings.GetLastProfile()) + self.SetEscapeId(wxID_DLGRENDERCMDCANCEL) self.SetInitialSize(self.GetEffectiveMinSize()) self.CentreOnParent() self.SetFocus() - + + self.profile = None + self.draftMode = False + self.rendererClass = None + def __GetChoiceDataSelected(self, choice): return choice.GetClientData(choice.GetSelection()) - - def __SetChoiceSelectionByData(self, choice, data): + + def __SelectProfileByName(self, profName): + if profName is None: + profName = self.DEFAULT_PROFILE + choice = self.choiceProfile for idx in range(choice.GetCount()): - if choice.GetClientData(idx) == data: + prof = choice.GetClientData(idx) + if prof and prof.GetName() == profName: choice.Select(idx) return - def __GetOutputPath(self): - profile = self.__GetChoiceDataSelected(self.choiceProfile) - outpath = os.path.dirname(self.__photoFilmStrip.GetFilename()) - outpath = os.path.join(outpath, profile.GetName()) - return outpath - + choice.Select(0) + + def __InitProfiles(self, filtr=None, profiles=None): + if profiles is None: + profiles = [] + profs = GetOutputProfiles(self.aspectRatio) + for prof in profs: + if prof.GetFriendlyName(): + profiles.append(prof) + profiles.append("-") + profiles.extend(profs) + + selection = self.choiceFormat.GetStringSelection() + self.choiceProfile.Clear() + + useFriendlyName = True + for profile in profiles: + if profile == "-": + self.choiceProfile.Append(u"----------") + useFriendlyName = False + continue + + if filtr and not profile.GetName().startswith(filtr): + continue + + if useFriendlyName: + profName = profile.GetFriendlyName() + else: + profName = profile.GetName() + + self.choiceProfile.Append(u"%s (%sx%s)" % (profName, + profile.GetResolution()[0], + profile.GetResolution()[1]), + profile) + + self.choiceProfile.SetStringSelection(selection) + def OnChoiceFormat(self, event): if event is None: formatData = self.__GetChoiceDataSelected(self.choiceFormat) else: formatData = event.GetClientData() - - strAuto = _(u"Automatic") - idxAuto = self.choiceProfile.FindString(strAuto) - if idxAuto != wx.NOT_FOUND: - self.choiceProfile.Delete(idxAuto) - + if isinstance(formatData, FormatData): self.cmdStart.Enable(formatData.IsOk()) if formatData.IsMPEG(): - self.choiceProfile.Append(strAuto) - self.choiceProfile.SetStringSelection(strAuto) - self.choiceProfile.Enable(False) + self.__InitProfiles(formatData.GetRendererClass().GetName().split(" ")[0], + GetMPEGProfiles()) else: - self.choiceProfile.Enable(True) - self.choiceProfile.Select(0) + self.__InitProfiles() + + self.__SelectProfileByName(Settings().GetLastProfile()) def OnCmdStartButton(self, event): formatData = self.__GetChoiceDataSelected(self.choiceFormat) - rendererClass = formatData.PRendererClass + self.rendererClass = formatData.GetRendererClass() - profile = GetMPEGProfiles().get(rendererClass.GetName()) - if profile is None: - profile = self.__GetChoiceDataSelected(self.choiceProfile) + profile = self.__GetChoiceDataSelected(self.choiceProfile) if profile is None: return - ar = ActionRender(self.__photoFilmStrip, - profile, - self.__GetChoiceDataSelected(self.choiceType), - rendererClass, - self.cbDraft.GetValue()) - - audioFile = self.__photoFilmStrip.GetAudioFile() - if not CheckFile(audioFile): - dlg = wx.MessageDialog(self, - _(u"Audio file '%s' does not exist! Continue anyway?") % audioFile, - _(u"Warning"), - wx.YES_NO | wx.ICON_WARNING) - try: - if dlg.ShowModal() == wx.ID_NO: - return - finally: - dlg.Destroy() - - try: - ar.Execute() - renderJob = ar.GetRenderJob() - JobManager().EnqueueContext(renderJob) - except RenderException, exc: - dlg = wx.MessageDialog(self, - exc.GetMessage(), - _(u"Error"), - wx.OK | wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() + self.profile = profile + self.draftMode = self.cbDraft.GetValue() self.EndModal(wx.ID_OK) @@ -315,34 +288,40 @@ data = self.__GetChoiceDataSelected(self.choiceFormat) if data is None: return - rendererClass = data.PRendererClass - + rendererClass = data.GetRendererClass() + dlg = DlgRendererProps(self, rendererClass) dlg.ShowModal() dlg.Destroy() - + def OnCmdHelpButton(self, event): HelpViewer().DisplayID(HelpViewer.ID_RENDER) event.Skip() + def GetProfile(self): + return self.profile + + def GetDraftMode(self): + return self.draftMode + + def GetRendererClass(self): + return self.rendererClass + class FormatComboBox(wx.combo.OwnerDrawnComboBox): - + def __init__(self, *args, **kwargs): wx.combo.OwnerDrawnComboBox.__init__(self, *args, **kwargs) for rend in RENDERERS: - if rend.GetName() in FormatData.MPEG_PROFILES: - continue - self.AddRenderer(rend) - + def AddRenderer(self, rend, altName=None): msgList = [] rend.CheckDependencies(msgList) - self.Append(altName or rend.GetName(), + self.Append(altName or rend.GetName(), FormatData(rend, msgList)) - + def SetSelection(self, index): if index >= self.GetCount(): index = 0 @@ -353,47 +332,52 @@ return data = self.GetClientData(item) - + rect2 = wx.Rect(*rect) rect2.Deflate(5, 0) - if data.PMessages: - bmp = wx.ArtProvider_GetBitmap(wx.ART_ERROR, wx.ART_OTHER, (16, 16)) - dc.SetTextForeground(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT)) + if data.GetMessages(): + bmp = wx.ArtProvider.GetBitmap('PFS_ALERT_16') + dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) else: bmp = wx.NullBitmap if flags & wx.combo.ODCB_PAINTING_SELECTED: - dc.SetTextForeground(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) + dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) else: - dc.SetTextForeground(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOWTEXT)) + dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) if flags & wx.combo.ODCB_PAINTING_CONTROL: - dc.DrawLabel(self.GetString(item), rect2, wx.ALIGN_CENTER_VERTICAL) - + dc.DrawLabel(self.GetString(item), rect2, wx.ALIGN_CENTER_VERTICAL) else: - dc.DrawImageLabel("\n".join([self.GetString(item)] + data.PMessages), - bmp, rect2, - wx.ALIGN_CENTER_VERTICAL) + dc.DrawImageLabel("\n".join([self.GetString(item)] + data.GetMessages()), + bmp, rect2, + wx.ALIGN_CENTER_VERTICAL) def OnMeasureItem(self, item): data = self.GetClientData(item) - height = self.GetTextExtent(self.GetString(item))[1] * (len(data.PMessages) + 1) + height = self.GetTextExtent(self.GetString(item))[1] * (len(data.GetMessages()) + 1) return height + 8 class FormatData(object): - + MPEG_PROFILES = ("VCD", "SVCD", "DVD") - + def __init__(self, rendClass, msgList): - self.PRendererClass = rendClass - self.PMessages = msgList + self._rendererClass = rendClass + self._msgList = msgList def IsOk(self): - return len(self.PMessages) == 0 - + return len(self._msgList) == 0 + def IsMPEG(self): for mpegProf in FormatData.MPEG_PROFILES: - if self.PRendererClass.GetName().startswith(mpegProf): + if self._rendererClass.GetName().startswith(mpegProf): return True - return False + return False + + def GetRendererClass(self): + return self._rendererClass + + def GetMessages(self): + return self._msgList diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/FrmMain.py photofilmstrip-3.3.1/photofilmstrip/gui/FrmMain.py --- photofilmstrip-3.2.0/photofilmstrip/gui/FrmMain.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/FrmMain.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:Frame:FrmMain +# Boa:Frame:FrmMain # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -30,6 +30,8 @@ from photofilmstrip.action.ActionI18N import ActionI18N +from photofilmstrip.core.RenderJob import RenderJob + from photofilmstrip.lib.common.ObserverPattern import Observer from photofilmstrip.lib.Settings import Settings from photofilmstrip.lib.util import Decode @@ -39,223 +41,156 @@ from photofilmstrip.lib.jobimpl.JobManager import JobManager from photofilmstrip.lib.jobimpl.PnlJobManager import PnlJobManager -from photofilmstrip.gui.DlgRender import DlgRender -from photofilmstrip.gui.PnlWelcome import PnlWelcome from photofilmstrip.gui.ActionManager import ActionManager +from photofilmstrip.gui.PnlWelcome import PnlWelcome from photofilmstrip.gui.HelpViewer import HelpViewer from photofilmstrip.gui.DlgProjectProps import DlgProjectProps from photofilmstrip.gui.PnlPfsProject import PnlPfsProject from photofilmstrip.gui.WxProjectFile import WxProjectFile from photofilmstrip.gui.PnlRenderJobVisual import PnlRenderJobVisual +from photofilmstrip.gui.PnlEditorPage import PnlEditorPage from photofilmstrip.res.license import licenseText -from photofilmstrip.core.RenderJob import RenderJob + +ID_PAGE_UP = wx.NewId() +ID_PAGE_DOWN = wx.NewId() class FrmMain(wx.Frame, Observer, WxVisualJobManager): - + def __init__(self): wx.Frame.__init__(self, None, -1, name=u'FrmMain', pos=wx.Point(-1, -1), size=wx.Size(-1, -1), - style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL, - title='PhotoFilmStrip') + style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL) WxVisualJobManager.__init__(self) - self.Bind(wx.EVT_CLOSE, self.OnClose) self.SetTitle(Constants.APP_NAME) - + iconBundle = wx.IconBundle() - iconBundle.AddIcon(wx.ArtProvider_GetIcon("PFS_ICON_16", wx.ART_OTHER)) - iconBundle.AddIcon(wx.ArtProvider_GetIcon("PFS_ICON_24", wx.ART_OTHER)) - iconBundle.AddIcon(wx.ArtProvider_GetIcon("PFS_ICON_32", wx.ART_OTHER)) - iconBundle.AddIcon(wx.ArtProvider_GetIcon("PFS_ICON_48", wx.ART_OTHER)) - iconBundle.AddIcon(wx.ArtProvider_GetIcon("PFS_ICON_64", wx.ART_OTHER)) - iconBundle.AddIcon(wx.ArtProvider_GetIcon("PFS_ICON_128", wx.ART_OTHER)) + iconBundle.AddIcon(wx.ArtProvider.GetIcon("PFS_ICON_16", wx.ART_OTHER)) + iconBundle.AddIcon(wx.ArtProvider.GetIcon("PFS_ICON_24", wx.ART_OTHER)) + iconBundle.AddIcon(wx.ArtProvider.GetIcon("PFS_ICON_32", wx.ART_OTHER)) + iconBundle.AddIcon(wx.ArtProvider.GetIcon("PFS_ICON_48", wx.ART_OTHER)) + iconBundle.AddIcon(wx.ArtProvider.GetIcon("PFS_ICON_64", wx.ART_OTHER)) + iconBundle.AddIcon(wx.ArtProvider.GetIcon("PFS_ICON_128", wx.ART_OTHER)) self.SetIcons(iconBundle) - + self.statusBar = wx.StatusBar(self) self.statusBar.SetFieldsCount(4) self.statusBar.Bind(wx.EVT_LEFT_DOWN, self.OnStatusBarLeftDown) self.SetStatusBar(self.statusBar) - - self.actionManager = ActionManager() - - menuBar = self.actionManager.GetMenuBar() - self.SetMenuBar(menuBar) - toolBar = self.actionManager.GetToolBar(self) - self.SetToolBar(toolBar) - + + self.menuBar = wx.MenuBar() + self.SetMenuBar(self.menuBar) + + self.toolBar = wx.ToolBar(self) + self.SetToolBar(self.toolBar) + + self._actionMgr = ActionManager(self, self.menuBar, self.toolBar) + self.notebook = wx.aui.AuiNotebook(self, -1, style=wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB) self.notebook.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged) self.notebook.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnPageClose) - + self.pnlWelcome = PnlWelcome(self.notebook, self) self.pnlWelcome.SetDropTarget(ProjectDropTarget(self)) - + self.notebook.AddPage(self.pnlWelcome, _(u"Welcome"), True) - + self.frmJobManager = wx.Frame(self, -1, _(u"Job queue"), - size=wx.Size(600,400), + size=wx.Size(600, 400), style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP) + self.frmJobManager.SetIcon(wx.ArtProvider.GetIcon("PFS_JOB_QUEUE_16", wx.ART_OTHER)) self.frmJobManager.Bind(wx.EVT_CLOSE, self.OnCloseFrameJobManager) - pnlJobManager = PnlJobManager(self.frmJobManager, pnlJobClass=PnlRenderJobVisual) - + PnlJobManager(self.frmJobManager, pnlJobClass=PnlRenderJobVisual) + + self.Bind(wx.EVT_CLOSE, self.OnClose) + self.Bind(wx.EVT_MENU, self.OnProjectNew, id=wx.ID_NEW) self.Bind(wx.EVT_MENU, self.OnProjectLoad, id=wx.ID_OPEN) self.Bind(wx.EVT_MENU, self.OnProjectSave, id=wx.ID_SAVE) - self.Bind(wx.EVT_MENU, self.OnProjectClose, id=ActionManager.ID_PROJECT_CLOSE) self.Bind(wx.EVT_MENU, self.OnProjectSaveAs, id=wx.ID_SAVEAS) - self.Bind(wx.EVT_MENU, self.OnProjectExport, id=ActionManager.ID_PROJECT_EXPORT) - self.Bind(wx.EVT_MENU, self.OnProjectImport, id=ActionManager.ID_PROJECT_IMPORT) - self.Bind(wx.EVT_MENU, self.OnProjectProps, id=ActionManager.ID_PROJECT_PROPS) + self.Bind(wx.EVT_MENU, self.OnProjectClose, + id=ActionManager.ID_PROJECT_CLOSE) self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) - - self.Bind(wx.EVT_MENU, self.OnCmdMoveLeftButton, id=ActionManager.ID_PIC_MOVE_LEFT) - self.Bind(wx.EVT_MENU, self.OnCmdMoveRightButton, id=ActionManager.ID_PIC_MOVE_RIGHT) - self.Bind(wx.EVT_MENU, self.OnCmdRemoveButton, id=ActionManager.ID_PIC_REMOVE) - - self.Bind(wx.EVT_MENU, self.OnCmdRotateLeftButton, id=ActionManager.ID_PIC_ROTATE_CCW) - self.Bind(wx.EVT_MENU, self.OnCmdRotateRightButton, id=ActionManager.ID_PIC_ROTATE_CW) - self.Bind(wx.EVT_MENU, self.OnCmdMotionRandom, id=ActionManager.ID_PIC_MOTION_RANDOM) - self.Bind(wx.EVT_MENU, self.OnCmdMotionCenter, id=ActionManager.ID_PIC_MOTION_CENTER) - - self.Bind(wx.EVT_MENU, self.OnImportPics, id=ActionManager.ID_PIC_IMPORT) self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT) self.Bind(wx.EVT_MENU, self.OnHelpIndex, id=wx.ID_HELP) for wxId in ActionManager.LANG_MAP.keys(): self.Bind(wx.EVT_MENU, self.OnChangeLanguage, id=wxId) - self.Bind(wx.EVT_MENU, self.OnRenderFilmstrip, id=ActionManager.ID_RENDER_FILMSTRIP) - self.Bind(wx.EVT_MENU, self.OnShowFrameJobManager, id=ActionManager.ID_JOB_QUEUE) - + self.Bind(wx.EVT_MENU, self.OnShowFrameJobManager, + id=ActionManager.ID_JOB_QUEUE) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectChanged, id=wx.ID_SAVE) self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectActive, id=wx.ID_SAVEAS) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectActive, id=ActionManager.ID_PIC_IMPORT) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectActive, id=ActionManager.ID_PROJECT_EXPORT) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectActive, id=ActionManager.ID_PROJECT_PROPS) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectActive, id=ActionManager.ID_PROJECT_CLOSE) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectReady, id=ActionManager.ID_RENDER_FILMSTRIP) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ActionManager.ID_PIC_REMOVE) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ActionManager.ID_PIC_ROTATE_CCW) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ActionManager.ID_PIC_ROTATE_CW) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ActionManager.ID_PIC_MOVE_LEFT) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ActionManager.ID_PIC_MOVE_RIGHT) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ActionManager.ID_PIC_MOTION_RANDOM) - self.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ActionManager.ID_PIC_MOTION_CENTER) - + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectActive, + id=ActionManager.ID_PROJECT_CLOSE) + + self.Bind(wx.EVT_MENU, self.OnHelpContent, id=wx.ID_HELP_CONTENTS) + self.Bind(wx.EVT_MENU, self.OnPageNext, id=ID_PAGE_DOWN) + self.Bind(wx.EVT_MENU, self.OnPagePrev, id=ID_PAGE_UP) + self.SetInitialSize((720, 680)) - - id1 = wx.NewId() - id2 = wx.NewId() + at = wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_F1, wx.ID_HELP_CONTENTS), - (wx.ACCEL_CTRL, wx.WXK_PAGEDOWN, id1), - (wx.ACCEL_CTRL, wx.WXK_PAGEUP, id2)]) + (wx.ACCEL_CTRL, wx.WXK_PAGEDOWN, ID_PAGE_DOWN), + (wx.ACCEL_CTRL, wx.WXK_PAGEUP, ID_PAGE_UP)]) self.SetAcceleratorTable(at) - self.Bind(wx.EVT_MENU, self.OnHelpContent, id=wx.ID_HELP_CONTENTS) - self.Bind(wx.EVT_MENU, self.OnPageNext, id=id1) - self.Bind(wx.EVT_MENU, self.OnPagePrev, id=id2) - self.actionManager.SelectLanguage(Settings().GetLanguage()) JobManager().AddVisual(self) - + self.Bind(EVT_REGISTER_JOB, self.OnRegisterJob) self.Bind(EVT_REMOVE_JOB, self.OnRemoveJob) - + def ObservableUpdate(self, obj, arg): if obj is self.__GetCurrentProject(): self.UpdateStatusText() +#### Event-Handler - Begin ##################################################### +# Jobs def OnRegisterJob(self, event): job = event.GetJob() if isinstance(job, RenderJob): self.statusBar.SetStatusText(_(u"Rendering in progress..."), 3) - + def OnRemoveJob(self, event): self.statusBar.SetStatusText("", 3) - def OnStatusBarLeftDown(self, event): - if self.statusBar.GetFieldRect(3).Contains(event.GetPosition()) \ - and self.statusBar.GetStatusText(3) != "": - self.frmJobManager.Show() + def OnCloseFrameJobManager(self, event): + self.frmJobManager.Show(False) - def __GetCurrentPnlPfs(self): - sel = self.notebook.GetSelection() - page = self.notebook.GetPage(sel) - if isinstance(page, PnlPfsProject): - return page - - def __GetCurrentProject(self): - page = self.__GetCurrentPnlPfs() - if page: - return page.GetProject() - return None - - def OnCheckProjectActive(self, event): - pnl = self.__GetCurrentPnlPfs() - event.Enable(pnl is not None) - def OnCheckProjectChanged(self, event): - pnl = self.__GetCurrentPnlPfs() - if pnl: - event.Enable(pnl.HasChanged()) - else: - event.Enable(False) - def OnCheckProjectReady(self, event): - pnl = self.__GetCurrentPnlPfs() - if pnl: - event.Enable(pnl.IsReady()) - else: - event.Enable(False) - def OnCheckImageSelected(self, event): - pnl = self.__GetCurrentPnlPfs() - if pnl: - value = pnl.IsPictureSelected() - kind = pnl.GetSelectedImageState() - if event.GetId() == ActionManager.ID_PIC_MOVE_LEFT: - # FIXME: does not work with multiselect - value = kind not in ['first', 'none'] and value - elif event.GetId() == ActionManager.ID_PIC_MOVE_RIGHT: - # FIXME: does not work with multiselect - value = kind not in ['last', 'none'] and value - event.Enable(value) - else: - event.Enable(False) - - def OnChangeLanguage(self, event): - lang = ActionManager.LANG_MAP.get(event.GetId(), "en") - Settings().SetLanguage(lang) - ActionI18N().Execute() - dlg = wx.MessageDialog(self, - _(u"You must restart %s for your new language setting to take effect.") % Constants.APP_NAME, - _(u"Information"), - wx.ICON_INFORMATION | wx.OK) - dlg.ShowModal() - dlg.Destroy() - + def OnShowFrameJobManager(self, event): + self.frmJobManager.Show() + +# Pages def OnPageChanged(self, event): sel = event.GetSelection() + page = None if sel == 0: self.notebook.SetWindowStyleFlag(0) self.SetTitle(Constants.APP_NAME) else: page = self.notebook.GetPage(sel) self.notebook.SetWindowStyleFlag(wx.aui.AUI_NB_CLOSE_ON_ACTIVE_TAB) + filepath = page.GetProject().GetFilename() self.SetTitle(Constants.APP_NAME + u' - ' + Decode(filepath)) - + + self._actionMgr.UpdateActions(page) self.UpdateStatusText() - + def OnPageNext(self, event): idx = self.notebook.GetSelection() idx += 1 if idx < self.notebook.GetPageCount(): self.notebook.SetSelection(idx) - + def OnPagePrev(self, event): idx = self.notebook.GetSelection() idx -= 1 - if idx >=0: + if idx >= 0: self.notebook.SetSelection(idx) - + def OnPageClose(self, event): sel = event.GetSelection() if sel == 0: @@ -266,12 +201,24 @@ event.Skip() else: event.Veto() - - def OnCloseFrameJobManager(self, event): - self.frmJobManager.Show(False) - - def OnShowFrameJobManager(self, event): - self.frmJobManager.Show() + +# UpdateUI + def OnCheckProjectActive(self, event): + pnl = self.__GetCurrentPnlEditor() + event.Enable(pnl is not None) + + def OnCheckProjectChanged(self, event): + pnl = self.__GetCurrentPnlEditor() + if pnl: + event.Enable(pnl.HasChanged()) + else: + event.Enable(False) + +# Misc + def OnStatusBarLeftDown(self, event): + if self.statusBar.GetFieldRect(3).Contains(event.GetPosition()) \ + and self.statusBar.GetStatusText(3) != "": + self.frmJobManager.Show() def OnClose(self, event): while self.notebook.GetPageCount() > 1: @@ -285,177 +232,90 @@ self.frmJobManager.Destroy() event.Skip() - def OnExit(self, event): - self.Close() - - def OnAbout(self, event): - info = wx.AboutDialogInfo() - info.Name = Constants.APP_NAME - info.Version = Constants.APP_VERSION_EX - info.Copyright = u"(C) 2017 %s" % Constants.DEVELOPERS[0] - info.Description = wordwrap(_("PhotoFilmStrip creates movies out of your pictures in just 3 steps. First select your photos, customize the motion path and render the video. There are several output possibilities for VCD, SVCD, DVD up to FULL-HD."), - 350, - wx.ClientDC(self)) - info.WebSite = (Constants.APP_URL, "%s %s" % (Constants.APP_NAME, _(u"online"))) - info.Developers = Constants.DEVELOPERS - info.Translators = Constants.TRANSLATORS - - info.License = wordwrap(licenseText, 500, wx.ClientDC(self)) - - wx.AboutBox(info) - +# Menu def OnProjectNew(self, event): dlg = DlgProjectProps(self) if dlg.ShowModal() == wx.ID_OK: photoFilmStrip = dlg.GetProject() self.NewProject(photoFilmStrip) dlg.Destroy() - + def OnProjectLoad(self, event): - dlg = wx.FileDialog(self, _(u"Select %s-Project") % Constants.APP_NAME, - Settings().GetProjectPath(), "", - Constants.APP_NAME + u'-' + _(u"Project") + " (*.pfs)|*.pfs", + dlg = wx.FileDialog(self, _(u"Select %s-Project") % Constants.APP_NAME, + Settings().GetProjectPath(), "", + Constants.APP_NAME + u'-' + _(u"Files") + " (*.pfs)|*.pfs", wx.FD_OPEN) if dlg.ShowModal() == wx.ID_OK: self.LoadProject(dlg.GetPath()) - + def OnProjectSave(self, event): - pnlPfs = self.__GetCurrentPnlPfs() - prj = self.__GetCurrentProject() - if prj: - if self.SaveProject(prj.GetFilename(), False): - pnlPfs.SetChanged(False) + pnlEditor = self.__GetCurrentPnlEditor() + if pnlEditor: + if pnlEditor.OnSave(): + self.AddFileToHistory(pnlEditor.GetSaveFilePath()) def OnProjectSaveAs(self, event): - prj = self.__GetCurrentProject() - if prj is None: - return - curFilePath = prj.GetFilename() - dlg = wx.FileDialog(self, _(u"Save %s-Project") % Constants.APP_NAME, - Settings().GetProjectPath(), - curFilePath, - Constants.APP_NAME + u'-' + _(u"Project") + " (*.pfs)|*.pfs", - wx.FD_SAVE) - if dlg.ShowModal() == wx.ID_OK: - filepath = dlg.GetPath() - if os.path.splitext(filepath)[1].lower() != ".pfs": - filepath += ".pfs" - - if os.path.isfile(filepath): - dlg2 = wx.MessageDialog(self, - _(u"Overwrite existing file '%s'?") % filepath, - _(u"Question"), - wx.YES_NO | wx.ICON_QUESTION) - if dlg2.ShowModal() == wx.ID_NO: - return False - - return self.SaveProject(filepath, False) - return False - + pnlEditor = self.__GetCurrentPnlEditor() + if pnlEditor: + if pnlEditor.OnSaveAs(): + self.AddFileToHistory(pnlEditor.GetSaveFilePath()) + def OnProjectClose(self, event): sel = self.notebook.GetSelection() if self.ClosePage(sel): self.notebook.DeletePage(sel) - - def OnProjectExport(self, event): - prj = self.__GetCurrentProject() - if prj is None: - return - curFilePath = prj.GetFilename() - dlg = wx.FileDialog(self, _(u"Export %s-Project") % Constants.APP_NAME, - Settings().GetProjectPath(), - curFilePath, - u"%s %s-%s %s" % (_(u"Portable"), Constants.APP_NAME, _(u"Project"), "(*.ppfs)|*.ppfs"), - wx.FD_SAVE) - if dlg.ShowModal() == wx.ID_OK: - filepath = dlg.GetPath() - if os.path.splitext(filepath)[1].lower() != ".ppfs": - filepath += ".ppfs" - self.SaveProject(filepath, True) - - def OnProjectImport(self, event): - dlg = wx.FileDialog(self, _(u"Import %s-Project") % Constants.APP_NAME, - Settings().GetProjectPath(), "", - u"%s %s-%s %s" % (_(u"Portable"), Constants.APP_NAME, _(u"Project"), "(*.ppfs)|*.ppfs"), - wx.FD_OPEN) - if dlg.ShowModal() == wx.ID_OK: - self.LoadProject(dlg.GetPath(), True) - - def OnProjectProps(self, event): - pnlPfs = self.__GetCurrentPnlPfs() - if pnlPfs is None: - return - - dlg = DlgProjectProps(self, self.__GetCurrentProject()) - if dlg.ShowModal() == wx.ID_OK: - dlg.GetProject() - pnlPfs.UpdateProperties() - dlg.Destroy() + + def OnExit(self, event): + self.Close() def OnHelpIndex(self, event): HelpViewer().DisplayID(HelpViewer.ID_INDEX) event.Skip() + def OnHelpContent(self, event): HelpViewer().DisplayID(HelpViewer.ID_CREATE_PFS) event.Skip() - - def OnCmdMoveLeftButton(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.OnCmdMoveLeftButton(event) - def OnCmdMoveRightButton(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.OnCmdMoveRightButton(event) - def OnCmdRemoveButton(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.OnCmdRemoveButton(event) - def OnCmdRotateLeftButton(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.pnlEditPicture.OnCmdRotateLeftButton(event) - def OnCmdRotateRightButton(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.pnlEditPicture.OnCmdRotateRightButton(event) - def OnCmdMotionRandom(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.OnMotionRandom() - def OnCmdMotionCenter(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.OnMotionCenter() - def OnImportPics(self, event): - sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - page.OnImportPics(event) - def OnRenderFilmstrip(self, event): + def OnChangeLanguage(self, event): + lang = ActionManager.LANG_MAP.get(event.GetId(), "en") + Settings().SetLanguage(lang) + ActionI18N().Execute() + dlg = wx.MessageDialog(self, + _(u"You must restart %s for your new language setting to take effect.") % Constants.APP_NAME, + _(u"Information"), + wx.ICON_INFORMATION | wx.OK) + dlg.ShowModal() + dlg.Destroy() + + def OnAbout(self, event): + info = wx.AboutDialogInfo() + info.Name = Constants.APP_NAME + info.Version = Constants.APP_VERSION_EX + info.Copyright = u"(C) 2017 %s" % Constants.DEVELOPERS[0] + info.Description = wordwrap(_("PhotoFilmStrip creates movies out of your pictures in just 3 steps. First select your photos, customize the motion path and render the video. There are several output possibilities for VCD, SVCD, DVD up to FULL-HD."), + 350, + wx.ClientDC(self)) + info.WebSite = (Constants.APP_URL, "%s %s" % (Constants.APP_NAME, _(u"online"))) + info.Developers = Constants.DEVELOPERS + info.Translators = Constants.TRANSLATORS + + info.License = wordwrap(licenseText, 500, wx.ClientDC(self)) + + wx.AboutBox(info) + +#### Event-Handler - END ####################################################### + + def __GetCurrentPnlEditor(self): sel = self.notebook.GetSelection() - if sel > 0: - page = self.notebook.GetPage(sel) - photoFilmStrip = page.GetProject() - dlg = DlgRender(self, photoFilmStrip) - dlg.ShowModal() -# dlg.Destroy() - - def ClosePage(self, idx): - page = self.notebook.GetPage(idx) - if self.CheckAndAskSaving(page): - page.Close() - return True - else: - return False + page = self.notebook.GetPage(sel) + if isinstance(page, PnlEditorPage): + return page + + def __GetCurrentProject(self): + page = self.__GetCurrentPnlEditor() + if page: + return page.GetProject() + return None def AddFileToHistory(self, filename): fileList = Settings().GetFileHistory() @@ -463,51 +323,23 @@ fileList.remove(filename) fileList.insert(0, filename) Settings().SetFileHistory(fileList) - - def CheckAndAskSaving(self, pnlPfs): - if pnlPfs.HasChanged(): - filepath = pnlPfs.GetProject().GetFilename() - - dlg = wx.MessageDialog(self, - _(u"'%s' has been modified. Save changes?") % Decode(filepath), - _(u"Question"), - wx.YES_NO | wx.CANCEL | wx.ICON_EXCLAMATION) - response = dlg.ShowModal() - dlg.Destroy() - - if response == wx.ID_CANCEL: - return False - elif response == wx.ID_YES and not self.SaveProject(filepath, False): - return False - return True def UpdateStatusText(self): - page = self.__GetCurrentPnlPfs() + page = self.__GetCurrentPnlEditor() if page is None: self.statusBar.SetStatusText(Constants.APP_URL, 1) self.statusBar.SetStatusText("%s %s" % (Constants.APP_NAME, Constants.APP_VERSION), 2) else: - project = page.GetProject() + self.statusBar.SetStatusText(page.GetStatusText(0), 1) + self.statusBar.SetStatusText(page.GetStatusText(1), 2) - imgCount = len(project.GetPictures()) - totalTime = project.GetDuration(False) - if project.GetTimelapse(): - # TODO: calc from image count - totalTime = 1 - imgCount = 0 - elif totalTime == -1: - # TODO: calc from audio files - totalTime = 0 - elif totalTime is None: - totalTime = project.GetDuration(True) - - self.statusBar.SetStatusText("%s: %d" % (_(u"Images"), imgCount), 1) - - minutes = totalTime / 60 - seconds = totalTime % 60 - self.statusBar.SetStatusText("%s: %02d:%02d" % (_(u"Duration"), - minutes, - seconds), 2) + def ClosePage(self, idx): + page = self.notebook.GetPage(idx) + if page.CheckAndAskSaving(): + page.Close() + return True + else: + return False def NewProject(self, project): pnl = PnlPfsProject(self.notebook, project) @@ -522,13 +354,13 @@ if page.GetProject().GetFilename() == filepath: self.notebook.SetSelection(idx) return - + prjFile = WxProjectFile(self, filename=filepath) result = prjFile.Load() if not result: dlg = wx.MessageDialog(self, _(u"Invalid %(app)s-Project: %(file)s") % {"app": Constants.APP_NAME, - "file": filepath}, + "file": filepath}, _(u"Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() @@ -537,43 +369,20 @@ photoFilmStrip = prjFile.GetProject() pics = photoFilmStrip.GetPictures() - + pnl = self.NewProject(photoFilmStrip) pnl.InsertPictures(pics) pnl.SetChanged(False) if not skipHistory: self.AddFileToHistory(filepath) - -# self.pnlWelcome.RefreshPage() # crashes on unix - wx.CallAfter(self.pnlWelcome.RefreshPage) - - def SaveProject(self, filepath, includePics): - project = self.__GetCurrentProject() - prjFile = WxProjectFile(self, project, filepath) - try: - prjFile.Save(includePics) - except StandardError, err: - dlg = wx.MessageDialog(self, - _(u"Could not save the file '%(file)s': %(errMsg)s") % \ - {'file': Decode(filepath), - 'errMsg': unicode(err)}, - _(u"Question"), - wx.OK | wx.ICON_ERROR) - dlg.ShowModal() - dlg.Destroy() - return False - if not includePics: - self.AddFileToHistory(filepath) - -# self.pnlWelcome.RefreshPage() # crashes on unix +# self.pnlWelcome.RefreshPage() # crashes on unix wx.CallAfter(self.pnlWelcome.RefreshPage) - - return True - - + + class ProjectDropTarget(wx.FileDropTarget): + def __init__(self, frmMain): wx.FileDropTarget.__init__(self) self.frmMain = frmMain @@ -587,5 +396,3 @@ return True return False - - diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/helper.py photofilmstrip-3.3.1/photofilmstrip/gui/helper.py --- photofilmstrip-3.2.0/photofilmstrip/gui/helper.py 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/helper.py 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,47 @@ +# encoding: UTF-8 +# +# Copyright (C) 2017 Jens Goepfert +# + +import wx + + +def CreateMenuItem(menu, ident, text="", bmp=None, disabledBitmap=None): + if text: + item = wx.MenuItem(menu, ident, text) + item.SetHelp(text.replace('&', '').split('\t')[0]) + else: + item = wx.MenuItem(menu, ident) + if bmp is not None: + item.SetBitmap(bmp) + + if disabledBitmap is not None: + item.SetDisabledBitmap(disabledBitmap) + + menu.AppendItem(item) + + +def ChopText(dc, text, maxSize): + """ + Chops the input `text` if its size does not fit in `maxSize`, by cutting the + text and adding ellipsis at the end. + + :param `dc`: a `wx.DC` device context; + :param `text`: the text to chop; + :param `maxSize`: the maximum size in which the text should fit. + """ + + # first check if the text fits with no problems + width, __ = dc.GetTextExtent(text) + + if width <= maxSize: + return text, width + + for i in xrange(len(text), -1, -1): + s = '%s ... %s' % (text[:i * 33 / 100], text[-i * 67 / 100:]) + + width, __ = dc.GetTextExtent(s) + + if width <= maxSize: + break + return s, width diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/HelpViewer.py photofilmstrip-3.3.1/photofilmstrip/gui/HelpViewer.py --- photofilmstrip-3.2.0/photofilmstrip/gui/HelpViewer.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/HelpViewer.py 2017-12-03 22:12:24.000000000 +0000 @@ -28,18 +28,18 @@ class HelpViewer(Singleton): - - ID_INDEX = 1 + + ID_INDEX = 1 ID_CREATE_PFS = 3 - ID_RENDER = 4 - + ID_RENDER = 4 + def __init__(self): self.__htmlCtrl = wx.html.HtmlHelpController() - docFile = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), + docFile = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "..", "share", "doc", "photofilmstrip", "photofilmstrip.hhp") fn = os.path.abspath(docFile) self.__htmlCtrl.AddBook(fn) - + def DisplayID(self, ident): self.__htmlCtrl.DisplayID(ident) diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/ImageSectionEditor.py photofilmstrip-3.3.1/photofilmstrip/gui/ImageSectionEditor.py --- photofilmstrip-3.2.0/photofilmstrip/gui/ImageSectionEditor.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/ImageSectionEditor.py 2017-12-03 22:12:24.000000000 +0000 @@ -35,12 +35,12 @@ from photofilmstrip.gui.util.ImageCache import ImageCache - EVT_RECT_CHANGED_TYPE = wx.NewEventType() EVT_RECT_CHANGED = wx.PyEventBinder(EVT_RECT_CHANGED_TYPE, 1) class RectChangedEvent(wx.PyCommandEvent): + def __init__(self, wxId, rect): wx.PyCommandEvent.__init__(self, EVT_RECT_CHANGED_TYPE, wxId) self._rect = rect @@ -62,14 +62,13 @@ INFO_TIME_OUT = 2.0 - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, name='panel'): wx.Panel.__init__(self, parent, id, pos, size, style, name) Observer.__init__(self) - self.SetMinSize(wx.Size(200, 150)) + self.SetSizeHints(200, 150) self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) @@ -184,10 +183,11 @@ alpha = 255 if now - self._lastRectUpdate > self.INFO_TIME_OUT / 2: alpha = (1 - ((now - self._lastRectUpdate) - (self.INFO_TIME_OUT / 2)) / (self.INFO_TIME_OUT / 2)) * 255 + alpha = int(round(alpha)) if alpha < 0: alpha = 0 dc.SetTextForeground(wx.Colour(255, 255, 255, alpha)) - font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FIXED_FONT) + font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FIXED_FONT) font.SetPointSize(16) font.SetWeight(wx.BOLD) dc.SetFont(font) @@ -207,7 +207,7 @@ except StandardError: dc = pdc - dc.SetBrush(wx.GREY_BRUSH) + dc.SetBrush(wx.BLACK_BRUSH) dc.DrawRectangle(0, 0, sz[0], sz[1]) if not self.IsEnabled(): dc.SetBrush(wx.Brush(wx.Colour(90, 90, 90, 255), @@ -299,7 +299,7 @@ else: self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) - def OnCaptureLost(self, event): + def OnCaptureLost(self, event): # pylint: disable=unused-argument if self._action is not None: self.__SelectCursor(None) self._action = None @@ -429,7 +429,10 @@ ny = self._imgProxy.GetHeight() # everything should be ok now - self._sectRect.Set(nx, ny, width, height) + self._sectRect.SetX(nx) + self._sectRect.SetY(ny) + self._sectRect.SetWidth(width) + self._sectRect.SetHeight(height) # self._SendRectChangedEvent() @@ -565,7 +568,7 @@ data = None if wx.TheClipboard.GetData(do): data = do.GetText() - sectData = re.findall("(\d+), (\d+) - (\d+) x (\d+)", data) + sectData = re.findall(r"(\d+), (\d+) - (\d+) x (\d+)", data) if sectData: sectData = sectData[0] try: @@ -592,6 +595,7 @@ class ScaleThread(threading.Thread): + def __init__(self, picture, callbackOnDone): threading.Thread.__init__(self, name="reload %s" % Encode(picture.GetFilename())) self._picture = picture @@ -603,7 +607,7 @@ def run(self): self._abort = False - for i in range(20): + for __ in range(20): time.sleep(0.1) if self._abort: return @@ -661,6 +665,8 @@ return self.GetWidth(), self.GetHeight() def Scale(self, width, height): + if not (width > 0 and height > 0): + return img = self._wxImg.Scale(width, height) self._wxBmp = img.ConvertToBitmap() self._curSize = width, height diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PhotoFilmStripApp.py photofilmstrip-3.3.1/photofilmstrip/gui/PhotoFilmStripApp.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PhotoFilmStripApp.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PhotoFilmStripApp.py 2017-12-03 22:12:24.000000000 +0000 @@ -30,7 +30,7 @@ class PhotoFilmStripApp(wx.App): - + def OnInit(self): self.SetAssertMode(wx.PYAPP_ASSERT_SUPPRESS) # loc = wx.Locale(wx.LANGUAGE_GERMAN) @@ -41,9 +41,9 @@ frame.Show() frame.Maximize() self.SetTopWindow(frame) - + DlgBugReport.Initialize(frame) - + if len(sys.argv) > 1: for arg in sys.argv[1:]: fname = arg.decode(sys.getfilesystemencoding()) diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PhotoFilmStripList.py photofilmstrip-3.3.1/photofilmstrip/gui/PhotoFilmStripList.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PhotoFilmStripList.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PhotoFilmStripList.py 2017-12-03 22:12:24.000000000 +0000 @@ -24,161 +24,222 @@ import wx from photofilmstrip.gui.util.ImageCache import ImageCache, EVT_THUMB_READY +from photofilmstrip.gui.helper import ChopText - -EVT_CHANGED_TYPE = wx.NewEventType() -EVT_CHANGED = wx.PyEventBinder(EVT_CHANGED_TYPE, 1) +EVT_CHANGED_TYPE = wx.NewEventType() +EVT_CHANGED = wx.PyEventBinder(EVT_CHANGED_TYPE, 1) class ChangedEvent(wx.PyCommandEvent): + def __init__(self, wxId): wx.PyCommandEvent.__init__(self, EVT_CHANGED_TYPE, wxId) class PhotoFilmStripList(wx.ScrolledWindow): - - HEIGHT = 200 - BORDER = 40 - GAP = 10 - - def __init__(self, parent, id=-1, - pos=wx.DefaultPosition, size=wx.DefaultSize, + + GAP = 10 + BORDER = 45 + THUMB_HEIGHT = 120 + HOLE_WIDTH = 11 + HOLE_HEIGHT = 16 + HOLE_PADDING = 13 # distance between holes + HOLE_MARGIN = 6 # distance to thumb + LABEL_MARGIN = 8 + + STRIP_HEIGHT = THUMB_HEIGHT + 2 * BORDER + + def __init__(self, parent, id=-1, + pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.HSCROLL | wx.VSCROLL, name='PhotoFilmStripList'): - wx.ScrolledWindow.__init__(self, parent, id, pos, size, style, name) + wx.ScrolledWindow.__init__(self, parent, id, pos, size, style, name) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.SetBackgroundColour(wx.BLACK) - self.SetSizeHints(-1, self.HEIGHT+20, -1, self.HEIGHT+20) - - self.__frozen = False + clientSize = wx.Size(-1, self.STRIP_HEIGHT + wx.SystemSettings.GetMetric(wx.SYS_HSCROLL_Y)) + self.SetSizeHintsSz(clientSize, clientSize) + + self.__frozen = False self.__pictures = [] - self.__selIdxs = [] - self.__hvrIdx = -1 - - self.__dragPic = None - self.__dragX = 0 + self.__selIdxs = [] + self.__hvrIdx = -1 + + self.__dragIdx = None + self.__dropIdx = None + self.__dragBmp = None + self.__dragBmpIdx = None + self.__dragX = 0 self.__dragOffX = 0 - + self.__UpdateVirtualSize() - + self.SetScrollRate(1, 0) - + self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouseEvent) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost) - + ImageCache().RegisterWin(self) ImageCache().thumb = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_TOOLBAR, (120, 120)) self.Bind(EVT_THUMB_READY, self.__OnThumbReady) - + def Freeze(self, *args): self.__frozen = True + def Thaw(self, *args): self.__frozen = False self.__UpdateVirtualSize() + def IsFrozen(self, *args): return self.__frozen - + def __OnThumbReady(self, event): self.__UpdateVirtualSize() - + def OnPaint(self, event): pdc = wx.BufferedPaintDC(self) try: dc = wx.GCDC(pdc) except StandardError: dc = pdc - - font = wx.SystemSettings_GetFont(wx.SYS_ANSI_FIXED_FONT) - font.SetPointSize(9) - dc.SetFont(font) - dc.SetTextForeground(wx.Colour(237, 156, 0)) - dc.SetBackground(wx.BLACK_BRUSH) + dc.SetBackground(wx.BLACK_BRUSH) dc.Clear() - - dc.SetBrush(wx.WHITE_BRUSH) - dc.SetPen(wx.WHITE_PEN) vx = self.GetViewStart()[0] - hx = self.GetClientSize()[0] + clientWidth = self.GetClientSize()[0] + + diaRect = wx.Rect(-vx, 0, 0, self.STRIP_HEIGHT) - sxPic = self.GAP - n = 0 for idx, pic in enumerate(self.__pictures): bmp = ImageCache().GetThumbBmp(pic) # if the picture cannot be loaded GetWidth may return -1 - stepWidth = bmp.GetWidth() + self.GAP + bmpWidth = bmp.GetWidth() + + diaRect.SetWidth(bmpWidth + self.GAP) + + if idx == self.__dropIdx and self.__dragIdx > idx: + diaRect.OffsetXY(self.__dragBmp.GetWidth(), 0) + + if diaRect.right + 1 >= 0 and idx != self.__dragIdx: + if diaRect.left <= clientWidth: + label = os.path.splitext(os.path.basename(pic.GetFilename()))[0] + diaNo = idx + 1 - if sxPic >= vx - stepWidth: - if sxPic <= vx + hx: - dc.DrawBitmap(bmp, sxPic - vx, self.BORDER, True) - labelRect = wx.Rect(sxPic - vx, 0, bmp.GetWidth(), self.HEIGHT) - dc.DrawLabel(str(idx + 1), labelRect, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_TOP) - dc.DrawLabel(os.path.basename(pic.GetFilename()), - labelRect, - wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) + if idx >= self.__dropIdx and idx < self.__dragIdx: + diaNo += 1 + + if idx <= self.__dropIdx and idx > self.__dragIdx: + diaNo -= 1 + + self.__DrawDia(dc, diaRect, diaRect.x + vx, bmp, str(diaNo), label, idx in self.__selIdxs, idx == self.__hvrIdx) else: break - sxPic += stepWidth - - # draw filmstrip - while 1: - sxFilmStrip = (n * 32) + 10 - if sxFilmStrip > sxPic: - break - - dc.DrawRoundedRectangle(sxFilmStrip - vx, 14, 14, 20, 3) - dc.DrawRoundedRectangle(sxFilmStrip - vx, self.HEIGHT - 34, 14, 20, 3) - n += 1 - - self.__DrawHighlights(dc) - - if self.__dragPic is not None: - if self.__dragPic >= 0 and self.__dragPic < len(self.__pictures): - bmp = ImageCache().GetThumbBmp(self.__pictures[self.__dragPic]) - dc.DrawBitmap(bmp, self.__dragX - self.__dragOffX - vx, self.BORDER) - else: - self.__dragPic = None + if idx != self.__dragIdx or self.__dragIdx == self.__dropIdx: + diaRect.OffsetXY(diaRect.width, 0) - def __DrawHighlights(self, dc): - vs = self.GetViewStart()[0] - dc.SetPen(wx.TRANSPARENT_PEN) - for selIdx in self.__selIdxs: - rect = self.GetThumbRect(selIdx) - rect.OffsetXY(-vs, 0) - col = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT) - dc.SetBrush(wx.Brush(wx.Colour(col.Red(), col.Green(), col.Blue(), 180))) - dc.DrawRectangleRect(rect) - if self.__hvrIdx != -1: - rect = self.GetThumbRect(self.__hvrIdx) - rect.OffsetXY(-vs, 0) - col = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT) - color = wx.Colour(col.Red(), col.Green(), col.Blue(), 80) - dc.SetBrush(wx.Brush(color)) + if idx == self.__dropIdx and self.__dragIdx < idx: + diaRect.OffsetXY(self.__dragBmp.GetWidth(), 0) + + if self.__dragIdx is not None: + dc.DrawBitmap(self.__dragBmp, self.__dragX - self.__dragOffX - vx, 0, True) + + def __CreateDiaBmp(self, picIdx, selected=False, highlighted=False, dropIdx=None): + pic = self.__pictures[picIdx] + thumbBmp = ImageCache().GetThumbBmp(pic) + diaRect = self.GetDiaRect(picIdx) + holeOffset = diaRect.x + + bmp = wx.EmptyBitmap(diaRect.width, diaRect.height) + diaNo = str(picIdx + 1) + label = os.path.splitext(os.path.basename(pic.GetFilename()))[0] + + dc = wx.MemoryDC(bmp) + try: + dc = wx.GCDC(dc) + except StandardError: + pass + + if dropIdx is not None: + diaNo = str(dropIdx + 1) + dropRect = self.GetDiaRect(dropIdx) + + if dropIdx > picIdx: + holeOffset = dropRect.right + 1 - diaRect.width + + diaRect.SetX(0) + self.__DrawDia(dc, diaRect, holeOffset, thumbBmp, diaNo, label, selected, highlighted) + return bmp + + def __DrawDia(self, dc, rect, holeOffset, thumbBmp, diaNo, label, selected=False, highlighted=False): + font = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT) + font.SetPointSize(9) + dc.SetFont(font) + + colour = wx.Colour(235, 235, 235) + + bmpX = rect.x + self.GAP / 2 + bmpY = (rect.height - thumbBmp.GetHeight()) / 2 + + holeX = rect.x + self.GAP / 2 - (holeOffset % (self.HOLE_WIDTH + self.HOLE_PADDING)) + + dc.SetClippingRect(rect) + + if selected: + dc.SetBackground(wx.Brush(wx.Colour(38, 54, 70))) + dc.Clear() + dc.SetPen(wx.Pen(wx.Colour(237, 156, 0))) + dc.SetBrush(wx.Brush(wx.Colour(237, 156, 0))) + dc.DrawRectangle(rect.x, 0, rect.right + 1, 3) + dc.DrawRectangle(rect.x, rect.bottom - 2, rect.right + 1, rect.bottom) + else: + dc.SetBackground(wx.BLACK_BRUSH) + dc.Clear() + + dc.SetTextForeground(wx.Colour(237, 156, 0)) + dc.SetBrush(wx.Brush(colour)) + dc.SetPen(wx.Pen(colour)) + + diaNoWidth, textHeight = dc.GetTextExtent(diaNo) + label, labelWidth = ChopText(dc, label, thumbBmp.GetWidth()) + + dc.DrawBitmap(thumbBmp, bmpX, bmpY, True) + dc.DrawText(diaNo, rect.x + (rect.width - diaNoWidth) / 2, self.LABEL_MARGIN - 3) + dc.DrawText(label, rect.x + (rect.width - labelWidth) / 2, rect.height - self.LABEL_MARGIN - textHeight) + + while holeX <= rect.right + 1: + dc.DrawRoundedRectangle(holeX, self.BORDER - self.HOLE_MARGIN - self.HOLE_HEIGHT, self.HOLE_WIDTH, self.HOLE_HEIGHT, 2) + dc.DrawRoundedRectangle(holeX, self.BORDER + self.THUMB_HEIGHT + self.HOLE_MARGIN, self.HOLE_WIDTH, self.HOLE_HEIGHT, 2) + holeX += self.HOLE_WIDTH + self.HOLE_PADDING + + if highlighted: + dc.SetPen(wx.TRANSPARENT_PEN) + dc.SetBrush(wx.Brush(wx.Colour(77, 136, 196, 80))) dc.DrawRectangleRect(rect) + dc.DestroyClippingRegion() + def _SendChangedEvent(self): evt = ChangedEvent(self.GetId()) evt.SetEventObject(self) - self.GetEventHandler().ProcessEvent(evt) + self.GetEventHandler().ProcessEvent(evt) def __Scroll(self, value): sp = self.GetScrollPos(wx.HORIZONTAL) self.Scroll(sp + value, -1) - + def OnMouseWheel(self, event): rot = event.GetWheelRotation() - linesPer = 40 #event.GetLinesPerAction() + linesPer = 40 # event.GetLinesPerAction() if rot > 0: self.__Scroll(-linesPer) else: self.__Scroll(linesPer) - + def OnMouseEvent(self, event): mPos = event.GetPosition() unscrolledPos = self.CalcUnscrolledPosition(mPos) @@ -187,22 +248,37 @@ if idx != self.__hvrIdx: self.__hvrIdx = idx self.Refresh() + if event.Dragging(): + if idx != -1: + self.__dropIdx = idx + if mPos.x < 10: self.__Scroll(-40) - elif mPos.x > self.GetClientSizeTuple()[0] - 10: + elif mPos.x > self.GetClientSize()[0] - 10: self.__Scroll(40) + self.__dragX = unscrolledPos.x - if self.__dragPic is None and idx != -1: - self.__dragPic = idx - rect = self.GetThumbRect(idx) - self.__dragOffX = self.__dragX - rect.GetLeft() - self.CaptureMouse() + if self.__dragIdx is None: + if idx != -1: + self.__dragIdx = idx + self.__dragBmp = self.__CreateDiaBmp(idx, True, True) + self.__dragBmpIdx = idx + rect = self.GetDiaRect(idx) + self.__dragOffX = self.__dragX - rect.GetLeft() + self.CaptureMouse() + + elif self.__dragBmpIdx != self.__dropIdx: + self.__dragBmpIdx = self.__dropIdx + self.__dragBmp = self.__CreateDiaBmp(self.__dragIdx, True, True, self.__dropIdx) + self.Refresh() + if event.Leaving(): self.__hvrIdx = -1 self.Refresh() - if event.LeftDown(): + + if event.LeftDown() and not event.Dragging(): if idx != -1: if event.ControlDown(): self.Select(idx, idx not in self.__selIdxs, False) @@ -212,34 +288,29 @@ self.Select(idx) else: step = 1 if idx > self.__selIdxs[0] else -1 - for ct, _idx in enumerate(xrange(self.__selIdxs[0], - idx + step, + for ct, _idx in enumerate(xrange(self.__selIdxs[0], + idx + step, step)): self.Select(_idx, deselectOthers=ct == 0) else: self.Select(idx) - if event.LeftUp() and self.__dragPic is not None: - if self.HasCapture(): - self.ReleaseMouse() - if idx == -1: - self.__dragPic = None - self.Refresh() - else: - self.MovePicture(self.__dragPic, idx) - self.__dragPic = None - self.Select(idx) + + if event.LeftUp() and self.__dragIdx is not None: + self.__FinishDnD() + event.Skip() - + def OnCaptureLost(self, event): - self.__dragPic = None + self.__dragIdx = None + self.__dropIdx = None self.Refresh() event.Skip() - + def OnKeyDown(self, event): if event.HasModifiers(): event.Skip() return - + key = event.GetKeyCode() if self.__selIdxs: if event.ShiftDown(): @@ -251,97 +322,118 @@ sel = -1 if key == wx.WXK_LEFT: if sel > 0: - self.Select(sel - 1, + self.Select(sel - 1, deselectOthers=not event.ShiftDown()) self.EnsureVisible(sel - 1) - + elif key == wx.WXK_RIGHT: if sel < self.GetItemCount() - 1: self.Select(sel + 1, deselectOthers=not event.ShiftDown()) self.EnsureVisible(sel + 1) - + elif key == wx.WXK_END: self.Select(self.GetItemCount() - 1) self.EnsureVisible(self.GetItemCount() - 1) - + elif key == wx.WXK_HOME: self.Select(0) self.EnsureVisible(0) - + + elif key == wx.WXK_ESCAPE: + if self.__dragIdx is not None: + self.__FinishDnD(abort=True) + else: event.Skip() + def __FinishDnD(self, abort=False): + if self.__dragIdx is not None: + if self.HasCapture(): + self.ReleaseMouse() + + idx = self.__dragIdx + if not abort: + self.MovePicture(self.__dragIdx, self.__dropIdx) + self.Select(self.__dropIdx) + idx = self.__dropIdx + + self.__dragIdx = None + self.__dropIdx = None + + self.Refresh() + self.EnsureVisible(idx) + def EnsureVisible(self, idx): - rect = self.GetThumbRect(idx) + rect = self.GetDiaRect(idx) left = rect.GetLeft() vs = self.GetViewStart()[0] - ch = self.GetClientSizeTuple()[0] + ch = self.GetClientSize()[0] if left < vs: self.Scroll(left, 0) elif left > vs + ch: self.Scroll(rect.GetRight() - ch, 0) def __UpdateVirtualSize(self): - width = self.GAP + width = 0 for pic in self.__pictures: bmp = ImageCache().GetThumbBmp(pic) # if the picture cannot be loaded GetWidth may return -1 width += bmp.GetWidth() + self.GAP - - self.SetVirtualSize((width, self.HEIGHT)) + + self.SetVirtualSize((width, self.STRIP_HEIGHT)) self.Refresh() def GetThumbSize(self, pic): aspect = float(pic.GetWidth()) / float(pic.GetHeight()) - thumbHeight = self.HEIGHT - (2 * self.BORDER) + thumbHeight = self.THUMB_HEIGHT thumbWidth = int(round(thumbHeight * aspect)) return thumbWidth, thumbHeight - - def GetThumbRect(self, idx): - sx = self.GAP + + def GetDiaRect(self, idx): + sx = 0 for picIdx, pic in enumerate(self.__pictures): - thumbWidth = self.GetThumbSize(pic)[0] - + thumbWidth = ImageCache().GetThumbBmp(pic).GetWidth() + if idx == picIdx: - rect = wx.Rect(sx, 0, thumbWidth, self.HEIGHT) + rect = wx.Rect(sx, 0, thumbWidth + self.GAP, self.STRIP_HEIGHT) return rect - + sx += thumbWidth + self.GAP - + def HitTest(self, pos): pos = self.CalcUnscrolledPosition(pos) - sx = self.GAP + sx = 0 for idx, pic in enumerate(self.__pictures): - thumbWidth = self.GetThumbSize(pic)[0] - - rect = wx.Rect(sx, 0, thumbWidth + self.GAP, self.HEIGHT) + thumbWidth = ImageCache().GetThumbBmp(pic).GetWidth() + + rect = wx.Rect(sx, 0, thumbWidth + self.GAP, self.STRIP_HEIGHT) if rect.Contains(pos): return idx - + sx += thumbWidth + self.GAP return -1 - + # def AddPicture(self, pic): # self.__pictures.append(pic) # self.__UpdateVirtualSize() # self._SendChangedEvent() - + def InsertPicture(self, idx, pic): self.__pictures.insert(idx, pic) - + for i in xrange(len(self.__selIdxs)): if self.__selIdxs[i] >= idx \ and self.__selIdxs[i] + 1 not in self.__selIdxs: self.__selIdxs[i] += 1 - + if not self.IsFrozen(): self.__UpdateVirtualSize() self._SendChangedEvent() - + def DeleteItem(self, idx): self.__pictures.pop(idx) - + firstSel = 0 if self.__selIdxs: firstSel = self.__selIdxs[0] @@ -350,56 +442,57 @@ if idx in self.__selIdxs: self.__selIdxs.remove(idx) - + if firstSel != idx \ and firstSel not in self.__selIdxs: self.__selIdxs.insert(0, firstSel) - + if len(self.__selIdxs) == 0: self.__selIdxs.append(firstSel) - + for i in xrange(len(self.__selIdxs)): if self.__selIdxs[i] > idx \ and self.__selIdxs[i] - 1 not in self.__selIdxs: self.__selIdxs[i] -= 1 - + if len(self.__pictures) == 0: self.__selIdxs = [] if self.__hvrIdx >= len(self.__pictures): self.__hvrIdx = -1 - + self.__UpdateVirtualSize() self._SendChangedEvent() evt = wx.ListEvent(wx.EVT_LIST_ITEM_SELECTED.typeId, self.GetId()) self.GetEventHandler().ProcessEvent(evt) - + def DeleteAllItems(self): - self.__selIdxs = [] + self.__selIdxs = [] self.__pictures = [] self.__UpdateVirtualSize() self._SendChangedEvent() - + def GetItemCount(self): return len(self.__pictures) - + def GetPicture(self, idx): try: return self.__pictures[idx] except IndexError: return None + def SetPicture(self, idx, pic): if idx in xrange(len(self.__pictures)): self.__pictures[idx] = pic self.Refresh() - + def GetPictures(self): return self.__pictures[:] - + def GetSelected(self): return self.__selIdxs[:] - + def GetSelectedPictures(self): selPics = [] for idx in self.__selIdxs: @@ -407,7 +500,7 @@ if pic is not None: selPics.append(pic) return selPics - + def Select(self, idx, on=True, deselectOthers=True): if idx in xrange(len(self.__pictures)): if deselectOthers: @@ -420,7 +513,7 @@ # must have more than one selected item to make sure # there is at least one selected newSel.remove(idx) - + evt = None if newSel != self.__selIdxs: evt = wx.ListEvent(wx.EVT_LIST_ITEM_SELECTED.typeId, self.GetId()) @@ -429,19 +522,19 @@ self.__selIdxs = newSel self.Refresh() - + if evt: self.GetEventHandler().ProcessEvent(evt) return True else: return False - + def SwapPictures(self, idxFrom, idxTo): picFrom = self.__pictures[idxFrom] picTo = self.__pictures[idxTo] self.__pictures[idxFrom] = picTo self.__pictures[idxTo] = picFrom - + evt = None try: p = self.__selIdxs.index(idxFrom) @@ -451,7 +544,7 @@ evt.m_oldItemIndex = idxFrom except ValueError: pass - + self.Refresh() self._SendChangedEvent() if evt: @@ -470,7 +563,7 @@ evt.m_oldItemIndex = idxFrom except ValueError: pass - + self.Refresh() self._SendChangedEvent() if evt: @@ -478,5 +571,4 @@ # FIXME: should be fixed height -ImageCache.THUMB_SIZE = PhotoFilmStripList.HEIGHT - (2 * PhotoFilmStripList.BORDER) - +ImageCache.THUMB_SIZE = PhotoFilmStripList.THUMB_HEIGHT diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PnlAddPics.py photofilmstrip-3.3.1/photofilmstrip/gui/PnlAddPics.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PnlAddPics.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PnlAddPics.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:FramePanel:PnlAddPics +# Boa:FramePanel:PnlAddPics # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -22,11 +22,13 @@ import wx -[wxID_PNLADDPICS, wxID_PNLADDPICSCMDBROWSE, wxID_PNLADDPICSSTINFO, - wxID_PNLADDPICSSTTITLE, +[wxID_PNLADDPICS, wxID_PNLADDPICSCMDBROWSE, wxID_PNLADDPICSSTINFO, + wxID_PNLADDPICSSTTITLE, ] = [wx.NewId() for _init_ctrls in range(4)] + class PnlAddPics(wx.Panel): + def _init_coll_szMain_Items(self, parent): # generated method, don't edit @@ -72,22 +74,22 @@ pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.ALIGN_CENTRE) - self.cmdBrowse = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('wxART_ADD_BOOKMARK', - wx.ART_TOOLBAR, (32, 32)), id=wxID_PNLADDPICSCMDBROWSE, + self.cmdBrowse = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('PFS_IMPORT_PICTURES_32'), + id=wxID_PNLADDPICSCMDBROWSE, name=u'cmdBrowse', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.BU_AUTODRAW) self._init_sizers() - def __init__(self, parent, id=wx.ID_ANY, - pos=wx.DefaultPosition, size=wx.DefaultSize, + def __init__(self, parent, id=wx.ID_ANY, + pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, name='panel'): self._init_ctrls(parent) - + font = self.stTitle.GetFont() font.SetWeight(wx.BOLD) self.stTitle.SetFont(font) - + self.stTitle.SetLabel(_(u"Welcome to PhotoFilmStrip")) self.stInfo.SetLabel(_(u"Drag some pictures onto this text or\nclick the button below\nto add pictures to your new PhotoFilmStrip.")) diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PnlEditorPage.py photofilmstrip-3.3.1/photofilmstrip/gui/PnlEditorPage.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PnlEditorPage.py 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PnlEditorPage.py 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,153 @@ +# encoding: UTF-8 +# +# PhotoFilmStrip - Creates movies out of your pictures. +# +# Copyright (C) 2017 Jens Goepfert +# +# 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import os + +import wx + +from photofilmstrip.lib.Settings import Settings +from photofilmstrip.lib.util import Decode + + +class PnlEditorPage(wx.Panel): + + def __init__(self, parent, id=wx.ID_ANY, name=wx.PanelNameStr): + wx.Panel.__init__(self, parent, id, name=name) + self.__hasChanged = False + + def __Save(self, filepath): + try: + return self._Save(filepath) + except StandardError, err: + dlg = wx.MessageDialog(self.GetParent(), + _(u"Could not save the file '%(file)s': %(errMsg)s") % \ + {'file': Decode(filepath), + 'errMsg': unicode(err)}, + _(u"Question"), + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return False + + def SetChanged(self, changed=True): + self.__hasChanged = changed + + def HasChanged(self): + return self.__hasChanged + + def CheckAndAskSaving(self): + if self.HasChanged(): + filepath = self.GetSaveFilePath() + if filepath is None: + filepath = _(u"New file") + + dlg = wx.MessageDialog(self.GetParent(), + _(u"'%s' has been modified. Save changes?") % Decode(filepath), + _(u"Question"), + wx.YES_NO | wx.CANCEL | wx.ICON_EXCLAMATION) + response = dlg.ShowModal() + dlg.Destroy() + + if response == wx.ID_CANCEL: + return False + elif response == wx.ID_YES and not self.OnSave(): + return False + return True + + def OnSave(self): + curFilePath = self.GetSaveFilePath() + if curFilePath is None: + return self.OnSaveAs() + elif self.__Save(curFilePath): + self.SetChanged(False) + return True + else: + return False + + def OnSaveAs(self): + curFilePath = self.GetSaveFilePath() + if curFilePath is None: + curFilePath = "{0}{1}".format(self._GetEditorName(), self.GetFileExtension()) + dlg = wx.FileDialog(self.GetParent(), _(u"Save %s") % self._GetEditorName(), + self._GetDefaultSaveFolder(), + curFilePath, + self._GetEditorName() + u'-' + _(u"File") + " (*{0})|*{0}".format(self.GetFileExtension()), + wx.FD_SAVE) + try: + if dlg.ShowModal() == wx.ID_OK: + filepath = dlg.GetPath() + if os.path.splitext(filepath)[1].lower() != self.GetFileExtension(): + filepath += self.GetFileExtension() + + if os.path.isfile(filepath): + dlg2 = wx.MessageDialog(self.GetParent(), + _(u"Overwrite existing file '%s'?") % filepath, + _(u"Question"), + wx.YES_NO | wx.ICON_QUESTION) + try: + if dlg2.ShowModal() == wx.ID_NO: + return False + finally: + dlg2.Destroy() + + if self.__Save(filepath): + self.SetChanged(False) + return True + else: + return False + finally: + dlg.Destroy() + + def _GetDefaultSaveFolder(self): + return Settings().GetProjectPath() + + def _GetEditorName(self): + raise NotImplementedError() + + def _Save(self, filepath): + raise NotImplementedError() + + def GetProject(self): + raise NotImplementedError() + + def GetFileExtension(self): + raise NotImplementedError() + + def GetStatusText(self, index): + raise NotImplementedError() + + def GetSaveFilePath(self): + raise NotImplementedError() + + def AddMenuFileActions(self, menu): + pass + + def AddMenuEditActions(self, menu): + pass + + def AddToolBarActions(self, toolBar): + pass + + def ConnectEvents(self, evtHandler): + pass + + def DisconnEvents(self, evtHandler): + pass diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PnlEditPicture.py photofilmstrip-3.3.1/photofilmstrip/gui/PnlEditPicture.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PnlEditPicture.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PnlEditPicture.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:FramePanel:PnlEditPicture +# Boa:FramePanel:PnlEditPicture # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. @@ -25,27 +25,26 @@ from photofilmstrip.core.Picture import Picture from photofilmstrip.gui.ctrls.PnlFloatSpinCtrl import ( - PnlFloatSpinCtrl, + PnlFloatSpinCtrl, EVT_VALUE_CHANGED) - -[wxID_PNLEDITPICTURE, wxID_PNLEDITPICTURECHOICEEFFECT, - wxID_PNLEDITPICTURECHOICEMOVEMENT, wxID_PNLEDITPICTURECHOICETRANS, - wxID_PNLEDITPICTURECMDROTATELEFT, wxID_PNLEDITPICTURECMDROTATERIGHT, - wxID_PNLEDITPICTUREPNLIMGDURATION, wxID_PNLEDITPICTUREPNLTRANSDURATION, - wxID_PNLEDITPICTURESTATICLINE1, wxID_PNLEDITPICTURESTATICLINE2, - wxID_PNLEDITPICTURESTDURATIONUNIT, wxID_PNLEDITPICTURESTEFFECT, - wxID_PNLEDITPICTURESTMOVEMENT, wxID_PNLEDITPICTURESTPROCESS, - wxID_PNLEDITPICTURESTROTATION, wxID_PNLEDITPICTURESTSETTINGS, - wxID_PNLEDITPICTURESTSUBTITLE, wxID_PNLEDITPICTURESTTRANS, - wxID_PNLEDITPICTURESTTRANSUNIT, wxID_PNLEDITPICTURETCCOMMENT, +[wxID_PNLEDITPICTURE, wxID_PNLEDITPICTURECHOICEEFFECT, + wxID_PNLEDITPICTURECHOICEMOVEMENT, wxID_PNLEDITPICTURECHOICETRANS, + wxID_PNLEDITPICTURECMDROTATELEFT, wxID_PNLEDITPICTURECMDROTATERIGHT, + wxID_PNLEDITPICTUREPNLIMGDURATION, wxID_PNLEDITPICTUREPNLTRANSDURATION, + wxID_PNLEDITPICTURESTATICLINE1, wxID_PNLEDITPICTURESTATICLINE2, + wxID_PNLEDITPICTURESTDURATIONUNIT, wxID_PNLEDITPICTURESTEFFECT, + wxID_PNLEDITPICTURESTMOVEMENT, wxID_PNLEDITPICTURESTPROCESS, + wxID_PNLEDITPICTURESTROTATION, wxID_PNLEDITPICTURESTSETTINGS, + wxID_PNLEDITPICTURESTSUBTITLE, wxID_PNLEDITPICTURESTTRANS, + wxID_PNLEDITPICTURESTTRANSUNIT, wxID_PNLEDITPICTURETCCOMMENT, ] = [wx.NewId() for _init_ctrls in range(20)] class PnlEditPicture(wx.Panel): - + _custom_classes = {"wx.Panel": ["PnlFloatSpinCtrl"]} - + def _init_coll_sizerMain_Items(self, parent): # generated method, don't edit @@ -129,7 +128,7 @@ self.sizerRotationTools = wx.BoxSizer(orient=wx.HORIZONTAL) - self.sizerTimesCtrls = wx.FlexGridSizer(cols=4, hgap=8, rows=1, vgap=8) + self.sizerTimesCtrls = wx.FlexGridSizer(cols=4, hgap=8, rows=2, vgap=8) self.szTimes = wx.BoxSizer(orient=wx.VERTICAL) @@ -161,19 +160,19 @@ label=_(u'Rotation:'), name=u'stRotation', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) - self.cmdRotateLeft = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('wxART_UNDO', - wx.ART_TOOLBAR, (16, 16)), + self.cmdRotateLeft = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_LEFT_16'), id=wxID_PNLEDITPICTURECMDROTATELEFT, name=u'cmdRotateLeft', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.BU_AUTODRAW) + self.cmdRotateLeft.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_LEFT_D_16')) self.cmdRotateLeft.Bind(wx.EVT_BUTTON, self.OnCmdRotateLeftButton, id=wxID_PNLEDITPICTURECMDROTATELEFT) - self.cmdRotateRight = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('wxART_REDO', - wx.ART_TOOLBAR, (16, 16)), + self.cmdRotateRight = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_RIGHT_16'), id=wxID_PNLEDITPICTURECMDROTATERIGHT, name=u'cmdRotateRight', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.BU_AUTODRAW) + self.cmdRotateRight.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_RIGHT_D_16')) self.cmdRotateRight.Bind(wx.EVT_BUTTON, self.OnCmdRotateRightButton, id=wxID_PNLEDITPICTURECMDROTATERIGHT) @@ -251,22 +250,22 @@ self.stSettings.SetFont(font) self.stProcess.SetFont(font) self.stSubtitle.SetFont(font) - + self.choiceMovement.Append(_(u"Linear"), Picture.MOVE_LINEAR) self.choiceMovement.Append(_(u"Accelerated"), Picture.MOVE_ACCEL) self.choiceMovement.Append(_(u"Delayed"), Picture.MOVE_DELAYED) self.choiceMovement.SetSelection(1) self.choiceMovement.Bind(wx.EVT_CHOICE, self.OnChoiceMvmntChoice) - + self.pnlImgDuration.SetRange(1, 6000) self.pnlImgDuration.SetValue(7) self.pnlImgDuration.Bind(EVT_VALUE_CHANGED, self.OnImgDurationChanged) - + self.choiceEffect.Append(_(u"No effect"), Picture.EFFECT_NONE) self.choiceEffect.Append(_(u"Black and White"), Picture.EFFECT_BLACK_WHITE) self.choiceEffect.Append(_(u"Sepia tone"), Picture.EFFECT_SEPIA) self.choiceEffect.SetSelection(0) - + self.pnlTransDuration.SetRange(5, 200) self.pnlTransDuration.SetValue(1) self.pnlTransDuration.Bind(EVT_VALUE_CHANGED, self.OnTransDurationChanged) @@ -288,31 +287,29 @@ def OnCmdRotateLeftButton(self, event): for pic in self._pictures: pic.Rotate(False) - event.Skip() def OnCmdRotateRightButton(self, event): for pic in self._pictures: pic.Rotate(True) - event.Skip() def OnChoiceEffectChoice(self, event): for pic in self._pictures: pic.SetEffect(event.GetClientData()) event.Skip() - + def OnChoiceMvmntChoice(self, event): mvmnt = event.GetClientData() for pic in self._pictures: pic.SetMovement(mvmnt) event.Skip() - + def OnChoiceTransChoice(self, event): trans = event.GetClientData() for pic in self._pictures: pic.SetTransition(trans) self.pnlTransDuration.Enable(trans != Picture.TRANS_NONE) event.Skip() - + def OnTransDurationChanged(self, event): duration = event.GetValue() for pic in self._pictures: @@ -327,7 +324,7 @@ for pic in self._pictures: pic.SetComment(self.tcComment.GetValue()) event.Skip() - + def SetPictures(self, pictures): if pictures is None: pictures = [] @@ -336,12 +333,12 @@ self._pictures = pictures if self._pictures: pic = self._pictures[0] - + self.tcComment.SetValue(pic.GetComment()) self.pnlImgDuration.SetValue(pic.GetDuration()) self.__SetChoiceSelectionByData(self.choiceMovement, pic.GetMovement()) self.__SetChoiceSelectionByData(self.choiceEffect, pic.GetEffect()) - + self.__SetChoiceSelectionByData(self.choiceTrans, pic.GetTransition()) self.pnlTransDuration.SetValue(pic.GetTransitionDuration(rawValue=True)) self.pnlTransDuration.Enable(pic.GetTransition() != Picture.TRANS_NONE) diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PnlPfsProject.py photofilmstrip-3.3.1/photofilmstrip/gui/PnlPfsProject.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PnlPfsProject.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PnlPfsProject.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,9 +1,9 @@ -#Boa:FramePanel:PnlPfsProject +# Boa:FramePanel:PnlPfsProject # encoding: UTF-8 # # PhotoFilmStrip - Creates movies out of your pictures. # -# Copyright (C) 2010 Jens Goepfert +# Copyright (C) 2017 Jens Goepfert # # 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 @@ -25,12 +25,20 @@ import wx +from photofilmstrip.action.ActionAutoPath import ActionAutoPath +from photofilmstrip.action.ActionCenterPath import ActionCenterPath +from photofilmstrip.action.ActionRender import ActionRender + from photofilmstrip.core.Picture import Picture from photofilmstrip.core.Project import Project +from photofilmstrip.core.PicturePattern import PicturePattern from photofilmstrip.lib.Settings import Settings from photofilmstrip.lib.common.ObserverPattern import Observer +from photofilmstrip.lib.jobimpl.JobManager import JobManager +from photofilmstrip.lib.util import CheckFile +from photofilmstrip.gui.helper import CreateMenuItem from photofilmstrip.gui.ImageSectionEditor import ( ImageSectionEditor, ImageProxy, EVT_RECT_CHANGED) from photofilmstrip.gui.PhotoFilmStripList import ( @@ -38,37 +46,53 @@ from photofilmstrip.gui.util.ImageCache import ImageCache +from photofilmstrip.gui.PnlEditorPage import PnlEditorPage from photofilmstrip.gui.PnlEditPicture import PnlEditPicture from photofilmstrip.gui.PnlAddPics import PnlAddPics from photofilmstrip.gui.DlgPositionInput import DlgPositionInput +from photofilmstrip.gui.DlgProjectProps import DlgProjectProps +from photofilmstrip.gui.DlgRender import DlgRender +from photofilmstrip.gui.WxProjectFile import WxProjectFile +from photofilmstrip.core.exceptions import RenderException + +[wxID_PNLPFSPROJECT, wxID_PNLPFSPROJECTBITMAPLEFT, + wxID_PNLPFSPROJECTBITMAPRIGHT, wxID_PNLPFSPROJECTCMDMOVELEFT, + wxID_PNLPFSPROJECTCMDMOVERIGHT, wxID_PNLPFSPROJECTCMDREMOVE, + wxID_PNLPFSPROJECTLVPICS, wxID_PNLPFSPROJECTPANELTOP, + wxID_PNLPFSPROJECTPNLADDPICS, wxID_PNLPFSPROJECTPNLEDITPICTURE, + wxID_PNLPFSPROJECTTOOLBARIMGSECT, +] = [wx.NewId() for _init_ctrls in range(11)] -from photofilmstrip.action.ActionAutoPath import ActionAutoPath -from photofilmstrip.action.ActionCenterPath import ActionCenterPath -from photofilmstrip.core.PicturePattern import PicturePattern +[wxID_PNLPFSPROJECTTOOLBARIMGSECTADJUST, + wxID_PNLPFSPROJECTTOOLBARIMGSECTFTTORIGHT, + wxID_PNLPFSPROJECTTOOLBARIMGSECTGHTTOLEFT, + wxID_PNLPFSPROJECTTOOLBARIMGSECTUNLOCK, wxID_PNLPFSPROJECTTOOLBARIMGSECTSWAP, + wxID_PNLPFSPROJECTTOOLBARIMGSECTTOPATH, +] = [wx.NewId() for _init_coll_toolBarImgSect_Tools in range(6)] -[wxID_PNLPFSPROJECT, wxID_PNLPFSPROJECTBITMAPLEFT, - wxID_PNLPFSPROJECTBITMAPRIGHT, wxID_PNLPFSPROJECTCMDMOVELEFT, - wxID_PNLPFSPROJECTCMDMOVERIGHT, wxID_PNLPFSPROJECTCMDREMOVE, - wxID_PNLPFSPROJECTLVPICS, wxID_PNLPFSPROJECTPANELTOP, - wxID_PNLPFSPROJECTPNLADDPICS, wxID_PNLPFSPROJECTPNLEDITPICTURE, - wxID_PNLPFSPROJECTTOOLBARIMGSECT, -] = [wx.NewId() for _init_ctrls in range(11)] +[ID_PROJECT_PROPS, + ID_PIC_MOVE_LEFT, + ID_PIC_MOVE_RIGHT, + ID_PIC_REMOVE, + ID_PIC_ROTATE_CW, + ID_PIC_ROTATE_CCW, + ID_PIC_MOTION_RANDOM, + ID_PIC_MOTION_CENTER, + ID_PIC_IMPORT, + ID_PIC_SLIDE, + ID_RENDER_FILMSTRIP, + ID_EXPORT, ID_IMPORT, +] = [wx.NewId() for __ in range(13)] -[wxID_PNLPFSPROJECTTOOLBARIMGSECTADJUST, - wxID_PNLPFSPROJECTTOOLBARIMGSECTFTTORIGHT, - wxID_PNLPFSPROJECTTOOLBARIMGSECTGHTTOLEFT, - wxID_PNLPFSPROJECTTOOLBARIMGSECTUNLOCK, wxID_PNLPFSPROJECTTOOLBARIMGSECTSWAP, - wxID_PNLPFSPROJECTTOOLBARIMGSECTTOPATH, -] = [wx.NewId() for _init_coll_toolBarImgSect_Tools in range(6)] +class PnlPfsProject(PnlEditorPage, Observer): -class PnlPfsProject(wx.Panel, Observer): - - _custom_classes = {"wx.Panel": ["ImageSectionEditor", + _custom_classes = {"wx.Panel": ["PnlEditorPage", + "ImageSectionEditor", "PnlEditPicture", "PnlAddPics"], "wx.ListView": ["PhotoFilmStripList"]} - + def _init_coll_sizerPictures_Items(self, parent): # generated method, don't edit @@ -96,37 +120,37 @@ def _init_coll_sizerPnlTop_Items(self, parent): # generated method, don't edit - parent.AddWindow(self.bitmapLeft, 1, border=2, flag=wx.EXPAND | wx.ALL) + parent.AddWindow(self.bitmapLeft, 1, border=0, flag=wx.EXPAND | wx.ALL) parent.AddWindow(self.toolBarImgSect, 0, border=0, flag=wx.EXPAND) - parent.AddWindow(self.bitmapRight, 1, border=2, flag=wx.ALL | wx.EXPAND) + parent.AddWindow(self.bitmapRight, 1, border=0, flag=wx.ALL | wx.EXPAND) def _init_coll_toolBarImgSect_Tools(self, parent): # generated method, don't edit - parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_RANDOM', - wx.ART_TOOLBAR, wx.DefaultSize), bmpDisabled=wx.NullBitmap, + parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_RANDOM_24'), + bmpDisabled=wx.NullBitmap, id=wxID_PNLPFSPROJECTTOOLBARIMGSECTTOPATH, kind=wx.ITEM_NORMAL, label=u'', longHelp=u'', shortHelp=_(u'Random motion')) parent.AddSeparator() - parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_RIGHT', - wx.ART_TOOLBAR, wx.DefaultSize), bmpDisabled=wx.NullBitmap, + parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_START_TO_END_24'), + bmpDisabled=wx.NullBitmap, id=wxID_PNLPFSPROJECTTOOLBARIMGSECTFTTORIGHT, kind=wx.ITEM_NORMAL, - label='', longHelp='', shortHelp=_(u'Set motion end to start')) - parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_LEFT', - wx.ART_TOOLBAR, wx.DefaultSize), bmpDisabled=wx.NullBitmap, + label='', longHelp='', shortHelp=_(u'Set motion start to end')) + parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_END_TO_START_24'), + bmpDisabled=wx.NullBitmap, id=wxID_PNLPFSPROJECTTOOLBARIMGSECTGHTTOLEFT, kind=wx.ITEM_NORMAL, - label=u'', longHelp=u'', shortHelp=_(u'Set motion start to end')) - parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_SWAP', - wx.ART_TOOLBAR, wx.DefaultSize), bmpDisabled=wx.NullBitmap, + label=u'', longHelp=u'', shortHelp=_(u'Set motion end to start')) + parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_SWAP_24'), + bmpDisabled=wx.NullBitmap, id=wxID_PNLPFSPROJECTTOOLBARIMGSECTSWAP, kind=wx.ITEM_NORMAL, label='', longHelp='', shortHelp=_(u'Swap motion')) parent.AddSeparator() - parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_INPUT', + parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_MOTION_MANUAL_24', wx.ART_TOOLBAR, wx.DefaultSize), bmpDisabled=wx.NullBitmap, id=wxID_PNLPFSPROJECTTOOLBARIMGSECTADJUST, kind=wx.ITEM_NORMAL, label='', longHelp='', shortHelp=_(u'Adjust motion manual')) parent.AddSeparator() - parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_LOCK', + parent.DoAddTool(bitmap=wx.ArtProvider.GetBitmap('PFS_LOCK_24', wx.ART_TOOLBAR, wx.DefaultSize), bmpDisabled=wx.NullBitmap, id=wxID_PNLPFSPROJECTTOOLBARIMGSECTUNLOCK, kind=wx.ITEM_CHECK, label='', longHelp='', shortHelp=_(u'Preserve image dimension')) @@ -165,9 +189,8 @@ def _init_ctrls(self, prnt): # generated method, don't edit - wx.Panel.__init__(self, id=wxID_PNLPFSPROJECT, name=u'PnlPfsProject', - parent=prnt, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), - style=wx.TAB_TRAVERSAL) + PnlEditorPage.__init__(self, id=wxID_PNLPFSPROJECT, name=u'PnlPfsProject', + parent=prnt) self.SetClientSize(wx.Size(400, 250)) self.panelTop = wx.Panel(id=wxID_PNLPFSPROJECTPANELTOP, @@ -179,8 +202,9 @@ size=wx.Size(-1, -1), style=0) self.toolBarImgSect = wx.ToolBar(id=wxID_PNLPFSPROJECTTOOLBARIMGSECT, - name=u'toolBarImgSect', parent=self.panelTop, pos=wx.Point(-1, - -1), size=wx.Size(-1, -1), style=wx.TB_VERTICAL | wx.NO_BORDER) + name=u'toolBarImgSect', parent=self.panelTop, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), + style=wx.TB_VERTICAL | wx.NO_BORDER | wx.TB_NODIVIDER) self.bitmapRight = ImageSectionEditor(id=wxID_PNLPFSPROJECTBITMAPRIGHT, name=u'bitmapRight', parent=self.panelTop, pos=wx.Point(-1, -1), @@ -197,29 +221,31 @@ self.lvPics = PhotoFilmStripList(id=wxID_PNLPFSPROJECTLVPICS, name=u'lvPics', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), - style=wx.LC_ICON | wx.SUNKEN_BORDER | wx.LC_SINGLE_SEL) + style=wx.HSCROLL | wx.ALWAYS_SHOW_SB) self.lvPics.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnLvPicsSelectionChanged, id=wxID_PNLPFSPROJECTLVPICS) - self.cmdMoveLeft = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('wxART_GO_BACK', - wx.ART_OTHER, (32, 32)), id=wxID_PNLPFSPROJECTCMDMOVELEFT, + self.cmdMoveLeft = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_LEFT_32'), + id=wxID_PNLPFSPROJECTCMDMOVELEFT, name=u'cmdMoveLeft', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.BU_AUTODRAW) + self.cmdMoveLeft.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_LEFT_D_32')) self.cmdMoveLeft.Bind(wx.EVT_BUTTON, self.OnCmdMoveLeftButton, id=wxID_PNLPFSPROJECTCMDMOVELEFT) - self.cmdMoveRight = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('wxART_GO_FORWARD', - wx.ART_OTHER, (32, 32)), + self.cmdMoveRight = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_RIGHT_32'), id=wxID_PNLPFSPROJECTCMDMOVERIGHT, name=u'cmdMoveRight', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.BU_AUTODRAW) + self.cmdMoveRight.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_RIGHT_D_32')) self.cmdMoveRight.Bind(wx.EVT_BUTTON, self.OnCmdMoveRightButton, id=wxID_PNLPFSPROJECTCMDMOVERIGHT) - self.cmdRemove = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('wxART_DELETE', - wx.ART_OTHER, (32, 32)), id=wxID_PNLPFSPROJECTCMDREMOVE, + self.cmdRemove = wx.BitmapButton(bitmap=wx.ArtProvider.GetBitmap('PFS_IMAGE_REMOVE_32'), + id=wxID_PNLPFSPROJECTCMDREMOVE, name=u'cmdRemove', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.BU_AUTODRAW) + self.cmdRemove.SetBitmapDisabled(wx.ArtProvider.GetBitmap('PFS_IMAGE_REMOVE_D_32')) self.cmdRemove.Bind(wx.EVT_BUTTON, self.OnCmdRemoveButton, id=wxID_PNLPFSPROJECTCMDREMOVE) @@ -230,15 +256,14 @@ def __init__(self, parent, project): self._init_ctrls(parent) Observer.__init__(self) - + self.lvPics.SetDropTarget(ImageDropTarget(self)) - + self.imgProxyLeft = None self.imgProxyRight = None self.__project = project - self.__hasChanged = False self.__usedAltPath = False - + self.__InitImageProxy() self.bitmapLeft.SetAspect(project.GetAspect()) @@ -251,10 +276,10 @@ self.cmdMoveRight.Enable(False) self.cmdRemove.Enable(False) self.panelTop.Show(False) - + self.Bind(EVT_RECT_CHANGED, self.OnRectChanged, id=self.bitmapLeft.GetId()) self.Bind(EVT_RECT_CHANGED, self.OnRectChanged, id=self.bitmapRight.GetId()) - + self.Bind(EVT_CHANGED, self.OnPhotoFilmStripListChanged, id=self.lvPics.GetId()) project.AddObserver(self) @@ -279,25 +304,197 @@ self.bitmapLeft.SetImgProxy(self.imgProxyLeft) self.bitmapRight.SetImgProxy(self.imgProxyRight) + def GetFileExtension(self): + return ".pfs" + + def GetStatusText(self, index): + project = self.__project + + imgCount = len(project.GetPictures()) + totalTime = project.GetDuration(False) + if project.GetTimelapse(): + # TODO: calc from image count + totalTime = 1 + imgCount = 0 + elif totalTime == -1: + # TODO: calc from audio files + totalTime = 0 + elif totalTime is None: + totalTime = project.GetDuration(True) + + if index == 0: + return u"%s: %d" % (_(u"Images"), imgCount) + + elif index == 1: + minutes = totalTime / 60 + seconds = totalTime % 60 + return u"%s: %02d:%02d" % (_(u"Duration"), + minutes, + seconds) + else: + return u"" + + def GetSaveFilePath(self): + return self.__project.GetFilename() + + def _GetEditorName(self): + return _(u"Project") + + def _Save(self, filepath): + prjFile = WxProjectFile(self, self.__project, filepath) + prjFile.Save(False) + return True + + def AddMenuFileActions(self, menu): +# CreateMenuItem(menu, self.ID_IMPORT, _(u"&Import Project")) +# CreateMenuItem(menu, self.ID_EXPORT, _(u"&Export Project")) +# menu.AppendSeparator() + CreateMenuItem(menu, ID_PROJECT_PROPS, + _(u"&Properties"), + wx.ArtProvider.GetBitmap('PFS_PROPERTIES_16')) + + def AddMenuEditActions(self, menu): + CreateMenuItem(menu, ID_PIC_IMPORT, + _(u'&Import Pictures') + '\tCtrl+I', + wx.ArtProvider.GetBitmap('PFS_IMPORT_PICTURES_16'), + wx.ArtProvider.GetBitmap('PFS_IMPORT_PICTURES_D_16')) + menu.AppendSeparator() + CreateMenuItem(menu, ID_PIC_MOVE_LEFT, + _(u'Move picture &left'), + wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_LEFT_16'), + wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_LEFT_D_16')) + CreateMenuItem(menu, ID_PIC_MOVE_RIGHT, + _(u'Move picture &right'), + wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_RIGHT_16'), + wx.ArtProvider.GetBitmap('PFS_IMAGE_MOVING_RIGHT_D_16')) + menu.AppendSeparator() + CreateMenuItem(menu, ID_PIC_REMOVE, + _(u'R&emove Picture') + '\tCtrl+Del', + wx.ArtProvider.GetBitmap('PFS_IMAGE_REMOVE_16'), + wx.ArtProvider.GetBitmap('PFS_IMAGE_REMOVE_D_16')) + menu.AppendSeparator() + CreateMenuItem(menu, ID_PIC_ROTATE_CW, + _(u'Rotate &clockwise') + '\tCtrl+r', + wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_RIGHT_16'), + wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_RIGHT_D_16')) + CreateMenuItem(menu, ID_PIC_ROTATE_CCW, + _(u'Rotate counter clock&wise') + '\tCtrl+l', + wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_LEFT_16'), + wx.ArtProvider.GetBitmap('PFS_IMAGE_ROTATION_LEFT_D_16')) + menu.AppendSeparator() + CreateMenuItem(menu, ID_PIC_MOTION_RANDOM, + _(u'Random &motion' + '\tCtrl+d'), + wx.ArtProvider.GetBitmap('PFS_MOTION_RANDOM_16'), + wx.ArtProvider.GetBitmap('PFS_MOTION_RANDOM_D_16')) + CreateMenuItem(menu, ID_PIC_MOTION_CENTER, + _(u'Centralize m&otion') + '\tCtrl+f', + wx.ArtProvider.GetBitmap('PFS_MOTION_CENTER_16'), + wx.ArtProvider.GetBitmap('PFS_MOTION_CENTER_D_16')) + + def AddToolBarActions(self, toolBar): + toolBar.DoAddTool(ID_PIC_IMPORT, '', + wx.ArtProvider.GetBitmap('PFS_IMPORT_PICTURES_24'), + wx.ArtProvider.GetBitmap('PFS_IMPORT_PICTURES_D_24'), + wx.ITEM_NORMAL, + _(u'Import Pictures'), + _(u'Import Pictures'), + None) + toolBar.AddSeparator() + toolBar.DoAddTool(ID_RENDER_FILMSTRIP, '', + wx.ArtProvider.GetBitmap('PFS_RENDER_24'), + wx.ArtProvider.GetBitmap('PFS_RENDER_D_24'), + wx.ITEM_NORMAL, + _(u'Render filmstrip'), + _(u'Render filmstrip'), + None) + + def ConnectEvents(self, evtHandler): + evtHandler.Bind(wx.EVT_MENU, self.OnProjectExport, id=ID_EXPORT) + evtHandler.Bind(wx.EVT_MENU, self.OnProjectImport, id=ID_IMPORT) + evtHandler.Bind(wx.EVT_MENU, self.OnProjectProps, id=ID_PROJECT_PROPS) + + evtHandler.Bind(wx.EVT_MENU, self.OnCmdMoveLeftButton, id=ID_PIC_MOVE_LEFT) + evtHandler.Bind(wx.EVT_MENU, self.OnCmdMoveRightButton, id=ID_PIC_MOVE_RIGHT) + evtHandler.Bind(wx.EVT_MENU, self.OnCmdRemoveButton, id=ID_PIC_REMOVE) + + evtHandler.Bind(wx.EVT_MENU, self.OnCmdRotateLeftButton, id=ID_PIC_ROTATE_CCW) + evtHandler.Bind(wx.EVT_MENU, self.OnCmdRotateRightButton, id=ID_PIC_ROTATE_CW) + evtHandler.Bind(wx.EVT_MENU, self.OnCmdMotionRandom, id=ID_PIC_MOTION_RANDOM) + evtHandler.Bind(wx.EVT_MENU, self.OnCmdMotionCenter, id=ID_PIC_MOTION_CENTER) + + evtHandler.Bind(wx.EVT_MENU, self.OnImportPics, id=ID_PIC_IMPORT) + evtHandler.Bind(wx.EVT_MENU, self.OnRenderFilmstrip, id=ID_RENDER_FILMSTRIP) + + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ID_PIC_REMOVE) + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ID_PIC_ROTATE_CCW) + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ID_PIC_ROTATE_CW) + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ID_PIC_MOVE_LEFT) + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ID_PIC_MOVE_RIGHT) + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ID_PIC_MOTION_RANDOM) + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckImageSelected, id=ID_PIC_MOTION_CENTER) + evtHandler.Bind(wx.EVT_UPDATE_UI, self.OnCheckProjectReady, id=ID_RENDER_FILMSTRIP) + + def DisconnEvents(self, evtHandler): + for wId in [ID_PIC_MOVE_LEFT, ID_PIC_MOVE_RIGHT, ID_PIC_REMOVE, + ID_PIC_ROTATE_CCW, ID_PIC_ROTATE_CW, ID_PIC_MOTION_RANDOM, + ID_PIC_MOTION_CENTER, ID_PIC_IMPORT, ID_PIC_SLIDE]: + evtHandler.Disconnect(wId) + def GetSelectedImageState(self): items = self.lvPics.GetSelected() if len(items) == 0: kind = 'none' elif items[0] == 0: if self.lvPics.GetItemCount() == 1: - kind = 'none' # to disable move buttons + kind = 'none' # to disable move buttons else: kind = 'first' elif items[0] == self.lvPics.GetItemCount() - 1: kind = 'last' else: kind = 'any' - + # if len(items) > 1: # kind = 'multi' - + return kind + def OnProjectExport(self, event): + prj = self.__project + curFilePath = prj.GetFilename() + dlg = wx.FileDialog(self, _(u"Export slideshow"), + Settings().GetProjectPath(), + curFilePath, + u"%s %s" % (_(u"Portable slideshow"), "(*.ppfs)|*.ppfs"), + wx.FD_SAVE) + if dlg.ShowModal() == wx.ID_OK: + filepath = dlg.GetPath() + if os.path.splitext(filepath)[1].lower() != ".ppfs": + filepath += ".ppfs" + + prjFile = WxProjectFile(self, self.__project, filepath) + prjFile.Save(True) + + def OnProjectImport(self, event): + dlg = wx.FileDialog(self, _(u"Import Slideshow"), + Settings().GetProjectPath(), "", + u"%s %s" % (_(u"Portable slideshow"), "(*.ppfs)|*.ppfs"), + wx.FD_OPEN) + if dlg.ShowModal() == wx.ID_OK: + filepath = dlg.GetPath() + + prjFile = WxProjectFile(self, filename=filepath) + prjFile.Load() + + def OnProjectProps(self, event): + dlg = DlgProjectProps(self, self.__project) + if dlg.ShowModal() == wx.ID_OK: + dlg.GetProject() # Makes changes to self.__project + self.bitmapLeft.SetAspect(self.__project.GetAspect()) + self.bitmapRight.SetAspect(self.__project.GetAspect()) + self.SetChanged(True) + dlg.Destroy() + def OnImportPics(self, event): dlg = wx.FileDialog(self, _(u"Import images"), Settings().GetImagePath(), "", @@ -336,13 +533,58 @@ self.pnlEditPicture.SetPictures(selPics) dlg.Destroy() + def OnRenderFilmstrip(self, event): + self.PrepareRendering() + + project = self.__project + dlg = DlgRender(self, project.GetAspect()) + try: + if dlg.ShowModal() != wx.ID_OK: + return + + profile = dlg.GetProfile() + draftMode = dlg.GetDraftMode() + rendererClass = dlg.GetRendererClass() + finally: + dlg.Destroy() + + ar = ActionRender(project, + profile, + rendererClass, + draftMode) + try: + ar.Execute() + renderJob = ar.GetRenderJob() + JobManager().EnqueueContext(renderJob) + except RenderException, exc: + dlg = wx.MessageDialog(self, + exc.GetMessage(), + _(u"Error"), + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + + def OnCheckImageSelected(self, event): + value = self.IsPictureSelected() + kind = self.GetSelectedImageState() + if event.GetId() == ID_PIC_MOVE_LEFT: + # FIXME: does not work with multiselect + value = kind not in ['first', 'none'] and value + elif event.GetId() == ID_PIC_MOVE_RIGHT: + # FIXME: does not work with multiselect + value = kind not in ['last', 'none'] and value + event.Enable(value) + + def OnCheckProjectReady(self, event): + event.Enable(self.IsReady()) + def OnLvPicsSelectionChanged(self, event): selItems = self.lvPics.GetSelected() - + self.cmdMoveLeft.Enable(selItems.count(0) == 0) self.cmdMoveRight.Enable(selItems.count(self.lvPics.GetItemCount() - 1) == 0) self.cmdRemove.Enable(len(selItems) > 0) - + selPics = self.lvPics.GetSelectedPictures() self.pnlEditPicture.SetPictures(selPics) @@ -363,7 +605,7 @@ # assert self.imgProxyLeft is self.imgProxyRight self.imgProxyLeft.SetPicture(selPics[0]) self.imgProxyRight.SetPicture(selPics[0]) - + self.__CheckAndSetLock(selPics[0]) self.bitmapLeft.SetSection(wx.Rect(*selPics[0].GetStartRect())) self.bitmapRight.SetSection(wx.Rect(*selPics[0].GetTargetRect())) @@ -420,7 +662,7 @@ selItems.sort() for selItem in selItems: self.lvPics.SwapPictures(selItem, selItem - 1) - + self.SetChanged(True) def OnCmdMoveRightButton(self, event): @@ -437,7 +679,7 @@ selItems.sort(reverse=True) for selItem in selItems: self.lvPics.DeleteItem(selItem) - + if self.lvPics.GetItemCount() == 0: self.imgProxyLeft.SetPicture(None) self.imgProxyRight.SetPicture(None) @@ -445,14 +687,26 @@ self.pnlEditPicture.Enable(False) self.cmdMoveLeft.Enable(False) self.cmdMoveRight.Enable(False) - + self.pnlAddPics.Show(True) self.panelTop.Show(False) - + self.cmdRemove.Enable(self.lvPics.GetItemCount() > 0) - + self.Layout() + def OnCmdRotateLeftButton(self, event): + self.pnlEditPicture.OnCmdRotateLeftButton(event) + + def OnCmdRotateRightButton(self, event): + self.pnlEditPicture.OnCmdRotateRightButton(event) + + def OnCmdMotionRandom(self, event): + self.OnMotionRandom() + + def OnCmdMotionCenter(self, event): + self.OnMotionCenter() + def OnPhotoFilmStripListChanged(self, event): self.__project.SetPictures(self.lvPics.GetPictures()) self.SetChanged(True) @@ -482,11 +736,11 @@ target = pic.GetTargetRect() pic.SetTargetRect(pic.GetStartRect()) pic.SetStartRect(target) - + def OnToolBarImgSectToolAdjust(self, event): selItem = self.lvPics.GetSelected() selPic = self.lvPics.GetPicture(selItem[0]) - + dlg = DlgPositionInput(self, selPic, self.__project.GetAspect()) dlg.ShowModal() dlg.Destroy() @@ -495,6 +749,7 @@ for pic in self.lvPics.GetSelectedPictures(): actAp = ActionAutoPath(pic, self.__project.GetAspect()) actAp.Execute() + def OnMotionCenter(self): for pic in self.lvPics.GetSelectedPictures(): actCp = ActionCenterPath(pic, self.__project.GetAspect()) @@ -509,11 +764,25 @@ def GetProject(self): return self.__project + def PrepareRendering(self): + for audioFile in self.__project.GetAudioFiles(): + if not CheckFile(audioFile): + dlg = wx.MessageDialog(self, + _(u"Audio file '%s' does not exist! Continue anyway?") % audioFile, + _(u"Warning"), + wx.YES_NO | wx.ICON_WARNING) + dlgResult = dlg.ShowModal() + dlg.Destroy() + if dlgResult == wx.ID_NO: + return + else: + break + def InsertPictures(self, pics, position=None, autopath=False): logging.debug("InsertPictures(pos=%s)", position) if position is None: position = self.lvPics.GetItemCount() - + self.lvPics.Freeze() for pic in pics: if autopath: @@ -521,19 +790,19 @@ actAp.Execute() self.lvPics.InsertPicture(position, pic) - position += 1 + position += 1 pic.AddObserver(self) self.lvPics.Thaw() if len(self.lvPics.GetSelected()) == 0: self.lvPics.Select(0) - + self.SetChanged(True) self.pnlAddPics.Show(self.lvPics.GetItemCount() == 0) self.panelTop.Show(self.lvPics.GetItemCount() != 0) self.Layout() - + self.lvPics.SetFocus() def ObservableUpdate(self, obj, arg): @@ -544,7 +813,7 @@ elif self.bitmapRight._imgProxy._picture is obj: self.imgProxyRight.SetPicture(obj) self.lvPics.Refresh() - + if arg == 'duration': self.__project.Notify("duration") @@ -553,7 +822,7 @@ if arg == 'target' and self.bitmapLeft._imgProxy._picture is obj: self.bitmapRight.SetSection(wx.Rect(*obj.GetTargetRect())) - + self.SetChanged(True) elif isinstance(obj, Project): @@ -561,21 +830,11 @@ self.__InitImageProxy() self.OnLvPicsSelectionChanged(None) - def UpdateProperties(self): - self.bitmapLeft.SetAspect(self.__project.GetAspect()) - self.bitmapRight.SetAspect(self.__project.GetAspect()) - self.SetChanged(True) - def IsReady(self): return self.lvPics.GetItemCount() > 0 - + def IsPictureSelected(self): return len(self.lvPics.GetSelected()) > 0 - - def SetChanged(self, changed=True): - self.__hasChanged = changed - def HasChanged(self): - return self.__hasChanged def __CheckAndSetLock(self, pic): unlocked = False @@ -587,9 +846,9 @@ self.toolBarImgSect.ToggleTool(wxID_PNLPFSPROJECTTOOLBARIMGSECTUNLOCK, unlocked) if unlocked: - resName = 'PFS_UNLOCK' + resName = 'PFS_UNLOCK_24' else: - resName = 'PFS_LOCK' + resName = 'PFS_LOCK_24' self.toolBarImgSect.SetToolNormalBitmap( wxID_PNLPFSPROJECTTOOLBARIMGSECTUNLOCK, wx.ArtProvider.GetBitmap(resName, wx.ART_TOOLBAR, wx.DefaultSize)) @@ -598,9 +857,9 @@ def OnToolBarImgSectUnlockTool(self, event): if event.IsChecked(): - resName = 'PFS_UNLOCK' + resName = 'PFS_UNLOCK_24' else: - resName = 'PFS_LOCK' + resName = 'PFS_LOCK_24' self.toolBarImgSect.SetToolNormalBitmap( wxID_PNLPFSPROJECTTOOLBARIMGSECTUNLOCK, wx.ArtProvider.GetBitmap(resName, wx.ART_TOOLBAR, wx.DefaultSize)) @@ -610,7 +869,7 @@ class ImageDropTarget(wx.FileDropTarget): - + def __init__(self, pnlPfs): wx.FileDropTarget.__init__(self) self.pnlPfs = pnlPfs @@ -618,8 +877,8 @@ def OnDropFiles(self, x, y, filenames): itm = self.pnlPfs.lvPics.HitTest((x, y)) logging.debug("OnDropFiles(%d, %d, %s): %s", x, y, filenames, itm) - - pics = [] + + pics = [] for path in filenames: ext = os.path.splitext(path)[1].lower() if ext in ['.jpg', '.jpeg', '.png', '.bmp']: @@ -630,4 +889,3 @@ self.pnlPfs.InsertPictures(pics, itm + 1 if itm != wx.NOT_FOUND else None, True) return True return False - diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PnlRenderJobVisual.py photofilmstrip-3.3.1/photofilmstrip/gui/PnlRenderJobVisual.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PnlRenderJobVisual.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PnlRenderJobVisual.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:FramePanel:PnlJobVisual +# Boa:FramePanel:PnlJobVisual # encoding: UTF-8 import wx @@ -13,25 +13,18 @@ def __init__(self, parent, pnlJobManager, jobContext): PnlJobVisual.__init__(self, parent, pnlJobManager, jobContext) - - ms = wx.ArtProvider.GetSizeHint(wx.ART_MENU) - ts = wx.ArtProvider.GetSizeHint(wx.ART_TOOLBAR) self._actPlay = WxAction( _(u"Play video"), self._PlayVideo, - bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, - wx.ART_MENU, - ms), - wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, - wx.ART_TOOLBAR, - ts)} + bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap('PFS_PLAY_16'), + wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap('PFS_PLAY_24')} ) self._actOpenFldr = WxAction( _(u"Open folder"), self._OpenFolder, - bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_MENU, ms), - wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_TOOLBAR, ts)} + bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap('PFS_FOLDER_OPEN_16'), + wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap('PFS_FOLDER_OPEN_24')} ) def _OnMenuActions(self, menu): @@ -40,13 +33,13 @@ mitm = self._actOpenFldr.ToMenu(self, menu) menu.Enable(mitm.GetId(), not self.jobContext.IsIdle()) - + def _OnSetupAction(self): if self.jobContext.IsDone(): self.curAction = self._actPlay - + def _PlayVideo(self): ActionPlayVideo(self.jobContext.GetOutputPath()).Execute() - + def _OpenFolder(self): ActionOpenFolder(self.jobContext.GetOutputPath()).Execute() diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/PnlWelcome.py photofilmstrip-3.3.1/photofilmstrip/gui/PnlWelcome.py --- photofilmstrip-3.2.0/photofilmstrip/gui/PnlWelcome.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/PnlWelcome.py 2017-12-03 22:12:24.000000000 +0000 @@ -40,34 +40,41 @@ def __init__(self, parent, frmMain): wx.Panel.__init__(self, parent) self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) - + self.title = _(u"Welcome to PhotoFilmStrip") - + self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_SIZE, self.OnSize) - + self.__frmMain = frmMain self.htmlTitle = _(u"Recent projects") - self.htmlText = u"" + self.htmlText = u"" self.htmlRecentProjects = u"" self.htmlUpdate = u"" - self.htmlWin = wx.html.HtmlWindow(self, -1, style=wx.SIMPLE_BORDER) + self.pnlHtmlBackground = wx.Panel(self) + self.pnlHtmlBackground.SetBackgroundColour(wx.Colour(52, 73, 94)) + + self.htmlWin = wx.html.HtmlWindow(self.pnlHtmlBackground, -1, style=wx.NO_BORDER) self.htmlWin.Bind(EVT_LINK, self.OnLinkClicked) - self.RefreshPage() self.htmlWin.SetSizeHints(650, -1, 650, -1) + sizerHtmlBackground = wx.BoxSizer(wx.HORIZONTAL) + sizerHtmlBackground.Add(self.htmlWin, 1, wx.EXPAND | wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 8) + + self.bmpFilmstrip = wx.ArtProvider.GetBitmap('PFS_FILMSTRIP') + self.cmdNew = wx.BitmapButton(self, -1, - wx.ArtProvider_GetBitmap(wx.ART_NEW, wx.ART_OTHER, (64, 64))) + wx.ArtProvider.GetBitmap('PFS_PROJECT_NEW_64')) self.cmdNew.SetToolTipString(_(u"Create new project")) self.cmdNew.Bind(wx.EVT_BUTTON, self.__frmMain.OnProjectNew) - + self.cmdOpen = wx.BitmapButton(self, -1, - wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, (64, 64))) + wx.ArtProvider.GetBitmap('PFS_PROJECT_OPEN_64')) self.cmdOpen.SetToolTipString(_(u"Open existing project")) self.cmdOpen.Bind(wx.EVT_BUTTON, self.__frmMain.OnProjectLoad) - + sizerCmd = wx.BoxSizer(wx.HORIZONTAL) sizerCmd.Add(self.cmdNew, 0, wx.ALL, 30) sizerCmd.AddStretchSpacer(1) @@ -76,15 +83,18 @@ sizerMain = wx.BoxSizer(wx.VERTICAL) sizerMain.AddStretchSpacer(1) sizerMain.Add(sizerCmd, 0, wx.ALIGN_CENTER_HORIZONTAL, 8) - sizerMain.Add(self.htmlWin, 3, wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 8) - sizerMain.AddStretchSpacer(2) - + sizerMain.Add(self.pnlHtmlBackground, 3, wx.ALL | wx.ALIGN_CENTER_HORIZONTAL, 8) + sizerMain.AddStretchSpacer(1) + + self.pnlHtmlBackground.SetSizer(sizerHtmlBackground) self.SetSizer(sizerMain) self.Layout() - + + self.RefreshPage() + self.__updateChecker = UpdateChecker() wx.CallLater(500, self.__NotifyUpdate) - + def RefreshPage(self, withHistory=True): if withHistory: htmlParts = [] @@ -97,27 +107,27 @@ """ % recentFile htmlParts.append(htmlPart) - + breakAt = 4 for idx in xrange((len(htmlParts) - 1) / breakAt): htmlParts.insert(idx + ((idx + 1) * breakAt), "") - + if htmlParts: self.htmlTitle = _(u"Recent projects") - self.htmlText = "" + self.htmlText = "" else: self.htmlTitle = _(u"How to start...") - self.htmlText = _(u"Create a new project or load an existing one.") - + self.htmlText = _(u"Create a new project or load an existing one.") + self.htmlRecentProjects = "".join(htmlParts) - - html = HTML_TEMPLATE % {'title': self.htmlTitle, + + html = HTML_TEMPLATE % {'title': self.htmlTitle, 'text': self.htmlText, 'htmlRecentProjects': self.htmlRecentProjects, 'htmlUpdate': self.htmlUpdate} - + self.htmlWin.SetPage(html) - + def __NotifyUpdate(self): if not self.__updateChecker.IsDone(): wx.CallLater(100, self.__NotifyUpdate) @@ -128,7 +138,7 @@ # return if not self.__updateChecker.IsNewer(Constants.APP_VERSION): return - + Settings().SetLastKnownVersion(self.__updateChecker.GetVersion()) html = """

%(title)s

@@ -144,7 +154,7 @@ "msg": _(u'The following changes has been made:'), "changes": self.__updateChecker.GetChanges(), "url": Constants.APP_URL} - + self.htmlUpdate = html self.RefreshPage(withHistory=False) @@ -155,32 +165,34 @@ def OnPaint(self, event): dc = wx.AutoBufferedPaintDC(self) sz = self.GetSize() - dc.SetBackground(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE))) + dc.SetBackground(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))) dc.Clear() - - rect = wx.RectPS(wx.Point(0, 180), sz) - dc.GradientFillLinear(rect, - wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE), - wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT), + + rect = wx.Rect(0, 180, sz[0], sz[1]) + dc.GradientFillLinear(rect, + wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE), + wx.Colour(52, 73, 94), wx.SOUTH) - - font = wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD) + + font = wx.Font(28, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD, False, 'Tahoma') dc.SetFont(font) - dc.SetTextForeground(wx.Colour(127, 127, 127)) - dc.DrawLabel(self.title, wx.Rect(0, 10, sz[0], 50), wx.ALIGN_CENTER_HORIZONTAL) - + dc.SetTextForeground(wx.Colour(99, 102, 106)) + dc.DrawLabel(self.title, wx.Rect(0, 10, sz[0], 75), wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL) + + dc.DrawBitmap(self.bmpFilmstrip, 10, sz[1] - self.bmpFilmstrip.GetSize()[1] - 30) + def OnLinkClicked(self, event): filename = event.GetFilename() self.__frmMain.LoadProject(filename) class LinkOpenPfs(IconLabelLink): - + BMP_MAP = {} - + def __init__(self, parent, size=wx.DefaultSize, filename=None): self.filename = filename - + if not LinkOpenPfs.BMP_MAP.has_key(filename): prjFile = ProjectFile(filename=filename) imgCount = prjFile.GetPicCount() @@ -189,27 +201,28 @@ wxImg = wx.ImageFromStream(PILBackend.ImageToStream(img), wx.BITMAP_TYPE_JPEG) bmp = wxImg.ConvertToBitmap() else: - bmp = wx.ArtProvider_GetBitmap("PFS_ICON_48", wx.ART_OTHER) + bmp = wx.ArtProvider.GetBitmap("PFS_ICON_48", wx.ART_OTHER) descr = "%d images" % imgCount LinkOpenPfs.BMP_MAP[filename] = (bmp, descr) - + bmp, descr = LinkOpenPfs.BMP_MAP[filename] - + IconLabelLink.__init__(self, parent, size, os.path.splitext(os.path.basename(filename))[0], bmp, descr) - + def OnClick(self): evt = LinkClickedEvent(self.GetParent().GetId(), self.filename) self.GetEventHandler().ProcessEvent(evt) - -EVT_LINK_TYPE = wx.NewEventType() -EVT_LINK = wx.PyEventBinder(EVT_LINK_TYPE, 1) + +EVT_LINK_TYPE = wx.NewEventType() +EVT_LINK = wx.PyEventBinder(EVT_LINK_TYPE, 1) class LinkClickedEvent(wx.PyCommandEvent): + def __init__(self, wxId, filename): wx.PyCommandEvent.__init__(self, EVT_LINK_TYPE, wxId) self._filename = filename @@ -219,18 +232,18 @@ class PfsHyperlink(wx.lib.hyperlink.HyperLinkCtrl): - + def __init__(self, parent, size=wx.DefaultSize, label=""): - wx.lib.hyperlink.HyperLinkCtrl.__init__(self, parent, -1, - label, + wx.lib.hyperlink.HyperLinkCtrl.__init__(self, parent, -1, + label, wx.DefaultPosition, size) self.SetBackgroundColour(parent.GetBackgroundColour()) self.SetURL(Constants.APP_URL) HTML_TEMPLATE = """ - - + +

%(title)s

@@ -239,7 +252,7 @@
-

%(text)s

+
%(text)s
%(htmlUpdate)s
diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/util/FloatValidator.py photofilmstrip-3.3.1/photofilmstrip/gui/util/FloatValidator.py --- photofilmstrip-3.2.0/photofilmstrip/gui/util/FloatValidator.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/util/FloatValidator.py 2017-12-03 22:12:24.000000000 +0000 @@ -24,7 +24,7 @@ class FloatValidator(wx.PyValidator): - + def __init__(self): wx.PyValidator.__init__(self) self.Bind(wx.EVT_CHAR, self.OnChar) @@ -40,7 +40,6 @@ return False return True - def OnChar(self, event): key = event.GetKeyCode() @@ -51,7 +50,7 @@ if chr(key) in string.digits: event.Skip() return - + if chr(key) == '-' and '-' not in self.GetWindow().GetValue(): self.GetWindow().SetInsertionPoint(0) self.GetWindow().WriteText("-") @@ -69,4 +68,3 @@ # gets to the text control return - diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/util/ImageCache.py photofilmstrip-3.3.1/photofilmstrip/gui/util/ImageCache.py --- photofilmstrip-3.2.0/photofilmstrip/gui/util/ImageCache.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/util/ImageCache.py 2017-12-03 22:12:24.000000000 +0000 @@ -19,45 +19,46 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # +import threading +import time + import wx from photofilmstrip.lib.common.Singleton import Singleton from photofilmstrip.lib.common.ObserverPattern import Observer from photofilmstrip.core import PILBackend -import threading -import time from photofilmstrip.lib.DestructionManager import Destroyable class ImageCache(Singleton, Observer): - + SIZE = 400 THUMB_SIZE = 100 - + def __init__(self): self._picRegistry = {} self._wxImgCache = {} self._wxBmpCache = {} self._pilCache = {} self._inScalingQueue = object() - + self.scaleThread = ScaleThread(self) self.scaleThread.start() self.win = None self.thumb = None - + def RegisterWin(self, win): self.win = win - + def ObservableUpdate(self, obj, arg): if arg == 'bitmap': self.UpdatePicture(obj) - + def ClearCache(self): self._wxImgCache.clear() self._wxBmpCache.clear() - + def RegisterPicture(self, picture, pilThumb=None): # if pilThumb is None: # pilThumb = PILBackend.GetThumbnail(picture, height=120) @@ -65,9 +66,9 @@ key = picture.GetKey() self._picRegistry[key] = picture self._pilCache[key] = pilThumb - + picture.AddObserver(self) - + def UpdatePicture(self, picture): key = picture.GetKey() if self._wxImgCache.has_key(key): @@ -76,9 +77,9 @@ del self._wxBmpCache[key] if self._pilCache.has_key(key): del self._pilCache[key] - + self.RegisterPicture(picture) - + def GetImage(self, picture): key = picture.GetKey() if not self._wxImgCache.has_key(key): @@ -86,7 +87,7 @@ wxImg = wx.ImageFromStream(PILBackend.ImageToStream(pilImg), wx.BITMAP_TYPE_JPEG) self._wxImgCache[key] = wxImg return self._wxImgCache[key] - + def GetThumbBmp(self, picture): key = picture.GetKey() if not self._wxBmpCache.has_key(key): @@ -105,17 +106,17 @@ class ScaleThread(threading.Thread, Destroyable): - + def __init__(self, imgCache): threading.Thread.__init__(self, name="ScaleThread") Destroyable.__init__(self) self.imgCache = imgCache self.active = True self.queue = [] - + def Destroy(self): self.active = False - + def run(self): while self.active: pic = None @@ -124,23 +125,24 @@ except IndexError: time.sleep(0.1) continue - + pilImg = PILBackend.GetThumbnail(pic, height=ImageCache.THUMB_SIZE) self.imgCache.RegisterPicture(pic, pilImg) - + if self.imgCache.win: evt = ThumbnailReadyEvent(pic) wx.PostEvent(self.imgCache.win, evt) - + _EVT_THUMB_READY_TYPE = wx.NewEventType() EVT_THUMB_READY = wx.PyEventBinder(_EVT_THUMB_READY_TYPE, 1) - + + class ThumbnailReadyEvent(wx.PyEvent): def __init__(self, pic): wx.PyEvent.__init__(self, eventType=_EVT_THUMB_READY_TYPE) self.__pic = pic - + def GetPicture(self): return self.__pic diff -Nru photofilmstrip-3.2.0/photofilmstrip/gui/WxProjectFile.py photofilmstrip-3.3.1/photofilmstrip/gui/WxProjectFile.py --- photofilmstrip-3.2.0/photofilmstrip/gui/WxProjectFile.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/gui/WxProjectFile.py 2017-12-03 22:12:24.000000000 +0000 @@ -15,37 +15,38 @@ class WxProjectFile(ProjectFile): - + def __init__(self, wxParent, project=None, filename=None): ProjectFile.__init__(self, project, filename) self.__wxParent = wxParent self.__wxvJob = None - self.__resultEvent = None - + self.__result = None + def __WaitUntilJobDone(self): - while self.__resultEvent is None: + while self.__result is None: if wx.Thread_IsMain(): wx.Yield() time.sleep(0.05) self.__wxvJob = None try: - return self.__resultEvent.GetResult() + return self.__result finally: - self.__resultEvent = None - + self.__result = None + def __OnJobDone(self, event): - self.__resultEvent = event + self.__result = event.GetResult() def __Load(self, importPath, job=None): return ProjectFile.Load(self, importPath) - + def __Save(self, includePics, job=None): - return ProjectFile.Save(self, includePics) + ProjectFile.Save(self, includePics) + return True def _SelectAlternatePath(self, imgPath): sapEvent = SelectAlternatePathEvent(imgPath) self.__wxvJob._Interact(sapEvent) - + def _StepProgress(self, msg): self.__wxvJob.StepProgress(msg) @@ -55,9 +56,9 @@ wxvJob.SetAltPath = self.SetAltPath dlg = DlgJobVisual(self.__wxParent, wxvJob) dlg.Bind(EVT_JOB_RESULT, self.__OnJobDone) - + wxvJob.AddVisualJobHandler(dlg) - + self.__wxvJob = wxvJob JobManager().EnqueueContext(wxvJob) try: @@ -66,15 +67,15 @@ dlg.Destroy() def Save(self, includePics=False): - wxvJob = VisualJob(_("Saving project %s") % self._filename, + wxvJob = VisualJob(_("Saving project %s") % self._filename, self.__Save, args=(includePics,), maxProgress=len(self._project.GetPictures())) dlg = DlgJobVisual(self.__wxParent, wxvJob) dlg.Bind(EVT_JOB_RESULT, self.__OnJobDone) - + wxvJob.AddVisualJobHandler(dlg) - + self.__wxvJob = wxvJob JobManager().EnqueueContext(wxvJob) try: @@ -84,14 +85,14 @@ class SelectAlternatePathEvent(WxInteractionEvent): - + def __init__(self, imgPath): WxInteractionEvent.__init__(self) self.__imgPath = imgPath - + def OnProcess(self, wxParent): dlg = wx.MessageDialog(wxParent, - _(u"Some images does not exist in the folder '%s' anymore. If the files has moved you can select the new path. Do you want to select a new path?") % self.__imgPath, + _(u"Some images does not exist in the folder '%s' anymore. If the files has moved you can select the new path. Do you want to select a new path?") % self.__imgPath, _(u"Question"), wx.YES_NO | wx.ICON_QUESTION) try: diff -Nru photofilmstrip-3.2.0/photofilmstrip/GUI.py photofilmstrip-3.3.1/photofilmstrip/GUI.py --- photofilmstrip-3.2.0/photofilmstrip/GUI.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/GUI.py 2017-12-03 22:12:24.000000000 +0000 @@ -29,12 +29,12 @@ class GuiApp(AppMixin): - + def _OnStart(self): if not getattr(sys, 'frozen', False): import wxversion wxversion.select("3.0") - + from photofilmstrip.gui.PhotoFilmStripApp import PhotoFilmStripApp app = PhotoFilmStripApp(0) app.MainLoop() @@ -51,5 +51,6 @@ guiApp = GuiApp() guiApp.Start() + if __name__ == "__main__": main() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/common/ObserverPattern.py photofilmstrip-3.3.1/photofilmstrip/lib/common/ObserverPattern.py --- photofilmstrip-3.2.0/photofilmstrip/lib/common/ObserverPattern.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/common/ObserverPattern.py 2017-12-03 22:12:24.000000000 +0000 @@ -21,26 +21,26 @@ class Observable(object): - + def __init__(self): self.__observers = [] - + def AddObserver(self, observer): if isinstance(observer, Observer): if observer not in self.__observers: self.__observers.append(observer) else: raise RuntimeError() - + def RemoveObserver(self, observer): self.__observers.remove(observer) - + def Notify(self, arg=None): for observer in self.__observers: observer.ObservableUpdate(self, arg) - - + + class Observer(object): - + def ObservableUpdate(self, obj, arg): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/common/Singleton.py photofilmstrip-3.3.1/photofilmstrip/lib/common/Singleton.py --- photofilmstrip-3.2.0/photofilmstrip/lib/common/Singleton.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/common/Singleton.py 2017-12-03 22:12:24.000000000 +0000 @@ -21,9 +21,11 @@ class SingletonType(type): + def __init__(self, name, bases, dict): type.__init__(self, name, bases, dict) self.instance = None + def __call__(self): if self.instance is None: self.instance = type.__call__(self) @@ -31,4 +33,4 @@ class Singleton(object): - __metaclass__ = SingletonType \ No newline at end of file + __metaclass__ = SingletonType diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/DestructionManager.py photofilmstrip-3.3.1/photofilmstrip/lib/DestructionManager.py --- photofilmstrip-3.2.0/photofilmstrip/lib/DestructionManager.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/DestructionManager.py 2017-12-03 22:12:24.000000000 +0000 @@ -6,36 +6,36 @@ class DestructionManager(Singleton): - + def __init__(self): self.__destroyables = [] - + def AddDestroyable(self, destroyable): assert isinstance(destroyable, IDestroyable) self.__destroyables.append(destroyable) - + def Destroy(self): while self.__destroyables: dest = self.__destroyables.pop(0) logging.getLogger('DestructionManager').debug("destroying '%s'", dest) - + try: dest.Destroy() - + logging.getLogger('DestructionManager').debug("destroyed '%s'", dest) except BaseException, exc: logging.debug("could not destroy '%s': %s", dest, exc, exc_info=True) logging.getLogger('DestructionManager').debug("everything destroyed") - + class IDestroyable(object): - + def Destroy(self): raise NotImplementedError() - - + + class Destroyable(IDestroyable): - + def __init__(self): DestructionManager().AddDestroyable(self) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/DlgJobVisual.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/DlgJobVisual.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/DlgJobVisual.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/DlgJobVisual.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:Dialog:DlgJobVisual +# Boa:Dialog:DlgJobVisual # encoding: UTF-8 import time @@ -7,16 +7,16 @@ from .WxVisualJobHandler import WxVisualJobHandler, EVT_JOB_UPDATE - -[wxID_DLGJOBVISUAL, wxID_DLGJOBVISUALCMDABORT, wxID_DLGJOBVISUALGAUGE, - wxID_DLGJOBVISUALSTELAPSEDDIV, wxID_DLGJOBVISUALSTELAPSEDLABEL, - wxID_DLGJOBVISUALSTELAPSEDVALUE, wxID_DLGJOBVISUALSTINFO, - wxID_DLGJOBVISUALSTREMAININGDIV, wxID_DLGJOBVISUALSTREMAININGLABEL, - wxID_DLGJOBVISUALSTREMAININGVALUE, +[wxID_DLGJOBVISUAL, wxID_DLGJOBVISUALCMDABORT, wxID_DLGJOBVISUALGAUGE, + wxID_DLGJOBVISUALSTELAPSEDDIV, wxID_DLGJOBVISUALSTELAPSEDLABEL, + wxID_DLGJOBVISUALSTELAPSEDVALUE, wxID_DLGJOBVISUALSTINFO, + wxID_DLGJOBVISUALSTREMAININGDIV, wxID_DLGJOBVISUALSTREMAININGLABEL, + wxID_DLGJOBVISUALSTREMAININGVALUE, ] = [wx.NewId() for _init_ctrls in range(10)] class DlgJobVisual(wx.Dialog, WxVisualJobHandler): + def _init_coll_szMain_Items(self, parent): # generated method, don't edit @@ -63,16 +63,16 @@ size=wx.Size(-1, -1), style=0) self.gauge = wx.Gauge(id=wxID_DLGJOBVISUALGAUGE, name=u'gauge', - parent=self, pos=wx.Point(-1, -1), range=100, size=wx.Size(-1, - -1), style=wx.GA_HORIZONTAL) + parent=self, pos=wx.Point(-1, -1), range=100, + size=wx.Size(-1, -1), style=wx.GA_HORIZONTAL) self.stElapsedLabel = wx.StaticText(id=wxID_DLGJOBVISUALSTELAPSEDLABEL, label=_(u'Elapsed time'), name=u'stElapsedLabel', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.ALIGN_RIGHT) self.stElapsedDiv = wx.StaticText(id=wxID_DLGJOBVISUALSTELAPSEDDIV, - label=u':', name=u'stElapsedDiv', parent=self, pos=wx.Point(-1, - -1), size=wx.Size(-1, -1), style=0) + label=u':', name=u'stElapsedDiv', parent=self, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.stElapsedValue = wx.StaticText(id=wxID_DLGJOBVISUALSTELAPSEDVALUE, label=u'0:00:00', name=u'stElapsedValue', parent=self, @@ -83,8 +83,8 @@ pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.stRemainingDiv = wx.StaticText(id=wxID_DLGJOBVISUALSTREMAININGDIV, - label=u':', name=u'stRemainingDiv', parent=self, pos=wx.Point(-1, - -1), size=wx.Size(-1, -1), style=0) + label=u':', name=u'stRemainingDiv', parent=self, + pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.stRemainingValue = wx.StaticText(id=wxID_DLGJOBVISUALSTREMAININGVALUE, label=u'0:00:00', name=u'stRemainingValue', parent=self, @@ -103,12 +103,12 @@ self._init_ctrls(parent) WxVisualJobHandler.__init__(self) self.SetTitle(job.GetName()) - + if self.cmdAbort.IsShown(): self.__state = "Continue" else: self.__state = "Uncancelable" - + self.__job = job self.__delay = 3 self.__maximum = 100 @@ -145,9 +145,9 @@ self.gauge.Pulse() self.__UpdateMessage(newmsg) - if 1:#self.__elapsed or self.__remaining or self.__estimated: + if 1: # self.__elapsed or self.__remaining or self.__estimated: elapsed = time.time() - self.__timeStart - + self.__SetTimeLabel(elapsed, self.stElapsedValue) # self.__SetTimeLabel(-1, self.stEstimated) self.__SetTimeLabel(-1, self.stRemainingValue) @@ -156,7 +156,7 @@ if value <= self.__maximum: self.gauge.SetValue(value) self.__UpdateMessage(msg) - + # if (self.__elapsed or self.__remaining or self.__estimated) and (value != 0): if value != 0: elapsed = time.time() - self.__timeStart @@ -177,11 +177,11 @@ or (elapsed > 0 and elapsed < 4): self.__display_estimated = estimated self.__ctdelay = 0 - + display_remaining = self.__display_estimated - elapsed if display_remaining < 0: display_remaining = 0; - + self.__SetTimeLabel(elapsed, self.stElapsedValue) # self.__SetTimeLabel(m_display_estimated, self.stEstimated) self.__SetTimeLabel(display_remaining, self.stRemainingValue) @@ -205,9 +205,9 @@ def __OnJobUpdate(self, event): if event.IsBegin(): self.__timeStart = time.time() -# self.__dlg = wx.ProgressDialog(self.__job.GetName(), -# self.__job.GetInfo(), -# maximum=self.__job.GetMaxProgress(), +# self.__dlg = wx.ProgressDialog(self.__job.GetName(), +# self.__job.GetInfo(), +# maximum=self.__job.GetMaxProgress(), # parent=self, # style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_REMAINING_TIME)# | wx.PD_AUTO_HIDE) self.SetInitialSize(self.GetEffectiveMinSize()) @@ -228,7 +228,7 @@ if maximum > 0: self.__maximum = maximum self.gauge.SetRange(maximum) - - self.__Update(self.__job.GetProgress(), + + self.__Update(self.__job.GetProgress(), self.__job.GetInfo()) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IJobContext.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IJobContext.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IJobContext.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IJobContext.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,5 +1,6 @@ # encoding: UTF-8 + class IJobContext(object): ''' The JobContext interface handles the processing of a long running job. @@ -10,44 +11,45 @@ def GetGroupId(self): raise NotImplementedError - + def GetWorkLoad(self): raise NotImplementedError() - + def PushResult(self, resultObject): raise NotImplementedError() - + def _Begin(self): """ internal - called from the framework """ raise NotImplementedError() + def Begin(self): raise NotImplementedError() - + def _Done(self): """ internal - called from the framework """ raise NotImplementedError() + def Done(self): raise NotImplementedError() def IsDone(self): raise NotImplementedError() - + def IsAborted(self): raise NotImplementedError() + def Abort(self, msg=None): raise NotImplementedError() - + def IsIdle(self): raise NotImplementedError() - - class IWorker(object): - + def GetContextGroupId(self): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IVisualJobHandler.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IVisualJobHandler.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IVisualJobHandler.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IVisualJobHandler.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,12 +1,13 @@ # encoding: UTF-8 + class IVisualJobHandler(object): - + def OnHandleJobBegin(self, jobContext): raise NotImplementedError() - + def OnHandleJobDone(self, jobContext): raise NotImplementedError() - + def OnHandleJobUpdate(self, jobContext, fields=None): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IVisualJobManager.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IVisualJobManager.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IVisualJobManager.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IVisualJobManager.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,9 +1,10 @@ # encoding: UTF-8 + class IVisualJobManager(object): - + def RegisterJob(self, job): raise NotImplementedError() - + def RemoveJob(self, job): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IVisualJob.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IVisualJob.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IVisualJob.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IVisualJob.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,25 +1,31 @@ # encoding: UTF-8 + class IVisualJob(object): - + def GetName(self): raise NotImplementedError() + def SetName(self, value): raise NotImplementedError() - + def GetInfo(self): raise NotImplementedError() + def SetInfo(self, info): raise NotImplementedError() - + def GetMaxProgress(self): raise NotImplementedError() + def SetMaxProgress(self, value): raise NotImplementedError() - + def GetProgress(self): raise NotImplementedError() + def SetProgress(self, value): raise NotImplementedError() + def StepProgress(self, info=None, progress=1): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IWorkLoad.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IWorkLoad.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/IWorkLoad.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/IWorkLoad.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,9 +1,11 @@ # encoding: UTF-8 + class IWorkLoad(object): + def _Execute(self, jobContext): raise NotImplementedError() - + def _Finish(self): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/JobAbortedException.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/JobAbortedException.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/JobAbortedException.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/JobAbortedException.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,5 @@ # encoding: UTF-8 + class JobAbortedException(Exception): pass diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/JobManager.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/JobManager.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/JobManager.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/JobManager.py 2017-12-03 22:12:24.000000000 +0000 @@ -9,7 +9,6 @@ from photofilmstrip.lib.DestructionManager import Destroyable from .IVisualJobManager import IVisualJobManager -from .IVisualJob import IVisualJob from .LogVisualJobManager import LogVisualJobManager from .Worker import Worker, WorkerAbortSignal from .JobAbortedException import JobAbortedException @@ -236,7 +235,7 @@ self.__logger.debug("<%s> starting %s...", threading.currentThread().getName(), ctx.GetName()) try: - ctx._Begin() # IGNORE:W0212 + ctx._Begin() # pylint: disable=protected-access except JobAbortedException: return False except Exception, exc: @@ -257,7 +256,7 @@ self.__logger.debug("<%s> finalizing %s...", threading.currentThread().getName(), ctx.GetName()) try: - ctx._Done() # IGNORE:W0212 + ctx._Done() # pylint: disable=protected-access except: self.__logger.error("<%s> error %s", # IGNORE:W0702 threading.currentThread().getName(), ctx.GetName(), exc_info=1) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/Job.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/Job.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/Job.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/Job.py 2017-12-03 22:12:24.000000000 +0000 @@ -16,16 +16,16 @@ in a queue. ''' - def __init__(self, target=None, args=None, kwargs=None, + def __init__(self, target=None, args=None, kwargs=None, groupId="general"): IJobContext.__init__(self) self.__groupId = groupId - + self.__logger = logging.getLogger("Job<%s> %s" % (groupId, self)) - + self.__workQueue = Queue.Queue() self.__resultObject = NoResultObject(WorkLoad()) - + self.__done = False self.__aborted = False self.__idle = True @@ -35,11 +35,11 @@ def GetGroupId(self): return self.__groupId - + def AddWorkLoad(self, workLoad): assert isinstance(workLoad, IWorkLoad) self.__workQueue.put(workLoad) - + def GetWorkLoad(self): if self.__aborted: while 1: @@ -50,19 +50,21 @@ self.__logger.debug("task queue empty") else: return self.__workQueue.get(False) - + def PushResult(self, resultObject): self.__resultObject = resultObject - + def _Begin(self): if self.__aborted: self.__done = True raise JobAbortedException() - + self.Begin() self.__idle = False + def Begin(self): pass + def IsIdle(self): return self.__idle @@ -71,17 +73,20 @@ self.Done() finally: self.__done = True + def Done(self): pass + def IsDone(self): return self.__done - + def IsAborted(self): return self.__aborted + def Abort(self, msg=None): if self.__aborted: return False - + if self.__done: self.__logger.debug("cannot abort finished job!") return False @@ -93,14 +98,13 @@ self.__idle = False self.__done = True return False - + self.__logger.debug("aborting... (%s)", msg) - + return True - - def GetResultObject(self):#, block=True): - return self.__resultObject + def GetResultObject(self): # , block=True): + return self.__resultObject class SingleWorkLoad(WorkLoad): @@ -126,8 +130,8 @@ self.__args = args self.__kwargs = kwargs - def Run(self, job): - return self.__target(*self.__args, job=job, **self.__kwargs) - + def Run(self, jobContext): + return self.__target(*self.__args, job=jobContext, **self.__kwargs) + def GetJob(self): return self.__job diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/LogVisualJobHandler.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/LogVisualJobHandler.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/LogVisualJobHandler.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/LogVisualJobHandler.py 2017-12-03 22:12:24.000000000 +0000 @@ -8,9 +8,9 @@ def OnHandleJobBegin(self, jobContext): LOGGER.debug("OnHandleJobBegin %s", jobContext) - + def OnHandleJobDone(self, jobContext): LOGGER.debug("OnHandleJobDone %s", jobContext) - + def OnHandleJobUpdate(self, jobContext, fields=None): LOGGER.debug("OnHandleJobUpdate %s -> %s", jobContext, fields) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/LogVisualJobManager.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/LogVisualJobManager.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/LogVisualJobManager.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/LogVisualJobManager.py 2017-12-03 22:12:24.000000000 +0000 @@ -6,10 +6,11 @@ LOGGER = logging.getLogger("VisualJobManager") + class LogVisualJobManager(IVisualJobManager): - + def RegisterJob(self, job): LOGGER.debug("RegisterJob %s", job.GetName()) - + def RemoveJob(self, job): LOGGER.debug("RemoveJob %s", job.GetName()) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/PnlJobManager.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/PnlJobManager.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/PnlJobManager.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/PnlJobManager.py 2017-12-03 22:12:24.000000000 +0000 @@ -28,12 +28,12 @@ from photofilmstrip.lib.jobimpl.PnlJobVisual import PnlJobVisual - [wxID_PNLJOBMANAGER, wxID_PNLJOBMANAGERCMDCLEAR, wxID_PNLJOBMANAGERPNLJOBS, ] = [wx.NewId() for _init_ctrls in range(3)] class PnlJobManager(wx.Panel, WxVisualJobManager): + def _init_coll_szMain_Items(self, parent): # generated method, don't edit diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/PnlJobVisual.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/PnlJobVisual.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/PnlJobVisual.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/PnlJobVisual.py 2017-12-03 22:12:24.000000000 +0000 @@ -1,4 +1,4 @@ -#Boa:FramePanel:PnlJobVisual +# Boa:FramePanel:PnlJobVisual # encoding: UTF-8 import wx @@ -7,15 +7,15 @@ from photofilmstrip.lib.jobimpl.WxVisualJobHandler import ( WxVisualJobHandler, EVT_JOB_UPDATE) - -[wxID_PNLJOBVISUAL, wxID_PNLJOBVISUALBMPJOB, wxID_PNLJOBVISUALCMDACTION, - wxID_PNLJOBVISUALCMDMENU, wxID_PNLJOBVISUALGAUGEPROGRESS, - wxID_PNLJOBVISUALSTATICLINE, wxID_PNLJOBVISUALSTJOBINFO, - wxID_PNLJOBVISUALSTJOBNAME, +[wxID_PNLJOBVISUAL, wxID_PNLJOBVISUALBMPJOB, wxID_PNLJOBVISUALCMDACTION, + wxID_PNLJOBVISUALCMDMENU, wxID_PNLJOBVISUALGAUGEPROGRESS, + wxID_PNLJOBVISUALSTATICLINE, wxID_PNLJOBVISUALSTJOBINFO, + wxID_PNLJOBVISUALSTJOBNAME, ] = [wx.NewId() for _init_ctrls in range(8)] class PnlJobVisual(wx.Panel, WxVisualJobHandler): + def _init_coll_szMain_Items(self, parent): # generated method, don't edit @@ -62,12 +62,13 @@ def _init_ctrls(self, prnt): # generated method, don't edit wx.Panel.__init__(self, id=wxID_PNLJOBVISUAL, name=u'PnlJobVisual', - parent=prnt, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), + parent=prnt, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL) self.SetBackgroundColour(wx.Colour(255, 255, 255)) - self.bmpJob = wx.StaticBitmap(bitmap=wx.ArtProvider.GetBitmap('wxART_EXECUTABLE_FILE', - wx.ART_TOOLBAR, (32, 32)), id=wxID_PNLJOBVISUALBMPJOB, + self.bmpJob = wx.StaticBitmap( + bitmap=wx.ArtProvider.GetBitmap('PFS_RENDER_24'), + id=wxID_PNLJOBVISUALBMPJOB, name=u'bmpJob', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) @@ -83,14 +84,16 @@ label=u'job info', name=u'stJobInfo', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) - self.cmdAction = wx.StaticBitmap(bitmap=wx.ArtProvider.GetBitmap('wxART_FOLDER_OPEN', - wx.ART_TOOLBAR, (24, 24)), id=wxID_PNLJOBVISUALCMDACTION, + self.cmdAction = wx.StaticBitmap( + bitmap=wx.ArtProvider.GetBitmap('PFS_FOLDER_OPEN_24'), + id=wxID_PNLJOBVISUALCMDACTION, name=u'cmdAction', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.cmdAction.Bind(wx.EVT_LEFT_DOWN, self.OnCmdActionLeftDown) - self.cmdMenu = wx.StaticBitmap(bitmap=wx.ArtProvider.GetBitmap('wxART_GO_DOWN', - wx.ART_TOOLBAR, (24, 24)), id=wxID_PNLJOBVISUALCMDMENU, + self.cmdMenu = wx.StaticBitmap( + bitmap=wx.ArtProvider.GetBitmap('PFS_MENU_24'), + id=wxID_PNLJOBVISUALCMDMENU, name=u'cmdMenu', parent=self, pos=wx.Point(-1, -1), size=wx.Size(-1, -1), style=0) self.cmdMenu.Bind(wx.EVT_LEFT_DOWN, self.OnCmdMenuLeftDown) @@ -107,43 +110,32 @@ self.pnlJobManager = pnlJobManager for ctrl in (self, self.stJobName, self.stJobInfo, self.gaugeProgress): ctrl.Bind(wx.EVT_LEFT_DOWN, self.__OnLeftDown) - + font = self.stJobName.GetFont() font.SetWeight(wx.FONTWEIGHT_BOLD) self.stJobName.SetFont(font) self.stJobName.SetLabel(jobContext.GetName()) self.gaugeProgress.SetRange(jobContext.GetMaxProgress()) - + self.jobContext = jobContext - ms = wx.ArtProvider.GetSizeHint(wx.ART_MENU) - ts = wx.ArtProvider.GetSizeHint(wx.ART_TOOLBAR) - self._actAbort = WxAction( - _(u"Abort"), - self._Abort, - bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap(wx.ART_GO_BACK, - wx.ART_MENU, - ms), - wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap(wx.ART_GO_BACK, - wx.ART_TOOLBAR, - ts)} + _(u"Abort"), + self._Abort, + bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap('PFS_ABORT_16'), + wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap('PFS_ABORT_24')} ) self._actRemove = WxAction( _("Remove from list"), self._Remove, - bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, - wx.ART_MENU, - ms), - wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap(wx.ART_CROSS_MARK, - wx.ART_TOOLBAR, - ts)} + bmp={wx.ART_MENU: wx.ArtProvider.GetBitmap('PFS_LIST_REMOVE_16'), + wx.ART_TOOLBAR: wx.ArtProvider.GetBitmap('PFS_LIST_REMOVE_24')} ) self.curAction = None self.jobContext.AddVisualJobHandler(self) - + self.Bind(EVT_JOB_UPDATE, self.OnJobUpdate) def OnJobUpdate(self, event): @@ -167,15 +159,15 @@ if value: if self.IsShownOnScreen(): self.SetFocus() - bgCol = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT) - txtCol = wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) + bgCol = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT) + txtCol = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) else: bgCol = wx.WHITE - txtCol = wx.SystemSettings_GetColour(wx.SYS_COLOUR_LISTBOXTEXT) + txtCol = wx.SystemSettings.GetColour(wx.SYS_COLOUR_LISTBOXTEXT) self.SetBackgroundColour(bgCol) self.stJobName.SetForegroundColour(txtCol) self.stJobInfo.SetForegroundColour(txtCol) - + self.Refresh() def OnCmdActionLeftDown(self, event): @@ -186,22 +178,22 @@ menu = wx.Menu() mitm = self._actAbort.ToMenu(self, menu) - menu.Enable(mitm.GetId(), + menu.Enable(mitm.GetId(), self.jobContext.IsIdle() or not self.jobContext.IsDone()) mitm = self._actRemove.ToMenu(self, menu) menu.Enable(mitm.GetId(), self.jobContext.IsDone()) - + menu.AppendSeparator() - + self._OnMenuActions(menu) - + self.cmdMenu.PopupMenu(menu) - + def _OnMenuActions(self, menu): pass - + def _SetupAction(self): if self.jobContext.IsIdle() or not self.jobContext.IsDone(): self.curAction = self._actAbort @@ -210,23 +202,23 @@ else: print 'shit' self.curAction = None - + self._OnSetupAction() - + curTip = self.cmdAction.GetToolTip() if curTip: curTip = curTip.GetTip() - + if self.curAction and curTip != self.curAction.GetName(): self.cmdAction.SetBitmap(self.curAction.GetBitmap(wx.ART_TOOLBAR)) self.cmdAction.SetToolTipString(self.curAction.GetName()) - + def _OnSetupAction(self): pass - + def _Abort(self): dlg = wx.MessageDialog(self, - _(u"Abort selected process?"), + _(u"Abort selected process?"), _(u"Question"), wx.YES_NO | wx.ICON_EXCLAMATION) try: @@ -234,7 +226,7 @@ self.jobContext.Abort() finally: dlg.Destroy() - + def _Remove(self): wx.CallAfter(self.pnlJobManager.RemovePnlJobVisual, self, True) # self.pnlJobManager.RemovePnlJobVisual(self, True) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/ResultObject.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/ResultObject.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/ResultObject.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/ResultObject.py 2017-12-03 22:12:24.000000000 +0000 @@ -12,7 +12,7 @@ self.result = None self.exception = None self.traceback = None - + def GetSource(self): return self.__source @@ -20,7 +20,7 @@ if self.exception: if printTraceback and self.traceback is not None: print >> sys.stderr, self.traceback, - raise self.exception # IGNORE:E0702 + raise self.exception # pylint: disable=raising-bad-type else: return self.result diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/VisualJobMixin.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/VisualJobMixin.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/VisualJobMixin.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/VisualJobMixin.py 2017-12-03 22:12:24.000000000 +0000 @@ -6,20 +6,21 @@ class VisualJobMixin(IVisualJob): + def __init__(self, name, maxProgress=-1, visualJobHandler=None): IVisualJob.__init__(self) - + self.__defaultVisualJobHdl = LogVisualJobHandler() self.__visualJobHandler = [] if visualJobHandler is not None: self.AddVisualJobHandler(visualJobHandler) - + self.__name = name self.__maxProgress = maxProgress self.__progress = 0 self.__info = _(u"Waiting...") - + def __NotifyHandler(self, funcName, args=None): if args is None: args = () @@ -36,33 +37,35 @@ self.__visualJobHandler.append(visualJobHandler) # if a new visual is added, notify it about all fields possible # for an inital update - visualJobHandler.OnHandleJobUpdate(self, ("name", "maxProgress", + visualJobHandler.OnHandleJobUpdate(self, ("name", "maxProgress", "info", "progress"),) - + def RemoveVisualJobHandler(self, visualJobHandler): if visualJobHandler in self.__visualJobHandler: self.__visualJobHandler.remove(visualJobHandler) - + if len(self.__visualJobHandler) == 0: self.__visualJobHandler.append(self.__defaultVisualJobHdl) def _VJMBegin(self): self.__NotifyHandler("OnHandleJobBegin") - + def _VJMDone(self): self.__NotifyHandler("OnHandleJobDone") - + def _VJMAbort(self): self.SetInfo(_(u"Aborted")) - + def GetName(self): return self.__name + def SetName(self, name): self.__name = name self.__NotifyHandler("OnHandleJobUpdate", (("name",),)) def GetMaxProgress(self): return self.__maxProgress + def SetMaxProgress(self, maxProgress): self.__maxProgress = maxProgress self.__NotifyHandler("OnHandleJobUpdate", (("maxProgress",),)) @@ -77,12 +80,14 @@ def GetInfo(self): return self.__info + def SetInfo(self, info): self.__info = info self.__NotifyHandler("OnHandleJobUpdate", (("info",),)) def GetProgress(self): return self.__progress + def SetProgress(self, progress): self.__progress = progress self.__NotifyHandler("OnHandleJobUpdate", (("progress",),)) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/VisualJob.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/VisualJob.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/VisualJob.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/VisualJob.py 2017-12-03 22:12:24.000000000 +0000 @@ -7,23 +7,24 @@ class VisualJob(Job, IVisualJob): + def __init__(self, name, target=None, args=None, kwargs=None, maxProgress=-1, visualJobHandler=None, groupId="general"): Job.__init__(self, target, args, kwargs, groupId) IVisualJob.__init__(self) - + self.__defaultVisualJobHdl = LogVisualJobHandler() self.__visualJobHandler = [] if visualJobHandler is not None: self.AddVisualJobHandler(visualJobHandler) - + self.__name = name self.__maxProgress = maxProgress self.__progress = 0 self.__info = _(u"Waiting...") - + def __NotifyHandler(self, funcName, args=None): if args is None: args = () @@ -31,7 +32,7 @@ if hdl: func = getattr(hdl, funcName) func(self, *args) - + def _Interact(self, evtClass): for hdl in self.__visualJobHandler: if not hdl.OnHandleJobInteraction(self, evtClass): @@ -45,20 +46,20 @@ self.__visualJobHandler.append(visualJobHandler) # if a new visual is added, notify it about all fields possible # for an inital update - visualJobHandler.OnHandleJobUpdate(self, ("name", "maxProgress", + visualJobHandler.OnHandleJobUpdate(self, ("name", "maxProgress", "info", "progress")) - + def RemoveVisualJobHandler(self, visualJobHandler): if visualJobHandler in self.__visualJobHandler: self.__visualJobHandler.remove(visualJobHandler) - + if len(self.__visualJobHandler) == 0: self.__visualJobHandler.append(self.__defaultVisualJobHdl) def _Begin(self): self.__NotifyHandler("OnHandleJobBegin") Job._Begin(self) - + def _Done(self): if self.IsAborted(): self.SetInfo(_(u"Aborted")) @@ -68,7 +69,7 @@ Job._Done(self) finally: self.__NotifyHandler("OnHandleJobDone") - + def Abort(self, msg=None): if Job.Abort(self, msg): if msg is None: @@ -81,15 +82,17 @@ msg = _(u"Aborted") self.SetInfo(msg) return False - + def GetName(self): return self.__name + def SetName(self, name): self.__name = name self.__NotifyHandler("OnHandleJobUpdate", (("name",),)) def GetMaxProgress(self): return self.__maxProgress + def SetMaxProgress(self, maxProgress): self.__maxProgress = maxProgress self.__NotifyHandler("OnHandleJobUpdate", (("maxProgress",),)) @@ -104,12 +107,14 @@ def GetInfo(self): return self.__info + def SetInfo(self, info): self.__info = info self.__NotifyHandler("OnHandleJobUpdate", (("info",),)) def GetProgress(self): return self.__progress + def SetProgress(self, progress): self.__progress = progress self.__NotifyHandler("OnHandleJobUpdate", (("progress",),)) diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/Worker.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/Worker.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/Worker.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/Worker.py 2017-12-03 22:12:24.000000000 +0000 @@ -47,7 +47,7 @@ break if not isinstance(workLoad, IWorkLoad): - self.__logger.debug("<%s> Retrieved invalid job object from Queue: %s", + self.__logger.debug("<%s> Retrieved invalid job object '%s' from Queue: %s", self.getName(), jobContext, workLoad) continue diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/WorkLoad.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/WorkLoad.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/WorkLoad.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/WorkLoad.py 2017-12-03 22:12:24.000000000 +0000 @@ -4,7 +4,7 @@ class WorkLoad(IWorkLoad): - + def __init__(self): pass @@ -16,6 +16,6 @@ return self.Run(jobContext) finally: self._Finish() - + def _Finish(self): pass diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/WxVisualJobHandler.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/WxVisualJobHandler.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/WxVisualJobHandler.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/WxVisualJobHandler.py 2017-12-03 22:12:24.000000000 +0000 @@ -18,49 +18,48 @@ class WxVisualJobHandler(IVisualJobHandler): - + def __init__(self, win=None): self.__id = wx.NewId() if win is None: win = self assert isinstance(win, wx.EvtHandler) self.__win = win - + self.__win.Bind(EVT_JOB_UIINTERACT, self.__OnInteract) - + def GetId(self): return self.__id - + def OnHandleJobBegin(self, jobContext): evt = UpdateEvent(self.__win.GetId(), None, UpdateEvent.KIND_BEGIN) wx.PostEvent(self.__win, evt) - + def OnHandleJobDone(self, jobContext): evt = ResultEvent(self.__win.GetId(), jobContext.GetResultObject()) wx.PostEvent(self.__win, evt) evt = UpdateEvent(self.__win.GetId(), None, UpdateEvent.KIND_DONE) wx.PostEvent(self.__win, evt) - + def OnHandleJobUpdate(self, jobContext, fields=None): evt = UpdateEvent(self.__win.GetId(), fields, UpdateEvent.KIND_UPDATE) wx.PostEvent(self.__win, evt) - + def OnHandleJobInteraction(self, jobContext, evt): assert isinstance(evt, WxInteractionEvent) - evt._threadEvt = threading.Event() - evt._job = jobContext + evt._threadEvt = threading.Event() # pylint: disable=protected-access + evt._job = jobContext # pylint: disable=protected-access wx.PostEvent(self.__win, evt) - evt._threadEvt.wait() + evt._threadEvt.wait() # pylint: disable=protected-access return evt.GetSkipped() - + def __OnInteract(self, event): assert wx.Thread_IsMain() try: event.OnProcess(self.__win) finally: - event._threadEvt.set() - + event._threadEvt.set() # pylint: disable=protected-access class ResultEvent(wx.PyEvent): @@ -69,7 +68,7 @@ wx.PyEvent.__init__(self, ident, _EVT_JOB_RESULT_TYPE) assert isinstance(resultObj, ResultObject) self.__resultObj = resultObj - + def GetResult(self, printTraceback=True): return self.__resultObj.GetResult(printTraceback) @@ -78,10 +77,10 @@ class UpdateEvent(wx.PyEvent): - + KIND_UPDATE = 1 - KIND_BEGIN = 2 - KIND_DONE = 4 + KIND_BEGIN = 2 + KIND_DONE = 4 def __init__(self, ident, fields, kind): wx.PyEvent.__init__(self, ident, _EVT_JOB_UPDATE_TYPE) @@ -109,9 +108,9 @@ wx.PyEvent.__init__(self, eventType=_EVT_JOB_UIINTERACT_TYPE) self._threadEvt = None self._job = None - + def GetJob(self): return self._job - + def OnProcess(self, wxParent): raise NotImplementedError() diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/WxVisualJobManager.py photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/WxVisualJobManager.py --- photofilmstrip-3.2.0/photofilmstrip/lib/jobimpl/WxVisualJobManager.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/jobimpl/WxVisualJobManager.py 2017-12-03 22:12:24.000000000 +0000 @@ -14,7 +14,7 @@ class WxVisualJobManager(IVisualJobManager): - + def __init__(self, win=None): self.__id = wx.NewId() if win is None: @@ -25,22 +25,22 @@ def GetId(self): return self.__id - + def RegisterJob(self, job): evt = JobEvent(self.__win.GetId(), job, _EVT_REGISTER_JOB_TYPE) wx.PostEvent(self.__win, evt) - + def RemoveJob(self, job): evt = JobEvent(self.__win.GetId(), job, _EVT_REMOVE_JOB_TYPE) wx.PostEvent(self.__win, evt) class JobEvent(wx.PyEvent): - + def __init__(self, ident, job, evtType): wx.PyEvent.__init__(self, ident, evtType) assert isinstance(job, Job) self.__job = job - + def GetJob(self): return self.__job diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/Settings.py photofilmstrip-3.3.1/photofilmstrip/lib/Settings.py --- photofilmstrip-3.2.0/photofilmstrip/lib/Settings.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/Settings.py 2017-12-03 22:12:24.000000000 +0000 @@ -32,11 +32,11 @@ class Settings(Singleton): - + def __init__(self): # self.__isFirstStart = False self.cp = None - + if IsPathWritable(Constants.APP_DIR): setPath = Constants.APP_DIR else: @@ -52,7 +52,7 @@ logging.debug("settings file: %s", self.filename) self.Load() - + def Load(self): if self.cp is None: self.cp = ConfigParser() @@ -62,13 +62,13 @@ if not self.cp.has_section("General"): self.cp.add_section("General") - + if not self.cp.has_section("History"): self.cp.add_section("History") - + if not self.cp.has_section("Profiles"): self.cp.add_section("Profiles") - + def Save(self): try: fd = open(self.filename, 'w') @@ -79,7 +79,7 @@ # def IsFirstStart(self): # return self.__isFirstStart - + def SetLanguage(self, lang): self.Load() self.cp.set("General", "Language", Encode(lang)) @@ -102,7 +102,7 @@ if idx < 10 and os.path.exists(filename): self.cp.set("History", "%d" % idx, Encode(os.path.abspath(filename))) self.Save() - + def GetFileHistory(self): self.Load() fileList = [] @@ -113,7 +113,7 @@ fileList.append(filename) return fileList - + def SetProjectPath(self, path): self.Load() self.cp.set("General", "ProjectPath", Encode(path)) @@ -156,24 +156,10 @@ self.Load() if self.cp.has_option("General", "LastProfile"): try: - return self.cp.getint("General", "LastProfile") + return self.cp.get("General", "LastProfile") except: pass - return 3 - - def SetVideoType(self, typ): - self.Load() - self.cp.set("General", "VideoType", str(typ)) - self.Save() - - def GetVideoType(self): - self.Load() - if self.cp.has_option("General", "VideoType"): - try: - return self.cp.getint("General", "VideoType") - except: - pass - return 1 + return None def SetUsedRenderer(self, renderer): self.Load() @@ -187,8 +173,8 @@ return self.cp.getint("General", "Renderer") except: pass - return 1 - + return None + def SetLastKnownVersion(self, version): self.Load() self.cp.set("General", "LastKnownVersion", version) @@ -199,7 +185,7 @@ if self.cp.has_option("General", "LastKnownVersion"): return self.cp.get("General", "LastKnownVersion") return "0.0.0" - + def SetRenderProperties(self, renderer, props): self.Load() if self.cp.has_section(renderer): @@ -208,7 +194,7 @@ for prop, value in props.items(): self.cp.set(renderer, prop, Encode(value)) self.Save() - + def GetRenderProperties(self, renderer): self.Load() result = {} @@ -216,6 +202,5 @@ return result for prop, value in self.cp.items(renderer): result[prop] = Decode(value) - + return result - \ No newline at end of file diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/UpdateChecker.py photofilmstrip-3.3.1/photofilmstrip/lib/UpdateChecker.py --- photofilmstrip-3.2.0/photofilmstrip/lib/UpdateChecker.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/UpdateChecker.py 2017-12-03 22:12:24.000000000 +0000 @@ -27,17 +27,17 @@ class UpdateChecker(threading.Thread): URL = "http://www.photofilmstrip.org/update.txt" - + def __init__(self): threading.Thread.__init__(self, name="UpdateCheck") - + self._onlineVersion = None self._changes = [] self._checkDone = False self._isOk = False - + self.start() - + def run(self): try: fd = urllib.urlopen(self.URL) @@ -47,35 +47,35 @@ except IOError: self._checkDone = True return - + lines = data.split('\n') - - ovMatch = re.match("(\d+).(\d+).(\d+)?(.+)?", lines.pop(0)) + + ovMatch = re.match(r"(\d+).(\d+).(\d+)?(.+)?", lines.pop(0)) if ovMatch: self._onlineVersion = ".".join(ovMatch.groups()[:3]) else: return self._changes = lines - + self._checkDone = True - self._isOk = True - + self._isOk = True + def IsDone(self): return self._checkDone - + def IsOk(self): return self._isOk - + def IsNewer(self, currentVersion): if self.IsDone() and self.IsOk(): curTup = currentVersion.split(".") newTup = self._onlineVersion.split(".") return newTup > curTup return False - + def GetChanges(self): return "\n".join(self._changes) - + def GetVersion(self): return self._onlineVersion diff -Nru photofilmstrip-3.2.0/photofilmstrip/lib/util.py photofilmstrip-3.3.1/photofilmstrip/lib/util.py --- photofilmstrip-3.2.0/photofilmstrip/lib/util.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/lib/util.py 2017-12-03 22:12:24.000000000 +0000 @@ -32,6 +32,7 @@ else: return str(value) + def Decode(value, coding="utf-8"): if isinstance(value, unicode): return value @@ -40,6 +41,7 @@ else: return unicode(value) + def IsPathWritable(path): _path = Encode(path, sys.getfilesystemencoding()) try: @@ -52,6 +54,7 @@ logging.debug("IsPathWritable(%s): %s", path, err) return False + def CheckFile(filename): if filename and not os.path.exists(filename): return False diff -Nru photofilmstrip-3.2.0/photofilmstrip/res/cursors.py photofilmstrip-3.3.1/photofilmstrip/res/cursors.py --- photofilmstrip-3.2.0/photofilmstrip/res/cursors.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/res/cursors.py 2017-12-03 22:12:24.000000000 +0000 @@ -21,25 +21,26 @@ import wx -DATA = [[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], - [2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 0, 0, 0, 0], - [2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 2, 0, 1, 1, 0], - [2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 0, 2, 0, 1, 1, 0], - [2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 0, 2, 0, 1, 1, 0], - [2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], - [2, 2, 2, 2, 0, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], - [2, 2, 2, 0, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], - [2, 2, 0, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], - [2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], - [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 0], - [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 0], - [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], - [2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], - [2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], - [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] +DATA = [[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], + [2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 0, 0, 0, 0], + [2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 2, 0, 1, 1, 0], + [2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 0, 2, 0, 1, 1, 0], + [2, 2, 2, 2, 2, 2, 0, 1, 1, 1, 0, 2, 0, 1, 1, 0], + [2, 2, 2, 2, 2, 0, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], + [2, 2, 2, 2, 0, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], + [2, 2, 2, 0, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], + [2, 2, 0, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], + [2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0], + [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 0], + [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1, 0], + [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], + [2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], + [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] __CURSORS = {} + def __MakeCursor(data): img = wx.EmptyImage(16, 16) img.SetMaskColour(255, 0, 0) @@ -56,10 +57,11 @@ img.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 8) return wx.CursorFromImage(img) + def GetNW(): if __CURSORS.has_key('NW'): return __CURSORS['NW'] - + result = [] for line in DATA: tmp = [] @@ -70,18 +72,20 @@ __CURSORS['NW'] = cursor return cursor + def GetSE(): if __CURSORS.has_key('SE'): return __CURSORS['SE'] - + cursor = __MakeCursor(DATA) __CURSORS['SE'] = cursor return cursor + def GetSW(): if __CURSORS.has_key('SW'): return __CURSORS['SW'] - + result = [] for line in DATA: tmp = [] @@ -92,10 +96,11 @@ __CURSORS['SW'] = cursor return cursor + def GetNE(): if __CURSORS.has_key('NE'): return __CURSORS['NE'] - + result = [] for line in DATA: tmp = [] diff -Nru photofilmstrip-3.2.0/photofilmstrip/res/images.py photofilmstrip-3.3.1/photofilmstrip/res/images.py --- photofilmstrip-3.2.0/photofilmstrip/res/images.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/photofilmstrip/res/images.py 2017-12-03 22:12:24.000000000 +0000 @@ -6,203 +6,6 @@ catalog = {} index = [] -PLAY_PAUSE = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAZiS0dE" - "AAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oHFRcdAqKdVpEAAAAZ" - "dEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAW0lEQVQ4y2NgGDbgIgH5/0g0" - "NjbDfwKGEDTgL5RzBo9mvAb8Y2Bg+AMVOEaOAf+hhsBccppYA5iICDxGYmIBlxf+YzGQpEAk" - "2gBs0fgfh5ewGnCJQPQRNGAIAwCUWETr+Gvg7AAAAABJRU5ErkJggg==") -index.append('PLAY_PAUSE') -catalog['PLAY_PAUSE'] = PLAY_PAUSE - -#---------------------------------------------------------------------- -MOTION_RIGHT = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAAZiS0dE" - "AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oHExMpCawHi+4AAAAZ" - "dEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAADw0lEQVRIx6WUS2hcZRTHf+d7" - "JGliGouTapI6GVNjqRNLjVhMqAQLYlFETBe1C6ULxZULdSNuDBGEVt0IEkSRLGp1oRsXKi5c" - "SQyKCNJINDUSY9PER2OTyWNe97i4d+6dmTQa8FvMXO733fM//8d3pCHzUAaRUwRlz/9cml/+" - "qLg4OQMUAQVwCA8/8djwKzd3dQCKKggCoqiG/6ISFgAQiA4hKiiKiDB/6TLj746lgTPAHFAI" - "AYLA9fakOXjgVkRBJaqBInFrUXFAhKQJQEURhKZGjxZWDwN9wGICgIqzBm8FQVAIf8XEVTUR" - "AZHoRTWQgLMGNGgGdkU8iQDAW8F7iyjx1ypJ5fBRYmYhE4mZiSjeyTV9cQDOWrw1sQRUCmmi" - "iURQFc2pNCOAGqyx2wNYK3hnqtslIRDJRWQupkpIjT1xVkBsyuzuGbat3VnKG+eLi5MzEYCJ" - "ARIZhFoH6hMVglWWtUIqlWo/OjhwouWGbs6/N34jcCaSSPA+AlBFMUl5qThak/ioeALurKGp" - "qZFMupPd7fviRIUATvBWoi6rG68wqX0fB0kS050Lm3JWahJlQgahRN6HcfU2enYW7224F0XZ" - "O4Nz4flPv36GleUraLmMs4KIYI3gqhJVJ5EkTWtdHERBDfFtjNbEzAi3Xf80GlhEwBqDFVsP" - "YHDWJpeIqvsQ211tduLJYN8JJi68hf55HDTAWgkTVRtTQ0NVTM99/tSOB1y+uM5dBx7kWz6h" - "sLmGBiHIFgDvTDR/ws2+W4ZqpIqZ1I2KfGEdgGzPEM+OwuzkAqnO/bUAU9OzBKXSls62FKUO" - "rG6vd9/dcM83LP48h2ogAE4LVz97ceTs4aCYOwR03bS3PfXcS53ki+vbDP1aFvG0ldCx9N4s" - "8CWU842Ac8XLX80Ao0C/aU0PP3L80ZMwG1IXaga3aE3vCYMq4KUrv/DOy1NoMXcd0OKAEvAr" - "8LttzfQO3nvs5FJhls2IgfxLpurn59+5Jc6d/YmudIYf5/7KaX55zUVnC0BBfPNGW1sbS3/A" - "1dzSjlK0q7EVUDbyOd5/bYZsto/+gWN8MXEhD5Rc/QfWGu6/Y4SxN99gYeESqrpt8aFTzWwW" - "19GgzAevX+RgNsvp00+yVmpAxGicouo1NT1LfqODI0cfoFwqXVOMyhhf4UM0KPP26Pd0Z/Zz" - "55H7WNk0XJyb32IRAL5j4HZUXwiKuUMalJv/S55Xx/p7n3/841URE0jjnhVcU77SebA6P63F" - "1fF6nzzQDfQDLTuwYA8wAPwA/BYFprLWgO/+AfnAeESGpPkHAAAAAElFTkSuQmCC") -index.append('MOTION_RIGHT') -catalog['MOTION_RIGHT'] = MOTION_RIGHT - -#---------------------------------------------------------------------- -MOTION_LEFT = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAAZiS0dE" - "AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oHExMsBkHPYjoAAAAZ" - "dEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAADu0lEQVRIx6WVXWgcZRSGn/P9" - "7CZpIoJJSshPk2ooSUTFUmmqEhRBVPRCERTRWylCoXjjld6JoN4o0qIgvYs3gaIXtVgUC2Jo" - "qH9JaFAxNDGUtE1Nss3fzs4cL2Z2ZnazVcEPdmfm8M37nvOe9zsj1K1C/1P9iLxIFHr+59Kd" - "vybcrqjw9CsvPPt2b3cXoKiCICCKanwVlRgg3k+yCVFBUUSExaUrnPr0RN9ugihyg/v7GDpw" - "F6KgkmCgSJpaAg6IkCUBqCiC0FT0aLl0n2tQmDhr8FYQBIX4X0yKqtleRJJAnkjAWQMatbhG" - "2nkreG8RJX1bJUOObyWtLK5E0spEFO/iihoSOGvx1qQSUAXSTBNJqKqaU01GADVYY2Os3a7R" - "I9YK3pl8umQFJHKRNBeTE1LTnjhbraDONZMXfsBakxJkMgi1Hah3VExWXTYlqHPNn0tLOCt4" - "nxCoopgMXqodrTFGAp6Ru0RiV+8aI4JzgreSZJlPvFpJbTw1kmRNd4kCJu8a7wzWxOxfTh1j" - "fW0FDQO8NXhv8M6m+3ySlHcG52JJ40Qt3tq0BybvGucM1hqWbn4AwOmJcdZXbyQVmQzYGbyX" - "hDAmSX/Jcw1B1TXeGfqHznHk7ucA+HVuFo0qCWhttmksra4aT5TIekDqmvPTxzl44El2gk0A" - "HnreMTn/DpPz/zzUHh1+i/aOTgoF36jJsWfPTx9nZP8YO+UNAEYGxmrGQHrOsqEICjPz3/Lx" - "yQ85+toxenp6k5lVR7ASfMRgzyHK5c2al/O+oQ44H5+eucSFi7MsXFlL45d+X4i3v//ZS9rX" - "ORKPYwSpP1PSiCVbC8uzvPnqOVrbB7h+Y60M0Q3EbIBEUWlxzn793W36wMPBI03FVsIwINSA" - "MAri+5prmUpUoRIFhFGZMKoQhgEb26sszGwzevgwv/w0dTUqLXyhW9dP69a1b4jKF5245i1W" - "nmCZM9zeupf68ym5J02nfu1B7urq5uChUcYnzpR069oUcBYoAZET48KBOwfZ4/Yxc/0kzcVW" - "QNjaKf3nT2OhWKCtrQ0xNgQ2gTVgPW1yU1ORe0eGsDNH+Xn5BJKM2vH3fqO9o4NCoXBLcBGh" - "p7ubYrHxHgcwO/cHUaVCEFjMyuNEd5yNJ2KhmbHHnqG9Y29u+pMTKpbKOcfS1bXGCfiu0WFU" - "34iCm/egUYtqJFS2i+9+8mDv6y9/XjItnSuYQvBvMokIUWlxToPSKeCrpAcI4IF9wP3Anlxl" - "PcAw8D2wWtfXW60N4EfgMlAG+Bug5XjrvKyrJQAAAABJRU5ErkJggg==") -index.append('MOTION_LEFT') -catalog['MOTION_LEFT'] = MOTION_LEFT - -#---------------------------------------------------------------------- -MOTION_SWAP = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAA" - "CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QsMCCMDdsFcmwAAABl0RVh0Q29tbWVudABD" - "cmVhdGVkIHdpdGggR0lNUFeBDhcAAARwSURBVEjHlZVZbFRlGIaf//z/ma5sU2agtIXO2Ha2" - "sioqaKwSEhMLNxJiQQvEiDEmxkRvuCHGmKgs3mgiRNyQrVxw45VINBpZTIgssQRom5ZSobRQ" - "LMy0dJae34tzZjobRr9kLs75z5z3e9/3e78jyCtXfWs9QmzAmjQpUh/tcL+/7Z3rO5GlE8JQ" - "k/xL6fjfx0QBgK/1rU1t6z6tq6kGNFqDQIDQWBZM9x4CoOvck3iqF6BME+chhBZoNEIIBm4M" - "8u3Xe75SBbCWpRr98wkFGhAatABhQ4HWdA/CyuZ1wDGMaD0L/H6UctlNAFpoBILSEhOdiC7J" - "AHzS8bKeQvmG7psPpx5PjvNo4AX+uNrBjf4N1PsDmC5XFltQ0gBtlecwaPa1pNu1u8G+zNwT" - "thrxxDgAEX8Ll3qPMHBtI/7GEC7lsh8TGlPZjFR+ZwUvJQ8s76yxdjndfx1moK8df0MAl8sF" - "2kAa0gbITI0DUHwcclmk79n+aOZ7I1wfPkB/XzsNTSGUcqFkmoFg7aa2Fz+En2zqAsdS+wGh" - "c3qfYpAFPHS3j0O7e3l8xS/U1NThrvIgMwDO1ABMOAxy/z8FUASK0dgQ+z++SmNTmJbnVuOe" - "NRNTGbbJtgdapC/uxYb4L1VWMg3QPIjH+G5HF02BMOvbNhMIRTBddj6VMqZMNqVgdsXbHDu8" - "jwsXzjPbPZ2ZMypzhB8cOUdVZYQ1W6uYSI6jrUkO7OwiEAzz0sYtBIIR22CnpjwAlJR4PV7a" - "XnmdCs/PPLGkieaQz5lLOH52O7CUO1f9wG20NcnBXV0Eg2E2tG8hGFw49XInnWkAA0BKQXlZ" - "KfNqapnl9jKvphaf7xH8fj9n+3ewZtVm3N5Khm/Z6fvtaIJwuJn2za+ysHkRFRWlmMqwf1Ji" - "KgMpsySS0j602RgoJSkxJQdPbOWxYCuJ1AOEEDy9XjE6Mk6ytA9PaC6dt/dw5ZQs8GhV+D20" - "NZktkcA0bQBpCKQ0OHhiKxF/C/HEmJ1aXwtCQLIuRcQ/TuW0cpSpCsLX2fcrX+z9jBXPtmYB" - "KIEpBSAwpODyrV001i4n4ayE/PVRPk1hkSCRTGTOskf4z87LzKgOZTNwJBICT/0PzPdGiCfH" - "0AiELgxW0UBk1ckzv8dOX+y7o8eHe/IkEqxs2M7png+Y4/YVrIb8/aGFk/bMJnSOkrEu617s" - "KHAtw0BJiRDg9XpoHH6N7rtfMrNyTtGVlAHIfAUK8AeBH4HezBS5nCkyK8tYumwpJZ1v0Hln" - "L2UlduAexKP8j0oC94H7OWOa7sksK2XR4sXIzje5OPQ5wlm9R3Z3M9vjyUlsuu6ORjl56sx9" - "UmOXgRsOiG3ypSu9WKlUgRjJpIEx8jxW1XF7hF2lPLN6LR7P3ALfe/pvcvpcz7AVHesAjgND" - "AMKsXhFG621WMrYIbZUXWKktQWqiZNe+p+rebf8+apR7RzBcyWK6WNGBK6Ri+4ETjkQIwAQW" - "AMuAiodoqoBaIAycAUaLzRUwBpwH+oEEwD/ITowXmkYrlwAAAABJRU5ErkJggg==") -index.append('MOTION_SWAP') -catalog['MOTION_SWAP'] = MOTION_SWAP - -#---------------------------------------------------------------------- -MOTION_INPUT = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAAZiS0dE" - "AKYAvwBHIJ68VwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oHExIxLGTarccAAAAZ" - "dEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAD1klEQVRIx6WWy09cVRzHP+dx" - "Z2BgeIygAqVNp50ZHgMlrYmtxB1JMwvjxgVtE+NON65M3LjUhQv9A9zUuDBpdKM1le6amEZL" - "k6YusBUoTEGkHaAIDAzc53Exd+hAhVL8Jjcnuffc7/f83kewP0T4yHA9KAwQAGa/n8TQ0NB5" - "4GIQBJYxRh2UvVQqXR8dHf0RKO63Tw4NDX1tDoHBwcFfgUHgJV1NWOUWAB0EQQQgl8ttbxoZ" - "GXmuBY7jtAIZYF4DRI6dTyLURQIvigkUgDGBXNs0AxXSXC53IHKAIAhqgWbA0uWTy7ffvfDO" - "p50dbYDBGAh8n/E7P3MYGGM0EAVU2UXGi6SSR+nOnESYcuh9z2Vh6ibVLjqoFaGABaABYQJP" - "CxMgjIeSGiElykiklAf2+x7pjQb051+0fwbfsLTwPolEC7FYHUZLjiW7GL70HqsryziOXc7u" - "7TRnV2kYXM+nuLbqLi0uPgbWAU9/eeXS1usDPqO/K8bu/kb/6bPU18cQSpHq7qOmpo65uWk2" - "1tcJfD8kNSBEqGPCV4LHC0vcHP2+YLae3ALywFp1mjI3O0Uq0wPG527+EwDqa4bp7j1FJBJF" - "KgXGAAJBeTWYspaByQezXL12fdVsPbkHTG4LeJ7PmawPwMp8gY21NgDOZB3ujF3BWn2L5MkM" - "DQ3NaEshwgZgQpEK1ko+qIgNLAMrgKsBbLdMnk2XGOMGk8s3yGZK2K4gm95kbOInZmcUXV1Z" - "YrFmtNZhHMSOeNREowghDeBXepH8aPjb/rHxWmzHw/F8UseLpI8XsV0fx/VwXI90sshm7Ace" - "5iew7Q2UhIhWWFoSsRSWJbEsgdby2X4DFD7+4PblyXyciek4rudhuz6u42E7PrbrMzEd55fv" - "PBYL83h2CSVBa4mlJVpJLKWwlEKrZ3unBlZFTaKwMnWW0lphx8e2V5Z4VGjh6lcLZPtO0dl5" - "hIZ4nGhUIUXVacPq3EvAE7q2lMp082riNWZm8ozfv0fb6TyPCi2MXF4m29fPG4Nv0tPdS1Nz" - "YzkG22n6FErJ/xRACBU0NjaRySRpb2/jxIkkMzMPmZqc4Nw5SV//AN09vSQSCbS2qoptZ5D1" - "XgIAlqWJ18eIxaIkmps40tFBOp1BCMHLra3EGxqxtN5B/bSGDeJ5An/8OU3geVUt18f3AwCW" - "Vv5GykdVpVUuNXbZcv/BLGF6BhXTBCB168CA0LUfGreUNMZvqBo+L4ogKP512zir14BbwFJl" - "oMeAo0AqHBSHFgD+CdvELFCq2KlCkTogwv+DA2wAJSAQu4pOvOD1ZK8rS+Xawr+jYLnbWFs6" - "rwAAAABJRU5ErkJggg==") -index.append('MOTION_INPUT') -catalog['MOTION_INPUT'] = MOTION_INPUT - -#---------------------------------------------------------------------- -MOTION_RANDOM = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAAZiS0dE" - "AP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oHExMDJIazG7MAAAAZ" - "dEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAEp0lEQVRIx7WWW2yURRTHfzPf" - "fLvdhd3SbQv0sphu7Q22pQjhZg0iMRIJookPKMYHEwkvxKiJ8ZL4Igk+6IMvRl+IgiaGaCAa" - "heCFRBBNIzFi5bKF3i9s6Y1ud9v9buPD7pJiITUaTzL5kvnPN78zM+ecGfifTSw0oGNvea0U" - "vKChyfGYHZvxTj70ydhhIN2xt7zmbhrgLQi48Hx5RZHiDyFE6dz+88PW0Z8G7IP71wW/u5O2" - "+9jki0AScOUcTeabUWhC8JwQojRj69ndxybOnOu3BgBWFBs7GkvVm3fTgO1AGEAB+O55JIYw" - "nsZz/GjPKBC3ncosivmun9LZyZopL1RaX6ZKAS6OavHqWSP2UcJ3VrqZZXO1znHXAlYD3wIT" - "Kue13PXsU0++Fa2qADRag0Dgeg7p1BRy/BLPzB4hyAyJ6QDv90eC67e2rK6Lryc8e5092cME" - "meHylJ+XfkhnADvvvFQAaMdXF1tBU8O9CA1a5A5Ho9GeR9mvZwl2zTBoL+ZAZ5Ta5lW0bd1B" - "dbSW5b+/R7A7p71+oZRxe9qCdB9gFbZIaM9RQnsI7WBIhZASgQYhQRtML99EYiRD+5V+Kmvq" - "2PrwTqqjMUy/n1TFRhI30rQnBiitLEd0j2R0diKVDyAhAfX2O5UHjPDHjI4MYVsZlNSYSqKU" - "QClBedfntE2f4LFomtY1G6isihIIBvCZiqVdX9A2fZJd1WnqGptBmnYhRAHku5/tmd3Q6uZi" - "/refmZy4gZQawxAI7SK0i9a58enUJMODPaBd/D6FaUjQGoDp1E1GR4bIbTC6AFBzY3ig7xp1" - "DStBu5y/+gYAFUX7GF3zGufOfE/PSILayiJ8psI0BCC4vuUgR04epyt5mUDIPy+1FIDjuKyN" - "51YxOZQkPVUBwNq4xfmODzCndrK5bQsPbttOcFGQ4nAJShloNCUlEbY/+gRWNktnzyBHj3/j" - "zgNk7VxfvD5DB6fpHD9NvCFD1hbE62foSHzF2NjjNDbGCReXoJTK74LEVJJA0VJAMDY1ixBC" - "zwXIl3d/2tJxJUDWcrAcl7qaFPU1KbK2i2U7WLZDfSzFTPA4Pd0Jstk0hgSfMjCVxGcamKbE" - "NAVKyXnlRgLJV/a1H+rsDpHoCmE7DlnbxbYcspZL1nZJdIX48ajDjeQQTjaDIUGpnPfKkJiG" - "gWkYKGN+aVPATVEUSU5e20hmKnmbWLFslOFkGV9+OEK8eTXRaDXhUAi/30CKOd7ms/NuAEeo" - "QKauoYnlkXX09nZz5dJFKu7rZjhZxolD48SbW9h8/wOsbFrFkpLi3BkIMScYc2YY8o4AhDC8" - "4uIlNDTEqKysoLY2Rm9vD9c6E2zaJGluaaVp5SoikQhKmflfNYWCUrha1N0AAKapCC0OEgz6" - "iZQsobqqivr6BoQQLC0vJxQuxlTqtqm5hdKIhQB/Xu7Cc5xbgue5uG4ug0cnB5FyOD+xzn/F" - "HEAOeOlqH/ky4RWWJgCpyltbhQrs13YmprUbzkfXvzHPS/W3a+vm18AvwKjITxYEVgB1QMl/" - "AQATQCfQB2QK6zTykEWA7z8+JKz8pZ8BPPG3pBP/5KWxgOl88wD+An064uIDVnlMAAAAAElF" - "TkSuQmCC") -index.append('MOTION_RANDOM') -catalog['MOTION_RANDOM'] = MOTION_RANDOM - -#---------------------------------------------------------------------- -LOCK = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QAfgCJAJ5G8nudAAAA" - "CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QsNDSovK6wuvwAAABl0RVh0Q29tbWVudABD" - "cmVhdGVkIHdpdGggR0lNUFeBDhcAAAM4SURBVEjH1ZVPbFRFHMc/v/nT3Yot/yopiFG5ICEi" - "JrLxwkFjYmJiUg94MeFkTDw38cLBU4F42UhMUIg0gQRDi1oxMRpJD8VollpXUywhRbHQNHUJ" - "rAHTbvvezHjYfdvd7isqPfEu782b38xnvvP7zm/gQX/kXp0HDh7PRYsLHd77ljgXR/P5g70X" - "gRgI/xtwoO94Lrv2ZsHHmdr45lClK4yO/Pb6ucETXwFzK0F02s933+vPZTtKBRe34SobCC5L" - "cO2EuPZ27YiK2bpt7T4jXZO/T/46WVPy74BD75/KtT1cKhAyhLgLAXRbGTEVlKmgzHwdKCri" - "ie1dPfeCNAHyH57J6fY/CxKyKLcJJYLK3kaZBQb7Px+6Mn6luPPZbU+Liqtq4gSyscfII6kQ" - "09jwznfYzBrwXXjrcaqEJ6L/yODZifGxIvDDho2bRl549bmjZP/CVdbjFtYBZcq3Ss8DBeAq" - "EKUCtEK0USgxRMwCi/Tnz5ydGB/7CRgGLg9/89lYWyazsPflZ04oVSaaXw8IcRyvAdoB1WSG" - "xoa1BmM01hiM1pz+aGjo0i+jxdrkl4C7wN2vz30y8OOFybeNrsZqJUCQNFc2KTDWYrTBKIPz" - "GmvtPPA9MLHMinNP7dg1pY1GrCYYjVIq1e5NAKsVWmusGFys0Vr52qoXl/k8dHSui4yeIxiL" - "0xql5D8ArEFpjVWGCIOIrHgordEYoyEYlKysoD5oZOzG7j9uzBZXU3fOf3nqzZMfHxkA/k4U" - "C8Dwxand0zOlIsCTjz8KCJJy9qurCYSU/mtT0wB8d/7TN459cPiLJGcCcHJoNAA8tnVLS9kR" - "pDplSKKTLIAs2/br0zMA7O/Zs6fmuko9B5s3d+NcICSA2gQheOomXOpCUmhburuZmZ0F2Atc" - "bwLEcQD80rJC895UdVRJItVVBBqhvlFiZ1KG6gDnPSEIgm8pziFRBFT3CoKE5HNJVUrK6oAQ" - "kgS2CkgaobEj0BIbUq6EunnLt2+u+npcNkeoA65dnXhxtZBkbL6vdwC4A7jGg5bd/9Y7r730" - "yr7Tq1GQ7+sdKI6O/Ax8m9hUGhLyELCjZrHO+2TcAS4Al5OD9g/91lPG7Vrj2gAAAABJRU5E" - "rkJggg==") -index.append('LOCK') -catalog['LOCK'] = LOCK - -#---------------------------------------------------------------------- -UNLOCK = PyEmbeddedImage( - "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QAfgCJAJ5G8nudAAAA" - "CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QsNDS0NsY35nAAAABl0RVh0Q29tbWVudABD" - "cmVhdGVkIHdpdGggR0lNUFeBDhcAAANmSURBVEjHpZXfaxxVFMc/59472Y01qW1jSGtFzYuI" - "iBXs4oMFf4EgCOlDfRH6JP4DAX3wwadE8cHFIlosNtqCpUnVGEFaLBFSUZKQrpKYUlNt04aw" - "brFbqjS7mZl7fZiZze5mNgVzYZhf957P/Z7zPTPCBuOtwSM5f7XaYa2V5ndh4K/kB/ungABw" - "rWJIy+ADR3LZrdcnbZCJ1zdOVbrC9MQfr4yNHP0OuN0KotMevv3eUC7bUZoMgzbCynZcmMWF" - "7bggPoftiArY3bv1gJGuhT8XfluIldwZ8M4Hx3Ntd5cmcRlc0IUAuq2MmArKVFBmpQYU5fPg" - "w119G0EaAPnDJ3O6/a9JcVlU2I0SQWVvoEyVkaGvRy/OXiw8+kTvY6KCSE2QQHb0Gbk3FWLq" - "b2xoO7zMFrBdWM8SqhIWn6FDI6fmZ2cKwM/bd3RPPPvykx+TvUlY2UZYvQcoU/679BQwCVwC" - "/FSAVog2CiUGnyKwylD+5Kn52ZnzwDhwYfzMVzNtmUx134uPH1WqjL+yDRCCINgCtAOqpQLP" - "Mxij0WJwTvPZR6Ojc79OF+Lgc7FbOD12Yvj02Ik54GmgM15+E6gAtiXAeB5GG4wyhFbjed4K" - "8BMw32TF28AssFgXIwRubVgDTyu01nhiCAON1soC/wCrTT538W6rTaZZ1wvrUqS0xlMGH4OI" - "cIfhNmrWlBQZxGg8bTBOoZRqufDw52PPWFX6QcJufIpc+b28//3BN8/EympKGiJ4JiqyZwza" - "mGaA1B+BXzXamMgYWnN+6tzzQG/zpmvyJmau7blyrVhgE+Pst8dfO/bpoWHg30SFAIxPLe5Z" - "Wi4VAB564D5AkJSKSZx2l/L+8uISAD+e/fLVTz5895vEdQJwbHTaAdy/e9e6sgkShXTJ7LXy" - "Nnvg6tIyAAf79u6N+6ZSy9fOnT2EocMlgDiAcza6lTUVDpAU2q6eHpaLRYB9wNUGQBC4qAmT" - "bbnG3EQ6IpJItAtHPdTWS+xMPqQ1QGgtzgmCXWdulygColyBE5dcrqlKKVkN4FxSwJSWdHWn" - "ugnNc13KT61m9PKN62x2NMVwNcDlS/PPbRaSrM0P9A/HH72wvtGyB19/Y/8LLx34YjMK8gP9" - "w4XpiV+A7xObSl1B7gIeiS3W+T8Zt4BzwIWk0f4DcXNt5u3KdCcAAAAASUVORK5CYII=") -index.append('UNLOCK') -catalog['UNLOCK'] = UNLOCK - -#---------------------------------------------------------------------- ICON_16 = PyEmbeddedImage( "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" "SFlzAAAAsQAAALEBxi1JjQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" @@ -484,3 +287,1730 @@ index.append('ICON_128') catalog['ICON_128'] = ICON_128 +#---------------------------------------------------------------------- +PROJECT_NEW_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADYSURBVDiNxZG9DsFgFIbf03aR1j1wDSLRGxDp3sbg5x7MBo0raW1MliJ2hpaVjWugjUmP" + "QSslxNdBvNP3nZ/nnJwX+LcIAEzTlA9hoc7MWppg4LSdjxZCgGqjPWSi/pusHXju4DvA6I6Z" + "2cyxeQhCK/DcqZSjKSsNTE0AEAYEM5eIaJL+iSDnAnySIjI5ffueYwH3mwkD0mLfc6yK0elJ" + "oBoz60S0FgJk3Uman9wSvkFitf4aV5Ix+zybAEDM2D0AJe1iHyN1FcfXosg2kiSfy2q03IgU" + "/1w3lwVNl0cM9gQAAAAASUVORK5CYII=") +index.append('PROJECT_NEW_16') +catalog['PROJECT_NEW_16'] = PROJECT_NEW_16 + +#---------------------------------------------------------------------- +PROJECT_NEW_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAC2SURBVEiJY2AYBQMNGGEMY/d4bwam/zMZGRikcahsPLNtUQOpFjDDGNJq+vsYGRhk8Kh1" + "kFLTZ3x2++IBUiyA+8DEM+4/qa7DAZ4wMDCkndm+aDsDAwMDE5UMRQYyDAwMM2EcWljAwMDA" + "IEsVC85sX8R4ZvsiRnxqaOUD+lnAQqoGbEGCLIaeGgefD5BdCHM5vjw0AiMZGRBTvCD74Akl" + "lqGBx9gsSKOSJY8ZGZnSqGDOKKASAAAvnCjJd55JwAAAAABJRU5ErkJggg==") +index.append('PROJECT_NEW_24') +catalog['PROJECT_NEW_24'] = PROJECT_NEW_24 + +#---------------------------------------------------------------------- +PROJECT_NEW_64 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAk6QAAJOkBUCTn+AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAJKSURBVHic7Zo9axRRFIbfM7vENHYGQQvRYDrZSHYkdmIh7oDlCiruRsgvsBYSOxsL/4HZ" + "FJEliCBJFBGsLHT8CEgaP7BKpRBDmiTsHFvBMzu7m7lzltzzlPfemfPuszP33tkdwDAMwzAM" + "w/AT6mVMGM1UGMkpTnhk0EIMbH98sfhy0ONd0VVAtdaoMfCIgLM5Vbsfr7bmczlXTpTSOqpX" + "mzdAWCbgWI71Lp2YqNDm1/U3OZ7zQIgCztfujAWUvAIw6qDmUEkIpMYydW4COOqsKmOuGjXm" + "nZ2/D0QBCWjSeWXGXFhrPHBeJwNxEgyjZpuZ60WHyZE9AD+Jub0/Wnr4+dnjrbSB4hVwCBgB" + "MMFE98q7SXzhyu3TaQMPq4B/GU9K9LRer4sTvg8CAGDyx86Ra1KHLwJACC5L7d4IYMZxqd0b" + "AUFA4ornjYA0ytoBsojXWv99c3nuU7y/AkyAdgBtTIB2AG1MgHYAbdT3AdI6n8X71YXr3fr7" + "2Sd4fwWYAO0A2ngvQH0SDKNmu1u/NOFNRY27AWg67RhmvthrfXUBgzzVBaBpexrMCROgHUAb" + "E6AdQBvvBagvg1lI+4R+1vkshl6A63+pvb8FRAHMvFN0ENcwsC21ywKAT27jaJCIn0m+Bcr7" + "SwD+uIxTMFvBLj2ROkQBH54v/QIwC6DjMlVBdEA0++5167fUmfqe4Oa39Y2T45W3IIQAxpzF" + "cwiDNgKmW/HawkramJ5+kJyKZs4RkjMHeVW2SCigPRB/j1cWv2hnMQzDMAzDMIaVvyYdlwhv" + "9dW2AAAAAElFTkSuQmCC") +index.append('PROJECT_NEW_64') +catalog['PROJECT_NEW_64'] = PROJECT_NEW_64 + +#---------------------------------------------------------------------- +PROJECT_OPEN_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEFSURBVDiNxZKxSkNBEEXP7EsjJmDhBwTxB1SEdFpIfNhvZ9DGv7Aw2Nv4AZGkU7CMT7AR" + "RAIaQbCwEBT8AEESRMnuWMToCsJbC/FWw1zumZ1l4L8lANba5L43VlXV4shQeL7KWsdRgPm0" + "tq0imz+49ct2cysfsLK2r6o28tVOlMZF1twAKASkjlfdiSEIuFFtvrry2M1aBwkyyAN4SObS" + "mp1dXp0uhEYlXS8PxB/KcLNcGWHRhA0nWo1KDtV/YqLzDYCw9AvA6d3R7uvnCqregCxEx1VO" + "IPxEmAEmo/MmBKjegkzFD+e62967gY87KBdf6g/98XPvXSkvbMC9Oc4AjR34t3oHnFtQJ7uM" + "K6EAAAAASUVORK5CYII=") +index.append('PROJECT_OPEN_16') +catalog['PROJECT_OPEN_16'] = PROJECT_OPEN_16 + +#---------------------------------------------------------------------- +PROJECT_OPEN_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEUSURBVEiJ7ZG7SgNREIa/WQ1ELW3EpDFF2oC3xmZRQcR3iCkkz7E+Rtq1TO+CBrEI2Cze" + "WtslhWCneIFkLGQ1JCfCOgs2+ZozDMP/nTkHpvw3khZre4cHeNoSKE2YPI5PwyCrYCYtStXa" + "hUD5l1l/uVqT3sPdZRbB9wbr+3XNejsHCdCMozBKG14OocOUgdZwY3Z0Io5CGe1ZyHuDMcY2" + "APD9RvF5bvAEzBuy9aOvS84NXoq6ZQwHuL0/O3l0P5Gnu8ZwQM9hwh+oYheIdpyCzZ36IrBq" + "jH8rLLx3nYJ+Qbdd/UwI3at2+9UpELE/jyqdtHbd1C7wxClIvg6pGPN71xsrNy5B80fyZxLg" + "iCAYGHOm5MgnJQRAyyN2E8cAAAAASUVORK5CYII=") +index.append('PROJECT_OPEN_24') +catalog['PROJECT_OPEN_24'] = PROJECT_OPEN_24 + +#---------------------------------------------------------------------- +PROJECT_OPEN_64 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAk6QAAJOkBUCTn+AAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAM1SURBVHic7ZrLaxNRFMa/M4lpUUQEhSIFpWI3UmsfsQoFn0gS1120QhrBP6A7l213XYnS" + "naAtESlod8UmtdUWFz7IQ9RFF4oIBamgQmspiM09rqJ9TJLJzJ2bTLy/1eTeM/d8+TjnzmQy" + "gEaj0Wg0Go3m/4SsxAQjsVaGOMyCA3YTMbCaTd6fsXu+WxQ1oDMcDTNwm4BjkrINp6fjQ1LW" + "koSv0ERnqL8XhEkCDkjMd+5Qcyt9+fB2QeKajjA1oC187aBBYhZAvQs5q8oEw2zQT7k+AHtd" + "y8oY7IxEh1xbvwxMDRCgk65nZgwGw9ER1/OUwHQTDEb6HzJzj2oxElgGYV4IjGST8XdWTjCt" + "AA/TAEavQUh1RKJ9Vk6oNQPyBIgx1h6KnigVWKsGAEDAR7hRKqiWDQADF0rF+K0uRsArwXzT" + "mSS1EBGXirFsAIiWMon4I0eKqpCabgEraAMqLaDSWN8DCnAqFD2TAzfKEKMKw/D9TE2PJwEJ" + "BgjCOIGanctSB7OYBJAEHLZAV/hqIwBPfXkAINBs/tiRATn4LjuXUwEM39zfQ0cLES45FqMY" + "Bj6nHt/7lP/sxAAC47wETUohwpYHs7YNCEZirQAaHCtSzr/+B5xUALPnyh9AblfOP795wEEL" + "eNEAzr6cuftj84gtA4739AQY6JYjSiVbyx+waUDdWn03gD2O9SiGDcxtH7NlALH3Ln8A1lfE" + "vhfbB23dCpMHr/9gfv4xOfpr+3DZFdBypW8/QO1yVKmDaWf5AzYMqBP+iyjyn2K1wrxzAwTs" + "7AFeLH/Q12wy/t5spnwDPLgBMsQcANMHpGUZcDoUOwLgqARNSjHYvP+BMg3IEXvz56/wPy00" + "VV4LeLL/sZh6MrZUaNLyfQCzMAA6K0eTOojYdPfPU04FtEHu6zJKYGEULH+ggAHMvLZzlJrk" + "SFLKho82FooFmBsAvHFFjnqevU48WC0WYN4C/t8TAFbcUKSYW6UCTA3ITE18A3AdQE62IoWM" + "phPxRKmggptgOhGfJIEQgEWpstznOxEG0l1NA1aCrbwqi45IrIUgmpy8KqsCZl6mwO5MZurO" + "eqW1aDQajUaj0WiqnT/yqMjSmxhvqAAAAABJRU5ErkJggg==") +index.append('PROJECT_OPEN_64') +catalog['PROJECT_OPEN_64'] = PROJECT_OPEN_64 + +#---------------------------------------------------------------------- +PROJECT_SAVE_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADWSURBVDiNxZJBDsFAGIXfP0PiCG7Bopv2BK1DlLiBSBzCQmJPFxWbOkDdAAmXsZGgnk0r" + "g7ahC14yyf9n3nz/m8wA/5ZkhdXpzkD2AOgS/0YjcXfx8vgO8PwriCnBbe4kkSgPUjM8muD2" + "sF6s8gCW52elnUCvATgAoErilsnOCjMBRCQyJn2kqgk+BmzSVQXAwT4OnX0cOhQMvwZo3IJH" + "c27MvwZcbtJ6mOqndpHPfIUExi9USkWW2x1TUUgZAcSL9xlAIBCgb0CaEE6E6e7TYRZe6fe6" + "AyKdQQ5+P1IOAAAAAElFTkSuQmCC") +index.append('PROJECT_SAVE_16') +catalog['PROJECT_SAVE_16'] = PROJECT_SAVE_16 + +#---------------------------------------------------------------------- +PROJECT_SAVE_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAArElEQVR42mNkoBAwUs2ASZMm" + "zQFSCUDMjEf9cSD2yMvL+4TNgD9AaiIQn8CheRU2Q5AN+A+kwoASq7HphsrDXQJUZ0WJAQxA" + "dYzYDCAa0M2A41DakhwDCoGKJkDlioBUL6kG8MOiCijHD6Q+kGTA////7fLz8w9D5eyB1AFC" + "BoASEnIqfAHEXVA1ZUAsjiT3F2gAC7oBs4BUEgP+pAzWDMRzgQakoxhALqDYAADNVlkROfKn" + "qAAAAABJRU5ErkJggg==") +index.append('PROJECT_SAVE_D_16') +catalog['PROJECT_SAVE_D_16'] = PROJECT_SAVE_D_16 + +#---------------------------------------------------------------------- +PROJECT_SAVE_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAESSURBVEiJ7ZS/bsIwEMa/cywegrC2a5GAnbHhHcjIK5CpAqbAI7A1eQeyVeykQ+eOVH0I" + "ZOwOEMlyDPmnTPS33ec7f/addMA/BZAeDF+nE0W0JcCteMsy3UUL25GjB92n/gcBvaqvBDDu" + "Pr/Q7/fXPu+tMfR8BQBpEpGZaCPL1y5bH5Io0DVW+a13UMB85PlhawaZSasGJtwmmr1tQus/" + "eByDE6DmZ8Hds+CuAoKLVox1yCYKePtM4o0mrQeeDwLCm0VXyv1AyihXSOy9TGkpAyk7udXB" + "mXRsubUMGBdTUzsJ5DQbpWZAwGrg+ZCCx5khAcs6Bj+wr+sOAaHDReFQARz1wGzR7GpSlyMR" + "mzWof0T+AB1zQEAqbAbfAAAAAElFTkSuQmCC") +index.append('PROJECT_SAVE_24') +catalog['PROJECT_SAVE_24'] = PROJECT_SAVE_24 + +#---------------------------------------------------------------------- +PROJECT_SAVE_D_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAvklEQVR42mNkoDFgHF4WTJo0" + "yQtIzQJiaRLNaczLy2sgxoLHQEqGTMditQTdgv8gGqiQqKCDqUcCnUC9FbS0AMMSWliAon9g" + "LKAUjFpAEwt+AXEtEC+B8mOBuAmI2ahlQQVQUyea2nIg1UEVC/7//y+Vn5//HE2tBJB6ThUL" + "gEAaqOkZmlpQgfiElkEEKg7aqWUBKJLrgHgxlE92JFNSXMPAY6AFcrgs8GSAVDjkWgJyYBrQ" + "gh1YLaAFGPoWAACwQnwZ7O4euAAAAABJRU5ErkJggg==") +index.append('PROJECT_SAVE_D_24') +catalog['PROJECT_SAVE_D_24'] = PROJECT_SAVE_D_24 + +#---------------------------------------------------------------------- +PROJECT_CLOSE_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAD4SURBVDiNxZGhTsNQFIb/09aQjAcAv9kKUoEHstXfZILRd8BgJtrUoHiI4orCtKNuYslE" + "WTK/BIHAkwoM+zEb65rbtAuCI88933f+nAv8d0m1cTa4uRPgXjtN+PkkCsotszrzsVrOTrr2" + "lwAXTbBWoJXUwLWCreS0ZwsE0zzVw8DmBkop8604uiLZ2SXG52Ly+FIH7gmc/iikyFjzGuRJ" + "5DcLXC8mqZq2laqA4DpPomerZJqvyYc2tCFyS8oQwE4AkffXNHpqI3BcT8nmA4wDYuvT/FVg" + "AQDJAsCl43pxG4jkOYDsV2B8M1ybQgDHLRdnFo3w8Lya+gEzTVbi59ZlJwAAAABJRU5ErkJg" + "gg==") +index.append('PROJECT_CLOSE_16') +catalog['PROJECT_CLOSE_16'] = PROJECT_CLOSE_16 + +#---------------------------------------------------------------------- +PROJECT_CLOSE_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAArUlEQVR42mNkoBAwUt2ASZMm" + "lQOpDhzqG/Ly8hoJugCHIRia8XoBzRCsmgmGAdCQBhAN1NyANwymTp3K/PfvXzcgkwcm8f//" + "/0/5+fk7iQpEoE3NQKoGi3wjPtuRDVgFpEIJ2YYEvgBxDNDwjcgGyAJxH5EGFAHxA6ABkcgG" + "gAIrjBjdyOoHjwHzgJQrEB8nMgwsgXgX0IBkmAGKDJBo5CXSgM9A3Aw04AHFuREA8YJTEbpb" + "QPsAAAAASUVORK5CYII=") +index.append('PROJECT_CLOSE_D_16') +catalog['PROJECT_CLOSE_D_16'] = PROJECT_CLOSE_D_16 + +#---------------------------------------------------------------------- +FOLDER_OPEN_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEFSURBVDiNxZKxSkNBEEXP7EsjJmDhBwTxB1SEdFpIfNhvZ9DGv7Aw2Nv4AZGkU7CMT7AR" + "RAIaQbCwEBT8AEESRMnuWMToCsJbC/FWw1zumZ1l4L8lANba5L43VlXV4shQeL7KWsdRgPm0" + "tq0imz+49ct2cysfsLK2r6o28tVOlMZF1twAKASkjlfdiSEIuFFtvrry2M1aBwkyyAN4SObS" + "mp1dXp0uhEYlXS8PxB/KcLNcGWHRhA0nWo1KDtV/YqLzDYCw9AvA6d3R7uvnCqregCxEx1VO" + "IPxEmAEmo/MmBKjegkzFD+e62967gY87KBdf6g/98XPvXSkvbMC9Oc4AjR34t3oHnFtQJ7uM" + "K6EAAAAASUVORK5CYII=") +index.append('FOLDER_OPEN_16') +catalog['FOLDER_OPEN_16'] = FOLDER_OPEN_16 + +#---------------------------------------------------------------------- +FOLDER_OPEN_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEUSURBVEiJ7ZG7SgNREIa/WQ1ELW3EpDFF2oC3xmZRQcR3iCkkz7E+Rtq1TO+CBrEI2Cze" + "WtslhWCneIFkLGQ1JCfCOgs2+ZozDMP/nTkHpvw3khZre4cHeNoSKE2YPI5PwyCrYCYtStXa" + "hUD5l1l/uVqT3sPdZRbB9wbr+3XNejsHCdCMozBKG14OocOUgdZwY3Z0Io5CGe1ZyHuDMcY2" + "APD9RvF5bvAEzBuy9aOvS84NXoq6ZQwHuL0/O3l0P5Gnu8ZwQM9hwh+oYheIdpyCzZ36IrBq" + "jH8rLLx3nYJ+Qbdd/UwI3at2+9UpELE/jyqdtHbd1C7wxClIvg6pGPN71xsrNy5B80fyZxLg" + "iCAYGHOm5MgnJQRAyyN2E8cAAAAASUVORK5CYII=") +index.append('FOLDER_OPEN_24') +catalog['FOLDER_OPEN_24'] = FOLDER_OPEN_24 + +#---------------------------------------------------------------------- +MOTION_START_TO_END_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADSSURBVEiJ7ZTBEcIgEEUfjF0Yq1BrcDL2EG9pQY/JzRLMlSLEHqQL7cEjXqIT0SRAzEn/" + "jZ3lv1k+AH/1SDQX89VmjbSVgGmk3xXIjVb6UZAvNGkPA8wBEqBqFiYfGjBaCSK0SDMLzJo1" + "2dL7NQUDlmm2HxVgYRsCiTqiEIgb8pvq4NognLXade0fFLLPJINvkbXcxgNYCnNSZVdLbwbu" + "o3tm4mEOsRN4mscBBKWveRTAHFUR0j/6X+SGfAWStsflqUtz4U6Q15BocyFkPmD/L+oOI24+" + "Er15FBIAAAAASUVORK5CYII=") +index.append('MOTION_START_TO_END_24') +catalog['MOTION_START_TO_END_24'] = MOTION_START_TO_END_24 + +#---------------------------------------------------------------------- +MOTION_END_TO_START_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADXSURBVEiJ7ZPNEYIwEEZfMnahVgE9OGAPeKMGb+JNOpBrijBNQBXSg8d4QSfiTyCRk363" + "3dl8Lzu7C385JOwgWm3WSFMJmHv6tUBea6VvCflAk+YYYA6wACo7MXtRQK2VwENxkhlgaefk" + "m9qvaRQgTrNiMkCcZgWG3SQAX3N4HrLTvBvkXa6F+NhByM8HAYzhEmLuBDRalQa2IQDnDBqt" + "yijJEHCA8Uc4aItCOhl8B41WJYL9ZACA+qSKSQE+6g+5BRb9Yxqpsx30O8g7iLe5EDIPeP+L" + "ugLqLTw21wMy1wAAAABJRU5ErkJggg==") +index.append('MOTION_END_TO_START_24') +catalog['MOTION_END_TO_START_24'] = MOTION_END_TO_START_24 + +#---------------------------------------------------------------------- +MOTION_SWAP_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEpSURBVEiJ7ZRBTsMwEEX/GN+CNguuELNGFQsUVb2CK3WRa1S9Bd2gKBwBIXfXbaWGK6Co" + "9BhVhk0NIXESkxaxgL+b0fg9j2QZ+E9HqFyEd9MxBC8JuOzJ2wOIM5Ma2xBfbILvT4ADwADA" + "styQjgFkJiX0iIo0AxiWe6Jh9mzxEoQTHahoqm2tIj27Hs+uziIIJzqgA69B/AkkBFwc1j6S" + "VsEHHOQCeUkaBTU4Y64izSrSDMbcV+IUdNy8mlbJ77yil6d0x5JGAL96MHYk5Gj7/OCcbdyg" + "JiEsMpNSZlICYeEDbxU4Jd+4uZfASiRf3FLBue1RwblkcdMFB+p/kTObVZIDSGy9XT0mTbPV" + "/Pgrqm6wBzA4/op981YuqhvER0lvOJGITzj/F/MOEHR7/G1z6tAAAAAASUVORK5CYII=") +index.append('MOTION_SWAP_24') +catalog['MOTION_SWAP_24'] = MOTION_SWAP_24 + +#---------------------------------------------------------------------- +MOTION_MANUAL_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADrSURBVEiJ7ZVLisJAEEBfNbPzBh5BzU4FT+DnDgacG7lyJ6hnEI8giLrwc4W5Rbpmk9Zo" + "IpqOoKBvFarSr7qqOwS+3EHcQ7PXr1uVMVBLxnOiwMEaGWznkw2AcZlYHhSQE68NjNWxC5hE" + "slpAfE0tq4DJeNGXk+snlVJmIvz5WFUpI/STsVQBA6PVYrr0KdDshC3LZYFnjiWT9Ihi6t1Q" + "84jWi2nm7XtdB7d2lJf3PoNHuvyewV2SHVjAREij0Q5LPrIIqQjqXKkCRyAQ0aF6DieWo8Le" + "xc7/AyMDYAfk+oKvUGBHZH8LOD6Nf3rBO2ntq8pUAAAAAElFTkSuQmCC") +index.append('MOTION_MANUAL_24') +catalog['MOTION_MANUAL_24'] = MOTION_MANUAL_24 + +#---------------------------------------------------------------------- +MOTION_MANUAL_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAASdAAAEnQB3mYfeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAE+SURBVFiF7ZWxS8NAFMZ/L60IHWxXXRV0FNquzkYc1c3GXfxr6ixaNzvLObs2Dg6iQnHT" + "uXUItEOfU0psqyEk4Sr2N717d9z38b6DgwX/HYkuqq63Ljo6R2QHKGWsFaB6L4Wl087txduU" + "gQ33bLlC/xHYzFj4O8JLT8vbXdMcADhhv6z9eu7iAMpWhc9auHQiO6u5i4dKOlqbYcAO1g0U" + "ZzUFrjqmdZKlUN1tXCp4k33rE7BuYGYEUWpuo51GwDetw1QGgIM0BuKY/wh805K4M2mY/wlU" + "d49/fUSTPNxdJ3q0sQZE5CbJhUx88XHMfwSqemTVQNJMk2I9AusGxhGIOB+gACh4Nbcx9XWm" + "QSO1U9D3cR0WPVZ84DVL0R94DkoDf8pA1zQH4hT3AAMEOQgHgBGnuP/Ubg9zuH/BH+ULaclM" + "X5CXfNQAAAAASUVORK5CYII=") +index.append('MOTION_MANUAL_32') +catalog['MOTION_MANUAL_32'] = MOTION_MANUAL_32 + +#---------------------------------------------------------------------- +MOTION_RANDOM_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEkSURBVDiNpZI/S8NQFMXPfX8yuAgOGRxCxk4ZGoQuDlleOzg7NRD8HI5+Dgno5K5WB10L" + "JQU3JwkdnKQfIP9eB2kwaRJTeqb3uPd3z71wgANFfz/ueDqEka8AAAm3opf75X91URln5Ctk" + "cvH7Ts927Brq7NATqhsk3CqdE24B+HGUb0rwk+g1/GyqEzo0mgR2RvkDQFkBfb18vnur97Se" + "UMIMV7KQFwx046pg0GvAaBLYKRXvmsiQmfGdiuQU0CJFvq737pywhQmwAUATPkjrRGh+OZ+F" + "cb1fdMEAAI1jobk3n4VxZw6aYA3EUjOvdG7LQS+4RcJRvtkbbsqBq4IB8SICcLSP81YEAMPx" + "9Jwx9gRgTUx4i8fbrz5wRa4KBo7yzX25DQydl2pgAjkjAAAAAElFTkSuQmCC") +index.append('MOTION_RANDOM_16') +catalog['MOTION_RANDOM_16'] = MOTION_RANDOM_16 + +#---------------------------------------------------------------------- +MOTION_RANDOM_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA1klEQVR42mNkoBAwInMmTpxo" + "xMjI+AjE/v//v1x+fv45QvIoBkyaNEkESJ2Gck3z8vLeEJKnrgHYnAgUEwOKCQEV3yDoBXQA" + "tFEBSK0C4j9AXAM0ZB/eQMShOQmInwHxFhAb5BKCBkA17wfij0DsBMRSQDwP6GwfoLNf4TUA" + "SbMCVOgiEP8C4jCg7Q/wegGLZhAAaXIEacYbiIQ0441GYjTjNAAazycJaQYBrF4AmqoB5J8F" + "Yi58mnEBRqjJtkCTtwGZ76Ca7xGjGSUWQC4BOusdejwTAgCVuZwRQ2i1dAAAAABJRU5ErkJg" + "gg==") +index.append('MOTION_RANDOM_D_16') +catalog['MOTION_RANDOM_D_16'] = MOTION_RANDOM_D_16 + +#---------------------------------------------------------------------- +MOTION_RANDOM_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAGWSURBVEiJ3ZQxSBthGIaf79fBreDoHnAQFO5Sl0wqMaeTRtqh9RI6idBFBHc3F0FcMome" + "OEoRJBcCZuoWI3Tr4KyTuwje1+VSRHL/JTnr0Hf8eb/n/f53+OC/VN6rbH9c/DoN4BSrk/mS" + "vzmsf7TXgJqooZhO3vN/KlFBjTq2AJtfkrfyrxTmBFrtMJi3Bdj8ppfZXV6fUigItBQK7vL6" + "lA1u8/cMIGIBo047DOYx6hCxYF3f4k+sKEn5pWpJNToDCa7Dky1Abf7eP7DDzwU9AP3sliqH" + "aUv2HdCFA9/b4emuPps5RFddr7KfOSCG/xB07zoMjgA6zePfgtZA/UwBXTgwpsiGU6xOArie" + "/02RHRHzxTZv7e8l/MXzvaC1GF5u148bQwU4XqUo6MUreFdPkVC+qQeXNjgkVDQofKBblFBL" + "V48iZuXmVS1936J+4Emdp96iLPDUW5QFDqTfItfzH4DxoeApiiuS4F/AAUYA7m5/NSdy0+PA" + "bPz+FAlrnfpJPQv8b0Ac0pjIzXwAciLm01vA30V/AFm8+QgTQy8lAAAAAElFTkSuQmCC") +index.append('MOTION_RANDOM_24') +catalog['MOTION_RANDOM_24'] = MOTION_RANDOM_24 + +#---------------------------------------------------------------------- +MOTION_CENTER_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADbSURBVDiNtZNNagJBEIW/6layEAZyFX9xk50kxiMIeolANmY3B1HBI8QJeAGFxKsEXNtT" + "blRmtDvOIHm7rn7vq6Kahv9Q+2XULVIDMD5jKnxd1lNh1XodP/0JyIQjT7Oaqi4vIWfAjXAQ" + "YkqEvRAJuTr9YbTHfoigVl28SRY7n68SAjixE1HeUHAYBd59vqtXKKvgBFZdfOzMQ7Uah3wC" + "UB+MGzbVlcLj6eI7mef20+yPNHPcpZjnbTJdG4Dt5+zHGekJ/BaY+hyGzA4KQnLhHKAA5Coc" + "VJnPdLcODA5ijErR8qcAAAAASUVORK5CYII=") +index.append('MOTION_CENTER_16') +catalog['MOTION_CENTER_16'] = MOTION_CENTER_16 + +#---------------------------------------------------------------------- +MOTION_CENTER_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAt0lEQVR42mNkoBAwYhOcNGmS" + "ZV5e3nFCYlgNACkEUjuAivnRxL8AKS+g+CGcBsA0AzEfUCG63H8g9RXdEEZsmkF8HAYwoBvC" + "iE0zAQNQDMEaiFANIMNqgRiksQWo+BPRsQA1oAtIlUK5XUADyuluAMgL1WBFjIwtubm5n3Ea" + "AFRsDKR2A7EgkYEICg93oJoTyNGIYggeA+CaMbyAbAgOA1A0Yw0DmCFARUJo4h/RNeMMRIoy" + "E6kAAKLscxEHiPl/AAAAAElFTkSuQmCC") +index.append('MOTION_CENTER_D_16') +catalog['MOTION_CENTER_D_16'] = MOTION_CENTER_D_16 + +#---------------------------------------------------------------------- +LOCK_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAFWSURBVEiJzZS7TgJBFIa/s4NU+gICCY21iWB8BZeYWBvjlqutNhgLa7SwsoFKQZ9AdGNj" + "awxS0NuBl2cwzI7FSkLA7C4LJvzJJJMz5/zfmUsG/lkSJ6lYcrYxHALFIGJaAhctr3EXVaui" + "EtZtpwJcAnkgHQzJg+wsr6ymP946T2H1VlTnBsrAN5iy7qcyup/KGDgOYpyslZytMI9UaPvB" + "sWDgtO01zodWzgq2g0DF8jkCmol2ABQA8P36WKFY1wDI4F6SARYB2o83n6MLrYerr9/p0jSA" + "qTX2TIubeyUjUhPITOjVA9xXr+4NB8d3IFJNYA6QBaqjwb+OKJvAfKBcHMBMNUcA4X5BkVXo" + "HOBF5k8KUEYfPDfr7y/ebU+02p85IKnC/6IhaVRtw951fZ0WY/VrMX/6+ADA1qguShPXHObq" + "Fc0Q0JvCrxsH4CaEdEUsN0HdnOsHtElTop3yxk0AAAAASUVORK5CYII=") +index.append('LOCK_24') +catalog['LOCK_24'] = LOCK_24 + +#---------------------------------------------------------------------- +UNLOCK_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAFNSURBVEiJzZSxSgNBEIa/2Y15CJNAGmvBO/ER5KJgLcLZnbbaRCyso4WVhUlngk9g5Dpb" + "kWhhb5fEh5DsrcURCEbuLpcE8sM2s/P//8zssLBkSJYkt+YfYDkD3DhiewK3vbDzlMbVaQnb" + "nt8A7oAqUIyPVEEO1zc2i99fny9JfJVWuYU68AO2bkaFkhkVShYu4hiXWzV/P0mjkFh+PBYs" + "XH2EnZuJm2vH8xFoqIhzoJurA8ABIIraU0RRDwDI+F2WANfzrev5NiknrYO5MbWmzu7xHso2" + "BUozag2A4D1sh5PBqQ5E2fsc4gBloPk3+N+IyjnEx6hkMVgoVshAeF7TlDWmAoSp+bMaaGtO" + "X7vt4Vv4OBCjTxZukBfJf9EEDLq14x0FkSmKVaNWxp8+uwHgGXQfbcgqDiu1RQs0GMyh189i" + "EOQ06YuoIAdvxfELb7xSIP/N950AAAAASUVORK5CYII=") +index.append('UNLOCK_24') +catalog['UNLOCK_24'] = UNLOCK_24 + +#---------------------------------------------------------------------- +MENU_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AABmSURBVEiJ7ZJBDYBADASntQEuEMEDEfxOE/fFxJnAxeGjOCCFQIDQee9m9zEQPI14g10/" + "DqhlAQPSUubi6an7idok0AAtkL0998BZjgwkYAWqiKab/ryQsOjSgbBon7DIw08t+j4b1DYk" + "HJtnLRoAAAAASUVORK5CYII=") +index.append('MENU_24') +catalog['MENU_24'] = MENU_24 + +#---------------------------------------------------------------------- +ABORT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAGOSURBVDiNpZI9SyNhFIWfOzNiOv+Apeu3jRux0c4mEdROMIx2FmIhprS2FNMsiJUagrVN" + "ImJpI0waFYkfZf6AVgbzzt1i3okTHVxYb3cP9xzOOVz44UgaOJ0rjIbiLYYwCODAo6Pts+ta" + "5f5bgd9z633S0zoAXU4RV4HT8D2zUb88fPkiEJHfroDxf7i+dTEz17XKq3VnlXpaBwlyM4UY" + "YxNG3D8x6MSZrW2ApnqZIZBSImkpwqyIUpic90c6AgZ3KRGnX9qt3aB2vI3oPqL7Qe14W9qt" + "XaA/VhQjiwCeBQa63epWNu9rUC0XAbJ5fw/VreSFCL+6OvjfiR08d8NSCqonxWze3wMIquVi" + "Nrcm8OFClSewuadzhVGDe2f3pnqZoShzTJCSer070n57IOohVOOM1S+OGp0/mMqtVhRW7Nrk" + "ozC+YEo5OD9ZhUQH4XtmA7i162dyErtxxWzGYEegfnn44mJmFK0AmiIQopRdzGz8hZ0OPs/k" + "vD8ioSwgMhxZ1gbGOatfHDXS7n80fwEqbI9NTan9sgAAAABJRU5ErkJggg==") +index.append('ABORT_16') +catalog['ABORT_16'] = ABORT_16 + +#---------------------------------------------------------------------- +ABORT_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAJZSURBVEiJ1ZXNS5RRFMZ/5xo2YxOthMgWaQXCGFQzbVoEKUoqZGovCGHNPqKg7ONPsGYT" + "7VoNDoEwlRmYkiTRMmdcpKELkRZi0WyCBgcK72nhDL4fo6m06Vnd95xzn+d8XM4L/ztkK2fU" + "caprCuFuRS6BngIOl1zLCDOijK5GiiOfM5lfOxaIt1+9DDoI0rB1jrokysD0RPrltgQcx6n6" + "UqgZVPT21sQ+GUg2RIr3M5nMmtu+xx+4G/JSpneWCmGAAZ99A/GOa72oPt8puYdQtdfdLlM+" + "RB2nGtVBX1oLqDkPfKvAlbdoCzDrNqqR5LH2G3sDAjWFcDdw1B1sVa9nJ1LvMdoK5N3kGG2e" + "GU9PWfSWR1apP6A/LgYE1p+iFwYZjnUkTmTH0nO6Zs6VKsmrmJbsWHou1pZoNMizQG1CV0AA" + "9HSwC9SK2nfxzv6m3NvUAkZbMdqce5OajXf2N0mV/QAcDPJLvHx2v6JDFQQAarEyFetItGTH" + "UrMAsbZEI9ZOArWb3KmrUME/ha0ksLJJcN7dFk+7vIN342tQQMhVIncPFCuTpXb5B++FMB0Q" + "EGXUH2fRvgoD9Qzeolf899Tq6w2tEqKOUx0uhOZ9y23OojcNMkxwoHmL9hnkMdDksi8WI8Vo" + "ecN6VsWZC/09KvIiUPIOYJSejxNDI+XvKrdzZfHTfN3xk/uBs7tiFx5Njw898Qj6Y45EVu8p" + "JHfKrZCs31d8ENTcBKV2PcS3nypg0Sh33W3ZlgCsDz70M9SF0CUiMbT0yxSWVTUnyCv9HhrN" + "5Z7+/ksS/zH+AJly9UDPAIpxAAAAAElFTkSuQmCC") +index.append('ABORT_24') +catalog['ABORT_24'] = ABORT_24 + +#---------------------------------------------------------------------- +LIST_REMOVE_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADtSURBVDiN7ZAxSgNhEIW/+c1abZdrCCnUxT5FYCVgo1WMZ9DCLqAXSO6wNuKUgmwhWlis" + "BANa5AaCR/glxYyNhYGsW6Sx8Gvfe8N7A/8IwG5+cuPuh3Umdz+alVe6SmsBiPnE8JUGgJZY" + "VavVCRvI+7QsaoNLBzzIqThLE1xEgSrrDtu2yUWSxvNKNWa9QcckHLyUxSV8/+A3dvaPtzB5" + "BN6CMzLhFniNacznqgsB2M6HZwHZ+xk0/Hl2V4wBst6gYyHcA23gIUljv1KNAKGpQRNrT2hs" + "ED7lA7hO0tiflkUVzLo4T3PVxbrt/whfVVpeFIrDr/sAAAAASUVORK5CYII=") +index.append('LIST_REMOVE_16') +catalog['LIST_REMOVE_16'] = LIST_REMOVE_16 + +#---------------------------------------------------------------------- +LIST_REMOVE_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADwSURBVEiJ7VOxCsIwFLzXzHYT/AgdxEoHJwWH9BcKRb/I0bEi9BM0izrpUBQ66OAnCN10" + "DrokUupgo9TF3hSOl/fu3SVAhQrfgvTB4cHd5OJBzOl9FWCZKvo/FM4g5zm53K/FIrpma1zu" + "27GIbgCevT7JgDo8mEhicdcbNTTZ5uO6BNs6XjDNCi/0EvIqJdgOQBPASYINAIBBbjTHIHt6" + "O+MBWm22oaKfAxMRpi8bGGagh6wBtFSnM8Hq75ezS7au9H/wO4uKwjRkY4tiEV0JWIBwJrKG" + "iQjTRISpGnQEaKX+wlcgl/t2nlTcR7ZXKA8PCIFhMNuUM9wAAAAASUVORK5CYII=") +index.append('LIST_REMOVE_24') +catalog['LIST_REMOVE_24'] = LIST_REMOVE_24 + +#---------------------------------------------------------------------- +RENDER_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEKSURBVDiNzZM9SkNRFIS/uQa0dAHWthbG3x28tJJYGRfhDgSLIJjGSrCI6RTsDCL2EUIs" + "bNxAFhALm6B3LHxPXvDlITY6cOGewzlzZxiuyGG91lx+j14BUAhx8hZvn+66r5Sgki+iOZS0" + "C4DNfGAHuC4jEMBqsncg1ALmCmbGMXj78ab7PFNBUNiwXbQMsBiiztdq+6Mptfhh2Ls4CSXq" + "RpKussL2ku16et8KaBNgJoGk/qDXaaQLbdttgEGv05DUn7JQBNv1atJ0SnaZ9atJ07bJ1JVZ" + "+BH+N0E+hX56Mu9fkf59CpV0OJZYAXHs6EG+FfxpIyXgVJKl738h2mMmC0fD+7OX0kd+iw+H" + "DX6VW9DlbAAAAABJRU5ErkJggg==") +index.append('RENDER_16') +catalog['RENDER_16'] = RENDER_16 + +#---------------------------------------------------------------------- +RENDER_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAqUlEQVR42mNkQAKTJk1SA1L6" + "UO6/////78jPz//KgAcwohmwAkiFIwkF5+XlrSNoAFBjMZDqBGJmLGo+ALEV0KDr+AxYBaRC" + "8Vh0HIifoImdABrah8+AJ1CNoVAaBCyBeDWUPg40IAyfAatBCoBy/4HsMKjYKqAYI1Q9AyED" + "CIHVI8CAIRYL6HkAHXQD8Wl0LwINOA4zwAZIZTPgzgulQMUfsZnMyEAhAAB4bG8RCLGU3wAA" + "AABJRU5ErkJggg==") +index.append('RENDER_D_16') +catalog['RENDER_D_16'] = RENDER_D_16 + +#---------------------------------------------------------------------- +RENDER_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AACoSURBVEiJ7ZXBDcIwDEWfEUKMA6JD0CHoEj1y55QpsoSXiATrkAtcShVVjeIieqF9p+TL" + "9rdlRYGZkTGxqps7cBjIj6D+ONVgk9GHxXNakX6C0/lyE5EW2BVyIuCC+qvFoJ/AWJwuprUU" + "h2SCqm5e1iQLQb1Afgc/w2wQ1MunK8t9ssG3LGgHq8ECDNaHNhvb5Byx/QcAz6B+bwlMJ3Cd" + "SYkI4oyN/AFvXnk5eAGTlBwAAAAASUVORK5CYII=") +index.append('RENDER_24') +catalog['RENDER_24'] = RENDER_24 + +#---------------------------------------------------------------------- +RENDER_D_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAg0lEQVR42mNkoDFgxCY4adKk" + "80DKAE34Ql5eniG1LPiPTRxoASMDiQCuAWhoG5AqBmI2Anp+AXEP0LJqUi34SYThMPATaAEH" + "qRb8J0YDsQAWnIPHApgGmDpi+YPHgqEfB6MWjAALRjMaXSygeX3QCqRKiLAEVKN1Ay2oIckC" + "WgGaWwAAEdiLGVc80bIAAAAASUVORK5CYII=") +index.append('RENDER_D_24') +catalog['RENDER_D_24'] = RENDER_D_24 + +#---------------------------------------------------------------------- +RENDER_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAASdAAAEnQB3mYfeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAGNSURBVFiF7Za/ThRRFMZ/36zQgJWtz0CzaBYNVsQsFnS7hclCJCGhJCS+hAXyBuoaG7c0" + "AUmoKGDR3dpeKHgACv7szGdBduMqAzM7hGnmK+c7957fnHNu7oWcpTjj+cLyw/PL8J3Eo389" + "4x4hm52d5o+sAA/ijMuL3hxi1Y4JKAHwOitAEGeEOBYOQOhGP6mGWjA9v/QevAJMpNgjlLQP" + "qv/c+niSFmBQgafVxRnwWsrkACXbs46it2mTw18zEOLHip/JWyXxrFxt1BIlVXRwuP3leAgg" + "qwwVSV+TxPYc1IEW3DCE96XRKmA2jNsA/b8WtCN7AyCQ1g0VANv1K18VxPqdABi3u98/twCm" + "5xevPkpH3e1mC+DJq6UadgWgH1euNrhuxnJvwQCpXG3Ukg5RVtmu9yuTewUKgAKgAMgdoLgL" + "cm9BcRfc2ZMMOJZ0kCQwIjj6D0DSaZbslnY7W5/epF03aMFF6D3g14j5zwL4MMrCoXMx9bIx" + "MV7SC9uTSTcIIIzG1Ol+a/4eBaDQHzSwnCzjZ+iqAAAAAElFTkSuQmCC") +index.append('RENDER_32') +catalog['RENDER_32'] = RENDER_32 + +#---------------------------------------------------------------------- +IMPORT_PICTURES_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAFFSURBVDiNxZIxS4JRFIafcz+1wU9/QtRa4BCYW2NpW5OGlUP/oqk/0BbtSi0RgYsiDX5L" + "RJhjRZsI1RREZVl+3tuQSsqn6dQ7Hc55n/feAwf+WwKwGN9a00IOsMfk3hA2rgq5vALQQnIC" + "GMDGSApAAYiImgDmh8HqBfzt5hRoeY2GBZwATQAMZfu9nhRkZ7wAQ9n+qK+LSAZ4MEanHcdx" + "K8XsHob8yAAD91/apBzHcSuF7LHlby1US4eP3bFqsQ3UfzO+/lV5mvKp/ehqBgDtQrfuPADG" + "PAPT/QFa3yECEDHGRLx2HZQ23PYCZkLN3VojeK51OzQOrJT1OhtsnFXpXOKgoiuZeS16rg8y" + "6qZSyl4Pen2DDYBPo2sBJQfAUqd1ocSNe3k9fwAQWd4MBiwpAH6LdvyyePQyzDtUsUQ6HEuk" + "w6M8328PaIbPBK3lAAAAAElFTkSuQmCC") +index.append('IMPORT_PICTURES_16') +catalog['IMPORT_PICTURES_16'] = IMPORT_PICTURES_16 + +#---------------------------------------------------------------------- +IMPORT_PICTURES_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA/0lEQVR42mNkoBAwUsWASZMm" + "BQKpRUDMQ6S+L0Ack5eXtxFmwAogFU6i5SuABkTCDFgFpEJJNGA10IAwYg1YB8S+QMxKrAFr" + "gNgHiDmAeP+/f//cmJiYCoDsbmIMgGkIArL7////b5Kfn/+8oaGBUUhIaD1QzB+fAU+BGoyA" + "Gl5BxcWBil7CrJw4caIwIyPjOSBTDpcBl4D4JoHAUwdiPXQDmoFUDYmx0AQ0oB5swNSpU5n/" + "/v3rCmTyEqn5MzMz8+7s7Oy/WJMy0EXaQEoLTfga0Mar6GqxGgAMLG5gYG0DMu2gQseB2ANo" + "wCeiDEAzhBWXZrwGQL3CB6JxaQYBACO6bhEIM2UOAAAAAElFTkSuQmCC") +index.append('IMPORT_PICTURES_D_16') +catalog['IMPORT_PICTURES_D_16'] = IMPORT_PICTURES_D_16 + +#---------------------------------------------------------------------- +IMPORT_PICTURES_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAFgSURBVEiJ7ZG/S0JRFMe/52ZT9Qf0C1pqdTDoHwhCmkJoaLBBcHKPttraWhMk/BEI3THq" + "PXNqCEF9RYFNLaHk0pg80XynyTK5r/fMVzj0ne4959zPh3sv8B+HUHcRWNteh+A4AbNDMmsA" + "omUtrQGA+DAJPvIADgBzAOLdjehreJV5leBXMrKCV2beBNAYWkCA0VdiIooYekYSc2xIAeUX" + "Js0VELKfeByWLlKnAFDSM0kmSv5U8MS+1paUsjM+YUZAKAIomFPmbu9Q+82KMehhUEHTEhQy" + "zrIvAFCQ0uy0fRtsWaGKlK3ewfvLTENYsP0PtYA5dnOe+vL2t/njZyN3UleNl3Kpit1/+JQC" + "osRyMJxQ9mzCNvXeG9QGATqkqhJEPZJUiUTUA86IhJwGAsHwDgEHyiZjr6yn9787P+YkqD/e" + "XU8v+psErA4KdyVQSlzCXQu6kpklP4FwVdbcwf8k73FigUuDDyceAAAAAElFTkSuQmCC") +index.append('IMPORT_PICTURES_24') +catalog['IMPORT_PICTURES_24'] = IMPORT_PICTURES_24 + +#---------------------------------------------------------------------- +IMPORT_PICTURES_D_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAABCElEQVR42mNkoDFgHD4WTJo0" + "yRtIzQRiaQrNfALEaXl5edvRLXgMpGSo5PDHQAvk0C34T82gAVrAOLIt+ALESUA8H4i5KbXg" + "LBAbI/FB6iKABqwC6kmAWkK2BbuZmZk9//79uxjIjoSK9QE1FyPpA1mQQI4FD4HYBKjwDVCO" + "E8g+AMR/////75Cfn/8LpmjixIncjIyMp4BMLVIs+AHENkBFZ5HkpYCG/wca/hzdtUA5bSB1" + "Ejk+CFmQAlQwl4EEgB4fA5JMaV5UeAKpWVSwBORQUGG3A8UCWoGBtwAYdOVAqgOHdAMwKBop" + "9gEOSwgaTlIQoVlClOEkWQC1pAFEAw1vIFYPzSMZADaqhhlDHKEVAAAAAElFTkSuQmCC") +index.append('IMPORT_PICTURES_D_24') +catalog['IMPORT_PICTURES_D_24'] = IMPORT_PICTURES_D_24 + +#---------------------------------------------------------------------- +IMPORT_PICTURES_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAASdAAAEnQB3mYfeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAISSURBVFiF7Za/T1NRFMc/570mWlOJ4J/gqA6Kgl2MG1UTBw0DMUCMiYMDg3Hxj9BBNhel" + "Fga7GJQ2VYcmxsQCrVFk0ThYjcb4g9gAJbbvHqciFPr6Wl5rIn6388457/t5756be+G/trtk" + "bXD01PBxg94U5QBg++zlAHPGmJFcKvZ0A0C472JXySq9A/b4bLxOAgsrVnnf3NTEAoBVSZSs" + "Um+rzQEUOneYwLFKvAqgqqFWm2/mZbkVtkP/HMDXvwkwqQGOAN9aCCBfaiTe2DiD2QfRvBEu" + "ANoKgEk1ziEgX/V8CUvPZZLjBYBcIvpQ4bqvAApvtbRzKJuKfbaMOQMs/snK5dmpu6/X1u8u" + "5q8Bz/wCWBJLz2af3PoJMJ2KvVTMIGCA0dnkWLS6IZ1Ol8WxB/AwD3UBVLhU/YXZZOy+iAwU" + "Q8WrtfpmHt3+4GUe6gGMZhPRiU0NEmP35uPxX27NXuYh4JL7IUimOzLYXwfSXcILlO/A3kYB" + "uhSNiYhLiQfV2ZCrSyBifdqak3fZyMcNAKHi+wzCdBv8M7tW8jOVYN3/3X+iPxQMBkdADor4" + "eyNSxRHh1fLy8uh8Or5Yv2O7yPOI95483+FI4IZAh1udQsHW8pXK2eAbAMDh08PdttHHCp01" + "SgoGqy+XvPPc6zsb3uQuEA2bNwVQA6Ip86YBqiDsZs23rJ7IULgnMhRuu7Gf+g23rdCkMz7M" + "KwAAAABJRU5ErkJggg==") +index.append('IMPORT_PICTURES_32') +catalog['IMPORT_PICTURES_32'] = IMPORT_PICTURES_32 + +#---------------------------------------------------------------------- +JOB_QUEUE_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADGSURBVDiNxZG9DcJADIU/k4zBGEQKI4QeSiIKFmAQNgAEZegRG4DEGqwBjwIiHReHnwbc" + "3J393rP9Dv4dVl96xXgBlEDyhnMxsTrtN1OATlD4hAyQyJjUjzQsPM6zmR08pqQ+0A0bpTHI" + "zA6n3XrkCWSDspI0DHMNAUnDXjFWywSNXHMCOF6luSfQMZsJ8qecB/wmmitAbmaVB/b28kzc" + "xiZ65rVPIPWzQVnFOY8cC1y4/2+3rVuEBQITBcuw8JqsxQe4H8UNzexBrvi09KgAAAAASUVO" + "RK5CYII=") +index.append('JOB_QUEUE_16') +catalog['JOB_QUEUE_16'] = JOB_QUEUE_16 + +#---------------------------------------------------------------------- +JOB_QUEUE_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAiklEQVR42mNkoBAwUs2ASZMm" + "zQVS8UDMTEDPXyCen5eXl4puwB8iNMMNARrAgm7AfyjzCRAfx6HREohlQAygAYy4DFgNlAzD" + "phuoZhWQCiVkAFEAnwEngLgPh74iILaguQEUewEjEJEDjxgDsEUjPPrwGUBxQpoFpJKIMASU" + "lOcCDUhHMYBcQLEBADPRSBFbV1sbAAAAAElFTkSuQmCC") +index.append('JOB_QUEUE_D_16') +catalog['JOB_QUEUE_D_16'] = JOB_QUEUE_D_16 + +#---------------------------------------------------------------------- +JOB_QUEUE_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AACFSURBVEiJY2AYBQQAIzLH2D3em4Hp/0xGBgZpMs17wsDAkHZm+6LtMAEmFNuY/s+gwHAG" + "BgYGGQYGhpnIAkxYFFAKZPFZQHXAgk/yzPZFjPjkYcDEM+4/LrmB9QE+lxELRuOAIBjBcUCs" + "70bjgGQLnlDBzMf4LEij0JLHjIxMaRToH4kAAGiVH8B1T57tAAAAAElFTkSuQmCC") +index.append('JOB_QUEUE_24') +catalog['JOB_QUEUE_24'] = JOB_QUEUE_24 + +#---------------------------------------------------------------------- +JOB_QUEUE_D_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAdklEQVR42mNkoDFgHF4WTJo0" + "yRtIzQRiaTLNewLEaXl5edtxWfAYSMlQ6OjHQAvkcFnwnxrBArQAbu7AWoCsEB/Ap29gLaB5" + "ENHcgtE4GHgL8AURPscMHgtoHkS0sIDmxbUnkJpFgSUgB4IqnB1YLaAFGPoWAADtt2YZzccp" + "JAAAAABJRU5ErkJggg==") +index.append('JOB_QUEUE_D_24') +catalog['JOB_QUEUE_D_24'] = JOB_QUEUE_D_24 + +#---------------------------------------------------------------------- +IMAGE_ROTATION_LEFT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAITSURBVDiNjZFPSJNxGMc/z/vu1bmpUyQkIyxoFkklzgIvVgjF1EBEPYjMW3rp1rVDXesQ" + "jIJJO+SlwzQIbcNDtLp4KA/9EYSEQOwgVDpazndz79PFLZNt9Fx/z+fz+z7PI1So7oHQsVye" + "BUWqBH0ljkTeLT5dOdgjlQQFSTbPa4FmYAeY3cZ3ey0RtisKTgVvVTeSigBguO6Rd5ocy/7K" + "njUtQl3Gm+lficWyRjm4gdRzhQmFCXX2wltS93F5/tn3usz6KMqO57f7fskEBRjoO/QU38Y3" + "tJYI2+f6xxqrHdcXceSy+Z8wgN+N3enx98ytxqPpo/4OL0J3MUH7yEhVTdozC3qj3F72Iy96" + "M8ZgukYDKvqomOBEa1cUGC0BbBlKrxr6RpDPil7JWZzP1GYiVs7acAWC44O7tXacdOkfFRoc" + "y/1heX56KdAXGhOVVkfk7UoslgVeuATjrvdXzeZP8U02kDryz/zCKopqdqcl0Be6JMoMsJjS" + "+qlCiyGiSQeurSXC9ja+ISBeFDg8fJ+YOSumUYQLlyi0mC1tFzZAHjedbn+yGo+mPf6eOTd2" + "J+BX9FNLW0dzOXh/R9AVDIVRjtfurg8nk8m9v+fUMyCt5eCiYB94iZBSMzdp5KpPYho/HM3f" + "AUhp/VQpuCg4IHkADAMehc0qk6tLCzPfSt/nkKBQF69PtGM6N1WlF8hZJgOVJH8A8YzipTpp" + "yrkAAAAASUVORK5CYII=") +index.append('IMAGE_ROTATION_LEFT_16') +catalog['IMAGE_ROTATION_LEFT_16'] = IMAGE_ROTATION_LEFT_16 + +#---------------------------------------------------------------------- +IMAGE_ROTATION_LEFT_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABaUlEQVR42o2SPUjDQBiGe0Eq" + "iAri4CAigoqgm+Aq4qRVKdJJB3GpXfIzuDrUxcUhiTi0k9hVnbTQQTq4C4KC4KCLg4MWl4I/" + "JD4pSYhtkvbg4ct3vfc57noiETNM0xymXEISrqGgKMpDcI1ItBmupApDUIcz2EX0FSsg2O3s" + "6Lb7MAjPUIQ+27ZTqqp+i5jwBSy7U2VYd3bVdb1LkqRz+hd6VXQQTjRLDMMYEEI80c+LDsMt" + "Etbm+e73BViTWJ0LWm1zrxVIwywc+wKMJ5StkEANUjAOE7AJN1xilg2XBME0TZmmGCGw+a1X" + "luU6azfoT6HEMbYbfyOTd9Qc3Iac/9ERMNaQzLnhincPnsCgfjCRD7nEHPOFwM7/wp5ghlpl" + "l0keRq1JcgD3UeGGwL3AI8qIZVkZTdN+A5IpGI0KBwVO4Ao+YQfG4B32AkdpCfuCgOQQMtAD" + "b7BA8DXuUYQ95WlKFhbhB1biJH9Z/5/CudBE8gAAAABJRU5ErkJggg==") +index.append('IMAGE_ROTATION_LEFT_D_16') +catalog['IMAGE_ROTATION_LEFT_D_16'] = IMAGE_ROTATION_LEFT_D_16 + +#---------------------------------------------------------------------- +IMAGE_ROTATION_RIGHT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAIGSURBVDiNhZI9aFNRGIaf7yRNTFtJqoNDh4JEEKogGIcuEnEIiQEhEHAxLYjWJYODo10c" + "3HSIoNZFgy5eKBVKo0LtZlGriFgpUhFRB4fa/PTHpLn3c+kN8ZrWdzocvufhPT+CJ7FTZw/h" + "yAVFTgra6PKRnpsq/vDOuRF3EU3mg2GpXBclA3Qr/Az4OLET3BJEk/lgH5VpRVdMQ0a1y+zH" + "Z5ZxmmMAK4RHl0qFeieBAeijckOVWu/GtzOvZorLK7L7vTrNgsKwwnCEykQ0mQ92bHA0NXJY" + "1HneDJoD7ybvlaPJfDBCZQJIeWany4Qz3iZG1DkvaOE/MECqUxMDxG18zwaz2UCEqrUN3JL0" + "UXkcj4/sagkUZ6zeu/a2ezU0Ds6gql5DuYiw2MmgkKh1662W4E3pweSCZTW2rmQAIx/mnxTv" + "tDG/OokGs9lALJU7/dc/2Dp/QoWc35jXJrT23a6FjjjCizZ2ukw4E6EaA71p3N2lUqFeJpwB" + "nopSbDrOsTnL2nCMRr3wUqlQFzSB6KzgibeJUQ4qXGmHhxLn9myazU8+7OP/CLwS0K8giy4c" + "j8f9q6GBCeDzfOn+pY4CVxKW6m0AI76r2M5ep6v+RZqBu0DPRu96esGyGtsK3Aylc/0Nm1mB" + "fcC6iD5a7/l92X25HQVD6Vz/ps0U4FeY8WOPvyw9/Ng+8wffL+Zav9jy/AAAAABJRU5ErkJg" + "gg==") +index.append('IMAGE_ROTATION_RIGHT_16') +catalog['IMAGE_ROTATION_RIGHT_16'] = IMAGE_ROTATION_RIGHT_16 + +#---------------------------------------------------------------------- +IMAGE_ROTATION_RIGHT_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABYUlEQVR42n2STygFQRzHd7ZX" + "CicOiptSDpSDKyUH0VOvlyPKxbvtroMjh+eubZP0XF4OiuSkVw64uSgHB6QkxUH5dxIv7fpM" + "zdMaszP16TezM99P82eFo7Uoivoo8zAKdch7nvfoZDSRCjZRVqEIzfAEI7bwr0CFa/CWJElJ" + "CNFN/wWW1boSoi+bYJ3SGcfxVBAE30q4DxNqnZQXTRLB4n7qMfSw4N0QdmwSKYioz0yULeFM" + "iRRcyFvn7OecfY/+pGNvh1BA8tkQFAjXCFcYD8EO3EMAvRmSKoI5/RmrlGmYZXKb8ZUSvEKb" + "LlCvNa7/B/L8Y1ICZ/AAA3Cq3wMMwppIa3WJ2skM/S39Evlept8qtK2ZdiKPsaSF5ZFuYPif" + "wCCRF3rdCIdhmHNdV87dMl4wClKSDTVcgXa4g01o4RLzvu/XMwUpURflBDrgA3YJL8rwn2e0" + "hA8gB0dQYduX6TU/ZXOiv6ytZKAAAAAASUVORK5CYII=") +index.append('IMAGE_ROTATION_RIGHT_D_16') +catalog['IMAGE_ROTATION_RIGHT_D_16'] = IMAGE_ROTATION_RIGHT_D_16 + +#---------------------------------------------------------------------- +IMAGE_MOVING_LEFT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAECSURBVDiNxZIxSgNRFEXP+xlwBHeglUuQUQubVILTxVaYWLiAlKbRaUSsXICNBCsXYLRK" + "G8GxcgcquoCBVPOvjUwizIyBIJ7q8/479/Phwn9jVcN2+zDMQ+0Kv9QkOx+Mg6qLfFnnoJ5V" + "55eoVby52UEUJymAGauN5pS1MiCKkxRxOqdY4haRAdwiMoCTmPyy48uTGAlOfgRkw8GF4LhG" + "zj1uB3gBPiV/kG2vnyHdlwEAdSEGR8/D67H3vuNxnezh5oM09YUFieD9e2dKFCfp090g3Yy7" + "t5I2BFd1/zJjC7Ff2ZRor3sJ6tXJM7xWNnFlYv08ZNRUZTOTFa3HOR75Y74AfnxbCh9D2xsA" + "AAAASUVORK5CYII=") +index.append('IMAGE_MOVING_LEFT_16') +catalog['IMAGE_MOVING_LEFT_16'] = IMAGE_MOVING_LEFT_16 + +#---------------------------------------------------------------------- +IMAGE_MOVING_LEFT_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAsklEQVR42mNkoBAw0sSASZMm" + "cQApNyBmJ6D/BC4D+oFUAREOeMKIprEhLy+vAUivAnJDSfICSDOQqgcawEiyATDNIDbJBiBr" + "JteAciDdgceAf0DMBGXvh+ImdC/ADUEz4AsQuwLxbCAW+f//vxELC8vLv3//bgXyPdADEWwI" + "mgERQP7KiRMnqjAyMooA2SegakWB1HkglsYXjUZQm3EBMyAOojQhPaYkKf8H4pO0yUykAAC1" + "i1qQz5ZMvwAAAABJRU5ErkJggg==") +index.append('IMAGE_MOVING_LEFT_D_16') +catalog['IMAGE_MOVING_LEFT_D_16'] = IMAGE_MOVING_LEFT_D_16 + +#---------------------------------------------------------------------- +IMAGE_MOVING_LEFT_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAASdAAAEnQB3mYfeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAHSSURBVFiF7Za/a9RwGIefN7mh0h/uVaj4HxROFNylDbh0UKjt0aFQcOmi0M0OLgUnrYtQ" + "IakgGLdypP4BFbHJILR0qO3mJqiId601eR2k1cslMddc75b7bN83b77PM7wkL/TSS5cjrTRf" + "G5u59Et0XoQLRaCqhCq6edBfX84tcHX8zlCIuQMMF4E3RGTFyNsbYl5vKxxA9VamQNmqLP7t" + "1YG2wv9kMFWgbFUWUR6cAbQhiQKdgicKdBLeJNBpeINAN+AnAt2CAxjdhAMYqtTP6nKFXVRn" + "MwUCz1lSWCjIqiXUfoihE/766gqwnCoAUEhCeAFyAziMPbjrV1e3AL5y/p5AkCpwWgkVPqjZ" + "N+d79oYqcydo0ce+ZzvH54/ek8MIuQ18SxVoVULgiyGliWDtWQ0gWHdshUcC72r9B/fj/YFn" + "7wFN89D0JcwpEUWRTG9Wn+//W7w8UF+ISkc3t133Z9JLvue8JjYPif+C/0ko8jB4Y1fjddd1" + "w2Dt5ecs8/g8lNIaA89ZKluVcykKlfL49FQWKEtBkaHjU+6N6Io1M6YaeaeDpuZ77o3I0KO3" + "Cp/aihd51dJSOmpNjpiY84JxsQhXlRDlfX2w9rTIPb300pb8Bkt9tPNSsvOcAAAAAElFTkSu" + "QmCC") +index.append('IMAGE_MOVING_LEFT_32') +catalog['IMAGE_MOVING_LEFT_32'] = IMAGE_MOVING_LEFT_32 + +#---------------------------------------------------------------------- +IMAGE_MOVING_LEFT_D_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABiElEQVR42mNkGGDAOOqAUQeQ" + "onjSpEkKQCofiKUptPcvEJ/+////FKIdALScD0hdB2IpKgbAXFIc4AmktlHRchD4jNcBQEsb" + "8vLyGqDsUCC1isoOwJ0GQJYDqXqgAxjp7gCY5SA23R2AbDndHYBuOV0dgM1yujkAl+V0cQA+" + "y+nlgHIg3UEjB9wG4k4gnoPTAVDDcTqCSAd8A2IuNLGvQGwB1H8FqHcykJ2D0wH4HEGEA5YA" + "8Qwg3gvE7Eji8UC9i6B6QeJHgdgYpwNwOYKAAy4yMjJa5ebmfgPKxwP5C2BGAfXlo5mtDKTO" + "AjE/TgdgcwQeB7wHYhOg/D0kvd1AygZYzdrn5+f/wmJ2CJBajdcB6I7A4YB/QOwHlNuKrG/q" + "1KnMf//+FQSKv2HAAdDTA77KCOwIHA5oAorjzLr4AHp6ILc6fgANBXIBqHEjQtABaI7xAFLb" + "KbAUG/hMapPsGgPl7UFkQHyTDAQmTpwoD8x2oOwlQ6HFoEbpKWBumTq0muWjDhiWDgAAO0PF" + "1wqSFgAAAAAASUVORK5CYII=") +index.append('IMAGE_MOVING_LEFT_D_32') +catalog['IMAGE_MOVING_LEFT_D_32'] = IMAGE_MOVING_LEFT_D_32 + +#---------------------------------------------------------------------- +IMAGE_MOVING_RIGHT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEOSURBVDiNxZC9SgNREIW/ubs2IvgAiq0PECSQBxBSWIiI3VZ5AhFsky5N8BV0bewDJgpC" + "KgO6eYQ0wcJGsBDM396x2GzcbNj1p8mBC8OdOd+ce2HVksKBt8NEi7lDmNHGUO47ncthuucy" + "5VFEtvL3KB/r9gI4TXeMwA/meYptgL2yV18A/Ma8mIXzJOTPgDTE/Q8gAVlKYL8H9AzhKRei" + "fCYBXVHZB8YgN73WdUMdjoG3jAjVoO3XYsCrWnv03L56UOzJOLQVgF7THyi2EiVeNsPsDxS6" + "GOMVyh4Aaw67cT1Tf14JtaAVmWPAi8Ah0cl+L7YJENz61eS9K6FTUicsqqpkmQUzemfzLm/B" + "6vQFM/Vb/jMIvyYAAAAASUVORK5CYII=") +index.append('IMAGE_MOVING_RIGHT_16') +catalog['IMAGE_MOVING_RIGHT_16'] = IMAGE_MOVING_RIGHT_16 + +#---------------------------------------------------------------------- +IMAGE_MOVING_RIGHT_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA0ElEQVR42mNkoBAwUmzApEmT" + "5IC0OQF1P4F4V15e3g9sBjwB0tJEWNYPNKAImwH/iXTtaqABYUD1HUC6ghIDQOo7YYaQawAD" + "zBBKDAAbgm7APyBmgrJLgDgMiM3wGNCAbMBxIK4F4m1AvA6oOBIaxeeAWBiLAQ1AfiPMgBf/" + "//83ys/Pfw7kBwDZu4HsryBVID7IQCBeg2QAWDNyIK4H4pN4/J8CxOehBoA0NyBH42MgLUNE" + "IOJMSLIMkKSML1+AkvJOoAE/MQwgMgpxAooNAADYLXyEpVe9PgAAAABJRU5ErkJggg==") +index.append('IMAGE_MOVING_RIGHT_D_16') +catalog['IMAGE_MOVING_RIGHT_D_16'] = IMAGE_MOVING_RIGHT_D_16 + +#---------------------------------------------------------------------- +IMAGE_MOVING_RIGHT_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAASdAAAEnQB3mYfeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAHaSURBVFiF7Za/axNhGMc/z3vXNoV066SbW9WxBcG/IIugmK2mdCzWWXBKyCK4ZFYo+YE6" + "OFmwF6vgFGh7VwotnRz8QSvYQZBSg2nuXodQSeLd5bikqUO+08vd87yfD8fD8cAoo1xw5Fo6" + "PZ44mVwWLXMiGP1cpjWHrpwWdtZefIksMJvKrACL/YA7JOAwMWbO1FZXjqPUKyA9KDiAwOVG" + "07sZtV4ByUEKAHieO3V2nktlHvcSONdoeBgmce4CvSSGIhAmMTSBIImhCvhJDF2gW8K8CIE2" + "iVhfwBVkHvjWt4SmHibwK6DtkW2VnmvFPODGp5N1quVckMBX5errwF5X02vHqjwB2H5T/oAm" + "3w8c/Ifwt2h1d2u98snU6pbAUauHj7qZWGgdW3FuXMmDvIsL9xUQ9AO7WrQBNqrFzxq5A/xQ" + "ntzefv/0Z0dxNus1XC/6PHTB/xHQIkXbqjxrf+ZYpZoxdnrVflva97tzd71yFGkefODdArsY" + "E/f9ejdXX34Pu7vnPATAofM/cEma9b3Z1L0wVggDJX4vhJxj+cPPBI6BKWAaZDoWHWiHK2X8" + "3YactXI2rE8Br+JCA3Iwbqpa1GKznqwvJU4m9weylOIdaEMKUffBUUb5L/IH3W26DRZa1FkA" + "AAAASUVORK5CYII=") +index.append('IMAGE_MOVING_RIGHT_32') +catalog['IMAGE_MOVING_RIGHT_32'] = IMAGE_MOVING_RIGHT_32 + +#---------------------------------------------------------------------- +IMAGE_MOVING_RIGHT_D_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABnUlEQVR42u2WsUvDQBTGLxUc" + "RNcKTl0VHDuIKDo4OLq4ig5OJhl189y0UxPIJIq7U50E/wJxEAQnJ0s7CBJQoeAQ4vdKW0xy" + "J9ck5Abz4ONeL+/e9zsSemcwzWGUACWA4ziThmEcIK9DExn7dcMwbNq2/aoM4LruJcbdHDfV" + "xYbmTdP8UgWgwukcASg2Lcu6VQUIczan2AbANSXof4r8SCcA9T+TQRQFwGQQRQIIIYoGSEDo" + "AIhA6AIYQegE6EOkAQigHagBzWUE4H8B9KApwfwhmjewbh35HROfHyoAHDUnMoA2tAa1oMVf" + "8y3f97c45+Gg+TE1SgHQN6dEBPANraDgAc9qyO+hKvQC1TH/MSz0PK8SBAH952+MATAylwHs" + "o+B8+APPlzHcQKuYf45vBcd5FaffI4t+DzKAiLkI4AoFiaMZNbOYf5O8Syb4HkQACfM4wBN2" + "soRzvMdSROx7iAMIzeMA79BnGvNBVKCaAIDMuWwRAZDpTAZjUYx1IbnAuJejeQevckH5Spbz" + "pbQDNbH7tuoC/dfyEuDfA/wAnmX8lAqs+aIAAAAASUVORK5CYII=") +index.append('IMAGE_MOVING_RIGHT_D_32') +catalog['IMAGE_MOVING_RIGHT_D_32'] = IMAGE_MOVING_RIGHT_D_32 + +#---------------------------------------------------------------------- +IMAGE_REMOVE_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAFGSURBVDiNvZA/S0JxFIaf8/Oa4VS49hFqUcvdGryJSyCS4nWqdre+QFu4BEVLkEVDo6QR" + "4RqRNERbEA1NJTSFpN57mpQg/FNB7/Zyznl43wP/oahdcBYWnVDfJ5yNSGo9CGCNOo7ZuRkX" + "3XUDPERSq0vS8W8iFHFbAuzJOAnCdj5ukArQAkKIlhrVchHAjAO4rZXrInIGhICm+rpbvdlY" + "gGjC2VbVtIicAkFc/2XvJxbAXDI7HVB/XD3vG1CMWigFREs31cNi2M7HjUrFm5AkcCgAEdvZ" + "F1gbGEG9bOP86KRnY3Zu5rp2/NyvYESmhlVQpPvV9477gL9oGOD15wDhTOANuGq7Ogv6+BPA" + "fburGVWz4veRvrsovxghA3wMA1gAquoB7wHLHIDS9YT55QIKKNo04A5NoMoO8DRgp9qZ9NVH" + "Vfm1PgFPlm4X5nAV2gAAAABJRU5ErkJggg==") +index.append('IMAGE_REMOVE_16') +catalog['IMAGE_REMOVE_16'] = IMAGE_REMOVE_16 + +#---------------------------------------------------------------------- +IMAGE_REMOVE_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABBklEQVR42mNkoBAwEqNo0qRJ" + "cf///9+an5//FspPZ2RkXJybm/uNoAFAxTJA6iYQ3wZiFyCuBOIiIM7My8ubQawLnIDUZiD+" + "DsTCQNwP1FxEtBeghqwCUqFA/AaINYEGvCElDHqhzl4NxN4g7wDDxBkUJmADJk6cKAgMFJAz" + "mbDoZwHiyUC8CORsJO+AwmARI9SGWUAqFY8jooCKlyMHLJD/BO4FJP/hAmFADauxSdDUgNdA" + "LEqqAVuB2AqIbwBDOQAYsMeBbCViDdAEarIAajIFRRNQw1OguAmQfQSIYwkZsAJIKQDxIyxq" + "QC4C6s9bh88AGyCVw4A9HXwA4jKgAR9wGkAJAABWGnIRb3GQzgAAAABJRU5ErkJggg==") +index.append('IMAGE_REMOVE_D_16') +catalog['IMAGE_REMOVE_D_16'] = IMAGE_REMOVE_D_16 + +#---------------------------------------------------------------------- +IMAGE_REMOVE_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAASdAAAEnQB3mYfeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAKxSURBVFiF7ZbPS1RRFMc/5z0dWrQMgimChigyomycxiCEFtKM9ItI0UwLyUKiRes2bxH9" + "BUY/EEGtjCSCKNMoJSrMZhTsh2iKuxSDaFOL5sc7LZwZnjpCMz6LwLM759x7v5973rn3Plg1" + "Fy0Yrt24ZNKyjOLyBu/CsOGWeEm4viGJOeEPnzqWJS2BwalmsyA5HAzXFs1LuCIeqqtG5A5z" + "G4qhUhntaXsEgGUZgbdTN1U4mxo+XWiyd+Bx+xdwqQKmJ9GvyFjK9SDalaqEBAanmh3iAD0D" + "Jb6ZtONKBQCKyxu8ZkGiD9iWCsUE+hUOZsSUlkip7zyWZbsOABA8UrM+Eff0CVqUJd0aDfoa" + "neKuAwDsO1S/IZ5kDFjrEOmNBH0VC8XBxVOQ1kokuewUB1A44B+cPJJtgumatGUZgTWbbqlw" + "3hH9AXgAU5Dj3i27309Pjow7p7lVgWzd3qq2vVWR0ZTvPB3uAgRC9U0KTRkapSUa9DUO9d6e" + "sRNmOZDetUcwOp035rwmDFScrkL1KCKFuQDY2OOGGrsUPUyWbnecju2KXBh62nZ9EYC/4sxO" + "UXtkIdSfmopeMWyZiZT6bmTr9uLyBq9pxsuiPR33nPGMWEm4/gTQlY84gIh0RbrbqnKdl+kB" + "VXX9TsgJ4F/ZKsD/ByAir4DpvwQgs05P4YtREKsU9CSQXFEAhQkjpjsQnqdCcZTqwUeds5Gn" + "HS9VxVpJgJ9i6PF3L9q//ZJEFfAZ0UtDPe2v0wOGSjdfBZ6tCIAK56JPOj4CfHhy97tZGC+L" + "dndcmzfIsuxYUutYZj8ULA7JMLYd94fqKtORRAz8obql1ngAXFw+gGh87mnQPSJyP+eVVOP5" + "AGQ+gU3hG4Gv+SwC2AoP85k47wHyH65ZR8Lcj+b2P2CoMRrpbfuUD8Cq/QavlPR7ZeZ/5gAA" + "AABJRU5ErkJggg==") +index.append('IMAGE_REMOVE_32') +catalog['IMAGE_REMOVE_32'] = IMAGE_REMOVE_32 + +#---------------------------------------------------------------------- +IMAGE_REMOVE_D_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACDElEQVR42u2Xz0sCQRTHd5Nu" + "XZLSsG4R/YDoEERBdYgoCKKItMJbFGFL/gUehDp0VZAKwlsSGfTjEkE/DnXoVAQmRdd+4MVT" + "QRRm38lRntt6WJ0tEge+vN19s/M+83wzO8rSHze5qAD8fn+d2+1+0PIFAoGyRCJRA/+TIQAI" + "Ps3iQFMIskt9Xq9XNpvNzDcG9cEfFQqA4JMwG1AZ9A7ZEWSfzHwNlzO8O8tAB/yPIgGsMCdQ" + "C3/EICbi8fgen7mLdA+aTKZZRVE+hQFwCBuHaCQQp9Ag6baO4HPp4EIBcmSCtqyZGwLAIWph" + "bqEK8vgQwYfUwYUDkGp3qVzfNaFeHUIBNKqdtReSiazVIRQgx8yDyWTSI8vykaRaHTQTopbh" + "vJTahNItU+0aq+MNakjvmLJqIAfMCFSuk+EOaoOGJY1qJ6ujGVIQfOVHBtCpFea6gKwsQc8I" + "vqpV7TwTvQi+SZ9TgHGYcAG/RBiDO/S+RAHsMFslgBLAfwA4g+oh228AxCAruWenmHaoCTqG" + "TEYC3GMv78JezjaOfuhDSp3nznl/D8yiUQCvUCcGjPh8vkpAXLAuuM/s9/zrd4DLASMAnBgs" + "RHxW3MfULwPOArgrKVUPwgAuoWUdY/RACyIARmF29A5AWggAzkIAqmEikCWP4Ozrxw4a23kD" + "cIgqmG5J/3kgiuA3eYAX2Z/TfNoXuRn2Ich80EsAAAAASUVORK5CYII=") +index.append('IMAGE_REMOVE_D_32') +catalog['IMAGE_REMOVE_D_32'] = IMAGE_REMOVE_D_32 + +#---------------------------------------------------------------------- +MUSIC_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAErSURBVDiNxY8xS0JhGIWf81lpBUa/IYggCOLi1OIUCYkROF4QWmpp6pc0Cg3aFg0RmfQH" + "gkwbmmqJxsYsgyC8b0NZ16uWm2f6Du/5nvc9MGppmNDSqj897rTsHJ4FeMhW6tXDOYCxaDif" + "z8ceX6YWzOFJgWcmD0gBE2adlb97ewAPr4lNOTsCMPsJvmNcItWExQ12BgJC3UoYtXZMV3qK" + "3zYaxQ8Ab83PS/ofcF0tFwbNwnLDhP7SwAvCSqcLiVYiKCJywFtfQCrjZ00uBzaLdQNak+1d" + "kP9tkz2AVMbPGjrFIj87kpuPzFqdhwP42tyldtgE2EnYm3TcBSCw+wigHjY35+UzC7SOdGDY" + "XtOS210VnjWzP0tz0WADuFOgrWiLxkWpAlT6dxylPgETllziqjxp4wAAAABJRU5ErkJggg==") +index.append('MUSIC_16') +catalog['MUSIC_16'] = MUSIC_16 + +#---------------------------------------------------------------------- +PLAY_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAC0SURBVDiNY2AYnsDUK97OwcGBhRi1TDjEc75wyp019oo1J9cABgYGBj3G/4zHTDxjZ1r7" + "JfGSYwBUnjHtx+8/1409YwLIMYCBgYGBgZGBQZqRgWm9qVf8Kj23WDGSDYCB////q7OwMsmS" + "Y8APBkaGxu88303PbV14FlmCYFQxMjIe/veHMe3srgU3sMnjM+ADIwNj+eltC2czMDD8x6UI" + "qwH/Gf5tZmb9k3ty0/KXhFw4DAAAy24ur2eu4uQAAAAASUVORK5CYII=") +index.append('PLAY_16') +catalog['PLAY_16'] = PLAY_16 + +#---------------------------------------------------------------------- +PLAY_24 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAENSURBVEiJ7ZOxSsNQFIa/E7rY3VVw8AG0zeaQzabg6Giqg63gKKKPIL6Cglid7G7ara41" + "qIgO7eTu4GChGWyOgzgIprkpzSDkW+//3+8eOBdycspV76S0Xi9O27cSE8qBjMPnlcrmWjaC" + "b8miJdK2q7XrZXd7fvaCH4/qRoFx33ZrdUBMOomhsutpjK5riTR6N83BpH6qCX4jTqQ8llzv" + "0HGcQgYCAOYEjj+KC4Fd2bKzEAAgypKiq3+dxY6Wgls0agTtq/5MBQLvIEd3/sUpELMIUwpE" + "pPWp1t6Df/6WlE0lUHhV1d17v9kx7ZgKItCzcBTuv3RbwzSPMhE8EbETdC57aS42ZtInyvkf" + "fAFjgU5Rd7miLwAAAABJRU5ErkJggg==") +index.append('PLAY_24') +catalog['PLAY_24'] = PLAY_24 + +#---------------------------------------------------------------------- +PLAY_PAUSE_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADMSURBVDiN3Y47DgFhFIXP/b06pc4mjAmtzvzqqcg/RGIBNkAsRDGhGbVHpyXsQqfUkXBU" + "kzCIoeNU99zHdw/wP7JqpvKsX3CaZVt7gaVNFwBs7QW29oJwrsJCLljYVdOIAoTnPElXQcoA" + "QNIl6T4AAKQp8Iva9D9JriJeQPSKjhlaVif1DSBUS3LHacmpZ78FxNYrwJD7TG09Hx/eAZIR" + "TwgG25nfj5vgFnASor2Z+6O4x3cAKlS3U38ZXaAkdko4uYArABCRyScPfkBX/1A7r5UA2DMA" + "AAAASUVORK5CYII=") +index.append('PLAY_PAUSE_16') +catalog['PLAY_PAUSE_16'] = PLAY_PAUSE_16 + +#---------------------------------------------------------------------- +PLAY_PAUSE_d_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAfklEQVR42mNkoBAwDh4DJk2a" + "5JiXl7cfXQFQ3AJIFQHxCaB8H5C/CiQOZIehG/ATSCUDJZagGRAKpECaVoM0Afn/oQYwohsA" + "kgDhJqBkA7kGwMD8////p+fn5/8m1wAQ2A3EIUDsPiAGzAN6IYMcL1AUiBRHI2UJiVww8AYA" + "ADGljhFAyvuxAAAAAElFTkSuQmCC") +index.append('PLAY_PAUSE_d_16') +catalog['PLAY_PAUSE_d_16'] = PLAY_PAUSE_d_16 + +#---------------------------------------------------------------------- +ARROW_UP_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAB6SURBVDiNY2AY1EA7NJRNOzSUDZ8aJnyaOb9wrub8zLHRwSGBA5c6RnyaGRgY/BgYGBgY" + "/v/fwfODOfDAgQU/CBqAoRkGcBjCSJRmPIYwEq0ZhyFYw4CBgYHBxDPuPzL/zPZFWNXijAVi" + "wTAwgAWXxP///8MoNZw+AAB5qTZGwoz1IgAAAABJRU5ErkJggg==") +index.append('ARROW_UP_16') +catalog['ARROW_UP_16'] = ARROW_UP_16 + +#---------------------------------------------------------------------- +ARROW_UP_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAZUlEQVR42mNkoBAw0tSAiRMn" + "soHo/Pz8XyQbANLMyMi4GsgEGRKYl5f3g2gDkDT7QYV24DKEkQjNDPgMYSRSM05DGEnQjNUQ" + "nIE4adKk/8h8oAasakcNwG9AKJoBq0kygFhAsQEAvBQ5EU8K8roAAAAASUVORK5CYII=") +index.append('ARROW_UP_D_16') +catalog['ARROW_UP_D_16'] = ARROW_UP_D_16 + +#---------------------------------------------------------------------- +ARROW_DOWN_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AACISURBVDiNY2AYaMCIS8LYIzYUmX92x+LV2NSx4DSZkXEVMZYx4XEdUWAYGAAPGO3QUDbO" + "z5yrGBgZ/Ano2c7znSnowIEFPxgYGBiYYaKvr137K2ioto71J6seAyODBjGaUQwgwhAMzRgG" + "4DEEq2YGBjwpESlM2HBpJgi0Q0PZtEND2UjWSFcAAA/vNvugThMHAAAAAElFTkSuQmCC") +index.append('ARROW_DOWN_16') +catalog['ARROW_DOWN_16'] = ARROW_DOWN_16 + +#---------------------------------------------------------------------- +ARROW_DOWN_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAaUlEQVR42mNkoBAw0syASZMm" + "hSLz8/LyVpNqwH80AxhHDSBgwMSJE9kYGRlXAZn+DPjBdiAOAhr4A8MFRBiCohmrF/AYgqEZ" + "ZxhgMQSrZryBiGQIGy7NeA2AGQKi8/Pzf+FSQ7vMRCwAAFJWORHb+TzcAAAAAElFTkSuQmCC") +index.append('ARROW_DOWN_D_16') +catalog['ARROW_DOWN_D_16'] = ARROW_DOWN_D_16 + +#---------------------------------------------------------------------- +REMOVE_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEHSURBVDiNxZCxTgJBFEXP3R1JNGG/QPwFC6OJDYU2W9FZqpWtifZW9P4AaKEFiZQ0/IGJ" + "yRb6CcZGExpKdOZZIGSzLAIVt5r35sx99w2sW8oXB+nZoce2BQnSLZD8XQ0xuzYYxujjpf/w" + "PHnj8gYW6UrGScmgBKktwKQuMDVQkdxLT8sMpsr6j9187YqApKf/DIpDowXwQs0x0GcIoQ68" + "mXgNIdQFX2XkzApjWTVWXAludAwQh8quYdUVErBlsmbW6wyyXmdgsiawuUIC3s19N/bT8yOA" + "4EYN/WxkwM6yBrXIuxuTXQBE3rUMassm8EBspstJI3f2RXjmDwzuy8Bxz+7mJF6jfgEfLE/B" + "MgWxkwAAAABJRU5ErkJggg==") +index.append('REMOVE_16') +catalog['REMOVE_16'] = REMOVE_16 + +#---------------------------------------------------------------------- +REMOVE_D_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAw0lEQVR42mNkoBAwUtWASZMm" + "WQIpGSDmA+I+KA0Cn4C4CEo/ycvLO47LgFVAKpSApauBBoTh9ALQELwGADWvxhsGQAP+EzCA" + "kS4GvPz//38oIyPjFCAbyPyfC2SvAbLFiDXgGxD7AfFFqLA+EG8GYk5SvHD83bt31iCGkJDQ" + "USBlSYoXHgGxMdRmBqhLzgKxHLEGgPBkIE6FCs8G4lyQemIM+AOkmHFEwl+gASyEDJgFpJKw" + "GPIXiOcCDUjHawCpgGIDAPaBUBFQre+bAAAAAElFTkSuQmCC") +index.append('REMOVE_D_16') +catalog['REMOVE_D_16'] = REMOVE_D_16 + +#---------------------------------------------------------------------- +VIDEO_FORMAT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AACSSURBVDiNY2AYBYwwholX3D2G/wyKeNT+YvrP4HBqx6LjZh5xlqd2LDrOwMDAwASXxq+Z" + "gYGBge0vw38ZM484y3+MDDtggkz4dGA6l9ECqpkPJsZCigEMjAxF6EIkuQAbINELDJ2MDAzv" + "yTbg3///Z/8yMboiG4IwgJHhPgH9v5gZGJ+c27rwLON/Bm9SLB7uAAAucyMEvcgZegAAAABJ" + "RU5ErkJggg==") +index.append('VIDEO_FORMAT_16') +catalog['VIDEO_FORMAT_16'] = VIDEO_FORMAT_16 + +#---------------------------------------------------------------------- +VIDEO_FORMAT_32 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAASdAAAEnQB3mYfeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AADhSURBVFiF7ZI9CsJAEEbfupbiaQS9gSZgLyjowcRCCdY2Ri1tRLDyKP40wjpWYoiRFZIl" + "oPvKYWa+x86Cx+P5d1S60AiHY0RGgM6x94JicFhOF8liM+jX93F0StYqb6P5wwFqiOqlww16" + "lW6sZgznDQdAqdeeZtCv39FroJXue3+BgnmGS0a4cwFbOGSfoBhEnjf/GO5UQKD9TZ/zP+AF" + "yhSIgW1pAkqpy81IaJNweoLjZna1STj/AzaJLAFTRLDIa89xM7tqTBfYWQUEJgVInBHmycI+" + "jk4a08m51+Px/CAP3CJJ5X55UlcAAAAASUVORK5CYII=") +index.append('VIDEO_FORMAT_32') +catalog['VIDEO_FORMAT_32'] = VIDEO_FORMAT_32 + +#---------------------------------------------------------------------- +ALERT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAE6SURBVDiNtZC9SgNBFIW/2WxMtjEIAUsJQkRCLIxE7GKRRQykcgWFqI0oVuoTaK9E8RXE" + "wl4tBFsbu3RBwQcQVNYmqHMtsob8TFYscstzzznz3YFBTt6tpPJuJRXmscOW2lZHiAiw1M+j" + "+i1ypbV5pblrurT7cH1+a/JZJtHzvIjSnLQEsaqFQsFIayx49p0tYKpNyvjO2KbJ23NCtrQ6" + "EtN2HUgC94E8B7w0rK907eriNZQgpu3DIIyIVEWkGqyScYkchJ4wXapMAtsm1Gah2sktbmTb" + "tY6PsbR1ChJt3afUXleHrUSOAbeHYGZhvQxS7Pd6G0ex6Q0eAch43pDz4dSAdCeyLAckl10t" + "T28kMo83Zw0LIO47+93h36AhDDCe4H0XQM2WV0a/P6N1YPhv/I7xReuJf2YGMD+zk1NTit/4" + "+AAAAABJRU5ErkJggg==") +index.append('ALERT_16') +catalog['ALERT_16'] = ALERT_16 + +#---------------------------------------------------------------------- +PROPERTIES_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAGASURBVDiNpZO9SwNBEMV/szmxCNjY2GmRwj4X1BBBG7lYqJhSPIOdhZXgf2FlYSGInFgq" + "Vl46BRG/zl6wSWljI1gELjsWnmeiFxGdandn3rx5jx34Z0ivRLHqrxuRSQCrenEfBttZdU7v" + "zrqsSglAhGEgs0E6wbhXH4mlvYbqnkVGjMgRkE/Sr1a1ZtAmIquO5nauG/vNrgliY7dQWURk" + "03wnyhuRxgdfbGwBqKUTuF59CrFnX0AWuErOZb76pWY6auyfGwC1PCk8doKtMB+FQSUKgwoq" + "C4CmWHhUy1OXB2PVpYE2uedE1mUUBpVOQtfzLxHKQJyjPXgTHr4ApHJb/X0Z0rOjs9YAFGfq" + "o07L3vFpatn1VuZS9ll/HmEiuTpOy94VZ+qjfADEMAQUOkgE0RPX868S0RN0m1hIMA/pozvr" + "H6Es/kqDcBydBrV0AgDHmo1Y7ANqg58/kvEda3Y/e/UIt7p8C1JKqm6j02Asq67nLihyYESa" + "8L5Mv5L2l3gDAC2ETODWK80AAAAASUVORK5CYII=") +index.append('PROPERTIES_16') +catalog['PROPERTIES_16'] = PROPERTIES_16 + +#---------------------------------------------------------------------- +EXIT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAEZSURBVDiNxZK/SsNgFMV/1/gIHX0Fp6SYR0gCnUShSJJBnAtdnISKi4OLD1DFiBR0LDR5" + "hEqTzUdwkj6Ag+F2kITYJK2Tnun+Pfccvg/+G1IElhuMgRAwtuzkotwvkugMYLfSCFFuFZ1v" + "vii2CgOgRmAoOs+Sx5eicOCe7L3GT+9VAtPxEWRY5Dttl8xev5NjvFleMNqkqCRI40iq17Pp" + "ZAkMUS66bnDdRlBa6Hrhc9OAqn4onFte8JnOopqaVgu/RalgMXs4Xm9ajn+KyCHKKI2jyyaC" + "UoHlBmo6/lGRm71+B5EbhKs0aV7+QbCObDpZGuT7Tb4bLQC5ILbp+GXhS7/fvQpBbCCvESjc" + "iTCofpIW5KDjLTN/iBX3XlWagRr2qAAAAABJRU5ErkJggg==") +index.append('EXIT_16') +catalog['EXIT_16'] = EXIT_16 + +#---------------------------------------------------------------------- +HELP_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAGHSURBVDiNrZIxa1RREIW/M/cZQYP5AbZGNIqiIW5lIaRZBGMpLpYGIgEL/0fQQtMIissq" + "qdTAotglWGjhFkngKfoTrGKxW+y9Y5F969vdFxs93Zw5c+6Zy8A/QlVkrd6YS8qWEpwGIPk3" + "D/62027mfzWYX1ye0VRvHedWhbk7/jIj3fv8rrU/YTC/uDyjI72PwPkBteuupwCS3y3xO4F4" + "tTCxodNUb708PN21K2baDh63pru2AOwNeheiwuORBLV6Yy4S9oraXfeDx61k1jn4Ai4F45o7" + "D4t1kvm5TruZZwCRcLO8juSPkobh0sGEDPkfSdQSkBeqUxwCoRWP2U+XPxjhxSxAdtjgABvH" + "u3rx61j/k5yTVYIiwY/K193f7x/tL8i5ON5z5/vQIJm/BnxCJD0zs+0K70SyN0ODTruZC15N" + "yJw1nLUKvvXlw/Ov5RUw4gqwW7XKGHaC4mpRjJxrrd440ceeCN0e7wEJpxUUVytPuYzL1++c" + "VdINpDMA8pR7DJtF7P+K37sKku4pcjReAAAAAElFTkSuQmCC") +index.append('HELP_16') +catalog['HELP_16'] = HELP_16 + +#---------------------------------------------------------------------- +ABOUT_16 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlw" + "SFlzAAAJOgAACToB8GSSSgAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoA" + "AAFHSURBVDiNpZK/S8JBGMY/7/fM1T+g2lLKkiAHEWprkSCbIpBWQehvcQuHlsIkaCkCiZqD" + "ctDBAqPcW5qcXO7eFn93GuEDt9zd83mf972DOSW+zVQmF3cSyjqIAQTwYcXdNqrl1kxAcjcf" + "kXC3hHLkgavAVYAt1O4rnV+A5G4+IgvdJ2Djj9SvBrvdhwQDUrhb8pife2tUCSvmdCxBKpOL" + "W8zbZGxVPQQQkevJdlyg641quRUCsJgDT88+4/DIShZo9VtY8V5TiihFP4EoQGhKhZ5fXwDE" + "99oiCsMhtmeBvHCn7QHABXoD6D/8DhfcAhiAr8/m92J0MwYkxlPKkoikgeXx8lzWHy7OYGQG" + "AbZgMYkJSNpTvWnEngx9PdXuKx2D3Va0MqUdh1I22B3vVx7V1t7xmjjZR2QVQNS11Jq7+uP5" + "u+/+XPoBXM1s1TkhatwAAAAASUVORK5CYII=") +index.append('ABOUT_16') +catalog['ABOUT_16'] = ABOUT_16 + +#---------------------------------------------------------------------- +FILMSTRIP = PyEmbeddedImage( + "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") +index.append('FILMSTRIP') +catalog['FILMSTRIP'] = FILMSTRIP + +#---------------------------------------------------------------------- +DIA = PyEmbeddedImage( + "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") +index.append('DIA') +catalog['DIA'] = DIA + +#---------------------------------------------------------------------- +DIA_S = PyEmbeddedImage( + "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") +index.append('DIA_S') +catalog['DIA_S'] = DIA_S + diff -Nru photofilmstrip-3.2.0/po/de.po photofilmstrip-3.3.1/po/de.po --- photofilmstrip-3.2.0/po/de.po 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/po/de.po 2017-12-03 22:12:24.000000000 +0000 @@ -5,8 +5,8 @@ msgid "" msgstr "" "Project-Id-Version: PhotoFilmStrip\n" -"POT-Creation-Date: 2014-10-20 22:41+CEST\n" -"PO-Revision-Date: 2014-10-20 22:48+0100\n" +"POT-Creation-Date: 2017-11-24 00:01+CET\n" +"PO-Revision-Date: 2017-11-24 00:12+0100\n" "Last-Translator: Jens Göpfert \n" "Language-Team: Jens \n" "Language: de_DE\n" @@ -15,10 +15,10 @@ "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 1.5\n" "X-Poedit-SourceCharset: utf-8\n" -"X-Generator: Poedit 1.5.4\n" +"X-Generator: Poedit 2.0.4\n" #: photofilmstrip/action/ActionAutoPath.py:37 -#: photofilmstrip/gui/PnlPfsProject.py:108 +#: photofilmstrip/gui/PnlPfsProject.py:109 msgid "Random motion" msgstr "Zufällige Bewegung" @@ -27,12 +27,12 @@ msgstr "Auswahl zentrieren" #: photofilmstrip/action/ActionI18N.py:38 -#: photofilmstrip/gui/ActionManager.py:249 +#: photofilmstrip/gui/ActionManager.py:283 msgid "Language" msgstr "Sprache" #: photofilmstrip/action/ActionOpenFolder.py:34 -#: photofilmstrip/gui/PnlRenderJobVisual.py:31 +#: photofilmstrip/gui/PnlRenderJobVisual.py:27 msgid "Open folder" msgstr "Ordner öffnen" @@ -41,43 +41,43 @@ msgid "Play video" msgstr "Video abspielen" -#: photofilmstrip/action/ActionRender.py:50 +#: photofilmstrip/action/ActionRender.py:53 msgid "Start" msgstr "Start" -#: photofilmstrip/cli/Main.py:62 photofilmstrip/cli/Main.py:209 +#: photofilmstrip/cli/Main.py:59 photofilmstrip/cli/Main.py:212 msgid "all done" msgstr "Fertig" -#: photofilmstrip/cli/Main.py:80 +#: photofilmstrip/cli/Main.py:77 msgid "processing project" msgstr "Verarbeite Projekt" -#: photofilmstrip/cli/Main.py:81 +#: photofilmstrip/cli/Main.py:78 msgid "using renderer" msgstr "Verwende Renderer" -#: photofilmstrip/cli/Main.py:82 +#: photofilmstrip/cli/Main.py:79 msgid "output format" msgstr "Ausgabeformat" -#: photofilmstrip/cli/Main.py:83 +#: photofilmstrip/cli/Main.py:80 msgid "framerate" msgstr "Bildrate" -#: photofilmstrip/cli/Main.py:109 +#: photofilmstrip/cli/Main.py:106 msgid "specifies the project file" msgstr "Angabe der Projektdatei" -#: photofilmstrip/cli/Main.py:110 +#: photofilmstrip/cli/Main.py:107 msgid "The path where to save the output files. Use - for stdout." msgstr "Pfad, in dem die Ausgabe gespeichert wird. Verwende - für stdout." -#: photofilmstrip/cli/Main.py:114 +#: photofilmstrip/cli/Main.py:111 msgid "enable draft mode" msgstr "Entwurfsmodus aktivieren" -#: photofilmstrip/cli/Main.py:114 photofilmstrip/gui/DlgRender.py:200 +#: photofilmstrip/cli/Main.py:111 photofilmstrip/gui/DlgRender.py:200 msgid "" "Activate this option to generate a preview of your PhotoFilmStrip. The " "rendering process will speed up dramatically, but results in lower quality." @@ -85,66 +85,71 @@ "Aktivieren Sie diese Option, um eine Vorschau zu erstellen. Die Erstellung " "geht zu Lasten der Bildqualität wesentlich schneller." -#: photofilmstrip/cli/Main.py:123 +#: photofilmstrip/cli/Main.py:124 msgid "project file does not exist: %s" msgstr "Projektdatei nicht vorhanden: %s" -#: photofilmstrip/cli/Main.py:127 +#: photofilmstrip/cli/Main.py:128 msgid "no project file specified!" msgstr "Keine Projektdatei angegeben!" -#: photofilmstrip/cli/Main.py:133 -msgid "invalid profile specified: %s" -msgstr "Ungültiges Profil: %s" - -#: photofilmstrip/cli/Main.py:144 +#: photofilmstrip/cli/Main.py:138 msgid "invalid videonorm specified: %s" msgstr "Videonorm ungültig: %s" -#: photofilmstrip/cli/Main.py:150 +#: photofilmstrip/cli/Main.py:144 msgid "invalid format specified: %s" msgstr "Ungültiges Format: %s" -#: photofilmstrip/cli/Main.py:157 +#: photofilmstrip/cli/Main.py:153 +msgid "invalid profile specified: %s" +msgstr "Ungültiges Profil: %s" + +#: photofilmstrip/cli/Main.py:160 msgid "cannot load photofilmstrip" msgstr "PhotoFilmStrip kann nicht geladen werden" -#: photofilmstrip/cli/Main.py:171 +#: photofilmstrip/cli/Main.py:174 msgid "cannot create output path: %s" msgstr "Ausgabe-Verzeichnis kann nicht erstellt werden: %s" -#: photofilmstrip/cli/Main.py:182 photofilmstrip/gui/DlgProjectProps.py:389 -#: photofilmstrip/gui/DlgProjectProps.py:392 -#: photofilmstrip/gui/DlgProjectProps.py:432 -#: photofilmstrip/gui/DlgRender.py:218 +#: photofilmstrip/cli/Main.py:185 photofilmstrip/gui/DlgProjectProps.py:430 +#: photofilmstrip/gui/DlgProjectProps.py:452 +#: photofilmstrip/gui/DlgRender.py:217 msgid "Audio file '%s' does not exist!" msgstr "Audio-Datei '%s' nicht vorhanden!" -#: photofilmstrip/cli/Main.py:203 +#: photofilmstrip/cli/Main.py:206 msgid "...aborted!" msgstr "...abgebrochen!" -#: photofilmstrip/core/BaseRenderer.py:64 +#: photofilmstrip/core/BaseRenderer.py:66 msgid "Unknown property: %s" msgstr "Unbekannte Eigenschaft: %s" -#: photofilmstrip/core/BaseRenderer.py:72 +#: photofilmstrip/core/BaseRenderer.py:74 msgid "" msgstr "" +#: photofilmstrip/core/BaseRenderer.py:89 +msgid "no" +msgstr "nein" + #: photofilmstrip/core/ProjectFile.py:225 msgid "Saving '%s' ..." msgstr "Speicher '%s' ..." -#: photofilmstrip/core/ProjectFile.py:276 +#: photofilmstrip/core/ProjectFile.py:279 msgid "Loading '%s' ..." msgstr "Lade '%s' ..." -#: photofilmstrip/core/RenderEngine.py:139 +#: photofilmstrip/core/RenderEngine.py:130 +#: photofilmstrip/core/RenderEngine.py:218 msgid "processing transition %d/%d" msgstr "Berechne Bildübergang %d/%d" -#: photofilmstrip/core/RenderEngine.py:150 +#: photofilmstrip/core/RenderEngine.py:141 +#: photofilmstrip/core/RenderEngine.py:226 msgid "processing image %d/%d" msgstr "Verarbeite Bild %d/%d" @@ -152,92 +157,67 @@ msgid "Preview" msgstr "Vorschau" -#: photofilmstrip/core/renderer/GStreamerRenderer.py:66 -msgid "GStreamer (python-gst0.10) required!" -msgstr "GStreamer (python-gst0.10) nicht gefunden!" - -#: photofilmstrip/core/renderer/GStreamerRenderer.py:105 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:149 -#: photofilmstrip/core/renderer/MEncoderRenderer.py:132 -#: photofilmstrip/core/renderer/MEncoderRenderer.py:142 -msgid "no" -msgstr "nein" +#: photofilmstrip/core/renderer/GStreamerRenderer.py:63 +msgid "GStreamer (python-gst-1.0) required!" +msgstr "GStreamer (python-gst-1.0) nicht gefunden!" -#: photofilmstrip/core/renderer/GStreamerRenderer.py:225 -#: photofilmstrip/core/renderer/MEncoderRenderer.py:170 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:301 msgid "Bitrate must be a number!" msgstr "Bitrate muss eine Zahl sein!" -#: photofilmstrip/core/renderer/GStreamerRenderer.py:299 -msgid "MP3-Codec (gstreamer0.10-plugins-ugly-multiverse) required!" -msgstr "MP3-Codec (gstreamer0.10-plugins-ugly-multiverse) nicht gefunden!" - -#: photofilmstrip/core/renderer/GStreamerRenderer.py:303 -msgid "x264-Codec (gstreamer0.10-plugins-ugly-multiverse) required!" -msgstr "x264-Codec (gstreamer0.10-plugins-ugly-multiverse) nicht gefunden!" - -#: photofilmstrip/core/renderer/GStreamerRenderer.py:307 -msgid "MKV-Muxer (gstreamer0.10-plugins-good) required!" -msgstr "MKV-Muxer (gstreamer0.10-plugins-good) nicht gefunden!" - -#: photofilmstrip/core/renderer/GStreamerRenderer.py:340 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:379 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:419 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:468 -msgid "Theora-Codec (gstreamer0.10-plugins) required!" -msgstr "Theora-Codec (gstreamer0.10-plugins) nicht gefunden!" - -#: photofilmstrip/core/renderer/GStreamerRenderer.py:344 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:383 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:423 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:472 -msgid "Vorbis-Codec (gstreamer0.10-plugins) required!" -msgstr "Vorbis-Codec (gstreamer0.10-plugins) nicht gefunden!" - -#: photofilmstrip/core/renderer/GStreamerRenderer.py:348 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:387 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:427 -#: photofilmstrip/core/renderer/GStreamerRenderer.py:476 -msgid "OGV-Muxer (gstreamer0.10-plugins) required!" -msgstr "OGV-Muxer (gstreamer0.10-plugins) nicht gefunden!" - -#: photofilmstrip/core/renderer/MEncoderRenderer.py:79 -msgid "mencoder (mencoder) required!" -msgstr "mencoder (mencoder) nicht gefunden!" - -#: photofilmstrip/core/renderer/MEncoderRenderer.py:198 -msgid "MPEG format supports only VCD, SVCD and DVD profile!" -msgstr "MPEG-Format unterstützt nur die Profile VCD, SVCD und DVD!" - -#: photofilmstrip/core/renderer/MEncoderRenderer.py:270 -msgid "MPEG4-XVid/AC3 (AVI)" -msgstr "MPEG4-XVid/AC3 (AVI)" - -#: photofilmstrip/core/renderer/MEncoderRenderer.py:315 -msgid "mencoder with MP3 support (mp3lame) required!" -msgstr "mencoder mit MP3-Unterstützung (mp3lame) erforderlich!" - -#: photofilmstrip/core/renderer/MEncoderRenderer.py:325 -msgid "MPEG4-XVid/MP3 (AVI)" -msgstr "MPEG4-XVid/MP3 (AVI)" - -#: photofilmstrip/core/renderer/MEncoderRenderer.py:358 -msgid "Flash-Video (FLV)" -msgstr "Flash-Video (FLV)" - -#: photofilmstrip/core/renderer/MEncoderRenderer.py:381 -msgid "Motion-JPEG (AVI)" -msgstr "Motion-JPEG (AVI)" - -#: photofilmstrip/core/renderer/OpenCvRenderer.py:52 -msgid "Open-CV (python-opencv) required!" -msgstr "Open-CV (python-opencv) nicht gefunden!" +#: photofilmstrip/core/renderer/GStreamerRenderer.py:448 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:500 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:546 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:635 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:675 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:724 +msgid "libav (gstreamer1.0-libav) required!" +msgstr "libav (gstreamer1.0-libav) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:452 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:504 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:550 +msgid "x264-Codec (gstreamer1.0-plugins-ugly) required!" +msgstr "x264-Codec (gstreamer1.0-plugins-ugly) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:456 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:554 +msgid "MKV-Muxer (gstreamer1.0-plugins-good) required!" +msgstr "MKV-Muxer (gstreamer1.0-plugins-good) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:508 +msgid "FLV-Muxer (gstreamer1.0-plugins-good) required!" +msgstr "FLV-Muxer (gstreamer1.0-plugins-good) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:592 +msgid "Theora-Codec (gstreamer1.0-plugins-base) required!" +msgstr "Theora-Codec (gstreamer1.0-plugins-base) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:596 +msgid "Vorbis-Codec (gstreamer1.0-plugins-base) required!" +msgstr "Vorbis-Codec (gstreamer1.0-plugins-base) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:600 +msgid "OGV-Muxer (gstreamer1.0-plugins-base) required!" +msgstr "OGV-Muxer (gstreamer1.0-plugins-base) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:631 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:671 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:720 +msgid "MPEG-1/2-Codec (gstreamer1.0-plugins-bad) required!" +msgstr "MPEG-1/2-Codec (gstreamer1.0-plugins-bad) nicht gefunden!" + +#: photofilmstrip/core/renderer/GStreamerRenderer.py:639 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:679 +#: photofilmstrip/core/renderer/GStreamerRenderer.py:728 +msgid "MPEG-Muxer (gstreamer1.0-plugins-bad) required!" +msgstr "MPEG-Muxer (gstreamer1.0-plugins-bad) nicht gefunden!" -#: photofilmstrip/core/renderer/SingleFileRenderer.py:35 +#: photofilmstrip/core/renderer/SingleFileRenderer.py:36 msgid "Single pictures" msgstr "Einzelbilder" -#: photofilmstrip/core/tasks.py:38 +#: photofilmstrip/core/tasks.py:61 msgid "generating subtitle" msgstr "generiere Untertitel" @@ -254,7 +234,7 @@ msgstr "&Extras" #: photofilmstrip/gui/ActionManager.py:87 -#: photofilmstrip/gui/ActionManager.py:233 photofilmstrip/gui/DlgRender.py:173 +#: photofilmstrip/gui/ActionManager.py:267 photofilmstrip/gui/DlgRender.py:174 #: photofilmstrip/gui/DlgRendererProps.py:101 msgid "&Help" msgstr "&Hilfe" @@ -267,83 +247,91 @@ msgid "Load Project" msgstr "Projekt laden" -#: photofilmstrip/gui/ActionManager.py:107 +#: photofilmstrip/gui/ActionManager.py:109 +#: photofilmstrip/gui/ActionManager.py:110 msgid "Save Project" msgstr "Projekt speichern" -#: photofilmstrip/gui/ActionManager.py:114 +#: photofilmstrip/gui/ActionManager.py:120 +#: photofilmstrip/gui/ActionManager.py:121 msgid "Import Pictures" msgstr "Bilder importieren" -#: photofilmstrip/gui/ActionManager.py:117 photofilmstrip/gui/DlgRender.py:117 +#: photofilmstrip/gui/ActionManager.py:127 +#: photofilmstrip/gui/ActionManager.py:128 photofilmstrip/gui/DlgRender.py:119 msgid "Render filmstrip" msgstr "Filmstreifen erstellen" -#: photofilmstrip/gui/ActionManager.py:121 +#: photofilmstrip/gui/ActionManager.py:135 +#: photofilmstrip/gui/ActionManager.py:136 msgid "Show job queue" msgstr "Auftragsliste zeigen" -#: photofilmstrip/gui/ActionManager.py:142 +#: photofilmstrip/gui/ActionManager.py:162 msgid "&New Project" msgstr "&Neues Projekt" -#: photofilmstrip/gui/ActionManager.py:146 +#: photofilmstrip/gui/ActionManager.py:166 msgid "&Open Project" msgstr "Pr&ojekt öffnen" -#: photofilmstrip/gui/ActionManager.py:152 +#: photofilmstrip/gui/ActionManager.py:172 msgid "&Save Project" msgstr "Projekt &speichern" -#: photofilmstrip/gui/ActionManager.py:156 +#: photofilmstrip/gui/ActionManager.py:177 msgid "&Close Project" msgstr "Projekt s&chließen" -#: photofilmstrip/gui/ActionManager.py:168 +#: photofilmstrip/gui/ActionManager.py:190 msgid "&Properties" msgstr "&Eigenschaften" -#: photofilmstrip/gui/ActionManager.py:173 +#: photofilmstrip/gui/ActionManager.py:195 msgid "E&xit" msgstr "B&eenden" -#: photofilmstrip/gui/ActionManager.py:181 +#: photofilmstrip/gui/ActionManager.py:203 msgid "Move picture &left" msgstr "Bild nach &links" -#: photofilmstrip/gui/ActionManager.py:185 +#: photofilmstrip/gui/ActionManager.py:208 msgid "Move picture &right" msgstr "Bild nach re&chts" -#: photofilmstrip/gui/ActionManager.py:190 +#: photofilmstrip/gui/ActionManager.py:214 msgid "R&emove Picture" msgstr "Bild &entfernen" -#: photofilmstrip/gui/ActionManager.py:195 +#: photofilmstrip/gui/ActionManager.py:220 msgid "Rotate &clockwise" msgstr "Im Uhrzeigersinn d&rehen" -#: photofilmstrip/gui/ActionManager.py:199 +#: photofilmstrip/gui/ActionManager.py:225 msgid "Rotate counter clock&wise" msgstr "&Gegen Uhrzeigersinn drehen" -#: photofilmstrip/gui/ActionManager.py:207 +#: photofilmstrip/gui/ActionManager.py:231 +msgid "Random &motion" +msgstr "Zufällige Bewegung" + +#: photofilmstrip/gui/ActionManager.py:236 msgid "Centralize m&otion" msgstr "Auswahl &zentrieren" -#: photofilmstrip/gui/ActionManager.py:215 +#: photofilmstrip/gui/ActionManager.py:246 msgid "&Import Pictures" msgstr "Bilder &importieren" -#: photofilmstrip/gui/ActionManager.py:220 +#: photofilmstrip/gui/ActionManager.py:252 msgid "&Render filmstrip" msgstr "&Filmstreifen erstellen" -#: photofilmstrip/gui/ActionManager.py:225 +#: photofilmstrip/gui/ActionManager.py:258 msgid "&Show job queue" msgstr "Auftragsliste &zeigen" -#: photofilmstrip/gui/ActionManager.py:253 +#: photofilmstrip/gui/ActionManager.py:287 msgid "&About" msgstr "&Info" @@ -363,7 +351,7 @@ msgid "Bug-Report send. Thank you for your support." msgstr "Fehlerbericht gesendet. Vielen Dank für die Unterstützung." -#: photofilmstrip/gui/DlgBugReport.py:105 photofilmstrip/gui/FrmMain.py:225 +#: photofilmstrip/gui/DlgBugReport.py:105 photofilmstrip/gui/FrmMain.py:229 msgid "Information" msgstr "Information" @@ -372,11 +360,13 @@ msgstr "Entschuldigung, diese Funktion ist zur Zeit nicht verfügbar." #: photofilmstrip/gui/DlgBugReport.py:112 -#: photofilmstrip/gui/DlgProjectProps.py:393 -#: photofilmstrip/gui/DlgProjectProps.py:422 -#: photofilmstrip/gui/DlgProjectProps.py:433 -#: photofilmstrip/gui/DlgProjectProps.py:480 -#: photofilmstrip/gui/DlgProjectProps.py:491 photofilmstrip/gui/FrmMain.py:518 +#: photofilmstrip/gui/DlgProjectProps.py:431 +#: photofilmstrip/gui/DlgProjectProps.py:443 +#: photofilmstrip/gui/DlgProjectProps.py:453 +#: photofilmstrip/gui/DlgProjectProps.py:502 +#: photofilmstrip/gui/DlgProjectProps.py:513 +#: photofilmstrip/gui/DlgRender.py:302 photofilmstrip/gui/FrmMain.py:532 +#: photofilmstrip/gui/PnlPfsProject.py:320 msgid "Error" msgstr "Fehler" @@ -407,15 +397,15 @@ msgstr "Zurücksetzen" #: photofilmstrip/gui/DlgPositionInput.py:253 -#: photofilmstrip/gui/DlgProjectProps.py:223 -#: photofilmstrip/gui/DlgRender.py:179 +#: photofilmstrip/gui/DlgProjectProps.py:196 +#: photofilmstrip/gui/DlgRender.py:180 #: photofilmstrip/gui/DlgRendererProps.py:107 #: photofilmstrip/lib/jobimpl/DlgJobVisual.py:94 msgid "&Cancel" msgstr "&Abbrechen" #: photofilmstrip/gui/DlgPositionInput.py:259 -#: photofilmstrip/gui/DlgProjectProps.py:229 +#: photofilmstrip/gui/DlgProjectProps.py:201 #: photofilmstrip/gui/DlgRendererProps.py:112 msgid "&Ok" msgstr "&Ok" @@ -424,133 +414,140 @@ msgid "Adjust motion positions directly" msgstr "Bewegungspfad manuell anpassen" -#: photofilmstrip/gui/DlgProjectProps.py:125 -msgid "Project properties" -msgstr "Projekteigenschaften" - -#: photofilmstrip/gui/DlgProjectProps.py:134 +#: photofilmstrip/gui/DlgProjectProps.py:110 msgid "Project name:" msgstr "Projektname:" -#: photofilmstrip/gui/DlgProjectProps.py:146 +#: photofilmstrip/gui/DlgProjectProps.py:117 msgid "Folder:" msgstr "Ordner:" -#: photofilmstrip/gui/DlgProjectProps.py:161 +#: photofilmstrip/gui/DlgProjectProps.py:129 msgid "Aspect ratio:" msgstr "Seitenverhältnis:" +#: photofilmstrip/gui/DlgProjectProps.py:134 +msgid "Audio files:" +msgstr "Audiodateien:" + #: photofilmstrip/gui/DlgProjectProps.py:169 msgid "Total length:" msgstr "Gesamtlänge:" -#: photofilmstrip/gui/DlgProjectProps.py:172 +#: photofilmstrip/gui/DlgProjectProps.py:171 msgid "" "Overrides the duration of single pictures and gives the project this total " "length." msgstr "Dauer der Einzelbilder durch diese Gesamtlänge überschreiben." -#: photofilmstrip/gui/DlgProjectProps.py:178 +#: photofilmstrip/gui/DlgProjectProps.py:175 msgid "User defined:" msgstr "Manuell:" -#: photofilmstrip/gui/DlgProjectProps.py:192 -msgid "Audio file:" -msgstr "Audiodatei:" +#: photofilmstrip/gui/DlgProjectProps.py:185 +msgid "Fit to audio files" +msgstr "An Audiodateien angleichen" + +#: photofilmstrip/gui/DlgProjectProps.py:189 +msgid "Timelapse" +msgstr "Zeitraffer" -#: photofilmstrip/gui/DlgProjectProps.py:238 +#: photofilmstrip/gui/DlgProjectProps.py:210 +msgid "Project properties" +msgstr "Projekteigenschaften" + +#: photofilmstrip/gui/DlgProjectProps.py:218 msgid "PhotoFilmStrip project" msgstr "PhotoFilmStrip-Projekt" -#: photofilmstrip/gui/DlgProjectProps.py:269 +#: photofilmstrip/gui/DlgProjectProps.py:249 msgid "Unnamed PhotoFilmStrip" msgstr "Unbenannter PhotoFilmStrip" -#: photofilmstrip/gui/DlgProjectProps.py:276 +#: photofilmstrip/gui/DlgProjectProps.py:256 msgid "My PhotoFilmStrips" msgstr "Eigene PhotoFilmStrips" -#: photofilmstrip/gui/DlgProjectProps.py:320 +#: photofilmstrip/gui/DlgProjectProps.py:310 msgid "Browse for folder" msgstr "Ordner auswählen" -#: photofilmstrip/gui/DlgProjectProps.py:334 +#: photofilmstrip/gui/DlgProjectProps.py:327 msgid "Select music" msgstr "Audiodatei auswählen" -#: photofilmstrip/gui/DlgProjectProps.py:336 +#: photofilmstrip/gui/DlgProjectProps.py:329 msgid "Audio files" msgstr "Audiodateien" -#: photofilmstrip/gui/DlgProjectProps.py:418 -#: photofilmstrip/gui/DlgProjectProps.py:421 +#: photofilmstrip/gui/DlgProjectProps.py:442 msgid "Audio file not supported!" msgstr "Audio-Datei nicht unterstützt!" -#: photofilmstrip/gui/DlgProjectProps.py:469 +#: photofilmstrip/gui/DlgProjectProps.py:491 msgid "Folder does not exists! Do you want %s to create it?" msgstr "Ordner existiert nicht. Soll %s ihn erstellen?" -#: photofilmstrip/gui/DlgProjectProps.py:470 photofilmstrip/gui/FrmMain.py:343 -#: photofilmstrip/gui/FrmMain.py:469 photofilmstrip/gui/FrmMain.py:547 +#: photofilmstrip/gui/DlgProjectProps.py:492 photofilmstrip/gui/FrmMain.py:347 +#: photofilmstrip/gui/FrmMain.py:473 photofilmstrip/gui/FrmMain.py:561 #: photofilmstrip/gui/WxProjectFile.py:95 -#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:232 +#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:225 msgid "Question" msgstr "Frage" -#: photofilmstrip/gui/DlgProjectProps.py:479 +#: photofilmstrip/gui/DlgProjectProps.py:501 msgid "Cannot create folder: %s" msgstr "Ordner kann nicht erstellt werden: %s" -#: photofilmstrip/gui/DlgProjectProps.py:490 +#: photofilmstrip/gui/DlgProjectProps.py:512 msgid "Cannot write into folder!" msgstr "Ordner nicht beschreibbar!" -#: photofilmstrip/gui/DlgProjectProps.py:504 +#: photofilmstrip/gui/DlgProjectProps.py:526 msgid "The project name must be filled." msgstr "Bitte einen Projektnamen angeben." -#: photofilmstrip/gui/DlgProjectProps.py:510 +#: photofilmstrip/gui/DlgProjectProps.py:532 msgid "The project name contains invalid characters." msgstr "Der Projektname enthält ungültige Zeichen." -#: photofilmstrip/gui/DlgRender.py:129 +#: photofilmstrip/gui/DlgRender.py:131 msgid "Format:" msgstr "Format:" -#: photofilmstrip/gui/DlgRender.py:145 +#: photofilmstrip/gui/DlgRender.py:146 msgid "Properties" msgstr "Eigenschaften" -#: photofilmstrip/gui/DlgRender.py:150 +#: photofilmstrip/gui/DlgRender.py:151 msgid "Resolution:" msgstr "Auflösung:" -#: photofilmstrip/gui/DlgRender.py:159 +#: photofilmstrip/gui/DlgRender.py:160 msgid "Type:" msgstr "Typ:" -#: photofilmstrip/gui/DlgRender.py:168 +#: photofilmstrip/gui/DlgRender.py:169 msgid "Draft" msgstr "Entwurf" -#: photofilmstrip/gui/DlgRender.py:184 +#: photofilmstrip/gui/DlgRender.py:185 msgid "&Start" msgstr "&Start" -#: photofilmstrip/gui/DlgRender.py:196 +#: photofilmstrip/gui/DlgRender.py:197 msgid "Configure output and start render process" msgstr "Ausgabe konfigurieren und erzeugen" -#: photofilmstrip/gui/DlgRender.py:253 +#: photofilmstrip/gui/DlgRender.py:252 msgid "Automatic" msgstr "Automatisch" -#: photofilmstrip/gui/DlgRender.py:293 +#: photofilmstrip/gui/DlgRender.py:286 msgid "Audio file '%s' does not exist! Continue anyway?" msgstr "Audio-Datei '%s' nicht vorhanden! Dennoch fortsetzen?" -#: photofilmstrip/gui/DlgRender.py:294 +#: photofilmstrip/gui/DlgRender.py:287 msgid "Warning" msgstr "Warnung" @@ -570,28 +567,28 @@ msgid "Edit extended output properties" msgstr "Erweiterte Videoeigenschaften bearbeiten" -#: photofilmstrip/gui/DlgRendererProps.py:164 +#: photofilmstrip/gui/DlgRendererProps.py:162 msgid "Edit property" msgstr "Eigenschaft bearbeiten" -#: photofilmstrip/gui/FrmMain.py:90 +#: photofilmstrip/gui/FrmMain.py:94 msgid "Welcome" msgstr "Willkommen" -#: photofilmstrip/gui/FrmMain.py:92 +#: photofilmstrip/gui/FrmMain.py:96 msgid "Job queue" msgstr "Aufträge" -#: photofilmstrip/gui/FrmMain.py:167 +#: photofilmstrip/gui/FrmMain.py:171 msgid "Rendering in progress..." msgstr "Wird erstellt..." -#: photofilmstrip/gui/FrmMain.py:224 +#: photofilmstrip/gui/FrmMain.py:228 msgid "You must restart %s for your new language setting to take effect." msgstr "" "Starten Sie %s neu, damit die neuen Spracheinstellungen wirksam werden." -#: photofilmstrip/gui/FrmMain.py:292 +#: photofilmstrip/gui/FrmMain.py:296 msgid "" "PhotoFilmStrip creates movies out of your pictures in just 3 steps. First " "select your photos, customize the motion path and render the video. There " @@ -601,56 +598,56 @@ "Fotos auswählen, Bewegung anpassen und Video erstellen lassen. Verfügbar " "sind Formate für VCD, SVCD, DVD bis hin zu FULL-HD." -#: photofilmstrip/gui/FrmMain.py:295 +#: photofilmstrip/gui/FrmMain.py:299 msgid "online" msgstr "Online" -#: photofilmstrip/gui/FrmMain.py:311 +#: photofilmstrip/gui/FrmMain.py:315 msgid "Select %s-Project" msgstr "%s-Projekt auswählen" -#: photofilmstrip/gui/FrmMain.py:313 photofilmstrip/gui/FrmMain.py:333 -#: photofilmstrip/gui/FrmMain.py:364 photofilmstrip/gui/FrmMain.py:375 +#: photofilmstrip/gui/FrmMain.py:317 photofilmstrip/gui/FrmMain.py:337 +#: photofilmstrip/gui/FrmMain.py:368 photofilmstrip/gui/FrmMain.py:379 msgid "Project" msgstr "Projekt" -#: photofilmstrip/gui/FrmMain.py:330 +#: photofilmstrip/gui/FrmMain.py:334 msgid "Save %s-Project" msgstr "%s-Projekt speichern" -#: photofilmstrip/gui/FrmMain.py:342 +#: photofilmstrip/gui/FrmMain.py:346 msgid "Overwrite existing file '%s'?" msgstr "Bestehende Datei '%s' überschreiben?" -#: photofilmstrip/gui/FrmMain.py:361 +#: photofilmstrip/gui/FrmMain.py:365 msgid "Export %s-Project" msgstr "%s-Projekt exportieren" -#: photofilmstrip/gui/FrmMain.py:364 photofilmstrip/gui/FrmMain.py:375 +#: photofilmstrip/gui/FrmMain.py:368 photofilmstrip/gui/FrmMain.py:379 msgid "Portable" msgstr "Mitnehm" -#: photofilmstrip/gui/FrmMain.py:373 +#: photofilmstrip/gui/FrmMain.py:377 msgid "Import %s-Project" msgstr "%s-Projekt importieren" -#: photofilmstrip/gui/FrmMain.py:468 +#: photofilmstrip/gui/FrmMain.py:472 msgid "'%s' has been modified. Save changes?" msgstr "'%s' wurde geändert. Änderungen speichern?" -#: photofilmstrip/gui/FrmMain.py:489 +#: photofilmstrip/gui/FrmMain.py:504 msgid "Images" msgstr "Bilder" -#: photofilmstrip/gui/FrmMain.py:494 +#: photofilmstrip/gui/FrmMain.py:508 msgid "Duration" msgstr "Dauer" -#: photofilmstrip/gui/FrmMain.py:516 +#: photofilmstrip/gui/FrmMain.py:530 msgid "Invalid %(app)s-Project: %(file)s" msgstr "Kein gültiges %(app)s-Projekt: %(file)s" -#: photofilmstrip/gui/FrmMain.py:544 +#: photofilmstrip/gui/FrmMain.py:558 msgid "Could not save the file '%(file)s': %(errMsg)s" msgstr "Konnte Datei '%(file)s' nicht speichern: %(errMsg)s" @@ -690,6 +687,7 @@ #: photofilmstrip/gui/PnlEditPicture.py:211 #: photofilmstrip/gui/PnlEditPicture.py:227 +#, fuzzy msgid "sec" msgstr "Sek." @@ -699,7 +697,7 @@ #: photofilmstrip/gui/PnlEditPicture.py:235 msgid "Subtitle" -msgstr "Untertitel:" +msgstr "Untertitel" #: photofilmstrip/gui/PnlEditPicture.py:255 msgid "Linear" @@ -737,34 +735,42 @@ msgid "Roll" msgstr "Rollen" -#: photofilmstrip/gui/PnlPfsProject.py:113 +#: photofilmstrip/gui/PnlPfsProject.py:114 msgid "Set motion end to start" msgstr "Endauswahl zu Startauswahl" -#: photofilmstrip/gui/PnlPfsProject.py:117 +#: photofilmstrip/gui/PnlPfsProject.py:118 msgid "Set motion start to end" msgstr "Startauswahl zu Endauswahl" -#: photofilmstrip/gui/PnlPfsProject.py:121 +#: photofilmstrip/gui/PnlPfsProject.py:122 msgid "Swap motion" msgstr "Start- und Zielauswahl tauschen" -#: photofilmstrip/gui/PnlPfsProject.py:126 +#: photofilmstrip/gui/PnlPfsProject.py:127 msgid "Adjust motion manual" msgstr "Bewegung manuell eingeben" -#: photofilmstrip/gui/PnlPfsProject.py:131 +#: photofilmstrip/gui/PnlPfsProject.py:132 msgid "Preserve image dimension" msgstr "Bildgrößenbeschränkung aufheben" -#: photofilmstrip/gui/PnlPfsProject.py:284 +#: photofilmstrip/gui/PnlPfsProject.py:304 msgid "Import images" msgstr "Bilder importieren" -#: photofilmstrip/gui/PnlPfsProject.py:286 +#: photofilmstrip/gui/PnlPfsProject.py:306 msgid "Imagefiles" msgstr "Bilddateien" +#: photofilmstrip/gui/PnlPfsProject.py:317 +msgid "" +"Filename '%s' does not match a number pattern which is necessary for a time " +"lapse slide show!" +msgstr "" +"Datei '%s' enthält kein Zahlenmuster, das aber für Zeitraffer-Slideshows " +"erforderlich ist!" + #: photofilmstrip/gui/PnlWelcome.py:51 photofilmstrip/gui/PnlWelcome.py:106 msgid "Recent projects" msgstr "Letzte Projekte" @@ -827,22 +833,22 @@ msgid "&Clear list" msgstr "Liste &leeren" -#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:124 +#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:127 msgid "Abort" msgstr "Abbrechen" -#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:134 +#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:133 msgid "Remove from list" msgstr "Von Liste entfernen" -#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:231 +#: photofilmstrip/lib/jobimpl/PnlJobVisual.py:224 msgid "Abort selected process?" msgstr "Aktuellen Vorgang abbrechen?" #: photofilmstrip/lib/jobimpl/VisualJob.py:25 #: photofilmstrip/lib/jobimpl/VisualJobMixin.py:21 msgid "Waiting..." -msgstr "warten..." +msgstr "Warte..." #: photofilmstrip/lib/jobimpl/VisualJob.py:64 #: photofilmstrip/lib/jobimpl/VisualJob.py:81 @@ -856,7 +862,37 @@ #: photofilmstrip/lib/jobimpl/VisualJob.py:75 msgid "Aborting..." -msgstr "abbrechen..." +msgstr "Breche ab..." + +#~ msgid "MP3-Codec (gstreamer0.10-plugins-ugly-multiverse) required!" +#~ msgstr "MP3-Codec (gstreamer0.10-plugins-ugly-multiverse) nicht gefunden!" + +#~ msgid "mencoder (mencoder) required!" +#~ msgstr "mencoder (mencoder) nicht gefunden!" + +#~ msgid "MPEG format supports only VCD, SVCD and DVD profile!" +#~ msgstr "MPEG-Format unterstützt nur die Profile VCD, SVCD und DVD!" + +#~ msgid "MPEG4-XVid/AC3 (AVI)" +#~ msgstr "MPEG4-XVid/AC3 (AVI)" + +#~ msgid "mencoder with MP3 support (mp3lame) required!" +#~ msgstr "mencoder mit MP3-Unterstützung (mp3lame) erforderlich!" + +#~ msgid "MPEG4-XVid/MP3 (AVI)" +#~ msgstr "MPEG4-XVid/MP3 (AVI)" + +#~ msgid "Flash-Video (FLV)" +#~ msgstr "Flash-Video (FLV)" + +#~ msgid "Motion-JPEG (AVI)" +#~ msgstr "Motion-JPEG (AVI)" + +#~ msgid "Open-CV (python-opencv) required!" +#~ msgstr "Open-CV (python-opencv) nicht gefunden!" + +#~ msgid "Audio file:" +#~ msgstr "Audiodatei:" #~ msgid "Please wait..." #~ msgstr "Bitte warten" @@ -953,9 +989,6 @@ #~ msgid "Audio file does not exist: %s" #~ msgstr "Audio-Datei nicht vorhanden: %s" -#~ msgid "audio file" -#~ msgstr "Audio-Datei" - #~ msgid "" #~ "The path where to save the output files. If single file renderer is used, " #~ "this option can be omitted to use stdout." Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/debpkg.tar.gz and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/debpkg.tar.gz differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/abort_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/abort_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/abort_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/abort_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/about_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/about_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/alert_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/alert_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/align_bottom.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/align_bottom.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/align_center.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/align_center.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/align_left.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/align_left.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/align_middle.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/align_middle.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/align_right.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/align_right.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/align_top.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/align_top.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/arrow_down_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/arrow_down_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/arrow_down_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/arrow_down_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/arrow_up_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/arrow_up_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/arrow_up_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/arrow_up_d_16.png differ diff -Nru photofilmstrip-3.2.0/res/icons/design/abort.svg photofilmstrip-3.3.1/res/icons/design/abort.svg --- photofilmstrip-3.2.0/res/icons/design/abort.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/abort.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1 @@ + \ No newline at end of file diff -Nru photofilmstrip-3.2.0/res/icons/design/about.svg photofilmstrip-3.3.1/res/icons/design/about.svg --- photofilmstrip-3.2.0/res/icons/design/about.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/about.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/alert.svg photofilmstrip-3.3.1/res/icons/design/alert.svg --- photofilmstrip-3.2.0/res/icons/design/alert.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/alert.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/arrow_down.svg photofilmstrip-3.3.1/res/icons/design/arrow_down.svg --- photofilmstrip-3.2.0/res/icons/design/arrow_down.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/arrow_down.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/arrow_up.svg photofilmstrip-3.3.1/res/icons/design/arrow_up.svg --- photofilmstrip-3.2.0/res/icons/design/arrow_up.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/arrow_up.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/dia_s.svg photofilmstrip-3.3.1/res/icons/design/dia_s.svg --- photofilmstrip-3.2.0/res/icons/design/dia_s.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/dia_s.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,99 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/dia.svg photofilmstrip-3.3.1/res/icons/design/dia.svg --- photofilmstrip-3.2.0/res/icons/design/dia.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/dia.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,92 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/exit.svg photofilmstrip-3.3.1/res/icons/design/exit.svg --- photofilmstrip-3.2.0/res/icons/design/exit.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/exit.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/design/filmstrip_dark_blue.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/design/filmstrip_dark_blue.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/design/filmstrip_original.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/design/filmstrip_original.png differ diff -Nru photofilmstrip-3.2.0/res/icons/design/folder_open.svg photofilmstrip-3.3.1/res/icons/design/folder_open.svg --- photofilmstrip-3.2.0/res/icons/design/folder_open.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/folder_open.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/help.svg photofilmstrip-3.3.1/res/icons/design/help.svg --- photofilmstrip-3.2.0/res/icons/design/help.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/help.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/image_moving_left.svg photofilmstrip-3.3.1/res/icons/design/image_moving_left.svg --- photofilmstrip-3.2.0/res/icons/design/image_moving_left.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/image_moving_left.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,73 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/image_moving_right.svg photofilmstrip-3.3.1/res/icons/design/image_moving_right.svg --- photofilmstrip-3.2.0/res/icons/design/image_moving_right.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/image_moving_right.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,73 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/image_remove.svg photofilmstrip-3.3.1/res/icons/design/image_remove.svg --- photofilmstrip-3.2.0/res/icons/design/image_remove.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/image_remove.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,63 @@ + + + + + + image/svg+xml + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/image_rotation_left.svg photofilmstrip-3.3.1/res/icons/design/image_rotation_left.svg --- photofilmstrip-3.2.0/res/icons/design/image_rotation_left.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/image_rotation_left.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/image_rotation_right.svg photofilmstrip-3.3.1/res/icons/design/image_rotation_right.svg --- photofilmstrip-3.2.0/res/icons/design/image_rotation_right.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/image_rotation_right.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/import_pictures.svg photofilmstrip-3.3.1/res/icons/design/import_pictures.svg --- photofilmstrip-3.2.0/res/icons/design/import_pictures.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/import_pictures.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/job_queue.svg photofilmstrip-3.3.1/res/icons/design/job_queue.svg --- photofilmstrip-3.2.0/res/icons/design/job_queue.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/job_queue.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/list_remove.svg.svg photofilmstrip-3.3.1/res/icons/design/list_remove.svg.svg --- photofilmstrip-3.2.0/res/icons/design/list_remove.svg.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/list_remove.svg.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/lock.svg photofilmstrip-3.3.1/res/icons/design/lock.svg --- photofilmstrip-3.2.0/res/icons/design/lock.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/lock.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/menu.svg photofilmstrip-3.3.1/res/icons/design/menu.svg --- photofilmstrip-3.2.0/res/icons/design/menu.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/menu.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/motion_center.svg photofilmstrip-3.3.1/res/icons/design/motion_center.svg --- photofilmstrip-3.2.0/res/icons/design/motion_center.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/motion_center.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,58 @@ + + + + + + image/svg+xml + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/motion_end_to_start.svg photofilmstrip-3.3.1/res/icons/design/motion_end_to_start.svg --- photofilmstrip-3.2.0/res/icons/design/motion_end_to_start.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/motion_end_to_start.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/motion_manual.svg photofilmstrip-3.3.1/res/icons/design/motion_manual.svg --- photofilmstrip-3.2.0/res/icons/design/motion_manual.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/motion_manual.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,64 @@ + + + + + + image/svg+xml + + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/motion_random.svg photofilmstrip-3.3.1/res/icons/design/motion_random.svg --- photofilmstrip-3.2.0/res/icons/design/motion_random.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/motion_random.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/motion_start_to_end.svg photofilmstrip-3.3.1/res/icons/design/motion_start_to_end.svg --- photofilmstrip-3.2.0/res/icons/design/motion_start_to_end.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/motion_start_to_end.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/motion_swap.svg photofilmstrip-3.3.1/res/icons/design/motion_swap.svg --- photofilmstrip-3.2.0/res/icons/design/motion_swap.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/motion_swap.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,58 @@ + + + + + + image/svg+xml + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/music.svg photofilmstrip-3.3.1/res/icons/design/music.svg --- photofilmstrip-3.2.0/res/icons/design/music.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/music.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/play_pause.svg photofilmstrip-3.3.1/res/icons/design/play_pause.svg --- photofilmstrip-3.2.0/res/icons/design/play_pause.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/play_pause.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/play.svg photofilmstrip-3.3.1/res/icons/design/play.svg --- photofilmstrip-3.2.0/res/icons/design/play.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/play.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/project_close.svg photofilmstrip-3.3.1/res/icons/design/project_close.svg --- photofilmstrip-3.2.0/res/icons/design/project_close.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/project_close.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/project_new.svg photofilmstrip-3.3.1/res/icons/design/project_new.svg --- photofilmstrip-3.2.0/res/icons/design/project_new.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/project_new.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/project_open.svg photofilmstrip-3.3.1/res/icons/design/project_open.svg --- photofilmstrip-3.2.0/res/icons/design/project_open.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/project_open.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/project_save.svg photofilmstrip-3.3.1/res/icons/design/project_save.svg --- photofilmstrip-3.2.0/res/icons/design/project_save.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/project_save.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/properties.svg photofilmstrip-3.3.1/res/icons/design/properties.svg --- photofilmstrip-3.2.0/res/icons/design/properties.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/properties.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/remove.svg photofilmstrip-3.3.1/res/icons/design/remove.svg --- photofilmstrip-3.2.0/res/icons/design/remove.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/remove.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/render.svg photofilmstrip-3.3.1/res/icons/design/render.svg --- photofilmstrip-3.2.0/res/icons/design/render.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/render.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/unlock.svg photofilmstrip-3.3.1/res/icons/design/unlock.svg --- photofilmstrip-3.2.0/res/icons/design/unlock.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/unlock.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + diff -Nru photofilmstrip-3.2.0/res/icons/design/video_format.svg photofilmstrip-3.3.1/res/icons/design/video_format.svg --- photofilmstrip-3.2.0/res/icons/design/video_format.svg 1970-01-01 00:00:00.000000000 +0000 +++ photofilmstrip-3.3.1/res/icons/design/video_format.svg 2017-12-03 22:12:24.000000000 +0000 @@ -0,0 +1,57 @@ + + + + + + image/svg+xml + + + + + + + + Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/dia.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/dia.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/dia_s.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/dia_s.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/exit_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/exit_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/filmstrip.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/filmstrip.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/folder_open_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/folder_open_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/folder_open_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/folder_open_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/help_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/help_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_left_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_left_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_left_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_left_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_left_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_left_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_left_d_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_left_d_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_right_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_right_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_right_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_right_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_right_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_right_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_moving_right_d_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_moving_right_d_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_remove_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_remove_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_remove_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_remove_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_remove_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_remove_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_remove_d_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_remove_d_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_rotation_left_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_rotation_left_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_rotation_left_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_rotation_left_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_rotation_right_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_rotation_right_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/image_rotation_right_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/image_rotation_right_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/import_pictures_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/import_pictures_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/import_pictures_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/import_pictures_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/import_pictures_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/import_pictures_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/import_pictures_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/import_pictures_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/import_pictures_d_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/import_pictures_d_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/job_queue_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/job_queue_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/job_queue_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/job_queue_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/job_queue_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/job_queue_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/job_queue_d_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/job_queue_d_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/list_remove_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/list_remove_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/list_remove_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/list_remove_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/lock_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/lock_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/menu_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/menu_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_center_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_center_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_center_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_center_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_end_to_start_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_end_to_start_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_input_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_input_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_left_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_left_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_manual_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_manual_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_manual_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_manual_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_random_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_random_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_random_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_random_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_random_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_random_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_right_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_right_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_start_to_end_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_start_to_end_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/motion_swap_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/motion_swap_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/music_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/music_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/play_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/play_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/play_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/play_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/play_pause_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/play_pause_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/play_pause_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/play_pause_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_close_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_close_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_close_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_close_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_new_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_new_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_new_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_new_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_new_64.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_new_64.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_open_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_open_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_open_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_open_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_open_64.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_open_64.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_save_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_save_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_save_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_save_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_save_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_save_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/project_save_d_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/project_save_d_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/properties_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/properties_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/remove_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/remove_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/remove_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/remove_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/render_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/render_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/render_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/render_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/render_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/render_32.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/render_d_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/render_d_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/render_d_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/render_d_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/unlock_24.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/unlock_24.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/video_format_16.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/video_format_16.png differ Binary files /tmp/tmpeLxqsI/tFbvH04jQ7/photofilmstrip-3.2.0/res/icons/video_format_32.png and /tmp/tmpeLxqsI/JKWk5urr6n/photofilmstrip-3.3.1/res/icons/video_format_32.png differ diff -Nru photofilmstrip-3.2.0/setup.py photofilmstrip-3.3.1/setup.py --- photofilmstrip-3.2.0/setup.py 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/setup.py 2017-12-03 22:12:24.000000000 +0000 @@ -141,26 +141,103 @@ target_mtime = os.path.getmtime(target) imgResources = ( -# ("ALIGN_BOTTOM", "align_bottom.png"), -# ("ALIGN_MIDDLE", "align_middle.png"), -# ("ALIGN_TOP", "align_top.png"), -# ("ALIGN_LEFT", "align_left.png"), -# ("ALIGN_CENTER", "align_center.png"), -# ("ALIGN_RIGHT", "align_right.png"), - ("PLAY_PAUSE", "play_pause_16.png"), - ("MOTION_RIGHT", "motion_right_24.png"), - ("MOTION_LEFT", "motion_left_24.png"), - ("MOTION_SWAP", "motion_swap_24.png"), - ("MOTION_INPUT", "motion_input_24.png"), - ("MOTION_RANDOM", "motion_random_24.png"), - ("LOCK", "lock_24.png"), - ("UNLOCK", "unlock_24.png"), - ("ICON_16", "photofilmstrip_16.png"), - ("ICON_24", "photofilmstrip_24.png"), - ("ICON_32", "photofilmstrip_32.png"), - ("ICON_48", "photofilmstrip_48.png"), - ("ICON_64", "photofilmstrip_64.png"), - ("ICON_128", "photofilmstrip_128.png"), + ("ICON_16","photofilmstrip_16.png"), + ("ICON_24","photofilmstrip_24.png"), + ("ICON_32","photofilmstrip_32.png"), + ("ICON_48","photofilmstrip_48.png"), + ("ICON_64","photofilmstrip_64.png"), + ("ICON_128","photofilmstrip_128.png"), + + ("PROJECT_NEW_16","project_new_16.png"), + ("PROJECT_NEW_24","project_new_24.png"), + ("PROJECT_NEW_64","project_new_64.png"), + ("PROJECT_OPEN_16","project_open_16.png"), + ("PROJECT_OPEN_24","project_open_24.png"), + ("PROJECT_OPEN_64","project_open_64.png"), + ("PROJECT_SAVE_16","project_save_16.png"), + ("PROJECT_SAVE_D_16","project_save_d_16.png"), + ("PROJECT_SAVE_24","project_save_24.png"), + ("PROJECT_SAVE_D_24","project_save_d_24.png"), + ("PROJECT_CLOSE_16","project_close_16.png"), + ("PROJECT_CLOSE_D_16","project_close_d_16.png"), + ("FOLDER_OPEN_16","folder_open_16.png"), + ("FOLDER_OPEN_24","folder_open_24.png"), + + ("MOTION_START_TO_END_24","motion_start_to_end_24.png"), + ("MOTION_END_TO_START_24","motion_end_to_start_24.png"), + ("MOTION_SWAP_24","motion_swap_24.png"), + ("MOTION_MANUAL_24","motion_manual_24.png"), + ("MOTION_MANUAL_32","motion_manual_32.png"), + ("MOTION_RANDOM_16","motion_random_16.png"), + ("MOTION_RANDOM_D_16","motion_random_d_16.png"), + ("MOTION_RANDOM_24","motion_random_24.png"), + ("MOTION_CENTER_16","motion_center_16.png"), + ("MOTION_CENTER_D_16","motion_center_d_16.png"), + ("LOCK_24","lock_24.png"), + ("UNLOCK_24","unlock_24.png"), + + ("MENU_24","menu_24.png"), + ("ABORT_16","abort_16.png"), + ("ABORT_24","abort_24.png"), + ("LIST_REMOVE_16","list_remove_16.png"), + ("LIST_REMOVE_24","list_remove_24.png"), + + ("RENDER_16","render_16.png"), + ("RENDER_D_16","render_d_16.png"), + ("RENDER_24","render_24.png"), + ("RENDER_D_24","render_d_24.png"), + ("RENDER_32","render_32.png"), + ("IMPORT_PICTURES_16","import_pictures_16.png"), + ("IMPORT_PICTURES_D_16","import_pictures_d_16.png"), + ("IMPORT_PICTURES_24","import_pictures_24.png"), + ("IMPORT_PICTURES_D_24","import_pictures_d_24.png"), + ("IMPORT_PICTURES_32","import_pictures_32.png"), + ("JOB_QUEUE_16","job_queue_16.png"), + ("JOB_QUEUE_D_16","job_queue_d_16.png"), + ("JOB_QUEUE_24","job_queue_24.png"), + ("JOB_QUEUE_D_24","job_queue_d_24.png"), + + ("IMAGE_ROTATION_LEFT_16","image_rotation_left_16.png"), + ("IMAGE_ROTATION_LEFT_D_16","image_rotation_left_d_16.png"), + ("IMAGE_ROTATION_RIGHT_16","image_rotation_right_16.png"), + ("IMAGE_ROTATION_RIGHT_D_16","image_rotation_right_d_16.png"), + ("IMAGE_MOVING_LEFT_16","image_moving_left_16.png"), + ("IMAGE_MOVING_LEFT_D_16","image_moving_left_d_16.png"), + ("IMAGE_MOVING_LEFT_32","image_moving_left_32.png"), + ("IMAGE_MOVING_LEFT_D_32","image_moving_left_d_32.png"), + ("IMAGE_MOVING_RIGHT_16","image_moving_right_16.png"), + ("IMAGE_MOVING_RIGHT_D_16","image_moving_right_d_16.png"), + ("IMAGE_MOVING_RIGHT_32","image_moving_right_32.png"), + ("IMAGE_MOVING_RIGHT_D_32","image_moving_right_d_32.png"), + ("IMAGE_REMOVE_16","image_remove_16.png"), + ("IMAGE_REMOVE_D_16","image_remove_d_16.png"), + ("IMAGE_REMOVE_32","image_remove_32.png"), + ("IMAGE_REMOVE_D_32","image_remove_d_32.png"), + + ("MUSIC_16","music_16.png"), + ("PLAY_16","play_16.png"), + ("PLAY_24","play_24.png"), + ("PLAY_PAUSE_16","play_pause_16.png"), + ("PLAY_PAUSE_d_16","play_pause_d_16.png"), + ("ARROW_UP_16","arrow_up_16.png"), + ("ARROW_UP_D_16","arrow_up_d_16.png"), + ("ARROW_DOWN_16","arrow_down_16.png"), + ("ARROW_DOWN_D_16","arrow_down_d_16.png"), + ("REMOVE_16","remove_16.png"), + ("REMOVE_D_16","remove_d_16.png"), + ("VIDEO_FORMAT_16","video_format_16.png"), + ("VIDEO_FORMAT_32","video_format_32.png"), + + ("ALERT_16","alert_16.png"), + ("PROPERTIES_16","properties_16.png"), + ("EXIT_16","exit_16.png"), + ("HELP_16","help_16.png"), + ("ABOUT_16","about_16.png"), + + ("FILMSTRIP","filmstrip.png"), + ("DIA","dia.png"), + ("DIA_S","dia_s.png"), + ) for idx, (imgName, imgFile) in enumerate(imgResources): diff -Nru photofilmstrip-3.2.0/.travis.yml photofilmstrip-3.3.1/.travis.yml --- photofilmstrip-3.2.0/.travis.yml 2017-11-22 20:19:27.000000000 +0000 +++ photofilmstrip-3.3.1/.travis.yml 2017-12-03 22:12:24.000000000 +0000 @@ -15,8 +15,9 @@ provider: releases api_key: secure: Sy4CkTH86aJB2yUIlsoQLErG223xBLzQjjL/kG3T1JpL4T7ECznqyCOXrUUmMJxKwMQiZIIRb9wGGjRPonysMZfjSTC+NMkJI+wA+Q+sbeLjXlZXUK0XwBW+MOVXzsFW5YoGlPmdEuSjoyfVSovotRcZiUTjGUqiuXDVU4KjYfienWcsSo/Adu4gaUU1C/eU3D8iQlSbFpGDu28jxPNUwKPYBIbFcWbc8HRlQlPO5KZblGLNe44Q8TADNm0+/6GhuPGFiqmAYu+YpZH1LH/AqJTkZQ/Id+sTioWopRe9Joo8OsPD75zo3rXgWNuHDTk/v3Il9BLZZojsFeLiszliouQ2R/er/cjg7T4VQWnweKtqkCUIUWSgqEiZQywMBJ562w7wxRzCcb85Qb/ZTO8OqRcoGZe5OpedLDaAaZ29aEAtfBtJJF2abh/1twwx6X/gwwfFr0tgssIQwHHlA7tgPvi0d5ENpnuhh2Q++6Ig1ZgdC21yNMk/zxcNA//Qe61qCf3eFL3NHp4JvqzgCcZgKq4/0mYmQD6sR6ZCStkJKwm7/IHRHIwmhV2rB1XkvOdRXRYqDEj5GnlgblX/vLoanZynMCJTAjL4KOo8hr7b7L2Ux+hgELjF4FpiHTdvtig1UzQG1PR5oRUAYbeNHgyiiUJTGgWu/Sct3ITHBBI2eO0= + file_glob: true file: dist/* - skip_cleanup: true overwrite: true + skip_cleanup: true on: tags: true