<commit_before>extern crate pkg_config;
extern crate cmake;
extern crate gcc;

fn main() {
    // Build IlmBase
    let ilmbase_dst = cmake::Config::new("openexr/IlmBase")
        .define("BUILD_SHARED_LIBS", "OFF")
        .build();
    println!("cargo:rustc-link-search=native={}", ilmbase_dst.join("lib").display());

    // Build OpenEXR
    let openexr_dst = cmake::Config::new("openexr/OpenEXR")
        .define("ILMBASE_PACKAGE_PREFIX", &ilmbase_dst)
        .define("BUILD_SHARED_LIBS", "OFF")
        .build();
    println!("cargo:rustc-link-search=native={}", openexr_dst.join("lib").display());
    let exr_include_path = openexr_dst.join("include");

    // Build C wrapper for OpenEXR
    gcc::Config::new()
                .cpp(true)
                .flag("-std=c++11")
                .include("c_wrapper")
                .include(&exr_include_path)
                .file("c_wrapper/cexr.cpp")
                .file("c_wrapper/memory_istream.cpp")
                .compile("libcexr.a");

    // Link all the libs from OpenEXR
    println!("cargo:rustc-link-lib=static=IlmImf-2_2");
    println!("cargo:rustc-link-lib=static=IlmImfUtil-2_2");
    println!("cargo:rustc-link-lib=static=IexMath-2_2");
    println!("cargo:rustc-link-lib=static=Iex-2_2");
    println!("cargo:rustc-link-lib=static=Imath-2_2");
    println!("cargo:rustc-link-lib=static=IlmThread-2_2");
    println!("cargo:rustc-link-lib=static=Half");

    // Find and link zlib, needed for OpenEXR
    pkg_config::probe_library("zlib").unwrap();
}
<commit_msg>Support using system OpenEXR and IlmBase<commit_after>extern crate pkg_config;
extern crate cmake;
extern crate gcc;

use std::env;

fn main() {
    let include_paths = if env::var("USE_SYSTEM_OPENEXR").map(|x| x != "0").unwrap_or(false) {
        // We don't take linker flags from IlmBase because OpenEXR's subsume them.
        let ilm = pkg_config::Config::new().cargo_metadata(false).probe("IlmBase").unwrap();
        let exr = pkg_config::probe_library("OpenEXR").unwrap();
        let mut include_paths = ilm.include_paths.clone();
        include_paths.extend_from_slice(&exr.include_paths);
        include_paths
    } else {
        // Build IlmBase
        let ilmbase_dst = cmake::Config::new("openexr/IlmBase")
            .define("BUILD_SHARED_LIBS", "OFF")
            .build();
        println!("cargo:rustc-link-search=native={}", ilmbase_dst.join("lib").display());

        // Build OpenEXR
        let openexr_dst = cmake::Config::new("openexr/OpenEXR")
            .define("ILMBASE_PACKAGE_PREFIX", &ilmbase_dst)
            .define("BUILD_SHARED_LIBS", "OFF")
            .build();
        println!("cargo:rustc-link-search=native={}", openexr_dst.join("lib").display());

        // Link all the libs from OpenEXR
        println!("cargo:rustc-link-lib=static=IlmImf-2_2");
        println!("cargo:rustc-link-lib=static=IlmImfUtil-2_2");
        println!("cargo:rustc-link-lib=static=IexMath-2_2");
        println!("cargo:rustc-link-lib=static=Iex-2_2");
        println!("cargo:rustc-link-lib=static=Imath-2_2");
        println!("cargo:rustc-link-lib=static=IlmThread-2_2");
        println!("cargo:rustc-link-lib=static=Half");

        vec![openexr_dst.join("include")]
    };

    // Build C wrapper for OpenEXR
    let mut gcc = gcc::Config::new();
    gcc.cpp(true)
        .flag("-std=c++11")
        .include("c_wrapper");
    for path in &include_paths {
        gcc.include(path);
    }
    gcc.file("c_wrapper/cexr.cpp")
        .file("c_wrapper/memory_istream.cpp")
        .compile("libcexr.a");

    // Find and link zlib, needed for OpenEXR
    pkg_config::probe_library("zlib").unwrap();
}
<|endoftext|>


<commit_before>use super::{EdgeKey, FaceKey, Features, Mesh};
use crate::shapes::{Shape, StateOfShape};
use crate::StrError;
use russell_lab::Vector;

/// Holds data to evaluate normal vectors at edge or face
#[derive(Clone, Debug)]
pub struct NormalVector {
    /// Holds the Shape data for a given boundary edge or face
    pub shape: Shape,

    /// Holds the state for the Shape data corresponding to an edge or face
    pub state: StateOfShape,

    /// Holds the normal vector output from the evaluate function
    pub value: Vector,
}

impl NormalVector {
    /// Allocates data to compute normal vector at edge
    ///
    /// **Important:** You must call [NormalVector::evaluate] to compute the actual values.
    ///
    /// **Note:** This function works in 2D only
    pub fn at_edge(mesh: &Mesh, features: &Features, edge_key: EdgeKey) -> Result<Self, StrError> {
        if mesh.space_ndim != 2 {
            return Err("normal at_edge works in 2D only");
        }
        const GEO_NDIM: usize = 1;
        let edge = match features.edges.get(&edge_key) {
            Some(e) => e,
            None => return Err("edge_key is not present in boundary"),
        };
        let shape = Shape::new(mesh.space_ndim, GEO_NDIM, edge.points.len())?;
        let state = StateOfShape::new(
            GEO_NDIM,
            &edge
                .points
                .iter()
                .map(|id| mesh.points[*id].coords.clone())
                .collect::<Vec<_>>(),
        )?;
        Ok(NormalVector {
            shape,
            state,
            value: Vector::new(mesh.space_ndim),
        })
    }

    /// Allocates data to compute normal vector at face
    ///
    /// **Important:** You must call [NormalVector::evaluate] to compute the actual values.
    ///
    /// **Note:** This function works in 3D only
    pub fn at_face(mesh: &Mesh, features: &Features, face_key: FaceKey) -> Result<Self, StrError> {
        if mesh.space_ndim != 3 {
            return Err("normal at_face works in 3D only");
        }
        const GEO_NDIM: usize = 2;
        let face = match features.faces.get(&face_key) {
            Some(e) => e,
            None => return Err("face_key is not present in boundary"),
        };
        let shape = Shape::new(mesh.space_ndim, GEO_NDIM, face.points.len())?;
        let state = StateOfShape::new(
            GEO_NDIM,
            &face
                .points
                .iter()
                .map(|id| mesh.points[*id].coords.clone())
                .collect::<Vec<_>>(),
        )?;
        Ok(NormalVector {
            shape,
            state,
            value: Vector::new(mesh.space_ndim),
        })
    }

