conrod 0.46.0

An easy-to-use, 100% Rust, extensible 2D GUI library.
Documentation
//! Text layout logic.

use {FontSize, Scalar};
use std;

// Re-export all relevant rusttype types here.
pub use rusttype::{Glyph, GlyphId, GlyphIter, LayoutIter, Scale};
pub use rusttype::gpu_cache::Cache as GlyphCache;

/// Re-exported RustType geometrical types.
pub mod rt {
    pub use rusttype::{Point, Rect, Vector, point, vector};
}


/// The RustType `FontCollection` type used by conrod.
pub type FontCollection = ::rusttype::FontCollection<'static>;
/// The RustType `Font` type used by conrod.
pub type Font = ::rusttype::Font<'static>;
/// The RustType `PositionedGlyph` type used by conrod.
pub type PositionedGlyph = ::rusttype::PositionedGlyph<'static>;

/// An iterator yielding each line within the given `text` as a new `&str`, where the start and end
/// indices into each line are provided by the given iterator.
#[derive(Clone)]
pub struct Lines<'a, I> {
    text: &'a str,
    ranges: I,
}


/// Determine the total height of a block of text with the given number of lines, font size and
/// `line_spacing` (the space that separates each line of text).
pub fn height(num_lines: usize, font_size: FontSize, line_spacing: Scalar) -> Scalar {
    if num_lines > 0 {
        num_lines as Scalar * font_size as Scalar + (num_lines - 1) as Scalar * line_spacing
    } else {
        0.0
    }
}


/// Produce an iterator yielding each line within the given `text` as a new `&str`, where the
/// start and end indices into each line are provided by the given iterator.
pub fn lines<I>(text: &str, ranges: I) -> Lines<I>
    where I: Iterator<Item=std::ops::Range<usize>>,
{
    Lines {
        text: text,
        ranges: ranges,
    }
}


/// Converts the given font size in "points" to its font size in pixels.
pub fn pt_to_px(font_size_in_points: FontSize) -> f32 {
    (font_size_in_points * 4) as f32 / 3.0
}

/// Converts the given font size in "points" to a uniform `rusttype::Scale`.
pub fn pt_to_scale(font_size_in_points: FontSize) -> Scale {
    Scale::uniform(pt_to_px(font_size_in_points))
}


impl<'a, I> Iterator for Lines<'a, I>
    where I: Iterator<Item=std::ops::Range<usize>>,
{
    type Item = &'a str;
    fn next(&mut self) -> Option<Self::Item> {
        let Lines { text, ref mut ranges } = *self;
        ranges.next().map(|range| &text[range])
    }
}


/// The `font::Id` and `font::Map` types.
pub mod font {
    use std;

    /// A type-safe wrapper around the `FontId`.
    ///
    /// This is used as both:
    ///
    /// - The key for the `font::Map`'s inner `HashMap`.
    /// - The `font_id` field for the rusttype::gpu_cache::Cache.
    #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
    pub struct Id(usize);

    /// A collection of mappings from `font::Id`s to `rusttype::Font`s.
    pub struct Map {
        next_index: usize,
        map: std::collections::HashMap<Id, super::Font>,
    }

    /// An iterator yielding an `Id` for each new `rusttype::Font` inserted into the `Map` via the
    /// `insert_collection` method.
    pub struct NewIds {
        index_range: std::ops::Range<usize>,
    }

    /// Yields the `Id` for each `Font` within the `Map`.
    #[derive(Clone)]
    pub struct Ids<'a> {
        keys: std::collections::hash_map::Keys<'a, Id, super::Font>,
    }

    /// Returned when loading new fonts from file or bytes.
    #[derive(Debug)]
    pub enum Error {
        /// Some error occurred while loading a `FontCollection` from a file.
        IO(std::io::Error),
        /// No `Font`s could be yielded from the `FontCollection`.
        NoFont,
    }

    impl Id {

        /// Returns the inner `usize` from the `Id`.
        pub fn index(self) -> usize {
            self.0
        }

    }

    impl Map {

        /// Construct the new, empty `Map`.
        pub fn new() -> Self {
            Map {
                next_index: 0,
                map: std::collections::HashMap::new(),
            }
        }

        /// Borrow the `rusttype::Font` associated with the given `font::Id`.
        pub fn get(&self, id: Id) -> Option<&super::Font> {
            self.map.get(&id)
        }

        /// Adds the given `rusttype::Font` to the `Map` and returns a unique `Id` for it.
        pub fn insert(&mut self, font: super::Font) -> Id {
            let index = self.next_index;
            self.next_index = index.wrapping_add(1);
            let id = Id(index);
            self.map.insert(id, font);
            id
        }

        /// Insert a single `Font` into the map by loading it from the given file path.
        pub fn insert_from_file<P>(&mut self, path: P) -> Result<Id, Error>
            where P: AsRef<std::path::Path>,
        {
            let font = try!(from_file(path));
            Ok(self.insert(font))
        }

        // /// Adds each font in the given `rusttype::FontCollection` to the `Map` and returns an
        // /// iterator yielding a unique `Id` for each.
        // pub fn insert_collection(&mut self, collection: super::FontCollection) -> NewIds {
        //     let start_index = self.next_index;
        //     let mut end_index = start_index;
        //     for index in 0.. {
        //         match collection.font_at(index) {
        //             Some(font) => {
        //                 self.insert(font);
        //                 end_index += 1;
        //             }
        //             None => break,
        //         }
        //     }
        //     NewIds { index_range: start_index..end_index }
        // }

        /// Produces an iterator yielding the `Id` for each `Font` within the `Map`.
        pub fn ids(&self) -> Ids {
            Ids { keys: self.map.keys() }
        }

    }


    /// Load a `super::FontCollection` from a file at a given path.
    pub fn collection_from_file<P>(path: P) -> Result<super::FontCollection, std::io::Error>
        where P: AsRef<std::path::Path>,
    {
        use std::io::Read;
        let path = path.as_ref();
        let mut file = try!(std::fs::File::open(path));
        let mut file_buffer = Vec::new();
        try!(file.read_to_end(&mut file_buffer));
        Ok(super::FontCollection::from_bytes(file_buffer))
    }

    /// Load a single `Font` from a file at the given path.
    pub fn from_file<P>(path: P) -> Result<super::Font, Error>
        where P: AsRef<std::path::Path>
    {
        let collection = try!(collection_from_file(path));
        collection.into_font().ok_or(Error::NoFont)
    }


    impl Iterator for NewIds {
        type Item = Id;
        fn next(&mut self) -> Option<Self::Item> {
            self.index_range.next().map(|i| Id(i))
        }
    }

    impl<'a> Iterator for Ids<'a> {
        type Item = Id;
        fn next(&mut self) -> Option<Self::Item> {
            self.keys.next().map(|&id| id)
        }
    }

    impl From<std::io::Error> for Error {
        fn from(e: std::io::Error) -> Self {
            Error::IO(e)
        }
    }

    impl std::error::Error for Error {
        fn description(&self) -> &str {
            match *self {
                Error::IO(ref e) => std::error::Error::description(e),
                Error::NoFont => "No `Font` found in the loaded `FontCollection`.",
            }
        }
    }

    impl std::fmt::Display for Error {
        fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
            writeln!(f, "{}", std::error::Error::description(self))
        }
    }

}


