|
| 1 | +use gtk::prelude::*; |
| 2 | +use gtk::subclass::prelude::*; |
| 3 | +use gtk::{glib, graphene, gsk}; |
| 4 | + |
| 5 | +use tdlib::types::ClosedVectorPath; |
| 6 | + |
| 7 | +mod imp { |
| 8 | + use super::*; |
| 9 | + use std::cell::RefCell; |
| 10 | + |
| 11 | + #[derive(Default)] |
| 12 | + pub(crate) struct VectorPath { |
| 13 | + pub(super) node: RefCell<Option<gsk::RenderNode>>, |
| 14 | + } |
| 15 | + |
| 16 | + #[glib::object_subclass] |
| 17 | + impl ObjectSubclass for VectorPath { |
| 18 | + const NAME: &'static str = "ComponentsVectorPath"; |
| 19 | + type Type = super::VectorPath; |
| 20 | + type ParentType = gtk::Widget; |
| 21 | + |
| 22 | + fn class_init(klass: &mut Self::Class) { |
| 23 | + klass.set_css_name("vectorpath"); |
| 24 | + } |
| 25 | + } |
| 26 | + |
| 27 | + impl ObjectImpl for VectorPath {} |
| 28 | + |
| 29 | + impl WidgetImpl for VectorPath { |
| 30 | + fn snapshot(&self, snapshot: >k::Snapshot) { |
| 31 | + let widget = self.obj(); |
| 32 | + |
| 33 | + let factor = (widget.width() as f32).max(widget.height() as f32) / 512.0; |
| 34 | + snapshot.scale(factor, factor); |
| 35 | + |
| 36 | + if let Some(node) = &*self.node.borrow() { |
| 37 | + snapshot.append_node(node); |
| 38 | + } |
| 39 | + } |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +glib::wrapper! { |
| 44 | + pub(crate) struct VectorPath(ObjectSubclass<imp::VectorPath>) |
| 45 | + @extends gtk::Widget; |
| 46 | +} |
| 47 | + |
| 48 | +impl VectorPath { |
| 49 | + pub fn new(outline: &[ClosedVectorPath]) -> Self { |
| 50 | + let obj: Self = glib::Object::new(); |
| 51 | + obj.imp().node.replace(Self::path_node(outline)); |
| 52 | + obj |
| 53 | + } |
| 54 | + |
| 55 | + fn path_node(outline: &[ClosedVectorPath]) -> Option<gsk::RenderNode> { |
| 56 | + use tdlib::enums::VectorPathCommand::{CubicBezierCurve, Line}; |
| 57 | + use tdlib::types::VectorPathCommandCubicBezierCurve as Curve; |
| 58 | + |
| 59 | + let snapshot = gtk::Snapshot::new(); |
| 60 | + let context = snapshot.append_cairo(&graphene::Rect::new(0.0, 0.0, 512.0, 512.0)); |
| 61 | + |
| 62 | + context.set_source_rgba(0.5, 0.5, 0.5, 0.4); |
| 63 | + |
| 64 | + for closed_path in outline { |
| 65 | + context.new_sub_path(); |
| 66 | + for command in &closed_path.commands { |
| 67 | + match command { |
| 68 | + Line(line) => { |
| 69 | + let e = &line.end_point; |
| 70 | + context.line_to(e.x, e.y); |
| 71 | + } |
| 72 | + CubicBezierCurve(curve) => { |
| 73 | + let Curve { |
| 74 | + start_control_point: sc, |
| 75 | + end_control_point: ec, |
| 76 | + end_point: e, |
| 77 | + } = curve; |
| 78 | + |
| 79 | + context.curve_to(sc.x, sc.y, ec.x, ec.y, e.x, e.y); |
| 80 | + } |
| 81 | + } |
| 82 | + } |
| 83 | + context.close_path(); |
| 84 | + } |
| 85 | + _ = context.fill(); |
| 86 | + |
| 87 | + snapshot.to_node() |
| 88 | + } |
| 89 | +} |
0 commit comments