native-windows-gui 1.0.13

A rust library to develop native GUI applications on the desktop for Microsoft Windows. Native-windows-gui wraps the native win32 window controls in a rustic API
Documentation
/*!

    Small custom control example using GDI. NWG has no drawing API, so raw winapi must be used.

    Requires the following features: `cargo run --example basic_drawing_d --features "extern-canvas"`
*/

extern crate native_windows_gui as nwg;
extern crate native_windows_derive as nwd;

use nwd::NwgUi;
use nwg::NativeUi;
use std::mem;
use std::cell::{RefCell, Cell};
use winapi::shared::windef::{HBRUSH, HPEN};
use winapi::um::wingdi::{CreateSolidBrush, CreatePen, Ellipse, Polygon, SelectObject, RGB, PS_SOLID};


pub struct PaintData {
    background: HBRUSH,
    border: HBRUSH,
    pen: HPEN,
    yellow: HBRUSH,
    white: HBRUSH,
    black: HBRUSH,
    red: HBRUSH,
}

impl Default for PaintData {
    fn default() -> Self {
        unsafe { mem::zeroed() }
    }
}

#[derive(Default, NwgUi)]
pub struct DrawingApp {
    #[nwg_control(size: (300, 300), position: (300, 300), title: "Drawing (that's a duck)", flags: "WINDOW|VISIBLE")]
    #[nwg_events( OnWindowClose: [nwg::stop_thread_dispatch()], OnInit: [DrawingApp::setup])]
    window: nwg::Window,

    // By default ExternCanvas is a window so we must specify the parent here
    #[nwg_control(parent: Some(&data.window), position: (10, 10), size: (280, 280))]
    #[nwg_events( 
        OnPaint: [DrawingApp::paint(SELF, EVT_DATA)], 
        OnMousePress: [DrawingApp::events(SELF, EVT)],
    )]
    canvas: nwg::ExternCanvas,

    paint_data: RefCell<PaintData>,
    clicked: Cell<bool>,
}

impl DrawingApp {

    fn setup(&self) {
        let mut data = self.paint_data.borrow_mut();
        unsafe {
            data.background = CreateSolidBrush(RGB(190, 190, 255));
            data.border = CreateSolidBrush(RGB(100, 100, 255));
            data.pen = CreatePen(PS_SOLID as _, 2, RGB(20, 20, 20));
            data.yellow = CreateSolidBrush(RGB(255, 255, 0));
            data.white = CreateSolidBrush(RGB(255, 255, 255));
            data.black = CreateSolidBrush(RGB(10, 10, 10));
            data.red = CreateSolidBrush(RGB(255, 10, 0));
        }
    }

    fn events(&self, evt: nwg::Event) {
        use nwg::Event as E;
        use nwg::MousePressEvent as M;

        match evt {
            E::OnMousePress(M::MousePressLeftUp) => { self.clicked.set(false); },
            E::OnMousePress(M::MousePressLeftDown) => { self.clicked.set(true); },
            _ => {},
        }

        self.canvas.invalidate();
    }

    fn paint(&self, data: &nwg::EventData) {
        use winapi::um::winuser::{FillRect, FrameRect};
        use winapi::shared::windef::POINT as P;
        
        let paint = data.on_paint();
        let ps = paint.begin_paint();
        
        unsafe {
            let p = self.paint_data.borrow();
            let hdc = ps.hdc;
            let rc = &ps.rcPaint;

            FillRect(hdc, rc, p.background as _);
            FrameRect(hdc, rc, p.border as _);

            SelectObject(hdc, p.pen as _);
            SelectObject(hdc, p.yellow as _);
            Ellipse(hdc, rc.left + 20, rc.top + 20, rc.right - 20, rc.bottom - 20);

            SelectObject(hdc, p.white as _);
            Ellipse(hdc, 60, 60, 130, 130);
            Ellipse(hdc, 150, 60, 220, 130);

            if self.clicked.get() {
                SelectObject(hdc, p.red as _);
            } else {
                SelectObject(hdc, p.black as _);
            }
            
            Ellipse(hdc, 80, 80, 110, 110);
            Ellipse(hdc, 170, 80, 200, 110);

            SelectObject(hdc, p.red as _);
            let pts = &[P{x: 60, y: 150}, P{x: 220, y: 150}, P{x: 140, y: 220}];
            Polygon(hdc, pts.as_ptr(), pts.len() as _);
        }

        paint.end_paint(&ps);
    }

}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");

    let _app = DrawingApp::build_ui(Default::default()).expect("Failed to build UI");

    nwg::dispatch_thread_events();
}