winapi_easy/ui/
resource.rs

1//! Application resources.
2
3use std::io;
4
5use num_enum::IntoPrimitive;
6use windows::Win32::Foundation::HANDLE;
7use windows::Win32::Graphics::Gdi::{
8    COLOR_3DDKSHADOW,
9    COLOR_3DLIGHT,
10    COLOR_ACTIVEBORDER,
11    COLOR_ACTIVECAPTION,
12    COLOR_APPWORKSPACE,
13    COLOR_BACKGROUND,
14    COLOR_BTNFACE,
15    COLOR_BTNHIGHLIGHT,
16    COLOR_BTNSHADOW,
17    COLOR_BTNTEXT,
18    COLOR_CAPTIONTEXT,
19    COLOR_GRADIENTACTIVECAPTION,
20    COLOR_GRADIENTINACTIVECAPTION,
21    COLOR_GRAYTEXT,
22    COLOR_HIGHLIGHT,
23    COLOR_HIGHLIGHTTEXT,
24    COLOR_HOTLIGHT,
25    COLOR_INACTIVEBORDER,
26    COLOR_INACTIVECAPTION,
27    COLOR_INACTIVECAPTIONTEXT,
28    COLOR_INFOBK,
29    COLOR_INFOTEXT,
30    COLOR_MENU,
31    COLOR_MENUBAR,
32    COLOR_MENUHILIGHT,
33    COLOR_MENUTEXT,
34    COLOR_SCROLLBAR,
35    COLOR_WINDOW,
36    COLOR_WINDOWFRAME,
37    COLOR_WINDOWTEXT,
38    HBRUSH,
39};
40use windows::Win32::UI::WindowsAndMessaging::{
41    LoadImageW,
42    GDI_IMAGE_TYPE,
43    HCURSOR,
44    HICON,
45    IMAGE_CURSOR,
46    IMAGE_ICON,
47    LR_DEFAULTSIZE,
48    LR_SHARED,
49    OCR_APPSTARTING,
50    OCR_CROSS,
51    OCR_HAND,
52    OCR_HELP,
53    OCR_IBEAM,
54    OCR_NO,
55    OCR_NORMAL,
56    OCR_SIZEALL,
57    OCR_SIZENESW,
58    OCR_SIZENS,
59    OCR_SIZENWSE,
60    OCR_SIZEWE,
61    OCR_UP,
62    OCR_WAIT,
63    OIC_ERROR,
64    OIC_INFORMATION,
65    OIC_QUES,
66    OIC_SAMPLE,
67    OIC_SHIELD,
68    OIC_WARNING,
69};
70
71use windows_missing::*;
72
73pub trait Icon {
74    fn as_handle(&self) -> io::Result<HICON>;
75}
76
77#[derive(IntoPrimitive, Copy, Clone, Eq, PartialEq, Default, Debug)]
78#[repr(u32)]
79pub enum BuiltinIcon {
80    #[default]
81    Application = OIC_SAMPLE,
82    QuestionMark = OIC_QUES,
83    Warning = OIC_WARNING,
84    Error = OIC_ERROR,
85    Information = OIC_INFORMATION,
86    Shield = OIC_SHIELD,
87}
88
89impl Icon for BuiltinIcon {
90    fn as_handle(&self) -> io::Result<HICON> {
91        let handle = get_shared_image_handle((*self).into(), IMAGE_ICON)?;
92        Ok(HICON(handle.0))
93    }
94}
95
96pub trait Cursor {
97    fn as_handle(&self) -> io::Result<HCURSOR>;
98}
99
100#[derive(IntoPrimitive, Copy, Clone, Eq, PartialEq, Default, Debug)]
101#[repr(u32)]
102pub enum BuiltinCursor {
103    /// Standard arrow
104    #[default]
105    Normal = OCR_NORMAL.0,
106    /// Standard arrow and small hourglass
107    NormalPlusWaiting = OCR_APPSTARTING.0,
108    /// Hourglass
109    Waiting = OCR_WAIT.0,
110    /// Arrow and question mark
111    NormalPlusQuestionMark = OCR_HELP.0,
112    /// Crosshair
113    Crosshair = OCR_CROSS.0,
114    /// Hand
115    Hand = OCR_HAND.0,
116    /// I-beam
117    IBeam = OCR_IBEAM.0,
118    /// Slashed circle
119    SlashedCircle = OCR_NO.0,
120    /// Four-pointed arrow pointing north, south, east, and west
121    ArrowAllDirections = OCR_SIZEALL.0,
122    /// Double-pointed arrow pointing northeast and southwest
123    ArrowNESW = OCR_SIZENESW.0,
124    /// Double-pointed arrow pointing north and south
125    ArrowNS = OCR_SIZENS.0,
126    /// Double-pointed arrow pointing northwest and southeast
127    ArrowNWSE = OCR_SIZENWSE.0,
128    /// Double-pointed arrow pointing west and east
129    ArrowWE = OCR_SIZEWE.0,
130    /// Vertical arrow
131    Up = OCR_UP.0,
132}
133
134impl Cursor for BuiltinCursor {
135    fn as_handle(&self) -> io::Result<HCURSOR> {
136        let handle = get_shared_image_handle((*self).into(), IMAGE_CURSOR)?;
137        Ok(HCURSOR(handle.0))
138    }
139}
140
141pub trait Brush {
142    fn as_handle(&self) -> io::Result<HBRUSH>;
143}
144
145#[derive(IntoPrimitive, Copy, Clone, Eq, PartialEq, Default, Debug)]
146#[repr(i32)]
147pub enum BuiltinColor {
148    #[default]
149    Scrollbar = COLOR_SCROLLBAR.0,
150    Background = COLOR_BACKGROUND.0,
151    ActiveCaption = COLOR_ACTIVECAPTION.0,
152    InactiveCaption = COLOR_INACTIVECAPTION.0,
153    Menu = COLOR_MENU.0,
154    Window = COLOR_WINDOW.0,
155    WindowFrame = COLOR_WINDOWFRAME.0,
156    MenuText = COLOR_MENUTEXT.0,
157    WindowText = COLOR_WINDOWTEXT.0,
158    CaptionText = COLOR_CAPTIONTEXT.0,
159    ActiveBorder = COLOR_ACTIVEBORDER.0,
160    InactiveBorder = COLOR_INACTIVEBORDER.0,
161    AppWorkspace = COLOR_APPWORKSPACE.0,
162    Highlight = COLOR_HIGHLIGHT.0,
163    HighlightText = COLOR_HIGHLIGHTTEXT.0,
164    ButtonFace = COLOR_BTNFACE.0,
165    ButtonShadow = COLOR_BTNSHADOW.0,
166    GrayText = COLOR_GRAYTEXT.0,
167    ButtonText = COLOR_BTNTEXT.0,
168    InactiveCaptionText = COLOR_INACTIVECAPTIONTEXT.0,
169    ButtonHighlight = COLOR_BTNHIGHLIGHT.0,
170    Shadow3DDark = COLOR_3DDKSHADOW.0,
171    Light3D = COLOR_3DLIGHT.0,
172    InfoText = COLOR_INFOTEXT.0,
173    InfoBlack = COLOR_INFOBK.0,
174    HotLight = COLOR_HOTLIGHT.0,
175    GradientActiveCaption = COLOR_GRADIENTACTIVECAPTION.0,
176    GradientInactiveCaption = COLOR_GRADIENTINACTIVECAPTION.0,
177    MenuHighlight = COLOR_MENUHILIGHT.0,
178    MenuBar = COLOR_MENUBAR.0,
179}
180
181impl Brush for BuiltinColor {
182    fn as_handle(&self) -> io::Result<HBRUSH> {
183        Ok(HBRUSH(i32::from(*self) as *mut std::ffi::c_void))
184    }
185}
186
187fn get_shared_image_handle(resource_id: u32, resource_type: GDI_IMAGE_TYPE) -> io::Result<HANDLE> {
188    let handle = unsafe {
189        LoadImageW(
190            None,
191            MAKEINTRESOURCEW(resource_id),
192            resource_type,
193            0,
194            0,
195            LR_SHARED | LR_DEFAULTSIZE,
196        )?
197    };
198    Ok(handle)
199}
200
201mod windows_missing {
202    use windows::core::PCWSTR;
203
204    // Temporary function until this gets resolved: https://github.com/microsoft/windows-rs/issues/641
205    #[allow(non_snake_case)]
206    #[inline]
207    pub fn MAKEINTRESOURCEW(i: u32) -> PCWSTR {
208        PCWSTR(i as usize as *const u16)
209    }
210}