fyrox_ui/file_browser/
filter.rs1use crate::core::{reflect::prelude::*, visitor::prelude::*};
22use std::fmt::Display;
23use std::ops::Index;
24use std::path::PathBuf;
25use std::{
26 fmt::{Debug, Formatter},
27 path::Path,
28};
29
30#[derive(Default, Clone, Debug, Visit, Reflect, PartialEq)]
31pub struct FileType {
32 pub description: String,
33 pub extension: String,
34}
35
36impl FileType {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn new_extension(extension: impl AsRef<str>) -> Self {
42 Self {
43 description: Default::default(),
44 extension: extension.as_ref().to_string(),
45 }
46 }
47
48 pub fn with_description(mut self, description: impl AsRef<str>) -> Self {
49 self.description = description.as_ref().to_string();
50 self
51 }
52
53 pub fn with_extension(mut self, extension: impl AsRef<str>) -> Self {
54 self.extension = extension.as_ref().to_string();
55 self
56 }
57
58 pub fn matches(&self, path: &Path) -> bool {
59 path.extension()
60 .is_some_and(|ext| ext.to_string_lossy() == self.extension)
61 }
62
63 pub fn make_file_name(&self, name: &str) -> PathBuf {
64 let mut file_name = PathBuf::from(name);
65 file_name.set_extension(&self.extension);
66 file_name
67 }
68}
69
70impl Display for FileType {
71 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
72 write!(f, "{} (*.{})", self.description, self.extension)
73 }
74}
75
76#[derive(Default, Clone, Debug, Visit, Reflect, PartialEq)]
77pub struct PathFilter {
78 pub folders_only: bool,
79 pub types: Vec<FileType>,
80}
81
82impl Index<usize> for PathFilter {
83 type Output = FileType;
84
85 fn index(&self, index: usize) -> &Self::Output {
86 self.types.index(index)
87 }
88}
89
90impl PathFilter {
91 pub fn new() -> Self {
92 Self::default()
93 }
94
95 pub fn with_file_type(mut self, file_type: FileType) -> Self {
96 self.types.push(file_type);
97 self
98 }
99
100 pub fn folder() -> Self {
101 Self {
102 folders_only: true,
103 types: Default::default(),
104 }
105 }
106
107 pub fn supports_all(&self, path: &Path) -> bool {
108 if self.folders_only {
109 path.is_dir()
110 } else {
111 path.is_dir()
112 || self.is_empty()
113 || self.types.iter().any(|file_type| file_type.matches(path))
114 }
115 }
116
117 pub fn supports_specific_type(&self, path: &Path, index: Option<usize>) -> bool {
118 if self.folders_only {
119 path.is_dir()
120 } else if let Some(index) = index {
121 self.types
122 .get(index)
123 .is_some_and(|file_type| file_type.matches(path))
124 } else {
125 self.is_empty() || self.types.iter().any(|file_type| file_type.matches(path))
126 }
127 }
128
129 pub fn len(&self) -> usize {
130 self.types.len()
131 }
132
133 pub fn is_empty(&self) -> bool {
134 self.types.is_empty()
135 }
136
137 pub fn iter(&self) -> impl Iterator<Item = &FileType> {
138 self.types.iter()
139 }
140
141 pub fn get(&self, i: usize) -> Option<&FileType> {
142 self.types.get(i)
143 }
144}