pax_global_header00006660000000000000000000000064115230352500014506gustar00rootroot0000000000000052 comment=e15c20785e89ae9fb14fa1ab0787af06dbcd0da3 douf00-3.0.0/000077500000000000000000000000001152303525000126035ustar00rootroot00000000000000douf00-3.0.0/.gitignore000066400000000000000000000000361152303525000145720ustar00rootroot00000000000000*.pyc build/* dist/* MANIFEST douf00-3.0.0/LICENSE000066400000000000000000000026061152303525000136140ustar00rootroot00000000000000Copyright (c) 2010 Martin Natano All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. douf00-3.0.0/MANIFEST.in000066400000000000000000000000251152303525000143360ustar00rootroot00000000000000include doc/douf00.1 douf00-3.0.0/README000066400000000000000000000035331152303525000134670ustar00rootroot00000000000000 DDDDDDDD FFFFFFFFFFF 00000000000 00000000000 DDD DDD FFF 000 0000 000 DDD DDD FFF 000 0000 000 DDD DDD FFF 000 0000 000 DDD DDD FFFFFFFFF 000 0000 000 DDD DDD ooooooooo uu uu FFF 000 0000 000 DDD DDD oo oo uu uu FFF 000 0000 000 DDD DDD oo oo uu uu FFF 000 0000 000 DDDDDDDDDDD ooooooooo uuuuuuuuu FFF 00000000000 00000000000 --==} FAT FREE PRESENTATIONS {==-- Description ~~~~~~~~~~~ Douf00 is a lightweight, slim and straight forward Presentation Tool. It assists novice as well as experienced speakers when giving lectures and business meetings. With its simple presenters Screen that includes current slide - next slide (preview) as well as timers it is designed to assist those of us, that are willing to step up their lectures to the next level. Installation ~~~~~~~~~~~~ Before you jump right into, some prerequisites have to be fulfilled. Dependencies: * python >= 2.5.4 * wxPython >= 2.8 * wxversion * python-poppler After you are done - feel free to do the following: $ curl http://www.natano.net/data/DouF00/DouF00-x.x.x.tar.gz | tar xzf $ cd DouF00* $ sudo python ./setup.py install Author ~~~~~~ Martin Natano Contributors ~~~~~~~~~~~~ Sebastian "Naxxatoe" Graf Bernd Zeimetz Stefan Heinecke Josef Philip Bernhart Links ~~~~~ Web: http://www.natano.net/ UpToDateVersion: http://www.natano.net/data/DouF00/ $Id: README,v 1.5 2011-02-04 17:26:32 natano Exp $ douf00-3.0.0/doc/000077500000000000000000000000001152303525000133505ustar00rootroot00000000000000douf00-3.0.0/doc/douf00.1000066400000000000000000000101171152303525000145270ustar00rootroot00000000000000.\" $Id: douf00.1,v 1.6 2011-02-04 17:26:33 natano Exp $ .\" .\" Copyright (c) 2010 Martin Natano .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. The name of the author may not be used to endorse or promote products .\" derived from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .Dd $Mdocdate$ .Dt DOUF00 1 .Os .Sh NAME .Nm douf00 .Nd fat free presentation tool .Sh SYNOPSIS .Nm douf00 .Op Fl t|--time Ar TIME .Op Fl b|--blank Ar BLANKSLIDE .Op Fl e|--exit .Op Fl s|--pre Ar PREDOUF00 .Op Fl p|--post Ar POSTDOUF00 .Op Fl B|--blankpage Ar BLANKPAGE .Op Fl S|--password .Op Fl a|--autostart .Op Ar SlideDir|PDF .Nm .Fl h|--help .Nm .Fl -version .Sh DESCRIPTION .Nm is a lightweight, slim and straight forward presentation tool. .Pp It assists novice as well as expierienced speakers when giving lectures and buissness meetings. With its simple presentors Screen that includes current slide - next slide (preview) aswell as timers it is designed to assist thoose of us, that are willing to step up their lectures to the next level. .Pp If you place in your presentation directory a file with the name blank.foo where foo can be: jpeg,jpg,png,bmp or pcx that will be your blank slide, which shows up when you start .Nm .Pp The options are as follows: .Bl -tag -width Ds .It Fl -version Show the version number and exit .It Fl h|--help Show the help message and exit .It Fl t|--time Ar TIME The duration of your presentation in minutes. .It Fl b|--blank Ar BLANKSLIDE A blank slide which is shown before the first and after the last slide. Please note, that unless this value is set, the first and last slide will always be black. .It Fl e|--exit Exit after the last slide .It Fl s|--pre Ar PREDOUF00 Run command PREDOUF00 after startup .It Fl p|--post Ar POSTDOUF00 Run command POSTDOUF00 before the exit .It Fl B|--blankpage Ar BLANKPAGE The 1-based index of the PDF page to use as the blank slide. .It Fl S|--password Ask for the password of the PDF file .It Fl a|--autostart Automatically start the presentation .Sh "CONFIGURATION FILE" There is no requirement for having any configuration file at all. If you do not have a configuration file, the program will use some sane default settings. However, if you have a speakers remote, that you want to work with .Nm you should set it up in the configuration file. .Sh FILES .Bl -tag -width "~/.douf00/douf00.confXXX" -compact .It Pa ~/.douf00/douf00.conf Default .Nm configuration file .Sh BUGS There is a bug which prevents .Nm from going fullscreen under the .Xr compiz 1 window manager. To work around this enable the "Legacy Fullscreen Support" for compiz. Therefor you can use compizconfig-settings-manager. .Pp If you experience problems using .Nm please write a bug report to natanoptacek@gmail.com .Sh "SEE ALSO" .Xr impressive 1 , .Xr keyjnote 1 , .Xr ooimpress 1 .Sh AUTHORS .An Martin Natano Aq natano@natano.net douf00-3.0.0/douf00.spec000066400000000000000000000024331152303525000145560ustar00rootroot00000000000000Name: douf00 Summary: A simple and fatfree presentation software Version: 3.0.0 Release: 3 Source0: %{name}-%{version}.tar.gz License: BSD Group: Applications/Publishing Buildroot: %{_tmppath}/root-%{name}-%{version} BuildRequires: python >= 2.5 Requires: python >= 2.5, wxPython, pypoppler %{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} %description DouF00 is a simple presentation- and screenmanagement software, including timers, previews an audience and presentor screen %prep %setup -q %build cd pysrc && python setup.py build %install if test "%{buildroot}" != ""; then rm -rf %{buildroot} mkdir -p %{buildroot} fi cd pysrc && python setup.py install --root=%{buildroot} mkdir -p %{buildroot}/usr/share/doc/douf00/ install -pm 0644 README %{buildroot}/usr/share/doc/douf00/README %files %defattr(-,root,root) /usr/bin/douf00 %{python_sitelib}/DouF00 %doc /usr/share/doc/douf00/README %clean if test "%{buildroot}" != ""; then rm -rf "%{buildroot}" fi %changelog * Sun Aug 23 2009 Bernd Zeimetz - Updated to use the new setup.py/distutils * Mon May 4 2009 Stefan Heinecke - updated specfile for python modules * Mon Apr 27 2009 Stefan Heinecke 1.0-1 - inital specfile creation douf00-3.0.0/pkgbuild000066400000000000000000000007421152303525000143320ustar00rootroot00000000000000# Package-Maintaner: not me pkgname=DouF00 pkgver=20110204 pkgrel=2 pkgdesc="Fat free presentation program" arch=(i686) url="http://www.natano.net/" license=('BSD') groups= provides= depends=('wxpython' 'python') makedepends=('git' 'python') _gitroot='git://github.com/natano/presentation.git' _gitname='presentation' build() { cd ${srcdir} msg "Connecting to github" git clone $_gitroot cd $_gitname python setup.py install --prefix=/usr --root="$pkgdir" || return 1 } douf00-3.0.0/pysrc/000077500000000000000000000000001152303525000137435ustar00rootroot00000000000000douf00-3.0.0/pysrc/DouF00/000077500000000000000000000000001152303525000147405ustar00rootroot00000000000000douf00-3.0.0/pysrc/DouF00/DisplayChoice.py000066400000000000000000000065651152303525000200460ustar00rootroot00000000000000# $Id: DisplayChoice.py,v 1.3 2011-02-01 14:04:55 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import wx from DouF00 import appcfg, usercfg class DisplayChoice(wx.Frame): def __init__(self): geometry = wx.Display(0).GetGeometry() style = wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP super(DisplayChoice, self).__init__(None, wx.ID_ANY, appcfg.title, style = style) self.choices = ['-- Nothing --', 'Audience', 'Presentor'] displays = wx.Display.GetCount() box = wx.BoxSizer(wx.VERTICAL) self.selections = [] for d in xrange(displays): choice = wx.Choice(self, wx.ID_ANY, choices = self.choices) if str(d) in usercfg.config['presentor']: choice.SetSelection(2) else: choice.SetSelection(1) self.selections.append(choice) hbox = wx.BoxSizer(wx.HORIZONTAL) hbox.Add(wx.StaticText( self, wx.ID_ANY, 'Display ' + str(d) + ': ' ), 0, wx.ALIGN_CENTER_VERTICAL ) hbox.Add(choice, 0, wx.ALIGN_CENTER_VERTICAL) box.Add(hbox, 0, wx.ALIGN_CENTER_HORIZONTAL) hbox = wx.BoxSizer(wx.HORIZONTAL) timelabel = wx.StaticText(self, wx.ID_ANY, 'Time:') hbox.Add(timelabel, 0, wx.ALIGN_CENTER_VERTICAL) self.spinctrl = wx.SpinCtrl( self, wx.ID_ANY, min = 0, max = 120, initial = usercfg.config['time'] ) hbox.Add(self.spinctrl, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) box.Add(hbox, 0, wx.ALIGN_CENTER_HORIZONTAL) self.button = wx.Button(self, wx.ID_ANY, label = 'OK') box.Add(self.button, 0, wx.ALIGN_CENTER_HORIZONTAL) self.SetSizerAndFit(box) position = (geometry[0] + 50, geometry[1] + 50) self.SetPosition(position) self.Show() douf00-3.0.0/pysrc/DouF00/ImageList.py000066400000000000000000000073541152303525000172010ustar00rootroot00000000000000# $Id: ImageList.py,v 1.2 2011-02-04 17:41:56 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys import threading from Queue import Queue from cStringIO import StringIO import wx import cairo from DouF00 import appcfg class ImageList(list): def __init__(self, imagelist_name, images_size=None): super(ImageList, self).__init__() if appcfg.blankslide == '': buffer = '\0\0\0' * 320 * 240 self.blank = wx.ImageFromBuffer(320, 240, buffer) elif appcfg.blankslide[0] == 'image': f = open(appcfg.blankslide[1], 'rb') self.blank = wx.ImageFromStream(f) f.close() elif appcfg.blankslide[0] == 'PDF': f = self.loadPdfPage(appcfg.blankslide[1]) self.blank = wx.ImageFromStream(f) f.close() else: raise KeyError('Unknown blank slide format') slidecount = len(appcfg.pictureFiles) for i, j in enumerate(appcfg.pictureFiles): sys.stdout.write('\r* Loading {0}: {1:03}/{2:03} '.format( imagelist_name, i+1, slidecount)) sys.stdout.flush() image = self.loadImage(i) if images_size: image = image.scaleTo(images_size) self.append(image) sys.stdout.write('\n') def loadImage(self, slideindex): if appcfg.pdfdoc: f = self.loadPdfPage(appcfg.pictureFiles[slideindex]) else: f = open(appcfg.pictureFiles[slideindex], 'rb') image = wx.ImageFromStream(f) f.close() return image def loadPdfPage(self, pagenum): page = appcfg.pdfdoc.get_page(pagenum) size = [int(n) for n in page.get_size()] img = cairo.ImageSurface(cairo.FORMAT_RGB24, *size) context = cairo.Context(img) context.set_source_rgb(1.0, 1.0, 1.0) context.rectangle(0, 0, *size) context.fill() page.render(context) f = StringIO() img.write_to_png(f) f.seek(0) return f def __getitem__(self, slideindex): if (slideindex < 0) or (slideindex == len(self)): return self.blank elif slideindex > len(self): buffer = '\0\0\0' * 320 * 240 return wx.ImageFromBuffer(320, 240, buffer) return super(ImageList, self).__getitem__(slideindex) douf00-3.0.0/pysrc/DouF00/MyImage.py000066400000000000000000000052311152303525000166430ustar00rootroot00000000000000# $Id: MyImage.py,v 1.5 2011-02-02 16:49:06 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import wx from DouF00 import appcfg def makeImageBorder(self, pixels=5): img = self.Copy() color = appcfg.presentorBorderColor size = img.GetSize() for (x, y, width, height) in [(0, 0, size[0], pixels ), (0, 0, pixels, size[1]), (0, size[1] - pixels, size[0], pixels ), (size[0] - pixels, 0, pixels, size[1])]: rect = wx.Rect(x, y, width, height) img.SetRGBRect(rect, color[0], color[1], color[2]) return img def scaleTo(self, size, method='scale'): imageSize = self.GetSize() if method == 'stretch': imageSize = size else: ratioX = float(size[0]) / imageSize[0] ratioY = float(size[1]) / imageSize[1] ratio = min(ratioX, ratioY) imageSize = [n * ratio for n in imageSize] return self.Scale(*imageSize) def scaleImageToBitmap(self, size, method='scale'): image = self.scaleTo(size, method=method) return wx.BitmapFromImage(image) wx.Image.makeImageBorder = makeImageBorder wx.Image.scaleTo = scaleTo wx.Image.scaleImageToBitmap = scaleImageToBitmap douf00-3.0.0/pysrc/DouF00/NumberFrame.py000066400000000000000000000046261152303525000175250ustar00rootroot00000000000000# $Id: NumberFrame.py,v 1.3 2011-02-01 14:04:55 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import wx from DouF00 import appcfg class NumberFrame(wx.Frame): def __init__(self, displayindex): geometry = wx.Display(displayindex).GetGeometry() style = wx.NO_BORDER | wx.STAY_ON_TOP | wx.FRAME_TOOL_WINDOW super(NumberFrame, self).__init__(None, wx.ID_ANY, appcfg.title, style = style) self.SetBackgroundColour(wx.Colour(255, 255, 255)) box = wx.BoxSizer(wx.VERTICAL) font = wx.Font(appcfg.numberFontSize, wx.DEFAULT, wx.NORMAL, wx.BOLD) text = wx.StaticText(self, wx.ID_ANY, str(displayindex)) text.SetFont(font) box.Add(text, 0, wx.ALIGN_CENTER) self.SetSizerAndFit(box) size = self.GetSize() position = (geometry[0] + (geometry[2] / 2) - (size[0] / 2), geometry[1] + (geometry[3] / 2) - (size[1] / 2)) self.SetPosition(position) self.Show() douf00-3.0.0/pysrc/DouF00/PresentationScreen.py000066400000000000000000000050701152303525000211270ustar00rootroot00000000000000# $Id: PresentationScreen.py,v 1.4 2011-02-04 17:26:33 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import wx from DouF00 import appcfg from DouF00.MyImage import * class PresentationScreen(wx.Frame): def __init__(self, displayindex = 0): self.displayindex = displayindex geometry = wx.Display(displayindex).GetGeometry() position = (geometry[0], geometry[1]) self.size = (geometry[2], geometry[3]) style = wx.NO_BORDER | wx.STAY_ON_TOP super(PresentationScreen, self).__init__(None, wx.ID_ANY, appcfg.title, style = style, pos = position, size = self.size) box = wx.BoxSizer(wx.VERTICAL) self.SetBackgroundColour(wx.Colour(0, 0, 0)) self.static_bitmap = wx.StaticBitmap(self, wx.ID_ANY) box.Add(self.static_bitmap, 0, wx.ALIGN_CENTER_HORIZONTAL) self.SetSizer(box) self.panel = wx.Panel(self, wx.ID_ANY, size = (0, 0), pos = (0, 0)) self.panel.SetBackgroundColour(wx.Colour(0, 0, 0)) def load(self, slideindex): bitmap = appcfg.slidelist[slideindex].scaleImageToBitmap(self.size) self.static_bitmap.SetBitmap(bitmap) self.Layout() douf00-3.0.0/pysrc/DouF00/PresentorsScreen.py000066400000000000000000000161411152303525000206210ustar00rootroot00000000000000# $Id: PresentorsScreen.py,v 1.5 2011-02-04 17:26:33 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import wx from DouF00 import appcfg from DouF00.MyImage import * class PresentorsScreen(wx.Frame): def __init__(self, displayindex = 0): self.displayindex = displayindex geometry = wx.Display(displayindex).GetGeometry() position = (geometry[0], geometry[1]) self.size = (geometry[2], geometry[3]) style = wx.NO_BORDER | wx.STAY_ON_TOP super(PresentorsScreen, self).__init__(None, wx.ID_ANY, appcfg.title, style = style, size = self.size, pos = position) self.SetBackgroundColour(appcfg.presentorBackgroundColor) self.static_bitmap = [] for i in xrange(9): self.static_bitmap.append(wx.StaticBitmap(self, wx.ID_ANY)) self.hbox = wx.GridSizer(1, 2, 10, 10) self.hbox.Add(self.static_bitmap[0], 0, wx.ALIGN_CENTER_HORIZONTAL) self.hbox.Add(self.static_bitmap[1], 0, wx.ALIGN_CENTER_HORIZONTAL) self.box = wx.BoxSizer(wx.VERTICAL) self.box.Add(self.hbox, 179, wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND) self.box.AddStretchSpacer(1) font = wx.Font(30, wx.DEFAULT, wx.NORMAL, wx.BOLD) hbox2 = wx.BoxSizer(wx.HORIZONTAL) textcolor = wx.Colour(210, 210 , 210) self.clock = wx.StaticText(self, wx.ID_ANY, '13:37:00') self.clock.SetForegroundColour(textcolor) self.clock.SetFont(font) hbox2.Add(self.clock , 3, wx.ALIGN_CENTER_VERTICAL) hbox2.AddStretchSpacer(1) self.countDown = wx.StaticText(self, wx.ID_ANY, ' 10.00 ') self.countDown.SetForegroundColour(textcolor) self.countDown.SetFont(font) hbox2.Add(self.countDown , 3, wx.ALIGN_CENTER_VERTICAL) hbox2.AddStretchSpacer(1) self.countUp = wx.StaticText(self, wx.ID_ANY, ' 00:00 ') self.countUp.SetForegroundColour(textcolor) self.countUp.SetFont(font) hbox2.Add(self.countUp , 3, wx.ALIGN_CENTER_VERTICAL) self.box.Add(hbox2, 17, wx.ALIGN_CENTER_HORIZONTAL) self.panel = wx.Panel(self, wx.ID_ANY) self.box.Add(self.panel, 3, wx.EXPAND) self.SetSizer(self.box) self.numbers = [] textcolor = wx.Colour(210, 210 , 210) font = wx.Font(25, wx.DEFAULT, wx.NORMAL, wx.BOLD) for i in xrange(9): self.numbers.append(wx.StaticText(self, wx.ID_ANY, '0')) self.numbers[i].Hide() self.numbers[i].SetForegroundColour(textcolor) self.numbers[i].SetFont(font) self.Layout() def load(self, slideindex, prevSlide = None): method = 'scale' if (self.size[0] < 1024) or (self.size[1] < 768): method = 'stretch' width = int(float(self.size[0]) / 2) - 5 height = int(float(self.size[1]) / 200 * 179) update = (prevSlide != None) and ((prevSlide - ((prevSlide + 1) % 9)) == (slideindex - ((slideindex + 1) % 9))) if appcfg.index: self.hbox.SetRows(3) self.hbox.SetCols(3) width = int(float(self.size[0]) / 3) - 5 height = int(float(height) / 3) if update: updateList = [(slideindex + 1) % 9, (prevSlide + 1) % 9] else: updateList = xrange(9) for i in updateList: slidelistindex = slideindex - ((slideindex + 1) % 9) + i img = appcfg.thumbnaillist[slidelistindex] if i == (slideindex + 1) % 9: img = img.makeImageBorder() bitmap = img.scaleImageToBitmap((width, height), method=method) self.static_bitmap[i].SetBitmap(bitmap) if not update: self.Layout() for i in updateList: slidelistindex = slideindex - ((slideindex + 1) % 9) + i self.numbers[i].SetLabel(str(slidelistindex + 1)) self.Layout() for i in updateList: pos = self.static_bitmap[i].GetPosition() x = pos[0] + self.static_bitmap[i].GetSize()[0] - self.numbers[i].GetSize()[0] - 5 y = pos[1] + 5 self.numbers[i].SetPosition((x, y)) else: self.hbox.SetRows(1) self.hbox.SetCols(2) image1 = appcfg.slidelist[slideindex] image1 = image1.makeImageBorder() bitmap1 = image1.scaleImageToBitmap((width, height), method = method) bitmap2 = appcfg.slidelist[slideindex + 1].scaleImageToBitmap( (width, height), method = method) self.static_bitmap[0].SetBitmap(bitmap1) self.static_bitmap[1].SetBitmap(bitmap2) self.Layout() if not update: self.Refresh() def index(self, slideindex, force = False): if force == True: appcfg.index = False if appcfg.index: for i in xrange(2, 9): self.static_bitmap[i].Show() self.hbox.Add(self.static_bitmap[i], 0, wx.ALIGN_CENTER_HORIZONTAL) self.thumbs = [] for i in xrange(slideindex - 4, slideindex + 5): self.thumbs.append(appcfg.thumbnaillist[i]) for i in xrange(9): self.numbers[i].Show() self.load(slideindex) else: for i in xrange(2, 9): self.static_bitmap[i].Hide() self.hbox.Detach(self.static_bitmap[i]) for i in xrange(9): self.numbers[i].Hide() self.load(slideindex) douf00-3.0.0/pysrc/DouF00/__init__.py000066400000000000000000000000001152303525000170370ustar00rootroot00000000000000douf00-3.0.0/pysrc/DouF00/appcfg.py000066400000000000000000000041521152303525000165540ustar00rootroot00000000000000# $Id: appcfg.py,v 1.6 2011-02-04 17:26:33 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import wx import os title = 'DouF00' __version__ = '3.0.0' __author__ = 'Martin Natano' numberFontSize = 150 preLoadCache = 5 pictureFiles = None blankslide = None slidelist = None thumbnaillist = None EVT_CLOCK_ID = wx.NewId() pause = False index = False presentorBackgroundColor = wx.Color(80, 80, 80) presentorBorderColor = (255, 0, 0) blankThumbnail = None pdfdoc = None pdfpass = '' filetypes = ( ('JPEG', '\xff\xd8'), ('PNG', '\x89PNG\x0d\x0a\x1a\x0a'), ('BMP', 'BM'), ('PCX', '\x0a'), ('PDF', '\x25\x50\x44\x46'), ) configFile = os.path.expanduser('~/.douf00/douf00.conf') THUMBNAIL_SIZE = (320, 240) douf00-3.0.0/pysrc/DouF00/douf00.py000066400000000000000000000411461152303525000164150ustar00rootroot00000000000000#!/usr/bin/env python # $Id: douf00.py,v 1.4 2011-02-02 16:49:06 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import os import sys import threading import time import atexit from optparse import OptionParser WXVER_REQ = '2.8' if 'wx' not in sys.modules and 'wxPython' not in sys.modules: import wxversion wxversion.ensureMinimal(WXVER_REQ) try: import wx assert wx.VERSION_STRING >= WXVER_REQ except: print('wxpython >= %s required' % WXVER_REQ) sys.exit(1) from DouF00 import appcfg, usercfg from DouF00.PresentorsScreen import PresentorsScreen from DouF00.PresentationScreen import PresentationScreen from DouF00.NumberFrame import NumberFrame from DouF00.DisplayChoice import DisplayChoice from DouF00.ImageList import ImageList class TriggerClock(wx.PyEvent): def __init__(self): super(TriggerClock, self).__init__() self.SetEventType(appcfg.EVT_CLOCK_ID) def filetype(path): if os.path.isdir(path): return 'dir' try: file = open(path, 'r') except IOError: print('No such file or directory: %s' % path) sys.exit(1) filemagic = file.read(8) file.close() for type, magic in appcfg.filetypes: if magic == filemagic[:len(magic)]: return type return None class MyApp(wx.App): def OnInit(self): self.presentationScreens = [] self.presentorsScreens = [] atexit.register(self.exit) usercfg.parseConfig() parser = OptionParser(usage='%prog [options] [slidepath]', version=appcfg.__version__) parser.add_option('-t', '--time', help='presentation time', action='store', type='int', dest='time') parser.add_option('-b', '--blank', help='blank slide', action='store', dest='blankslide') parser.add_option('-e', '--exit', help='exit after last slide', action='store_true', dest='exitafterlastslide') parser.add_option('-s', '--pre', help='command to be run when startin app', action='store', dest='predouf00') parser.add_option('-p', '--post', help='command to be run after the app', action='store', dest='postdouf00') parser.add_option('-B', '--blankpage', help='page of PDF file to use as blank slide', action='store', type='int', dest='blankpage') parser.add_option('-S', '--password', help='PDF file is password protection', action='store_true', dest='password') parser.add_option('-a', '--autostart', help='Automatically start presentation', action='store_true', dest='autostart') (options, args) = parser.parse_args() options = options.__dict__ for key in options: if not options[key] == None: usercfg.config[key] = options[key] if usercfg.config['blankslide'] and (not usercfg.config['blankpage'] == 0): parser.error('Options -b and -B are mutually exclusive') self.preApp() atexit.register(self.postApp) if len(args) > 1: print parser.format_help() sys.exit(1) elif len(args) == 1: slidepath = args[0] else: if usercfg.config['slidepath']: slidepath = usercfg.config['slidepath'] else: slidepath = wx.FileSelector('Choose a file to open', wildcard='*.pdf') if not slidepath: print parser.format_help() sys.exit('No path specified') slidetype = filetype(slidepath) if (not slidetype == 'PDF') and (usercfg.config['password']): parser.error('Option -S is only suitable for PDF files') if usercfg.config['password']: appcfg.pdfpass = wx.GetPasswordFromUser('PDF password') if (not slidetype == 'PDF') and (not usercfg.config['blankpage'] == 0): parser.error('Option -B is only supported with PDF files') if slidetype == 'dir': if usercfg.config['blankslide']: usercfg.config['blankslide'] = os.path.abspath(usercfg.config['blankslide']) try: os.chdir(slidepath) except OSError: sys.exit('No such file or directory') appcfg.pictureFiles = [] files = os.listdir(os.getcwd()) # support for more picture types for file in files: if filetype(file) in ('JPEG', 'PNG', 'BMP', 'PCX'): appcfg.pictureFiles.append(file) appcfg.pictureFiles.sort() if usercfg.config['blankslide']: if filetype(usercfg.config['blankslide']) in ('JPEG', 'PNG', 'BMP', 'PCX'): appcfg.blankslide = ('image', usercfg.config['blankslide']) if appcfg.blankslide[1] in appcfg.pictureFiles: appcfg.pictureFiles.remove(appcfg.blankslide[1]) else: print('File type not supported') sys.exit(1) else: appcfg.blankslide = '' elif slidetype == 'PDF': try: import poppler except ImportError: print 'python-poppler required' sys.exit(1) appcfg.pdfdoc = poppler.document_new_from_file('file://%s' % os.path.abspath(slidepath), appcfg.pdfpass) appcfg.pictureFiles = [] for i in xrange(appcfg.pdfdoc.get_n_pages()): appcfg.pictureFiles.append(i) if usercfg.config['blankslide']: if filetype(usercfg.config['blankslide']) in ('JPEG', 'PNG', 'BMP', 'PCX'): appcfg.blankslide = ('image', usercfg.config['blankslide']) if appcfg.blankslide[1] in appcfg.pictureFiles: appcfg.pictureFiles.remove(appcfg.blankslide[1]) else: print('File type not supported') sys.exit(1) elif not usercfg.config['blankpage'] == 0: appcfg.blankslide = ('PDF', usercfg.config['blankpage'] - 1) appcfg.pictureFiles.remove(appcfg.blankslide[1]) else: appcfg.blankslide = '' elif slidetype == None: print('File type not supported') sys.exit(1) appcfg.thumbnaillist = ImageList('Thumbnails', appcfg.THUMBNAIL_SIZE) appcfg.slidelist = ImageList('Slides') displayCount = wx.Display.GetCount() self.numberFrames = [] for d in xrange(displayCount): self.numberFrames.append(NumberFrame(d)) self.choice = DisplayChoice() self.choice.button.Bind(wx.EVT_BUTTON, self.Run) self.runTime = 120 self.startTime = int(time.mktime(time.localtime())) self.remainingTime = self.runTime self.elapsedTime = 0 if usercfg.config['autostart']: self.Run(None) return True def preApp(self): if usercfg.config['predouf00']: os.system(usercfg.config['predouf00']) def postApp(self): if usercfg.config['postdouf00']: os.system(usercfg.config['postdouf00']) def OnKeyPress(self, event): event.Skip() key = event.GetKeyCode() if (key == wx.WXK_RIGHT) or (key == wx.WXK_SPACE) or (key == wx.WXK_PAGEDOWN): self.NextSlide() elif (key == wx.WXK_LEFT) or (key == wx.WXK_PAGEUP): self.PrevSlide() elif (key == wx.WXK_DOWN): if appcfg.index: self.NextSlide(3) elif (key == wx.WXK_UP): if appcfg.index: self.PrevSlide(3) elif (key == ord('q')) or (key == ord('Q')): sys.exit() elif (key == ord('r')) or (key == ord('R')): self.startTime = int(time.time()) self.elapsedTime = 0 elif (key == ord('p')) or (key == ord('P')): appcfg.pause = not appcfg.pause elif (key == ord('i')) or (key == ord('I')) or (key == wx.WXK_ESCAPE) or (key == wx.WXK_F5): if appcfg.index: for p in self.presentationScreens: p.load(self.slideindex) p.Show() appcfg.index = not appcfg.index for p in self.presentorsScreens: p.index(self.slideindex) elif (key == wx.WXK_RETURN): self.exitIndex() elif (key == ord('s')) or (key == ord('S')): self.swapScreens() def exit(self): for p in self.presentationScreens: p.Destroy() for p in self.presentorsScreens: p.Destroy() def swapScreens(self): presentationScreens = [] presentorsScreens = [] for i in xrange(len(self.presentationScreens)): displayindex = self.presentationScreens[i].displayindex self.presentationScreens[i].Destroy() p = PresentorsScreen(displayindex) p.load(self.slideindex) p.Show() presentorsScreens.append(p) for i in xrange(len(self.presentorsScreens)): displayindex = self.presentorsScreens[i].displayindex self.presentorsScreens[i].index(self.slideindex, force = True) self.presentorsScreens[i].Destroy() p = PresentationScreen(displayindex) p.load(self.slideindex) p.Show() presentationScreens.append(p) self.presentationScreens = presentationScreens self.presentorsScreens = presentorsScreens for p in self.presentationScreens: p.load(self.slideindex) p.Show() p.panel.Bind(wx.EVT_KEY_UP, self.OnKeyPress) for thing in (p, p.panel, p.static_bitmap): thing.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick) thing.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick) p.panel.SetFocus() for p in self.presentorsScreens: p.load(self.slideindex) p.Show() p.panel.Bind(wx.EVT_KEY_UP, self.OnKeyPress) for thing in (p, p.panel, p.clock, p.countUp, p.countDown, p.static_bitmap[0], p.static_bitmap[1]): thing.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick) thing.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick) p.panel.SetFocus() def OnLeftClick(self, event): event.Skip() self.NextSlide() def OnRightClick(self, event): event.Skip() self.PrevSlide() def exitIndex(self): if appcfg.index: appcfg.index = not appcfg.index for p in self.presentorsScreens: p.index(self.slideindex) for p in self.presentationScreens: p.load(self.slideindex) p.Show() def Run(self, event): self.runTime = self.choice.spinctrl.GetValue() * 60 self.slideindex = -1 displayCount = wx.Display.GetCount() for displayindex in xrange(displayCount): if self.choice.choices[self.choice.selections[displayindex].GetSelection()] == 'Audience': self.presentationScreens.append(PresentationScreen(displayindex = displayindex)) elif self.choice.choices[self.choice.selections[displayindex].GetSelection()] == 'Presentor': self.presentorsScreens.append(PresentorsScreen(displayindex = displayindex)) self.choice.Destroy() for numberFrame in self.numberFrames: numberFrame.Destroy() if (self.presentationScreens == []) and (self.presentorsScreens == []): sys.exit() for p in self.presentationScreens: p.load(self.slideindex) p.Show() p.panel.Bind(wx.EVT_KEY_UP, self.OnKeyPress) for thing in (p, p.panel, p.static_bitmap): thing.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick) thing.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick) p.panel.SetFocus() for p in self.presentorsScreens: p.load(self.slideindex) p.Show() p.panel.Bind(wx.EVT_KEY_UP, self.OnKeyPress) for thing in (p, p.panel, p.clock, p.countUp, p.countDown, p.static_bitmap[0], p.static_bitmap[1]): thing.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick) thing.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick) p.panel.SetFocus() self.setClock('f00') t = self.Clock(self, self.presentorsScreens) t.setDaemon(True) t.start() self.Connect(-1, -1, appcfg.EVT_CLOCK_ID, self.setClock) def setClock(self, event): t = time.localtime() now = int(time.time()) is_running = 0 if ((0 <= self.slideindex < len(appcfg.pictureFiles)) and \ (self.remainingTime > 0)) and (not appcfg.pause): is_running = 1 else: self.startTime = now - self.elapsedTime if is_running == 1: self.elapsedTime = now - self.startTime + 1 else: self.elapsedTime = now - self.startTime self.remainingTime = self.runTime - self.elapsedTime for s in self.presentorsScreens: tstr = '%02d:%02d:%02d' % (t[3], t[4], t[5]) s.clock.SetLabel(tstr) countUpStr = ' %02d:%02d ' % (self.elapsedTime / 60, self.elapsedTime % 60) countDownStr = ' %02d:%02d ' % (self.remainingTime / 60, self.remainingTime % 60) s.countUp.SetLabel(countUpStr) s.countDown.SetLabel(countDownStr) try: red = int(float(255) * self.elapsedTime / self.runTime) green = int(float(150) * self.remainingTime / self.runTime) color = wx.Colour(red, green, 0) s.panel.SetBackgroundColour(color) if self.remainingTime < 120: color = wx.Colour(255, 0, 0) s.countDown.SetForegroundColour(color) except: pass class Clock(threading.Thread): def __init__(self, mainApp, presentorsScreens): self.mainApp = mainApp self.presentorsScreens = presentorsScreens super(MyApp.Clock, self).__init__() def run(self): while 1: wx.PostEvent(self.mainApp, TriggerClock()) time.sleep(1) def NextSlide(self, step = 1): if (self.slideindex + step > len(appcfg.pictureFiles)) and usercfg.config['exitafterlastslide'] and not appcfg.index: sys.exit() if self.slideindex + step <= len(appcfg.pictureFiles): self.slideindex += step if not appcfg.index: for p in self.presentationScreens: p.load(self.slideindex) p.Show() for p in self.presentorsScreens: p.load(self.slideindex, prevSlide = self.slideindex - step) p.Show() def PrevSlide(self, step = 1): if self.slideindex - step >= -1: self.slideindex -= step if not appcfg.index: for p in self.presentationScreens: p.load(self.slideindex) p.Show() for p in self.presentorsScreens: p.load(self.slideindex, prevSlide = self.slideindex + step) p.Show() def main(): app = MyApp() app.MainLoop() if __name__ == '__main__': main() douf00-3.0.0/pysrc/DouF00/usercfg.py000066400000000000000000000055551152303525000167620ustar00rootroot00000000000000# $Id: usercfg.py,v 1.4 2011-02-01 14:04:56 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import sys import ConfigParser from DouF00 import appcfg defaults = { 'blankslide': '', 'exitafterlastslide': 'False', 'predouf00': '', 'postdouf00': '', 'time': '45', 'slidepath': '', 'blankpage': '0', 'password': 'False', 'autostart': 'False', 'presentor': '', } config = defaults.copy() def parseConfig(): cfg = ConfigParser.SafeConfigParser(defaults) try: f = open(appcfg.configFile, 'r') cfg.readfp(f) try: userconfig = cfg.items('general') for item in userconfig: key, value = item if value: config[key] = value except ConfigParser.NoSectionError: print "Config file error" sys.exit(1) f.close except IOError: pass for key in ('exitafterlastslide', 'password', 'autostart'): if config[key] == 'True': config[key] = True elif config[key] == 'False': config[key] = False else: print "Config file error" sys.exit(1) for key in ('presentor', 'audience'): if key in config: config[key] = config[key].split(' ') for key in ('time', 'blankpage'): try: config[key] = int(config[key]) except ValueError: print "Config file error" sys.exit(1) douf00-3.0.0/pysrc/wrapper/000077500000000000000000000000001152303525000154235ustar00rootroot00000000000000douf00-3.0.0/pysrc/wrapper/douf00000077500000000000000000000030541152303525000164500ustar00rootroot00000000000000#!/usr/bin/env python # $Id: douf00,v 1.3 2011-02-01 14:04:56 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from DouF00 import douf00 douf00.main() douf00-3.0.0/setup.py000077500000000000000000000041641152303525000143250ustar00rootroot00000000000000#!/usr/bin/env python # $Id: setup.py,v 1.5 2011-02-04 17:26:33 natano Exp $ # # Copyright (c) 2010 Martin Natano # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from distutils.core import setup import os dirname = os.path.dirname(__file__) args = { 'name': 'DouF00', 'version': '3.0.0', 'description': 'fat free presentations', 'author': 'Martin Natano', 'author_email': 'natanoptacek@gmail.com', 'license': 'MIT', 'url': 'http://www.natano.net/', 'platforms': ['Linux'], 'packages': ['DouF00'], 'package_dir': {'DouF00': os.path.join(dirname, 'pysrc/DouF00')}, 'scripts': [os.path.join(dirname, 'pysrc/wrapper/douf00')], 'data_files': [('share/man/man1', [ os.path.join(dirname, 'doc/douf00.1'), ])], } setup(**args)