    /// Evaluates boundary normal
    ///
    /// # Input
    ///
    /// * `ksi` -- ξ reference coordinate. The length of ξ must be equal to geo_ndim at least,
    ///            while lengths greater than geo_ndim are allowed (and ignored). In this way,
    ///            we can pass a slice with integration point data such as `[f64; 4]`.
    pub fn evaluate(&mut self, ksi: &[f64]) -> Result<(), StrError> {
        self.shape.calc_boundary_normal(&mut self.value, &mut self.state, ksi)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {}
<commit_msg>Rename normal vector<commit_after>use super::{EdgeKey, FaceKey, Features, Mesh};
use crate::shapes::{Shape, StateOfShape};
use crate::StrError;
use russell_lab::Vector;

/// Holds data to evaluate normal vectors at edge or face
#[derive(Clone, Debug)]
pub struct NormalVector {
    /// Holds the Shape data for a given boundary edge or face
    pub shape: Shape,

    /// Holds the state for the Shape data corresponding to an edge or face
    pub state: StateOfShape,

    /// Holds the normal vector output from the evaluate function
    pub normal: Vector,
}

impl NormalVector {
    /// Allocates data to compute normal vector at edge
    ///
    /// **Important:** You must call [NormalVector::evaluate] to compute the actual values.
    ///
    /// **Note:** This function works in 2D only
    pub fn at_edge(mesh: &Mesh, features: &Features, edge_key: EdgeKey) -> Result<Self, StrError> {
        if mesh.space_ndim != 2 {
            return Err("normal at_edge works in 2D only");
        }
        const GEO_NDIM: usize = 1;
        let edge = match features.edges.get(&edge_key) {
            Some(e) => e,
            None => return Err("edge_key is not present in boundary"),
        };
        let shape = Shape::new(mesh.space_ndim, GEO_NDIM, edge.points.len())?;
        let state = StateOfShape::new(
            GEO_NDIM,
            &edge
                .points
                .iter()
                .map(|id| mesh.points[*id].coords.clone())
                .collect::<Vec<_>>(),
        )?;
        Ok(NormalVector {
            shape,
            state,
            normal: Vector::new(mesh.space_ndim),
        })
    }

    /// Allocates data to compute normal vector at face
    ///
    /// **Important:** You must call [NormalVector::evaluate] to compute the actual values.
    ///
    /// **Note:** This function works in 3D only
    pub fn at_face(mesh: &Mesh, features: &Features, face_key: FaceKey) -> Result<Self, StrError> {
        if mesh.space_ndim != 3 {
            return Err("normal at_face works in 3D only");
        }
        const GEO_NDIM: usize = 2;
        let face = match features.faces.get(&face_key) {
            Some(e) => e,
            None => return Err("face_key is not present in boundary"),
        };
        let shape = Shape::new(mesh.space_ndim, GEO_NDIM, face.points.len())?;
        let state = StateOfShape::new(
            GEO_NDIM,
            &face
                .points
                .iter()
                .map(|id| mesh.points[*id].coords.clone())
                .collect::<Vec<_>>(),
        )?;
        Ok(NormalVector {
            shape,
            state,
            normal: Vector::new(mesh.space_ndim),
        })
    }

    /// Evaluates boundary normal
    ///
    /// # Input
    ///
    /// * `ksi` -- ξ reference coordinate. The length of ξ must be equal to geo_ndim at least,
    ///            while lengths greater than geo_ndim are allowed (and ignored). In this way,
    ///            we can pass a slice with integration point data such as `[f64; 4]`.
    pub fn evaluate(&mut self, ksi: &[f64]) -> Result<(), StrError> {
        self.shape.calc_boundary_normal(&mut self.normal, &mut self.state, ksi)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support bind()

use std::time::Duration;
use tokio::io::{self, copy_bidirectional, AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio::task::JoinHandle;

async fn make_socketpair() -> (TcpStream, TcpStream) {
    let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
    let addr = listener.local_addr().unwrap();
    let connector = TcpStream::connect(addr);
    let acceptor = listener.accept();

    let (c1, c2) = tokio::join!(connector, acceptor);

    (c1.unwrap(), c2.unwrap().0)
}

async fn block_write(s: &mut TcpStream) -> usize {
    static BUF: [u8; 2048] = [0; 2048];

    let mut copied = 0;
    loop {
        tokio::select! {
            result = s.write(&BUF) => {
                copied += result.expect("write error")
            },
            _ = tokio::time::sleep(Duration::from_millis(10)) => {
                break;
            }
        }
    }

    copied
}

async fn symmetric<F, Fut>(mut cb: F)
where
    F: FnMut(JoinHandle<io::Result<(u64, u64)>>, TcpStream, TcpStream) -> Fut,
    Fut: std::future::Future<Output = ()>,
{
    // We run the test twice, with streams passed to copy_bidirectional in
    // different orders, in order to ensure that the two arguments are
    // interchangeable.

    let (a, mut a1) = make_socketpair().await;
    let (b, mut b1) = make_socketpair().await;

    let handle = tokio::spawn(async move { copy_bidirectional(&mut a1, &mut b1).await });
    cb(handle, a, b).await;

    let (a, mut a1) = make_socketpair().await;
    let (b, mut b1) = make_socketpair().await;

    let handle = tokio::spawn(async move { copy_bidirectional(&mut b1, &mut a1).await });

    cb(handle, b, a).await;
}

#[tokio::test]
async fn test_basic_transfer() {
    symmetric(|_handle, mut a, mut b| async move {
        a.write_all(b"test").await.unwrap();
        let mut tmp = [0; 4];
        b.read_exact(&mut tmp).await.unwrap();
        assert_eq!(&tmp[..], b"test");
    })
    .await
}

#[tokio::test]
async fn test_transfer_after_close() {
    symmetric(|handle, mut a, mut b| async move {
        AsyncWriteExt::shutdown(&mut a).await.unwrap();
        b.read_to_end(&mut Vec::new()).await.unwrap();

        b.write_all(b"quux").await.unwrap();
        let mut tmp = [0; 4];
        a.read_exact(&mut tmp).await.unwrap();
        assert_eq!(&tmp[..], b"quux");

        // Once both are closed, we should have our handle back
        drop(b);

        assert_eq!(handle.await.unwrap().unwrap(), (0, 4));
    })
    .await
}

#[tokio::test]
async fn blocking_one_side_does_not_block_other() {
    symmetric(|handle, mut a, mut b| async move {
        block_write(&mut a).await;

        b.write_all(b"quux").await.unwrap();
        let mut tmp = [0; 4];
        a.read_exact(&mut tmp).await.unwrap();
        assert_eq!(&tmp[..], b"quux");

        AsyncWriteExt::shutdown(&mut a).await.unwrap();

        let mut buf = Vec::new();
        b.read_to_end(&mut buf).await.unwrap();

        drop(b);

        assert_eq!(handle.await.unwrap().unwrap(), (buf.len() as u64, 4));
    })
    .await
}

#[tokio::test]
async fn immediate_exit_on_error() {
    symmetric(|handle, mut a, mut b| async move {
        block_write(&mut a).await;

        // Fill up the b->copy->a path. We expect that this will _not_ drain
        // before we exit the copy task.
        let _bytes_written = block_write(&mut b).await;

        // Drop b. We should not wait for a to consume the data buffered in the
        // copy loop, since b will be failing writes.
        drop(b);
        assert!(handle.await.unwrap().is_err());
    })
    .await
}
<commit_msg>io: rewrite `immediate_exit_on_error` test to use `io::Mock` (#4984)<commit_after>#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))] // Wasi does not support bind()

use std::time::Duration;
use tokio::io::{self, copy_bidirectional, AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpStream;
use tokio::task::JoinHandle;

async fn make_socketpair() -> (TcpStream, TcpStream) {
    let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
    let addr = listener.local_addr().unwrap();
    let connector = TcpStream::connect(addr);
    let acceptor = listener.accept();

    let (c1, c2) = tokio::join!(connector, acceptor);

    (c1.unwrap(), c2.unwrap().0)
}

async fn block_write(s: &mut TcpStream) -> usize {
    static BUF: [u8; 2048] = [0; 2048];

    let mut copied = 0;
    loop {
        tokio::select! {
            result = s.write(&BUF) => {
                copied += result.expect("write error")
            },
            _ = tokio::time::sleep(Duration::from_millis(10)) => {
                break;
            }
        }
    }

    copied
}

async fn symmetric<F, Fut>(mut cb: F)
where
    F: FnMut(JoinHandle<io::Result<(u64, u64)>>, TcpStream, TcpStream) -> Fut,
    Fut: std::future::Future<Output = ()>,
{
    // We run the test twice, with streams passed to copy_bidirectional in
    // different orders, in order to ensure that the two arguments are
    // interchangeable.

    let (a, mut a1) = make_socketpair().await;
    let (b, mut b1) = make_socketpair().await;

    let handle = tokio::spawn(async move { copy_bidirectional(&mut a1, &mut b1).await });
    cb(handle, a, b).await;

    let (a, mut a1) = make_socketpair().await;
    let (b, mut b1) = make_socketpair().await;

    let handle = tokio::spawn(async move { copy_bidirectional(&mut b1, &mut a1).await });

    cb(handle, b, a).await;
}

#[tokio::test]
async fn test_basic_transfer() {
    symmetric(|_handle, mut a, mut b| async move {
        a.write_all(b"test").await.unwrap();
        let mut tmp = [0; 4];
        b.read_exact(&mut tmp).await.unwrap();
        assert_eq!(&tmp[..], b"test");
    })
    .await
}

#[tokio::test]
async fn test_transfer_after_close() {
    symmetric(|handle, mut a, mut b| async move {
        AsyncWriteExt::shutdown(&mut a).await.unwrap();
        b.read_to_end(&mut Vec::new()).await.unwrap();

        b.write_all(b"quux").await.unwrap();
        let mut tmp = [0; 4];
        a.read_exact(&mut tmp).await.unwrap();
        assert_eq!(&tmp[..], b"quux");

        // Once both are closed, we should have our handle back
        drop(b);

        assert_eq!(handle.await.unwrap().unwrap(), (0, 4));
    })
    .await
}

#[tokio::test]
async fn blocking_one_side_does_not_block_other() {
    symmetric(|handle, mut a, mut b| async move {
        block_write(&mut a).await;

        b.write_all(b"quux").await.unwrap();
        let mut tmp = [0; 4];
        a.read_exact(&mut tmp).await.unwrap();
        assert_eq!(&tmp[..], b"quux");

        AsyncWriteExt::shutdown(&mut a).await.unwrap();

        let mut buf = Vec::new();
        b.read_to_end(&mut buf).await.unwrap();

        drop(b);

        assert_eq!(handle.await.unwrap().unwrap(), (buf.len() as u64, 4));
    })
    .await
}

#[tokio::test]
async fn immediate_exit_on_write_error() {
    let payload = b"here, take this";
    let error = || io::Error::new(io::ErrorKind::Other, "no thanks!");

    let mut a = tokio_test::io::Builder::new()
        .read(payload)
        .write_error(error())
        .build();

    let mut b = tokio_test::io::Builder::new()
        .read(payload)
        .write_error(error())
        .build();

    assert!(copy_bidirectional(&mut a, &mut b).await.is_err());
}

#[tokio::test]
async fn immediate_exit_on_read_error() {
    let error = || io::Error::new(io::ErrorKind::Other, "got nothing!");

    let mut a = tokio_test::io::Builder::new().read_error(error()).build();

    let mut b = tokio_test::io::Builder::new().read_error(error()).build();

    assert!(copy_bidirectional(&mut a, &mut b).await.is_err());
}
<|endoftext|>


<commit_before>
#![feature(phase)]

#[phase(plugin, link)]
extern crate conrod;
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use sdl2_game_window::GameWindowSDL2;
use opengl_graphics::Gl;
use piston::{
    Game,
    GameEvent,
    GameWindowSettings,
    GameIterator,
    GameIteratorSettings,
    RenderArgs,
    Render,
};
use conrod::{
    button,
    drop_down_list,
    label,
    number_dialer,
    slider,
    toggle,
    widget_matrix,
    Color,
    Point,
    Frame,
    UIContext,
};
use conrod::label::{
    Label,
    NoLabel,
};
use graphics::{
    Context,
    AddColor,
    Draw,
};

fn main() {

    // Create a SDL2 window.
    let mut window = GameWindowSDL2::new(
        GameWindowSettings {
            title: "Hello Conrod".to_string(),
            size: [860, 600],
            fullscreen: false,
            exit_on_esc: true
        }
    );

    // Some settings for how the game should be run.
    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 180,
        max_frames_per_second: 60
    };

    // Create GameIterator to begin the event iteration loop.
    let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
    // Create OpenGL instance.
    let mut gl = Gl::new();
    // Create the UIContext and specify the name of a font that's in our "assets" directory.
    let mut uic = UIContext::new("Dense-Regular.otf");

    // TODO: Put the following vars all in an 'app' struct or something and pass
    // as a mut reference to struct instead.

    // Background color (for demonstration of button and sliders).
    let mut bg_color = Color::new(0.2, 0.35, 0.45, 1.0);
    // Should the button be shown (for demonstration of button).
    let mut show_button = false;
    // The label that will be drawn to the Toggle.
    let mut toggle_label = "OFF".to_string();
    // The number of pixels between the left side of the window and the title.
    let mut title_padding = 50f64;
    // The height of the vertical sliders (we will play with this using a number_dialer).
    let mut v_slider_height = 185f64;
    // The widget frame width (we'll use this to demo Framing and number_dialer).
    let mut frame_width = 1f64;
    // Bool matrix for widget_matrix demonstration.
    let mut bool_matrix = vec![
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, false, false, false, false, false, false, true],
                            vec![true, false, true, false, true, true, true, true],
                            vec![true, false, true, false, true, true, true, true],
                            vec![true, false, false, false, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, false, true, false, false, false, true],
                            vec![true, true, true, true, true, true, true, true],
                            ];
    // A vector of strings for drop_down_list demonstration.
    let mut ddl_colors = vec!["Black".to_string(),
                              "White".to_string(),
                              "Red".to_string(),
                              "Green".to_string(),
                              "Blue".to_string()];
    // We also need an Option<idx> to indicate whether or not an item is selected.
    let mut selected_idx = None;

    // Main program loop begins.
    loop {
        match game_iter.next() {
            None => break,
            Some(mut e) => handle_event(&mut e,
                                        &mut gl,
                                        &mut uic,
                                        &mut bg_color,
                                        &mut show_button,
                                        &mut toggle_label,
                                        &mut title_padding,
                                        &mut v_slider_height,
                                        &mut frame_width,
                                        &mut bool_matrix,
                                        &mut ddl_colors,
                                        &mut selected_idx),
        }
    }

}

/// Match the game event.
fn handle_event(event: &mut GameEvent,
                gl: &mut Gl,
                uic: &mut UIContext,
                bg_color: &mut Color,
                show_button: &mut bool,
                toggle_label: &mut String,
                title_padding: &mut f64,
                v_slider_height: &mut f64,
                frame_width: &mut f64,
                bool_matrix: &mut Vec<Vec<bool>>,
                ddl_colors: &mut Vec<String>,
                selected_idx: &mut Option<uint>) {
    uic.event(event);
    match *event {
        Render(ref mut args) => {
            draw_background(args, gl, bg_color);
            draw_ui(args,
                    gl,
                    uic,
                    bg_color,
                    show_button,
                    toggle_label,
                    title_padding,
                    v_slider_height,
                    frame_width,
                    bool_matrix,
                    ddl_colors,
                    selected_idx);
        },
        _ => (),
    }
}

/// Draw the window background.
fn draw_background(args: &RenderArgs,
                   gl: &mut Gl,
                   bg_color: &mut Color) {
    // Set up a context to draw into.
    let context = &Context::abs(args.width as f64, args.height as f64);
    // Return the individual  elements of the background color.
    let (r, g, b, a) = bg_color.as_tuple();
    // Draw the background.
    context.rgba(r, g, b, a).draw(gl);
}

/// Draw the User Interface.
fn draw_ui(args: &RenderArgs,
           gl: &mut Gl,
           uic: &mut UIContext,
           bg_color: &mut Color,
           show_button: &mut bool,
           toggle_label: &mut String,
           title_padding: &mut f64,
           v_slider_height: &mut f64,
           frame_width: &mut f64,
           bool_matrix: &mut Vec<Vec<bool>>,
           ddl_colors: &mut Vec<String>,
           selected_idx: &mut Option<uint>) {

    // Label example.
    label::draw(args, // RenderArgs.
                gl, // Open GL instance.
                uic, // UIContext.
                Point::new(*title_padding, 30f64, 0f64), // Screen position.
                48u32, // Font size.
                bg_color.plain_contrast(),
                "Widgets Demonstration");

    if *show_button {
        // Button widget example.
        button::draw(args, // RenderArgs.
                     gl, // Open GL instance.
                     uic, // UIContext.
                     0u64, // UI ID.
                     Point::new(50f64, 115f64, 0f64), // Screen position.
                     90f64, // Width.
                     60f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.4f32, 0.75f32, 0.6f32, 1f32), // Button Color.
                     Label("PRESS", 24u32, Color::black()), // Label for button.
                     || { // Button "callback" event.
            *bg_color = Color::random();
        });
    }

    // Horizontal slider example.
    else {

        // Create the label for the slider.
        let pad = *title_padding as i16;
        let pad_string = pad.to_string();
        let label = "Padding: ".to_string().append(pad_string.as_slice());

        // Draw the slider.
        slider::draw(args, // RenderArgs.
                     gl, // OpenGL Instance.
                     uic, // UIContext.
                     1u64, // UIID
                     Point::new(50.0f64, 115.0, 0.0), // Screen position.
                     200f64, // Width.
                     50f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.5, 0.3, 0.6, 1.0), // Rectangle color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     pad as i16, // Slider value.
                     10i16, // Min value.
                     560i16, // Max value.
                     |new_pad| {
            *title_padding = new_pad as f64;
        });

    }

    // Clone the label toggle to be drawn.
    let label = toggle_label.clone();

    // Toggle widget example.
    toggle::draw(args, // RenderArgs.
                 gl, // Open GL instance.
                 uic, // UIContext.
                 2u64, // UI ID.
                 Point::new(50f64, 200f64, 0f64), // Screen position.
                 75f64, // Width.
                 75f64, // Height.
                 Frame(*frame_width, Color::black()), // Widget Frame.
                 Color::new(0.6f32, 0.25f32, 0.75f32, 1f32), // Button Color.
                 Label(label.as_slice(), 24u32, Color::white()),
                 *show_button, // bool.
                 |value| {
        *show_button = value;
        match value {
            true => {
                *toggle_label = "ON".to_string();
            },
            false => {
                *toggle_label = "OFF".to_string();
            },
        }
    });

    // Let's draw a slider for each color element.
    // 0 => red, 1 => green, 2 => blue.
    for i in range(0u, 3) {

        // We'll color the slider similarly to the color element which it will control.
        let color = match i {
            0u => Color::new(0.75f32, 0.3f32, 0.3f32, 1f32),
            1u => Color::new(0.3f32, 0.75f32, 0.3f32, 1f32),
            _  => Color::new(0.3f32, 0.3f32, 0.75f32, 1f32),
        };

        // Grab the value of the color element.
        let value = match i {
            0u => bg_color.r(),
            1u => bg_color.g(),
            _  => bg_color.b(),
        };

        // Create the label to be drawn with the slider.
        let mut label = value.to_string();
        if label.len() > 4u { label.truncate(4u); }

        // Vertical slider widget example.
        slider::draw(args, // RenderArgs.
                     gl, // Open GL instance
                     uic, // UIContext.
                     3u64 + i as u64, // UI ID.
                     Point::new(50f64 + i as f64 * 60f64, 300f64, 0f64), // Position.
                     35f64, // Width.
                     *v_slider_height, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     color, // Slider color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     value, // Slider value.
                     0f32, // Minimum value.
                     1f32, // Maximum value.
                     |color| {
            match i {
                0u => { bg_color.set_r(color); },
                1u => { bg_color.set_g(color); },
                _ => { bg_color.set_b(color); },
            }
        });

    }

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        6u64, // UIID.
                        Point::new(330.0, 115.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(*frame_width, Color::black()), // Widget Frame
                        bg_color.invert(), // Number Dialer Color.
                        Label("Height (pixels)", 24u32, bg_color.invert().plain_contrast()),
                        *v_slider_height, // Initial value.
                        25f64, // Minimum value.
                        250f64, // Maximum value.
                        1u8, // Precision (number of digits to show after decimal point).
                        |new_height| { // Callback closure.
        *v_slider_height = new_height;
    });

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        7u64, // UIID.
                        Point::new(330.0, 195.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(4.0, bg_color.plain_contrast()), // Widget Frame
                        bg_color.invert().plain_contrast(), // Number Dialer Color.
                        Label("Frame (pixels)", 24u32, bg_color.plain_contrast()),
                        *frame_width, // Initial value.
                        0f64, // Minimum value.
                        15f64, // Maximum value.
                        2u8, // Precision (number of digits to show after decimal point).
                        |new_width| { // Callback closure.
        *frame_width = new_width;
    });

    // A demonstration using widget_matrix to easily draw
    // a matrix of any kind of widget.
    let (cols, rows) = (8u, 8u);
    widget_matrix::draw(cols, // cols.
                        rows, // rows.
                        Point::new(300.0, 270.0, 0.0), // matrix position.
                        260.0, // width.
                        260.0, // height.
                        |num, col, row, pos, width, height| {

        // Now draw the widgets with the given callback.
        let val = (*bool_matrix)[col][row];
        toggle::draw(args, gl, uic, 8u64 + num as u64, pos, width, height,
                     Frame(*frame_width, Color::black()),
                     Color::new(0.5 + (col as f32 / cols as f32) / 2.0,
                                0.75,
                                1.0 - (row as f32 / rows as f32) / 2.0,
                                1.0),
                     NoLabel,
                     val,
                     |new_val| {
            *bool_matrix.get_mut(col).get_mut(row) = new_val;
        });

    });

    let ddl_color = match *selected_idx {
        Some(idx) => match (*ddl_colors)[idx].as_slice() {
            "Black" => Color::black(),
            "White" => Color::white(),
            "Red" => Color::new(0.75, 0.4, 0.4, 1.0),
            "Green" => Color::new(0.4, 0.8, 0.4, 1.0),
            "Blue" => Color::new(0.4, 0.4, 0.8, 1.0),
            _ => Color::new(0.75, 0.55, 0.85, 1.0),
        },
        None => Color::new(0.75, 0.55, 0.85, 1.0),
    };

    // A demonstration using drop_down_list.
    drop_down_list::draw(args,
                         gl,
                         uic,
                         75u64,
                         Point::new(620.0, 115.0, 0.0), // Position.
                         150.0, // width.
                         40.0, // height.
                         Frame(*frame_width, ddl_color.plain_contrast()),
                         ddl_color,
                         Label("Colors", 24u32, ddl_color.plain_contrast()),
                         ddl_colors,
                         *selected_idx,
                         |idx, _string| {
        *selected_idx = Some(idx);
    });

}

<commit_msg>Added docs on drop_down_list::draw in all_widgets example<commit_after>
#![feature(phase)]

#[phase(plugin, link)]
extern crate conrod;
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

use sdl2_game_window::GameWindowSDL2;
use opengl_graphics::Gl;
use piston::{
    Game,
    GameEvent,
    GameWindowSettings,
    GameIterator,
    GameIteratorSettings,
    RenderArgs,
    Render,
};
use conrod::{
    button,
    drop_down_list,
    label,
    number_dialer,
    slider,
    toggle,
    widget_matrix,
    Color,
    Point,
    Frame,
    UIContext,
};
use conrod::label::{
    Label,
    NoLabel,
};
use graphics::{
    Context,
    AddColor,
    Draw,
};

fn main() {

    // Create a SDL2 window.
    let mut window = GameWindowSDL2::new(
        GameWindowSettings {
            title: "Hello Conrod".to_string(),
            size: [860, 600],
            fullscreen: false,
            exit_on_esc: true
        }
    );

    // Some settings for how the game should be run.
    let game_iter_settings = GameIteratorSettings {
        updates_per_second: 180,
        max_frames_per_second: 60
    };

    // Create GameIterator to begin the event iteration loop.
    let mut game_iter = GameIterator::new(&mut window, &game_iter_settings);
    // Create OpenGL instance.
    let mut gl = Gl::new();
    // Create the UIContext and specify the name of a font that's in our "assets" directory.
    let mut uic = UIContext::new("Dense-Regular.otf");

    // TODO: Put the following vars all in an 'app' struct or something and pass
    // as a mut reference to struct instead.

    // Background color (for demonstration of button and sliders).
    let mut bg_color = Color::new(0.2, 0.35, 0.45, 1.0);
    // Should the button be shown (for demonstration of button).
    let mut show_button = false;
    // The label that will be drawn to the Toggle.
    let mut toggle_label = "OFF".to_string();
    // The number of pixels between the left side of the window and the title.
    let mut title_padding = 50f64;
    // The height of the vertical sliders (we will play with this using a number_dialer).
    let mut v_slider_height = 185f64;
    // The widget frame width (we'll use this to demo Framing and number_dialer).
    let mut frame_width = 1f64;
    // Bool matrix for widget_matrix demonstration.
    let mut bool_matrix = vec![
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, false, false, false, false, false, false, true],
                            vec![true, false, true, false, true, true, true, true],
                            vec![true, false, true, false, true, true, true, true],
                            vec![true, false, false, false, true, true, true, true],
                            vec![true, true, true, true, true, true, true, true],
                            vec![true, true, false, true, false, false, false, true],
                            vec![true, true, true, true, true, true, true, true],
                            ];
    // A vector of strings for drop_down_list demonstration.
    let mut ddl_colors = vec!["Black".to_string(),
                              "White".to_string(),
                              "Red".to_string(),
                              "Green".to_string(),
                              "Blue".to_string()];
    // We also need an Option<idx> to indicate whether or not an item is selected.
    let mut selected_idx = None;

    // Main program loop begins.
    loop {
        match game_iter.next() {
            None => break,
            Some(mut e) => handle_event(&mut e,
                                        &mut gl,
                                        &mut uic,
                                        &mut bg_color,
                                        &mut show_button,
                                        &mut toggle_label,
                                        &mut title_padding,
                                        &mut v_slider_height,
                                        &mut frame_width,
                                        &mut bool_matrix,
                                        &mut ddl_colors,
                                        &mut selected_idx),
        }
    }

}

/// Match the game event.
fn handle_event(event: &mut GameEvent,
                gl: &mut Gl,
                uic: &mut UIContext,
                bg_color: &mut Color,
                show_button: &mut bool,
                toggle_label: &mut String,
                title_padding: &mut f64,
                v_slider_height: &mut f64,
                frame_width: &mut f64,
                bool_matrix: &mut Vec<Vec<bool>>,
                ddl_colors: &mut Vec<String>,
                selected_idx: &mut Option<uint>) {
    uic.event(event);
    match *event {
        Render(ref mut args) => {
            draw_background(args, gl, bg_color);
            draw_ui(args,
                    gl,
                    uic,
                    bg_color,
                    show_button,
                    toggle_label,
                    title_padding,
                    v_slider_height,
                    frame_width,
                    bool_matrix,
                    ddl_colors,
                    selected_idx);
        },
        _ => (),
    }
}

/// Draw the window background.
fn draw_background(args: &RenderArgs,
                   gl: &mut Gl,
                   bg_color: &mut Color) {
    // Set up a context to draw into.
    let context = &Context::abs(args.width as f64, args.height as f64);
    // Return the individual  elements of the background color.
    let (r, g, b, a) = bg_color.as_tuple();
    // Draw the background.
    context.rgba(r, g, b, a).draw(gl);
}

/// Draw the User Interface.
fn draw_ui(args: &RenderArgs,
           gl: &mut Gl,
           uic: &mut UIContext,
           bg_color: &mut Color,
           show_button: &mut bool,
           toggle_label: &mut String,
           title_padding: &mut f64,
           v_slider_height: &mut f64,
           frame_width: &mut f64,
           bool_matrix: &mut Vec<Vec<bool>>,
           ddl_colors: &mut Vec<String>,
           selected_idx: &mut Option<uint>) {

    // Label example.
    label::draw(args, // RenderArgs.
                gl, // Open GL instance.
                uic, // UIContext.
                Point::new(*title_padding, 30f64, 0f64), // Screen position.
                48u32, // Font size.
                bg_color.plain_contrast(),
                "Widgets Demonstration");

    if *show_button {
        // Button widget example.
        button::draw(args, // RenderArgs.
                     gl, // Open GL instance.
                     uic, // UIContext.
                     0u64, // UI ID.
                     Point::new(50f64, 115f64, 0f64), // Screen position.
                     90f64, // Width.
                     60f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.4f32, 0.75f32, 0.6f32, 1f32), // Button Color.
                     Label("PRESS", 24u32, Color::black()), // Label for button.
                     || { // Button "callback" event.
            *bg_color = Color::random();
        });
    }

    // Horizontal slider example.
    else {

        // Create the label for the slider.
        let pad = *title_padding as i16;
        let pad_string = pad.to_string();
        let label = "Padding: ".to_string().append(pad_string.as_slice());

        // Draw the slider.
        slider::draw(args, // RenderArgs.
                     gl, // OpenGL Instance.
                     uic, // UIContext.
                     1u64, // UIID
                     Point::new(50.0f64, 115.0, 0.0), // Screen position.
                     200f64, // Width.
                     50f64, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     Color::new(0.5, 0.3, 0.6, 1.0), // Rectangle color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     pad as i16, // Slider value.
                     10i16, // Min value.
                     560i16, // Max value.
                     |new_pad| {
            *title_padding = new_pad as f64;
        });

    }

    // Clone the label toggle to be drawn.
    let label = toggle_label.clone();

    // Toggle widget example.
    toggle::draw(args, // RenderArgs.
                 gl, // Open GL instance.
                 uic, // UIContext.
                 2u64, // UI ID.
                 Point::new(50f64, 200f64, 0f64), // Screen position.
                 75f64, // Width.
                 75f64, // Height.
                 Frame(*frame_width, Color::black()), // Widget Frame.
                 Color::new(0.6f32, 0.25f32, 0.75f32, 1f32), // Button Color.
                 Label(label.as_slice(), 24u32, Color::white()),
                 *show_button, // bool.
                 |value| {
        *show_button = value;
        match value {
            true => {
                *toggle_label = "ON".to_string();
            },
            false => {
                *toggle_label = "OFF".to_string();
            },
        }
    });

    // Let's draw a slider for each color element.
    // 0 => red, 1 => green, 2 => blue.
    for i in range(0u, 3) {

        // We'll color the slider similarly to the color element which it will control.
        let color = match i {
            0u => Color::new(0.75f32, 0.3f32, 0.3f32, 1f32),
            1u => Color::new(0.3f32, 0.75f32, 0.3f32, 1f32),
            _  => Color::new(0.3f32, 0.3f32, 0.75f32, 1f32),
        };

        // Grab the value of the color element.
        let value = match i {
            0u => bg_color.r(),
            1u => bg_color.g(),
            _  => bg_color.b(),
        };

        // Create the label to be drawn with the slider.
        let mut label = value.to_string();
        if label.len() > 4u { label.truncate(4u); }

        // Vertical slider widget example.
        slider::draw(args, // RenderArgs.
                     gl, // Open GL instance
                     uic, // UIContext.
                     3u64 + i as u64, // UI ID.
                     Point::new(50f64 + i as f64 * 60f64, 300f64, 0f64), // Position.
                     35f64, // Width.
                     *v_slider_height, // Height.
                     Frame(*frame_width, Color::black()), // Widget Frame.
                     color, // Slider color.
                     //NoLabel,
                     Label(label.as_slice(), 24u32, Color::white()),
                     value, // Slider value.
                     0f32, // Minimum value.
                     1f32, // Maximum value.
                     |color| {
            match i {
                0u => { bg_color.set_r(color); },
                1u => { bg_color.set_g(color); },
                _ => { bg_color.set_b(color); },
            }
        });

    }

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        6u64, // UIID.
                        Point::new(330.0, 115.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(*frame_width, Color::black()), // Widget Frame
                        bg_color.invert(), // Number Dialer Color.
                        Label("Height (pixels)", 24u32, bg_color.invert().plain_contrast()),
                        *v_slider_height, // Initial value.
                        25f64, // Minimum value.
                        250f64, // Maximum value.
                        1u8, // Precision (number of digits to show after decimal point).
                        |new_height| { // Callback closure.
        *v_slider_height = new_height;
    });

    // Number Dialer example.
    number_dialer::draw(args, // RenderArgs.
                        gl, // OpenGL instance.
                        uic, // UIContext.
                        7u64, // UIID.
                        Point::new(330.0, 195.0, 0.0), // Position.
                        24u32, // Number Dialer font size.
                        Frame(4.0, bg_color.plain_contrast()), // Widget Frame
                        bg_color.invert().plain_contrast(), // Number Dialer Color.
                        Label("Frame (pixels)", 24u32, bg_color.plain_contrast()),
                        *frame_width, // Initial value.
                        0f64, // Minimum value.
                        15f64, // Maximum value.
                        2u8, // Precision (number of digits to show after decimal point).
                        |new_width| { // Callback closure.
        *frame_width = new_width;
    });

    // A demonstration using widget_matrix to easily draw
    // a matrix of any kind of widget.
    let (cols, rows) = (8u, 8u);
    widget_matrix::draw(cols, // cols.
                        rows, // rows.
                        Point::new(300.0, 270.0, 0.0), // matrix position.
                        260.0, // width.
                        260.0, // height.
                        |num, col, row, pos, width, height| {

        // Now draw the widgets with the given callback.
        let val = (*bool_matrix)[col][row];
        toggle::draw(args, gl, uic, 8u64 + num as u64, pos, width, height,
                     Frame(*frame_width, Color::black()),
                     Color::new(0.5 + (col as f32 / cols as f32) / 2.0,
                                0.75,
                                1.0 - (row as f32 / rows as f32) / 2.0,
                                1.0),
                     NoLabel,
                     val,
                     |new_val| {
            *bool_matrix.get_mut(col).get_mut(row) = new_val;
        });

    });

    let ddl_color = match *selected_idx {
        Some(idx) => match (*ddl_colors)[idx].as_slice() {
            "Black" => Color::black(),
            "White" => Color::white(),
            "Red" => Color::new(0.75, 0.4, 0.4, 1.0),
            "Green" => Color::new(0.4, 0.8, 0.4, 1.0),
            "Blue" => Color::new(0.4, 0.4, 0.8, 1.0),
            _ => Color::new(0.75, 0.55, 0.85, 1.0),
        },
        None => Color::new(0.75, 0.55, 0.85, 1.0),
    };

    // A demonstration using drop_down_list.
    drop_down_list::draw(args, // RenderArgs.
                         gl, // OpenGL instance.
                         uic, // UIContext.
                         75u64, // UIID.
                         Point::new(620.0, 115.0, 0.0), // Position.
                         150.0, // width.
                         40.0, // height.
                         Frame(*frame_width, ddl_color.plain_contrast()),
                         ddl_color, // Color of drop_down_list.
                         Label("Colors", 24u32, ddl_color.plain_contrast()),
                         ddl_colors, // String vector.
                         *selected_idx, // Currently selected string index.
                         |idx, _string| { // Callback (on new selection).
        *selected_idx = Some(idx); // Assign the newly selected index.
    });

}

<|endoftext|>


<commit_before>use std::error::Error;

use diesel::*;
use diesel::query_builder::BoxedSelectStatement;
use diesel::types::Oid;
use diesel::pg::{PgConnection, Pg};

use table_data::TableData;
use super::data_structures::*;

// https://www.postgresql.org/docs/9.5/static/catalog-pg-attribute.html
table! {
    pg_attribute (attrelid) {
        attrelid -> Oid,
        attname -> VarChar,
        atttypid -> Oid,
        attnotnull -> Bool,
        attnum -> SmallInt,
        attisdropped -> Bool,
    }
}

// https://www.postgresql.org/docs/9.5/static/catalog-pg-type.html
table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> VarChar,
    }
}

