From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- skinengine/api/m_skinengine.h | 55 ++ skinengine/samples/01-basic/title_cb.png | Bin 0 -> 207 bytes skinengine/samples/01-basic/title_cc.png | Bin 0 -> 320 bytes skinengine/samples/01-basic/title_ct.png | Bin 0 -> 176 bytes skinengine/samples/01-basic/title_lb.png | Bin 0 -> 158 bytes skinengine/samples/01-basic/title_lc.png | Bin 0 -> 233 bytes skinengine/samples/01-basic/title_lt.png | Bin 0 -> 202 bytes skinengine/samples/01-basic/title_rb.png | Bin 0 -> 154 bytes skinengine/samples/01-basic/title_rc.png | Bin 0 -> 221 bytes skinengine/samples/01-basic/title_rt.png | Bin 0 -> 223 bytes skinengine/skinengine.sln | 20 + skinengine/skinengine.vcproj | 282 +++++++ skinengine/skinengine_8.sln | 20 + skinengine/skinengine_8.vcproj | 282 +++++++ skinengine/src/bitmap_cache.cpp | 53 ++ skinengine/src/bitmap_cache.h | 32 + skinengine/src/bitmap_funcs.cpp | 1178 ++++++++++++++++++++++++++++++ skinengine/src/bitmap_funcs.h | 101 +++ skinengine/src/data_source.cpp | 31 + skinengine/src/data_source.h | 41 ++ skinengine/src/headers.h | 60 ++ skinengine/src/main.cpp | 121 +++ skinengine/src/skin_common.h | 24 + skinengine/src/skin_complex.cpp | 59 ++ skinengine/src/skin_complex.h | 23 + skinengine/src/skin_layout.cpp | 167 +++++ skinengine/src/skin_layout.h | 30 + skinengine/src/skin_manager.cpp | 22 + skinengine/src/skin_manager.h | 6 + skinengine/src/skin_object.cpp | 116 +++ skinengine/src/skin_object.h | 90 +++ skinengine/src/skin_simple.cpp | 79 ++ skinengine/src/skin_simple.h | 48 ++ skinengine/src/xml_cache.cpp | 71 ++ skinengine/src/xml_cache.h | 50 ++ 35 files changed, 3061 insertions(+) create mode 100644 skinengine/api/m_skinengine.h create mode 100644 skinengine/samples/01-basic/title_cb.png create mode 100644 skinengine/samples/01-basic/title_cc.png create mode 100644 skinengine/samples/01-basic/title_ct.png create mode 100644 skinengine/samples/01-basic/title_lb.png create mode 100644 skinengine/samples/01-basic/title_lc.png create mode 100644 skinengine/samples/01-basic/title_lt.png create mode 100644 skinengine/samples/01-basic/title_rb.png create mode 100644 skinengine/samples/01-basic/title_rc.png create mode 100644 skinengine/samples/01-basic/title_rt.png create mode 100644 skinengine/skinengine.sln create mode 100644 skinengine/skinengine.vcproj create mode 100644 skinengine/skinengine_8.sln create mode 100644 skinengine/skinengine_8.vcproj create mode 100644 skinengine/src/bitmap_cache.cpp create mode 100644 skinengine/src/bitmap_cache.h create mode 100644 skinengine/src/bitmap_funcs.cpp create mode 100644 skinengine/src/bitmap_funcs.h create mode 100644 skinengine/src/data_source.cpp create mode 100644 skinengine/src/data_source.h create mode 100644 skinengine/src/headers.h create mode 100644 skinengine/src/main.cpp create mode 100644 skinengine/src/skin_common.h create mode 100644 skinengine/src/skin_complex.cpp create mode 100644 skinengine/src/skin_complex.h create mode 100644 skinengine/src/skin_layout.cpp create mode 100644 skinengine/src/skin_layout.h create mode 100644 skinengine/src/skin_manager.cpp create mode 100644 skinengine/src/skin_manager.h create mode 100644 skinengine/src/skin_object.cpp create mode 100644 skinengine/src/skin_object.h create mode 100644 skinengine/src/skin_simple.cpp create mode 100644 skinengine/src/skin_simple.h create mode 100644 skinengine/src/xml_cache.cpp create mode 100644 skinengine/src/xml_cache.h (limited to 'skinengine') diff --git a/skinengine/api/m_skinengine.h b/skinengine/api/m_skinengine.h new file mode 100644 index 0000000..98b3e88 --- /dev/null +++ b/skinengine/api/m_skinengine.h @@ -0,0 +1,55 @@ +struct ISkinBackend; +struct ISkinElement; + +struct SkinRenderParams +{ + HDC hdc; + RECT rc; +}; + +struct ISkinDataSource +{ + virtual LPCTSTR GetText(const TCHAR *key) = 0; + virtual HICON GetIcon(const TCHAR *key) = 0; + virtual HBITMAP GetBitmap(const TCHAR *key) = 0; + virtual ISkinBackend *GetObject(const TCHAR *key) = 0; +}; + +struct ISkinElement +{ + // general manadgement + virtual void SetParent(ISkinElement *parent) = 0; + virtual void LoadFromXml(HXML hXml) = 0; + virtual void SetId(const TCHAR *id) = 0; + virtual void SetDataSource(ISkinDataSource *ds) = 0; + virtual void Destroy() = 0; + + // rendering and layouting + virtual void Measure(SkinRenderParams *params) = 0; + virtual void Layout(SkinRenderParams *params) = 0; + virtual void Paint(SkinRenderParams *params) = 0; + + // element tree + virtual bool IsComplexObject() = 0; + virtual ISkinElement *GetParent() = 0; + virtual int GetChildCount() = 0; + virtual ISkinElement *GetChild(int index) = 0; + virtual bool AppendChild(ISkinElement *child) = 0; + virtual bool InsertChild(ISkinElement *child, int index) = 0; + virtual void RemoveChild(ISkinElement *child) = 0; + + // element properties + virtual void SetPropText(const TCHAR *key, const TCHAR *value) = 0; + virtual const TCHAR *GetPropText(const TCHAR *key, const TCHAR *value) = 0; + virtual void SetPropInt(const TCHAR *key, int value) = 0; + virtual void SetPropIntText(const TCHAR *key, const TCHAR *value) = 0; + virtual int GetPropInt(const TCHAR *key) = 0; +}; + +struct ISkinBackend +{ + virtual LPCTSTR GetText(const TCHAR *key) = 0; + virtual HICON GetIcon(const TCHAR *key) = 0; + virtual HBITMAP GetBitmap(const TCHAR *key) = 0; + virtual ISkinBackend *GetObject(const TCHAR *key) = 0; +}; diff --git a/skinengine/samples/01-basic/title_cb.png b/skinengine/samples/01-basic/title_cb.png new file mode 100644 index 0000000..ab04df9 Binary files /dev/null and b/skinengine/samples/01-basic/title_cb.png differ diff --git a/skinengine/samples/01-basic/title_cc.png b/skinengine/samples/01-basic/title_cc.png new file mode 100644 index 0000000..8919649 Binary files /dev/null and b/skinengine/samples/01-basic/title_cc.png differ diff --git a/skinengine/samples/01-basic/title_ct.png b/skinengine/samples/01-basic/title_ct.png new file mode 100644 index 0000000..089ddca Binary files /dev/null and b/skinengine/samples/01-basic/title_ct.png differ diff --git a/skinengine/samples/01-basic/title_lb.png b/skinengine/samples/01-basic/title_lb.png new file mode 100644 index 0000000..15250a0 Binary files /dev/null and b/skinengine/samples/01-basic/title_lb.png differ diff --git a/skinengine/samples/01-basic/title_lc.png b/skinengine/samples/01-basic/title_lc.png new file mode 100644 index 0000000..1ae9171 Binary files /dev/null and b/skinengine/samples/01-basic/title_lc.png differ diff --git a/skinengine/samples/01-basic/title_lt.png b/skinengine/samples/01-basic/title_lt.png new file mode 100644 index 0000000..62bbe07 Binary files /dev/null and b/skinengine/samples/01-basic/title_lt.png differ diff --git a/skinengine/samples/01-basic/title_rb.png b/skinengine/samples/01-basic/title_rb.png new file mode 100644 index 0000000..9a1278d Binary files /dev/null and b/skinengine/samples/01-basic/title_rb.png differ diff --git a/skinengine/samples/01-basic/title_rc.png b/skinengine/samples/01-basic/title_rc.png new file mode 100644 index 0000000..f3b45d7 Binary files /dev/null and b/skinengine/samples/01-basic/title_rc.png differ diff --git a/skinengine/samples/01-basic/title_rt.png b/skinengine/samples/01-basic/title_rt.png new file mode 100644 index 0000000..2d52671 Binary files /dev/null and b/skinengine/samples/01-basic/title_rt.png differ diff --git a/skinengine/skinengine.sln b/skinengine/skinengine.sln new file mode 100644 index 0000000..b729cc3 --- /dev/null +++ b/skinengine/skinengine.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skinengine", "skinengine.vcproj", "{4A27088E-5ABF-433F-8061-4909A03CC9AB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Debug|Win32.Build.0 = Debug|Win32 + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Release|Win32.ActiveCfg = Release|Win32 + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/skinengine/skinengine.vcproj b/skinengine/skinengine.vcproj new file mode 100644 index 0000000..77dea58 --- /dev/null +++ b/skinengine/skinengine.vcproj @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skinengine/skinengine_8.sln b/skinengine/skinengine_8.sln new file mode 100644 index 0000000..5047e7a --- /dev/null +++ b/skinengine/skinengine_8.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "skinengine", "skinengine_8.vcproj", "{4A27088E-5ABF-433F-8061-4909A03CC9AB}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Debug|Win32.ActiveCfg = Debug|Win32 + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Debug|Win32.Build.0 = Debug|Win32 + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Release|Win32.ActiveCfg = Release|Win32 + {4A27088E-5ABF-433F-8061-4909A03CC9AB}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/skinengine/skinengine_8.vcproj b/skinengine/skinengine_8.vcproj new file mode 100644 index 0000000..88d0fa3 --- /dev/null +++ b/skinengine/skinengine_8.vcproj @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/skinengine/src/bitmap_cache.cpp b/skinengine/src/bitmap_cache.cpp new file mode 100644 index 0000000..5c4eab8 --- /dev/null +++ b/skinengine/src/bitmap_cache.cpp @@ -0,0 +1,53 @@ +#include "headers.h" + +CBitmapCache g_BitmapCache; + +CBitmapCache::CBitmapCache(): m_cache(5, CacheNode::cmp) +{ +} + +CBitmapCache::~CBitmapCache() +{ + for (int i = 0; i < m_cache.getCount(); ++i) + { + delete m_cache[i].bitmap; + free(m_cache[i].path); + } +} + +HBITMAP CBitmapCache::LoadBitmap(const TCHAR *path) +{ + CacheNode search = {0}; + search.path = (TCHAR *)path; + CacheNode *newNode = m_cache.find(&search); + if (newNode) + { + newNode->refCount++; + return newNode->bitmap; + } + + newNode = new CacheNode; + newNode->path = _tcsdup(path); + char *s = mir_t2a(path); + newNode->bitmap = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (LPARAM)s); + mir_free(s); + newNode->refCount = 1; + m_cache.insert(newNode); + + return newNode->bitmap; +} + +void CBitmapCache::UnloadBitmap(HBITMAP bmp) +{ + for (int i = 0; i < m_cache.getCount(); ++i) + if (m_cache[i].bitmap == bmp) + { + if (--m_cache[i].refCount == 0) + { + DeleteObject(m_cache[i].bitmap); + free(m_cache[i].path); + m_cache.remove(i); + } + return; + } +} diff --git a/skinengine/src/bitmap_cache.h b/skinengine/src/bitmap_cache.h new file mode 100644 index 0000000..3cf4893 --- /dev/null +++ b/skinengine/src/bitmap_cache.h @@ -0,0 +1,32 @@ +#ifndef bitmap_cache_h__ +#define bitmap_cache_h__ + +class CMyBitmap; + +class CBitmapCache +{ +private: + struct CacheNode + { + TCHAR *path; + HBITMAP bitmap; + int refCount; + + static int cmp(const CacheNode *p1, const CacheNode *p2) + { + return lstrcmp(p1->path, p2->path); + } + }; + OBJLIST m_cache; + +public: + CBitmapCache(); + ~CBitmapCache(); + HBITMAP LoadBitmap(const TCHAR *path); + void UnloadBitmap(HBITMAP); +}; + +// The only instance +extern CBitmapCache g_BitmapCache; + +#endif // bitmap_cache_h__ diff --git a/skinengine/src/bitmap_funcs.cpp b/skinengine/src/bitmap_funcs.cpp new file mode 100644 index 0000000..37b4f3b --- /dev/null +++ b/skinengine/src/bitmap_funcs.cpp @@ -0,0 +1,1178 @@ +#include "headers.h" + +#include + +#define INT2FLOAT(x) ((x) << 10) +#define FLOAT2INT(x) ((x) >> 10) + +#define PU_FONT_THRESHOLD 96 +#define PU_BMP_ACCURATE_ARITHMETICS + +#ifdef PU_BMP_ACCURATE_ARITHMETICS + #define PU_DIV255(x) ((x)/255) + #define PU_DIV128(x) ((x)>>128) + typedef float pu_koef; +#else + #define PU_DIV255(x) ((x)>>8) + #define PU_DIV128(x) ((x)>>7) + typedef long pu_koef; +#endif + +CMyBitmap::CMyBitmap() +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; +} + +CMyBitmap::CMyBitmap(int w, int h) +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; + allocate(w,h); +} + +CMyBitmap::CMyBitmap(const TCHAR *fn, const TCHAR *fnAlpha) +{ + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; + bitsSave = 0; + loadFromFile(fn, fnAlpha); +} + +CMyBitmap::~CMyBitmap() +{ + if (bitsSave) + delete [] bitsSave; + free(); +} + +void CMyBitmap::setAlpha(BYTE level) +{ + if (!bits) return; + + GdiFlush(); + for (int i = 0; i < width*height; i++) + { + if (bits[i] & 0xff000000) + { + bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, geta(bits[i])*level/255); + } else + { + bits[i] = rgba(getr(bits[i])*level/255, getg(bits[i])*level/255, getb(bits[i])*level/255, level); + } + } +} + +void CMyBitmap::setAlphaRect(int x1, int y1, int x2, int y2, BYTE level) +{ + if (!bits) return; + + GdiFlush(); + for (int i = y1; i < y2; i++) + for (int j = x1; j < x2; j++) + { + int idx = i * width + j; + if (bits[idx] & 0xff000000) + { + bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, geta(bits[idx])*level/255); + } else + { + bits[idx] = rgba(getr(bits[idx])*level/255, getg(bits[idx])*level/255, getb(bits[idx])*level/255, level); + } + } +} + +void CMyBitmap::makeOpaque() +{ + if (!bits) return; + + GdiFlush(); + for (int i = 0; i < width*height; i++) + bits[i] |= 0xff000000; +} + +void CMyBitmap::makeOpaqueRect(int x1, int y1, int x2, int y2) +{ + if (!bits) return; + + GdiFlush(); + for (int i = y1; i < y2; i++) + for (int j = x1; j < x2; j++) + { + int idx = i * width + j; + bits[idx] |= 0xff000000; + } +} + +void CMyBitmap::saveAlpha(int x, int y, int w, int h) +{ + if (bitsSave) + delete [] bitsSave; + + GdiFlush(); + + if (!w) w = width; + if (!h) h = height; + + bitsSave = new COLOR32[w*h]; + COLOR32 *p1 = bitsSave; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + COLOR32 *p2 = bits + (y+i)*width + x; + p1 = bitsSave + i*w; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + *p1++ = *p2++; + } + } +} + +void CMyBitmap::restoreAlpha(int x, int y, int w, int h) +{ + if (!bitsSave) + return; + + GdiFlush(); + + if (!w) w = width; + if (!h) h = height; + + COLOR32 *p1 = bitsSave; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + COLOR32 *p2 = bits + (y+i)*width + x; + p1 = bitsSave + i*w; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + if ((*p1&0x00ffffff) != (*p2&0x00ffffff)) + { + *p2 |= 0xff000000; + } else + { + *p2 = (*p2&0x00ffffff) | (*p1&0xff000000); + } + ++p1; + ++p2; + } + } + + delete [] bitsSave; + bitsSave = 0; +} + +void CMyBitmap::BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h) +{ + if (!(bits && inbits)) return; + + GdiFlush(); + + float kx = (float)inw / w; + float ky = (float)inh / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + int dst_pixel = (i+y)*width + (j+x); + COLOR32 src = inbits[int(i*ky)*inw + int(j*kx)]; + COLOR32 dst = bits[dst_pixel]; + long alpha = geta(src); + bits[dst_pixel] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + } + } +} + +void CMyBitmap::Blend(CMyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + int kx = INT2FLOAT(bmp->width) / w; + int ky = INT2FLOAT(bmp->height) / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + int dst_pixel = (i+y)*width + (j+x); + COLOR32 src = bmp->bits[FLOAT2INT(i*ky)*bmp->width + FLOAT2INT(j*kx)]; + COLOR32 dst = bits[dst_pixel]; + long alpha = geta(src); + bits[dst_pixel] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + } + } +} + +void CMyBitmap::Draw(CMyBitmap *bmp, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + + if (!x && !y && (w == width) && (h == height) && (w == bmp->width) && (h == bmp->height)) + { + // fast bitmap copy is possible good for animated avatars + CopyMemory(bits, bmp->bits, width*height*sizeof(COLOR32)); + return; + } + + int kx = INT2FLOAT(bmp->width) / w; + int ky = INT2FLOAT(bmp->height) / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[FLOAT2INT(i*ky)*bmp->width + FLOAT2INT(j*kx)]; + } + } +} + +void CMyBitmap::BlendColorized(CMyBitmap *bmp, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// bits[(i+y)*width + (j+x)] = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])); + + long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + COLOR32 src = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 src = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha); + COLOR32 dst = bits[(i+y)*width + (j+x)]; +// long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + + } + } +} + +void CMyBitmap::DrawColorized(CMyBitmap *bmp, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + + GdiFlush(); + + if (!w) w = bmp->width; + if (!h) h = bmp->height; + float kx = (float)bmp->width / w; + float ky = (float)bmp->height / h; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + + long alpha = geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + bits[(i+y)*width + (j+x)] = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// bits[(i+y)*width + (j+x)] = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, geta(bmp->bits[int(i*ky)*bmp->width + int(j*kx)])); + } + } +} + +void CMyBitmap::BlendPart(CMyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + int kx = INT2FLOAT(win) / w; + int ky = INT2FLOAT(hin) / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + int dst_pixel = (i+y)*width + (j+x); + COLOR32 src = bmp->bits[FLOAT2INT(yin+i*ky)*bmp->width + FLOAT2INT(xin+j*kx)]; + COLOR32 dst = bits[dst_pixel]; + long alpha = geta(src); + bits[dst_pixel] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); +// bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void CMyBitmap::BlendPartColorized(CMyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + float kx = (float)win / w; + float ky = (float)hin / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + // we should swap B and R channels when working with win32 COLORREF + float koef1r = (255 - getb(color)) / 128.0f; + float koef1g = (255 - getg(color)) / 128.0f; + float koef1b = (255 - getr(color)) / 128.0f; + + int br = - 255 + 2 * getb(color); + int bg = - 255 + 2 * getg(color); + int bb = - 255 + 2 * getr(color); + + float koef2r = (getb(color)) / 128.0f; + float koef2g = (getg(color)) / 128.0f; + float koef2b = (getr(color)) / 128.0f; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + + long alpha = geta(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]); +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); + COLOR32 cl = alpha ? getr(bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)])*255/alpha : 0; +#pragma warning(push) +#pragma warning(disable: 4244) + COLOR32 src = (cl > 128) ? + rgba( + PU_DIV255((koef1r * cl + br)*alpha), + PU_DIV255((koef1g * cl + bg)*alpha), + PU_DIV255((koef1b * cl + bb)*alpha), + alpha): + rgba( + PU_DIV255(koef2r * cl * alpha), + PU_DIV255(koef2g * cl * alpha), + PU_DIV255(koef2b * cl * alpha), + alpha); +#pragma warning(pop) +// COLOR32 cl = getr(bmp->bits[int(i*ky)*bmp->width + int(j*kx)]); +// COLOR32 src = (cl > 128) ? +// rgba(koef1r * cl + br, koef1g * cl + bg, koef1b * cl + bb, alpha): +// rgba(koef2r * cl, koef2g * cl, koef2b * cl, alpha); + COLOR32 dst = bits[(i+y)*width + (j+x)]; +// long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+PU_DIV255((255-alpha)*getr(dst)), + getg(src)+PU_DIV255((255-alpha)*getg(dst)), + getb(src)+PU_DIV255((255-alpha)*getb(dst)), + geta(src)+PU_DIV255((255-alpha)*geta(dst)) + ); + +/* COLOR32 src = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + COLOR32 dst = bits[(i+y)*width + (j+x)]; + long alpha = geta(src); + bits[(i+y)*width + (j+x)] = rgba( + getr(src)+(255-alpha)*getr(dst)/255, + getg(src)+(255-alpha)*getg(dst)/255, + getb(src)+(255-alpha)*getb(dst)/255, + geta(src)+(255-alpha)*geta(dst)/255 + );*/ +// bits[(i+y)*width + (j+x)] = bmp->bits[int(yin+i*ky)*bmp->width + int(xin+j*kx)]; + } + } +} + +void CMyBitmap::DrawPart(CMyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h) +{ + if (!(bits && bmp && bmp->bits)) return; + if (!win || !hin) return; + + GdiFlush(); + + if (!w) w = win; + if (!h) h = hin; + int kx = INT2FLOAT(win) / w; + int ky = INT2FLOAT(hin) / h; + + if (x+w >= this->getWidth()) + w = this->getWidth() - x; + if (y+h >= this->getHeight()) + h = this->getHeight() - y; + + for (int i = 0; i < h; i++) + { + if (i+y < 0) continue; + if (i+y >= height) break; + for (int j = 0; j < w; j++) + { + if (j+x < 0) continue; + if (j+x >= width) break; + bits[(i+y)*width + (j+x)] = bmp->bits[FLOAT2INT(yin+i*ky)*bmp->width + FLOAT2INT(xin+j*kx)]; + } + } +} + +static __forceinline int ReadP(long *p, int w, int h, int x, int y, int k) +{ + if (x<0) x=0; else if (x>=w) x=w-1; + if (y<0) y=0; else if (y>=h) y=h-1; + return p[(x+y*w)*4+k]; +} + +void CMyBitmap::Blur(int w, int h) +{ + if ((w <= 0) || (h <= 0)) return; + + BYTE *buf_src = new BYTE[width*height*4]; + long *buf_tmp = new long[width*height*4]; + BYTE *buf_dst = (BYTE *)bits; + memcpy(buf_src, buf_dst, width*height*4); + + BYTE *src, *dst; + long *tmp; + + src = buf_src; + tmp = buf_tmp; + dst = buf_dst; + + int y; + + for (y = 0; y < height; ++y) + { + for (int x = 0; x < width; ++x) + { + for (int k = 0; k < 4; ++k) + { + int tot = src[0]; + if (x > 0) tot += tmp[-4]; + if (y > 0) tot += tmp[-width*4]; + if (x > 0 && y > 0) tot -= tmp[-(width+1)*4]; + *tmp = tot; + + ++src; + ++tmp; + } + } + } + + src = buf_src; + tmp = buf_tmp; + dst = buf_dst; + + float mul = 1.f/((w*2+1)*(h*2+1)); + for (y=0;yBlendBits((COLOR32 *)cbit, bmpColor.bmWidth, bmpColor.bmHeight, x, y, w, h); + + delete [] mbit; + delete [] cbit; + } else + { + this->saveAlpha(x,y,w,h); + DrawIconEx(this->getDC(), x, y, hic, w, h, 0, NULL, DI_NORMAL); + this->restoreAlpha(x,y,w,h); + } + + DeleteObject(info.hbmColor); + DeleteObject(info.hbmMask); +} + +//Base on code by Artem Shpynov +//from clist_modern plugin +//slightly modified and integrated to CMyBitmap class +void CMyBitmap::DrawText(TCHAR *str, int x, int y, int blur, int strength) +{ + SIZE sz; GetTextExtentPoint32(this->getDC(), str, lstrlen(str), &sz); + sz.cx += (blur+2)*2; sz.cy += (blur+2)*2; + x -= blur+2; y -= blur+2; + + static BYTE pbGammaWeight[256]={0}; + static BOOL bGammaWeightFilled=FALSE; + + if (!bGammaWeightFilled) + { + int i; + for(i=0;i<256;i++) + { + double f; + double gamma=(double)700/1000; + + f=(double)i/255; + f=pow(f,(1/gamma)); + + pbGammaWeight[i]=(BYTE)(255*f); + } + bGammaWeightFilled=1; + } + + CMyBitmap tmp(sz.cx, sz.cy); + HFONT hfnTmp = (HFONT)SelectObject(tmp.getDC(), GetCurrentObject(this->getDC(), OBJ_FONT)); + + RECT rc; SetRect(&rc, 0, 0, sz.cx, sz.cy); + SetTextColor(tmp.getDC(), RGB(255,255,255)); + SetBkColor(tmp.getDC(), RGB(0,0,0)); + ExtTextOutA(tmp.getDC(), 0, 0, ETO_OPAQUE, &rc, "", 0, NULL); + ::DrawText(tmp.getDC(), str, lstrlen(str), &rc, DT_CENTER|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER); + SelectObject(tmp.getDC(), hfnTmp); + + GdiFlush(); + + if (blur) + { + for (int i = 0; i < sz.cy; i++) + { + COLOR32 *row_src = tmp.bits + i * tmp.width; + + for (int j = 0; j < sz.cx; j++) + { + COLOR32 cl = row_src[j]; + if (!cl) continue; + + int a1 = (getr(cl) + getg(cl) + getb(cl)) / 3; + row_src[j] = rgba(a1, a1, a1, a1); + } + } + tmp.Blur(blur, blur); + tmp.IncreaseAlpha((float)(strength ? strength : blur)); + } + + // use Get*Value for COLORREF and get* for COLOR32 + COLOR32 textColor = GetTextColor(this->getDC()); + COLOR32 r = GetRValue(textColor); + COLOR32 g = GetGValue(textColor); + COLOR32 b = GetBValue(textColor); + + int minx = max(0,-x); + int miny = max(0,-y); + int maxx = min(sz.cx, width-x); + int maxy = min(sz.cy, height-y); + + for (int i = miny; i < maxy; i++) + { + COLOR32 *row_dst = bits + (i+y) * width + x; + COLOR32 *row_src = tmp.bits + i * tmp.width; + + for (int j = minx; j < maxx; j++) + { + COLOR32 bx,rx,gx,mx; + { + bx=pbGammaWeight[getb(row_src[j])]; + gx=pbGammaWeight[getg(row_src[j])]; + rx=pbGammaWeight[getr(row_src[j])]; + } + + bx=(pbGammaWeight[bx]*(255-b)+bx*(b))/255; + gx=(pbGammaWeight[gx]*(255-g)+gx*(g))/255; + rx=(pbGammaWeight[rx]*(255-r)+rx*(r))/255; + + mx=(BYTE)(max(max(bx,rx),gx)); + + if (1) + { + bx=(bx>3):bx; + rx=(rx>3):rx; + gx=(gx>3):gx; + // reduce boldeness at white fonts + } + COLOR32 cl = row_dst[j]; + if (mx) + { + COLOR32 rrx,grx,brx; + COLOR32 rlx,glx,blx; + COLOR32 axx=geta(cl); + COLOR32 mmx=(bx+gx+rx)/3; + COLOR32 nx=mmx;;//pbGammaWeight[mx];// + { + //Normalize components to alpha level + bx=(nx*(255-axx)+bx*axx)/255; + gx=(nx*(255-axx)+gx*axx)/255; + rx=(nx*(255-axx)+rx*axx)/255; + mx=(nx*(255-axx)+mmx*axx)/255; + } + { + blx = getb(cl); + glx = getg(cl); + rlx = getr(cl); + + brx=(b-blx)*bx/255; + grx=(g-glx)*gx/255; + rrx=(r-rlx)*rx/255; + row_dst[j] = rgba(rlx+rrx, glx+grx, blx+brx, mx+(255-mx)*axx/255); + } + } + } + } +} + +// based on code by Yuriy Zaporozhets from: +// http://www.codeproject.com/gdi/coolrgn.asp?df=100&forumid=739&exp=0&select=6341 +// slightly modified to integrate with CMyBitmap class. +HRGN CMyBitmap::buildOpaqueRgn(int level, bool opaque) +{ + GdiFlush(); + + const int addRectsCount = 64; + int rectsCount = addRectsCount; + PRGNDATA pRgnData = (PRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + LPRECT pRects = (LPRECT)(&pRgnData->Buffer); + + memset(pRgnData, 0, sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)); + pRgnData->rdh.dwSize = sizeof(RGNDATAHEADER); + pRgnData->rdh.iType = RDH_RECTANGLES; + + int first = 0; + bool wasfirst = false; + bool ismask = false; + for (int i = 0; i < height; i++) + { + int j; // we will need j after the loop! + for (j = 0; j < width; j++) + { + ismask = opaque ? (int)geta(this->getRow(i)[j]) > level : (int)geta(this->getRow(i)[j]) < level; + if (wasfirst) + { + if (!ismask) + { + SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1); + if ((int)(pRgnData->rdh.nCount) >= rectsCount) + { + rectsCount += addRectsCount; + LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT)); + delete pRgnData; + pRgnData = pRgnDataNew; + pRects = (LPRECT)(&pRgnData->Buffer); + } + wasfirst = false; + } + } else + if (ismask) // set wasfirst when mask is found + { + first = j; + wasfirst = true; + } + } + + if (wasfirst && ismask) + { + SetRect(&pRects[pRgnData->rdh.nCount++], first, i, j, i+1); + if ((int)(pRgnData->rdh.nCount) >= rectsCount) + { + rectsCount += addRectsCount; + LPRGNDATA pRgnDataNew = (LPRGNDATA)(new BYTE[sizeof(RGNDATAHEADER) + (rectsCount)*sizeof(RECT)]); + memcpy(pRgnDataNew, pRgnData, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT)); + delete pRgnData; + pRgnData = pRgnDataNew; + pRects = (LPRECT)(&pRgnData->Buffer); + } + wasfirst = false; + } + + } + + HRGN hRgn = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount*sizeof(RECT), (LPRGNDATA)pRgnData); + delete pRgnData; + return hRgn; +} + +static int hex2dec(char hex) +{ + if ((hex >= '0') && (hex <= '9')) + return hex - '0'; + if ((hex >= 'a') && (hex <= 'f')) + return hex - 'a' + 0xa; + if ((hex >= 'A') && (hex <= 'F')) + return hex - 'A' + 0xa; + return 0; +} +/* +bool CMyBitmap::loadFromFile_pixel(const TCHAR *fn, const TCHAR *fnAlpha) +{ + allocate(1,1); + int r, g, b, a=255; + const TCHAR *p = fn + lstrlenA("pixel:"); + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + *bits = rgba(r,g,b,a); + return true; +} + +bool CMyBitmap::loadFromFile_gradient(const TCHAR *fn, const TCHAR *fnAlpha) +{ + const char *p = fn + lstrlenA("gradient:"); + + if (*p == 'h') allocate(256,1); + else allocate(1,256); + + int r, g, b, a=255; + + p += 2; + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + COLOR32 from = rgba(r,g,b,a); + + p += 7; + r = (hex2dec(p[0]) << 4) + hex2dec(p[1]); + g = (hex2dec(p[2]) << 4) + hex2dec(p[3]); + b = (hex2dec(p[4]) << 4) + hex2dec(p[5]); + COLOR32 to = rgba(r,g,b,a); + + for (int i = 0; i < 256; ++i) + { + bits[i] = rgba( + ((255-i) * getr(from) + i * getr(to)) / 255, + ((255-i) * getg(from) + i * getg(to)) / 255, + ((255-i) * getb(from) + i * getb(to)) / 255, + 255 + ); + } + + return true; +} +*/ +bool CMyBitmap::loadFromFile_png(const TCHAR *fn, const TCHAR *fnAlpha) +{ + if (ServiceExists(MS_PNG2DIB)) + { + HANDLE hFile, hMap = 0; + BYTE *ppMap = 0; + long cbFileSize = 0; + BITMAPINFOHEADER *pDib; + BYTE *pDibBits; + if ((hFile = CreateFile(fn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) + if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL) + if ((ppMap = (BYTE*)MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL) + cbFileSize = GetFileSize(hFile, NULL); + if (cbFileSize) + { + PNG2DIB param; + param.pSource = ppMap; + param.cbSourceSize = cbFileSize; + param.pResult = &pDib; + if (CallService(MS_PNG2DIB, 0, (LPARAM)¶m)) + pDibBits = (BYTE*)(pDib+1); + else + cbFileSize = 0; + } + + if (ppMap) UnmapViewOfFile(ppMap); + if (hMap) CloseHandle(hMap); + if (hFile) CloseHandle(hFile); + + if (!cbFileSize) return false; + + BITMAPINFO *bi=(BITMAPINFO*)pDib; + BYTE *pt=(BYTE*)bi; + pt+=bi->bmiHeader.biSize; + + if (bi->bmiHeader.biBitCount != 32) + { + allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight)); + HDC hdcTmp = CreateCompatibleDC(getDC()); + HBITMAP hBitmap = CreateDIBitmap(getDC(), pDib, CBM_INIT, pDibBits, bi, DIB_PAL_COLORS); + SelectObject(hdcTmp, hBitmap); + BitBlt(this->getDC(), 0, 0, abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight), hdcTmp, 0, 0, SRCCOPY); + this->makeOpaque(); + DeleteDC(hdcTmp); + DeleteObject(hBitmap); + } else + { + allocate(abs(bi->bmiHeader.biWidth), abs(bi->bmiHeader.biHeight)); + BYTE *p2=(BYTE *)pt; + for (int y=0; ybmiHeader.biHeight; ++y) + { + BYTE *p1=(BYTE *)bits + (bi->bmiHeader.biHeight-y-1)*bi->bmiHeader.biWidth*4; + for (int x=0; xbmiHeader.biWidth; ++x) + { + p1[0]= p2[0]; + p1[1]= p2[1]; + p1[2]= p2[2]; + p1[3]= p2[3]; + p1 += 4; + p2 += 4; + } + } +// memcpy(bits, pt, bi->bmiHeader.biSizeImage); + premultipleChannels(); + } + + GlobalFree(pDib); + return true; + } else + { +// MessageBox(NULL, Translate("You need the png2dib plugin v. 0.1.3.x or later to process PNG images"), Translate("Error"), MB_OK); + return false; + } +} + +bool CMyBitmap::loadFromFile_default(const TCHAR *fn, const TCHAR *fnAlpha) +{ + SIZE sz; + HBITMAP hBmpLoaded = (HBITMAP)LoadImage(NULL, fn, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + if (!hBmpLoaded) + return false; + + BITMAP bm; GetObject(hBmpLoaded, sizeof(bm), &bm); + SetBitmapDimensionEx(hBmpLoaded, bm.bmWidth, bm.bmHeight, NULL); + + HDC dcTmp = CreateCompatibleDC(0); + GetBitmapDimensionEx(hBmpLoaded, &sz); + HBITMAP hBmpDcSave = (HBITMAP)SelectObject(dcTmp, hBmpLoaded); + + allocate(sz.cx, sz.cy); + BitBlt(dcBmp, 0, 0, width, height, dcTmp, 0, 0, SRCCOPY); + + DeleteObject(SelectObject(dcTmp, hBmpDcSave)); + DeleteDC(dcTmp); + + CMyBitmap alpha; + if (fnAlpha && alpha.loadFromFile(fnAlpha) && + (alpha.getWidth() == width) && + (alpha.getHeight() == height) ) + { + for (int i = 0; i < width*height; i++) + bits[i] = (bits[i] & 0x00ffffff) | ( (alpha.bits[i] & 0x000000ff) << 24 ); + premultipleChannels(); + } else + { + makeOpaque(); + } + return true; +} + +bool CMyBitmap::loadFromFile(const TCHAR *fn, const TCHAR *fnAlpha) +{ + if (bits) free(); + + /* + if (!_tcsncmp(fn, "pixel:", lstrlenA("pixel:"))) + { + return loadFromFile_pixel(fn, fnAlpha); + } else + if (!_tcsncmp(fn, "gradient:", lstrlenA("gradient:"))) + { + return loadFromFile_gradient(fn, fnAlpha); + } else + */ + { + TCHAR ext[5]; + memcpy(ext,fn+(lstrlen(fn)-4),5); + if (!lstrcmpi(ext,_T(".png"))) + { + return loadFromFile_png(fn, fnAlpha); + } else + { + return loadFromFile_default(fn, fnAlpha); + } + } + // unreachable place + return false; +} + +void CMyBitmap::allocate(int w, int h) +{ + if (dcBmp && (width == w) && (height == h)) return; + + width = w; + height = h; + + BITMAPINFO bi; + + bi.bmiHeader.biSize = sizeof(bi.bmiHeader); + bi.bmiHeader.biWidth = w; + bi.bmiHeader.biHeight = -h; + bi.bmiHeader.biPlanes = 1; + bi.bmiHeader.biBitCount = 32; + bi.bmiHeader.biCompression = BI_RGB; + + if (dcBmp) + { + DeleteObject(SelectObject(dcBmp, hBmpSave)); + DeleteDC(dcBmp); + } + + hBmp = (HBITMAP)CreateDIBSection(0, &bi, DIB_RGB_COLORS, (void **)&bits, 0, 0); + dcBmp = CreateCompatibleDC(0); + hBmpSave = (HBITMAP)SelectObject(dcBmp, hBmp); + + GdiFlush(); +} + +void CMyBitmap::free() +{ + GdiFlush(); + + DeleteObject(SelectObject(dcBmp, hBmpSave)); + DeleteDC(dcBmp); + + dcBmp = 0; + hBmp = 0; + bits = 0; + width = height = 0; +} + +void CMyBitmap::premultipleChannels() +{ + GdiFlush(); + + for (int i = 0; i < width*height; i++) + bits[i] = rgba(getr(bits[i])*geta(bits[i])/255, getg(bits[i])*geta(bits[i])/255, getb(bits[i])*geta(bits[i])/255, geta(bits[i])); +} diff --git a/skinengine/src/bitmap_funcs.h b/skinengine/src/bitmap_funcs.h new file mode 100644 index 0000000..054baef --- /dev/null +++ b/skinengine/src/bitmap_funcs.h @@ -0,0 +1,101 @@ +#ifndef bitmap_funcs_h__ +#define bitmap_funcs_h__ + +// This should make bitmap manipulations much easier... +class CMyBitmap +{ +public: + typedef unsigned long COLOR32; + static inline COLOR32 RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0xff) + { + return (a << 24) | (r << 16) | (g << 8) | b; + }; + +private: + HBITMAP hBmpSave, hBmp; + HDC dcBmp; + COLOR32 *bits; + COLOR32 *bitsSave; + int width, height; + + void free(); + + bool loadFromFile_pixel(const TCHAR *fn, const TCHAR *fnAlpha = 0); + bool loadFromFile_gradient(const TCHAR *fn, const TCHAR *fnAlpha = 0); + bool loadFromFile_png(const TCHAR *fn, const TCHAR *fnAlpha = 0); + bool loadFromFile_default(const TCHAR *fn, const TCHAR *fnAlpha = 0); + void premultipleChannels(); + +public: + CMyBitmap(); + CMyBitmap(int w, int h); + CMyBitmap(const TCHAR *fn, const TCHAR *fnAlpha = 0); + ~CMyBitmap(); + void allocate(int w, int h); + + bool loadFromFile(const TCHAR *fn, const TCHAR *fnAlpha = 0); + + int getWidth() { return width; } + int getHeight() { return height; } + + HDC getDC() { return dcBmp; } + HBITMAP getBitmap() { return hBmp; } + + void setAlpha(BYTE level); + void setAlphaRect(int x1, int y1, int x2, int y2, BYTE level); + void setAlphaRect(RECT rc, BYTE level) { setAlphaRect(rc.left, rc.top, rc.right, rc.bottom, level); } + + void makeOpaque(); + void makeOpaqueRect(int x1, int y1, int x2, int y2); + void makeOpaqueRect(RECT rc) { makeOpaqueRect(rc.left, rc.top, rc.right, rc.bottom); } + + void saveAlpha(int x = 0, int y = 0, int w = 0, int h = 0); + void restoreAlpha(int x = 0, int y = 0, int w = 0, int h = 0); + + void Blend(CMyBitmap *bmp, int x, int y, int w, int h); + void BlendPart(CMyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h); + void BlendBits(COLOR32 *inbits, int inw, int inh, int x, int y, int w, int h); + + void Draw(CMyBitmap *bmp, int x, int y, int w, int h); + void DrawPart(CMyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h); + + // slow, very slow... + void BlendColorized(CMyBitmap *bmp, int x, int y, int w, int h, COLOR32 color); + void DrawColorized(CMyBitmap *bmp, int x, int y, int w, int h, COLOR32 color); + void BlendPartColorized(CMyBitmap *bmp, int xin, int yin, int win, int hin, int x, int y, int w, int h, COLOR32 color); + + void Blur(int w, int h); + void IncreaseAlpha(float q); + + void DrawIcon(HICON hic, int x, int y, int w = 0, int h = 0); + void DrawText(TCHAR *str, int x, int y, int blur=0, int strength=0); + + __forceinline COLOR32 *getBits() { return bits; } + __forceinline COLOR32 *getRow(int row) { return bits + row * width; } + __forceinline COLOR32 *operator[] (int row) { return bits + row * width; } + + static __forceinline COLOR32 rgba(COLOR32 r, COLOR32 g, COLOR32 b, COLOR32 a) + { + return ((a & 0xff) << 24) | ((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff); + } + static __forceinline COLOR32 getr(COLOR32 c) + { + return (c >> 16) & 0xff; + } + static __forceinline COLOR32 getg(COLOR32 c) + { + return (c >> 8) & 0xff; + } + static __forceinline COLOR32 getb(COLOR32 c) + { + return c & 0xff; + } + static __forceinline COLOR32 geta(COLOR32 c) + { + return (c >> 24) & 0xff; + } + + HRGN buildOpaqueRgn(int level = 64, bool opaque = true); +}; + +#endif // __bitmap_funcs_h__ diff --git a/skinengine/src/data_source.cpp b/skinengine/src/data_source.cpp new file mode 100644 index 0000000..ec8545f --- /dev/null +++ b/skinengine/src/data_source.cpp @@ -0,0 +1,31 @@ +#include "headers.h" + +CSkinDataSource::CSkinDataSource() +{ +} + +CSkinDataSource::~CSkinDataSource() +{ +} + +LPCTSTR CSkinDataSource::GetText(const TCHAR *key) +{ + if (!key || key[0] != '@') return key; + if (key[1] == '@') return key + 1; + return NULL; +} + +HICON CSkinDataSource::GetIcon(const TCHAR *key) +{ + return NULL; +} + +HBITMAP CSkinDataSource::GetBitmap(const TCHAR *key) +{ + return g_BitmapCache.LoadBitmap(key); +} + +ISkinBackend *CSkinDataSource::GetObject(const TCHAR *key) +{ + return NULL; +} diff --git a/skinengine/src/data_source.h b/skinengine/src/data_source.h new file mode 100644 index 0000000..b6aba18 --- /dev/null +++ b/skinengine/src/data_source.h @@ -0,0 +1,41 @@ +#ifndef data_source_h__ +#define data_source_h__ +/* +class CSkinDataItem +{ +private: + TCHAR *m_name; + HICON m_icon; + HBITMAP m_bitmap; + const TCHAR *m_text; + +public: + CSkinDataItem(const TCHAR *name, HICON icon); + CSkinDataItem(const TCHAR *name, HBITMAP bitmap); + CSkinDataItem(const TCHAR *name, const TCHAR *text); + ~CSkinDataItem(); + + const TCHAR *GetName() { return m_text; } + HICON GetIcon() { return m_icon; } + HBITMAP GetBitmap() { return m_bitmap; } + const TCHAR *GetText() { return m_text; } +}; +*/ + +class CSkinDataSource: public ISkinDataSource +{ +private: + TCHAR *m_basePath; + ISkinBackend *m_backend; + +public: + CSkinDataSource(); + ~CSkinDataSource(); + + virtual LPCTSTR GetText(const TCHAR *key); + virtual HICON GetIcon(const TCHAR *key); + virtual HBITMAP GetBitmap(const TCHAR *key); + virtual ISkinBackend *GetObject(const TCHAR *key); +}; + +#endif // data_source_h__ diff --git a/skinengine/src/headers.h b/skinengine/src/headers.h new file mode 100644 index 0000000..f4e4849 --- /dev/null +++ b/skinengine/src/headers.h @@ -0,0 +1,60 @@ +#ifndef headers_h__ +#define headers_h__ + +// disable security warnings about "*_s" functions +#define _CRT_SECURE_NO_DEPRECATE + +// disable warnings about underscore in stdc functions +#pragma warning(disable: 4996) + +#define _WIN32_WINNT 0x0501 +#define WINVER 0x0500 +#define OEMRESOURCE + +// Windows headers +#include +#include +#include +#include + +// Resources +//#include "../resource.h" + +// Miranda headers +#define NOWIN2K +#define MIRANDA_VER 0x0700 + +extern "C" +{ + #include "newpluginapi.h" + #include "win2k.h" + #include "m_system.h" + #include "m_plugins.h" + #include "m_clui.h" + #include "m_clist.h" + #include "m_options.h" + #include "m_skin.h" + #include "m_langpack.h" + #include "m_database.h" + #include "m_utils.h" + #include "m_png.h" + #include "m_xml.h" +}; + +#include "m_system_cpp.h" + +// API for other plugins +#include "../api/m_skinengine.h" + +// Our common handlers +#include "bitmap_funcs.h" +#include "bitmap_cache.h" +#include "xml_cache.h" +#include "data_source.h" +#include "skin_object.h" +#include "skin_complex.h" +#include "skin_simple.h" +#include "skin_layout.h" +#include "skin_manager.h" + +#endif diff --git a/skinengine/src/main.cpp b/skinengine/src/main.cpp new file mode 100644 index 0000000..0f27f1e --- /dev/null +++ b/skinengine/src/main.cpp @@ -0,0 +1,121 @@ +#include "headers.h" + +PLUGINLINK* pluginLink; +HINSTANCE g_hInst; + +LIST_INTERFACE li; +MM_INTERFACE mmi; +XML_API xi; + +// {AC8B66B3-AFE1-4475-BABA-49783BA39A66} +#define MIID_SKINENGINE { 0xac8b66b3, 0xafe1, 0x4475, { 0xba, 0xba, 0x49, 0x78, 0x3b, 0xa3, 0x9a, 0x66 } } + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + "ske", + PLUGIN_MAKE_VERSION(0, 0, 0, 3), + "ske", + "", + "nullbie@gmail.com", + "(c)", + "http://miranda-im.org/", + UNICODE_AWARE, + 0, // replace internal version (if any) +#ifdef _UNICODE + // {CE2C0401-F9E0-40d7-8E95-1A4197D7AB04} + { 0xce2c0401, 0xf9e0, 0x40d7, { 0x8e, 0x95, 0x1a, 0x41, 0x97, 0xd7, 0xab, 0x4 } } +#else + // {DE1D765C-9DC2-4679-8633-EDAD492C8479} + { 0xde1d765c, 0x9dc2, 0x4679, { 0x86, 0x33, 0xed, 0xad, 0x49, 0x2c, 0x84, 0x79 } } +#endif +}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + g_hInst = hinstDLL; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID *MirandaPluginInterfaces(void) +{ + static const MUUID interfaces[] = { MIID_SKINENGINE, MIID_LAST }; + return interfaces; +} + +#ifdef _DEBUG +const TCHAR *xml =_T( +"\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +"); + +int svcTest(WPARAM, LPARAM) +{ + ISkinDataSource *ds = new CSkinDataSource; + + SkinRenderParams params = { GetDC(0) }; + int bytesProcessed = 0; + HXML hXml = xi.parseString(xml, &bytesProcessed, NULL); + ISkinElement *obj = SkinCreateObjectFromXml(hXml, ds); + obj->Measure(¶ms); + obj->Layout(¶ms); + obj->Paint(¶ms); + obj->Destroy(); + xi.destroyNode(hXml); + + delete ds; + return 0; +} +#endif + +extern "C" __declspec(dllexport) int Load(PLUGINLINK * link) +{ + pluginLink = link; + mir_getLI(&li); + mir_getMMI(&mmi); + mir_getXI(&xi); + +#ifdef _DEBUG + CreateServiceFunction("SkinEngine/Test", svcTest); + + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.flags = CMIF_ICONFROMICOLIB; + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_MIRANDA); + mi.position = 1900000000; + mi.pszName = LPGEN("Skin engine test"); + mi.pszService = "SkinEngine/Test"; + CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi ); +#endif + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + return 0; +} diff --git a/skinengine/src/skin_common.h b/skinengine/src/skin_common.h new file mode 100644 index 0000000..e5fb410 --- /dev/null +++ b/skinengine/src/skin_common.h @@ -0,0 +1,24 @@ +#ifndef skin_common_h__ +#define skin_common_h__ + +#define SKIN_PROP_GET(name) \ + if (!lstrcmp(key, _T(#name))) \ + return m_##name; + +#define SKIN_PROP_SET_INT(name) \ + if (!lstrcmp(key, _T(#name))) \ + { \ + m_##name = value; \ + return; \ + } + +#define SKIN_PROP_SET_STR(name) \ + if (!lstrcmp(key, _T(#name))) \ + { \ + if (m_##name) \ + free(m_##name); \ + m_##name = _tcsdup(value); \ + return; \ + } + +#endif // skin_common_h__ diff --git a/skinengine/src/skin_complex.cpp b/skinengine/src/skin_complex.cpp new file mode 100644 index 0000000..0deefc2 --- /dev/null +++ b/skinengine/src/skin_complex.cpp @@ -0,0 +1,59 @@ +#include "headers.h" + +CSkinComplexObject::CSkinComplexObject(): m_children(5) +{ +} + +CSkinComplexObject::~CSkinComplexObject() +{ + for (int i = 0; i < m_children.getCount(); ++i) + m_children[i]->Destroy(); + m_children.destroy(); +} + +void CSkinComplexObject::LoadFromXml(HXML hXml) +{ + CSkinObject::LoadFromXml(hXml); + + int nChildren = xi.getChildCount(hXml); + for (int i = 0; i < nChildren; ++i) + { + HXML hChild = xi.getChild(hXml, i); + if (ISkinElement *obj = SkinCreateObjectFromXml(hChild, m_ds)) + m_children.insert(obj, m_children.getCount()); + } +} + +bool CSkinComplexObject::IsComplexObject() +{ + return true; +} + +int CSkinComplexObject::GetChildCount() +{ + return m_children.getCount(); +} + +ISkinElement *CSkinComplexObject::GetChild(int index) +{ + return (index >= 0 && index < m_children.getCount()) ? m_children[index] : NULL; +} + +bool CSkinComplexObject::AppendChild(ISkinElement *child) +{ + m_children.insert(child, m_children.getCount()); + child->SetParent(this); + return true; +} + +bool CSkinComplexObject::InsertChild(ISkinElement *child, int index) +{ + m_children.insert(child, index); + child->SetParent(this); + return true; +} + +void CSkinComplexObject::RemoveChild(ISkinElement *child) +{ + m_children.remove(child); +} diff --git a/skinengine/src/skin_complex.h b/skinengine/src/skin_complex.h new file mode 100644 index 0000000..11fc37e --- /dev/null +++ b/skinengine/src/skin_complex.h @@ -0,0 +1,23 @@ +#ifndef skin_complex_h__ +#define skin_complex_h__ + +class CSkinComplexObject: public CSkinObject +{ +protected: + LIST m_children; + +public: + CSkinComplexObject(); + ~CSkinComplexObject(); + + virtual void CSkinComplexObject::LoadFromXml(HXML hXml); + + virtual bool IsComplexObject(); + virtual int GetChildCount(); + virtual ISkinElement *GetChild(int index); + virtual bool AppendChild(ISkinElement *child); + virtual bool InsertChild(ISkinElement *child, int index); + virtual void RemoveChild(ISkinElement *child); +}; + +#endif // skin_complex_h__ diff --git a/skinengine/src/skin_layout.cpp b/skinengine/src/skin_layout.cpp new file mode 100644 index 0000000..4f5f209 --- /dev/null +++ b/skinengine/src/skin_layout.cpp @@ -0,0 +1,167 @@ +#include "headers.h" + +void CSkinLayout::LoadFromXml(HXML hXml) +{ + CSkinComplexObject::LoadFromXml(hXml); + + const TCHAR *s = xi.getAttrValue(hXml, _T("type")); + if (!lstrcmp(s, _T("horizontal"))) + m_layoutMode = MODE_HORIZONTAL; + else if (!lstrcmp(s, _T("layered"))) + m_layoutMode = MODE_LAYERED; + else + m_layoutMode = MODE_VERTICAL; +} + +void CSkinLayout::Measure(SkinRenderParams *params) +{ + switch (m_layoutMode) + { + case MODE_HORIZONTAL: + MeasureHorizontal(params); + break; + + case MODE_LAYERED: + MeasureLayered(params); + break; + + case MODE_VERTICAL: + default: + MeasureVertical(params); + break; + } + +} + +void CSkinLayout::MeasureHorizontal(SkinRenderParams *params) +{ + int width = 0, height = 0; + for (int i = 0; i < m_children.getCount(); ++i) + { + m_children[i]->Measure(params); + width += params->rc.right; + height = max(height, params->rc.bottom); + } + SetRect(¶ms->rc, 0, 0, width, height); +} + +void CSkinLayout::MeasureVertical(SkinRenderParams *params) +{ + int width = 0, height = 0; + for (int i = 0; i < m_children.getCount(); ++i) + { + m_children[i]->Measure(params); + width = max(width, params->rc.right); + height += params->rc.bottom; + } + SetRect(¶ms->rc, 0, 0, width, height); +} + +void CSkinLayout::MeasureLayered(SkinRenderParams *params) +{ + int width = 0, height = 0; + for (int i = 0; i < m_children.getCount(); ++i) + { + m_children[i]->Measure(params); + width = max(width, params->rc.right); + height = max(height, params->rc.bottom); + } + SetRect(¶ms->rc, 0, 0, width, height); +} + +void CSkinLayout::Layout(SkinRenderParams *params) +{ + switch (m_layoutMode) + { + case MODE_HORIZONTAL: + LayoutHorizontal(params); + break; + + case MODE_LAYERED: + LayoutLayered(params); + break; + + case MODE_VERTICAL: + default: + LayoutVertical(params); + break; + } +} + +void CSkinLayout::Paint(SkinRenderParams *params) +{ + for (int i = 0; i < m_children.getCount(); ++i) + m_children[i]->Paint(params); +} + +void CSkinLayout::LayoutHorizontal(SkinRenderParams *params) +{ + int usedWidth = 0, flexibleCount = 0; + SkinRenderParams newParams = *params; + + for (int i = 0; i < m_children.getCount(); ++i) + { + m_children[i]->Measure(&newParams); + if (newParams.rc.right > 0) + usedWidth += newParams.rc.right; + else + ++flexibleCount; + } + + int flexibleWidth = flexibleCount ? ((params->rc.right - params->rc.left - usedWidth) / flexibleCount) : 0; + int x = params->rc.left; + + for (int i = 0; i < m_children.getCount(); ++i) + { + m_children[i]->Measure(&newParams); + if (newParams.rc.right <= 0) + newParams.rc.right = flexibleWidth; + + newParams.rc.left = x; + newParams.rc.right = x + newParams.rc.right; + newParams.rc.top = params->rc.top; + newParams.rc.bottom = params->rc.bottom; + x = newParams.rc.right; + + m_children[i]->Layout(&newParams); + } +} + +void CSkinLayout::LayoutVertical(SkinRenderParams *params) +{ + int usedHeight = 0, flexibleCount = 0; + SkinRenderParams newParams = *params; + + for (int i = 0; i < m_children.getCount(); ++i) + { + m_children[i]->Measure(&newParams); + if (newParams.rc.bottom > 0) + usedHeight += newParams.rc.bottom; + else + ++flexibleCount; + } + + int flexibleHeight = flexibleCount ? ((params->rc.bottom - params->rc.top - usedHeight) / flexibleCount) : 0; + int y = params->rc.top; + + for (int i = 0; i < m_children.getCount(); ++i) + { + m_children[i]->Measure(&newParams); + if (newParams.rc.bottom <= 0) + newParams.rc.bottom = flexibleHeight; + + newParams.rc.left = params->rc.left; + newParams.rc.right = params->rc.right; + newParams.rc.top = y; + newParams.rc.bottom = y + newParams.rc.bottom; + y = newParams.rc.bottom; + + m_children[i]->Layout(&newParams); + } +} + +void CSkinLayout::LayoutLayered(SkinRenderParams *params) +{ + for (int i = 0; i < m_children.getCount(); ++i) + m_children[i]->Layout(params); +} diff --git a/skinengine/src/skin_layout.h b/skinengine/src/skin_layout.h new file mode 100644 index 0000000..7e5a6a0 --- /dev/null +++ b/skinengine/src/skin_layout.h @@ -0,0 +1,30 @@ +#ifndef skin_layout_h__ +#define skin_layout_h__ + +class CSkinLayout: public CSkinComplexObject +{ +private: + enum + { + MODE_HORIZONTAL, + MODE_VERTICAL, + MODE_LAYERED + } m_layoutMode; + +public: + virtual void LoadFromXml(HXML hXml); + virtual void Measure(SkinRenderParams *params); + virtual void Layout(SkinRenderParams *params); + virtual void Paint(SkinRenderParams *params); + +private: + void MeasureHorizontal(SkinRenderParams *params); + void MeasureVertical(SkinRenderParams *params); + void MeasureLayered(SkinRenderParams *params); + + void LayoutHorizontal(SkinRenderParams *params); + void LayoutVertical(SkinRenderParams *params); + void LayoutLayered(SkinRenderParams *params); +}; + +#endif // skin_layout_h__ diff --git a/skinengine/src/skin_manager.cpp b/skinengine/src/skin_manager.cpp new file mode 100644 index 0000000..aa59b47 --- /dev/null +++ b/skinengine/src/skin_manager.cpp @@ -0,0 +1,22 @@ +#include "headers.h" + +ISkinElement *SkinCreateObjectFromXml(HXML hXml, ISkinDataSource *ds) +{ + CSkinObject *result = NULL; + + const TCHAR *name = xi.getName(hXml); + if (!lstrcmp(name, _T("image"))) + result = new CSkinImage; + else if (!lstrcmp(name, _T("icon"))) + result = new CSkinIcon; + else if (!lstrcmp(name, _T("text"))) + result = new CSkinText; + else if (!lstrcmp(name, _T("layout"))) + result = new CSkinLayout; + else + return NULL; + + result->SetDataSource(ds); + result->LoadFromXml(hXml); + return result; +} diff --git a/skinengine/src/skin_manager.h b/skinengine/src/skin_manager.h new file mode 100644 index 0000000..f17a2ae --- /dev/null +++ b/skinengine/src/skin_manager.h @@ -0,0 +1,6 @@ +#ifndef skin_manager_h__ +#define skin_manager_h__ + +ISkinElement *SkinCreateObjectFromXml(HXML hXml, ISkinDataSource *ds); + +#endif // skin_manager_h__ diff --git a/skinengine/src/skin_object.cpp b/skinengine/src/skin_object.cpp new file mode 100644 index 0000000..3224191 --- /dev/null +++ b/skinengine/src/skin_object.cpp @@ -0,0 +1,116 @@ +#include "headers.h" + +static int sttParseTextToInt(const TCHAR *str) +{ + if (!str) return 0; + if (!lstrcmp(str, _T("auto"))) return -1; + return _ttoi(str); +} + +void CSkinObject::LoadFromXml(HXML hXml) +{ + m_width = sttParseTextToInt(xi.getAttrValue(hXml, _T("width"))); + m_height = sttParseTextToInt(xi.getAttrValue(hXml, _T("height"))); +} + +void CSkinObject::SetParent(ISkinElement *parent) +{ + if (m_parent) m_parent->RemoveChild(this); + m_parent = parent; +} + +void CSkinObject::SetId(const TCHAR *id) +{ + if (m_id) free(m_id); + m_id = _tcsdup(id); +} + +void CSkinObject::SetDataSource(ISkinDataSource *ds) +{ + m_ds = ds; +} + +void CSkinObject::Destroy() +{ + delete this; +} + +void CSkinObject::Measure(SkinRenderParams *params) +{ + SetRect(¶ms->rc, 0, 0, m_width, m_height); +} + +void CSkinObject::Layout(SkinRenderParams *params) +{ + m_rcPosition = params->rc; +} + +bool CSkinObject::IsComplexObject() +{ + return false; +} + +ISkinElement *CSkinObject::GetParent() +{ + return m_parent; +} + +int CSkinObject::GetChildCount() +{ + return 0; +} + +ISkinElement *CSkinObject::GetChild(int index) +{ + return NULL; +} + +bool CSkinObject::AppendChild(ISkinElement *child) +{ + return false; +} + +bool CSkinObject::InsertChild(ISkinElement *child, int index) +{ + return false; +} + +void CSkinObject::RemoveChild(ISkinElement *child) +{ +} + +void CSkinObject::SetPropText(const TCHAR *key, const TCHAR *value) +{ + m_properties.insert(new Property(key, value)); +} + +const TCHAR *CSkinObject::GetPropText(const TCHAR *key, const TCHAR *value) +{ + Property search(key, 0); + if (Property *result = m_properties.find(&search)) + if (result->m_type == Property::Text) + return result->m_valueText; + return NULL; +} + +void CSkinObject::SetPropInt(const TCHAR *key, int value) +{ + m_properties.insert(new Property(key, value)); + + if (!lstrcmp(key, _T("width"))) m_width = value; else + if (!lstrcmp(key, _T("height"))) m_height = value; +} + +void CSkinObject::SetPropIntText(const TCHAR *key, const TCHAR *value) +{ + SetPropInt(key, sttParseTextToInt(value)); +} + +int CSkinObject::GetPropInt(const TCHAR *key) +{ + Property search(key, 0); + if (Property *result = m_properties.find(&search)) + if (result->m_type == Property::Integer) + return result->m_valueInt; + return 0; +} diff --git a/skinengine/src/skin_object.h b/skinengine/src/skin_object.h new file mode 100644 index 0000000..8d8c466 --- /dev/null +++ b/skinengine/src/skin_object.h @@ -0,0 +1,90 @@ +#ifndef skin_object_h__ +#define skin_object_h__ + +class CSkinObject: public ISkinElement +{ +protected: + // ganaral options + TCHAR *m_id; + ISkinDataSource *m_ds; + ISkinElement *m_parent; + + // options from skin data + int m_width, m_height; + int m_stateMask; + + // dynamic parameters + RECT m_rcPosition; + + // properties + struct Property + { + enum { None, Text, Integer } m_type; + TCHAR *m_key; + union + { + TCHAR *m_valueText; + int m_valueInt; + }; + + Property(const TCHAR *key, int value) + { + m_type = Integer; + m_key = _tcsdup(key); + m_valueInt = value; + } + Property(const TCHAR *key, const TCHAR *value) + { + m_type = Text; + m_key = _tcsdup(key); + m_valueText = _tcsdup(value); + } + ~Property() + { + free(m_key); + if (m_type == Text) free(m_valueText); + } + + static int cmp(const Property *p1, const Property *p2) + { + return lstrcmp(p1->m_key, p2->m_key); + } + }; + OBJLIST m_properties; + +public: + CSkinObject(): m_id(0), m_ds(0), m_parent(0), m_properties(5, Property::cmp) + { + } + virtual ~CSkinObject() + { + if (m_id) free(m_id); + } + +public: // ISkinElement implementation + virtual void SetParent(ISkinElement *parent); + virtual void SetId(const TCHAR *id); + virtual void SetDataSource(ISkinDataSource *ds); + virtual void Destroy(); + + virtual void LoadFromXml(HXML hXml); + virtual void Measure(SkinRenderParams *params); + virtual void Layout(SkinRenderParams *params); + virtual void Paint(SkinRenderParams *params) = 0; + + virtual bool IsComplexObject(); + virtual ISkinElement *GetParent(); + virtual int GetChildCount(); + virtual ISkinElement *GetChild(int index); + virtual bool AppendChild(ISkinElement *child); + virtual bool InsertChild(ISkinElement *child, int index); + virtual void RemoveChild(ISkinElement *child); + + virtual void SetPropText(const TCHAR *key, const TCHAR *value); + virtual const TCHAR *GetPropText(const TCHAR *key, const TCHAR *value); + virtual void SetPropInt(const TCHAR *key, int value); + virtual void SetPropIntText(const TCHAR *key, const TCHAR *value); + virtual int GetPropInt(const TCHAR *key); +}; + +#endif // skin_object_h__ diff --git a/skinengine/src/skin_simple.cpp b/skinengine/src/skin_simple.cpp new file mode 100644 index 0000000..7e72dfe --- /dev/null +++ b/skinengine/src/skin_simple.cpp @@ -0,0 +1,79 @@ +#include "headers.h" + +void CSkinImage::LoadFromXml(HXML hXml) +{ + CSkinObject::LoadFromXml(hXml); + m_source = xi.getAttrValue(hXml, _T("src")); + m_hbmp = m_ds->GetBitmap(m_source); + GetObject(m_hbmp, sizeof(m_bi), &m_bi); +} + +void CSkinImage::Measure(SkinRenderParams *params) +{ + + SetRect(¶ms->rc, 0, 0, 0, 0); + if (m_width == 0) params->rc.right = m_bi.bmWidth; + else if (m_width < 0) params->rc.right = 0; + else params->rc.right = m_width; + if (m_height == 0) params->rc.bottom = m_bi.bmHeight; + else if (m_height < 0) params->rc.bottom = 0; + else params->rc.bottom = m_height; +} + +void CSkinImage::Paint(SkinRenderParams *params) +{ + HDC hdc = CreateCompatibleDC(params->hdc); + SelectObject(hdc, m_hbmp); + BLENDFUNCTION bf = {0}; + bf.AlphaFormat = AC_SRC_ALPHA; + bf.BlendOp = AC_SRC_OVER; + bf.SourceConstantAlpha = 255; + AlphaBlend(params->hdc, + m_rcPosition.left, m_rcPosition.top, + m_rcPosition.right - m_rcPosition.left, m_rcPosition.bottom - m_rcPosition.top, + hdc, 0, 0, + m_bi.bmWidth, abs(m_bi.bmHeight), + bf); + DeleteDC(hdc); +} + +void CSkinIcon::LoadFromXml(HXML hXml) +{ + CSkinObject::LoadFromXml(hXml); + m_source = xi.getAttrValue(hXml, _T("src")); +} + +void CSkinIcon::Measure(SkinRenderParams *params) +{ + SetRect(¶ms->rc, 0, 0, 16, 16); +} + +void CSkinIcon::Paint(SkinRenderParams *params) +{ + DrawIconEx(params->hdc, + (m_rcPosition.left + m_rcPosition.right - 16) / 2, + (m_rcPosition.top + m_rcPosition.bottom - 16) / 2, + LoadSkinnedIcon(SKINICON_OTHER_MIRANDA), + 16, 16, + 0, NULL, DI_NORMAL); +} + +void CSkinText::LoadFromXml(HXML hXml) +{ + CSkinObject::LoadFromXml(hXml); + m_text = xi.getAttrValue(hXml, _T("text")); +} + +void CSkinText::Measure(SkinRenderParams *params) +{ + LPCTSTR text = m_ds ? m_ds->GetText(m_text) : m_text; + DrawText(params->hdc, text, lstrlen(text), ¶ms->rc, DT_NOPREFIX|DT_WORDBREAK|DT_CALCRECT); +} + +void CSkinText::Paint(SkinRenderParams *params) +{ + LPCTSTR text = m_ds ? m_ds->GetText(m_text) : m_text; + SetTextColor(params->hdc, RGB(255, 255, 255)); + SetBkMode(params->hdc, TRANSPARENT); + DrawText(params->hdc, text, lstrlen(text), &m_rcPosition, DT_NOPREFIX|DT_WORDBREAK); +} diff --git a/skinengine/src/skin_simple.h b/skinengine/src/skin_simple.h new file mode 100644 index 0000000..2f16fb1 --- /dev/null +++ b/skinengine/src/skin_simple.h @@ -0,0 +1,48 @@ +#ifndef skin_simple_h__ +#define skin_simple_h__ + +class CSkinImage: public CSkinObject +{ +private: + const TCHAR *m_source; + HBITMAP m_hbmp; + BITMAP m_bi; + +public: + CSkinImage() {} + ~CSkinImage() {} + + virtual void LoadFromXml(HXML hXml); + virtual void Measure(SkinRenderParams *params); + virtual void Paint(SkinRenderParams *params); +}; + +class CSkinIcon: public CSkinObject +{ +private: + const TCHAR *m_source; + +public: + CSkinIcon() {} + ~CSkinIcon() {} + + virtual void LoadFromXml(HXML hXml); + virtual void Measure(SkinRenderParams *params); + virtual void Paint(SkinRenderParams *params); +}; + +class CSkinText: public CSkinObject +{ +private: + const TCHAR *m_text; + +public: + CSkinText() {} + ~CSkinText() {} + + virtual void LoadFromXml(HXML hXml); + virtual void Measure(SkinRenderParams *params); + virtual void Paint(SkinRenderParams *params); +}; + +#endif // skin_simple_h__ diff --git a/skinengine/src/xml_cache.cpp b/skinengine/src/xml_cache.cpp new file mode 100644 index 0000000..136d257 --- /dev/null +++ b/skinengine/src/xml_cache.cpp @@ -0,0 +1,71 @@ +#include "headers.h" + +CXmlCache g_XmlCache; + +CXmlCache::CachedFile::CachedFile(const TCHAR *path, bool load) +{ + this->path = _tcsdup(path); + if (load) + { + } else + { + hXmlRoot = NULL; + } +} + +CXmlCache::CachedFile::~CachedFile() +{ + free(path); + if (hXmlRoot) xi.destroyNode(hXmlRoot); +} + +CXmlCache::CXmlCache(): m_files(5, CachedFile::cmp), m_classes(10, CachedClass::cmp) +{ +} + +CXmlCache::~CXmlCache() +{ +} + +void CXmlCache::LoadXmlFile(const TCHAR *path) +{ + CachedFile *file = new CachedFile(path); + if (!file->hXmlRoot) + { + delete file; + return; + } + + int count = xi.getChildCount(file->hXmlRoot); + for (int i = 0; i < count; ++i) + { + HXML hXml = xi.getChild(file->hXmlRoot, i); + if (!hXml) break; + + const TCHAR *tagName = xi.getName(hXml); + if (!tagName || lstrcmp(tagName, _T("class"))) continue; + + const TCHAR *className = xi.getAttrValue(hXml, _T("name")); + if (!className) continue; + + RegisterClass(className, file, hXml); + } +} + +void CXmlCache::UnloadXmlFile(const TCHAR *path) +{ +} + +void CXmlCache::RegisterClass(const TCHAR *name, CachedFile *file, HXML hXmlClass) +{ + CachedClass *cls = new CachedClass; + cls->name = name; + cls->file = file; + cls->hXml = hXmlClass; + m_classes.insert(cls); +} + +ISkinElement *CXmlCache::CreateObject(const TCHAR *name) +{ + return NULL; +} diff --git a/skinengine/src/xml_cache.h b/skinengine/src/xml_cache.h new file mode 100644 index 0000000..50e30e0 --- /dev/null +++ b/skinengine/src/xml_cache.h @@ -0,0 +1,50 @@ +#ifndef xml_cache_h__ +#define xml_cache_h__ + +class CXmlCache +{ +private: + struct CachedFile + { + TCHAR *path; + HXML hXmlRoot; + + CachedFile(const TCHAR *path, bool load=true); + ~CachedFile(); + + static int cmp(const CachedFile *p1, const CachedFile *p2) + { + return lstrcmp(p1->path, p2->path); + } + }; + + struct CachedClass + { + const TCHAR *name; + CachedFile *file; + HXML hXml; + + static int cmp(const CachedClass *p1, const CachedClass *p2) + { + return lstrcmp(p1->name, p2->name); + } + }; + + OBJLIST m_classes; + OBJLIST m_files; + + void RegisterClass(const TCHAR *name, CachedFile *file, HXML hXmlClass); + +public: + CXmlCache(); + ~CXmlCache(); + + void LoadXmlFile(const TCHAR *path); + void UnloadXmlFile(const TCHAR *path); + + ISkinElement *CreateObject(const TCHAR *name); +}; + +extern CXmlCache g_XmlCache; + +#endif // xml_cache_h__ -- cgit v1.2.3