our
(
$mw
,
$root_bookkeeper
,
$hlist
,
$hlist_stuff
,
$font
,
$statusarea
,
$paused
,
$pausebutton
,
$resumebutton
,
$debugmode
);
our
$VERSION
=
'0.32'
;
&init
;
sub
newdo {
my
$class
=
shift
;
$root_bookkeeper
= Win32::CtrlGUI::State::bookkeeper->new(Win32::CtrlGUI::State->new(
@_
));
$Win32::CtrlGUI::State::atom::action_error_handler
=
sub
{
my
(
$errormsg
) =
@_
;
&update_status
(
'paused'
);
$mw
->deiconify;
$mw
->update;
my
$dialog
=
$mw
->Dialog(
-text
=>
"The following exception was thrown:\n$errormsg"
,
-bitmap
=>
'error'
,
-title
=>
'Action Error'
,
-default_button
=>
'OK'
,
-buttons
=> [
qw/OK/
]
);
$dialog
->Show();
};
my
$old_debug_print
= \
&Win32::CtrlGUI::State::debug_print
;
*Win32::CtrlGUI::State::debug_print
=
sub
{
my
$self
=
shift
;
my
(
$debug_level
,
$text
) =
@_
;
&append_to_status_area
(
$text
);
};
foreach
my
$widget
(
$mw
->children) {
$widget
->destroy;
}
$hlist
=
$mw
->Scrolled(
'HList'
,
-scrollbars
=>
'se'
,
-drawbranch
=> 1,
-separator
=>
'/'
,
-indent
=> 15,
-background
=>
'grey'
)->
pack
(
-side
=>
'top'
,
-expand
=> 1,
-fill
=>
'both'
);
$hlist
->Subwidget(
'scrolled'
)->configure(
-padx
=> 2,
-pady
=> 2);
my
$exit_trigger
= 0;
$mw
->protocol(
WM_DELETE_WINDOW
=>
sub
{
$exit_trigger
= 1});
$statusarea
=
$mw
->Scrolled(
'ROText'
,
-scrollbars
=>
'se'
,
-width
=> 140,
-height
=> 9,
-wrap
=>
'none'
)->
pack
(
-side
=>
'top'
,
-fill
=>
'both'
);
$mw
->Button(
-text
=>
'Exit'
,
-command
=>
sub
{
$exit_trigger
= 1})->
pack
(
-side
=>
'right'
,
-padx
=> 5,
-pady
=> 5);
$resumebutton
=
$mw
->Button(
-text
=>
'Resume'
,
-command
=>
sub
{
&update_status
(
'running'
)})->
pack
(
-side
=>
'right'
,
-padx
=> 5,
-pady
=> 5);
$pausebutton
=
$mw
->Button(
-text
=>
'Pause'
,
-command
=>
sub
{
&update_status
(
'paused'
)})->
pack
(
-side
=>
'right'
,
-padx
=> 5,
-pady
=> 5);
&update_status
(
'running'
);
$mw
->iconify;
$mw
->title(
"Win32::CtrlGUI::State Debugger - $0"
);
$mw
->update;
Win32::API->new(
"user32"
,
"SetWindowPos"
,[
qw(N N N N N N N)
],
'N'
)->Call(
hex
(
$mw
->frame()),-1,0,0,0,0,3);
$debugmode
and
$mw
->deiconify;
&add_state
(
'root'
,
$root_bookkeeper
);
my
$last_sweep
= Win32::GetTickCount();
my
$intvl
=
$root_bookkeeper
->{state}->wait_intvl;
while
(1) {
if
(
$last_sweep
+
$intvl
< Win32::GetTickCount()) {
unless
(
$paused
) {
if
(
$root_bookkeeper
->bk_status eq
'pfs'
) {
$root_bookkeeper
->bk_set_status(
'pcs'
);
}
if
(
$root_bookkeeper
->bk_status eq
'pcs'
) {
$root_bookkeeper
->is_recognized and
$root_bookkeeper
->bk_set_status(
'active'
);
}
if
(
$root_bookkeeper
->bk_status eq
'active'
) {
$root_bookkeeper
->do_action_step;
}
if
(
$root_bookkeeper
->state =~ /^done|fail$/) {
$root_bookkeeper
->{executed}++;
$root_bookkeeper
->bk_set_status(
'never'
);
&update_status
(
'finished'
);
$debugmode
or
$exit_trigger
= 1;
}
&refresh_states
(
'root'
,
'active'
);
}
$last_sweep
= Win32::GetTickCount();
}
$mw
->update;
$exit_trigger
and
last
;
Win32::Sleep(100);
}
$Win32::CtrlGUI::State::atom::action_error_handler
=
undef
;
*Win32::CtrlGUI::State::debug_print
=
$old_debug_print
;
}
sub
update_status {
my
(
$status
) =
@_
;
$status
=~ /^running|paused|finished$/ or
die
"Illegal status value '$status' passed.\n"
;
$paused
=
$status
eq
'running'
? 0 : 1;
$pausebutton
->configure(
-state
=>
$status
eq
'running'
?
'normal'
:
'disabled'
);
$resumebutton
->configure(
-state
=>
$status
eq
'paused'
?
'normal'
:
'disabled'
);
&append_to_status_area
(
"Script $status"
);
}
sub
append_to_status_area {
my
(
$text
) =
@_
;
$statusarea
->insert(
'end'
,
$text
?
map
{(
split
(/\s+/,
localtime
(
$_
->[0])))[3].
sprintf
(
".%03d"
,
$_
->[1]).
" $text\n"
} [
&finetime
] :
"\n"
);
$statusarea
->see(
'end'
);
}
sub
add_state {
my
(
$path
,
$bookkeeper
) =
@_
;
my
$text
;
if
(UNIVERSAL::isa(
$bookkeeper
->{state},
'Win32::CtrlGUI::State::multi'
)) {
(
$text
=
ref
(
$bookkeeper
->{state})) =~ s/^Win32::CtrlGUI::State:://;
}
else
{
$text
=
$bookkeeper
->{state}->stringify;
$text
=~ s/^([^=]+) =>/$1:\t/gm;
}
my
$widget
=
$hlist
->ROText(
-wrap
=>
'none'
,
-borderwidth
=> 0,
-background
=>
'grey'
,
-height
=> 1,
-width
=> 200,
-tabs
=> [
'35p'
]);
$widget
->tagConfigure(
'active'
,
-foreground
=>
'red'
,
-font
=> [@{
$font
},
'bold'
]);
$widget
->tagConfigure(
'pcs'
,
-foreground
=>
'black'
,
-font
=> [@{
$font
},
'bold'
]);
$widget
->tagConfigure(
'pfs'
,
-foreground
=>
'black'
,
-font
=> [@{
$font
}]);
$widget
->tagConfigure(
'executed'
,
-foreground
=>
'dark red'
,
-font
=> [@{
$font
}]);
$widget
->tagConfigure(
'skipped'
,
-foreground
=>
'black'
,
-font
=> [@{
$font
},
'overstrike'
]);
$widget
->tagConfigure(
'default'
,
map
{@{
$_
}[0,4]}
$widget
->tagConfigure(
'pfs'
));
$widget
->insert(
'end'
,
$text
,
'default'
);
$widget
->configure(
-height
=> (
$text
=~
tr
/\n//)+1);
$hlist
->add(
$path
,
-itemtype
=>
'window'
,
-widget
=>
$widget
);
$hlist_stuff
->{
$path
} = {
widget
=>
$widget
,
bookkeeper
=>
$bookkeeper
};
if
(UNIVERSAL::isa(
$bookkeeper
->{state},
'Win32::CtrlGUI::State::multi'
)) {
my
$i
= 0;
foreach
my
$substate
(
$bookkeeper
->{state}->get_states) {
&add_state
(
"$path/"
.
$i
++,
$substate
);
}
}
}
sub
refresh_states {
my
(
$path
,
$pstatus
) =
@_
;
my
$stuff
=
$hlist_stuff
->{
$path
};
my
$status
=
$stuff
->{bookkeeper}->bk_status_given(
$pstatus
);
if
(
$status
ne
$stuff
->{old_status}) {
if
(
$status
eq
'active'
) {
$stuff
->{widget}->tagConfigure(
'default'
,
map
{@{
$_
}[0,4]}
$stuff
->{widget}->tagConfigure(
$status
));
$hlist
->yview(
$path
);
}
elsif
(
$status
eq
'pcs'
or
$status
eq
'pfs'
) {
$stuff
->{widget}->tagConfigure(
'default'
,
map
{@{
$_
}[0,4]}
$stuff
->{widget}->tagConfigure(
$status
));
}
elsif
(
$status
eq
'never'
) {
if
(
$stuff
->{bookkeeper}->{executed}) {
$stuff
->{widget}->tagConfigure(
'default'
,
map
{@{
$_
}[0,4]}
$stuff
->{widget}->tagConfigure(
'executed'
));
}
else
{
$stuff
->{widget}->tagConfigure(
'default'
,
map
{@{
$_
}[0,4]}
$stuff
->{widget}->tagConfigure(
'skipped'
));
}
}
else
{
die
"ARGH!"
;
}
if
(
$stuff
->{old_status} eq
'pcs'
&& !UNIVERSAL::isa(
$stuff
->{bookkeeper}->{state},
'Win32::CtrlGUI::State::multi'
)) {
my
$text
=
$stuff
->{bookkeeper}->{state}->stringify;
$text
=~ s/^([^=]+) =>/$1:\t/gm;
$stuff
->{widget}->
delete
(
'1.0'
,
'end'
);
$stuff
->{widget}->insert(
'end'
,
$text
,
'default'
);
$stuff
->{widget}->configure(
-height
=> (
$text
=~
tr
/\n//)+1);
}
$stuff
->{old_status} =
$status
;
}
if
(
$status
eq
'pcs'
&& !UNIVERSAL::isa(
$stuff
->{bookkeeper}->{state},
'Win32::CtrlGUI::State::multi'
)) {
my
(
@text
) =
$stuff
->{bookkeeper}->{state}->tagged_stringify;
$stuff
->{widget}->
delete
(
'1.0'
,
'end'
);
my
$lines
= 1;
foreach
my
$i
(
@text
) {
$stuff
->{widget}->insert(
'end'
,
$i
->[0],
$i
->[1]);
$lines
+= (
$i
->[0] =~
tr
/\n//);
}
$stuff
->{widget}->configure(
-height
=>
$lines
);
}
my
(
@children
) =
$hlist
->info(
'children'
,
$path
);
if
(
$status
eq
'active'
&&
scalar
(
grep
{
$hlist_stuff
->{
$_
}->{bookkeeper}->bk_status eq
'active'
}
@children
)) {
$status
=
'pfs'
;
}
foreach
my
$subpath
(
@children
) {
&refresh_states
(
$subpath
,
$status
);
}
}
sub
init {
$mw
= MainWindow->new;
$mw
->withdraw();
$font
= [
qw(Arial 8)
];
my
$width
=
$mw
->screenwidth();
my
$height
=
$mw
->screenheight();
$mw
->geometry(
sprintf
(
"%dx%d+%d+%d"
,
$width
*.4,
$height
-100,
$width
*.6-32, 0));
$debugmode
= 0;
}
{
my
$finetime_tick
;
my
$finetime_time
;
sub
finetime {
unless
(
$finetime_tick
) {
$finetime_time
=
time
+1;
until
(
$finetime_time
<=
time
) {
$finetime_tick
= Win32::GetTickCount();
}
}
my
$tick
= Win32::GetTickCount();
my
(
$finetime
,
$finetick
) = (
$finetime_time
+
int
((
$tick
-
$finetime_tick
)/1000), (
$tick
-
$finetime_tick
)%1000);
$finetime
=
$finetime
+
int
((
$finetime
-
time
+2_147_483_648)/4_294_967_296);
return
wantarray
? (
$finetime
,
$finetick
) :
$finetime
+
$finetick
/1000;
}
}
1;