hapi_rs/parameter/
mod.rs

1//! Reading and setting node parameters, setting expressions and keyframes.
2//!
3//! Different parameter types are modeled with a [Parameter] enum, to get to a concrete type,
4//! use pattern matching:
5//!
6//! ```
7//! use hapi_rs::session::new_in_process_session;
8//! use hapi_rs::session::SessionOptions;
9//! use hapi_rs::parameter::*;
10//! let session = new_in_process_session(Some(SessionOptions::default())).unwrap();
11//! let lib = session.load_asset_file("../otls/hapi_parms.hda").unwrap();
12//! let node = lib.try_create_first().unwrap();
13//! if let Parameter::String(p) = node.parameter("single_string").unwrap() {
14//!     assert_eq!(p.get(0).unwrap(), "hello");
15//!     assert!(p.set(0, "world").is_ok());
16//! }
17//! ```
18//! Extra parameter features are available in [`ParmBaseTrait`]
19
20mod base;
21mod access;
22
23use crate::Result;
24pub use crate::ffi::enums::ParmType;
25pub use crate::ffi::structs::{KeyFrame, ParmInfo};
26use crate::node::{HoudiniNode, NodeHandle, Session};
27pub use base::*;
28use std::fmt::Debug;
29
30/// An internal handle to a parameter
31#[repr(transparent)]
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct ParmHandle(pub crate::ffi::raw::HAPI_ParmId);
34
35#[derive(Debug)]
36/// Enum of different parameter types.
37pub enum Parameter {
38    /// `ParmType::Float | ParmType::Color`
39    Float(FloatParameter),
40    /// `ParmType::Int | ParmType::Toggle`
41    Int(IntParameter),
42    /// `ParmType::String | ParmType::Node | ParmType::PathFile | ParmType::PathFileDir | ParmType::PathFileGeo | ParmType::PathFileImage`
43    String(StringParameter),
44    /// `ParmType::Int`
45    Button(IntParameter),
46    /// `Other ParmType::_`
47    Other(BaseParameter),
48}
49
50impl Parameter {
51    pub(crate) fn new(node: NodeHandle, info: ParmInfo) -> Parameter {
52        let wrap = ParmInfoWrap { info, node };
53        match wrap.info.parm_type() {
54            ParmType::Int | ParmType::Toggle | ParmType::Multiparmlist => {
55                Parameter::Int(IntParameter(wrap))
56            }
57            ParmType::Button => Parameter::Button(IntParameter(wrap)),
58            ParmType::Float | ParmType::Color => Parameter::Float(FloatParameter(wrap)),
59            ParmType::String
60            | ParmType::Node
61            | ParmType::PathFile
62            | ParmType::PathFileDir
63            | ParmType::PathFileGeo
64            | ParmType::PathFileImage => Parameter::String(StringParameter(wrap)),
65            _ => Parameter::Other(BaseParameter(wrap)),
66        }
67    }
68
69    /// A convenient method to evaluate a parameter value as string for debugging.
70    pub fn value_as_debug(&self) -> Result<Box<dyn Debug>> {
71        match self {
72            Parameter::Float(parm) => Ok(Box::new(parm.get_array()?)),
73            Parameter::Int(parm) | Parameter::Button(parm) => Ok(Box::new(parm.get_array()?)),
74            Parameter::String(parm) => Ok(Box::new(parm.get_array()?)),
75            Parameter::Other(parm) => Ok(Box::new(parm.0.info.parm_type())),
76        }
77    }
78    /// Information about the parameter
79    #[inline]
80    pub fn info(&self) -> &ParmInfo {
81        &self.base().info
82    }
83
84    /// Parameter internal name
85    #[inline]
86    pub fn name(&self) -> Result<String> {
87        self.info().name()
88    }
89
90    /// Parameter UI label
91    #[inline]
92    pub fn label(&self) -> Result<String> {
93        self.info().label()
94    }
95
96    /// Number or elements in the parameter
97    #[inline]
98    pub fn size(&self) -> i32 {
99        self.info().size()
100    }
101
102    /// Parameter parent if any (examples are multi-parm or Folder type parameters)
103    pub fn parent(&self) -> Result<Option<ParmInfo>> {
104        let wrap = self.base();
105        debug_assert!(wrap.info.1.is_valid());
106        match wrap.info.parent_id() {
107            ParmHandle(-1) => Ok(None),
108            handle => {
109                let session = wrap.info.1.clone();
110                let info = crate::ffi::get_parm_info(wrap.node, &session, handle)?;
111                Ok(Some(ParmInfo(info, session, None)))
112            }
113        }
114    }
115
116    pub(crate) fn base(&self) -> &ParmInfoWrap {
117        match self {
118            Parameter::Float(p) => &p.0,
119            Parameter::Int(p) => &p.0,
120            Parameter::Button(p) => &p.0,
121            Parameter::String(p) => &p.0,
122            Parameter::Other(p) => &p.0,
123        }
124    }
125}
126
127impl ParmBaseTrait for Parameter {
128    fn inner(&self) -> &ParmInfoWrap {
129        self.base()
130    }
131
132    fn inner_mut(&mut self) -> &mut ParmInfoWrap {
133        match self {
134            Parameter::Float(p) => &mut p.0,
135            Parameter::Int(p) => &mut p.0,
136            Parameter::Button(p) => &mut p.0,
137            Parameter::String(p) => &mut p.0,
138            Parameter::Other(p) => &mut p.0,
139        }
140    }
141}
142
143impl ParmHandle {
144    /// Find a parameter handle by name
145    pub fn from_name(name: &str, node: &HoudiniNode) -> Result<Self> {
146        debug_assert!(node.is_valid()?);
147        let name = std::ffi::CString::new(name)?;
148        let id = crate::ffi::get_parm_id_from_name(&name, node.handle, &node.session)?;
149        Ok(ParmHandle(id))
150    }
151    /// Retrieve parameter information from of the handle
152    pub fn info(&self, node: &HoudiniNode) -> Result<ParmInfo> {
153        debug_assert!(node.is_valid()?);
154        let info = crate::ffi::get_parm_info(node.handle, &node.session, *self)?;
155        Ok(ParmInfo::new(info, node.session.clone(), None))
156    }
157}
158
159impl ParmInfo {
160    pub(crate) fn from_parm_name(name: &str, node: &HoudiniNode) -> Result<Self> {
161        debug_assert!(node.is_valid()?);
162        let name = std::ffi::CString::new(name)?;
163        let info = crate::ffi::get_parm_info_from_name(node.handle, &node.session, &name);
164        info.map(|info| ParmInfo::new(info, node.session.clone(), Some(name)))
165    }
166
167    pub(crate) fn from_parm_handle(
168        parm: ParmHandle,
169        node: NodeHandle,
170        session: &Session,
171    ) -> Result<Self> {
172        let parm_info = crate::ffi::get_parm_info(node, session, parm)?;
173        Ok(ParmInfo::new(parm_info, session.clone(), None))
174    }
175}