Skip to content

Commit

Permalink
Button gradient background
Browse files Browse the repository at this point in the history
This adds the rendering of the gradient to the button widget.

The "piet_scene_helpers" module is a bit hacky, we'll need to have some discussions about how to handle kurbo shape types more easily. But it should work for now.
  • Loading branch information
raphlinus committed Nov 21, 2022
1 parent 209fd9d commit 09038d9
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 13 deletions.
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ mod widget;

pub use app::App;
pub use app_main::AppLauncher;
pub use view::View;
pub use view::button::button;
pub use widget::Widget;
pub use view::View;
pub use widget::align::VertAlignment;
pub use widget::Widget;

use glazier::kurbo::Size;
use glazier::{
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use xilem::{App, AppLauncher, View, button};
use xilem::{button, App, AppLauncher, View};

fn app_logic(_data: &mut ()) -> impl View<()> {
button("click me", |_| println!("clicked"))
Expand Down
50 changes: 43 additions & 7 deletions src/widget/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use glazier::{
kurbo::{Insets, Size},
};
use glazier::kurbo::{Insets, Size};
use parley::Layout;
use piet_scene::{Brush, Color, Affine, SceneFragment, SceneBuilder};
use piet_scene::{Affine, Brush, Color, GradientStop, GradientStops, SceneBuilder, SceneFragment};

use crate::{event::Event, id::IdPath, VertAlignment, text::ParleyBrush};
use crate::{event::Event, id::IdPath, text::ParleyBrush, VertAlignment};

use super::{
align::{FirstBaseline, LastBaseline, SingleAlignment},
contexts::LifeCycleCx,
AlignCx, EventCx, LayoutCx, LifeCycle, PaintCx, RawEvent, UpdateCx, Widget, Rendered, piet_scene_helpers,
piet_scene_helpers::{self, UnitPoint},
AlignCx, EventCx, LayoutCx, LifeCycle, PaintCx, RawEvent, Rendered, UpdateCx, Widget,
};

pub struct Button {
Expand Down Expand Up @@ -137,6 +136,31 @@ impl Widget for Button {
} else {
Color::rgb8(0x3a, 0x3a, 0x3a)
};
let bg_stops = if is_active {
[
GradientStop {
offset: 0.0,
color: Color::rgb8(0x3a, 0x3a, 0x3a),
},
GradientStop {
offset: 1.0,
color: Color::rgb8(0xa1, 0xa1, 0xa1),
},
][..]
.into()
} else {
[
GradientStop {
offset: 0.0,
color: Color::rgb8(0xa1, 0xa1, 0xa1),
},
GradientStop {
offset: 1.0,
color: Color::rgb8(0x3a, 0x3a, 0x3a),
},
][..]
.into()
};
/*
let bg_gradient = if is_active {
LinearGradient::new(
Expand All @@ -154,7 +178,19 @@ impl Widget for Button {
*/
let mut fragment = SceneFragment::default();
let mut builder = SceneBuilder::for_fragment(&mut fragment);
piet_scene_helpers::stroke(&mut builder, &rounded_rect, &Brush::Solid(border_color), 1.0);
piet_scene_helpers::stroke(
&mut builder,
&rounded_rect,
&Brush::Solid(border_color),
button_border_width,
);
piet_scene_helpers::fill_lin_gradient(
&mut builder,
&rounded_rect,
bg_stops,
UnitPoint::TOP,
UnitPoint::BOTTOM,
);
//cx.fill(rounded_rect, &bg_gradient);
if let Some(layout) = &self.layout {
let size = Size::new(layout.width() as f64, layout.height() as f64);
Expand Down
84 changes: 81 additions & 3 deletions src/widget/piet_scene_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
use glazier::kurbo::{self, Rect, Shape};
use piet_scene::{
Affine, Brush, Cap, ExtendMode, Fill, GradientStops, Join, LinearGradient, PathElement, Point,
SceneBuilder, Stroke,
};

use glazier::kurbo::Shape;
use piet_scene::{SceneBuilder, Stroke, Join, Cap, Brush, Affine, PathElement};
#[derive(Debug, Clone, Copy)]
pub struct UnitPoint {
u: f64,
v: f64,
}

pub fn stroke(builder: &mut SceneBuilder, path: &impl Shape, brush: &Brush, stroke_width: f64) {
let style = Stroke {
Expand All @@ -13,6 +21,76 @@ pub fn stroke(builder: &mut SceneBuilder, path: &impl Shape, brush: &Brush, stro
dash_offset: 0.0,
scale: false,
};
let elements = path.path_elements(1e-3).map(PathElement::from_kurbo).collect::<Vec<_>>();
// TODO: figure out how to avoid allocation
// (Just removing the collect should work in theory, but running into a clone bound)
let elements = path
.path_elements(1e-3)
.map(PathElement::from_kurbo)
.collect::<Vec<_>>();
builder.stroke(&style, Affine::IDENTITY, brush, None, &elements)
}

// Note: copied from piet
impl UnitPoint {
/// `(0.0, 0.0)`
pub const TOP_LEFT: UnitPoint = UnitPoint::new(0.0, 0.0);
/// `(0.5, 0.0)`
pub const TOP: UnitPoint = UnitPoint::new(0.5, 0.0);
/// `(1.0, 0.0)`
pub const TOP_RIGHT: UnitPoint = UnitPoint::new(1.0, 0.0);
/// `(0.0, 0.5)`
pub const LEFT: UnitPoint = UnitPoint::new(0.0, 0.5);
/// `(0.5, 0.5)`
pub const CENTER: UnitPoint = UnitPoint::new(0.5, 0.5);
/// `(1.0, 0.5)`
pub const RIGHT: UnitPoint = UnitPoint::new(1.0, 0.5);
/// `(0.0, 1.0)`
pub const BOTTOM_LEFT: UnitPoint = UnitPoint::new(0.0, 1.0);
/// `(0.5, 1.0)`
pub const BOTTOM: UnitPoint = UnitPoint::new(0.5, 1.0);
/// `(1.0, 1.0)`
pub const BOTTOM_RIGHT: UnitPoint = UnitPoint::new(1.0, 1.0);

/// Create a new UnitPoint.
///
/// The `u` and `v` coordinates describe the point, with (0.0, 0.0) being
/// the top-left, and (1.0, 1.0) being the bottom-right.
pub const fn new(u: f64, v: f64) -> UnitPoint {
UnitPoint { u, v }
}

/// Given a rectangle, resolve the point within the rectangle.
pub fn resolve(self, rect: Rect) -> kurbo::Point {
kurbo::Point::new(
rect.x0 + self.u * (rect.x1 - rect.x0),
rect.y0 + self.v * (rect.y1 - rect.y0),
)
}
}

pub fn fill_lin_gradient(
builder: &mut SceneBuilder,
path: &impl Shape,
stops: GradientStops,
start: UnitPoint,
end: UnitPoint,
) {
let rect = path.bounding_box();
let lin_grad = LinearGradient {
start: Point::from_kurbo(start.resolve(rect)),
end: Point::from_kurbo(end.resolve(rect)),
stops,
extend: ExtendMode::Pad,
};
let elements = path
.path_elements(1e-3)
.map(PathElement::from_kurbo)
.collect::<Vec<_>>();
builder.fill(
Fill::NonZero,
Affine::IDENTITY,
&Brush::LinearGradient(lin_grad),
None,
elements,
);
}

0 comments on commit 09038d9

Please sign in to comment.