Skip to main content

native_windows_gui2/controls/
rich_text_box.rs

1use super::{ControlBase, ControlHandle};
2use crate::win32::base_helper::check_hwnd;
3use crate::win32::richedit as rich;
4use crate::win32::window_helper as wh;
5use crate::{Font, NwgError};
6use newline_converter::{dos2unix, unix2dos};
7use std::ops::Range;
8use winapi::shared::minwindef::{LPARAM, WPARAM};
9use winapi::um::winuser::{
10    ES_AUTOHSCROLL, ES_AUTOVSCROLL, WS_DISABLED, WS_HSCROLL, WS_TABSTOP, WS_VISIBLE, WS_VSCROLL,
11};
12
13const NOT_BOUND: &'static str = "RichTextBox is not yet bound to a winapi object";
14const BAD_HANDLE: &'static str = "INTERNAL ERROR: RichTextBox handle is not HWND!";
15
16const ES_SAVESEL: u32 = 32768;
17
18bitflags! {
19    /**
20        The rich text box flags
21
22        * VSCROLL:  The text box has a vertical scrollbar
23        * HSCROLL:  The text box has a horizontal scrollbar
24        * AUTOVSCROLL:  The rich text box has a vertical scrollbar
25        * AUTOHSCROLL:  The rich text box has a horizontal scrollbar
26        * VISIBLE:  The rich text box is immediatly visible after creation
27        * DISABLED: The rich text box cannot be interacted with by the user. It also has a grayed out look.
28        * TAB_STOP: The rich text box can be selected using tab navigation
29        * SAVE_SELECTION: Keep the selected text when the control lose focus
30    */
31    pub struct RichTextBoxFlags: u32 {
32        const VSCROLL = WS_VSCROLL;
33        const HSCROLL = WS_HSCROLL;
34        const AUTOVSCROLL = ES_AUTOVSCROLL;
35        const AUTOHSCROLL = ES_AUTOHSCROLL;
36        const VISIBLE = WS_VISIBLE;
37        const DISABLED = WS_DISABLED;
38        const TAB_STOP = WS_TABSTOP;
39        const SAVE_SELECTION = ES_SAVESEL;
40    }
41}
42
43bitflags! {
44    /**
45        The effets that can be applied to the text of a rich edit control
46
47        * BOLD:      Characters are bold.
48        * ITALIC:    Characters are italic.
49        * STRIKEOUT: Characters are struck.
50        * UNDERLINE: Characters are underlined.
51        * AUTOCOLOR: Characters use the default system color
52    */
53    pub struct CharEffects: u32 {
54        const BOLD = 0x0001;
55        const ITALIC = 0x0002;
56        const UNDERLINE = 0x0004;
57        const STRIKEOUT = 0x0008;
58        const AUTOCOLOR = 0x40000000;
59    }
60}
61
62#[repr(u8)]
63#[derive(Copy, Clone, Debug)]
64pub enum UnderlineType {
65    None,
66    Solid,
67    Dash,
68    DashDot,
69    DashDotDot,
70    Dotted,
71    DoubleSolid,
72    Wave,
73}
74
75/// Contains information about character formatting in a rich edit control
76#[derive(Clone, Debug, Default)]
77pub struct CharFormat {
78    /// Character effects (bold, italics, strikeout, etc)
79    ///
80    /// When returned by `char_format`, specifies which attributes are consistent throughout the entire selection.
81    /// For example, if the entire selection is either in italics or not in italics.
82    pub effects: Option<CharEffects>,
83
84    /// Character height, in twips (1/1440 of an inch or 1/20 of a printer's point).
85    pub height: Option<i32>,
86
87    /// Character offset, in twips, from the baseline. If the value of this member is positive, the character is a superscript; if it is negative, the character is a subscript.
88    pub y_offset: Option<i32>,
89
90    /// Text color. This member is ignored if the AUTOCOLOR character effect is specified.
91    pub text_color: Option<[u8; 3]>,
92
93    /// The font family name
94    pub font_face_name: Option<String>,
95
96    /// Text underline type. Does not work with effects
97    pub underline_type: Option<UnderlineType>,
98}
99
100#[derive(Copy, Clone, Debug)]
101/// Options used for bulleted or numbered paragraphs.
102pub enum ParaNumbering {
103    /// No paragraph numbering or bullets.
104    None,
105
106    /// Insert a bullet at the beginning of each selected paragraph.
107    Bullet,
108
109    /// Use Arabic numbers (0, 1, 2, and so on).
110    Arabic,
111
112    /// Use lowercase letters (a, b, c, and so on).
113    LcLetter,
114
115    /// Use lowercase Roman letters (i, ii, iii, and so on).
116    LcRoman,
117
118    /// Use uppercase letters (A, B, C, and so on).
119    UcLetter,
120
121    /// Use uppercase Roman letters (I, II, III, and so on).
122    UcRoman,
123
124    /// Uses a sequence of characters beginning with the Unicode character specified
125    Seq(char),
126}
127
128#[derive(Copy, Clone, Debug)]
129/// Numbering style used with the numbering paragraphs. Used with `ParamNumbering`
130pub enum ParaNumberingStyle {
131    /// Follows the number with a right parenthesis
132    Paren,
133    /// Encloses the number in parentheses
134    Parens,
135    /// Follows the number with a period
136    Period,
137    /// Display only the number
138    Plain,
139    /// Continues a numbered lsit without applying the next number of bullet
140    NoNumber,
141    /// Starts a new number using the value of `ParaNumbering::Seq(char)`
142    NewNumber,
143}
144
145#[derive(Copy, Clone, Debug)]
146/// Paragraph alignment
147pub enum ParaAlignment {
148    /// Paragraphs are aligned with the left margin.
149    Left,
150    /// Paragraphs are aligned with the right margin.
151    Right,
152    /// Paragraphs are centered.
153    Center,
154    /// Paragraphs are justified.
155    Justify,
156    /// Paragraphs are justified by expanding the blanks alone.
157    FullInterword,
158}
159
160/// Type of line spacing
161#[derive(Copy, Clone, Debug)]
162pub enum ParaLineSpacing {
163    /// Single spacing.
164    Single,
165
166    /// One-and-a-half spacing.
167    OneAndHalf,
168
169    /// Double spacing.
170    Double,
171
172    /// Value in twips (twentieth of a point). If the value specifies a value that is less than single spacing, the control displays single-spaced text
173    SingleOr(i32),
174
175    /// Value in twips (twentieth of a point). The control uses the exact spacing specified, even if dyLineSpacing specifies a value that is less than single spacing.
176    Exact(i32),
177
178    /// The value of `value` / 20 is the spacing, in lines, from one line to the next. 20 produces single-spaced text, 40 is double spaced, 60 is triple spaced, and so on.
179    Exact20(i32),
180}
181
182/// Contains information about paragraph formatting in a rich edit control
183#[derive(Clone, Debug, Default)]
184pub struct ParaFormat {
185    /// Options used for bulleted or numbered paragraphs.
186    pub numbering: Option<ParaNumbering>,
187
188    /// Numbering style used with numbered paragraphs.
189    pub numbering_style: Option<ParaNumberingStyle>,
190
191    /// Minimum space between a paragraph number and the paragraph text, in twips (twentieth of a point).
192    pub numbering_tab: Option<u16>,
193
194    /// Paragraph alignment
195    pub alignment: Option<ParaAlignment>,
196
197    /// Size of the spacing above the paragraph, in twips (twentieth of a point).
198    pub space_before: Option<i32>,
199
200    /// Specifies the size of the spacing below the paragraph, in twips (twentieth of a point).
201    pub space_after: Option<i32>,
202
203    /// Indentation of the paragraph's first line, in twips (twentieth of a point). The indentation of subsequent lines depends on the `offset` member
204    pub start_indent: Option<i32>,
205
206    /// Indentation of the right side of the paragraph, relative to the right margin, in twips (twentieth of a point).
207    pub right_indent: Option<i32>,
208
209    /// Indentation of the second and subsequent lines, **relative** to the indentation of the first line, in twips. The first line is indented if this member is negative or outdented if this member is positive.
210    pub offset: Option<i32>,
211
212    /// Line spacing. For a description of how this value is interpreted, see `ParaLineSpacing`
213    pub line_spacing: Option<ParaLineSpacing>,
214
215    /// Displays text using right-to-left (or left-to-right if set to false)
216    pub rtl: Option<bool>,
217}
218
219/**
220An edit control is a rectangular control window to permit the user to enter and edit text by typing on the keyboard
221This control allow multi line input. For a single line of text, use `TextInput`.
222
223A rich text box is almost a superset of the normal textbox. Unlike text box, rich text box has more features and can support Component Object Model (COM) objects.
224
225The rich text box control supports the following rich text features:
226
227* Colored text
228* Multiple fonts
229* Styled text such as bold, underscore, strikeout, etc
230* Bullet point list
231* Paragraph with custom indent/offset
232* Custom line spacing
233
234
235See: <https://docs.microsoft.com/en-us/windows/win32/controls/about-rich-edit-controls#rich-edit-version-41>
236
237Note: Use `\r\n` to input a new line not just `\n`.
238
239**Builder parameters:**
240  * `parent`:   **Required.** The text box parent container.
241  * `text`:     The text box text.
242  * `size`:     The text box size.
243  * `position`: The text box position.
244  * `flags`:    A combination of the TextBoxFlags values.
245  * `ex_flags`: A combination of win32 window extended flags. Unlike `flags`, ex_flags must be used straight from winapi
246  * `font`:     The font used for the text box text
247  * `limit`:    The maximum number of character that can be inserted in the control
248  * `readonly`: If the textbox should allow user input or not
249  * `focus`:    The control receive focus after being created
250
251**Control events:**
252  * `OnMouseMove`:   Generic mouse mouse event
253  * `OnMouseWheel`:  Generic mouse wheel event
254  * `MousePress(_)`: Generic mouse press events on the button
255  * `OnKeyPress`:    Generic key press event
256  * `OnKeyRelease`:  Generic key release event
257  * `OnChar`:        Generic key event. Returns a `char` instead of a virtual key code
258*/
259#[derive(Default, PartialEq, Eq)]
260pub struct RichTextBox {
261    pub handle: ControlHandle,
262}
263
264impl RichTextBox {
265    pub fn builder<'a>() -> RichTextBoxBuilder<'a> {
266        RichTextBoxBuilder {
267            text: "",
268            size: (100, 25),
269            position: (0, 0),
270            flags: None,
271            ex_flags: 0,
272            limit: 0,
273            readonly: false,
274            focus: false,
275            font: None,
276            parent: None,
277        }
278    }
279
280    /// Sets the background color for a rich edit control.
281    /// You cannot get the background color of a rich text box
282    pub fn set_background_color(&self, color: [u8; 3]) {
283        use winapi::um::wingdi::RGB;
284
285        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
286        let color = RGB(color[0], color[1], color[2]);
287        wh::send_message(handle, rich::EM_SETBKGNDCOLOR, 0, color as _);
288    }
289
290    /// Sets the character format of the currently selected text
291    pub fn set_char_format(&self, fmt: &CharFormat) {
292        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
293        rich::set_char_format(handle, fmt);
294    }
295
296    /// Returns the character format of the current selected text
297    pub fn char_format(&self) -> CharFormat {
298        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
299        rich::char_format(handle)
300    }
301
302    /// Sets the paragraph formatting for the current selection in a rich edit control
303    pub fn set_para_format(&self, fmt: &ParaFormat) {
304        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
305        rich::set_para_format(handle, fmt)
306    }
307
308    /// Returns the paragraph formatting for the current selection in a rich edit control
309    /// If more than one paragraph is selected, receive the attributes of the first paragraph
310    pub fn para_format(&self) -> ParaFormat {
311        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
312        rich::para_format(handle)
313    }
314
315    /// Set the font of the control
316    /// It is not possible to get the base font handle of a rich label. Use `char_format` instead.
317    pub fn set_font(&self, font: Option<&Font>) {
318        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
319
320        wh::set_window_font(handle, font.map(|f| f.handle), true);
321    }
322
323    /// Return the number of maximum character allowed in this text input
324    pub fn limit(&self) -> u32 {
325        use winapi::um::winuser::EM_GETLIMITTEXT;
326        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
327        wh::send_message(handle, EM_GETLIMITTEXT as u32, 0, 0) as u32
328    }
329
330    /// Set the number of maximum character allowed in this text input
331    pub fn set_limit(&self, limit: usize) {
332        use winapi::um::winuser::EM_SETLIMITTEXT;
333
334        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
335        wh::send_message(handle, EM_SETLIMITTEXT as u32, limit, 0);
336    }
337
338    /// Check if the content of the text input was modified after it's creation
339    pub fn modified(&self) -> bool {
340        use winapi::um::winuser::EM_GETMODIFY;
341
342        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
343        wh::send_message(handle, EM_GETMODIFY as u32, 0, 0) != 0
344    }
345
346    /// Manually set modified flag of the text input
347    pub fn set_modified(&self, e: bool) {
348        use winapi::um::winuser::EM_SETMODIFY;
349        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
350        wh::send_message(handle, EM_SETMODIFY as u32, e as usize, 0);
351    }
352
353    /// Undo the last action by the user in the control
354    pub fn undo(&self) {
355        use winapi::um::winuser::EM_UNDO;
356
357        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
358        wh::send_message(handle, EM_UNDO as u32, 0, 0);
359    }
360
361    /// Return the selected range of characters by the user in the text input
362    pub fn selection(&self) -> Range<u32> {
363        use winapi::um::winuser::EM_GETSEL;
364
365        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
366
367        let (mut out1, mut out2) = (0u32, 0u32);
368        let (ptr1, ptr2) = (&mut out1 as *mut u32, &mut out2 as *mut u32);
369        wh::send_message(handle, EM_GETSEL as u32, ptr1 as WPARAM, ptr2 as LPARAM);
370
371        Range {
372            start: out1 as u32,
373            end: out2 as u32,
374        }
375    }
376
377    /// Return the selected range of characters by the user in the text input
378    pub fn set_selection(&self, r: Range<u32>) {
379        use winapi::um::winuser::EM_SETSEL;
380
381        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
382        wh::send_message(handle, EM_SETSEL as u32, r.start as usize, r.end as isize);
383    }
384
385    /// Return the length of the user input in the control. Performs a newline conversion first since
386    /// Windows treats "\r\n" as a single character
387    pub fn len(&self) -> u32 {
388        use std::convert::TryInto;
389
390        dos2unix(&self.text())
391            .chars()
392            .count()
393            .try_into()
394            .unwrap_or_default()
395    }
396
397    /// Return the number of lines in the multiline edit control.
398    /// If the control has no text, the return value is 1.
399    pub fn linecount(&self) -> i32 {
400        use winapi::um::winuser::EM_GETLINECOUNT;
401
402        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
403        wh::send_message(handle, EM_GETLINECOUNT as u32, 0, 0) as i32
404    }
405
406    /// Scroll `v` lines in the multiline edit control.
407    pub fn scroll(&self, v: i32) {
408        use winapi::um::winuser::EM_LINESCROLL;
409
410        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
411        wh::send_message(handle, EM_LINESCROLL as u32, 0, v as LPARAM);
412    }
413
414    /// Get the linecount and then scroll the text to the last line
415    pub fn scroll_lastline(&self) {
416        let lines = self.linecount();
417        self.scroll(lines * -1);
418        self.scroll(lines - 2);
419    }
420
421    /// Return true if the TextInput value cannot be edited. Retrurn false otherwise.
422    /// A user can still copy text from a readonly TextEdit (unlike disabled)
423    pub fn readonly(&self) -> bool {
424        use winapi::um::winuser::ES_READONLY;
425
426        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
427        wh::get_style(handle) & ES_READONLY == ES_READONLY
428    }
429
430    /// Set the readonly flag of the text input
431    /// A user can still copy text from a readonly TextEdit (unlike disabled)
432    pub fn set_readonly(&self, r: bool) {
433        use winapi::um::winuser::EM_SETREADONLY;
434
435        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
436        wh::send_message(handle, EM_SETREADONLY as u32, r as WPARAM, 0);
437    }
438
439    /// Remove all text from the textbox
440    pub fn clear(&self) {
441        self.set_text("");
442    }
443
444    /// Return true if the control currently has the keyboard focus
445    pub fn focus(&self) -> bool {
446        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
447        wh::get_focus(handle)
448    }
449
450    /// Set the keyboard focus on the button
451    pub fn set_focus(&self) {
452        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
453
454        wh::set_focus(handle);
455    }
456
457    /// Return true if the control user can interact with the control, return false otherwise
458    pub fn enabled(&self) -> bool {
459        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
460        wh::get_window_enabled(handle)
461    }
462
463    /// Enable or disable the control
464    pub fn set_enabled(&self, v: bool) {
465        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
466        wh::set_window_enabled(handle, v)
467    }
468
469    /// Return true if the control is visible to the user. Will return true even if the
470    /// control is outside of the parent client view (ex: at the position (10000, 10000))
471    pub fn visible(&self) -> bool {
472        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
473        wh::get_window_visibility(handle)
474    }
475
476    /// Show or hide the control to the user
477    pub fn set_visible(&self, v: bool) {
478        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
479        wh::set_window_visibility(handle, v)
480    }
481
482    /// Return the size of the button in the parent window
483    pub fn size(&self) -> (u32, u32) {
484        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
485        wh::get_window_size(handle)
486    }
487
488    /// Set the size of the button in the parent window
489    pub fn set_size(&self, x: u32, y: u32) {
490        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
491        wh::set_window_size(handle, x, y, false)
492    }
493
494    /// Return the position of the button in the parent window
495    pub fn position(&self) -> (i32, i32) {
496        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
497        wh::get_window_position(handle)
498    }
499
500    /// Set the position of the button in the parent window
501    pub fn set_position(&self, x: i32, y: i32) {
502        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
503        wh::set_window_position(handle, x, y)
504    }
505
506    /// Return the text displayed in the TextInput
507    pub fn text(&self) -> String {
508        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
509        wh::get_window_text(handle)
510    }
511
512    /// Set the text displayed in the TextInput
513    pub fn set_text<'a>(&self, v: &'a str) {
514        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
515        wh::set_window_text(handle, v)
516    }
517
518    /// Set the text in the current control, converting unix-style newlines in the input to "\r\n"
519    pub fn set_text_unix2dos<'a>(&self, v: &'a str) {
520        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
521        wh::set_window_text(handle, &unix2dos(&v).to_string())
522    }
523
524    /// Append text to the current control
525    pub fn append<'a>(&self, v: &'a str) {
526        let text = self.text() + &unix2dos(&v).to_string();
527        self.set_text(&text);
528        self.scroll_lastline();
529    }
530
531    /// Append text to the current control followed by "\r\n"
532    pub fn appendln<'a>(&self, v: &'a str) {
533        let text = self.text() + &unix2dos(&v).to_string() + "\r\n";
534        self.set_text(&text);
535        self.scroll_lastline();
536    }
537
538    /// Winapi class name used during control creation
539    pub fn class_name(&self) -> &'static str {
540        "RICHEDIT50W"
541    }
542
543    /// Winapi base flags used during window creation
544    pub fn flags(&self) -> u32 {
545        WS_VISIBLE
546            | ES_AUTOVSCROLL
547            | ES_AUTOHSCROLL
548            | WS_TABSTOP
549            | WS_VSCROLL
550            | WS_HSCROLL
551            | ES_SAVESEL
552    }
553
554    /// Winapi flags required by the control
555    pub fn forced_flags(&self) -> u32 {
556        use winapi::um::winuser::{ES_MULTILINE, ES_WANTRETURN, WS_BORDER, WS_CHILD};
557
558        WS_BORDER | WS_CHILD | ES_MULTILINE | ES_WANTRETURN
559    }
560}
561
562impl Drop for RichTextBox {
563    fn drop(&mut self) {
564        self.handle.destroy();
565    }
566}
567pub struct RichTextBoxBuilder<'a> {
568    text: &'a str,
569    size: (i32, i32),
570    position: (i32, i32),
571    flags: Option<RichTextBoxFlags>,
572    ex_flags: u32,
573    limit: usize,
574    readonly: bool,
575    focus: bool,
576    font: Option<&'a Font>,
577    parent: Option<ControlHandle>,
578}
579
580impl<'a> RichTextBoxBuilder<'a> {
581    pub fn flags(mut self, flags: RichTextBoxFlags) -> RichTextBoxBuilder<'a> {
582        self.flags = Some(flags);
583        self
584    }
585
586    pub fn ex_flags(mut self, flags: u32) -> RichTextBoxBuilder<'a> {
587        self.ex_flags = flags;
588        self
589    }
590
591    pub fn text(mut self, text: &'a str) -> RichTextBoxBuilder<'a> {
592        self.text = text;
593        self
594    }
595
596    pub fn size(mut self, size: (i32, i32)) -> RichTextBoxBuilder<'a> {
597        self.size = size;
598        self
599    }
600
601    pub fn position(mut self, pos: (i32, i32)) -> RichTextBoxBuilder<'a> {
602        self.position = pos;
603        self
604    }
605
606    pub fn limit(mut self, limit: usize) -> RichTextBoxBuilder<'a> {
607        self.limit = limit;
608        self
609    }
610
611    pub fn readonly(mut self, read: bool) -> RichTextBoxBuilder<'a> {
612        self.readonly = read;
613        self
614    }
615
616    pub fn font(mut self, font: Option<&'a Font>) -> RichTextBoxBuilder<'a> {
617        self.font = font;
618        self
619    }
620
621    pub fn focus(mut self, focus: bool) -> RichTextBoxBuilder<'a> {
622        self.focus = focus;
623        self
624    }
625
626    pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> RichTextBoxBuilder<'a> {
627        self.parent = Some(p.into());
628        self
629    }
630
631    pub fn build(self, out: &mut RichTextBox) -> Result<(), NwgError> {
632        let flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
633
634        let parent = match self.parent {
635            Some(p) => Ok(p),
636            None => Err(NwgError::no_parent("RichTextBox")),
637        }?;
638
639        *out = Default::default();
640
641        out.handle = ControlBase::build_hwnd()
642            .class_name(out.class_name())
643            .forced_flags(out.forced_flags())
644            .flags(flags)
645            .ex_flags(self.ex_flags)
646            .size(self.size)
647            .position(self.position)
648            .text(self.text)
649            .parent(Some(parent))
650            .build()?;
651
652        if self.limit > 0 {
653            out.set_limit(self.limit);
654        }
655
656        if self.readonly {
657            out.set_readonly(self.readonly);
658        }
659
660        if self.font.is_some() {
661            out.set_font(self.font);
662        } else {
663            out.set_font(Font::global_default().as_ref());
664        }
665
666        if self.focus {
667            out.set_focus();
668        }
669
670        Ok(())
671    }
672}