joinable!(pg_attribute -> pg_type (atttypid));
select_column_workaround!(pg_attribute -> pg_type (attrelid, attname, atttypid, attnotnull, attnum, attisdropped));
select_column_workaround!(pg_type -> pg_attribute (oid, typname));

// https://www.postgresql.org/docs/9.5/static/catalog-pg-index.html
table! {
    pg_index (indrelid) {
        indrelid -> Oid,
        indexrelid -> Oid,
        indkey -> Array<SmallInt>,
        indisprimary -> Bool,
    }
}

// https://www.postgresql.org/docs/9.5/static/catalog-pg-class.html
table! {
    pg_class (oid) {
        oid -> Oid,
        relname -> VarChar,
        relnamespace -> Oid,
    }
}

// https://www.postgresql.org/docs/9.5/static/catalog-pg-namespace.html
table! {
    pg_namespace (oid) {
        oid -> Oid,
        nspname -> VarChar,
    }
}

mod information_schema {
    table! {
        information_schema.tables (table_catalog, table_schema, table_name) {
            table_catalog -> VarChar,
            table_schema -> VarChar,
            table_name -> VarChar,
            table_type -> VarChar,
        }
    }

    table! {
        information_schema.schemata (schema_name) {
            schema_name -> VarChar,
        }
    }
}

