Add --new flag which creates a skeleton talk.
[techtalk-pse.git] / techtalk-pse.pl
index 5d9369c..5f5b688 100755 (executable)
@@ -67,10 +67,38 @@ there is a discussion on L<WHAT MAKES A GOOD TALK>.
 
 =head1 RUNNING THE TOOL FROM THE COMMAND LINE
 
-A Tech Talk PSE talk is not a single file, but a directory full of
-files.  (If you want to start a new talk, see the L</TUTORIAL> section
-below).  To display or run the talk, change into the directory
-containing all those files and run the C<techtalk-pse> command:
+=head2 CREATING A NEW TALK
+
+Tech Talk PSE talks are just directories containing C<*.html> and
+C<*.sh> (shell script) files:
+
+ 0010-introduction.html
+ 0500-demonstration.sh
+ 9900-conclusion.html
+
+The filenames that Tech Talk PSE considers to be slides have to match
+the regular expression:
+
+ ^(\d+)(?:-.*)\.(html|sh)$
+
+(any other file or subdirectory is ignored).  Shell scripts I<must>
+be executable.
+
+You can create a new talk just by creating an empty directory and
+adding files as above, but you can also create a useful skeleton talk
+like this:
+
+ mkdir talk
+ cd talk
+ techtalk-pse --new
+
+The C<--new> flag will refuse to overwrite any existing files, so you
+should run it in an empty directory.
+
+=head2 DISPLAYING AN EXISTING TALK
+
+To display or run a talk, change into the directory containing all
+those files and run the C<techtalk-pse> command:
 
  cd /path/to/talk/; techtalk-pse
 
@@ -103,6 +131,16 @@ You cannot use this with the B<-n> / B<--start> option.
 
 =cut
 
+my $new;
+
+=item B<--new>
+
+Create a new outline talk in an empty directory.
+
+This refuses to overwrite existing files.
+
+=cut
+
 my $start;
 
 =item B<-n SLIDE> | B<--start SLIDE>
@@ -143,15 +181,12 @@ Display version number and exit.
 =cut
 
 my $mozembed;
