From eb1c585ecbe4da10b3d8ab4235437577f737922a Mon Sep 17 00:00:00 2001 From: MeexReay Date: Tue, 2 Sep 2025 20:15:15 +0300 Subject: [PATCH] fix: make scrolled_window always scrolled to the end --- src/chat/gui/mod.rs | 1 + src/chat/gui/page.rs | 16 +++++++++++ src/chat/gui/widgets/imp.rs | 53 +++++++++++++++++++++++++++++++++++++ src/chat/gui/widgets/mod.rs | 15 +++++++++++ 4 files changed, 85 insertions(+) create mode 100644 src/chat/gui/widgets/imp.rs create mode 100644 src/chat/gui/widgets/mod.rs diff --git a/src/chat/gui/mod.rs b/src/chat/gui/mod.rs index ecea4a1..4cefa94 100644 --- a/src/chat/gui/mod.rs +++ b/src/chat/gui/mod.rs @@ -46,6 +46,7 @@ use super::{ mod preferences; mod page; +mod widgets; use page::*; use preferences::*; diff --git a/src/chat/gui/page.rs b/src/chat/gui/page.rs index 65029b4..269e627 100644 --- a/src/chat/gui/page.rs +++ b/src/chat/gui/page.rs @@ -35,6 +35,7 @@ use crate::chat::{ on_send_message, parse_message, SERVER_LIST, }; +use super::widgets::CustomLayout; use super::{add_chat_messages, get_avatar_id, get_message_sign, load_pixbuf, send_notification, try_save_config, update_window_title, UiModel}; pub fn get_message_box( @@ -359,6 +360,21 @@ pub fn build_page_box(ctx: Arc, app: &Application) -> (GtkBox, GtkBox, .propagate_natural_height(true) .build(); + let layout = CustomLayout::default(); + + layout.connect_local("size-changed", false, { + let chat_scrolled = chat_scrolled.downgrade(); + move |_| { + if let Some(chat_scrolled) = chat_scrolled.upgrade() { + let value = chat_scrolled.vadjustment().upper() - chat_scrolled.vadjustment().page_size(); + chat_scrolled.vadjustment().set_value(value); + } + return None; + } + }); + + page_box.set_layout_manager(Some(layout)); + timeout_add_local_once(Duration::ZERO, clone!( #[weak] chat_scrolled, move || { diff --git a/src/chat/gui/widgets/imp.rs b/src/chat/gui/widgets/imp.rs new file mode 100644 index 0000000..1f4f056 --- /dev/null +++ b/src/chat/gui/widgets/imp.rs @@ -0,0 +1,53 @@ +use libadwaita::{glib, gtk}; + +use glib::object::ObjectExt; +use gtk::{subclass::prelude::*, prelude::LayoutManagerExt, BoxLayout}; + +#[derive(Debug)] +pub struct CustomLayout { + box_layout: BoxLayout +} + +impl Default for CustomLayout { + fn default() -> Self { + CustomLayout { + box_layout: BoxLayout::builder() + .orientation(gtk::Orientation::Vertical) + .spacing(5) + .build() + } + } +} + +#[glib::object_subclass] +impl ObjectSubclass for CustomLayout { + const NAME: &'static str = "CustomLayout"; + type Type = super::CustomLayout; + type ParentType = gtk::LayoutManager; +} + +impl ObjectImpl for CustomLayout { + fn signals() -> &'static [glib::subclass::Signal] { + use std::sync::OnceLock; + + static SIGNALS: OnceLock> = OnceLock::new(); + + SIGNALS.get_or_init(|| { + vec![glib::subclass::Signal::builder("size-changed").build()] + }) + } +} +impl LayoutManagerImpl for CustomLayout { + fn allocate(&self, widget: >k::Widget, width: i32, height: i32, baseline: i32) { + self.obj().emit_by_name::<()>("size-changed", &[]); + self.box_layout.allocate(widget, width, height, baseline) + } + fn measure( + &self, + widget: >k::Widget, + orientation: gtk::Orientation, + for_size: i32, + ) -> (i32, i32, i32, i32) { + self.box_layout.measure(widget, orientation, for_size) + } +} diff --git a/src/chat/gui/widgets/mod.rs b/src/chat/gui/widgets/mod.rs new file mode 100644 index 0000000..03f88c5 --- /dev/null +++ b/src/chat/gui/widgets/mod.rs @@ -0,0 +1,15 @@ +mod imp; + +use libadwaita::gtk::glib; +use libadwaita::gtk; + +glib::wrapper! { + pub struct CustomLayout(ObjectSubclass) + @extends gtk::LayoutManager; +} + +impl Default for CustomLayout { + fn default() -> Self { + glib::Object::new() + } +}