绘制事物 Drawing things

fltk-rsdraw mod中提供了可以绘制自定义元素的函数。但是只有当绘制函数的调用是在特定的上下文中时,例如在WidgetBase::draw()方法中或在Offscreen上下文中,绘制才有效:

在组件上绘制

注意,我们在组件的draw方法中使用了draw

use fltk::{enums, prelude::*, *};

fn main() {
    let a = app::App::default();
    let mut win = window::Window::default().with_size(400, 300);
    win.end();
    win.show();

    win.draw(|w| {
        use draw::*;
        // 白色窗口
        draw_rect_fill(0, 0, w.w(), w.h(), enums::Color::White);
        // 画一个蓝色的圆
        set_draw_color(enums::Color::Blue.inactive());
        draw_pie(w.w() / 2 - 50, w.h() / 2 - 50, 100, 100, 0.0, 360.0);
        // 让文字旋转一定角度
        set_draw_color(enums::Color::Red);
        set_font(enums::Font::Courier, 16);
        draw_text_angled(45, "Hello World", w.w() / 2, w.h() / 2);
    });

    a.run().unwrap();
}

draw

我们用了整个窗口当绘制的画板,任何其他组件理论上都可以进行绘制。还有许多其他函数可以让你绘制直线、矩形、弧线、饼、循环、多边形,甚至图像。

屏幕外事件的绘制

有时可能会需要通过绘制来响应一些事件,例如拖动鼠标时,在屏幕上绘制出鼠标的轨迹。在这种情况下,你可以使用draw::Offscreen来做到这一点。我们所用组件的draw方法只是复制屏幕外事件的内容,例如鼠标的坐标,而绘制是在组件的handle方法中进行的。

use fltk::{
    app,
    draw::{
        draw_line, draw_point, draw_rect_fill, set_draw_color, set_line_style, LineStyle, Offscreen,
    },
    enums::{Color, Event, FrameType},
    frame::Frame,
    prelude::*,
    window::Window,
};
use std::cell::RefCell;
use std::rc::Rc;

const WIDTH: i32 = 800;
const HEIGHT: i32 = 600;

fn main() {
    let app = app::App::default().with_scheme(app::Scheme::Gtk);

    let mut wind = Window::default()
        .with_size(WIDTH, HEIGHT)
        .with_label("RustyPainter");
    let mut frame = Frame::default()
        .with_size(WIDTH - 10, HEIGHT - 10)
        .center_of(&wind);
    frame.set_color(Color::White);
    frame.set_frame(FrameType::DownBox);

    wind.end();
    wind.show();

    // 用白色填充
    let offs = Offscreen::new(frame.width(), frame.height()).unwrap();
    #[cfg(not(target_os = "macos"))]
    {
        offs.begin();
        draw_rect_fill(0, 0, WIDTH - 10, HEIGHT - 10, Color::White);
        offs.end();
    }

    let offs = Rc::from(RefCell::from(offs));

    frame.draw({
        let offs = offs.clone();
        move |_| {
            let mut offs = offs.borrow_mut();
            if offs.is_valid() {
                offs.rescale();
                offs.copy(5, 5, WIDTH - 10, HEIGHT - 10, 0, 0);
            } else {
                offs.begin();
                draw_rect_fill(0, 0, WIDTH - 10, HEIGHT - 10, Color::White);
                offs.copy(5, 5, WIDTH - 10, HEIGHT - 10, 0, 0);
                offs.end();
            }
        }
    });

    frame.handle({
        let mut x = 0;
        let mut y = 0;
        move |f, ev| {
            // println!("{}", ev);
            // println!("coords {:?}", app::event_coords());
            // println!("get mouse {:?}", app::get_mouse());
            let offs = offs.borrow_mut();
            match ev {
                Event::Push => {
                    offs.begin();
                    set_draw_color(Color::Red);
                    set_line_style(LineStyle::Solid, 3);
                    let coords = app::event_coords();
                    x = coords.0;
                    y = coords.1;
                    draw_point(x, y);
                    offs.end();
                    f.redraw();
                    set_line_style(LineStyle::Solid, 0);
                    true
                }
                Event::Drag => {
                    offs.begin();
                    set_draw_color(Color::Red);
                    set_line_style(LineStyle::Solid, 3);
                    let coords = app::event_coords();
                    draw_line(x, y, coords.0, coords.1);
                    x = coords.0;
                    y = coords.1;
                    offs.end();
                    f.redraw();
                    set_line_style(LineStyle::Solid, 0);
                    true
                }
                _ => false,
            }
        }
    });

    app.run().unwrap();
}

注意,这里我们用offs.begin()开始了OffScreen上下文,用offs.end()表示上下文结束。只有在上下文内,我们才能调用Offscreen绘图函数:

image