use crate::bindings::*;
use crate::icon::IconInfo;
use crate::notify::*;
use crate::utils::{ComBuilder, OkOrEmpty, assert_send_sync, map_array};
use std::sync::RwLock;
use windows::Win32::Foundation::ERROR_LOCK_VIOLATION;
use windows_core::{
ComObject, Error, Event, HSTRING, IInspectable, IUnknownImpl as _, Result, implement,
};
#[doc = include_str!("./bindings_docs/ISeparatorFilterItem.md")]
#[implement(ISeparatorFilterItem, IFilterItem)]
pub struct FilterSeparator;
impl ISeparatorFilterItem_Impl for FilterSeparator_Impl {}
impl IFilterItem_Impl for FilterSeparator_Impl {}
#[doc = include_str!("./bindings_docs/IFilter.md")]
#[implement(IFilter, IFilterItem, INotifyPropChanged)]
pub struct Filter {
name: NotifyLock<HSTRING>,
id: NotifyLock<HSTRING>,
icon: NotifyLock<Option<ComObject<IconInfo>>>,
event: PropChangedEventHandler,
}
pub struct FilterBuilder {
name: HSTRING,
id: HSTRING,
icon: Option<ComObject<IconInfo>>,
}
impl FilterBuilder {
pub fn new() -> Self {
Self {
name: HSTRING::new(),
id: HSTRING::new(),
icon: None,
}
}
pub fn name(mut self, name: impl Into<HSTRING>) -> Self {
self.name = name.into();
self
}
pub fn id(mut self, id: impl Into<HSTRING>) -> Self {
self.id = id.into();
self
}
pub fn icon(mut self, icon: ComObject<IconInfo>) -> Self {
self.icon = Some(icon);
self
}
}
impl ComBuilder for FilterBuilder {
type Output = Filter;
fn build_unmanaged(self) -> Filter {
Filter {
name: NotifyLock::new(self.name),
id: NotifyLock::new(self.id),
icon: NotifyLock::new(self.icon),
event: Event::new(),
}
}
}
impl Default for FilterBuilder {
fn default() -> Self {
Self::new()
}
}
impl IFilter_Impl for Filter_Impl {
fn Icon(&self) -> windows_core::Result<IIconInfo> {
self.icon
.read()?
.as_ref()
.map(|icon| icon.to_interface())
.ok_or_empty()
}
fn Id(&self) -> windows_core::Result<windows_core::HSTRING> {
self.id.read().map(|id| id.clone())
}
fn Name(&self) -> windows_core::Result<windows_core::HSTRING> {
self.name.read().map(|name| name.clone())
}
}
impl INotifyPropChanged_Impl for Filter_Impl {
fn PropChanged(
&self,
handler: windows_core::Ref<
'_,
windows::Foundation::TypedEventHandler<
windows_core::IInspectable,
IPropChangedEventArgs,
>,
>,
) -> windows_core::Result<i64> {
self.event.add(handler.ok()?)
}
fn RemovePropChanged(&self, token: i64) -> windows_core::Result<()> {
self.event.remove(token);
Ok(())
}
}
impl Filter_Impl {
pub(crate) fn emit_prop_changed(&self, sender: IInspectable, prop: &str) {
let args: IPropChangedEventArgs = PropChangedEventArgs(prop.into()).into();
self.event
.call(|handler| handler.Invoke(&sender, &args.clone()));
}
fn emit_self_prop_changed(&self, prop: &str) {
self.emit_prop_changed(self.to_interface(), prop);
}
#[doc = include_str!("./bindings_docs/IFilter/Name.md")]
pub fn name(&self) -> windows_core::Result<NotifyLockReadGuard<'_, windows_core::HSTRING>> {
self.name.read()
}
#[doc = include_str!("./bindings_docs/IFilter/Name.md")]
pub fn name_mut(
&self,
) -> windows_core::Result<NotifyLockWriteGuard<'_, windows_core::HSTRING>> {
self.name.write(|| self.emit_self_prop_changed("Name"))
}
#[doc = include_str!("./bindings_docs/IFilter/Id.md")]
pub fn id(&self) -> windows_core::Result<NotifyLockReadGuard<'_, windows_core::HSTRING>> {
self.id.read()
}
#[doc = include_str!("./bindings_docs/IFilter/Id.md")]
pub fn id_mut(&self) -> windows_core::Result<NotifyLockWriteGuard<'_, windows_core::HSTRING>> {
self.id.write(|| self.emit_self_prop_changed("Id"))
}
#[doc = include_str!("./bindings_docs/IFilter/Icon.md")]
pub fn icon(
&self,
) -> windows_core::Result<NotifyLockReadGuard<'_, Option<ComObject<IconInfo>>>> {
self.icon.read()
}
#[doc = include_str!("./bindings_docs/IFilter/Icon.md")]
pub fn icon_mut(
&self,
) -> windows_core::Result<NotifyLockWriteGuard<'_, Option<ComObject<IconInfo>>>> {
self.icon.write(|| self.emit_self_prop_changed("Icon"))
}
}
impl IFilterItem_Impl for Filter_Impl {}
pub enum FilterItem {
Separator(ComObject<FilterSeparator>),
Filter(ComObject<Filter>),
}
impl From<&FilterItem> for IFilterItem {
fn from(item: &FilterItem) -> Self {
match item {
FilterItem::Separator(item) => item.to_interface(),
FilterItem::Filter(item) => item.to_interface(),
}
}
}
#[implement(IFilters)]
pub struct Filters {
items: Vec<FilterItem>,
current: RwLock<Option<ComObject<Filter>>>,
on_update: Box<
dyn Send + Sync + Fn(Option<ComObject<Filter>>, Option<ComObject<Filter>>) -> Result<()>,
>,
}
pub struct FiltersBuilder {
items: Vec<FilterItem>,
on_update: Box<
dyn Send + Sync + Fn(Option<ComObject<Filter>>, Option<ComObject<Filter>>) -> Result<()>,
>,
}
impl FiltersBuilder {
pub fn new() -> Self {
Self {
items: Vec::new(),
on_update: Box::new(|_, _| Ok(())),
}
}
pub fn add(mut self, item: FilterItem) -> Self {
self.items.push(item);
self
}
pub fn add_filter(mut self, item: ComObject<Filter>) -> Self {
self.items.push(FilterItem::Filter(item));
self
}
pub fn add_separator(mut self) -> Self {
self.items
.push(FilterItem::Separator(ComObject::new(FilterSeparator)));
self
}
pub fn on_update<F>(mut self, func: F) -> Self
where
F: Send
+ Sync
+ Fn(Option<ComObject<Filter>>, Option<ComObject<Filter>>) -> Result<()>
+ 'static,
{
self.on_update = Box::new(func);
self
}
}
impl ComBuilder for FiltersBuilder {
type Output = Filters;
fn build_unmanaged(self) -> Self::Output {
Filters {
items: self.items,
current: RwLock::new(None),
on_update: self.on_update,
}
}
}
impl IFilters_Impl for Filters_Impl {
fn CurrentFilterId(&self) -> windows_core::Result<windows_core::HSTRING> {
self.current
.read()
.map_err(|_| Error::from(ERROR_LOCK_VIOLATION))?
.as_ref()
.ok_or_empty()?
.id()
.map(|id| id.clone())
}
fn GetFilters(&self) -> windows_core::Result<windows_core::Array<IFilterItem>> {
Ok(map_array(&self.items, |filter| {
Some(IFilterItem::from(filter))
}))
}
fn SetCurrentFilterId(&self, value: &windows_core::HSTRING) -> windows_core::Result<()> {
let mut guard = self
.current
.write()
.map_err(|_| Error::from(ERROR_LOCK_VIOLATION))?;
let old = guard.clone();
let mut new = None;
for filter in self.items.iter() {
match filter {
FilterItem::Separator(_) => continue,
FilterItem::Filter(item) => {
if let Some(id) = item.id().ok()
&& *id == *value
{
new = Some(item.clone());
break;
}
}
}
}
*guard = new.clone();
drop(guard);
(self.on_update)(old, new)
}
}
const _: () = assert_send_sync::<Filter>();
const _: () = assert_send_sync::<ComObject<Filters>>();