diff options
Diffstat (limited to 'presentty/presentty.py')
| -rw-r--r-- | presentty/presentty.py | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/presentty/presentty.py b/presentty/presentty.py new file mode 100644 index 0000000..35e19c1 --- /dev/null +++ b/presentty/presentty.py | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | # Copyright (C) 2015 James E. Blair <corvus@gnu.org> | ||
| 2 | # | ||
| 3 | # This program is free software: you can redistribute it and/or modify | ||
| 4 | # it under the terms of the GNU General Public License as published by | ||
| 5 | # the Free Software Foundation, either version 3 of the License, or | ||
| 6 | # (at your option) any later version. | ||
| 7 | # | ||
| 8 | # This program is distributed in the hope that it will be useful, | ||
| 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | # GNU General Public License for more details. | ||
| 12 | # | ||
| 13 | # You should have received a copy of the GNU General Public License | ||
| 14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | |||
| 16 | import argparse | ||
| 17 | import os | ||
| 18 | import sys | ||
| 19 | import time | ||
| 20 | |||
| 21 | import urwid | ||
| 22 | |||
| 23 | import slide | ||
| 24 | import server | ||
| 25 | import rst | ||
| 26 | import palette | ||
| 27 | |||
| 28 | |||
| 29 | class Presenter(object): | ||
| 30 | def __init__(self, palette): | ||
| 31 | blank = urwid.Text(u'') | ||
| 32 | self.blank = slide.UrwidSlide('Blank', None, blank, | ||
| 33 | palette['_default']) | ||
| 34 | self.current = self.blank | ||
| 35 | self.program = [] | ||
| 36 | self.palette = palette | ||
| 37 | self.pos = -1 | ||
| 38 | self.loop = urwid.MainLoop(self.blank, | ||
| 39 | unhandled_input=self.unhandledInput) | ||
| 40 | self.loop.screen.set_terminal_properties(colors=256) | ||
| 41 | |||
| 42 | self.server_pipe_in = self.loop.watch_pipe(self.serverData) | ||
| 43 | r,w = os.pipe() | ||
| 44 | self.server_pipe_out_read = os.fdopen(r) | ||
| 45 | self.server_pipe_out_write = w | ||
| 46 | self.server = server.ConsoleServer(self) | ||
| 47 | self.server.start() | ||
| 48 | |||
| 49 | def serverData(self, data): | ||
| 50 | parts = data.split() | ||
| 51 | if parts[0] == 'jump': | ||
| 52 | try: | ||
| 53 | index = int(parts[1]) | ||
| 54 | except Exception: | ||
| 55 | os.write(self.server_pipe_out_write, 'err\n') | ||
| 56 | return | ||
| 57 | if index < 0 or index > len(self.program)-1: | ||
| 58 | os.write(self.server_pipe_out_write, 'err\n') | ||
| 59 | return | ||
| 60 | self.transitionTo(index) | ||
| 61 | os.write(self.server_pipe_out_write, 'ok\n') | ||
| 62 | elif parts[0] == 'next': | ||
| 63 | self.nextSlide() | ||
| 64 | os.write(self.server_pipe_out_write, 'ok\n') | ||
| 65 | elif parts[0] == 'prev': | ||
| 66 | self.prevSlide() | ||
| 67 | os.write(self.server_pipe_out_write, 'ok\n') | ||
| 68 | |||
| 69 | def setProgram(self, program): | ||
| 70 | self.program = program | ||
| 71 | |||
| 72 | def run(self): | ||
| 73 | self.loop.set_alarm_in(0, self.nextSlide) | ||
| 74 | self.loop.run() | ||
| 75 | |||
| 76 | def unhandledInput(self, key): | ||
| 77 | if key in ('right', 'page down'): | ||
| 78 | self.nextSlide() | ||
| 79 | elif key in ('left', 'page up'): | ||
| 80 | self.prevSlide() | ||
| 81 | |||
| 82 | def transitionTo(self, index, forward=True): | ||
| 83 | self.pos = index | ||
| 84 | current_slide = self.current | ||
| 85 | new_slide = self.program[index] | ||
| 86 | if forward: | ||
| 87 | transition = new_slide.transition | ||
| 88 | new_slide.resetProgressive() | ||
| 89 | else: | ||
| 90 | transition = current_slide.transition | ||
| 91 | new_slide.resetProgressive(True) | ||
| 92 | current_slide.stopAnimation() | ||
| 93 | if forward: | ||
| 94 | transition.setTargets(current_slide, new_slide) | ||
| 95 | else: | ||
| 96 | transition.setTargets(new_slide, current_slide) | ||
| 97 | self.loop.widget = transition | ||
| 98 | duration = transition.getDuration() | ||
| 99 | start = time.time() | ||
| 100 | now = start | ||
| 101 | end = start + duration | ||
| 102 | while duration: | ||
| 103 | if forward: | ||
| 104 | progress = min(1-((end-now)/duration), 1.0) | ||
| 105 | else: | ||
| 106 | progress = max(((end-now)/duration), 0.0) | ||
| 107 | transition.setProgress(progress) | ||
| 108 | self.loop.draw_screen() | ||
| 109 | now = time.time() | ||
| 110 | if now >= end: | ||
| 111 | break | ||
| 112 | end = time.time() | ||
| 113 | self.loop.widget = new_slide | ||
| 114 | self.current = new_slide | ||
| 115 | self.loop.draw_screen() | ||
| 116 | current_slide.resetAnimation() | ||
| 117 | new_slide.startAnimation(self.loop) | ||
| 118 | |||
| 119 | def nextSlide(self, loop=None, data=None): | ||
| 120 | if self.current.nextProgressive(): | ||
| 121 | return | ||
| 122 | if self.pos+1 == len(self.program): | ||
| 123 | return | ||
| 124 | self.transitionTo(self.pos+1) | ||
| 125 | |||
| 126 | def prevSlide(self, loop=None, data=None): | ||
| 127 | if self.current.prevProgressive(): | ||
| 128 | return | ||
| 129 | if self.pos == 0: | ||
| 130 | return | ||
| 131 | self.transitionTo(self.pos-1, forward=False) | ||
| 132 | |||
| 133 | def main(): | ||
| 134 | parser = argparse.ArgumentParser( | ||
| 135 | description='Console-based presentation system') | ||
| 136 | parser.add_argument('--light', dest='light', | ||
| 137 | default=False, | ||
| 138 | action='store_true', | ||
| 139 | help='use a black on white palette') | ||
| 140 | parser.add_argument('--warnings', dest='warnings', | ||
| 141 | default=False, | ||
| 142 | action='store_true', | ||
| 143 | help='print RST parser warnings and exit if any') | ||
| 144 | parser.add_argument('file', | ||
| 145 | help='presentation file (RST)') | ||
| 146 | args = parser.parse_args() | ||
| 147 | if args.light: | ||
| 148 | plt = palette.LIGHT_PALETTE | ||
| 149 | else: | ||
| 150 | plt = palette.DARK_PALETTE | ||
| 151 | hinter = slide.ScreenHinter() | ||
| 152 | parser = rst.PresentationParser(plt, hinter) | ||
| 153 | program = parser.parse(open(args.file).read(), args.file) | ||
| 154 | if args.warnings: | ||
| 155 | w = parser.warnings.getvalue() | ||
| 156 | if w: | ||
| 157 | print w | ||
| 158 | sys.exit(1) | ||
| 159 | p = Presenter(plt) | ||
| 160 | p.setProgram(program) | ||
| 161 | hinter.setScreen(p.loop.screen) | ||
| 162 | p.run() | ||