pub fn determine_column_type(attr: &ColumnInformation) -> Result<ColumnType, Box<Error>> {
    let is_array = attr.type_name.starts_with('_');
    let tpe = if is_array {
        &attr.type_name[1..]
    } else {
        &attr.type_name
    };

    Ok(ColumnType {
        path: vec!["diesel".into(), "types".into(), capitalize(tpe)],
        is_array: is_array,
        is_nullable: attr.nullable,
    })
}

fn capitalize(name: &str) -> String {
    name[..1].to_uppercase() + &name[1..]
}

pub fn get_table_data(conn: &PgConnection, table: &TableData) -> QueryResult<Vec<ColumnInformation>> {
    use self::pg_attribute::dsl::*;
    use self::pg_type::dsl::{pg_type, typname};

    pg_attribute.inner_join(pg_type)
        .select((attname, typname, attnotnull))
        .filter(attrelid.eq_any(table_oid(table)))
        .filter(attnum.gt(0).and(attisdropped.ne(true)))
        .order(attnum)
        .load(conn)
}

pub fn get_primary_keys(conn: &PgConnection, table: &TableData) -> QueryResult<Vec<String>> {
    use self::pg_attribute::dsl::*;
    use self::pg_index::dsl::{pg_index, indisprimary, indexrelid, indrelid};

    let pk_query = pg_index.select(indexrelid)
        .filter(indrelid.eq_any(table_oid(table)))
        .filter(indisprimary.eq(true));

    pg_attribute.select(attname)
        .filter(attrelid.eq_any(pk_query))
        .order(attnum)
        .load(conn)
}

