gtk4/subclass/
text_view.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 [`TextView`](crate::TextView).
5
6use glib::translate::*;
7
8use crate::{
9    ffi, prelude::*, subclass::prelude::*, DeleteType, MovementStep, Snapshot, TextExtendSelection,
10    TextIter, TextView, TextViewLayer,
11};
12
13pub trait TextViewImpl: TextViewImplExt + WidgetImpl {
14    /// The class handler for the `GtkTextView::backspace`
15    ///   keybinding signal.
16    fn backspace(&self) {
17        self.parent_backspace()
18    }
19
20    /// The class handler for the `GtkTextView::copy-clipboard`
21    ///   keybinding signal.
22    fn copy_clipboard(&self) {
23        self.parent_copy_clipboard()
24    }
25
26    /// The class handler for the `GtkTextView::cut-clipboard`
27    ///   keybinding signal
28    fn cut_clipboard(&self) {
29        self.parent_cut_clipboard()
30    }
31
32    /// The class handler for the `GtkTextView::delete-from-cursor`
33    ///   keybinding signal.
34    fn delete_from_cursor(&self, type_: DeleteType, count: i32) {
35        self.parent_delete_from_cursor(type_, count)
36    }
37
38    /// The class handler for the `GtkTextView::extend-selection` signal.
39    fn extend_selection(
40        &self,
41        granularity: TextExtendSelection,
42        location: &TextIter,
43        start: &mut TextIter,
44        end: &mut TextIter,
45    ) -> glib::ControlFlow {
46        self.parent_extend_selection(granularity, location, start, end)
47    }
48
49    /// The class handler for the `GtkTextView::insert-at-cursor`
50    ///   keybinding signal.
51    fn insert_at_cursor(&self, text: &str) {
52        self.parent_insert_at_cursor(text)
53    }
54
55    /// The class handler for the `GtkTextView::insert-emoji` signal.
56    fn insert_emoji(&self) {
57        self.parent_insert_emoji()
58    }
59
60    /// The class handler for the `GtkTextView::move-cursor`
61    ///   keybinding signal.
62    fn move_cursor(&self, step: MovementStep, count: i32, extend_selection: bool) {
63        self.parent_move_cursor(step, count, extend_selection)
64    }
65
66    /// The class handler for the `GtkTextView::paste-clipboard`
67    ///   keybinding signal.
68    fn paste_clipboard(&self) {
69        self.parent_paste_clipboard()
70    }
71
72    /// The class handler for the `GtkTextView::set-anchor`
73    ///   keybinding signal.
74    fn set_anchor(&self) {
75        self.parent_set_anchor()
76    }
77
78    /// The snapshot_layer vfunc is called before and after the text
79    ///   view is drawing its own text. Applications can override this vfunc
80    ///   in a subclass to draw customized content underneath or above the
81    ///   text. In the [`TextViewLayer::BelowText`][crate::TextViewLayer::BelowText] and [`TextViewLayer::AboveText`][crate::TextViewLayer::AboveText]
82    ///   layers the drawing is done in the buffer coordinate space.
83    fn snapshot_layer(&self, layer: TextViewLayer, snapshot: Snapshot) {
84        self.parent_snapshot_layer(layer, snapshot)
85    }
86
87    /// The class handler for the `GtkTextView::toggle-overwrite`
88    ///   keybinding signal.
89    fn toggle_overwrite(&self) {
90        self.parent_toggle_overwrite()
91    }
92}
93
94mod sealed {
95    pub trait Sealed {}
96    impl<T: super::TextViewImplExt> Sealed for T {}
97}
98
99pub trait TextViewImplExt: sealed::Sealed + ObjectSubclass {
100    fn parent_backspace(&self) {
101        unsafe {
102            let data = Self::type_data();
103            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
104            if let Some(f) = (*parent_class).backspace {
105                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
106            }
107        }
108    }
109
110    fn parent_copy_clipboard(&self) {
111        unsafe {
112            let data = Self::type_data();
113            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
114            if let Some(f) = (*parent_class).copy_clipboard {
115                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
116            }
117        }
118    }
119
120    fn parent_cut_clipboard(&self) {
121        unsafe {
122            let data = Self::type_data();
123            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
124            if let Some(f) = (*parent_class).cut_clipboard {
125                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
126            }
127        }
128    }
129
130    fn parent_delete_from_cursor(&self, type_: DeleteType, count: i32) {
131        unsafe {
132            let data = Self::type_data();
133            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
134            if let Some(f) = (*parent_class).delete_from_cursor {
135                f(
136                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
137                    type_.into_glib(),
138                    count,
139                )
140            }
141        }
142    }
143
144    fn parent_extend_selection(
145        &self,
146        granularity: TextExtendSelection,
147        location: &TextIter,
148        start: &mut TextIter,
149        end: &mut TextIter,
150    ) -> glib::ControlFlow {
151        unsafe {
152            let data = Self::type_data();
153            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
154            if let Some(f) = (*parent_class).extend_selection {
155                glib::ControlFlow::from_glib(f(
156                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
157                    granularity.into_glib(),
158                    location.to_glib_none().0,
159                    start.to_glib_none_mut().0,
160                    end.to_glib_none_mut().0,
161                ))
162            } else {
163                glib::ControlFlow::Break
164            }
165        }
166    }
167
168    fn parent_insert_at_cursor(&self, text: &str) {
169        unsafe {
170            let data = Self::type_data();
171            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
172            if let Some(f) = (*parent_class).insert_at_cursor {
173                f(
174                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
175                    text.to_glib_none().0,
176                )
177            }
178        }
179    }
180
181    fn parent_insert_emoji(&self) {
182        unsafe {
183            let data = Self::type_data();
184            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
185            if let Some(f) = (*parent_class).insert_emoji {
186                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
187            }
188        }
189    }
190
191    fn parent_move_cursor(&self, step: MovementStep, count: i32, extend_selection: bool) {
192        unsafe {
193            let data = Self::type_data();
194            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
195            if let Some(f) = (*parent_class).move_cursor {
196                f(
197                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
198                    step.into_glib(),
199                    count,
200                    extend_selection.into_glib(),
201                )
202            }
203        }
204    }
205
206    fn parent_paste_clipboard(&self) {
207        unsafe {
208            let data = Self::type_data();
209            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
210            if let Some(f) = (*parent_class).paste_clipboard {
211                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
212            }
213        }
214    }
215
216    fn parent_set_anchor(&self) {
217        unsafe {
218            let data = Self::type_data();
219            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
220            if let Some(f) = (*parent_class).set_anchor {
221                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
222            }
223        }
224    }
225
226    fn parent_snapshot_layer(&self, layer: TextViewLayer, snapshot: Snapshot) {
227        unsafe {
228            let data = Self::type_data();
229            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
230            if let Some(f) = (*parent_class).snapshot_layer {
231                f(
232                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
233                    layer.into_glib(),
234                    snapshot.to_glib_none().0,
235                )
236            }
237        }
238    }
239
240    fn parent_toggle_overwrite(&self) {
241        unsafe {
242            let data = Self::type_data();
243            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
244            if let Some(f) = (*parent_class).toggle_overwrite {
245                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
246            }
247        }
248    }
249}
250
251impl<T: TextViewImpl> TextViewImplExt for T {}
252
253unsafe impl<T: TextViewImpl> IsSubclassable<T> for TextView {
254    fn class_init(class: &mut glib::Class<Self>) {
255        Self::parent_class_init::<T>(class);
256
257        let klass = class.as_mut();
258        klass.backspace = Some(text_view_backspace::<T>);
259        klass.copy_clipboard = Some(text_view_copy_clipboard::<T>);
260        klass.cut_clipboard = Some(text_view_cut_clipboard::<T>);
261        klass.delete_from_cursor = Some(text_view_delete_from_cursor::<T>);
262        klass.extend_selection = Some(text_view_extend_selection::<T>);
263        klass.insert_at_cursor = Some(text_view_insert_at_cursor::<T>);
264        klass.insert_emoji = Some(text_view_insert_emoji::<T>);
265        klass.move_cursor = Some(text_view_move_cursor::<T>);
266        klass.paste_clipboard = Some(text_view_paste_clipboard::<T>);
267        klass.set_anchor = Some(text_view_set_anchor::<T>);
268        klass.snapshot_layer = Some(text_view_snapshot_layer::<T>);
269        klass.toggle_overwrite = Some(text_view_toggle_overwrite::<T>);
270    }
271}
272
273unsafe extern "C" fn text_view_backspace<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
274    let instance = &*(ptr as *mut T::Instance);
275    let imp = instance.imp();
276
277    imp.backspace()
278}
279
280unsafe extern "C" fn text_view_copy_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
281    let instance = &*(ptr as *mut T::Instance);
282    let imp = instance.imp();
283
284    imp.copy_clipboard()
285}
286
287unsafe extern "C" fn text_view_cut_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
288    let instance = &*(ptr as *mut T::Instance);
289    let imp = instance.imp();
290
291    imp.cut_clipboard()
292}
293
294unsafe extern "C" fn text_view_delete_from_cursor<T: TextViewImpl>(
295    ptr: *mut ffi::GtkTextView,
296    type_: ffi::GtkDeleteType,
297    count: i32,
298) {
299    let instance = &*(ptr as *mut T::Instance);
300    let imp = instance.imp();
301
302    imp.delete_from_cursor(from_glib(type_), count)
303}
304
305unsafe extern "C" fn text_view_extend_selection<T: TextViewImpl>(
306    ptr: *mut ffi::GtkTextView,
307    granularity: ffi::GtkTextExtendSelection,
308    location: *const ffi::GtkTextIter,
309    start: *mut ffi::GtkTextIter,
310    end: *mut ffi::GtkTextIter,
311) -> glib::ffi::gboolean {
312    let instance = &*(ptr as *mut T::Instance);
313    let imp = instance.imp();
314
315    let mut start_copy = from_glib_none(start);
316    let mut end_copy = from_glib_none(end);
317
318    let result = imp.extend_selection(
319        from_glib(granularity),
320        &from_glib_borrow(location),
321        &mut start_copy,
322        &mut end_copy,
323    );
324    *start = *start_copy.to_glib_none().0;
325    *end = *end_copy.to_glib_none().0;
326
327    result.into_glib()
328}
329
330unsafe extern "C" fn text_view_insert_at_cursor<T: TextViewImpl>(
331    ptr: *mut ffi::GtkTextView,
332    text_ptr: *const libc::c_char,
333) {
334    let instance = &*(ptr as *mut T::Instance);
335    let imp = instance.imp();
336    let text: Borrowed<glib::GString> = from_glib_borrow(text_ptr);
337
338    imp.insert_at_cursor(text.as_str())
339}
340
341unsafe extern "C" fn text_view_insert_emoji<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
342    let instance = &*(ptr as *mut T::Instance);
343    let imp = instance.imp();
344
345    imp.insert_emoji()
346}
347
348unsafe extern "C" fn text_view_move_cursor<T: TextViewImpl>(
349    ptr: *mut ffi::GtkTextView,
350    step: ffi::GtkMovementStep,
351    count: i32,
352    extend_selection: glib::ffi::gboolean,
353) {
354    let instance = &*(ptr as *mut T::Instance);
355    let imp = instance.imp();
356
357    imp.move_cursor(from_glib(step), count, from_glib(extend_selection))
358}
359
360unsafe extern "C" fn text_view_paste_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
361    let instance = &*(ptr as *mut T::Instance);
362    let imp = instance.imp();
363
364    imp.paste_clipboard()
365}
366
367unsafe extern "C" fn text_view_set_anchor<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
368    let instance = &*(ptr as *mut T::Instance);
369    let imp = instance.imp();
370
371    imp.set_anchor()
372}
373
374unsafe extern "C" fn text_view_snapshot_layer<T: TextViewImpl>(
375    ptr: *mut ffi::GtkTextView,
376    layer: ffi::GtkTextViewLayer,
377    snapshot: *mut ffi::GtkSnapshot,
378) {
379    let instance = &*(ptr as *mut T::Instance);
380    let imp = instance.imp();
381
382    imp.snapshot_layer(from_glib(layer), from_glib_none(snapshot))
383}
384
385unsafe extern "C" fn text_view_toggle_overwrite<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
386    let instance = &*(ptr as *mut T::Instance);
387    let imp = instance.imp();
388
389    imp.toggle_overwrite()
390}