Merge branch 'master' into construct_color

This commit is contained in:
phailhaus 2025-06-27 23:36:30 -05:00 committed by GitHub
commit cd5e9cdfbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 62 additions and 17 deletions

View file

@ -143,7 +143,7 @@ impl LayoutHolder for ShapeTool {
true,
|_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(None)).into(),
|color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColorType(color_type.clone())).into()),
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(color.value.as_solid())).into(),
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::FillColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
));
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
@ -154,7 +154,7 @@ impl LayoutHolder for ShapeTool {
true,
|_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(None)).into(),
|color_type: ToolColorType| WidgetCallback::new(move |_| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColorType(color_type.clone())).into()),
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(color.value.as_solid())).into(),
|color: &ColorInput| ShapeToolMessage::UpdateOptions(ShapeOptionsUpdate::StrokeColor(color.value.as_solid().map(|color| color.to_linear_srgb()))).into(),
));
widgets.push(Separator::new(SeparatorType::Unrelated).widget_holder());
widgets.push(create_weight_widget(self.options.line_weight));

View file

@ -30,6 +30,7 @@
let open = false;
$: watchSelectedIndex(selectedIndex);
$: watchEntries(entries);
$: watchActiveEntry(activeEntry);
$: watchOpen(open);
@ -38,7 +39,13 @@
}
// Called only when `selectedIndex` is changed from outside this component
function watchSelectedIndex(_?: number) {
function watchSelectedIndex(_?: typeof selectedIndex) {
activeEntrySkipWatcher = true;
activeEntry = makeActiveEntry();
}
// Called only when `entries` is changed from outside this component
function watchEntries(_?: typeof entries) {
activeEntrySkipWatcher = true;
activeEntry = makeActiveEntry();
}

View file

@ -291,7 +291,15 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) ->
*image_frame_table.instance_mut_iter().next().unwrap().alpha_blending = alpha_blending;
image_frame_table
}
FormatVersions::ImageFrame(image_frame) => RasterDataTable::new(Raster::new_cpu(image_frame.instance_ref_iter().next().unwrap().instance.image.clone())),
FormatVersions::ImageFrame(image_frame) => RasterDataTable::new(Raster::new_cpu(
image_frame
.instance_ref_iter()
.next()
.unwrap_or(Instances::new(ImageFrame::default()).instance_ref_iter().next().unwrap())
.instance
.image
.clone(),
)),
FormatVersions::ImageFrameTable(image_frame_table) => RasterDataTable::new(Raster::new_cpu(image_frame_table.instance_ref_iter().next().unwrap().instance.clone())),
FormatVersions::RasterDataTable(raster_data_table) => raster_data_table,
})

View file

@ -57,6 +57,10 @@ impl Raster<CPU> {
let RasterStorage::Cpu(cpu) = self.data else { unreachable!() };
cpu
}
pub fn is_empty(&self) -> bool {
let data = self.data();
data.height == 0 || data.width == 0
}
}
impl Default for Raster<CPU> {
fn default() -> Self {
@ -93,6 +97,10 @@ impl Raster<GPU> {
let RasterStorage::Gpu(gpu) = &self.data else { unreachable!() };
gpu.clone()
}
pub fn is_empty(&self) -> bool {
let data = self.data();
data.width() == 0 || data.height() == 0
}
}
#[cfg(feature = "wgpu")]
impl Deref for Raster<GPU> {
@ -104,9 +112,23 @@ impl Deref for Raster<GPU> {
}
pub type RasterDataTable<Storage> = Instances<Raster<Storage>>;
impl<S: Storage> BoundingBox for RasterDataTable<S> {
// TODO: Make this not dupliated
impl BoundingBox for RasterDataTable<CPU> {
fn bounding_box(&self, transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
self.instance_ref_iter()
.filter(|instance| !instance.instance.is_empty()) // Eliminate empty images
.flat_map(|instance| {
let transform = transform * *instance.transform;
(transform.matrix2.determinant() != 0.).then(|| (transform * Quad::from_box([DVec2::ZERO, DVec2::ONE])).bounding_box())
})
.reduce(Quad::combine_bounds)
}
}
impl BoundingBox for RasterDataTable<GPU> {
fn bounding_box(&self, transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> {
self.instance_ref_iter()
.filter(|instance| !instance.instance.is_empty()) // Eliminate empty images
.flat_map(|instance| {
let transform = transform * *instance.transform;
(transform.matrix2.determinant() != 0.).then(|| (transform * Quad::from_box([DVec2::ZERO, DVec2::ONE])).bounding_box())

View file

@ -289,19 +289,21 @@ impl GraphicElementRendered for GraphicGroupTable {
let mut layer = false;
let bounds = self
.instance_ref_iter()
.filter_map(|element| element.instance.bounding_box(transform, true))
.reduce(Quad::combine_bounds);
if let Some(bounds) = bounds {
let blend_mode = match render_params.view_mode {
ViewMode::Outline => peniko::Mix::Normal,
_ => alpha_blending.blend_mode.to_peniko(),
};
let blend_mode = match render_params.view_mode {
ViewMode::Outline => peniko::Mix::Normal,
_ => alpha_blending.blend_mode.to_peniko(),
};
let mut bounds = None;
let factor = if render_params.for_mask { 1. } else { alpha_blending.fill };
let opacity = alpha_blending.opacity * factor;
if opacity < 1. || (render_params.view_mode != ViewMode::Outline && alpha_blending.blend_mode != BlendMode::default()) {
let factor = if render_params.for_mask { 1. } else { alpha_blending.fill };
let opacity = alpha_blending.opacity * factor;
if opacity < 1. || (render_params.view_mode != ViewMode::Outline && alpha_blending.blend_mode != BlendMode::default()) {
bounds = self
.instance_ref_iter()
.filter_map(|element| element.instance.bounding_box(transform, true))
.reduce(Quad::combine_bounds);
if let Some(bounds) = bounds {
scene.push_layer(
peniko::BlendMode::new(blend_mode, peniko::Compose::SrcOver),
opacity,
@ -321,6 +323,12 @@ impl GraphicElementRendered for GraphicGroupTable {
if !next_clips {
mask_instance_state = None;
}
if !layer {
bounds = self
.instance_ref_iter()
.filter_map(|element| element.instance.bounding_box(transform, true))
.reduce(Quad::combine_bounds);
}
if let Some(bounds) = bounds {
let rect = kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);