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.