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`].
5
6use glib::translate::*;
7
8use crate::{
9    ffi, prelude::*, subclass::prelude::*, TextBuffer, TextChildAnchor, TextIter, TextMark, TextTag,
10};
11
12pub trait TextBufferImpl: ObjectImpl + ObjectSubclass<Type: IsA<TextBuffer>> {
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
144pub trait TextBufferImplExt: TextBufferImpl {
145    fn parent_apply_tag(&self, tag: &TextTag, start: &TextIter, end: &TextIter) {
146        unsafe {
147            let data = Self::type_data();
148            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
149            if let Some(f) = (*parent_class).apply_tag {
150                f(
151                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
152                    tag.to_glib_none().0,
153                    start.to_glib_none().0,
154                    end.to_glib_none().0,
155                )
156            }
157        }
158    }
159
160    fn parent_begin_user_action(&self) {
161        unsafe {
162            let data = Self::type_data();
163            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
164            if let Some(f) = (*parent_class).begin_user_action {
165                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
166            }
167        }
168    }
169
170    fn parent_changed(&self) {
171        unsafe {
172            let data = Self::type_data();
173            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
174            if let Some(f) = (*parent_class).changed {
175                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
176            }
177        }
178    }
179
180    fn parent_delete_range(&self, start: &mut TextIter, end: &mut TextIter) {
181        unsafe {
182            let data = Self::type_data();
183            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
184            if let Some(f) = (*parent_class).delete_range {
185                f(
186                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
187                    start.to_glib_none_mut().0,
188                    end.to_glib_none_mut().0,
189                )
190            }
191        }
192    }
193
194    fn parent_end_user_action(&self) {
195        unsafe {
196            let data = Self::type_data();
197            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
198            if let Some(f) = (*parent_class).end_user_action {
199                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
200            }
201        }
202    }
203
204    fn parent_insert_child_anchor(&self, iter: &mut TextIter, anchor: &TextChildAnchor) {
205        unsafe {
206            let data = Self::type_data();
207            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
208            if let Some(f) = (*parent_class).insert_child_anchor {
209                f(
210                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
211                    iter.to_glib_none_mut().0,
212                    anchor.to_glib_none().0,
213                )
214            }
215        }
216    }
217
218    fn parent_insert_paintable(&self, iter: &mut TextIter, paintable: &gdk::Paintable) {
219        unsafe {
220            let data = Self::type_data();
221            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
222            if let Some(f) = (*parent_class).insert_paintable {
223                f(
224                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
225                    iter.to_glib_none_mut().0,
226                    paintable.to_glib_none().0,
227                )
228            }
229        }
230    }
231
232    fn parent_insert_text(&self, iter: &mut TextIter, new_text: &str) {
233        unsafe {
234            let data = Self::type_data();
235            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
236            if let Some(f) = (*parent_class).insert_text {
237                f(
238                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
239                    iter.to_glib_none_mut().0,
240                    new_text.to_glib_none().0,
241                    new_text.len() as i32,
242                )
243            }
244        }
245    }
246
247    fn parent_mark_deleted(&self, mark: &TextMark) {
248        unsafe {
249            let data = Self::type_data();
250            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
251            if let Some(f) = (*parent_class).mark_deleted {
252                f(
253                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
254                    mark.to_glib_none().0,
255                )
256            }
257        }
258    }
259
260    fn parent_mark_set(&self, location: &TextIter, mark: &TextMark) {
261        unsafe {
262            let data = Self::type_data();
263            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
264            if let Some(f) = (*parent_class).mark_set {
265                f(
266                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
267                    location.to_glib_none().0,
268                    mark.to_glib_none().0,
269                )
270            }
271        }
272    }
273
274    fn parent_modified_changed(&self) {
275        unsafe {
276            let data = Self::type_data();
277            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
278            if let Some(f) = (*parent_class).modified_changed {
279                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
280            }
281        }
282    }
283
284    fn parent_paste_done(&self, clipboard: &gdk::Clipboard) {
285        unsafe {
286            let data = Self::type_data();
287            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
288            if let Some(f) = (*parent_class).paste_done {
289                f(
290                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
291                    clipboard.to_glib_none().0,
292                )
293            }
294        }
295    }
296
297    fn parent_redo(&self) {
298        unsafe {
299            let data = Self::type_data();
300            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
301            if let Some(f) = (*parent_class).redo {
302                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
303            }
304        }
305    }
306
307    fn parent_remove_tag(&self, tag: &TextTag, start: &TextIter, end: &TextIter) {
308        unsafe {
309            let data = Self::type_data();
310            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
311            if let Some(f) = (*parent_class).remove_tag {
312                f(
313                    self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0,
314                    tag.to_glib_none().0,
315                    start.to_glib_none().0,
316                    end.to_glib_none().0,
317                )
318            }
319        }
320    }
321
322    fn parent_undo(&self) {
323        unsafe {
324            let data = Self::type_data();
325            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextBufferClass;
326            if let Some(f) = (*parent_class).undo {
327                f(self.obj().unsafe_cast_ref::<TextBuffer>().to_glib_none().0)
328            }
329        }
330    }
331}
332
333impl<T: TextBufferImpl> TextBufferImplExt for T {}
334
335unsafe impl<T: TextBufferImpl> IsSubclassable<T> for TextBuffer {
336    fn class_init(class: &mut glib::Class<Self>) {
337        Self::parent_class_init::<T>(class);
338
339        assert_initialized_main_thread!();
340
341        let klass = class.as_mut();
342        klass.apply_tag = Some(text_buffer_apply_tag::<T>);
343        klass.begin_user_action = Some(text_buffer_begin_user_action::<T>);
344        klass.changed = Some(text_buffer_changed::<T>);
345        klass.delete_range = Some(text_buffer_delete_range::<T>);
346        klass.end_user_action = Some(text_buffer_end_user_action::<T>);
347        klass.insert_child_anchor = Some(text_buffer_insert_child_anchor::<T>);
348        klass.insert_paintable = Some(text_buffer_insert_paintable::<T>);
349        klass.insert_text = Some(text_buffer_insert_text::<T>);
350        klass.mark_deleted = Some(text_buffer_mark_deleted::<T>);
351        klass.mark_set = Some(text_buffer_mark_set::<T>);
352        klass.modified_changed = Some(text_buffer_modified_changed::<T>);
353        klass.paste_done = Some(text_buffer_paste_done::<T>);
354        klass.remove_tag = Some(text_buffer_remove_tag::<T>);
355        klass.redo = Some(text_buffer_redo::<T>);
356        klass.undo = Some(text_buffer_undo::<T>);
357    }
358}
359
360unsafe extern "C" fn text_buffer_apply_tag<T: TextBufferImpl>(
361    ptr: *mut ffi::GtkTextBuffer,
362    tag_ptr: *mut ffi::GtkTextTag,
363    start_ptr: *const ffi::GtkTextIter,
364    end_ptr: *const ffi::GtkTextIter,
365) {
366    let instance = &*(ptr as *mut T::Instance);
367    let imp = instance.imp();
368
369    imp.apply_tag(
370        &from_glib_borrow(tag_ptr),
371        &from_glib_borrow(start_ptr),
372        &from_glib_borrow(end_ptr),
373    )
374}
375
376unsafe extern "C" fn text_buffer_begin_user_action<T: TextBufferImpl>(
377    ptr: *mut ffi::GtkTextBuffer,
378) {
379    let instance = &*(ptr as *mut T::Instance);
380    let imp = instance.imp();
381
382    imp.begin_user_action()
383}
384
385unsafe extern "C" fn text_buffer_changed<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
386    let instance = &*(ptr as *mut T::Instance);
387    let imp = instance.imp();
388
389    imp.changed()
390}
391
392unsafe extern "C" fn text_buffer_delete_range<T: TextBufferImpl>(
393    ptr: *mut ffi::GtkTextBuffer,
394    start_ptr: *mut ffi::GtkTextIter,
395    end_ptr: *mut ffi::GtkTextIter,
396) {
397    let instance = &*(ptr as *mut T::Instance);
398    let imp = instance.imp();
399
400    let mut start_copy = from_glib_none(start_ptr);
401    let mut end_copy = from_glib_none(end_ptr);
402
403    imp.delete_range(&mut start_copy, &mut end_copy);
404
405    *start_ptr = *start_copy.to_glib_none().0;
406    *end_ptr = *end_copy.to_glib_none().0;
407}
408
409unsafe extern "C" fn text_buffer_end_user_action<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
410    let instance = &*(ptr as *mut T::Instance);
411    let imp = instance.imp();
412
413    imp.end_user_action()
414}
415
416unsafe extern "C" fn text_buffer_insert_child_anchor<T: TextBufferImpl>(
417    ptr: *mut ffi::GtkTextBuffer,
418    iter_ptr: *mut ffi::GtkTextIter,
419    anchor_ptr: *mut ffi::GtkTextChildAnchor,
420) {
421    let instance = &*(ptr as *mut T::Instance);
422    let imp = instance.imp();
423
424    let mut iter = from_glib_none(iter_ptr);
425
426    imp.insert_child_anchor(&mut iter, &from_glib_borrow(anchor_ptr));
427    *iter_ptr = *iter.to_glib_none().0;
428}
429
430unsafe extern "C" fn text_buffer_insert_paintable<T: TextBufferImpl>(
431    ptr: *mut ffi::GtkTextBuffer,
432    iter_ptr: *mut ffi::GtkTextIter,
433    paintable_ptr: *mut gdk::ffi::GdkPaintable,
434) {
435    let instance = &*(ptr as *mut T::Instance);
436    let imp = instance.imp();
437
438    let mut iter = from_glib_none(iter_ptr);
439
440    imp.insert_paintable(&mut iter, &from_glib_borrow(paintable_ptr));
441    *iter_ptr = *iter.to_glib_none().0;
442}
443
444unsafe extern "C" fn text_buffer_insert_text<T: TextBufferImpl>(
445    ptr: *mut ffi::GtkTextBuffer,
446    iter_ptr: *mut ffi::GtkTextIter,
447    text_ptr: *const libc::c_char,
448    _length: libc::c_int,
449) {
450    let instance = &*(ptr as *mut T::Instance);
451    let imp = instance.imp();
452    let text: Borrowed<glib::GString> = from_glib_borrow(text_ptr);
453
454    let mut iter = from_glib_none(iter_ptr);
455
456    imp.insert_text(&mut iter, text.as_str());
457    *iter_ptr = *iter.to_glib_none().0;
458}
459
460unsafe extern "C" fn text_buffer_modified_changed<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
461    let instance = &*(ptr as *mut T::Instance);
462    let imp = instance.imp();
463
464    imp.modified_changed()
465}
466
467unsafe extern "C" fn text_buffer_mark_deleted<T: TextBufferImpl>(
468    ptr: *mut ffi::GtkTextBuffer,
469    mark: *mut ffi::GtkTextMark,
470) {
471    let instance = &*(ptr as *mut T::Instance);
472    let imp = instance.imp();
473
474    imp.mark_deleted(&from_glib_borrow(mark))
475}
476
477unsafe extern "C" fn text_buffer_mark_set<T: TextBufferImpl>(
478    ptr: *mut ffi::GtkTextBuffer,
479    iter: *const ffi::GtkTextIter,
480    mark: *mut ffi::GtkTextMark,
481) {
482    let instance = &*(ptr as *mut T::Instance);
483    let imp = instance.imp();
484
485    imp.mark_set(&from_glib_borrow(iter), &from_glib_borrow(mark))
486}
487
488unsafe extern "C" fn text_buffer_paste_done<T: TextBufferImpl>(
489    ptr: *mut ffi::GtkTextBuffer,
490    clipboard_ptr: *mut gdk::ffi::GdkClipboard,
491) {
492    let instance = &*(ptr as *mut T::Instance);
493    let imp = instance.imp();
494
495    imp.paste_done(&from_glib_borrow(clipboard_ptr))
496}
497
498unsafe extern "C" fn text_buffer_redo<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
499    let instance = &*(ptr as *mut T::Instance);
500    let imp = instance.imp();
501
502    imp.redo()
503}
504
505unsafe extern "C" fn text_buffer_remove_tag<T: TextBufferImpl>(
506    ptr: *mut ffi::GtkTextBuffer,
507    tag: *mut ffi::GtkTextTag,
508    start: *const ffi::GtkTextIter,
509    end: *const ffi::GtkTextIter,
510) {
511    let instance = &*(ptr as *mut T::Instance);
512    let imp = instance.imp();
513
514    imp.remove_tag(
515        &from_glib_borrow(tag),
516        &from_glib_borrow(start),
517        &from_glib_borrow(end),
518    )
519}
520
521unsafe extern "C" fn text_buffer_undo<T: TextBufferImpl>(ptr: *mut ffi::GtkTextBuffer) {
522    let instance = &*(ptr as *mut T::Instance);
523    let imp = instance.imp();
524
525    imp.undo()
526}