mirror of https://github.com/linebender/xilem
Add Properties to Button (#892)
Depends on #904. Add BackgroundColor, BorderColor, BorderWidth, CornerRadius and Padding properties. Modularize button painting code. Paint border after background to get slightly better border appearance. Update screenshots. Add screenshot test using properties.
This commit is contained in:
parent
5c32f5c44b
commit
fad997afa5
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:102ab52259d07eb250f83acaeb5a985549ef2b5052eae7fca8e882548b34955a
|
||||
size 17856
|
||||
oid sha256:4fb1e0aad3dc074028a723304a04af836d4496a547bc6377acd4f0ea4caeaacd
|
||||
size 17713
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:8c74fb27ee2165e855dd631e496426793344c93dee37cdb9bb989ba3129cf495
|
||||
size 6758
|
||||
oid sha256:6c8c66f1c91c102ef9f3b806f8f380eec781d4eb2261f421a651829c49f2686e
|
||||
size 1542
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2025 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use crate::core::UpdateCtx;
|
||||
use crate::peniko::color::{AlphaColor, Srgb};
|
||||
|
||||
/// The background color of a widget.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BackgroundColor {
|
||||
pub color: AlphaColor<Srgb>,
|
||||
}
|
||||
|
||||
impl BackgroundColor {
|
||||
/// Helper function to be called in [`Widget::property_changed`](crate::core::Widget::property_changed).
|
||||
pub fn prop_changed(ctx: &mut UpdateCtx<'_>, property_type: TypeId) {
|
||||
if property_type != TypeId::of::<Self>() {
|
||||
return;
|
||||
}
|
||||
ctx.request_paint_only();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2025 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use crate::core::UpdateCtx;
|
||||
use crate::peniko::color::{AlphaColor, Srgb};
|
||||
|
||||
/// The background color of a widget.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BorderColor {
|
||||
pub color: AlphaColor<Srgb>,
|
||||
}
|
||||
|
||||
impl BorderColor {
|
||||
/// Helper function to be called in [`Widget::property_changed`](crate::core::Widget::property_changed).
|
||||
pub fn prop_changed(ctx: &mut UpdateCtx<'_>, property_type: TypeId) {
|
||||
if property_type != TypeId::of::<Self>() {
|
||||
return;
|
||||
}
|
||||
ctx.request_paint_only();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2025 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use crate::core::{BoxConstraints, UpdateCtx};
|
||||
use crate::kurbo::{Point, RoundedRect, Size, Vec2};
|
||||
use crate::properties::CornerRadius;
|
||||
|
||||
/// The width of a widget's border.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BorderWidth {
|
||||
pub width: f64,
|
||||
}
|
||||
|
||||
impl BorderWidth {
|
||||
/// Helper function to be called in [`Widget::property_changed`](crate::core::Widget::property_changed).
|
||||
pub fn prop_changed(ctx: &mut UpdateCtx<'_>, property_type: TypeId) {
|
||||
if property_type != TypeId::of::<Self>() {
|
||||
return;
|
||||
}
|
||||
ctx.request_layout();
|
||||
}
|
||||
|
||||
/// Shrinks the box constraints by the border width.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::layout`](crate::core::Widget::layout).
|
||||
pub fn layout_down(&self, bc: BoxConstraints) -> BoxConstraints {
|
||||
bc.shrink((self.width * 2., self.width * 2.))
|
||||
}
|
||||
|
||||
/// Expands the size and raises the baseline by the border width.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::layout`](crate::core::Widget::layout).
|
||||
pub fn layout_up(&self, size: Size, baseline: f64) -> (Size, f64) {
|
||||
let size = Size::new(size.width + self.width * 2., size.height + self.width * 2.);
|
||||
let baseline = baseline + self.width;
|
||||
(size, baseline)
|
||||
}
|
||||
|
||||
/// Shifts the position by the border width.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::layout`](crate::core::Widget::layout).
|
||||
pub fn place_down(&self, pos: Point) -> Point {
|
||||
pos + Vec2::new(self.width, self.width)
|
||||
}
|
||||
|
||||
/// Creates a rounded rectangle that is inset by the border width.
|
||||
///
|
||||
/// Use to display a box's background.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::paint`](crate::core::Widget::paint).
|
||||
pub fn bg_rect(&self, size: Size, border_radius: &CornerRadius) -> RoundedRect {
|
||||
size.to_rect()
|
||||
.inset(-self.width)
|
||||
.to_rounded_rect(border_radius.radius - self.width)
|
||||
}
|
||||
|
||||
/// Creates a rounded rectangle that is inset by half the border width.
|
||||
///
|
||||
/// Use to display a box's border.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::paint`](crate::core::Widget::paint).
|
||||
pub fn border_rect(&self, size: Size, border_radius: &CornerRadius) -> RoundedRect {
|
||||
size.to_rect()
|
||||
.inset(-self.width / 2.0)
|
||||
.to_rounded_rect(border_radius.radius)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2025 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use crate::core::UpdateCtx;
|
||||
|
||||
/// The radius of a widget's box corners.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct CornerRadius {
|
||||
pub radius: f64,
|
||||
}
|
||||
|
||||
impl CornerRadius {
|
||||
pub(crate) fn prop_changed(ctx: &mut UpdateCtx<'_>, property_type: TypeId) {
|
||||
if property_type != TypeId::of::<Self>() {
|
||||
return;
|
||||
}
|
||||
ctx.request_layout();
|
||||
}
|
||||
}
|
|
@ -10,24 +10,14 @@
|
|||
reason = "A lot of properties and especially their fields are self-explanatory."
|
||||
)]
|
||||
|
||||
use std::any::TypeId;
|
||||
mod background_color;
|
||||
mod border_color;
|
||||
mod border_width;
|
||||
mod corner_radius;
|
||||
mod padding;
|
||||
|
||||
use vello::peniko::color::{AlphaColor, Srgb};
|
||||
|
||||
use crate::core::UpdateCtx;
|
||||
|
||||
// TODO - Split out into files.
|
||||
|
||||
/// The background color of a widget.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct BackgroundColor {
|
||||
pub color: AlphaColor<Srgb>,
|
||||
}
|
||||
|
||||
impl BackgroundColor {
|
||||
pub(crate) fn prop_changed(ctx: &mut UpdateCtx<'_>, property_type: TypeId) {
|
||||
if property_type == TypeId::of::<Self>() {
|
||||
ctx.request_paint_only();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use background_color::BackgroundColor;
|
||||
pub use border_color::BorderColor;
|
||||
pub use border_width::BorderWidth;
|
||||
pub use corner_radius::CornerRadius;
|
||||
pub use padding::Padding;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2025 the Xilem Authors
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use crate::core::{BoxConstraints, UpdateCtx};
|
||||
use crate::kurbo::{Point, Size, Vec2};
|
||||
|
||||
/// The width of padding between a widget's border and its contents.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Padding {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
}
|
||||
|
||||
impl Padding {
|
||||
/// Helper function to be called in [`Widget::property_changed`](crate::core::Widget::property_changed).
|
||||
pub fn prop_changed(ctx: &mut UpdateCtx<'_>, property_type: TypeId) {
|
||||
if property_type != TypeId::of::<Self>() {
|
||||
return;
|
||||
}
|
||||
ctx.request_layout();
|
||||
}
|
||||
|
||||
/// Shrinks the box constraints by the padding amount.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::layout`](crate::core::Widget::layout).
|
||||
pub fn layout_down(&self, bc: BoxConstraints) -> BoxConstraints {
|
||||
bc.shrink((self.x * 2., self.y * 2.))
|
||||
}
|
||||
|
||||
/// Expands the size and raises the baseline by the padding amount.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::layout`](crate::core::Widget::layout).
|
||||
pub fn layout_up(&self, size: Size, baseline: f64) -> (Size, f64) {
|
||||
let size = Size::new(size.width + self.x * 2., size.height + self.y * 2.);
|
||||
let baseline = baseline + self.y;
|
||||
(size, baseline)
|
||||
}
|
||||
|
||||
/// Shifts the position by the padding amount.
|
||||
///
|
||||
/// Helper function to be called in [`Widget::layout`](crate::core::Widget::layout).
|
||||
pub fn place_down(&self, pos: Point) -> Point {
|
||||
pos + Vec2::new(self.x, self.y)
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
//! A button widget.
|
||||
|
||||
use std::any::TypeId;
|
||||
|
||||
use accesskit::{Node, Role};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use tracing::{Span, trace, trace_span};
|
||||
|
@ -13,15 +15,26 @@ use crate::core::{
|
|||
PointerButton, PointerEvent, PropertiesMut, PropertiesRef, QueryCtx, TextEvent, Update,
|
||||
UpdateCtx, Widget, WidgetId, WidgetMut, WidgetPod,
|
||||
};
|
||||
use crate::kurbo::{Insets, Size};
|
||||
use crate::kurbo::Size;
|
||||
use crate::properties::*;
|
||||
use crate::theme;
|
||||
use crate::util::{UnitPoint, fill_lin_gradient, stroke};
|
||||
use crate::widgets::Label;
|
||||
|
||||
// The minimum padding added to a button.
|
||||
// --- MARK: CONSTANTS ---
|
||||
const DEFAULT_BORDER_COLOR: BorderColor = BorderColor {
|
||||
color: theme::BORDER_DARK,
|
||||
};
|
||||
const DEFAULT_BORDER_WIDTH: BorderWidth = BorderWidth {
|
||||
width: theme::BUTTON_BORDER_WIDTH,
|
||||
};
|
||||
const DEFAULT_BORDER_RADII: CornerRadius = CornerRadius {
|
||||
radius: theme::BUTTON_BORDER_RADIUS,
|
||||
};
|
||||
|
||||
// NOTE: these values are chosen to match the existing look of TextBox; these
|
||||
// should be reevaluated at some point.
|
||||
const LABEL_INSETS: Insets = Insets::uniform_xy(8., 2.);
|
||||
const DEFAULT_PADDING: Padding = Padding { x: 8., y: 2. };
|
||||
|
||||
/// A button with a text label.
|
||||
///
|
||||
|
@ -151,66 +164,82 @@ impl Widget for Button {
|
|||
ctx.register_child(&mut self.label);
|
||||
}
|
||||
|
||||
fn property_changed(&mut self, ctx: &mut UpdateCtx, property_type: TypeId) {
|
||||
BorderColor::prop_changed(ctx, property_type);
|
||||
BorderWidth::prop_changed(ctx, property_type);
|
||||
CornerRadius::prop_changed(ctx, property_type);
|
||||
Padding::prop_changed(ctx, property_type);
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
ctx: &mut LayoutCtx,
|
||||
_props: &mut PropertiesMut<'_>,
|
||||
props: &mut PropertiesMut<'_>,
|
||||
bc: &BoxConstraints,
|
||||
) -> Size {
|
||||
let padding = Size::new(LABEL_INSETS.x_value(), LABEL_INSETS.y_value());
|
||||
let label_bc = bc.shrink(padding).loosen();
|
||||
let border = props.get::<BorderWidth>().unwrap_or(&DEFAULT_BORDER_WIDTH);
|
||||
let padding = props.get::<Padding>().unwrap_or(&DEFAULT_PADDING);
|
||||
|
||||
let label_size = ctx.run_layout(&mut self.label, &label_bc);
|
||||
let initial_bc = bc;
|
||||
|
||||
let bc = bc.loosen();
|
||||
let bc = border.layout_down(bc);
|
||||
let bc = padding.layout_down(bc);
|
||||
|
||||
let label_size = ctx.run_layout(&mut self.label, &bc);
|
||||
let baseline = ctx.child_baseline_offset(&self.label);
|
||||
ctx.set_baseline_offset(baseline + LABEL_INSETS.y1);
|
||||
|
||||
let size = label_size;
|
||||
let (size, baseline) = padding.layout_up(size, baseline);
|
||||
let (size, baseline) = border.layout_up(size, baseline);
|
||||
|
||||
// TODO - Add MinimumSize property.
|
||||
// HACK: to make sure we look okay at default sizes when beside a textbox,
|
||||
// we make sure we will have at least the same height as the default textbox.
|
||||
let min_height = theme::BORDERED_WIDGET_HEIGHT;
|
||||
let mut size = size;
|
||||
size.height = size.height.max(theme::BORDERED_WIDGET_HEIGHT);
|
||||
|
||||
let button_size = bc.constrain(Size::new(
|
||||
label_size.width + padding.width,
|
||||
(label_size.height + padding.height).max(min_height),
|
||||
));
|
||||
|
||||
let label_offset = (button_size.to_vec2() - label_size.to_vec2()) / 2.0;
|
||||
// TODO - Figure out how to handle cases where label size doesn't fit bc.
|
||||
let size = initial_bc.constrain(size);
|
||||
let label_offset = (size.to_vec2() - label_size.to_vec2()) / 2.0;
|
||||
ctx.place_child(&mut self.label, label_offset.to_point());
|
||||
|
||||
button_size
|
||||
// TODO - pos = (size - label_size) / 2
|
||||
|
||||
ctx.set_baseline_offset(baseline);
|
||||
size
|
||||
}
|
||||
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, _props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let is_active = ctx.is_pointer_capture_target() && !ctx.is_disabled();
|
||||
fn paint(&mut self, ctx: &mut PaintCtx, props: &PropertiesRef<'_>, scene: &mut Scene) {
|
||||
let is_pressed = ctx.is_pointer_capture_target() && !ctx.is_disabled();
|
||||
let is_hovered = ctx.is_hovered();
|
||||
let size = ctx.size();
|
||||
let stroke_width = theme::BUTTON_BORDER_WIDTH;
|
||||
let border_radius = theme::BUTTON_BORDER_RADIUS;
|
||||
|
||||
let bg_rect = size
|
||||
.to_rect()
|
||||
.inset(-stroke_width)
|
||||
.to_rounded_rect(border_radius - stroke_width);
|
||||
let border_rect = size
|
||||
.to_rect()
|
||||
.inset(-stroke_width / 2.0)
|
||||
.to_rounded_rect(border_radius);
|
||||
let border_color = props.get::<BorderColor>().unwrap_or(&DEFAULT_BORDER_COLOR);
|
||||
let border_width = props.get::<BorderWidth>().unwrap_or(&DEFAULT_BORDER_WIDTH);
|
||||
let border_radius = props.get::<CornerRadius>().unwrap_or(&DEFAULT_BORDER_RADII);
|
||||
|
||||
let bg_rect = border_width.bg_rect(size, border_radius);
|
||||
let border_rect = border_width.border_rect(size, border_radius);
|
||||
|
||||
// TODO - Handle gradient bg with properties.
|
||||
let bg_gradient = if ctx.is_disabled() {
|
||||
[theme::DISABLED_BUTTON_LIGHT, theme::DISABLED_BUTTON_DARK]
|
||||
} else if is_active {
|
||||
} else if is_pressed {
|
||||
[theme::BUTTON_DARK, theme::BUTTON_LIGHT]
|
||||
} else {
|
||||
[theme::BUTTON_LIGHT, theme::BUTTON_DARK]
|
||||
};
|
||||
|
||||
// TODO - Handle hovered color with properties.
|
||||
let border_color = if is_hovered && !ctx.is_disabled() {
|
||||
theme::BORDER_LIGHT
|
||||
BorderColor {
|
||||
color: theme::BORDER_LIGHT,
|
||||
}
|
||||
} else {
|
||||
theme::BORDER_DARK
|
||||
*border_color
|
||||
};
|
||||
|
||||
stroke(scene, &border_rect, border_color, stroke_width);
|
||||
fill_lin_gradient(
|
||||
scene,
|
||||
&bg_rect,
|
||||
|
@ -218,6 +247,7 @@ impl Widget for Button {
|
|||
UnitPoint::TOP,
|
||||
UnitPoint::BOTTOM,
|
||||
);
|
||||
stroke(scene, &border_rect, border_color.color, border_width.width);
|
||||
}
|
||||
|
||||
fn accessibility_role(&self) -> Role {
|
||||
|
@ -309,4 +339,27 @@ mod tests {
|
|||
// We don't use assert_eq because we don't want rich assert
|
||||
assert!(image_1 == image_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_properties() {
|
||||
let red = crate::palette::css::RED;
|
||||
let button = Button::new("Some random text");
|
||||
|
||||
let window_size = Size::new(200.0, 80.0);
|
||||
let mut harness = TestHarness::create_with_size(button, window_size);
|
||||
|
||||
harness.edit_root_widget(|mut button| {
|
||||
let mut button = button.downcast::<Button>();
|
||||
|
||||
button.insert_prop(BorderColor { color: red });
|
||||
button.insert_prop(BorderWidth { width: 5.0 });
|
||||
button.insert_prop(CornerRadius { radius: 20.0 });
|
||||
button.insert_prop(Padding { x: 8.0, y: 3.0 });
|
||||
|
||||
let mut label = Button::label_mut(&mut button);
|
||||
Label::set_brush(&mut label, red);
|
||||
});
|
||||
|
||||
assert_render_snapshot!(harness, "set_properties");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:825ba955c58734a2f82f08cbafada08564df81ce7cdba3c91b9f6d9c479739fb
|
||||
size 826
|
||||
oid sha256:28c7e13b2243154c8f7c875995f5cb8e494b35b179f16e87bba841df2c075e13
|
||||
size 850
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:49af17e2d7c0c00f14a2e6148fcb17fa00723864fef9a1a669d96b64731152e0
|
||||
size 2696
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b955377e7a281de6023c89c2e1df74bb022fd79d9b66f61f94935d2745d51f20
|
||||
size 633
|
||||
oid sha256:952d44c493901d7d573ed1f52692d9a00f16bdf27b22dec5a5f8be967c46e10c
|
||||
size 657
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1a0cc0452c057a6ad53f6387ddc4dd106d9290007d308caf646d50f207982e31
|
||||
size 788
|
||||
oid sha256:fa053bfee46b3c2f06f3ce7279b79a371283bf7d8e0ce4f648edd63ef97a65b1
|
||||
size 823
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:44d955df21b773e49b617a35dd7e947c5fa4cd3f2d03f45669fe45c4bb953b82
|
||||
size 740
|
||||
oid sha256:b3ade1c4d892f3d0f46ce5bf318a76dcd76975602ae35a589c66f155d55dc41f
|
||||
size 749
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c8a7a6c3b0d099955329c4507df537c585744cbfef667c70330ff4519cacfd40
|
||||
size 632
|
||||
oid sha256:6d40fb5c5f871c7d5e3e4dca8b15d4dde34133aa6a13a18f44b62c02b2642a1b
|
||||
size 637
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:db92d77f0185fa0a093ab0dedf5015ac990891ebc6caea2c08790ad4b53fe26e
|
||||
size 726
|
||||
oid sha256:64584c9dbb5c0d8dcbca73e2e0d89447a998f16f740e634e7c0c2151d38dd40a
|
||||
size 733
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:497972bc7a7b0374104f9bd871bb74a24697439b89d2a099e0c72de358857516
|
||||
size 662
|
||||
oid sha256:e9d4d67c617852036aca1192390c82a528cf3a804a02894ccb573c867c2ae99f
|
||||
size 684
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5107d76df5e0936517691f90ef2249df8d5d50791c899b6bd1c6215830518387
|
||||
size 673
|
||||
oid sha256:833caf3788288cd278c7cbd9c9c9976744dbbef08594581814373cf85d7534d2
|
||||
size 684
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:db92d77f0185fa0a093ab0dedf5015ac990891ebc6caea2c08790ad4b53fe26e
|
||||
size 726
|
||||
oid sha256:64584c9dbb5c0d8dcbca73e2e0d89447a998f16f740e634e7c0c2151d38dd40a
|
||||
size 733
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4370d776f4833a0969b6e2759711a40dd29b5ba1de7ab98f909d4277cf39f989
|
||||
size 1524
|
||||
oid sha256:61e272612808ccb0d406f4bc311e93de256ad90b12d6429e79dd4110287aa778
|
||||
size 1550
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1c0059bea7b40880476a3dc43c4d1ddd1f865313bb17b39f87f2929c87f4bc13
|
||||
size 1856
|
||||
oid sha256:8a0a530636e460d0e488d63dbe2f39d7009ec6a364435ed9126aa430cba0990b
|
||||
size 1854
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:adebbe105edd9839a1bb534415c54845bdac3c6282516248906988eabc845322
|
||||
size 904
|
||||
oid sha256:404e43d6e09799b59802b9d4446521744972a47dc9386d994e2ebfc12d08c758
|
||||
size 893
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7151dd150c2b41c94049f0d300afc45bc03f2373b9143ea6adf5fa0e47d3067e
|
||||
size 1624
|
||||
oid sha256:9d127fed30616831cc500e20de77f26065cb88e4e43bfd1b4aec2140e9fbbda8
|
||||
size 1630
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b5fc32216fa0af42215981cb6c6e1d893abc6d0514d33417f7d409e265b7a714
|
||||
size 1300
|
||||
oid sha256:a3b8226344af72f9b03f280f01384c71da355260096f5cce5b84d38f119eca73
|
||||
size 1309
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:74e774f297202ad08e6db2b44dbe01b6b9f59ad245f67c53d07e523487e351b2
|
||||
size 11846
|
||||
oid sha256:f1e34b1be1279938f2bb56ac359270ab67f0930a82a2561c7002d32265361305
|
||||
size 11912
|
||||
|
|
Loading…
Reference in New Issue