fn table_oid(table: &TableData) -> BoxedSelectStatement<Oid, pg_class::table, Pg> {
    use self::pg_class::dsl::*;
    use self::pg_namespace::{table as pg_namespace, oid as nsoid, nspname};

    let schema_oid = pg_namespace.select(nsoid)
        .filter(nspname.eq(table.schema().clone()
            .expect("Postgres TableDate has schema")))
        .limit(1);
    pg_class.select(oid)
        .filter(relname.eq(table.name()))
        .filter(relnamespace.eq_any(schema_oid))
        .limit(1)
        .into_boxed()
}

pub fn load_table_names(connection: &PgConnection, schema_name: Option<&str>)
    -> Result<Vec<TableData>, Box<Error>>
{
    use self::information_schema::tables::dsl::*;

    let schema_name = schema_name.unwrap_or("public");

    let tns: Vec<String> = tables.select(table_name)
        .filter(table_schema.eq(schema_name))
        .filter(table_name.not_like("\\_\\_%"))
        .filter(table_type.like("BASE TABLE"))
        .load(connection)?;

    let tns = tns.iter().map(|n| TableData::new(n, Some(schema_name))).collect();

    Ok(tns)
}

#[cfg(test)]
extern crate dotenv;

#[test]
fn skip_views() {
    use self::dotenv::dotenv;
    dotenv().ok();

    let connection_url = ::std::env::var("DATABASE_URL")
        .expect("DATABASE_URL must be set in order to run tests");
    let connection = PgConnection::establish(&connection_url).unwrap();
    connection.begin_test_transaction().unwrap();

    connection.execute("CREATE TABLE a_regular_table (id SERIAL PRIMARY KEY)").unwrap();
    connection.execute("CREATE VIEW a_view AS SELECT 42").unwrap();

    let table_names = load_table_names(&connection, None).unwrap();

    assert!(table_names.contains(&TableData::new("a_regular_table", Some("public"))));
    assert!(!table_names.contains(&TableData::new("a_view", Some("public"))));
}
<commit_msg>Remove unneccessary clone/unwrap<commit_after>use std::error::Error;

use diesel::*;
use diesel::query_builder::BoxedSelectStatement;
use diesel::types::Oid;
use diesel::pg::{PgConnection, Pg};

use table_data::TableData;
use super::data_structures::*;

// https://www.postgresql.org/docs/9.5/static/catalog-pg-attribute.html
table! {
    pg_attribute (attrelid) {
        attrelid -> Oid,
        attname -> VarChar,
        atttypid -> Oid,
        attnotnull -> Bool,
        attnum -> SmallInt,
        attisdropped -> Bool,
    }
}

// https://www.postgresql.org/docs/9.5/static/catalog-pg-type.html
table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> VarChar,
    }
}

joinable!(pg_attribute -> pg_type (atttypid));
select_column_workaround!(pg_attribute -> pg_type (attrelid, attname, atttypid, attnotnull, attnum, attisdropped));
select_column_workaround!(pg_type -> pg_attribute (oid, typname));

// https://www.postgresql.org/docs/9.5/static/catalog-pg-index.html
table! {
    pg_index (indrelid) {
        indrelid -> Oid,
        indexrelid -> Oid,
        indkey -> Array<SmallInt>,
        indisprimary -> Bool,
    }
}

// https://www.postgresql.org/docs/9.5/static/catalog-pg-class.html
table! {
    pg_class (oid) {
        oid -> Oid,
        relname -> VarChar,
        relnamespace -> Oid,
    }
}

// https://www.postgresql.org/docs/9.5/static/catalog-pg-namespace.html
table! {
    pg_namespace (oid) {
        oid -> Oid,
        nspname -> VarChar,
    }
}

