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