dear_imgui_rs/text_filter.rs
1//! Text filtering functionality for Dear ImGui
2//!
3//! This module provides a text filter system that allows users to filter content
4//! based on text patterns. The filter supports include/exclude syntax similar to
5//! many search interfaces.
6//!
7//! # Basic Usage
8//!
9//! ```no_run
10//! # use dear_imgui_rs::*;
11//! # let mut ctx = Context::create();
12//! # let ui = ctx.frame();
13//! let mut filter = TextFilter::new("Search".to_string());
14//!
15//! // Draw the filter input
16//! filter.draw();
17//!
18//! // Test if text passes the filter
19//! if filter.pass_filter("some text") {
20//! // Display matching content
21//! }
22//! ```
23//!
24//! # Filter Syntax
25//!
26//! The filter supports the following syntax:
27//! - `word` - Include items containing "word"
28//! - `-word` - Exclude items containing "word"
29//! - `word1,word2` - Include items containing "word1" OR "word2"
30//! - `word1,-word2` - Include items containing "word1" but NOT "word2"
31
32use crate::{Ui, sys};
33use std::ptr;
34
35/// Helper to parse and apply text filters
36///
37/// This struct provides text filtering functionality similar to many search interfaces.
38/// It supports include/exclude patterns and can be used to filter lists of items.
39///
40/// # Examples
41///
42/// ```no_run
43/// # use dear_imgui_rs::*;
44/// # let mut ctx = Context::create();
45/// # let ui = ctx.frame();
46/// // Create a filter with default empty pattern
47/// let mut filter = TextFilter::new("Search".to_string());
48///
49/// // Create a filter with initial pattern
50/// let mut filter_with_pattern = TextFilter::new_with_filter(
51/// "Advanced Search".to_string(),
52/// "include,-exclude".to_string()
53/// );
54/// ```
55pub struct TextFilter {
56 id: String,
57 raw: *mut sys::ImGuiTextFilter,
58}
59
60impl TextFilter {
61 /// Creates a new TextFilter with an empty filter.
62 ///
63 /// This is equivalent to [`new_with_filter`](Self::new_with_filter) with `filter` set to `""`.
64 ///
65 /// # Arguments
66 /// * `label` - The label to display for the filter input
67 ///
68 /// # Examples
69 ///
70 /// ```no_run
71 /// # use dear_imgui_rs::*;
72 /// let filter = TextFilter::new("Search".to_string());
73 /// ```
74 pub fn new(label: String) -> Self {
75 Self::new_with_filter(label, String::new())
76 }
77
78 /// Creates a new TextFilter with a custom filter pattern.
79 ///
80 /// # Arguments
81 /// * `label` - The label to display for the filter input
82 /// * `filter` - The initial filter pattern
83 ///
84 /// # Examples
85 ///
86 /// ```no_run
87 /// # use dear_imgui_rs::*;
88 /// let filter = TextFilter::new_with_filter(
89 /// "Search".to_string(),
90 /// "include,-exclude".to_string()
91 /// );
92 /// ```
93 pub fn new_with_filter(label: String, filter: String) -> Self {
94 let filter_cstr = format!("{}\0", filter);
95 unsafe {
96 let raw = sys::ImGuiTextFilter_ImGuiTextFilter(
97 filter_cstr.as_ptr() as *const std::os::raw::c_char
98 );
99 Self { id: label, raw }
100 }
101 }
102
103 /// Builds the TextFilter with its current filter pattern.
104 ///
105 /// You can use [`pass_filter`](Self::pass_filter) after calling this method.
106 /// If you want to control the filter with an InputText, use [`draw`](Self::draw) instead.
107 ///
108 /// # Examples
109 ///
110 /// ```no_run
111 /// # use dear_imgui_rs::*;
112 /// let mut filter = TextFilter::new_with_filter(
113 /// "Search".to_string(),
114 /// "test".to_string()
115 /// );
116 /// filter.build();
117 ///
118 /// if filter.pass_filter("test string") {
119 /// println!("Text matches filter!");
120 /// }
121 /// ```
122 pub fn build(&mut self) {
123 unsafe {
124 sys::ImGuiTextFilter_Build(self.raw);
125 }
126 }
127
128 /// Draws an InputText widget to control the filter.
129 ///
130 /// This is equivalent to [`draw_with_size`](Self::draw_with_size) with `size` set to `0.0`.
131 /// Returns `true` if the filter was modified.
132 ///
133 /// # Examples
134 ///
135 /// ```no_run
136 /// # use dear_imgui_rs::*;
137 /// # let mut ctx = Context::create();
138 /// # let ui = ctx.frame();
139 /// let mut filter = TextFilter::new("Search".to_string());
140 ///
141 /// if filter.draw() {
142 /// println!("Filter was modified!");
143 /// }
144 /// ```
145 pub fn draw(&mut self) -> bool {
146 self.draw_with_size(0.0)
147 }
148
149 /// Draws an InputText widget to control the filter with a specific width.
150 ///
151 /// # Arguments
152 /// * `width` - The width of the input text widget (0.0 for default width)
153 ///
154 /// Returns `true` if the filter was modified.
155 ///
156 /// # Examples
157 ///
158 /// ```no_run
159 /// # use dear_imgui_rs::*;
160 /// # let mut ctx = Context::create();
161 /// # let ui = ctx.frame();
162 /// let mut filter = TextFilter::new("Search".to_string());
163 ///
164 /// if filter.draw_with_size(200.0) {
165 /// println!("Filter was modified!");
166 /// }
167 /// ```
168 pub fn draw_with_size(&mut self, width: f32) -> bool {
169 let label_cstr = format!("{}\0", self.id);
170 unsafe {
171 sys::ImGuiTextFilter_Draw(
172 self.raw,
173 label_cstr.as_ptr() as *const std::os::raw::c_char,
174 width,
175 )
176 }
177 }
178
179 /// Returns true if the filter is not empty.
180 ///
181 /// An empty filter (no pattern specified) will match all text.
182 ///
183 /// # Examples
184 ///
185 /// ```no_run
186 /// # use dear_imgui_rs::*;
187 /// let empty_filter = TextFilter::new("Search".to_string());
188 /// assert!(!empty_filter.is_active());
189 ///
190 /// let active_filter = TextFilter::new_with_filter(
191 /// "Search".to_string(),
192 /// "test".to_string()
193 /// );
194 /// assert!(active_filter.is_active());
195 /// ```
196 pub fn is_active(&self) -> bool {
197 // IsActive() is an inline method: return !Filters.empty();
198 // We need to check if the Filters vector is empty
199 unsafe { (*self.raw).Filters.Size > 0 }
200 }
201
202 /// Returns true if the text matches the filter.
203 ///
204 /// [`draw`](Self::draw) or [`build`](Self::build) must be called **before** this function.
205 ///
206 /// # Arguments
207 /// * `text` - The text to test against the filter
208 ///
209 /// # Examples
210 ///
211 /// ```no_run
212 /// # use dear_imgui_rs::*;
213 /// let mut filter = TextFilter::new_with_filter(
214 /// "Search".to_string(),
215 /// "test".to_string()
216 /// );
217 /// filter.build();
218 ///
219 /// assert!(filter.pass_filter("test string"));
220 /// assert!(!filter.pass_filter("example string"));
221 /// ```
222 pub fn pass_filter(&self, text: &str) -> bool {
223 let text_cstr = format!("{}\0", text);
224 unsafe {
225 sys::ImGuiTextFilter_PassFilter(
226 self.raw,
227 text_cstr.as_ptr() as *const std::os::raw::c_char,
228 ptr::null(),
229 )
230 }
231 }
232
233 /// Returns true if the text range matches the filter.
234 ///
235 /// This version allows you to specify both start and end pointers for the text.
236 ///
237 /// # Arguments
238 /// * `start` - The start of the text to test
239 /// * `end` - The end of the text to test
240 ///
241 /// # Examples
242 ///
243 /// ```no_run
244 /// # use dear_imgui_rs::*;
245 /// let mut filter = TextFilter::new_with_filter(
246 /// "Search".to_string(),
247 /// "test".to_string()
248 /// );
249 /// filter.build();
250 ///
251 /// assert!(filter.pass_filter_with_end("test", " string"));
252 /// ```
253 pub fn pass_filter_with_end(&self, start: &str, end: &str) -> bool {
254 let start_cstr = format!("{}\0", start);
255 let end_cstr = format!("{}\0", end);
256 unsafe {
257 sys::ImGuiTextFilter_PassFilter(
258 self.raw,
259 start_cstr.as_ptr() as *const std::os::raw::c_char,
260 end_cstr.as_ptr() as *const std::os::raw::c_char,
261 )
262 }
263 }
264
265 /// Clears the filter pattern.
266 ///
267 /// This sets the filter to an empty state, which will match all text.
268 ///
269 /// # Examples
270 ///
271 /// ```no_run
272 /// # use dear_imgui_rs::*;
273 /// let mut filter = TextFilter::new_with_filter(
274 /// "Search".to_string(),
275 /// "test".to_string()
276 /// );
277 ///
278 /// assert!(filter.is_active());
279 /// filter.clear();
280 /// assert!(!filter.is_active());
281 /// ```
282 pub fn clear(&mut self) {
283 // Clear() is an inline method: InputBuf[0] = 0; Build();
284 unsafe {
285 (*self.raw).InputBuf[0] = 0;
286 sys::ImGuiTextFilter_Build(self.raw);
287 }
288 }
289}
290
291impl Ui {
292 /// Creates a new TextFilter with an empty pattern.
293 ///
294 /// This is a convenience method equivalent to [`TextFilter::new`].
295 ///
296 /// # Arguments
297 /// * `label` - The label to display for the filter input
298 ///
299 /// # Examples
300 ///
301 /// ```no_run
302 /// # use dear_imgui_rs::*;
303 /// # let mut ctx = Context::create();
304 /// # let ui = ctx.frame();
305 /// let filter = ui.text_filter("Search".to_string());
306 /// ```
307 pub fn text_filter(&self, label: String) -> TextFilter {
308 TextFilter::new(label)
309 }
310
311 /// Creates a new TextFilter with a custom filter pattern.
312 ///
313 /// This is a convenience method equivalent to [`TextFilter::new_with_filter`].
314 ///
315 /// # Arguments
316 /// * `label` - The label to display for the filter input
317 /// * `filter` - The initial filter pattern
318 ///
319 /// # Examples
320 ///
321 /// ```no_run
322 /// # use dear_imgui_rs::*;
323 /// # let mut ctx = Context::create();
324 /// # let ui = ctx.frame();
325 /// let filter = ui.text_filter_with_filter(
326 /// "Search".to_string(),
327 /// "include,-exclude".to_string()
328 /// );
329 /// ```
330 pub fn text_filter_with_filter(&self, label: String, filter: String) -> TextFilter {
331 TextFilter::new_with_filter(label, filter)
332 }
333}