Skip to main content

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`].
5
6use glib::translate::*;
7
8use crate::{
9    DeleteType, MovementStep, Scrollable, Snapshot, TextExtendSelection, TextIter, TextView,
10    TextViewLayer, ffi, prelude::*, subclass::prelude::*,
11};
12
13pub trait TextViewImpl: WidgetImpl + ObjectSubclass<Type: IsA<TextView> + IsA<Scrollable>> {
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
94pub trait TextViewImplExt: TextViewImpl {
95    fn parent_backspace(&self) {
96        unsafe {
97            let data = Self::type_data();
98            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
99            if let Some(f) = (*parent_class).backspace {
100                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
101            }
102        }
103    }
104
105    fn parent_copy_clipboard(&self) {
106        unsafe {
107            let data = Self::type_data();
108            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
109            if let Some(f) = (*parent_class).copy_clipboard {
110                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
111            }
112        }
113    }
114
115    fn parent_cut_clipboard(&self) {
116        unsafe {
117            let data = Self::type_data();
118            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
119            if let Some(f) = (*parent_class).cut_clipboard {
120                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
121            }
122        }
123    }
124
125    fn parent_delete_from_cursor(&self, type_: DeleteType, count: i32) {
126        unsafe {
127            let data = Self::type_data();
128            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
129            if let Some(f) = (*parent_class).delete_from_cursor {
130                f(
131                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
132                    type_.into_glib(),
133                    count,
134                )
135            }
136        }
137    }
138
139    fn parent_extend_selection(
140        &self,
141        granularity: TextExtendSelection,
142        location: &TextIter,
143        start: &mut TextIter,
144        end: &mut TextIter,
145    ) -> glib::ControlFlow {
146        unsafe {
147            let data = Self::type_data();
148            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
149            if let Some(f) = (*parent_class).extend_selection {
150                glib::ControlFlow::from_glib(f(
151                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
152                    granularity.into_glib(),
153                    location.to_glib_none().0,
154                    start.to_glib_none_mut().0,
155                    end.to_glib_none_mut().0,
156                ))
157            } else {
158                glib::ControlFlow::Break
159            }
160        }
161    }
162
163    fn parent_insert_at_cursor(&self, text: &str) {
164        unsafe {
165            let data = Self::type_data();
166            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
167            if let Some(f) = (*parent_class).insert_at_cursor {
168                f(
169                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
170                    text.to_glib_none().0,
171                )
172            }
173        }
174    }
175
176    fn parent_insert_emoji(&self) {
177        unsafe {
178            let data = Self::type_data();
179            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
180            if let Some(f) = (*parent_class).insert_emoji {
181                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
182            }
183        }
184    }
185
186    fn parent_move_cursor(&self, step: MovementStep, count: i32, extend_selection: bool) {
187        unsafe {
188            let data = Self::type_data();
189            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
190            if let Some(f) = (*parent_class).move_cursor {
191                f(
192                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
193                    step.into_glib(),
194                    count,
195                    extend_selection.into_glib(),
196                )
197            }
198        }
199    }
200
201    fn parent_paste_clipboard(&self) {
202        unsafe {
203            let data = Self::type_data();
204            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
205            if let Some(f) = (*parent_class).paste_clipboard {
206                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
207            }
208        }
209    }
210
211    fn parent_set_anchor(&self) {
212        unsafe {
213            let data = Self::type_data();
214            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
215            if let Some(f) = (*parent_class).set_anchor {
216                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
217            }
218        }
219    }
220
221    fn parent_snapshot_layer(&self, layer: TextViewLayer, snapshot: Snapshot) {
222        unsafe {
223            let data = Self::type_data();
224            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
225            if let Some(f) = (*parent_class).snapshot_layer {
226                f(
227                    self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0,
228                    layer.into_glib(),
229                    snapshot.to_glib_none().0,
230                )
231            }
232        }
233    }
234
235    fn parent_toggle_overwrite(&self) {
236        unsafe {
237            let data = Self::type_data();
238            let parent_class = data.as_ref().parent_class() as *mut ffi::GtkTextViewClass;
239            if let Some(f) = (*parent_class).toggle_overwrite {
240                f(self.obj().unsafe_cast_ref::<TextView>().to_glib_none().0)
241            }
242        }
243    }
244}
245
246impl<T: TextViewImpl> TextViewImplExt for T {}
247
248unsafe impl<T: TextViewImpl> IsSubclassable<T> for TextView {
249    fn class_init(class: &mut glib::Class<Self>) {
250        Self::parent_class_init::<T>(class);
251
252        let klass = class.as_mut();
253        klass.backspace = Some(text_view_backspace::<T>);
254        klass.copy_clipboard = Some(text_view_copy_clipboard::<T>);
255        klass.cut_clipboard = Some(text_view_cut_clipboard::<T>);
256        klass.delete_from_cursor = Some(text_view_delete_from_cursor::<T>);
257        klass.extend_selection = Some(text_view_extend_selection::<T>);
258        klass.insert_at_cursor = Some(text_view_insert_at_cursor::<T>);
259        klass.insert_emoji = Some(text_view_insert_emoji::<T>);
260        klass.move_cursor = Some(text_view_move_cursor::<T>);
261        klass.paste_clipboard = Some(text_view_paste_clipboard::<T>);
262        klass.set_anchor = Some(text_view_set_anchor::<T>);
263        klass.snapshot_layer = Some(text_view_snapshot_layer::<T>);
264        klass.toggle_overwrite = Some(text_view_toggle_overwrite::<T>);
265    }
266}
267
268unsafe extern "C" fn text_view_backspace<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
269    unsafe {
270        let instance = &*(ptr as *mut T::Instance);
271        let imp = instance.imp();
272
273        imp.backspace()
274    }
275}
276
277unsafe extern "C" fn text_view_copy_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
278    unsafe {
279        let instance = &*(ptr as *mut T::Instance);
280        let imp = instance.imp();
281
282        imp.copy_clipboard()
283    }
284}
285
286unsafe extern "C" fn text_view_cut_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
287    unsafe {
288        let instance = &*(ptr as *mut T::Instance);
289        let imp = instance.imp();
290
291        imp.cut_clipboard()
292    }
293}
294
295unsafe extern "C" fn text_view_delete_from_cursor<T: TextViewImpl>(
296    ptr: *mut ffi::GtkTextView,
297    type_: ffi::GtkDeleteType,
298    count: i32,
299) {
300    unsafe {
301        let instance = &*(ptr as *mut T::Instance);
302        let imp = instance.imp();
303
304        imp.delete_from_cursor(from_glib(type_), count)
305    }
306}
307
308unsafe extern "C" fn text_view_extend_selection<T: TextViewImpl>(
309    ptr: *mut ffi::GtkTextView,
310    granularity: ffi::GtkTextExtendSelection,
311    location: *const ffi::GtkTextIter,
312    start: *mut ffi::GtkTextIter,
313    end: *mut ffi::GtkTextIter,
314) -> glib::ffi::gboolean {
315    unsafe {
316        let instance = &*(ptr as *mut T::Instance);
317        let imp = instance.imp();
318
319        let mut start_copy = from_glib_none(start);
320        let mut end_copy = from_glib_none(end);
321
322        let result = imp.extend_selection(
323            from_glib(granularity),
324            &from_glib_borrow(location),
325            &mut start_copy,
326            &mut end_copy,
327        );
328        *start = *start_copy.to_glib_none().0;
329        *end = *end_copy.to_glib_none().0;
330
331        result.into_glib()
332    }
333}
334
335unsafe extern "C" fn text_view_insert_at_cursor<T: TextViewImpl>(
336    ptr: *mut ffi::GtkTextView,
337    text_ptr: *const libc::c_char,
338) {
339    unsafe {
340        let instance = &*(ptr as *mut T::Instance);
341        let imp = instance.imp();
342        let text: Borrowed<glib::GString> = from_glib_borrow(text_ptr);
343
344        imp.insert_at_cursor(text.as_str())
345    }
346}
347
348unsafe extern "C" fn text_view_insert_emoji<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
349    unsafe {
350        let instance = &*(ptr as *mut T::Instance);
351        let imp = instance.imp();
352
353        imp.insert_emoji()
354    }
355}
356
357unsafe extern "C" fn text_view_move_cursor<T: TextViewImpl>(
358    ptr: *mut ffi::GtkTextView,
359    step: ffi::GtkMovementStep,
360    count: i32,
361    extend_selection: glib::ffi::gboolean,
362) {
363    unsafe {
364        let instance = &*(ptr as *mut T::Instance);
365        let imp = instance.imp();
366
367        imp.move_cursor(from_glib(step), count, from_glib(extend_selection))
368    }
369}
370
371unsafe extern "C" fn text_view_paste_clipboard<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
372    unsafe {
373        let instance = &*(ptr as *mut T::Instance);
374        let imp = instance.imp();
375
376        imp.paste_clipboard()
377    }
378}
379
380unsafe extern "C" fn text_view_set_anchor<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
381    unsafe {
382        let instance = &*(ptr as *mut T::Instance);
383        let imp = instance.imp();
384
385        imp.set_anchor()
386    }
387}
388
389unsafe extern "C" fn text_view_snapshot_layer<T: TextViewImpl>(
390    ptr: *mut ffi::GtkTextView,
391    layer: ffi::GtkTextViewLayer,
392    snapshot: *mut ffi::GtkSnapshot,
393) {
394    unsafe {
395        let instance = &*(ptr as *mut T::Instance);
396        let imp = instance.imp();
397
398        imp.snapshot_layer(from_glib(layer), from_glib_none(snapshot))
399    }
400}
401
402unsafe extern "C" fn text_view_toggle_overwrite<T: TextViewImpl>(ptr: *mut ffi::GtkTextView) {
403    unsafe {
404        let instance = &*(ptr as *mut T::Instance);
405        let imp = instance.imp();
406
407        imp.toggle_overwrite()
408    }
409}