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