/// Logic and types specific to individual glyph layout.
pub mod glyph {
    use {FontSize, Range, Rect, Scalar};
    use std;

    /// Some position along the X axis (used within `CharXs`).
    pub type X = Scalar;

    /// The half of the width of some character (used within `CharXs`).
    pub type HalfW = Scalar;

    /// An iterator yielding the `Rect` for each `char`'s `Glyph` in the given `text`.
    pub struct Rects<'a, 'b> {
        /// The *y* axis `Range` of the `Line` for which character `Rect`s are being yielded.
        ///
        /// Every yielded `Rect` will use this as its `y` `Range`.
        y: Range,
        /// The position of the next `Rect`'s left edge along the *x* axis.
        next_left: Scalar,
        /// `PositionedGlyphs` yielded by the RustType `LayoutIter`.
        layout: super::LayoutIter<'a, 'b>,
    }

    /// An iterator that, for every `(line, line_rect)` pair yielded by the given iterator,
    /// produces an iterator that yields a `Rect` for every character in that line.
    pub struct RectsPerLine<'a, I> {
        lines_with_rects: I,
        font: &'a super::Font,
        font_size: FontSize,
    }

    /// Yields an iteraor yielding `Rect`s for each selected character in each line of text within
    /// the given iterator yielding char `Rect`s.
    ///
    /// Given some `start` and `end` indices, only `Rect`s for `char`s between these two indices
    /// will be produced.
    ///
    /// All lines that have no selected `Rect`s will be skipped.
    pub struct SelectedRectsPerLine<'a, I> {
        enumerated_rects_per_line: std::iter::Enumerate<RectsPerLine<'a, I>>,
        start_cursor_idx: super::cursor::Index,
        end_cursor_idx: super::cursor::Index,
    }

    /// Yields a `Rect` for each selected character in a single line of text.
    ///
    /// This iterator can only be produced by the `SelectedCharRectsPerLine` iterator.
    pub struct SelectedRects<'a, 'b> {
        enumerated_rects: std::iter::Enumerate<Rects<'a, 'b>>,
        end_char_idx: usize,
    }


    /// Find the index of the character that directly follows the cursor at the given `cursor_idx`.
    ///
    /// Returns `None` if either the given `cursor::Index` `line` or `idx` fields are out of bounds
    /// of the line information yielded by the `line_infos` iterator.
    pub fn index_after_cursor<I>(mut line_infos: I,
                                 cursor_idx: super::cursor::Index) -> Option<usize>
        where I: Iterator<Item=super::line::Info>,
    {
        line_infos
            .nth(cursor_idx.line)
            .and_then(|line_info| {
                let start_char = line_info.start_char;
                let end_char = line_info.end_char();
                let char_index = start_char + cursor_idx.char;
                if char_index <= end_char { Some(char_index) } else { None }
            })
    }

    /// Produce an iterator that, for every `(line, line_rect)` pair yielded by the given iterator,
    /// produces an iterator that yields a `Rect` for every character in that line.
    ///
    /// This is useful when information about character positioning is needed when reasoning about
    /// text layout.
    pub fn rects_per_line<'a, I>(lines_with_rects: I,
                                 font: &'a super::Font,
                                 font_size: FontSize) -> RectsPerLine<'a, I>
        where I: Iterator<Item=(&'a str, Rect)>,
    {
        RectsPerLine {
            lines_with_rects: lines_with_rects,
            font: font,
            font_size: font_size,
        }
    }

    /// Produces an iterator that yields iteraors yielding `Rect`s for each selected character in
    /// each line of text within the given iterator yielding char `Rect`s.
    ///
    /// Given some `start` and `end` indices, only `Rect`s for `char`s between these two indices
    /// will be produced.
    ///
    /// All lines that have no selected `Rect`s will be skipped.
    pub fn selected_rects_per_line<'a, I>(lines_with_rects: I,
                                          font: &'a super::Font,
                                          font_size: FontSize,
                                          start: super::cursor::Index,
                                          end: super::cursor::Index) -> SelectedRectsPerLine<'a, I>
        where I: Iterator<Item=(&'a str, Rect)>,
    {
        SelectedRectsPerLine {
            enumerated_rects_per_line:
                rects_per_line(lines_with_rects, font, font_size).enumerate(),
            start_cursor_idx: start,
            end_cursor_idx: end,
        }
    }

    impl<'a, I> Iterator for RectsPerLine<'a, I>
        where I: Iterator<Item=(&'a str, Rect)>,
    {
        type Item = Rects<'a, 'a>;
        fn next(&mut self) -> Option<Self::Item> {
            let RectsPerLine { ref mut lines_with_rects, font, font_size } = *self;
            let scale = super::pt_to_scale(font_size);
            lines_with_rects.next().map(|(line, line_rect)| {
                let (x, y) = (line_rect.left() as f32, line_rect.top() as f32);
                let point = super::rt::Point { x: x, y: y };
                Rects {
                    next_left: line_rect.x.start,
                    layout: font.layout(line, scale, point),
                    y: line_rect.y
                }
            })
        }
    }

    impl<'a, I> Iterator for SelectedRectsPerLine<'a, I>
        where I: Iterator<Item=(&'a str, Rect)>,
    {
        type Item = SelectedRects<'a, 'a>;
        fn next(&mut self) -> Option<Self::Item> {
            let SelectedRectsPerLine {
                ref mut enumerated_rects_per_line,
                start_cursor_idx,
                end_cursor_idx,
            } = *self;

            enumerated_rects_per_line.next().map(|(i, rects)| {
                let end_char_idx =
                    // If this is the last line, the end is the char after the final selected char.
                    if i == end_cursor_idx.line {
                        end_cursor_idx.char
                    // Otherwise if in range, every char in the line is selected.
                    } else if start_cursor_idx.line <= i && i < end_cursor_idx.line {
                        std::u32::MAX as usize
                    // Otherwise if out of range, no chars are selected.
                    } else {
                        0
                    };

                let mut enumerated_rects = rects.enumerate();

                // If this is the first line, skip all non-selected chars.
                if i == start_cursor_idx.line {
                    for _ in 0..start_cursor_idx.char {
                        enumerated_rects.next();
                    }
                }

                SelectedRects {
                    enumerated_rects: enumerated_rects,
                    end_char_idx: end_char_idx,
                }
            })
        }
    }

    impl<'a, 'b> Iterator for Rects<'a, 'b> {
        type Item = Rect;
        fn next(&mut self) -> Option<Self::Item> {
            let Rects { ref mut next_left, ref mut layout, y } = *self;
            layout.next().map(|g| {
                let left = *next_left;
                let right = g.pixel_bounding_box()
                    .map(|bb| bb.max.x as Scalar)
                    .unwrap_or_else(|| left + g.unpositioned().h_metrics().advance_width as Scalar);
                *next_left = right;
                let x = Range::new(left, right);
                Rect { x: x, y: y }
            })
        }
    }

    impl<'a, 'b> Iterator for SelectedRects<'a, 'b> {
        type Item = Rect;
        fn next(&mut self) -> Option<Self::Item> {
            let SelectedRects { ref mut enumerated_rects, end_char_idx } = *self;
            enumerated_rects.next()
                .and_then(|(i, rect)| {
                    if i < end_char_idx { Some(rect) }
                    else                { None }
                })
        }
    }

}


/// Logic related to the positioning of the cursor within text.
pub mod cursor {
    use {FontSize, Range, Rect, Scalar, Point, Align};
    use std;

    /// Every possible cursor position within each line of text yielded by the given iterator.
    ///
    /// Yields `(xs, y_range)`, where `y_range` is the `Range` occupied by the line across the *y*
    /// axis and `xs` is every possible cursor position along the *x* axis
    #[derive(Clone)]
    pub struct XysPerLine<'a, I> {
        lines_with_rects: I,
        font: &'a super::Font,
        text: &'a str,
        font_size: FontSize,
    }

    /// Similarly to `XysPerLine`, yields every possible cursor position within each line of text
    /// yielded by the given iterator.
    ///
    /// Rather than taking an iterator type yielding lines and positioning data, this method
    /// constructs its own iterator to do so internally, saving some boilerplate involved in common
    /// `XysPerLine` use cases.
    ///
    /// Yields `(xs, y_range)`, where `y_range` is the `Range` occupied by the line across the *y*
    /// axis and `xs` is every possible cursor position along the *x* axis.
    #[derive(Clone)]
    pub struct XysPerLineFromText<'a> {
        xys_per_line: XysPerLine<'a,
            std::iter::Zip<std::iter::Cloned<std::slice::Iter<'a, super::line::Info>>,
            super::line::Rects<std::iter::Cloned<std::slice::Iter<'a, super::line::Info>>>>
        >,
    }

    /// Each possible cursor position along the *x* axis within a line of text.
    ///
    /// `Xs` iterators are produced by the `XysPerLine` iterator.
    pub struct Xs<'a, 'b> {
        next_x: Option<Scalar>,
        layout: super::LayoutIter<'a, 'b>,
    }

    /// An index representing the position of a cursor within some text.
    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
    pub struct Index {
        /// The index of the line upon which the cursor is situated.
        pub line: usize,
        /// The index within all possible cursor positions for the line.
        ///
        /// For example, for the line `foo`, a `char` of `1` would indicate the cursor's position
        /// as `f|oo` where `|` is the cursor.
        pub char: usize,
    }


    impl Index {

        /// The cursor index of the beginning of the word (block of non-whitespace) before `self`.
        ///
        /// If `self` is at the beginning of the line, call previous, which returns the last
        /// index position of the previous line, or None if it's the first line
        ///
        /// If `self` points to whitespace, skip past that whitespace, then return the index of 
        /// the start of the word that precedes the whitespace
        ///
        /// If `self` is in the middle or end of a word, return the index of the start of that word
        pub fn previous_word_start<I>(self, text: &str, mut line_infos: I) -> Option<Self>
            where I: Iterator<Item=super::line::Info>,
        {
            let Index { line, char } = self;
            if char > 0 {
                line_infos.nth(line).and_then(|line_info| {
                    let line_count = line_info.char_range().count();
                    let mut chars_rev = (&text[line_info.byte_range()]).chars().rev();
                    if char != line_count {
                        chars_rev.nth(line_count - char - 1);
                    }
                    let mut new_char = 0;
                    let mut hit_non_whitespace = false;
                    for (i, char_) in chars_rev.enumerate() {
                        // loop until word starts, then continue until the word ends
                        if !char_.is_whitespace() { hit_non_whitespace = true; }
                        if char_.is_whitespace() && hit_non_whitespace {
                            new_char = char - i;
                            break
                        }
                    }
                    Some(Index { line: line, char: new_char })
                })
            } else {
                self.previous(line_infos)
            }
        }

        /// The cursor index of the end of the first word (block of non-whitespace) after `self`.
        ///
        /// If `self` is at the end of the text, this returns `None`.
        ///
        /// If `self` is at the end of a line other than the last, this returns the first index of
        /// the next line.
        ///
        /// If `self` points to whitespace, skip past that whitespace, then return the index of 
        /// the end of the word after the whitespace
        ///
        /// If `self` is in the middle or start of a word, return the index of the end of that word
        pub fn next_word_end<I>(self, text: &str, mut line_infos: I) -> Option<Self>
            where I: Iterator<Item=super::line::Info>,
        {
            let Index { line, char } = self;
            line_infos.nth(line)
                .and_then(|line_info| {
                    let line_count = line_info.char_range().count();
                    if char < line_count {
                        let mut chars = (&text[line_info.byte_range()]).chars();
                        let mut new_char = line_count;
                        let mut hit_non_whitespace = false;
                        if char != 0 {
                            chars.nth(char - 1);
                        }
                        for (i, char_) in chars.enumerate() {
                            // loop until word starts, then continue until the word ends
                            if !char_.is_whitespace() { hit_non_whitespace = true; }
                            if char_.is_whitespace() && hit_non_whitespace {
                                new_char = char + i;
                                break
                            }
                        }
                        Some(Index { line: line, char: new_char })
                    } else {
                        line_infos.next().map(|_| Index { line: line + 1, char: 0 })
                    }
                })
        }

        /// The cursor index that comes before `self`.
        ///
        /// If `self` is at the beginning of the text, this returns `None`.
        ///
        /// If `self` is at the beginning of a line other than the first, this returns the last
        /// index position of the previous line.
        ///
        /// If `self` is a position other than the start of a line, it will return the position
        /// that is immediately to the left.
        pub fn previous<I>(self, mut line_infos: I) -> Option<Self>
            where I: Iterator<Item=super::line::Info>,
        {
            let Index { line, char } = self;
            if char > 0 {
                let new_char = char - 1;
                line_infos.nth(line)
                    .and_then(|info| if new_char <= info.char_range().count() {
                        Some(Index { line: line, char: new_char })
                    } else {
                        None
                    })
            } else if line > 0 {
                let new_line = line - 1;
                line_infos.nth(new_line)
                    .map(|info| {
                        let new_char = info.end_char() - info.start_char;
                        Index { line: new_line, char: new_char }
                    })
            } else {
                None
            }
        }

        /// The cursor index that follows `self`.
        ///
        /// If `self` is at the end of the text, this returns `None`.
        ///
        /// If `self` is at the end of a line other than the last, this returns the first index of
        /// the next line.
        ///
        /// If `self` is a position other than the end of a line, it will return the position that
        /// is immediately to the right.
        pub fn next<I>(self, mut line_infos: I) -> Option<Self>
            where I: Iterator<Item=super::line::Info>,
        {
            let Index { line, char } = self;
            line_infos.nth(line)
                .and_then(|info| {
                    if char >= info.char_range().count() {
                        line_infos.next().map(|_| Index { line: line + 1, char: 0 })
                    } else {
                        Some(Index { line: line, char: char + 1 })
                    }
                })
        }

    }


    /// Every possible cursor position within each line of text yielded by the given iterator.
    ///
    /// Yields `(xs, y_range)`, where `y_range` is the `Range` occupied by the line across the *y*
    /// axis and `xs` is every possible cursor position along the *x* axis
    pub fn xys_per_line<'a, I>(lines_with_rects: I,
                               font: &'a super::Font,
                               text: &'a str,
                               font_size: FontSize) -> XysPerLine<'a, I>
    {
        XysPerLine {
            lines_with_rects: lines_with_rects,
            font: font,
            text: text,
            font_size: font_size,
        }
    }

    /// Similarly to `xys_per_line`, this produces an iterator yielding every possible cursor
    /// position within each line of text yielded by the given iterator.
    ///
    /// Rather than taking an iterator yielding lines and their positioning data, this method
    /// constructs its own iterator to do so internally, saving some boilerplate involved in common
    /// `xys_per_line` use cases.
    ///
    /// Yields `(xs, y_range)`, where `y_range` is the `Range` occupied by the line across the *y*
    /// axis and `xs` is every possible cursor position along the *x* axis.
    pub fn xys_per_line_from_text<'a>(text: &'a str,
                                      line_infos: &'a [super::line::Info],
                                      font: &'a super::Font,
                                      font_size: FontSize,
                                      x_align: Align,
                                      y_align: Align,
                                      line_spacing: Scalar,
                                      rect: Rect) -> XysPerLineFromText<'a>
    {
        let line_infos = line_infos.iter().cloned();
        let line_rects = super::line::rects(line_infos.clone(), font_size, rect,
                                            x_align, y_align, line_spacing);
        let lines = line_infos.clone();
        let lines_with_rects = lines.zip(line_rects.clone());
        XysPerLineFromText {
            xys_per_line: super::cursor::xys_per_line(lines_with_rects, font, text, font_size),
        }
    }

    /// Convert the given character index into a cursor `Index`.
    pub fn index_before_char<I>(line_infos: I, char_index: usize) -> Option<Index>
        where I: Iterator<Item=super::line::Info>,
    {
        for (i, line_info) in line_infos.enumerate() {
            let start_char = line_info.start_char;
            let end_char = line_info.end_char();
            if start_char <= char_index && char_index <= end_char {
                return Some(Index { line: i, char: char_index - start_char });
            }
        }
        None
    }

    /// Determine the *xy* location of the cursor at the given cursor `Index`.
    pub fn xy_at<'a, I>(xys_per_line: I, idx: Index) -> Option<(Scalar, Range)>
        where I: Iterator<Item=(Xs<'a, 'a>, Range)>,
    {
        for (i, (xs, y)) in xys_per_line.enumerate() {
            if i == idx.line {
                for (j, x) in xs.enumerate() {
                    if j == idx.char {
                        return Some((x, y));
                    }
                }
            }
        }
        None
    }

    /// Find the closest line for the given `y` position, and return the line index, Xs iterator, and y-range of that line
    ///
    /// Returns `None` if there are no lines
    pub fn closest_line<'a, I>(y_pos: Scalar, xys_per_line: I) -> Option<(usize, Xs<'a,'a>, Range)>
        where I: Iterator<Item = (Xs<'a, 'a>, Range)>,
    {
        let mut xys_per_line_enumerated = xys_per_line.enumerate();
        xys_per_line_enumerated.next().and_then(|(first_line_idx, (first_line_xs, first_line_y))| {
            let mut closest_line = (first_line_idx,first_line_xs,first_line_y);
            let mut closest_diff = (y_pos - first_line_y.middle()).abs();
            for (line_idx, (line_xs, line_y)) in xys_per_line_enumerated {
                if line_y.is_over(y_pos) {
                    closest_line = (line_idx,line_xs,line_y);
                    break;
                } else {
                    let diff = (y_pos - line_y.middle()).abs();
                    if diff < closest_diff {
                        closest_line = (line_idx,line_xs,line_y);
                        closest_diff = diff;
                    } else {
                        break;
                    }
                }
            }
            Some(closest_line)
        })
    }

    /// Find the closest cursor index to the given `xy` position, and the center `Point` of that
    /// cursor.
    ///
    /// Returns `None` if the given `text` is empty.
    pub fn closest_cursor_index_and_xy<'a, I>(xy: Point, xys_per_line: I) -> Option<(Index, Point)>
        where I: Iterator<Item = (Xs<'a, 'a>, Range)>,
    {
        closest_line(xy[1], xys_per_line)
            .and_then(|(closest_line_idx, closest_line_xs, closest_line_y)| {
                let (closest_char_idx, closest_x) =
                    closest_cursor_index_on_line(xy[0], closest_line_xs);
                let index = Index {
                    line: closest_line_idx,
                    char: closest_char_idx,
                };
                let point = [closest_x, closest_line_y.middle()];
                Some((index, point))
            })
    }

    /// Find the closest cursor index to the given `x` position on the given line along with the
    /// `x` position of that cursor.
    pub fn closest_cursor_index_on_line<'a>(x_pos: Scalar, line_xs: Xs<'a, 'a>) -> (usize, Scalar) {
        let mut xs_enumerated = line_xs.enumerate();
        // `xs` always yields at least one `x` (the start of the line).
        let (first_idx, first_x) = xs_enumerated.next().unwrap();
        let first_diff = (x_pos - first_x).abs();
        let mut closest = (first_idx,first_x);
        let mut closest_diff = first_diff;
        for (i, x) in xs_enumerated {
            let diff = (x_pos - x).abs();
            if diff < closest_diff {
                closest = (i,x);
                closest_diff = diff;
            } else {
                break;
            }
        }
        closest
    }


    impl<'a, I> Iterator for XysPerLine<'a, I>
        where I: Iterator<Item=(super::line::Info, Rect)>,
    {
        // The `Range` occupied by the line across the *y* axis, along with an iterator yielding
        // each possible cursor position along the *x* axis.
        type Item = (Xs<'a, 'a>, Range);
        fn next(&mut self) -> Option<Self::Item> {
            let XysPerLine { ref mut lines_with_rects, font, text, font_size } = *self;
            let scale = super::pt_to_scale(font_size);
            lines_with_rects.next().map(|(line_info, line_rect)| {
                let line = &text[line_info.byte_range()];
                let (x, y) = (line_rect.left() as f32, line_rect.top() as f32);
                let point = super::rt::Point { x: x, y: y };
                let y = line_rect.y;
                let layout = font.layout(line, scale, point);
                let xs = Xs {
                    next_x: Some(line_rect.x.start),
                    layout: layout,
                };
                (xs, y)
            })
        }
    }

    impl<'a> Iterator for XysPerLineFromText<'a> {
        type Item = (Xs<'a, 'a>, Range);
        fn next(&mut self) -> Option<Self::Item> {
            self.xys_per_line.next()
        }
    }

    impl<'a, 'b> Iterator for Xs<'a, 'b> {
        // Each possible cursor position along the *x* axis.
        type Item = Scalar;
        fn next(&mut self) -> Option<Self::Item> {
            self.next_x.map(|x| {
                self.next_x = self.layout.next()
                    .map(|g| {
                        g.pixel_bounding_box()
                            .map(|r| r.max.x as Scalar)
                            .unwrap_or_else(|| {
                                x + g.unpositioned().h_metrics().advance_width as Scalar
                            })
                    });
                x
            })
        }
    }
}


