aviutl2\filter/
config.rs

1use crate::common::LeakManager;
2
3/// [`Vec<FilterConfigItem>`] と相互変換するためのトレイト。
4/// 基本的にはこのトレイトを手動で実装する必要はありません。
5/// [`derive@FilterConfigItems`] マクロを使用してください。
6///
7/// <div class="warning">
8///
9/// このcrateは[`Vec<FilterConfigItem>`]との相互変換が可能であれば十分に機能します。
10/// このトレイトを手動で実装する必要はありません。
11///
12/// </div>
13///
14/// # See Also
15///
16/// [derive@FilterConfigItems]
17pub trait FilterConfigItems: Sized {
18    /// [`Vec<FilterConfigItem>`] に変換します。
19    fn to_config_items() -> Vec<FilterConfigItem>;
20
21    /// [`Vec<FilterConfigItem>`] から変換します。
22    ///
23    /// # Panics
24    ///
25    /// `items` の内容が不正な場合、パニックします。
26    fn from_config_items(items: &[FilterConfigItem]) -> Self;
27}
28#[doc(inline)]
29pub use aviutl2_macros::FilterConfigItems;
30
31/// `&[FilterConfigItem]` に対する拡張トレイト。
32pub trait FilterConfigItemSliceExt {
33    /// `&[FilterConfigItem]` から指定した構造体に変換します。
34    fn to_struct<T: FilterConfigItems>(&self) -> T;
35}
36
37impl FilterConfigItemSliceExt for &[FilterConfigItem] {
38    fn to_struct<T: FilterConfigItems>(&self) -> T {
39        T::from_config_items(self)
40    }
41}
42
43/// フィルタの設定。
44#[derive(Debug, Clone)]
45pub enum FilterConfigItem {
46    /// トラックバー。
47    Track(FilterConfigTrack),
48    /// チェックボックス。
49    Checkbox(FilterConfigCheckbox),
50    /// 色選択。
51    Color(FilterConfigColor),
52    /// 選択リスト。
53    Select(FilterConfigSelect),
54    /// ファイル選択。
55    File(FilterConfigFile),
56}
57
58#[derive(Debug, Clone, PartialEq)]
59pub(crate) enum FilterConfigItemValue {
60    Track(f64),
61    Checkbox(bool),
62    Color(FilterConfigColorValue),
63    Select(i32),
64    File(String),
65}
66
67impl FilterConfigItem {
68    /// 設定名を取得します。
69    pub fn name(&self) -> &str {
70        match self {
71            FilterConfigItem::Track(item) => &item.name,
72            FilterConfigItem::Checkbox(item) => &item.name,
73            FilterConfigItem::Color(item) => &item.name,
74            FilterConfigItem::Select(item) => &item.name,
75            FilterConfigItem::File(item) => &item.name,
76        }
77    }
78
79    pub(crate) fn to_raw(&self, leak_manager: &LeakManager) -> aviutl2_sys::filter2::FILTER_ITEM {
80        match self {
81            FilterConfigItem::Track(item) => {
82                let step: f64 = item.step.into();
83                aviutl2_sys::filter2::FILTER_ITEM {
84                    track: aviutl2_sys::filter2::FILTER_ITEM_TRACK {
85                        r#type: leak_manager.leak_as_wide_string("track"),
86                        name: leak_manager.leak_as_wide_string(&item.name),
87                        value: item.value,
88                        s: *item.range.start(),
89                        e: *item.range.end(),
90                        step,
91                    },
92                }
93            }
94            FilterConfigItem::Checkbox(item) => aviutl2_sys::filter2::FILTER_ITEM {
95                checkbox: aviutl2_sys::filter2::FILTER_ITEM_CHECKBOX {
96                    r#type: leak_manager.leak_as_wide_string("check"),
97                    name: leak_manager.leak_as_wide_string(&item.name),
98                    value: item.value,
99                },
100            },
101            FilterConfigItem::Color(item) => aviutl2_sys::filter2::FILTER_ITEM {
102                color: aviutl2_sys::filter2::FILTER_ITEM_COLOR {
103                    r#type: leak_manager.leak_as_wide_string("color"),
104                    name: leak_manager.leak_as_wide_string(&item.name),
105                    value: item.value.into(),
106                },
107            },
108            FilterConfigItem::Select(item) => {
109                let mut raw_items: Vec<aviutl2_sys::filter2::FILTER_ITEM_SELECT_ITEM> = item
110                    .items
111                    .iter()
112                    .map(|i| aviutl2_sys::filter2::FILTER_ITEM_SELECT_ITEM {
113                        name: leak_manager.leak_as_wide_string(&i.name),
114                        value: i.value,
115                    })
116                    .collect();
117                raw_items.push(aviutl2_sys::filter2::FILTER_ITEM_SELECT_ITEM {
118                    name: std::ptr::null(),
119                    value: 0,
120                }); // 終端用
121                let raw_items_ptrs = leak_manager.leak_value_vec(raw_items);
122                aviutl2_sys::filter2::FILTER_ITEM {
123                    select: aviutl2_sys::filter2::FILTER_ITEM_SELECT {
124                        r#type: leak_manager.leak_as_wide_string("select"),
125                        name: leak_manager.leak_as_wide_string(&item.name),
126                        value: item.value,
127                        items: raw_items_ptrs,
128                    },
129                }
130            }
131            FilterConfigItem::File(item) => {
132                let raw_filters = crate::common::format_file_filters(&item.filters);
133                aviutl2_sys::filter2::FILTER_ITEM {
134                    file: aviutl2_sys::filter2::FILTER_ITEM_FILE {
135                        r#type: leak_manager.leak_as_wide_string("file"),
136                        name: leak_manager.leak_as_wide_string(&item.name),
137                        value: leak_manager.leak_as_wide_string(&item.value),
138                        filefilter: leak_manager.leak_as_wide_string(&raw_filters),
139                    },
140                }
141            }
142        }
143    }
144
145    /// # Safety
146    ///
147    /// `raw` は有効なポインタである必要があります。
148    pub(crate) unsafe fn get_value(
149        raw: *const aviutl2_sys::filter2::FILTER_ITEM,
150    ) -> FilterConfigItemValue {
151        let item_type = unsafe {
152            crate::common::load_wide_string(
153                // SAFETY: aviutl2_sys::filter2::FILTER_ITEM の最初のメンバーはLPCWSTRなので問題ないはず
154                *(raw as *const aviutl2_sys::common::LPCWSTR),
155            )
156        };
157        match item_type.as_str() {
158            "track" => {
159                let raw_track = unsafe { &(*raw).track };
160                FilterConfigItemValue::Track(raw_track.value)
161            }
162            "check" => {
163                let raw_checkbox = unsafe { &(*raw).checkbox };
164                FilterConfigItemValue::Checkbox(raw_checkbox.value)
165            }
166            "color" => {
167                let raw_color = unsafe { &(*raw).color };
168                FilterConfigItemValue::Color(raw_color.value.into())
169            }
170            "select" => {
171                let raw_select = unsafe { &(*raw).select };
172                FilterConfigItemValue::Select(raw_select.value)
173            }
174            "file" => {
175                let raw_file = unsafe { &(*raw).file };
176                let value = unsafe { crate::common::load_wide_string(raw_file.value) };
177                FilterConfigItemValue::File(value)
178            }
179            _ => panic!("Unknown filter config item type: {}", item_type),
180        }
181    }
182
183    /// # Safety
184    ///
185    /// `raw` は有効なポインタである必要があります。
186    pub(crate) unsafe fn should_apply_from_raw(
187        &self,
188        raw: *const aviutl2_sys::filter2::FILTER_ITEM,
189    ) -> bool {
190        let value = unsafe { Self::get_value(raw) };
191        match (self, value) {
192            (FilterConfigItem::Track(item), FilterConfigItemValue::Track(v)) => item.value != v,
193            (FilterConfigItem::Checkbox(item), FilterConfigItemValue::Checkbox(v)) => {
194                item.value != v
195            }
196            (FilterConfigItem::Color(item), FilterConfigItemValue::Color(v)) => item.value != v,
197            (FilterConfigItem::Select(item), FilterConfigItemValue::Select(v)) => item.value != v,
198            (FilterConfigItem::File(item), FilterConfigItemValue::File(v)) => item.value != v,
199            _ => {
200                panic!("Mismatched filter config item type");
201            }
202        }
203    }
204
205    /// # Safety
206    ///
207    /// `raw` は有効なポインタである必要があります。
208    pub(crate) unsafe fn apply_from_raw(&mut self, raw: *const aviutl2_sys::filter2::FILTER_ITEM) {
209        let value = unsafe { Self::get_value(raw) };
210        match (self, value) {
211            (FilterConfigItem::Track(item), FilterConfigItemValue::Track(v)) => {
212                item.value = v;
213            }
214            (FilterConfigItem::Checkbox(item), FilterConfigItemValue::Checkbox(v)) => {
215                item.value = v;
216            }
217            (FilterConfigItem::Color(item), FilterConfigItemValue::Color(v)) => {
218                item.value = v;
219            }
220            (FilterConfigItem::Select(item), FilterConfigItemValue::Select(v)) => {
221                item.value = v;
222            }
223            (FilterConfigItem::File(item), FilterConfigItemValue::File(v)) => {
224                item.value = v;
225            }
226            _ => {
227                panic!("Mismatched filter config item type");
228            }
229        }
230    }
231}
232
233/// トラックバー。
234#[derive(Debug, Clone)]
235pub struct FilterConfigTrack {
236    /// 設定名。
237    pub name: String,
238
239    /// 設定値。
240    pub value: f64,
241
242    /// 設定値の範囲。
243    pub range: std::ops::RangeInclusive<f64>,
244
245    /// 設定値の単位。
246    pub step: FilterConfigTrackStep,
247}
248
249/// トラックバーの設定値の単位。
250#[derive(Clone, Copy)]
251pub enum FilterConfigTrackStep {
252    /// 1.0
253    One,
254    /// 0.1
255    PointOne,
256    /// 0.01
257    PointZeroOne,
258    /// 0.001
259    PointZeroZeroOne,
260}
261impl TryFrom<f64> for FilterConfigTrackStep {
262    type Error = anyhow::Error;
263    fn try_from(value: f64) -> Result<Self, Self::Error> {
264        match value {
265            1.0 => Ok(FilterConfigTrackStep::One),
266            0.1 => Ok(FilterConfigTrackStep::PointOne),
267            0.01 => Ok(FilterConfigTrackStep::PointZeroOne),
268            0.001 => Ok(FilterConfigTrackStep::PointZeroZeroOne),
269            _ => Err(anyhow::anyhow!("Invalid step value: {}", value)),
270        }
271    }
272}
273impl From<FilterConfigTrackStep> for f64 {
274    fn from(value: FilterConfigTrackStep) -> Self {
275        match value {
276            FilterConfigTrackStep::One => 1.0,
277            FilterConfigTrackStep::PointOne => 0.1,
278            FilterConfigTrackStep::PointZeroOne => 0.01,
279            FilterConfigTrackStep::PointZeroZeroOne => 0.001,
280        }
281    }
282}
283impl std::fmt::Debug for FilterConfigTrackStep {
284    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285        let value: f64 = (*self).into();
286        f.debug_tuple("FilterConfigTrackStep")
287            .field(&value)
288            .finish()
289    }
290}
291
292/// チェックボックス。
293#[derive(Debug, Clone)]
294pub struct FilterConfigCheckbox {
295    /// 設定名。
296    pub name: String,
297
298    /// 設定値。
299    pub value: bool,
300}
301
302/// 色選択。
303#[derive(Debug, Clone)]
304pub struct FilterConfigColor {
305    /// 設定名。
306    pub name: String,
307    /// 設定値。
308    pub value: FilterConfigColorValue,
309}
310
311/// 色選択の設定値の色。
312#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
313pub struct FilterConfigColorValue(pub u32);
314impl FilterConfigColorValue {
315    /// 色をRGB形式の各成分に分解して取得します。
316    pub fn to_rgb(&self) -> (u8, u8, u8) {
317        let r = ((self.0 >> 16) & 0xFF) as u8;
318        let g = ((self.0 >> 8) & 0xFF) as u8;
319        let b = (self.0 & 0xFF) as u8;
320        (r, g, b)
321    }
322
323    /// RGB形式の各成分から色を作成します。
324    pub fn from_rgb(r: u8, g: u8, b: u8) -> Self {
325        let value = (r as u32) << 16 | (g as u32) << 8 | (b as u32);
326        FilterConfigColorValue(value)
327    }
328}
329impl From<u32> for FilterConfigColorValue {
330    fn from(value: u32) -> Self {
331        FilterConfigColorValue(value)
332    }
333}
334impl From<FilterConfigColorValue> for u32 {
335    fn from(value: FilterConfigColorValue) -> Self {
336        value.0
337    }
338}
339impl From<aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE> for FilterConfigColorValue {
340    fn from(value: aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE) -> Self {
341        unsafe { FilterConfigColorValue(value.code) }
342    }
343}
344impl From<FilterConfigColorValue> for aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE {
345    fn from(value: FilterConfigColorValue) -> Self {
346        aviutl2_sys::filter2::FILTER_ITEM_COLOR_VALUE { code: value.0 }
347    }
348}
349impl std::fmt::Display for FilterConfigColorValue {
350    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
351        let (r, g, b) = self.to_rgb();
352        write!(f, "#{:02X}{:02X}{:02X}", r, g, b)
353    }
354}
355impl std::fmt::LowerHex for FilterConfigColorValue {
356    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
357        write!(f, "{:06x}", self.0 & 0xFFFFFF)
358    }
359}
360impl std::fmt::UpperHex for FilterConfigColorValue {
361    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
362        write!(f, "{:06X}", self.0 & 0xFFFFFF)
363    }
364}
365
366/// 選択リスト。
367#[derive(Debug, Clone)]
368pub struct FilterConfigSelect {
369    /// 設定名。
370    pub name: String,
371    /// 設定値。
372    pub value: i32,
373    /// 選択肢リスト。
374    pub items: Vec<FilterConfigSelectItem>,
375}
376
377/// 選択リストの選択肢。
378#[derive(Debug, Clone)]
379pub struct FilterConfigSelectItem {
380    /// 選択肢の名前。
381    pub name: String,
382    /// 選択肢の値。
383    pub value: i32,
384}
385
386/// `[Vec<FilterConfigSelectItem>]`に変換したり、AviUtl2側の値から変換するためのトレイト。
387///
388/// 基本的にはこのトレイトを手動で実装する必要はありません。
389/// [`derive@FilterConfigSelectItems`] マクロを使用してください。
390///
391/// <div class="warning">
392///
393/// [`FilterConfigSelect`]は[`Vec<FilterConfigSelectItems>`]との相互変換が可能であれば十分に機能します。
394/// このトレイトを手動で実装する必要はありません。
395///
396/// </div>
397///
398/// # See Also
399///
400/// [derive@FilterConfigSelectItems]
401pub trait FilterConfigSelectItems {
402    /// [`Vec<FilterConfigSelectItem>`] に変換します。
403    fn to_select_items() -> Vec<FilterConfigSelectItem>;
404
405    /// [`i32`] から変換します。
406    ///
407    /// # Panics
408    ///
409    /// `item` の内容が不正な場合、パニックします。
410    fn from_select_item_value(item: i32) -> Self;
411
412    /// [`i32`] へ変換します。
413    fn to_select_item_value(&self) -> i32;
414}
415
416#[doc(inline)]
417pub use aviutl2_macros::FilterConfigSelectItems;
418
419/// ファイル選択。
420#[derive(Debug, Clone)]
421pub struct FilterConfigFile {
422    /// 設定名。
423    pub name: String,
424    /// 設定値。
425    pub value: String,
426    /// ファイルフィルタ。
427    pub filters: Vec<crate::common::FileFilter>,
428}