#include "stdafx.h" #include "resource.h" ///////////////////////////////////////////////////////////////////////////////////////////// struct CTreeItemData { enum EType { Protocol, Status }; EType m_nType; char *m_pszModule; int m_nStatus; }; enum ETreeCheckBoxState { // tree check box state TCBS_NOSTATEBOX = 0, TCBS_UNCHECKED = 1, TCBS_CHECKED = 2, TCBS_DISABLE_UNCHECKED = 3, TCBS_DISABLE_CHECKED = 4, }; HTREEITEM tree_insert_item(HWND hwndTree, wchar_t *pName, HTREEITEM htiParent, ETreeCheckBoxState nState, CTreeItemData *pData) { TVINSERTSTRUCT tvi = {}; tvi.hParent = htiParent; tvi.hInsertAfter = TVI_LAST; tvi.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_STATE; tvi.item.pszText = pName; tvi.item.lParam = reinterpret_cast(pData); tvi.item.stateMask = TVIS_STATEIMAGEMASK; tvi.item.state = INDEXTOSTATEIMAGEMASK(nState); return TreeView_InsertItem(hwndTree, &tvi); } void InitProtocolTree(HWND hwndTreeCtrl) { enum { OFFLINE_STATUS_INDEX = 5 }; for (auto &pAccount : Accounts()) { CTreeItemData *pItemData = new CTreeItemData; pItemData->m_nType = CTreeItemData::Protocol; pItemData->m_pszModule = pAccount->szModuleName; bool bProtocolExcluded = g_Options.IsProtocolExcluded(pAccount->szModuleName); HTREEITEM hti = tree_insert_item(hwndTreeCtrl, pAccount->tszAccountName, TVI_ROOT, ((true == bProtocolExcluded) ? TCBS_CHECKED : TCBS_UNCHECKED), pItemData); if (hti) { int nStatusBits = CallProtoService(pAccount->szModuleName, PS_GETCAPS, PFLAGNUM_2, 0); int nStatusExcluded = CallProtoService(pAccount->szModuleName, PS_GETCAPS, PFLAGNUM_5, 0); pItemData = new CTreeItemData; pItemData->m_nType = CTreeItemData::Status; pItemData->m_pszModule = pAccount->szModuleName; pItemData->m_nStatus = ID_STATUS_OFFLINE; bool bStatusExcluded = g_Options.IsProtocolStatusExcluded(pAccount->szModuleName, pItemData->m_nStatus); ETreeCheckBoxState nState = TCBS_UNCHECKED; if (bProtocolExcluded) { if (bStatusExcluded) nState = TCBS_DISABLE_CHECKED; else nState = TCBS_DISABLE_UNCHECKED; } else { if (bStatusExcluded) nState = TCBS_CHECKED; else nState = TCBS_UNCHECKED; } tree_insert_item(hwndTreeCtrl, TranslateW(g_aStatusCode[OFFLINE_STATUS_INDEX].m_ptszStatusName), hti, nState, pItemData); for (size_t k = 0; k < _countof(g_aStatusCode); ++k) { const CMirandaStatus2SkypeStatus &m2s = g_aStatusCode[k]; unsigned long statusFlags = Proto_Status2Flag(m2s.m_nMirandaStatus); if ((m2s.m_nMirandaStatus != ID_STATUS_OFFLINE) && (nStatusBits & statusFlags) && !(nStatusExcluded & statusFlags)) { pItemData = new CTreeItemData; pItemData->m_nType = CTreeItemData::Status; pItemData->m_pszModule = pAccount->szModuleName; pItemData->m_nStatus = m2s.m_nMirandaStatus; bStatusExcluded = g_Options.IsProtocolStatusExcluded(pAccount->szModuleName, pItemData->m_nStatus); if (bProtocolExcluded) { if (bStatusExcluded) nState = TCBS_DISABLE_CHECKED; else nState = TCBS_DISABLE_UNCHECKED; } else { if (bStatusExcluded) nState = TCBS_CHECKED; else nState = TCBS_UNCHECKED; } tree_insert_item(hwndTreeCtrl, TranslateW(m2s.m_ptszStatusName), hti, nState, pItemData); } } TreeView_Expand(hwndTreeCtrl, hti, TVE_EXPAND); } } } inline HTREEITEM tree_get_child_item(HWND hwndTreeCtrl, HTREEITEM hti) { return TreeView_GetChild(hwndTreeCtrl, hti); } inline HTREEITEM tree_get_next_sibling_item(HWND hwndTreeCtrl, HTREEITEM hti) { return TreeView_GetNextSibling(hwndTreeCtrl, hti); } const CTreeItemData *get_item_data(HWND hwndTreeCtrl, HTREEITEM hti) { TVITEM tvi = { 0 }; tvi.hItem = hti; tvi.mask = TVIF_PARAM | TVIF_HANDLE; if (TRUE == ::SendMessage(hwndTreeCtrl, TVM_GETITEM, 0, reinterpret_cast(&tvi))) { CTreeItemData *pData = reinterpret_cast(tvi.lParam); return pData; } return nullptr; } inline ETreeCheckBoxState tree_get_state_image(HWND hwndTree, HTREEITEM hti) { TVITEM tvi; tvi.hItem = hti; tvi.mask = TVIF_STATE | TVIF_HANDLE; tvi.stateMask = TVIS_STATEIMAGEMASK; if (TRUE == ::SendMessage(hwndTree, TVM_GETITEM, 0, reinterpret_cast(&tvi))) { UINT nState = (tvi.state >> 12); return static_cast(nState); } assert(!"we should never get here!"); return TCBS_UNCHECKED; } void FreeMemory(HWND hwndTreeCtrl, HTREEITEM hti) { for (HTREEITEM h = tree_get_child_item(hwndTreeCtrl, hti); h; h = tree_get_next_sibling_item(hwndTreeCtrl, h)) { FreeMemory(hwndTreeCtrl, h); const CTreeItemData *pData = get_item_data(hwndTreeCtrl, h); if (pData) delete pData; } } bool tree_set_item_state(HWND hwndTree, HTREEITEM hti, ETreeCheckBoxState nState) { TVITEM tvi; memset(&tvi, 0, sizeof(tvi)); tvi.mask = TVIF_STATE | TVIF_HANDLE; tvi.hItem = hti; tvi.stateMask = TVIS_STATEIMAGEMASK; tvi.state = INDEXTOSTATEIMAGEMASK(nState); return TRUE == ::SendMessage(hwndTree, TVM_SETITEM, 0, reinterpret_cast(&tvi)); } void disable_children(HWND hwndTree, HTREEITEM htiParent, bool bDisable) { for (HTREEITEM hti = tree_get_child_item(hwndTree, htiParent); hti; hti = tree_get_next_sibling_item(hwndTree, hti)) { ETreeCheckBoxState nState = tree_get_state_image(hwndTree, hti); if (bDisable) { if (TCBS_CHECKED == nState) nState = TCBS_DISABLE_CHECKED; else if (TCBS_UNCHECKED == nState) nState = TCBS_DISABLE_UNCHECKED; } else { if (TCBS_DISABLE_CHECKED == nState) nState = TCBS_CHECKED; else if (TCBS_DISABLE_UNCHECKED == nState) nState = TCBS_UNCHECKED; } tree_set_item_state(hwndTree, hti, nState); } } void save_exclusion_list(HWND hwndTree, HTREEITEM htiParent) { for (HTREEITEM hti = tree_get_child_item(hwndTree, htiParent); hti; hti = tree_get_next_sibling_item(hwndTree, hti)) { const CTreeItemData *pData = get_item_data(hwndTree, hti); ETreeCheckBoxState nState = tree_get_state_image(hwndTree, hti); if (CTreeItemData::Protocol == pData->m_nType) { g_Options.ExcludeProtocol(pData->m_pszModule, TCBS_CHECKED == nState); save_exclusion_list(hwndTree, hti); } else g_Options.ExcludeProtocolStatus(pData->m_pszModule, pData->m_nStatus, ((TCBS_CHECKED == nState) || (TCBS_DISABLE_CHECKED == nState))); } } static INT_PTR CALLBACK SettingsDlgProc(HWND hdlg, UINT msg, WPARAM wp, LPARAM lp) { switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hdlg); InitProtocolTree(GetDlgItem(hdlg, IDC_TREE_PROTOCOLS)); CheckDlgButton(hdlg, IDC_CHECK_SYNCK_STATUS_MSG, (g_Options.GetSyncStatusMsgFlag()) ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hdlg, IDC_CHECK_STATUSES, (g_Options.GetSyncStatusStateFlag()) ? BST_CHECKED : BST_UNCHECKED); return TRUE; case WM_NOTIFY: { LPNMHDR pNMHDR = reinterpret_cast(lp); switch (pNMHDR->code) { case PSN_APPLY: save_exclusion_list(GetDlgItem(hdlg, IDC_TREE_PROTOCOLS), TVI_ROOT); g_Options.SetSyncStatusMsgFlag(1 == IsDlgButtonChecked(hdlg, IDC_CHECK_SYNCK_STATUS_MSG)); g_Options.SetSyncStatusStateFlag(1 == IsDlgButtonChecked(hdlg, IDC_CHECK_STATUSES)); break; case NM_CLICK: if (IDC_TREE_PROTOCOLS == wp) { uint32_t pos = ::GetMessagePos(); HWND hwndTree = ::GetDlgItem(hdlg, IDC_TREE_PROTOCOLS); TVHITTESTINFO tvhti; tvhti.pt.x = LOWORD(pos); tvhti.pt.y = HIWORD(pos); ::ScreenToClient(hwndTree, &(tvhti.pt)); HTREEITEM hti = reinterpret_cast(::SendMessage(hwndTree, TVM_HITTEST, 0, reinterpret_cast(&tvhti))); if (hti && (tvhti.flags & (TVHT_ONITEMSTATEICON | TVHT_ONITEMICON))) { ETreeCheckBoxState nState = tree_get_state_image(hwndTree, hti); if (TCBS_CHECKED == nState || TCBS_UNCHECKED == nState) { if (TCBS_CHECKED == nState) nState = TCBS_UNCHECKED; else nState = TCBS_CHECKED; tree_set_item_state(hwndTree, hti, nState); disable_children(hwndTree, hti, TCBS_CHECKED == nState); PropSheet_Changed(::GetParent(hdlg), hdlg); } } } } } break; case WM_COMMAND: if (BN_CLICKED == HIWORD(wp) && ((IDC_CHECK_SYNCK_STATUS_MSG == LOWORD(wp)) || (IDC_CHECK_STATUSES == LOWORD(wp)))) PropSheet_Changed(::GetParent(hdlg), hdlg); break; case WM_DESTROY: FreeMemory(GetDlgItem(hdlg, IDC_TREE_PROTOCOLS), TVI_ROOT); break; } return FALSE; } int SSC_OptInitialise(WPARAM wp, LPARAM) { OPTIONSDIALOGPAGE odp = {}; odp.position = 910000000; odp.szTitle.a = LPGEN("Change Skype status"); odp.szGroup.a = LPGEN("Plugins"); odp.pszTemplate = MAKEINTRESOURCEA(IDD_DIALOG_SETTINGS); odp.pfnDlgProc = SettingsDlgProc; g_plugin.addOptions(wp, &odp); return 0; }