summaryrefslogtreecommitdiff
path: root/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f
diff options
context:
space:
mode:
Diffstat (limited to 'macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f')
-rw-r--r--macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/gvoz.pdfbin0 -> 39795 bytes
-rw-r--r--macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/presvoz.pdfbin0 -> 45582 bytes
-rw-r--r--macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/Flechitas.otfbin0 -> 8276 bytes
-rw-r--r--macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/iRaccoonShowBold.otfbin0 -> 305436 bytes
-rwxr-xr-xmacros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/gvoz.py574
-rw-r--r--macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/mtx-context-third-presvoz.tex798
-rw-r--r--macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/presvoz.mkxl183
7 files changed, 1555 insertions, 0 deletions
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/gvoz.pdf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/gvoz.pdf
new file mode 100644
index 0000000000..06c4f78b97
--- /dev/null
+++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/gvoz.pdf
Binary files differ
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/presvoz.pdf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/presvoz.pdf
new file mode 100644
index 0000000000..1e09286df2
--- /dev/null
+++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/doc/context/third/presvoz/presvoz.pdf
Binary files differ
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/Flechitas.otf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/Flechitas.otf
new file mode 100644
index 0000000000..0107c921d2
--- /dev/null
+++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/Flechitas.otf
Binary files differ
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/iRaccoonShowBold.otf b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/iRaccoonShowBold.otf
new file mode 100644
index 0000000000..487baf938b
--- /dev/null
+++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/fonts/opentype/presvoz/iRaccoonShowBold.otf
Binary files differ
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/gvoz.py b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/gvoz.py
new file mode 100755
index 0000000000..b7efcb3d2e
--- /dev/null
+++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/gvoz.py
@@ -0,0 +1,574 @@
+#!/usr/bin/env python3
+# coding: utf-8
+#
+# Copyright 2021-2022 (C) Pablo Rodríguez
+#
+# 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, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301, USA or see <http://www.gnu.org/licenses/gpl.html>.
+
+import os, sys, shutil
+import xml.etree.ElementTree as ET
+import cairo
+import gi
+gi.require_version("Gtk", "3.0")
+gi.require_version("Gst", "1.0")
+from gi.repository import Gtk, Gdk, GObject, GLib, Gst, GdkPixbuf
+gi.require_version('Poppler', '0.18')
+from gi.repository import Poppler
+
+Gst.init(sys.argv)
+
+class gvoz:
+ def __init__(self):
+
+ self.execname = os.path.splitext(os.path.basename(sys.argv[0]))[0]
+ self.real_path = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0])))
+ self.program_version = "0.9.9.2"
+
+ if(len(sys.argv) < 2):
+ self.on_file_selection()
+ print("")
+ print(" " + self.execname + "-" + self.program_version
+ + " (https://gvoz.presvoz.tk)")
+ print(" Written by Pablo Rodríguez")
+ print(" Usage: " + self.execname + " presentation.pdf")
+ print("")
+
+ if len(sys.argv) > 1:
+ self.main_filename = sys.argv[1]
+ elif self.dialog_filename != "":
+ self.main_filename = self.dialog_filename
+
+ self.filename = os.path.splitext(self.main_filename)[0]
+
+ if os.path.splitext(self.main_filename)[1] != (".pdf" or ".PDF"):
+ self.pdffilename = os.path.splitext(self.main_filename)[0] + ".pdf"
+ if os.path.isfile(self.pdffilename) == False:
+ self.pdffilename = os.path.splitext(self.main_filename)[0] + ".PDF"
+ if os.path.isfile(self.pdffilename) == False:
+ self.on_file_selection()
+ elif os.path.isfile(self.pdffilename) == False:
+ self.on_file_selection()
+ else:
+ self.pdffilename = self.main_filename
+
+ self.define_soundtimesnames()
+
+ self.uri = Gst.filename_to_uri(os.path.abspath(self.pdffilename))
+
+ self.document = Poppler.Document.new_from_file(self.uri, None)
+ self.n_pages = self.document.get_n_pages()
+ self.page_selector = self.document.get_page(0)
+ self.current_page = 0
+
+ self.win = Gtk.Window()
+ self.win.set_icon_from_file(self.real_path + '/gvoz.svg')
+ self.doc_title = self.document.get_title() or "χαλεπὰ τὰ καλά"
+ self.win.set_title (self.execname + " — " + str(self.current_page + 1) + "/" + str(self.n_pages) + " — " + self.doc_title)
+
+ self.win.set_default_size(500, 500)
+ self.win.set_position(Gtk.WindowPosition.CENTER_ALWAYS)
+
+ self.box = Gtk.Box()
+
+ self.area = Gtk.DrawingArea()
+ self.area.connect("draw", self.on_draw)
+
+ self.box.pack_start(self.area, True, True, 0)
+
+ self.win.add(self.box)
+ self.win.connect("destroy", Gtk.main_quit)
+ self.win.show_all()
+
+ self.win.connect('key-press-event', self.key_press_event)
+
+ self.width, self.height = self.win.get_size()
+ self.page_width, self.page_height= self.page_selector.get_size()
+
+ self.surface = cairo.ImageSurface(cairo.FORMAT_RGB24,
+ int(self.width),
+ int(self.height))
+
+ if sys.platform.startswith('win'):
+ self.player = Gst.parse_launch("wasapisrc low-latency=true ! audio/x-raw,format=F32LE ! wavenc ! filesink location=\"" + self.audiofilename + "\"")
+ else:
+ self.player = Gst.parse_launch("autoaudiosrc ! audio/x-raw,format=F32LE,rate=48000,channels=1 ! wavenc ! filesink location=\"" + self.audiofilename + "\"")
+
+ bus = self.player.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', self.on_message)
+
+ xmp = self.document.get_metadata()
+ if xmp != None and xmp != "":
+ xmp_root = ET.fromstring(xmp)
+ for language in xmp_root.findall(".//{http://purl.org/dc/elements/1.1/}language"):
+ doc_lang = language.text
+ else:
+ print("The PDF document has no language information")
+
+ title_separator = ". "
+
+ self.sound_metadata = { "title" : "The Title" }
+ self.sound_metadata["genre"] = "Other/Presentation"
+ self.sound_metadata["application-name"] = "GVoz"
+ self.sound_metadata["encoder"] = self.sound_metadata["application-name"]
+ self.sound_metadata["encoder-version"] = self.program_version
+ self.sound_metadata["datetime"] = Gst.DateTime.new_now_local_time()
+ self.sound_metadata["date"] = GLib.Date.new_dmy(self.sound_metadata["datetime"].get_day(),
+ self.sound_metadata["datetime"].get_month(), self.sound_metadata["datetime"].get_year())
+
+ try:
+ doc_lang
+ except NameError:
+ print("\n\"" + os.path.basename(self.pdffilename) +
+ "\" contains no language information.")
+ self.doc_lang = None
+ else:
+ if doc_lang != None and doc_lang != "":
+ self.sound_metadata["language-code"] = doc_lang
+ self.sound_metadata["language-name"] = GstTag.tag_get_language_name(language_code)
+ if doc_lang.startswith('en'):
+ title_separator = ": "
+ else:
+ title_separator = ". "
+
+ if self.document.get_subject() != None and self.document.get_subject() != "":
+ self.sound_metadata["comment"] = self.document.get_subject()
+ elif self.document.get_title() != None and self.document.get_title() != "":
+ self.sound_metadata["title"] = self.document.get_title()
+ if self.document.get_keywords() != None and self.document.get_keywords() != "":
+ self.sound_metadata["keywords"] = self.document.get_keywords()
+ if self.document.get_author() != None and self.document.get_author() != "":
+ self.sound_metadata["artist"] = self.document.get_author()
+ self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year()) + " " + self.document.get_author()
+ else:
+ self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year())
+
+ self.taglist = Gst.TagList.new_empty()
+
+ self.mp3_converter = Gst.parse_launch("filesrc location=\"" + self.audiofilename + "\" ! decodebin ! audioconvert ! audioresample ! lamemp3enc mono=true cbr=true target=bitrate bitrate=32 ! id3v2mux ! filesink location=\"" + self.mp3_audio + "\"")
+
+ mp3_bus = self.mp3_converter.get_bus()
+ mp3_bus.add_signal_watch()
+ mp3_bus.connect('message', self.on_mp3_message)
+
+ self.mp3_metadata = True
+
+ tagsetter = self.mp3_converter.get_by_interface(Gst.TagSetter)
+ for tag_key, tag_value in self.sound_metadata.items():
+ try:
+ self.taglist.add_value(Gst.TagMergeMode.REPLACE, tag_key, tag_value)
+ except ValueError:
+ print("WARNING: skipping tag %s; value %s is not valid" % (tag_key, tag_value))
+ if not self.taglist.is_empty() and self.mp3_metadata:
+ tagsetter.merge_tags(self.taglist, Gst.TagMergeMode.REPLACE_ALL)
+ print(type(self.mp3_metadata))
+ print(self.taglist.to_string() + "\n")
+ else:
+ print("<<<< WARNING: Could not find element to set tags. >>>")
+
+ # ~ self.opus_converter = Gst.parse_launch("filesrc location=\"" + self.audiofilename + "\" ! decodebin ! audioconvert ! audioresample ! opusenc audio-type=voice bitrate=16000 ! oggmux ! filesink location=\"" + self.opus_audio + "\"")
+
+ # ~ opus_bus = self.opus_converter.get_bus()
+ # ~ opus_bus.add_signal_watch()
+ # ~ opus_bus.connect('message', self.on_opus_message)
+
+ # ~ self.opus_metadata = True
+
+ # ~ tagsetter = self.opus_converter.get_by_interface(Gst.TagSetter)
+ # ~ if not self.taglist.is_empty() and self.opus_metadata:
+ # ~ tagsetter.merge_tags(self.taglist, Gst.TagMergeMode.REPLACE_ALL)
+ # ~ else:
+ # ~ print("<<<< WARNING: Could not find element to set tags. >>>")
+
+ self.use_presvoz = True
+
+ def on_message(self, bus, message):
+ t = message.type
+ if t == Gst.MessageType.EOS:
+ self.player.set_state(Gst.State.NULL)
+ # ~ Gtk.main_quit()
+ elif t == Gst.MessageType.ERROR:
+ err, debug = message.parse_error()
+ print ("Error: %s" % err, debug)
+ self.player.set_state(Gst.State.NULL)
+
+ def on_mp3_message(self, mp3_bus, message):
+ t = message.type
+ if t == Gst.MessageType.EOS:
+ self.mp3_converter.set_state(Gst.State.NULL)
+ self.generate_presentation()
+ Gtk.main_quit()
+ elif t == Gst.MessageType.ERROR:
+ err, debug = message.parse_error()
+ print ("Error: %s" % err, debug)
+ self.mp3_converter.set_state(Gst.State.NULL)
+
+ # ~ def on_opus_message(self, opus_bus, message):
+ # ~ t = message.type
+ # ~ if t == Gst.MessageType.EOS:
+ # ~ self.opus_converter.set_state(Gst.State.NULL)
+ # ~ Gtk.main_quit()
+ # ~ elif t == Gst.MessageType.ERROR:
+ # ~ err, debug = message.parse_error()
+ # ~ print ("Error: %s" % err, debug)
+ # ~ self.opus_converter.set_state(Gst.State.NULL)
+
+ def generate_presentation (self):
+ if shutil.which("context") != None and shutil.which("context") != "" and self.use_presvoz:
+ os.system("context --purgeall --extra=third-presvoz " + self.pdffilename)
+ if os.path.isfile(self.js_timesfilename):
+ os.remove(self.js_timesfilename)
+
+ def define_soundtimesnames (self):
+ if sys.platform.startswith('win'):
+ self.audiofilename = self.filename.replace("\\", "/") + "-audio.wav"
+ self.mp3_audio = self.filename.replace("\\", "/") + "-audio.mp3"
+ self.opus_audio = self.filename.replace("\\", "/") + "-audio.opus"
+ else:
+ self.audiofilename = self.filename + "-audio.wav"
+ self.mp3_audio = self.filename + "-audio.mp3"
+ self.opus_audio = self.filename + "-audio.opus"
+
+ self.times = []
+ self.timesfilename = self.filename + '-times.txt'
+ self.js_timesfilename = self.filename + '-times.js'
+
+ def on_metadata_info (self):
+ if self.document.get_title() != None and self.document.get_title() != "":
+ metadata_info = "\n<b>Title:</b> <i>" + self.document.get_title() + "</i>"
+ if self.document.get_author() != None and self.document.get_author() != "":
+ metadata_info += "\n\n<b>Author:</b> <i>" + self.document.get_author() + "</i>"
+ if self.document.get_subject() != None and self.document.get_subject() != "":
+ metadata_info += "\n\n<b>Comments:</b> <i>" + self.document.get_subject() + "</i>"
+ if self.document.get_keywords() != None and self.document.get_keywords() != "":
+ metadata_info += "\n\n<b>Keywords:</b> <i>" + self.document.get_keywords() + "</i>"
+ if self.doc_lang != None and self.doc_lang != "":
+ metadata_info += "\n\n<b>Language:</b> <i>" + self.sound_metadata['language-name'] + "</i>"
+ else:
+ metadata_info = "\nThe PDF document contains no metadata"
+
+
+ self.sound_metadata["comment"] = self.document.get_subject()
+ if self.document.get_author() != None and self.document.get_author() != "":
+ self.sound_metadata["artist"] = self.document.get_author()
+ self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year()) + " " + self.document.get_author()
+ else:
+ self.sound_metadata["copyright"] = "© " + str(self.sound_metadata["datetime"].get_year())
+
+ dialog = Gtk.MessageDialog(
+ # ~ transient_for=self,
+ flags=0,
+ message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.OK,
+ text="Metadata from PDF Document",
+ )
+
+ dialog.format_secondary_text(metadata_info)
+
+ dialog.props.secondary_use_markup = True
+
+ dialog.run()
+
+ dialog.destroy()
+
+ def on_keys_info (self):
+ keys_info = "\n<b>space</b>\t\tGo to next slide and write its time"
+ keys_info += "\n\t\t\tThis starts and finishes sound recording"
+ keys_info += "\n\t\t\tAfter that, <i>PresVoz</i> will generate the presentation"
+ keys_info += "\n\n<b>a</b>\t\t\tAbout <i>GVoz</i>"
+ keys_info += "\n\n<b>c</b>\t\t\tDon’t generate PDF and <i>Flash</i> presentations with <i>PresVoz</i>"
+ keys_info += "\n\n<b>d</b>\t\t\tShow metadata imported from the PDF document"
+ keys_info += "\n\n<b>h</b>\t\t\tShow key information"
+ keys_info += "\n\n<b>m</b>\t\t\tEnable mouse–click to advance slides"
+ keys_info += "\n\n<b>p</b>\t\t\tPause / unpause sound and times recording"
+ keys_info += "\n\t\t\tWith paused recording, <i>GVoz</i> will exit full–screen"
+ keys_info += "\n\t\t\tWith recording started again, <i>GVoz</i> will go full–screen"
+ # ~ keys_info += "\n\n<b>x</b>\t\t\tRemove metadata in MP3 file\n\t\t\tTitle and author are read from the PDF document\n\t\t\tDates and times are set from the recording"
+ keys_info += "\n\n<b>q</b>\t\t\tQuit <i>GVoz</i> (presentation won’t be generated)"
+
+ dialog = Gtk.MessageDialog(
+ # ~ transient_for=self,
+ flags=0,
+ message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.OK,
+ text="Keyboard Info",
+ )
+ dialog.format_secondary_text(
+ keys_info
+ )
+
+ dialog.props.secondary_use_markup = True
+
+ dialog.run()
+
+ dialog.destroy()
+
+ def on_presvoz_info (self):
+ presvoz_info = "\nPresentation won’t be generated after sound and times recording."
+ presvoz_info += "\n\nIf you want to generate it, just use <i>Presvoz</i> after <i>GVoz</i> finishes."
+
+ dialog = Gtk.MessageDialog(
+ # ~ transient_for=self,
+ flags=0,
+ message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.OK,
+ text="Presentation Disabled",
+ )
+ dialog.format_secondary_text(
+ presvoz_info
+ )
+
+ dialog.props.secondary_use_markup = True
+
+ dialog.run()
+
+ dialog.destroy()
+
+ def on_mouse_info (self):
+ mouse_info = "\nMouse has been activated to advance slides."
+ mouse_info += "\n\nMouse–clicks have been enabled to advance slides."
+ mouse_info += "\n\nThere is no way to disable the mouse again."
+
+ dialog = Gtk.MessageDialog(
+ # ~ transient_for=self,
+ flags=0,
+ message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.OK,
+ text="Mouse Enabled",
+ )
+ dialog.format_secondary_text(mouse_info)
+
+ dialog.props.secondary_use_markup = True
+
+ dialog.run()
+
+ dialog.destroy()
+
+ def on_presvoz_presentation (self):
+ presvoz_presentation = "\nThe selected PDF document is already a presentation with voice."
+ presvoz_presentation += "\n\nPlease, select other PDF document not already generated by <i>PresVoz</i>."
+
+ dialog = Gtk.MessageDialog(
+ # ~ transient_for=self,
+ flags=0,
+ message_type=Gtk.MessageType.INFO,
+ buttons=Gtk.ButtonsType.OK,
+ text="<big><b><i>PresVoz</i> Presentation Detected</b></big>",
+ )
+
+ dialog.format_secondary_text(presvoz_presentation)
+
+ dialog.props.use_markup = True
+ dialog.props.secondary_use_markup = True
+
+ response = dialog.run()
+ if response == Gtk.ResponseType.OK:
+ self.on_file_selection()
+
+ dialog.run()
+
+ dialog.destroy()
+
+ def on_existing_files (self):
+ already_recorded_files = "\nVoice and times have already been recorded in a previous session."
+ already_recorded_files += "\n\nIf you proceed, <tt>" + os.path.basename(self.audiofilename) + "</tt> and <tt>" + os.path.basename(self.timesfilename) + "</tt> will be lost forever."
+ already_recorded_files += "\n\nIf you cancel, you will quit <i>GVoz</i>."
+ already_recorded_files += "\n\nIf you want to keep <tt>" + os.path.basename(self.audiofilename) + "</tt> and <tt>" + os.path.basename(self.timesfilename) + "</tt>, please quit and rename them or move them to another directory."
+ already_recorded_files += "\n\nDo you really want to proceed?\n"
+
+ dialog = Gtk.MessageDialog(
+ # ~ transient_for=self,
+ flags=0,
+ message_type=Gtk.MessageType.WARNING,
+ buttons=Gtk.ButtonsType.YES_NO,
+ text="Existing Sound and Times",
+ )
+
+ dialog.format_secondary_text(already_recorded_files)
+
+ dialog.set_default_response(Gtk.ResponseType.NO)
+
+ dialog.props.secondary_use_markup = True
+
+ response = dialog.run()
+ if response == Gtk.ResponseType.YES:
+ if os.path.isfile(self.audiofilename):
+ os.remove(self.audiofilename)
+ if os.path.isfile(self.timesfilename):
+ os.remove(self.timesfilename)
+ if os.path.isfile(self.mp3_audio):
+ os.remove(self.mp3_audio)
+ if os.path.isfile(self.opus_audio):
+ os.remove(self.opus_audio)
+ elif response == Gtk.ResponseType.NO:
+ Gtk.main_quit()
+
+ dialog.destroy()
+
+ def button_press_event(self, widget, event):
+ if event.button == 1:
+ self.record_and_advance()
+
+ def key_press_event(self, widget, event):
+ if event.keyval != Gdk.keyval_from_name("a"):
+ if event.keyval != Gdk.keyval_from_name("h"):
+ if event.keyval != Gdk.keyval_from_name("q"):
+ if event.keyval != Gdk.keyval_from_name("x"):
+ if event.keyval != Gdk.keyval_from_name("c"):
+ if event.keyval != Gdk.keyval_from_name("m"):
+ if event.keyval != Gdk.keyval_from_name("d"):
+ if self.player.get_state(0)[1] == Gst.State.NULL and self.current_page + 1 <= self.n_pages:
+ if os.path.exists(self.audiofilename) or os.path.exists(self.timesfilename):
+ self.on_existing_files()
+ elif self.document.get_subject() != None:
+ if self.document.get_subject().endswith('🤞🐞 – https://www.presvoz.tk'):
+ self.on_presvoz_presentation()
+ if event.keyval == Gdk.keyval_from_name("h"):
+ self.on_keys_info()
+ if event.keyval == Gdk.keyval_from_name("a"):
+ self.about_info()
+ if event.keyval == Gdk.keyval_from_name("q"):
+ if self.player.get_state(0)[1] == Gst.State.PLAYING or self.player.get_state(0)[1] == Gst.State.PAUSED:
+ self.player.set_state(Gst.State.NULL)
+ self.file_times.close()
+ if os.path.isfile(self.audiofilename):
+ self.mp3_converter.set_state(Gst.State.PLAYING)
+ self.win.set_title (self.execname + " — Converting sound to MP3 format…")
+ Gtk.main_quit()
+ if event.keyval == Gdk.keyval_from_name("x"):
+ self.mp3_metadata = False
+ self.opus_metadata = False
+ if event.keyval == Gdk.keyval_from_name("c"):
+ self.use_presvoz = False
+ self.on_presvoz_info()
+ if event.keyval == Gdk.keyval_from_name("d"):
+ self.on_metadata_info()
+ if event.keyval == Gdk.keyval_from_name("m"):
+ self.win.connect('button-press-event', self.button_press_event)
+ self.on_mouse_info()
+ if event.keyval == Gdk.keyval_from_name("p"):
+ if self.player.get_state(0)[1] == Gst.State.PLAYING:
+ self.win.unfullscreen()
+ self.win.set_title (self.execname + " — " + str(self.current_page + 1) + "/" + str(self.n_pages) + " — " + self.doc_title)
+ self.player.set_state(Gst.State.PAUSED)
+ elif self.player.get_state(0)[1] == Gst.State.PAUSED:
+ self.win.fullscreen()
+ self.player.set_state(Gst.State.PLAYING)
+ if event.keyval == Gdk.keyval_from_name("space"):
+ self.record_and_advance()
+
+ def record_and_advance(self):
+ if self.player.get_state(0)[1] == Gst.State.NULL and self.current_page + 1 <= self.n_pages:
+ self.win.fullscreen()
+ self.player.set_state(Gst.State.PLAYING)
+ self.file_times = open(self.timesfilename, 'w')
+ elif self.player.get_state(0)[1] == Gst.State.PLAYING:
+ if self.current_page + 1 < self.n_pages:
+ self.current_page += 1
+ self.page_selector = self.document.get_page(self.current_page)
+ self.area.set_size_request(int(self.width),int(self.height))
+ self.area.queue_draw()
+ self.file_times.write(str(int(self.player.get_pipeline_clock().get_time()/1000000)) + "\n")
+ elif self.current_page + 1 == self.n_pages:
+ self.win.unfullscreen()
+ self.win.set_title (self.execname + " — " + str(self.current_page + 1) + "/" + str(self.n_pages) + " — " + self.doc_title)
+ self.player.send_event(Gst.Event.new_eos())
+ self.file_times.write(str(int(self.player.get_pipeline_clock().get_time()/1000000)))
+ self.file_times.close()
+ self.current_page += 1
+ self.mp3_converter.set_state(Gst.State.PLAYING)
+ self.win.set_title (self.execname + " — Converting sound to MP3 format…")
+ if shutil.which("context") != None and shutil.which("context") != "" and self.use_presvoz:
+ self.win.set_title (self.execname + " — Generating presentation…")
+ # ~ self.opus_converter.set_state(Gst.State.PLAYING)
+ # ~ self.win.set_title (self.execname + " — Converting sound to Opus format…")
+
+ def on_file_selection(self):
+ dialog = Gtk.FileChooserDialog(
+ title="Please choose a PDF document", action=Gtk.FileChooserAction.OPEN
+ )
+ dialog.add_buttons(
+ Gtk.STOCK_CANCEL,
+ Gtk.ResponseType.CANCEL,
+ Gtk.STOCK_OPEN,
+ Gtk.ResponseType.OK,
+ )
+
+ self.add_filters(dialog)
+
+ response = dialog.run()
+ if response == Gtk.ResponseType.OK:
+ self.dialog_filename = dialog.get_filename()
+ self.pdffilename = self.dialog_filename
+ self.filename = os.path.splitext(self.dialog_filename)[0]
+ self.define_soundtimesnames()
+
+ dialog.destroy()
+
+ def add_filters(self, dialog):
+ filter_pdf = Gtk.FileFilter()
+ filter_pdf.set_name("PDF documents")
+ filter_pdf.add_mime_type("application/pdf")
+ dialog.add_filter(filter_pdf)
+
+ def on_draw(self, widget, cairo_context):
+ add_x = 0
+ add_y = 0
+
+ if (self.area.get_allocated_width()/self.page_width) < (self.area.get_allocated_height()/self.page_height):
+ self.scale = self.area.get_allocated_width()/self.page_width
+ add_y = (((self.area.get_allocated_height()-(self.page_height*self.scale))/2)/self.scale)
+ else:
+ self.scale = self.area.get_allocated_height()/self.page_height
+ add_x = (((self.area.get_allocated_width()-(self.page_width*self.scale))/2)/self.scale)
+
+ # ~ cr = Gdk.cairo_create(self.win.get_window()) # deprecated
+ # ~ cairo_context = cairo.Context(self.surface) # new, seems not required
+
+ cairo_context.set_source_surface(self.surface)
+ cairo_context.set_source_rgba(1, 1, 1)
+
+ if self.scale != 1:
+ cairo_context.scale(self.scale, self.scale)
+
+ cairo_context.translate(add_x, add_y)
+ cairo_context.rectangle(0, 0, self.page_width, self.page_height)
+ cairo_context.fill()
+ self.page_selector.render(cairo_context)
+
+ def about_info (self):
+ dialog = Gtk.AboutDialog()
+ dialog.set_program_name("GVoz")
+ dialog.set_version(self.program_version)
+ dialog.set_comments("Record and create presentations with voice")
+ dialog.set_website("https://gvoz.presvoz.tk")
+ dialog.set_website_label("https://gvoz.presvoz.tk")
+ dialog.set_authors(["Pablo Rodríguez"])
+ dialog.set_copyright("© 2021-2022 Pablo Rodríguez")
+ dialog.set_license_type(Gtk.License.GPL_2_0)
+ dialog.set_wrap_license = True
+ dialog.set_logo(GdkPixbuf.Pixbuf.new_from_file(self.real_path + "/gvoz.svg"))
+ dialog.connect('response', lambda dialog, data: dialog.destroy())
+ dialog.show_all()
+
+ def gtk_main_quit(self, widget, event):
+ Gtk.main_quit()
+
+ def main(self):
+ Gtk.main()
+
+gv = gvoz()
+gv.main()
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/mtx-context-third-presvoz.tex b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/mtx-context-third-presvoz.tex
new file mode 100644
index 0000000000..2e9fc84a53
--- /dev/null
+++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/mtx-context-third-presvoz.tex
@@ -0,0 +1,798 @@
+%D \module
+%D [ file=mtx-context-third-presvoz,
+%D version=2022.02.02,
+%D title=PresVoz,
+%D subtitle=Presentations with Voice,
+%D author=Pablo Rodríguez,
+%D date=\currentdate,
+%D copyright={Michal Vlásak \&\ Pablo Rodríguez}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C copyrighted by its authors.
+
+\starttext
+\startlmtxmode
+\def\Presentation{\getdocumentfilename{1}}
+
+\startluacode
+if file.extname(document.files[1]) == "" then
+ document.main_file = file.addsuffix(document.files[1],"pdf")
+else
+ document.main_file = document.files[1]
+end
+
+if file.pathpart(document.main_file) == "" then
+ document.main_filename = file.nameonly(document.main_file)
+else
+ document.main_filename = file.pathpart(document.main_file):gsub(io.fileseparator, "/") .. "/" .. file.nameonly(document.main_file)
+end
+
+document.original_times = document.main_filename .. "-times.txt"
+
+document.uncompressed_audio = document.main_filename .. "-audio.wav"
+
+document.audio_mp3 = document.main_filename .. "-audio.mp3"
+
+document.audio_opus = document.main_filename .. "-audio.opus" -- opus might work later
+
+document.compressed_audio = document.audio_mp3
+
+--twolame is not an option: gives wrong sizes
+
+if io.exists(document.uncompressed_audio) and not(io.exists(document.audio_mp3)) and os.which('lame') then
+ os.execute('lame -m m -b 32 "' .. document.uncompressed_audio .. '" "' .. document.audio_mp3 .. '"')
+elseif io.exists(document.uncompressed_audio) and not(io.exists(document.compressed_audio)) then
+ if os.which('opusenc') then os.execute('opusenc --downmix-mono --bitrate 16 "' .. document.uncompressed_audio .. '" "' .. document.audio_opus .. '"') end
+end
+
+presvoz_name = document.main_filename .. "-presvoz.pdf"
+
+if not(io.exists(document.original_times)) or not(io.exists(document.compressed_audio)) then
+ context.enablemode({"missing-files"})
+end
+\stopluacode
+
+\startmode[missing-files]
+\setupinteractionscreen[option=max]
+\setupbodyfont[pagella]
+\startTEXpage[offset=2em, align=center]
+ \bf\color[darkred]{{\bi PresVoz} requires\\
+ {\tt\cldcontext{document.original_times}} and {\tt\cldcontext{document.uncompressed_audio}}\\
+ to do its magic with {\tt\cldcontext{document.main_file}}.}
+\stopTEXpage
+\stopmode
+
+\startnotmode[missing-files]
+\startluacode
+document.timeline_filename = document.main_filename .. "-times.js"
+
+document.slides_swf = document.main_filename .. ".swf"
+
+document.presentation_script = document.main_filename .. "-presentation.sc"
+
+document.presentation_swf = document.main_filename .. "-presentation.swf"
+
+document.presentation_filename = file.nameonly(document.main_file) .. "-presentation.swf"
+
+document.first_slide_swf = document.main_filename .. "-first.swf"
+
+document.loader_script = document.main_filename .. "-loader.sc"
+
+document.loader_swf = document.main_filename .. "-loader.swf"
+
+function document.transfer_metadata(name)
+ local main_doc = lpdf.epdf.load(name)
+ lpdf.addtocatalog("Lang", lpdf.unicode(main_doc.Catalog.Lang), lpdf.string(main_doc.Catalog.Lang))
+ if main_doc.Catalog.Lang == "en" then
+ document.separate_subtitle = ": "
+ else
+ document.separate_subtitle = ". "
+ end
+ if main_doc.Info.Subject ~= nil and main_doc.Info.Subject ~= "" then
+ context.setupinteraction{ title = main_doc.Info.Title .. document.separate_subtitle .. main_doc.Info.Subject }
+ else
+ context.setupinteraction{ title = main_doc.Info.Title }
+ end
+ if main_doc.Catalog.Lang == "es" then
+ document.presvoz_banner = "Hecho con «PresVoz»  🤞🐞"
+ elseif main_doc.Catalog.Lang == "pt" then
+ document.presvoz_banner = "Feito con «PresVoz»  🤞🐞"
+ elseif main_doc.Catalog.Lang == "it" then
+ document.presvoz_banner = "Fatto con «PresVoz»  🤞🐞"
+ elseif main_doc.Catalog.Lang == "fr" then
+ document.presvoz_banner = "Fait avec « PresVoz »  🤞🐞"
+ elseif main_doc.Catalog.Lang == "de" then
+ document.presvoz_banner = "Erezeugt mit »PresVoz«  🤞🐞"
+ elseif main_doc.Catalog.Lang == "nl" then
+ document.presvoz_banner = "Gedaan med „PresVoz”  🤞🐞"
+ elseif main_doc.Catalog.Lang == "nl" then
+ document.presvoz_banner = "Gedaan med „PresVoz”  🤞🐞"
+ else
+ document.presvoz_banner = "Done with “PresVoz”  🤞🐞"
+ end
+ context.setupinteraction{ subtitle = document.presvoz_banner .. " – https://www.presvoz.tk" }
+ if main_doc.Info.Author ~= nil and main_doc.Info.Author ~= "" then
+ context.setupinteraction{ author = main_doc.Info.Author }
+ end
+ if main_doc.Info.ModDate ~=nil and main_doc.Info.ModDate ~= "" then
+ original_Doc_date = main_doc.Info.ModDate:sub(3,6) .. "-" ..
+ main_doc.Info.ModDate:sub(7,8) .. "-" ..
+ main_doc.Info.ModDate:sub(9,10) .. "T" ..
+ main_doc.Info.ModDate:sub(11,12) .. ":" ..
+ main_doc.Info.ModDate:sub(13,14) .. ":" ..
+ main_doc.Info.ModDate:sub(15,22):gsub("'", ":")
+ directives.enable('backend.date=' .. original_Doc_date .. "'")
+ end
+ lpdf.epdf.unload(name)
+end
+
+document.transfer_metadata(document.main_file)
+\stopluacode
+
+\startbuffer[flash-presentation]
+ \startluacode
+ local raw_times = io.open(document.original_times)
+ local swf_times = io.open(document.presentation_script, "w")
+
+ swf_times:write([[# Presentation script, generated by PresVoz
+ #
+ # Copyright (C) 2003 Leonard Lin
+ # Copyright (C) 2007-2008 Sergio Costas
+ # Copyright (C) 2009-2021 Pablo Rodríguez
+ #
+ # 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 <http://www.gnu.org/licenses>.
+ #
+ # Additional permission under GNU GPL version 3 section 7
+ #
+ # As a special exception, if you create a document which uses this
+ # script, and compile this script or a modified version of it in the
+ # document, this script does not by itself cause the resulting document
+ # to be covered by the GNU General Public License. This exception does
+ # not however invalidate any other reasons why the document might be
+ # covered by the GNU General Public License.
+
+ .flash filename="]] .. document.presentation_swf .. [[" version=8 fps=12
+
+ .swf slides "]] .. document.slides_swf .. [["
+ .sound audio "]] .. document.audio_mp3 .. [["
+
+ .action:
+ var times=new Array();
+ var maxtimes;
+ var position;
+ var mode;
+ var sound_position;
+ var sound_length;
+ var show_slide;
+
+ var contextual = new ContextMenu();
+ function ssurl(){
+ getURL("https://www.presvoz.tk", "_blank");
+ }
+
+ switch (System.capabilities.language) {
+ case "en" :
+ ss_message = "Done with PresVoz  🤞🐞";
+ break;
+ case "es" :
+ ss_message = "Hecho con PresVoz  🤞🐞";
+ break;
+ case "gl" :
+ ss_message = "Feito con PresVoz  🤞🐞";
+ break;
+ case "pt" :
+ ss_message = "Feito con PresVoz  🤞🐞";
+ break;
+ case "it" :
+ ss_message = "Fatto con PresVoz  🤞🐞";
+ break;
+ case "fr" :
+ ss_message = "Fait avec PresVoz  🤞🐞";
+ break;
+ case "de" :
+ ss_message = "Erezeugt mit PresVoz  🤞🐞";
+ break;
+ case "nl" :
+ ss_message = "Gedaan med PresVoz  🤞🐞";
+ break;
+ case "el" :
+ ss_message = "Kατασκευασμένος με PresVoz  🤞🐞";
+ break;
+ default:
+ ss_message = "Made with PresVoz  🤞🐞";
+ break;
+ }
+
+ contextual.hideBuiltInItems();
+ ss_url = new ContextMenuItem(ss_message, ssurl);
+ contextual.customItems.push(ss_url);
+ _root.menu = contextual;
+
+ snd = new Sound(this);
+ snd.attachSound("audio");
+ sound_length=snd.duration;
+ position = 0;
+
+ show_slide = false;
+ times[0] = 0;]] .. "\n")
+
+ line_number = 0
+ while true do
+ line = raw_times:read()
+ if line == nil then break end
+ if line:match("%D") == nil then
+ line_number = line_number + 1
+ print ("times["..line_number.."] = " .. line .. ";")
+ swf_times:write(" times["..line_number.."] = " .. line .. ";")
+ swf_times:write("\n")
+ end
+ end
+
+ swf_times:write("\n" .. [[
+ maxtimes = times.length - 1;
+
+ function pause_or_play() {
+ if (mode==0) {
+ snd.start(snd.position/1000.0,0);
+ mode=1;
+ } else if (mode==1) {
+ snd.stop();
+ mode=0;
+ }
+ }
+
+ function previous_slide() {
+ if (mode<2) {
+ if (mode==0) { mode=1; }
+ snd.stop();
+ if (position>0) {
+ sound_position=times[position-1];
+ } else {
+ sound_position=0;
+ }
+ snd.start(sound_position/1000.0,0);
+ }
+ }
+
+ function next_slide() {
+ if (mode<2) {
+ if (mode==0) { mode=1; }
+ snd.stop();
+ sound_position = times[position+1];
+ if (sound_position>sound_length) {
+ sound_position=sound_length-500;
+ }
+ snd.start(sound_position/1000.0,0);
+ }
+ }
+
+ function first_slide() {
+ snd.stop();
+ snd.start(0,0);
+ slides.gotoAndStop(1);
+ position=0;
+ mode=1;
+ show_slide=true;
+ }
+
+ function last_slide() {
+ snd.stop();
+ sound_position = times[maxtimes-1];
+ slides.gotoAndStop(maxtimes);
+ show_slide=false;
+ snd.start(sound_position/1000.0,0);
+ }
+
+ function toogle_fullscreen() {
+ if(Stage.displayState == "normal"){
+ Stage.displayState="fullScreen";
+ } else {
+ Stage.displayState="normal";
+ }
+ }
+
+ Mouse.onMouseDown = function() {
+ if ((getTimer() - lastClick) < 400) {
+ pause_or_play();
+ } else {
+ lastClick = getTimer();
+ }
+ };
+
+
+ key_listen=new Object();
+
+ key_listen.onKeyDown = function() {
+ switch (Key.getCode()) {
+ case 32:
+ pause_or_play();
+ break;
+ case 37:
+ previous_slide();
+ break;
+ case 38:
+ first_slide();
+ break;
+ case 39:
+ next_slide();
+ break;
+ case 40:
+ last_slide();
+ break;
+ case 70:
+ toogle_fullscreen();
+ break;
+ }
+ };
+
+ function check_time() {
+ if (mode==1) {
+ if ( sound_position + 50 > sound_length) {
+ snd.stop();
+ mode=2;
+ if(Stage.displayState == "fullScreen"){
+ Stage.displayState="normal";
+ }
+ } else {
+ if ((snd.position>=times[position])&&(snd.position<times[position+1])) {
+ if (show_slide) {
+ slides.gotoAndStop(position+1);
+ show_slide=false;
+ }
+ } else {
+ if (position>maxtimes) {
+ snd.stop();
+ mode=2;
+ } else {
+ if (snd.position<times[position]) {
+ position-=1;
+ } else {
+ position+=1;
+ }
+ show_slide=true;
+ }
+ }
+ }
+ }
+ }
+
+ setInterval(check_time, 10);
+
+ mode=1;
+ snd.start(0,0);
+ Stage["displayState"] = "fullScreen";
+ Mouse.addListener(Mouse);
+ Key.addListener(key_listen);
+
+ .end
+
+ .frame 1
+ .put slides
+ .stop slides
+
+ .end
+ ]])
+
+ raw_times:close()
+ swf_times:close()
+
+ os.execute('pdf2swf -f -T 8 -s filloverlap -s linksopennewwindow "' .. document.main_file .. '" -o "' .. document.slides_swf .. '"')
+ os.execute('swfc "' .. document.presentation_script .. '"')
+ if io.exists(document.presentation_swf) then os.remove(document.presentation_script) os.remove(document.slides_swf) end
+ \stopluacode
+\stopbuffer
+
+\startbuffer[flash-loader]
+ \startluacode
+ local raw_times = io.open(document.original_times)
+ local loader_times = io.open(document.loader_script, "w")
+
+ fig = figures.getinfo(document.main_file)
+ function dimension_bp(dimension)
+ return math.floor(dimension*number.dimenfactors.bp)
+ end
+
+ loader_times:write([[# Preloader script, generated by PresVoz
+ #
+ # Copyright (C) 2009-2021 Pablo Rodríguez
+ #
+ # 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 <http://www.gnu.org/licenses>.
+ #
+ # Additional permission under GNU GPL version 3 section 7
+ #
+ # As a special exception, if you create a document which uses this
+ # script, and compile this script or a modified version of this script
+ # into the document, this script does not by itself cause the resulting
+ # document to be covered by the GNU General Public License.
+ # This exception does not however invalidate any other reasons why
+ # the document might be covered by the GNU General Public License.
+
+ .flash filename="]] .. document.loader_swf .. [[" version=8 fps=12"
+ .font roman "]] .. resolvers.findfile("iRaccoonShowBold.otf") .. [[" glyphs=" %()KB0123456789/:,.CPDNuk[]resntiocanbld!"
+ .edittext newloader font=roman color=#ffff00 size=30% width=350 height=30 border=none align="center" noselect variable=load_text
+ .box placeholder width=]] .. dimension_bp(fig.used.width) .. [[ height=]] .. dimension_bp(fig.used.height) .. "\n" .. [[
+ .box fsarea fill=#ffffff00 color=#ffffff00 width=]] .. dimension_bp(fig.used.width) .. [[ height=]] .. dimension_bp(fig.used.height) .. "\n" .. [[
+ .outline fscreen_outline: M 62.78125 18.703125 L 43.367188 23.734375 L 38.390625 43.09375 L 42.109375 39.375 L 48.671875 45.9375 L 65.625 29.039062 L 59.0625 22.421875 L 62.78125 18.703125 z M 199.71875 18.703125 L 203.4375 22.421875 L 196.875 29.039062 L 213.773438 45.9375 L 220.390625 39.375 L 224.109375 43.09375 L 219.132812 23.734375 L 199.71875 18.703125 z M 83.125 45.9375 C 73.429688 45.9375 65.625 53.742188 65.625 63.4375 L 65.625 133.4375 C 65.625 143.132812 73.429688 150.9375 83.125 150.9375 L 179.375 150.9375 C 189.070312 150.9375 196.875 143.132812 196.875 133.4375 L 196.875 63.4375 C 196.875 53.742188 189.070312 45.9375 179.375 45.9375 L 83.125 45.9375 z M 48.726562 150.9375 L 42.109375 157.5 L 38.390625 153.78125 L 43.367188 173.140625 L 62.78125 178.171875 L 59.0625 174.453125 L 65.625 167.835938 L 48.726562 150.9375 z M 213.773438 150.9375 L 196.875 167.835938 L 203.4375 174.453125 L 199.71875 178.171875 L 219.132812 173.140625 L 224.109375 153.78125 L 220.390625 157.5 L 213.773438 150.9375 z .end
+ .outline fulls_outline: M 17.5 0 L 245 0 C 254.695312 0 262.5 7.804688 262.5 17.5 L 262.5 179.375 C 262.5 189.070312 254.695312 196.875 245 196.875 L 17.5 196.875 C 7.804688 196.875 0 189.070312 0 179.375 L 0 17.5 C 0 7.804688 7.804688 0 17.5 0 z .end
+ .filled fscreen outline=fscreen_outline fill=#969696ff color=#969696ff
+ .filled fulls outline=fulls_outline fill=#64646496 color=#64646496
+
+ .button fscr_button
+ .show fscreen as=idle
+ .show fscreen as=area
+ .show fscreen as=hover
+ .show fscreen as=pressed
+ .end
+
+ .button fs_area
+ .show fsarea as=idle
+ .show fsarea as=area
+ .show fsarea as=hover
+ .show fsarea as=pressed
+ .on_release:
+ fullscreen_button._visible = 0;
+ fs_area._visible = 0;
+ Stage["displayState"] = "fullScreen";
+ _root.load_text = "[Click to start]";
+ _root.dlprogress_mvclip._visible = true;
+ the_presentation = "./]] .. document.presentation_filename .. [[";
+ this.loadMovie(the_presentation, this.placeholder);
+ .end
+ .end
+
+ .sprite fullscreen_button
+ .put fscreen
+ .put fulls
+ .end
+
+ .swf first_slide "]] .. document.first_slide_swf .. [["
+ .frame 1
+ .put first_slide
+ .stop first_slide
+ .put fullscreen_button
+ .stop fullscreen_button
+ .put fs_area
+ .stop fs_area
+
+ .action:
+ slide_height=Stage.height;
+ slide_width=Stage.width;
+
+ var contextual = new ContextMenu();
+ function ssurl(){ getURL("https://www.presvoz.tk", "_blank"); }
+
+ switch (System.capabilities.language) {
+ case "en" :
+ ss_message = "Done with PresVoz  🤞🐞";
+ break;
+ case "es" :
+ ss_message = "Hecho con PresVoz  🤞🐞";
+ break;
+ case "gl" :
+ ss_message = "Feito con PresVoz  🤞🐞";
+ break;
+ case "pt" :
+ ss_message = "Feito con PresVoz  🤞🐞";
+ break;
+ case "it" :
+ ss_message = "Fatto con PresVoz  🤞🐞";
+ break;
+ case "fr" :
+ ss_message = "Fait avec PresVoz  🤞🐞";
+ break;
+ case "de" :
+ ss_message = "Erezeugt mit PresVoz  🤞🐞";
+ break;
+ case "nl" :
+ ss_message = "Gedaan med PresVoz  🤞🐞";
+ break;
+ case "el" :
+ ss_message = "Kατασκευασμένος με PresVoz  🤞🐞";
+ break;
+ default:
+ ss_message = "Made with PresVoz  🤞🐞";
+ break;
+ }
+
+ contextual.hideBuiltInItems();
+ ss_url = new ContextMenuItem(ss_message, ssurl);
+ contextual.customItems.push(ss_url);
+ _root.menu = contextual;
+
+ counter_percent=(slide_width/800)*100;
+ newloader._xscale=counter_percent;
+ newloader._yscale=counter_percent;
+ newloader._x = (slide_width-(newloader._width))/2;
+ newloader._y = (slide_height-newloader._height)/2;
+
+ button_percent = (slide_width/600)*100;
+ fullscreen_button._xscale = button_percent;
+ fullscreen_button._yscale = button_percent;
+ fullscreen_button._x = (slide_width-(fullscreen_button._width))/2;
+ fullscreen_button._y = (slide_height-fullscreen_button._height)/2;
+
+ _root.createEmptyMovieClip("dlprogress_mvclip", 0);
+ dlprogress_mvclip.createEmptyMovieClip("bar", 1);
+ dlprogress_mvclip.createEmptyMovieClip("stroke", 2);
+
+ with (dlprogress_mvclip.stroke) {
+ lineStyle(0, 0xFF0000, 30);
+ moveTo(0, 0);
+ lineTo(300, 0);
+ lineTo(300, 40);
+ lineTo(0, 40);
+ lineTo(0, 0);
+ }
+ with (dlprogress_mvclip.bar) {
+ beginFill(0xFF0000, 30);
+ moveTo(0, 0);
+ lineTo(300, 0);
+ lineTo(300, 40);
+ lineTo(0, 40);
+ lineTo(0, 0);
+ endFill();
+ _xscale = 0;
+ }
+ dlprogress_mvclip._x = (slide_width-dlprogress_mvclip._width)/2;
+ dlprogress_mvclip._y = (slide_height-dlprogress_mvclip._height)/2;
+
+ dlprogress_mvclip._visible = false;
+ fs_listen=new Object();
+
+ fs_listen.onKeyDown = function() {
+ if (Key.isDown(13)) {
+ if(Stage.displayState == "normal"){
+ Stage.displayState="fullScreen";
+ } else {
+ Stage.displayState="normal";
+ }
+ }
+ };
+
+ Key.addListener(fs_listen);
+
+
+ .end
+
+ .sprite images
+ .put placeholder alpha=0%
+ .action:
+ the_presentation = "./]] .. document.presentation_filename .. [[";
+ first_loading = new Object();
+ first_loading.onMouseDown = function () {
+ load_swf = new MovieClipLoader();
+ load_swf.loadClip(the_presentation, placeholder);
+ listen_loading = new Object();
+ listen_loading.onLoadStart = function(target) {
+ _root.dlprogress_mvclip.bar._xscale = 0;
+ _starttime = gettimer();
+ };
+ listen_loading.onLoadError = function(){
+ _root.load_text = "Presentation cannot be loaded!";
+ };
+ listen_loading.onLoadProgress = function(target, bytesLoaded, bytesTotal) {
+ downldtime = (gettimer() - _starttime) / 1000;
+ _root.load_text = (String (Math.round ((bytesLoaded * 100) / bytesTotal)) + "% (" + Math.round((bytesLoaded / 1024) / downldtime) + " KB/s)");
+ _root.dlprogress_mvclip.bar._xscale = Math.round(bytesLoaded/bytesTotal*100);
+ keeping_awake = setInterval(function(){}, 1000);
+ };
+ listen_loading.onLoadComplete = function(target) {
+ clearInterval(keeping_awake);
+ _root.load_text = "";
+ _root.dlprogress_mvclip._visible = 0;
+ _root.dlprogress_mvclip.bar._visible = 0;
+ _root.first_slide._visible = 0;
+ };
+ load_swf.addListener(listen_loading);
+ };
+ Mouse.addListener(first_loading);
+ .end
+ .end
+
+ .put newloader
+ .stop newloader
+ .end]])
+
+ raw_times:close()
+ loader_times:close()
+
+ os.execute('pdf2swf -f -p 1 -T 8 -s filloverlap -s linksopennewwindow "' .. document.main_file .. '" -o "' .. document.first_slide_swf .. '"')
+ os.execute('swfc "' .. document.loader_script .. '"')
+ if io.exists(document.loader_swf) then os.remove(document.loader_script) os.remove(document.first_slide_swf) end
+ \stopluacode
+\stopbuffer
+
+\def\TimeLine#1%
+ {\cldcontext{ document.timeline_filename }}
+
+\def\SoundFile#1%
+ {\cldcontext{ document.compressed_audio }}
+
+\startbuffer[generate-timeline]
+ \startluacode
+ local raw_times = io.open(document.original_times)
+ local js_times = io.open(document.timeline_filename, "w")
+
+ js_times:write("\\startJSpreamble times used now")
+ js_times:write("\n")
+ js_times:write("var times = [];")
+ js_times:write("\n")
+ js_times:write("var maxtimes = times[times.length - 1];")
+ js_times:write("\n")
+ js_times:write("times[0] = 0;")
+ js_times:write("\n")
+ line_number = 0
+ while true do
+ line = raw_times:read()
+ if line == nil then break end
+ if line:match("%D") == nil then
+ line_number = line_number + 1
+ print ("times["..line_number.."] = " .. line .. ";")
+ js_times:write("times["..line_number.."] = " .. line .. ";")
+ js_times:write("\n")
+ end
+ end
+
+ js_times:write("\\stopJSpreamble")
+
+ raw_times:close()
+ js_times:close()
+ \stopluacode
+\stopbuffer
+
+\startmode[*first]
+\getbuffer[generate-timeline]
+\doiftext
+ {\ctxlua{if os.which('pdf2swf') and os.which('swfc') then context("a") end}}
+ {\getbuffer[flash-presentation]
+ \getbuffer[flash-loader]}
+\stopmode
+
+\getfiguredimensions[\Presentation]
+
+\setupexternalfigures[interaction=all]
+
+\setupinteraction
+ [state=start,
+ color=,
+ contrastcolor=,
+ style=,
+ focus=standard]
+
+\useJSscripts[presvoz.mkxl]
+\startnotmode[*first]
+ \useJSscripts[\TimeLine{\Presentation}]
+\stopnotmode
+
+\definefontfamily
+ [mainface]
+ [rm]
+ [Latin Modern Sans]
+
+\definefontfamily
+ [mainface]
+ [ss]
+ [Flechitas]
+
+\setupbodyfont
+ [mainface, 25pt]
+
+\setupmakeup
+ [page]
+ [pagestate=start,
+ style=\bfd,
+ color=white,
+ footerstate=start,
+ align=center]
+
+\definecolor[transparent-gray]
+ [r=.45, g=.45, b=.45]
+
+\defineviewerlayer[fullscreen][state=start]
+\defineviewerlayer[unfullscreen][state=stop]
+\defineviewerlayer[play][state=start]
+\defineviewerlayer[pause][state=stop]
+
+\definecolor[transparent][r=1, a=1, t=0]
+
+\startbuffer[fullscreen-button]
+ \startoverlay
+ {\viewerlayer[fullscreen]{C}}
+ {\viewerlayer[unfullscreen]{I}}
+ {\goto{\color[transparent]{C}}[JS(SwitchFS{})]}
+ \stopoverlay
+\stopbuffer
+
+\startbuffer[play-pause-button]
+ \startoverlay
+ {\viewerlayer[play]{R}}
+ {\viewerlayer[pause]{H}}
+ {\goto{\color[transparent]{C}}[JS(PlayPauseSound{})]}
+ \stopoverlay
+\stopbuffer
+
+\def\SlideNavigationButtons{%
+ \goto{F}[JS(GoToFirstSlide{})]\,%
+ \goto{B}[JS(GoToPreviousSlide{})]\,%
+ \inlinebuffer[play-pause-button]\,%
+ \goto{S}[JS(StopSound{})]\,%
+ \goto{N}[JS(GoToNextSlide{})]\,%
+ \goto{L}[JS(GoToLastSlide{})]\quad
+ \null\inlinebuffer[fullscreen-button]%
+ }
+
+\definelayer[player-buttons]
+ [x=.5\dimexpr\figurewidth\relax,
+ y=.9525\dimexpr\figureheight\relax,
+ location=middle,
+ state=repeat]
+
+\definelayer[placesound]
+
+\startbuffer[placesound]
+ \definerenderingwindow[soundplace]
+ [width=0pt, height=0pt, frame=on]
+
+\doiftextelse{\ctxlua{if document.compressed_audio == document.audio_opus then context("opus") end}}
+ {\userendering[mainsound][audio/opus][\SoundFile{\Presentation}][embed=yes, list=no]}
+ {\userendering[mainsound][audio/mp3][\SoundFile{\Presentation}][embed=yes, list=no]}
+
+ \placerenderingwindow[soundplace][mainsound]
+\stopbuffer
+
+\setupbackgrounds
+ [page]
+ [background={foreground, placesound, player-buttons}]
+
+
+\setlayer[player-buttons]
+ {\switchtobodyfont[sans, \cldcontext{tex.dimen.paperwidth/1000000}pt]\color[transparent-gray]{\SlideNavigationButtons}}
+
+\resetpagenumber
+
+\dorecurse{\noffigurepages}{\startTEXpage[pagestate=start]
+\ifnum\recurselevel=1 \setlayer[placesound]{\getbuffer[placesound]}\fi
+\externalfigure[\Presentation][page=\recurselevel]
+\stopTEXpage}
+\stopnotmode
+
+\startluacode
+luatex.wrapup(
+ function()
+ os.remove(presvoz_name)
+ os.rename(tex.jobname .. ".pdf", presvoz_name)
+ end
+)
+\stopluacode
+\stoptext
+\stoplmtxmode
+
+\startmkivmode
+\setupinteractionscreen[option=max]
+\startTEXpage[offset=2em, align=center]
+ \ssbf\color[darkgreen]{\LMTX\ required,\\I’m afraid.}
+\stopTEXpage
+\stopmkivmode
+\stoptext
diff --git a/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/presvoz.mkxl b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/presvoz.mkxl
new file mode 100644
index 0000000000..8d8ecd3cde
--- /dev/null
+++ b/macros/context/contrib/context-handlecsv/context-presvoz-master-5196bdec981cf48b83896ec7b7009fda20d9106f/tex/context/third/presvoz/presvoz.mkxl
@@ -0,0 +1,183 @@
+\startJSpreamble PresVoz used now
+var ocgs = this.getOCGs(0);
+this.pageNum = 0;
+
+var label = "mainsound" ;
+var rendition = this.media.getRendition(label) ;
+var screen = this.media.getAnnot({nPage: 0, cAnnotTitle: label}) ;
+var main_sound_player;
+
+function ToogleFSButton() {
+ if (app.fs.isFullScreen) {
+ ocgs[0].state = false;
+ ocgs[3].state = true;
+ } else {
+ ocgs[0].state = true;
+ ocgs[3].state = false;
+ }
+}
+
+function TooglePlayPauseButton() {
+ if (main_sound_player.isPlaying) {
+ ocgs[1].state = true;
+ ocgs[2].state = false;
+ } else {
+ ocgs[1].state = false;
+ ocgs[2].state = true;
+ }
+}
+
+function timer_resume() {
+ check_time = app.setInterval("advance_slide()", 10);
+}
+
+function timer_pause() {
+ app.clearInterval(check_time);
+}
+
+function jump() {
+ if (!main_sound_player.isOpen) { main_sound_player.open(); }
+
+ if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) {
+ if (this.pageNum < times.length) {
+ if (!main_sound_player.isPlaying) {
+ timer_resume();
+ }
+
+ var jump_time = times[this.pageNum] / 1000;
+
+ main_sound_player.pause();
+ main_sound_player.seek({time: jump_time});
+ main_sound_player.play();
+ }
+ }
+}
+
+function advance_slide() {
+ if (!main_sound_player.isOpen) { main_sound_player.open(); }
+ if ( typeof main_sound_player.where() != "undefined") {
+ var current_offset = 1000 * main_sound_player.where().time;
+
+ if (current_offset >= times[this.pageNum + 1]) {
+ this.pageNum += 1;
+ } else if (current_offset <= times[this.pageNum - 1]) {
+ this.pageNum -= 1;
+ }
+ }
+}
+
+function start_player() {
+ main_sound_player = app.media.createPlayer({
+ rendition: rendition,
+ annot: screen,
+ settings: {
+ autoPlay: false,
+ },
+ events: {
+ onDone: function() {
+ timer_pause();
+ app.fs.isFullScreen = false;
+ ToogleFSButton();
+ this.pageNum = this.numPages - 1;
+ },
+ afterDone: function() {
+ main_sound_player.pause();
+ TooglePlayPauseButton();
+ main_sound_player.seek({time: maxtimes});
+ this.pageNum = this.numPages - 1;
+ },
+ onEscape: function() {
+ app.fs.isFullScreen = false;
+ ToogleFSButton();
+ },
+ afterEscape: function() {
+ main_sound_player.pause();
+ TooglePlayPauseButton();
+ },
+ afterPause: function() {
+ timer_pause();
+ TooglePlayPauseButton();
+ },
+ onPlay: function() {
+ app.fs.isFullScreen = true;
+ ToogleFSButton();
+ },
+ afterPlay: function() {
+ timer_resume();
+ TooglePlayPauseButton();
+ },
+ afterReady: function() {
+ main_sound_player.play();
+ },
+ },
+ });
+ main_sound_player.open();
+}
+
+function GoToFirstSlide(label) {
+ this.pageNum = 0;
+ if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) {
+ if ( main_sound_player.isPlaying ) { jump(); }
+ }
+}
+
+function PlayPauseSound() {
+ if ( typeof main_sound_player == "undefined" ) {
+ start_player();
+ } else if ( !main_sound_player.isPlaying ) {
+ if (!main_sound_player.isOpen) { main_sound_player.open(); }
+ if ( typeof main_sound_player.where() != "undefined" && main_sound_player.where().time == 0 )
+ { this.pageNum = 0; }
+ timer_resume();
+ main_sound_player.play();
+ } else if ( main_sound_player.isPlaying ) {
+ timer_pause();
+ main_sound_player.pause();
+ }
+}
+
+function StopSound() {
+ if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) {
+ main_sound_player.pause();
+ main_sound_player.seek({time: 0});
+ }
+ this.pageNum = 0;
+}
+
+function GoToLastSlide(label) {
+ this.pageNum = this.numPages - 1;
+ if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) {
+ if ( main_sound_player.isPlaying ) { jump(); }
+ }
+}
+
+function GoToNextSlide(label) {
+ ++this.pageNum;
+ if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) {
+ if ( main_sound_player.isPlaying ) { jump(); }
+ }
+}
+
+function GoToPreviousSlide(label) {
+ --this.pageNum;
+ if ( typeof main_sound_player != "undefined" || ( typeof main_sound_player != "undefined" && main_sound_player.isOpen )) {
+ if ( main_sound_player.isPlaying ) { jump(); }
+ }
+}
+
+function SwitchFS() {
+ if (app.fs.isFullScreen == false) {
+ app.fs.isFullScreen = true;
+ if (app.fs.isFullScreen) {
+ ocgs[0].state = false;
+ ocgs[3].state = true;
+ }
+ } else {
+ app.fs.isFullScreen = false;
+ if (!app.fs.isFullScreen) {
+ ocgs[0].state = true;
+ ocgs[3].state = false;
+ }
+ }
+}
+\stopJSpreamble