basic druid drawing canvas
This commit is contained in:
parent
995c544149
commit
20ffea1dbe
|
|
@ -67,6 +67,15 @@ version = "1.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "bitmaps"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
|
|
@ -275,6 +284,7 @@ dependencies = [
|
|||
"fluent-langneg",
|
||||
"fluent-syntax",
|
||||
"fnv",
|
||||
"im",
|
||||
"instant",
|
||||
"log",
|
||||
"simple_logger",
|
||||
|
|
@ -748,6 +758,20 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "im"
|
||||
version = "15.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "111c1983f3c5bb72732df25cddacee9b546d08325fb584b5ebd38148be7b0246"
|
||||
dependencies = [
|
||||
"bitmaps",
|
||||
"rand_core",
|
||||
"rand_xoshiro",
|
||||
"sized-chunks",
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "input"
|
||||
version = "0.5.0"
|
||||
|
|
@ -1113,6 +1137,21 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
|
||||
[[package]]
|
||||
name = "rand_xoshiro"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9fcdd2e881d02f1d9390ae47ad8e5696a9e4be7b547a1da2afbc61973217004"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.1.9"
|
||||
|
|
@ -1224,6 +1263,16 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sized-chunks"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ec31ceca5644fa6d444cc77548b88b67f46db6f7c71683b0f9336e671830d2f"
|
||||
dependencies = [
|
||||
"bitmaps",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.2"
|
||||
|
|
@ -1310,6 +1359,7 @@ dependencies = [
|
|||
"gdk",
|
||||
"gio",
|
||||
"gtk",
|
||||
"im",
|
||||
"input",
|
||||
"libc",
|
||||
"udev 0.2.0",
|
||||
|
|
@ -1441,6 +1491,12 @@ dependencies = [
|
|||
"fxhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33"
|
||||
|
||||
[[package]]
|
||||
name = "udev"
|
||||
version = "0.2.0"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ udev = "0.2"
|
|||
libc = "0.2"
|
||||
errno = "0.2"
|
||||
csv = "1.1"
|
||||
druid = { git = "https://github.com/doppioandante/druid", branch = "stylus_events" }
|
||||
druid = { git = "https://github.com/doppioandante/druid", branch = "stylus_events", features = ["im"] }
|
||||
im = { version = "*" }
|
||||
|
||||
[dependencies.gtk]
|
||||
version = "0.9.2"
|
||||
|
|
|
|||
110
src/main.rs
110
src/main.rs
|
|
@ -14,37 +14,67 @@
|
|||
|
||||
//! An example of a custom drawing widget.
|
||||
|
||||
use druid::im::{vector, Vector};
|
||||
use druid::kurbo::BezPath;
|
||||
use druid::piet::{FontFamily, ImageFormat, InterpolationMode};
|
||||
use druid::widget::prelude::*;
|
||||
use druid::{
|
||||
Affine, AppLauncher, ArcStr, Color, FontDescriptor, LocalizedString, Point, Rect, TextLayout,
|
||||
Affine, AppLauncher, ArcStr, Color, Data, Event, FontDescriptor, LocalizedString, Point, Rect, TextLayout,
|
||||
WindowDesc,
|
||||
};
|
||||
|
||||
struct CustomWidget;
|
||||
#[derive(Clone, Data)]
|
||||
struct CanvasData {
|
||||
drawn_paths: Vector<BezPath>,
|
||||
is_drawing: bool,
|
||||
}
|
||||
|
||||
impl Widget<String> for CustomWidget {
|
||||
fn event(&mut self, _ctx: &mut EventCtx, event: &Event, _data: &mut String, _env: &Env) {
|
||||
println!("{:?}", event);
|
||||
struct CanvasWidget;
|
||||
|
||||
impl Widget<CanvasData> for CanvasWidget {
|
||||
fn event(&mut self, _ctx: &mut EventCtx, event: &Event, data: &mut CanvasData, _env: &Env) {
|
||||
match event {
|
||||
Event::MouseDown(mouse_event) => {
|
||||
if mouse_event.pointer_type == druid::PointerType::Stylus {
|
||||
data.is_drawing = true;
|
||||
let mut new_path = BezPath::new();
|
||||
new_path.move_to((mouse_event.pos.x, mouse_event.pos.y));
|
||||
data.drawn_paths.push_back(new_path);
|
||||
}
|
||||
},
|
||||
Event::MouseMove(mouse_event) => {
|
||||
if data.is_drawing && mouse_event.pointer_type == druid::PointerType::Stylus {
|
||||
data.drawn_paths.back_mut().unwrap().line_to((mouse_event.pos.x, mouse_event.pos.y));
|
||||
}
|
||||
},
|
||||
Event::MouseUp(_) => {
|
||||
if data.is_drawing {
|
||||
data.is_drawing = false;
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn lifecycle(
|
||||
&mut self,
|
||||
_ctx: &mut LifeCycleCtx,
|
||||
_event: &LifeCycle,
|
||||
_data: &String,
|
||||
_data: &CanvasData,
|
||||
_env: &Env,
|
||||
) {
|
||||
}
|
||||
|
||||
fn update(&mut self, _ctx: &mut UpdateCtx, _old_data: &String, _data: &String, _env: &Env) {}
|
||||
fn update(&mut self, ctx: &mut UpdateCtx, _old_data: &CanvasData, _data: &CanvasData, _env: &Env) {
|
||||
ctx.request_paint();
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_layout_ctx: &mut LayoutCtx,
|
||||
bc: &BoxConstraints,
|
||||
_data: &String,
|
||||
_data: &CanvasData,
|
||||
_env: &Env,
|
||||
) -> Size {
|
||||
// BoxConstraints are passed by the parent widget.
|
||||
|
|
@ -59,7 +89,7 @@ impl Widget<String> for CustomWidget {
|
|||
// The paint method gets called last, after an event flow.
|
||||
// It goes event -> update -> layout -> paint, and each method can influence the next.
|
||||
// Basically, anything that changes the appearance of a widget causes a paint.
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, data: &String, env: &Env) {
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, data: &CanvasData, _env: &Env) {
|
||||
// Let's draw a picture with Piet!
|
||||
|
||||
// Clear the whole widget with the color of your choice
|
||||
|
|
@ -71,67 +101,23 @@ impl Widget<String> for CustomWidget {
|
|||
// Note: ctx also has a `clear` method, but that clears the whole context,
|
||||
// and we only want to clear this widget's area.
|
||||
|
||||
// Create an arbitrary bezier path
|
||||
let mut path = BezPath::new();
|
||||
path.move_to(Point::ORIGIN);
|
||||
path.quad_to((80.0, 90.0), (size.width, size.height));
|
||||
// Create a color
|
||||
let stroke_color = Color::rgb8(0, 128, 0);
|
||||
// Stroke the path with thickness 1.0
|
||||
ctx.stroke(path, &stroke_color, 1.0);
|
||||
|
||||
// Rectangles: the path for practical people
|
||||
let rect = Rect::from_origin_size((10., 10.), (100., 100.));
|
||||
// Note the Color:rgba8 which includes an alpha channel (7F in this case)
|
||||
let fill_color = Color::rgba8(0x00, 0x00, 0x00, 0x7F);
|
||||
ctx.fill(rect, &fill_color);
|
||||
|
||||
// Text is easy; in real use TextLayout should be stored in the widget
|
||||
// and reused.
|
||||
let mut layout = TextLayout::<ArcStr>::from_text(data.to_owned());
|
||||
layout.set_font(FontDescriptor::new(FontFamily::SERIF).with_size(24.0));
|
||||
layout.set_text_color(fill_color);
|
||||
layout.rebuild_if_needed(ctx.text(), env);
|
||||
|
||||
// Let's rotate our text slightly. First we save our current (default) context:
|
||||
ctx.with_save(|ctx| {
|
||||
// Now we can rotate the context (or set a clip path, for instance):
|
||||
ctx.transform(Affine::rotate(0.1));
|
||||
layout.draw(ctx, (80.0, 40.0));
|
||||
});
|
||||
// When we exit with_save, the original context's rotation is restored
|
||||
|
||||
// Let's burn some CPU to make a (partially transparent) image buffer
|
||||
let image_data = make_image_data(256, 256);
|
||||
let image = ctx
|
||||
.make_image(256, 256, &image_data, ImageFormat::RgbaSeparate)
|
||||
.unwrap();
|
||||
// The image is automatically scaled to fit the rect you pass to draw_image
|
||||
ctx.draw_image(&image, size.to_rect(), InterpolationMode::Bilinear);
|
||||
for path in &data.drawn_paths {
|
||||
ctx.stroke(path, &stroke_color, 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let window = WindowDesc::new(|| CustomWidget {}).title(
|
||||
let window = WindowDesc::new(|| CanvasWidget {}).title(
|
||||
LocalizedString::new("custom-widget-demo-window-title").with_placeholder("Fancy Colors"),
|
||||
);
|
||||
let canvas_data = CanvasData {
|
||||
drawn_paths: vector![],
|
||||
is_drawing: false,
|
||||
};
|
||||
AppLauncher::with_window(window)
|
||||
.use_simple_logger()
|
||||
.launch("Druid + Piet".to_string())
|
||||
.launch(canvas_data)
|
||||
.expect("launch failed");
|
||||
}
|
||||
|
||||
fn make_image_data(width: usize, height: usize) -> Vec<u8> {
|
||||
let mut result = vec![0; width * height * 4];
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let ix = (y * width + x) * 4;
|
||||
result[ix] = x as u8;
|
||||
result[ix + 1] = y as u8;
|
||||
result[ix + 2] = !(x as u8);
|
||||
result[ix + 3] = 127;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue