|
1 | 1 | use adw::prelude::*; |
| 2 | +use glib::clone; |
2 | 3 | use gtk::subclass::prelude::*; |
3 | | -use gtk::{glib, CompositeTemplate}; |
| 4 | +use gtk::{gdk, glib, graphene, gsk, CompositeTemplate}; |
4 | 5 | use std::collections::hash_map::DefaultHasher; |
5 | 6 | use std::hash::{Hash, Hasher}; |
6 | 7 |
|
@@ -28,6 +29,8 @@ mod imp { |
28 | 29 | using Adw 1; |
29 | 30 |
|
30 | 31 | template $MessageBubble { |
| 32 | + overflow: hidden; |
| 33 | +
|
31 | 34 | Overlay overlay { |
32 | 35 | Box { |
33 | 36 | orientation: vertical; |
@@ -60,6 +63,7 @@ mod imp { |
60 | 63 | pub(crate) struct MessageBubble { |
61 | 64 | pub(super) sender_color_class: RefCell<Option<String>>, |
62 | 65 | pub(super) sender_binding: RefCell<Option<gtk::ExpressionWatch>>, |
| 66 | + pub(super) parent_list_view: RefCell<glib::WeakRef<gtk::ListView>>, |
63 | 67 | #[template_child] |
64 | 68 | pub(super) overlay: TemplateChild<gtk::Overlay>, |
65 | 69 | #[template_child] |
@@ -119,6 +123,45 @@ mod imp { |
119 | 123 | } |
120 | 124 |
|
121 | 125 | impl WidgetImpl for MessageBubble { |
| 126 | + fn realize(&self) { |
| 127 | + self.parent_realize(); |
| 128 | + |
| 129 | + let widget = self.obj(); |
| 130 | + |
| 131 | + if let Some(view) = widget.parent_list_view() { |
| 132 | + self.parent_list_view.replace(view.downgrade()); |
| 133 | + view.vadjustment() |
| 134 | + .unwrap() |
| 135 | + .connect_value_notify(clone!(@weak widget => move |_| { |
| 136 | + widget.queue_draw(); |
| 137 | + })); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + fn snapshot(&self, snapshot: >k::Snapshot) { |
| 142 | + let widget = self.obj(); |
| 143 | + if widget.has_css_class("outgoing") { |
| 144 | + let width = widget.width() as f32; |
| 145 | + let height = widget.height() as f32; |
| 146 | + |
| 147 | + let bounds = graphene::Rect::new(0.0, 0.0, width, height); |
| 148 | + let gradient_bounds = widget.gradient_bounds(); |
| 149 | + let [first, second] = widget.linear_gradient_colors(); |
| 150 | + |
| 151 | + snapshot.append_linear_gradient( |
| 152 | + &bounds, |
| 153 | + &graphene::Point::new(0.0, gradient_bounds.y()), |
| 154 | + &graphene::Point::new(0.0, gradient_bounds.height()), |
| 155 | + &[ |
| 156 | + gsk::ColorStop::new(0.0, first), |
| 157 | + gsk::ColorStop::new(1.0, second), |
| 158 | + ], |
| 159 | + ); |
| 160 | + } |
| 161 | + |
| 162 | + self.parent_snapshot(snapshot); |
| 163 | + } |
| 164 | + |
122 | 165 | fn measure(&self, orientation: gtk::Orientation, for_size: i32) -> (i32, i32, i32, i32) { |
123 | 166 | // Limit the widget width |
124 | 167 | if orientation == gtk::Orientation::Horizontal { |
@@ -308,4 +351,44 @@ impl MessageBubble { |
308 | 351 | .set_indicators(Some(imp.indicators.clone())); |
309 | 352 | } |
310 | 353 | } |
| 354 | + |
| 355 | + fn parent_list_view(&self) -> Option<gtk::ListView> { |
| 356 | + let mut parent = self.parent()?; |
| 357 | + loop { |
| 358 | + match parent.downcast() { |
| 359 | + Ok(list_view) => return Some(list_view), |
| 360 | + Err(not_list_view) => parent = not_list_view.parent()?, |
| 361 | + } |
| 362 | + } |
| 363 | + } |
| 364 | + |
| 365 | + fn gradient_bounds(&self) -> graphene::Rect { |
| 366 | + if let Some(view) = self.imp().parent_list_view.borrow().upgrade() { |
| 367 | + let view_bounds = view.compute_bounds(self.imp().obj().as_ref()).unwrap(); |
| 368 | + |
| 369 | + graphene::Rect::new( |
| 370 | + view_bounds.x(), |
| 371 | + view_bounds.y(), |
| 372 | + view_bounds.width() + view_bounds.x(), |
| 373 | + view_bounds.height() + view_bounds.y(), |
| 374 | + ) |
| 375 | + } else { |
| 376 | + panic!("can't get parent ListView"); |
| 377 | + } |
| 378 | + } |
| 379 | + |
| 380 | + fn linear_gradient_colors(&self) -> [gdk::RGBA; 2] { |
| 381 | + // default colors from iOS |
| 382 | + if !adw::StyleManager::default().is_dark() { |
| 383 | + [ |
| 384 | + gdk::RGBA::new(0.91764706, 0.9882353, 0.8235294, 1.0), |
| 385 | + gdk::RGBA::new(0.91764706, 0.9882353, 0.8235294, 1.0), |
| 386 | + ] |
| 387 | + } else { |
| 388 | + [ |
| 389 | + gdk::RGBA::new(0.21960784, 0.32156864, 0.89411765, 1.0), |
| 390 | + gdk::RGBA::new(0.63529414, 0.3372549, 0.58431375, 1.0), |
| 391 | + ] |
| 392 | + } |
| 393 | + } |
311 | 394 | } |
0 commit comments