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