largely complete automated generation of cheat sheets & bindings from templates,...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 31 Jul 2009 00:34:36 +0000 (00:34 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 31 Jul 2009 00:34:36 +0000 (00:34 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5446 d708f5d6-7413-0410-9779-e7cbd77b26cf

tools/fmt-bindings

index 8aed63daccde4618d8d6f71cdfffdcc60b917c24..55fe42710deccb89612c8aa5e238aa2c4fb81871 100755 (executable)
 #!/usr/bin/perl
 
+# import module
+use Getopt::Long; 
+
+$semicolon = ";"; # help out stupid emacs
 $in_group_def = 0;
 $group_name;
 $group_text;
 $group_key;
+$group_number = 0;
 %group_names;
 %group_text;
+%group_bindings;
+%modifier_map;
+%group_numbering;
+
+$platform = linux;
+
+GetOptions ("platform=s" => \$platform);
+
+if ($platform eq "osx") {
+    $gtk_modifier_map{'PRIMARY'} = 'meta';
+    $gtk_modifier_map{'SECONDARY'} = 'Mod1';
+    $gtk_modifier_map{'TERTIARY'} = 'Shift';
+    $gtk_modifier_map{'LEVEL4'} = 'Control';
+    $gtk_modifier_map{'WINDOW'} = 'Mod1';
+
+    $cs_modifier_map{'PRIMARY'} = 'Command';
+    $cs_modifier_map{'SECONDARY'} = 'Alt';
+    $cs_modifier_map{'TERTIARY'} = 'Shift';
+    $cs_modifier_map{'LEVEL4'} = 'Control';
+    $cs_modifier_map{'WINDOW'} = 'Alt';
+
+} else {
+
+    $gtk_modifier_map{'PRIMARY'} = 'Control';
+    $gtk_modifier_map{'SECONDARY'} = 'Alt';
+    $gtk_modifier_map{'TERTIARY'} = 'Shift';
+    $gtk_modifier_map{'LEVEL4'} = 'Mod4';
+    $gtk_modifier_map{'WINDOW'} = 'Alt';
+
+    $cs_modifier_map{'PRIMARY'} = 'Control';
+    $cs_modifier_map{'SECONDARY'} = 'Alt';
+    $cs_modifier_map{'TERTIARY'} = 'Shift';
+    $cs_modifier_map{'LEVEL4'} = 'Win';
+    $cs_modifier_map{'WINDOW'} = 'Alt';
+}
+
+%keycodes = (
+    'asciicircum' => '\\verb=^=',
+    'apostrophe' => '\'',
+    'bracketleft' => '[',
+    'bracketright' => ']',
+    'braceleft' => '\\{',
+    'braceright' => '\\}',
+    'backslash' => '$\\backslash$',
+    'rightanglebracket' => '>',
+    'leftanglebracket' => '<',
+    'ampersand' => '\\&',
+    'comma' => ',',
+    'period' => '.',
+    'semicolon' => ';',
+    'colon' => ':',
+    'equal' => '=',
+    'minus' => '-',
+    'plus' => '+',
+    'grave' => '`',
+    'rightarrow' => '$\rightarrow$',
+    'leftarrow' => '$\\leftarrow$',
+    'uparrow' => '$\\uparrow$',
+    'downarrow' => '$\\downarrow$',
+    'Page_Down' => 'Page Down',
+    'Page_Up' => 'Page Up',
+    'space' => 'space',
+    'KP_' => 'KP$\_$'
+    );
 
 while (<>) {
-    next if /^\;/;
+    next if /^$semicolon/;
 
     if (/^%/) {
-
+       
        if ($in_group_def) {
            chop $group_text;
            $group_names{$group_key} = $group_name;
            $group_text{$group_key} = $group_text;
+           $group_numbering{$group_key} = $group_number;
+           # each binding entry is 2 element array. bindings
+           # are all collected into a container array. create
+           # the first dummy entry so that perl knows what we
+           # are doing.
+           $group_bindings{$group_key} = [ [] ];
        }
 
        s/^%//;
        chop;
        ($group_key,$group_name) = split (/\s+/, $_, 2);
+       $group_number++;
        $group_text = "";
        $in_group_def = 1;
        next;
     }
 
     if ($in_group_def) {
-       next if (/^[ \t]+$/);
-       $group_text .= $_;
-       $group_text;
+       if (/^@/) {
+           chop $group_text;
+           $group_names{$group_key} = $group_name;
+           $group_text{$group_key} = $group_text;
+           $in_group_def = 0;
+       } else {
+           next if (/^[ \t]+$/);
+           $group_text .= $_;
+           $group_text;
+           next;
+       }
+    }
+
+    if (/^@/) {
+       s/^@//;
+       chop;
+       ($key,$action,$binding,$text) = split (/\|/, $_, 4);
+
+       # substitute bindings
+
+       $gtk_binding = $binding;
+
+       foreach $k (keys %gtk_modifier_map) {
+           $gtk_binding =~ s/\@$k\@/$gtk_modifier_map{$k}/;
+       }
+
+       # print the accelmap output
+
+       if ($key =~ /^\+/) {
+           # remove + and don't print it in the accelmap
+           $key =~ s/^\+//;
+       } else {
+           # include this in the accelmap
+           # print "(gtk_accel_map \"<Actions>/$action\" \"$gtk_binding\")\n";
+       }
+
+       if ($key =~ /^-/) {
+           # do not include this binding in the cheat sheet
+           next;
+       }
+
+       $bref = $group_bindings{$key};
+       push (@$bref, [$binding, $text]);
+
        next;
     }
 
     next;
 }
 
-foreach $k (keys %group_names) {
-    print "GROUP: ", $k, " ", $group_names{$k}, "\n\t", $group_text{$k}, "\n";
+# Now print the cheatsheet
+
+$boilerplate_header = <<END_HEADER;
+\\documentclass[10pt,landscape]{article}
+\\usepackage{multicol}
+\\usepackage{calc}
+\\usepackage{ifthen}
+\\usepackage{palatino}
+\\usepackage[landscape]{geometry}
+
+
+% This sets page margins to .5 inch if using letter paper, and to 1cm
+% if using A4 paper. (This probably isnott strictly necessary.)
+% If using another size paper, use default 1cm margins.
+\\ifthenelse{\\lengthtest { \\paperwidth = 11in}}
+       { \\geometry{top=.5in,left=.5in,right=.5in,bottom=.5in} }
+       {\\ifthenelse{ \\lengthtest{ \\paperwidth = 297mm}}
+               {\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
+               {\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
+       }
+
+% Turn off header and footer
+\\pagestyle{empty}
+% Redefine section commands to use less space
+\\makeatletter
+\\renewcommand{\\section}{\\\@startsection{section}{1}{0mm}%
+                                {-1ex plus -.5ex minus -.2ex}%
+                                {0.5ex plus .2ex}%x
+                                {\\normalfont\\large\\bfseries}}
+\\renewcommand{\\subsection}{\\\@startsection{subsection}{2}{0mm}%
+                                {-1explus -.5ex minus -.2ex}%
+                                {0.5ex plus .2ex}%
+                                {\\normalfont\\normalsize\\bfseries}}
+\\renewcommand{\\subsubsection}{\\\@startsection{subsubsection}{3}{0mm}%
+                                {-1ex plus -.5ex minus -.2ex}%
+                                {1ex plus .2ex}%
+                                {\\normalfont\\small\\bfseries}}
+\\makeatother
+
+% Define BibTeX command
+\\def\\BibTeX{{\\rm B\\kern-.05em{\\sc i\\kern-.025em b}\\kern-.08em
+    T\\kern-.1667em\\lower.7ex\\hbox{E}\\kern-.125emX}}
+
+% Do not print section numbers
+\\setcounter{secnumdepth}{0}
+
+\\setlength{\\parindent}{0pt}
+\\setlength{\\parskip}{0pt plus 0.5ex}
+
+%-------------------------------------------
+
+\\begin{document}
+\\newlength{\\MyLen}
+\\raggedright
+\\footnotesize
+\\begin{multicols}{3}
+END_HEADER
+
+$boilerplate_footer = <<END_FOOTER;
+\\end{multicols}
+\\end{document}
+END_FOOTER
+
+print $boilerplate_header;
+
+@groups_sorted_by_number = sort { $group_numbering{$a} <=> $group_numbering{$b} } keys %group_numbering; 
+
+foreach $gk (@groups_sorted_by_number) {
+    # $bref is a reference to the array of arrays for this group
+    $bref = $group_bindings{$gk};
+
+    if (scalar @$bref > 1) {
+       print "\\section*{$group_names{$gk}}\n";
+
+       if (!($group_text{$gk} eq  "")) {
+           print "$group_text{$gk}\n\\par\n";
+       }
+       
+       # ignore the first entry, which was empty
+
+       shift (@$bref);
+
+       # find the longest descriptive text (this is not 100% accuracy due to typography)
+
+       $maxtextlen = 0;
+       $maxtext = "";
+
+       for $bbref (@$bref) {
+           # $bbref is a reference to an array
+           $text = @$bbref[1];
+           if ($text =~ /\\linebreak/) {
+               $matchtext = s/\\linebreak.*//;
+           } else {
+               $matchtext = $text;
+           }
+           if (length ($matchtext) > $maxtextlen) {
+               $maxtextlen = length ($matchtext);
+               $maxtext = $matchtext;
+           }
+       }
+
+       $maxtext .= "....";
+
+       # set up the table
+
+       print "\\settowidth{\\MyLen}{\\texttt{$maxtext}}\n";
+       print "\\begin{tabular}{\@{}p{\\the\\MyLen}% 
+                                \@{}p{\\linewidth-\\the\\MyLen}%
+                                \@{}}\n";
+
+       # now print the bindings
+
+       for $bbref (@$bref) {
+           # $bbref is a reference to an array
+
+           $binding = @$bbref[0];
+           $text = @$bbref[1];
+
+           if ($binding =~ /:/) { # mouse binding with "where" clause
+               ($binding,$where) = split (/:/, $binding, 2);
+           }
+
+           $binding =~ s/></\+/g;
+           $binding =~ s/^<//;
+           $binding =~ s/>/\+/;
+
+           foreach $k (keys %cs_modifier_map) {
+               $binding =~ s/\@$k\@/$cs_modifier_map{$k}/;
+           }
+
+           # substitute keycode names for something printable
+
+           $re = qr/${ \(join'|', map quotemeta, keys %keycodes)}/;
+           $binding =~ s/($re)/$keycodes{$1}/g;
+
+           # split up mouse bindings to "click" and "where" parts
+
+           if ($gk eq "mobject") {
+               print "{\\tt @$bbref[1] } & {\\tt $binding} {\\it $where}\\\\\n";
+           } else {
+               print "{\\tt @$bbref[1] } & {\\tt $binding} \\\\\n";
+           }
+       }
+
+       print "\\end{tabular}\n";
+
+    }
 }
 
+print $boilerplate_footer;
+
 exit 0;