home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
CMAGIC.ZIP
/
TUTOR.2
< prev
next >
Wrap
Text File
|
1992-09-02
|
53KB
|
1,090 lines
CONTINUED FROM FILE: TUTOR.DOC
Program #20 is going to be a big, but very special program
because it will be something you'll use everyday. Run it
and see what it does, then study the source code to
understand it.
/* program #20 */
#include <magic.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
void extkey(void);
void asciichart(void);
void main(){ /*** 1 ***/
magic_setup();
centerjustify = 1;
xclear();
mc = 1;
do {
boxback = RED;
pile("Programmer's Tools");
pile("Copyright 1992, Freeware by Another Company");
pop(18,2);
boxback = GREEN;
strcpy(sent[1],"ASCII Chart"); /*** 2 ***/
strcpy(sent[2],"Extended Keys");
strcpy(sent[3],"Quit");
menu(-1,-1);
if (u == 13) switch (mc) {
case 1 : asciichart(); break; /*** 3 ***/
case 2 : extkey();
}
restore(); /*** 4 ***/
}
while (!((u == 13) && (mc == 3)));
cleanup();
}
void extkey(void){
char tempstr[3];
xclear();
pile("Press any key to see it's extended code");
pile("Press [Esc] when done.");
pop(18,3);
strcpy(sent[1]," ");
strcpy(sent[2],"");
do {
getanykey(-1,-1);
if (keydetect == 2){ /*** 5 ***/
strcpy(sent[1],"#0 + ");
}
sprintf(tempstr,"%c",u);
if ((u == 13) || (u == 8) || (u == 10) || (u == 7))
strcat(sent[1]," "); /*** 6 ***/
else strcat(sent[1],tempstr);
itoa(u,tempstr,10);
strcat(sent[1],"(#");
strcat(sent[1],tempstr);
strcat(sent[1],")");
}
while (u != 27); /*** 7 ***/
xclear();
} // end of function extkey()
void asciichart(void){
char x = 1,y = 1; /*** 8 ***/
int temp;
char tempstr[3];
textcolor(YELLOW); textbackground(BLUE);
clrscr();
for (temp = 0; temp < 256; temp++) { /*** 9 ***/
gotoxy(x,y);
cprintf(" ");
if (temp < 10) cprintf(" "); /*** 10 ***/
if (temp < 100) cprintf (" ");
if ((temp != 7) && (temp != 8) && (temp != 10)
&&(temp != 13) && (temp != 27)) /*** 11 ***/
cprintf("%d=%c ",temp,temp);
else cprintf("%d=",temp);
y++;
if (y > 25){
y = 1;
x += 7; /*** 12 ***/
} //end of if y > 25
} // end of for loop;
waitforuser(); /*** 13 ***/
xclear();
}
Note #1: When most programmers start looking over an
unfamiliar program, they head right for the main() function,
and follow it line by line. When one of these lines is a call
to another function, they go to that function, observe it
line by line, then return to the main() function.
Note #2: Unlike, menu(), getanykey() and dialog(), after a
call to pop(), the sent[]s are not cleared, so if we used
pile() here, sent[4] and sent[5] would get these strings.
Note #3: These are the functions below. If the user selects
menu item 3, the program falls through, otherwise one of
these is then executed.
Note #4: This wipes out the pop(), and frees memory that it
was holding.
Note #5: These two lines are interesting. Getanykey(),
getyn() and many other functions use an internal Magic
function called poll(), (more about it later) which returns
u, the character value of the key pressed, plus keydetected,
a little more information about the keypress. If the user
operated the mouse, keypress = 0. If the user presses
something on the keyboard the value of keypress is greater
than 0. Specifically, if it is an alphanumeric key, the
value will be 1, and if it is an extended key, such as [F2],
[Insert], [Home], etc, keydetected will be 2. For your
convenience, extkey() returns the value of the key pressed,
prefixed by "0 +" for extended keys.
Note #6: These keys are excluded because their values are
unprintable. Some "characters," when written to the screen,
do funny things. For instance ASCII #7 beeps, and #13 causes
a carriage return, which would mess up the chart.
Note #7: This function falls through when the user presses
[Esc], which is ASCII #27.
Note #8: By declaring variables this way, you can force their
initial value. Forgetting to make sure you have a handle on
the initial value of variables is a frequent and hard-to-find
programmer's mistake.
But what's going on here? Are we using char - character -
globals to hold numbers? The answer is YES. You see, C makes
no distinction between a character and a byte. Since any
alphanumeric character can be represented within 0 - 127, we
can use a single byte, which can have a value of -128 to +127
to hold a character. So a byte-size variable has been named
"char" (somewhere in history) because it is often used to
hold character values. So, the variable char, can hold a
small integer value, or hold a character, represented by it's
integer value as listed in the ASCII chart. In other words,
if your char = 65, it also can equal "A", and 66 = "B" and so
on.
Just when you thought it all made sense, remember that
there are 256 values on the entire ASCII chart. So we often
don't use "char" variables to hold characters after all, but
rather "unsigned char" which is still a byte, but in the
range of 0 to 255 (no negative numbers) or even "unsigned
int", in the range of 0 to +65,535. Ints require more RAM
space, since it takes two bytes to hold a number as large as
65,535. Well, don't worry about all this now. It will make
sense later on, as you get more practice.
Note #9: The "for loop." If you haven't seen a for loop
before, get used to it, because it is a very frequent thing
in C programming. The for loop is very flexible and
powerful, but it is usually used this way:
It has 3 parts in the parentheses using the same variable.
The first part initializes the variable to the first value at
which it will be used. The middle statement tests the
variable every time the loop executes. As long as the middle
statement evaluates truthfully, the loop continues. So
usually the > or < test are used. Remember, if you want a
specific number of iterations, it must test for <= your
number, or < your number + 1. The last part changes the value
each time the loop runs. Usually the variable is incremented
by one, as in this example. Whatever follows the for loop is
what occurs on each execution of the loop. Many times there
is a whole block surrounded by { and }. It is usually good
programming practice not to change the loop variable within
the { and }, because you can easily become confused between
your changes here and the loop's own incrementation of the
variable.
In this particular loop, the variable called "temp" is
incremented until it is equal to 255. Since we are testing
up to 256, "temp" must be an "int", not a "char" or an
"unsigned char," because these variables are incapable of
holding an number as big as 256.
There are nine lines within the for loop's block.
Although it may be hard to understand at first, they take
each instance of "temp," - all the characters of the ASCII
chart - and lay them out neatly at x and y coordinates on the
screen.
Note #10: We use "cprintf()" instead of "printf()" because
the former will work with the chosen color variable, a
capability printf() doesn't have. If you can't figure why we
are printing spaces when "temp" is less than 100, try
commenting out these lines and see how your chart looks.
Note #11: These few characters are unprintable. See note #6.
Note #12: We increment "y" until we hit the bottom of the
screen. then we go to the top by resetting y to 1 and move
over to the next row by incrementing x by 7. Notice the
function gotoxy() a few lines above. It moves the next
location at which text will be printed to the coordinates
passed to it.
Note #13: Waitforuser() is a simple Magic function which,
like it sounds, simply stalls until the user presses a key or
clicks a mouse button.
This is an excellent program to study in detail. A
really good way to understand it is to modify it.
Experiment. Make changes, and see if when you run the
program, your changes act as you had expected. See if you can
improve on this program or add new features. Perhaps you can
add a metric to inch converter. Hint: Extend the menu, make
a new function called metric() or something similar. (Make
sure to declare the new function at the top of the program.)
If you can understand all of this, you are well on your
way to being a GOOD programmer.
Program #21 is derived from program #20. It is a
demonstration of writing to a disk file. The object of this
program is to put a column of ASCII equivalents in a text
file, so you can use it with your word processor, etc. Run
program #21, then go look at the file called ASCII.TXT with
the IDE or your favorite word processor.
/* program #21 */
#include <magic.h>
#include <stdio.h>
#include <string.h>
void main(){
magic_setup();
int temp;
nameoutfile("Ascii.txt");
for (temp = 0; temp <= 255; temp++){
if ((temp != 7) && (temp != 8) && (temp != 10)
&& (temp != 13) && (temp != 26) && (temp != 27))
sprintf(sent[1],"%d = %c ",temp,temp);
else sprintf(sent[1],"%d = ",temp);
filewriteln(sent[1]);
}
}
There are two special items in Magic, "infile" and
"outfile." Infile is used to get text or binary information
in from the disk and use it within your program. Outfile is
used to put information out to the disk. Essentially, these
are pathways to disk files. You must give them names that
will be used in the disk directory. As usual with disk
files, these names must be DOS-legal, with up to 8
characters, optionally followed by a period and up to a
three-character extension. Drive designator and sub-directory
designations can precede file names.
The neat thing about the way Magic uses these files is
that you don't have to know all that confusing stuff about
file types, and file handling as presented by your Borland
manuals. Although, later on, you might like to study that
stuff, because pretty much anything you can do with a text or
a binary file, can be done with the two special Magic files.
Anyway, we would use outfile to convey information to
the disk. The first operation in program #21 is to associate
a disk filename with outfile, using "nameoutfile()."
If you forget to attach a name to the magic output file,
it will automatically be named "OUTPUT." If you forget to
rename then input file it will be "INPUT" on disk.
Then a for loop builds a string in the variable sent[1],
containing each ASCII number and the character represented by
that number. The last line in this loop, "filewriteln()"
writes sent[1] to the disk.
There is another function called "filewrite()" which
writes strings to disk, but does not put each one on a
separate line.
If you have named a file that does not yet exist on disk,
it will be created automatically with the first call to
filewriteln() or filewrite(). If the file already exists, the
string passed to filewriteln or filewrite() will be appended
to the end of the file.
The compliment of filewriteln() is filereadln(). Program
#22 shows it in operation, using the previously created
file, "ASCII.TXT".
/* program #22 */
#include <magic.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
void main(){
magic_setup();
clrscr();
nameinfile("ASCII.TXT");
problem = 0;
while (!problem) {
filereadln();
strcpy(sent[1],answer);
printf("%s\n",sent[1]);
}
waitforuser();
cleanup();
}
Not very elegant, since the stuff scrolls right off the
screen, but you get the general idea. If you don't pass
"ASCII.TXT" to nameinfile(), the program will be looking for
the standard infile called "INPUT."
There is a char variable in Magic called "problem" which
is used in many of it's functions. If a function works like
it should, problem is 0, but if the function cannot perform
properly, it changes problem to a number larger than 0,
typically 1. You can use this for many checks and balances
in your program. In this case, problem will become 1 if
filereadln() tries to read past the end of the file. This is,
of course, where the program should stop, so the while loop
is constantly checking the condition of "problem". You'll
notice that this "while" loop is an inversion of the
"do-while" loop you are used to. Sometimes it is easier to
write. The difference is that this variation checks the
condition before the loop executes, the do-while loop always
runs at least once, then checks the condition at the end of
the loop. When using this type of while loop, you must know
or set the condition in advance. That's why the line:
"problem = 0."
And, printf() has a new feature. Actually, it is one of
the first things you see in a typical C tutorial, but we have
held back for a while, because Magic often replaces printf()
with more elegant functions. Printf() is nice because it can
handle a variety of inputs such as floats, ints, and strings.
But it usually requires a weird construction called "format
specifiers," which are notices of what kind of variables to
print, followed by the actual variables. You can also
include some information about how to write the text to the
screen. "\n" is one of the most common. It appends a
carriage return/linefeed to the end of the line. See your
Borland Library Reference manual for a complete rundown of
the fascinating powers of printf().
Program 23 explores graphics a bit. Compile it, run it, study it.
/* program #23 */
#include <magic.h>
void main(){
magic_setup();
pile("This is text mode");
getanykey(-1,-1);
bestvideo();
pile("This is a graphics mode");
getanykey(-1,-1);
cleanup();
}
This simple program is like several that you have already
seen, except for the new function bestvideo(). This is truly
a magic function, since it sets up the computer to run in the
highest-resolution graphics mode it is capable of, and then
makes getanykey(), getyn(), dialog(), menu(), pop() and other
functions work in the graphics mode just as easily as if they
were running in text mode.
Cleanup() at the end of this program returns the computer
to a text-based screen mode.
Instead of bestvideo(), you could also use vgahivideo()
or hercvideo(), for instance, if you want to force the
computer to a specific mode. Obviously, you can't use
something like egavideo() with a Hercules system, however.
You can always uses bestvideo(). These are the graphics
functions available, depending on your equipment:
textvideo() - 80 x 25 color text
cgalovideo() - 320 x 200 4-color
cgahivideo() - 640 x 200 2-color
egalovideo() - 640 x 200 16-color
egahivideo() - 640 x 350 16-color
hercvideo() - 720 x 348 2-color
vgalovideo() - 320 x 200 256-color (will not work with older
versions of Turbo C)
vgahivideo() - 640 x 480 16-color
bestvideo() - something from the above chart, highest
resolution possible for your equipment
You can switch from one video mode to another as often as
you like within a program. However, RAM becomes quite full if
you use bestvideo() or several different graphics modes
within one program.
Those of you who have done some graphics programming will
find a surprise. You don't have to include a *.BGI file on
disk with your finished program. The graphics stuff is built
entirely into your .EXE file. This is true for graphics
fonts, too, which we'll cover in a few minutes.
Pop(), getyn(), getanykey(), dialog(), and menu() all
work almost the same in any graphics mode as in text mode.
The only difference, is that in text mode, you can have up to
10 layers of pop-ups, and each one can be restored, revealing
the screen underneath. In any graphics mode, only one layer
is saved to memory.
(However, with the purchase of source code, you can
easily wrap up the graphics stuff into object oriented
programming and then create as many instances of pop(),
menu(), etc as you require, within the limits of RAM.)
Textvideo() is the way out of graphics. For instance, if
you write a program that starts in graphics mode to display a
drawing, then you want to switch back to text for faster
handling of strings, you simply call the textvideo()
function, as in program #24 below:
/* program #24 */
#include <magic.h>
#include <string.h>
void main(){
magic_setup();
strcpy(sent[1],"This is text mode");
getanykey(-1,-1);
cgahivideo();
strcpy(sent[1],"This is a graphics mode");
getanykey(-1,-1);
textvideo();
strcpy(sent[1],"This is text again");
getanykey(-1,-1);
cleanup();
}
Program #24 switches to CGA graphics mode, then back to text
mode. After running in a graphics mode, cleanup()
automatically does one more thing. It resets the video
system to text mode as the program ends.
Program #25 shows some complexity in using bestvideo().
/* program #25 */
#include <magic.h>
#include <string.h>
#include <graphics.h>
void main(){
magic_setup();
strcpy(sent[1],"This is text mode");
getanykey(-1,-1);
bestvideo();
setcolor(YELLOW);
circle(getmaxx() / 2,getmaxy() / 2, getmaxy() / 4);
strcpy(sent[1],"This is a graphics mode");
getanykey(-1,-1);
textvideo();
cleanup();
}
This one switches to a graphics mode when a key is
pressed. If you have a VGA system, then you'll see a yellow
circle around a pop-up box. But, then change the
"bestvideo()" line to "cgalovideo()" and you'll see that the
pop-up box partially covers the circle, even though the
circle is supposedly the same size. It's the pop-up that
changed it's size.
Notice that you can change color by simply passing a color
to setcolor(). In the GRAPHICS.H file, the 16 colors used by
EGA and VGA (16-color mode) are defined the same as CONIO.H
(in newer Borland compilers) uses for text colors. In
graphics modes (except CGA, which is all weird, with three
possible palettes of 3 fixed colors each and one variable
background color), all elements of background or foreground
may be changed to any of the sixteen colors. The function,
"circle()" is declared in the GRAPHICS.H file.
Program #26 shows a few of the many other things you can do
with the Borland graphics library (GRAPHICS.LIB).
/* program #26 */
#include <magic.h>
#include <graphics.h>
void main(){
magic_setup();
bestvideo();
setcolor(WHITE);
circle(100,100,50);
circle(100,100,40);
setfillstyle(SOLID_FILL,WHITE);
floodfill(51,100,WHITE);
setcolor(LIGHTGREEN);
setlinestyle(0,0,3);
rectangle(70,70,130,130);
setfillstyle(SOLID_FILL,LIGHTMAGENTA);
bar(90,90,110,110);
waitforuser();
cleanup();
}
Go ahead and mess with this program a bit. See what
other patterns you can make. To find out what tools are
available to you, take a look at the GRAPHICS.H file. Or,
even better, look through your Borland Library Reference book
for the various graphics functions available.
Program #27 shows how to work with text in a graphics
mode. Borland C supplies a default font, which is an 8 x 8
pixel bitmapped font. Pop(), getanykey(), dialog(), menu()
and the other similar Magic functions always use this default
font.
/* program #27 */
#include <magic.h>
#include <graphics.h>
void main(){
magic_setup();
bestvideo();
setcolor(LIGHTMAGENTA);
outtextxy(100,100,"This is the default font.");
waitforuser();
cleanup();
}
In Program #27 we see that the way to display a string is
through outtextxy(), which is similar to gotoxy() combined
with printf() in text mode. Outtextxy() requires screen
coordinates, then a string. Unlike printf(), which allows
you to print numeric variables, strings, and what-have-you,
you must pass a string, and only one string at a time to
outtextxy() after the coordinates.
In older versions of Borland and Turbo C/C++, there were
four external fonts provided, and in the newest versions,
there are 10. By external, I mean that they were usually
supplied on disk along with your finished program, not
actually linked into the .EXE program. Of course, Borland
provides a way to link these into your program, and C Magic
takes it a step further and does it automatically with a
single line of code as in the following example:
Program #28 shows how to work with different fonts.
/* program #28 */
#include <magic.h>
#include <graphics.h>
void main(){
magic_setup();
bestvideo();
setcolor(YELLOW);
triplex();
outtextxy(100,100,"This is TRIPLEX font.");
waitforuser();
cleanup();
}
We have simply called the Magic function, triplex(), and
now outtextxy() will use the Triplex font until we
specifically call another font function. For the older C
compilers, these font functions are available:
triplex() {1}
little() {2}
sansserif() {3}
gothic() {4}
The newer compilers will also allow you to use these font
functions:
script() {5}
simple() {6}
italic() {7}
complex() {8}
european() {9}
bold() {10}
And, to return to the default Bitmap font:
bitmap()
By simply calling one of these functions, the font is
linked into the .EXE program (thereby occupying space in RAM
when run) and outtextxy() will use the chosen font. You can
switch from one font to another as often as you like, but
everytime you choose a new font, the RAM and disk space
requirement will increase. Only bitmap() does not call for
extra RAM.
You don't want to automatically link all 10 fonts every
time you write a program, because the program would be about
207k in size, minimum!
You can also use a font without linking it into the .EXE file
by keeping it as an external .CHR file on disk and using the
Borland-provided function settextstyle(). You can also use
settexstyle() to change the size of a Magic-linked font.
Settextstyle() takes three variables. The first is a number
representing the chosen font (see chart above for our
Magic-imposed font function names, and their corresponding
font numbers). The second number, usually 0, tells the
compiler whether you want the font to lay across the screen
horizontally or vertically, and the last is the relative size
of the font, ranging from 1 to 10. If you state 0 for a
size, then the font's default size will be used. Here's
settextstyle() in action:
/* program #29 */
#include <magic.h>
#include <graphics.h>
void main(){
magic_setup();
cgalovideo();
setcolor(YELLOW);
triplex();
settextstyle(1,0,8);
outtextxy(0,0,"TEST");
waitforuser();
cleanup();
}
In program #29 we've done the usual stuff to enter a
graphics mode (CGA - LO) then linked in the Triplex font with
a call to triplex(). Then comes a call to settextstyle() to
enlarge our Triplex font. See your Borland books for more
information about settextstyle(), settextjustify() and
setusercharsize(). Note: setusercharsize() is available with
the newer compilers.
Program 30 shows off some basic mouse work, and the main
principal of drawing to the screen. This will work whether
or not you have a mouse. Our mouse support includes arrow
key emulation. In addition to the arrow keys, [Insert],
[Page Up], [Delete] and [Page Down] move diagonally. With
the [Num Lock] on, the number keys move the mouse up, down or
diagonally large amounts, while with [Num Lock] off, the
movements are small. Pressing [Enter] is like clicking the
left mouse button and [Esc] is like clicking the right
button.
/* program #30 */
#include <magic.h>
#include <graphics.h>
void main(){
magic_setup();
bestvideo();
waste();
moveto(getmaxx() / 2, getmaxy() / 2);
while (!left){
poll();
lineto(px,py);
}
cleanup();
}
In program we use the function moveto() to start out in
the middle of the screen. Getmaxx() and getmaxy() are simple
functions which return the number of pixels at the
coordinates in the middle of the screen. We start there.
Then, with a while loop, we poll(), which is a Magic function
which determines whether the mouse has been moved or if an
arrow key or number key has been pressed. If movement has
been requested by the user through keyboard or mouse, the
global int px and py are updated, and the current position is
moved to the new px and py coordinates. A line is drawn from
the previous position to the new one with the function
lineto(). This loop continues until the global variable,
left is 1, meaning the left mouse button has been clicked or
the [Enter] key was pressed. There are corresponding
variables, right (for right mouse button and [Esc] key), and
center, for the center mouse button on three-button mice.
Waste() was called early in this program, to make sure
the variable "left" is reset to 0, otherwise the loop may not
execute.
Px and py are global int variables declared in Magic,
which are generally used for graphics screen coordinates.
They are used by poll(), pointertoxy(), etc.
Program 31 shows you one way to move a rectangle around. This
program will display the mouse pointer until the left mouse
button is clicked, then it will turn it off and show a
movable rectangle until the right mouse button is clicked.
Remember, the way to end this program is to click the right
mouse button (or press [Esc]).
/* program #31 */
#include <magic.h>
#include <graphics.h>
void main(){
magic_setup();
bestvideo();
waste();
px = getmaxx() / 2;
py = getmaxy() / 2;
pointertoxy();
pointeron();
do poll(); while (!left);
pointeroff();
setfillstyle(SOLID_FILL,BLACK);
rectangle(px,py, px + 40, py + 20);
do{
bar(px,py, px + 40, py + 20);
poll();
rectangle(px,py, px + 40, py + 20);
}
while (!right);
cleanup();
}
First we set px and py to coordinates representing the
middle of the screen, move the mouse pointer to that
location, and make it visible with pointeron().
Pointertoxy() always uses the global ints, px and py.
Pointertoxy() works even when the pointer is invisible. Then
we poll() over and over again until the user clicks the left
button. When this happens, the pointer is turned off and a
rectangle is drawn on the screen, with its upper left corner
at px,py.
Then, a loop starts. With each iteration of the loop, the
rectangle is erased by drawing a black bar over it, poll() is
called to see if the user has a new position for px and py,
and then a new rectangle is drawn.
You'll also notice in this program, a function called
setfillstyle(). This dictates what kind of bar() will be
drawn. Besides a solid black bar (best for our purposes
here) you can use various patterns and colors. See the
Borland Library Reference for more information.
There are at least two other techniques commonly used for
animations, but they are beyond the scope of this tutorial.
Basically, you can switch back and forth between two video
pages, one with the original picture in it, and the other
with a rectangle on it. The other way is to save an image of
the area where the rectangle is to be placed in RAM first,
place the rectangle, then replace it with the original image
again. Look up getimage(), putimage(), and setwritemode() in
your Borland books for more information. Setwritemode() is
available only with the newer compilers.
Program #32 shows a couple of small improvements:
/* program #32 */
#include <magic.h>
#include <graphics.h>
void main(){
int oldx,oldy;
magic_setup();
bestvideo();
waste();
settextjustify(CENTER_TEXT,BOTTOM_TEXT);
outtextxy(getmaxx() / 2,getmaxy() - 4,
"Click right mouse button to end program");
px = getmaxx() / 2;
py = getmaxy() / 2;
pointertoxy();
setfillstyle(SOLID_FILL,BLACK);
rectangle(px,py, px + 40, py + 20);
do {
oldx = px;
oldy = py;
while ((px == oldx) && (py == oldy) && (!right)) poll();
bar(oldx,oldy, oldx + 40, oldy + 20);
rectangle(px,py, px + 40, py + 20);
}
while (!right);
cleanup();
}
First, we took off the mouse pointer stuff to simplify
the program. Then we use one of the fancy features of the
GRAPHICS.LIB file to cause text to be centered from left to
right around the x coordinate and the bottom of the string at
the y coordinate. With outtextxy() a notice is posted for
the user.
When writing software, always make it as user-friendly as
possible. Ultimately, you will gain a reputation for writing
GOOD software, if it is easy to use.
You'll notice that the rectangle no longer flickers as it
did in program #31. In that program, the rectangle was
redrawn every time the loop recycled, even if the position
hadn't changed. Now, we remember the old coordinates in
"oldx" and "oldy" and keep poll()ing until the coordinates
change. Only then do we redraw the rectangle.
In our last program I'll show you how to use the sound
effects in Magic, and we'll fool around with text in graphics
modes a bit more.
/* program #33 */
#include <magic.h>
#include <string.h>
#include <dos.h> /*** 1 ***/
/* #include <conio.h> */ /*** 1a ***/
#include <graphics.h>
void main(){
magic_setup();
musicon = 1; /*** 2 ***/
bugle(); /*** 3 ***/
mainback = BLUE; /*** 4 ***/
vgahivideo(); /*** 5 ***/
setcolor(LIGHTMAGENTA);
gothic(); /*** 6 ***/
settextstyle(GOTHIC_FONT,HORIZ_DIR,6);
settextjustify(CENTER_TEXT,TOP_TEXT);
outtextxy(getmaxx()/2,0,"Type Anything");
setcolor(YELLOW);
settextstyle(DEFAULT_FONT,VERT_DIR,2); /*** 7 ***/
settextjustify(LEFT_TEXT,CENTER_TEXT);
outtextxy(20,(getmaxy() / 2) + 30,"Press [Enter]");
outtextxy(40,(getmaxy() / 2) + 30,"when done.");
settextstyle(0,0,2);
settextjustify(LEFT_TEXT,TOP_TEXT);
setfillstyle(SOLID_FILL,BLACK);
setcolor(LIGHTCYAN);
waste();
pile("This sentence has no purpose!");
savesettings(); /*** 8 ***/
pop(-1,400);
restoresettings(); /*** 9 ***/
strcpy(answer,""); /*** 10 ***/
do {
u = getch(); /*** 11 ***/
pink(); /*** 12 ***/
if (u > 31) { /*** 13 ***/
answer[strlen(answer) + 1] = 0; /*** 14 ***/
answer[strlen(answer)] = u;
}
if ((u == 8) && (strlen(answer) > 0)) /*** 15 ***/
{
bar(70,100,70 + textwidth(answer), /*** 16 ***/
130 + textheight(answer));
answer[strlen(answer) - 1] = 0; /*** 17 ***/
}
outtextxy(70,100,answer); /*** 18 ***/
}
while (u != 13); /*** 19 ***/
restore(); /*** 20 ***/
delay(500); /*** 21 ***/
sorry(); /*** 22 ***/
delay(500);
twinkle(); /*** 23 ***/
cleanup();
}
Program #33 has notes within /*** and ***/:
Note #1: A function called delay(), used in this program, is
declared in the DOS.H file.
Note #1a: The function getch() is prototyped in CONIO.H in
newer Borland compiler packages, and will result in an
executable program, but with a warning if this line is
commented out. The older versions did not have a CONIO.H
file.
Note #2: Before we can use the built-in sound effects in the
Magic library, we have to turn them on by setting the global
variable "musicon" to 1. Actually, the default is 1, or ON,
but good programming practice dictates that we KNOW the
status of all control variables.
Note #3: Bugle() is one of several sound effects within
Magic. The others are: soundup(), sounddown(), pink(),
sorry() and twinkle(). Calling any of these when musicon = 0
will have no effect.
Note #4: By changing the variable mainback to BLUE (BLUE is
color 1, as defined in GRAPHICS.H), the screen background
will be blue when cleared with xclear() or (in this case)
when a graphics mode is chosen.
Note #5: For this example we use vgahivideo(), but if your
computer does not support it, change to a different graphics
mode and change the coordinates throughout this program
accordingly.
Note #6: First, we load the Gothic font into the program,
then in the next line, we change it's size.
Note #7: Do this for vertical text.
Note #8: We're gonna use pop(), which draws a rectangle
border in a box, and uses the Bitmap font, in a small size.
When it is done, we want our old colors, linestyle, font type
and size, etc. back. We don't want to reset all these
variables. Therefore, the Magic library provides
savesettings() and restoresettings(). Call savesettings()
before an operation which may mess up your choices of font,
color, etc., and then restoresettings() when done. This can
be use with pop() as well as almost anything you want to
create. It is not necessary with getanykey(), getyn(),
dialog() or menu() because they call savesettings() and
restoresettings() automatically.
Note #9: So, right after pop(), which changed color,
fillstyle, font choice and size, etc., we restore all these
variables we were using with restoresettings().
Savesettings() and restoresettings() have no effect in text
mode - only in graphics modes.
Note #10: We'll be borrowing a string variable (character
array) from Magic for building a string which as the user
types, will be displayed on screen. This first "strcpy()"
makes sure the string, "answer" starts out empty.
Note #11: We have established a loop which will wait for
keystrokes from the user, turn them into a string and and
write it on the screen. At the top of the loop, the variable,
"u" takes on the value of the key the user pressed with the
function getch().
Note #12: Pink() makes a click every time a key is pressed.
Note #13: The first 32 ASCII characters starting with #0 are
generally unprintable, containing such "characters" as
carriage return or "beep." So, we won't add them to the
string.
Note #14: These two goofy-looking lines illustrate one way to
build a string of text using a character array. A character
array is a line of locations in memory all containing one
byte, or character. C handles strings by filling part or all
of an array with the text and then the next byte after the
last character is always set to 0. This way, even the array
may allow room for more characters than the string actually
contains. When the compiler comes across a #0, it knows to
regard that spot as the end of the string. So to add a
character, we effectively move the #0 over one position and
squeeze in the new character where the #0 was.
Note #15: ASCII #8 is the backspace key. This is a compound
"if" statement because we better not try to backspace if the
length of our string is already 0 characters! No telling what
might happen.
Note #16: If we are backspacing, we need to erase at least
part of what is displayed on the screen. The simplest way to
do it is erase the whole general area and redisplay the new,
shorter string. Bar() uses the currently selected fill
pattern and color as set by setfillstyle() a few lines
earlier.
Note #17: This is the actual deletion, using direct
manipulation of the character string. Remembering that the
compiler ignores everything past the #0, we simply put a zero
where the last character was when backspacing.
Note #18: And, no matter what the user pressed, we might as
well rewrite the new string onto screen. It takes only a
split second.
Note #19: This is the end of the loop. If the user presses
[Enter] (ASCII #13) the loop "falls through."
Note #20: Restore() is the compliment of pop(). It gets rid
of the pop up box and replaces what was on the screen
previously.
Note #21: Delay() is a function prototyped in DOS.H which
will delay for the specified number of milliseconds. 1000
milliseconds = one second, so our delay is 1/2 second.
Note #22: sorry() is a fun sound effect.
Note #23: Twinkle(): another fun sound effect.
- - -
And that almost wraps up this tutorial! Hope you have had
as much fun reading and experimenting as I did writing it.
There is far more available in C than this short tutorial
can tell you about. To learn as much as you can, in a
reasonable amount of time, I recommend getting several books
on C and C++, and experimenting with every idea that crosses
your mind. You'll find the overwhelmingly powerful and huge
Borland compilers and related programs easier to tackle if
you stay with C (and possibly C++) until you fairly master
them, and only then move onto TASM, Turbo Profiler, Windows
programming and all the other neat stuff.
In fact, there's quite a bit more to the Magic unit
itself. You can read MAGIC.TXT to learn more of its included
functions and global variables, and get more technical
information on the ones you already know.
This is shareware. Feel free to copy and distribute the
shareware version of C Magic as long as all files remain
intact and unchanged.
If you have paid a professional shareware distributor a
few dollars for this disk, you have paid for the service of
providing a copy. The author (that's me!) has not yet been
paid.
If you use MAGIC.LIB in your programs, or if you have
found this tutorial helpful, you must pay for the creation of
the product. Send $39.95 to:
Another Company
P.O. Box 298
Applegate, OR 97530
Please add $3 per order for USA postage, $5 for Canada or
$7 - all other countries.
If you need 3.5" disk size, please add $1.00.
Complete source code is available for the MAGIC.LIB. This
is good for using as a framework for your own very customized
applications, for learning more about C programming, for
stripping down to top efficiency, for using MAGIC functions
in object oriented programming, and for improving. For
registration AND source code, send $79.90.
Even in this version 1.5 you may find a bug or two. I make
no guarantees about it's suitability to your programming
needs.
If we find any major bugs, they will probably be corrected by
the time you get your registered version! Furthermore, if
this evolves the same way our Pascal Magic did, registered
users may get a version with even more features.
If you require technical assistance, you can try to phone me
at 503-846-7884. Best bet is 9-5 weekdays, but I'm not always
available. Or, you can contact me via Compuserve: 71022,175.
Since you are going to write some wonderful programs, you
might as well start making money with them! You won't have to
work in an office doing programming for someone else. You
can write exactly the kind of programs you want to write, and
make money at home!
The 'secret' is shareware. Does it work? You bet! You
can easily have a small success, making some extra spending
money each month, or with some practice, you may even have a
larger success!
ANOTHER COMPANY shows you everything. Besides our own
shareware products, including WRITER'S DREAM, BICYCLE TUNE-UP
AND REPAIR, MONEY, THE MULTIMEDIA WORKSHOP, BETTER EYESIGHT,
WHAT'S IN THAT BOX? and THE 21ST CENTURY ALMANAC, we have
researched the shareware market, we have interviewed other
shareware authors and have learned about all sides of the
rapidly expanding shareware business.
We show you how to write programs that capture the
public's interest, how to make sure your customers want to
'register', and how to get money by other means through your
shareware. We show you more. We show you frequency charts
indicating which types of programs sell best, we offer
suggestions for programs as yet unwritten, we talk about your
on-disk instruction manuals, we even show you how to write
user-friendliness into your programs.
Can you succeed without SUCCESS WITH SHAREWARE? Yes!
But why do it the hard way? We have learned all the
super-professional approaches, the pitfalls and the
shortcuts. We'll tell you all about it, and then instead of
stumbling around for the first couple of years, you'll be
a professional from the start!
To get your copy of SUCCESS WITH SHAREWARE! (which is not
shareware, itself - only available from Another Company),
send $29.95. Please add $1.00 if you need 3.5" disk size.
Thanks,
- Jeff Napier -
September 1, 1992
Please include $3 per order for postage within USA, $5 to
Canada, or $7 for all other countries.
You can order products by writing your order on plain paper,
or by printing the included ASCII file called ORDER.FRM, or
by phoning 1-503-846-7884, generally weekdays between 9 and
5, west coast time.