use
subs
qw/ClearMsg DoSingleStep NotDone ShowMsg SimStart SimStop mkmb/
;
my
(
@menu_button_list
,
$quit_flag
,
$quit_code
,
$bounce_status
,
$bounce_speed
,
$bounce_running
,
$bounce_counter
);
sub
bounce {
my
(
$demo
) =
@_
;
$TOP
->destroy
if
Exists(
$TOP
);
$TOP
=
$MW
->Toplevel;
$TOP
->title(
'Bouncing Ball Simulator'
);
$TOP
->iconname(
'bounce'
);
@menu_button_list
= ();
$quit_flag
= 0;
$quit_code
=
sub
{
$quit_flag
= 1};
$TOP
->protocol(
'WM_DELETE_WINDOW'
=>
$quit_code
);
my
$menubar
=
$TOP
->Frame(
qw/-relief raised -background DarkGreen -bd 2/
);
$menubar
->
pack
(
-side
=>
'top'
,
-fill
=>
'x'
);
mkmb(
$menubar
,
'File'
, 0,
'File related stuff'
,
[
[
'Open'
, \
&NotDone
, 0],
[
'New'
, \
&NotDone
, 0],
[
'Print'
, \
&NotDone
, 0],
[
'Exit'
,
sub
{
$TOP
->bell}, 0],
]);
mkmb(
$menubar
,
'Simulate'
, 0,
'Simulator control'
,
[
[
'Start'
, \
&SimStart
, 2],
[
'Stop'
, \
&SimStop
, 2],
]);
mkmb(
$menubar
,
'Display'
, 0,
'Display settings'
,
[
[
'Redraw'
, \
&NotDone
, 2],
[
'Clear'
, \
&NotDone
, 2],
]);
mkmb(
$menubar
,
'Options'
, 0,
'Various preferences'
,
[
[
'Steptime'
, \
&NotDone
, 0],
[
'Colors'
, \
&NotDone
, 0],
[
'Display'
, \
&NotDone
, 0],
]);
mkmb(
$menubar
,
'Help'
, 0,
'There when you need it'
,
[
[
'About..'
, \
&NotDone
, 0],
[
'Intro'
, \
&NotDone
, 0],
[
'Contents'
, \
&NotDone
, 0],
]);
$menu_button_list
[
$#menu_button_list
]->
pack
(
-side
=>
'right'
);
my
$feedback
=
$TOP
->Frame();
$feedback
->
pack
(
-side
=>
'bottom'
,
-fill
=>
'x'
);
$bounce_status
=
$feedback
->Text(
-relief
=>
'sunken'
,
-height
=> 1,
-background
=>
'gray'
,
-borderwidth
=> 2,
);
$bounce_status
->
pack
(
-side
=>
'left'
,
-fill
=>
'x'
,
-expand
=> 1);
my
$drawarea
=
$TOP
->Frame();
$drawarea
->
pack
(
-side
=>
'top'
,
-fill
=>
'both'
,
-expand
=> 1);
my
$canvas
=
$drawarea
->Canvas(
-relief
=>
'ridge'
,
-height
=> 400,
-width
=> 600,
-borderwidth
=> 2,
);
$canvas
->
pack
(
-side
=>
'left'
,
-fill
=>
'both'
,
-expand
=> 1);
$bounce_speed
=
$drawarea
->Scale(
-orient
=>
'vert'
,
-showvalue
=> 0,
-width
=> 10,
-from
=> 100,
-to
=> 0,
-borderwidth
=> 1,
);
$bounce_speed
->
pack
(
-side
=>
'left'
,
-fill
=>
'y'
);
$bounce_speed
->
bind
(
'<Enter>'
=>
sub
{
ClearMsg; ShowMsg(
'Adjust slider for ball speed'
);
});
$bounce_speed
->
bind
(
'<Leave>'
=> \
&ClearMsg
);
$bounce_speed
->set(50);
my
$w_buttons
=
$TOP
->Frame;
$w_buttons
->
pack
(
qw(-side bottom -expand y -fill x -pady 2m)
);
my
$w_dismiss
=
$w_buttons
->Button(
-text
=>
'Dismiss'
,
-command
=>
$quit_code
,
);
$w_dismiss
->
pack
(
qw(-side left -expand 1)
);
my
$w_see
=
$w_buttons
->Button(
-text
=>
'See Code'
,
-command
=> [\
&see_code
,
$demo
],
);
$w_see
->
pack
(
qw(-side left -expand 1)
);
my
$w_ball
=
$w_buttons
->Button(
-text
=>
'View Ball Class Module'
,
-command
=> [\
&view_widget
,
Tk->findINC(
'demos/widget_lib'
) .
'/Ball.pm'
],
);
$w_ball
->
pack
(
qw(-side left -expand 1)
);
$bounce_running
= 0;
$menu_button_list
[1]->cget(-menu)->entryconfigure(1,
-state
=>
'disabled'
);
$canvas
->Ball;
$canvas
->Ball(
-color
=>
'red'
,
-size
=> 30,
-position
=> [200, 75]);
$canvas
->Ball(
-color
=>
'green'
,
-size
=> 60,
-position
=> [490, 275],
-velocity
=> [8.0, 12.0],
);
$canvas
->Ball(
-color
=>
'yellow'
,
-size
=> 100,
-position
=> [360, 60],
-velocity
=> [8.0, 12.0],
);
$bounce_counter
= 0;
$TOP
->repeat(
1000
=>
sub
{
return
unless
$bounce_running
;
ClearMsg;
ShowMsg(
sprintf
(
"%6d interations/second"
,
$bounce_counter
));
$bounce_counter
= 0
});
while
(1) {
if
(
$quit_flag
) {
$TOP
->destroy;
return
;
}
DoOneEvent(
$bounce_running
? DONT_WAIT : ALL_EVENTS);
DoSingleStep(
$canvas
)
if
$bounce_running
;
}
}
sub
mkmb {
my
(
$mb0
,
$mb_label
,
$mb_label_underline
,
$mb_msg
,
$mb_list_ref
) =
@_
;
my
$mb
=
$mb0
->Menubutton(
-text
=>
$mb_label
,
-underline
=>
$mb_label_underline
,
-background
=>
'DarkGreen'
,
-foreground
=>
'Yellow'
,
);
my
(
$menu
) =
$mb
->Menu(
-tearoff
=> 0);
$mb
->configure(
-menu
=>
$menu
);
my
$mb_list
;
foreach
$mb_list
(@{
$mb_list_ref
}) {
$mb
->command(
-label
=>
$mb_list
->[0],
-command
=>
$mb_list
->[1] ,
-underline
=>
$mb_list
->[2],
-background
=>
'DarkGreen'
,
-foreground
=>
'White'
,
);
}
$mb
->
pack
(
-side
=>
'left'
);
$TOP
->
bind
(
$mb
,
'<Enter>'
=>
sub
{ClearMsg; ShowMsg(
$mb_msg
)});
$TOP
->
bind
(
$mb
,
'<Leave>'
=> \
&ClearMsg
);
push
@menu_button_list
,
$mb
;
return
$mb
;
}
sub
SimStart {
if
(not
$bounce_running
) {
$bounce_running
= 1;
$menu_button_list
[1]->cget(-menu)->entryconfigure(0,
-state
=>
'disabled'
,
);
$menu_button_list
[1]->cget(-menu)->entryconfigure(1,
-state
=>
'normal'
,
);
}
}
sub
SimStop {
if
(
$bounce_running
) {
$bounce_running
= 0;
$menu_button_list
[1]->cget(-menu)->entryconfigure(0,
-state
=>
'normal'
,
);
$menu_button_list
[1]->cget(-menu)->entryconfigure(1,
-state
=>
'disabled'
,
);
}
}
sub
NotDone {
print
"Not yet implemented.\n"
;
}
sub
ShowMsg {
my
(
$msg
) =
shift
;
$bounce_status
->insert(
'1.0'
,
$msg
);
}
sub
ClearMsg {
$bounce_status
->
delete
(
'1.0'
,
'end'
);
}
sub
DoSingleStep {
my
(
$canvas
) =
@_
;
$bounce_counter
++;
Ball->move_all_balls(
$canvas
,
$bounce_speed
->get() / 100.0);
}