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