export entire TextView widget reference to the Search component

This commit is contained in:
yggverse 2024-12-17 02:13:47 +02:00
parent e0cb5d7a0f
commit 8b65df99f4
8 changed files with 52 additions and 43 deletions

View File

@ -575,7 +575,7 @@ impl Page {
}; };
// Update `find` model with new buffer // Update `find` model with new buffer
search.update(Some(text_widget.buffer)); search.update(Some(text_widget.text_view));
// Update page meta // Update page meta
meta.set_status(Status::Success) meta.set_status(Status::Success)

View File

@ -7,8 +7,8 @@ use source::Source;
use super::{BrowserAction, TabAction, WindowAction}; use super::{BrowserAction, TabAction, WindowAction};
use gtk::{ use gtk::{
glib::Uri, glib::Uri,
prelude::{BoxExt, TextViewExt}, prelude::{BoxExt, Cast},
Box, Orientation, ScrolledWindow, TextBuffer, Box, Orientation, ScrolledWindow, TextView,
}; };
use std::rc::Rc; use std::rc::Rc;
@ -17,7 +17,7 @@ pub struct Meta {
} // @TODO move to separated mod } // @TODO move to separated mod
pub struct Text { pub struct Text {
pub buffer: TextBuffer, pub text_view: TextView,
pub g_box: Box, pub g_box: Box,
pub meta: Meta, pub meta: Meta,
} }
@ -91,7 +91,7 @@ impl Text {
});*/ });*/
Self { Self {
buffer: gemini.reader.widget.text_view.buffer(), text_view: gemini.reader.widget.text_view.clone().upcast::<TextView>(),
meta: Meta { meta: Meta {
title: gemini.reader.title.clone(), title: gemini.reader.title.clone(),
}, },
@ -108,7 +108,7 @@ impl Text {
g_box.append(&ScrolledWindow::builder().child(&source.text_view).build()); g_box.append(&ScrolledWindow::builder().child(&source.text_view).build());
Self { Self {
buffer: source.text_view.buffer(), text_view: source.text_view.upcast::<TextView>(),
meta: Meta { title: None }, meta: Meta { title: None },
g_box, g_box,
} }

View File

@ -1,19 +1,19 @@
mod buffer;
mod form; mod form;
mod placeholder; mod placeholder;
mod subject;
use buffer::Buffer;
use form::Form; use form::Form;
use placeholder::Placeholder; use placeholder::Placeholder;
use subject::Subject;
use gtk::{ use gtk::{
prelude::{BoxExt, WidgetExt}, prelude::{BoxExt, WidgetExt},
Align, Box, Orientation, TextBuffer, Align, Box, Orientation, TextBuffer, TextView,
}; };
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
pub struct Search { pub struct Search {
buffer: Rc<RefCell<Option<Buffer>>>, subject: Rc<RefCell<Option<Subject>>>,
pub form: Rc<Form>, pub form: Rc<Form>,
pub placeholder: Rc<Placeholder>, pub placeholder: Rc<Placeholder>,
pub g_box: Box, pub g_box: Box,
@ -25,8 +25,8 @@ impl Search {
/// Create new `Self` /// Create new `Self`
pub fn new() -> Self { pub fn new() -> Self {
// Init components // Init components
let buffer = Rc::new(RefCell::new(None)); let subject = Rc::new(RefCell::new(None));
let form = Rc::new(Form::new(&buffer)); let form = Rc::new(Form::new(&subject));
let placeholder = Rc::new(Placeholder::new()); let placeholder = Rc::new(Placeholder::new());
// Init main container // Init main container
@ -42,7 +42,7 @@ impl Search {
// Done // Done
Self { Self {
buffer, subject,
form, form,
g_box, g_box,
placeholder, placeholder,
@ -52,7 +52,7 @@ impl Search {
// Actions // Actions
pub fn show(&self) { pub fn show(&self) {
if self.buffer.borrow().is_some() { if self.subject.borrow().is_some() {
self.form.show(); self.form.show();
self.placeholder.hide(); self.placeholder.hide();
} else { } else {
@ -74,9 +74,10 @@ impl Search {
} }
} }
pub fn update(&self, text_buffer: Option<TextBuffer>) { /// * currently supports [TextView](https://docs.gtk.org/gtk4/class.TextView.html) only
self.buffer.replace(match text_buffer { pub fn update(&self, text_view: Option<TextView>) {
Some(buffer) => Some(Buffer::new(buffer)), self.subject.replace(match text_view {
Some(subject) => Some(Subject::new(subject)),
None => None, None => None,
}); });
} }

View File

@ -3,12 +3,14 @@ mod input;
mod match_case; mod match_case;
mod navigation; mod navigation;
use super::Buffer; use super::Subject;
use input::Input; use input::Input;
use navigation::Navigation; use navigation::Navigation;
use gtk::{ use gtk::{
prelude::{BoxExt, ButtonExt, CheckButtonExt, EditableExt, TextBufferExt, WidgetExt}, prelude::{
BoxExt, ButtonExt, CheckButtonExt, EditableExt, TextBufferExt, TextViewExt, WidgetExt,
},
Align, Box, Orientation, TextIter, TextSearchFlags, Align, Box, Orientation, TextIter, TextSearchFlags,
}; };
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
@ -21,7 +23,7 @@ impl Form {
// Constructors // Constructors
/// Create new `Self` /// Create new `Self`
pub fn new(buffer: &Rc<RefCell<Option<Buffer>>>) -> Self { pub fn new(buffer: &Rc<RefCell<Option<Subject>>>) -> Self {
// Init components // Init components
let close = close::new(); let close = close::new();
let input = Rc::new(Input::new()); let input = Rc::new(Input::new());
@ -99,41 +101,44 @@ impl Form {
// Tools // Tools
fn find( fn find(
buffer: &Rc<RefCell<Option<Buffer>>>, subject: &Rc<RefCell<Option<Subject>>>,
subject: &str, request: &str,
is_match_case: bool, is_match_case: bool,
) -> Vec<(TextIter, TextIter)> { ) -> Vec<(TextIter, TextIter)> {
// Init matches holder // Init matches holder
let mut result = Vec::new(); let mut result = Vec::new();
// Borrow buffer // Borrow buffer
match buffer.borrow().as_ref() { match subject.borrow().as_ref() {
Some(buffer) => { Some(subject) => {
// Get iters // Get iters
let buffer_start = buffer.text_buffer.start_iter(); let buffer_start = subject.text_view.buffer().start_iter();
let buffer_end = buffer.text_buffer.end_iter(); let buffer_end = subject.text_view.buffer().end_iter();
// Cleanup previous search highlights // Cleanup previous search highlights
buffer subject
.text_buffer .text_view
.remove_tag(&buffer.tag.current, &buffer_start, &buffer_end); .buffer()
buffer .remove_tag(&subject.tag.current, &buffer_start, &buffer_end);
.text_buffer subject
.remove_tag(&buffer.tag.found, &buffer_start, &buffer_end); .text_view
.buffer()
.remove_tag(&subject.tag.found, &buffer_start, &buffer_end);
// Begin new search // Begin new search
let mut next = buffer_start; let mut next = buffer_start;
while let Some((match_start, match_end)) = next.forward_search( while let Some((match_start, match_end)) = next.forward_search(
subject, request,
match is_match_case { match is_match_case {
true => TextSearchFlags::TEXT_ONLY, true => TextSearchFlags::TEXT_ONLY,
false => TextSearchFlags::CASE_INSENSITIVE, false => TextSearchFlags::CASE_INSENSITIVE,
}, },
None, // unlimited None, // unlimited
) { ) {
buffer subject
.text_buffer .text_view
.apply_tag(&buffer.tag.found, &match_start, &match_end); .buffer()
.apply_tag(&subject.tag.found, &match_start, &match_end);
next = match_end; next = match_end;
result.push((match_start, match_end)); result.push((match_start, match_end));
} }

View File

@ -2,24 +2,27 @@ mod tag;
use tag::Tag; use tag::Tag;
use gtk::{prelude::TextBufferExt, TextBuffer}; use gtk::{
prelude::{TextBufferExt, TextViewExt},
TextView,
};
pub struct Buffer { pub struct Subject {
pub text_buffer: TextBuffer, pub text_view: TextView,
pub tag: Tag, pub tag: Tag,
} }
impl Buffer { impl Subject {
// Constructors // Constructors
/// Create new `Self` /// Create new `Self`
pub fn new(text_buffer: TextBuffer) -> Self { pub fn new(text_view: TextView) -> Self {
// Init components // Init components
// * create new tag objects required for new buffer, // * create new tag objects required for new buffer,
// instead of re-use existing refs (maybe the bug) // instead of re-use existing refs (maybe the bug)
let tag = Tag::new(text_buffer.tag_table()); let tag = Tag::new(text_view.buffer().tag_table());
// Init `Self` // Init `Self`
Self { text_buffer, tag } Self { text_view, tag }
} }
} }