#!/usr/bin/perl -w # menu_data.pl: generate the menu structure from menu_data.dat # Copyright (c) 2004-2007 Philip Kendall, Stuart Brady, Marek Januszewski # $Id$ # 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 2 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. # Author contact information: # Philip Kendall use strict; use Fuse; sub get_branch ($$); sub cname ($); sub dump_widget ($); sub _dump_widget ($$); sub dump_gtk ($$); sub _dump_gtk ($$$$$); sub dump_win32 ($$); sub _dump_win32 ($$$$); die "usage: $0 " unless @ARGV >= 1; my $ui = shift; my $filename; my $mode = 'none'; # for Win32: my $idmnum = 100; if( $ui eq 'win32' ) { die "$0: dump_win32: which mode -- c, h, or rc?" unless @ARGV >= 1; $mode = shift; $filename = 'menu_data.' . $mode; } elsif( $ui eq 'gtk' ) { die "$0: dump_gtk: which mode -- c, or ui?" unless @ARGV >= 1; $mode = shift; $filename = 'menu_data.' . $mode; } else { $filename = 'menu_data.c'; } print Fuse::GPL( $filename . ': menu structure for Fuse', '2004-2007 Philip Kendall, Stuart Brady, Marek Januszewski' ) . << "CODE" if $mode ne 'ui'; /* This file is autogenerated from menu_data.dat by $0. Any changes made here will not be preserved. */ #include #include "menu.h" CODE my %menus = ( name => 'Main menu', submenu => [ ] ); while(<>) { s/#.*//; next if /^\s*$/; chomp; my( $path, $type, $hotkey, $function, $detail, $action ) = split /\s*,\s*/; my @segments = split '/', $path; my $entry = { }; $entry->{name} = pop @segments; $entry->{type} = $type; $entry->{hotkey} = $hotkey if $hotkey; my $walk = $menus{submenu}; $walk = get_branch( $walk, $_ ) foreach @segments; if( $type eq 'Branch' ) { $entry->{submenu} = [ ]; } elsif( $type eq 'Item' ) { $entry->{function} = $function if $function; $entry->{action} = $action if $action; } $entry->{detail} = $detail if $detail; push @$walk, $entry; } if( $ui eq 'gtk' ) { dump_gtk( $mode, \%menus ); } elsif( $ui eq 'widget' ) { dump_widget( \%menus ); } elsif( $ui eq 'win32' ) { dump_win32( $mode, \%menus ); } else { die "$0: unknown ui: $ui"; } sub get_branch ($$) { my( $menus, $branch ) = @_; foreach my $entry ( @$menus ) { next unless $entry->{submenu}; my $name = $entry->{name}; $name =~ s/_//; return $entry->{submenu} if $name eq $branch; } } sub cname ($) { my( $name ) = @_; my $cname = lc $name; $cname =~ s/\\01[12]//g if $ui eq 'widget'; $cname =~ tr/a-z0-9_//cd; return $cname; } sub dump_widget ($) { my( $menu ) = @_; print << "HEADERS"; #include "input.h" #include "options_internals.h" #include "widget_internals.h" HEADERS _dump_widget( $menu, 'menu' ); } sub _dump_widget ($$) { my( $menu, $path ) = @_; my $menu_name = $menu->{name}; $menu_name =~ s/_//; my $s; if( $path eq 'menu' ) { $s = 'widget_menu_entry widget_menu[]'; } else { # Slight ugliness here is because "${path}[]" doesn't work under # Perl 5.6 $s = "static widget_menu_entry $path" . "[]"; } $s .= " = {\n { \"$menu_name\" },\n"; foreach my $item ( @{ $menu->{submenu} } ) { next if $item->{type} eq 'Separator'; my $name = $item->{name}; my $key; if( $ui eq 'widget' ) { $name =~ s/_(.)/\\012$1\\011/; $key = lc $1 if $1; } else { $name =~ s/_(.)/($1)/; $key = lc $1 if $1; } $s .= " { \"$name\", INPUT_KEY_" . ( $key || 'NONE' ) . ', '; my $cname = cname( $name ); my $detail = $item->{detail} || "NULL"; if( $item->{submenu} ) { $s .= "${path}_$cname, NULL, $detail, 0"; _dump_widget( $item, "${path}_$cname" ); } else { my $function = $item->{function} || "${path}_$cname"; $s .= "NULL, $function, $detail, " . ( $item->{action} || 0 ); } $s .= " },\n"; } $s .= " { NULL }\n};\n\n"; print $s; } sub dump_gtk ($$) { my( $mode, $menu ) = @_; if( $mode eq 'c' ) { print << "HEADERS"; #include HEADERS print "/* Bindings to callbacks with action */\n"; _dump_gtk( 'callbacks', $menu, '', 'menu', ' ' ); print "GtkActionEntry gtkui_menu_data[] = {\n\n"; _dump_gtk( 'actions', $menu, '', 'menu', ' ' ); print << "CODE"; }; guint gtkui_menu_data_size = sizeof( gtkui_menu_data ) / sizeof( GtkActionEntry ); CODE } elsif( $mode eq 'ui' ) { print << "XML"; XML _dump_gtk( 'ui', $menu, '', 'menu', ' ' ); print << "XML"; XML } } sub _dump_gtk ($$$$$) { my( $mode, $menu, $gtk_path, $cpath, $spaces ) = @_; foreach my $item ( @{ $menu->{submenu} } ) { next if $item->{type} eq 'Separator' && $mode ne 'ui'; #Remove toplevel accelerators my $name = $item->{name}; $name =~ s/_// if !$gtk_path; my $label = $name; my $action_name = $name; $action_name =~ s/_//; $action_name = $gtk_path . "/" . $action_name; $action_name =~ s|/|_|g; $action_name =~ s/_//; $action_name = uc( cname( $action_name ) ); $name =~ s/_// if $gtk_path; my $new_cpath = "${cpath}_" . cname( $name ); my $function; my $binded_function = $item->{function} || $new_cpath; if( $item->{type} eq 'Item' && $item->{action} ) { $function = $new_cpath; } else { $function = $binded_function; } if( $mode eq 'callbacks' ) { if( $item->{type} eq 'Item' && $item->{action} ) { print "MENU_CALLBACK( ", $function, " )\n{\n"; print " $binded_function( gtk_action, $item->{action} );\n}\n\n"; } } elsif( $mode eq 'ui' ) { if( $item->{type} eq 'Item' ) { print "$spaces\n"; } elsif( $item->{type} eq 'Separator' ) { print "$spaces\n"; } else { print "$spaces\n"; } } else { #action_name, stock_id, label print " { \"$action_name\", NULL, \"$label\", "; #hotkey if( $item->{hotkey} ) { print "\"$item->{hotkey}\""; } else { print 'NULL'; } #tooltip print ", NULL, "; #callback if( $item->{type} eq 'Item' ) { print "G_CALLBACK( ", $function, " )"; } else { print "NULL"; } print " },\n"; } _dump_gtk( $mode, $item, "$gtk_path/$name", $new_cpath, $spaces . " " ) if $item->{submenu}; print "$spaces\n" if $mode eq 'ui' && $item->{type} eq 'Branch'; } } sub dump_win32 ($$) { my( $mode, $menu ) = @_; if( $mode eq 'c' ) { print << "CODE"; #include "menu_data.h" int handle_menu( DWORD cmd, HWND window ) { switch( cmd ) { CODE } elsif( $mode eq 'h' ) { print << "CODE"; #include CODE } elsif( $mode eq 'rc' ) { print << "CODE"; #include #include "menu_data.h" win32_menu MENU { CODE } _dump_win32( $mode, $menu, 'menu', ' ' ); if( $mode eq 'c' ) { print << "CODE"; } return 1; } CODE } elsif( $mode eq 'rc' ) { print << "CODE"; } win32_accel ACCELERATORS { CODE _dump_win32( 'a', $menu, 'menu', '' ); print << "CODE"; } CODE } } sub _dump_win32 ($$$$) { my( $mode, $menu, $path, $spaces ) = @_; my $menu_name = $menu->{name}; $menu_name =~ s/_//; foreach my $item ( @{ $menu->{submenu} } ) { if( $item->{type} eq 'Separator' ) { if( $mode eq 'rc' ) { print "${spaces}MENUITEM SEPARATOR\n"; } next; } my $name = $item->{name}; $name =~ s/_/&/; my $cname = cname( $name ); my $idmname = "IDM_" . uc( "${path}_$cname" ); if( $mode eq 'h' ) { print "#define $idmname $idmnum\n"; $idmnum++; } elsif( $mode eq 'a' ) { if( $item->{hotkey} ) { print " VK_" . uc( $item->{hotkey} ) . ", $idmname, VIRTKEY\n"; } } if( $item->{submenu} ) { if( $mode eq 'rc' ) { print "${spaces}POPUP \"$name\"\n"; print "${spaces}\{\n"; } _dump_win32( $mode, $item, "${path}_$cname", $spaces . " " ); if( $mode eq 'rc' ) { print "${spaces}}\n"; } } else { if( $mode eq 'c' ) { my $function = $item->{function} || "${path}_$cname"; print " case $idmname:\n"; print " $function( " . ( $item->{action} || 0 ) . " ); " . "return 0;\n"; } elsif( $mode eq 'rc' ) { my $hotkey; if( $item->{hotkey} ) { $hotkey = "\\t" . $item->{hotkey}; } else { $hotkey = ""; } print "${spaces}MENUITEM \"$name$hotkey\", $idmname\n"; } } } }