gtk4/subclass/
text_buffer.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3// rustdoc-stripper-ignore-next
4//! Traits intended for subclassing [`TextBuffer`](crate::TextBuffer).
5
6use glib::translate::*;
7
8use crate::{
9    ffi, prelude::*, subclass::prelude::*, TextBuffer, TextChildAnchor, TextIter, TextMark, TextTag,
10};
11
12pub trait TextBufferImpl: TextBufferImplExt + ObjectImpl {
13    /// Emits the “apply-tag” signal on @self.
14    ///
15    /// The default handler for the signal applies
16    /// @tag to the given range. @start and @end do
17    /// not have to be in order.
18    /// ## `tag`
19    /// a [`TextTag`][crate::TextTag]
20    /// ## `start`
21    /// one bound of range to be tagged
22    /// ## `end`
23    /// other bound of range to be tagged
24    fn apply_tag(&self, tag: &TextTag, start: &TextIter, end: &TextIter) {
25        self.parent_apply_tag(tag, start, end)
26    }
27    /// Called to indicate that the buffer operations between here and a
28    /// call to gtk_text_buffer_end_user_action() are part of a single
29    /// user-visible operation.
30    ///
31    /// The operations between gtk_text_buffer_begin_user_action() and
32    /// gtk_text_buffer_end_user_action() can then be grouped when creating
33    /// an undo stack. [`TextBuffer`][crate::TextBuffer] maintains a count of calls to
34    /// gtk_text_buffer_begin_user_action() that have not been closed with
35    /// a call to gtk_text_buffer_end_user_action(), and emits the
36    /// “begin-user-action” and “end-user-action” signals only for the
37    /// outermost pair of calls. This allows you to build user actions
38    /// from other user actions.
39    ///
40    /// The “interactive” buffer mutation functions, such as
41    /// [`TextBufferExt::insert_interactive()`][crate::prelude::TextBufferExt::insert_interactive()], automatically call
42    /// begin/end user action around the buffer operations they perform,
43    /// so there's no need to add extra calls if you user action consists
44    /// solely of a single call to one of those functions.
45    fn begin_user_action(&self) {
46        self.parent_begin_user_action()
47    }
48    /// The class handler for the `GtkTextBuffer::changed` signal.
49    fn changed(&self) {
50        self.parent_changed()
51    }
52    /// The class handler for the `GtkTextBuffer::delete-range` signal.
53    fn delete_range(&self, start: &mut TextIter, end: &mut TextIter) {
54        self.parent_delete_range(start, end)
55    }
56    /// Ends a user-visible operation.
57    ///
58    /// Should be paired with a call to
59    /// [`TextBufferExt::begin_user_action()`][crate::prelude::TextBufferExt::begin_user_action()].
60    /// See that function for a full explanation.
61    fn end_user_action(&self) {
62        self.parent_end_user_action()
63    }
64    /// Inserts a child widget anchor into the text buffer at @iter.
65    ///
66    /// The anchor will be counted as one character in character counts, and
67    /// when obtaining the buffer contents as a string, will be represented
68    /// by the Unicode “object replacement character” 0xFFFC. Note that the
69    /// “slice” variants for obtaining portions of the buffer as a string
70    /// include this character for child anchors, but the “text” variants do
71    /// not. E.g. see [`TextBufferExt::slice()`][crate::prelude::TextBufferExt::slice()] and
72    /// [`TextBufferExt::text()`][crate::prelude::TextBufferExt::text()].
73    ///
74    /// Consider [`TextBufferExt::create_child_anchor()`][crate::prelude::TextBufferExt::create_child_anchor()] as a more
75    /// convenient alternative to this function. The buffer will add a
76    /// reference to the anchor, so you can unref it after insertion.
77    /// ## `iter`
78    /// location to insert the anchor
79    /// ## `anchor`
80    /// a [`TextChildAnchor`][crate::TextChildAnchor]
81    fn insert_child_anchor(&self, iter: &mut TextIter, anchor: &TextChildAnchor) {
82        self.parent_insert_child_anchor(iter, anchor)
83    }
84    /// Inserts an image into the text buffer at @iter.
85    ///
86    /// The image will be counted as one character in character counts,
87    /// and when obtaining the buffer contents as a string, will be
88    /// represented by the Unicode “object replacement character” 0xFFFC.
89    /// Note that the “slice” variants for obtaining portions of the buffer
90    /// as a string include this character for paintable, but the “text”
91    /// variants do not. e.g. see [`TextBufferExt::slice()`][crate::prelude::TextBufferExt::slice()] and
92    /// [`TextBufferExt::text()`][crate::prelude::TextBufferExt::text()].
93    /// ## `iter`
94    /// location to insert the paintable
95    /// ## `paintable`
96    /// a [`gdk::Paintable`][crate::gdk::Paintable]
97    fn insert_paintable(&self, iter: &mut TextIter, paintable: &gdk::Paintable) {
98        self.parent_insert_paintable(iter, paintable)
99    }
100    /// The class handler for the `GtkTextBuffer::insert-text` signal.
101    fn insert_text(&self, iter: &mut TextIter, new_text: &str) {
102        self.parent_insert_text(iter, new_text)
103    }
104    /// The class handler for the `GtkTextBuffer::mark-deleted` signal.
105    fn mark_deleted(&self, mark: &TextMark) {
106        self.parent_mark_deleted(mark);
107    }
108    /// The class handler for the `GtkTextBuffer::mark-set` signal.
109    fn mark_set(&self, location: &TextIter, mark: &TextMark) {
110        self.parent_mark_set(location, mark)
111    }
112    /// The class handler for the `GtkTextBuffer::modified-changed` signal.
113    fn modified_changed(&self) {
114        self.parent_modified_changed();
115    }
116    /// The class handler for the `GtkTextBuffer::paste-done` signal.
117    fn paste_done(&self, clipboard: &gdk::Clipboard) {
118        self.parent_paste_done(clipboard)
119    }
120    /// Redoes the next redoable action on the buffer, if there is one.
121    fn redo(&self) {
122        self.parent_redo()
123    }
124    /// Emits the “remove-tag” signal.
125    ///
126    /// The default handler for the signal removes all occurrences
127    /// of @tag from the given range. @start and @end don’t have
128    /// to be in order.
129    /// ## `tag`
130    /// a [`TextTag`][crate::TextTag]
131    /// ## `start`
132    /// one bound of range to be untagged
133    /// ## `end`
134    /// other bound of range to be untagged
135    fn remove_tag(&self, tag: &TextTag, start: &TextIter, end: &TextIter) {
136        self.parent_remove_tag(tag, start, end)
137    }
138    /// Undoes the last undoable action on the buffer, if there is one.
139    fn undo(&self) {
140        self.parent_undo()
141    }
142}
143
144mod sealed {
145    pub trait Sealed {}
146    impl<T: super::TextBufferImplExt> Sealed for T {}
147}
148
149pub trait TextBufferImplExt: sealed::Sealed + ObjectSubclass {
150    fn parent_apply_tag(&self, tag: &TextTag, start: &TextIter, end: &TextIter) {
151        unsafe {
152            let data = Self::type_data();
153            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
154            if let Some(f) = (*parent_class).apply_tag {
155                f(
156                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
157                    tag.to_glib_none().0,
158                    start.to_glib_none().0,
159                    end.to_glib_none().0,
160                )
161            }
162        }
163    }
164
165    fn parent_begin_user_action(&self) {
166        unsafe {
167            let data = Self::type_data();
168            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
169            if let Some(f) = (*parent_class).begin_user_action {
170                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
171            }
172        }
173    }
174
175    fn parent_changed(&self) {
176        unsafe {
177            let data = Self::type_data();
178            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
179            if let Some(f) = (*parent_class).changed {
180                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
181            }
182        }
183    }
184
185    fn parent_delete_range(&self, start: &mut TextIter, end: &mut TextIter) {
186        unsafe {
187            let data = Self::type_data();
188            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
189            if let Some(f) = (*parent_class).delete_range {
190                f(
191                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
192                    start.to_glib_none_mut().0,
193                    end.to_glib_none_mut().0,
194                )
195            }
196        }
197    }
198
199    fn parent_end_user_action(&self) {
200        unsafe {
201            let data = Self::type_data();
202            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
203            if let Some(f) = (*parent_class).end_user_action {
204                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
205            }
206        }
207    }
208
209    fn parent_insert_child_anchor(&self, iter: &mut TextIter, anchor: &TextChildAnchor) {
210        unsafe {
211            let data = Self::type_data();
212            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
213            if let Some(f) = (*parent_class).insert_child_anchor {
214                f(
215                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
216                    iter.to_glib_none_mut().0,
217                    anchor.to_glib_none().0,
218                )
219            }
220        }
221    }
222
223    fn parent_insert_paintable(&self, iter: &mut TextIter, paintable: &gdk::Paintable) {
224        unsafe {
225            let data = Self::type_data();
226            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
227            if let Some(f) = (*parent_class).insert_paintable {
228                f(
229                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
230                    iter.to_glib_none_mut().0,
231                    paintable.to_glib_none().0,
232                )
233            }
234        }
235    }
236
237    fn parent_insert_text(&self, iter: &mut TextIter, new_text: &str) {
238        unsafe {
239            let data = Self::type_data();
240            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
241            if let Some(f) = (*parent_class).insert_text {
242                f(
243                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
244                    iter.to_glib_none_mut().0,
245                    new_text.to_glib_none().0,
246                    new_text.len() as i32,
247                )
248            }
249        }
250    }
251
252    fn parent_mark_deleted(&self, mark: &TextMark) {
253        unsafe {
254            let data = Self::type_data();
255            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
256            if let Some(f) = (*parent_class).mark_deleted {
257                f(
258                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
259                    mark.to_glib_none().0,
260                )
261            }
262        }
263    }
264
265    fn parent_mark_set(&self, location: &TextIter, mark: &TextMark) {
266        unsafe {
267            let data = Self::type_data();
268            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
269            if let Some(f) = (*parent_class).mark_set {
270                f(
271                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
272                    location.to_glib_none().0,
273                    mark.to_glib_none().0,
274                )
275            }
276        }
277    }
278
279    fn parent_modified_changed(&self) {
280        unsafe {
281            let data = Self::type_data();
282            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
283            if let Some(f) = (*parent_class).modified_changed {
284                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
285            }
286        }
287    }
288
289    fn parent_paste_done(&self, clipboard: &gdk::Clipboard) {
290        unsafe {
291            let data = Self::type_data();
292            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
293            if let Some(f) = (*parent_class).paste_done {
294                f(
295                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
296                    clipboard.to_glib_none().0,
297                )
298            }
299        }
300    }
301
302    fn parent_redo(&self) {
303        unsafe {
304            let data = Self::type_data();
305            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
306            if let Some(f) = (*parent_class).redo {
307                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
308            }
309        }
310    }
311
312    fn parent_remove_tag(&self, tag: &TextTag, start: &TextIter, end: &TextIter) {
313        unsafe {
314            let data = Self::type_data();
315            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
316            if let Some(f) = (*parent_class).remove_tag {
317                f(
318                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
319                    tag.to_glib_none().0,
320                    start.to_glib_none().0,
321                    end.to_glib_none().0,
322                )
323            }
324        }
325    }
326
327    fn parent_undo(&self) {
328        unsafe {
329            let data = Self::type_data();
330            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
331            if let Some(f) = (*parent_class).undo {
332                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
333            }
334        }
335    }
336}
337
338impl<T: TextBufferImpl> TextBufferImplExt for T {}
339
340unsafe impl<T: TextBufferImpl> IsSubclassable<T> for TextBuffer {
341    fn class_init(class: &mut glib::Class<Self>) {
342        Self::parent_class_init::<T>(class);
343
344        assert_initialized_main_thread!();
345
346        let klass = class.as_mut();
347        klass.apply_tag = Some(text_buffer_apply_tag::<T>);
348        klass.begin_user_action = Some(text_buffer_begin_user_action::<T>);
349        klass.changed = Some(text_buffer_changed::<T>);
350        klass.delete_range = Some(text_buffer_delete_range::<T>);
351        klass.end_user_action = Some(text_buffer_end_user_action::<T>);
352        klass.insert_child_anchor = Some(text_buffer_insert_child_anchor::<T>);
353        klass.insert_paintable = Some(text_buffer_insert_paintable::<T>);
354        klass.insert_text = Some(text_buffer_insert_text::<T>);
355        klass.mark_deleted = Some(text_buffer_mark_deleted::<T>);
356        klass.mark_set = Some(text_buffer_mark_set::<T>);
357        klass.modified_changed = Some(text_buffer_modified_changed::<T>);
358        klass.paste_done = Some(text_buffer_paste_done::<T>);
359        klass.remove_tag = Some(text_buffer_remove_tag::<T>);
360        klass.redo = Some(text_buffer_redo::<T>);
361        klass.undo = Some(text_buffer_undo::<T>);
362    }
363}
364
365unsafe extern "C" fn text_buffer_apply_tag<T: TextBufferImpl>(
366    ptr: *mut ffi::GtkTextBuffer,
367    tag_ptr: *mut ffi::GtkTextTag,
368    start_ptr: *const ffi::GtkTextIter,
369    end_ptr: *const ffi::GtkTextIter,
370) {
371    let instance = &*(ptr as *mut T::Instance);
372    let imp = instance.imp();
373
374    imp.apply_tag(
375        &from_glib_borrow(tag_ptr),
376        &from_glib_borrow(start_ptr),
377        &from_glib_borrow(end_ptr),
378    )
379}
380
381unsafe extern "C" fn text_buffer_begin_user_action<T: TextBufferImpl>(
382    ptr: *mut ffi::GtkTextBuffer,
383) {
384    let instance = &*(ptr as *mut T::Instance);
385    let imp = instance.imp();
386
387    imp.begin_user_action()
388}
389
390unsafe extern "C" fn text_buffer_changed<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
391    let instance = &*(ptr as *mut T::Instance);
392    let imp = instance.imp();
393
394    imp.changed()
395}
396
397unsafe extern "C" fn text_buffer_delete_range<T: TextBufferImpl>(
398    ptr: *mut ffi::GtkTextBuffer,
399    start_ptr: *mut ffi::GtkTextIter,
400    end_ptr: *mut ffi::GtkTextIter,
401) {
402    let instance = &*(ptr as *mut T::Instance);
403    let imp = instance.imp();
404
405    let mut start_copy = from_glib_none(start_ptr);
406    let mut end_copy = from_glib_none(end_ptr);
407
408    imp.delete_range(&mut start_copy, &mut end_copy);
409
410    *start_ptr = *start_copy.to_glib_none().0;
411    *end_ptr = *end_copy.to_glib_none().0;
412}
413
414unsafe extern "C" fn text_buffer_end_user_action<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
415    let instance = &*(ptr as *mut T::Instance);
416    let imp = instance.imp();
417
418    imp.end_user_action()
419}
420
421unsafe extern "C" fn text_buffer_insert_child_anchor<T: TextBufferImpl>(
422    ptr: *mut ffi::GtkTextBuffer,
423    iter_ptr: *mut ffi::GtkTextIter,
424    anchor_ptr: *mut ffi::GtkTextChildAnchor,
425) {
426    let instance = &*(ptr as *mut T::Instance);
427    let imp = instance.imp();
428
429    let mut iter = from_glib_none(iter_ptr);
430
431    imp.insert_child_anchor(&mut iter, &from_glib_borrow(anchor_ptr));
432    *iter_ptr = *iter.to_glib_none().0;
433}
434
435unsafe extern "C" fn text_buffer_insert_paintable<T: TextBufferImpl>(
436    ptr: *mut ffi::GtkTextBuffer,
437    iter_ptr: *mut ffi::GtkTextIter,
438    paintable_ptr: *mut gdk::ffi::GdkPaintable,
439) {
440    let instance = &*(ptr as *mut T::Instance);
441    let imp = instance.imp();
442
443    let mut iter = from_glib_none(iter_ptr);
444
445    imp.insert_paintable(&mut iter, &from_glib_borrow(paintable_ptr));
446    *iter_ptr = *iter.to_glib_none().0;
447}
448
449unsafe extern "C" fn text_buffer_insert_text<T: TextBufferImpl>(
450    ptr: *mut ffi::GtkTextBuffer,
451    iter_ptr: *mut ffi::GtkTextIter,
452    text_ptr: *const libc::c_char,
453    _length: libc::c_int,
454) {
455    let instance = &*(ptr as *mut T::Instance);
456    let imp = instance.imp();
457    let text: Borrowed<glib::GString> = from_glib_borrow(text_ptr);
458
459    let mut iter = from_glib_none(iter_ptr);
460
461    imp.insert_text(&mut iter, text.as_str());
462    *iter_ptr = *iter.to_glib_none().0;
463}
464
465unsafe extern "C" fn text_buffer_modified_changed<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
466    let instance = &*(ptr as *mut T::Instance);
467    let imp = instance.imp();
468
469    imp.modified_changed()
470}
471
472unsafe extern "C" fn text_buffer_mark_deleted<T: TextBufferImpl>(
473    ptr: *mut ffi::GtkTextBuffer,
474    mark: *mut ffi::GtkTextMark,
475) {
476    let instance = &*(ptr as *mut T::Instance);
477    let imp = instance.imp();
478
479    imp.mark_deleted(&from_glib_borrow(mark))
480}
481
482unsafe extern "C" fn text_buffer_mark_set<T: TextBufferImpl>(
483    ptr: *mut ffi::GtkTextBuffer,
484    iter: *const ffi::GtkTextIter,
485    mark: *mut ffi::GtkTextMark,
486) {
487    let instance = &*(ptr as *mut T::Instance);
488    let imp = instance.imp();
489
490    imp.mark_set(&from_glib_borrow(iter), &from_glib_borrow(mark))
491}
492
493unsafe extern "C" fn text_buffer_paste_done<T: TextBufferImpl>(
494    ptr: *mut ffi::GtkTextBuffer,
495    clipboard_ptr: *mut gdk::ffi::GdkClipboard,
496) {
497    let instance = &*(ptr as *mut T::Instance);
498    let imp = instance.imp();
499
500    imp.paste_done(&from_glib_borrow(clipboard_ptr))
501}
502
503unsafe extern "C" fn text_buffer_redo<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
504    let instance = &*(ptr as *mut T::Instance);
505    let imp = instance.imp();
506
507    imp.redo()
508}
509
510unsafe extern "C" fn text_buffer_remove_tag<T: TextBufferImpl>(
511    ptr: *mut ffi::GtkTextBuffer,
512    tag: *mut ffi::GtkTextTag,
513    start: *const ffi::GtkTextIter,
514    end: *const ffi::GtkTextIter,
515) {
516    let instance = &*(ptr as *mut T::Instance);
517    let imp = instance.imp();
518
519    imp.remove_tag(
520        &from_glib_borrow(tag),
521        &from_glib_borrow(start),
522        &from_glib_borrow(end),
523    )
524}
525
526unsafe extern "C" fn text_buffer_undo<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
527    let instance = &*(ptr as *mut T::Instance);
528    let imp = instance.imp();
529
530    imp.undo()
531}