Detach submenu before its parent is destroyed. Fixes #3134.
[ArdourMidi.git] / tools / fmt-bindings
blob39849b1847734155df9b576470af07a12be999d9
1 #!/usr/bin/perl
3 # import module
4 use Getopt::Long;
6 $semicolon = ";"; # help out stupid emacs
7 $title = "Ardour Shortcuts";
8 $in_group_def = 0;
9 $group_name;
10 $group_text;
11 $group_key;
12 $group_number = 0;
13 %group_names;
14 %group_text;
15 %group_bindings;
16 %modifier_map;
17 %group_numbering;
18 %merge_bindings;
20 $platform = linux;
21 $winkey = 'Mod4><Super';
22 $make_cheatsheet = 1;
23 $make_accelmap = 0;
24 $merge_from = "";
26 GetOptions ("platform=s" => \$platform,
27 "winkey=s" => \$winkey,
28 "cheatsheet" => \$make_cheatsheet,
29 "accelmap" => \$make_accelmap,
30 "merge=s" => \$merge_from);
32 if ($platform eq "osx") {
34 $gtk_modifier_map{'PRIMARY'} = 'meta';
35 $gtk_modifier_map{'SECONDARY'} = 'Mod1';
36 $gtk_modifier_map{'TERTIARY'} = 'Shift';
37 $gtk_modifier_map{'LEVEL4'} = 'Control';
38 $gtk_modifier_map{'WINDOW'} = 'Mod1';
40 $cs_modifier_map{'PRIMARY'} = 'Command';
41 $cs_modifier_map{'SECONDARY'} = 'Opt';
42 $cs_modifier_map{'TERTIARY'} = 'Shift';
43 $cs_modifier_map{'LEVEL4'} = 'Control';
44 $cs_modifier_map{'WINDOW'} = 'Opt';
46 $mouse_modifier_map{'PRIMARY'} = 'Cmd';
47 $mouse_modifier_map{'SECONDARY'} = 'Opt';
48 $mouse_modifier_map{'TERTIARY'} = 'Shift';
49 $mouse_modifier_map{'LEVEL4'} = 'Control';
50 $mouse_modifier_map{'WINDOW'} = 'Opt';
52 } else {
54 $gtk_modifier_map{'PRIMARY'} = 'Control';
55 $gtk_modifier_map{'SECONDARY'} = 'Alt';
56 $gtk_modifier_map{'TERTIARY'} = 'Shift';
57 $gtk_modifier_map{'LEVEL4'} = $winkey;
58 $gtk_modifier_map{'WINDOW'} = 'Alt';
59 $gtk_modifier_map{$winkey} => 'Win';
61 $cs_modifier_map{'PRIMARY'} = 'Control';
62 $cs_modifier_map{'SECONDARY'} = 'Alt';
63 $cs_modifier_map{'TERTIARY'} = 'Shift';
64 $cs_modifier_map{'LEVEL4'} = 'Win';
65 $cs_modifier_map{'WINDOW'} = 'Alt';
66 $cs_modifier_map{$winkey} => 'Win';
68 $mouse_modifier_map{'PRIMARY'} = 'Ctl';
69 $mouse_modifier_map{'SECONDARY'} = 'Alt';
70 $mouse_modifier_map{'TERTIARY'} = 'Shift';
71 $mouse_modifier_map{'LEVEL4'} = 'Win';
72 $mouse_modifier_map{'WINDOW'} = 'Alt';
73 $mouse_modifier_map{$winkey} => 'Win';
76 %keycodes = (
77 'asciicircum' => '\\verb=^=',
78 'apostrophe' => '\'',
79 'bracketleft' => '[',
80 'bracketright' => ']',
81 'braceleft' => '\\{',
82 'braceright' => '\\}',
83 'backslash' => '$\\backslash$',
84 'slash' => '/',
85 'rightanglebracket' => '>',
86 'leftanglebracket' => '<',
87 'ampersand' => '\\&',
88 'comma' => ',',
89 'period' => '.',
90 'semicolon' => ';',
91 'colon' => ':',
92 'equal' => '=',
93 'minus' => '-',
94 'plus' => '+',
95 'grave' => '`',
96 'rightarrow' => '$\rightarrow$',
97 'leftarrow' => '$\\leftarrow$',
98 'uparrow' => '$\\uparrow$',
99 'downarrow' => '$\\downarrow$',
100 'Page_Down' => 'Page Down',
101 'Page_Up' => 'Page Up',
102 'space' => 'space',
103 'KP_' => 'KP$\_$',
106 if ($merge_from) {
107 open (BINDINGS, $merge_from) || die ("merge from bindings: file not readable");
108 while (<BINDINGS>) {
109 next if (/^$semicolon/);
110 if (/^\(gtk_accel/) {
111 chop; # newline
112 chop; # closing parenthesis
113 s/"//g;
114 ($junk, $action, $binding) = split;
115 $merge_bindings{$action} = $binding;
118 close (BINDINGS);
121 if ($make_accelmap && !$merge_from) {
122 print ";; this accelmap was produced by tools/fmt-bindings\n";
125 while (<>) {
126 next if /^$semicolon/;
128 if (/^\$/) {
129 s/^\$//;
130 $title = $_;
131 next;
134 if (/^%/) {
136 if ($in_group_def) {
137 chop $group_text;
138 $group_names{$group_key} = $group_name;
139 $group_text{$group_key} = $group_text;
140 $group_numbering{$group_key} = $group_number;
141 # each binding entry is 2 element array. bindings
142 # are all collected into a container array. create
143 # the first dummy entry so that perl knows what we
144 # are doing.
145 $group_bindings{$group_key} = [ [] ];
148 s/^%//;
149 chop;
150 ($group_key,$group_name) = split (/\s+/, $_, 2);
151 $group_number++;
152 $group_text = "";
153 $in_group_def = 1;
154 next;
157 if ($in_group_def) {
158 if (/^@/) {
159 chop $group_text;
160 $group_names{$group_key} = $group_name;
161 $group_text{$group_key} = $group_text;
162 $in_group_def = 0;
163 } else {
164 next if (/^[ \t]+$/);
165 $group_text .= $_;
166 $group_text;
167 next;
171 if (/^@/) {
172 s/^@//;
173 chop;
174 ($key,$action,$binding,$text) = split (/\|/, $_, 4);
176 # substitute bindings
178 $gtk_binding = $binding;
180 if ($merge_from) {
181 $lookup = "<Actions>/" . $action;
182 if ($merge_bindings{$lookup}) {
183 $binding = $merge_bindings{$lookup};
184 } else {
185 if ($key =~ /^\+/) {
186 # forced inclusion of bindings from template
187 } else {
188 # this action is not defined in the merge from set, so forget it
189 next;
194 # print the accelmap output
196 if ($key =~ /^\+/) {
197 # remove + and don't print it in the accelmap
198 $key =~ s/^\+//;
199 } else {
200 # include this in the accelmap
201 if (!$merge_from && $make_accelmap) {
202 foreach $k (keys %gtk_modifier_map) {
203 $gtk_binding =~ s/\@$k\@/$gtk_modifier_map{$k}/;
205 print "(gtk_accel_path \"<Actions>/$action\" \"$gtk_binding\")\n";
209 if ($key =~ /^-/) {
210 # do not include this binding in the cheat sheet
211 next;
214 $bref = $group_bindings{$key};
215 push (@$bref, [$binding, $text]);
217 next;
220 next;
223 if ($make_accelmap || !$make_cheatsheet) {
224 exit 0;
227 # Now print the cheatsheet
229 $boilerplate_header = <<END_HEADER;
230 \\documentclass[10pt,landscape]{article}
231 \\usepackage{multicol}
232 \\usepackage{calc}
233 \\usepackage{ifthen}
234 \\usepackage{palatino}
235 \\usepackage{geometry}
237 \\setlength{\\parskip}{0pt}
238 \\setlength{\\parsep}{0pt}
239 \\setlength{\\headsep}{0pt}
240 \\setlength{\\topskip}{0pt}
241 \\setlength{\\topmargin}{0pt}
242 \\setlength{\\topsep}{0pt}
243 \\setlength{\\partopsep}{0pt}
245 % This sets page margins to .5 inch if using letter paper, and to 1cm
246 % if using A4 paper. (This probably isnott strictly necessary.)
247 % If using another size paper, use default 1cm margins.
248 \\ifthenelse{\\lengthtest { \\paperwidth = 11in}}
249 { \\geometry{top=.5in,left=1in,right=0in,bottom=.5in} }
250 {\\ifthenelse{ \\lengthtest{ \\paperwidth = 297mm}}
251 {\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
252 {\\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} }
255 % Turn off header and footer
256 \\pagestyle{empty}
258 % Redefine section commands to use less space
259 \\makeatletter
260 \\renewcommand{\\section}{\\\@startsection{section}{1}{0mm}%
261 {-1ex plus -.5ex minus -.2ex}%
262 {0.5ex plus .2ex}%
263 {\\normalfont\\large\\bfseries}}
264 \\renewcommand{\\subsection}{\\\@startsection{subsection}{2}{0mm}%
265 {-1explus -.5ex minus -.2ex}%
266 {0.5ex plus .2ex}%
267 {\\normalfont\\normalsize\\bfseries}}
268 \\renewcommand{\\subsubsection}{\\\@startsection{subsubsection}{3}{0mm}%
269 {-1ex plus -.5ex minus -.2ex}%
270 {1ex plus .2ex}%
271 {\\normalfont\\small\\bfseries}}
272 \\makeatother
274 % Do not print section numbers% Do not print section numbers
275 \\setcounter{secnumdepth}{0}
277 \\setlength{\\parindent}{0pt}
278 \\setlength{\\parskip}{0pt plus 0.5ex}
280 %-------------------------------------------
282 \\begin{document}
283 \\newlength{\\MyLen}
284 \\raggedright
285 \\footnotesize
286 \\begin{multicols}{3}
287 END_HEADER
289 $boilerplate_footer = <<END_FOOTER;
290 \\rule{0.3\\linewidth}{0.25pt}
291 \\scriptsize
293 Copyright \\copyright\\ 2009 ardour.org
295 % Should change this to be date of file, not current date.
296 %\\verb!$Revision: 1.13 $, $Date: 2008/05/29 06:11:56 $.!
298 http://ardour.org/manual
300 \\end{multicols}
301 \\end{document}
302 END_FOOTER
304 if ($make_cheatsheet) {
305 print $boilerplate_header;
306 print "\\begin{center}\\Large\\bf $title \\end{center}\n";
309 @groups_sorted_by_number = sort { $group_numbering{$a} <=> $group_numbering{$b} } keys %group_numbering;
311 foreach $gk (@groups_sorted_by_number) {
312 # $bref is a reference to the array of arrays for this group
313 $bref = $group_bindings{$gk};
315 if (scalar @$bref > 1) {
316 print "\\section{$group_names{$gk}}\n";
318 if (!($group_text{$gk} eq "")) {
319 print "$group_text{$gk}\n\\par\n";
322 # ignore the first entry, which was empty
324 shift (@$bref);
326 # find the longest descriptive text (this is not 100% accuracy due to typography)
328 $maxtextlen = 0;
329 $maxtext = "";
331 for $bbref (@$bref) {
332 # $bbref is a reference to an array
333 $text = @$bbref[1];
336 # if there is a linebreak, just use everything up the linebreak
337 # to determine the width
340 if ($text =~ /\\linebreak/) {
341 $matchtext = s/\\linebreak.*//;
342 } else {
343 $matchtext = $text;
345 if (length ($matchtext) > $maxtextlen) {
346 $maxtextlen = length ($matchtext);
347 $maxtext = $matchtext;
351 if ($gk =~ /^m/) {
352 # mouse mode: don't extend max text at all - space it tight
353 $maxtext .= ".";
354 } else {
355 $maxtext .= "....";
358 # set up the table
360 print "\\settowidth{\\MyLen}{\\texttt{$maxtext}}\n";
361 print "\\begin{tabular}{\@{}p{\\the\\MyLen}%
362 \@{}p{\\linewidth-\\the\\MyLen}%
363 \@{}}\n";
365 # sort the array of arrays by the descriptive text for nicer appearance,
366 # and print them
368 for $bbref (sort { @$a[1] cmp @$b[1] } @$bref) {
369 # $bbref is a reference to an array
371 $binding = @$bbref[0];
372 $text = @$bbref[1];
374 if ($binding =~ /:/) { # mouse binding with "where" clause
375 ($binding,$where) = split (/:/, $binding, 2);
378 if ($gk =~ /^m/) {
379 # mouse mode - use shorter abbrevs
380 foreach $k (keys %mouse_modifier_map) {
381 $binding =~ s/\@$k\@/$mouse_modifier_map{$k}/;
383 } else {
384 foreach $k (keys %cs_modifier_map) {
385 $binding =~ s/\@$k\@/$cs_modifier_map{$k}/;
389 $binding =~ s/></\+/g;
390 $binding =~ s/^<//;
391 $binding =~ s/>/\+/;
393 # substitute keycode names for something printable
395 $re = qr/${ \(join'|', map quotemeta, keys %keycodes)}/;
396 $binding =~ s/($re)/$keycodes{$1}/g;
398 # split up mouse bindings to "click" and "where" parts
400 if ($gk eq "mobject") {
401 print "{\\tt @$bbref[1] } & {\\tt $binding} {\\it $where}\\\\\n";
402 } else {
403 print "{\\tt @$bbref[1] } & {\\tt $binding} \\\\\n";
407 print "\\end{tabular}\n";
412 print $boilerplate_footer;
414 exit 0;