#include "stdhdr.h" ThumbList thumbList; ///////////////////////////////////////////////////////////////////////////// // ThumbInfo static POINT ptOld; static BOOL bMouseDown = FALSE; static BOOL bMouseIn = FALSE; static BOOL bMouseMoved = FALSE; static short nLeft = 0; static short nTop = 0; static int nOffs = 5; static ThumbInfo *pThumbMouseIn = NULL; static void SnapToScreen( RECT rcThumb, int nX, int nY, int *pX, int *pY ) { int nWidth; int nHeight; assert( NULL != pX ); assert( NULL != pY ); nWidth = rcThumb.right - rcThumb.left; nHeight = rcThumb.bottom - rcThumb.top; *pX = nX < ( nOffs + rcScreen.left ) ? rcScreen.left : nX; *pY = nY < ( nOffs + rcScreen.top ) ? rcScreen.top : nY; *pX = *pX > ( rcScreen.right - nWidth - nOffs ) ? ( rcScreen.right - nWidth ) : *pX; *pY = *pY > ( rcScreen.bottom - nHeight - nOffs ) ? ( rcScreen.bottom - nHeight ) : *pY; } ThumbInfo::ThumbInfo() { dropTarget = new CDropTarget; dropTarget->AddRef(); btAlpha = 255; } ThumbInfo::~ThumbInfo() { if (pThumbMouseIn == this){ pThumbMouseIn = NULL; KillTimer(hwnd, TIMERID_LEAVE_T); } dropTarget->Release(); } void ThumbInfo::GetThumbRect(RECT *rc) { rc->left = ptPos.x; rc->top = ptPos.y; rc->right = ptPos.x + szSize.cx; rc->bottom = ptPos.y + szSize.cy; } void ThumbInfo::PositionThumb(short nX, short nY) { POINT pos = { nX, nY }; HDWP hdwp; hdwp = BeginDeferWindowPos(1); ThumbInfo *pThumb = this; while (pThumb) { pThumb->PositionThumbWorker( (short)pos.x, (short)pos.y, &pos ); DeferWindowPos( hdwp, pThumb->hwnd, HWND_TOPMOST, pos.x, pos.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE ); pThumb->ptPos = pos; pos.x += pThumb->szSize.cx; pThumb = fcOpt.bMoveTogether ? thumbList.FindThumb( pThumb->dockOpt.hwndRight ) : NULL; } EndDeferWindowPos(hdwp); } void ThumbInfo::PositionThumbWorker(short nX, short nY, POINT *newPos) { RECT rc; RECT rcThumb; int nNewX; int nNewY; int nWidth; int nHeight; POINT pt; RECT rcLeft; RECT rcTop; RECT rcRight; RECT rcBottom; BOOL bDocked; BOOL bDockedLeft; BOOL bDockedRight; BOOL bLeading; // Get thumb dimnsions GetThumbRect( &rcThumb ); nWidth = rcThumb.right - rcThumb.left; nHeight = rcThumb.bottom - rcThumb.top; // Docking and screen boundaries check SnapToScreen( rcThumb, nX, nY, &nNewX, &nNewY ); bLeading = dockOpt.hwndRight != NULL; if ( fcOpt.bMoveTogether ) { UndockThumbs( this, thumbList.FindThumb( dockOpt.hwndLeft )); } for (int i = 0; i < thumbList.getCount(); ++i) { ThumbInfo *pCurThumb = thumbList[i]; if ( pCurThumb != this ) { GetThumbRect( &rcThumb ); OffsetRect( &rcThumb, nX - rcThumb.left, nY - rcThumb.top ); pCurThumb->GetThumbRect( &rc ); // These are rects we will dock into rcLeft.left = rc.left - nOffs; rcLeft.top = rc.top - nOffs; rcLeft.right = rc.left + nOffs; rcLeft.bottom = rc.bottom + nOffs; rcTop.left = rc.left - nOffs; rcTop.top = rc.top - nOffs; rcTop.right = rc.right + nOffs; rcTop.bottom = rc.top + nOffs; rcRight.left = rc.right - nOffs; rcRight.top = rc.top - nOffs; rcRight.right = rc.right + nOffs; rcRight.bottom = rc.bottom + nOffs; rcBottom.left = rc.left - nOffs; rcBottom.top = rc.bottom - nOffs; rcBottom.right = rc.right + nOffs; rcBottom.bottom = rc.bottom + nOffs; bDockedLeft = FALSE; bDockedRight = FALSE; // Upper-left pt.x = rcThumb.left; pt.y = rcThumb.top; bDocked = FALSE; if ( PtInRect( &rcRight, pt )) { nNewX = rc.right; bDocked = TRUE; } if ( PtInRect( &rcBottom, pt )) { nNewY = rc.bottom; if ( PtInRect( &rcLeft, pt )) { nNewX = rc.left; } } if ( PtInRect( &rcTop, pt )) { nNewY = rc.top; bDockedLeft = bDocked; } // Upper-right pt.x = rcThumb.right; pt.y = rcThumb.top; bDocked = FALSE; if ( !bLeading && PtInRect( &rcLeft, pt )) { if ( !bDockedLeft ) { nNewX = rc.left - nWidth; bDocked = TRUE; } else if ( rc.right == rcThumb.left ) { bDocked = TRUE; } } if ( PtInRect( &rcBottom, pt )) { nNewY = rc.bottom; if ( PtInRect( &rcRight, pt )) { nNewX = rc.right - nWidth; } } if ( !bLeading && PtInRect( &rcTop, pt )) { nNewY = rc.top; bDockedRight = bDocked; } if ( fcOpt.bMoveTogether ) { if ( bDockedRight ) { DockThumbs( this, pCurThumb, TRUE ); } if ( bDockedLeft ) { DockThumbs( pCurThumb, this, FALSE ); } } // Lower-left pt.x = rcThumb.left; pt.y = rcThumb.bottom; if ( PtInRect( &rcRight, pt )) { nNewX = rc.right; } if ( PtInRect( &rcTop, pt )) { nNewY = rc.top - nHeight; if ( PtInRect( &rcLeft, pt )) { nNewX = rc.left; } } // Lower-right pt.x = rcThumb.right; pt.y = rcThumb.bottom; if ( !bLeading && PtInRect( &rcLeft, pt )) { nNewX = rc.left - nWidth; } if ( !bLeading && PtInRect( &rcTop, pt )) { nNewY = rc.top - nHeight; if ( PtInRect( &rcRight, pt )) { nNewX = rc.right - nWidth; } } } } // Adjust coords once again SnapToScreen( rcThumb, nNewX, nNewY, &nNewX, &nNewY ); newPos->x = nNewX; newPos->y = nNewY; } void ThumbInfo::ResizeThumb() { HDC hdc = NULL; HFONT hOldFont = NULL; POINT ptText; SIZEL sizeIcon; SIZEL sizeText; RECT rcThumb; int index = FLT_FONTID_NOTONLIST; ThumbInfo *pNextThumb = NULL; himl = ( HIMAGELIST )CallService( MS_CLIST_GETICONSIMAGELIST, 0, 0 ); if ( himl == NULL ) return; ImageList_GetIconSize_my(himl, sizeIcon); hdc = GetWindowDC(hwnd); if (!db_get_b(hContact, "CList", "NotOnList", 0)) { int nStatus; int nContactStatus; int nApparentMode; char* szProto; szProto = GetContactProto(hContact); if ( NULL != szProto ) { nStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); nContactStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); nApparentMode = db_get_w(hContact, szProto, "ApparentMode", 0); if ( (nStatus == ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_ONLINE) || (nStatus != ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_OFFLINE) ) { if (ID_STATUS_OFFLINE == nContactStatus) { index = FLT_FONTID_OFFINVIS; } else { index = FLT_FONTID_INVIS; } } else if (ID_STATUS_OFFLINE == nContactStatus) { index = FLT_FONTID_OFFLINE; } else { index = FLT_FONTID_CONTACTS; } } } else { index = FLT_FONTID_NOTONLIST; } hOldFont = (HFONT)SelectObject( hdc, hFont[ index ] ); // Get text and icon sizes GetTextExtentPoint32( hdc, ptszName, (DWORD)_tcslen(ptszName), &sizeText); SelectObject( hdc, hOldFont ); // Transform text size ptText.x = sizeText.cx; ptText.y = sizeText.cy; LPtoDP( hdc, &ptText, 1 ); szSize.cx = fcOpt.bFixedWidth ? fcOpt.nThumbWidth : sizeIcon.cx + ptText.x + 10; szSize.cy = ( ( sizeIcon.cy > ptText.y ) ? sizeIcon.cy : ptText.y ) + 4; SetWindowPos( hwnd, HWND_TOPMOST, 0, 0, szSize.cx, szSize.cy, SWP_NOMOVE | /*SWP_NOZORDER |*/ SWP_NOACTIVATE ); RefreshContactIcon(0xFFFFFFFF); ReleaseDC( hwnd, hdc ); // Move the docked widnow if needed if (pNextThumb = thumbList.FindThumb(dockOpt.hwndRight)) { GetThumbRect( &rcThumb ); pNextThumb->PositionThumb( (short)rcThumb.right, (short)rcThumb.top ); } } void ThumbInfo::RefreshContactIcon(int iIcon) { if ( iIcon == 0xFFFFFFFF || ImageList_GetImageCount(himl)<=iIcon ) { this->iIcon = CallService( MS_CLIST_GETCONTACTICON, (WPARAM)hContact, 0 ); } else { this->iIcon = iIcon; } UpdateContent(); } void ThumbInfo::RefreshContactStatus(int idStatus) { if ( IsStatusVisible( idStatus )) { RegisterFileDropping( hwnd, dropTarget ); } else { UnregisterFileDropping( hwnd ); } ShowWindow( hwnd, fcOpt.bHideAll || HideOnFullScreen() || ( fcOpt.bHideOffline && ( !IsStatusVisible( idStatus )) ) || (fcOpt.bHideWhenCListShow && bIsCListShow) ? SW_HIDE : SW_SHOWNA ); } void ThumbInfo::DeleteContactPos() { DBDeleteContactSetting( hContact, MODULE, "ThumbsPos" ); } void ThumbInfo::OnLButtonDown(short nX, short nY) { RECT rc; if (bEnableTip && fcOpt.bShowTip) KillTip(); // ptOld.x = nX; // ptOld.y = nY; // ClientToScreen( hwnd, &ptOld ); GetCursorPos(&ptOld); GetThumbRect(&rc); nLeft = (short)rc.left; nTop = (short)rc.top; //bMouseIn = FALSE; bMouseDown = TRUE; bMouseMoved = FALSE; // SetCapture(hwnd); } void ThumbInfo::OnLButtonUp() { RECT rcMiranda; RECT rcThumb; RECT rcOverlap; if (!bMouseMoved && fcOpt.bUseSingleClick && bMouseIn){ PopUpMessageDialog(); } //ThumbDeselect( TRUE ); if ( bMouseDown ) { bMouseDown = FALSE; SetCursor( LoadCursor( NULL, IDC_ARROW )); // Check whether we shoud remove the window GetWindowRect( hwndMiranda, &rcMiranda ); GetThumbRect( &rcThumb ); if ( IntersectRect( &rcOverlap, &rcMiranda, &rcThumb )) { if ( IsWindowVisible( hwndMiranda )) { DeleteContactPos( ); thumbList.RemoveThumb( this ); } } } SaveContactsPos(); } void ThumbInfo::OnMouseMove(short nX, short nY, WPARAM wParam) { // if (bMouseDown && !wParam&MK_LBUTTON) OnLButtonUp(); int dX; int dY; POINT ptNew; // Position thumb if ( bMouseDown ) { ptNew.x = nX; ptNew.y = nY; ClientToScreen( hwnd, &ptNew ); dX = ptNew.x - ptOld.x; dY = ptNew.y - ptOld.y; if (dX || dY){ bMouseMoved = TRUE; nLeft += (short)dX; nTop += (short)dY; PositionThumb( nLeft, nTop ); } ptOld = ptNew; } else { SetCursor( LoadCursor( NULL, IDC_ARROW )); } // Update selection status if ( !pThumbMouseIn )// { SetTimer( hwnd, TIMERID_LEAVE_T, 10, NULL ); pThumbMouseIn = this; ThumbSelect( TRUE ); } if (bEnableTip && fcOpt.bShowTip && !bMouseDown){ WORD tmpTimeIn; POINT pt; RECT rc; GetCursorPos(&pt); GetThumbRect(&rc); if (!PtInRect(&rc,pt)) { KillTip(); return; } if (fTipTimerActive && abs(pt.x-ptTipSt.x)<5 && abs(pt.y-ptTipSt.x)<5){ return; } ptTipSt = pt; if (fTipTimerActive) { KillTimer(hwnd, TIMERID_HOVER_T); } if (fTipActive) { return; } tmpTimeIn = (fcOpt.TimeIn>0)?fcOpt.TimeIn:CallService(MS_CLC_GETINFOTIPHOVERTIME, 0, 0); SetTimer(hwnd, TIMERID_HOVER_T, tmpTimeIn, 0); fTipTimerActive = TRUE; } } void ThumbInfo::ThumbSelect(BOOL bMouse) { if ( bMouse ) { bMouseIn = TRUE; SetCapture( hwnd ); } SetThumbOpacity( 255 ); } void ThumbInfo::ThumbDeselect(BOOL bMouse) { if ( bMouse ) { bMouseIn = FALSE; ReleaseCapture(); } SetThumbOpacity( fcOpt.thumbAlpha ); } void ThumbInfo::SetThumbOpacity(BYTE bAlpha) { if ( pUpdateLayeredWindow && (bAlpha != btAlpha)) { btAlpha = bAlpha; UpdateContent(); } } void ThumbInfo::KillTip() { if (fTipTimerActive) { KillTimer(hwnd, TIMERID_HOVER_T); fTipTimerActive = FALSE; } if (fTipActive) { CallService("mToolTip/HideTip", 0, 0); fTipActive = FALSE; } } void ThumbInfo::UpdateContent() { bmpContent.allocate(szSize.cx, szSize.cy); HFONT hOldFont; SIZE size; RECT rc; RECT rcText; DWORD oldColor; int oldBkMode, index = 0;// nStatus; UINT fStyle = ILD_NORMAL; HDC hdcDraw = bmpContent.getDC(); SetRect(&rc, 0, 0, szSize.cx, szSize.cy); if ( NULL != hBmpBackground ) { RECT rcBkgnd; BITMAP bmp; HDC hdcBmp; HBITMAP hbmTmp; int x,y; int maxx,maxy; int destw,desth; int width; int height; SetRect(&rcBkgnd, 0, 0, szSize.cx, szSize.cy); if (NULL != hLTEdgesPen) InflateRect(&rcBkgnd, -1, -1); width = rcBkgnd.right - rcBkgnd.left; height = rcBkgnd.bottom - rcBkgnd.top; GetObject(hBmpBackground, sizeof(bmp), &bmp); hdcBmp = CreateCompatibleDC( hdcDraw ); hbmTmp = (HBITMAP)SelectObject( hdcBmp, hBmpBackground ); maxx = (0 != (nBackgroundBmpUse & CLBF_TILEH) ? rcBkgnd.right : rcBkgnd.left + 1); maxy = (0 != (nBackgroundBmpUse & CLBF_TILEV) ? rcBkgnd.bottom : rcBkgnd.top + 1); switch (nBackgroundBmpUse & CLBM_TYPE) { case CLB_STRETCH: if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL)) { if (width * bmp.bmHeight < height * bmp.bmWidth) { desth = height; destw = desth * bmp.bmWidth / bmp.bmHeight; } else { destw = width; desth = destw * bmp.bmHeight / bmp.bmWidth; } } else { destw = width; desth = height; } break; case CLB_STRETCHH: destw = width; if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL)) desth = destw * bmp.bmHeight / bmp.bmWidth; else desth = bmp.bmHeight; break; case CLB_STRETCHV: desth = height; if (0 != (nBackgroundBmpUse & CLBF_PROPORTIONAL)) destw = desth * bmp.bmWidth / bmp.bmHeight; else destw = bmp.bmWidth; break; default: //clb_topleft destw = bmp.bmWidth; desth = bmp.bmHeight; break; } SetStretchBltMode(hdcBmp, STRETCH_HALFTONE); for (x = rcBkgnd.left; x < maxx; x += destw) { for (y = rcBkgnd.top; y < maxy; y += desth) { StretchBlt( hdcDraw, x, y, destw, desth, hdcBmp, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY ); } } SelectObject( hdcBmp, hbmTmp ); DeleteDC( hdcBmp ); } else { FillRect( hdcDraw, &rc, hBkBrush ); } if (NULL != hLTEdgesPen) { HPEN hOldPen = (HPEN)SelectObject( hdcDraw, hLTEdgesPen ); MoveToEx(hdcDraw, 0, 0, NULL); LineTo(hdcDraw, szSize.cx, 0); MoveToEx(hdcDraw, 0, 0, NULL); LineTo(hdcDraw, 0, szSize.cy); SelectObject(hdcDraw, hRBEdgesPen); MoveToEx(hdcDraw, 0, szSize.cy - 1, NULL); LineTo(hdcDraw, szSize.cx - 1, szSize.cy - 1); MoveToEx(hdcDraw, szSize.cx - 1, szSize.cy - 1, NULL); LineTo(hdcDraw, szSize.cx - 1, 0); SelectObject(hdcDraw, hOldPen); //InflateRect(&rc, -1, -1); } bmpContent.setAlpha(btAlpha); ImageList_GetIconSize_my( himl, size ); oldBkMode = SetBkMode( hdcDraw, TRANSPARENT ); if (!db_get_b(hContact, "CList", "NotOnList", 0)) { int nStatus; int nContactStatus; int nApparentMode; char* szProto; szProto = GetContactProto(hContact); if ( NULL != szProto ) { nStatus = CallProtoService(szProto, PS_GETSTATUS, 0, 0); nContactStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); nApparentMode = db_get_w(hContact, szProto, "ApparentMode", 0); if ( (nStatus == ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_ONLINE) || (nStatus != ID_STATUS_INVISIBLE && nApparentMode == ID_STATUS_OFFLINE)) { if (ID_STATUS_OFFLINE == nContactStatus) { index = FLT_FONTID_OFFINVIS; } else { index = FLT_FONTID_INVIS; if (fcOpt.bShowIdle && db_get_dw(hContact, szProto, "IdleTS", 0)) { fStyle|=ILD_BLEND50; } } } else if (ID_STATUS_OFFLINE == nContactStatus) { index = FLT_FONTID_OFFLINE; } else { index = FLT_FONTID_CONTACTS; if (fcOpt.bShowIdle && db_get_dw(hContact, szProto, "IdleTS", 0)) { fStyle|=ILD_BLEND50; } } } } else { index = FLT_FONTID_NOTONLIST; fStyle|=ILD_BLEND50; } oldColor = SetTextColor( hdcDraw, tColor[ index ] ); HICON icon = ImageList_GetIcon(himl, iIcon, ILD_NORMAL); MyBitmap bmptmp(size.cx, size.cy); bmptmp.DrawIcon(icon,0,0);//bmpContent BLENDFUNCTION blend; blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = (fStyle&ILD_BLEND50)?128:255; blend.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(hdcDraw, 2,( szSize.cy - size.cx ) / 2, bmptmp.getWidth(), bmptmp.getHeight(), bmptmp.getDC(), 0, 0, bmptmp.getWidth(), bmptmp.getHeight(), blend); DestroyIcon(icon); SetRect(&rcText, 0, 0, szSize.cx, szSize.cy); rcText.left += size.cx + 4; hOldFont = (HFONT)SelectObject( hdcDraw, hFont[ index ] ); SIZE szText; GetTextExtentPoint32(hdcDraw, ptszName, (DWORD)_tcslen(ptszName), &szText); SetTextColor(hdcDraw, bkColor); // simple border bmpContent.DrawText(ptszName, rcText.left-1, (rcText.top + rcText.bottom - szText.cy)/2); bmpContent.DrawText(ptszName, rcText.left+1, (rcText.top + rcText.bottom - szText.cy)/2); bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2-1); bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2+1); // blurred border // bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2, 3); // text itself SetTextColor(hdcDraw, tColor[index]); bmpContent.DrawText(ptszName, rcText.left, (rcText.top + rcText.bottom - szText.cy)/2); SelectObject( hdcDraw, hOldFont ); SetTextColor( hdcDraw, oldColor ); SetBkMode( hdcDraw, oldBkMode ); if (pUpdateLayeredWindow) { SetWindowLongPtr( hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED ); RECT rc; GetWindowRect(hwnd, &rc); POINT ptDst = {rc.left, rc.top}; POINT ptSrc = {0, 0}; BLENDFUNCTION blend; blend.BlendOp = AC_SRC_OVER; blend.BlendFlags = 0; blend.SourceConstantAlpha = 255; blend.AlphaFormat = AC_SRC_ALPHA; pUpdateLayeredWindow(hwnd, NULL, &ptDst, &szSize, bmpContent.getDC(), &ptSrc, 0xffffffff, &blend, ULW_ALPHA); } else { RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); UpdateWindow(hwnd); } } void ThumbInfo::PopUpMessageDialog( ) { CallService( MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)hContact, 0 ); } void ThumbInfo::OnTimer(BYTE idTimer) { if (idTimer == TIMERID_SELECT_T){ KillTimer( hwnd, TIMERID_SELECT_T ); ThumbDeselect( FALSE ); } if (idTimer == TIMERID_LEAVE_T && !bMouseDown){ POINT pt; RECT rc; GetCursorPos(&pt); GetThumbRect(&rc); if (!PtInRect(&rc, pt)) { KillTimer( hwnd, TIMERID_LEAVE_T ); pThumbMouseIn = NULL; ThumbDeselect( TRUE ); } } if (bEnableTip && fcOpt.bShowTip && idTimer == TIMERID_HOVER_T){ POINT pt; CLCINFOTIP ti = {0}; ti.cbSize = sizeof(ti); KillTimer(hwnd, TIMERID_HOVER_T); fTipTimerActive = FALSE; GetCursorPos(&pt); if (abs(pt.x-ptTipSt.x)<5 && abs(pt.y-ptTipSt.y)<5){ ti.ptCursor = pt; fTipActive = TRUE; ti.isGroup = 0; ti.hItem = hContact; ti.isTreeFocused = 0; CallService("mToolTip/ShowTip", 0, (LPARAM)&ti); } } } void DockThumbs( ThumbInfo *pThumbLeft, ThumbInfo *pThumbRight, BOOL bMoveLeft ) { if ( ( pThumbRight->dockOpt.hwndLeft == NULL ) && ( pThumbLeft->dockOpt.hwndRight == NULL )) { pThumbRight->dockOpt.hwndLeft = pThumbLeft->hwnd; pThumbLeft->dockOpt.hwndRight = pThumbRight->hwnd; } } void UndockThumbs( ThumbInfo *pThumb1, ThumbInfo *pThumb2 ) { if ( ( pThumb1 == NULL ) || ( pThumb2 == NULL )) { return; } if ( pThumb1->dockOpt.hwndRight == pThumb2->hwnd ) { pThumb1->dockOpt.hwndRight = NULL; } if ( pThumb1->dockOpt.hwndLeft == pThumb2->hwnd ) { pThumb1->dockOpt.hwndLeft = NULL; } if ( pThumb2->dockOpt.hwndRight == pThumb1->hwnd ) { pThumb2->dockOpt.hwndRight = NULL; } if ( pThumb2->dockOpt.hwndLeft == pThumb1->hwnd ) { pThumb2->dockOpt.hwndLeft = NULL; } } ///////////////////////////////////////////////////////////////////////////// // ThumbList ThumbList::ThumbList(): LIST(1, cmp) { } ThumbList::~ThumbList() { for (int i = 0; i < getCount(); ++i) delete (*this)[i]; destroy(); } ThumbInfo *ThumbList::AddThumb(HWND hwnd, TCHAR *ptszName, HANDLE hContact) { ThumbInfo *pThumb = NULL; if ( ptszName == NULL ) return( NULL ); if ( hContact == NULL ) return( NULL ); if ( hwnd == NULL ) return( NULL ); pThumb = new ThumbInfo; if ( pThumb != NULL ) { _tcsncpy( pThumb->ptszName, ptszName, USERNAME_LEN - 1 ); pThumb->hContact = hContact; pThumb->hwnd = hwnd; pThumb->dockOpt.hwndLeft = NULL; pThumb->dockOpt.hwndRight = NULL; pThumb->fTipActive = FALSE; // RegHotkey(szName, hwnd); RegHotkey(hContact, hwnd); } insert(pThumb); return( pThumb ); } void ThumbList::RemoveThumb(ThumbInfo *pThumb) { if (!pThumb) return; if (fcOpt.bMoveTogether) { UndockThumbs(pThumb, FindThumb(pThumb->dockOpt.hwndLeft)); UndockThumbs(pThumb, FindThumb(pThumb->dockOpt.hwndRight)); } remove(pThumb); UnregisterFileDropping( pThumb->hwnd ); DestroyWindow( pThumb->hwnd ); delete pThumb; } ThumbInfo *ThumbList::FindThumb(HWND hwnd) { if (!hwnd) return NULL; for (int i = 0; i < getCount(); ++i) if ((*this)[i]->hwnd == hwnd) return (*this)[i]; return NULL; } ThumbInfo *ThumbList::FindThumbByContact(HANDLE hContact) { if (!hContact) return NULL; for (int i = 0; i < getCount(); ++i) if ((*this)[i]->hContact == hContact) return (*this)[i]; return NULL; } int ThumbList::cmp(const ThumbInfo *p1, const ThumbInfo *p2) { if ((DWORD)p1->hContact < (DWORD)p2->hContact) return -1; if ((DWORD)p1->hContact > (DWORD)p2->hContact) return +1; return 0; }