/// Text handling logic related to individual lines of text.
///
/// This module is the core of multi-line text handling.
pub mod line {
    use {Align, FontSize, Range, Rect, Scalar};
    use std;

    /// The two types of **Break** indices returned by the **WrapIndicesBy** iterators.
    #[derive(Copy, Clone, Debug, PartialEq)]
    pub enum Break {
        /// A break caused by the text exceeding some maximum width.
        Wrap {
            /// The byte index at which the break occurs.
            byte: usize,
            /// The char index at which the string should wrap due to exceeding a maximum width.
            char: usize,
            /// The byte length which should be skipped in order to reach the first non-whitespace
            /// character to use as the beginning of the next line.
            len_bytes: usize,
        },
        /// A break caused by a newline character.
        Newline {
            /// The byte index at which the string should wrap due to exceeding a maximum width.
            byte: usize,
            /// The char index at which the string should wrap due to exceeding a maximum width.
            char: usize,
            /// The width of the "newline" token in bytes.
            len_bytes: usize,
        },
        /// The end of the string has been reached, with the given length.
        End {
            /// The ending byte index.
            byte: usize,
            /// The ending char index.
            char: usize,
        },
    }

    /// Information about a single line of text within a `&str`.
    ///
    /// `Info` is a minimal amount of information that can be stored for efficient reasoning about
    /// blocks of text given some `&str`. The `start` and `end_break` can be used for indexing into
    /// the `&str`, and the `width` can be used for calculating line `Rect`s, alignment, etc.
    #[derive(Copy, Clone, Debug, PartialEq)]
    pub struct Info {
        /// The index into the `&str` that represents the first character within the line.
        pub start_byte: usize,
        /// The character index of the first character in the line.
        pub start_char: usize,
        /// The index within the `&str` at which this line breaks into a new line, along with the
        /// index at which the following line begins. The variant describes whether the break is
        /// caused by a `Newline` character or a `Wrap` by the given wrap function.
        pub end_break: Break,
        /// The total width of all characters within the line.
        pub width: Scalar,
    }

