enamel 0.3.0

A simple OpenGL interface overlay for use with Glium.
Documentation
//! This example demonstrates how Enamel would generally be used. 
//!
//! One trait must be implemented to use custom handler closures. In this
//! example we've implemented it on the enum, `BackgroundCtl` but it can be
//! implemented on a struct just as well. This type carries information from
//! our custom defined event handling closures. It can do anything you want as
//! long as it implements the `Default` and `EventRemainder` traits. `Default`
//! should set a variant or a flag indicating that no action should be taken.
//!


extern crate glium;
extern crate enamel;
#[macro_use] extern crate colorify;

use glium::{DisplayBuild, Surface};
use enamel::{ui, Pane, Event, EventRemainder, UiRequest, TextBox, RectButton, HexButton, ElementState, 
    MouseButton, MouseScrollDelta};
use enamel::ui::C_ORANGE as ORANGE;


/// This enum is used by our event handling closures to return useful
/// information and commands back to the main window. 
///
/// This can contain as many custom variants as we need (and doesn't even need
/// to be an enum) but must implement `Default` and `EventRemainder` which are
/// used by enamel to send information about events not handled by custom
/// closures.
///
pub enum BackgroundCtl {
    None,
    Event(Event),
    Start,
    Stop,
    Text(String),
}

impl Default for BackgroundCtl {
    fn default() -> BackgroundCtl {
        BackgroundCtl::None
    }
}

impl EventRemainder for BackgroundCtl {
    fn event(event: Event) -> Self {
        BackgroundCtl::Event(event)
    }
}


/// This represents a 'background' which is sent any events that the interface
/// layer did not make use of. These 'leftover' events are represented by the
/// `EventRemainder` trait, which in this case we have implemented on an enum.
///
/// If any mouse or keyboard events happen when no interface elements make use
/// of them, they would be sent here.
///
pub struct Background {
	pub mouse_pos: (i32, i32),
	pub closed: bool,
}

impl<'a> Background {
	fn new() -> Background {
	    Background {
	    	mouse_pos: (0, 0),
	    	closed: false,
	    }
	}

	fn handle_event_remainder(&mut self, rdr: BackgroundCtl) {
	    match rdr {
	        BackgroundCtl::None => (),
            BackgroundCtl::Event(e) => { match e {
                Event::KeyboardInput(st, key, vkc) => 
                    println!("Key: 0x{:02X} ({:?}) has been {:?}.", key, enamel::ui::map_vkc(vkc), st),
                Event::MouseMoved(p_x, p_y) => self.handle_mouse_moved((p_x, p_y)),
                Event::MouseWheel(delta, _) => self.handle_mouse_wheel(delta),
                Event::MouseInput(st, btn) => self.handle_mouse_input(st, btn),
                Event::Touch(touch) => println!("Touch recieved: {:?}", touch),
                Event::Closed => self.handle_closed(),
                _ => (),
            } }
	        BackgroundCtl::Text(s) => printlnc!(royal_blue: "String entered: '{}'.", &s),
            BackgroundCtl::Start => printlnc!(lime: "Starting something!"),
            BackgroundCtl::Stop => printlnc!(red: "Stopping everything!"),
	    }
	}

	fn handle_mouse_wheel(&self, scroll_delta: MouseScrollDelta) {
	    let (hrz, vrt) = match scroll_delta {
	        MouseScrollDelta::LineDelta(h, v) => (h, v),
	        MouseScrollDelta::PixelDelta(x, y) => (x, y),
	    };
	    printlnc!(green: "Mouse wheel scrolled by: horizontal: {}, vertical: {}", hrz, vrt)
	}

	fn handle_mouse_moved(&mut self, pos: (i32, i32)) {
	    // println!("Mouse has moved to: ({}, {})", pos.0, pos.1)
	    self.mouse_pos = pos;
	}

	fn handle_mouse_input(&self, btn_st: ElementState, btn: MouseButton) {
	    match btn {
	        MouseButton::Left => { match btn_st {
                ElementState::Pressed => 
                    printlnc!(teal: "Left mouse button pressed on background."),
                ElementState::Released => 
                    printlnc!(cyan: "Left mouse button released on background."),
            } },
            MouseButton::Right => { match btn_st {
                ElementState::Pressed => 
                    printlnc!(magenta: "Right mouse button pressed on background."),
                ElementState::Released => 
                    printlnc!(purple: "Right mouse button released on background."),
            } },
	        _ => (),
	    }
	}

    fn handle_closed(&mut self) {
        self.closed = true;
        printlnc!(yellow: "Exiting.");
    }
}


