summaryrefslogtreecommitdiff
path: root/plugins/CountryFlags/src/icons.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/CountryFlags/src/icons.cpp')
-rw-r--r--plugins/CountryFlags/src/icons.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/plugins/CountryFlags/src/icons.cpp b/plugins/CountryFlags/src/icons.cpp
new file mode 100644
index 0000000000..3b456a4d11
--- /dev/null
+++ b/plugins/CountryFlags/src/icons.cpp
@@ -0,0 +1,282 @@
+/*
+Miranda IM Country Flags Plugin
+Copyright (C) 2006-1007 H. Herkenrath
+
+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 (Flags-License.txt); if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "flags.h"
+
+extern HINSTANCE hInst;
+extern int nCountriesCount;
+extern struct CountryListEntry *countries;
+static HANDLE hServiceLoadIcon,hServiceCreateMergedIcon;
+
+/************************* Bitmap Access **************************/
+
+static HANDLE *phIconHandles;
+
+static int FASTCALL CountryNumberToBitmapIndex(int countryNumber)
+{
+ /* country number indices (same order as in flags.bmp) */
+ const int BitmapIndexMap[232]={
+ 0, 1, 7, 20, 27, 30, 31, 32, 33, 34, 36, 39, 40, 41, 43, 44, 45, 46, 47, 48,
+ 49, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 81, 82, 84, 86,
+ 90, 91, 92, 93, 94, 95, 98, 101, 102, 103, 104, 105, 106, 107, 178, 108, 109, 110, 111, 112,
+ 113, 116, 117, 118, 121, 122, 123, 212, 213, 216, 218, 220, 221, 222, 223, 224, 225, 226, 227, 228,
+ 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 248, 249,
+ 250, 251, 252, 253, 254, 255, 256, 257, 258, 260, 261, 263, 264, 265, 266, 267, 268, 269, 290, 291,
+ 297, 298, 299, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 370, 371, 372, 373, 374, 375, 376,
+ 377, 378, 379, 380, 381, 382, 385, 386, 387, 389, 420, 421, 441, 442, 500, 501, 502, 503, 504, 505,
+ 506, 507, 508, 509, 590, 591, 592, 593, 595, 596, 597, 598, 599, 670, 671, 672, 673, 674, 675, 676,
+ 677, 678, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 705, 706, 708, 709,
+ 711, 850, 852, 853, 855, 856, 880, 886, 960, 961, 962, 963, 964, 965, 966, 967, 968, 971, 972, 973,
+ 974, 975, 976, 977, 994, 995,1141,2691,3811,4101,6101,6722
+ };
+ /* shared flags by multiple countries */
+ switch(countryNumber) {
+ case 262: /* Reunion Island */
+ case 594: /* French Guiana */
+ case 5901: /* French Antilles */
+ countryNumber=33; /* France */
+ break;
+ case 120: /* Barbuda */
+ countryNumber=102; /* Antigua and Barbuda */
+ break;
+ case 6702: /* Tinian Island */
+ case 6701: /* Rota Island */
+ countryNumber=670; /* Saipan Island (Northern Mariana Islands) */
+ break;
+ case 115: /* Saint Kitts */
+ case 114: /* Nevis */
+ countryNumber=1141; /* Saint Kitts and Nevis */
+ break;
+ case 247: /* Ascension Island */
+ countryNumber=44; /* United Kingdom */
+ break;
+ case 6721: /* Australian Antarctic Territory */
+ countryNumber=61; /* Australia */
+ break;
+ case 5399: /* Guantanamo Bay */
+ countryNumber=1; /* USA */
+ }
+ /* binary search in index array */
+ { int low=0,i,high;
+ high=SIZEOF(BitmapIndexMap)-1;
+ if(countryNumber<=BitmapIndexMap[high])
+ while(low<=high) {
+ i=low+((high-low)/2);
+ /* never happens */
+ if(i<0 || i>=SIZEOF(BitmapIndexMap)) DebugBreak();
+ if(BitmapIndexMap[i]==countryNumber) return i;
+ if(countryNumber>BitmapIndexMap[i]) low=i+1;
+ else high=i-1;
+ }
+ }
+ /* Other,Unknown,Unspecified */
+ return 0;
+}
+
+// return value needs to be released using DestroyIcon()
+// only operates on color icons, which isn't a problem here
+static HICON FASTCALL ResizeIconCentered(HICON hIcon,int cx,int cy)
+{
+ HICON hResIcon=NULL;
+ ICONINFO icoi;
+ BITMAP bm;
+ register HDC hdc;
+ HBITMAP hbmPrev,hbm;
+ POINT pt;
+ hdc=CreateCompatibleDC(NULL);
+ if(hdc!=NULL) {
+ if(GetIconInfo(hIcon,&icoi)) {
+ if(GetObject(icoi.hbmColor,sizeof(bm),&bm) && bm.bmWidth<=cx && bm.bmHeight<=cy) {
+ pt.x=(cx-bm.bmWidth)/2;
+ pt.y=(cy-bm.bmHeight)/2;
+ hbmPrev = (HBITMAP)SelectObject(hdc, icoi.hbmColor);
+ if(hbmPrev!=NULL) { /* error on select? */
+ hbm=icoi.hbmColor;
+ icoi.hbmColor=CreateCompatibleBitmap(hdc,cx,cy);
+ if(icoi.hbmColor!=NULL)
+ if(SelectObject(hdc,icoi.hbmColor)!=NULL) { /* error on select? */
+ DeleteObject(hbm); /* delete prev color (XOR) */
+ if(BitBlt(hdc,0,0,cx,cy,NULL,0,0,BLACKNESS)) /* transparency: AND=0, XOR=1 */
+ if(DrawIconEx(hdc,pt.x,pt.y,hIcon,bm.bmWidth,bm.bmHeight,0,NULL,DI_IMAGE|DI_NOMIRROR)) {
+ if(SelectObject(hdc,icoi.hbmMask)!=NULL) { /* error on select? */
+ hbm=icoi.hbmMask;
+ icoi.hbmMask=CreateBitmap(cx,cy,1,1,NULL); /* mono */
+ if(icoi.hbmMask!=NULL)
+ if(SelectObject(hdc,icoi.hbmMask)!=NULL) { /* error on select? */
+ DeleteObject(hbm); /* delete prev mask (AND) */
+ if(BitBlt(hdc,0,0,cx,cy,NULL,0,0,WHITENESS)) /* transparency: AND=0, XOR=1 */
+ if(DrawIconEx(hdc,pt.x,pt.y,hIcon,0,0,0,NULL,DI_MASK|DI_NOMIRROR)) {
+ SelectObject(hdc,hbmPrev);
+ hResIcon=CreateIconIndirect(&icoi); /* bitmaps must not be selected */
+ }
+ }
+ }
+ }
+ }
+ SelectObject(hdc,hbmPrev);
+ }
+ }
+ DeleteObject(icoi.hbmColor);
+ DeleteObject(icoi.hbmMask);
+ }
+ DeleteDC(hdc);
+ }
+ return hResIcon;
+}
+
+/************************* Utils **********************************/
+
+HICON FASTCALL LoadFlagIcon(int countryNumber)
+{
+ char szId[20],*szCountry;
+ /* create identifier */
+ szCountry=(char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,countryNumber,0);
+ if(szCountry==NULL) szCountry=(char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,countryNumber=0xFFFF,0);
+ wsprintfA(szId,(countryNumber==0xFFFF)?"%s0x%X":"%s%i","flags_",countryNumber); /* buffer safe */
+ return (HICON)CallService(MS_SKIN2_GETICON,0,(LPARAM)szId);
+}
+
+int FASTCALL CountryNumberToIndex(int countryNumber)
+{
+ int i,nf=0;
+ for(i=0;i<nCountriesCount;++i) {
+ if(countries[i].id==countryNumber) return i;
+ if(countries[i].id==0xFFFF) nf=i;
+ }
+ return nf; /* Unknown */
+
+}
+
+/************************* Services *******************************/
+
+static INT_PTR ServiceLoadFlagIcon(WPARAM wParam,LPARAM lParam)
+{
+ /* return handle */
+ if ((BOOL)lParam) {
+ if(phIconHandles==NULL) return (int)(HANDLE)NULL;
+ return (int)phIconHandles[CountryNumberToIndex((int)wParam)];
+ }
+ /* return icon */
+ return (int)LoadFlagIcon(wParam);
+}
+
+static INT_PTR ServiceCreateMergedFlagIcon(WPARAM wParam,LPARAM lParam)
+{
+ HICON hUpperIcon,hLowerIcon;
+ ICONINFO icoi;
+ BITMAP bm;
+ HDC hdc;
+ POINT aptTriangle[3];
+ HICON hIcon=NULL;
+ HRGN hrgn;
+ HBITMAP hbmPrev;
+ /* load both icons */
+ hLowerIcon=(HICON)ServiceLoadFlagIcon((WPARAM)lParam,0);
+ if(hLowerIcon==NULL) return (int)(HICON)NULL;
+ hUpperIcon=(HICON)ServiceLoadFlagIcon(wParam,0);
+ /* merge them */
+ if(GetIconInfo(hLowerIcon,&icoi)) {
+ if(hUpperIcon!=NULL && GetObject(icoi.hbmColor,sizeof(bm),&bm)) {
+ hdc=CreateCompatibleDC(NULL);
+ if(hdc!=NULL) {
+ ZeroMemory(&aptTriangle,sizeof(aptTriangle));
+ aptTriangle[1].y=bm.bmHeight-1;
+ aptTriangle[2].x=bm.bmWidth-1;
+ hrgn=CreatePolygonRgn(aptTriangle,SIZEOF(aptTriangle),WINDING);
+ if(hrgn!=NULL) {
+ SelectClipRgn(hdc,hrgn);
+ DeleteObject(hrgn);
+ hbmPrev = (HBITMAP)SelectObject(hdc, icoi.hbmColor);
+ if(hbmPrev!=NULL) { /* error on select? */
+ if(DrawIconEx(hdc,0,0,hUpperIcon,bm.bmWidth,bm.bmHeight,0,NULL,DI_NOMIRROR|DI_IMAGE))
+ if(SelectObject(hdc,icoi.hbmMask)!=NULL) /* error on select? */
+ DrawIconEx(hdc,0,0,hUpperIcon,bm.bmWidth,bm.bmHeight,0,NULL,DI_NOMIRROR|DI_MASK);
+ SelectObject(hdc,hbmPrev);
+ }
+ DeleteObject(hrgn);
+ }
+ DeleteDC(hdc);
+ }
+ }
+ /* create icon */
+ hIcon=CreateIconIndirect(&icoi);
+ DeleteObject(icoi.hbmColor);
+ DeleteObject(icoi.hbmMask);
+ }
+ return (int)hIcon;
+}
+
+/************************* Misc ***********************************/
+
+void InitIcons(void)
+{
+ HIMAGELIST himl;
+ SKINICONDESC sid;
+ char szId[20];
+ int i,index;
+ HICON hIcon;
+
+ WCHAR szName[64];
+ LCID locale;
+ locale=(LCID)CallService(MS_LANGPACK_GETLOCALE,0,0);
+
+
+ /* register icons */
+ ZeroMemory(&sid,sizeof(sid));
+ sid.cbSize=sizeof(sid);
+ sid.pszName=szId;
+ sid.cx=GetSystemMetrics(SM_CXSMICON);
+ sid.cy=GetSystemMetrics(SM_CYSMICON);
+ sid.flags=SIDF_SORTED|SIDF_TCHAR;
+ sid.ptszSection=TranslateT("Country Flags");
+ /* all those flag icons do not need any transparency mask (flags are always opaque),
+ * storing them in a large bitmap to reduce file size */
+ himl=ImageList_LoadImage(hInst,MAKEINTRESOURCE(IDB_FLAGS),sid.cx,0,CLR_NONE,IMAGE_BITMAP,LR_CREATEDIBSECTION);
+ if(himl!=NULL) {
+ phIconHandles=(HANDLE*)mir_alloc(nCountriesCount*sizeof(HANDLE));
+ if(phIconHandles!=NULL)
+ for(i=0;i<nCountriesCount;++i) {
+
+ MultiByteToWideChar(locale,0,countries[i].szName,-1,szName,SIZEOF(szName));
+ szName[SIZEOF(szName)-1]=L'\0';
+ sid.pwszDescription=TranslateW(szName);
+
+ /* create identifier */
+ wsprintfA(szId,(countries[i].id==0xFFFF)?"%s0x%X":"%s%i","flags_",countries[i].id); /* buffer safe */
+ index=CountryNumberToBitmapIndex(countries[i].id);
+ /* create icon */
+ hIcon=ImageList_GetIcon(himl,index,ILD_NORMAL);
+ sid.hDefaultIcon=(hIcon!=NULL)?ResizeIconCentered(hIcon,sid.cx,sid.cy):NULL;
+ if(hIcon!=NULL) DestroyIcon(hIcon);
+ index=CountryNumberToIndex(countries[i].id);
+ phIconHandles[index] = Skin_AddIcon(&sid);
+ if(sid.hDefaultIcon!=NULL) DestroyIcon(sid.hDefaultIcon);
+ }
+ ImageList_Destroy(himl);
+ }
+ /* create services */
+ hServiceLoadIcon=CreateServiceFunction(MS_FLAGS_LOADFLAGICON,ServiceLoadFlagIcon);
+ hServiceCreateMergedIcon=CreateServiceFunction(MS_FLAGS_CREATEMERGEDFLAGICON,ServiceCreateMergedFlagIcon);
+}
+
+void UninitIcons(void)
+{
+ DestroyServiceFunction(hServiceLoadIcon);
+ DestroyServiceFunction(hServiceCreateMergedIcon);
+}