Skip to main content

hapi_rs/parameter/
base.rs

1use crate::Result;
2use crate::ffi::enums::ChoiceListType;
3use crate::ffi::{KeyFrame, ParmChoiceInfo, ParmInfo};
4use crate::node::{NodeHandle, ParmType};
5use crate::session::Session;
6use std::borrow::Cow;
7use std::ffi::{CStr, CString};
8
9use super::Parameter;
10
11/// Common trait for parameters
12pub trait ParmBaseTrait {
13    #[inline]
14    fn name(&self) -> Result<Cow<'_, str>> {
15        let inner = self.inner();
16        match inner.info.2.as_ref() {
17            None => inner.info.name().map(Cow::Owned),
18            Some(c_name) => Ok(c_name.to_string_lossy()),
19        }
20    }
21
22    #[inline]
23    fn session(&self) -> &Session {
24        &self.info().1
25    }
26
27    #[inline]
28    fn node(&self) -> NodeHandle {
29        self.inner().node
30    }
31
32    #[inline]
33    fn size(&self) -> i32 {
34        self.info().size()
35    }
36
37    #[inline]
38    fn info(&self) -> &ParmInfo {
39        &self.inner().info
40    }
41
42    /// Update the internal parameter metadata if Houdini parameter changed,
43    /// for example children added to a multi-parm or the menu was updated.
44    fn update(&mut self) -> Result<()> {
45        let inner = self.inner_mut();
46        let name = inner.info.2.take();
47        let mut info = ParmInfo::from_parm_handle(inner.info.id(), inner.node, &inner.info.1)?;
48        info.2 = name;
49        inner.info = info;
50        Ok(())
51    }
52
53    /// If the parameter has choice menu.
54    #[inline]
55    fn is_menu(&self) -> bool {
56        !matches!(self.info().choice_list_type(), ChoiceListType::None)
57    }
58    /// If parameter is a menu type, return a vec of menu items
59    fn menu_items(&self) -> Result<Option<Vec<ParmChoiceInfo>>> {
60        if !self.is_menu() {
61            return Ok(None);
62        }
63        let inner = self.inner();
64        debug_assert!(inner.info.1.is_valid());
65        if inner.info.choice_count() == 0 {
66            return Ok(Some(Vec::new()));
67        }
68        let parms = crate::ffi::get_parm_choice_list(
69            inner.node,
70            &inner.info.1,
71            inner.info.choice_index(),
72            inner.info.choice_count(),
73        );
74        let parms = parms.map(|v| {
75            use std::ops::Deref;
76
77            v.into_iter()
78                .map(|p| ParmChoiceInfo(p, inner.info.1.deref().clone()))
79                .collect::<Vec<ParmChoiceInfo>>()
80        })?;
81        Ok(Some(parms))
82    }
83
84    /// If the parameter is a multiparm, return its children parms.
85    /// NOTE: `THis` is not a recommended way to traverse parameters in general,
86    /// this is here for convenience only
87    fn multiparm_children(&self) -> Result<Option<Vec<Parameter>>> {
88        let inner = self.inner();
89        if inner.info.parm_type() != ParmType::Multiparmlist {
90            return Ok(None);
91        }
92        let node = inner.node.to_node(&inner.info.1)?;
93        let mut all_parameters = node.parameters()?;
94        all_parameters.retain(|parm| {
95            parm.info().is_child_of_multi_parm() && parm.info().parent_id() == inner.info.id()
96        });
97
98        Ok(Some(all_parameters))
99    }
100
101    fn insert_multiparm_instance(&self, position: i32) -> Result<()> {
102        let ParmInfoWrap { info, node } = self.inner();
103        crate::ffi::insert_multiparm_instance(&info.1, *node, info.id(), position)
104    }
105
106    fn remove_multiparm_instance(&self, position: i32) -> Result<()> {
107        let ParmInfoWrap { info, node } = self.inner();
108        crate::ffi::remove_multiparm_instance(&info.1, *node, info.id(), position)
109    }
110
111    /// Returns a parameter expression string
112    fn expression(&self, index: i32) -> Result<Option<String>> {
113        let inner = self.inner();
114        debug_assert!(inner.info.1.is_valid());
115        let name = self.c_name()?;
116        let expr_string = crate::ffi::get_parm_expression(inner.node, &inner.info.1, &name, index)?;
117        Ok(if expr_string.is_empty() {
118            None
119        } else {
120            Some(expr_string)
121        })
122    }
123
124    /// Checks if parameter has an expression
125    fn has_expression(&self, index: i32) -> Result<bool> {
126        let inner = self.inner();
127        debug_assert!(inner.info.1.is_valid());
128        let name = self.c_name()?;
129        crate::ffi::parm_has_expression(inner.node, &inner.info.1, &name, index)
130    }
131
132    /// Set parameter expression
133    fn set_expression(&self, value: &str, index: i32) -> Result<()> {
134        let inner = self.inner();
135        debug_assert!(inner.info.1.is_valid());
136        let value = CString::new(value)?;
137        crate::ffi::set_parm_expression(inner.node, &inner.info.1, inner.info.id(), &value, index)
138    }
139
140    /// Remove parameter expression
141    fn remove_expression(&self, index: i32) -> Result<()> {
142        let inner = self.inner();
143        debug_assert!(inner.info.1.is_valid());
144        crate::ffi::remove_parm_expression(inner.node, &inner.info.1, inner.info.id(), index)
145    }
146
147    /// Revert parameter at index to its default value. If `index` is None - reset all instances.
148    fn revert_to_default(&self, index: Option<i32>) -> Result<()> {
149        let inner = self.inner();
150        crate::ffi::revert_parameter_to_default(inner.node, &inner.info.1, &self.c_name()?, index)
151    }
152
153    /// Set keyframes on the parameter
154    fn set_anim_curve(&self, index: i32, keys: &[KeyFrame]) -> Result<()> {
155        let inner = self.inner();
156        debug_assert!(inner.info.1.is_valid());
157        // SAFETY: Both structures have the same memory layout.
158        let keys = unsafe {
159            &*(std::ptr::from_ref::<[crate::ffi::structs::KeyFrame]>(keys)
160                as *const [crate::ffi::raw::HAPI_Keyframe])
161        };
162        crate::ffi::set_parm_anim_curve(&inner.info.1, inner.node, inner.info.id(), index, keys)
163    }
164
165    fn has_tag(&self, tag: &str) -> Result<bool> {
166        let inner = self.inner();
167        let tag = CString::new(tag)?;
168        crate::ffi::parm_has_tag(&inner.info.1, inner.node, inner.info.id(), &tag)
169    }
170
171    /// Get parameter tag name by index. The number of tags is stored in `self.info().tag_count()`
172    fn get_tag_name(&self, tag_index: i32) -> Result<String> {
173        let inner = self.inner();
174        crate::ffi::get_parm_tag_name(&inner.info.1, inner.node, inner.info.id(), tag_index)
175    }
176
177    fn get_tag_value(&self, tag_name: &str) -> Result<String> {
178        let inner = self.inner();
179        let tag = CString::new(tag_name)?;
180        crate::ffi::get_parm_tag_value(&inner.info.1, inner.node, inner.info.id(), &tag)
181    }
182
183    #[doc(hidden)]
184    // If the parameter was obtained by name (node.parameter(..))
185    // we store the name in the info struct, otherwise, call API to get name
186    fn c_name(&self) -> Result<Cow<'_, CStr>> {
187        let inner = self.inner();
188        match inner.info.2.as_deref() {
189            None => inner.info.name_cstr().map(Cow::Owned),
190            Some(name) => Ok(Cow::Borrowed(name)),
191        }
192    }
193    #[doc(hidden)]
194    fn inner(&self) -> &ParmInfoWrap;
195
196    #[doc(hidden)]
197    fn inner_mut(&mut self) -> &mut ParmInfoWrap;
198}
199
200#[derive(Debug)]
201#[doc(hidden)]
202pub struct ParmInfoWrap {
203    pub(crate) info: ParmInfo,
204    pub(crate) node: NodeHandle,
205}
206
207#[derive(Debug)]
208#[doc(hidden)]
209pub struct BaseParameter(pub(crate) ParmInfoWrap);
210
211/// Represents float parameters, including `Color` type.
212#[derive(Debug)]
213pub struct FloatParameter(pub(crate) ParmInfoWrap);
214
215/// Represents integer parameters, including `Button` type
216#[derive(Debug)]
217pub struct IntParameter(pub(crate) ParmInfoWrap);
218
219/// Represents string parameters of many different types.
220#[derive(Debug)]
221pub struct StringParameter(pub(crate) ParmInfoWrap);
222
223impl ParmBaseTrait for FloatParameter {
224    #[inline]
225    #[doc(hidden)]
226    fn inner(&self) -> &ParmInfoWrap {
227        &self.0
228    }
229
230    #[inline]
231    #[doc(hidden)]
232    fn inner_mut(&mut self) -> &mut ParmInfoWrap {
233        &mut self.0
234    }
235}
236
237impl ParmBaseTrait for IntParameter {
238    #[inline]
239    #[doc(hidden)]
240    fn inner(&self) -> &ParmInfoWrap {
241        &self.0
242    }
243
244    #[inline]
245    #[doc(hidden)]
246    fn inner_mut(&mut self) -> &mut ParmInfoWrap {
247        &mut self.0
248    }
249}
250
251impl ParmBaseTrait for StringParameter {
252    #[inline]
253    #[doc(hidden)]
254    fn inner(&self) -> &ParmInfoWrap {
255        &self.0
256    }
257
258    #[inline]
259    #[doc(hidden)]
260    fn inner_mut(&mut self) -> &mut ParmInfoWrap {
261        &mut self.0
262    }
263}