------------------------------
-- guiTimer.adb
-- (mathtalk 2003-01-22)
--
-- GUI "stopwatch" application
-- built with JEWL library in
-- Ada (GNAT 3.16 compiler)
--
-- Bouncing balls in box added
-- (mathtalk 2003-01-31)
------------------------------
with JEWL.Simple_Windows; use JEWL.Simple_Windows;
with Ada.Calendar; use Ada.Calendar;
procedure GuiTimer is
-- declare the task to manage bouncing balls
task BallBox is
entry setFlag(Flag : in Integer);
end BallBox;
Time_Start : Time;
Time_Flag : Integer := 0;
My_Frame : Frame_Type
:= Frame (180, 150, "GUI Timer", 'Q');
Start_It : Button_Type
:= Button (My_Frame, (45,10), 80, 25, "Start", 'R');
Stop_It : Button_Type
:= Button (My_Frame, (45,45), 80, 25, "Stop", 'S');
Elapsed : Label_Type
:= Label (My_Frame, (20,95), 130, 25, "0 sec.", Center);
-- define the task to manage three bouncing balls
task body BallBox is
F : Frame_Type := Frame (300, 250, "Balls", 'Q');
C : Canvas_Type := Canvas (F, (0,0), 0, 0, 'X', 'X');
P : Integer := Get_Width(C)/2;
W : Integer := Get_Width(C);
H : Integer := Get_Height(C);
B1 : Point_Type := (P, Get_Height(C) - 25);
X1 : Integer := 5;
Y1 : Integer := -10;
B2 : Point_Type := (P - 20, Get_Height(C) - 25);
X2 : Integer := -5;
Y2 : Integer := 10;
B3 : Point_Type := (P + 20, Get_Height(C) - 25);
X3 : Integer := -5;
Y3 : Integer := -10;
M : Integer := 0;
begin
Set_Fill(C,Black);
Save(C);
loop
select
accept setFlag(Flag: in Integer) do
M := Flag;
end setFlag;
else
delay 0.05;
end select;
if M=-1 then
exit;
elsif M=1 then
Restore(C);
Draw_Circle(C,B1,5);
if B1.Y < 5 or B1.Y >= H-5 then
Y1 := -Y1;
end if;
if B1.X < 5 or B1.X >= W-5 then
X1 := -X1;
end if;
B1 := B1 + (X1,Y1);
Draw_Circle(C,B2,5);
if B2.Y < 5 or B2.Y >= H-5 then
Y2 := -Y2;
end if;
if B2.X < 5 or B2.X >= W-5 then
X2 := -X2;
end if;
B2 := B2 + (X2,Y2);
Draw_Circle(C,B3,5);
if B3.Y < 5 or B3.Y >= H-5 then
Y3 := -Y3;
end if;
if B3.X < 5 or B3.X >= W-5 then
X3 := -X3;
end if;
B3 := B3 + (X3,Y3);
end if;
end loop;
Close(F);
exception
when others =>
Close(F);
end BallBox;
begin
loop
if Command_Ready then
case Next_Command is
when 'Q' =>
BallBox.setFlag(-1);
Close (My_Frame);
exit;
when 'R' =>
if Time_Flag=0 then
Time_Flag := 1;
BallBox.setFlag(1);
Time_Start := Clock;
Set_Text (Elapsed, "0 sec.");
end if;
when 'S' =>
if Time_Flag=1 then
Set_Text (Elapsed,
Duration'Image(Clock - Time_Start) & " sec.");
Time_Flag := 0;
BallBox.setFlag(0);
end if;
when others =>
null;
end case;
elsif Time_Flag=1 then
Set_Text (Elapsed,
Integer'Image(Integer(Clock - Time_Start)) & " sec.");
Delay 0.1;
end if;
end loop;
end GuiTimer; |
Clarification of Answer by
mathtalk-ga
on
31 Jan 2003 05:37 PST
Hi, twbarrel:
Above is the modified GUI timer program presented earlier, modified to
manage three bouncing balls in a box. These balls do not collide with
each other, only with the edges of the box, per our previous
discussion.
Since you were able to compile and run the earlier program, I think
you will not have any difficulty with this one either. However for
the sake of completeness here are a couple of notes on how I build the
application.
There is only one compilation unit, not the two units that I was
struggling with earlier. I named it guitimer.adb, same as the earlier
program. While I started development in the C:\JEWL\examples
directory on my machine, I realized that this ran a risk of clobbering
the sample programs there and moved the files to another directory
(TimerAda) under my personal documents.
I created a "batch" command file called setenv.bat in C:\JEWL\examples
with these lines:
set ADA_INCLUDE_PATH=C:\JEWL\source
set ADA_OBJECTS_PATH=C:\JEWL\source
Then, when I open a "DOS" command box to do builds, I can first run
this file, which alerts the gnatmake utility where to find the
necessary JEWL library contents.
Finally I execute:
gnatmake guiTimer -largs -mwindows
from within the same directory (TimerAda) as my application source.
I'll be happy to provide a more commented version of the program if
you like. For now let me mention the "program limitations" that I'm
aware of.
The limited options in JEWL, specifically for the Frame( )
constructor, do not allow for the "child" window to be made
unresizable. There is essentially only one window type available.
The JEWL pong demo program I emulated handled the resizing in a
partial fashion. I decided not to try handling resizing at all, in the
sense that if you enlarge the window or move it, the balls continue to
"bounce" within boundaries congruent to the original window. I
believe this to be a more stable approach than was present in the pong
code, but a "proper" handling of frame resizing would be possible at
the expense of more complicated logic. [The big problem with resizing
in the original demo would be seen if the frame size is reduced so
that the ball is off the screen; the logic would not permit the ball
to return.]
The other limitation is a bit of a glitch in appearance. The timer
"parent" window and the ball box "child" window seem to consistently
overlap when the program starts. I don't believe that any of the
arguments to the Frame( ) constructor allow us to mitigate this.
Instead I find it necessary to grab the title bar of the "Balls"
window and move it so that it does not overlap.
One final comment on JEWL: I found it to be a very easy to use
package, just as author John English describes it, with a tradeoff of
limited functionality such as illustrated above. I sent John an
email, thanking him for his efforts, and also reporting a minor bug
(the first two arguments of Frame( ) are reversed in the
documentation).
Thanks for posting this very challenging question, twbarrel. Please
let me know what clarifications would be most useful to you.
regards, mathtalk
|