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)
}
}
}