/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2003 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ------------------------ implements a simple status floater as a layered (and skinnable) window with a minimalistic UI (change status, access main menu). It also may hold a copy of the event area. Also implementes floating contacts (FLT_*() functions) */ #include #define SNAP_SCREEN_TOLERANCE 10 #define SNAP_FLT_TOLERANCE 10 #define TOOLTIP_TIMER 1 #define MS_TOOLTIP_SHOWTIP "mToolTip/ShowTip" #define MS_TOOLTIP_HIDETIP "mToolTip/HideTip" BYTE __forceinline percent_to_byte(UINT32 percent) { return(BYTE) ((FLOAT) (((FLOAT) percent) / 100) * 255); } void FLT_Update(struct ClcData *dat, ClcContact *contact); void FLT_ShowHideAll(int showCmd); void FLT_SnapToEdges(HWND hwnd); void FLT_SnapToFloater(HWND hwnd); HWND g_hwndSFL = 0; HDC g_SFLCachedDC = 0; HBITMAP g_SFLhbmOld = 0, g_SFLhbm = 0; ContactFloater *pFirstFloater = 0; BOOL hover = FALSE; BOOL tooltip = FALSE; UINT_PTR hTooltipTimer = 0; POINT start_pos; extern StatusItems_t *StatusItems; extern int g_padding_y; extern HIMAGELIST hCListImages; extern HWND g_hwndEventArea; extern HDC g_HDC; extern int g_list_avatars; FLOATINGOPTIONS g_floatoptions; static UINT padctrlIDs[] = { IDC_FLT_PADLEFTSPIN, IDC_FLT_PADRIGHTSPIN, IDC_FLT_PADTOPSPIN, IDC_FLT_PADBOTTOMSPIN, 0 }; /* * floating contacts support functions * simple linked list of allocated ContactFloater* structs */ static ContactFloater *FLT_AddToList(ContactFloater *pFloater) { ContactFloater *pCurrent = pFirstFloater; if ( !pFirstFloater) { pFirstFloater = pFloater; pFirstFloater->pNextFloater = NULL; return pFirstFloater; } else { while (pCurrent->pNextFloater != 0) pCurrent = pCurrent->pNextFloater; pCurrent->pNextFloater = pFloater; pFloater->pNextFloater = NULL; return pCurrent; } } static ContactFloater *FLT_RemoveFromList(ContactFloater *pFloater) { ContactFloater *pCurrent = pFirstFloater; if (pFloater == pFirstFloater) { if (pFloater->pNextFloater != NULL) pFirstFloater = pFloater->pNextFloater; else pFirstFloater = NULL; return pFirstFloater; } do { if (pCurrent->pNextFloater == pFloater) { pCurrent->pNextFloater = pCurrent->pNextFloater->pNextFloater; return 0; } } while (pCurrent = pCurrent->pNextFloater); return NULL; } void FLT_SnapToEdges(HWND hwnd) { RECT dr; MONITORINFO monInfo; RECT rcWindow; HMONITOR curMonitor; if ( API::pfnMonitorFromWindow == NULL ) return; curMonitor = API::pfnMonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); monInfo.cbSize = sizeof(monInfo); API::pfnGetMonitorInfo(curMonitor, &monInfo); dr = monInfo.rcWork; GetWindowRect(hwnd, &rcWindow); if (rcWindow.left < dr.left + SNAP_SCREEN_TOLERANCE){ SetWindowPos(hwnd, HWND_TOPMOST, 0, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); GetWindowRect(hwnd, &rcWindow); } if (rcWindow.top < dr.top + SNAP_SCREEN_TOLERANCE){ SetWindowPos(hwnd, HWND_TOPMOST, rcWindow.left, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER); GetWindowRect(hwnd, &rcWindow); } if (rcWindow.right > dr.right - SNAP_SCREEN_TOLERANCE) SetWindowPos(hwnd, HWND_TOPMOST, dr.right - (rcWindow.right - rcWindow.left), rcWindow.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); if (rcWindow.bottom > dr.bottom - SNAP_SCREEN_TOLERANCE) SetWindowPos(hwnd, HWND_TOPMOST, rcWindow.left, dr.bottom - (rcWindow.bottom - rcWindow.top), 0, 0, SWP_NOSIZE | SWP_NOZORDER); } void FLT_SnapToFloater(HWND hwnd) { ContactFloater *pCurrent = pFirstFloater; RECT rcWindow, rcBase; int minTop = 0xFFFFFF, minBottom = 0xFFFFFF, minRight = 0xFFFFFF, minLeft = 0xFFFFFF; int posTop = 0, posBottom = 0, posRight = 0, posLeft = 0; GetWindowRect(hwnd, &rcBase); //find the closest floater while(pCurrent) { GetWindowRect(pCurrent->hwnd, &rcWindow); //top if ((rcWindow.top - rcBase.bottom > -SNAP_FLT_TOLERANCE) && (rcWindow.top - rcBase.bottom < minTop)) { posTop = rcWindow.top; minTop = rcWindow.top - rcBase.bottom; } //bottom if ((rcBase.top - rcWindow.bottom > -SNAP_FLT_TOLERANCE) && (rcBase.top - rcWindow.bottom < minBottom)) { posBottom = rcWindow.bottom; minBottom = rcBase.top - rcWindow.bottom; } //left if ((rcWindow.left - rcBase.right > -SNAP_FLT_TOLERANCE) && (rcWindow.left - rcBase.right < minLeft)) { posLeft= rcWindow.left; minLeft = rcWindow.left - rcBase.right; } //right if ((rcBase.left - rcWindow.right > -SNAP_FLT_TOLERANCE) && (rcBase.left - rcWindow.right < minRight)) { posRight= rcWindow.right; minRight = rcBase.left - rcWindow.right; } pCurrent = pCurrent->pNextFloater; } //snap to the closest floater if spacing is under SNAP_FLT_TOLERANCE if (posTop && (rcBase.bottom > posTop - SNAP_FLT_TOLERANCE)) SetWindowPos(hwnd, HWND_TOPMOST, rcBase.left, posTop - (rcBase.bottom - rcBase.top), 0, 0, SWP_NOSIZE | SWP_NOZORDER); if (posBottom && (rcBase.top < posBottom + SNAP_FLT_TOLERANCE)) SetWindowPos(hwnd, HWND_TOPMOST, rcBase.left, posBottom, 0, 0, SWP_NOSIZE | SWP_NOZORDER); if (posLeft && (rcBase.right > posLeft - SNAP_FLT_TOLERANCE)) SetWindowPos(hwnd, HWND_TOPMOST, posLeft - (rcBase.right - rcBase.left), rcBase.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); if (posRight && (rcBase.left < posRight + SNAP_FLT_TOLERANCE)) SetWindowPos(hwnd, HWND_TOPMOST, posRight, rcBase.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } /* * dialog procedure for the floating contacts option page */ INT_PTR CALLBACK DlgProcFloatingContacts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_INITDIALOG: { DWORD dwFlags = g_floatoptions.dwFlags; int i = 0; TranslateDialogDefault(hwndDlg); CheckDlgButton(hwndDlg, IDC_FLT_ENABLED, g_floatoptions.enabled); SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_ENABLED, 0); CheckDlgButton(hwndDlg, IDC_FLT_SIMPLELAYOUT, dwFlags & FLT_SIMPLE); SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_SIMPLELAYOUT, 0); CheckDlgButton(hwndDlg, IDC_FLT_AVATARS, dwFlags & FLT_AVATARS); CheckDlgButton(hwndDlg, IDC_FLT_DUALROWS, dwFlags & FLT_DUALROW); CheckDlgButton(hwndDlg, IDC_FLT_EXTRAICONS, dwFlags & FLT_EXTRAICONS); CheckDlgButton(hwndDlg, IDC_FLT_SYNCED, dwFlags & FLT_SYNCWITHCLIST); CheckDlgButton(hwndDlg, IDC_FLT_AUTOHIDE, dwFlags & FLT_AUTOHIDE); CheckDlgButton(hwndDlg, IDC_FLT_SNAP, dwFlags & FLT_SNAP); CheckDlgButton(hwndDlg, IDC_FLT_BORDER, dwFlags & FLT_BORDER); SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_BORDER, 0); CheckDlgButton(hwndDlg, IDC_FLT_ROUNDED, dwFlags & FLT_ROUNDED); CheckDlgButton(hwndDlg, IDC_FLT_FILLSTD, dwFlags & FLT_FILLSTDCOLOR); SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_ROUNDED, 0); if (ServiceExists(MS_TOOLTIP_SHOWTIP)) { CheckDlgButton(hwndDlg, IDC_FLT_SHOWTOOLTIPS, dwFlags & FLT_SHOWTOOLTIPS); SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_SHOWTOOLTIPS, 0); CheckDlgButton(hwndDlg, IDC_FLT_DEFHOVERTIME, g_floatoptions.def_hover_time); SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_DEFHOVERTIME, 0); } else { CheckDlgButton(hwndDlg, IDC_FLT_SHOWTOOLTIPS, 0); Utils::enableDlgControl(hwndDlg, IDC_FLT_SHOWTOOLTIPS, 0); } for (i = 0; padctrlIDs[i] != 0; i++) SendDlgItemMessage(hwndDlg, padctrlIDs[i], UDM_SETRANGE, 0, MAKELONG(20, 0)); SendDlgItemMessage(hwndDlg, IDC_FLT_WIDTHSPIN, UDM_SETRANGE, 0, MAKELONG(200, 50)); SendDlgItemMessage(hwndDlg, IDC_FLT_RADIUSSPIN, UDM_SETRANGE, 0, MAKELONG(20, 1)); SendDlgItemMessage(hwndDlg, IDC_FLT_HOVERTIMESPIN, UDM_SETRANGE, 0, MAKELONG(5000, 1)); SendDlgItemMessage(hwndDlg, IDC_FLT_PADLEFTSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_left); SendDlgItemMessage(hwndDlg, IDC_FLT_PADRIGHTSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_right); SendDlgItemMessage(hwndDlg, IDC_FLT_PADTOPSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_top); SendDlgItemMessage(hwndDlg, IDC_FLT_PADBOTTOMSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.pad_top); SendDlgItemMessage(hwndDlg, IDC_FLT_WIDTHSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.width); SendDlgItemMessage(hwndDlg, IDC_FLT_RADIUSSPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.radius); SendDlgItemMessage(hwndDlg, IDC_FLT_HOVERTIMESPIN, UDM_SETPOS, 0, (LPARAM)g_floatoptions.hover_time); SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_SETRANGE, FALSE, MAKELONG(1, 255)); SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_SETPOS, TRUE, g_floatoptions.act_trans); SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_SETRANGE, FALSE, MAKELONG(1, 255)); SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_SETPOS, TRUE, g_floatoptions.trans); SendMessage(hwndDlg, WM_HSCROLL, 0, 0); SendDlgItemMessage(hwndDlg, IDC_FLT_BORDERCOLOUR, CPM_SETDEFAULTCOLOUR, 0, 0); SendDlgItemMessage(hwndDlg, IDC_FLT_BORDERCOLOUR, CPM_SETCOLOUR, 0, g_floatoptions.border_colour); FLT_ShowHideAll(SW_SHOWNOACTIVATE); } return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_FLT_ENABLED: { int isEnabled = IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED); int isSimple = IsDlgButtonChecked(hwndDlg, IDC_FLT_SIMPLELAYOUT); int isBorder = IsDlgButtonChecked(hwndDlg, IDC_FLT_BORDER); int isRounded = IsDlgButtonChecked(hwndDlg, IDC_FLT_ROUNDED); int isTooltip = IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS); int isDefHoverTime = IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME); Utils::enableDlgControl(hwndDlg, IDC_FLT_SIMPLELAYOUT, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_SYNCED, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_AUTOHIDE, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_SNAP, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_ACTIVEOPACITY, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_OPACITY, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_PADLEFTSPIN, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_PADRIGHTSPIN, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_PADTOPSPIN, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_PADLEFT, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_PADRIGHT, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_PADTOP, isEnabled); //EnableWindow(GetDlgItem(hwndDlg, IDC_FLT_PADBOTTOMSPIN), isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_PADBOTTOM, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_WIDTHSPIN, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_WIDTH, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_BORDER, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_ROUNDED, isEnabled); Utils::enableDlgControl(hwndDlg, IDC_FLT_BORDERCOLOUR, isEnabled & isBorder); Utils::enableDlgControl(hwndDlg, IDC_FLT_RADIUS, isEnabled & isRounded); Utils::enableDlgControl(hwndDlg, IDC_FLT_RADIUSSPIN, isEnabled & isRounded); Utils::enableDlgControl(hwndDlg, IDC_FLT_SHOWTOOLTIPS, isEnabled & ServiceExists(MS_TOOLTIP_SHOWTIP)); Utils::enableDlgControl(hwndDlg, IDC_FLT_DEFHOVERTIME, isEnabled & isTooltip); Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIME, isEnabled & isTooltip & !isDefHoverTime); Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIMESPIN, isEnabled & isTooltip & !isDefHoverTime); Utils::enableDlgControl(hwndDlg, IDC_FLT_AVATARS, isEnabled & !isSimple); Utils::enableDlgControl(hwndDlg, IDC_FLT_EXTRAICONS, isEnabled & !isSimple); Utils::enableDlgControl(hwndDlg, IDC_FLT_DUALROWS, isEnabled & !isSimple); } break; case IDC_FLT_SIMPLELAYOUT: if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED)) { int isSimple = IsDlgButtonChecked(hwndDlg, IDC_FLT_SIMPLELAYOUT); Utils::enableDlgControl(hwndDlg, IDC_FLT_AVATARS, !isSimple); Utils::enableDlgControl(hwndDlg, IDC_FLT_EXTRAICONS, !isSimple); Utils::enableDlgControl(hwndDlg, IDC_FLT_DUALROWS, !isSimple); } break; case IDC_FLT_BORDER: if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED)) { int isBorder = IsDlgButtonChecked(hwndDlg, IDC_FLT_BORDER); Utils::enableDlgControl(hwndDlg, IDC_FLT_BORDERCOLOUR, isBorder); } break; case IDC_FLT_ROUNDED: if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED)) { int isRounded = IsDlgButtonChecked(hwndDlg, IDC_FLT_ROUNDED); Utils::enableDlgControl(hwndDlg, IDC_FLT_RADIUS, isRounded); Utils::enableDlgControl(hwndDlg, IDC_FLT_RADIUSSPIN, isRounded); } break; case IDC_FLT_SHOWTOOLTIPS: if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED)) { int isTooltip = IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS); int isDefHoverTime = IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME); Utils::enableDlgControl(hwndDlg, IDC_FLT_DEFHOVERTIME, isTooltip); Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIME, isTooltip & !isDefHoverTime); Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIMESPIN, isTooltip & !isDefHoverTime); } break; case IDC_FLT_DEFHOVERTIME: if (IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED) && IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS)) { int isDefHoverTime = IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME); Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIME, !isDefHoverTime); Utils::enableDlgControl(hwndDlg, IDC_FLT_HOVERTIMESPIN, !isDefHoverTime); } break; case IDC_FLT_PADTOP: if (HIWORD(wParam) == EN_CHANGE){ int value = SendDlgItemMessage(hwndDlg, IDC_FLT_PADTOPSPIN, UDM_GETPOS, 0, 0); SendDlgItemMessage(hwndDlg, IDC_FLT_PADBOTTOMSPIN, UDM_SETPOS, 0, (LPARAM)value); } break; } SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); break; case WM_HSCROLL: { char str[10]; wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_GETPOS, 0, 0) / 255); SetDlgItemTextA(hwndDlg, IDC_FLT_ACTIVEOPACITYVALUE, str); wsprintfA(str, "%d%%", 100 * SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_GETPOS, 0, 0) / 255); SetDlgItemTextA(hwndDlg, IDC_FLT_OPACITYVALUE, str); if (lParam) SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); } break; case WM_NOTIFY: switch (((LPNMHDR) lParam)->idFrom) { case 0: if (((LPNMHDR) lParam)->code == PSN_APPLY) { g_floatoptions.enabled = IsDlgButtonChecked(hwndDlg, IDC_FLT_ENABLED) ? 1 : 0; g_floatoptions.dwFlags = 0; if (IsDlgButtonChecked(hwndDlg, IDC_FLT_SIMPLELAYOUT)) g_floatoptions.dwFlags = FLT_SIMPLE; g_floatoptions.dwFlags |= (IsDlgButtonChecked(hwndDlg, IDC_FLT_AVATARS) ? FLT_AVATARS : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_DUALROWS) ? FLT_DUALROW : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_EXTRAICONS) ? FLT_EXTRAICONS : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_SYNCED) ? FLT_SYNCWITHCLIST : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_AUTOHIDE) ? FLT_AUTOHIDE : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_SNAP) ? FLT_SNAP : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_BORDER) ? FLT_BORDER : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_FILLSTD) ? FLT_FILLSTDCOLOR : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS) ? FLT_SHOWTOOLTIPS : 0) | (IsDlgButtonChecked(hwndDlg, IDC_FLT_ROUNDED) ? FLT_ROUNDED : 0); g_floatoptions.act_trans = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_ACTIVEOPACITY, TBM_GETPOS, 0, 0); g_floatoptions.trans = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_OPACITY, TBM_GETPOS, 0, 0); g_floatoptions.pad_left = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADLEFTSPIN, UDM_GETPOS, 0, 0); g_floatoptions.pad_right = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADRIGHTSPIN, UDM_GETPOS, 0, 0); g_floatoptions.pad_top = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADTOPSPIN, UDM_GETPOS, 0, 0); g_floatoptions.pad_bottom = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_PADBOTTOMSPIN, UDM_GETPOS, 0, 0); g_floatoptions.width = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_WIDTHSPIN, UDM_GETPOS, 0, 0); g_floatoptions.radius = (BYTE)SendDlgItemMessage(hwndDlg, IDC_FLT_RADIUSSPIN, UDM_GETPOS, 0, 0); g_floatoptions.border_colour = SendDlgItemMessage(hwndDlg, IDC_FLT_BORDERCOLOUR, CPM_GETCOLOUR, 0, 0); g_floatoptions.def_hover_time= IsDlgButtonChecked(hwndDlg, IDC_FLT_DEFHOVERTIME) ? 1 : 0; if (g_floatoptions.def_hover_time) g_floatoptions.hover_time = cfg::getWord("CLC", "InfoTipHoverTime", 200); else g_floatoptions.hover_time = (WORD)SendDlgItemMessage(hwndDlg, IDC_FLT_HOVERTIMESPIN, UDM_GETPOS, 0, 0); FLT_WriteOptions(); FLT_RefreshAll(); return TRUE; } break; } break; } return FALSE; } void FLT_ReadOptions() { ZeroMemory(&g_floatoptions, sizeof(FLOATINGOPTIONS)); g_floatoptions.enabled = cfg::getByte("CList", "flt_enabled", 0); g_floatoptions.dwFlags = cfg::getDword("CList", "flt_flags", FLT_SIMPLE); DWORD dwPad = cfg::getDword("CList", "flt_padding", 0); g_floatoptions.pad_top = LOBYTE(LOWORD(dwPad)); g_floatoptions.pad_right = HIBYTE(LOWORD(dwPad)); g_floatoptions.pad_bottom = LOBYTE(HIWORD(dwPad)); g_floatoptions.pad_left = HIBYTE(HIWORD(dwPad)); g_floatoptions.width = cfg::getDword("CList", "flt_width", 100); g_floatoptions.act_trans = cfg::getByte("CList", "flt_acttrans", 255); g_floatoptions.trans = cfg::getByte("CList", "flt_trans", 255); g_floatoptions.radius = cfg::getByte("CList", "flt_radius", 3); g_floatoptions.border_colour = cfg::getDword("CList", "flt_bordercolour", 0); g_floatoptions.def_hover_time = cfg::getByte("CList", "flt_defhovertime", 1); if (g_floatoptions.def_hover_time) g_floatoptions.hover_time = cfg::getWord("CLC", "InfoTipHoverTime", 200); else g_floatoptions.hover_time = cfg::getWord("CList", "flt_hovertime", 200); } void FLT_WriteOptions() { cfg::writeByte("CList", "flt_enabled", g_floatoptions.enabled); cfg::writeDword("CList", "flt_flags", g_floatoptions.dwFlags); DWORD dwPad = MAKELONG(MAKEWORD(g_floatoptions.pad_top, g_floatoptions.pad_right), MAKEWORD(g_floatoptions.pad_bottom, g_floatoptions.pad_left)); cfg::writeDword("CList", "flt_padding", dwPad); cfg::writeDword("CList", "flt_width", g_floatoptions.width); cfg::writeByte("CList", "flt_acttrans", g_floatoptions.act_trans); cfg::writeByte("CList", "flt_trans", g_floatoptions.trans); cfg::writeByte("CList", "flt_radius", g_floatoptions.radius); cfg::writeDword("CList", "flt_bordercolour", g_floatoptions.border_colour); cfg::writeByte("CList", "flt_defhovertime", g_floatoptions.def_hover_time); if ( !g_floatoptions.def_hover_time) cfg::writeWord("CList", "flt_hovertime", g_floatoptions.hover_time); } LRESULT CALLBACK StatusFloaterClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DESTROY: Utils_SaveWindowPosition(hwnd, 0, "CLUI", "sfl"); if (g_SFLCachedDC) { SelectObject(g_SFLCachedDC, g_SFLhbmOld); DeleteObject(g_SFLhbm); DeleteDC(g_SFLCachedDC); g_SFLCachedDC = 0; } break; case WM_ERASEBKGND: return TRUE; case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint(hwnd, &ps); ps.fErase = FALSE; EndPaint(hwnd, &ps); } return TRUE; case WM_LBUTTONDOWN: { POINT ptMouse; RECT rcWindow; GetCursorPos(&ptMouse); GetWindowRect(hwnd, &rcWindow); rcWindow.right = rcWindow.left + 25; if ( !PtInRect(&rcWindow, ptMouse)) return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(ptMouse.x, ptMouse.y)); } break; case WM_LBUTTONUP: { HMENU hmenu = (HMENU)CallService(MS_CLIST_MENUGETSTATUS, 0, 0); RECT rcWindow; POINT pt; GetCursorPos(&pt); GetWindowRect(hwnd, &rcWindow); if (cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS) { if (pt.y > rcWindow.top + ((rcWindow.bottom - rcWindow.top) / 2)) SendMessage(g_hwndEventArea, WM_COMMAND, MAKEWPARAM(IDC_NOTIFYBUTTON, 0), 0); else TrackPopupMenu(hmenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, pcli->hwndContactList, NULL); } else TrackPopupMenu(hmenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, pcli->hwndContactList, NULL); } return 0; case WM_CONTEXTMENU: { HMENU hmenu = (HMENU)CallService(MS_CLIST_MENUGETMAIN, 0, 0); RECT rcWindow; GetWindowRect(hwnd, &rcWindow); TrackPopupMenu(hmenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, pcli->hwndContactList, NULL); } return 0; } return DefWindowProc(hwnd, msg, wParam, lParam); } void CALLBACK ShowTooltip(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { ContactFloater *pCurrent = pFirstFloater; POINT pt; CLCINFOTIP ti = {0}; KillTimer(hwnd, TOOLTIP_TIMER); hTooltipTimer = 0; GetCursorPos(&pt); if ((abs(pt.x - start_pos.x) > 3) && (abs(pt.y - start_pos.y) > 3)) return; while(pCurrent->hwnd != hwnd) pCurrent = pCurrent->pNextFloater; ti.cbSize = sizeof(ti); ti.isGroup = 0; ti.isTreeFocused = 0; ti.hItem = pCurrent->hContact; ti.ptCursor = pt; CallService(MS_TOOLTIP_SHOWTIP, 0, (LPARAM)&ti); tooltip = TRUE; } LRESULT CALLBACK ContactFloaterClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { INT_PTR iEntry = GetWindowLongPtr(hwnd, GWLP_USERDATA); struct TExtraCache *centry = NULL; if (iEntry >= 0 && iEntry < cfg::nextCacheEntry) centry = &cfg::eCache[iEntry]; switch(msg) { case WM_NCCREATE: { CREATESTRUCT *cs = (CREATESTRUCT *)lParam; SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)cs->lpCreateParams); iEntry = (int)cs->lpCreateParams; if (iEntry >= 0 && iEntry < cfg::nextCacheEntry) centry = &cfg::eCache[iEntry]; return TRUE; } case WM_DESTROY: if (centry) { WINDOWPLACEMENT wp = {0}; SelectObject(centry->floater->hdc, centry->floater->hbmOld); DeleteObject(centry->floater->hbm); DeleteDC(centry->floater->hdc); FLT_RemoveFromList(centry->floater); free(centry->floater); centry->floater = 0; Utils_SaveWindowPosition(hwnd, centry->hContact, "CList", "flt"); break; } case WM_ERASEBKGND: return TRUE; case WM_PAINT: { HDC hdc; PAINTSTRUCT ps; hdc = BeginPaint(hwnd, &ps); ps.fErase = FALSE; EndPaint(hwnd, &ps); return TRUE; } case WM_LBUTTONDBLCLK: if (centry) CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)centry->hContact, 0); return 0; case WM_LBUTTONDOWN: { POINT ptMouse; RECT rcWindow; GetCursorPos(&ptMouse); GetWindowRect(hwnd, &rcWindow); rcWindow.right = rcWindow.left + 25; if ( !PtInRect(&rcWindow, ptMouse)) return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(ptMouse.x, ptMouse.y)); break; } case WM_MOUSEMOVE: if ( API::pfnTrackMouseEvent && !hover ) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_HOVER | TME_LEAVE; tme.hwndTrack = hwnd; tme.dwHoverTime = 5; API::pfnTrackMouseEvent(&tme); hover = TRUE; } if ( ServiceExists( MS_TOOLTIP_SHOWTIP )) { if ((g_floatoptions.dwFlags & FLT_SHOWTOOLTIPS) && !tooltip) { GetCursorPos(&start_pos); if (hTooltipTimer) KillTimer(hwnd, TOOLTIP_TIMER); hTooltipTimer = SetTimer(hwnd, TOOLTIP_TIMER, g_floatoptions.hover_time, ShowTooltip); } } return FALSE; case WM_MOUSEHOVER: { ClcContact *contact = NULL; ContactFloater *pCurrent = pFirstFloater; int oldTrans = g_floatoptions.trans; while(pCurrent->hwnd != hwnd) pCurrent = pCurrent->pNextFloater; if (FindItem(pcli->hwndContactTree, cfg::clcdat, pCurrent->hContact, &contact, NULL, 0)) { g_floatoptions.trans = g_floatoptions.act_trans; FLT_Update(cfg::clcdat, contact); g_floatoptions.trans = oldTrans; } break; } case WM_MOUSELEAVE: { ClcContact *contact = NULL; ContactFloater *pCurrent = pFirstFloater; while(pCurrent->hwnd != hwnd) pCurrent = pCurrent->pNextFloater; if (FindItem(pcli->hwndContactTree, cfg::clcdat, pCurrent->hContact, &contact, NULL, 0)) FLT_Update(cfg::clcdat, contact); if (hTooltipTimer) { KillTimer(hwnd, TOOLTIP_TIMER); hTooltipTimer = 0; } if (tooltip) CallService(MS_TOOLTIP_HIDETIP, 0, 0); hover = FALSE; tooltip = FALSE; break; } case WM_MOVE: { if (g_floatoptions.dwFlags & FLT_SNAP) FLT_SnapToEdges(hwnd); if (GetKeyState(VK_CONTROL) < 0) FLT_SnapToFloater(hwnd); break; } case WM_MEASUREITEM: return(CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam)); case WM_DRAWITEM: return(CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam)); case WM_COMMAND: return(CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKELONG(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)centry->hContact)); case WM_CONTEXTMENU: { if (centry) { HMENU hContactMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)centry->hContact, 0); RECT rcWindow; GetWindowRect(hwnd, &rcWindow); TrackPopupMenu(hContactMenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_RIGHTBUTTON, rcWindow.left, rcWindow.bottom, 0, hwnd, NULL); DestroyMenu(hContactMenu); return 0; } break; } } return DefWindowProc(hwnd, msg, wParam, lParam); } void SFL_RegisterWindowClass() { WNDCLASS wndclass; wndclass.style = 0; wndclass.lpfnWndProc = StatusFloaterClassProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_hInst; wndclass.hIcon = 0; wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE); wndclass.lpszMenuName = 0; wndclass.lpszClassName = _T("StatusFloaterClass"); RegisterClass(&wndclass); wndclass.style = CS_DBLCLKS; wndclass.lpszClassName = _T("ContactFloaterClass"); wndclass.lpfnWndProc = ContactFloaterClassProc; RegisterClass(&wndclass); } void SFL_UnregisterWindowClass() { UnregisterClass(_T("StatusFloaterClass"), g_hInst); UnregisterClass(_T("ContactFloaterClass"), g_hInst); } void SFL_Destroy() { if (g_hwndSFL) DestroyWindow(g_hwndSFL); g_hwndSFL = 0; } static HICON sfl_hIcon = (HICON)-1; static int sfl_iIcon = -1; static TCHAR sfl_statustext[100] = _T(""); void SFL_Update(HICON hIcon, int iIcon, HIMAGELIST hIml, const TCHAR *szText, BOOL refresh) { RECT rcClient, rcWindow; POINT ptDest, ptSrc = {0}; SIZE szDest, szT; BLENDFUNCTION bf = {0}; HFONT hOldFont; StatusItems_t *item = &StatusItems[ID_EXTBKSTATUSFLOATER - ID_STATUS_OFFLINE]; RECT rcStatusArea; LONG cy; if (g_hwndSFL == 0) return; GetClientRect(g_hwndSFL, &rcClient); GetWindowRect(g_hwndSFL, &rcWindow); ptDest.x = rcWindow.left; ptDest.y = rcWindow.top; szDest.cx = rcWindow.right - rcWindow.left; szDest.cy = rcWindow.bottom - rcWindow.top; if (item->IGNORED) { FillRect(g_SFLCachedDC, &rcClient, GetSysColorBrush(COLOR_3DFACE)); SetTextColor(g_SFLCachedDC, GetSysColor(COLOR_BTNTEXT)); } else { FillRect(g_SFLCachedDC, &rcClient, GetSysColorBrush(COLOR_3DFACE)); DrawAlpha(g_SFLCachedDC, &rcClient, item->COLOR, 100, item->COLOR2, item->COLOR2_TRANSPARENT, item->GRADIENT, item->CORNER, item->BORDERSTYLE, item->imageItem); SetTextColor(g_SFLCachedDC, item->TEXTCOLOR); } bf.BlendOp = AC_SRC_OVER; bf.AlphaFormat = 0; bf.SourceConstantAlpha = item->IGNORED ? 255 : percent_to_byte(item->ALPHA); rcStatusArea = rcClient; if (cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS) rcStatusArea.bottom = 20; cy = rcStatusArea.bottom - rcStatusArea.top; if (szText != NULL && refresh) { _tcsncpy(sfl_statustext, szText, 100); sfl_statustext[99] = 0; } if ( !hIcon) { HICON p_hIcon; if (refresh) sfl_iIcon = iIcon; if (sfl_iIcon != -1) { p_hIcon = ImageList_ExtractIcon(0, hCListImages, sfl_iIcon); DrawIconEx(g_SFLCachedDC, 5, (cy - 16) / 2, p_hIcon, 16, 16, 0, 0, DI_NORMAL); DestroyIcon(p_hIcon); } } else { if (refresh) sfl_hIcon = hIcon; if (sfl_hIcon != (HICON)-1) DrawIconEx(g_SFLCachedDC, 5, (cy - 16) / 2, sfl_hIcon, 16, 16, 0, 0, DI_NORMAL); } hOldFont = reinterpret_cast(SelectObject(g_SFLCachedDC, GetStockObject(DEFAULT_GUI_FONT))); SetBkMode(g_SFLCachedDC, TRANSPARENT); GetTextExtentPoint32(g_SFLCachedDC, sfl_statustext, lstrlen(sfl_statustext), &szT); TextOut(g_SFLCachedDC, 24, (cy - szT.cy) / 2, sfl_statustext, lstrlen(sfl_statustext)); if (cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS) { RECT rcNA = rcClient; rcNA.top = 18; PaintNotifyArea(g_SFLCachedDC, &rcNA); } SelectObject(g_SFLCachedDC, hOldFont); if (API::pfnUpdateLayeredWindow) API::pfnUpdateLayeredWindow(g_hwndSFL, 0, &ptDest, &szDest, g_SFLCachedDC, &ptSrc, GetSysColor(COLOR_3DFACE), &bf, ULW_ALPHA | ULW_COLORKEY); } /* * set the floater * mode = 0/1 forced hide/show * OR -1 to set it depending on the clist state (visible/hidden) (this is actually reversed, because the function * is called *before* the clist is shown or hidden) */ void SFL_SetState(int uMode) { BYTE bClistState; if (g_hwndSFL == 0 || !(cfg::dat.bUseFloater & CLUI_USE_FLOATER)) return; if (uMode == -1) { if (cfg::dat.bUseFloater & CLUI_FLOATER_AUTOHIDE) { bClistState = cfg::getByte("CList", "State", SETTING_STATE_NORMAL); ShowWindow(g_hwndSFL, bClistState == SETTING_STATE_NORMAL ? SW_SHOW : SW_HIDE); } else ShowWindow(g_hwndSFL, SW_SHOW); } else ShowWindow(g_hwndSFL, uMode ? SW_SHOW : SW_HIDE); } // XXX improve size calculations for the floater window. void SFL_SetSize() { HDC hdc; LONG lWidth; RECT rcWindow; SIZE sz; char *szStatusMode; HFONT oldFont; int i; GetWindowRect(g_hwndSFL, &rcWindow); lWidth = rcWindow.right - rcWindow.left; hdc = GetDC(g_hwndSFL); oldFont = reinterpret_cast(SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT))); for (i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) { szStatusMode = Translate((char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)i, 0)); GetTextExtentPoint32A(hdc, szStatusMode, lstrlenA(szStatusMode), &sz); lWidth = max(lWidth, sz.cx + 16 + 8); } SetWindowPos(g_hwndSFL, HWND_TOPMOST, rcWindow.left, rcWindow.top, lWidth, max(cfg::dat.bUseFloater & CLUI_FLOATER_EVENTS ? 36 : 20, sz.cy + 4), SWP_SHOWWINDOW); GetWindowRect(g_hwndSFL, &rcWindow); if (g_SFLCachedDC) { SelectObject(g_SFLCachedDC, g_SFLhbmOld); DeleteObject(g_SFLhbm); DeleteDC(g_SFLCachedDC); g_SFLCachedDC = 0; } g_SFLCachedDC = CreateCompatibleDC(hdc); g_SFLhbm = CreateCompatibleBitmap(hdc, lWidth, rcWindow.bottom - rcWindow.top); g_SFLhbmOld = reinterpret_cast(SelectObject(g_SFLCachedDC, g_SFLhbm)); ReleaseDC(g_hwndSFL, hdc); CluiProtocolStatusChanged(0, 0); } void SFL_Create() { if (g_hwndSFL == 0 && cfg::dat.bUseFloater & CLUI_USE_FLOATER && API::pfnUpdateLayeredWindow != NULL) g_hwndSFL = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED, _T("StatusFloaterClass"), _T("sfl"), WS_VISIBLE, 0, 0, 0, 0, 0, 0, g_hInst, 0); else return; SetWindowLongPtr(g_hwndSFL, GWL_STYLE, GetWindowLongPtr(g_hwndSFL, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW)); Utils_RestoreWindowPosition(g_hwndSFL, 0, "CLUI", "sfl"); SFL_SetSize(); } void FLT_SetSize(struct TExtraCache *centry, LONG width, LONG height) { HDC hdc; RECT rcWindow; HFONT oldFont; int flags = SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOACTIVATE; int iVis = pcli->pfnGetWindowVisibleState(pcli->hwndContactList, 0, 0); if ((g_floatoptions.dwFlags & FLT_AUTOHIDE) && (iVis == 2 || iVis == 4)) //2 = GWVS_VISIBLE, 4 = GWVS_PARTIALLY_COVERED flags = SWP_NOMOVE | SWP_NOACTIVATE; if (centry->floater) { hdc = GetDC(centry->floater->hwnd); oldFont = reinterpret_cast(SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT))); SetWindowPos(centry->floater->hwnd, HWND_TOPMOST, 0, 0, width, height, flags); GetWindowRect(centry->floater->hwnd, &rcWindow); if (centry->floater->hdc) { SelectObject(centry->floater->hdc, centry->floater->hbmOld); DeleteObject(centry->floater->hbm); DeleteDC(centry->floater->hdc); centry->floater->hdc = 0; } centry->floater->hdc = CreateCompatibleDC(hdc); centry->floater->hbm = CreateCompatibleBitmap(hdc, width, rcWindow.bottom - rcWindow.top); centry->floater->hbmOld= reinterpret_cast(SelectObject(centry->floater->hdc, centry->floater->hbm)); ReleaseDC(centry->floater->hwnd, hdc); } } void FLT_Create(int iEntry) { struct TExtraCache *centry = NULL; if (iEntry >= 0 && iEntry < cfg::nextCacheEntry) { ClcContact *contact = NULL; ClcGroup *group = NULL; centry = &cfg::eCache[iEntry]; if (centry->floater == 0 && API::pfnUpdateLayeredWindow != NULL) { centry->floater = (ContactFloater *)malloc(sizeof(ContactFloater)); if (centry->floater == NULL) return; FLT_AddToList(centry->floater); centry->floater->hwnd = CreateWindowEx(WS_EX_TOOLWINDOW | WS_EX_LAYERED, _T("ContactFloaterClass"), _T("sfl"), WS_VISIBLE, 0, 0, 0, 0, 0, 0, g_hInst, (LPVOID)iEntry); centry->floater->hContact = centry->hContact; } else if (centry->floater != NULL) { ShowWindow(centry->floater->hwnd, SW_SHOWNOACTIVATE); return; } SetWindowLongPtr(centry->floater->hwnd, GWL_STYLE, GetWindowLongPtr(centry->floater->hwnd, GWL_STYLE) & ~(WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_OVERLAPPEDWINDOW | WS_POPUPWINDOW)); if (Utils_RestoreWindowPosition(centry->floater->hwnd, centry->hContact, "CList", "flt")) if (Utils_RestoreWindowPositionNoMove(centry->floater->hwnd, centry->hContact, "CList", "flt")) SetWindowPos(centry->floater->hwnd, 0, 50, 50, 150, 30, SWP_NOZORDER | SWP_NOACTIVATE); //FLT_SetSize(centry, 100, 20); ShowWindow(centry->floater->hwnd, SW_SHOWNOACTIVATE); if (FindItem(pcli->hwndContactTree, cfg::clcdat, centry->hContact, &contact, &group, 0)) { if (contact) FLT_Update(cfg::clcdat, contact); } } } extern HDC hdcAV; extern HDC hdcTempAV; extern HBITMAP hbmTempAV, hbmTempOldAV; extern LONG g_maxAV_X, g_maxAV_Y; void FLT_Update(struct ClcData *dat, ClcContact *contact) { RECT rcClient, rcWindow; POINT ptSrc = {0}; ClcGroup *group = NULL; ClcContact *newContact = NULL; HRGN rgn; if (contact == NULL || dat == NULL) return; if (contact->extraCacheEntry < 0 || contact->extraCacheEntry >= cfg::nextCacheEntry) return; if (cfg::eCache[contact->extraCacheEntry].floater == NULL) return; FLT_SetSize(&cfg::eCache[contact->extraCacheEntry], g_floatoptions.width, RowHeight::getFloatingRowHeight(dat, pcli->hwndContactTree, contact, g_floatoptions.dwFlags) + (2*g_floatoptions.pad_top)); HWND hwnd = cfg::eCache[contact->extraCacheEntry].floater->hwnd; HDC hdc = cfg::eCache[contact->extraCacheEntry].floater->hdc; if (hwnd == 0) return; GetClientRect(hwnd, &rcClient); GetWindowRect(hwnd, &rcWindow); POINT ptDest = {rcWindow.left, rcWindow.top }; SIZE szDest = {rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top}; /* * fill with a DESATURATED representation of the clist bg color and use this later as a color key */ float greyLevel = (float)(GetRValue(cfg::clcdat->bkColour) * 0.299 + GetGValue(cfg::clcdat->bkColour) * 0.587 + GetBValue(cfg::clcdat->bkColour) * 0.144); if (greyLevel > 255) greyLevel = 255; COLORREF clrKey = RGB((BYTE)greyLevel, (BYTE)greyLevel, (BYTE)greyLevel); HBRUSH brKey = CreateSolidBrush(clrKey); FillRect(hdc, &rcClient, brKey); DeleteObject(brKey); SetBkMode(hdc, TRANSPARENT); if (g_floatoptions.dwFlags & FLT_ROUNDED){ rgn = CreateRoundRectRgn(0, 0, rcClient.right, rcClient.bottom, g_floatoptions.radius, g_floatoptions.radius); SelectClipRgn(hdc, rgn); if (g_floatoptions.dwFlags & FLT_FILLSTDCOLOR) { HBRUSH br = CreateSolidBrush(cfg::clcdat->bkColour); FillRect(hdc, &rcClient, br); DeleteObject(br); } } if (FindItem(pcli->hwndContactTree, dat, contact->hContact, &newContact, &group, 0)) { DWORD oldFlags = cfg::dat.dwFlags; BYTE oldPadding = cfg::dat.avatarPadding; struct avatarCacheEntry *ace_old = contact->ace; BYTE oldDualRow = contact->bSecondLine; int oldLeftMargin = dat->leftMargin; int oldRightMargin = dat->rightMargin; if (g_floatoptions.dwFlags & FLT_SIMPLE) { contact->ace = 0; contact->bSecondLine = MULTIROW_NEVER; cfg::dat.dwFlags &= ~CLUI_SHOWCLIENTICONS; } else { if ( !(g_floatoptions.dwFlags & FLT_AVATARS)) { contact->ace = 0; g_list_avatars = 0; } else g_list_avatars = 1; if ( !(g_floatoptions.dwFlags & FLT_DUALROW)) contact->bSecondLine = MULTIROW_NEVER; else contact->bSecondLine = MULTIROW_ALWAYS; if ( !(g_floatoptions.dwFlags & FLT_EXTRAICONS)) cfg::dat.dwFlags &= ~CLUI_SHOWCLIENTICONS; } dat->leftMargin = g_floatoptions.pad_left; dat->rightMargin = g_floatoptions.pad_right; g_HDC = hdc; hdcTempAV = CreateCompatibleDC(g_HDC); hdcAV = CreateCompatibleDC(g_HDC); hbmTempAV = CreateCompatibleBitmap(g_HDC, g_maxAV_X, g_maxAV_Y); hbmTempOldAV = reinterpret_cast(SelectObject(hdcTempAV, hbmTempAV)); g_padding_y = g_floatoptions.pad_top; BOOL firstDrawn = TRUE; PaintItem(hdc, group, contact, 0, 0, dat, -4, pcli->hwndContactTree, 0, &rcClient, &firstDrawn, 0, rcClient.bottom - rcClient.top); g_padding_y = 0; SelectObject(hdcTempAV, hbmTempOldAV); DeleteObject(hbmTempAV); DeleteDC(hdcTempAV); DeleteDC(hdcAV); cfg::dat.dwFlags = oldFlags; cfg::dat.avatarPadding = oldPadding; contact->ace = ace_old; contact->bSecondLine = oldDualRow; dat->leftMargin = oldLeftMargin; dat->rightMargin = oldRightMargin; } if (g_floatoptions.dwFlags & FLT_BORDER){ HBRUSH hbrBorder = CreateSolidBrush(g_floatoptions.border_colour); if (g_floatoptions.dwFlags & FLT_ROUNDED) FrameRgn(hdc, rgn, hbrBorder, 1, 1); else FrameRect(hdc, &rcClient, hbrBorder); DeleteObject(hbrBorder); } if (g_floatoptions.dwFlags & FLT_ROUNDED) DeleteObject(rgn); BLENDFUNCTION bf = {0}; bf.BlendOp = AC_SRC_OVER; bf.AlphaFormat = 0; bf.SourceConstantAlpha = g_floatoptions.trans; if (API::pfnUpdateLayeredWindow) API::pfnUpdateLayeredWindow(hwnd, 0, &ptDest, &szDest, hdc, &ptSrc, clrKey /*GetSysColor(COLOR_3DFACE)*/, &bf, ULW_COLORKEY | ULW_ALPHA); } /* * syncs the floating contacts with clist contact visibility. * will hide all floating contacts which are not visible on the list * needed after a list rebuild */ void FLT_SyncWithClist() { ContactFloater *pCurrent = pFirstFloater; int iVis = pcli->pfnGetWindowVisibleState(pcli->hwndContactList, 0, 0); if (g_floatoptions.dwFlags & FLT_SYNCWITHCLIST){ while(pCurrent) { HWND hwnd = pCurrent->hwnd; if (hwnd && IsWindow(hwnd)) { ClcContact *contact; if (FindItem(pcli->hwndContactTree, cfg::clcdat, pCurrent->hContact, &contact, NULL, 0)) { FLT_Update(cfg::clcdat, contact); if (((g_floatoptions.dwFlags & FLT_AUTOHIDE) && (iVis == 2 || iVis == 4)) || !(g_floatoptions.dwFlags & FLT_AUTOHIDE)) ShowWindow(hwnd, SW_SHOWNOACTIVATE); else ShowWindow(hwnd, SW_HIDE); } else ShowWindow(hwnd, SW_HIDE); } pCurrent = pCurrent->pNextFloater; } } } /* * quickly show or hide all floating contacts * used by autohide/show feature */ void FLT_ShowHideAll(int showCmd) { ClcContact *contact; ContactFloater *pCurrent = pFirstFloater; HWND hwnd; if (g_floatoptions.dwFlags & FLT_AUTOHIDE) { while(pCurrent) { hwnd = pCurrent->hwnd; if (hwnd && IsWindow(hwnd)) { if (showCmd == SW_SHOWNOACTIVATE && FindItem(pcli->hwndContactTree, cfg::clcdat, pCurrent->hContact, &contact, NULL, 0)) ShowWindow(hwnd, SW_SHOWNOACTIVATE); else if (showCmd != SW_SHOWNOACTIVATE) ShowWindow(hwnd, showCmd); } pCurrent = pCurrent->pNextFloater; } } } /* * update/repaint all contact floaters */ void FLT_RefreshAll() { ClcContact *contact = NULL; ContactFloater *pCurrent = pFirstFloater; while(pCurrent) { if (FindItem(pcli->hwndContactTree, cfg::clcdat, pCurrent->hContact, &contact, NULL, 0)) { HWND hwnd = pCurrent->hwnd; if (hwnd && IsWindow(hwnd)) FLT_Update(cfg::clcdat, contact); } pCurrent = pCurrent->pNextFloater; } }