fn main() {
	// Glutin window:
    let display = glium::glutin::WindowBuilder::new()
        .with_depth_buffer(24)
        .with_dimensions(600, 800)
        .with_title("Button Sample".to_string())
        // .with_multisampling(4)
        // .with_vsync()
        .build_glium().unwrap();

    // Primary user interface elements:
    let mut ui = Pane::new(&display)
        .element(HexButton::new(ui::BOTTOM_RIGHT, (-0.57, 0.37), 1.8, "Previous", ORANGE)
            .mouse_event_handler(Box::new(|_, _| {
            	println!("This button doesn't do much.");
                (UiRequest::None, BackgroundCtl::None)
            }))
        )
        .element(HexButton::new(ui::BOTTOM_RIGHT, (-0.20, 0.37), 1.8, "Next", ORANGE)
            .mouse_event_handler(Box::new(|_, _| {
            	println!("This button does less than the one next to it.");
                (UiRequest::None, BackgroundCtl::None)
            }))
        )
        .element(TextBox::new(ui::BOTTOM_RIGHT, (-0.385, 0.27), 4.45, "Text:", ORANGE, "")
            .keyboard_event_handler(Box::new(|key_st, vk_code, kb_st, text_string| {
                enamel::ui::key_into_string(key_st, vk_code, kb_st, text_string);
                (UiRequest::None, BackgroundCtl::Text(text_string.clone()))
            }))
            .mouse_event_handler(Box::new(|_, _| {
            	println!("TextBox clicked and now has keyboard focus.");
                (UiRequest::KeyboardFocus(true), BackgroundCtl::None)
            }))

        )
        .element(RectButton::new(ui::BOTTOM_RIGHT, (-0.57, 0.17), 4.8, "Start", ORANGE)
            .mouse_event_handler(Box::new(|_, _| {
            	printlnc!(lime_bold: "Start clicked!");
                (UiRequest::None, BackgroundCtl::Start)
            }))
        )
        .element(RectButton::new(ui::BOTTOM_RIGHT, (-0.20, 0.17), 4.8, "Stop", ORANGE)
            .mouse_event_handler(Box::new(|_, _| {                     
                printlnc!(red_bold: "Stop clicked!");
                (UiRequest::None, BackgroundCtl::Stop)
            }))
        )
        .element(RectButton::new(ui::BOTTOM_RIGHT, (-0.20, 0.07), 4.8, "Exit", ORANGE)
            .mouse_event_handler(Box::new(|_, _| {
                printlnc!(yellow_bold: "Exit clicked!");
                (UiRequest::None, BackgroundCtl::Event(Event::Closed))
            }))
        )
        .init();

    // This can be whatever we want as long as it implements `SetMouseFocus`:
    let mut background = Background::new();

    printlnc!(white: "Enamel 'typical' example running. Press 'ctrl + q' or \
        push the 'Exit' button to quit.");

    loop {
        // Create draw target and clear color and depth:
        let mut target = display.draw();
        target.clear_color_and_depth((0.03, 0.03, 0.05, 1.0), 1.0);

        // Check input events:
        for ev in display.poll_events() {
            background.handle_event_remainder(ui.handle_event(ev));
        }

        // Draw UI:
        ui.draw(&mut target);

        // Swap buffers:
        target.finish().unwrap();

        if background.closed { break; }
    }
}