This is a command line utility that I quickly transferred to Tk a year or more ago (my first Tk app I think). Basically, it's used for managing renderings with file formats like Name00001.TGA through Name98765.TGA (long animations mostly). Render a few thousand files into a folder. Find the files that were skipped by a process that never spawned, or it never finished rendering the file completely.
#!/usr/bin/perl
#############################
use strict;
use Tk 8.0;
use Tk::ROText;
use Cwd;
use Tk::FileSelect;
use Tk::NoteBook;
use Tk::LabEntry;
require Tk::FileSelect;
require Tk::ROText;
require Tk::NoteBook;
require Tk::LabEntry;
require TK::DialogBox;
# remove extra perl window
#if( 'MSWin32' eq $^O ) {
# require Win32::GUI;
# # Win32::GUI->import(); # Pretend to be 'use' ???
# my ($DOS) = Win32::GUI::GetPerlWindow();
# Win32::GUI::Hide($DOS);
#}
# default start frame
my $start = 1;
# default end frame
my $end = 2000;
# default search pattern
my $search_pattern = "H\#.tga";
# default size sensitivity
my $size_sensitive = 50;
# default number of entries per line
my $entriesPerLine = 50;
# default startup folder
my $folder = Cwd::cwd();
# default refresh speed in seconds
my $refresh_speed = 60;
# in seconds - DANGER! should be >= 10
my $fastest_refresh = 10;
# refresh on OK to start prog
my $refresh_on_OK = 0;
##########################################
my $version = "HuntTK v1.06";
my $name = "htk";
my $win_title = "";
my $refresh_id = ();
my $main = MainWindow->new;
###############
# hunt global vars
###############
my $pad =();
my $ispad = 0;
my @final_frames = ();
my @start_frames = ();
my $gBlankFileSize = 11264;
my $gFlagCheckBlank = 0;
# refresh on?
my $isRefresh = 0;
# display characters
my $gCharNormal = ".";
my $gCharZero = "0";
my $gCharMissing = "*";
my $gCharQuestionable = "?";
my $gCharBlank = "B";
my $gPrefix = ();
my $gSuffix = ();
###############
# help text
###############
my ($helptxt) = <<"assignment";
$name Help:
Program written by Darren Patterson
darren\@dougstruthers.com
ALT-P => Preferences
SPACE => Refresh
ALT-R => Refresh
F5 => Refresh
ALT-Q => Quit
-------------------------------
Command line arguments:
htk [-] [FOLDER]
If supplied, $name points itself at FOLDER
The optional '-' makes $name refresh in FOLDER on opening
assignment
################
# menu frame
################
my ($menubar) = $main->Menu;
$main->configure (-menu => $menubar);
my $filemenu = $menubar->cascade(-label => "~File",
-tearoff => 0);
my $helpmenu = $menubar->cascade(-label => "~Help",
-tearoff => 0);
##############
# file menu commands
###############
$filemenu->command(-command => \&getPrefs,
-label => "Preferences... -- ALT-P",
-underline => 0);
$filemenu->separator;
$filemenu->command(-label => "Refresh -- ALT-R",
-command => \&refresh,
-underline => 0);
$filemenu->separator;
$filemenu->command(-label => "Exit -- ALT-Q",
-command => \&exit_choice,
-underline => 1);
##############
# help menu commands
###############
$helpmenu->command(-command => \&print_help,
-label => "Print Help",
-underline => 6);
################
# main window
################
$main->title("$name");
$main->configure(-background=>'grey');
my $rframe = $main->Frame()->pack(-side => 'top', -expand => 'yes', -f
+ill => 'both',);
my $right = $rframe->Scrolled("ROText",
-width => 68,
-height => 16,
-background=>'white',
-wrap => 'none',
-relief => 'sunken',
-scrollbars => 'osoe',
)->pack(-side => 'right',
-fill => 'both',
-expand => 1,
);
#####################
# Status Bar
#####################
my $status_bar = $main->Label(-text => "Status Area",
-relief => 'sunken',
-borderwidth => 2,
-anchor => 'w');
$status_bar->pack(-side => 'top', -fill => 'x');
#######################
# input the version
#######################
$right->insert('end',"$version\n");
#######################
# key bindings
#######################
$main->bind( '<Alt-r>' => \&refresh); # bind 'Alt-r' to refresh
$main->bind( '<F5>' => \&refresh); # bind 'F5' to refresh
$main->bind( '<space>' => \&refresh); # bind 'space' to refresh
$main->bind( '<Alt-F4>' => \&exit_choice); # bind 'Alt-F4' to quit
$main->bind( '<Alt-q>' => \&exit_choice); # bind 'Alt-q' to quit
$main->bind( '<Alt-p>' => \&getPrefs); # bind 'Alt-p' to get prefs
###################
# Check Arguments and possibly refresh
###################
&checkArgs;
###################
$refresh_id = Tk::After->new($main,$refresh_speed * 1000,'repeat',\&re
+fresh) if ($isRefresh);
##########################
# main loop (never returns)
##########################
MainLoop();
my $pref_window = ();
######################################################################
+##########
# End of Main
######################################################################
+##########
#########################
# sub routines
#########################
sub exit_choice {
exit;
}
################
sub getPrefs {
if ($isRefresh) {
$refresh_id->cancel; # stop refreshing while opening prefs
}
if (not defined $pref_window) {
$pref_window = $main->DialogBox(-title => "HuntTK Preferences",
-buttons => ["OK", "Cancel"]);
my $nb = $pref_window->add('NoteBook', -ipadx => 6, ipady => 6);
my $pref_p = $nb->add("prefs", -label => "Preferences");
my $refresh_p = $nb->add("refresh", -label => "Refresh");
my $open = $pref_p->Button(-text=>"Open Folder...", -command => \&
+open_choice)->pack(-side => 'top',
-anchor => "w",
-expand => "no",
-padx => 4,
-pady => 4);
my $open_entry = $pref_p->Entry(-textvariable => \$folder,
-width => 40)->pack(-expand => 1,
-side => "top",
-anchor => "w");
$pref_p->LabEntry(-label => "Start Frame: ",
-labelPack => [-side => "left", -anchor => "w"],
-width => 10,
-textvariable => \$start,
-background => 'white')->pack(-side => "top", -anchor => "nw")
+;
$pref_p->LabEntry(-label => "End Frame: ",
-labelPack => [-side => "left", -anchor => "w"],
-width => 10,
-textvariable => \$end,
-background => 'white')->pack(-side => "top", -anchor => "nw")
+;
$pref_p->LabEntry(-label => "Search Pattern: ",
-labelPack => [-side => "left", -anchor => "w"],
-width => 20,
-textvariable => \$search_pattern,
-background => 'white')->pack(-side => "top", -anchor => "nw")
+;
my $search_label = $pref_p->Label(-text => "(E.G. \"H\#.tga\")")->
+pack(-expand => 1, -side => "top", -anchor => 'nw');
$pref_p->LabEntry(-label => "Empty Frame Size (bytes):",
-labelPack => [-side => "left", -anchor => "w"],
-width => 10,
-textvariable => \$gBlankFileSize,
-background => 'white')->pack(-side => "top", -anchor => "nw")
+;
$pref_p->LabEntry(-label => "Size Sensitivity:",
-labelPack => [-side => "left", -anchor => "w"],
-width => 10,
-textvariable => \$size_sensitive,
-background => 'white')->pack(-side => "top", -anchor => "nw")
+;
my $size_label = $pref_p->Label(-text => "(default is 50)")->pack(
+-expand => 1, -side => "top", -anchor => 'nw');
$pref_p->LabEntry(-label => "Line Length:",
-labelPack => [-side => "left", -anchor => "w"],
-width => 10,
-textvariable => \$entriesPerLine,
-background => 'white')->pack(-side => "top", -anchor => "nw")
+;
#####################
# refresh_p entry
#####################
my $refresh_OK = $refresh_p->Checkbutton(-variable => \$refresh_on
+_OK,
-text => "Refresh after clicking OK")->pack(-side => "top", -a
+nchor => "nw");
my $refresh_check = $refresh_p->Checkbutton(-variable => \$isRefre
+sh,
-text => "Refresh Interval On") -> pack(-side => "top", -ancho
+r => 'nw');
$refresh_p->LabEntry(-label => "Refresh every (X) seconds:",
-labelPack => [-side => "left", -anchor => "w"],
-width => 10,
-textvariable => \$refresh_speed,
-background => 'white')->pack(-side => "top", -anchor => "nw")
+;
####################
# bind
####################
$nb->pack(-expand => "yes",
-fill => "both",
-padx => 5, -pady => 5,
-side => "top");
} # end if (not defined...)
my $ result = $pref_window->Show;
if ($result =~ /OK/) {
if ( $entriesPerLine < 10) {
$entriesPerLine = 10;
}
if ($isRefresh) {
if ( $refresh_speed < $fastest_refresh ) {
$refresh_speed = $fastest_refresh;
}
$refresh_id = Tk::After->new($main,$refresh_speed * 1000,'
+repeat',\&refresh);
}
&get_env_vars;
if ( $refresh_on_OK ) {
&getTitle;
&refresh;
}
}
else {
# restore old refreshing status
$refresh_id = Tk::After->new($main,$refresh_speed * 1000,'repe
+at',\&refresh) if ($isRefresh);
}
}
################
sub get_env_vars {
##########################################
# This handles ENV variables in the Prefs
##########################################
my $env_variable = ();
my $old_var = ();
if ($folder =~ /\$/) {
$env_variable = $folder;
$env_variable =~ s/\/$// ; # del trailing '/'
# does the var have additional paths attached to it?
if ( $env_variable =~ /\// ) {
#loop and del folders
while ( $env_variable =~ /\//) {
$env_variable =~ s/(.*)\/.*/$1/ ;
}
$env_variable =~ s/\$// ;
$old_var = $env_variable ;
$env_variable = $ENV{"$env_variable"} ;
$folder =~ s/^\$$old_var(.*)/$env_variable$1/ ;
}
else {
$env_variable =~ s/\$// ;
$env_variable = $ENV{"$env_variable"} ;
$folder = $env_variable;
}
}
####################
# end get_env_var
####################
}
#################
sub open_choice {
&get_env_vars;
my $fs = $pref_window->FileSelect
(-directory => "$folder", # Alias: -initialdir
-initialfile => "*",
-filter => "", # only allow dir choices
-filelabel => "File",
-filelistlabel => "File List",
-dirlabel => "Look In...",
-dirlistlabel => "Directories",
-verify => ['-d'], # accept only dirs
-acceptlabel => "OK",
-cancellabel => "Cancel",
-resetlabel => "Reset",
-homelabel => "Home",
-title => "Choose a folder...",
);
my $newfolder = $fs->Show;
if ($newfolder) {
$folder = $newfolder;
&getTitle;
$main->title("$name - $win_title");
}
}
###################
sub doHunt {
$right->delete(0.1,'end');
$right->insert('end',"$version\n");
$right->insert('end',&getDate."\n");
&hunt;
}
###################
sub refresh {
&getTitle;
$main->title("$name - Refreshing $win_title...");
my ($ymytopchar, $ymyposition) = $right->yview(); #save the curren
+t scroll pos
my ($xmyleftchar, $xmyposition) = $right->xview();
#print "$xmyleftchar, $xmyposition, $ymytopchar, $ymyposition\n";
&doHunt();
if ($ymyposition == 1 && $ymytopchar != 0) {
$right->yview(moveto=>$ymyposition); # stay at bottom of text
+if already there
}
else {
$right->yview(moveto=>$ymytopchar); # restore old y scroll pos
}
$right->xview(moveto=>$xmyleftchar); # restore old x scroll pos
$main->title("$name - $win_title");
}
###################
sub getDate {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) ;
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(
+time);
$mon++;
if ($min < 10) { $min = "0$min"; }
if ($hour < 10) { $hour = "0$hour"; }
if ($mday < 10) { $mday = "0$mday"; }
if ($mon < 10) { $mon = "0$mon"; }
if ($sec < 10) { $sec = "0$sec"; }
if ( $year < 1900 ) { $year = $year+1900; }
return "$mon/$mday/$year $hour:$min:$sec";
}
###################
sub getTitle {
$win_title = $folder;
$win_title =~ s/\/$// ; # get rid of possible ending '/'
$win_title =~ s/.*\/(.*)/$1/ ; # del all but last folder in pat
+h
}
######################
sub print_help {
$right->delete(0.1,'end');
$right->insert('end',"$version\n");
$right->insert('end',&getDate."\n");
$right->insert('end',$helptxt);
$main->title("$name");
&update_status('Help');
}
#####################
#
# pass in value to be put into status bar
###########
sub update_status {
my ($status_value) = @_;
$status_bar->configure(-text => $status_value, -justify => 'left')
+;
}
#######################
sub checkArgs {
if ($#ARGV eq 0) {
$folder = $ARGV[0] ;
}
elsif ( $ARGV[0] eq '-' && $#ARGV eq 1 ) {
$folder = $ARGV[1] ;
&refresh();
}
}
####################################
sub hunt {
# global vars
##############
$pad =();
$ispad = 0;
@final_frames = ();
@start_frames = ();
# get the prefix and suffix
($gPrefix, $gSuffix) = split (/\#/, $search_pattern);
&getPadding(0); # This gets the initial amount of padding ze
+ros
# There are conditional statements inside of &driver t
+o remove
# zeros when the frame count increases.
&driver;
} # end sub hunt
######################
sub showLegend {
$right->insert('end',"Legend:\n");
$right->insert('end'," $gCharNormal -> Normal Frame $g
+CharMissing -> Missing Frame\n");
$right->insert('end'," $gCharZero -> Zero-Sized Frame $gCh
+arQuestionable -> Questionable Frame\n");
if ($gFlagCheckBlank == 1) {
$right->insert('end', " $gCharBlank -> Possible Blank Frame
+ \n");
} # if
} # showLegend
#################################################
sub getPadding {
my ($i) = @_;
$pad = "";
my $theFileName = "${gPrefix}${i}${gSuffix}";
my $thePath = "${folder}/${theFileName}";
my $isfound = 0 ;
while (! $isfound ) {
if (-e "$thePath") {
$isfound = 1;
$ispad = 1;
}
else {
$pad = $pad."0";
$theFileName = "${gPrefix}${pad}${i}${gSuffix}";
$thePath = "${folder}/${theFileName}";
if ($pad eq "0000") {
$pad = "";
$isfound = 1; # stop looping
}
}
} # end while
}
###########################
sub showKeyFrames {
my $status_value = "Start/End Frame(s): ";
my $frame = 0;
while ($start_frames[$frame]) {
$status_value .= "[ $start_frames[$frame], $final_frames[$fram
+e] ] - ";
$frame++;
}
&update_status ($status_value);
$right->insert('end', "\n$status_value\n");
}
#################
sub driver {
my ($thePath, $theFileName, $theCount, $deltaSize,
$previousSize, $size);
# check desintation directory for readability.
if (!((-d $folder) && (-x $folder))) {
die "Not a readable directory: ${folder}\n";
} # if
$right->insert('end',"Checking $folder from $start to $end \n");
$theCount = 0;
$previousSize = -2;
my $i = ();
for ($i = $start; $i <= $end; $i++) {
# line header
if (!($theCount % $entriesPerLine)) {
$right->insert('end',"$i\t ");
} else {
if (!($theCount % ($entriesPerLine / 2))) {
$right->insert('end'," | ");
} # if
} # else
############################
# remove padding if needed
############################
if ($ispad && $i =~ /^10{1,}$/) {
if ($i eq 10 ) {
$pad =~ s/\d// ;
}
elsif ($i eq 100 ) {
$pad =~ s/\d//;
}
elsif ($i eq 1000 ) {
$pad =~ s/\d//;
}
elsif ($i eq 10000 ) {
$pad =~ s/\d//;
}
}
if (! $ispad ) {
&getPadding($i);
}
$theFileName = "${gPrefix}${pad}${i}${gSuffix}";
$thePath = "${folder}/${theFileName}";
# $right->insert('end',"Checking for: ${thePath}\n");
if (!(-r $thePath)) {
$right->insert('end', $gCharMissing);
if ($previousSize ne -1) {
push @final_frames, ${i}-1 ;
}
$previousSize = -1;
} else {
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime
+,$ctime,$blksize,$blocks) = stat $thePath;
# get possible starting frames
###############################
if ($previousSize lt 0 && $size ge 0) {
push @start_frames, ${i} ;
}
if ($size == 0) {
$right->insert('end',$gCharZero);
} elsif (($gFlagCheckBlank == 1) && ($size == $gBlankFileSize)
+) {
$right->insert('end',$gCharBlank);
} else {
if ($previousSize != 0) {
$deltaSize = abs($size - $previousSize);
if (($deltaSize / $previousSize) > ($size_sensitive / 100.
+0)) {
$right->insert('end',$gCharQuestionable);
} else {
$right->insert('end',$gCharNormal);
} # else
} else {
$right->insert('end', $gCharNormal);
} # else
} # else
$previousSize = $size;
} # else
$theCount++;
if (!($theCount % $entriesPerLine) || (($i + 1) > $end)) {
$right->insert('end'," $i\n");
} # if
} # for i
$right->insert('end',"\n");
&showLegend;
&showKeyFrames;
} # driver
################
-
dystrophy -