-my $mozembed_first;
-my $mozembed_last;
 
 GetOptions ("help|?" => \$help,
             "last" => \$last,
             "mozembed" => \$mozembed,
-            "mozembed-first" => \$mozembed_first,
-            "mozembed-last" => \$mozembed_last,
             "n=s" => \$start,
+            "new" => \$new,
             "splash!" => \$splash,
             "start=s" => \$start,
             "verbose" => \$verbose,
@@ -170,11 +205,7 @@ if ($version) {
 die "techtalk-pse: cannot use --start and --last options together\n"
     if defined $last && defined $start;
 
-# Run with --mozembed: see below.
-run_mozembed () if $mozembed;
-
-# Normal run of the program.
-die "techtalk-pse: too many arguments\n" if @ARGV >= 2;
+die "techtalk-pse: too many arguments\n" if !$mozembed && @ARGV >= 2;
 
 # Get the true name of the program.
 $0 = abs_path ($0);
@@ -196,6 +227,144 @@ if (@ARGV > 0) {
 my $talkdir = getcwd;
 $ENV{talkdir} = $talkdir;
 
+# Create a new talk (--new flag).
+if ($new) {
+    my %files = (
+        "essay.txt" => {
+            mode => 0644,
+            desc => "essay and background notes",
+            c => 'Start by writing your thoughts in this file as an essay.
+
+You can then provide this as extra background reading material
+for your audience after the talk.'
+        },
+
+        "0010-introduction.html" => {
+            mode => 0644,
+            desc => "title slide",
+            c => '<link rel="stylesheet" href="style.css" type="text/css"/>
+<script src="code.js" type="text/javascript"></script>
+
+<div class="titlepage">
+<p>A Technical Talk</p>
+<author>by John Smith (jsmith@example.com)</author>
+</div>'
+        },
+
+        "0500-demonstration.html" => {
+            mode => 0644,
+            desc => "intro to demonstration slide",
+            c => '<link rel="stylesheet" href="style.css" type="text/css"/>
+<script src="code.js" type="text/javascript"></script>
+
+<h1>Demonstration</h1>
+
+<p>The next slide demonstrates a gnome terminal.</p>
+
+<p>Hit the UP arrow to access the preloaded history.</p>'
+        },
+
+        "0510-demonstration.sh" => {
+            mode => 0755,
+            desc => "shell demonstration slide",
+            c => '#!/bin/bash -
+source functions
+add_history ls -l
+add_history virt-df -a
+terminal --title="Demonstration terminal"'
+        },
+
+        "9900-conclusion.html" => {
+            mode => 0644,
+            desc => "last slide",
+            c => '<link rel="stylesheet" href="style.css" type="text/css"/>
+<script src="code.js" type="text/javascript"></script>
+
+<h1>Conclusions</h1>
+
+<p>The conclusion page</p>'
+        },
+
+        "functions" => {
+            mode => 0644,
+            desc => "shell script helper functions",
+            c => '# -*- shell-script -*-
+
+# Place any local environment variables and settings in "local".
+if [ -f local ]; then source local; fi
+
+export PS1=\'\\$ \'
+
+export HISTFILE=$talkdir/history
+
+rm -f $HISTFILE
+touch $HISTFILE
+
+add_history ()
+{
+    echo "$@" >> $HISTFILE
+}
+
+# Note: If you hand-configure gnome-terminal by adding a
+# new profile (eg. with larger fonts) then you can use that
+# profile here by replacing the --window flag with
+# --window-with-profile=ProfileName
+
+terminal ()
+{
+    chmod -w $HISTFILE
+    exec \\
+        gnome-terminal \\
+        --window \\
+        --geometry=+140+64 \\
+        --hide-menubar \\
+        --disable-factory \\
+        -e \'/bin/bash --norc\' \\
+        "$@"
+}
+'
+        },
+
+        "style.css" => {
+            mode => 0644,
+            desc => "HTML stylesheet",
+            c => 'body {
+    font-size: 28pt;
+    font-family: liberation, helvetica;
+}
+
+h1 {
+    font-size: 48px;
+    top: 8;
+    left: 0;
+    border-bottom: 2px solid #ccc;
+}
+
+div.titlepage {
+    margin-top: 100px;
+    text-align: center;
+}
+'
+        },
+    );
+
+    # Refuse to overwrite existing files.
+    foreach (sort keys %files) {
+        die "techtalk-pse: refusing to overwrite '$_'\n" if -f $_;
+    }
+
+    # Write the files.
+    foreach (sort keys %files) {
+        print "writing $_ ($files{$_}{desc}) ...\n";
+        open FILE, ">$_" or die "$_: open: $!";
+        print FILE $files{$_}{c} or die "$_: print: $!";
+        close FILE or die "$_: close: $!";
+        chmod $files{$_}{mode}, $_ or die "$_: chmod: $!";
+    }
+
+    exit 0;
+}
+
 # Get the files.
 my @files;
 my %files;
@@ -233,6 +402,11 @@ if (@files == 0) {
     warn "techtalk-pse: no files found, continuing anyway ...\n"
 }
 
+# Run with --mozembed: see below.
+run_mozembed () if $mozembed;
+
+# Else, normal run of the program ...
+
 # Work out what slide we're starting on.
 my $current;
 if (defined $current) {
@@ -276,6 +450,7 @@ MAIN: while (1) {
             $i++ if $go eq "NEXT" && $i+1 < @files;
             $i = 0 if $go eq "FIRST";
             $i = $#files if $go eq "LAST";
+            $i = $1 if $go =~ /^I_(\d+)$/;
             $current = $files[$i];
         }
     } else {
@@ -303,11 +478,7 @@ sub show_slide
         # subprocess, so when it segfaults we don't care.  If all goes
         # well and it doesn't crash, it should print a line 'RESULT FOO'
         # where 'FOO' is the instruction (eg. 'NEXT', 'PREV', 'QUIT' etc).
-        my @cmd = ($0, "--mozembed");
-        push @cmd, "--mozembed-first" if exists $slide->{first};
-        push @cmd, "--mozembed-last" if exists $slide->{last};
-        my $url = "file://$talkdir/" . $slide->{name};
-        push @cmd, $url;
+        my @cmd = ($0, "--mozembed", $talkdir, $slide->{name});
        print STDERR "running subcommand: ", join (" ", @cmd), "\n"
            if $verbose;
         open CMD, "-|", @cmd
@@ -391,8 +562,14 @@ sub run_mozembed
     my $vbox = Gtk2::VBox->new ();
     my $moz = Gtk2::MozEmbed->new ();
 
+    reread_directory ();
+
+    my $name = $ARGV[1];
+    $current = $files{$name};
+    my $url = "file://$talkdir/$name";
+
     my $bbox =
-        make_button_bar ($mozembed_first, $mozembed_last,
+        make_button_bar ($current->{first}, $current->{last},
                          sub { print "RESULT ", $_[0], "\n"; $w->destroy }
         );
 
@@ -408,7 +585,8 @@ sub run_mozembed
     });
     $w->show_all ();
 
-    $moz->load_url ($ARGV[0]);
+    $moz->load_url ($url);
+
     Gtk2->main;
 
     exit 0;
@@ -423,6 +601,7 @@ sub make_button_bar
     my %params = @_;
 
     my $bbox = Gtk2::Toolbar->new ();
+    $bbox->set_style ("GTK_TOOLBAR_TEXT");
 
     my $i = 0;
 
@@ -461,10 +640,34 @@ sub make_button_bar
     $blast->show ();
     $optsmenu->append ($blast);
 
+    my $slidesmenu = Gtk2::Menu->new ();
+    foreach (@files) {
+        my $item = Gtk2::MenuItem->new ($_->{name});
+        my $index = $_->{i};
+        $item->signal_connect (activate => sub { \&$cb ("I_$index") });
+        $item->set_sensitive ($current->{i} != $index);
+        $item->show ();
+        $slidesmenu->append ($item);
+    }
+
+    my $bslides = Gtk2::MenuItem->new ("Slides");
+    $bslides->set_submenu ($slidesmenu);
+    $bslides->show ();
+    $optsmenu->append ($bslides);
+
     my $sep2 = Gtk2::SeparatorMenuItem->new ();
     $sep2->show ();
     $optsmenu->append ($sep2);
 
+    my $bscreenshot = Gtk2::MenuItem->new ("Take a screenshot");
+    $bscreenshot->signal_connect (activate => sub { screenshot () });
+    $bscreenshot->show ();
+    $optsmenu->append ($bscreenshot);
+
+    my $sep3 = Gtk2::SeparatorMenuItem->new ();
+    $sep3->show ();
+    $optsmenu->append ($sep3);
+
     my $bquit = Gtk2::MenuItem->new ("Quit");
     $bquit->signal_connect (activate => sub { \&$cb ("QUIT") });
     $bquit->show ();
@@ -479,8 +682,36 @@ sub make_button_bar
     return $bbox;
 }
 
+# Try running the external "gnome-screenshot" program, if it's
+# available, else take a screenshot using gdk routines.
+sub screenshot
+{
+    system ("gnome-screenshot");
+
+    if ($? == -1) {
+        # We are going to save the entire screen.
+        my $root = Gtk2::Gdk->get_default_root_window ();
+        my ($width, $height) = $root->get_size;
+
+        # Create blank pixbuf to hold the image.
+        my $gdkpixbuf = Gtk2::Gdk::Pixbuf->new ('rgb',
+                                                0, 8, $width, $height);
+
+        $gdkpixbuf->get_from_drawable ($root, $root->get_colormap (),
+                                       0, 0, 0, 0, $width, $height);
+
+        my $i = 0;
+        $i++ while -f "screenshot$i.png";
+        $gdkpixbuf->save ("screenshot$i.png", 'png');
+    }
+
+    return FALSE;
+}
+
 1;
 
+__END__
+
 =head1 TUTORIAL
 
 =head2 START WRITING A TALK
@@ -489,18 +720,16 @@ sub make_button_bar
 L</WHAT MAKES A GOOD TALK> below].
 
 To start your talk, all you have to do is to make a new directory
-somewhere:
+somewhere and run Tech Talk PSE with the C<--new> flag to create an
+outline:
 
  mkdir talk
  cd talk
+ techtalk-pse --new
 
 A tech talk consists of HTML files ("slides") and shell scripts.  The
 filenames must start with a number, followed optionally by a
-description, followed by the extension (C<.html> or C<.sh>).  So to
-start our talk with two slides:
-
- echo "This is the introduction" > 0010-introduction.html
- echo "This is the second slide" > 0020-second.html
+description, followed by the extension (C<.html> or C<.sh>).
 
 To run it, run the command from within the talk directory: