Convert "sl" Source Code from C to Rust

Click here to see entire code to this point.
Previous - Tweak Ferris

Trim A String Using a Different Method

Let's also revise our "my_mvaddstr()" function to use a different method of trimming the string, just so you can see a different way of doing it.

main.rs
...
fn my_mvaddstr(row: i32, mut col: i32, frame_line: &str, screen_width: i32, screen_height: i32) {
...
    // Trim from left side as trainimage moves off left edge
    if col < 0 { // If we've moved left of the left-edge,
        for _ in 0..col.abs() { // then for each column beyond edge,
            line.remove(0); // trim the first char off the string, repeatedly.
        }                   // "line" should now have front end trimmed off.
        let num_of_left_chars_to_trim = col.abs() as usize;
        line.replace_range(0..num_of_left_chars_to_trim, "");
        // "line" should now have front end trimmed off.
        col = 0;
    }

    // Trim from right side if it extends off right edge
    if col + (line.len() as i32) > screen_width {
        let amt_to_trim = (col + (line.len() as i32)) - screen_width;
        for _ in 0..amt_to_trim {
            line.pop();
        }
        let num_of_left_chars_to_keep = (screen_width - col) as usize;
        line.replace_range(num_of_left_chars_to_keep.., "");
    }
...

Trim A String Using Yet a Third Method

Let's also revise our "my_mvaddstr()" function to use a third method of trimming the string, just so you can see yet a different way of doing it. Replace all of "my_mvaddstr()" with the following:

main.rs

fn my_mvaddstr(row: i32, mut col: i32, frame_line: &str, screen_width: i32, screen_height: i32) {
    /* This function recieves one line of an ASCII-art image, and
       trims away any of that line that would otherwise be displayed
       off-screen; then it displays the remaining portion of the
       line at the designated row,col coordinates.
    */

    let mut left_char = 0;
    let mut right_char = frame_line.len();

    // We'll later trim everything left of left_char.
    if col < 0 {
        // If we've moved left of the left-edge,
        left_char = col.abs() as usize;
        col = 0;
    }

    // And we'll later trim everything right of right_char.
    if col + (frame_line.len() as i32) > screen_width {
        let amt_to_trim = (col + (frame_line.len() as i32)) - screen_width;
        right_char = frame_line.len() - amt_to_trim as usize;
    }

    // We only want what's between left_char and right_char, so trim away the rest.
    let line_slice = &frame_line[left_char..right_char];

    // If we're on-screen, it's okay to print this line.
    if (row >= 0) && (row < screen_height) {
        mvaddstr(row, col, line_slice);
    }
} // end of my_mvaddstr()

Feel free to use whichever method makes the most sense to you (the third is probably the cleanest; it's the method I'll use). Also, keep in mind that Rust encodes strings as UTF-8, not as ASCII, and each of these three methods will break the program if the image being drawn uses a character outside of the standard ASCII subset of UTF-8. You can see this by temporarily adding a multi-byte character (e.g. ท) to one of your images, like so:

images.rs
...
pub const BOAT: &str = r"
   |\    ท'
   | \    '
   |  \   '
   |___\  '
\--|----/ '
 \_____/  '
"; // end of BOAT

Try running the program with the "boat" option ($ cargo run -- --kind=boat) and you'll see that the program now crashes. (Remember, Ctrl-C, followed by blindly typing "reset", should return your terminal to a usable state.)

The solution is to either limit the ASCII-art images to using the ASCII subset of characters within the UTF-8 character set (as we are doing; so don't forget to remove that temporary ท character from your image), or to use a more robust trimming method as well as something other than ncurses (perhaps ncursesw, but that crate is a different critter, and isn't as much of a drop-in replacement for the curses used by the C-version of "sl").

If the animation is too slow for you, decrease the "delay" setting in "main()". If the animation is too fast, increase the "delay". Soon we'll make the speed an option.

We now have an animated image that moves across the screen. Well done!

Now let's provide the capability to Get More User-Provided Options from the Command-line.