native_windows_gui/controls/
image_frame.rs1use winapi::um::winuser::{WS_VISIBLE, WS_DISABLED};
2use winapi::um::wingdi::DeleteObject;
3use winapi::shared::windef::HBRUSH;
4use crate::win32::{
5 base_helper::check_hwnd,
6 window_helper as wh,
7 resources_helper as rh
8};
9use super::{ControlBase, ControlHandle};
10use crate::{Bitmap, Icon, NwgError, RawEventHandler, unbind_raw_event_handler};
11use std::cell::RefCell;
12
13const NOT_BOUND: &'static str = "ImageFrame is not yet bound to a winapi object";
14const BAD_HANDLE: &'static str = "INTERNAL ERROR: ImageFrame handle is not HWND!";
15
16
17bitflags! {
18 pub struct ImageFrameFlags: u32 {
19 const VISIBLE = WS_VISIBLE;
20 const DISABLED = WS_DISABLED;
21 }
22}
23
24#[derive(Default)]
56pub struct ImageFrame {
57 pub handle: ControlHandle,
58 background_brush: Option<HBRUSH>,
59 handler0: RefCell<Option<RawEventHandler>>,
60}
61
62impl ImageFrame {
63
64 pub fn builder<'a>() -> ImageFrameBuilder<'a> {
65 ImageFrameBuilder {
66 size: (100, 100),
67 position: (0, 0),
68 flags: None,
69 ex_flags: 0,
70 bitmap: None,
71 icon: None,
72 parent: None,
73 background_color: None
74 }
75 }
76
77 pub fn set_bitmap<'a>(&self, image: Option<&'a Bitmap>) {
80 use winapi::um::winuser::{STM_SETIMAGE, IMAGE_BITMAP};
81 use winapi::shared::minwindef::{WPARAM, LPARAM};
82
83 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
84
85 let image_handle = image.map(|i| i.handle as LPARAM).unwrap_or(0);
86 let prev_img = wh::send_message(handle, STM_SETIMAGE, IMAGE_BITMAP as WPARAM, image_handle);
87 if prev_img != 0 {
88 unsafe { DeleteObject(prev_img as _); }
89 }
90 }
91
92 pub fn set_icon<'a>(&self, image: Option<&'a Icon>) {
95 use winapi::um::winuser::{STM_SETIMAGE, IMAGE_ICON};
96 use winapi::shared::minwindef::{WPARAM, LPARAM};
97
98 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
99
100 let image_handle = image.map(|i| i.handle as LPARAM).unwrap_or(0);
101 let prev_img = wh::send_message(handle, STM_SETIMAGE, IMAGE_ICON as WPARAM, image_handle);
102 if prev_img != 0 {
103 unsafe { DeleteObject(prev_img as _); }
104 }
105 }
106
107 pub fn image<'a>(&self, bitmap: &mut Option<Bitmap>, icon: &mut Option<Icon>) {
111 use winapi::um::winuser::{STM_GETIMAGE, IMAGE_BITMAP, IMAGE_ICON};
112 use winapi::shared::minwindef::WPARAM;
113 use winapi::shared::windef::HBITMAP;
114 use winapi::um::winnt::HANDLE;
115
116 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
117 let bitmap_handle = wh::send_message(handle, STM_GETIMAGE, IMAGE_BITMAP as WPARAM, 0);
118 let icon_handle = wh::send_message(handle, STM_GETIMAGE, IMAGE_ICON as WPARAM, 0);
119
120 *bitmap = None;
121 *icon = None;
122
123 if bitmap_handle != 0 && rh::is_bitmap(bitmap_handle as HBITMAP) {
124 *bitmap = Some(Bitmap { handle: bitmap_handle as HANDLE, owned: false });
125 } else if icon_handle != 0 {
126 *icon = Some(Icon { handle: icon_handle as HANDLE, owned: false });
127 }
128 }
129
130 pub fn enabled(&self) -> bool {
132 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
133 unsafe { wh::get_window_enabled(handle) }
134 }
135
136 pub fn set_enabled(&self, v: bool) {
138 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
139 unsafe { wh::set_window_enabled(handle, v) }
140 }
141
142 pub fn visible(&self) -> bool {
145 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
146 unsafe { wh::get_window_visibility(handle) }
147 }
148
149 pub fn set_visible(&self, v: bool) {
151 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
152 unsafe { wh::set_window_visibility(handle, v) }
153 }
154
155 pub fn size(&self) -> (u32, u32) {
157 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
158 unsafe { wh::get_window_size(handle) }
159 }
160
161 pub fn set_size(&self, x: u32, y: u32) {
163 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
164 unsafe { wh::set_window_size(handle, x, y, false) }
165 }
166
167 pub fn position(&self) -> (i32, i32) {
169 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
170 unsafe { wh::get_window_position(handle) }
171 }
172
173 pub fn set_position(&self, x: i32, y: i32) {
175 let handle = check_hwnd(&self.handle, NOT_BOUND, BAD_HANDLE);
176 unsafe { wh::set_window_position(handle, x, y) }
177 }
178
179 pub fn class_name(&self) -> &'static str {
181 "STATIC"
182 }
183
184 pub fn flags(&self) -> u32 {
186 WS_VISIBLE
187 }
188
189 pub fn forced_flags(&self) -> u32 {
191 use winapi::um::winuser::{SS_NOTIFY, WS_CHILD, SS_CENTERIMAGE};
192
193 WS_CHILD | SS_NOTIFY | SS_CENTERIMAGE
194 }
195
196 fn hook_background_color(&mut self, c: [u8; 3]) {
199 use crate::bind_raw_event_handler_inner;
200 use winapi::um::winuser::{WM_CTLCOLORSTATIC};
201 use winapi::shared::{basetsd::UINT_PTR, windef::{HWND}, minwindef::LRESULT};
202 use winapi::um::wingdi::{CreateSolidBrush, RGB};
203
204 if self.handle.blank() { panic!("{}", NOT_BOUND); }
205 let handle = self.handle.hwnd().expect(BAD_HANDLE);
206
207 let parent_handle = ControlHandle::Hwnd(wh::get_window_parent(handle));
208 let brush = unsafe { CreateSolidBrush(RGB(c[0], c[1], c[2])) };
209 self.background_brush = Some(brush);
210
211 let handler = bind_raw_event_handler_inner(&parent_handle, handle as UINT_PTR, move |_hwnd, msg, _w, l| {
212 match msg {
213 WM_CTLCOLORSTATIC => {
214 let child = l as HWND;
215 if child == handle {
216 return Some(brush as LRESULT);
217 }
218 },
219 _ => {}
220 }
221
222 None
223 });
224
225 *self.handler0.borrow_mut() = Some(handler.unwrap());
226 }
227
228}
229
230impl Drop for ImageFrame {
231 fn drop(&mut self) {
232 let handler = self.handler0.borrow();
233 if let Some(h) = handler.as_ref() {
234 drop(unbind_raw_event_handler(h));
235 }
236
237 if let Some(bg) = self.background_brush {
238 unsafe { DeleteObject(bg as _); }
239 }
240
241 self.handle.destroy();
242 }
243}
244
245pub struct ImageFrameBuilder<'a> {
246 size: (i32, i32),
247 position: (i32, i32),
248 flags: Option<ImageFrameFlags>,
249 ex_flags: u32,
250 bitmap: Option<&'a Bitmap>,
251 icon: Option<&'a Icon>,
252 parent: Option<ControlHandle>,
253 background_color: Option<[u8; 3]>,
254}
255
256impl<'a> ImageFrameBuilder<'a> {
257
258 pub fn flags(mut self, flags: ImageFrameFlags) -> ImageFrameBuilder<'a> {
259 self.flags = Some(flags);
260 self
261 }
262
263 pub fn ex_flags(mut self, flags: u32) -> ImageFrameBuilder<'a> {
264 self.ex_flags = flags;
265 self
266 }
267
268 pub fn size(mut self, size: (i32, i32)) -> ImageFrameBuilder<'a> {
269 self.size = size;
270 self
271 }
272
273 pub fn position(mut self, pos: (i32, i32)) -> ImageFrameBuilder<'a> {
274 self.position = pos;
275 self
276 }
277
278 pub fn bitmap(mut self, bit: Option<&'a Bitmap>) -> ImageFrameBuilder<'a> {
279 self.bitmap = bit;
280 self
281 }
282
283 pub fn icon(mut self, ico: Option<&'a Icon>) -> ImageFrameBuilder<'a> {
284 self.icon = ico;
285 self
286 }
287
288 pub fn parent<C: Into<ControlHandle>>(mut self, p: C) -> ImageFrameBuilder<'a> {
289 self.parent = Some(p.into());
290 self
291 }
292
293 pub fn background_color(mut self, color: Option<[u8;3]>) -> ImageFrameBuilder<'a> {
294 self.background_color = color;
295 self
296 }
297
298 pub fn build(self, out: &mut ImageFrame) -> Result<(), NwgError> {
299 use winapi::um::winuser::{SS_BITMAP, SS_ICON};
300
301 let mut flags = self.flags.map(|f| f.bits()).unwrap_or(out.flags());
302 if self.icon.is_some() {
303 flags |= SS_ICON;
304 } else {
305 flags |= SS_BITMAP;
306 }
307
308 let parent = match self.parent {
309 Some(p) => Ok(p),
310 None => Err(NwgError::no_parent("ImageFrame"))
311 }?;
312
313 *out = Default::default();
314
315 out.handle = ControlBase::build_hwnd()
316 .class_name(out.class_name())
317 .forced_flags(out.forced_flags())
318 .flags(flags)
319 .ex_flags(self.ex_flags)
320 .size(self.size)
321 .position(self.position)
322 .parent(Some(parent))
323 .build()?;
324
325 if self.bitmap.is_some() {
326 out.set_bitmap(self.bitmap);
327 } else if self.icon.is_some() {
328 out.set_icon(self.icon);
329 }
330
331 if self.background_color.is_some() {
332 out.hook_background_color(self.background_color.unwrap());
333 }
334
335 Ok(())
336 }
337
338}
339
340impl PartialEq for ImageFrame {
341 fn eq(&self, other: &Self) -> bool {
342 self.handle == other.handle
343 }
344}