use wiard::ToLogical;
fn main() -> anyhow::Result<()> {
pnte::co_initialize(pnte::CoInit::ApartmentThreaded)?;
let mut event_rx = wiard::EventReceiver::new();
let window = wiard::Window::builder(&event_rx)
.title("pnte gallery")
.build()?;
let size = window.inner_size().unwrap();
let dpi = window.dpi().unwrap();
let mut ctx = pnte::Context::new(pnte::Direct2D::new()?)?;
ctx.set_scale_factor(dpi as f32 / 96.0);
let target = ctx.create_render_target(&window, (size.width, size.height))?;
let image = pnte::Image::from_file(&ctx, "./assets/ferris.png")?;
let image_size = image.size();
let image_size = pnte::Size::new(image_size.width / 8.0, image_size.height / 8.0);
let white = pnte::SolidColorBrush::new(&ctx, (1.0, 1.0, 1.0, 1.0))?;
let text_format = pnte::TextFormat::new(&ctx)
.font(pnte::Font::File(
&std::path::Path::new(
"./assets/Inconsolata/static/Inconsolata/Inconsolata-Regular.ttf",
),
"Inconsolata",
))
.size(pnte::FontPoint(25.0))
.build()?;
let text_layout = pnte::TextLayout::new(&ctx)
.text("abcdefghijklmnopqrstuvwxyz")
.format(&text_format)
.build()?;
let pt_text = pnte::Point::new(10.0, 530.0);
let layout_size = text_layout.size();
let mut hit_test_display: Option<(char, bool)> = None;
loop {
let Some((event, _)) = event_rx.recv() else {
break;
};
match event {
wiard::Event::MouseInput(m) => {
let left_button = m.button == wiard::MouseButton::Left
&& m.button_state == wiard::ButtonState::Released;
if left_button {
let dpi = window.dpi().unwrap();
let mouse_position = m.mouse_state.position.to_logical(dpi as i32);
let mouse_position =
pnte::Point::new(mouse_position.x as f32, mouse_position.y as f32);
let inside = pt_text.x <= mouse_position.x
&& pt_text.y <= mouse_position.y
&& pt_text.x + layout_size.width >= mouse_position.x
&& pt_text.y + layout_size.height >= mouse_position.y;
if inside {
let result = text_layout.hit_test((
mouse_position.x - pt_text.x,
mouse_position.y - pt_text.y,
))?;
if result.inside {
hit_test_display = Some((result.c, result.trailing_hit));
}
}
}
window.redraw(None);
}
wiard::Event::Draw(_) => {
ctx.draw(&target, |cmd| -> anyhow::Result<()> {
cmd.clear((0.0, 0.0, 0.3, 0.0));
let pt = pnte::Point::new(10.0, 0.0);
cmd.draw_text("image", pt, &white)?;
let pt = pnte::Point::new(10.0, 20.0);
cmd.draw_image(
&image,
None,
(
pt.x + 10.0,
pt.y,
pt.x + 10.0 + image_size.width,
pt.y + 10.0 + image_size.height,
),
None,
pnte::Interpolation::HighQualityCubic,
);
let pt = pnte::Point::new(10.0, 20.0 + image_size.height + 10.0);
cmd.draw_text("image (opacity = 0.5)", pt, &white)?;
let pt = pnte::Point::new(pt.x, pt.y + 20.0);
cmd.draw_image(
&image,
None,
(
pt.x + 10.0,
pt.y,
pt.x + 10.0 + image_size.width,
pt.y + 10.0 + image_size.height,
),
Some(0.5),
pnte::Interpolation::HighQualityCubic,
);
let pt = pnte::Point::new(image_size.width + 100.0, 0.0);
cmd.draw_text("stroke line (width = 2.0)", pt, &white)?;
cmd.stroke(
&pnte::Line::new((pt.x, 30.0), (pt.x + 200.0, 90.0)),
&white,
2.0,
None,
);
let pt = pnte::Point::new(pt.x, 90.0 + 10.0);
let line_style = pnte::StrokeStyle::new(
&ctx,
&pnte::StrokeStyleProperties {
start_cap: pnte::CapStyle::Round,
end_cap: pnte::CapStyle::Triangle,
line_join: pnte::LineJoin::Miter,
dash: Some(pnte::Dash {
cap: pnte::CapStyle::Flat,
style: pnte::DashStyle::DashDot,
offset: 0.0,
}),
},
)?;
cmd.draw_text("stroke line (styled)", pt, &white)?;
cmd.stroke(
&pnte::Line::new((pt.x, pt.y + 30.0), (pt.x + 200.0, pt.y + 90.0)),
&white,
2.0,
Some(&line_style),
);
let pt = pnte::Point::new(pt.x, pt.y + 90.0 + 10.0);
cmd.draw_text("stroke quadratic bezier", pt, &white)?;
let pt = pnte::Point::new(pt.x, pt.y + 30.0);
let path = pnte::Path::builder(&ctx, pt)?
.quadratic_bezier_to(
(pt.x + 20.0, pt.y + 90.0),
(pt.x + 200.0, pt.y + 90.0),
)
.build(pnte::PathEnd::Open)?;
cmd.stroke(&path, &white, 2.0, None);
let pt = pnte::Point::new(pt.x, pt.y + 90.0 + 10.0);
cmd.draw_text("stroke cubic bezier", pt, &white).unwrap();
let pt = pnte::Point::new(pt.x, pt.y + 30.0);
let path = pnte::Path::builder(&ctx, pt)?
.cubic_bezier_to(
(pt.x + 100.0, pt.y),
(pt.x + 100.0, pt.y + 90.0),
(pt.x + 200.0, pt.y + 90.0),
)
.build(pnte::PathEnd::Open)?;
cmd.stroke(&path, &white, 2.0, None);
let pt_text_caption = pnte::Point::new(pt_text.x, pt_text.y - 30.0);
cmd.draw_text("text", pt_text_caption, &white)?;
cmd.draw_text(&text_layout, pt_text, &white)?;
if let Some((c, trailing_hit)) = hit_test_display.as_ref() {
let pt_text = pnte::Point::new(pt_text.x, pt_text.y + 35.0);
cmd.draw_text(
&format!("{c}, trailing_hit = {trailing_hit}"),
pt_text,
&white,
)?;
}
let pt_text_caption = pnte::Point::new(pt_text.x, pt_text.y + 35.0 + 30.0);
cmd.draw_text("accent", pt_text_caption, &white)?;
let pt_text = pnte::Point::new(pt_text_caption.x, pt_text_caption.y + 30.0);
cmd.draw_text("é à â ü ç", pt_text, &white)?;
let pt = pnte::Point::new(pt.x + 230.0, 0.0);
cmd.draw_text("fill rectangle", pt, &white)?;
let pt = pnte::Point::new(pt.x, pt.y + 30.0);
cmd.fill(&pnte::Rect::from_point_size(pt, (60.0, 60.0)), &white);
let pt = pnte::Point::new(pt.x, pt.y + 90.0);
cmd.draw_text("fill circle", pt, &white)?;
let pt_circle = pnte::Point::new(pt.x + 30.0, pt.y + 30.0 + 30.0);
cmd.fill(&pnte::Circle::new(pt_circle, 30.0), &white);
let pt = pnte::Point::new(pt.x, pt_circle.y + 60.0);
cmd.draw_text("fill ellipse", pt, &white)?;
let pt_ellipse = pnte::Point::new(pt.x + 30.0, pt.y + 30.0 + 30.0);
cmd.fill(&pnte::Ellipse::new(pt_ellipse, 30.0, 15.0), &white);
let pt = pnte::Point::new(pt.x + 150.0, 0.0);
let grad = pnte::LinearGradientBrush::new(
&ctx,
pt,
(pt.x + 60.0, pt.y),
pnte::GradientMode::Clamp,
&[
pnte::GradientStop::new(0.0, (1.0, 0.0, 0.0, 1.0)),
pnte::GradientStop::new(0.5, (0.0, 1.0, 0.0, 1.0)),
pnte::GradientStop::new(1.0, (0.0, 0.0, 1.0, 1.0)),
],
)?;
cmd.draw_text("line gradient", pt, &white)?;
let pt = pnte::Point::new(pt.x, pt.y + 30.0);
cmd.fill(&pnte::Rect::from_point_size(pt, (60.0, 60.0)), &grad);
let pt = pnte::Point::new(pt.x, pt.y + 60.0 + 30.0);
cmd.draw_text("radial gradient", pt, &white)?;
let pt = pnte::Point::new(pt.x, pt.y + 30.0);
let grad = pnte::RadialGradientBrush::new(
&ctx,
pnte::Circle::new((pt.x + 30.0, pt.y + 30.0), 30.0).to_ellipse(),
(0.0, 0.0),
pnte::GradientMode::Clamp,
&[
pnte::GradientStop::new(0.0, (1.0, 0.0, 0.0, 1.0)),
pnte::GradientStop::new(0.5, (0.0, 1.0, 0.0, 1.0)),
pnte::GradientStop::new(1.0, (0.0, 0.0, 1.0, 1.0)),
],
)?;
cmd.fill(&pnte::Rect::from_point_size(pt, (60.0, 60.0)), &grad);
Ok(())
})??;
}
_ => {}
}
}
Ok(())
}