Skip to content

Commit

Permalink
stickers: Add vector path
Browse files Browse the repository at this point in the history
  • Loading branch information
yuraiz committed Mar 26, 2023
1 parent fcf312f commit ff0ab78
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ mod avatar;
mod message_entry;
mod snow;
mod sticker;
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::sticker::Sticker;
pub(crate) use self::vector_path::VectorPath;
12 changes: 8 additions & 4 deletions src/components/sticker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use gtk::{gio, glib};
use tdlib::enums::StickerFormat;
use tdlib::types::Sticker as TdSticker;

use super::VectorPath;
use crate::session::Session;
use crate::utils::{decode_image_from_path, spawn};

Expand Down Expand Up @@ -52,11 +53,15 @@ mod imp {
}

impl WidgetImpl for Sticker {
fn measure(&self, orientation: gtk::Orientation, _for_size: i32) -> (i32, i32, i32, i32) {
fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) {
let size = self.longer_side_size.get();
let aspect_ratio = self.aspect_ratio.get();

let min_size = 1;
let min_size = if let Some(child) = &*self.child.borrow_mut() {
child.measure(orientation, for_size).0
} else {
1
};

let size = if let gtk::Orientation::Horizontal = orientation {
if aspect_ratio >= 1.0 {
Expand Down Expand Up @@ -103,8 +108,7 @@ impl Sticker {
return;
}

// TODO: draw sticker outline with cairo
self.set_child(None);
self.set_child(Some(VectorPath::new(&sticker.outline).upcast()));

let aspect_ratio = sticker.width as f64 / sticker.height as f64;
imp.aspect_ratio.set(aspect_ratio);
Expand Down
89 changes: 89 additions & 0 deletions src/components/vector_path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use gtk::{glib, graphene, gsk};

use tdlib::types::ClosedVectorPath;

mod imp {
use super::*;
use std::cell::RefCell;

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

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

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

impl ObjectImpl for VectorPath {}

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

let factor = (widget.width() as f32).max(widget.height() as f32) / 512.0;
snapshot.scale(factor, factor);

if let Some(node) = &*self.node.borrow() {
snapshot.append_node(node);
}
}
}
}

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

impl VectorPath {
pub fn new(outline: &[ClosedVectorPath]) -> Self {
let obj: Self = glib::Object::new();
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()
}
}

0 comments on commit ff0ab78

Please sign in to comment.