native_windows_gui2/controls/
status_bar.rs

1use super::{ControlBase, ControlHandle};
2use crate::win32::base_helper::check_hwnd;
3use crate::win32::window_helper as wh;
4use crate::{Font, NwgError, RawEventHandler, unbind_raw_event_handler};
5use std::cell::RefCell;
6use winapi::shared::minwindef::{LPARAM, WPARAM};
7
8const NOT_BOUND: &'static str = "StatusBar is not yet bound to a winapi object";
9const BAD_HANDLE: &'static str = "INTERNAL ERROR: StatusBar handle is not HWND!";
10
11/**
12A status bar is a horizontal window at the bottom of a parent window in which an application can display various kinds of status information.
13Status bar cannot stack, so there must be only one per window.
14
15Requires the `status-bar` feature.
16
17**Builder parameters:**
18  * `parent`:   **Required.** The status bar parent container.
19  * `text`:     The status bar text.
20  * `font`:     The font used for the status bar text
21
22**Control events:**
23  * `MousePress(_)`: Generic mouse press events on the status bar
24  * `OnMouseMove`: Generic mouse mouse event
25  * `OnMouseWheel`: Generic mouse wheel event
26
27```rust
28use native_windows_gui2 as nwg;
29fn build_status(status: &mut nwg::StatusBar, window: &nwg::Window, font: &nwg::Font) {
30    nwg::StatusBar::builder()
31        .text("Hello")
32        .font(Some(font))
33        .parent(window)
34        .build(status);
35}
36```
37
38*/
39#[derive(Default)]
40pub struct StatusBar {
41    pub handle: ControlHandle,
42    handler0: RefCell<Option<RawEventHandler>>,
43}
44
45impl StatusBar {
46    pub fn builder<'a>() -> StatusBarBuilder<'a> {
47        StatusBarBuilder {
48            text: "",
49            font: None,
50            parent: None,
51        }
52    }
53
54    /// Set the minimum height of the statusbar (in pixels)
55    pub fn set_min_height(&self, height: u32) {
56        use winapi::um::commctrl::SB_SETMINHEIGHT;
57        use winapi::um::winuser::WM_SIZE;
58
59        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
60        wh::send_message(handle, SB_SETMINHEIGHT, height as WPARAM, 0);
61        wh::send_message(handle, WM_SIZE, 0, 0); // redraw the statusbar
62    }
63
64    /// Return the font of the control
65    pub fn font(&self) -> Option<Font> {
66        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
67        let font_handle = wh::get_window_font(handle);
68        if font_handle.is_null() {
69            None
70        } else {
71            Some(Font {
72                handle: font_handle,
73            })
74        }
75    }
76
77    /// Set the font of the control
78    pub fn set_font(&self, font: Option<&Font>) {
79        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
80
81        wh::set_window_font(handle, font.map(|f| f.handle), true);
82    }
83
84    /// Return the text in one of the region of the status bar
85    pub fn text<'a>(&self, index: u8) -> String {
86        use crate::win32::base_helper::from_utf16;
87        use winapi::shared::minwindef::LOWORD;
88        use winapi::um::commctrl::{SB_GETTEXTLENGTHW, SB_GETTEXTW};
89
90        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
91        let result = wh::send_message(handle, SB_GETTEXTLENGTHW, index as WPARAM, 0);
92        let text_length = (LOWORD(result as u32) as usize) + 1; // +1 for the terminating null character
93
94        let mut buffer: Vec<u16> = Vec::with_capacity(text_length);
95        unsafe {
96            buffer.set_len(text_length);
97        }
98
99        wh::send_message(
100            handle,
101            SB_GETTEXTW,
102            index as WPARAM,
103            buffer.as_mut_ptr() as LPARAM,
104        );
105
106        from_utf16(&buffer)
107    }
108
109    /// Set the text in one of the region of the status bar
110    pub fn set_text<'a>(&self, index: u8, text: &'a str) {
111        use crate::win32::base_helper::to_utf16;
112        use winapi::um::commctrl::SB_SETTEXTW;
113
114        let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
115        let text = to_utf16(text);
116        wh::send_message(
117            handle,
118            SB_SETTEXTW,
119            index as WPARAM,
120            text.as_ptr() as LPARAM,
121        );
122    }
123
124    /// Winapi class name used during control creation
125    pub fn class_name(&self) -> &'static str {
126        "msctls_statusbar32"
127    }
128
129    /// Winapi base flags used during window creation
130    pub fn flags(&self) -> u32 {
131        ::winapi::um::winuser::WS_VISIBLE
132    }
133
134    /// Winapi flags required by the control
135    pub fn forced_flags(&self) -> u32 {
136        use winapi::um::winuser::WS_CHILD;
137
138        WS_CHILD
139    }
140
141    /// Status bar do not resize automatically. Instead, a resize message must be
142    /// manually sent by the parent window to trigger the resize action.
143    pub fn hook_parent_resize(&self) {
144        use crate::bind_raw_event_handler_inner;
145        use winapi::um::winuser::WM_SIZE;
146
147        if self.handle.blank() {
148            panic!("{}", NOT_BOUND);
149        }
150        let handle = self.handle.hwnd().expect(BAD_HANDLE);
151
152        let parent_handle = ControlHandle::Hwnd(wh::get_window_parent(handle));
153        let handler = bind_raw_event_handler_inner(
154            &parent_handle,
155            handle as usize,
156            move |_hwnd, msg, _w, _l| {
157                if msg == WM_SIZE {
158                    wh::send_message(handle, WM_SIZE, 0, 0);
159                }
160
161                None
162            },
163        );
164
165        *self.handler0.borrow_mut() = Some(handler.unwrap());
166    }
167}
168
169impl Drop for StatusBar {
170    fn drop(&mut self) {
171        let handler = self.handler0.borrow();
172        if let Some(h) = handler.as_ref() {
173            drop(unbind_raw_event_handler(h));
174        }
175        self.handle.destroy();
176    }
177}
178
179pub struct StatusBarBuilder<'a> {
180    text: &'a str,
181    font: Option<&'a Font>,
182    parent: Option<ControlHandle>,
183}
184
185impl<'a> StatusBarBuilder<'a> {
186    pub fn text(mut self, text: &'a str) -> StatusBarBuilder<'a> {
187        self.text = text;
188        self
189    }
190
191    pub fn font(mut self, font: Option<&'a Font>) -> StatusBarBuilder<'a> {
192        self.font = font;
193        self
194    }
195
196    pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> StatusBarBuilder<'a> {
197        self.parent = Some(p.into());
198        self
199    }
200
201    pub fn build(self, out: &mut StatusBar) -> Result<(), NwgError> {
202        let parent = match self.parent {
203            Some(p) => Ok(p),
204            None => Err(NwgError::no_parent("StatusBar")),
205        }?;
206
207        *out = Default::default();
208
209        out.handle = ControlBase::build_hwnd()
210            .class_name(out.class_name())
211            .forced_flags(out.forced_flags())
212            .flags(out.flags())
213            .parent(Some(parent))
214            .build()?;
215
216        if self.font.is_some() {
217            out.set_font(self.font);
218        } else {
219            out.set_font(Font::global_default().as_ref());
220        }
221
222        out.set_text(0, self.text);
223        out.hook_parent_resize();
224
225        Ok(())
226    }
227}
228
229impl PartialEq for StatusBar {
230    fn eq(&self, other: &Self) -> bool {
231        self.handle == other.handle
232    }
233}