Programming Assignment
4: Pterodactyl
program
CS 130, Dr. Beeson
Purpose: practice creating and using fonts, and
calculating the position for text.
Create
a C# Windows Forms application called Pterodactyl;
change the text property so the title bar shows Pterodactyl2345, using the last four digits of your student ID (as
usual) instead of 2345.
Specifications:
1. The application will write the following
dictionary entry in the window:
_____________________________________________________
ptero·dac·tyl \ter-ə-'dak-təl\ pl. pterodactyls, noun [New Latin Pterodactylus, genus of reptiles, from Greek pteron wing + daktylos
finger] Any of various pterosaurs (suborder Pterodactyloidea) of the Late Jurassic and
Cretaceous having a rudimentary tail and a beak with reduced dentition. Petrosaurs are
extinct flying
reptiles existing from the Late Triassic throughout the Jurassic and most of
the Cretaceous and having a featherless wing membrane extending from the side
of the body along the arm to the end of the greatly elongated fourth digit.
_____________________________________________________
Note that the text in brackets (the etymology of the word) is in 14-point type (including the brackets) while the main text is in 16-point type. The backslashes are in bold. Note the upside-down e in the pronunciation. This character does not appear in the standard fonts. Getting it to appear properly is required only for an A+. If you are content with an A you can just use an ordinary “e” character. The horizontal lines are not part of the desired output--they just set it off in this document.
The application should re-display the dictionary entry properly when the window is resized--it should all be legible as long as the window is big enough to hold it. (We won't try making the window extremely small in either direction; the point is just that the coordinates can't be completely hard-coded.) It will take more than one line to print this definition, but the text should be broken between words only--that is, we never want part of a word on one line and part on the next.
2. The window should also display a picture of
a pterodactyl in or near the upper left corner of the window. The text should “flow” around the picture. That means that the text does not overwrite
the picture or disappear behind the picture,
but it does fill up the area to the right of the picture, and if the
window is narrow enough, continues into the area beneath the picture. When the window is resized, the text
continues to “flow” properly around the picture, even as line breaks come at
different places.
3. The text lines are broken between words
only; that is, we never have part of a word on one line and the rest on the
next line. Also, we never have a word that is partly
invisible because it did not fit on the window. There is a margin of ten to twenty pixels
(you can decide) at the top, left, and right of the window. A margin
refers to a strip of “paper” (or in this case of the window) that is left blank at the left, right,
top, or bottom edges. Having a margin
only requires that the margin area be left free of text; it does not require that the text
should extend exactly to the edge of the right margin. See the A+ specifications below.
4. When the mouse moves over the text, the word
that the mouse is currently over turns red, and any previously red word turns
black. Thus at most one word at a time
is red. This happens whether the mouse
buttons have been depressed or not.
There must be no flicker when
the mouse is moved; that is, only the words that have to change color are
redrawn. When you move the mouse over a
word that is already red, not only all the other words don’t flicker, but that red word does not flicker either.
5. For an A+, the text should be “right
justified”. That means that each line
of text (except possibly the last one) should extend all the way to the right
margin, so all the lines will line up
vertically at their right ends. This is
usually the standard for typesetting books.
“Right-justified” text means that the blank space required on each line
is distributed as much as possible between the different words. For example if there are 11 words on the line
and 7 characters more could fit, so 7 spaces are required, then the pixels required for those 7 spaces
need to be distributed evenly among the 10 gaps between the 11 words.
6. The words written in smaller type appear with
their baselines lined up with the other words, instead of the top of their
character cells.
Grading Criteria
Definition
appears correctly upon opening the program. (20 points) (check bold, italic,
size, baseline alignment, line breaks, margin)
Picture
appears and text flows around it when the program opens. (15 points)
When
window is resized, line breaks change correctly to preserve margin and
visibility of text and picture. (30
points) Flicker on resize is OK.
Words
turn red and black correctly on MouseMove. (25
points)
No
flicker on MouseMove (10 points, but only if you got the 20
for red/black)
And for the A+: the ə character appears correctly and the text is
right-justified.
Programming hints:
4. Add
a new class DString
(for displayed string) to your project.
Give it the following member variables of type int: m_italic, m_bold, m_size,
and m_nospace.
This last member is meant to indicate that we don't need a space after
the word. Give it a member variable m_string of type String.
5. Add an array of DString as a member variable m_data in your document class, of dimension
100, and a
member variable m_nwords
of type int to count how many entries in m_data are actually used. Initialize m_data and m_nwords
appropriately in the document's constructor.
Use m_size
to specify the point size of the word. Use
a loop to initialize all the fields to default values for 16-point roman
text. Then (it's painful) initialize the
entry for each "word".
Remember that backslashes and single quotes need to be preceded by a
backslash when included in a string. You
can do this manually, although it’s painful. This code starts out like this:
m_data[0].m_string = "ptero·dac·tyl \\\'";
// includes first backslash
// note that the · symbol
is not on the keyboard.
m_data[0].m_bold = 1;
m_data[0].m_nospace = 1; // no space after the backslash
m_data[1].m_string = "ter-e-\'dac-tel";
// use ordinary e until you’re trying for an A+
/
m_data[1].m_nospace = 1; // no space after this before the
backslash
m_data[2].m_string = "\\"; // second backslash is in bold so, new word
m_data[2].m_bold = 1;
m_data[3].m_italic = 1;
m_data[3].m_string = "pl.";
I know, this part is
tedious. But the assignment as a whole is fun so just
grit your teeth and do it.
6. You will
need to know the baseline-to-baseline distance in the main output font. It would be a good idea to record that
number in a member variable m_linespacing of
the view class. There is a GetHeight member function in the Font class. If you don’t like the result of using that
height for line spacing, you can just adjust that value by some hard-coded
number that you find by trial and error.
But GetHeight
takes a Graphics argument, so you
can’t initialize m_linespacing
using GetHeight
in your form’s constructor. Instead,
initialize it to zero, and then in your Paint
handler, check
whether the value is nonzero, and if it is still zero, that would be the time
to initialize it.
7. Now it's a
matter of getting the words printed in the right font in the right place. In your Paint
handler, declare local variables x, y, and margin, and initialize each to 10.
Use ClientRectangle
to get a Rectangle representing the
client area of the window (in which you can write). Then loop through the m_data array, and in the loop do
the following: select the correct font,
then call MeasureString
to calculate whether it will fit in the window if written at (x,y). If not, you must go to a new line. When you do go to a new line, you will have
to increment y by m_linespacing, and reset x to margin. After writing the word, increase x if m_data[i].nospace is zero, to leave some space before the next
word.
8. Improve your code so there is a right margin
as well as a left margin.
9. Improve your code so that when you move the
mouse over the text, whatever word the mouse is over turns red, and then turns
black again when the mouse leaves that word.
Note, you don't have to click. To do this, you will have to keep an array
of rectangles, one rectangle for each word.
(Or, you could add a rectangle as a member of your DWord class.) These rectangles can change, for example if
the window has been resized; so they have to be recalculated
somewhere. It works well to calculate
them in your Paint handler before
doing any actual drawing. That way they
will always be correct, i.e. they will correspond to the actual location of the
words on the screen. Now, in your MouseMove handler, use those
rectangles for hit-testing, and invalidate the rectangles that need to change
color. There should be no flicker when the mouse is moved. To
ensure this, be sure that only the words changing color are redrawn, and only
when they are actually changing color.