#include "hdr/modern_commonheaders.h" #include "hdr/modern_statusbar.h" #include "./m_api/m_skin_eng.h" #include "hdr/modern_commonprototypes.h" #include "hdr/modern_clcpaint.h" #include "hdr/modern_sync.h" BOOL tooltipshoing; POINT lastpnt; #define TM_STATUSBAR 23435234 #define TM_STATUSBARHIDE 23435235 HWND hModernStatusBar = NULL; HANDLE hFramehModernStatusBar = NULL; extern void ApplyViewMode(const char *Name, bool onlySelector = false ); extern void SaveViewMode(const char *name, const TCHAR *szGroupFilter, const char *szProtoFilter, DWORD statusMask, DWORD stickyStatusMask, unsigned int options, unsigned int stickies, unsigned int operators, unsigned int lmdat); //int FindFrameID(HWND FrameHwnd); COLORREF sttGetColor(char * module, char * color, COLORREF defColor); #define DBFONTF_BOLD 1 #define DBFONTF_ITALIC 2 #define DBFONTF_UNDERLINE 4 struct ProtoItemData : public MZeroedObject { ~ProtoItemData() { mir_free(ProtoXStatus); mir_free(ProtoName); mir_free(AccountName); mir_free(ProtoHumanName); mir_free(ProtoEMailCount); mir_free(ProtoStatusText); } HICON icon; HICON extraIcon; int iconIndex; char *ProtoName; char *AccountName; int ProtoStatus; TCHAR *ProtoHumanName; char *ProtoEMailCount; char *ProtoStatusText; TCHAR *ProtoXStatus; int ProtoPos; int fullWidth; RECT protoRect; BOOL DoubleIcons; BYTE showProtoIcon; BYTE showProtoName; BYTE showStatusName; BYTE xStatusMode; // 0-only main, 1-xStatus, 2-main as overlay BYTE connectingIcon; BYTE showProtoEmails; BYTE SBarRightClk; int PaddingLeft; int PaddingRight; bool isDimmed; }; static OBJLIST ProtosData(5); STATUSBARDATA g_StatusBarData = {0}; char* ApendSubSetting(char * buf, int size, char *first, char *second) { _snprintf(buf,size,"%sFont%s",first,second); return buf; } int LoadStatusBarData() { g_StatusBarData.perProtoConfig = db_get_b(NULL,"CLUI","SBarPerProto",SETTING_SBARPERPROTO_DEFAULT); g_StatusBarData.showProtoIcon = db_get_b(NULL,"CLUI","SBarShow",SETTING_SBARSHOW_DEFAULT)&1; g_StatusBarData.showProtoName = db_get_b(NULL,"CLUI","SBarShow",SETTING_SBARSHOW_DEFAULT)&2; g_StatusBarData.showStatusName = db_get_b(NULL,"CLUI","SBarShow",SETTING_SBARSHOW_DEFAULT)&4; g_StatusBarData.xStatusMode = (BYTE)(db_get_b(NULL,"CLUI","ShowXStatus",SETTING_SHOWXSTATUS_DEFAULT)); g_StatusBarData.connectingIcon = db_get_b(NULL,"CLUI","UseConnectingIcon",SETTING_USECONNECTINGICON_DEFAULT); g_StatusBarData.showProtoEmails = db_get_b(NULL,"CLUI","ShowUnreadEmails",SETTING_SHOWUNREADEMAILS_DEFAULT); g_StatusBarData.SBarRightClk = db_get_b(NULL,"CLUI","SBarRightClk",SETTING_SBARRIGHTCLK_DEFAULT); g_StatusBarData.nProtosPerLine = db_get_b(NULL,"CLUI","StatusBarProtosPerLine",SETTING_PROTOSPERLINE_DEFAULT); g_StatusBarData.Align = db_get_b(NULL,"CLUI","Align",SETTING_ALIGN_DEFAULT); g_StatusBarData.VAlign = db_get_b(NULL,"CLUI","VAlign",SETTING_VALIGN_DEFAULT); g_StatusBarData.sameWidth = db_get_b(NULL,"CLUI","EqualSections",SETTING_EQUALSECTIONS_DEFAULT); g_StatusBarData.rectBorders.left = db_get_dw(NULL,"CLUI","LeftOffset",SETTING_LEFTOFFSET_DEFAULT); g_StatusBarData.rectBorders.right = db_get_dw(NULL,"CLUI","RightOffset",SETTING_RIGHTOFFSET_DEFAULT); g_StatusBarData.rectBorders.top = db_get_dw(NULL,"CLUI","TopOffset",SETTING_TOPOFFSET_DEFAULT); g_StatusBarData.rectBorders.bottom = db_get_dw(NULL,"CLUI","BottomOffset",SETTING_BOTTOMOFFSET_DEFAULT); g_StatusBarData.extraspace = (BYTE)db_get_dw(NULL,"CLUI","SpaceBetween",SETTING_SPACEBETWEEN_DEFAULT); if (g_StatusBarData.BarFont) DeleteObject(g_StatusBarData.BarFont); g_StatusBarData.BarFont = NULL;//LoadFontFromDB("ModernData","StatusBar",&g_StatusBarData.fontColor); int vis = db_get_b(NULL,"CLUI","ShowSBar",SETTING_SHOWSBAR_DEFAULT); int frameopt; int frameID = Sync( FindFrameID, hModernStatusBar ); frameopt = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS,MAKEWPARAM(FO_FLAGS,frameID),0); frameopt = frameopt & (~F_VISIBLE); if (vis) { ShowWindow(hModernStatusBar,SW_SHOW); frameopt |= F_VISIBLE; } else ShowWindow(hModernStatusBar,SW_HIDE); CallService(MS_CLIST_FRAMES_SETFRAMEOPTIONS,MAKEWPARAM(FO_FLAGS,frameID),frameopt); g_StatusBarData.TextEffectID = db_get_b(NULL,"StatusBar","TextEffectID",SETTING_TEXTEFFECTID_DEFAULT); g_StatusBarData.TextEffectColor1 = db_get_dw(NULL,"StatusBar","TextEffectColor1",SETTING_TEXTEFFECTCOLOR1_DEFAULT); g_StatusBarData.TextEffectColor2 = db_get_dw(NULL,"StatusBar","TextEffectColor2",SETTING_TEXTEFFECTCOLOR2_DEFAULT); if (g_StatusBarData.hBmpBackground) {DeleteObject(g_StatusBarData.hBmpBackground); g_StatusBarData.hBmpBackground = NULL;} if (g_CluiData.fDisableSkinEngine) { DBVARIANT dbv; g_StatusBarData.bkColour = sttGetColor("StatusBar","BkColour",CLCDEFAULT_BKCOLOUR); if (db_get_b(NULL,"StatusBar","UseBitmap",CLCDEFAULT_USEBITMAP)) { if ( !DBGetContactSettingString(NULL,"StatusBar","BkBitmap",&dbv)) { g_StatusBarData.hBmpBackground = (HBITMAP)CallService(MS_UTILS_LOADBITMAP,0,(LPARAM)dbv.pszVal); db_free(&dbv); } } g_StatusBarData.bkUseWinColors = db_get_b(NULL,"StatusBar", "UseWinColours", CLCDEFAULT_USEWINDOWSCOLOURS); g_StatusBarData.backgroundBmpUse = db_get_w(NULL,"StatusBar","BkBmpUse",CLCDEFAULT_BKBMPUSE); } SendMessage(pcli->hwndContactList,WM_SIZE,0,0); return 1; } int BgStatusBarChange(WPARAM wParam,LPARAM lParam) { if (MirandaExiting()) return 0; LoadStatusBarData(); return 0; } //ProtocolData; int NewStatusPaintCallbackProc(HWND hWnd, HDC hDC, RECT * rcPaint, HRGN rgn, DWORD dFlags, void * CallBackData) { return ModernDrawStatusBar(hWnd,hDC); } int ModernDrawStatusBar(HWND hwnd, HDC hDC) { if (hwnd == (HWND)-1) return 0; if (GetParent(hwnd) == pcli->hwndContactList) return ModernDrawStatusBarWorker(hwnd,hDC); CLUI__cliInvalidateRect(hwnd,NULL,FALSE); return 0; } int ModernDrawStatusBarWorker(HWND hWnd, HDC hDC) { int line; int iconHeight = GetSystemMetrics(SM_CYSMICON)+2; int protosperline = 0; int SumWidth = 0; int rectwidth = 0; int aligndx = 0; int i,po = 0; char servName[40]; char protoNameExt[40]; // Count visible protos RECT rc; HFONT hOldFont; int maxwidth = 0; int xstatus = 0; SIZE textSize = {0}; GetClientRect(hWnd,&rc); if (g_CluiData.fDisableSkinEngine) { if (g_StatusBarData.bkUseWinColors && xpt_IsThemed(g_StatusBarData.hTheme)) xpt_DrawTheme(g_StatusBarData.hTheme, hWnd, hDC, 0, 0, &rc, &rc); else DrawBackGround(hWnd, hDC, g_StatusBarData.hBmpBackground, g_StatusBarData.bkColour, g_StatusBarData.backgroundBmpUse ); } else SkinDrawGlyph(hDC,&rc,&rc,"Main,ID=StatusBar"); //TBD g_StatusBarData.nProtosPerLine = db_get_b(NULL,"CLUI","StatusBarProtosPerLine",SETTING_PROTOSPERLINE_DEFAULT); hOldFont = g_clcPainter.ChangeToFont(hDC,NULL,FONTID_STATUSBAR_PROTONAME,NULL); GetTextExtentPoint32A(hDC," ",1,&textSize); int spaceWidth = textSize.cx; int textY = rc.top+((rc.bottom-rc.top-textSize.cy)>>1); int iconY = rc.top+((rc.bottom-rc.top-GetSystemMetrics(SM_CXSMICON))>>1); ProtosData.destroy(); int protoCount; PROTOACCOUNT **accs; ProtoEnumAccounts( &protoCount, &accs ); if (protoCount == 0) return 0; for (int j = 0; j < protoCount; j++) { int vis; i = pcli->pfnGetAccountIndexByPos(j); if (i == -1) vis = FALSE; else vis = pcli->pfnGetProtocolVisibility(accs[i]->szModuleName); if ( !vis) continue; char buf[256]; mir_snprintf(buf, SIZEOF(buf), "SBarAccountIsCustom_%s", accs[i]->szModuleName); ProtoItemData* p = new ProtoItemData; if (g_StatusBarData.perProtoConfig && db_get_b(NULL, "CLUI", buf, SETTING_SBARACCOUNTISCUSTOM_DEFAULT)) { mir_snprintf(buf, SIZEOF(buf), "HideAccount_%s", accs[i]->szModuleName); if (db_get_b(NULL, "CLUI", buf, SETTING_SBARHIDEACCOUNT_DEFAULT)) continue; mir_snprintf(buf, SIZEOF(buf), "SBarShow_%s", accs[i]->szModuleName); BYTE showOps = db_get_b(NULL,"CLUI", buf, SETTING_SBARSHOW_DEFAULT); p->showProtoIcon = showOps & 1; p->showProtoName = showOps & 2; p->showStatusName = showOps & 4; mir_snprintf(buf, SIZEOF(buf), "ShowXStatus_%s", accs[i]->szModuleName); p->xStatusMode = db_get_b(NULL,"CLUI", buf, SETTING_SBARSHOW_DEFAULT); mir_snprintf(buf, SIZEOF(buf), "UseConnectingIcon_%s", accs[i]->szModuleName); p->connectingIcon = db_get_b(NULL,"CLUI", buf, SETTING_USECONNECTINGICON_DEFAULT); mir_snprintf(buf, SIZEOF(buf), "ShowUnreadEmails_%s", accs[i]->szModuleName); p->showProtoEmails = db_get_b(NULL,"CLUI", buf, SETTING_SHOWUNREADEMAILS_DEFAULT); mir_snprintf(buf, SIZEOF(buf), "SBarRightClk_%s", accs[i]->szModuleName); p->SBarRightClk = db_get_b(NULL,"CLUI", buf, SETTING_SBARRIGHTCLK_DEFAULT); mir_snprintf(buf, SIZEOF(buf), "PaddingLeft_%s", accs[i]->szModuleName); p->PaddingLeft = db_get_dw(NULL,"CLUI", buf, SETTING_PADDINGLEFT_DEFAULT); mir_snprintf(buf, SIZEOF(buf), "PaddingRight_%s", accs[i]->szModuleName); p->PaddingRight = db_get_dw(NULL,"CLUI", buf, SETTING_PADDINGRIGHT_DEFAULT); } else { p->showProtoIcon = g_StatusBarData.showProtoIcon; p->showProtoName = g_StatusBarData.showProtoName; p->showStatusName = g_StatusBarData.showStatusName; p->xStatusMode = g_StatusBarData.xStatusMode; p->connectingIcon = g_StatusBarData.connectingIcon; p->showProtoEmails = g_StatusBarData.showProtoEmails; p->SBarRightClk = 0; p->PaddingLeft = 0; p->PaddingRight = 0; } p->ProtoStatus = CallProtoService(accs[i]->szModuleName,PS_GETSTATUS,0,0); p->ProtoEMailCount = NULL; if (p->ProtoStatus > ID_STATUS_OFFLINE) { // create service name mir_snprintf(servName, SIZEOF(servName), "%s/GetUnreadEmailCount", accs[i]->szModuleName); if (p->showProtoEmails == 1 && ServiceExists(servName)) { mir_snprintf(protoNameExt, SIZEOF(protoNameExt),"[%d]", (int) CallService(servName, 0, 0)); p->ProtoEMailCount = mir_strdup(protoNameExt); } } p->ProtoHumanName = mir_tstrdup(accs[i]->tszAccountName); p->AccountName = mir_strdup(accs[i]->szModuleName); p->ProtoName = mir_strdup(accs[i]->szProtoName); p->ProtoStatusText = mir_strdup((char*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,(WPARAM)p->ProtoStatus,0)); p->ProtoPos = ProtosData.getCount(); p->isDimmed = 0; if (g_CluiData.bFilterEffective & CLVM_FILTER_PROTOS) { char szTemp[2048]; mir_snprintf(szTemp, SIZEOF(szTemp), "%s|", p->AccountName ); p->isDimmed = strstr(g_CluiData.protoFilter, szTemp) ? 0 : 1; } ProtosData.insert(p); } if ( ProtosData.getCount() == 0) return 0; //START MULTILINE HERE int orig_protoCount = protoCount; int orig_visProtoCount = ProtosData.getCount(); if (g_StatusBarData.nProtosPerLine) protosperline = g_StatusBarData.nProtosPerLine; else if (orig_visProtoCount) protosperline = orig_visProtoCount; else if (protoCount) { protosperline = protoCount; orig_visProtoCount = protoCount; } else { protosperline = 1; orig_visProtoCount = 1; } protosperline = min(protosperline,orig_visProtoCount); int linecount = protosperline ? (orig_visProtoCount+(protosperline-1))/protosperline : 1; //divide with rounding to up for (line = 0; line < linecount; line++) { int rowheight = max(textSize.cy+2,iconHeight); protoCount = min(protosperline,(orig_protoCount-line*protosperline)); int visProtoCount = min(protosperline,(orig_visProtoCount-line*protosperline)); GetClientRect(hWnd,&rc); rc.top += g_StatusBarData.rectBorders.top; rc.bottom -= g_StatusBarData.rectBorders.bottom; aligndx = 0; maxwidth = 0; xstatus = 0; SumWidth = 0; int height = (rowheight*linecount); if (height > (rc.bottom - rc.top)) { rowheight = (rc.bottom - rc.top) / linecount; height = (rowheight*linecount); } int rowsdy = ((rc.bottom-rc.top)-height)/2; if (rowheight*(line)+rowsdy < rc.top-rowheight) continue; if (rowheight*(line+1)+rowsdy>rc.bottom+rowheight) break; if (g_StatusBarData.VAlign == 0) { //top rc.bottom = rc.top+rowheight*(line+1); rc.top = rc.top+rowheight*line+1; } else if (g_StatusBarData.VAlign == 1) { //center rc.bottom = rc.top+rowsdy+rowheight*(line+1); rc.top = rc.top+rowsdy+rowheight*line+1; } else if (g_StatusBarData.VAlign == 2) { //bottom rc.top = rc.bottom - (rowheight*(linecount - line)); rc.bottom = rc.bottom - (rowheight*(linecount - line - 1)+1); } textY = rc.top+(((rc.bottom-rc.top)-textSize.cy)/2); iconY = rc.top+(((rc.bottom-rc.top)-iconHeight)/2); //Code for each line DWORD sw; rectwidth = rc.right-rc.left-g_StatusBarData.rectBorders.left-g_StatusBarData.rectBorders.right; if (visProtoCount > 1) sw = (rectwidth-(g_StatusBarData.extraspace*(visProtoCount-1)))/visProtoCount; else sw = rectwidth; int *ProtoWidth = (int*)mir_alloc(sizeof(int)*visProtoCount); for (i=0; i < visProtoCount; i++) { ProtoItemData& p = ProtosData[line*protosperline + i]; SIZE textSize; DWORD w = 0; w = p.PaddingLeft; w += p.PaddingRight; if (p.showProtoIcon) { w += GetSystemMetrics(SM_CXSMICON)+1; p.extraIcon = NULL; if ((p.xStatusMode & 8) && p.ProtoStatus > ID_STATUS_OFFLINE) { char str[MAXMODULELABELLENGTH]; mir_snprintf(str, SIZEOF(str), "%s/GetXStatus", p.AccountName); if (ServiceExists(str)) { char *dbTitle = "XStatusName"; char *dbTitle2 = NULL; xstatus = CallProtoService(p.AccountName,"/GetXStatus",(WPARAM)&dbTitle,(LPARAM)&dbTitle2); if (dbTitle && xstatus) { DBVARIANT dbv = {0}; if ( !DBGetContactSettingTString(NULL, p.AccountName, dbTitle, &dbv)) { p.ProtoXStatus = mir_tstrdup(dbv.ptszVal); db_free(&dbv); } } } } if ((p.xStatusMode & 3)) { if (p.ProtoStatus > ID_STATUS_OFFLINE) { char str[MAXMODULELABELLENGTH]; mir_snprintf(str, SIZEOF(str), "%s/GetXStatusIcon", p.AccountName); if ( ServiceExists(str)) p.extraIcon = (HICON)CallService(str,0,0); if (p.extraIcon && (p.xStatusMode & 3) == 3) w += GetSystemMetrics(SM_CXSMICON)+1; } } } if (p.showProtoName) { GetTextExtentPoint32(hDC, p.ProtoHumanName, lstrlen(p.ProtoHumanName), &textSize); w += textSize.cx + 3 + spaceWidth; } if (p.showProtoEmails && p.ProtoEMailCount) { GetTextExtentPoint32A(hDC, p.ProtoEMailCount, lstrlenA(p.ProtoEMailCount), &textSize); w += textSize.cx + 3 + spaceWidth; } if (p.showStatusName) { GetTextExtentPoint32A(hDC, p.ProtoStatusText, lstrlenA(p.ProtoStatusText), &textSize); w += textSize.cx + 3 + spaceWidth; } if ((p.xStatusMode&8) && p.ProtoXStatus) { GetTextExtentPoint32(hDC, p.ProtoXStatus, lstrlen(p.ProtoXStatus),&textSize); w += textSize.cx + 3 + spaceWidth; } if (p.showProtoName || (p.showProtoEmails && p.ProtoEMailCount) || p.showStatusName || ((p.xStatusMode & 8) && p.ProtoXStatus)) w -= spaceWidth; p.fullWidth = w; if (g_StatusBarData.sameWidth) { ProtoWidth[i] = sw; SumWidth += w; } else { ProtoWidth[i] = w; SumWidth += w; } } // Reposition rects for (i=0; i < visProtoCount; i++) if (ProtoWidth[i] > maxwidth) maxwidth = ProtoWidth[i]; if (g_StatusBarData.sameWidth) { for (i=0; i < visProtoCount; i++) ProtoWidth[i] = maxwidth; SumWidth = maxwidth * visProtoCount; } SumWidth += (visProtoCount-1) * (g_StatusBarData.extraspace+1); if (SumWidth > rectwidth) { float f = (float)rectwidth/SumWidth; SumWidth = 0; for (i=0; i < visProtoCount; i++) { ProtoWidth[i] = (int)((float)ProtoWidth[i]*f); SumWidth += ProtoWidth[i]; } SumWidth += (visProtoCount-1)*(g_StatusBarData.extraspace+1); } if (g_StatusBarData.Align == 1) //center aligndx = (rectwidth-SumWidth)>>1; else if (g_StatusBarData.Align == 2) //right aligndx = (rectwidth-SumWidth); // Draw in rects RECT r = rc; r.left += g_StatusBarData.rectBorders.left+aligndx; for (i=0; i < visProtoCount; i++) { ProtoItemData& p = ProtosData[line*protosperline + i]; HRGN rgn; HICON hIcon = NULL; HICON hxIcon = NULL; BOOL NeedDestroy = FALSE; int x = r.left; x += p.PaddingLeft; r.right = r.left+ProtoWidth[i]; if (p.showProtoIcon) { if (p.ProtoStatus > ID_STATUS_OFFLINE && (p.xStatusMode & 3) > 0) { char str[MAXMODULELABELLENGTH]; mir_snprintf(str, SIZEOF(str), "%s/GetXStatusIcon", p.AccountName); if ( ServiceExists(str)) { hxIcon = p.extraIcon; if (hxIcon) { if ((p.xStatusMode & 3) == 2) { hIcon = GetMainStatusOverlay(p.ProtoStatus); NeedDestroy = TRUE; } else if ((p.xStatusMode & 3) == 1) { hIcon = hxIcon; NeedDestroy = TRUE; hxIcon = NULL; } } } } if (hIcon == NULL && (hxIcon == NULL || ((p.xStatusMode & 3) == 3))) { if (hIcon == NULL && (p.connectingIcon == 1) && p.ProtoStatus >= ID_STATUS_CONNECTING && p.ProtoStatus <= ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES) { hIcon = (HICON)CLUI_GetConnectingIconService((WPARAM)p.AccountName,0); if (hIcon) NeedDestroy = TRUE; else hIcon = LoadSkinnedProtoIcon(p.AccountName,p.ProtoStatus); } else hIcon = LoadSkinnedProtoIcon(p.AccountName,p.ProtoStatus); } rgn = CreateRectRgn(r.left,r.top,r.right,r.bottom); if (g_StatusBarData.sameWidth) { int fw = p.fullWidth; int rw = r.right-r.left; if (g_StatusBarData.Align == 1) x = r.left+((rw-fw)/2); else if (g_StatusBarData.Align == 2) x = r.left+((rw-fw)); else x = r.left; } SelectClipRgn(hDC,rgn); p.DoubleIcons = FALSE; DWORD dim = p.isDimmed ? (( 64 << 24 ) | 0x80 ) : 0; if ((p.xStatusMode&3) == 3) { if (hIcon) mod_DrawIconEx_helper(hDC,x,iconY,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL, DI_NORMAL|dim ); if (hxIcon) { mod_DrawIconEx_helper(hDC,x+GetSystemMetrics(SM_CXSMICON)+1,iconY,hxIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL|dim); x += GetSystemMetrics(SM_CXSMICON)+1; } p.DoubleIcons = hIcon && hxIcon; } else { if (hxIcon) mod_DrawIconEx_helper(hDC,x,iconY,hxIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL|dim); if (hIcon) mod_DrawIconEx_helper(hDC,x,iconY,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL| ((hxIcon && (p.xStatusMode&4))?(192 << 24):0 ) | dim ); } if (hxIcon || hIcon) { /* TODO g_StatusBarData.bDrawLockOverlay options to draw locked proto*/ if ( db_get_b( NULL,p.AccountName,"LockMainStatus",0 )) { HICON hLockOverlay = LoadSkinnedIcon(SKINICON_OTHER_STATUS_LOCKED); if (hLockOverlay != NULL) { mod_DrawIconEx_helper(hDC, x, iconY, hLockOverlay, GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL | dim); Skin_ReleaseIcon(hLockOverlay); } } } if (hxIcon) DestroyIcon_protect(hxIcon); if (NeedDestroy) DestroyIcon_protect(hIcon); else Skin_ReleaseIcon(hIcon); x += GetSystemMetrics(SM_CXSMICON)+1; } if (p.showProtoName) { SIZE textSize; RECT rt = r; rt.left = x+(spaceWidth>>1); rt.top = textY; ske_DrawText(hDC,p.ProtoHumanName,lstrlen(p.ProtoHumanName),&rt,0); if ((p.showProtoEmails && p.ProtoEMailCount != NULL) || p.showStatusName || ((p.xStatusMode&8) && p.ProtoXStatus)) { GetTextExtentPoint32(hDC, p.ProtoHumanName, lstrlen(p.ProtoHumanName), &textSize); x += textSize.cx + 3; } } if (p.showProtoEmails && p.ProtoEMailCount != NULL) { SIZE textSize; RECT rt = r; rt.left = x+(spaceWidth>>1); rt.top = textY; ske_DrawTextA(hDC, p.ProtoEMailCount, lstrlenA(p.ProtoEMailCount), &rt, 0); if (p.showStatusName || ((p.xStatusMode&8) && p.ProtoXStatus)) { GetTextExtentPoint32A(hDC,p.ProtoEMailCount,lstrlenA(p.ProtoEMailCount),&textSize); x += textSize.cx+3; } } if (p.showStatusName) { SIZE textSize; RECT rt = r; rt.left = x+(spaceWidth>>1); rt.top = textY; ske_DrawTextA(hDC, p.ProtoStatusText, lstrlenA(p.ProtoStatusText), &rt, 0); if (((p.xStatusMode & 8) && p.ProtoXStatus)) { GetTextExtentPoint32A(hDC, p.ProtoStatusText, lstrlenA(p.ProtoStatusText), &textSize); x += textSize.cx+3; } } if ((p.xStatusMode&8) && p.ProtoXStatus) { RECT rt = r; rt.left = x+(spaceWidth>>1); rt.top = textY; ske_DrawText(hDC,p.ProtoXStatus,lstrlen(p.ProtoXStatus),&rt,0); } p.protoRect = r; r.left = r.right+g_StatusBarData.extraspace; DeleteObject(rgn); } mir_free(ProtoWidth); } SelectObject(hDC,hOldFont); ske_ResetTextEffect(hDC); return 0; } static BOOL _ModernStatus_OnExtraIconClick(int protoIndex) { if ( !mir_strcmpi(ProtosData[protoIndex].ProtoName, "ICQ")) { if (ProtosData[protoIndex].ProtoStatus < ID_STATUS_ONLINE) return FALSE; HMENU hMainStatusMenu = (HMENU)CallService(MS_CLIST_MENUGETSTATUS,0,0); if ( !hMainStatusMenu) return FALSE; HMENU hProtoStatusMenu = GetSubMenu( hMainStatusMenu, protoIndex ); if ( !hProtoStatusMenu) return FALSE; int extraStatusMenuIndex = 1; HMENU hExtraStatusMenu = GetSubMenu( hProtoStatusMenu, extraStatusMenuIndex ); if ( !hExtraStatusMenu) return FALSE; POINT pt; GetCursorPos( &pt ); HWND hWnd = (HWND) CallService( MS_CLUI_GETHWND, 0 ,0 ); TrackPopupMenu( hExtraStatusMenu, TPM_TOPALIGN|TPM_LEFTALIGN|TPM_LEFTBUTTON, pt.x, pt.y, 0, hWnd, NULL ); return TRUE; } if ( !mir_strcmpi( ProtosData[protoIndex].ProtoName, "JABBER" )) { if ( ProtosData[protoIndex].ProtoStatus < ID_STATUS_ONLINE ) return FALSE; // Show Moods char szService[128]; mir_snprintf(szService, SIZEOF(szService), "%s/AdvStatusSet/Mood", ProtosData[protoIndex].AccountName ); if ( ServiceExists(szService)) { CallService(szService, 0, 0); return TRUE; } } return FALSE; } #define TOOLTIP_TOLERANCE 5 LRESULT CALLBACK ModernStatusProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam) { static POINT ptToolTipShow = {0}; switch (msg) { case WM_CREATE: g_StatusBarData.hTheme = xpt_AddThemeHandle(hwnd,L"STATUS"); break; case WM_DESTROY: xpt_FreeThemeForWindow(hwnd); ProtosData.destroy(); break; case WM_SIZE: if ( !g_CluiData.fLayered || GetParent(hwnd) != pcli->hwndContactList) InvalidateRect(hwnd,NULL,FALSE); return DefWindowProc(hwnd, msg, wParam, lParam); case WM_ERASEBKGND: return 1; case WM_PAINT: if (GetParent(hwnd) == pcli->hwndContactList && g_CluiData.fLayered) CallService(MS_SKINENG_INVALIDATEFRAMEIMAGE,(WPARAM)hwnd,0); else if (GetParent(hwnd) == pcli->hwndContactList && !g_CluiData.fLayered) { RECT rc = {0}; GetClientRect(hwnd,&rc); rc.right++; rc.bottom++; HDC hdc = GetDC(hwnd); HDC hdc2 = CreateCompatibleDC(hdc); HBITMAP hbmp = ske_CreateDIB32(rc.right, rc.bottom); HBITMAP hbmpo = (HBITMAP)SelectObject(hdc2, hbmp); SetBkMode(hdc2,TRANSPARENT); ske_BltBackImage(hwnd, hdc2, &rc); ModernDrawStatusBarWorker(hwnd,hdc2); BitBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, hdc2, rc.left, rc.top, SRCCOPY); SelectObject(hdc2, hbmpo); DeleteObject(hbmp); mod_DeleteDC(hdc2); SelectObject(hdc,GetStockObject(DEFAULT_GUI_FONT)); ReleaseDC(hwnd,hdc); ValidateRect(hwnd,NULL); } else { RECT rc; GetClientRect(hwnd,&rc); PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd,&ps); HDC hdc2 = CreateCompatibleDC(hdc); HBITMAP hbmp = ske_CreateDIB32(rc.right,rc.bottom); HBITMAP hbmpo = (HBITMAP) SelectObject(hdc2,hbmp); HBRUSH br = GetSysColorBrush(COLOR_3DFACE); FillRect(hdc2,&ps.rcPaint,br); ModernDrawStatusBarWorker(hwnd,hdc2); BitBlt(hdc,ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right-ps.rcPaint.left,ps.rcPaint.bottom-ps.rcPaint.top, hdc2,ps.rcPaint.left,ps.rcPaint.top,SRCCOPY); SelectObject(hdc2,hbmpo); DeleteObject(hbmp); mod_DeleteDC(hdc2); ps.fErase = FALSE; EndPaint(hwnd,&ps); } return DefWindowProc(hwnd, msg, wParam, lParam); case WM_GETMINMAXINFO: { RECT rct; GetWindowRect(hwnd,&rct); memset((LPMINMAXINFO)lParam,0,sizeof(MINMAXINFO)); ((LPMINMAXINFO)lParam)->ptMinTrackSize.x = 16; ((LPMINMAXINFO)lParam)->ptMinTrackSize.y = 16; ((LPMINMAXINFO)lParam)->ptMaxTrackSize.x = 1600; ((LPMINMAXINFO)lParam)->ptMaxTrackSize.y = 1600; } return 0; case WM_SHOWWINDOW: { if (tooltipshoing) { NotifyEventHooks(g_CluiData.hEventStatusBarHideToolTip,0,0); tooltipshoing = FALSE; } int ID = Sync(FindFrameID, hwnd); if (ID) { int res = CallService(MS_CLIST_FRAMES_GETFRAMEOPTIONS, MAKEWPARAM(FO_FLAGS,ID),0); if (res >= 0) db_set_b(0,"CLUI","ShowSBar",(BYTE)(wParam/*(res&F_VISIBLE)*/?1:0)); } } break; case WM_TIMER: if (wParam == TM_STATUSBARHIDE) { KillTimer(hwnd,TM_STATUSBARHIDE); if (tooltipshoing) { NotifyEventHooks(g_CluiData.hEventStatusBarHideToolTip,0,0); tooltipshoing = FALSE; ReleaseCapture(); } } else if (wParam == TM_STATUSBAR) { POINT pt; KillTimer(hwnd,TM_STATUSBAR); GetCursorPos(&pt); if (pt.x == lastpnt.x && pt.y == lastpnt.y) { RECT rc; ScreenToClient(hwnd, &pt); for (int i=0; i < ProtosData.getCount(); i++) { rc = ProtosData[i].protoRect; if (PtInRect(&rc,pt)) { NotifyEventHooks(g_CluiData.hEventStatusBarShowToolTip,(WPARAM)ProtosData[i].AccountName,0); CLUI_SafeSetTimer(hwnd,TM_STATUSBARHIDE,db_get_w(NULL,"CLUIFrames","HideToolTipTime",SETTING_HIDETOOLTIPTIME_DEFAULT),0); tooltipshoing = TRUE; ClientToScreen(hwnd,&pt); ptToolTipShow = pt; SetCapture(hwnd); return 0; } } return 0; } } return 0; case WM_MOUSEMOVE: if (tooltipshoing) { POINT pt; GetCursorPos(&pt); if ( abs(pt.x-ptToolTipShow.x) > TOOLTIP_TOLERANCE || abs(pt.y-ptToolTipShow.y) > TOOLTIP_TOLERANCE) { KillTimer(hwnd,TM_STATUSBARHIDE); NotifyEventHooks(g_CluiData.hEventStatusBarHideToolTip,0,0); tooltipshoing = FALSE; ReleaseCapture(); } } break; case WM_SETCURSOR: if (g_CluiData.bBehindEdgeSettings) CLUI_UpdateTimer(0); { POINT pt; GetCursorPos(&pt); SendMessage(GetParent(hwnd),msg,wParam,lParam); if (pt.x == lastpnt.x && pt.y == lastpnt.y) return(CLUI_TestCursorOnBorders()); lastpnt = pt; if (tooltipshoing) if ( abs(pt.x-ptToolTipShow.x) > TOOLTIP_TOLERANCE || abs(pt.y-ptToolTipShow.y) > TOOLTIP_TOLERANCE) { KillTimer(hwnd,TM_STATUSBARHIDE); NotifyEventHooks(g_CluiData.hEventStatusBarHideToolTip,0,0); tooltipshoing = FALSE; ReleaseCapture(); } KillTimer(hwnd,TM_STATUSBAR); CLUI_SafeSetTimer(hwnd, TM_STATUSBAR, db_get_w(NULL,"CLC","InfoTipHoverTime", CLCDEFAULT_INFOTIPTIME),0); } return CLUI_TestCursorOnBorders(); case WM_LBUTTONDOWN: case WM_MBUTTONDOWN: case WM_RBUTTONDOWN: { RECT rc; POINT pt; pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam); KillTimer(hwnd,TM_STATUSBARHIDE); KillTimer(hwnd,TM_STATUSBAR); if (tooltipshoing) NotifyEventHooks(g_CluiData.hEventStatusBarHideToolTip,0,0); tooltipshoing = FALSE; for (int i=0; i < ProtosData.getCount(); i++) { ProtoItemData& p = ProtosData[i]; BOOL isOnExtra = FALSE; rc = p.protoRect; RECT rc1 = rc; rc1.left = rc.left+16; rc1.right = rc1.left+16; if ( PtInRect(&rc, pt) && PtInRect(&rc1,pt) && p.DoubleIcons) isOnExtra = TRUE; if ( PtInRect(&rc,pt)) { HMENU hMenu = NULL; BOOL bShift = ( GetKeyState( VK_SHIFT ) & 0x8000); BOOL bCtrl = ( GetKeyState( VK_CONTROL ) & 0x8000); if ((msg == WM_MBUTTONDOWN || (msg == WM_RBUTTONDOWN && bCtrl) || isOnExtra) && _ModernStatus_OnExtraIconClick( i )) return TRUE; if (msg == WM_LBUTTONDOWN && bCtrl) { if ( g_CluiData.bFilterEffective != CLVM_FILTER_PROTOS || !bShift ) { ApplyViewMode(""); mir_snprintf( g_CluiData.protoFilter, SIZEOF(g_CluiData.protoFilter), "%s|", p.AccountName ); g_CluiData.bFilterEffective = CLVM_FILTER_PROTOS; } else { char protoF[ sizeof(g_CluiData.protoFilter) ]; mir_snprintf( protoF, SIZEOF(protoF), "%s|", p.AccountName ); char *pos = strstri( g_CluiData.protoFilter, p.AccountName ); if (pos) { // remove filter int len = strlen( protoF ); memmove( pos, pos + len, strlen( pos + len ) + 1 ); if ( strlen( g_CluiData.protoFilter ) == 0 ) ApplyViewMode( "" ); else g_CluiData.bFilterEffective = CLVM_FILTER_PROTOS; } else { //add filter mir_snprintf( g_CluiData.protoFilter, SIZEOF(g_CluiData.protoFilter), "%s%s", g_CluiData.protoFilter, protoF ); g_CluiData.bFilterEffective = CLVM_FILTER_PROTOS; } } if (g_CluiData.bFilterEffective == CLVM_FILTER_PROTOS) { char filterName[ sizeof(g_CluiData.protoFilter) ] = { 0 }; filterName[0] = (char)13; int protoCount; PROTOACCOUNT ** accs; ProtoEnumAccounts( &protoCount, &accs ); bool first = true; for (int pos = 0; pos < protoCount; pos++) { int i = pcli->pfnGetAccountIndexByPos( pos ); if ( i < 0 && i >= protoCount ) continue; char protoF[ sizeof(g_CluiData.protoFilter) ]; mir_snprintf( protoF, SIZEOF(protoF), "%s|", accs[i]->szModuleName ); if ( strstri(g_CluiData.protoFilter, protoF)) { char * temp = mir_utf8encodeT( accs[i]->tszAccountName ); if ( !first ) strncat( filterName, "; ", SIZEOF(filterName) - strlen(filterName)); strncat( filterName, temp, SIZEOF(filterName) - strlen(filterName)); first = false; mir_free( temp ); } } SaveViewMode( filterName, _T(""), g_CluiData.protoFilter, 0, -1, 0, 0, 0, 0 ); ApplyViewMode( filterName ); } pcli->pfnClcBroadcast(CLM_AUTOREBUILD, 0, 0); CLUI__cliInvalidateRect( hwnd, NULL, FALSE ); SetCapture( NULL ); return 0; } if ( !hMenu) { if (msg == WM_RBUTTONDOWN) { BOOL a = ((g_StatusBarData.perProtoConfig && p.SBarRightClk) || g_StatusBarData.SBarRightClk ); if ( a ^ bShift ) hMenu = (HMENU)CallService(MS_CLIST_MENUGETMAIN,0,0); else hMenu = (HMENU)CallService(MS_CLIST_MENUGETSTATUS,0,0); } else { hMenu = (HMENU)CallService(MS_CLIST_MENUGETSTATUS,0,0); unsigned int cpnl = 0; int mcnt = GetMenuItemCount(hMenu); for (int j = 0; j < mcnt; ++j) { HMENU hMenus = GetSubMenu(hMenu, j); if (hMenus && cpnl++ == i) { hMenu = hMenus; break; } } } } ClientToScreen(hwnd,&pt); HWND parent = GetParent(hwnd); if (parent != pcli->hwndContactList) parent = GetParent(parent); TrackPopupMenu(hMenu,TPM_TOPALIGN|TPM_LEFTALIGN|TPM_LEFTBUTTON,pt.x,pt.y,0,parent,NULL); return 0; } } GetClientRect(hwnd, &rc); if ( PtInRect( &rc, pt ) && msg == WM_LBUTTONDOWN && g_CluiData.bFilterEffective == CLVM_FILTER_PROTOS) { ApplyViewMode( "" ); CLUI__cliInvalidateRect( hwnd, NULL, FALSE ); SetCapture( NULL ); return 0; } return SendMessage(GetParent(hwnd), msg, wParam, lParam ); } } return DefWindowProc(hwnd, msg, wParam, lParam); } HWND StatusBar_Create(HWND parent) { WNDCLASS wndclass = {0}; TCHAR pluginname[] = _T("ModernStatusBar"); int h = GetSystemMetrics(SM_CYSMICON)+2; if ( GetClassInfo(g_hInst,pluginname,&wndclass) == 0) { wndclass.style = 0; wndclass.lpfnWndProc = ModernStatusProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = g_hInst; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = GetSysColorBrush(COLOR_3DFACE); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = pluginname; RegisterClass(&wndclass); } hModernStatusBar = CreateWindow(pluginname, pluginname, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN, 0, 0, 0, h, parent, NULL, g_hInst, NULL); // register frame CLISTFrame Frame; memset(&Frame,0,sizeof(Frame)); Frame.cbSize = sizeof(CLISTFrame); Frame.hWnd = hModernStatusBar; Frame.align = alBottom; Frame.hIcon = LoadSkinnedIcon (SKINICON_OTHER_MIRANDA); Frame.Flags = (db_get_b(NULL,"CLUI","ShowSBar",SETTING_SHOWSBAR_DEFAULT)?F_VISIBLE:0)|F_LOCKED|F_NOBORDER|F_NO_SUBCONTAINER|F_TCHAR; Frame.height = h; Frame.tname = _T("Status Bar"); Frame.TBtname = TranslateT("Status Bar"); hFramehModernStatusBar = (HANDLE)CallService(MS_CLIST_FRAMES_ADDFRAME,(WPARAM)&Frame,0); CallService(MS_SKINENG_REGISTERPAINTSUB,(WPARAM)Frame.hWnd,(LPARAM)NewStatusPaintCallbackProc); //$$$$$ register sub for frame LoadStatusBarData(); CLUIServices_ProtocolStatusChanged(0,0); CallService(MS_CLIST_FRAMES_UPDATEFRAME,-1,0); return hModernStatusBar; }