<commit_before>use std::ffi::{CStr, CString, NulError};
use std::rc::Rc;
use libc::c_char;

use sys::sdl as ll;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    fn new() -> Result<Sdl, String> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err("Cannot initialize `Sdl` more than once at a time.".to_owned())
            } else {
                // Initialize SDL without any explicit subsystems (flags = 0).
                if ll::SDL_Init(0) == 0 {
                    Ok(Sdl {
                        sdldrop: Rc::new(SdlDrop)
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                let result = unsafe { ll::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        impl $name {
            #[inline]
            pub fn clone(&self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone()
                }
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug, Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: ll::SDL_InitFlag
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, ll::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, ll::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, ll::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, ll::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, ll::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, ll::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, ll::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = ll::SDL_InitSubSystem(ll::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone()
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            ll::SDL_QuitSubSystem(ll::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> Result<Sdl, String> { Sdl::new() }

pub fn get_error() -> String {
    unsafe {
        let err = ll::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = try!(CString::new(err));
    Ok(unsafe {
        ll::SDL_SetError(c_string.as_ptr() as *const c_char);
    })
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<commit_msg>Implement Display for SDL Error.<commit_after>use std::ffi::{CStr, CString, NulError};
use std::fmt;
use std::rc::Rc;
use libc::c_char;

use sys::sdl as ll;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum Error {
    NoMemError = ll::SDL_ENOMEM as isize,
    ReadError = ll::SDL_EFREAD as isize,
    WriteError = ll::SDL_EFWRITE as isize,
    SeekError = ll::SDL_EFSEEK as isize,
    UnsupportedError = ll::SDL_UNSUPPORTED as isize
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match *self {
            NoMemError => write!(f, "Out of memory"),
            ReadError => write!(f, "Error reading from datastream"),
            WriteError => write!(f, "Error writing to datastream"),
            SeekError => write!(f, "Error seeking in datastream"),
            UnsupportedError => write!(f, "Unknown SDL error")
        }
    }
}

use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
/// Only one Sdl context can be alive at a time.
/// Set to false by default (not alive).
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;

/// The SDL context type. Initialize with `sdl2::init()`.
///
/// From a thread-safety perspective, `Sdl` represents the main thread.
/// As such, `Sdl` is a useful type for ensuring that SDL types that can only
/// be used on the main thread are initialized that way.
///
/// For instance, `SDL_PumpEvents()` is not thread safe, and may only be
/// called on the main thread.
/// All functionality that calls `SDL_PumpEvents()` is thus put into an
/// `EventPump` type, which can only be obtained through `Sdl`.
/// This guarantees that the only way to call event-pumping functions is on
/// the main thread.
#[derive(Clone)]
pub struct Sdl {
    sdldrop: Rc<SdlDrop>
}

impl Sdl {
    #[inline]
    fn new() -> Result<Sdl, String> {
        unsafe {
            use std::sync::atomic::Ordering;

            // Atomically switch the `IS_SDL_CONTEXT_ALIVE` global to true
            let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);

            if was_alive {
                Err("Cannot initialize `Sdl` more than once at a time.".to_owned())
            } else {
                // Initialize SDL without any explicit subsystems (flags = 0).
                if ll::SDL_Init(0) == 0 {
                    Ok(Sdl {
                        sdldrop: Rc::new(SdlDrop)
                    })
                } else {
                    IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
                    Err(get_error())
                }
            }
        }
    }

    /// Initializes the audio subsystem.
    #[inline]
    pub fn audio(&self) -> Result<AudioSubsystem, String> { AudioSubsystem::new(self) }

    /// Initializes the event subsystem.
    #[inline]
    pub fn event(&self) -> Result<EventSubsystem, String> { EventSubsystem::new(self) }

    /// Initializes the joystick subsystem.
    #[inline]
    pub fn joystick(&self) -> Result<JoystickSubsystem, String> { JoystickSubsystem::new(self) }

    /// Initializes the haptic subsystem.
    #[inline]
    pub fn haptic(&self) -> Result<HapticSubsystem, String> { HapticSubsystem::new(self) }

    /// Initializes the game controller subsystem.
    #[inline]
    pub fn game_controller(&self) -> Result<GameControllerSubsystem, String> { GameControllerSubsystem::new(self) }

    /// Initializes the timer subsystem.
    #[inline]
    pub fn timer(&self) -> Result<TimerSubsystem, String> { TimerSubsystem::new(self) }

    /// Initializes the video subsystem.
    #[inline]
    pub fn video(&self) -> Result<VideoSubsystem, String> { VideoSubsystem::new(self) }

    /// Obtains the SDL event pump.
    ///
    /// At most one `EventPump` is allowed to be alive during the program's execution.
    /// If this function is called while an `EventPump` instance is alive, the function will return
    /// an error.
    #[inline]
    pub fn event_pump(&self) -> Result<EventPump, String> {
        EventPump::new(self)
    }

    #[inline]
    #[doc(hidden)]
    pub fn sdldrop(&self) -> Rc<SdlDrop> {
        self.sdldrop.clone()
    }
}

/// When SDL is no longer in use (the refcount in an `Rc<SdlDrop>` reaches 0), the library is quit.
#[doc(hidden)]
#[derive(Debug)]
pub struct SdlDrop;

impl Drop for SdlDrop {
    #[inline]
    fn drop(&mut self) {
        use std::sync::atomic::Ordering;

        let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
        assert!(was_alive);

        unsafe { ll::SDL_Quit(); }
    }
}

// No subsystem can implement `Send` because the destructor, `SDL_QuitSubSystem`,
// utilizes non-atomic reference counting and should thus be called on a single thread.
// Some subsystems have functions designed to be thread-safe, such as adding a timer or accessing
// the event queue. These subsystems implement `Sync`.

macro_rules! subsystem {
    ($name:ident, $flag:expr) => (
        impl $name {
            #[inline]
            fn new(sdl: &Sdl) -> Result<$name, String> {
                let result = unsafe { ll::SDL_InitSubSystem($flag) };

                if result == 0 {
                    Ok($name {
                        _subsystem_drop: Rc::new(SubsystemDrop {
                            _sdldrop: sdl.sdldrop.clone(),
                            flag: $flag
                        })
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    );
    ($name:ident, $flag:expr, nosync) => (
        #[derive(Debug, Clone)]
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }

        impl $name {
            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    );
    ($name:ident, $flag:expr, sync) => (
        pub struct $name {
            /// Subsystems cannot be moved or (usually) used on non-main threads.
            /// Luckily, Rc restricts use to the main thread.
            _subsystem_drop: Rc<SubsystemDrop>
        }
        unsafe impl Sync for $name {}

        impl $name {
            #[inline]
            pub fn clone(&self) -> $name {
                $name {
                    _subsystem_drop: self._subsystem_drop.clone()
                }
            }

            /// Obtain an SDL context.
            #[inline]
            pub fn sdl(&self) -> Sdl {
                Sdl { sdldrop: self._subsystem_drop._sdldrop.clone() }
            }
        }

        subsystem!($name, $flag);
    )
}

/// When a subsystem is no longer in use (the refcount in an `Rc<SubsystemDrop>` reaches 0),
/// the subsystem is quit.
#[derive(Debug, Clone)]
struct SubsystemDrop {
    _sdldrop: Rc<SdlDrop>,
    flag: ll::SDL_InitFlag
}

impl Drop for SubsystemDrop {
    #[inline]
    fn drop(&mut self) {
        unsafe { ll::SDL_QuitSubSystem(self.flag); }
    }
}

subsystem!(AudioSubsystem, ll::SDL_INIT_AUDIO, nosync);
subsystem!(GameControllerSubsystem, ll::SDL_INIT_GAMECONTROLLER, nosync);
subsystem!(HapticSubsystem, ll::SDL_INIT_HAPTIC, nosync);
subsystem!(JoystickSubsystem, ll::SDL_INIT_JOYSTICK, nosync);
subsystem!(VideoSubsystem, ll::SDL_INIT_VIDEO, nosync);
// Timers can be added on other threads.
subsystem!(TimerSubsystem, ll::SDL_INIT_TIMER, sync);
// The event queue can be read from other threads.
subsystem!(EventSubsystem, ll::SDL_INIT_EVENTS, sync);

static mut IS_EVENT_PUMP_ALIVE: bool = false;

/// A thread-safe type that encapsulates SDL event-pumping functions.
pub struct EventPump {
    _sdldrop: Rc<SdlDrop>
}

impl EventPump {
    /// Obtains the SDL event pump.
    #[inline]
    fn new(sdl: &Sdl) -> Result<EventPump, String> {
        // Called on the main SDL thread.

        unsafe {
            if IS_EVENT_PUMP_ALIVE {
                Err("an `EventPump` instance is already alive - there can only be one `EventPump` in use at a time.".to_owned())
            } else {
                // Initialize the events subsystem, just in case none of the other subsystems have done it yet.
                let result = ll::SDL_InitSubSystem(ll::SDL_INIT_EVENTS);

                if result == 0 {
                    IS_EVENT_PUMP_ALIVE = true;

                    Ok(EventPump {
                        _sdldrop: sdl.sdldrop.clone()
                    })
                } else {
                    Err(get_error())
                }
            }
        }
    }
}

impl Drop for EventPump {
    #[inline]
    fn drop(&mut self) {
        // Called on the main SDL thread.

        unsafe {
            assert!(IS_EVENT_PUMP_ALIVE);
            ll::SDL_QuitSubSystem(ll::SDL_INIT_EVENTS);
            IS_EVENT_PUMP_ALIVE = false;
        }
    }
}

/// Initializes the SDL library.
/// This must be called before using any other SDL function.
///
/// # Example
/// ```no_run
/// let sdl_context = sdl2::init().unwrap();
/// let mut event_pump = sdl_context.event_pump().unwrap();
///
/// for event in event_pump.poll_iter() {
///     // ...
/// }
///
/// // SDL_Quit() is called here as `sdl_context` is dropped.
/// ```
#[inline]
pub fn init() -> Result<Sdl, String> { Sdl::new() }

pub fn get_error() -> String {
    unsafe {
        let err = ll::SDL_GetError();
        CStr::from_ptr(err as *const _).to_str().unwrap().to_owned()
    }
}

pub fn set_error(err: &str) -> Result<(), NulError> {
    let c_string = try!(CString::new(err));
    Ok(unsafe {
        ll::SDL_SetError(c_string.as_ptr() as *const c_char);
    })
}

pub fn set_error_from_code(err: Error) {
    unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}

pub fn clear_error() {
    unsafe { ll::SDL_ClearError(); }
}
<|endoftext|>


<commit_before>use Error;
use Year;

use reqwest;

#[derive(Debug, Deserialize)]
pub struct SemesterPlan {
    pub year: Year,
    #[serde(rename = "type")]
    pub semester_type: String,
    pub period: Period,
    #[serde(rename = "freeDays")]
    pub holidays: Vec<Holiday>,
    #[serde(rename = "lecturePeriod")]
    pub lecture_period: Period,
    #[serde(rename = "examsPeriod")]
    pub exam_period: Period,
    #[serde(rename = "reregistration")]
    pub reregistration_period: Period,
}

#[derive(Debug, Deserialize)]
pub struct Period {
    #[serde(rename = "beginDay")]
    begin_day: String,
    #[serde(rename = "endDay")]
    end_day: String,
}

#[derive(Debug, Deserialize)]
pub struct Holiday {
    name: String,
    #[serde(rename = "beginDay")]
    begin_day: String,
    #[serde(rename = "endDay")]
    end_day: String,
}

const BASE_URL: &'static str = "https://www2.htw-dresden.de/~app/API/semesterplan.json";

impl SemesterPlan {
    /// Returns all currently available `SemesterPlan`s.
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::SemesterPlan;
    ///
    /// fn main() {
    ///     let semesters = SemesterPlan::get();
    /// }
    /// ```
    pub fn get() -> Result<Vec<SemesterPlan>, Error> {
        let semesters = reqwest::get(BASE_URL)?
            .json()
            .map(|response: Vec<SemesterPlan>| response)?;
        Ok(semesters)
    }
}
<commit_msg>workaround fix for long waiting on semester result<commit_after>use Error;
use Year;

use reqwest;

#[derive(Debug, Deserialize)]
pub struct SemesterPlan {
    pub year: Year,
    #[serde(rename = "type")]
    pub semester_type: String,
    pub period: Period,
    #[serde(rename = "freeDays")]
    pub holidays: Vec<Holiday>,
    #[serde(rename = "lecturePeriod")]
    pub lecture_period: Period,
    #[serde(rename = "examsPeriod")]
    pub exam_period: Period,
    #[serde(rename = "reregistration")]
    pub reregistration_period: Period,
}

#[derive(Debug, Deserialize)]
pub struct Period {
    #[serde(rename = "beginDay")]
    begin_day: String,
    #[serde(rename = "endDay")]
    end_day: String,
}

#[derive(Debug, Deserialize)]
pub struct Holiday {
    name: String,
    #[serde(rename = "beginDay")]
    begin_day: String,
    #[serde(rename = "endDay")]
    end_day: String,
}

const BASE_URL: &'static str = "https://www2.htw-dresden.de/~app/API/semesterplan.json";

impl SemesterPlan {
    /// Returns all currently available `SemesterPlan`s.
    ///
    /// # Example
    ///
    /// ```
    /// use htwdresden::SemesterPlan;
    ///
    /// fn main() {
    ///     let semesters = SemesterPlan::get();
    /// }
    /// ```
    pub fn get() -> Result<Vec<SemesterPlan>, Error> {
        let client = reqwest::Client::new().expect("failed to create new reqwest client o.O");
        // Working around a possible bug in reqwest/hyper on macOS, see https://github.com/seanmonstar/reqwest/issues/26
        let mut headers = reqwest::header::Headers::new();
        headers.set(reqwest::header::Connection::close());

        let semesters = client.get(BASE_URL)
            .headers(headers)
            .send()?
            .json()
            .map(|response: Vec<SemesterPlan>| response)?;
        Ok(semesters)
    }
}
<|endoftext|>


<commit_before>use super::theme::Theme;
use super::settings::*;
use super::super::LoadingError;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::io::{BufReader, BufRead, Seek};
use walkdir::WalkDir;
use std::fs::File;

#[derive(Debug, Serialize, Deserialize)]
pub struct ThemeSet {
    pub themes: BTreeMap<String, Theme>,
}

/// A set of themes, includes convenient methods for loading and discovering themes.
impl ThemeSet {
    /// Returns all the themes found in a folder, good for enumerating before loading one with get_theme
    pub fn discover_theme_paths<P: AsRef<Path>>(folder: P) -> Result<Vec<PathBuf>, LoadingError> {
        let mut themes = Vec::new();
        for entry in WalkDir::new(folder) {
            let entry = entry.map_err(LoadingError::WalkDir)?;
            if entry.path().extension().map_or(false, |e| e == "tmTheme") {
                themes.push(entry.path().to_owned());
            }
        }
        Ok(themes)
    }

    /// Loads a theme given a path to a .tmTheme file
    pub fn get_theme<P: AsRef<Path>>(path: P) -> Result<Theme, LoadingError> {
        let file = File::open(path)?;
        let mut file = BufReader::new(file);
        Self::load_from_reader(&mut file)
    }

    /// Loads a theme given a readable stream
    pub fn load_from_reader<R: BufRead + Seek>(r: &mut R) -> Result<Theme, LoadingError> {
        Ok(Theme::parse_settings(read_plist(r)?)?)
    }

    /// Loads all the themes in a folder
    pub fn load_from_folder<P: AsRef<Path>>(folder: P) -> Result<ThemeSet, LoadingError> {
        let paths = Self::discover_theme_paths(folder)?;
        let mut map = BTreeMap::new();
        for p in &paths {
            let theme = Self::get_theme(p)?;
            let basename =
                p.file_stem().and_then(|x| x.to_str()).ok_or(LoadingError::BadPath)?;
            map.insert(basename.to_owned(), theme);
        }
        Ok(ThemeSet { themes: map })
    }
}

#[cfg(test)]
mod tests {
    use highlighting::{ThemeSet, Color};
    #[test]
    fn can_parse_common_themes() {
        let themes = ThemeSet::load_from_folder("testdata").unwrap();
        let all_themes: Vec<&str> = themes.themes.keys().map(|x| &**x).collect();
        println!("{:?}", all_themes);

        let theme = ThemeSet::get_theme("testdata/spacegray/base16-ocean.dark.tmTheme").unwrap();
        assert_eq!(theme.name.unwrap(), "Base16 Ocean Dark");
        assert_eq!(theme.settings.selection.unwrap(),
                   Color {
                       r: 0x4f,
                       g: 0x5b,
                       b: 0x66,
                       a: 0xff,
                   });
        assert_eq!(theme.scopes[0].style.foreground.unwrap(),
                   Color {
                       r: 0xc0,
                       g: 0xc5,
                       b: 0xce,
                       a: 0xFF,
                   });
        // assert!(false);
    }
}
<commit_msg>Add `ThemeSet::load_themes` method<commit_after>use super::theme::Theme;
use super::settings::*;
use super::super::LoadingError;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::io::{BufReader, BufRead, Seek};
use walkdir::WalkDir;
use std::fs::File;

#[derive(Debug, Serialize, Deserialize)]
pub struct ThemeSet {
    pub themes: BTreeMap<String, Theme>,
}

/// A set of themes, includes convenient methods for loading and discovering themes.
impl ThemeSet {
    /// Creates an empty set
    pub fn new() -> ThemeSet {
        ThemeSet { themes: BTreeMap::new() }
    }

    /// Returns all the themes found in a folder, good for enumerating before loading one with get_theme
    pub fn discover_theme_paths<P: AsRef<Path>>(folder: P) -> Result<Vec<PathBuf>, LoadingError> {
        let mut themes = Vec::new();
        for entry in WalkDir::new(folder) {
            let entry = entry.map_err(LoadingError::WalkDir)?;
            if entry.path().extension().map_or(false, |e| e == "tmTheme") {
                themes.push(entry.path().to_owned());
            }
        }
        Ok(themes)
    }

    /// Loads a theme given a path to a .tmTheme file
    pub fn get_theme<P: AsRef<Path>>(path: P) -> Result<Theme, LoadingError> {
        let file = File::open(path)?;
        let mut file = BufReader::new(file);
        Self::load_from_reader(&mut file)
    }

    /// Loads a theme given a readable stream
    pub fn load_from_reader<R: BufRead + Seek>(r: &mut R) -> Result<Theme, LoadingError> {
        Ok(Theme::parse_settings(read_plist(r)?)?)
    }

    /// Generate a `ThemeSet` from all themes in a folder
    pub fn load_from_folder<P: AsRef<Path>>(folder: P) -> Result<ThemeSet, LoadingError> {
        let mut theme_set = Self::new();
        theme_set.load_themes(folder)?;
        Ok(theme_set)
    }

    /// Load all the themes in the folder into this `ThemeSet`
    pub fn load_themes<P: AsRef<Path>>(&mut self, folder: P) -> Result<(), LoadingError> {
        let paths = Self::discover_theme_paths(folder)?;
        for p in &paths {
            let theme = Self::get_theme(p)?;
            let basename =
                p.file_stem().and_then(|x| x.to_str()).ok_or(LoadingError::BadPath)?;
            self.themes.insert(basename.to_owned(), theme);
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use highlighting::{ThemeSet, Color};
    #[test]
    fn can_parse_common_themes() {
        let themes = ThemeSet::load_from_folder("testdata").unwrap();
        let all_themes: Vec<&str> = themes.themes.keys().map(|x| &**x).collect();
        assert!(all_themes.contains(&"base16-ocean.dark"));

        println!("{:?}", all_themes);

        let theme = ThemeSet::get_theme("testdata/spacegray/base16-ocean.dark.tmTheme").unwrap();
        assert_eq!(theme.name.unwrap(), "Base16 Ocean Dark");
        assert_eq!(theme.settings.selection.unwrap(),
                   Color {
                       r: 0x4f,
                       g: 0x5b,
                       b: 0x66,
                       a: 0xff,
                   });
        assert_eq!(theme.scopes[0].style.foreground.unwrap(),
                   Color {
                       r: 0xc0,
                       g: 0xc5,
                       b: 0xce,
                       a: 0xFF,
                   });
        // assert!(false);
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::mpsc::Receiver;

type WordCell = Rc<RefCell<Word>>;
pub type AuthorCell = Rc<RefCell<Author>>;
pub type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;
type InstanceCell = Rc<RefCell<WordInstance>>;

fn wrap<T>(t: T) -> Rc<RefCell<T>> {
    Rc::new(RefCell::new(t))
}

// const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

#[derive(Default)]
pub struct Lexicon<R: rand::Rng> {
    rng: R,
    words: BTreeMap<String, WordCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
    messages: Vec<MessageCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl<R: rand::Rng> Lexicon<R> {
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) -> Option<String> {
        let conversation = match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // TODO: Determine what to say back
        None
    }

    pub fn initiate(&mut self, source: SourceCell) -> Option<String> {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());

        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        let bborrow = base.borrow();

        Some(bborrow.instances.iter()
            .map(|instance| instance.borrow().category.clone())
            // TODO: Allow random choosing from co-category instances as well
            .map(|category| self.rng.choose(&category.borrow().instances[..]).unwrap().clone())
            .map(|instance| {
                let ins = instance.borrow();
                let word = ins.word.borrow();
                word.name.clone()
            })
            .join(" "))
    }

    pub fn think(&mut self, end: Receiver<()>) {
        use std::sync::mpsc::TryRecvError::Empty;
        while end.try_recv() == Err(Empty) {
            // Choose a random message or break if there are none
            let message = match self.rng.choose(&self.messages[..]) {
                Some(m) => m.clone(),
                None => break,
            };

            enum Amount<T> {
                None,
                One(T),
                Multiple,
            }

            // Vector of absolute perfect matches
            let mut vones = Vec::new();

            // Look through each word in the message
            for word in &message.borrow().instances {
                let borrow = word.borrow();
                // Check each instance in that words instances
                for instance in &borrow.word.borrow().instances {
                    // Get the message for each instance
                    let omessage = instance.borrow().message.clone();
                    // Make sure we dont get the same message twice and assure the same length
                    if omessage != message &&
                        omessage.borrow().instances.len() == message.borrow().instances.len() {
                        // Find what kind of matches exist between the messages
                        if let Amount::One(best) = message.borrow().instances.iter()
                            .zip(omessage.borrow().instances.iter())
                            .fold(Amount::None, |acc, ws| {
                                let bs = (ws.0.borrow(), ws.1.borrow());
                                match acc {
                                    Amount::None => {
                                        if bs.0.word.borrow().name !=
                                            bs.1.word.borrow().name {
                                            Amount::One((ws.0.clone(), ws.1.clone()))
                                        } else {
                                            Amount::None
                                        }
                                    },
                                    Amount::One(best) => {
                                        if bs.0.word.borrow().name !=
                                            bs.1.word.borrow().name {
                                            Amount::Multiple
                                        } else {
                                            Amount::One(best)
                                        }
                                    },
                                    Amount::Multiple => Amount::Multiple,
                                }
                            }) {
                            vones.push(best);
                        }
                    }
                }
            }

            // Now that we have perfect matches, merge them into the same Category
            for ms in vones {
                // We only want to combine if they aren't already in the same category
                if ms.0.borrow().category != ms.1.borrow().category {
                    let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                    Category::merge(cats);
                }
            }
        }
    }

    pub fn show_categories(&self) {
        for message in &self.messages {
            for instance in &message.borrow().instances {
                println!("Category:");
                let ib = instance.borrow();
                for instance in &ib.category.borrow().instances {
                    let ib = instance.borrow();
                    println!("\t{}", ib.word.borrow().name);
                }
            }
        }
    }
}

macro_rules! pointer_eq {
    ($s:ident) => {
        impl PartialEq for $s {
            fn eq(&self, other: &Self) -> bool {
                self as *const Self == other as *const Self
            }

            fn ne(&self, other: &Self) -> bool {
                self as *const Self != other as *const Self
            }
        }
    };
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

pointer_eq!(Conversation);

pub struct Author {
    source: SourceCell,
    name: String,
}

pointer_eq!(Author);

pub struct Source {
    name: String,
    messages: u64,
    authors: BTreeMap<String, AuthorCell>,
}

pointer_eq!(Source);

struct WordInstance {
    word: WordCell,
    category: CategoryCell,
    message: MessageCell,
    index: usize,
}

pointer_eq!(WordInstance);

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Message);

#[derive(Default)]
struct Category {
    instances: Vec<InstanceCell>,
    cocategories: Vec<CategoryCell>,
}

impl Category {
    fn merge(cs: (CategoryCell, CategoryCell)) -> CategoryCell {
        let cc = wrap(Self::default());
        {
            let clos = |cat: &CategoryCell| {
                for instance in cat.borrow().instances.iter().cloned() {
                    instance.borrow_mut().category = cc.clone();
                }
            };
            clos(&cs.0);
            clos(&cs.1);
            let mut ccm = cc.borrow_mut();
            ccm.instances.append(&mut cs.0.borrow_mut().instances);
            ccm.instances.append(&mut cs.1.borrow_mut().instances);
        }
        cc
    }
}

pointer_eq!(Category);

struct Word {
    name: String,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Word);
<commit_msg>fix show_categories to not print duplicates<commit_after>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::mpsc::Receiver;

type WordCell = Rc<RefCell<Word>>;
pub type AuthorCell = Rc<RefCell<Author>>;
pub type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;
type InstanceCell = Rc<RefCell<WordInstance>>;

fn wrap<T>(t: T) -> Rc<RefCell<T>> {
    Rc::new(RefCell::new(t))
}

// const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

#[derive(Default)]
pub struct Lexicon<R: rand::Rng> {
    rng: R,
    words: BTreeMap<String, WordCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
    messages: Vec<MessageCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl<R: rand::Rng> Lexicon<R> {
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) -> Option<String> {
        let conversation = match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // TODO: Determine what to say back
        None
    }

    pub fn initiate(&mut self, source: SourceCell) -> Option<String> {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());

        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        let bborrow = base.borrow();

        Some(bborrow.instances.iter()
            .map(|instance| instance.borrow().category.clone())
            // TODO: Allow random choosing from co-category instances as well
            .map(|category| self.rng.choose(&category.borrow().instances[..]).unwrap().clone())
            .map(|instance| {
                let ins = instance.borrow();
                let word = ins.word.borrow();
                word.name.clone()
            })
            .join(" "))
    }

    pub fn think(&mut self, end: Receiver<()>) {
        use std::sync::mpsc::TryRecvError::Empty;
        while end.try_recv() == Err(Empty) {
            // Choose a random message or break if there are none
            let message = match self.rng.choose(&self.messages[..]) {
                Some(m) => m.clone(),
                None => break,
            };

            enum Amount<T> {
                None,
                One(T),
                Multiple,
            }

            // Vector of absolute perfect matches
            let mut vones = Vec::new();

            // Look through each word in the message
            for word in &message.borrow().instances {
                let borrow = word.borrow();
                // Check each instance in that words instances
                for instance in &borrow.word.borrow().instances {
                    // Get the message for each instance
                    let omessage = instance.borrow().message.clone();
                    // Make sure we dont get the same message twice and assure the same length
                    if omessage != message &&
                        omessage.borrow().instances.len() == message.borrow().instances.len() {
                        // Find what kind of matches exist between the messages
                        if let Amount::One(best) = message.borrow().instances.iter()
                            .zip(omessage.borrow().instances.iter())
                            .fold(Amount::None, |acc, ws| {
                                let bs = (ws.0.borrow(), ws.1.borrow());
                                match acc {
                                    Amount::None => {
                                        if bs.0.word.borrow().name !=
                                            bs.1.word.borrow().name {
                                            Amount::One((ws.0.clone(), ws.1.clone()))
                                        } else {
                                            Amount::None
                                        }
                                    },
                                    Amount::One(best) => {
                                        if bs.0.word.borrow().name !=
                                            bs.1.word.borrow().name {
                                            Amount::Multiple
                                        } else {
                                            Amount::One(best)
                                        }
                                    },
                                    Amount::Multiple => Amount::Multiple,
                                }
                            }) {
                            vones.push(best);
                        }
                    }
                }
            }

            // Now that we have perfect matches, merge them into the same Category
            for ms in vones {
                // We only want to combine if they aren't already in the same category
                if ms.0.borrow().category != ms.1.borrow().category {
                    let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                    Category::merge(cats);
                }
            }
        }
    }

    pub fn show_categories(&self) {
        use std::collections::BTreeSet;
        let mut set = BTreeSet::new();
        for message in &self.messages {
            for instance in &message.borrow().instances {
                let ib = instance.borrow();
                set.insert(&*ib.category.borrow() as *const Category);
            }
        }

        for cat in set {
            println!("Category:");
            let catr = unsafe{&*cat};
            for instance in &catr.instances {
                let ib = instance.borrow();
                println!("\t{}", ib.word.borrow().name);
            }
        }
    }
}

macro_rules! pointer_eq {
    ($s:ident) => {
        impl PartialEq for $s {
            fn eq(&self, other: &Self) -> bool {
                self as *const Self == other as *const Self
            }

            fn ne(&self, other: &Self) -> bool {
                self as *const Self != other as *const Self
            }
        }
    };
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

pointer_eq!(Conversation);

pub struct Author {
    source: SourceCell,
    name: String,
}

pointer_eq!(Author);

pub struct Source {
    name: String,
    messages: u64,
    authors: BTreeMap<String, AuthorCell>,
}

pointer_eq!(Source);

struct WordInstance {
    word: WordCell,
    category: CategoryCell,
    message: MessageCell,
    index: usize,
}

pointer_eq!(WordInstance);

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Message);

#[derive(Default)]
struct Category {
    instances: Vec<InstanceCell>,
    cocategories: Vec<CategoryCell>,
}

impl Category {
    fn merge(cs: (CategoryCell, CategoryCell)) -> CategoryCell {
        let cc = wrap(Self::default());
        {
            let clos = |cat: &CategoryCell| {
                for instance in cat.borrow().instances.iter().cloned() {
                    instance.borrow_mut().category = cc.clone();
                }
            };
            clos(&cs.0);
            clos(&cs.1);
            let mut ccm = cc.borrow_mut();
            ccm.instances.append(&mut cs.0.borrow_mut().instances);
            ccm.instances.append(&mut cs.1.borrow_mut().instances);
        }
        cc
    }
}

pointer_eq!(Category);

struct Word {
    name: String,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Word);
<|endoftext|>


<commit_before>use color::Color;
use dimensions::Dimensions;
use graphics;
use graphics::{
    Graphics,
};
use graphics::character::CharacterCache;
use label;
use label::FontSize;
use mouse::Mouse;
use piston::input::keyboard::Key::{
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use std::num::Float;
use clock_ticks::precise_time_s;
use ui_context::{
    Id,
    UIID,
    UiContext,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::{ DefaultWidgetState, Widget };
use std::cmp;
use Callback;
use FrameColor;
use FrameWidth;
use Position;
use Size;

pub type Idx = usize;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct State(DrawState, Capturing);

/// Represents the next tier of state.
#[derive(Debug, PartialEq, Clone,Copy)]
pub enum DrawState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx, CursorX),
}

/// Represents an element of the TextBox widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Capturing::Captured(_, _) => rectangle::State::Normal,
                Capturing::Uncaptured => match state {
                    DrawState::Normal => rectangle::State::Normal,
                    DrawState::Highlighted(_) => rectangle::State::Highlighted,
                    DrawState::Clicked(_) => rectangle::State::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, Widget::TextBox(State(DrawState::Normal, Capturing::Uncaptured)));

static TEXT_PADDING: f64 = 5f64;

// if the index is 0 return (0, the start of the text)
// until we reach the each index we start with iterate over the characters character in the string
//   if the

/// Calculate the index and x position for a text box cursor.
fn update_cursor_position<C: CharacterCache>(uic: &mut UiContext<C>,
                          mut idx: usize,
                          mut text_x: f64,
                          font_size: FontSize,
                          text: &str) -> (Idx, CursorX) {
    if idx == 0 { return (0, text_x); }
    let text_len = text.len();
    if idx > text_len { idx = text_len; }
    for (i, ch) in text.chars().enumerate() {
        if i >= idx { break; }
        text_x += uic.get_character(font_size, ch).width();
    }
    (idx, text_x)
}

/// Check if cursor is over the pad and if so, which
fn over_elem<C: CharacterCache>(uic: &mut UiContext<C>,
             pos: Point,
             mouse_pos: Point,
             rect_dim: Dimensions,
             pad_pos: Point,
             pad_dim: Dimensions,
             text_pos: Point,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_dim) {
        false => Element::Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_dim) {
            false => Element::Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, text_pos[0], text_w, font_size, text);
                Element::Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx<C: CharacterCache>(uic: &mut UiContext<C>,
               mouse_pos: Point,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos[0] <= text_x { return (0, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = character.width();
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos[0] > left_x && mouse_pos[0] < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::Capturing::{Uncaptured, Captured};
    use self::DrawState::{Normal, Highlighted, Clicked};
    use self::Element::{Nill, Text};
    match prev_box_state {
        State(prev, Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, Normal, Down)                       => State(Normal, Uncaptured),
                (Nill, Normal, Up)                      |
                (Nill, Highlighted(_), Up)              => State(Normal, Uncaptured),
                (_, Normal, Up)                         |
                (_, Highlighted(_), Up)                 => State(Highlighted(over_elem), Uncaptured),
                (_, Highlighted(p_elem), Down)          |
                (_, Clicked(p_elem), Down)              => State(Clicked(p_elem), Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (Nill, _, _)                            => State(Normal, Uncaptured),
                _                                       => prev_box_state,
            }
        },
        State(prev, Captured(p_idx, p_x)) => {
            match (over_elem, prev, mouse.left) {
                (Nill, Clicked(Nill), Up)               => State(Normal, Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (_, Normal, Up)                         |
                (_, Highlighted(_), Up)                 |
                (_, Clicked(_), Up)                     => State(Highlighted(over_elem), Captured(p_idx, p_x)),
                (_, Highlighted(p_elem), Down)          |
                (_, Clicked(p_elem), Down)              => State(Clicked(p_elem), Captured(p_idx, p_x)),
                _                                       => prev_box_state,
            }
        },
    }
}

/// Draw the text cursor.
fn draw_cursor<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    color: Color,
    cursor_x: f64,
    pad_pos_y: f64,
    pad_h: f64
) {
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    let Color(color) = color.plain_contrast();
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    graphics::Line::round([r, g, b, (a * (precise_time_s() * 2.5).sin() as f32).abs()], 0.5f64)
        .draw(
            [cursor_x, pad_pos_y, cursor_x, pad_pos_y + pad_h],
            draw_state,
            transform,
            graphics
        );
}

/// A context on which the builder pattern can be implemented.
pub struct TextBox<'a, F> {
    ui_id: UIID,
    text: &'a mut String,
    font_size: u32,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
}

impl<'a, F> TextBox<'a, F> {
    pub fn font_size(self, font_size: FontSize) -> TextBox<'a, F> {
        TextBox { font_size: font_size, ..self }
    }
}

impl<'a, F> TextBox<'a, F> {
    /// Initialise a TextBoxContext.
    pub fn new(ui_id: UIID, text: &'a mut String) -> TextBox<'a, F> {
        TextBox {
            ui_id: ui_id,
            text: text,
            font_size: 24, // Default font_size.
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
        }
    }
}

quack! {
    tb: TextBox['a, F]
    get:
        fn () -> Size [] { Size(tb.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(
                Widget::TextBox(State(DrawState::Normal, Capturing::Uncaptured))
            )
        }
        fn () -> Id [] { Id(tb.ui_id) }
    set:
        fn (val: Color) [] { tb.maybe_color = Some(val) }
        fn (val: Callback<F>) [where F: FnMut(&mut String) + 'a] {
            tb.maybe_callback = Some(val.0)
        }
        fn (val: FrameColor) [] { tb.maybe_frame_color = Some(val.0) }
        fn (val: FrameWidth) [] { tb.maybe_frame = Some(val.0) }
        fn (val: Position) [] { tb.pos = val.0 }
        fn (val: Size) [] { tb.dim = val.0 }
    action:
}

impl<'a, F> ::draw::Drawable for TextBox<'a, F>
    where
        F: FnMut(&mut String) + 'a
{

    #[inline]
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let mouse = uic.get_mouse_state();
        let state = *get_state(uic, self.ui_id);

        // Rect.
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        let pad_pos = vec2_add(self.pos, [frame_w; 2]);
        let pad_dim = vec2_sub(self.dim, [frame_w2; 2]);
        let text_x = pad_pos[0] + TEXT_PADDING;
        let text_y = pad_pos[1] + (pad_dim[1] - self.font_size as f64) / 2.0;
        let text_pos = [text_x, text_y];
        let text_w = label::width(uic, self.font_size, &self.text);
        let over_elem = over_elem(uic, self.pos, mouse.pos, self.dim,
                                  pad_pos, pad_dim, text_pos, text_w,
                                  self.font_size, &self.text);
        let new_state = get_new_state(over_elem, state, mouse);

        rectangle::draw(uic.win_w, uic.win_h, graphics, new_state.as_rectangle_state(),
                        self.pos, self.dim, maybe_frame, color);
        uic.draw_text(graphics, text_pos, self.font_size,
                           color.plain_contrast(), &self.text);

        let new_state = match new_state { State(w_state, capturing) => match capturing {
            Capturing::Uncaptured => new_state,
            Capturing::Captured(idx, cursor_x) => {
                let (idx, cursor_x) = update_cursor_position(uic, idx, text_x, self.font_size, &self.text);
                draw_cursor(uic.win_w, uic.win_h, graphics, color,
                            cursor_x, pad_pos[1], pad_dim[1]);
                let mut new_idx = idx;
                let mut new_cursor_x = cursor_x;

                // Check for entered text.
                let entered_text = uic.get_entered_text();
                for t in entered_text.iter() {
                    let mut entered_text_width = 0.0;
                    for ch in t[..].chars() {
                        let c = uic.get_character(self.font_size, ch);
                        entered_text_width += c.width();
                    }
                    if new_cursor_x + entered_text_width < pad_pos[0] + pad_dim[0] - TEXT_PADDING {
                        new_cursor_x += entered_text_width;
                    }
                    else {
                        break;
                    }
                    let new_text = format!("{}{}{}", &self.text[..idx], t, &self.text[idx..]);
                    *self.text = new_text;
                    new_idx += t.len();
                }

                // Check for control keys.
                let pressed_keys = uic.get_pressed_keys();
                for key in pressed_keys.iter() {
                    match *key {
                        Backspace => {
                            if self.text.len() > 0
                            && self.text.len() >= idx
                            && idx > 0 {
                                let rem_idx = idx - 1;
                                new_cursor_x -= uic.get_character_w(
                                    self.font_size, self.text[..].char_at(rem_idx)
                                );
                                let new_text = format!("{}{}", &self.text[..rem_idx], &self.text[idx..]);
                                *self.text = new_text;
                                new_idx = rem_idx;
                            }
                        },
                        Left => {
                            if idx > 0 {
                                new_cursor_x -= uic.get_character_w(
                                    self.font_size, self.text[..].char_at(idx - 1)
                                );
                                new_idx -= 1;
                            }
                        },
                        Right => {
                            if self.text.len() > idx {
                                new_cursor_x += uic.get_character_w(
                                    self.font_size, self.text[..].char_at(idx)
                                );
                                new_idx += 1;
                            }
                        },
                        Return => if self.text.len() > 0 {
                            let TextBox { // borrowck
                                ref mut maybe_callback,
                                ref font_size,
                                ref mut text,
                                ..
                            } = *self;
                            match *maybe_callback {
                                Some(ref mut callback) => {
                                    (*callback)(*text);

                                    new_idx = cmp::min(new_idx, text.len());
                                    let text = &*text;
                                    new_cursor_x = text.chars()
                                                       // Add text_pos.x for padding
                                                       .fold(text_pos[0], |acc, c| {
                                        acc + uic.get_character_w(*font_size, c)
                                    });
                                },
                                None => (),
                            }
                        },
                        _ => (),
                    }
                }

                State(w_state, Capturing::Captured(new_idx, new_cursor_x))
            },
        }};

        set_state(uic, self.ui_id, Widget::TextBox(new_state), self.pos, self.dim);

    }
}
<commit_msg>remove CursorX from Capturing<commit_after>use color::Color;
use dimensions::Dimensions;
use graphics;
use graphics::{
    Graphics,
};
use graphics::character::CharacterCache;
use label;
use label::FontSize;
use mouse::Mouse;
use piston::input::keyboard::Key::{
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use std::num::Float;
use clock_ticks::precise_time_s;
use ui_context::{
    Id,
    UIID,
    UiContext,
};
use vecmath::{
    vec2_add,
    vec2_sub,
};
use widget::{ DefaultWidgetState, Widget };
use std::cmp;
use Callback;
use FrameColor;
use FrameWidth;
use Position;
use Size;

pub type Idx = usize;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct State(DrawState, Capturing);

/// Represents the next tier of state.
#[derive(Debug, PartialEq, Clone,Copy)]
pub enum DrawState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx),
}

/// Represents an element of the TextBox widget.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Capturing::Captured(_) => rectangle::State::Normal,
                Capturing::Uncaptured => match state {
                    DrawState::Normal => rectangle::State::Normal,
                    DrawState::Highlighted(_) => rectangle::State::Highlighted,
                    DrawState::Clicked(_) => rectangle::State::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, Widget::TextBox(State(DrawState::Normal, Capturing::Uncaptured)));

static TEXT_PADDING: f64 = 5f64;

// if the index is 0 return (0, the start of the text)
// until we reach the each index we start with iterate over the characters character in the string
//   if the

/// Calculate the index and x position for a text box cursor.
fn update_cursor_position<C: CharacterCache>(uic: &mut UiContext<C>,
                          mut idx: usize,
                          mut text_x: f64,
                          font_size: FontSize,
                          text: &str) -> (Idx, CursorX) {
    if idx == 0 { return (0, text_x); }
    let text_len = text.len();
    if idx > text_len { idx = text_len; }
    for (i, ch) in text.chars().enumerate() {
        if i >= idx { break; }
        text_x += uic.get_character(font_size, ch).width();
    }
    (idx, text_x)
}

/// Check if cursor is over the pad and if so, which
fn over_elem<C: CharacterCache>(uic: &mut UiContext<C>,
             pos: Point,
             mouse_pos: Point,
             rect_dim: Dimensions,
             pad_pos: Point,
             pad_dim: Dimensions,
             text_pos: Point,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_dim) {
        false => Element::Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_dim) {
            false => Element::Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, text_pos[0], text_w, font_size, text);
                Element::Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx<C: CharacterCache>(uic: &mut UiContext<C>,
               mouse_pos: Point,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos[0] <= text_x { return (0, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = character.width();
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos[0] > left_x && mouse_pos[0] < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::Capturing::{Uncaptured, Captured};
    use self::DrawState::{Normal, Highlighted, Clicked};
    use self::Element::{Nill, Text};
    match prev_box_state {
        State(prev, Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, Normal, Down)                       => State(Normal, Uncaptured),
                (Nill, Normal, Up)                      |
                (Nill, Highlighted(_), Up)              => State(Normal, Uncaptured),
                (_, Normal, Up)                         |
                (_, Highlighted(_), Up)                 => State(Highlighted(over_elem), Uncaptured),
                (_, Highlighted(p_elem), Down)          |
                (_, Clicked(p_elem), Down)              => State(Clicked(p_elem), Uncaptured),
                (Text(idx, _), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx)),
                (Nill, _, _)                            => State(Normal, Uncaptured),
                _                                       => prev_box_state,
            }
        },
        State(prev, Captured(p_idx)) => {
            match (over_elem, prev, mouse.left) {
                (Nill, Clicked(Nill), Up)               => State(Normal, Uncaptured),
                (Text(idx, _), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx)),
                (_, Normal, Up)                         |
                (_, Highlighted(_), Up)                 |
                (_, Clicked(_), Up)                     => State(Highlighted(over_elem), Captured(p_idx)),
                (_, Highlighted(p_elem), Down)          |
                (_, Clicked(p_elem), Down)              => State(Clicked(p_elem), Captured(p_idx)),
                _                                       => prev_box_state,
            }
        },
    }
}

/// Draw the text cursor.
fn draw_cursor<B: Graphics>(
    win_w: f64,
    win_h: f64,
    graphics: &mut B,
    color: Color,
    cursor_x: f64,
    pad_pos_y: f64,
    pad_h: f64
) {
    let draw_state = graphics::default_draw_state();
    let transform = graphics::abs_transform(win_w, win_h);
    let Color(color) = color.plain_contrast();
    let (r, g, b, a) = (color[0], color[1], color[2], color[3]);
    graphics::Line::round([r, g, b, (a * (precise_time_s() * 2.5).sin() as f32).abs()], 0.5f64)
        .draw(
            [cursor_x, pad_pos_y, cursor_x, pad_pos_y + pad_h],
            draw_state,
            transform,
            graphics
        );
}

/// A context on which the builder pattern can be implemented.
pub struct TextBox<'a, F> {
    ui_id: UIID,
    text: &'a mut String,
    font_size: u32,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
}

impl<'a, F> TextBox<'a, F> {
    pub fn font_size(self, font_size: FontSize) -> TextBox<'a, F> {
        TextBox { font_size: font_size, ..self }
    }
}

impl<'a, F> TextBox<'a, F> {
    /// Initialise a TextBoxContext.
    pub fn new(ui_id: UIID, text: &'a mut String) -> TextBox<'a, F> {
        TextBox {
            ui_id: ui_id,
            text: text,
            font_size: 24, // Default font_size.
            pos: [0.0, 0.0],
            dim: [192.0, 48.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
        }
    }
}

quack! {
    tb: TextBox['a, F]
    get:
        fn () -> Size [] { Size(tb.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(
                Widget::TextBox(State(DrawState::Normal, Capturing::Uncaptured))
            )
        }
        fn () -> Id [] { Id(tb.ui_id) }
    set:
        fn (val: Color) [] { tb.maybe_color = Some(val) }
        fn (val: Callback<F>) [where F: FnMut(&mut String) + 'a] {
            tb.maybe_callback = Some(val.0)
        }
        fn (val: FrameColor) [] { tb.maybe_frame_color = Some(val.0) }
        fn (val: FrameWidth) [] { tb.maybe_frame = Some(val.0) }
        fn (val: Position) [] { tb.pos = val.0 }
        fn (val: Size) [] { tb.dim = val.0 }
    action:
}

impl<'a, F> ::draw::Drawable for TextBox<'a, F>
    where
        F: FnMut(&mut String) + 'a
{

    #[inline]
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let mouse = uic.get_mouse_state();
        let state = *get_state(uic, self.ui_id);

        // Rect.
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let frame_w2 = frame_w * 2.0;
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        let pad_pos = vec2_add(self.pos, [frame_w; 2]);
        let pad_dim = vec2_sub(self.dim, [frame_w2; 2]);
        let text_x = pad_pos[0] + TEXT_PADDING;
        let text_y = pad_pos[1] + (pad_dim[1] - self.font_size as f64) / 2.0;
        let text_pos = [text_x, text_y];
        let text_w = label::width(uic, self.font_size, &self.text);
        let over_elem = over_elem(uic, self.pos, mouse.pos, self.dim,
                                  pad_pos, pad_dim, text_pos, text_w,
                                  self.font_size, &self.text);
        let new_state = get_new_state(over_elem, state, mouse);

        rectangle::draw(uic.win_w, uic.win_h, graphics, new_state.as_rectangle_state(),
                        self.pos, self.dim, maybe_frame, color);
        uic.draw_text(graphics, text_pos, self.font_size,
                           color.plain_contrast(), &self.text);

        let new_state = match new_state { State(w_state, capturing) => match capturing {
            Capturing::Uncaptured => new_state,
            Capturing::Captured(idx) => {
                let (idx, cursor_x) = update_cursor_position(uic, idx, text_x, self.font_size, &self.text);
                draw_cursor(uic.win_w, uic.win_h, graphics, color,
                            cursor_x, pad_pos[1], pad_dim[1]);
                let mut new_idx = idx;
                let mut new_cursor_x = cursor_x;

                // Check for entered text.
                let entered_text = uic.get_entered_text();
                for t in entered_text.iter() {
                    let mut entered_text_width = 0.0;
                    for ch in t[..].chars() {
                        let c = uic.get_character(self.font_size, ch);
                        entered_text_width += c.width();
                    }
                    if new_cursor_x + entered_text_width < pad_pos[0] + pad_dim[0] - TEXT_PADDING {
                        new_cursor_x += entered_text_width;
                    }
                    else {
                        break;
                    }
                    let new_text = format!("{}{}{}", &self.text[..idx], t, &self.text[idx..]);
                    *self.text = new_text;
                    new_idx += t.len();
                }

                // Check for control keys.
                let pressed_keys = uic.get_pressed_keys();
                for key in pressed_keys.iter() {
                    match *key {
                        Backspace => {
                            if self.text.len() > 0
                            && self.text.len() >= idx
                            && idx > 0 {
                                let rem_idx = idx - 1;
                                new_cursor_x -= uic.get_character_w(
                                    self.font_size, self.text[..].char_at(rem_idx)
                                );
                                let new_text = format!("{}{}", &self.text[..rem_idx], &self.text[idx..]);
                                *self.text = new_text;
                                new_idx = rem_idx;
                            }
                        },
                        Left => {
                            if idx > 0 {
                                new_cursor_x -= uic.get_character_w(
                                    self.font_size, self.text[..].char_at(idx - 1)
                                );
                                new_idx -= 1;
                            }
                        },
                        Right => {
                            if self.text.len() > idx {
                                new_cursor_x += uic.get_character_w(
                                    self.font_size, self.text[..].char_at(idx)
                                );
                                new_idx += 1;
                            }
                        },
                        Return => if self.text.len() > 0 {
                            let TextBox { // borrowck
                                ref mut maybe_callback,
                                ref font_size,
                                ref mut text,
                                ..
                            } = *self;
                            match *maybe_callback {
                                Some(ref mut callback) => {
                                    (*callback)(*text);

                                    new_idx = cmp::min(new_idx, text.len());
                                    let text = &*text;
                                    new_cursor_x = text.chars()
                                                       // Add text_pos.x for padding
                                                       .fold(text_pos[0], |acc, c| {
                                        acc + uic.get_character_w(*font_size, c)
                                    });
                                },
                                None => (),
                            }
                        },
                        _ => (),
                    }
                }

                State(w_state, Capturing::Captured(new_idx))
            },
        }};

        set_state(uic, self.ui_id, Widget::TextBox(new_state), self.pos, self.dim);

    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(not(windows))]
pub mod posix_perm;
pub mod sys;
#[cfg(windows)]
pub mod win_perm;

use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::result;
use std::str::FromStr;

use serde;

pub fn deserialize_using_from_str<'de, T, E, D>(d: D) -> result::Result<T, D::Error>
where
    T: FromStr<Err = E>,
    E: error::Error,
    D: serde::Deserializer<'de>,
{
    struct FromStringable<T, E>(PhantomData<T>, PhantomData<E>);

    impl<'de, T, E> serde::de::Visitor<'de> for FromStringable<T, E>
    where
        T: FromStr<Err = E>,
        E: error::Error,
    {
        type Value = T;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a string")
        }

        fn visit_str<R>(self, value: &str) -> result::Result<T, R>
        where
            R: serde::de::Error,
        {
            match FromStr::from_str(value) {
                Ok(t) => Ok(t),
                Err(err) => Err(R::custom(format!(
                    "string cannot be parsed: \"{}\" ({})",
                    value,
                    err.description()
                ))),
            }
        }
    }

    d.deserialize_any(FromStringable(PhantomData, PhantomData))
}

pub fn serialize_using_to_string<T, S>(t: &T, s: S) -> result::Result<S::Ok, S::Error>
where
    T: ToString,
    S: serde::Serializer,
{
    s.serialize_str(&t.to_string())
}

/// Provide a way to convert numeric types safely to i64
trait ToI64 {
    fn to_i64(self) -> i64;
}

impl ToI64 for usize {
    fn to_i64(self) -> i64 {
        if mem::size_of::<usize>() >= mem::size_of::<i64>() && self > i64::max_value() as usize {
            error!(
                "Tried to convert an out-of-range usize ({}) to i64; using i64::max_value()",
                self
            );
            i64::max_value()
        } else {
            self as i64
        }
    }
}

impl ToI64 for u64 {
    fn to_i64(self) -> i64 {
        if mem::size_of::<u64>() >= mem::size_of::<i64>() && self > i64::max_value() as u64 {
            error!(
                "Tried to convert an out-of-range u64 ({}) to i64; using i64::max_value()",
                self
            );
            i64::max_value()
        } else {
            self as i64
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn conversion_of_usize_to_i64() {
        let too_big = usize::max_value();
        let just_right: usize = 42;
        let zero: usize = 0;

        assert_eq!(too_big.to_i64(), i64::max_value());
        assert_eq!(just_right.to_i64(), 42);
        assert_eq!(zero.to_i64(), 0);
    }

    #[test]
    fn conversion_of_u64_to_i64() {
        let too_big = u64::max_value();
        let just_right: u64 = 42;
        let zero: u64 = 0;

        assert_eq!(too_big.to_i64(), i64::max_value());
        assert_eq!(just_right.to_i64(), 42);
        assert_eq!(zero.to_i64(), 0);
    }
}
<commit_msg>Add a panic! when in debug mode<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[cfg(not(windows))]
pub mod posix_perm;
pub mod sys;
#[cfg(windows)]
pub mod win_perm;

use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::result;
use std::str::FromStr;

use serde;

pub fn deserialize_using_from_str<'de, T, E, D>(d: D) -> result::Result<T, D::Error>
where
    T: FromStr<Err = E>,
    E: error::Error,
    D: serde::Deserializer<'de>,
{
    struct FromStringable<T, E>(PhantomData<T>, PhantomData<E>);

    impl<'de, T, E> serde::de::Visitor<'de> for FromStringable<T, E>
    where
        T: FromStr<Err = E>,
        E: error::Error,
    {
        type Value = T;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("a string")
        }

        fn visit_str<R>(self, value: &str) -> result::Result<T, R>
        where
            R: serde::de::Error,
        {
            match FromStr::from_str(value) {
                Ok(t) => Ok(t),
                Err(err) => Err(R::custom(format!(
                    "string cannot be parsed: \"{}\" ({})",
                    value,
                    err.description()
                ))),
            }
        }
    }

    d.deserialize_any(FromStringable(PhantomData, PhantomData))
}

pub fn serialize_using_to_string<T, S>(t: &T, s: S) -> result::Result<S::Ok, S::Error>
where
    T: ToString,
    S: serde::Serializer,
{
    s.serialize_str(&t.to_string())
}

/// Provide a way to convert numeric types safely to i64
trait ToI64 {
    fn to_i64(self) -> i64;
}

impl ToI64 for usize {
    fn to_i64(self) -> i64 {
        if mem::size_of::<usize>() >= mem::size_of::<i64>() && self > i64::max_value() as usize {
            if cfg!(debug_assertions) {
                panic!("Tried to convert an out-of-range usize ({}) to i64", self);
            } else {
                error!(
                    "Tried to convert an out-of-range usize ({}) to i64; using i64::max_value()",
                    self
                );
                i64::max_value()
            }
        } else {
            self as i64
        }
    }
}

impl ToI64 for u64 {
    fn to_i64(self) -> i64 {
        if self > i64::max_value() as u64 {
            if cfg!(debug_assertions) {
                panic!("Tried to convert an out-of-range u64 ({}) to i64", self);
            } else {
                error!(
                    "Tried to convert an out-of-range u64 ({}) to i64; using i64::max_value()",
                    self
                );
                i64::max_value()
            }
        } else {
            self as i64
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn conversion_of_usize_to_i64() {
        let just_right: usize = 42;
        let zero: usize = 0;

        assert_eq!(just_right.to_i64(), 42);
        assert_eq!(zero.to_i64(), 0);
    }

    #[test]
    #[should_panic]
    #[cfg(debug_assertions)]
    fn conversion_of_too_big_usize_panics_in_debug_mode() {
        let too_big = usize::max_value();
        too_big.to_i64();
    }

    #[test]
    #[cfg(not(debug_assertions))]
    fn conversion_of_too_big_usize_caps_in_release_mode() {
        let too_big = usize::max_value();
        assert_eq!(too_big.to_i64(), i64::max_value());
    }

    #[test]
    fn conversion_of_u64_to_i64() {
        let just_right: u64 = 42;
        let zero: u64 = 0;

        assert_eq!(just_right.to_i64(), 42);
        assert_eq!(zero.to_i64(), 0);
    }

    #[test]
    #[should_panic]
    #[cfg(debug_assertions)]
    fn conversion_of_too_big_u64_panics_in_debug_mode() {
        let too_big = u64::max_value();
        too_big.to_i64();
    }

    #[test]
    #[cfg(not(debug_assertions))]
    fn conversion_of_too_big_u64_caps_in_release_mode() {
        let too_big = u64::max_value();
        assert_eq!(too_big.to_i64(), i64::max_value());
    }
}
<|endoftext|>


<commit_before>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use v2::{camera, mesh, scene, skin, Extras, Index, Root};

/// A node in the node hierarchy.
///
/// * When the node contains `skin`, all `mesh::Primitive`s must contain `"JOINT"`
///   and `"WEIGHT"` attributes.
/// * A node can have either a `matrix` or any combination of
///   `translation`/`rotation`/`scale` (TRS) properties.
/// * TRS properties are converted to matrices and postmultiplied in the
///   `T * R * S` order to compose the transformation matrix; first the scale is
///   applied to the vertices, then the rotation, and then the translation.
/// * If none are provided, the transform is the identity.
/// * When a node is targeted for animation (referenced by an
///   `animation::ChannelTarget`), only TRS properties may be present and `matrix`
///   will not be present.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Node {
    /// The camera referenced by this node.
    pub camera: Option<Index<camera::Camera>>,

    /// The child nodes belonging to this node in the node heirarchy.
    #[serde(default)]
    pub children: Vec<Index<scene::Node>>,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: NodeExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,

    /// 4x4 column-major transformation matrix.
    #[serde(default = "node_matrix_default")]
    pub matrix: [[f32; 4]; 4],

    /// The `Mesh` in this node.
    pub mesh: Option<Index<mesh::Mesh>>,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// The node's unit quaternion rotation `[x, y, z, w]`.
    #[serde(default = "node_rotation_default")]
    pub rotation: [f32; 4],

    #[serde(default = "node_scale_default")]
    /// The node's non-uniform scale.
    pub scale: [f32; 3],

    #[serde(default)]
    /// The node's translation.
    pub translation: [f32; 3],

    /// The index of the skin referenced by this node.
    pub skin: Option<Index<skin::Skin>>,

    /// The weights of the instantiated morph target.
    ///
    /// The number of elements must match the number of morph targets used by the
    /// mesh.
    pub weights: Option<Vec<f32>>,
}

/// Extension specific data for `Node`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct NodeExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

fn node_matrix_default() -> [[f32; 4]; 4] {
    [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]]
}

fn node_rotation_default() -> [f32; 4] {
    [0.0, 0.0, 0.0, 1.0]
}

fn node_scale_default() -> [f32; 3] {
    [1.0, 1.0, 1.0]
}

/// The root `Node`s of a scene.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Scene {
    /// Extension specific data.
    #[serde(default)]
    pub extensions: SceneExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// The indices of each root `Node`.
    #[serde(default)]
    pub nodes: Vec<Index<Node>>,
}

/// Extension specific data for `Scene`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SceneExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

impl Node {
    #[doc(hidden)]
    pub fn range_check(&self, root: &Root) -> Result<(), ()> {
        if let Some(ref camera) = self.camera {
            let _ = root.try_get(&camera)?;
            for node in &self.children {
                let _ = root.try_get(node)?;
            }
        }
        if let Some(ref mesh) = self.mesh {
            let _ = root.try_get(mesh)?;
        }
        if let Some(ref skin) = self.skin {
            let _ = root.try_get(skin)?;
        }
        Ok(())
    }
}

impl Scene {
    #[doc(hidden)]
    pub fn range_check(&self, root: &Root) -> Result<(), ()> {
        for node in &self.nodes {
            let _ = root.try_get(node)?;
        }
        Ok(())
    }
}
<commit_msg>fix node matrix<commit_after>
// Copyright 2017 The gltf Library Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use v2::{camera, mesh, scene, skin, Extras, Index, Root};

/// A node in the node hierarchy.
///
/// * When the node contains `skin`, all `mesh::Primitive`s must contain `"JOINT"`
///   and `"WEIGHT"` attributes.
/// * A node can have either a `matrix` or any combination of
///   `translation`/`rotation`/`scale` (TRS) properties.
/// * TRS properties are converted to matrices and postmultiplied in the
///   `T * R * S` order to compose the transformation matrix; first the scale is
///   applied to the vertices, then the rotation, and then the translation.
/// * If none are provided, the transform is the identity.
/// * When a node is targeted for animation (referenced by an
///   `animation::ChannelTarget`), only TRS properties may be present and `matrix`
///   will not be present.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Node {
    /// The camera referenced by this node.
    pub camera: Option<Index<camera::Camera>>,

    /// The child nodes belonging to this node in the node heirarchy.
    #[serde(default)]
    pub children: Vec<Index<scene::Node>>,

    /// Extension specific data.
    #[serde(default)]
    pub extensions: NodeExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,

    /// 4x4 column-major transformation matrix.
    #[serde(default = "node_matrix_default")]
    pub matrix: [f32; 16],

    /// The `Mesh` in this node.
    pub mesh: Option<Index<mesh::Mesh>>,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// The node's unit quaternion rotation `[x, y, z, w]`.
    #[serde(default = "node_rotation_default")]
    pub rotation: [f32; 4],

    #[serde(default = "node_scale_default")]
    /// The node's non-uniform scale.
    pub scale: [f32; 3],

    #[serde(default)]
    /// The node's translation.
    pub translation: [f32; 3],

    /// The index of the skin referenced by this node.
    pub skin: Option<Index<skin::Skin>>,

    /// The weights of the instantiated morph target.
    ///
    /// The number of elements must match the number of morph targets used by the
    /// mesh.
    pub weights: Option<Vec<f32>>,
}

/// Extension specific data for `Node`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct NodeExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

fn node_matrix_default() -> [f32; 16] {
    [1.0, 0.0, 0.0, 0.0,
     0.0, 1.0, 0.0, 0.0,
     0.0, 0.0, 1.0, 0.0,
     0.0, 0.0, 0.0, 1.0]
}

fn node_rotation_default() -> [f32; 4] {
    [0.0, 0.0, 0.0, 1.0]
}

fn node_scale_default() -> [f32; 3] {
    [1.0, 1.0, 1.0]
}

/// The root `Node`s of a scene.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Scene {
    /// Extension specific data.
    #[serde(default)]
    pub extensions: SceneExtensions,

    /// Optional application specific data.
    #[serde(default)]
    pub extras: Extras,

    /// Optional user-defined name for this object.
    pub name: Option<String>,

    /// The indices of each root `Node`.
    #[serde(default)]
    pub nodes: Vec<Index<Node>>,
}

/// Extension specific data for `Scene`.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SceneExtensions {
    #[serde(default)]
    _allow_extra_fields: (),
}

impl Node {
    #[doc(hidden)]
    pub fn range_check(&self, root: &Root) -> Result<(), ()> {
        if let Some(ref camera) = self.camera {
            let _ = root.try_get(&camera)?;
            for node in &self.children {
                let _ = root.try_get(node)?;
            }
        }
        if let Some(ref mesh) = self.mesh {
            let _ = root.try_get(mesh)?;
        }
        if let Some(ref skin) = self.skin {
            let _ = root.try_get(skin)?;
        }
        Ok(())
    }
}

impl Scene {
    #[doc(hidden)]
    pub fn range_check(&self, root: &Root) -> Result<(), ()> {
        for node in &self.nodes {
            let _ = root.try_get(node)?;
        }
        Ok(())
    }
}
<|endoftext|>