Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"renderer",
"vello",
"vello_cpu",
"vger",
"tiny_skia",
"reactive",
Expand All @@ -15,6 +16,7 @@ default-members = [
".",
"renderer",
"vello",
"vello_cpu",
"vger",
"tiny_skia",
"reactive",
Expand Down Expand Up @@ -86,8 +88,9 @@ strum_macros = { workspace = true, optional = true }
paste = "1.0"
floem_renderer = { path = "renderer", version = "0.2.0" }
floem_vello_renderer = { path = "vello", version = "0.2.0", optional = true }
floem_vello_cpu_renderer = { path = "vello_cpu", version = "0.2.0", optional = true }
floem_vger_renderer = { path = "vger", version = "0.2.0", optional = true }
floem_tiny_skia_renderer = { path = "tiny_skia", version = "0.2.0" }
floem_tiny_skia_renderer = { path = "tiny_skia", version = "0.2.0", optional = true }
floem_reactive = { path = "reactive", version = "0.2.0" }
floem-editor-core = { path = "editor-core", version = "0.2.0", optional = true }
copypasta = { version = "0.10", default-features = false, features = [
Expand Down Expand Up @@ -131,9 +134,17 @@ objc2-app-kit = { version = "0.3", features = [
] }

[features]
default = ["editor", "default-image-formats", "vger"]
default = ["editor", "default-image-formats", "vello", "vello_cpu"]

# Renderers - enable any combination you want
# They are tried in order: vello -> vger -> vello_cpu -> tiny_skia
vello = ["dep:floem_vello_renderer"]
vger = ["dep:floem_vger_renderer"]
vger = ["dep:floem_vger_renderer"]
vello_cpu = ["dep:floem_vello_cpu_renderer"]
tiny_skia = ["dep:floem_tiny_skia_renderer"]

# Feature flag for capabilities - simple renderer (vger) has limited features
simple_renderer = []
serde = [
"dep:serde",
"winit/serde",
Expand Down
2 changes: 1 addition & 1 deletion examples/widget-gallery/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
floem = { path = "../..", features = ["rfd-async-std", "vello"] }
floem = { path = "../..", features = ["rfd-async-std", "vello", "vello_cpu"] }
strum = { workspace = true }
files = { path = "../files/", optional = true }
stacks = { path = "../stacks/", optional = true }
Expand Down
33 changes: 27 additions & 6 deletions examples/widget-gallery/src/context_menu.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use floem::{
kurbo::Affine,
menu::*,
prelude::ViewTuple,
prelude::{RwSignal, SignalGet, SignalUpdate, ViewTuple},
reactive::Effect,
views::{ButtonClass, Decorators},
IntoView,
HasViewId, IntoView,
};

pub fn menu_view() -> impl IntoView {
let transform = RwSignal::new(Affine::IDENTITY);
let export_submenu = |m: SubMenu| {
m.item("PDF", |i| i.action(|| println!("Exporting as PDF...")))
.item("PNG", |i| i.action(|| println!("Exporting as PNG...")))
Expand Down Expand Up @@ -40,15 +43,27 @@ pub fn menu_view() -> impl IntoView {
})
};

let transform_submenu = |m: SubMenu| {
let transform_submenu = move |m: SubMenu| {
m.item("Rotate 90°", |i| {
i.action(|| println!("Rotating 90 degrees..."))
i.action(move || {
transform.update(|s| {
*s = s.then_rotate(90f64.to_radians());
})
})
})
.item("Flip Horizontal", |i| {
i.action(|| println!("Flipping horizontally..."))
i.action(move || {
transform.update(|s| {
*s *= Affine::FLIP_X;
})
})
})
.item("Flip Vertical", |i| {
i.action(|| println!("Flipping vertically..."))
i.action(move || {
transform.update(|s| {
*s *= Affine::FLIP_Y;
})
})
})
.separator()
.item("Reset Transform", |i| {
Expand Down Expand Up @@ -85,6 +100,12 @@ pub fn menu_view() -> impl IntoView {
.class(ButtonClass)
.style(|s| s.padding(10.0).border(1.0))
.context_menu(context_menu);
let id = context_button.view_id();

Effect::new(move |_| {
let transform = transform.get();
id.set_transform(transform);
});

(popout_button, context_button)
.v_stack()
Expand Down
7 changes: 5 additions & 2 deletions examples/widget-gallery/src/draggable.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use floem::{prelude::*, style::CursorStyle};
use floem::{
prelude::{palette::css, *},
style::CursorStyle,
};

fn sortable_item(
name: &str,
Expand Down Expand Up @@ -86,6 +89,6 @@ pub fn draggable_view() -> impl IntoView {
move |item_id| *item_id,
move |item_id| sortable_item(items[item_id], sortable_items, dragger_id, item_id),
)
.style(|s| s.flex_col().row_gap(5).padding(10))
.style(|s| s.flex_col().row_gap(5).padding(10).color(css::BLACK))
.into_view()
}
21 changes: 21 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{
clipboard::Clipboard,
inspector::Capture,
profiler::Profile,
renderer::RendererKind,
view::IntoView,
window::{WindowConfig, WindowCreation},
};
Expand All @@ -39,6 +40,7 @@ pub struct AppConfig {
pub(crate) exit_on_close: bool,
pub(crate) wgpu_features: wgpu::Features,
pub(crate) global_theme_override: Option<Theme>,
pub(crate) renderer_preference: RendererKind,
}

impl Default for AppConfig {
Expand All @@ -47,6 +49,7 @@ impl Default for AppConfig {
exit_on_close: !cfg!(target_os = "macos"),
wgpu_features: wgpu::Features::default(),
global_theme_override: None,
renderer_preference: RendererKind::Auto,
}
}
}
Expand All @@ -72,6 +75,24 @@ impl AppConfig {
self.global_theme_override = Some(theme);
self
}

/// Sets the preferred renderer type.
///
/// The renderer preference determines which renderer backend to use.
/// If the preferred renderer fails to initialize, the system will fall back
/// to other available renderers in order of preference.
///
/// # Examples
/// ```no_run
/// # use floem::{AppConfig, renderer::RendererKind};
/// let config = AppConfig::default()
/// .renderer_preference(RendererKind::VelloCpu);
/// ```
#[inline]
pub fn renderer_preference(mut self, renderer: RendererKind) -> Self {
self.renderer_preference = renderer;
self
}
}

/// Initializes and runs an application with a single window.
Expand Down
4 changes: 3 additions & 1 deletion src/app_handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ impl ApplicationHandle {
} = &handle.paint_state
{
let (gpu_resources, surface) = rx.recv().unwrap().unwrap();
let renderer = crate::renderer::Renderer::new(
let renderer = crate::renderer::Renderer::new_with_kind(
self.config.renderer_preference,
window.clone(),
gpu_resources.clone(),
surface,
Expand Down Expand Up @@ -548,6 +549,7 @@ impl ApplicationHandle {
transparent,
apply_default_theme,
font_embolden,
self.config.renderer_preference,
);
self.window_handles.insert(window_id, window_handle);
}
Expand Down
54 changes: 36 additions & 18 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use floem_reactive::Scope;
use floem_renderer::Renderer as FloemRenderer;
use floem_renderer::gpu_resources::{GpuResourceError, GpuResources};
use peniko::BlendMode;
use peniko::kurbo::{Affine, Point, Rect, RoundedRect, Shape, Size, Vec2};
use smallvec::SmallVec;
use std::{
Expand Down Expand Up @@ -74,6 +75,7 @@ pub struct DragState {
pub(crate) release_location: Option<Point>,
}

#[derive(Debug)]
pub(crate) enum FrameUpdate {
Style(ViewId),
Layout(ViewId),
Expand Down Expand Up @@ -1000,9 +1002,11 @@ impl<'a> StyleCx<'a> {
pub fn style_view(&mut self) {
let view_id = self.current_view;

let view = view_id.view();
let view_interact_state = self.get_interact_state(&view_id);
let view_state = view_id.state();

let view = view_id.view();

{
let mut view_state = view_state.borrow_mut();
if self.window_state.view_style_dirty.contains(&view_id) {
Expand All @@ -1026,7 +1030,6 @@ impl<'a> StyleCx<'a> {
}
}

let view_interact_state = self.get_interact_state(&view_id);
let view_class = view.borrow().view_class();

let (mut new_frame, classes_applied) = self.compute_combined(
Expand Down Expand Up @@ -1086,18 +1089,16 @@ impl<'a> StyleCx<'a> {
&mut new_frame,
);

if view_state.view_transform_props.read_explicit(
view_state.view_transform_props.read_explicit(
&self.direct,
&self.current,
&self.now,
&mut new_frame,
) || new_frame
{
self.window_state.schedule_layout(view_id);
}
);
}

if new_frame {
// TODO: we should still be scheduling style here. the style pass should still run, we just shouldn't be repainting because of a hidden view.
if new_frame && !self.hidden {
self.window_state.schedule_style(view_id);
}

Expand All @@ -1106,7 +1107,10 @@ impl<'a> StyleCx<'a> {
let taffy_style = self.direct.clone().apply(layout_style).to_taffy_style();
if taffy_style != view_state.borrow().taffy_style {
view_state.borrow_mut().taffy_style = taffy_style;
self.window_state.schedule_layout(view_id);
// TODO: we should still be requesting layout here. the layout should still run, we just shouldn't be repainting because of a hidden view.
if !self.hidden {
view_id.request_layout();
}
}

view.borrow_mut().style_pass(self);
Expand Down Expand Up @@ -1511,22 +1515,22 @@ pub struct PaintCx<'a> {
pub(crate) pending_drag_paint: Option<PendingDragPaint>,
pub gpu_resources: Option<GpuResources>,
pub window: Arc<dyn Window>,
#[cfg(feature = "vello")]
#[cfg(not(feature = "simple_renderer"))]
pub layer_count: usize,
#[cfg(feature = "vello")]
#[cfg(not(feature = "simple_renderer"))]
pub saved_layer_counts: Vec<usize>,
}

impl PaintCx<'_> {
pub fn save(&mut self) {
self.saved_transforms.push(self.transform);
self.saved_clips.push(self.clip);
#[cfg(feature = "vello")]
#[cfg(not(feature = "simple_renderer"))]
self.saved_layer_counts.push(self.layer_count);
}

pub fn restore(&mut self) {
#[cfg(feature = "vello")]
#[cfg(not(feature = "simple_renderer"))]
{
let saved_count = self.saved_layer_counts.pop().unwrap_or_default();
while self.layer_count > saved_count {
Expand All @@ -1541,7 +1545,7 @@ impl PaintCx<'_> {
.renderer_mut()
.set_transform(self.transform);

#[cfg(not(feature = "vello"))]
#[cfg(feature = "simple_renderer")]
{
if let Some(rect) = self.clip {
self.paint_state.renderer_mut().clip(&rect);
Expand Down Expand Up @@ -1596,12 +1600,24 @@ impl PaintCx<'_> {
if !is_empty {
let view_style_props = view_state.borrow().view_style_props.clone();
let layout_props = view_state.borrow().layout_props.clone();
let alpha = view_style_props.opacity();
if alpha != 1. {
self.push_layer(
BlendMode::default(),
alpha,
Affine::IDENTITY,
&size.to_rect(),
);
}

paint_bg(self, &view_style_props, size);

view.borrow_mut().paint(self);
paint_border(self, &layout_props, &view_style_props, size);
paint_outline(self, &view_style_props, size)
paint_outline(self, &view_style_props, size);
if alpha != 1. {
self.pop_layer();
}
}
// Check if this view is being dragged and needs deferred painting
if let Some(dragging) = self.window_state.dragging.as_ref() {
Expand Down Expand Up @@ -1719,7 +1735,7 @@ impl PaintCx<'_> {

/// Clip the drawing area to the given shape.
pub fn clip(&mut self, shape: &impl Shape) {
#[cfg(feature = "vello")]
#[cfg(not(feature = "simple_renderer"))]
{
use peniko::Mix;

Expand All @@ -1728,7 +1744,7 @@ impl PaintCx<'_> {
self.clip = Some(shape.bounding_box().to_rounded_rect(0.0));
}

#[cfg(not(feature = "vello"))]
#[cfg(feature = "simple_renderer")]
{
let rect = if let Some(rect) = shape.as_rect() {
rect.to_rounded_rect(0.0)
Expand Down Expand Up @@ -1849,8 +1865,10 @@ impl PaintState {
scale: f64,
size: Size,
font_embolden: f32,
renderer_preference: crate::renderer::RendererKind,
) -> Self {
let renderer = crate::renderer::Renderer::new(
let renderer = crate::renderer::Renderer::new_with_kind(
renderer_preference,
window.clone(),
gpu_resources,
surface,
Expand Down
4 changes: 2 additions & 2 deletions src/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

use std::{any::Any, cell::RefCell, rc::Rc};

use peniko::kurbo::{Affine, Insets, Point, Rect, Size};
use peniko::kurbo::{Insets, Point, Rect, Size};
use slotmap::new_key_type;
use taffy::{Layout, NodeId, TaffyTree};
use taffy::{Display, Layout, NodeId, TaffyTree};
use winit::window::WindowId;

use crate::{
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ mod app;
#[cfg(target_os = "macos")]
mod app_delegate;
mod app_handle;
#[cfg(feature = "vello")]
#[cfg(not(feature = "simple_renderer"))]
mod border_path_iter;
mod clipboard;
pub mod context;
Expand Down Expand Up @@ -244,6 +244,7 @@ pub use imbl;
pub use muda;
pub use peniko;
pub use peniko::kurbo;
pub use renderer::RendererKind;
pub use screen_layout::ScreenLayout;
pub use taffy;
pub use ui_events;
Expand Down
Loading
Loading