Skip to content
Jim edited this page Oct 7, 2024 · 59 revisions

image

README

In this challenging homework, we will learn how to use arrays and for loops by implementing a text input field.

Background

A text input field allows a user to type a message inside of a computer program. You've used these things your whole life, but probably haven't given them much thought.

Let's change that. 🙂👍

  • Try playing around with one of the search bars on this web page.
    • What happens when you...
      • press the B key on your keyboard?
      • press SHIFT + B?
      • press the LEFT_ARROW_KEY?
      • press the RIGHT_ARROW_KEY?
      • press BACKSPACE?
      • press COMMAND + A (or CONTROL + A on Windows)?
      • press the left mouse button?
      • hold the mouse and drag?
      • press B while some text is highlighted?
      • press BACKSPACE while some text is highlighted?
      • double-click?

We need to store a sequence of characters that we'll be changing a lot.

We will use an array, specifically an array of characters (char[]).

Java

arrays

  • char[] buffer = new char[8]; is an array of 8 char's called buffer
    • buffer.length will be 8
  • for (int i = 0; i < array.length; ++i) { ... } iterates over array forwards
  • for (int i = array.length - 1; i >= 0; --i) { ... } iterates over array backwards

Pro-tips

  • I highly recommend drawing simple little pictures of your array for this assignment
  • This will be very useful to work out carefully by hand what should happen to your array, rather than just guessing

Data

  • char[] buffer; stores the user's message as an array of characters
    • buffer can store a message of length at most buffer.length
  • int length; is the length of the current message stored in buffer
    • if (length == 0) then message is empty
    • if (length == buffer.length) then the message completely fills the buffer
  • int cursor; is the current cursor position
    • 0 means all the way to the left
    • 1 means in between buffer[0] and buffer[1]

Geometry

  • the left side of the canvas is $x = 0.0$
  • the right side of the canvas is $x = \texttt{buffer.length}$
  • we are using a monospaced font; this means each character is the same width;
    • for simplicity, we have each character be $1.0$ unit wide
    • buffer[0] is drawn from $x = 0.0$ to $x = 1.0$
    • cursor should be drawn at $x = \texttt{cursor}$
  • example
    • here is the message COW written in a monospaced font, with the cursor all the way to the left
      • buffer.length is 4
      • length is 3
      • cursor is 0
    | #####   #####   #   # 
    | #       #   #   #   # 
    | #       #   #   # # # 
    | #####   #####    # #  
    0       1       2       3       4   -> x
    
  • the bottom of the canvas is $y = -1.0$ and the top is $y = 2.0$ (NOTE: you don't need this fact except for the A++, at which point you'll probably want to write your own text drawing function(s) anyway)

User Interface

  • All features must match the behavior of a typical text input field
    • For example, pressing BACKSPACE should turn CO|W (length 3) into C|W (length 2); NOTE: the | is the cursor
    • You are responsible for discovering what the correct behavior of all commands is by experimenting with a real-world text input field

Reference

YouTube Link: https://www.youtube.com/watch?v=HTEWeeOiI3s

HW02S