mod information_schema {
    table! {
        information_schema.tables (table_catalog, table_schema, table_name) {
            table_catalog -> VarChar,
            table_schema -> VarChar,
            table_name -> VarChar,
            table_type -> VarChar,
        }
    }

    table! {
        information_schema.schemata (schema_name) {
            schema_name -> VarChar,
        }
    }
}

pub fn determine_column_type(attr: &ColumnInformation) -> Result<ColumnType, Box<Error>> {
    let is_array = attr.type_name.starts_with('_');
    let tpe = if is_array {
        &attr.type_name[1..]
    } else {
        &attr.type_name
    };

    Ok(ColumnType {
        path: vec!["diesel".into(), "types".into(), capitalize(tpe)],
        is_array: is_array,
        is_nullable: attr.nullable,
    })
}

fn capitalize(name: &str) -> String {
    name[..1].to_uppercase() + &name[1..]
}

pub fn get_table_data(conn: &PgConnection, table: &TableData) -> QueryResult<Vec<ColumnInformation>> {
    use self::pg_attribute::dsl::*;
    use self::pg_type::dsl::{pg_type, typname};

    pg_attribute.inner_join(pg_type)
        .select((attname, typname, attnotnull))
        .filter(attrelid.eq_any(table_oid(table)))
        .filter(attnum.gt(0).and(attisdropped.ne(true)))
        .order(attnum)
        .load(conn)
}

pub fn get_primary_keys(conn: &PgConnection, table: &TableData) -> QueryResult<Vec<String>> {
    use self::pg_attribute::dsl::*;
    use self::pg_index::dsl::{pg_index, indisprimary, indexrelid, indrelid};

    let pk_query = pg_index.select(indexrelid)
        .filter(indrelid.eq_any(table_oid(table)))
        .filter(indisprimary.eq(true));

    pg_attribute.select(attname)
        .filter(attrelid.eq_any(pk_query))
        .order(attnum)
        .load(conn)
}

fn table_oid(table: &TableData) -> BoxedSelectStatement<Oid, pg_class::table, Pg> {
    use self::pg_class::dsl::*;
    use self::pg_namespace::{table as pg_namespace, oid as nsoid, nspname};

    let schema_oid = pg_namespace.select(nsoid)
        .filter(nspname.nullable().eq(table.schema()))
        .limit(1);
    pg_class.select(oid)
        .filter(relname.eq(table.name()))
        .filter(relnamespace.eq_any(schema_oid))
        .limit(1)
        .into_boxed()
}

pub fn load_table_names(connection: &PgConnection, schema_name: Option<&str>)
    -> Result<Vec<TableData>, Box<Error>>
{
    use self::information_schema::tables::dsl::*;

    let schema_name = schema_name.unwrap_or("public");

    let tns: Vec<String> = tables.select(table_name)
        .filter(table_schema.eq(schema_name))
        .filter(table_name.not_like("\\_\\_%"))
        .filter(table_type.like("BASE TABLE"))
        .load(connection)?;

    let tns = tns.iter().map(|n| TableData::new(n, Some(schema_name))).collect();

    Ok(tns)
}

#[cfg(test)]
extern crate dotenv;

#[test]
fn skip_views() {
    use self::dotenv::dotenv;
    dotenv().ok();

    let connection_url = ::std::env::var("DATABASE_URL")
        .expect("DATABASE_URL must be set in order to run tests");
    let connection = PgConnection::establish(&connection_url).unwrap();
    connection.begin_test_transaction().unwrap();

    connection.execute("CREATE TABLE a_regular_table (id SERIAL PRIMARY KEY)").unwrap();
    connection.execute("CREATE VIEW a_view AS SELECT 42").unwrap();

    let table_names = load_table_names(&connection, None).unwrap();

    assert!(table_names.contains(&TableData::new("a_regular_table", Some("public"))));
    assert!(!table_names.contains(&TableData::new("a_view", Some("public"))));
}
<|endoftext|>


<commit_before>use super::behaviors::MouseBehavior;
use crate::{
    prelude::*,
    shell::{Key, KeyEvent},
};

// --- KEYS --

pub static ELEMENT_TEXT_BOX: &'static str = "text_box";

static ID_CURSOR: &'static str = "id_cursor";

// --- KEYS --

#[derive(Clone)]
enum TextBoxAction {
    Key(KeyEvent),
    Mouse(Mouse),
}

/// The `TextBoxState` handles the text processing of the `TextBox` widget.
#[derive(Default, AsAny)]
pub struct TextBoxState {
    action: Option<TextBoxAction>,
    len: usize,
    cursor: Entity,
}

impl TextBoxState {
    fn action(&mut self, action: TextBoxAction) {
        self.action = Some(action);
    }

    fn handle_key_event(&mut self, key_event: KeyEvent, ctx: &mut Context<'_>) {
        if !ctx.widget().get::<bool>("focused") {
            return;
        }

        match key_event.key {
            Key::Left => {
                self.move_cursor_left(ctx);
            }
            Key::Right => {
                self.move_cursor_right(ctx);
            }
            Key::Backspace => {
                self.back_space(ctx);
            }
            Key::Delete => {
                self.delete(ctx);
            }
            Key::Enter => {
                self.activate(ctx);
            }
            Key::A(..) => {
                // if cfg!(mac_os) {
                //     if ctx
                //         .window()
                //         .get::<Global>("global")
                //         .keyboard_state
                //         .is_home_down()
                //     {
                //         self.select_all(ctx);
                //     } else {
                //         self.insert_char(key_event, ctx);
                //     }
                // } else {
                if ctx
                    .window()
                    .get::<Global>("global")
                    .keyboard_state
                    .is_ctrl_down()
                {
                    self.select_all(ctx);
                } else {
                    self.insert_char(key_event, ctx);
                }
                // }
            }
            _ => {
                self.insert_char(key_event, ctx);
            }
        }
    }

    fn request_focus(&self, ctx: &mut Context<'_>) {
        ctx.push_event_by_window(FocusEvent::RequestFocus(ctx.entity));

        if ctx.widget().get::<String16>("text").len() > 0 {
            self.select_all(ctx);
        }
    }

    // Reset selection and offset if text is changed from outside
    fn reset(&self, ctx: &mut Context<'_>) {
        ctx.widget().set("text_selection", TextSelection::default());
        ctx.push_event_strategy_by_entity(
            ChangedEvent(ctx.entity),
            ctx.entity,
            EventStrategy::Direct,
        );
    }

    fn check_outside_update(&self, ctx: &mut Context<'_>) {
        let len = ctx.widget().get::<String16>("text").len();
        if self.len != len && self.len > len {
            self.reset(ctx);
        }
    }

    fn select_all(&self, ctx: &mut Context) {
        let len = ctx.widget().get::<String16>("text").len();
        ctx.widget()
            .get_mut::<TextSelection>("text_selection")
            .start_index = 0;
        ctx.widget()
            .get_mut::<TextSelection>("text_selection")
            .length = len;
    }

    fn move_cursor_left(&mut self, ctx: &mut Context) {
        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index = 0;
                selection.length = 0;
            }
        }

        if let Some(selection) = ctx
            .get_widget(self.cursor)
            .try_get_mut::<TextSelection>("text_selection")
        {
            selection.start_index = (selection.start_index as i32 - 1).max(0) as usize;
            selection.length = 0;
        }
    }

    fn move_cursor_right(&mut self, ctx: &mut Context) {
        let text_len = ctx.widget().get::<String16>("text").len();

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index = text_len;
                selection.length = 0;
            }

            return;
        }

        if let Some(selection) = ctx
            .get_widget(self.cursor)
            .try_get_mut::<TextSelection>("text_selection")
        {
            if selection.start_index < text_len {
                selection.start_index = (selection.start_index + 1).min(text_len);
            }
            selection.length = 0;
        }
    }

    fn clear_selection(&mut self, ctx: &mut Context) {
        let selection = ctx.widget().clone::<TextSelection>("text_selection");

        if let Some(text) = ctx.widget().try_get_mut::<String16>("text") {
            for i in (selection.start_index..(selection.start_index + selection.length)).rev() {
                text.remove(i);
            }
        }

        ctx.widget()
            .get_mut::<TextSelection>("text_selection")
            .length = 0;
    }

    fn back_space(&mut self, ctx: &mut Context) {
        let mut changed = false;

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            self.clear_selection(ctx);
            changed = true;
        } else {
            let index = ctx
                .widget()
                .clone::<TextSelection>("text_selection")
                .start_index;
            if index > 0 {
                ctx.widget().get_mut::<String16>("text").remove(index - 1);
                ctx.widget()
                    .get_mut::<TextSelection>("text_selection")
                    .start_index = index - 1;

                changed = true;
            }
        }

        if changed {
            ctx.push_event_strategy_by_entity(
                ChangedEvent(ctx.entity),
                ctx.entity,
                EventStrategy::Direct,
            );
        }
    }

    fn delete(&mut self, ctx: &mut Context) {
        let mut changed = false;

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            self.clear_selection(ctx);
        } else {
            let index = ctx
                .widget()
                .clone::<TextSelection>("text_selection")
                .start_index;
            if index < ctx.widget().get::<String16>("text").len() {
                ctx.widget().get_mut::<String16>("text").remove(index);
                changed = true;

                ctx.widget()
                    .get_mut::<TextSelection>("text_selection")
                    .start_index = index;
            }
        }

        if changed {
            ctx.push_event_strategy_by_entity(
                ChangedEvent(ctx.entity),
                ctx.entity,
                EventStrategy::Direct,
            );
        }
    }

    fn activate(&self, ctx: &mut Context) {
        if *ctx.widget().get::<bool>("lost_focus_on_activation") {
            ctx.push_event_by_window(FocusEvent::RemoveFocus(ctx.entity));
        }

        ctx.push_event_strategy_by_entity(
            ActivateEvent(ctx.entity),
            ctx.entity,
            EventStrategy::Direct,
        )
    }

    fn insert_char(&mut self, key_event: KeyEvent, ctx: &mut Context) {
        if key_event.text.is_empty() {
            return;
        }

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            ctx.widget().set("text", String16::from(key_event.text));
            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index = 1;
                selection.length = 0
            }
        } else {
            let current_selection = *ctx
                .get_widget(self.cursor)
                .get::<TextSelection>("text_selection");
            ctx.widget()
                .get_mut::<String16>("text")
                .insert_str(current_selection.start_index, key_event.text.as_str());

            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index =
                    current_selection.start_index + key_event.text.encode_utf16().count();
            }
        }

        ctx.push_event_strategy_by_entity(
            ChangedEvent(ctx.entity),
            ctx.entity,
            EventStrategy::Direct,
        );
    }
}

