Skip to content

Commit

Permalink
rlottie: Improve VectorPath
Browse files Browse the repository at this point in the history
  • Loading branch information
yuraiz committed Feb 13, 2023
1 parent 4722427 commit 550b4e3
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 44 deletions.
2 changes: 1 addition & 1 deletion src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ mod vector_path;
pub(crate) use self::avatar::Avatar;
pub(crate) use self::message_entry::MessageEntry;
pub(crate) use self::snow::Snow;
pub(crate) use self::vector_path::StickerPreview;
pub(crate) use self::vector_path::VectorPath;
95 changes: 54 additions & 41 deletions src/components/vector_path.rs
Original file line number Diff line number Diff line change
@@ -1,76 +1,89 @@
use gtk::glib;
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{glib, graphene, gsk};

use tdlib::types::ClosedVectorPath;

mod imp {
use super::*;
use gtk::graphene;
use std::cell::RefCell;
use tdlib::enums::VectorPathCommand::{CubicBezierCurve, Line};
use tdlib::types::VectorPathCommandCubicBezierCurve as Curve;

#[derive(Default)]
pub struct StickerPreview {
pub(super) path: RefCell<Vec<ClosedVectorPath>>,
pub struct VectorPath {
pub(super) node: RefCell<Option<gsk::RenderNode>>,
}

#[glib::object_subclass]
impl ObjectSubclass for StickerPreview {
impl ObjectSubclass for VectorPath {
const NAME: &'static str = "ComponentsVectorPath";
type Type = super::StickerPreview;
type Type = super::VectorPath;
type ParentType = gtk::Widget;

fn class_init(klass: &mut Self::Class) {
klass.set_css_name("vectorpath");
}
}

impl ObjectImpl for StickerPreview {}
impl ObjectImpl for VectorPath {}

impl WidgetImpl for StickerPreview {
impl WidgetImpl for VectorPath {
fn snapshot(&self, snapshot: &gtk::Snapshot) {
let widget = self.obj();

let context = snapshot.append_cairo(&graphene::Rect::new(0.0, 0.0, 512.0, 512.0));

let scale = widget.width().max(widget.height()) as f64 / 512.0;
context.scale(scale, scale);

context.set_source_rgba(0.5, 0.5, 0.5, 0.4);

let outline = &*self.path.borrow();
let factor = (widget.width() as f32).max(widget.height() as f32) / 512.0;
snapshot.scale(factor, factor);

for closed_path in outline {
for command in &closed_path.commands {
match command {
Line(line) => {
let e = &line.end_point;
context.line_to(e.x, e.y);
}
CubicBezierCurve(curve) => {
let Curve {
start_control_point: sc,
end_control_point: ec,
end_point: e,
} = curve;

context.curve_to(sc.x, sc.y, ec.x, ec.y, e.x, e.y);
}
}
}
_ = context.fill();
if let Some(node) = &*self.node.borrow() {
snapshot.append_node(node);
}
}
}
}

glib::wrapper! {
pub struct StickerPreview(ObjectSubclass<imp::StickerPreview>)
pub struct VectorPath(ObjectSubclass<imp::VectorPath>)
@extends gtk::Widget;
}

impl StickerPreview {
pub fn new(outline: Vec<ClosedVectorPath>) -> Self {
impl VectorPath {
pub fn new(outline: &[ClosedVectorPath]) -> Self {
let obj: Self = glib::Object::new(&[]);
obj.imp().path.replace(outline);
obj.imp().node.replace(Self::path_node(outline));
obj
}

fn path_node(outline: &[ClosedVectorPath]) -> Option<gsk::RenderNode> {
use tdlib::enums::VectorPathCommand::{CubicBezierCurve, Line};
use tdlib::types::VectorPathCommandCubicBezierCurve as Curve;

let snapshot = gtk::Snapshot::new();
let context = snapshot.append_cairo(&graphene::Rect::new(0.0, 0.0, 512.0, 512.0));

context.set_source_rgba(0.5, 0.5, 0.5, 0.4);

for closed_path in outline {
context.new_sub_path();
for command in &closed_path.commands {
match command {
Line(line) => {
let e = &line.end_point;
context.line_to(e.x, e.y);
}
CubicBezierCurve(curve) => {
let Curve {
start_control_point: sc,
end_control_point: ec,
end_point: e,
} = curve;

context.curve_to(sc.x, sc.y, ec.x, ec.y, e.x, e.y);
}
}
}
context.close_path();
}
_ = context.fill();

snapshot.to_node()
}
}
4 changes: 2 additions & 2 deletions src/session/content/message_row/sticker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::io::Cursor;
use tdlib::enums::{MessageContent, StickerFormat, StickerFullType};
use tdlib::types::File;

use crate::components::StickerPreview;
use crate::components::VectorPath;
use crate::session::content::message_row::{MessageBase, MessageBaseImpl, MessageIndicators};
use crate::tdlib::Message;
use crate::utils::spawn;
Expand Down Expand Up @@ -178,7 +178,7 @@ impl MessageBaseExt for MessageSticker {
imp.aspect_ratio
.set(sticker.width as f64 / sticker.height as f64);

let preview = StickerPreview::new(sticker.outline.clone());
let preview = VectorPath::new(&sticker.outline);
self.imp().bin.set_child(Some(&preview));

if sticker.sticker.local.is_downloading_completed {
Expand Down

0 comments on commit 550b4e3

Please sign in to comment.