use std::num::NonZero;
use crate::common::Rational32;
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct ObjectHandle {
pub(crate) internal: aviutl2_sys::plugin2::OBJECT_HANDLE,
}
impl std::fmt::Debug for ObjectHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ObjectHandle").field(&self.internal).finish()
}
}
impl From<aviutl2_sys::plugin2::OBJECT_HANDLE> for ObjectHandle {
fn from(value: aviutl2_sys::plugin2::OBJECT_HANDLE) -> Self {
Self { internal: value }
}
}
impl From<ObjectHandle> for aviutl2_sys::plugin2::OBJECT_HANDLE {
fn from(value: ObjectHandle) -> Self {
value.internal
}
}
unsafe impl Send for ObjectHandle {}
unsafe impl Sync for ObjectHandle {}
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub struct EffectHandle {
pub(crate) internal: aviutl2_sys::plugin2::EFFECT_HANDLE,
}
impl std::fmt::Debug for EffectHandle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("EffectHandle").field(&self.internal).finish()
}
}
impl From<aviutl2_sys::plugin2::EFFECT_HANDLE> for EffectHandle {
fn from(value: aviutl2_sys::plugin2::EFFECT_HANDLE) -> Self {
Self { internal: value }
}
}
impl From<EffectHandle> for aviutl2_sys::plugin2::EFFECT_HANDLE {
fn from(value: EffectHandle) -> Self {
value.internal
}
}
unsafe impl Send for EffectHandle {}
unsafe impl Sync for EffectHandle {}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct EditInfo {
pub width: usize,
pub height: usize,
pub fps: Rational32,
pub sample_rate: usize,
pub frame: usize,
pub layer: usize,
pub frame_max: usize,
pub layer_max: usize,
pub display_frame: std::ops::Range<usize>,
pub display_layer: std::ops::Range<usize>,
pub select_range: Option<std::ops::RangeInclusive<usize>>,
pub scene_id: i32,
pub background: Option<(u8, u8, u8)>,
}
impl EditInfo {
pub unsafe fn from_raw(ptr: *const aviutl2_sys::plugin2::EDIT_INFO) -> Self {
let raw = unsafe { &*ptr };
Self {
width: raw.width as usize,
height: raw.height as usize,
fps: Rational32::new(raw.rate, raw.scale),
sample_rate: raw.sample_rate as usize,
frame: raw.frame as usize,
layer: raw.layer as usize,
frame_max: raw.frame_max as usize,
layer_max: raw.layer_max as usize,
display_frame: raw.display_frame_start as usize
..(raw.display_frame_start + raw.display_frame_num) as usize,
display_layer: raw.display_layer_start as usize
..(raw.display_layer_start + raw.display_layer_num) as usize,
select_range: if raw.select_range_start >= 0 && raw.select_range_end >= 0 {
Some(raw.select_range_start as usize..=raw.select_range_end as usize)
} else {
None
},
scene_id: raw.scene_id,
background: if raw.background.a == 255 {
Some((raw.background.r, raw.background.g, raw.background.b))
} else {
None
},
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ObjectLayerFrame {
pub layer: usize,
pub start: usize,
pub end: usize,
}
impl ObjectLayerFrame {
pub fn frame_range(&self) -> std::ops::Range<usize> {
self.start..(self.end + 1)
}
pub fn frame_range_inclusive(&self) -> std::ops::RangeInclusive<usize> {
self.start..=self.end
}
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct LayerFrameData {
pub layer: usize,
pub frame: usize,
}
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub struct MediaInfo {
pub video_track_num: Option<NonZero<usize>>,
pub audio_track_num: Option<NonZero<usize>>,
pub total_time: f64,
pub width: usize,
pub height: usize,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub struct TrackInfo {
pub mode: Option<String>,
pub params: Vec<f64>,
pub accelerate: bool,
pub decelerate: bool,
pub twopoint: bool,
pub timecontrol: bool,
pub group_num: usize,
pub group_index: usize,
pub group_name: Option<String>,
}
impl Default for TrackInfo {
fn default() -> Self {
Self {
mode: None,
params: Vec::new(),
accelerate: false,
decelerate: false,
twopoint: false,
timecontrol: false,
group_num: 1,
group_index: 0,
group_name: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct PaletteInfo {
pub colors: [PaletteColor; Self::PALETTE_NUM],
}
impl PaletteInfo {
pub const PALETTE_NUM: usize = aviutl2_sys::plugin2::PALETTE_INFO::PALETTE_NUM;
fn from_raw(raw: aviutl2_sys::plugin2::PALETTE_INFO) -> Self {
Self {
colors: raw.color.map(|color| PaletteColor {
r: color.r,
g: color.g,
b: color.b,
a: color.a,
}),
}
}
fn to_raw(&self) -> aviutl2_sys::plugin2::PALETTE_INFO {
let colors: [aviutl2_sys::plugin2::PALETTE_INFO_COLOR; Self::PALETTE_NUM] = self
.colors
.iter()
.map(|color| aviutl2_sys::plugin2::PALETTE_INFO_COLOR {
r: color.r,
g: color.g,
b: color.b,
a: color.a,
})
.collect::<Vec<_>>()
.try_into()
.expect("PaletteInfo colors length mismatch");
aviutl2_sys::plugin2::PALETTE_INFO { color: colors }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct PaletteColor {
pub r: u8,
pub g: u8,
pub b: u8,
pub a: u8,
}
#[derive(Debug, Clone, Copy)]
pub enum MediaFileSupportMode {
ExtensionOnly,
Strict,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BpmInfo {
pub tempo: f32,
pub beat: i32,
pub start: f64,
pub offset: f32,
}
impl PartialOrd for BpmInfo {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if self.start == other.start {
None
} else {
self.start.partial_cmp(&other.start)
}
}
}
impl From<aviutl2_sys::plugin2::BPM_INFO> for BpmInfo {
fn from(value: aviutl2_sys::plugin2::BPM_INFO) -> Self {
Self {
tempo: value.tempo,
beat: value.beat,
start: value.start,
offset: value.offset,
}
}
}
impl From<BpmInfo> for aviutl2_sys::plugin2::BPM_INFO {
fn from(value: BpmInfo) -> Self {
Self {
tempo: value.tempo,
beat: value.beat,
start: value.start,
offset: value.offset,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ObjectFlagType {
EnableGroup,
EnableCamera,
ClippingObject,
ClippingUpperObject,
}
impl From<ObjectFlagType> for aviutl2_sys::plugin2::OBJECT_FLAG_TYPE {
fn from(value: ObjectFlagType) -> Self {
match value {
ObjectFlagType::EnableGroup => aviutl2_sys::plugin2::OBJECT_FLAG_TYPE::ENABLE_GROUP,
ObjectFlagType::EnableCamera => aviutl2_sys::plugin2::OBJECT_FLAG_TYPE::ENABLE_CAMERA,
ObjectFlagType::ClippingObject => {
aviutl2_sys::plugin2::OBJECT_FLAG_TYPE::CLIPPING_OBJECT
}
ObjectFlagType::ClippingUpperObject => {
aviutl2_sys::plugin2::OBJECT_FLAG_TYPE::CLIPPING_UPPER_OBJECT
}
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum EditSectionError {
#[error("api call failed")]
ApiCallFailed,
#[error("object does not exist")]
ObjectDoesNotExist,
#[error("effect does not exist")]
EffectDoesNotExist,
#[error("input utf-8 string contains null byte")]
InputCstrContainsNull(#[from] std::ffi::NulError),
#[error("input utf-16 string contains null byte")]
InputCwstrContainsNull(#[from] crate::common::NullByteError),
#[error("value is out of range")]
ValueOutOfRange(#[from] std::num::TryFromIntError),
#[error("api returned non-utf8 data")]
NonUtf8Data(#[from] std::str::Utf8Error),
#[cfg(feature = "aviutl2-alias")]
#[error("alias parse error: {0}")]
ParseFailed(#[from] aviutl2_alias::TableParseError),
}
#[derive(thiserror::Error, Debug)]
pub enum EditSectionParsedError<E: std::error::Error + Send + Sync + 'static> {
#[error(transparent)]
EditSectionError(#[from] EditSectionError),
#[error("value parse error: {0}")]
ParseError(E),
}
pub type EditSectionResult<T> = Result<T, EditSectionError>;
#[derive(Debug)]
pub struct ReadSection {
pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_SECTION,
}
#[derive(Debug)]
pub struct EditSection {
pub info: EditInfo,
pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_SECTION,
read_section: ReadSection,
}
impl std::ops::Deref for EditSection {
type Target = ReadSection;
fn deref(&self) -> &Self::Target {
&self.read_section
}
}
impl ReadSection {
pub unsafe fn from_raw(ptr: *mut aviutl2_sys::plugin2::EDIT_SECTION) -> Self {
Self { internal: ptr }
}
pub fn find_object_after(
&self,
layer: usize,
frame: usize,
) -> EditSectionResult<Option<ObjectHandle>> {
let object_handle =
unsafe { ((*self.internal).find_object)(layer.try_into()?, frame.try_into()?) };
if object_handle.is_null() {
Ok(None)
} else {
Ok(Some(ObjectHandle {
internal: object_handle,
}))
}
}
pub fn count_object_effect(
&self,
object: ObjectHandle,
effect: &str,
) -> EditSectionResult<usize> {
self.ensure_object_exists(object)?;
let c_effect = crate::common::CWString::new(effect)?;
let count =
unsafe { ((*self.internal).count_object_effect)(object.internal, c_effect.as_ptr()) };
Ok(count.try_into()?)
}
pub fn get_object_layer_frame(
&self,
object: ObjectHandle,
) -> EditSectionResult<ObjectLayerFrame> {
self.ensure_object_exists(object)?;
let object = unsafe { ((*self.internal).get_object_layer_frame)(object.internal) };
Ok(ObjectLayerFrame {
layer: object.layer.try_into()?,
start: object.start.try_into()?,
end: object.end.try_into()?,
})
}
pub fn get_object_alias(&self, object: ObjectHandle) -> EditSectionResult<String> {
self.ensure_object_exists(object)?;
let alias_ptr = unsafe { ((*self.internal).get_object_alias)(object.internal) };
if alias_ptr.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
let c_str = unsafe { std::ffi::CStr::from_ptr(alias_ptr) };
let alias = c_str.to_str()?.to_owned();
Ok(alias)
}
#[cfg(feature = "aviutl2-alias")]
pub fn get_object_alias_parsed(
&self,
object: ObjectHandle,
) -> Result<aviutl2_alias::Table, EditSectionParsedError<aviutl2_alias::TableParseError>> {
let alias_str = self.get_object_alias(object)?;
let alias_data = alias_str
.parse()
.map_err(EditSectionParsedError::ParseError)?;
Ok(alias_data)
}
pub fn get_object_name(&self, object: ObjectHandle) -> EditSectionResult<Option<String>> {
self.ensure_object_exists(object)?;
let name_ptr = unsafe { ((*self.internal).get_object_name)(object.internal) };
if name_ptr.is_null() {
return Ok(None);
}
Ok(Some(unsafe { crate::common::load_wide_string(name_ptr) }))
}
pub fn get_object_effect_item(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
item: &str,
) -> EditSectionResult<String> {
self.ensure_object_exists(object)?;
let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
let c_item = crate::common::CWString::new(item)?;
let value_ptr = unsafe {
((*self.internal).get_object_item_value)(
object.internal,
c_effect_name.as_ptr(),
c_item.as_ptr(),
)
};
if value_ptr.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
let c_str = unsafe { std::ffi::CStr::from_ptr(value_ptr) };
let value = c_str.to_str()?.to_owned();
Ok(value)
}
#[cfg(feature = "aviutl2-alias")]
pub fn get_object_effect_item_parsed<T: aviutl2_alias::FromTableValue>(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
item: &str,
) -> Result<T, EditSectionParsedError<<T as aviutl2_alias::FromTableValue>::Err>>
where
<T as aviutl2_alias::FromTableValue>::Err: std::error::Error + Sync + Send + 'static,
{
let value_str = self.get_object_effect_item(object, effect_name, effect_index, item)?;
T::from_table_value(&value_str).map_err(EditSectionParsedError::ParseError)
}
pub fn get_focused_object(&self) -> EditSectionResult<Option<ObjectHandle>> {
let object_handle = unsafe { ((*self.internal).get_focus_object)() };
if object_handle.is_null() {
Ok(None)
} else {
Ok(Some(ObjectHandle {
internal: object_handle,
}))
}
}
pub fn get_selected_objects(&self) -> EditSectionResult<Vec<ObjectHandle>> {
let mut handles = Vec::new();
let num_objects = unsafe { ((*self.internal).get_selected_object_num)() };
for i in 0..num_objects {
let object_handle = unsafe { ((*self.internal).get_selected_object)(i) };
if object_handle.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
handles.push(ObjectHandle {
internal: object_handle,
});
}
Ok(handles)
}
pub fn is_support_media_file<P: AsRef<std::path::Path>>(
&self,
file_path: P,
mode: MediaFileSupportMode,
) -> EditSectionResult<bool> {
let c_file_path = crate::common::CWString::new(&file_path.as_ref().to_string_lossy())?;
let is_supported = unsafe {
match mode {
MediaFileSupportMode::ExtensionOnly => {
((*self.internal).is_support_media_file)(c_file_path.as_ptr(), false)
}
MediaFileSupportMode::Strict => {
((*self.internal).is_support_media_file)(c_file_path.as_ptr(), true)
}
}
};
Ok(is_supported)
}
pub fn get_media_info<P: AsRef<std::path::Path>>(
&self,
file_path: P,
) -> EditSectionResult<MediaInfo> {
let c_file_path = crate::common::CWString::new(&file_path.as_ref().to_string_lossy())?;
let mut media_info = std::mem::MaybeUninit::<aviutl2_sys::plugin2::MEDIA_INFO>::uninit();
let success = unsafe {
((*self.internal).get_media_info)(
c_file_path.as_ptr(),
media_info.as_mut_ptr(),
std::mem::size_of::<aviutl2_sys::plugin2::MEDIA_INFO>() as i32,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
let media_info = unsafe { media_info.assume_init() };
Ok(MediaInfo {
video_track_num: NonZero::new(media_info.video_track_num.try_into()?),
audio_track_num: NonZero::new(media_info.audio_track_num.try_into()?),
total_time: media_info.total_time,
width: media_info.width.try_into()?,
height: media_info.height.try_into()?,
})
}
pub fn get_layer_name(&self, layer: usize) -> EditSectionResult<Option<String>> {
let name_ptr = unsafe { ((*self.internal).get_layer_name)(layer.try_into()?) };
if name_ptr.is_null() {
return Ok(None);
}
Ok(Some(unsafe { crate::common::load_wide_string(name_ptr) }))
}
pub fn get_scene_name(&self) -> EditSectionResult<String> {
let name_ptr = unsafe { ((*self.internal).get_scene_name)() };
if name_ptr.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(unsafe { crate::common::load_wide_string(name_ptr) })
}
pub fn get_layer_enable(&self, layer: usize) -> EditSectionResult<bool> {
let visible = unsafe { ((*self.internal).get_layer_enable)(layer.try_into()?) };
Ok(visible)
}
pub fn get_layer_lock(&self, layer: usize) -> EditSectionResult<bool> {
let locked = unsafe { ((*self.internal).get_layer_lock)(layer.try_into()?) };
Ok(locked)
}
pub fn get_object_section_num(&self, object: ObjectHandle) -> EditSectionResult<usize> {
self.ensure_object_exists(object)?;
let count = unsafe { ((*self.internal).get_object_section_num)(object.internal) };
Ok(count.try_into()?)
}
pub fn get_object_section_frame(
&self,
object: ObjectHandle,
section: usize,
) -> EditSectionResult<usize> {
self.ensure_object_exists(object)?;
let frame = unsafe {
((*self.internal).get_object_section_frame)(object.internal, section.try_into()?)
};
if frame == -1 {
Err(EditSectionError::ApiCallFailed)
} else {
Ok(frame.try_into()?)
}
}
pub fn get_object_section_frames(&self, object: ObjectHandle) -> EditSectionResult<Vec<usize>> {
self.ensure_object_exists(object)?;
let section_num = self.get_object_section_num(object)?;
let mut frames = Vec::new();
for section in 0..section_num {
frames.push(self.get_object_section_frame(object, section)?);
}
Ok(frames)
}
pub fn get_object_section_ranges(
&self,
object: ObjectHandle,
) -> EditSectionResult<Vec<std::ops::Range<usize>>> {
self.ensure_object_exists(object)?;
let frames = self.get_object_section_frames(object)?;
let position = self.get_object_layer_frame(object)?;
Ok(frames
.iter()
.enumerate()
.map(|(i, &start)| {
let end = if i + 1 < frames.len() {
frames[i + 1]
} else {
position.end + 1
};
start..end
})
.collect())
}
pub fn get_object_track_value(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
item: &str,
frame: f64,
) -> EditSectionResult<f64> {
self.ensure_object_exists(object)?;
let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
let c_item = crate::common::CWString::new(item)?;
let mut value = 0.0;
let success = unsafe {
((*self.internal).get_object_track_value)(
object.internal,
c_effect_name.as_ptr(),
c_item.as_ptr(),
frame,
&mut value,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(value)
}
pub fn get_object_check_value(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
item: &str,
frame: usize,
) -> EditSectionResult<bool> {
self.ensure_object_exists(object)?;
let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
let c_item = crate::common::CWString::new(item)?;
let mut value = false;
let success = unsafe {
((*self.internal).get_object_check_value)(
object.internal,
c_effect_name.as_ptr(),
c_item.as_ptr(),
frame.try_into()?,
&mut value,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(value)
}
pub fn get_object_track_info(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
item: &str,
) -> EditSectionResult<TrackInfo> {
self.ensure_object_exists(object)?;
let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
let c_item = crate::common::CWString::new(item)?;
let mut info = std::mem::MaybeUninit::<aviutl2_sys::plugin2::TRACK_INFO>::uninit();
let success = unsafe {
((*self.internal).get_object_track_info)(
object.internal,
c_effect_name.as_ptr(),
c_item.as_ptr(),
info.as_mut_ptr(),
std::mem::size_of::<aviutl2_sys::plugin2::TRACK_INFO>() as i32,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
let info = unsafe { info.assume_init() };
let mode = if info.mode.is_null() {
None
} else {
Some(unsafe { crate::common::load_wide_string(info.mode) })
};
let param_num: usize = info.param_num.try_into()?;
let params = if param_num == 0 {
Vec::new()
} else {
if info.param.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
unsafe { std::slice::from_raw_parts(info.param, param_num) }.to_vec()
};
Ok(TrackInfo {
mode,
params,
accelerate: info.accelerate,
decelerate: info.decelerate,
twopoint: info.twopoint,
timecontrol: info.timecontrol,
group_num: info.group_num.try_into()?,
group_index: info.group_index.try_into()?,
group_name: if info.group_name.is_null() {
None
} else {
Some(unsafe { crate::common::load_wide_string(info.group_name) })
},
})
}
pub fn get_palette_name(&self) -> EditSectionResult<String> {
let name_ptr = unsafe { ((*self.internal).get_palette_name)() };
if name_ptr.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(unsafe { crate::common::load_wide_string(name_ptr) })
}
pub fn get_palette_info(&self, name: &str) -> EditSectionResult<PaletteInfo> {
let c_name = crate::common::CWString::new(name)?;
let mut info = std::mem::MaybeUninit::<aviutl2_sys::plugin2::PALETTE_INFO>::uninit();
let success = unsafe {
((*self.internal).get_palette_info)(
c_name.as_ptr(),
info.as_mut_ptr(),
std::mem::size_of::<aviutl2_sys::plugin2::PALETTE_INFO>() as i32,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(PaletteInfo::from_raw(unsafe { info.assume_init() }))
}
pub fn get_current_palette_info(&self) -> EditSectionResult<PaletteInfo> {
let name = self.get_palette_name()?;
self.get_palette_info(&name)
}
pub fn get_font(&self, font_name: &str) -> EditSectionResult<*mut std::ffi::c_void> {
let c_font_name = crate::common::CWString::new(font_name)?;
let ptr = unsafe { ((*self.internal).get_font)(c_font_name.as_ptr()) };
if ptr.is_null() {
Err(EditSectionError::ApiCallFailed)
} else {
Ok(ptr)
}
}
pub fn get_object_track_group_names(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
group_name: &str,
) -> EditSectionResult<Vec<String>> {
self.ensure_object_exists(object)?;
let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
let c_group_name = crate::common::CWString::new(group_name)?;
let item_num = unsafe {
((*self.internal).get_object_track_group_names)(
object.internal,
c_effect_name.as_ptr(),
c_group_name.as_ptr(),
std::ptr::null_mut(),
0,
)
};
let item_num: usize = item_num.try_into()?;
if item_num == 0 {
return Ok(Vec::new());
}
let mut item_names = vec![std::ptr::null(); item_num];
let actual_item_num = unsafe {
((*self.internal).get_object_track_group_names)(
object.internal,
c_effect_name.as_ptr(),
c_group_name.as_ptr(),
item_names.as_mut_ptr(),
item_names.len().try_into()?,
)
};
let actual_item_num: usize = actual_item_num.try_into()?;
if actual_item_num > item_names.len() {
return Err(EditSectionError::ApiCallFailed);
}
item_names.truncate(actual_item_num);
item_names
.into_iter()
.map(|item_name| {
if item_name.is_null() {
Err(EditSectionError::ApiCallFailed)
} else {
Ok(unsafe { crate::common::load_wide_string(item_name) })
}
})
.collect()
}
pub fn get_focus_object_section(&self) -> EditSectionResult<Option<usize>> {
let section = unsafe { ((*self.internal).get_focus_object_section)() };
if section == -1 {
Ok(None)
} else {
Ok(Some(section.try_into()?))
}
}
pub fn get_object_flag(
&self,
object: ObjectHandle,
flag: ObjectFlagType,
) -> EditSectionResult<bool> {
self.ensure_object_exists(object)?;
let flag_value =
unsafe { ((*self.internal).get_object_flag)(object.internal, flag.into()) };
Ok(flag_value)
}
pub fn get_object_id(&self, object: ObjectHandle) -> EditSectionResult<i64> {
self.ensure_object_exists(object)?;
let id = unsafe { ((*self.internal).get_object_id)(object.internal) };
Ok(id)
}
pub fn get_grid_bpm_list(&self) -> EditSectionResult<Vec<BpmInfo>> {
let mut bpm_info_list = Vec::<aviutl2_sys::plugin2::BPM_INFO>::new();
let bpm_size = std::mem::size_of::<aviutl2_sys::plugin2::BPM_INFO>().try_into()?;
let bpm_num =
unsafe { ((*self.internal).get_grid_bpm_list)(std::ptr::null_mut(), 0, bpm_size) };
if bpm_num <= 0 {
return Ok(vec![]);
}
bpm_info_list.resize_with(bpm_num as usize, || aviutl2_sys::plugin2::BPM_INFO {
tempo: 0.0,
beat: 0,
start: 0.0,
offset: 0.0,
});
let actual_bpm_num = unsafe {
((*self.internal).get_grid_bpm_list)(
bpm_info_list.as_mut_ptr(),
bpm_info_list.len() as i32,
bpm_size,
)
};
if actual_bpm_num != bpm_num {
return Err(EditSectionError::ApiCallFailed);
}
let bpm_info_list = bpm_info_list.into_iter().map(BpmInfo::from).collect();
Ok(bpm_info_list)
}
pub fn find_effect(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
) -> EditSectionResult<EffectHandle> {
self.ensure_object_exists(object)?;
let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
let handle =
unsafe { ((*self.internal).find_effect)(object.internal, c_effect_name.as_ptr()) };
if handle.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(EffectHandle { internal: handle })
}
pub fn get_first_effect(&self, object: ObjectHandle) -> EditSectionResult<EffectHandle> {
self.ensure_object_exists(object)?;
let handle = unsafe { ((*self.internal).find_effect)(object.internal, std::ptr::null()) };
if handle.is_null() {
Err(EditSectionError::ApiCallFailed)
} else {
Ok(EffectHandle { internal: handle })
}
}
pub fn get_effects(&self, object: ObjectHandle) -> EditSectionResult<Vec<EffectHandle>> {
self.ensure_object_exists(object)?;
let mut effects = Vec::<aviutl2_sys::plugin2::EFFECT_HANDLE>::new();
let num_effects =
unsafe { ((*self.internal).get_effect_list)(object.internal, std::ptr::null_mut(), 0) };
if num_effects <= 0 {
return Err(EditSectionError::ApiCallFailed);
}
effects.resize_with(num_effects as usize, std::ptr::null_mut);
let actual_num_effects = unsafe {
((*self.internal).get_effect_list)(
object.internal,
effects.as_mut_ptr(),
effects.len() as i32,
)
};
if actual_num_effects != num_effects {
return Err(EditSectionError::ApiCallFailed);
}
let effect_handles = effects
.into_iter()
.map(|handle| EffectHandle { internal: handle })
.collect();
Ok(effect_handles)
}
pub fn get_effect_enable(&self, effect: EffectHandle) -> EditSectionResult<bool> {
self.ensure_effect_exists(effect)?;
let enabled = unsafe { ((*self.internal).get_effect_enable)(effect.internal) };
Ok(enabled)
}
pub fn get_effect_lock(&self, effect: EffectHandle) -> EditSectionResult<bool> {
self.ensure_effect_exists(effect)?;
let locked = unsafe { ((*self.internal).get_effect_lock)(effect.internal) };
Ok(locked)
}
pub fn get_effect_item_value(
&self,
effect: EffectHandle,
item: &str,
) -> EditSectionResult<String> {
self.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let value_ptr =
unsafe { ((*self.internal).get_effect_item_value)(effect.internal, c_item.as_ptr()) };
if value_ptr.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
let c_str = unsafe { std::ffi::CStr::from_ptr(value_ptr) };
let value = c_str.to_str()?.to_owned();
Ok(value)
}
#[cfg(feature = "aviutl2-alias")]
pub fn get_effect_item_value_parsed<T: aviutl2_alias::FromTableValue>(
&self,
effect: EffectHandle,
item: &str,
) -> Result<T, EditSectionParsedError<<T as aviutl2_alias::FromTableValue>::Err>>
where
<T as aviutl2_alias::FromTableValue>::Err: std::error::Error + Sync + Send + 'static,
{
let value_str = self.get_effect_item_value(effect, item)?;
T::from_table_value(&value_str).map_err(EditSectionParsedError::ParseError)
}
pub fn get_effect_data_size(
&self,
effect: EffectHandle,
item: &str,
) -> EditSectionResult<usize> {
self.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let size = unsafe {
((*self.internal).get_effect_data_value)(
effect.internal,
c_item.as_ptr(),
std::ptr::null_mut(),
0,
)
};
Ok(size.try_into()?)
}
pub fn get_effect_data_value(
&self,
effect: EffectHandle,
item: &str,
) -> EditSectionResult<Vec<u8>> {
self.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let size = self.get_effect_data_size(effect, item)?;
if size == 0 {
return Ok(Vec::new());
}
let mut buffer = vec![0u8; size];
let actual_size = unsafe {
((*self.internal).get_effect_data_value)(
effect.internal,
c_item.as_ptr(),
buffer.as_mut_ptr() as *mut std::ffi::c_void,
size.try_into()?,
)
};
if actual_size != i32::try_from(size)? {
return Err(EditSectionError::ApiCallFailed);
}
Ok(buffer)
}
pub unsafe fn get_effect_data_value_as<T>(
&self,
effect: EffectHandle,
item: &str,
) -> EditSectionResult<T> {
let size = std::mem::size_of::<T>();
let actual_size = self.get_effect_data_size(effect, item)?;
if actual_size != size {
return Err(EditSectionError::ApiCallFailed);
}
let value = unsafe {
let mut value = std::mem::MaybeUninit::<T>::uninit();
let actual_size = ((*self.internal).get_effect_data_value)(
effect.internal,
crate::common::CWString::new(item)?.as_ptr(),
value.as_mut_ptr() as *mut std::ffi::c_void,
size.try_into()?,
);
if actual_size != i32::try_from(size)? {
return Err(EditSectionError::ApiCallFailed);
}
value.assume_init()
};
Ok(value)
}
pub fn get_effect_track_value(
&self,
effect: EffectHandle,
item: &str,
frame: f64,
) -> EditSectionResult<f64> {
self.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let mut value = 0.0;
let success = unsafe {
((*self.internal).get_effect_track_value)(
effect.internal,
c_item.as_ptr(),
frame,
&mut value,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(value)
}
pub fn get_effect_check_value(
&self,
effect: EffectHandle,
item: &str,
frame: usize,
) -> EditSectionResult<bool> {
self.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let mut value = false;
let success = unsafe {
((*self.internal).get_effect_check_value)(
effect.internal,
c_item.as_ptr(),
frame.try_into()?,
&mut value,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(value)
}
pub fn get_effect_track_info(
&self,
effect: EffectHandle,
item: &str,
) -> EditSectionResult<TrackInfo> {
self.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let mut info = std::mem::MaybeUninit::<aviutl2_sys::plugin2::TRACK_INFO>::uninit();
let success = unsafe {
((*self.internal).get_effect_track_info)(
effect.internal,
c_item.as_ptr(),
info.as_mut_ptr(),
std::mem::size_of::<aviutl2_sys::plugin2::TRACK_INFO>() as i32,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
let info = unsafe { info.assume_init() };
let mode = if info.mode.is_null() {
None
} else {
Some(unsafe { crate::common::load_wide_string(info.mode) })
};
let param_num: usize = info.param_num.try_into()?;
let params = if param_num == 0 {
Vec::new()
} else {
if info.param.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
unsafe { std::slice::from_raw_parts(info.param, param_num) }.to_vec()
};
Ok(TrackInfo {
mode,
params,
accelerate: info.accelerate,
decelerate: info.decelerate,
twopoint: info.twopoint,
timecontrol: info.timecontrol,
group_num: info.group_num.try_into()?,
group_index: info.group_index.try_into()?,
group_name: if info.group_name.is_null() {
None
} else {
Some(unsafe { crate::common::load_wide_string(info.group_name) })
},
})
}
pub fn get_effect_name(&self, effect: EffectHandle) -> EditSectionResult<String> {
let name_ptr = unsafe { ((*self.internal).get_effect_name)(effect.internal) };
if name_ptr.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(unsafe { crate::common::load_wide_string(name_ptr) })
}
pub fn get_effect_id(&self, effect: EffectHandle) -> EditSectionResult<i64> {
let id = unsafe { ((*self.internal).get_effect_id)(effect.internal) };
Ok(id)
}
pub fn get_mark_frame_list(&self) -> EditSectionResult<Vec<usize>> {
let num_frames = unsafe { ((*self.internal).get_mark_frame_list)(std::ptr::null_mut(), 0) };
if num_frames < 0 {
return Err(EditSectionError::ApiCallFailed);
}
let num_frames = num_frames.try_into()?;
let mut frames = vec![0; num_frames];
let actual_num_frames = unsafe {
((*self.internal).get_mark_frame_list)(frames.as_mut_ptr(), num_frames.try_into()?)
};
if actual_num_frames != i32::try_from(num_frames)? {
return Err(EditSectionError::ApiCallFailed);
}
Ok(frames
.into_iter()
.map(|f| f.try_into())
.collect::<Result<Vec<_>, _>>()?)
}
pub fn get_mark_frame_memo(&self, frame: usize) -> EditSectionResult<String> {
let c_memo_ptr = unsafe { ((*self.internal).get_mark_frame_memo)(frame.try_into()?) };
if c_memo_ptr.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
let memo = unsafe { crate::common::load_wide_string(c_memo_ptr) };
Ok(memo)
}
pub fn object_exists(&self, object: ObjectHandle) -> bool {
let object = unsafe { ((*self.internal).get_object_layer_frame)(object.internal) };
object.layer != -1
}
pub fn effect_exists(&self, effect: EffectHandle) -> bool {
let name_ptr = unsafe { ((*self.internal).get_effect_name)(effect.internal) };
!name_ptr.is_null()
}
fn ensure_object_exists(&self, object: ObjectHandle) -> EditSectionResult<()> {
if !self.object_exists(object) {
return Err(EditSectionError::ObjectDoesNotExist);
}
Ok(())
}
fn ensure_effect_exists(&self, effect: EffectHandle) -> EditSectionResult<()> {
if !self.effect_exists(effect) {
return Err(EditSectionError::EffectDoesNotExist);
}
Ok(())
}
pub fn objects_in_layer(
&self,
layer: usize,
) -> EditSectionLayerObjectsIterator<'_, ReadSection> {
EditSectionLayerObjectsIterator::new(self, layer)
}
pub fn layer<'a>(&'a self, layer: usize) -> EditSectionLayerCaller<'a, ReadSection> {
EditSectionLayerCaller::new(self, layer)
}
pub fn object<'a>(&'a self, object: ObjectHandle) -> EditSectionObjectCaller<'a, ReadSection> {
EditSectionObjectCaller::new(self, object)
}
pub fn effect<'a>(&'a self, effect: EffectHandle) -> EditSectionEffectCaller<'a, ReadSection> {
EditSectionEffectCaller::new(self, effect)
}
}
impl EditSection {
pub unsafe fn from_raw(ptr: *mut aviutl2_sys::plugin2::EDIT_SECTION) -> Self {
let info = unsafe { EditInfo::from_raw((*ptr).info) };
Self {
internal: ptr,
info,
read_section: ReadSection { internal: ptr },
}
}
pub fn create_object_from_alias(
&self,
alias: &str,
layer: usize,
frame: usize,
length: usize,
) -> EditSectionResult<ObjectHandle> {
let c_alias = std::ffi::CString::new(alias)?;
let object_handle = unsafe {
((*self.internal).create_object_from_alias)(
c_alias.as_ptr(),
layer.try_into()?,
frame.try_into()?,
length.try_into()?,
)
};
if object_handle.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(ObjectHandle {
internal: object_handle,
})
}
pub fn set_object_name(
&self,
object: ObjectHandle,
name: Option<&str>,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
match name {
None => {
unsafe { ((*self.internal).set_object_name)(object.internal, std::ptr::null()) };
Ok(())
}
Some(name) => {
let c_name = crate::common::CWString::new(name)?;
unsafe {
((*self.internal).set_object_name)(object.internal, c_name.as_ptr());
}
Ok(())
}
}
}
pub fn set_object_effect_item(
&self,
object: ObjectHandle,
effect_name: &str,
effect_index: usize,
item: &str,
value: &str,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
let c_effect_name = crate::common::CWString::new(&effect_key(effect_name, effect_index))?;
let c_item = crate::common::CWString::new(item)?;
let c_value = std::ffi::CString::new(value)?;
let success = unsafe {
((*self.internal).set_object_item_value)(
object.internal,
c_effect_name.as_ptr(),
c_item.as_ptr(),
c_value.as_ptr(),
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn set_effect_data_value(
&self,
effect: EffectHandle,
item: &str,
data: &[u8],
) -> EditSectionResult<()> {
self.read_section.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let success = unsafe {
((*self.internal).set_effect_data_value)(
effect.internal,
c_item.as_ptr(),
data.as_ptr() as *mut std::ffi::c_void,
data.len().try_into()?,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn set_effect_data_value_with<T>(
&self,
effect: EffectHandle,
item: &str,
data: &T,
) -> EditSectionResult<()> {
self.read_section.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let success = unsafe {
((*self.internal).set_effect_data_value)(
effect.internal,
c_item.as_ptr(),
data as *const T as *mut std::ffi::c_void,
std::mem::size_of::<T>().try_into()?,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn move_object(
&self,
object: ObjectHandle,
new_layer: usize,
new_start_frame: usize,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
let success = unsafe {
((*self.internal).move_object)(
object.internal,
new_layer.try_into()?,
new_start_frame.try_into()?,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn delete_object(&self, object: ObjectHandle) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
unsafe { ((*self.internal).delete_object)(object.internal) };
Ok(())
}
pub fn set_focus_object(&self, object: Option<ObjectHandle>) -> EditSectionResult<()> {
if let Some(object) = object {
self.read_section.ensure_object_exists(object)?;
unsafe { ((*self.internal).set_focus_object)(object.internal) };
} else {
unsafe { ((*self.internal).set_focus_object)(std::ptr::null_mut()) };
}
Ok(())
}
pub fn get_project_file<'handle>(
&'handle self,
edit_handle: &crate::generic::EditHandle,
) -> crate::generic::ProjectFile<'handle> {
let pf_ptr = unsafe { ((*self.internal).get_project_file)(edit_handle.internal) };
unsafe { crate::generic::ProjectFile::from_raw(pf_ptr) }
}
pub fn get_mouse_layer_frame(&self) -> EditSectionResult<Option<LayerFrameData>> {
let mut layer = 0;
let mut frame = 0;
let on_layer_edit =
unsafe { ((*self.internal).get_mouse_layer_frame)(&mut layer, &mut frame) };
if on_layer_edit {
Ok(Some(LayerFrameData {
layer: layer.try_into()?,
frame: frame.try_into()?,
}))
} else {
Ok(None)
}
}
pub fn pos_to_layer_frame(&self, x: i32, y: i32) -> EditSectionResult<Option<LayerFrameData>> {
let mut layer = 0;
let mut frame = 0;
let on_layer_edit =
unsafe { ((*self.internal).pos_to_layer_frame)(x, y, &mut layer, &mut frame) };
if on_layer_edit {
Ok(Some(LayerFrameData {
layer: layer.try_into()?,
frame: frame.try_into()?,
}))
} else {
Ok(None)
}
}
pub fn create_object_from_media_file<P: AsRef<std::path::Path>>(
&self,
file_path: P,
layer: usize,
frame: usize,
length: Option<usize>,
) -> EditSectionResult<ObjectHandle> {
let c_file_path = crate::common::CWString::new(&file_path.as_ref().to_string_lossy())?;
let object_handle = unsafe {
((*self.internal).create_object_from_media_file)(
c_file_path.as_ptr(),
layer.try_into()?,
frame.try_into()?,
length.unwrap_or(0).try_into()?,
)
};
if object_handle.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(ObjectHandle {
internal: object_handle,
})
}
pub fn create_object(
&self,
effect: &str,
layer: usize,
frame: usize,
length: Option<usize>,
) -> EditSectionResult<ObjectHandle> {
let c_effect = crate::common::CWString::new(effect)?;
let object_handle = unsafe {
((*self.internal).create_object)(
c_effect.as_ptr(),
layer.try_into()?,
frame.try_into()?,
length.unwrap_or(0).try_into()?,
)
};
if object_handle.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(ObjectHandle {
internal: object_handle,
})
}
pub fn create_effect(
&self,
object: ObjectHandle,
effect: &str,
) -> EditSectionResult<EffectHandle> {
self.read_section.ensure_object_exists(object)?;
let c_effect = crate::common::CWString::new(effect)?;
let effect_handle =
unsafe { ((*self.internal).create_effect)(object.internal, c_effect.as_ptr()) };
if effect_handle.is_null() {
return Err(EditSectionError::ApiCallFailed);
}
Ok(EffectHandle {
internal: effect_handle,
})
}
pub fn delete_effect(
&self,
object: ObjectHandle,
effect: EffectHandle,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
self.read_section.ensure_effect_exists(effect)?;
let success = unsafe { ((*self.internal).delete_effect)(object.internal, effect.internal) };
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn create_object_section(
&self,
object: ObjectHandle,
frame: usize,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
let success =
unsafe { ((*self.internal).create_object_section)(object.internal, frame.try_into()?) };
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn delete_object_section(
&self,
object: ObjectHandle,
section: usize,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
let success = unsafe {
((*self.internal).delete_object_section)(object.internal, section.try_into()?)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn move_object_section(
&self,
object: ObjectHandle,
section: usize,
new_frame: usize,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
let success = unsafe {
((*self.internal).move_object_section)(
object.internal,
section.try_into()?,
new_frame.try_into()?,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn move_effect(
&self,
object: ObjectHandle,
effect: EffectHandle,
index: usize,
) -> EditSectionResult<usize> {
self.read_section.ensure_object_exists(object)?;
self.read_section.ensure_effect_exists(effect)?;
let success = unsafe {
((*self.internal).move_effect)(object.internal, effect.internal, index.try_into()?)
};
if success == -1 {
return Err(EditSectionError::ApiCallFailed);
}
Ok(success.try_into()?)
}
pub fn set_cursor_layer_frame(&self, layer: usize, frame: usize) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_cursor_layer_frame)(layer.try_into()?, frame.try_into()?);
}
Ok(())
}
pub fn set_display_layer_frame(&self, layer: usize, frame: usize) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_display_layer_frame)(layer.try_into()?, frame.try_into()?);
}
Ok(())
}
pub fn set_select_range(&self, start: usize, end: usize) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_select_range)(start.try_into()?, end.try_into()?);
}
Ok(())
}
pub fn clear_select_range(&self) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_select_range)(-1, -1);
}
Ok(())
}
pub fn set_grid_bpm_list(&self, bpm_info: &[BpmInfo]) -> EditSectionResult<()> {
let mut raw_bpm_info = bpm_info
.iter()
.copied()
.map(aviutl2_sys::plugin2::BPM_INFO::from)
.collect::<Vec<_>>();
unsafe {
((*self.internal).set_grid_bpm_list)(
raw_bpm_info.as_mut_ptr(),
raw_bpm_info.len().try_into()?,
std::mem::size_of::<aviutl2_sys::plugin2::BPM_INFO>().try_into()?,
);
}
Ok(())
}
pub fn set_layer_name(&self, layer: usize, name: Option<&str>) -> EditSectionResult<()> {
match name {
None => {
unsafe { ((*self.internal).set_layer_name)(layer.try_into()?, std::ptr::null()) };
Ok(())
}
Some(name) => {
let c_name = crate::common::CWString::new(name)?;
unsafe {
((*self.internal).set_layer_name)(layer.try_into()?, c_name.as_ptr());
}
Ok(())
}
}
}
pub fn set_scene_name(&self, name: &str) -> EditSectionResult<()> {
let c_name = crate::common::CWString::new(name)?;
unsafe { ((*self.internal).set_scene_name)(c_name.as_ptr()) };
Ok(())
}
pub fn set_scene_size(&self, width: usize, height: usize) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_scene_size)(width.try_into()?, height.try_into()?);
}
Ok(())
}
pub fn set_scene_fps(&self, fps: Rational32) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_scene_frame_rate)(*fps.numer(), *fps.denom());
}
Ok(())
}
pub fn set_scene_sample_rate(&self, sample_rate: usize) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_scene_sample_rate)(sample_rate.try_into()?);
}
Ok(())
}
pub fn set_layer_enable(&self, layer: usize, enable: bool) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_layer_enable)(layer.try_into()?, enable);
}
Ok(())
}
pub fn set_layer_lock(&self, layer: usize, lock: bool) -> EditSectionResult<()> {
unsafe {
((*self.internal).set_layer_lock)(layer.try_into()?, lock);
}
Ok(())
}
pub fn set_effect_enable(&self, effect: EffectHandle, enable: bool) -> EditSectionResult<()> {
self.read_section.ensure_effect_exists(effect)?;
unsafe {
((*self.internal).set_effect_enable)(effect.internal, enable);
}
Ok(())
}
pub fn set_effect_lock(&self, effect: EffectHandle, lock: bool) -> EditSectionResult<()> {
self.read_section.ensure_effect_exists(effect)?;
unsafe {
((*self.internal).set_effect_lock)(effect.internal, lock);
}
Ok(())
}
pub fn set_effect_item_value(
&self,
effect: EffectHandle,
item: &str,
value: &str,
) -> EditSectionResult<()> {
self.read_section.ensure_effect_exists(effect)?;
let c_item = crate::common::CWString::new(item)?;
let c_value = std::ffi::CString::new(value)?;
let success = unsafe {
((*self.internal).set_effect_item_value)(
effect.internal,
c_item.as_ptr(),
c_value.as_ptr(),
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn set_mark_frame(&self, frame: usize, memo: &str) -> EditSectionResult<()> {
let c_memo = crate::common::CWString::new(memo)?;
unsafe {
((*self.internal).set_mark_frame)(
frame.try_into()?,
if memo.is_empty() {
std::ptr::null()
} else {
c_memo.as_ptr()
},
)
};
Ok(())
}
pub fn clear_mark_frame(&self, frame: usize) -> EditSectionResult<()> {
unsafe { ((*self.internal).clear_mark_frame)(frame.try_into()?) };
Ok(())
}
pub fn move_mark_frame(&self, old_frame: usize, new_frame: usize) -> EditSectionResult<()> {
let success = unsafe {
((*self.internal).move_mark_frame)(old_frame.try_into()?, new_frame.try_into()?)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn set_palette_info(&self, name: &str, palette: &PaletteInfo) -> EditSectionResult<()> {
let name = crate::common::CWString::new(name)?;
let mut raw_palette = palette.to_raw();
let success = unsafe {
((*self.internal).set_palette_info)(
name.as_ptr(),
&mut raw_palette as *mut aviutl2_sys::plugin2::PALETTE_INFO,
std::mem::size_of::<aviutl2_sys::plugin2::PALETTE_INFO>().try_into()?,
)
};
if !success {
return Err(EditSectionError::ApiCallFailed);
}
Ok(())
}
pub fn set_object_flag(
&self,
object: ObjectHandle,
flag: ObjectFlagType,
value: bool,
) -> EditSectionResult<()> {
self.read_section.ensure_object_exists(object)?;
unsafe { ((*self.internal).set_object_flag)(object.internal, flag.into(), value) };
Ok(())
}
pub fn set_edited_state(&self) -> EditSectionResult<()> {
unsafe { ((*self.internal).set_edited_state)() };
Ok(())
}
pub fn layers(&self) -> EditSectionLayersIterator<'_> {
EditSectionLayersIterator::new(self)
}
pub fn objects_in_layer(
&self,
layer: usize,
) -> EditSectionLayerObjectsIterator<'_, EditSection> {
EditSectionLayerObjectsIterator::new(self, layer)
}
pub fn layer<'a>(&'a self, layer: usize) -> EditSectionLayerCaller<'a, EditSection> {
EditSectionLayerCaller::new(self, layer)
}
pub fn object<'a>(&'a self, object: ObjectHandle) -> EditSectionObjectCaller<'a, EditSection> {
EditSectionObjectCaller::new(self, object)
}
pub fn effect<'a>(&'a self, effect: EffectHandle) -> EditSectionEffectCaller<'a, EditSection> {
EditSectionEffectCaller::new(self, effect)
}
}
mod sealed {
pub trait Sealed {}
impl Sealed for super::ReadSection {}
impl Sealed for super::EditSection {}
}
pub trait ReadSectionProvider: sealed::Sealed {
fn as_read_section(&self) -> &ReadSection;
}
impl ReadSectionProvider for ReadSection {
fn as_read_section(&self) -> &ReadSection {
self
}
}
impl ReadSectionProvider for EditSection {
fn as_read_section(&self) -> &ReadSection {
&self.read_section
}
}
pub struct EditSectionObjectCaller<'a, S: ReadSectionProvider> {
edit_section: &'a S,
pub handle: ObjectHandle,
}
impl<'a, S: ReadSectionProvider> EditSectionObjectCaller<'a, S> {
pub fn new(edit_section: &'a S, object: ObjectHandle) -> Self {
Self {
edit_section,
handle: object,
}
}
}
impl<S: ReadSectionProvider> std::ops::Deref for EditSectionObjectCaller<'_, S> {
type Target = ObjectHandle;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl<S> EditSectionObjectCaller<'_, S>
where
S: ReadSectionProvider,
{
fn read_section(&self) -> &ReadSection {
self.edit_section.as_read_section()
}
pub fn get_layer_frame(&self) -> EditSectionResult<ObjectLayerFrame> {
self.read_section().get_object_layer_frame(self.handle)
}
pub fn get_alias(&self) -> EditSectionResult<String> {
self.read_section().get_object_alias(self.handle)
}
#[cfg(feature = "aviutl2-alias")]
pub fn get_alias_parsed(&self) -> EditSectionResult<aviutl2_alias::Table> {
self.read_section()
.get_object_alias(self.handle)?
.parse()
.map_err(Into::into)
}
pub fn count_effect(&self, effect: &str) -> EditSectionResult<usize> {
self.read_section().count_object_effect(self.handle, effect)
}
pub fn find_effect(
&self,
effect_name: &str,
effect_index: usize,
) -> EditSectionResult<EffectHandle> {
self.read_section()
.find_effect(self.handle, effect_name, effect_index)
}
pub fn get_first_effect(&self) -> EditSectionResult<EffectHandle> {
self.read_section().get_first_effect(self.handle)
}
pub fn get_effects(&self) -> EditSectionResult<Vec<EffectHandle>> {
self.read_section().get_effects(self.handle)
}
pub fn get_effect_item(
&self,
effect_name: &str,
effect_index: usize,
item: &str,
) -> EditSectionResult<String> {
self.read_section()
.get_object_effect_item(self.handle, effect_name, effect_index, item)
}
#[cfg(feature = "aviutl2-alias")]
pub fn get_effect_item_parsed<T: aviutl2_alias::FromTableValue>(
&self,
effect_name: &str,
effect_index: usize,
item: &str,
) -> Result<T, EditSectionParsedError<<T as aviutl2_alias::FromTableValue>::Err>>
where
<T as aviutl2_alias::FromTableValue>::Err: std::error::Error + Sync + Send + 'static,
{
let value_str = self.get_effect_item(effect_name, effect_index, item)?;
T::from_table_value(&value_str).map_err(EditSectionParsedError::ParseError)
}
pub fn exists(&self) -> bool {
self.read_section().object_exists(self.handle)
}
pub fn get_name(&self) -> EditSectionResult<Option<String>> {
self.read_section().get_object_name(self.handle)
}
pub fn get_section_num(&self) -> EditSectionResult<usize> {
self.read_section().get_object_section_num(self.handle)
}
pub fn get_section_frame(&self, section: usize) -> EditSectionResult<usize> {
self.read_section()
.get_object_section_frame(self.handle, section)
}
pub fn get_section_frames(&self) -> EditSectionResult<Vec<usize>> {
self.read_section().get_object_section_frames(self.handle)
}
pub fn get_track_value(
&self,
effect_name: &str,
effect_index: usize,
item: &str,
frame: f64,
) -> EditSectionResult<f64> {
self.read_section().get_object_track_value(
self.handle,
effect_name,
effect_index,
item,
frame,
)
}
pub fn get_check_value(
&self,
effect_name: &str,
effect_index: usize,
item: &str,
frame: usize,
) -> EditSectionResult<bool> {
self.read_section().get_object_check_value(
self.handle,
effect_name,
effect_index,
item,
frame,
)
}
pub fn get_track_info(
&self,
effect_name: &str,
effect_index: usize,
item: &str,
) -> EditSectionResult<TrackInfo> {
self.read_section()
.get_object_track_info(self.handle, effect_name, effect_index, item)
}
pub fn get_track_group_names(
&self,
effect_name: &str,
effect_index: usize,
group_name: &str,
) -> EditSectionResult<Vec<String>> {
self.read_section().get_object_track_group_names(
self.handle,
effect_name,
effect_index,
group_name,
)
}
pub fn get_object_flag(&self, flag: ObjectFlagType) -> EditSectionResult<bool> {
self.read_section().get_object_flag(self.handle, flag)
}
pub fn get_object_id(&self) -> EditSectionResult<i64> {
self.read_section().get_object_id(self.handle)
}
}
impl EditSectionObjectCaller<'_, EditSection> {
pub fn create_effect(&self, effect: &str) -> EditSectionResult<EffectHandle> {
self.edit_section.create_effect(self.handle, effect)
}
pub fn delete_effect(&self, effect: EffectHandle) -> EditSectionResult<()> {
self.edit_section.delete_effect(self.handle, effect)
}
pub fn move_effect(&self, effect: EffectHandle, index: usize) -> EditSectionResult<usize> {
self.edit_section.move_effect(self.handle, effect, index)
}
pub fn create_section(&self, frame: usize) -> EditSectionResult<()> {
self.edit_section.create_object_section(self.handle, frame)
}
pub fn delete_section(&self, section: usize) -> EditSectionResult<()> {
self.edit_section
.delete_object_section(self.handle, section)
}
pub fn move_section(&self, section: usize, new_frame: usize) -> EditSectionResult<()> {
self.edit_section
.move_object_section(self.handle, section, new_frame)
}
pub fn set_effect_item(
&self,
effect_name: &str,
effect_index: usize,
item: &str,
value: &str,
) -> EditSectionResult<()> {
self.edit_section.set_object_effect_item(
self.handle,
effect_name,
effect_index,
item,
value,
)
}
pub fn move_object(&self, new_layer: usize, new_start_frame: usize) -> EditSectionResult<()> {
self.edit_section
.move_object(self.handle, new_layer, new_start_frame)
}
pub fn delete_object(&self) -> EditSectionResult<()> {
self.edit_section.delete_object(self.handle)
}
pub fn set_focus_object(&self) -> EditSectionResult<()> {
self.edit_section.set_focus_object(Some(self.handle))
}
pub fn set_name(&self, name: Option<&str>) -> EditSectionResult<()> {
self.edit_section.set_object_name(self.handle, name)
}
pub fn set_object_flag(&self, flag: ObjectFlagType, value: bool) -> EditSectionResult<()> {
self.edit_section.set_object_flag(self.handle, flag, value)
}
}
pub struct EditSectionEffectCaller<'a, S: ReadSectionProvider> {
edit_section: &'a S,
pub handle: EffectHandle,
}
impl<'a, S: ReadSectionProvider> EditSectionEffectCaller<'a, S> {
pub fn new(edit_section: &'a S, effect: EffectHandle) -> Self {
Self {
edit_section,
handle: effect,
}
}
}
impl<S: ReadSectionProvider> std::ops::Deref for EditSectionEffectCaller<'_, S> {
type Target = EffectHandle;
fn deref(&self) -> &Self::Target {
&self.handle
}
}
impl<S> EditSectionEffectCaller<'_, S>
where
S: ReadSectionProvider,
{
fn read_section(&self) -> &ReadSection {
self.edit_section.as_read_section()
}
pub fn exists(&self) -> bool {
self.read_section().effect_exists(self.handle)
}
pub fn get_name(&self) -> EditSectionResult<String> {
self.read_section().get_effect_name(self.handle)
}
pub fn get_enable(&self) -> EditSectionResult<bool> {
self.read_section().get_effect_enable(self.handle)
}
pub fn get_lock(&self) -> EditSectionResult<bool> {
self.read_section().get_effect_lock(self.handle)
}
pub fn get_item_value(&self, item: &str) -> EditSectionResult<String> {
self.read_section().get_effect_item_value(self.handle, item)
}
#[cfg(feature = "aviutl2-alias")]
pub fn get_item_value_parsed<T: aviutl2_alias::FromTableValue>(
&self,
item: &str,
) -> Result<T, EditSectionParsedError<<T as aviutl2_alias::FromTableValue>::Err>>
where
<T as aviutl2_alias::FromTableValue>::Err: std::error::Error + Sync + Send + 'static,
{
let value_str = self.get_item_value(item)?;
T::from_table_value(&value_str).map_err(EditSectionParsedError::ParseError)
}
pub fn get_data_size(&self, item: &str) -> EditSectionResult<usize> {
self.read_section().get_effect_data_size(self.handle, item)
}
pub fn get_data_value(&self, item: &str) -> EditSectionResult<Vec<u8>> {
self.read_section().get_effect_data_value(self.handle, item)
}
pub unsafe fn get_data_value_as<T>(&self, item: &str) -> EditSectionResult<T> {
unsafe {
self.read_section()
.get_effect_data_value_as(self.handle, item)
}
}
pub fn get_track_value(&self, item: &str, frame: f64) -> EditSectionResult<f64> {
self.read_section()
.get_effect_track_value(self.handle, item, frame)
}
pub fn get_check_value(&self, item: &str, frame: usize) -> EditSectionResult<bool> {
self.read_section()
.get_effect_check_value(self.handle, item, frame)
}
pub fn get_track_info(&self, item: &str) -> EditSectionResult<TrackInfo> {
self.read_section().get_effect_track_info(self.handle, item)
}
pub fn get_effect_id(&self) -> EditSectionResult<i64> {
self.read_section().get_effect_id(self.handle)
}
}
impl EditSectionEffectCaller<'_, EditSection> {
pub fn set_enable(&self, enable: bool) -> EditSectionResult<()> {
self.edit_section.set_effect_enable(self.handle, enable)
}
pub fn set_lock(&self, lock: bool) -> EditSectionResult<()> {
self.edit_section.set_effect_lock(self.handle, lock)
}
pub fn set_item_value(&self, item: &str, value: &str) -> EditSectionResult<()> {
self.edit_section
.set_effect_item_value(self.handle, item, value)
}
pub fn set_data_value(&self, item: &str, data: &[u8]) -> EditSectionResult<()> {
self.edit_section
.set_effect_data_value(self.handle, item, data)
}
pub fn set_data_value_with<T>(&self, item: &str, data: &T) -> EditSectionResult<()> {
self.edit_section
.set_effect_data_value_with(self.handle, item, data)
}
}
pub struct EditSectionLayerCaller<'a, S> {
edit_section: &'a S,
pub index: usize,
}
impl<'a, S> EditSectionLayerCaller<'a, S> {
pub fn new(edit_section: &'a S, layer: usize) -> Self {
Self {
edit_section,
index: layer,
}
}
}
impl<S> EditSectionLayerCaller<'_, S>
where
S: ReadSectionProvider,
{
fn read_section(&self) -> &ReadSection {
self.edit_section.as_read_section()
}
pub fn find_object_after(&self, frame: usize) -> EditSectionResult<Option<ObjectHandle>> {
self.read_section().find_object_after(self.index, frame)
}
pub fn get_name(&self) -> EditSectionResult<Option<String>> {
self.read_section().get_layer_name(self.index)
}
pub fn get_enable(&self) -> EditSectionResult<bool> {
self.read_section().get_layer_enable(self.index)
}
pub fn get_lock(&self) -> EditSectionResult<bool> {
self.read_section().get_layer_lock(self.index)
}
pub fn objects(&self) -> EditSectionLayerObjectsIterator<'_, S> {
EditSectionLayerObjectsIterator::new(self.edit_section, self.index)
}
}
impl EditSectionLayerCaller<'_, EditSection> {
pub fn create_object_from_alias<P: AsRef<std::path::Path>>(
&self,
alias: &str,
frame: usize,
length: usize,
) -> EditSectionResult<ObjectHandle> {
self.edit_section
.create_object_from_alias(alias, self.index, frame, length)
}
pub fn create_object_from_media_file<P: AsRef<std::path::Path>>(
&self,
file_path: P,
frame: usize,
length: Option<usize>,
) -> EditSectionResult<ObjectHandle> {
self.edit_section
.create_object_from_media_file(file_path, self.index, frame, length)
}
pub fn create_object(
&self,
effect: &str,
frame: usize,
length: Option<usize>,
) -> EditSectionResult<ObjectHandle> {
self.edit_section
.create_object(effect, self.index, frame, length)
}
pub fn set_name(&self, name: Option<&str>) -> EditSectionResult<()> {
self.edit_section.set_layer_name(self.index, name)
}
pub fn set_enable(&self, enable: bool) -> EditSectionResult<()> {
self.edit_section.set_layer_enable(self.index, enable)
}
pub fn set_lock(&self, lock: bool) -> EditSectionResult<()> {
self.edit_section.set_layer_lock(self.index, lock)
}
}
#[derive(Debug, Clone)]
pub struct EditSectionLayersIterator<'a> {
edit_section: &'a EditSection,
current: usize,
end: usize,
}
impl<'a> EditSectionLayersIterator<'a> {
fn new(edit_section: &'a EditSection) -> Self {
Self {
edit_section,
current: 0,
end: edit_section.info.layer_max.saturating_add(1),
}
}
}
impl<'a> Iterator for EditSectionLayersIterator<'a> {
type Item = EditSectionLayerCaller<'a, EditSection>;
fn next(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
return None;
}
let layer = self.current;
self.current += 1;
Some(EditSectionLayerCaller::new(self.edit_section, layer))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.end.saturating_sub(self.current);
(len, Some(len))
}
}
impl<'a> DoubleEndedIterator for EditSectionLayersIterator<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
if self.current >= self.end {
return None;
}
self.end -= 1;
Some(EditSectionLayerCaller::new(self.edit_section, self.end))
}
}
impl ExactSizeIterator for EditSectionLayersIterator<'_> {}
#[derive(Debug, Clone)]
pub struct EditSectionLayerObjectsIterator<'a, S> {
edit_section: &'a S,
layer: usize,
next_frame: usize,
}
impl<'a, S> EditSectionLayerObjectsIterator<'a, S> {
fn new(edit_section: &'a S, layer: usize) -> Self {
Self {
edit_section,
layer,
next_frame: 0,
}
}
}
impl<S> Iterator for EditSectionLayerObjectsIterator<'_, S>
where
S: ReadSectionProvider,
{
type Item = (ObjectLayerFrame, ObjectHandle);
fn next(&mut self) -> Option<Self::Item> {
let read_section = self.edit_section.as_read_section();
let Ok(Some(handle)) = read_section.find_object_after(self.layer, self.next_frame) else {
return None;
};
let lf = match read_section.get_object_layer_frame(handle) {
Ok(lf) => lf,
Err(_) => return None,
};
self.next_frame = lf.end.saturating_add(1);
Some((lf, handle))
}
}
fn effect_key(effect_name: &str, effect_index: usize) -> String {
format!("{effect_name}:{effect_index}")
}