NOTE's

  • You may NOT use any fancy Java standard library functions
    • Use for loops, if statements, and the functions inside Cow.java
  • You may NOT use the Java String class anywhere.
  • You may NOT create any new arrays (just modify the contents of buffer)
  • You may NOT use excessive repetition (for example, don't use separate if statements for c == 'A', c == 'B', c == 'C', ...)
  • You may NOT have any out of bounds errors

TODO's

  • A-

    • Update Cow
    • User can press A-Z (any of the keys A, B, ...)
    • Draw the cursor bar (location of cursor as a vertical line)
    • User can press 0-9
    • User can press SHIFT + A, SHIFT + B ...
    • User can press the space bar
      • HINT: this is the character ' '
    • User can press LEFT_ARROW
    • User can press RIGHT_ARROW
    • User can press BACKSPACE
  • A

    • Make the cursor bar blink
      • HINT: You will want to introduce a frame or time variable to keep track of the current frame / time
      • NOTE: Making the cursor bar not blink for a bit after keyAnyPressed is an optional good idea
    • Click the mouse to move cursor to the closest int
    • If the user presses ENTER while the buffer contains Passw0rd, replace the contents of the buffer with accepted
      • HINT: some repetition here is OK
  • A+

    • Click and drag the mouse to select/highlight a sequence of characters
      • HINT: int select = 0; can be the "selection cursor"; if (cursor == select) is true, then nothing is selected (and the cursor should be blink as usual); it it is false, then the characters in between the two numbers are selected
        • MIN(...) and MAX(...) may be useful
      • NOTE: pressing BACKSPACE while characters are selected must do the right thing
      • NOTE: pressing A, B, ... should also do the right thing
    • Press COMMAND + A or CONTROL + A to select all characters
      • NOTE: we want our app to be "cross platform" (work on both Mac and Windows)
    • (Optional, but put in free response if you did it) Double-click the mouse to select all characters
      • HINT: Be careful about the built-in mouseHeld (NOTE: mouseHeld is true for the first frame mousePressed is true--and likely for a few frames after that as well)
    • Improve the animations of the cursor; Inspo: https://diskvoyager.com; Additional very important inspo: https://www.youtube.com/watch?v=emjuqqyq_qc
  • A++ (105)

    • Build a full raw text editor like TextEdit/Notepad
      • Copy and paste from system clipboard
      • Multiple lines

Starter Code

class HW02 extends Cow {
    public static void main(String[] arguments) {

        char[] buffer = new char[8];
        int length = 0;
        int cursor = 0;

        canvasConfig(0.0, -1.0, buffer.length, 2.0, WHITE, 512);
        while (beginFrame()) {

            // TODO

            // NOTE: This function draws the first length-many characters of the buffer
            HW02_drawText(buffer, length, BLACK);
        }
    }
}

Hints

Iterate over the characters A-Z
for (char c = 'A'; c <= 'Z'; ++c) { ... }
Convert char from uppercase to lowercase
(char)('a' + (c - 'A'))
  • Example: ('D' - 'A') -> 3 and (char) ('a' + 3) -> 'd'
How can I make my code for typing letters, numbers and spaces less repetitive?

If you're finding your code looks like this...

for (char c = 'A'; c <= 'Z'; ++c) {
    if (keyPressed(c)) {
         ... // Complicated logic for inserting a character
    }
}

for (char c = '1'; c <= '9'; ++c) {
    if (keyPressed(c)) {
        ... // Complicated logic for inserting a character
    }
}

if (keyPressed(' ')) {
    ... // Complicated logic for inserting a character
}

Maybe instead consider something like this!

char newCharacter = 0; // initialize to the null (0) character

for (char c = 'A'; c <= 'Z'; ++c) {
    ... // Simple logic to setting newCharacter
    // NOTE: this one also has to handle shift
}

for (char c = '0'; c <= '9'; ++c) {
    ... // Simple logic for setting newCharacter
}

if (keyPressed(' ')) {
    ... // Simple logic for setting newCharacter
}


if (newCharacter != 0) {
    ... // Complicated logic for inserting a character
}

Solution

👀
class HW02A extends Cow {

	public static void main(String[] arguments) {

		final char[] buffer = new char[8];
		int length = 0;
		int cursor = 0;

		// NOTE: each character is 1 unit wide
		canvasConfig(0.0, -1.0, buffer.length, 2.0, WHITE, 512);

		int blinkCounter = 0;

		while (beginFrame()) {
			boolean insertCharacterValid = (length != buffer.length);
			boolean backspaceValid = ((length != 0) && (cursor != 0));
			boolean leftArrowKeyValid = (cursor != 0);
			boolean rightArrowKeyValid = (cursor != length);
			
			if (keyAnyPressed) {
				blinkCounter = 0;
			}

			if (insertCharacterValid) {
				char newCharacter; {
					newCharacter = 0;
					for (char c = 'A'; c <= 'Z'; ++c) {
						if (keyPressed(c)) {
							if (!keyHeld(SHIFT)) {
								newCharacter = (char)('a' + (c - 'A'));
							} else {
								newCharacter = c;
							}
						}
					}
					for (char c = '0'; c <= '9'; ++c) {
						if (keyPressed(c)) newCharacter = c;
					}
					if (keyPressed(' ')) newCharacter = ' ';
				}
				if (newCharacter != 0) {
					for (int i = length; i > cursor; --i) buffer[i] = buffer[i - 1];
					buffer[cursor] = newCharacter;
					++cursor;
					++length;
				}
			}

			if (backspaceValid && keyPressed(BACKSPACE)) {
				for (int i = cursor; i < length; ++i) buffer[i - 1] = buffer[i];
				--cursor;
				--length;
			}

			if (leftArrowKeyValid && keyPressed(LEFT_ARROW)) {
				--cursor;
			}

			if (rightArrowKeyValid && keyPressed(RIGHT_ARROW)) {
				++cursor;
			}

			if (mousePressed) {
				cursor = length;
				for (int i = 0; i < length; ++i) {
					if (mouseX < i + 0.5) {
						cursor = i;
						blinkCounter = 0;
						break;
					}
				}
			}

			if (keyPressed(ENTER)) {
				if (true
						&& (buffer[0] == 'P')
						&& (buffer[1] == 'a')
						&& (buffer[2] == 's')
						&& (buffer[3] == 's')
						&& (buffer[4] == 'w')
						&& (buffer[5] == '0')
						&& (buffer[6] == 'r')
						&& (buffer[7] == 'd')) {
					buffer[0] = 'a';
					buffer[1] = 'c';
					buffer[2] = 'c';
					buffer[3] = 'e';
					buffer[4] = 'p';
					buffer[5] = 't';
					buffer[6] = 'e';
					buffer[7] = 'd';
				}
			}

			{ // draw
				if ((blinkCounter++ % 14) < 7) drawLine(cursor, -0.5, cursor, 1.5, PURPLE, 5.0);
				HW02_drawText(buffer, length, BLACK);
			}
		}

	}
}
Clone this wiki locally