    /// An iterator yielding an `Info` struct for each line in the given `text` wrapped by the
    /// given `next_break_fn`.
    ///
    /// `Infos` is a fundamental part of performing lazy reasoning about text within conrod.
    ///
    /// Construct an `Infos` iterator via the [infos function](./fn.infos.html) and its two builder
    /// methods, [wrap_by_character](./struct.Infos.html#method.wrap_by_character) and
    /// [wrap_by_whitespace](./struct.Infos.html#method.wrap_by_whitespace).
    pub struct Infos<'a, F> {
        text: &'a str,
        font: &'a super::Font,
        font_size: FontSize,
        max_width: Scalar,
        next_break_fn: F,
        /// The index that indicates the start of the next line to be yielded.
        start_byte: usize,
        /// The character index that indicates the start of the next line to be yielded.
        start_char: usize,
        /// The break type of the previously yielded line
        last_break: Option<Break>,
    }

    /// An iterator yielding a `Rect` for each line in 
    #[derive(Clone)]
    pub struct Rects<I> {
        infos: I,
        x_align: Align,
        line_spacing: Scalar,
        next: Option<Rect>,
    }

    /// An iterator yielding a `Rect` for each selected line in a block of text.
    ///
    /// The yielded `Rect`s represent the selected range within each line of text.
    ///
    /// Lines that do not contain any selected text will be skipped.
    pub struct SelectedRects<'a, I> {
        selected_char_rects_per_line: super::glyph::SelectedRectsPerLine<'a, I>,
    }

    /// An alias for function pointers that are compatible with the `Block`'s required text
    /// wrapping function.
    pub type NextBreakFnPtr = fn(&str, &super::Font, FontSize, Scalar) -> (Break, Scalar);


    impl Break {

        /// Return the index at which the break occurs.
        pub fn byte_index(self) -> usize {
            match self {
                Break::Wrap { byte, .. } |
                Break::Newline { byte, .. } |
                Break::End { byte, .. } => byte,
            }
        }

        /// Return the index of the `char` at which the break occurs.
        ///
        /// To clarify, this index is to be used in relation to the `Chars` iterator.
        pub fn char_index(self) -> usize {
            match self {
                Break::Wrap { char, .. } |
                Break::Newline { char, .. } |
                Break::End { char, .. } => char,
            }
        }

    }

    impl<'a, F> Clone for Infos<'a, F>
        where F: Clone,
    {
        fn clone(&self) -> Self {
            Infos {
                text: self.text,
                font: self.font,
                font_size: self.font_size,
                max_width: self.max_width,
                next_break_fn: self.next_break_fn.clone(),
                start_byte: self.start_byte,
                start_char: self.start_char,
                last_break: None,
            }
        }
    }

    impl Info {

        /// The end of the byte index range for indexing into the slice.
        pub fn end_byte(&self) -> usize {
            self.end_break.byte_index()
        }

        /// The end of the index range for indexing into the slice.
        pub fn end_char(&self) -> usize {
            self.end_break.char_index()
        }

        /// The index range for indexing (via bytes) into the original str slice.
        pub fn byte_range(self) -> std::ops::Range<usize> {
            self.start_byte..self.end_byte()
        }

        /// The index range for indexing into a `char` iterator over the original str slice.
        pub fn char_range(self) -> std::ops::Range<usize> {
            self.start_char..self.end_char()
        }

    }

    impl<'a> Infos<'a, NextBreakFnPtr> {

        /// Converts `Self` into an `Infos` whose lines are wrapped at the character that first
        /// causes the line width to exceed the given `max_width`.
        pub fn wrap_by_character(mut self, max_width: Scalar) -> Self {
            self.next_break_fn = next_break_by_character;
            self.max_width = max_width;
            self
        }

        /// Converts `Self` into an `Infos` whose lines are wrapped at the whitespace prior to the
        /// character that causes the line width to exceed the given `max_width`.
        pub fn wrap_by_whitespace(mut self, max_width: Scalar) -> Self {
            self.next_break_fn = next_break_by_whitespace;
            self.max_width = max_width;
            self
        }

    }


    /// A function for finding the advance width between the given character that also considers
    /// the kerning for some previous glyph.
    ///
    /// This also updates the `last_glyph` with the glyph produced for the given `char`.
    ///
    /// This is primarily for use within the `next_break` functions below.
    ///
    /// The following code is adapted from the rusttype::LayoutIter::next src.
    fn advance_width(ch: char,
                     font: &super::Font,
                     scale: super::Scale,
                     last_glyph: &mut Option<super::GlyphId>) -> Scalar
    {
        let g = font.glyph(ch).unwrap().scaled(scale);
        let kern = last_glyph
            .map(|last| font.pair_kerning(scale, last, g.id()))
            .unwrap_or(0.0);
        let advance_width = g.h_metrics().advance_width;
        *last_glyph = Some(g.id());
        (kern + advance_width) as Scalar
    }


    /// Returns the next index at which the text naturally breaks via a newline character,
    /// along with the width of the line.
    fn next_break(text: &str,
                  font: &super::Font,
                  font_size: FontSize) -> (Break, Scalar)
    {
        let scale = super::pt_to_scale(font_size);
        let mut width = 0.0;
        let mut char_i = 0;
        let mut char_indices = text.char_indices().peekable();
        let mut last_glyph = None;
        while let Some((byte_i, ch)) = char_indices.next() {
            // Check for a newline.
            if ch == '\r' {
                if let Some(&(_, '\n')) = char_indices.peek() {
                    let break_ = Break::Newline { byte: byte_i, char: char_i, len_bytes: 2 };
                    return (break_, width);
                }
            } else if ch == '\n' {
                let break_ = Break::Newline { byte: byte_i, char: char_i, len_bytes: 1 };
                return (break_, width);
            }

            // Update the width.
            width += advance_width(ch, font, scale, &mut last_glyph);
            char_i += 1;
        }
        let break_ = Break::End { byte: text.len(), char: char_i };
        (break_, width)
    }

    /// Returns the next index at which the text will break by either:
    /// - A newline character.
    /// - A line wrap at the beginning of the first character exceeding the `max_width`.
    ///
    /// Also returns the width of each line alongside the Break.
    fn next_break_by_character(text: &str,
                               font: &super::Font,
                               font_size: FontSize,
                               max_width: Scalar) -> (Break, Scalar)
    {
        let scale = super::pt_to_scale(font_size);
        let mut width = 0.0;
        let mut char_i = 0;
        let mut char_indices = text.char_indices().peekable();
        let mut last_glyph = None;
        while let Some((byte_i, ch)) = char_indices.next() {

            // Check for a newline.
            if ch == '\r' {
                if let Some(&(_, '\n')) = char_indices.peek() {
                    let break_ = Break::Newline { byte: byte_i, char: char_i, len_bytes: 2 };
                    return (break_, width);
                }
            } else if ch == '\n' {
                let break_ = Break::Newline { byte: byte_i, char: char_i, len_bytes: 1 };
                return (break_, width);
            }

            // Add the character's width to the width so far.
            let new_width = width + advance_width(ch, font, scale, &mut last_glyph);

            // Check for a line wrap.
            if new_width > max_width {
                let break_ = Break::Wrap { byte: byte_i, char: char_i, len_bytes: 0 };
                return (break_, width);
            }

            width = new_width;
            char_i += 1;
        }

        let break_ = Break::End { byte: text.len(), char: char_i };
        (break_, width)
    }

    /// Returns the next index at which the text will break by either:
    /// - A newline character.
    /// - A line wrap at the beginning of the whitespace that preceeds the first word
    /// exceeding the `max_width`.
    /// - A line wrap at the beginning of the first character exceeding the `max_width`,
    /// if no whitespace appears for `max_width` characters.
    ///
    /// Also returns the width the line alongside the Break.
    fn next_break_by_whitespace(text: &str,
                                font: &super::Font,
                                font_size: FontSize,
                                max_width: Scalar) -> (Break, Scalar)
    {
        struct Last { byte: usize, char: usize, width_before: Scalar }
        let scale = super::pt_to_scale(font_size);
        let mut last_whitespace_start = None;
        let mut width = 0.0;
        let mut char_i = 0;
        let mut char_indices = text.char_indices().peekable();
        let mut last_glyph = None;
        while let Some((byte_i, ch)) = char_indices.next() {

            // Check for a newline.
            if ch == '\r' {
                if let Some(&(_, '\n')) = char_indices.peek() {
                    let break_ = Break::Newline { byte: byte_i, char: char_i, len_bytes: 2 };
                    return (break_, width)
                }
            } else if ch == '\n' {
                let break_ = Break::Newline { byte: byte_i, char: char_i, len_bytes: 1 };
                return (break_, width);
            }

            // Add the character's width to the width so far.
            let new_width = width + advance_width(ch, font, scale, &mut last_glyph);

            // Check for a line wrap.
            if width > max_width {
                match last_whitespace_start {
                    Some(Last { byte, char, width_before }) => {
                        let break_ = Break::Wrap { byte: byte, char: char, len_bytes: 1 };
                        return (break_, width_before);
                    },
                    None => {
                        let break_ = Break::Wrap { byte: byte_i, char: char_i, len_bytes: 0 };
                        return (break_, width);
                    }
                }
            }

            // Check for a new whitespace.
            if ch.is_whitespace() {
                last_whitespace_start = Some(Last { byte: byte_i, char: char_i, width_before: width });
            }

            width = new_width;
            char_i += 1;
        }

        let break_ = Break::End { byte: text.len(), char: char_i };
        (break_, width)
    }


    /// Produce the width of the given line of text including spaces (i.e. ' ').
    pub fn width(text: &str, font: &super::Font, font_size: FontSize) -> Scalar {
        let scale = super::Scale::uniform(super::pt_to_px(font_size));
        let point = super::rt::Point { x: 0.0, y: 0.0 };

        let mut total_w = 0.0;
        for g in font.layout(text, scale, point) {
            match g.pixel_bounding_box() {
                Some(bb) => total_w = bb.max.x as f32,
                None => total_w += g.unpositioned().h_metrics().advance_width,
            }
        }

        total_w as Scalar
    }


    /// Produce an `Infos` iterator wrapped by the given `next_break_fn`.
    pub fn infos_wrapped_by<'a, F>(text: &'a str,
                                   font: &'a super::Font,
                                   font_size: FontSize,
                                   max_width: Scalar,
                                   next_break_fn: F) -> Infos<'a, F>
        where F: for<'b> FnMut(&'b str, &'b super::Font, FontSize, Scalar) -> (Break, Scalar)
    {
        Infos {
            text: text,
            font: font,
            font_size: font_size,
            max_width: max_width,
            next_break_fn: next_break_fn,
            start_byte: 0,
            start_char: 0,
            last_break: None,
        }
    }

    /// Produce an `Infos` iterator that yields an `Info` for every line in the given text.
    ///
    /// The produced `Infos` iterator will not wrap the text, and only break each line via newline
    /// characters within the text (either `\n` or `\r\n`).
    pub fn infos<'a>(text: &'a str,
                     font: &'a super::Font,
                     font_size: FontSize) -> Infos<'a, NextBreakFnPtr>
    {
        fn no_wrap(text: &str,
                   font: &super::Font,
                   font_size: FontSize,
                   _max_width: Scalar) -> (Break, Scalar)
        {
            next_break(text, font, font_size)
        }

        infos_wrapped_by(text, font, font_size, std::f64::MAX, no_wrap)
    }

    /// Produce an iterator yielding the bounding `Rect` for each line in the text.
    ///
    /// This function assumes that `font_size` is the same `FontSize` used to produce the `Info`s
    /// yielded by the `infos` Iterator.
    pub fn rects<I>(mut infos: I,
                    font_size: FontSize,
                    bounding_rect: Rect,
                    x_align: Align,
                    y_align: Align,
                    line_spacing: Scalar) -> Rects<I>
        where I: Iterator<Item=Info> + ExactSizeIterator,
    {
        let num_lines = infos.len();
        let first_rect = infos.next().map(|first_info| {

            // Calculate the `x` `Range` of the first line `Rect`.
            let range = Range::new(0.0, first_info.width);
            let x = match x_align {
                Align::Start => range.align_start_of(bounding_rect.x),
                Align::Middle => range.align_middle_of(bounding_rect.x),
                Align::End => range.align_end_of(bounding_rect.x),
            };

            // Calculate the `y` `Range` of the first line `Rect`.
            let total_text_height = super::height(num_lines, font_size, line_spacing);
            let total_text_y_range = Range::new(0.0, total_text_height);
            let total_text_y = match y_align {
                Align::Start => total_text_y_range.align_start_of(bounding_rect.y),
                Align::Middle => total_text_y_range.align_middle_of(bounding_rect.y),
                Align::End => total_text_y_range.align_end_of(bounding_rect.y),
            };
            let range = Range::new(0.0, font_size as Scalar);
            let y = range.align_end_of(total_text_y);

            Rect { x: x, y: y }
        });

        Rects {
            infos: infos,
            next: first_rect,
            x_align: x_align,
            line_spacing: line_spacing,
        }
    }

    /// Produces an iterator yielding a `Rect` for the selected range in each selected line in a block
    /// of text.
    ///
    /// The yielded `Rect`s represent the selected range within each line of text.
    ///
    /// Lines that do not contain any selected text will be skipped.
    pub fn selected_rects<'a, I>(lines_with_rects: I,
                                 font: &'a super::Font,
                                 font_size: FontSize,
                                 start: super::cursor::Index,
                                 end: super::cursor::Index) -> SelectedRects<'a, I>
        where I: Iterator<Item=(&'a str, Rect)>,
    {
        SelectedRects {
            selected_char_rects_per_line:
                super::glyph::selected_rects_per_line(lines_with_rects, font, font_size, start, end)
        }
    }


    impl<'a, F> Iterator for Infos<'a, F>
        where F: for<'b> FnMut(&'b str, &'b super::Font, FontSize, Scalar) -> (Break, Scalar)
    {
        type Item = Info;
        fn next(&mut self) -> Option<Self::Item> {
            let Infos {
                text,
                font,
                font_size,
                max_width,
                ref mut next_break_fn,
                ref mut start_byte,
                ref mut start_char,
                ref mut last_break,
            } = *self;

            match next_break_fn(&text[*start_byte..], font, font_size, max_width) {
                (next @ Break::Newline { .. }, width) | (next @ Break::Wrap { .. }, width) => {

                    let next_break = match next {
                        Break::Newline { byte, char, len_bytes } =>
                            Break::Newline {
                                byte: *start_byte + byte,
                                char: *start_char + char,
                                len_bytes: len_bytes,
                            },
                        Break::Wrap { byte, char, len_bytes } =>
                            Break::Wrap {
                                byte: *start_byte + byte,
                                char: *start_char + char,
                                len_bytes: len_bytes,
                            },
                        _ => unreachable!(),
                    };

                    let info = Info {
                        start_byte: *start_byte,
                        start_char: *start_char,
                        end_break: next_break,
                        width: width,
                    };

                    match next {
                        Break::Newline { byte, char, len_bytes } |
                        Break::Wrap { byte, char, len_bytes } => {
                            *start_byte = info.start_byte + byte + len_bytes;
                            *start_char = info.start_char + char + 1;
                        },
                        _ => unreachable!(),
                    };
                    *last_break = Some(next_break);
                    Some(info)
                },

                (Break::End { char, .. }, width) => {
                    // if the last line ends in a new line, or the entire text is empty, return an empty line Info
                    let empty_line = {
                        match *last_break {
                            Some(last_break_) => match last_break_ {
                                Break::Newline { .. } => true,
                                _ => false,
                            }, None => true,
                        }
                    };
                    if *start_byte < text.len() || empty_line {
                        let total_bytes = text.len();
                        let total_chars = *start_char + char;
                        let end_break = Break::End {
                            byte: total_bytes,
                            char: total_chars,
                        };
                        let info = Info {
                            start_byte: *start_byte,
                            start_char: *start_char,
                            end_break: end_break,
                            width: width,
                        };
                        *start_byte = total_bytes;
                        *start_char = total_chars;
                        *last_break = Some(end_break);
                        Some(info)
                    } else {
                        None
                    }
                },
            }
        }
    }

    impl<I> Iterator for Rects<I>
        where I: Iterator<Item=Info>,
    {
        type Item = Rect;
        fn next(&mut self) -> Option<Self::Item> {
            let Rects { ref mut next, ref mut infos, x_align, line_spacing } = *self;
            next.map(|line_rect| {
                *next = infos.next().map(|info| {

                    let y = {
                        let h = line_rect.h();
                        let y = line_rect.y() - h - line_spacing;
                        Range::from_pos_and_len(y, h)
                    };

                    let x = {
                        let range = Range::new(0.0, info.width);
                        match x_align {
                            Align::Start => range.align_start_of(line_rect.x),
                            Align::Middle => range.align_middle_of(line_rect.x),
                            Align::End => range.align_end_of(line_rect.x),
                        }
                    };

                    Rect { x: x, y: y }
                });

                line_rect
            })
        }
    }

    impl<'a, I> Iterator for SelectedRects<'a, I>
        where I: Iterator<Item=(&'a str, Rect)>,
    {
        type Item = Rect;
        fn next(&mut self) -> Option<Self::Item> {
            while let Some(mut rects) = self.selected_char_rects_per_line.next() {
                if let Some(first_rect) = rects.next() {
                    let total_selected_rect = rects.fold(first_rect, |mut total, next| {
                        total.x.end = next.x.end;
                        total
                    });
                    return Some(total_selected_rect);
                }
            }
            None
        }
    }

}