# These variables are global, so they don't have to be passed through to every # subroutine use vars qw ( $PROGRAM_TITLE $BGCOLOR $ACTIVE_BGCOLOR $SOUNDDIR $CURRENT_CATEGORY $CURRENT_PAGE $INDEXFILE $CATFILE $SOUND_EXT $IMG_EXT $NEXT_IMG $PREV_IMG $UP_IMG $MAX_HEIGHT $MAX_WIDTH $BORDER_WIDTH $SELECTED_BUTTON @BUTTONS ); #------------------------------------------------------------------------------ # Configuration-stuff $PROGRAM_TITLE = "pVoice"; $BGCOLOR = 'white'; $ACTIVE_BGCOLOR = 'red'; $SOUNDDIR = "./data"; $CURRENT_CATEGORY = ""; $CURRENT_PAGE = 1; $INDEXFILE = "index.txt"; $CATFILE = "cat.txt"; $SOUND_EXT = "wav"; $IMG_EXT = "jpg"; $NEXT_IMG = "volgende.$IMG_EXT"; # next-image $PREV_IMG = "vorige.$IMG_EXT"; # previous-image $UP_IMG = "omhoog.$IMG_EXT"; # up-image $MAX_HEIGHT = 120; $MAX_WIDTH = 100; $BORDER_WIDTH = 10; $SELECTED_BUTTON = 0; @BUTTONS = (); # Create the main window my $main = MainWindow->new(-background => $BGCOLOR); # Maximize the window my ($screenw, $screenh) = ($main->screenwidth, $main->screenheight); $main->geometry($screenw."x".$screenh); # Write the title of the window $main->title($PROGRAM_TITLE); #create the window for the images my $mainframe = $main->Frame(-background => $BGCOLOR)->pack(); # -fill=>'both', # -expand=>1 # ); #configure the grid to constant cellsizes $mainframe->gridColumnconfigure(0, -minsize => $MAX_WIDTH + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); $mainframe->gridColumnconfigure(1, -minsize => $MAX_WIDTH + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); $mainframe->gridColumnconfigure(2, -minsize => $MAX_WIDTH + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); $mainframe->gridColumnconfigure(3, -minsize => $MAX_WIDTH + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); $mainframe->gridRowconfigure (0, -weight => 0, -pad => 4); $mainframe->gridRowconfigure (1, -minsize => $MAX_HEIGHT + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); $mainframe->gridRowconfigure (2, -minsize => $MAX_HEIGHT + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); $mainframe->gridRowconfigure (3, -minsize => $MAX_HEIGHT + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); $mainframe->gridRowconfigure (4, -minsize => $MAX_HEIGHT + 2*$BORDER_WIDTH, -weight => 0, -pad => 4); # Write the header my $label=$main->Label(-text => $PROGRAM_TITLE, -background => $BGCOLOR); $label->grid( -in => $mainframe, -column => 0, -row => 0, -columnspan=> 4 ); # Read the categoryfile and draw the first page with category-buttons my @categories = readcategoryfile(); drawcatpage($mainframe, \@categories); # Make the first button active $BUTTONS[$SELECTED_BUTTON]->configure(-state => 'active'); # At present time only left and right mousebuttons are used... $main->bind('', sub { $BUTTONS[$SELECTED_BUTTON]->configure( -state => 'normal'); if ($SELECTED_BUTTON < @BUTTONS -1) {$SELECTED_BUTTON++} else {$SELECTED_BUTTON=0} $BUTTONS[$SELECTED_BUTTON]->configure( -state => 'active'); } ); $main->bind('', sub { $BUTTONS[$SELECTED_BUTTON]->invoke; } ); MainLoop; #------------------------------------------------------------------------------ sub play # Play the sound { my ($label) = @_; my $file = "$SOUNDDIR/$CURRENT_CATEGORY/$label.$SOUND_EXT"; warn "File does not exist ($file)" unless (-f $file); return sub {system('play', "$file")} if $^O ne 'MSWin32'; return sub {Win32::Sound::Play($file)} if $^O eq 'MSWin32'; } #------------------------------------------------------------------------------ sub readcurrentcategoryindex { my (@categorycontents, $page, $index, $file); # Parse index.txt in the category directory and open the files open (INDEX, "$SOUNDDIR/$CURRENT_CATEGORY/$INDEXFILE") || die "Can't open $SOUNDDIR/$CURRENT_CATEGORY/$INDEXFILE: $!\n"; my @indexfile = ; close(INDEX); foreach(@indexfile) { next if !($_); chop; ($page, $index, $file) = split(/\t/); $categorycontents[$page]->[$index]=$file; } return @categorycontents; } #------------------------------------------------------------------------------ sub readcategoryfile { my (@categoryfile, $page, $index, $dir); # Parse cat.txt open (INDEX, "$SOUNDDIR/$CATFILE") || die "Can't open $SOUNDDIR/$CATFILE: $!\n"; my @catfile = ; close(INDEX); foreach(@catfile) { next if !($_); chop; ($page, $index, $dir) = split(/\t/); $categoryfile[$page]->[$index]=$dir; } return @categoryfile; } #------------------------------------------------------------------------------ sub drawpage { my ($mainframe, $categorycontentsref) = @_; my @categorycontents = @{$categorycontentsref}; my ($j, @images); @BUTTONS = (); die "No words found\n" unless @{$categorycontents[$CURRENT_PAGE]}; if ($CURRENT_PAGE eq 1) { addupbutton($mainframe, \@categorycontents); } else { addprevbutton($mainframe, \@categorycontents); } my $y=1; #Draw the images of the current category (first page) for ($j=1; $j<15; $j++) { next if not defined($categorycontents[$CURRENT_PAGE]->[$j-1]); my $scaledimage = $mainframe->Photo( "button$y", -data => scaleimage("$SOUNDDIR/$CURRENT_CATEGORY/$categorycontents[$CURRENT_PAGE]->[$j-1].$IMG_EXT"), -format => 'jpeg' ); my $callback = \&play($categorycontents[$CURRENT_PAGE]->[$j-1]); $BUTTONS[$y] = $mainframe->Button( -activebackground => $ACTIVE_BGCOLOR, -borderwidth => $BORDER_WIDTH, -image => "button$y", -command => $callback, -relief => 'flat' ); $BUTTONS[$y]->grid( -in => $mainframe, -column => ($j%4), -row => int($j/4)+1 ); $y++; } } #------------------------------------------------------------------------------ sub scaleimage { my ($file) = @_; open(GDFILE, $file) || die "File could not be opened ($file) : $!\n"; my $im = GD::Image->newFromJpeg(\*GDFILE); close (GDFILE); my ($width, $height) = $im->getBounds(); # Create an empty image with the desired dimensions my $resizedim = $width/($height/$MAX_HEIGHT)<$MAX_WIDTH ? new GD::Image($width/($height/$MAX_HEIGHT),$MAX_HEIGHT) : new GD::Image($MAX_WIDTH, $height/($width/$MAX_WIDTH)); # Copy everything from $im and resize it into $resizedim $resizedim->copyResized($im,0,0,0,0,$resizedim->getBounds(),$width, $height); # encode the jpeg-output of the $resizedim return encode_base64($resizedim->jpeg(100)); } #------------------------------------------------------------------------------ sub drawcatpage { my ($mainframe, $categoryref) = @_; my @categories = @{$categoryref}; my ($j, @images, $x); @BUTTONS = (); die "No categories found\n" unless $#{$categories[$CURRENT_PAGE]}; $x = 0; #Put the images of the categories on the screen for ($j=1; $j<=@{$categories[$CURRENT_PAGE]}; $j++) { my $idx = $CURRENT_PAGE eq 1 ? $x : $j; my $cat = $categories[$CURRENT_PAGE]->[$x]; my $scaledimage = $mainframe->Photo("button$idx", -data => scaleimage("$SOUNDDIR/$cat.$IMG_EXT"), -format => 'jpeg' ); my $callback = sub { #retrieve the categorycontents $CURRENT_CATEGORY=$cat; my @categorycontent = readcurrentcategoryindex(); foreach (@BUTTONS) { $_->destroy() } @BUTTONS = (); $CURRENT_PAGE=1; drawpage($mainframe, \@categorycontent); if ($CURRENT_PAGE < $#categorycontent) {addlastbutton($mainframe, \@categorycontent);} else {addupbutton($mainframe, \@categorycontent);} $SELECTED_BUTTON=0; $BUTTONS[$SELECTED_BUTTON]->configure(-state => 'active'); }; $BUTTONS[$idx] = $mainframe->Button( -activebackground => $ACTIVE_BGCOLOR, -borderwidth => $BORDER_WIDTH, -image => "button$idx", -command => $callback, -relief => 'flat' ); $BUTTONS[$idx]->grid( -in => $mainframe, -column => ($idx%4), -row => int($idx/4)+1 ); $x++; } } #------------------------------------------------------------------------------ sub addupbutton { my ($mainframe, $categorycontentref) = @_; my @categorycontent = @$categorycontentref; my $i = @BUTTONS; my $y = $CURRENT_PAGE == $#{$categorycontentref} ? 15 : 0; my $scaledimage = $mainframe->Photo("button$i", -data => scaleimage("$SOUNDDIR/$UP_IMG"), -format => 'jpeg' ); my $callback = sub { my @categories = readcategoryfile(); foreach (@BUTTONS) { $_->destroy() } @BUTTONS = (); $CURRENT_PAGE=1; drawcatpage($mainframe, \@categories); $SELECTED_BUTTON=0; $BUTTONS[$SELECTED_BUTTON]->configure(-state => 'active'); }; $BUTTONS[$i] = $mainframe->Button( -activebackground => $ACTIVE_BGCOLOR, -borderwidth => $BORDER_WIDTH, -image => "button$i", -command => $callback, -relief => 'flat' ); $BUTTONS[$i]->grid( -in => $mainframe, -column => $y%4, -row => int($y/4)+1 ); } #------------------------------------------------------------------------------ sub addlastbutton { my ($mainframe, $categorycontentref) = @_; my @categorycontent = @$categorycontentref; my $y = 15; my $j = @BUTTONS; my $scaledimage = $mainframe->Photo("button$j", -data => scaleimage("$SOUNDDIR/$NEXT_IMG"), -format => 'jpeg' ); my $callback = sub { foreach (@BUTTONS) { $_->destroy() } @BUTTONS = (); $CURRENT_PAGE++; drawpage($mainframe, \@categorycontent); if ($CURRENT_PAGE < $#categorycontent) {addlastbutton($mainframe, \@categorycontent);} else {addupbutton($mainframe, \@categorycontent);} # Make the first button active $SELECTED_BUTTON=0; $BUTTONS[$SELECTED_BUTTON]->configure(-state => 'active'); }; $BUTTONS[$j] = $mainframe->Button( -activebackground => $ACTIVE_BGCOLOR, -borderwidth => $BORDER_WIDTH, -image => "button$j", -command => $callback, -relief => 'flat' ); $BUTTONS[$j]->grid( -in => $mainframe, -column => ($y%4), -row => int($y/4)+1 ); } #------------------------------------------------------------------------------ sub addprevbutton { my ($mainframe, $categorycontentref) = @_; my @categorycontent = @$categorycontentref; my $j = @BUTTONS; my $scaledimage = $mainframe->Photo("button$j", -data => scaleimage("$SOUNDDIR/$PREV_IMG"), -format => 'jpeg' ); my $callback = sub { foreach (@BUTTONS) { $_->destroy() } @BUTTONS = (); $CURRENT_PAGE--; drawpage($mainframe, \@categorycontent); if ($CURRENT_PAGE < $#categorycontent) {addlastbutton($mainframe, \@categorycontent);} else {addupbutton($mainframe, \@categorycontent);} $SELECTED_BUTTON=0; $BUTTONS[$SELECTED_BUTTON]->configure(-state => 'active'); }; $BUTTONS[$j] = $mainframe->Button( -activebackground => $ACTIVE_BGCOLOR, -borderwidth => $BORDER_WIDTH, -image => "button$j", -command => $callback, -relief => 'flat' ); $BUTTONS[$j]->grid( -in => $mainframe, -column => ($j%4), -row => int($j/4) +1 ); }