replace tag link tooltip with gutter widget

This commit is contained in:
yggverse 2025-02-04 22:26:30 +02:00
parent 7800ec6c26
commit 537ee92fb7
2 changed files with 81 additions and 6 deletions

View File

@ -1,10 +1,12 @@
mod ansi; mod ansi;
pub mod error; pub mod error;
mod gutter;
mod icon; mod icon;
mod syntax; mod syntax;
mod tag; mod tag;
pub use error::Error; pub use error::Error;
use gutter::Gutter;
use icon::Icon; use icon::Icon;
use syntax::Syntax; use syntax::Syntax;
use tag::Tag; use tag::Tag;
@ -98,6 +100,9 @@ impl Gemini {
.build() .build()
}; };
// Init gutter widget (the tooltip on URL tags hover)
let gutter = Gutter::build(&text_view);
// Parse gemtext lines // Parse gemtext lines
for line in gemtext.lines() { for line in gemtext.lines() {
// Is inline code // Is inline code
@ -375,8 +380,8 @@ impl Gemini {
Window::NONE, Window::NONE,
Cancellable::NONE, Cancellable::NONE,
|result| { |result| {
if let Err(error) = result { if let Err(e) = result {
println!("{error}") println!("{e}")
} }
}, },
), ),
@ -460,12 +465,12 @@ impl Gemini {
// Keep hovered tag in memory // Keep hovered tag in memory
hover.replace(Some(tag.clone())); hover.replace(Some(tag.clone()));
// Show tooltip
gutter.set_uri(Some(uri));
// Toggle cursor // Toggle cursor
text_view.set_cursor_from_name(Some("pointer")); text_view.set_cursor_from_name(Some("pointer"));
// Show tooltip | @TODO set_gutter option?
text_view.set_tooltip_text(Some(&uri.to_string()));
// Redraw required to apply changes immediately // Redraw required to apply changes immediately
text_view.queue_draw(); text_view.queue_draw();
@ -475,8 +480,8 @@ impl Gemini {
} }
// Restore defaults // Restore defaults
gutter.set_uri(None);
text_view.set_cursor_from_name(Some("text")); text_view.set_cursor_from_name(Some("text"));
text_view.set_tooltip_text(None);
text_view.queue_draw(); text_view.queue_draw();
} }
}); // @TODO may be expensive for CPU, add timeout? }); // @TODO may be expensive for CPU, add timeout?

View File

@ -0,0 +1,70 @@
use gtk::{
glib::{timeout_add_local_once, Uri},
pango::EllipsizeMode,
prelude::{TextViewExt, WidgetExt},
Align, Label, TextView, TextWindowType,
};
use std::{cell::Cell, rc::Rc, time::Duration};
pub struct Gutter {
pub label: Label,
is_active: Rc<Cell<bool>>,
}
impl Gutter {
pub fn build(text_view: &TextView) -> Self {
const MARGIN_X: i32 = 8;
const MARGIN_Y: i32 = 2;
let label = Label::builder()
.css_classes([
// "caption",
"dim-label",
])
.halign(Align::Start)
.margin_start(MARGIN_X)
.margin_end(MARGIN_X)
.margin_top(MARGIN_Y)
.margin_bottom(MARGIN_Y)
.ellipsize(EllipsizeMode::Middle)
.build();
text_view.set_gutter(TextWindowType::Bottom, Some(&label));
text_view
.gutter(TextWindowType::Bottom)
.unwrap()
.set_css_classes(&["view"]); // @TODO unspecified patch
Self {
is_active: Rc::new(Cell::new(false)),
label,
}
}
pub fn set_uri(&self, uri: Option<&Uri>) {
match uri {
Some(uri) => {
if !self.label.is_visible() {
if !self.is_active.replace(true) {
timeout_add_local_once(Duration::from_millis(500), {
let label = self.label.clone();
let is_active = self.is_active.clone();
let uri = uri.clone();
move || {
if is_active.replace(false) {
label.set_label(&uri.to_string());
label.set_visible(true)
}
}
});
}
} else {
self.label.set_label(&uri.to_string())
}
}
None => {
self.is_active.replace(false);
self.label.set_visible(false)
}
}
}
}