impl State for TextBoxState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        self.cursor = ctx
            .entity_of_child(ID_CURSOR)
            .expect("TextBoxState.init: cursor child could not be found.");
        self.len = ctx.widget().get::<String16>("text").len();
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        self.check_outside_update(ctx);

        if let Some(action) = self.action.clone() {
            match action {
                TextBoxAction::Key(event) => {
                    self.handle_key_event(event, ctx);
                }
                TextBoxAction::Mouse(_p) => {
                    self.request_focus(ctx);
                }
            }
        }

        self.action = None;
        ctx.widget().update_theme_by_state(false);
        self.len = ctx.widget().get::<String16>("text").len();
    }
}

widget!(
    /// The `TextBox` widget represents a single line text input widget.
    ///
    /// * CSS element: `text_box`
    TextBox<TextBoxState>: ActivateHandler, ChangedHandler, KeyDownHandler {
        /// Sets or shares the text property.
        text: String16,

        /// Sets or shares the water_mark text property.
        water_mark: String16,

        /// Sets or shares the text selection property.
        text_selection: TextSelection,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or shares the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the focused property.
        focused: bool,

        /// Sets or shares ta value that describes if the TextBox should lost focus on activation (enter).
        lost_focus_on_activation: bool
    }
);

impl Template for TextBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let text_block = TextBlock::create()
            .vertical_alignment("center")
            .horizontal_alignment("start")
            .foreground(id)
            .text(id)
            .water_mark(id)
            .font(id)
            .font_size(id)
            .build(ctx);

        self.name("TextBox")
            .element(ELEMENT_TEXT_BOX)
            .text("")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(fonts::FONT_SIZE_12)
            .font("Roboto Regular")
            .text_selection(TextSelection::default())
            .padding(4.0)
            .background(colors::LYNCH_COLOR)
            .border_brush("transparent")
            .border_width(0.0)
            .border_radius(2.0)
            .min_width(128.0)
            .height(32.0)
            .focused(false)
            .lost_focus_on_activation(true)
            .child(
                MouseBehavior::create()
                    .visibility(id)
                    .enabled(id)
                    .on_mouse_down(move |states, m| {
                        states
                            .get_mut::<TextBoxState>(id)
                            .action(TextBoxAction::Mouse(m));
                        true
                    })
                    .child(
                        Container::create()
                            .background(id)
                            .border_radius(id)
                            .border_width(id)
                            .border_brush(id)
                            .padding(id)
                            .child(
                                Grid::create()
                                    .clip(true)
                                    // It is important that cursor is the first child
                                    // should be refactored in the future.
                                    .child(
                                        Cursor::create()
                                            .id(ID_CURSOR)
                                            .horizontal_alignment("start")
                                            .text_block(text_block.0)
                                            .focused(id)
                                            .text_selection(id)
                                            .build(ctx),
                                    )
                                    .child(text_block)
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_key_down(move |states, event| -> bool {
                states
                    .get_mut::<TextBoxState>(id)
                    .action(TextBoxAction::Key(event));
                false
            })
    }
}
<commit_msg>Update caret position when clicking inside a text box.<commit_after>use super::behaviors::MouseBehavior;
use crate::{
    prelude::*,
    shell::{Key, KeyEvent},
};

// --- KEYS --

pub static ELEMENT_TEXT_BOX: &'static str = "text_box";

static ID_CURSOR: &'static str = "id_cursor";

// --- KEYS --

#[derive(Clone)]
enum TextBoxAction {
    Key(KeyEvent),
    Mouse(Mouse),
}

/// The `TextBoxState` handles the text processing of the `TextBox` widget.
#[derive(Default, AsAny)]
pub struct TextBoxState {
    action: Option<TextBoxAction>,
    len: usize,
    cursor: Entity,
}

impl TextBoxState {
    fn action(&mut self, action: TextBoxAction) {
        self.action = Some(action);
    }

    fn handle_key_event(&mut self, key_event: KeyEvent, ctx: &mut Context<'_>) {
        if !ctx.widget().get::<bool>("focused") {
            return;
        }

        match key_event.key {
            Key::Left => {
                self.move_cursor_left(ctx);
            }
            Key::Right => {
                self.move_cursor_right(ctx);
            }
            Key::Backspace => {
                self.back_space(ctx);
            }
            Key::Delete => {
                self.delete(ctx);
            }
            Key::Enter => {
                self.activate(ctx);
            }
            Key::A(..) => {
                // if cfg!(mac_os) {
                //     if ctx
                //         .window()
                //         .get::<Global>("global")
                //         .keyboard_state
                //         .is_home_down()
                //     {
                //         self.select_all(ctx);
                //     } else {
                //         self.insert_char(key_event, ctx);
                //     }
                // } else {
                if ctx
                    .window()
                    .get::<Global>("global")
                    .keyboard_state
                    .is_ctrl_down()
                {
                    self.select_all(ctx);
                } else {
                    self.insert_char(key_event, ctx);
                }
                // }
            }
            _ => {
                self.insert_char(key_event, ctx);
            }
        }
    }

    fn request_focus(&self, ctx: &mut Context<'_>, p: Mouse) {
        ctx.push_event_by_window(FocusEvent::RequestFocus(ctx.entity));

        // select all text if there is text and the element is not focused yet.
        if ctx.widget().get::<String16>("text").len() > 0 && !(*ctx.widget().get::<bool>("focused")) {
            self.select_all(ctx);
            return;
        }

        // change only the caret position if the text is already selected or if the element is focused already
        if *ctx.get_widget(self.cursor).get::<bool>("expanded") || *ctx.widget().get::<bool>("focused") {
            ctx.widget()
                .get_mut::<TextSelection>("text_selection")
                .start_index = self.get_new_caret_position(ctx, p);
            ctx.widget()
                .get_mut::<TextSelection>("text_selection")
                .length = 0;
        }
    }

    // Get new position for the caret based on current mouse position
    fn get_new_caret_position(&self, ctx: &mut Context<'_>, p: Mouse) -> usize {
        if let Some((index, _x)) = self.map_chars_index_to_position(ctx).iter().min_by_key(|(_index, x)| (p.x - x).abs() as i64) {
            return *index;
        }

        0
    }

    // Returns a vector with a tuple of each char's starting index (usize) and position (f64)
    fn map_chars_index_to_position(&self, ctx: &mut Context<'_>) -> Vec<(usize, f64)> {
        let text: String = ctx.widget().get::<String16>("text").as_string();
        // start x position of the cursor is start position of the text element + padding left
        let start_position: f64 = ctx.widget().get::<Point>("position").x + ctx.widget().get::<Thickness>("padding").left;
        // array which will hold char index and it's x position
        let mut position_index: Vec<(usize, f64)> = Vec::with_capacity(text.len());
        position_index.push((0, start_position));
        // current text font family and size
        let font: String = ctx.widget().clone_or_default::<String>("font");
        let font_size: f64 = ctx.widget().clone_or_default::<f64>("font_size");

        for (index, _) in text.chars().enumerate() {
            let bound_width: f64 = ctx.render_context_2_d().measure(&text[..index + 1], font_size, &font).width;
            let next_position: f64 = start_position + bound_width;

            position_index.push((index + 1, next_position));
        }

        position_index
    }

    // Reset selection and offset if text is changed from outside
    fn reset(&self, ctx: &mut Context<'_>) {
        ctx.widget().set("text_selection", TextSelection::default());
        ctx.push_event_strategy_by_entity(
            ChangedEvent(ctx.entity),
            ctx.entity,
            EventStrategy::Direct,
        );
    }

    fn check_outside_update(&self, ctx: &mut Context<'_>) {
        let len = ctx.widget().get::<String16>("text").len();
        if self.len != len && self.len > len {
            self.reset(ctx);
        }
    }

    fn select_all(&self, ctx: &mut Context) {
        let len = ctx.widget().get::<String16>("text").len();
        ctx.widget()
            .get_mut::<TextSelection>("text_selection")
            .start_index = 0;
        ctx.widget()
            .get_mut::<TextSelection>("text_selection")
            .length = len;
    }

    fn move_cursor_left(&mut self, ctx: &mut Context) {
        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index = 0;
                selection.length = 0;
            }
        }

        if let Some(selection) = ctx
            .get_widget(self.cursor)
            .try_get_mut::<TextSelection>("text_selection")
        {
            selection.start_index = (selection.start_index as i32 - 1).max(0) as usize;
            selection.length = 0;
        }
    }

    fn move_cursor_right(&mut self, ctx: &mut Context) {
        let text_len = ctx.widget().get::<String16>("text").len();

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index = text_len;
                selection.length = 0;
            }

            return;
        }

        if let Some(selection) = ctx
            .get_widget(self.cursor)
            .try_get_mut::<TextSelection>("text_selection")
        {
            if selection.start_index < text_len {
                selection.start_index = (selection.start_index + 1).min(text_len);
            }
            selection.length = 0;
        }
    }

    fn clear_selection(&mut self, ctx: &mut Context) {
        let selection = ctx.widget().clone::<TextSelection>("text_selection");

        if let Some(text) = ctx.widget().try_get_mut::<String16>("text") {
            for i in (selection.start_index..(selection.start_index + selection.length)).rev() {
                text.remove(i);
            }
        }

        ctx.widget()
            .get_mut::<TextSelection>("text_selection")
            .length = 0;
    }

    fn back_space(&mut self, ctx: &mut Context) {
        let mut changed = false;

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            self.clear_selection(ctx);
            changed = true;
        } else {
            let index = ctx
                .widget()
                .clone::<TextSelection>("text_selection")
                .start_index;
            if index > 0 {
                ctx.widget().get_mut::<String16>("text").remove(index - 1);
                ctx.widget()
                    .get_mut::<TextSelection>("text_selection")
                    .start_index = index - 1;

                changed = true;
            }
        }

        if changed {
            ctx.push_event_strategy_by_entity(
                ChangedEvent(ctx.entity),
                ctx.entity,
                EventStrategy::Direct,
            );
        }
    }

    fn delete(&mut self, ctx: &mut Context) {
        let mut changed = false;

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            self.clear_selection(ctx);
        } else {
            let index = ctx
                .widget()
                .clone::<TextSelection>("text_selection")
                .start_index;
            if index < ctx.widget().get::<String16>("text").len() {
                ctx.widget().get_mut::<String16>("text").remove(index);
                changed = true;

                ctx.widget()
                    .get_mut::<TextSelection>("text_selection")
                    .start_index = index;
            }
        }

        if changed {
            ctx.push_event_strategy_by_entity(
                ChangedEvent(ctx.entity),
                ctx.entity,
                EventStrategy::Direct,
            );
        }
    }

    fn activate(&self, ctx: &mut Context) {
        if *ctx.widget().get::<bool>("lost_focus_on_activation") {
            ctx.push_event_by_window(FocusEvent::RemoveFocus(ctx.entity));
        }

        ctx.push_event_strategy_by_entity(
            ActivateEvent(ctx.entity),
            ctx.entity,
            EventStrategy::Direct,
        )
    }

    fn insert_char(&mut self, key_event: KeyEvent, ctx: &mut Context) {
        if key_event.text.is_empty() {
            return;
        }

        if *ctx.get_widget(self.cursor).get::<bool>("expanded") {
            ctx.widget().set("text", String16::from(key_event.text));
            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index = 1;
                selection.length = 0
            }
        } else {
            let current_selection = *ctx
                .get_widget(self.cursor)
                .get::<TextSelection>("text_selection");
            ctx.widget()
                .get_mut::<String16>("text")
                .insert_str(current_selection.start_index, key_event.text.as_str());

            if let Some(selection) = ctx
                .get_widget(self.cursor)
                .try_get_mut::<TextSelection>("text_selection")
            {
                selection.start_index =
                    current_selection.start_index + key_event.text.encode_utf16().count();
            }
        }

        ctx.push_event_strategy_by_entity(
            ChangedEvent(ctx.entity),
            ctx.entity,
            EventStrategy::Direct,
        );
    }
}

