pango/
layout.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Take a look at the license at the top of the repository in the LICENSE file.

use glib::translate::*;

use crate::{ffi, LayoutLine, LayoutRun};

// rustdoc-stripper-ignore-next
/// The result of [`LayoutLine::x_to_index`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct HitPosition {
    index: i32,
    trailing: i32,
    is_inside: bool,
}

impl HitPosition {
    // rustdoc-stripper-ignore-next
    /// The UTF-8 byte offset of the grapheme closest to the position.
    ///
    /// This position is relative to the start of the [`Layout`]'s text.
    ///
    /// [`Layout`]: crate::Layout
    pub fn index(self) -> i32 {
        self.index
    }

    // rustdoc-stripper-ignore-next
    /// The codepoint within the grapheme of the position.
    ///
    /// This will always be either `0`, or the number of `char`s (*not bytes!*)
    /// in the grapheme. This represents whether the user clicked near the start
    /// of the grapheme or near the end; this is important for things like
    /// resolving cursor positions.
    pub fn trailing(self) -> i32 {
        self.trailing
    }

    // rustdoc-stripper-ignore-next
    /// Whether or not the position was within the bounds of the line.
    ///
    /// If this is `false`, then `index` and `trailing` will always resolve
    /// to either the very first or the very last position in the line; this
    /// behaviour is dependent on the line's resolved writing direction.
    pub fn is_inside(self) -> bool {
        self.is_inside
    }
}

impl LayoutLine {
    // rustdoc-stripper-ignore-next
    /// The byte index of the start of this line into the text used to create
    /// the source [`Layout`].
    ///
    /// [`Layout`]: crate::Layout
    #[cfg(not(feature = "v1_50"))]
    #[cfg_attr(docsrs, doc(cfg(not(feature = "v1_50"))))]
    pub fn start_index(&self) -> i32 {
        unsafe { (*self.as_ptr()).start_index }
    }

    // rustdoc-stripper-ignore-next
    /// The length of this line's text, in bytes.
    #[cfg(not(feature = "v1_50"))]
    #[cfg_attr(docsrs, doc(cfg(not(feature = "v1_50"))))]
    pub fn length(&self) -> i32 {
        unsafe { (*self.as_ptr()).length }
    }

    #[doc(alias = "pango_layout_line_runs")]
    pub fn runs(&self) -> Vec<LayoutRun> {
        unsafe { FromGlibPtrContainer::from_glib_none((*self.as_ptr()).runs) }
    }
    /// Converts from x offset to the byte index of the corresponding character
    /// within the text of the layout.
    ///
    /// If @x_pos is outside the line, @index_ and @trailing will point to the very
    /// first or very last position in the line. This determination is based on the
    /// resolved direction of the paragraph; for example, if the resolved direction
    /// is right-to-left, then an X position to the right of the line (after it)
    /// results in 0 being stored in @index_ and @trailing. An X position to the
    /// left of the line results in @index_ pointing to the (logical) last grapheme
    /// in the line and @trailing being set to the number of characters in that
    /// grapheme. The reverse is true for a left-to-right line.
    /// ## `x_pos`
    /// the X offset (in Pango units) from the left edge of the line.
    ///
    /// # Returns
    ///
    /// [`false`] if @x_pos was outside the line, [`true`] if inside
    ///
    /// ## `index_`
    /// location to store calculated byte index for the grapheme
    ///   in which the user clicked
    ///
    /// ## `trailing`
    /// location to store an integer indicating where in the
    ///   grapheme the user clicked. It will either be zero, or the number of
    ///   characters in the grapheme. 0 represents the leading edge of the grapheme.
    #[doc(alias = "pango_layout_line_x_to_index")]
    pub fn x_to_index(&self, x_pos: i32) -> HitPosition {
        let mut index = 0;
        let mut trailing = 0;

        let is_inside = unsafe {
            from_glib(ffi::pango_layout_line_x_to_index(
                self.to_glib_none().0,
                x_pos,
                &mut index,
                &mut trailing,
            ))
        };

        HitPosition {
            index,
            trailing,
            is_inside,
        }
    }

    /// Gets a list of visual ranges corresponding to a given logical range.
    ///
    /// This list is not necessarily minimal - there may be consecutive
    /// ranges which are adjacent. The ranges will be sorted from left to
    /// right. The ranges are with respect to the left edge of the entire
    /// layout, not with respect to the line.
    /// ## `start_index`
    /// Start byte index of the logical range. If this value
    ///   is less than the start index for the line, then the first range
    ///   will extend all the way to the leading edge of the layout. Otherwise,
    ///   it will start at the leading edge of the first character.
    /// ## `end_index`
    /// Ending byte index of the logical range. If this value is
    ///   greater than the end index for the line, then the last range will
    ///   extend all the way to the trailing edge of the layout. Otherwise,
    ///   it will end at the trailing edge of the last character.
    ///
    /// # Returns
    ///
    ///
    /// ## `ranges`
    /// location to
    ///   store a pointer to an array of ranges. The array will be of length
    ///   `2*n_ranges`, with each range starting at `(*ranges)[2*n]` and of
    ///   width `(*ranges)[2*n + 1] - (*ranges)[2*n]`. This array must be freed
    ///   with g_free(). The coordinates are relative to the layout and are in
    ///   Pango units.
    #[doc(alias = "pango_layout_line_get_x_ranges")]
    #[doc(alias = "get_x_ranges")]
    pub fn x_ranges(&self, start_index: i32, end_index: i32) -> Vec<i32> {
        unsafe {
            let mut ranges = std::ptr::null_mut();
            let mut n_ranges = std::mem::MaybeUninit::uninit();
            ffi::pango_layout_line_get_x_ranges(
                self.to_glib_none().0,
                start_index,
                end_index,
                &mut ranges,
                n_ranges.as_mut_ptr(),
            );
            FromGlibContainer::from_glib_full_num(ranges, 2 * n_ranges.assume_init() as usize)
        }
    }
}