Skip to main content

rdi_platform_windows/
folder_flags.rs

1//! Windows desktop folder flags, including unsupported and deprecated SDK values.
2//!
3//! Reference: [Microsoft FOLDERFLAGS documentation](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-folderflags).
4
5macro_rules! folder_flags {
6    ($($variant:ident, $sdk:ident, $bits:literal, $title:literal, $description:literal;)+) => {
7        /// A Windows folder-view flag or an arbitrary raw mask (R-FLAG-2).
8        ///
9        /// Pass [`Self::bits`] to integer-based controller operations.
10        /// See [Microsoft FOLDERFLAGS](https://learn.microsoft.com/en-us/windows/win32/api/shobjidl_core/ne-shobjidl_core-folderflags)
11        /// for platform support; legacy UI descriptions do not guarantee support.
12        #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
13        pub enum FolderFlag {
14            $(#[doc = $description] $variant,)+
15            /// An arbitrary unsigned mask, including combinations of flags.
16            Raw(u32),
17        }
18
19        impl FolderFlag {
20            /// Every documented flag, including zero, in Microsoft SDK order.
21            pub const ALL: &'static [Self] = &[$(Self::$variant,)+];
22
23            /// Raw unsigned Windows mask.
24            pub const fn bits(self) -> u32 {
25                match self {
26                    $(Self::$variant => $bits,)+
27                    Self::Raw(bits) => bits,
28                }
29            }
30
31            /// Windows SDK name; absent for raw masks.
32            pub const fn name(self) -> Option<&'static str> {
33                match self {
34                    $(Self::$variant => Some(stringify!($sdk)),)+
35                    Self::Raw(_) => None,
36                }
37            }
38
39            /// Display title; absent for raw masks.
40            pub const fn title(self) -> Option<&'static str> {
41                match self {
42                    $(Self::$variant => Some($title),)+
43                    Self::Raw(_) => None,
44                }
45            }
46
47            /// Display description; absent for raw masks.
48            pub const fn description(self) -> Option<&'static str> {
49                match self {
50                    $(Self::$variant => Some($description),)+
51                    Self::Raw(_) => None,
52                }
53            }
54        }
55
56        #[cfg(test)]
57        #[test]
58        fn folder_flag_catalog_matches_windows_sdk() {
59            $(assert_eq!(FolderFlag::$variant.bits(), windows::Win32::UI::Shell::$sdk.0 as u32);)+
60        }
61    };
62}
63
64folder_flags! {
65    None, FWF_NONE, 0x00000000, "None", "No special view options";
66    AutoArrange, FWF_AUTOARRANGE, 0x00000001, "Auto Arrange", "Automatically arrange the icons";
67    AbbreviatedNames, FWF_ABBREVIATEDNAMES, 0x00000002, "Abbreviated Names", "Not supported";
68    SnapToGrid, FWF_SNAPTOGRID, 0x00000004, "Snap to grid", "Snap icon positions to grid";
69    OwnerData, FWF_OWNERDATA, 0x00000008, "Owner Data", "Not supported";
70    BestFitWindow, FWF_BESTFITWINDOW, 0x00000010, "Best Fit Window", "Not supported";
71    Desktop, FWF_DESKTOP, 0x00000020, "Desktop", "Use desktop behavior; implies no client edge and no scroll bars";
72    SingleSelect, FWF_SINGLESEL, 0x00000040, "Single Select", "Prevents selection of multiple icons";
73    NoSubfolders, FWF_NOSUBFOLDERS, 0x00000080, "Hide Subfolders", "Don't show subfolders";
74    Transparent, FWF_TRANSPARENT, 0x00000100, "Transparent", "Draw transparently on the desktop";
75    NoClientEdge, FWF_NOCLIENTEDGE, 0x00000200, "No Client Edge", "Not supported";
76    NoScroll, FWF_NOSCROLL, 0x00000400, "No Scroll Bars", "Don't add scroll bars to the desktop view";
77    AlignLeft, FWF_ALIGNLEFT, 0x00000800, "Align Left", "Align the view to the left";
78    NoIcons, FWF_NOICONS, 0x00001000, "Hide Icons", "Don't show icons";
79    ShowSelectionAlways, FWF_SHOWSELALWAYS, 0x00002000, "Always Show Selection", "Deprecated since Windows XP; has no effect";
80    NoVisible, FWF_NOVISIBLE, 0x00004000, "Not Visible", "Not supported";
81    SingleClickActivate, FWF_SINGLECLICKACTIVATE, 0x00008000, "One Click Activate", "Icons open with one click";
82    NoWebView, FWF_NOWEBVIEW, 0x00010000, "No Web View", "Don't display the folder as a web view";
83    HideFileNames, FWF_HIDEFILENAMES, 0x00020000, "Hide Filenames", "Don't show filenames";
84    CheckSelect, FWF_CHECKSELECT, 0x00040000, "Checkbox Select #0", "Rudiment. Check for fun";
85    NoEnumRefresh, FWF_NOENUMREFRESH, 0x00080000, "No Enumeration Refresh", "Keep existing contents without re-enumerating on refresh";
86    NoGrouping, FWF_NOGROUPING, 0x00100000, "No Grouping", "Don't allow grouping in the view";
87    FullRowSelect, FWF_FULLROWSELECT, 0x00200000, "Full Row Select", "Highlight the item and all its sub-items when selected";
88    NoFilters, FWF_NOFILTERS, 0x00400000, "No Filters", "Don't display filters in the view";
89    NoColumnHeader, FWF_NOCOLUMNHEADER, 0x00800000, "No Column Header", "Don't display a column header in any view mode";
90    NoHeaderInAllViews, FWF_NOHEADERINALLVIEWS, 0x01000000, "Header in Details Only", "Show the column header only in details view";
91    ExtendedTiles, FWF_EXTENDEDTILES, 0x02000000, "Extended Tiles", "Extend each tile to the width of the view";
92    TriCheckSelect, FWF_TRICHECKSELECT, 0x04000000, "Checkbox Select #1", "Rudiment. Check for fun";
93    AutoCheckSelect, FWF_AUTOCHECKSELECT, 0x08000000, "Checkbox Select #2", "Rudiment. Check for fun";
94    NoBrowserViewState, FWF_NOBROWSERVIEWSTATE, 0x10000000, "Don't Save View State", "Don't save view state in the browser";
95    SubsetGroups, FWF_SUBSETGROUPS, 0x20000000, "Subset Groups", "Show the displayed item count in each group";
96    UseSearchFolder, FWF_USESEARCHFOLDER, 0x40000000, "Use Search Folder", "Use the search folder for stacking and searching";
97    AllowRtlReading, FWF_ALLOWRTLREADING, 0x80000000, "Allow Right-to-Left Reading", "Use right-to-left reading layout on right-to-left systems";
98}
99
100impl From<FolderFlag> for u32 {
101    fn from(flag: FolderFlag) -> Self {
102        flag.bits()
103    }
104}
105
106impl std::ops::BitOr for FolderFlag {
107    type Output = Self;
108
109    fn bitor(self, other: Self) -> Self {
110        Self::Raw(self.bits() | other.bits())
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::FolderFlag;
117
118    #[test]
119    fn folder_flag_catalog_is_complete_and_unique() {
120        let expected = std::iter::once(0).chain((0..32).map(|shift| 1u32 << shift));
121        assert_eq!(FolderFlag::ALL.len(), 33);
122        let mut names = std::collections::HashSet::new();
123        for (flag, bits) in FolderFlag::ALL.iter().zip(expected) {
124            assert_eq!(flag.bits(), bits);
125            assert!(names.insert(flag.name().unwrap()));
126            assert!(flag.name().unwrap().starts_with("FWF_"));
127            assert!(!flag.title().unwrap().is_empty());
128            assert!(!flag.description().unwrap().is_empty());
129        }
130    }
131
132    #[test]
133    fn folder_flag_raw_and_combined_masks_are_lossless() {
134        let combined =
135            FolderFlag::AutoArrange | FolderFlag::SnapToGrid | FolderFlag::Raw(0x80000000);
136        assert_eq!(u32::from(combined), 0x80000005);
137        assert_eq!(FolderFlag::Raw(u32::MAX).bits(), u32::MAX);
138        assert_eq!(FolderFlag::Raw(0).bits(), 0);
139        assert_eq!(combined.name(), None);
140        assert_eq!(combined.title(), None);
141        assert_eq!(combined.description(), None);
142    }
143}