impl State for TextBoxState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        self.cursor = ctx
            .entity_of_child(ID_CURSOR)
            .expect("TextBoxState.init: cursor child could not be found.");
        self.len = ctx.widget().get::<String16>("text").len();
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        self.check_outside_update(ctx);

        if let Some(action) = self.action.clone() {
            match action {
                TextBoxAction::Key(event) => {
                    self.handle_key_event(event, ctx);
                }
                TextBoxAction::Mouse(p) => {
                    self.request_focus(ctx, p);
                }
            }
        }

        self.action = None;
        ctx.widget().update_theme_by_state(false);
        self.len = ctx.widget().get::<String16>("text").len();
    }
}

widget!(
    /// The `TextBox` widget represents a single line text input widget.
    ///
    /// * CSS element: `text_box`
    TextBox<TextBoxState>: ActivateHandler, ChangedHandler, KeyDownHandler {
        /// Sets or shares the text property.
        text: String16,

        /// Sets or shares the water_mark text property.
        water_mark: String16,

        /// Sets or shares the text selection property.
        text_selection: TextSelection,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or shares the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the focused property.
        focused: bool,

        /// Sets or shares ta value that describes if the TextBox should lost focus on activation (enter).
        lost_focus_on_activation: bool
    }
);

impl Template for TextBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let text_block = TextBlock::create()
            .vertical_alignment("center")
            .horizontal_alignment("start")
            .foreground(id)
            .text(id)
            .water_mark(id)
            .font(id)
            .font_size(id)
            .build(ctx);

        self.name("TextBox")
            .element(ELEMENT_TEXT_BOX)
            .text("")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(fonts::FONT_SIZE_12)
            .font("Roboto Regular")
            .text_selection(TextSelection::default())
            .padding(4.0)
            .background(colors::LYNCH_COLOR)
            .border_brush("transparent")
            .border_width(0.0)
            .border_radius(2.0)
            .min_width(128.0)
            .height(32.0)
            .focused(false)
            .lost_focus_on_activation(true)
            .child(
                MouseBehavior::create()
                    .visibility(id)
                    .enabled(id)
                    .on_mouse_down(move |states, m| {
                        states
                            .get_mut::<TextBoxState>(id)
                            .action(TextBoxAction::Mouse(m));
                        true
                    })
                    .child(
                        Container::create()
                            .background(id)
                            .border_radius(id)
                            .border_width(id)
                            .border_brush(id)
                            .padding(id)
                            .child(
                                Grid::create()
                                    .clip(true)
                                    // It is important that cursor is the first child
                                    // should be refactored in the future.
                                    .child(
                                        Cursor::create()
                                            .id(ID_CURSOR)
                                            .horizontal_alignment("start")
                                            .text_block(text_block.0)
                                            .focused(id)
                                            .text_selection(id)
                                            .build(ctx),
                                    )
                                    .child(text_block)
                                    .build(ctx),
                            )
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_key_down(move |states, event| -> bool {
                states
                    .get_mut::<TextBoxState>(id)
                    .action(TextBoxAction::Key(event));
                false
            })
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use rand::Rng;

#[derive(Eq, PartialEq)]
enum Move {
    Rock,
    Paper,
    Scissors,
}

#[derive(Debug)]
enum GameResult {
    Human,
    Computer,
    Draw,
}

struct Game {
    frequencies: [u32; 3],
}

impl Move {
    fn beaten_by(&self) ->  Move {
        match *self {
            Move::Rock => Move::Paper,
            Move::Paper => Move::Scissors,
            Move::Scissors => Move::Rock,
        }
    }
}

impl Game {
    fn new() -> Game {
        Game{frequencies: [0, 0, 0]}
    }

    fn increment_frequency(&mut self, m: &Move) {
        let i = match *m {
            Move::Rock => 0,
            Move::Paper => 1,
            Move::Scissors => 2,
        };

        self.frequencies[i] += 1;
    }

    fn pick(&self) -> Move {
        let total = self.frequencies.iter().fold(0, |t, n| t + n);
        let guess = rand::thread_rng().gen_range(0, total + 1);
        let mut sum: u32 = 0;

        for (&f, c) in self.frequencies.iter().zip([Move::Rock, Move::Paper, Move::Scissors].iter()) {
            sum += f;

            if guess <= sum {
                return c.beaten_by();
            }
        }

        return Move::Rock;
    }

    fn play(&mut self, human: &Move) -> GameResult {
        let computer = self.pick();
        let best_answer = human.beaten_by();

        self.increment_frequency(&best_answer);

        if best_answer == computer {
            GameResult::Computer
        } else if computer.beaten_by() == *human {
            GameResult::Human
        } else {
            GameResult::Draw
        }
    }
}

fn main() {
   let mut game = Game::new();

   loop {
       println!("Enter a guess (r, p, s);");

       let mut input = String::new();

       io::stdin()
           .read_line(&mut input)
           .ok()
           .expect("Cuold not read input.");

       let human = match input.trim() {
           "r" => Move::Rock,
           "p" => Move::Paper,
           "s" => Move::Scissors,
           _ => { continue; },
       };

       println!("Winner: {:?}", game.play(&human));
   }
}
<commit_msg>Fixed bug in frequencies<commit_after>extern crate rand;

use std::io;
use rand::Rng;

#[derive(Eq, PartialEq)]
enum Move {
    Rock,
    Paper,
    Scissors,
}

#[derive(Debug)]
enum GameResult {
    Human,
    Computer,
    Draw,
}

struct Game {
    frequencies: [u32; 3],
}

impl Move {
    fn beaten_by(&self) ->  Move {
        match *self {
            Move::Rock => Move::Paper,
            Move::Paper => Move::Scissors,
            Move::Scissors => Move::Rock,
        }
    }
}

impl Game {
    fn new() -> Game {
        Game{frequencies: [0, 0, 0]}
    }

    fn increment_frequency(&mut self, m: &Move) {
        let i = match *m {
            Move::Rock => 0,
            Move::Paper => 1,
            Move::Scissors => 2,
        };

        self.frequencies[i] += 1;
    }

    fn pick(&self) -> Move {
        let total = self.frequencies.iter().fold(0, |t, n| t + n);
        let guess = rand::thread_rng().gen_range(0, total + 1);
        let mut sum: u32 = 0;

        for (&f, c) in self.frequencies.iter().zip([Move::Rock, Move::Paper, Move::Scissors].iter()) {
            sum += f;

            if guess <= sum {
                return c.beaten_by();
            }
        }

        return Move::Rock;
    }

    fn play(&mut self, human: &Move) -> GameResult {
        let computer = self.pick();

        self.increment_frequency(&human);

        if human.beaten_by() == computer {
            GameResult::Computer
        } else if computer.beaten_by() == *human {
            GameResult::Human
        } else {
            GameResult::Draw
        }
    }
}

fn main() {
   let mut game = Game::new();

   loop {
       println!("Enter a guess (r, p, s);");

       let mut input = String::new();

       io::stdin()
           .read_line(&mut input)
           .ok()
           .expect("Cuold not read input.");

       let human = match input.trim() {
           "r" => Move::Rock,
           "p" => Move::Paper,
           "s" => Move::Scissors,
           _ => { continue; },
       };

       println!("Winner: {:?}", game.play(&human));
   }
}
<|endoftext|>