Add a bevy-texture example based on wgpu-texture (#4360)

* Add a bevy-texture example based on wgpu-texture

* Use git branch of Blitz

* Update existing code to new blitz

* Use Device from Dioxus for bevy

* Use ManualTextureView

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Fix texture size on window resize

* Clean code

* Rename example to 'bevy-example' in 'bevy' directory

* Upgrade to blitz 0.1.0-alpha.5 and anyrender 0.4

* Install alsa in CI

Signed-off-by: Nico Burns <nico@nicoburns.com>

* Add libudev to CI

Signed-off-by: Nico Burns <nico@nicoburns.com>

---------

Signed-off-by: Nico Burns <nico@nicoburns.com>
Co-authored-by: Jerome Caucat <jerome.caucat@smartshape.com>
Co-authored-by: Nico Burns <nico@nicoburns.com>
This commit is contained in:
authored and GitHub committed 2025-07-04 22:01:00 +01:00
1 parent a66bffb487
commit 5495bcedb4
14 files changed
+2426 -79

No files matched your search

+6 -6
View File
@@ -73,7 +73,7 @@ jobs:
uses: ./.github/actions/free-disk-space uses: ./.github/actions/free-disk-space
- uses: awalsh128/cache-apt-pkgs-action@latest - uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
packages: libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev packages: libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libudev-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev
version: 1.0 version: 1.0
- uses: dtolnay/rust-toolchain@1.86.0 - uses: dtolnay/rust-toolchain@1.86.0
with: with:
@@ -94,7 +94,7 @@ jobs:
uses: ./.github/actions/free-disk-space uses: ./.github/actions/free-disk-space
- uses: awalsh128/cache-apt-pkgs-action@latest - uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
packages: libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev packages: libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libudev-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev
version: 1.0 version: 1.0
- uses: dtolnay/rust-toolchain@1.86.0 - uses: dtolnay/rust-toolchain@1.86.0
with: with:
@@ -127,7 +127,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: awalsh128/cache-apt-pkgs-action@latest - uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
packages: libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev packages: libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libudev-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev
version: 1.0 version: 1.0
- name: Install Rust ${{ env.rust_nightly }} - name: Install Rust ${{ env.rust_nightly }}
uses: dtolnay/rust-toolchain@nightly uses: dtolnay/rust-toolchain@nightly
@@ -150,7 +150,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: awalsh128/cache-apt-pkgs-action@latest - uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
packages: libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev packages: libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libudev-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev
version: 1.0 version: 1.0
- uses: dtolnay/rust-toolchain@1.86.0 - uses: dtolnay/rust-toolchain@1.86.0
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
@@ -166,7 +166,7 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: awalsh128/cache-apt-pkgs-action@latest - uses: awalsh128/cache-apt-pkgs-action@latest
with: with:
packages: libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev packages: libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libudev-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev
version: 1.0 version: 1.0
- uses: dtolnay/rust-toolchain@1.86.0 - uses: dtolnay/rust-toolchain@1.86.0
with: with:
@@ -318,7 +318,7 @@ jobs:
- uses: awalsh128/cache-apt-pkgs-action@latest - uses: awalsh128/cache-apt-pkgs-action@latest
if: ${{ matrix.platform.os == 'ubuntu-24.04' || matrix.platform.os == 'ubuntu-24.04-arm' }} if: ${{ matrix.platform.os == 'ubuntu-24.04' || matrix.platform.os == 'ubuntu-24.04-arm' }}
with: with:
packages: libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev packages: libwebkit2gtk-4.1-dev libgtk-3-dev libasound2-dev libudev-dev libayatana-appindicator3-dev libxdo-dev libglib2.0-dev
version: ${{ matrix.platform.target }}-${{ matrix.platform.os }} # disambiguate since we're in a matrix and this caching action doesn't factor in these variables version: ${{ matrix.platform.target }}-${{ matrix.platform.os }} # disambiguate since we're in a matrix and this caching action doesn't factor in these variables
- name: Install cross - name: Install cross
Generated
+1872 -58
View File
File diff suppressed because it is too large. Load diff
+1
View File
@@ -114,6 +114,7 @@ members = [
"examples/fullstack-auth", "examples/fullstack-auth",
"examples/fullstack-websockets", "examples/fullstack-websockets",
"examples/wgpu-texture", "examples/wgpu-texture",
"examples/bevy",
# Playwright tests # Playwright tests
"packages/playwright-tests/liveview", "packages/playwright-tests/liveview",
+20
View File
@@ -0,0 +1,20 @@
[package]
name = "bevy-example"
version = "0.0.0"
edition = "2021"
license = "MIT"
publish = false
[features]
default = ["desktop"]
desktop = ["dioxus/desktop"]
native = ["dioxus/native"]
tracing = ["dep:tracing-subscriber", "dioxus-native/tracing"]
[dependencies]
bevy = { version = "0.16" }
dioxus-native = { path = "../../packages/native" }
dioxus = { workspace = true }
wgpu = "24"
color = "0.3"
tracing-subscriber = { workspace = true, optional = true }
+163
View File
@@ -0,0 +1,163 @@
use crate::bevy_scene_plugin::BevyScenePlugin;
use bevy::{
prelude::*,
render::{
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
render_resource::TextureFormat,
renderer::{
RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue,
WgpuWrapper,
},
settings::{RenderCreation, RenderResources},
RenderPlugin,
},
};
use dioxus_native::{CustomPaintCtx, DeviceHandle, TextureHandle};
use std::sync::Arc;
use wgpu::Instance;
#[derive(Resource, Default)]
pub struct UIData {
pub color: [f32; 3],
}
pub struct BevyRenderer {
app: App,
wgpu_device: wgpu::Device,
last_texture_size: (u32, u32),
texture_handle: Option<TextureHandle>,
manual_texture_view_handle: Option<ManualTextureViewHandle>,
}
impl BevyRenderer {
pub fn new(instance: &Instance, device_handle: &DeviceHandle) -> Self {
// Create a headless Bevy App.
let mut app = App::new();
app.add_plugins(
DefaultPlugins
.set(RenderPlugin {
// Reuse the render resources from the Dioxus native renderer.
render_creation: RenderCreation::Manual(RenderResources(
RenderDevice::new(WgpuWrapper::new(device_handle.device.clone())),
RenderQueue(Arc::new(WgpuWrapper::new(device_handle.queue.clone()))),
RenderAdapterInfo(WgpuWrapper::new(device_handle.adapter.get_info())),
RenderAdapter(Arc::new(WgpuWrapper::new(device_handle.adapter.clone()))),
RenderInstance(Arc::new(WgpuWrapper::new(instance.clone()))),
)),
synchronous_pipeline_compilation: true,
..default()
})
.set(WindowPlugin {
primary_window: None,
exit_condition: bevy::window::ExitCondition::DontExit,
close_when_requested: false,
})
.disable::<bevy::winit::WinitPlugin>(),
);
// Setup the rendering to texture.
app.insert_resource(ManualTextureViews::default());
// Add data from the UI.
app.insert_resource(UIData::default());
// Add the Bevy scene.
app.add_plugins(BevyScenePlugin {});
// Initialize the app to set up the render world properly.
app.finish();
app.cleanup();
Self {
app,
wgpu_device: device_handle.device.clone(),
last_texture_size: (0, 0),
texture_handle: None,
manual_texture_view_handle: None,
}
}
pub fn render(
&mut self,
ctx: CustomPaintCtx<'_>,
color: [f32; 3],
width: u32,
height: u32,
_start_time: &std::time::Instant,
) -> Option<TextureHandle> {
// Update the UI data.
if let Some(mut ui) = self.app.world_mut().get_resource_mut::<UIData>() {
ui.color = color;
}
// Init self.texture_handle if None or if width/height changed.
self.init_texture(ctx, width, height);
// Run one frame of the Bevy app to render the 3D scene.
self.app.update();
self.texture_handle
}
fn init_texture(&mut self, mut ctx: CustomPaintCtx<'_>, width: u32, height: u32) {
// Reuse self.texture_handle if already initialized to the correct size.
let current_size = (width, height);
if self.texture_handle.is_some() && self.last_texture_size == current_size {
return;
}
let world = self.app.world_mut();
// Skip if no camera.
if world.query::<&Camera>().single(world).is_err() {
return;
}
if let Some(mut manual_texture_views) = world.get_resource_mut::<ManualTextureViews>() {
// Clean previous texture if any.
if let Some(texture_handle) = self.texture_handle {
ctx.unregister_texture(texture_handle);
self.texture_handle = None;
}
if let Some(old_handle) = self.manual_texture_view_handle {
manual_texture_views.remove(&old_handle);
self.manual_texture_view_handle = None;
}
// Create the texture for the camera target and the CustomPaintCtx.
let format = TextureFormat::Rgba8UnormSrgb;
let wgpu_texture = self.wgpu_device.create_texture(&wgpu::TextureDescriptor {
label: None,
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format,
usage: wgpu::TextureUsages::TEXTURE_BINDING
| wgpu::TextureUsages::RENDER_ATTACHMENT
| wgpu::TextureUsages::COPY_SRC,
view_formats: &[],
});
let wgpu_texture_view =
wgpu_texture.create_view(&wgpu::TextureViewDescriptor::default());
let manual_texture_view = ManualTextureView {
texture_view: wgpu_texture_view.into(),
size: bevy::math::UVec2::new(width, height),
format,
};
let manual_texture_view_handle = ManualTextureViewHandle(0);
manual_texture_views.insert(manual_texture_view_handle, manual_texture_view);
if let Ok(mut camera) = world.query::<&mut Camera>().single_mut(world) {
camera.target = RenderTarget::TextureView(manual_texture_view_handle);
self.last_texture_size = current_size;
self.manual_texture_view_handle = Some(manual_texture_view_handle);
self.texture_handle = Some(ctx.register_texture(wgpu_texture));
}
}
}
}
+77
View File
@@ -0,0 +1,77 @@
use crate::bevy_renderer::UIData;
use bevy::prelude::*;
#[derive(Component)]
pub struct DynamicColoredCube;
pub struct BevyScenePlugin {}
impl Plugin for BevyScenePlugin {
fn build(&self, app: &mut App) {
app.insert_resource(ClearColor(bevy::color::Color::srgba(0.0, 0.0, 0.0, 0.0)));
app.add_systems(Startup, setup);
app.add_systems(Update, (animate, update_cube_color));
}
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: bevy::color::Color::srgb(1.0, 0.0, 0.0),
metallic: 0.0,
perceptual_roughness: 0.5,
..default()
})),
Transform::from_xyz(0.0, 0.0, 0.0),
DynamicColoredCube,
));
commands.spawn((
DirectionalLight {
color: bevy::color::Color::WHITE,
illuminance: 10000.0,
shadows_enabled: false,
..default()
},
Transform::from_xyz(1.0, 1.0, 1.0).looking_at(Vec3::ZERO, Vec3::Y),
));
commands.insert_resource(AmbientLight {
color: bevy::color::Color::WHITE,
brightness: 100.0,
affects_lightmapped_meshes: true,
});
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 0.0, 3.0).looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
Name::new("MainCamera"),
));
}
fn animate(time: Res<Time>, mut cube_query: Query<&mut Transform, With<DynamicColoredCube>>) {
for mut transform in cube_query.iter_mut() {
transform.rotation = Quat::from_rotation_y(time.elapsed_secs());
transform.translation.x = (time.elapsed_secs() * 2.0).sin() * 0.5;
}
}
fn update_cube_color(
ui: Res<UIData>,
cube_query: Query<&MeshMaterial3d<StandardMaterial>, With<DynamicColoredCube>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
if ui.is_changed() {
for mesh_material in cube_query.iter() {
if let Some(material) = materials.get_mut(&mesh_material.0) {
let [r, g, b] = ui.color;
material.base_color = bevy::color::Color::srgb(r, g, b);
}
}
}
}
+93
View File
@@ -0,0 +1,93 @@
use crate::bevy_renderer::BevyRenderer;
use crate::Color;
use dioxus_native::{CustomPaintCtx, CustomPaintSource, DeviceHandle, TextureHandle};
use std::sync::mpsc::{channel, Receiver, Sender};
use wgpu::Instance;
pub enum DemoMessage {
// Color in RGB format
SetColor(Color),
}
enum DemoRendererState {
Active(Box<BevyRenderer>),
Suspended,
}
pub struct DemoPaintSource {
state: DemoRendererState,
start_time: std::time::Instant,
tx: Sender<DemoMessage>,
rx: Receiver<DemoMessage>,
color: Color,
}
impl DemoPaintSource {
pub fn new() -> Self {
let (tx, rx) = channel();
Self::with_channel(tx, rx)
}
pub fn with_channel(tx: Sender<DemoMessage>, rx: Receiver<DemoMessage>) -> Self {
Self {
state: DemoRendererState::Suspended,
start_time: std::time::Instant::now(),
tx,
rx,
color: Color::WHITE,
}
}
pub fn sender(&self) -> Sender<DemoMessage> {
self.tx.clone()
}
fn process_messages(&mut self) {
loop {
match self.rx.try_recv() {
Err(_) => return,
Ok(msg) => match msg {
DemoMessage::SetColor(color) => self.color = color,
},
}
}
}
fn render(
&mut self,
ctx: CustomPaintCtx<'_>,
width: u32,
height: u32,
) -> Option<TextureHandle> {
if width == 0 || height == 0 {
return None;
}
let DemoRendererState::Active(state) = &mut self.state else {
return None;
};
state.render(ctx, self.color.components, width, height, &self.start_time)
}
}
impl CustomPaintSource for DemoPaintSource {
fn resume(&mut self, instance: &Instance, device_handle: &DeviceHandle) {
let active_state = BevyRenderer::new(instance, device_handle);
self.state = DemoRendererState::Active(Box::new(active_state));
}
fn suspend(&mut self) {
self.state = DemoRendererState::Suspended;
}
fn render(
&mut self,
ctx: CustomPaintCtx<'_>,
width: u32,
height: u32,
_scale: f64,
) -> Option<TextureHandle> {
self.process_messages();
self.render(ctx, width, height)
}
}
+110
View File
@@ -0,0 +1,110 @@
use std::any::Any;
use color::{palette::css::WHITE, parse_color};
use color::{OpaqueColor, Srgb};
use demo_renderer::{DemoMessage, DemoPaintSource};
use dioxus::prelude::*;
use dioxus_native::use_wgpu;
use wgpu::Limits;
mod bevy_renderer;
mod bevy_scene_plugin;
mod demo_renderer;
// CSS Styles
static STYLES: Asset = asset!("./src/styles.css");
type Color = OpaqueColor<Srgb>;
fn limits() -> Limits {
Limits {
max_storage_buffers_per_shader_stage: 12,
..Limits::default()
}
}
fn main() {
#[cfg(feature = "tracing")]
tracing_subscriber::fmt::init();
let config: Vec<Box<dyn Any>> = vec![Box::new(limits())];
dioxus_native::launch_cfg(app, Vec::new(), config);
}
fn app() -> Element {
let mut show_cube = use_signal(|| true);
let color_str = use_signal(|| String::from("red"));
let color = use_memo(move || {
parse_color(&color_str())
.map(|c| c.to_alpha_color())
.unwrap_or(WHITE)
.split()
.0
});
use_effect(move || println!("{:?}", color().components));
rsx!(
document::Link { rel: "stylesheet", href: STYLES }
div { id:"overlay",
h2 { "Control Panel" },
button {
onclick: move |_| show_cube.toggle(),
if show_cube() {
"Hide cube"
} else {
"Show cube"
}
}
br {}
ColorControl { label: "Color:", color_str },
p { "This overlay demonstrates that the custom Bevy content can be rendered beneath layers of HTML content" }
}
div { id:"underlay",
h2 { "Underlay" },
p { "This underlay demonstrates that the custom Bevy content can be rendered above layers and blended with the content underneath" }
}
header {
h1 { "Blitz Bevy Demo" }
}
if show_cube() {
SpinningCube { color }
}
)
}
#[component]
fn ColorControl(label: &'static str, color_str: Signal<String>) -> Element {
rsx!(div {
class: "color-control",
{ label },
input {
value: color_str(),
oninput: move |evt| {
*color_str.write() = evt.value()
}
}
})
}
#[component]
fn SpinningCube(color: Memo<Color>) -> Element {
// Create custom paint source and register it with the renderer
let paint_source = DemoPaintSource::new();
let sender = paint_source.sender();
let paint_source_id = use_wgpu(move || paint_source);
use_effect(move || {
sender.send(DemoMessage::SetColor(color())).unwrap();
});
rsx!(
div { id:"canvas-container",
canvas {
id: "demo-canvas",
"src": paint_source_id
}
}
)
}
+62
View File
@@ -0,0 +1,62 @@
* {
box-sizing: border-box;
}
html, body, main {
height: 100%;
font-family: system-ui, sans;
margin: 0;
}
main {
display: grid;
grid-template-rows: 100px 1fr;
grid-template-columns: 100%;
background: #f4e8d2;
}
#canvas-container {
display: grid;
opacity: 0.8;
grid-row: 2;
}
header {
padding: 10px 40px;
background-color: white;
z-index: 100;
grid-row: 1;
}
#overlay {
position: absolute;
width: 33%;
height: 100%;
right: 0;
z-index: 10;
background-color: rgba(0, 0, 0, 0.5);
padding-top: 40%;
padding-inline: 20px;
color: white;
}
#underlay {
position: absolute;
width: 33%;
height: 100%;
z-index: -10;
background-color: black;
padding-top: 40%;
padding-inline: 20px;
color: white;
}
.color-control {
display: flex;
gap: 12px;
> input {
width: 150px;
color: black;
}
}
+8 -5
View File
@@ -1,10 +1,10 @@
// Copyright © SixtyFPS GmbH <info@slint.dev> // Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use crate::Color; use crate::Color;
use dioxus_native::{CustomPaintCtx, CustomPaintSource, TextureHandle}; use dioxus_native::{CustomPaintCtx, CustomPaintSource, DeviceHandle, TextureHandle};
use std::sync::mpsc::{channel, Receiver, Sender}; use std::sync::mpsc::{channel, Receiver, Sender};
use std::time::Instant; use std::time::Instant;
use wgpu::{Device, Queue}; use wgpu::Instance;
pub struct DemoPaintSource { pub struct DemoPaintSource {
state: DemoRendererState, state: DemoRendererState,
@@ -15,9 +15,9 @@ pub struct DemoPaintSource {
} }
impl CustomPaintSource for DemoPaintSource { impl CustomPaintSource for DemoPaintSource {
fn resume(&mut self, device: &Device, queue: &Queue) { fn resume(&mut self, _instance: &Instance, device_handle: &DeviceHandle) {
// TODO: work out what to do about width/height // TODO: work out what to do about width/height
let active_state = ActiveDemoRenderer::new(device, queue); let active_state = ActiveDemoRenderer::new(device_handle);
self.state = DemoRendererState::Active(Box::new(active_state)); self.state = DemoRendererState::Active(Box::new(active_state));
} }
@@ -110,7 +110,10 @@ impl DemoPaintSource {
} }
impl ActiveDemoRenderer { impl ActiveDemoRenderer {
pub(crate) fn new(device: &Device, queue: &Queue) -> Self { pub(crate) fn new(device_handle: &DeviceHandle) -> Self {
let device = &device_handle.device;
let queue = &device_handle.queue;
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None, label: None,
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!( source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(
+7 -7
View File
@@ -21,13 +21,13 @@ autofocus = []
[dependencies] [dependencies]
# Blitz dependencies # Blitz dependencies
anyrender = { version = "0.3", default-features = false } anyrender = { version = "0.4", default-features = false }
anyrender_vello = { version = "0.3", default-features = false } anyrender_vello = { version = "0.4", default-features = false }
blitz-dom = { version = "=0.1.0-alpha.4", default-features = false } blitz-dom = { version = "=0.1.0-alpha.5", default-features = false }
blitz-net = { version = "=0.1.0-alpha.4", optional = true } blitz-net = { version = "=0.1.0-alpha.5", optional = true }
blitz-paint = { version = "=0.1.0-alpha.4", optional = true } blitz-paint = { version = "=0.1.0-alpha.5", optional = true }
blitz-traits = { version = "=0.1.0-alpha.4" } blitz-traits = { version = "=0.1.0-alpha.5" }
blitz-shell = { version = "=0.1.0-alpha.4", default-features = false } blitz-shell = { version = "=0.1.0-alpha.5", default-features = false }
# DioxusLabs dependencies # DioxusLabs dependencies
dioxus-core = { workspace = true } dioxus-core = { workspace = true }
+3 -1
View File
@@ -8,7 +8,9 @@ use blitz_dom::{
net::Resource, BaseDocument, Document, EventDriver, EventHandler, Node, DEFAULT_CSS, net::Resource, BaseDocument, Document, EventDriver, EventHandler, Node, DEFAULT_CSS,
}; };
use blitz_traits::{ use blitz_traits::{
events::UiEvent, net::NetProvider, ColorScheme, DomEvent, DomEventData, EventState, Viewport, events::{DomEvent, DomEventData, EventState, UiEvent},
net::NetProvider,
shell::{ColorScheme, Viewport},
}; };
use dioxus_core::{ElementId, Event, VirtualDom}; use dioxus_core::{ElementId, Event, VirtualDom};
+1 -1
View File
@@ -1,4 +1,4 @@
use blitz_traits::{BlitzKeyEvent, BlitzMouseButtonEvent, MouseEventButton}; use blitz_traits::events::{BlitzKeyEvent, BlitzMouseButtonEvent, MouseEventButton};
use dioxus_html::{ use dioxus_html::{
geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint}, geometry::{ClientPoint, ElementPoint, PagePoint, ScreenPoint},
input_data::{MouseButton, MouseButtonSet}, input_data::{MouseButton, MouseButtonSet},
+3 -1
View File
@@ -17,7 +17,9 @@ mod dioxus_renderer;
mod events; mod events;
mod mutation_writer; mod mutation_writer;
pub use anyrender_vello::{CustomPaintCtx, CustomPaintSource, TextureHandle}; pub use anyrender_vello::{
wgpu_context::DeviceHandle, CustomPaintCtx, CustomPaintSource, TextureHandle,
};
use assets::DioxusNativeNetProvider; use assets::DioxusNativeNetProvider;
use blitz_dom::{ns, LocalName, Namespace, QualName}; use blitz_dom::{ns, LocalName, Namespace, QualName};
pub use dioxus_application::{DioxusNativeApplication, DioxusNativeEvent}; pub use dioxus_application::{DioxusNativeApplication, DioxusNativeEvent};