Canvas
Technically, the canvas is a built-in control. Nevertheless, its way to handle resources is very similar to a Ui.
Canvas is a light wrapper over the Direct2D api. As of
BETA1, only a few functions have been implemented. More will be added in the
BETA2
release. The Canvas control is planned to wrap the whole Direct2D API.
For a concrete example, see the
canvas example.
A canvas can be added to an existing Ui using the template
CanvasT
or using the
nwg_canvas!
macro. The template
do not have any particular properties:
pub struct CanvasT<ID: Hash+Clone> {
pub parent: ID,
pub position: (i32, i32),
pub size: (u32, u32),
pub visible: bool,
pub disabled: bool,
}
The canvas control accept a wide range of events, enabling it to respond easily to any user input:
Event::Destroyed, Event::KeyDown, Event::KeyUp, Event::Char, Event::MouseDown, Event::MouseUp, Event::Moved, Event::Resized, Event::Paint, Event::Raw
Just like a Ui needs to be packed with controls and resources, a canvas needs to be packed with brushes, pen and other drawing utilities.
Canvas has a set of methods like
create_solid_brush
that creates a named resource in the canvas. Then, this resource can be used in the painting phase.
Those functions take a ID using the same type as the UI and a struct defined under the
nwg::constants
module.
let mut canvas = nwg_get_mut!(app; ("Canvas", nwg::Canvas<&'static str>));
let b1 = nwgc::SolidBrush{color:(0.0, 0.7, 1.0, 1.0)};
let b2 = nwgc::SolidBrush{color:(0.0, 1.0, 0.5, 1.0)};
let b3 = nwgc::SolidBrush{color:(1.0, 1.0, 0.0, 1.0)};
let p1 = nwgc::Pen {
start_cap: nwgc::CapStyle::Round,
end_cap: nwgc::CapStyle::Round,
dash_cap: nwgc::CapStyle::Round,
line_join: nwgc::LineJoin::Round,
miter_limit: 0.0,
dash_style: nwgc::DashStyle::Dash,
dash_offset: 5.0
};
canvas.create_solid_brush(&"SolidBrush1", &b1).expect("Failed to create brush 1");
canvas.create_solid_brush(&"SolidBrush2", &b2).expect("Failed to create brush 2");
canvas.create_solid_brush(&"SolidBrush3", &b3).expect("Failed to create brush 3");
canvas.create_pen(&"DashedPen", &p1).expect("Failed to create pen");
Painting is the action of drawing shapes and stuff on a canvas. It should only be done during a
Paint
event.
To begin drawing into a canvas, a
CanvasRenderer
object must be requested using the
canvas.renderer()
method. Under very rare circumstances, the renderer
function can fail.
Once the renderer is acquired, functions like
clear
,
get_render_size
or
set_transform
can be used to prepare the renderer settings when drawing stuff.
Finally, methods like
draw_*
and
fill_*
can be used to draw the outline or fill a shape.
("Canvas", "Paint", Event::Paint, |app, _, _, _| {
let mut canvas = nwg_get_mut!(app; ("Canvas", nwg::Canvas<&'static str>));
// Get the renderer and clear the last scene
let mut renderer = canvas.renderer().unwrap();
renderer.clear(0.3, 0.3, 0.6, 1.0);
// Drawing setup
let (w, h) = renderer.get_render_size();
renderer.set_transform( &[[1.0, 0.0], [0.0, 1.0], [w/2.0, h/2.0]] );
let r1 = nwgc::Rectangle{left: -50.0, right: 50.0, top: -50.0, bottom: 50.0};
let r2 = nwgc::Rectangle{left: -100.0, right: 100.0, top: -100.0, bottom: 100.0};
let r3 = nwgc::Rectangle{left: -200.0, right: 200.0, top: -200.0, bottom: 200.0};
let e1 = nwgc::Ellipse{ center: (0.0, 0.0), radius: (25.0, 25.0) };
let e2 = nwgc::Ellipse{ center: (0.0, 0.0), radius: (190.0, 190.0) };
// Draw the shapes
renderer.draw_ellipse(&"SolidBrush2", Some(&"DashedPen"), &e2, 6.0).unwrap();
renderer.draw_rectangle(&"SolidBrush3", None, &r3, 3.0).unwrap();
renderer.fill_rectangle(&"SolidBrush2", &r2).unwrap();
renderer.fill_rounded_rectangle(&"SolidBrush1", &r1, (15.0, 15.0)).unwrap();
renderer.fill_ellipse(&"SolidBrush3", &e1).unwrap();
}),
The canvas control has a few other methods not directly related to painting.
Force the canvas to redraw itself. Don't call this while handling the
Paint
event.
Get or set the dot per inch of the canvas so that the painted result look consistently good across a wide variety of high-DPI display settings.
For more information see:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd756649(v=vs.85).aspx
canvas.set_dpi(100.0, 100.0);
let (dpi_x, dpi_y) = canvas.get_dpi();
Calling
canvas.set_size
resize the window control, but not the underlying render target of the canvas. If the control size do not match the render size,
the painted image will be downscaled or upscaled. In order to set the render_size,
set_render_size
can be used.
For a detailed example of what happens see:
https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
let mut canvas = nwg_get_mut!(app; ("Canvas", nwg::Canvas<&'static str>));
canvas.set_size(w, h);
canvas.set_render_size(w, h);