From f4ce2b5c214cce406dbd7a73dc7f35ae409546ad Mon Sep 17 00:00:00 2001 From: Tobias Weimer Date: Sun, 12 Jul 2015 14:10:16 +0000 Subject: Clist NG: Commit of CList NG by silvercircle from https://github.com/silvercircle/miranda-ng This is based on clist_nicer and Anti-Grain Geometry: http://www.antigrain.com/ This is the first version that actually compiles. Do NOT use it in production environment! git-svn-id: http://svn.miranda-ng.org/main/trunk@14543 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Clist_ng/SRC/statusfloater.cpp | 1170 ++++++++++++++++++++++++++++++++ 1 file changed, 1170 insertions(+) create mode 100644 plugins/Clist_ng/SRC/statusfloater.cpp (limited to 'plugins/Clist_ng/SRC/statusfloater.cpp') diff --git a/plugins/Clist_ng/SRC/statusfloater.cpp b/plugins/Clist_ng/SRC/statusfloater.cpp new file mode 100644 index 0000000000..0d2353710a --- /dev/null +++ b/plugins/Clist_ng/SRC/statusfloater.cpp @@ -0,0 +1,1170 @@ +/* + +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" + +void FLT_Update(struct ClcData *dat, struct ClcContact *contact); +void FLT_ShowHideAll(int showCmd); +void FLT_SnapToEdges(HWND hwnd); +void FLT_SnapToFloater(HWND hwnd); +void PaintNotifyArea(HDC hDC, RECT *rc, HANDLE hTheme); + +HWND g_hwndSFL = 0; +HDC g_SFLCachedDC = 0; +HBITMAP g_SFLhbmOld = 0, g_SFLhbm = 0; +struct ContactFloater *pFirstFloater = 0; +BOOL hover = FALSE; +BOOL tooltip = FALSE; +int hTooltipTimer = 0; +POINT start_pos; + +extern int g_padding_y; + +extern HWND g_hwndEventArea; +extern HDC g_HDC; + +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 struct ContactFloater *FLT_AddToList(struct ContactFloater *pFloater) { + struct 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 struct ContactFloater *FLT_RemoveFromList(struct ContactFloater *pFloater) { + struct 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; + + HWND onTop = g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST; + + curMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); + + monInfo.cbSize = sizeof(monInfo); + GetMonitorInfo(curMonitor, &monInfo); + + dr = monInfo.rcWork; + GetWindowRect(hwnd, &rcWindow); + + if (rcWindow.left < dr.left + SNAP_SCREEN_TOLERANCE){ + SetWindowPos(hwnd, onTop, 0, rcWindow.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + GetWindowRect(hwnd, &rcWindow); + } + + if (rcWindow.top < dr.top + SNAP_SCREEN_TOLERANCE){ + SetWindowPos(hwnd, onTop, rcWindow.left, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + GetWindowRect(hwnd, &rcWindow); + } + + if (rcWindow.right > dr.right - SNAP_SCREEN_TOLERANCE) + SetWindowPos(hwnd, onTop, dr.right - (rcWindow.right - rcWindow.left), rcWindow.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + + if (rcWindow.bottom > dr.bottom - SNAP_SCREEN_TOLERANCE) + SetWindowPos(hwnd, onTop, rcWindow.left, dr.bottom - (rcWindow.bottom - rcWindow.top), 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +void FLT_SnapToFloater(HWND hwnd) +{ + struct ContactFloater *pCurrent = pFirstFloater; + RECT rcWindow, rcBase; + int minTop = 0xFFFFFF, minBottom = 0xFFFFFF, minRight = 0xFFFFFF, minLeft = 0xFFFFFF; + int posTop = 0, posBottom = 0, posRight = 0, posLeft = 0; + HWND onTop = g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST; + + 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, onTop, rcBase.left, posTop - (rcBase.bottom - rcBase.top), 0, 0, SWP_NOSIZE | SWP_NOZORDER); + + if (posBottom && (rcBase.top < posBottom + SNAP_FLT_TOLERANCE)) + SetWindowPos(hwnd, onTop, rcBase.left, posBottom, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + + if (posLeft && (rcBase.right > posLeft - SNAP_FLT_TOLERANCE)) + SetWindowPos(hwnd, onTop, posLeft - (rcBase.right - rcBase.left), rcBase.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); + + if (posRight && (rcBase.left < posRight + SNAP_FLT_TOLERANCE)) + SetWindowPos(hwnd, onTop, posRight, rcBase.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER); +} + +/* + * dialog procedure for the floating contacts option page + */ + +INT_PTR CALLBACK cfg::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); + CheckDlgButton(hwndDlg, IDC_FLT_ONTOP, dwFlags & FLT_ONTOP); + SendMessage(hwndDlg, WM_COMMAND, (WPARAM)IDC_FLT_BORDER, 0); + CheckDlgButton(hwndDlg, IDC_FLT_FILLSTD, dwFlags & FLT_FILLSTDCOLOR); + + 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_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_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 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_BORDERCOLOUR, isEnabled & isBorder); + 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_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; + 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: + switch (((LPNMHDR) lParam)->code) { + case 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_ONTOP) ? FLT_ONTOP : 0) | + (IsDlgButtonChecked(hwndDlg, IDC_FLT_SHOWTOOLTIPS) ? FLT_SHOWTOOLTIPS : 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.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() +{ + DWORD dwPad; + + ZeroMemory(&g_floatoptions, sizeof(FLOATINGOPTIONS)); + + g_floatoptions.enabled = cfg::getByte("CList", "flt_enabled", 0); + g_floatoptions.dwFlags = cfg::getDword("CList", "flt_flags", FLT_SIMPLE); + 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.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() +{ + DWORD dwPad; + + cfg::writeByte("CList", "flt_enabled", g_floatoptions.enabled); + cfg::writeDword("CList", "flt_flags", g_floatoptions.dwFlags); + 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::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 = Menu_GetStatusMenu(); + 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 = Menu_GetMainMenu(); + 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){ + struct 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 = (HANDLE)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) { + 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(!hover) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_HOVER | TME_LEAVE; + tme.hwndTrack = hwnd; + tme.dwHoverTime = 5; + TrackMouseEvent(&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: + { + struct ClcContact *contact = NULL; + struct ContactFloater *pCurrent = pFirstFloater; + int oldTrans = g_floatoptions.trans; + + while(pCurrent->hwnd != hwnd) + pCurrent = pCurrent->pNextFloater; + + if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)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: + { + struct ClcContact *contact = NULL; + struct ContactFloater *pCurrent = pFirstFloater; + + while(pCurrent->hwnd != hwnd) + pCurrent = pCurrent->pNextFloater; + + if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)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(Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam)); + case WM_DRAWITEM: + return(Menu_DrawItem((LPDRAWITEMSTRUCT)lParam)); + case WM_COMMAND: + return(CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKELONG(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)centry->hContact)); + case WM_CONTEXTMENU: + { + if(centry) { + HMENU hContactMenu = Menu_BuildContactMenu(centry->hContact); + 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 wchar_t sfl_statustext[100] = _T(""); + +void SFL_Update(HICON hIcon, int iIcon, HIMAGELIST hIml, const wchar_t *szText, BOOL refresh) +{ + RECT rcClient, rcWindow; + POINT ptDest, ptSrc = {0}; + SIZE szDest, szT; + BLENDFUNCTION bf = {0}; + HFONT hOldFont; + TStatusItem *item = &Skin::statusItems[ID_EXTBKSTATUSFLOATER]; + 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) + Gfx::setTextColor(GetSysColor(COLOR_BTNTEXT)); + else { + FillRect(g_SFLCachedDC, &rcClient, GetSysColorBrush(COLOR_3DFACE)); + Gfx::renderSkinItem(g_SFLCachedDC, &rcClient, item->imageItem); + Gfx::setTextColor(item->TEXTCOLOR); + } + bf.BlendOp = AC_SRC_OVER; + bf.AlphaFormat = AC_SRC_ALPHA; + 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, CLC::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, 0); + } + + SelectObject(g_SFLCachedDC, hOldFont); + UpdateLayeredWindow(g_hwndSFL, 0, &ptDest, &szDest, g_SFLCachedDC, &ptSrc, 0, &bf, ULW_ALPHA); +} + +/* + * 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 = {0}; + wchar_t *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 = TranslateTS(pcli->pfnGetStatusModeDescription(i, 0)); + GetTextExtentPoint32W(hdc, szStatusMode, lstrlenW(szStatusMode), &sz); + lWidth = max(lWidth, sz.cx + 16 + 8); + } + SetWindowPos(g_hwndSFL, g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST, 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 = Gfx::createRGBABitmap(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) + 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; + + SetWindowLong(g_hwndSFL, GWL_STYLE, GetWindowLong(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, g_floatoptions.dwFlags & FLT_ONTOP ? HWND_TOPMOST : HWND_NOTOPMOST, 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 = Gfx::createRGBABitmap(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) { + struct ClcContact *contact = NULL; + struct ClcGroup *group = NULL; + centry = &cfg::eCache[iEntry]; + if(centry->floater == 0) { + centry->floater = (struct ContactFloater *)malloc(sizeof(struct 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; + } + + SetWindowLong(centry->floater->hwnd, GWL_STYLE, GetWindowLong(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(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)centry->hContact, &contact, &group, 0)) { + if(contact) + FLT_Update(cfg::clcdat, contact); + } + } +} + +extern HDC hdcTempAV; +extern HBITMAP hbmTempAV, hbmTempOldAV; +extern LONG g_maxAV_X, g_maxAV_Y; + +void FLT_Update(struct ClcData *dat, struct ClcContact *contact) +{ + RECT rcClient, rcWindow; + POINT ptDest, ptSrc = {0}; + SIZE szDest; + BLENDFUNCTION bf = {0}; + HWND hwnd; + HDC hdc; + ClcGroup *group = NULL; + ClcContact *newContact = NULL; + HBRUSH hbrBorder; + float greyLevel; + + 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 = cfg::eCache[contact->extraCacheEntry].floater->hwnd; + hdc = cfg::eCache[contact->extraCacheEntry].floater->hdc; + + if(hwnd == 0) + return; + + GetClientRect(hwnd, &rcClient); + GetWindowRect(hwnd, &rcWindow); + + ptDest.x = rcWindow.left; + ptDest.y = rcWindow.top; + szDest.cx = rcWindow.right - rcWindow.left; + szDest.cy = rcWindow.bottom - rcWindow.top; + + /* + * fill with a DESATURATED representation of the clist bg color and use this later as a color key + */ + + 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; + + SetBkMode(hdc, TRANSPARENT); + + if(CLC::findItem(pcli->hwndContactTree, dat, (HANDLE)contact->hContact, &newContact, &group, 0)) { + DWORD oldFlags = cfg::dat.dwFlags; + BYTE oldPadding = cfg::dat.avatarPadding; + DWORD oldExtraImageMask = cfg::eCache[contact->extraCacheEntry].dwXMask; + + int oldLeftMargin = dat->leftMargin; + int oldRightMargin = dat->rightMargin; + + dat->leftMargin = g_floatoptions.pad_left; + dat->rightMargin = g_floatoptions.pad_right; + + g_HDC = hdc; + + hdcTempAV = 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; + + CLCPaintHelper ph(pcli->hwndContactTree, dat, 0, &rcClient, 0, 0, -4); + ph.setHDC(hdc); + + if(g_floatoptions.dwFlags & FLT_SIMPLE) { + ph.fAvatar = ph.fSecondLine = false; + cfg::dat.dwFlags &= ~(CLUI_SHOWCLIENTICONS | CLUI_SHOWVISI); + cfg::eCache[contact->extraCacheEntry].dwXMask = 0; + } + else{ + ph.fAvatar = g_floatoptions.dwFlags & FLT_AVATARS ? true : false; + ph.fSecondLine = g_floatoptions.dwFlags & FLT_DUALROW ? true : false; + if(!(g_floatoptions.dwFlags & FLT_EXTRAICONS)) { + cfg::dat.dwFlags &= ~(CLUI_SHOWCLIENTICONS | CLUI_SHOWVISI); + cfg::eCache[contact->extraCacheEntry].dwXMask = 0; + } + } + + ph.aggctx->attach(cfg::eCache[contact->extraCacheEntry].floater->hbm); + ph.current_shape = 0; + Gfx::renderSkinItem(&ph, &Skin::statusItems[ID_EXTBKSTATUSFLOATER], &rcClient); + + ph.setFloater(); + ph.hTheme = Api::pfnOpenThemeData(hwnd, L"BUTTON"); + + ph.Paint(group, contact, rcClient.bottom - rcClient.top); + + Api::pfnCloseThemeData(ph.hTheme); + + g_padding_y = 0; + + SelectObject(hdcTempAV, hbmTempOldAV); + DeleteObject(hbmTempAV); + DeleteDC(hdcTempAV); + + cfg::dat.dwFlags = oldFlags; + cfg::dat.avatarPadding = oldPadding; + cfg::eCache[contact->extraCacheEntry].dwXMask = oldExtraImageMask; + + dat->leftMargin = oldLeftMargin; + dat->rightMargin = oldRightMargin; + } + + if(g_floatoptions.dwFlags & FLT_BORDER){ + hbrBorder = CreateSolidBrush(g_floatoptions.border_colour); + FrameRect(hdc, &rcClient, hbrBorder); + DeleteObject(hbrBorder); + } + + bf.BlendOp = AC_SRC_OVER; + bf.AlphaFormat = AC_SRC_ALPHA; + bf.SourceConstantAlpha = g_floatoptions.trans; + + UpdateLayeredWindow(hwnd, 0, &ptDest, &szDest, hdc, &ptSrc, 0, &bf, 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() +{ + struct ClcContact *contact; + struct ContactFloater *pCurrent = pFirstFloater; + HWND hwnd; + int iVis = pcli->pfnGetWindowVisibleState(pcli->hwndContactList, 0, 0); + + if(g_floatoptions.dwFlags & FLT_SYNCWITHCLIST){ + while(pCurrent) { + hwnd = pCurrent->hwnd; + if(hwnd && IsWindow(hwnd)){ + if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)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) +{ + struct ClcContact *contact; + struct ContactFloater *pCurrent = pFirstFloater; + HWND hwnd; + + if(g_floatoptions.dwFlags & FLT_AUTOHIDE){ + while(pCurrent) { + hwnd = pCurrent->hwnd; + if(hwnd && IsWindow(hwnd)){ + if(showCmd == SW_SHOWNOACTIVATE && CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)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() +{ + struct ClcContact *contact = NULL; + struct ContactFloater *pCurrent = pFirstFloater; + + while(pCurrent) { + if(CLC::findItem(pcli->hwndContactTree, cfg::clcdat, (HANDLE)pCurrent->hContact, &contact, NULL, 0)) { + HWND hwnd = pCurrent->hwnd; + if(hwnd && IsWindow(hwnd)) + FLT_Update(cfg::clcdat, contact); + } + pCurrent = pCurrent->pNextFloater; + } +} + -- cgit v1.2.3