6 $semicolon = ";"; # help out stupid emacs
7 $title = "Ardour Shortcuts";
30 GetOptions ("platform=s" => \$platform,
31 "winkey=s" => \$winkey,
32 "cheatsheet" => \$make_cheatsheet,
33 "accelmap" => \$make_accelmap,
34 "ardourbindings" => \$ardour_bindings,
35 "merge=s" => \$merge_from,
39 # The use of a separate @WINDOW@ meta-modifier was a mistake and needs to be removed from the bindings.in file.
40 # There is no separate key/modifier we can use for this, so inevitably it will be the same modifier as one of
41 # the other meta-modifiers. This means, for example, that @WINDOW@-b could be same as @SECONDARY@-b with no
42 # warnings given. One of the bindings will work, one won't.
45 if ($platform eq "darwin") {
47 $gtk_modifier_map{'PRIMARY'} = 'Primary'; # GTK supports Primary to allow platform-independent binding to the "primary" modifier, which on OS X is Command
48 $gtk_modifier_map{'SECONDARY'} = 'Control';
49 $gtk_modifier_map{'TERTIARY'} = 'Shift';
50 $gtk_modifier_map{'LEVEL4'} = 'Mod1';
51 $gtk_modifier_map{'WINDOW'} = 'Control';
53 # cs_modifier_map == "Cheat Sheet Modifier Map"
54 # Used to control what gets shown in the
55 # cheat sheet for a given (meta)-modifier
57 $cs_modifier_map{'PRIMARY'} = 'Cmd';
58 $cs_modifier_map{'SECONDARY'} = 'Control';
59 $cs_modifier_map{'TERTIARY'} = 'Shift';
60 $cs_modifier_map{'LEVEL4'} = 'Opt';
61 $cs_modifier_map{'WINDOW'} = 'Control';
63 # used to display what gets shown in the
64 # cheat sheet for mouse bindings. Differs
65 # from cs_modifier map in using shorter
68 $mouse_modifier_map{'PRIMARY'} = 'Cmd';
69 $mouse_modifier_map{'SECONDARY'} = 'Ctrl';
70 $mouse_modifier_map{'TERTIARY'} = 'Shift';
71 $mouse_modifier_map{'LEVEL4'} = 'Opt';
72 $mouse_modifier_map{'WINDOW'} = 'Ctrl';
76 $gtk_modifier_map{'PRIMARY'} = 'Control';
77 $gtk_modifier_map{'SECONDARY'} = 'Alt';
78 $gtk_modifier_map{'TERTIARY'} = 'Shift';
79 $gtk_modifier_map{'LEVEL4'} = $winkey; # something like "Mod4><Super"
80 $gtk_modifier_map{'WINDOW'} = 'Alt';
82 # cs_modifier_map == "Cheat Sheet Modifier Map"
83 # Used to control what gets shown in the
84 # cheat sheet for a given (meta)-modifier
86 $cs_modifier_map{'PRIMARY'} = 'Control';
87 $cs_modifier_map{'SECONDARY'} = 'Alt';
88 $cs_modifier_map{'TERTIARY'} = 'Shift';
89 $cs_modifier_map{'LEVEL4'} = 'Win';
90 $cs_modifier_map{'WINDOW'} = 'Alt';
92 # used to display what gets shown in the
93 # cheat sheet for mouse bindings. Differs
94 # from cs_modifier map in using shorter
97 $mouse_modifier_map{'PRIMARY'} = 'Ctl';
98 $mouse_modifier_map{'SECONDARY'} = 'Alt';
99 $mouse_modifier_map{'TERTIARY'} = 'Shift';
100 $mouse_modifier_map{'LEVEL4'} = 'Win';
101 $mouse_modifier_map{'WINDOW'} = 'Alt';
108 'asciicircum' => '^',
109 'apostrophe' => '\'',
110 'bracketleft' => '[',
111 'bracketright' => ']',
116 'rightanglebracket' => '>',
117 'leftanglebracket' => '<',
127 'rightarrow' => '→',
128 'leftarrow' => '←',
129 'uparrow' => '↑',
130 'downarrow' => '↓',
131 'Page_Down' => 'PageDown',
132 'Page_Up' => 'PageUp',
134 'KP_Right' => 'KP-→',
135 'KP_Left' => 'KP-←',
136 'KP_Up' => 'KP-↑',
137 'KP_Down' => 'KP-↓',
145 'asciicircum' => '\\verb=^=',
146 'apostrophe' => '\'',
147 'bracketleft' => '[',
148 'bracketright' => ']',
149 'braceleft' => '\\{',
150 'braceright' => '\\}',
151 'backslash' => '$\\backslash$',
153 'rightanglebracket' => '>',
154 'leftanglebracket' => '<',
155 'ampersand' => '\\&',
164 'rightarrow' => '$\rightarrow$',
165 'leftarrow' => '$\\leftarrow$',
166 'uparrow' => '$\\uparrow$',
167 'downarrow' => '$\\downarrow$',
168 'Page_Down' => 'Page Down',
169 'Page_Up' => 'Page Up',
178 open (BINDINGS, $merge_from) || die ("merge from bindings: file not readable");
180 next if (/^$semicolon/);
181 if (/^\(gtk_accel/) {
183 chop; # closing parenthesis
185 ($junk, $action, $binding) = split;
186 $merge_bindings{$action} = $binding;
192 if ($make_accelmap && !$merge_from && !$ardour_bindings) {
193 print ";; this accelmap was produced by tools/fmt-bindings\n";
197 next if /^$semicolon/;
209 $group_names{$group_key} = $group_name;
210 $group_text{$group_key} = $group_text;
211 $group_numbering{$group_key} = $group_number;
212 # each binding entry is 2 element array. bindings
213 # are all collected into a container array. create
214 # the first dummy entry so that perl knows what we
216 $group_bindings{$group_key} = [ [] ];
221 ($group_key,$group_file,$group_name) = split (/\s+/, $_, 3);
222 if ($make_accelmap && $ardour_bindings) {
223 if (!exists ($group_handles{$group_file})) {
224 print "Try to open ", $group_file . ".bindings\n";
225 open $group_handles{$group_file}, ">", $group_file . ".bindings" or die "Cannot open bindings file " . $group_file . ".bindings: $!"
227 $group_files{$group_key} = $group_handles{$group_file}
238 $group_names{$group_key} = $group_name;
239 $group_text{$group_key} = $group_text;
242 next if (/^[ \t]+$/);
252 ($key,$action,$binding,$text) = split (/\|/, $_, 4);
257 # substitute bindings
259 $gtk_binding = $binding;
262 $lookup = "<Actions>/" . $action;
263 if ($merge_bindings{$lookup}) {
264 $binding = $merge_bindings{$lookup};
267 # forced inclusion of bindings from template
269 # this action is not defined in the merge from set, so forget it
275 # print the accelmap output
278 # remove + and don't print it in the accelmap
281 # include this in the accelmap
282 if (!$merge_from && $make_accelmap) {
283 if (!$ardour_bindings) {
284 foreach $k (keys %gtk_modifier_map) {
285 $gtk_binding =~ s/\@$k\@/$gtk_modifier_map{$k}/;
287 print "(gtk_accel_path \"<Actions>/$action\" \"$gtk_binding\")\n";
292 $b =~ s/PRIMARY/Primary-/;
293 $b =~ s/SECONDARY/Secondary-/;
294 $b =~ s/TERTIARY/Tertiary-/;
295 $b =~ s/LEVEL4/Level4-/;
297 if (exists ($group_files{$gkey})) {
298 print { $group_files{$gkey} } "<Binding key=\"" . $b . "\" action=\"" . $action . "\"/>\n";
305 # do not include this binding in the cheat sheet
309 $bref = $group_bindings{$key};
310 push (@$bref, [$binding, $text]);
318 foreach my $key (keys %group_handles) {
319 close $group_handles{$key} or die "Group file $group_files{$key} not closed!"
322 if ($make_accelmap || !$make_cheatsheet) {
328 @groups_sorted_by_number = sort { $group_numbering{$a} <=> $group_numbering{$b} } keys %group_numbering;
330 foreach $gk (@groups_sorted_by_number) {
333 # mouse stuff - ignore
337 # $bref is a reference to the array of arrays for this group
338 $bref = $group_bindings{$gk};
340 if (scalar @$bref > 1) {
342 $name = $group_names{$gk};
343 $name =~ s/\\linebreak.*//;
345 $name =~ s/\$\\_\$/-/g;
346 $name =~ s/\\[a-z]+ //g;
350 print "<h3>$name</h3>\n";
352 $gtext = $group_text{$gk};
353 $gtext =~ s/\\linebreak.*//;
355 $gtext =~ s/\$\\_\$/-/g;
356 $gtext =~ s/\\[a-z]+ //g;
358 $gtext =~ s/\\par//g;
360 if (!($gtext eq "")) {
364 # ignore the first entry, which was empty
370 print "<dl class=\"bindings\">\n";
372 # sort the array of arrays by the descriptive text for nicer appearance,
375 for $bbref (sort { @$a[1] cmp @$b[1] } @$bref) {
376 # $bbref is a reference to an array
378 $binding = @$bbref[0];
381 if ($binding =~ /:/) { # mouse binding with "where" clause
382 ($binding,$where) = split (/:/, $binding, 2);
385 foreach $k (keys %cs_modifier_map) {
386 $binding =~ s/\@$k\@/$cs_modifier_map{$k}/;
389 # remove braces for HTML
391 $binding =~ s/></\+/g;
395 # substitute keycode names for something printable
397 $re = qr/${ \(join'|', map quotemeta, keys %keycodes)}/;
398 $binding =~ s/($re)/$keycodes{$1}/g;
400 # tidy up description
403 $descr =~ s/\\linebreak.*//;
405 $descr =~ s/\$\\_\$/-/g;
406 $descr =~ s/\\[a-z]+ //g;
408 $descr =~ s/\\par//g;
410 print "<dt>$descr</dt><dd>$binding</dd>\n";
417 print " <!-- remove this if more text is added below -->\n";
422 # Now print the cheatsheet
424 $boilerplate_header = <<END_HEADER;
425 \\documentclass[10pt,landscape]{article}
426 %\\documentclass[10pt,landscape,a4paper]{article}
427 %\\documentclass[10pt,landscape,letterpaper]{article}
428 \\usepackage{multicol}
431 \\usepackage{palatino}
432 \\usepackage{geometry}
434 \\setlength{\\parskip}{0pt}
435 \\setlength{\\parsep}{0pt}
436 \\setlength{\\headsep}{0pt}
437 \\setlength{\\topskip}{0pt}
438 \\setlength{\\topmargin}{0pt}
439 \\setlength{\\topsep}{0pt}
440 \\setlength{\\partopsep}{0pt}
442 % This sets page margins to .5 inch if using letter paper, and to 1cm
443 % if using A4 paper. (This probably isnott strictly necessary.)
444 % If using another size paper, use default 1cm margins.
445 \\ifthenelse{\\lengthtest { \\paperwidth = 11in}}
446 { \\geometry{top=.5in,left=.5in,right=.5in,bottom=.5in} }
447 {\\ifthenelse{ \\lengthtest{ \\paperwidth = 297mm}}
448 {\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
449 {\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
452 % Turn off header and footer
455 % Redefine section commands to use less space
457 \\renewcommand{\\section}{\\\@startsection{section}{1}{0mm}%
458 {-1ex plus -.5ex minus -.2ex}%
460 {\\normalfont\\large\\bfseries}}
461 \\renewcommand{\\subsection}{\\\@startsection{subsection}{2}{0mm}%
462 {-1explus -.5ex minus -.2ex}%
464 {\\normalfont\\normalsize\\bfseries}}
465 \\renewcommand{\\subsubsection}{\\\@startsection{subsubsection}{3}{0mm}%
466 {-1ex plus -.5ex minus -.2ex}%
468 {\\normalfont\\small\\bfseries}}
471 % Do not print section numbers% Do not print section numbers
472 \\setcounter{secnumdepth}{0}
474 \\setlength{\\parindent}{0pt}
475 \\setlength{\\parskip}{0pt plus 0.5ex}
477 %-------------------------------------------
483 \\begin{multicols}{3}
486 $boilerplate_footer = <<END_FOOTER;
487 \\rule{0.3\\linewidth}{0.25pt}
490 Copyright \\copyright\\ 2013 ardour.org
492 % Should change this to be date of file, not current date.
494 http://manual.ardour.org
500 if ($make_cheatsheet) {
501 print $boilerplate_header;
502 print "\\begin{center}\\Large\\bf $title \\end{center}\n";
505 @groups_sorted_by_number = sort { $group_numbering{$a} <=> $group_numbering{$b} } keys %group_numbering;
507 foreach $gk (@groups_sorted_by_number) {
508 # $bref is a reference to the array of arrays for this group
509 $bref = $group_bindings{$gk};
511 if (scalar @$bref > 1) {
512 print "\\section{$group_names{$gk}}\n";
514 if (!($group_text{$gk} eq "")) {
515 print "$group_text{$gk}\n\\par\n";
518 # ignore the first entry, which was empty
522 # find the longest descriptive text (this is not 100% accuracy due to typography)
527 for $bbref (@$bref) {
528 # $bbref is a reference to an array
532 # if there is a linebreak, just use everything up the linebreak
533 # to determine the width
536 if ($text =~ /\\linebreak/) {
537 $matchtext = s/\\linebreak.*//;
541 if (length ($matchtext) > $maxtextlen) {
542 $maxtextlen = length ($matchtext);
543 $maxtext = $matchtext;
548 # mouse mode: don't extend max text at all - space it tight
556 print "\\settowidth{\\MyLen}{\\texttt{$maxtext}}\n";
557 print "\\begin{tabular}{\@{}p{\\the\\MyLen}%
558 \@{}p{\\linewidth-\\the\\MyLen}%
561 # sort the array of arrays by the descriptive text for nicer appearance,
564 for $bbref (sort { @$a[1] cmp @$b[1] } @$bref) {
565 # $bbref is a reference to an array
567 $binding = @$bbref[0];
570 if ($binding =~ /:/) { # mouse binding with "where" clause
571 ($binding,$where) = split (/:/, $binding, 2);
575 # mouse mode - use shorter abbrevs
576 foreach $k (keys %mouse_modifier_map) {
577 $binding =~ s/\@$k\@/$mouse_modifier_map{$k}/;
580 foreach $k (keys %cs_modifier_map) {
581 $binding =~ s/\@$k\@/$cs_modifier_map{$k}/;
585 $binding =~ s/></\+/g;
589 # substitute keycode names for something printable
591 $re = qr/${ \(join'|', map quotemeta, keys %keycodes)}/;
592 $binding =~ s/($re)/$keycodes{$1}/g;
594 # split up mouse bindings to "click" and "where" parts
596 if ($gk eq "mobject") {
597 print "{\\tt @$bbref[1] } & {\\tt $binding} {\\it $where}\\\\\n";
599 print "{\\tt @$bbref[1] } & {\\tt $binding} \\\\\n";
603 print "\\end{tabular}\n";
608 print $boilerplate_footer;