summaryrefslogtreecommitdiff
path: root/SkinEngine
diff options
context:
space:
mode:
authormataes2007 <mataes2007@e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb>2011-11-26 15:41:10 +0000
committermataes2007 <mataes2007@e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb>2011-11-26 15:41:10 +0000
commitf04d64869f3b1de54fb343f28f955584780001b8 (patch)
tree5453dc10de3d980de79ffe019fa0b5fcb692a27d /SkinEngine
parent7aff1e4cb053394db57c2814d5fe1e6493e0cc75 (diff)
Project folders rename part 3
git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@215 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb
Diffstat (limited to 'SkinEngine')
-rw-r--r--SkinEngine/samples/01-basic/title_cb.pngbin0 -> 207 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_cc.pngbin0 -> 320 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_ct.pngbin0 -> 176 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_lb.pngbin0 -> 158 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_lc.pngbin0 -> 233 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_lt.pngbin0 -> 202 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_rb.pngbin0 -> 154 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_rc.pngbin0 -> 221 bytes
-rw-r--r--SkinEngine/samples/01-basic/title_rt.pngbin0 -> 223 bytes
-rw-r--r--SkinEngine/skinengine.sln20
-rw-r--r--SkinEngine/skinengine.vcproj282
-rw-r--r--SkinEngine/skinengine_8.sln20
-rw-r--r--SkinEngine/skinengine_8.vcproj282
-rw-r--r--SkinEngine/src/bitmap_cache.cpp53
-rw-r--r--SkinEngine/src/bitmap_cache.h32
-rw-r--r--SkinEngine/src/bitmap_funcs.cpp1178
-rw-r--r--SkinEngine/src/bitmap_funcs.h101
-rw-r--r--SkinEngine/src/data_source.cpp31
-rw-r--r--SkinEngine/src/data_source.h41
-rw-r--r--SkinEngine/src/headers.h60
-rw-r--r--SkinEngine/src/main.cpp121
-rw-r--r--SkinEngine/src/skin_common.h24
-rw-r--r--SkinEngine/src/skin_complex.cpp59
-rw-r--r--SkinEngine/src/skin_complex.h23
-rw-r--r--SkinEngine/src/skin_layout.cpp167
-rw-r--r--SkinEngine/src/skin_layout.h30
-rw-r--r--SkinEngine/src/skin_manager.cpp22
-rw-r--r--SkinEngine/src/skin_manager.h6
-rw-r--r--SkinEngine/src/skin_object.cpp116
-rw-r--r--SkinEngine/src/skin_object.h90
-rw-r--r--SkinEngine/src/skin_simple.cpp79
-rw-r--r--SkinEngine/src/skin_simple.h48
-rw-r--r--SkinEngine/src/xml_cache.cpp71
-rw-r--r--SkinEngine/src/xml_cache.h50
34 files changed, 3006 insertions, 0 deletions
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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_cb.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_cc.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_ct.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_lb.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_lc.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_lt.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_rb.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_rc.png
Binary files 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
--- /dev/null
+++ b/SkinEngine/samples/01-basic/title_rt.png
Binary files 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..8194957
--- /dev/null
+++ b/SkinEngine/skinengine.vcproj
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="skinengine"
+ ProjectGUID="{4A27088E-5ABF-433F-8061-4909A03CC9AB}"
+ RootNamespace="skinengine"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include;../ExternalAPI"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SKINENGINE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="msimg32.lib"
+ OutputFile="e:\Victor\CPP\miranda\cvsdump\miranda.my\bin9\Debug Unicode\Plugins\$(ProjectName).dll"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="../../include;../ExternalAPI"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SKINENGINE_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="msimg32.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\src\bitmap_cache.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\bitmap_funcs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\data_source.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_complex.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_layout.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_manager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_object.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_simple.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\xml_cache.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\src\bitmap_cache.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\bitmap_funcs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\data_source.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\headers.h"
+ >
+ </File>
+ <File
+ RelativePath=".\api\m_skinengine.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_common.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_complex.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_layout.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_manager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_object.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_simple.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\xml_cache.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
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..eb6be3d
--- /dev/null
+++ b/SkinEngine/skinengine_8.vcproj
@@ -0,0 +1,282 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="skinengine"
+ ProjectGUID="{4A27088E-5ABF-433F-8061-4909A03CC9AB}"
+ RootNamespace="skinengine"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="196613"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../include;../ExternalAPI"
+ PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SKINENGINE_EXPORTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="msimg32.lib"
+ OutputFile="e:\Victor\CPP\miranda\cvsdump\miranda.my\bin9\Debug Unicode\Plugins\$(ProjectName).dll"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ EnableIntrinsicFunctions="true"
+ AdditionalIncludeDirectories="../../include;../ExternalAPI"
+ PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SKINENGINE_EXPORTS"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="msimg32.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\src\bitmap_cache.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\bitmap_funcs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\data_source.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_complex.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_layout.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_manager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_object.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_simple.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\src\xml_cache.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\src\bitmap_cache.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\bitmap_funcs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\data_source.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\headers.h"
+ >
+ </File>
+ <File
+ RelativePath=".\api\m_skinengine.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_common.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_complex.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_layout.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_manager.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_object.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\skin_simple.h"
+ >
+ </File>
+ <File
+ RelativePath=".\src\xml_cache.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
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<CacheNode> 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 <math.h>
+
+#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;y<height;y++)
+ {
+ for (int x=0;x<width;x++)
+ {
+ for (int k = 0; k < 4; ++k)
+ {
+ int tot = ReadP(tmp,width,height,x+w,y+h,k) +
+ ReadP(tmp,width,height,x-w,y-h,k) -
+ ReadP(tmp,width,height,x-w,y+h,k) -
+ ReadP(tmp,width,height,x+w,y-h,k);
+
+ *dst = BYTE(tot*mul);
+
+ ++dst;
+ ++src;
+ }
+ }
+ }
+
+ delete [] buf_src;
+ delete [] buf_tmp;
+}
+
+void CMyBitmap::IncreaseAlpha(float q)
+{
+ BYTE *p = (BYTE *)bits;
+
+ for (int i = 0; i < height; ++i)
+ {
+ for (int j = 0; j < width; ++j)
+ {
+ if (!p[3])
+ {
+ p += 4;
+ continue;
+ }
+
+ float q1 = min(q, 255.f/p[3]);
+
+ for (int k = 0; k < 4; ++k)
+ {
+ *p = (BYTE)min(255, *p * q1);
+ ++p;
+ }
+ }
+ }
+}
+
+void CMyBitmap::DrawIcon(HICON hic, int x, int y, int w, int h)
+{
+ GdiFlush();
+
+ ICONINFO info;
+ GetIconInfo(hic, &info);
+
+ BITMAP bmpColor, bmpMask;
+ GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
+ GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);
+
+ if (!w) w = abs(bmpMask.bmWidth);
+ if (!h) h = abs(bmpMask.bmHeight);
+
+ if (bmpColor.bmBitsPixel == 32)
+ {
+ if ((w != abs(bmpMask.bmWidth)) || (h != abs(bmpMask.bmHeight)))
+ {
+ DeleteObject(info.hbmColor);
+ DeleteObject(info.hbmMask);
+ HICON hicTmp = (HICON)CopyImage(hic,IMAGE_ICON,w,h,LR_COPYFROMRESOURCE);
+ GetIconInfo(hicTmp, &info);
+ GetObject(info.hbmMask, sizeof(bmpMask), &bmpMask);
+ GetObject(info.hbmColor, sizeof(bmpColor), &bmpColor);
+ DestroyIcon(hicTmp);
+ }
+
+ BYTE *cbit = new BYTE[bmpColor.bmWidthBytes*bmpColor.bmHeight];
+ BYTE *mbit = new BYTE[bmpMask.bmWidthBytes*bmpMask.bmHeight];
+ GetBitmapBits(info.hbmColor, bmpColor.bmWidthBytes*bmpColor.bmHeight, cbit);
+ GetBitmapBits(info.hbmMask, bmpMask.bmWidthBytes*bmpMask.bmHeight, mbit);
+
+ for (int i = 0; i < bmpColor.bmHeight; i++)
+ {
+ for (int j = 0; j < bmpColor.bmWidth; j++)
+ {
+ BYTE *pixel = cbit + i*bmpColor.bmWidthBytes + j*4;
+ if (!pixel[3])
+ {
+ pixel[3] = (*(mbit + i*bmpMask.bmWidthBytes + j*bmpMask.bmBitsPixel/8) & (1<<(7-j%8))) ? 0 : 255;
+ }
+
+ if (pixel[3] != 255)
+ {
+ pixel[0] = PU_DIV255(pixel[0] * pixel[3]);
+ pixel[1] = PU_DIV255(pixel[1] * pixel[3]);
+ pixel[2] = PU_DIV255(pixel[2] * pixel[3]);
+ }
+ }
+ }
+
+ this->BlendBits((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<mx)?(BYTE)(((WORD)bx*7+(WORD)mx)>>3):bx;
+ rx=(rx<mx)?(BYTE)(((WORD)rx*7+(WORD)mx)>>3):rx;
+ gx=(gx<mx)?(BYTE)(((WORD)gx*7+(WORD)mx)>>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)&param))
+ 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; y<bi->bmiHeader.biHeight; ++y)
+ {
+ BYTE *p1=(BYTE *)bits + (bi->bmiHeader.biHeight-y-1)*bi->bmiHeader.biWidth*4;
+ for (int x=0; x<bi->bmiHeader.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..ca58cd5
--- /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 <windows.h>
+#include <process.h>
+#include <commctrl.h>
+#include <commdlg.h>
+
+// 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 "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(
+"<layout type='vertical'>\
+ <layout type='horizontal'>\
+ <image src='e:\\!!!\\title_lt.png' />\
+ <image src='e:\\!!!\\title_ct.png' width='auto' />\
+ <image src='e:\\!!!\\title_rt.png' />\
+ </layout>\
+ <layout type='horizontal'>\
+ <image src='e:\\!!!\\title_lc.png' height='auto' />\
+ <layout type='layered'>\
+ <image src='e:\\!!!\\title_cc.png' />\
+ <layout type='horizontal'>\
+ <text text='this is a sample text'/>\
+ <icon />\
+ </layout>\
+ </layout>\
+ <image src='e:\\!!!\\title_rc.png' height='auto' />\
+ </layout>\
+ <layout type='horizontal'>\
+ <image src='e:\\!!!\\title_lb.png' />\
+ <image src='e:\\!!!\\title_cb.png' width='auto' />\
+ <image src='e:\\!!!\\title_rb.png' />\
+ </layout>\
+</layout>");
+
+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(&params);
+ obj->Layout(&params);
+ obj->Paint(&params);
+ 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<ISkinElement> 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(&params->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(&params->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(&params->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(&params->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<Property> 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(&params->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(&params->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), &params->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<CachedClass> m_classes;
+ OBJLIST<CachedFile> 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__