1use std::ptr;
2
3use crate::action::{PdfAction, PdfActionLike};
4use crate::action_goto::PdfActionGoTo;
5use crate::action_url::PdfActionUrl;
6use crate::annotation_constants::PdfAnnotationSubtype;
7use crate::border::PdfBorder;
8use crate::error::Result;
9use crate::ffi;
10use crate::handle::ObjectHandle;
11use crate::types::{PdfAnnotationInfo, PdfRect};
12use crate::util::{c_string, option_c_string, parse_json};
13
14#[derive(Debug, Clone)]
16pub struct PdfAnnotation {
17 handle: ObjectHandle,
18}
19
20impl PdfAnnotation {
21 pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
22 Self { handle }
23 }
24
25 pub fn new(bounds: PdfRect, annotation_type: &str) -> Result<Self> {
27 let annotation_type = c_string(annotation_type)?;
28 let mut out_annotation = ptr::null_mut();
29 let mut out_error = ptr::null_mut();
30 let status = unsafe {
31 ffi::pdf_annotation_new(
32 bounds.x,
33 bounds.y,
34 bounds.width,
35 bounds.height,
36 annotation_type.as_ptr(),
37 &mut out_annotation,
38 &mut out_error,
39 )
40 };
41 crate::util::status_result(status, out_error)?;
42 Ok(Self::from_handle(crate::util::required_handle(
43 out_annotation,
44 "PDFAnnotation",
45 )?))
46 }
47
48 pub fn new_with_subtype(
50 bounds: PdfRect,
51 annotation_subtype: PdfAnnotationSubtype,
52 ) -> Result<Self> {
53 let annotation_type = c_string(annotation_subtype.name())?;
54 let mut out_annotation = ptr::null_mut();
55 let mut out_error = ptr::null_mut();
56 let status = unsafe {
57 ffi::pdf_annotation_new(
58 bounds.x,
59 bounds.y,
60 bounds.width,
61 bounds.height,
62 annotation_type.as_ptr(),
63 &mut out_annotation,
64 &mut out_error,
65 )
66 };
67 crate::util::status_result(status, out_error)?;
68 Ok(Self::from_handle(crate::util::required_handle(
69 out_annotation,
70 "PDFAnnotation",
71 )?))
72 }
73
74 pub fn info(&self) -> Result<PdfAnnotationInfo> {
76 parse_json(
77 unsafe { ffi::pdf_annotation_info_json(self.handle.as_ptr()) },
78 "PDFAnnotation",
79 )
80 }
81
82 pub fn set_contents(&self, value: Option<&str>) -> Result<()> {
84 let value = option_c_string(value)?;
85 let mut out_error = ptr::null_mut();
86 let status = unsafe {
87 ffi::pdf_annotation_set_contents(
88 self.handle.as_ptr(),
89 value.as_ref().map_or(ptr::null(), |value| value.as_ptr()),
90 &mut out_error,
91 )
92 };
93 crate::util::status_result(status, out_error)
94 }
95
96 pub fn set_highlighted(&self, value: bool) {
98 unsafe { ffi::pdf_annotation_set_highlighted(self.handle.as_ptr(), i32::from(value)) };
99 }
100
101 #[must_use]
103 pub fn border(&self) -> Option<PdfBorder> {
104 let ptr = unsafe { ffi::pdf_annotation_border(self.handle.as_ptr()) };
105 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfBorder::from_handle)
106 }
107
108 pub fn set_border(&self, border: Option<&PdfBorder>) -> Result<()> {
110 let mut out_error = ptr::null_mut();
111 let status = unsafe {
112 ffi::pdf_annotation_set_border(
113 self.handle.as_ptr(),
114 border.map_or(ptr::null_mut(), PdfBorder::as_handle_ptr),
115 &mut out_error,
116 )
117 };
118 crate::util::status_result(status, out_error)
119 }
120
121 #[must_use]
123 pub fn action(&self) -> Option<PdfAction> {
124 let ptr = unsafe { ffi::pdf_annotation_action(self.handle.as_ptr()) };
125 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfAction::from_handle)
126 }
127
128 pub fn set_action<A: PdfActionLike>(&self, action: Option<&A>) -> Result<()> {
130 let mut out_error = ptr::null_mut();
131 let status = unsafe {
132 ffi::pdf_annotation_set_action(
133 self.handle.as_ptr(),
134 action.map_or(ptr::null_mut(), PdfActionLike::as_action_handle_ptr),
135 &mut out_error,
136 )
137 };
138 crate::util::status_result(status, out_error)
139 }
140
141 pub fn clear_action(&self) -> Result<()> {
143 self.set_action::<PdfAction>(None)
144 }
145
146 #[must_use]
148 pub fn action_url(&self) -> Option<PdfActionUrl> {
149 let ptr = unsafe { ffi::pdf_annotation_action_url(self.handle.as_ptr()) };
150 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfActionUrl::from_handle)
151 }
152
153 pub fn set_action_url(&self, action: Option<&PdfActionUrl>) -> Result<()> {
155 self.set_action(action)
156 }
157
158 #[must_use]
160 pub fn action_goto(&self) -> Option<PdfActionGoTo> {
161 let ptr = unsafe { ffi::pdf_annotation_action_goto(self.handle.as_ptr()) };
162 unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfActionGoTo::from_handle)
163 }
164
165 pub fn set_action_goto(&self, action: Option<&PdfActionGoTo>) -> Result<()> {
167 self.set_action(action)
168 }
169
170 pub(crate) fn as_handle_ptr(&self) -> *mut core::ffi::c_void {
171 self.handle.as_ptr()
172 }
173}