Index: gs3-extensions/html-to-expeditee/trunk/src/bin/script/keyboard.pl
===================================================================
--- gs3-extensions/html-to-expeditee/trunk/src/bin/script/keyboard.pl	(revision 25056)
+++ gs3-extensions/html-to-expeditee/trunk/src/bin/script/keyboard.pl	(revision 25056)
@@ -0,0 +1,577 @@
+#!/usr/bin/perl -w
+
+###########################################################################
+#
+# keyboard.pl -- generate a set of Expeditee frames to implement a 
+#                touch-screen keyboard
+#
+# A component of the Greenstone digital library software
+# from the New Zealand Digital Library Project at the 
+# University of Waikato, New Zealand.
+#
+# Copyright (C) 1999 New Zealand Digital Library Project
+#
+# 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+###########################################################################
+
+BEGIN {
+    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
+    die "GSDLOS not set\n" unless defined $ENV{'GSDLOS'};
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/cpan");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugins");
+    unshift (@INC, "$ENV{'GSDLHOME'}/perllib/plugouts");
+
+    if (defined $ENV{'GSDLEXTS'}) {
+	my @extensions = split(/:/,$ENV{'GSDLEXTS'});
+	foreach my $e (@extensions) {
+	    my $ext_prefix = "$ENV{'GSDLHOME'}/ext/$e";
+
+	    unshift (@INC, "$ext_prefix/perllib");
+	    unshift (@INC, "$ext_prefix/perllib/cpan");
+	    unshift (@INC, "$ext_prefix/perllib/plugins");
+	    unshift (@INC, "$ext_prefix/perllib/plugouts");
+	}
+    }
+    if (defined $ENV{'GSDL3EXTS'}) {
+	my @extensions = split(/:/,$ENV{'GSDL3EXTS'});
+	foreach my $e (@extensions) {
+	    my $ext_prefix = "$ENV{'GSDL3SRCHOME'}/ext/$e";
+
+	    unshift (@INC, "$ext_prefix/perllib");
+	    unshift (@INC, "$ext_prefix/perllib/cpan");
+	    unshift (@INC, "$ext_prefix/perllib/plugins");
+	    unshift (@INC, "$ext_prefix/perllib/plugouts");
+	}
+    }
+
+    if ((defined $ENV{'DEBUG_UNICODE'}) && (defined $ENV{'DEBUG_UNICODE'})) {
+	binmode(STDERR,":utf8");
+    }
+}
+
+use utf8;
+use strict;
+
+use ExpediteeFrameIO;
+use util;
+
+
+my $default_key_width  = 85;
+my $default_key_height = 85;
+
+my $number_line = [ "`", "1", "2",  "3", "4", "5", "6", "7", "8", "9", "0", "-", "=" ];
+my $punct_line  = [ "~", "!", " \@", "\#", "\$", "\%", "^", "\&", "*", "(", ")", "_", "+" ];
+
+my $lc_letters_row1 = [ "q", "w", "e", "r", "t", "y", "u", "i", "o", "p", "[", "]", "\\" ];
+my $lc_letters_row2 = [ "a", "s", "d", "f", "g", "h", "j", "k", "l", ";", "'" ];
+my $lc_letters_row3 = [ "z", "x", "c", "v", "b", "n", "m", ",", ".", "/", "Bksp" ];
+
+my $uc_letters_row1 = [ "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "{", "}", "|" ];
+my $uc_letters_row2 = [ "A", "S", "D", "F", "G", "H", "J", "K", "L", ":", "\"" ];
+my $uc_letters_row3 = [ "Z", "X", "C", "V", "B", "N", "M", "<", ">", "?", "Bksp" ];
+
+my $spacebar_line = [ { 'label' => "\@Space", 'char' => " " } ];
+#my $backspace_line = [ "Bksp" ];
+
+my $macron_mapping = { 'a' => 'Ä',
+		       'e' => 'Ä',
+		       'i' => 'Ä«',
+		       'o' => 'Å',
+		       'u' => 'Å«',
+		       'A' => 'Ä',
+		       'E' => 'Ä',
+		       'I' => 'Äª',
+		       'O' => 'Å',
+		       'U' => 'Åª'  };
+
+my @main_number_line   = @$number_line;
+my @macron_number_line = @$number_line;
+
+my @shift_punct_line        = @$punct_line;
+my @shift_macron_punct_line = @$punct_line;
+
+my @main_lc_letters_row1         = @$lc_letters_row1;
+my @shift_uc_letters_row1        = @$uc_letters_row1;
+my @macron_lc_letters_row1       = @$lc_letters_row1;
+my @shift_macron_uc_letters_row1 = @$uc_letters_row1;
+
+my @main_lc_letters_row2         = @$lc_letters_row2;
+my @shift_uc_letters_row2        = @$uc_letters_row2;
+my @macron_lc_letters_row2       = @$lc_letters_row2;
+my @shift_macron_uc_letters_row2 = @$uc_letters_row2;
+
+my @main_lc_letters_row3         = @$lc_letters_row3;
+my @shift_uc_letters_row3        = @$uc_letters_row3;
+my @macron_lc_letters_row3       = @$lc_letters_row3;
+my @shift_macron_uc_letters_row3 = @$uc_letters_row3;
+
+
+
+sub print_keyboard
+{
+    my ($keyboard) = @_;
+
+    print "Title: $keyboard->{'title'}\n";
+
+    my $keys = $keyboard->{'keys'};
+
+    foreach my $row (@$keys) {
+
+	foreach my $letter_rec (@$row) {
+
+	    my $letter_rec_type = ref($letter_rec);
+
+	    if ($letter_rec_type eq "") {
+		my $letter = $letter_rec;
+		print " '$letter'";
+	    }
+	    elsif ($letter_rec_type eq "HASH") {
+	 	if (defined $letter_rec->{'char'}) {
+			my $label = $letter_rec->{'label'};
+			my $char  = $letter_rec->{'char'};
+			print " $label=>'$char'";
+		}
+		else {
+		  # assume we're a linked keyboard 
+		    my $label = $letter_rec->{'label'};
+		    my $goto_keyboard = $letter_rec->{'link'};
+		    my $goto_keyboard_title = $goto_keyboard->{'title'};
+		    
+		    print " ${label}->[$goto_keyboard_title]";
+		}
+	    }
+	    else {
+		print STDERR "Warning: unrecognized letter record type: $letter_rec_type\n";
+	    }
+	}
+	print "\n";
+    }
+    
+}
+
+##
+#
+# Subroutine to add overlay frame to frameset.
+# This frame contains the wooden desktop background,
+# which will display behind the keyboard.
+#
+##
+sub add_overlay_frame
+{
+       my ($expeditee_frame_io) = @_;
+       my $x = 20;
+       my $y = 20;
+       my $linkText = "\@o";
+       my $attr = {};
+
+       $attr->{'F'} = "keyboard5";
+       $expeditee_frame_io->addText($x,$y,$linkText,undef,$attr);
+}
+
+##
+#
+# Subroutine to add wooden desktop background
+# to the back of the keyboard.
+#
+##
+sub add_background
+{
+	my ($expeditee_frame_io) = @_;
+	my $x = 5;
+	my $y = 60;
+	my $bgImg = "\@i: images/backgrounds/wood-keyboard.png";
+
+	$expeditee_frame_io->addText($x,$y,$bgImg,undef,{});
+}
+
+##
+#
+# Subroutine to add search controls. These include
+# the search box, search button and reset button.
+#
+##
+sub add_search_controls
+{
+	my ($expeditee_frame_io) = @_;
+
+	my $x = 20;
+	my $y = 100;	
+
+	#add in search box.
+	my $xr = $x + 600;
+	my $yb = $y + 85;
+	
+	my $searchBoxAttr = {};
+	$searchBoxAttr->{'d'} = "0 0 0";		#set line colour
+	$searchBoxAttr->{'h'} = "2.0";			#set line thickness
+        $searchBoxAttr->{'e'} = "87 76 49";			#set rectangle fill colour
+	
+	$expeditee_frame_io->addRect($x,$y,$xr,$yb,$searchBoxAttr);
+	
+	#add in text to go inside search box.
+	$x += 5;
+	$y += 55;
+	my $searchBoxText = "Search text goes here";
+	
+	my $textAttr = {};
+	$textAttr->{'f'} = "tb30";
+
+	$expeditee_frame_io->addText($x,$y,$searchBoxText,undef,$textAttr);
+	
+	#add button images for 'Search' button and 'Reset' button.
+	$x = ($x - 5) + $xr + 10;
+	$y -= 55;				#reset y to original value so buttons align with search box.
+
+	$textAttr->{'X'} = "runFrame";
+	$textAttr->{'x'} = "false";		#set action mark.
+	$textAttr->{'n'} = "false";		#set link mark.
+
+	my $imgBtn = "\@i: images/buttons/search_controls.png";
+	my $width = 145;
+
+        $textAttr->{'F'} = "Keyboard-Actions31";			#link to frame containing Search SIMPLE program.
+
+	$expeditee_frame_io->addText($x,$y,$imgBtn,undef,$textAttr);	#add image text annotation to frame.
+	
+	$x += 25;
+	$y += 55;
+	
+	my $searchBtnText = "Search";
+        $textAttr->{'d'} = "100 100 100";			#set text color 
+	$expeditee_frame_io->addText($x,$y,$searchBtnText,undef,$textAttr);
+	
+	$x = ($x - 25) + $width + 10;
+	$y -= 55;
+        $textAttr->{'F'} = "Keyboard-Actions12";			#link to frame containing Reset SIMPLE program.
+	$expeditee_frame_io->addText($x,$y,$imgBtn,undef,$textAttr);
+	
+	$x += 25;
+	$y += 55;
+	
+	my $resetBtnText = "Reset";
+        
+	$expeditee_frame_io->addText($x,$y,$resetBtnText,undef,$textAttr);	
+
+}
+
+
+###
+#
+# Subroutine that gets a key and adds it to the keyboard.
+#
+###
+
+sub add_key
+{
+    my ($expeditee_frame_io,$label,$char,$x,$y) =@_;
+
+    my $imgBtn = "";
+    my $textAttr = {};
+    my $imgBtnAttr = {};
+
+    my $width = 0;
+    my $height = 85;
+
+    $imgBtnAttr->{'X'} = "runFrame";
+    $imgBtnAttr->{'F'} = "Keyboard-Actions7";
+    $imgBtnAttr->{'x'} = "false";			#set action mark
+    $imgBtnAttr->{'n'} = "false";			#set link mark
+
+    $textAttr->{'X'} = "runFrame";
+    $textAttr->{'F'} = "Keyboard-Actions7";
+    $textAttr->{'x'} = "false";				#set action mark
+    $textAttr->{'n'} = "false";				#set link mark
+    $textAttr->{'d'} = "100 100 100";			#set text color
+ 
+    #if we are adding in space bar then add the space bar image instead of the usual key button image.
+    if($label eq "\@Space") {
+		$imgBtn = "\@i: images/buttons/key_space.png";
+		$textAttr->{'f'} = "tb48";
+		
+		$width = 420;
+    }
+    #if we are adding in a shift or macron or backspace button then use following image instead.
+    elsif(($label eq "macron") || ($label eq "shift")) {
+                       
+         
+		$imgBtn = "\@i: images/buttons/key_special.png";
+
+		$textAttr->{'f'} = "tb32";
+		$width = 145;
+		
+    }
+    elsif($label eq "Bksp"){
+		
+		$imgBtn = "\@i: images/buttons/key_bksp.png";
+		$textAttr ->{'f'} = "tb28";
+		$width = 145;
+    }
+    #otherwise we are just adding in a normal key.
+    else {
+		$imgBtn = "\@i: images/buttons/key_letter.png";
+		$textAttr->{'f'} = "tb48";
+
+#TODO: Change this code so it's much tidier...
+		if(($label eq 'Ä') || ($label eq 'Ä') || ($label eq 'Ä«') || ($label eq 'Å') || ($label eq 'Å«') || ($label eq 'Ä') || ($label eq 'Ä') || ($label eq 'Äª') || ($label eq 'Å') || ($label eq 'Åª')) {
+
+			$textAttr->{'d'} = "100 0 0";
+		}
+
+		$width = 85;
+    }
+    
+    $default_key_width = $width;
+    $default_key_height = $height;
+
+    my $xl = $x;
+    my $xr = $xl + $width;
+    my $yt = $y;
+    my $yb = $yt + $height;
+
+    $expeditee_frame_io->addText($xl,$yt,$imgBtn,undef,$imgBtnAttr);	#adds image annotations to frame.
+
+    #used for positioning letters as centre to their keys as possible.
+    if($label eq "macron") {
+	$xl += 10;
+        $yt += 55;
+    }
+    elsif($label eq "shift") {
+	$xl += 35;
+        $yt += 55;
+    }
+    elsif($label eq "Bksp") {
+	$xl += 55;
+        $yt += 50;
+    }
+    else {
+	$xl += 20;
+        $yt += 55;
+    }
+
+
+
+
+    
+    if ($label =~ m/^ /) {
+	# compensate for any labels that start with a space 
+	# (i.e. on the @ key, where a space is needed for Expeditee so it doesn't treat it as an annotation)
+	$xl -= 20;
+    }
+
+    $expeditee_frame_io->addText($xl,$yt,$label,undef,$textAttr);
+
+}
+
+###
+#
+# Subroutine that generates an expeditee frame
+# for each keyboard.
+#
+###
+sub generate_expeditee_frame
+{
+    my ($expeditee_frame_io,$keyboard) = @_;
+
+    my $fn = $keyboard->{'frame-number'};
+    my $keys = $keyboard->{'keys'};
+   
+    my $y = 300;
+    my $offSetX = 0;
+
+    if ($fn != 0 && $fn != 5) {
+
+	add_overlay_frame($expeditee_frame_io);
+	add_search_controls($expeditee_frame_io);
+
+#	add_background($expeditee_frame_io);
+
+    foreach my $row (@$keys) {
+	
+	 my $x = 20 + $offSetX;
+         
+	 foreach my $letter_rec (@$row) {
+
+	     my $letter_rec_type = ref($letter_rec);
+		
+	     if ($letter_rec_type eq "") {
+		my $letter = $letter_rec;
+		add_key($expeditee_frame_io,$letter,$letter,$x,$y,$default_key_width,$default_key_height);	
+                print " $letter "; 
+	    }
+	    elsif ($letter_rec_type eq "HASH") {
+	 	if (defined $letter_rec->{'char'}) {
+			my $label = $letter_rec->{'label'};
+			my $char  = $letter_rec->{'char'};
+
+			add_key($expeditee_frame_io,$label,$char,$x,$y);
+
+			print " $label ";
+		}
+		else {
+		  # assume we're a linked keyboard 
+		    my $label = $letter_rec->{'label'};
+		    my $goto_keyboard = $letter_rec->{'link'};
+		    my $goto_keyboard_title = $goto_keyboard->{'title'};
+
+		    add_key($expeditee_frame_io,$label,$label,$x,$y);
+
+		    print " $label ";
+		}
+	    }
+	    else {
+		print STDERR "Warning: unrecognized letter record type: $letter_rec_type\n";
+	    }
+
+	    $x += $default_key_width + 5;
+	}
+
+	$y += $default_key_height + 5;
+        $offSetX += 25;
+        print "\n";
+    }
+
+    }
+    elsif($fn == 5) {   #create overlay frame.
+	add_background($expeditee_frame_io);
+
+    }
+
+    if ($expeditee_frame_io->saveFrame("$fn.exp")) {
+	
+	# write out next free frame num
+	$expeditee_frame_io->saveLastFrameNumber($fn);
+	print "Frame $fn written successfully\n";
+    }
+    else {
+	print STDERR "Error writing frame $fn.exp\n";
+    }
+}
+
+
+sub main
+{
+    my (@argv) = @_;
+
+    binmode(STDOUT,":utf8");
+
+    my $home_dir = (defined $ENV{'EXPEDITEE_HOME'}) ? $ENV{'EXPEDITEE_HOME'} : ".";
+    my $output_dir = util::filename_cat($home_dir,"expeditee","framesets","keyboard");
+ 
+    if (-e $output_dir) {
+	util::mk_all_dir($output_dir);
+    }
+
+    print "Saving output to directory: $output_dir\n";
+
+    my $expeditee_frame_io = new ExpediteeFrameIO($output_dir);
+
+    #used for creating zero frame - won't actually contain anything.
+    my $zero_keyboard
+	= { 'frame-number' => 0,
+	    'title' => "keyboard0",
+	    'keys' => [] };
+
+    my $main_keyboard 
+	= { 'frame-number' => 1,
+	    'title' => "Main keyboard",
+	    'keys' => [ \@main_number_line,
+			\@main_lc_letters_row1,
+			\@main_lc_letters_row2,
+			\@main_lc_letters_row3 ] };
+    
+# my @main_lc_letters_row1 = @$lc_letters_row1
+# \@main_lc_letters_row1
+
+    my $shift_keyboard 
+	= { 'frame-number' => 2,
+	    'title' => "Shift keyboard",
+	    'keys' => [ \@shift_punct_line,
+			\@shift_uc_letters_row1,
+			\@shift_uc_letters_row2,
+			\@shift_uc_letters_row3 ] };
+
+    my $macron_keyboard 
+	= { 'frame-number' => 3,
+	    'title' => "Macron keyboard",
+	    'keys' => [ \@macron_number_line,
+			\@macron_lc_letters_row1,
+			\@macron_lc_letters_row2,
+			\@macron_lc_letters_row3 ] };
+	    
+    my $shift_macron_keyboard 
+	= { 'frame-number' => 4,
+	    'title' => "Shift macron keyboard",
+	    'keys' => [ \@shift_macron_punct_line,
+			\@shift_macron_uc_letters_row1,
+			\@shift_macron_uc_letters_row2,
+			\@shift_macron_uc_letters_row3 ] };
+
+    #add background on to this overlay frame.
+    my $overlay_frame
+	= { 'frame-number' => 5,
+	    'title' => "keyboard5",
+            'keys' => [] };
+
+
+    # dynamically add in macron mappings
+    foreach my $keyboard ($macron_keyboard, $shift_macron_keyboard) {
+
+	foreach my $row (@{$keyboard->{'keys'}}) {
+
+	    for (my $i = 0; $i<scalar(@$row); $i++) {
+		my $letter = $row->[$i];
+		if (defined $macron_mapping->{$letter}) {
+		    $row->[$i] = $macron_mapping->{$letter};
+		}
+	    }
+	}
+    }
+
+    my $main_keyboard_press_macron = { 'label' => "macron", 'color' => "0 0 0", 'link' => $macron_keyboard };
+    my $main_keyboard_press_shift  = { 'label' => "shift",  'color' => "0 0 0", 'link' => $shift_keyboard };
+  
+    my $macron_keyboard_press_macron = { 'label' => "macron", 'color' => "100 100 100", 'link' => $main_keyboard };
+    my $macron_keyboard_press_shift  = { 'label' => "shift",  'color' => "0 0 0",       'link' => $shift_macron_keyboard };
+
+    my $shift_keyboard_press_macron = { 'label' => "macron", 'color' => "0 0 0",       'link' => $shift_macron_keyboard };
+    my $shift_keyboard_press_shift  = { 'label' => "shift",  'color' => "100 100 100", 'link' => $main_keyboard };
+
+    my $shift_macron_keyboard_press_macron = { 'label' => "macron", 'color' => "100 100 100", 'link' => $macron_keyboard };
+    my $shift_macron_keyboard_press_shift  = { 'label' => "shift",  'color' => "100 100 100", 'link' => $shift_keyboard };
+
+    my $main_spacebar_line         = [ $main_keyboard_press_macron,         @$spacebar_line, $main_keyboard_press_shift         ];
+    my $shift_spacebar_line        = [ $shift_keyboard_press_macron,        @$spacebar_line, $shift_keyboard_press_shift        ];
+    my $macron_spacebar_line       = [ $macron_keyboard_press_macron,       @$spacebar_line, $macron_keyboard_press_shift       ];
+    my $shift_macron_spacebar_line = [ $shift_macron_keyboard_press_macron, @$spacebar_line, $shift_macron_keyboard_press_shift];
+
+    push(@{$main_keyboard->{'keys'}},         $main_spacebar_line);
+    push(@{$shift_keyboard->{'keys'}},        $shift_spacebar_line);
+    push(@{$macron_keyboard->{'keys'}},       $macron_spacebar_line);
+    push(@{$shift_macron_keyboard->{'keys'}}, $shift_macron_spacebar_line);
+
+
+
+    foreach my $keyboard ($zero_keyboard,$main_keyboard, $shift_keyboard, $macron_keyboard, $shift_macron_keyboard, $overlay_frame) {
+	generate_expeditee_frame($expeditee_frame_io,$keyboard);
+	print "-" x 40, "\n";
+    }
+
+
+}
+
+
+main(@ARGV);
