1use crate::common::LeakManager;
2
3pub trait FilterConfigItems: Sized {
18 fn to_config_items() -> Vec<FilterConfigItem>;
20
21 fn from_config_items(items: &[FilterConfigItem]) -> Self;
27}
28#[doc(inline)]
29pub use aviutl2_macros::FilterConfigItems;
30
31pub trait FilterConfigItemSliceExt {
33 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#[derive(Debug, Clone)]
45pub enum FilterConfigItem {
46 Track(FilterConfigTrack),
48 Checkbox(FilterConfigCheckbox),
50 Color(FilterConfigColor),
52 Select(FilterConfigSelect),
54 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 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 }); 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 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 *(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 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 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#[derive(Debug, Clone)]
235pub struct FilterConfigTrack {
236 pub name: String,
238
239 pub value: f64,
241
242 pub range: std::ops::RangeInclusive<f64>,
244
245 pub step: FilterConfigTrackStep,
247}
248
249#[derive(Clone, Copy)]
251pub enum FilterConfigTrackStep {
252 One,
254 PointOne,
256 PointZeroOne,
258 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#[derive(Debug, Clone)]
294pub struct FilterConfigCheckbox {
295 pub name: String,
297
298 pub value: bool,
300}
301
302#[derive(Debug, Clone)]
304pub struct FilterConfigColor {
305 pub name: String,
307 pub value: FilterConfigColorValue,
309}
310
311#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
313pub struct FilterConfigColorValue(pub u32);
314impl FilterConfigColorValue {
315 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 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#[derive(Debug, Clone)]
368pub struct FilterConfigSelect {
369 pub name: String,
371 pub value: i32,
373 pub items: Vec<FilterConfigSelectItem>,
375}
376
377#[derive(Debug, Clone)]
379pub struct FilterConfigSelectItem {
380 pub name: String,
382 pub value: i32,
384}
385
386pub trait FilterConfigSelectItems {
402 fn to_select_items() -> Vec<FilterConfigSelectItem>;
404
405 fn from_select_item_value(item: i32) -> Self;
411
412 fn to_select_item_value(&self) -> i32;
414}
415
416#[doc(inline)]
417pub use aviutl2_macros::FilterConfigSelectItems;
418
419#[derive(Debug, Clone)]
421pub struct FilterConfigFile {
422 pub name: String,
424 pub value: String,
426 pub filters: Vec<crate::common::FileFilter>,
428}