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}